diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-15 12:42:11 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-15 12:42:11 +0300 |
| commit | 6d2dc774947787dcef73a3251d1e9ec51bc526df (patch) | |
| tree | 05f3c67039a9c6e69854e7de88ef9d40c110ec21 /tests/snapshot_failure_test.c | |
| parent | 7b31d6a05357953c035e2ab05ec117ef748f7798 (diff) | |
Report selection allocation failure instead of truncating
On a screen taller than 256 rows the selection's row list is allocated.
When that failed, it fell back to the 256-entry stack array, so the
selection and the snapshot's selection spans silently stopped at row
256 while every call still reported success.
lines_init() now reports the failure. term_select_start() and
term_select_extend() return false and leave the selection unchanged,
term_snapshot_update() fails and keeps its previous content, and the
text getters return NULL, as they do for their other allocations.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tests/snapshot_failure_test.c')
| -rw-r--r-- | tests/snapshot_failure_test.c | 57 |
1 files changed, 52 insertions, 5 deletions
diff --git a/tests/snapshot_failure_test.c b/tests/snapshot_failure_test.c index 6ce8f7b..7d4b139 100644 --- a/tests/snapshot_failure_test.c +++ b/tests/snapshot_failure_test.c @@ -327,9 +327,8 @@ static bool resize_at(int k) return injected; } -/* More than 256 rows moves the scratch keys and spans off the stack. The - * selection is left out: its own row list falls back to 256 rows when its - * allocation fails, which is outside the snapshot. */ +/* More than 256 rows moves the scratch keys and spans, and the selection's + * row list, off the stack. */ static bool tall_screen_at(int k) { struct term_options options = { .size = { 8, 300 }, .scrollback = 5 }; @@ -339,6 +338,9 @@ static bool tall_screen_at(int k) for (int y = 0; y < 299; y++) term_feed(t, "\r\n", 2, 0); term_feed(t, "e\xcc\x81yes", 5, 0); + assert(term_select_start(t, (struct term_vector2i){ .x = 0, .y = 299 }, false, + TERM_SELECT_CELL)); + assert(term_select_extend(t, (struct term_vector2i){ .x = 3, .y = 299 }, true)); bool injected = update_failing_at(s, t, k); @@ -346,6 +348,8 @@ static bool tall_screen_at(int k) const struct term_cell *row = term_snapshot_row(s, 299); uint32_t cps[4]; assert(cluster_cps(s, &row[0], cps, 4) == 2 && cps[0] == 'e' && cps[1] == 0x301); + struct term_span span = term_snapshot_row_selection(s, 299); + assert(span.begin == 0 && span.end == 4); expect_matches_fresh(t, s); term_snapshot_free(s); @@ -375,6 +379,47 @@ static void tall_selection_is_kept(void) term_free(t); } +/* On a screen taller than 256 rows, selecting needs memory. When none is + * left, the call fails and the selection stays as it was. */ +static void tall_selection_fails_cleanly(void) +{ + struct term_options options = { .size = { 8, 300 }, .scrollback = 5 }; + struct term *t = term_new(&options); + assert(t); + for (int y = 0; y < 299; y++) + term_feed(t, "\r\n", 2, 0); + term_feed(t, "yes", 3, 0); + assert(term_select_start(t, (struct term_vector2i){ .x = 0, .y = 299 }, false, + TERM_SELECT_CELL)); + assert(term_select_extend(t, (struct term_vector2i){ .x = 1, .y = 299 }, true)); + char *before = term_selection_text(t); + assert(before && !strcmp(before, "ye")); + + alloc_was_failed = false; + alloc_countdown = 0; + assert(!term_select_extend(t, (struct term_vector2i){ .x = 2, .y = 299 }, true)); + alloc_countdown = -1; + assert(alloc_was_failed); + + alloc_was_failed = false; + alloc_countdown = 0; + assert(!term_select_start(t, (struct term_vector2i){ .x = 2, .y = 299 }, false, + TERM_SELECT_WORD)); + alloc_countdown = -1; + assert(alloc_was_failed); + + char *after = term_selection_text(t); + assert(after && !strcmp(after, before)); + term_text_free(before); + term_text_free(after); + + assert(term_select_extend(t, (struct term_vector2i){ .x = 2, .y = 299 }, true)); + char *grown = term_selection_text(t); + assert(grown && !strcmp(grown, "yes")); + term_text_free(grown); + term_free(t); +} + /* Scroll with clusters in most lines. Each step fails every allocation in * turn, then retries, and must match a fresh capture. */ static void scrolling_fails_cleanly(void) @@ -417,10 +462,12 @@ int main(void) /* Four reserve() buffers and the arena, after the screen grows. */ failures = sweep(resize_at); assert(failures >= 5); - /* Four reserve() buffers, the scratch array, and the arena. */ + /* Four reserve() buffers, the scratch array, the selection's row list, + * and the arena. */ failures = sweep(tall_screen_at); - assert(failures >= 6); + assert(failures >= 7); tall_selection_is_kept(); + tall_selection_fails_cleanly(); scrolling_fails_cleanly(); return 0; } |
