summaryrefslogtreecommitdiff
path: root/tests/history_text_test.c
diff options
context:
space:
mode:
authorBerke GΓΌzel <wenekar1@gmail.com>2026-10-12 17:49:34 +0300
committerBerke GΓΌzel <wenekar1@gmail.com>2026-10-12 17:49:34 +0300
commit4384435941b8c7658856b381d071aee2e0035e89 (patch)
tree5ece99c3dd1decb8ec3fd404c0ece2b5865a552a /tests/history_text_test.c
term: move the term core to subprojects/term
The core now builds, tests, and benchmarks alone, as a Meson subproject with no dependency on the main tree. - include/term/ holds term.h and the header-only unicode/. src/ holds the core and its private headers. The main tree gets only include/term through term_dep, so it cannot reach a private header. - The term tests, the term benchmarks, the Kitty parser suite, and tools/amalgamate.py and tools/generate_unicode.py move with it. The tests run as term:<name>. - The main build passes its -march (arch_flag) and b_ndebug to the subproject. A directory configured before this commit needs meson configure -Dterm:arch_flag=-march=... once. - The term tests compile with -UNDEBUG. They do work inside assert. - The subproject exports term_test_dep with term_api.h, for the main tree's render, thumbnail, color, and selection tests. - The Kitty bridge used struct vector2i and has not compiled since the public API redesign. It builds again. 2 of its 14 tests fail: REP after a tab, and a cursor report after a resize. - dirgraph.py drops the term and unicode layers. Its self-test uses pty. - The symbols test ignores the __odr_asan symbols that ASan adds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tests/history_text_test.c')
-rw-r--r--tests/history_text_test.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/tests/history_text_test.c b/tests/history_text_test.c
new file mode 100644
index 0000000..88ca6aa
--- /dev/null
+++ b/tests/history_text_test.c
@@ -0,0 +1,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;
+}