aboutsummaryrefslogtreecommitdiffstats
path: root/tests/screen_test.c
blob: 531685e9b1e4cfb66dd0ecc09413ff801e915c54 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/* Canonical-screen projection into independently sized client views. */
#include "slosh.h"

#include <stdio.h>
#include <string.h>

static int fails;

static void ok(const char *name, bool cond) {
  if (!cond) fails++;
  printf("%s %s\n", cond ? "ok  " : "FAIL", name);
}

static char at(screen_t *s, uint16_t x, uint16_t y) {
  cell_t *c = screen_at(s, x, y);
  return c && c->len ? c->text[0] : ' ';
}

int main(void) {
  screen_t src, view;
  screen_init(&src, 6, 4);
  for (uint16_t y = 0; y < src.rows; y++)
    for (uint16_t x = 0; x < src.cols; x++) {
      char ch = (char)('A' + y * src.cols + x);
      screen_put_utf8(&src, x, y, &ch, 1, (color_t){0}, (color_t){0}, 0);
    }
  src.cursor_visible = true;
  src.cursor_x = 4;
  src.cursor_y = 2;
  uint16_t link = screen_link_id(&src, "https://example.test", 20);
  screen_set_link(&src, 3, 2, link);
  screen_at(&src, 3, 2)->attrs = ATTR_BOLD;

  screen_init(&view, 8, 5);
  screen_project(&view, &src, 0, 0);
  ok("a larger client gets the canonical top-left", at(&view, 5, 3) == 'X');
  ok("columns beyond the canonical screen are filler", at(&view, 6, 0) == ' ');
  ok("rows beyond the canonical screen are filler", at(&view, 0, 4) == ' ');
  ok("the cursor is translated into the client",
     view.cursor_visible && view.cursor_x == 4 && view.cursor_y == 2);

  screen_resize(&view, 3, 2);
  screen_project(&view, &src, 2, 1);
  ok("a smaller client receives the selected crop",
     at(&view, 0, 0) == 'I' && at(&view, 2, 1) == 'Q');
  ok("styles survive projection", (screen_at(&view, 1, 1)->attrs & ATTR_BOLD));
  ok("hyperlinks survive projection",
     view.cur_link[4] != 0 &&
         strcmp(view.links[view.cur_link[4] - 1], "https://example.test") == 0);
  ok("a cursor in the crop uses local coordinates",
     view.cursor_visible && view.cursor_x == 2 && view.cursor_y == 1);

  uint16_t vx = 0, vy = 0;
  screen_follow_cursor(&src, 3, 2, &vx, &vy);
  ok("a small viewport follows the cursor minimally", vx == 2 && vy == 1);
  src.cursor_x = 1;
  src.cursor_y = 0;
  screen_follow_cursor(&src, 3, 2, &vx, &vy);
  ok("the viewport follows the cursor back toward the origin",
     vx == 1 && vy == 0);
  src.cursor_visible = false;
  vx = 99;
  vy = 99;
  screen_follow_cursor(&src, 3, 2, &vx, &vy);
  ok("a hidden cursor retains and clamps the viewport", vx == 3 && vy == 2);

  screen_put_utf8(&src, 4, 0, "日", strlen("日"), (color_t){0}, (color_t){0},
                  0);
  screen_resize(&view, 5, 1);
  screen_project(&view, &src, 0, 0);
  ok("a wide glyph cut at the right edge is blank", at(&view, 4, 0) == ' ');
  screen_project(&view, &src, 5, 0);
  ok("a wide-glyph tail cut at the left edge is blank", at(&view, 0, 0) == ' ');

  /* The diff must not trust a wide glyph's tail column. Rule, then a wide
   * glyph over it, then rule again: overwriting the head makes the terminal
   * blank the tail cell, so the third frame has to repaint that column even
   * though its content matches what the diff last painted there. Skipping it
   * is a one-cell hole in a border, where a wide title glyph used to be. */
  screen_t d;
  screen_init(&d, 6, 1);
  for (uint16_t x = 0; x < 6; x++)
    screen_put_utf8(&d, x, 0, "-", 1, (color_t){0}, (color_t){0}, 0);
  screen_render(&d); /* frame 1: the rule */
  screen_put_utf8(&d, 2, 0, "\xe6\x97\xa5", 3, (color_t){0}, (color_t){0},
                  0); /* frame 2: 日 over columns 2-3 */
  screen_render(&d);
  screen_put_utf8(&d, 2, 0, "-", 1, (color_t){0}, (color_t){0}, 0);
  screen_put_utf8(&d, 3, 0, "-", 1, (color_t){0}, (color_t){0}, 0);
  screen_render(&d); /* frame 3: the rule again */
  /* Both rule cells must go out: an explicit CUP to column 4, or the run
   * that starts at the head's CUP simply carrying on into it. Counting the
   * plain '-' bytes in the frame answers both shapes at once. */
  size_t dashes = 0;
  for (size_t i = 0; i < d.out_len; i++)
    if (d.out[i] == '-') dashes++;
  ok("an overwritten wide glyph's tail column is repainted", dashes == 2);

  screen_free(&d);
  screen_free(&view);
  screen_free(&src);
  printf("\n%s (%d failures)\n", fails ? "FAILED" : "all green", fails);
  return fails ? 1 : 0;
}