summaryrefslogtreecommitdiff
path: root/tests/history_text_test.c
blob: 88ca6aa1ef56d8945d30f65358ba4c4bbceb5e0c (plain)
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include "term/term.h"
#include "term_api.h"

#include <assert.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static struct term *new_term(int cols)
{
    struct term *term = term_new(&(struct term_options){
        .size = { .x = cols, .y = 2 },
        .scrollback = 100,
    });
    assert(term);
    return term;
}

static void feed(struct term *term, const char *text)
{
    term_feed(term, text, strlen(text), 0);
}

static void expect_history(struct term *term, int rows, const char *expected)
{
    char *text = tt_history_text(term, rows);
    assert(text);
    if (strcmp(text, expected)) {
        fprintf(stderr, "history: got \"%s\" want \"%s\"\n", text, expected);
        assert(0);
    }
    free(text);
}

static void unicode_and_selection(void)
{
    struct term *term = new_term(16);
    expect_history(term, 100, "");
    feed(term, "eĢšŸ‘©ā€šŸ’»ē•Œ\r\nnext\r\nlast");
    expect_history(term, 100, "eĢšŸ‘©ā€šŸ’»ē•Œ\n");
    expect_history(term, 0, "");
    term_select_start(term, (struct term_vector2i){0}, false, TERM_SELECT_CELL);
    term_select_extend(term, (struct term_vector2i){ .x = 4 }, false);
    char *before = tt_selection_text(term);
    assert(before);
    expect_history(term, 100, "eĢšŸ‘©ā€šŸ’»ē•Œ\n");
    char *after = tt_selection_text(term);
    assert(after && !strcmp(before, after));
    free(before);
    free(after);
    feed(term, "\033[?1049h");
    expect_history(term, 100, "");
    feed(term, "\033[?1049l");
    expect_history(term, 100, "eĢšŸ‘©ā€šŸ’»ē•Œ\n");
    term_free(term);
}

static void limits_and_scrolled_view(void)
{
    struct term *term = new_term(8);
    feed(term, "one\r\ntwo\r\nthree\r\nfour\r\nfive");
    expect_history(term, 100, "one\ntwo\nthree\n");
    expect_history(term, 2, "two\nthree\n");
    term_scroll(term, 2);
    expect_history(term, 100, "one\n");
    term_scroll(term, 100);
    expect_history(term, 100, "");
    term_scroll_to(term, 0);
    assert(term_resize(term, (struct term_vector2i){ .x = 12, .y = 2 }));
    expect_history(term, 100, "one\ntwo\nthree\n");
    term_free(term);
}

static void wrapped_rows(void)
{
    struct term *term = new_term(4);
    feed(term, "abcdefghi\r\nx\r\ny");
    expect_history(term, 100, "abcdefghi\n");
    expect_history(term, 2, "efghi\n");
    term_free(term);

    term = new_term(4);
    feed(term, "abcdefghijklm");
    expect_history(term, 100, "abcdefgh");
    term_free(term);
}

struct writer {
    struct term *term;
    _Atomic bool done;
};

static const char unicode_line[] = "eĢšŸ‘©ā€šŸ’»ē•Œ\r\n";
static const char history_line[] = "eĢšŸ‘©ā€šŸ’»ē•Œ\n";

static void *write_history(void *userdata)
{
    struct writer *writer = userdata;
    for (int i = 0; i < 1000; i++)
        feed(writer->term, unicode_line);
    atomic_store(&writer->done, true);
    return NULL;
}

static void concurrent_history(void)
{
    struct term *term = new_term(16);
    struct writer writer = { .term = term };
    pthread_t thread;
    assert(pthread_create(&thread, NULL, write_history, &writer) == 0);
    do {
        char *text = tt_history_text(term, 10);
        assert(text);
        size_t n = strlen(text);
        size_t line_len = sizeof(history_line) - 1;
        assert(n % line_len == 0 && n / line_len <= 10);
        for (size_t offset = 0; offset < n; offset += line_len)
            assert(!memcmp(text + offset, history_line, line_len));
        free(text);
    } while (!atomic_load(&writer.done));
    assert(pthread_join(thread, NULL) == 0);
    term_free(term);
}

int main(void)
{
    unicode_and_selection();
    limits_and_scrolled_view();
    wrapped_rows();
    concurrent_history();
    puts("PASS: history text");
    return 0;
}