From 4384435941b8c7658856b381d071aee2e0035e89 Mon Sep 17 00:00:00 2001 From: Berke GΓΌzel Date: Mon, 12 Oct 2026 17:49:34 +0300 Subject: 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:. - 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 --- tests/history_text_test.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 tests/history_text_test.c (limited to 'tests/history_text_test.c') 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 +#include +#include +#include +#include +#include + +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; +} -- cgit v1.2.3