Line data Source code
1 : /**
2 : * @file tests/unit/test_tui_list_view.c
3 : * @brief Unit tests for the scroll/selection helper (US-11 v2).
4 : */
5 :
6 : #include "test_helpers.h"
7 : #include "tui/list_view.h"
8 :
9 1 : static void test_init_is_empty(void) {
10 : ListView lv;
11 1 : list_view_init(&lv);
12 1 : ASSERT(lv.count == 0, "count 0");
13 1 : ASSERT(lv.selected == -1, "selected -1");
14 1 : ASSERT(lv.scroll_top == 0, "scroll_top 0");
15 1 : ASSERT(lv.rows_visible == 0, "rows_visible 0");
16 : }
17 :
18 1 : static void test_set_count_selects_first_when_unset(void) {
19 1 : ListView lv; list_view_init(&lv);
20 1 : list_view_set_viewport(&lv, 5);
21 1 : list_view_set_count(&lv, 10);
22 1 : ASSERT(lv.selected == 0, "first item selected");
23 1 : ASSERT(lv.scroll_top == 0, "at top");
24 : }
25 :
26 1 : static void test_set_count_clamps_selected(void) {
27 1 : ListView lv; list_view_init(&lv);
28 1 : list_view_set_viewport(&lv, 5);
29 1 : list_view_set_count(&lv, 10);
30 1 : lv.selected = 7;
31 1 : lv.scroll_top = 5;
32 1 : list_view_set_count(&lv, 4);
33 1 : ASSERT(lv.selected == 3, "selection clamped to last valid");
34 1 : ASSERT(lv.scroll_top <= 3, "scroll clamped");
35 : }
36 :
37 1 : static void test_set_count_zero_resets_selection(void) {
38 1 : ListView lv; list_view_init(&lv);
39 1 : list_view_set_viewport(&lv, 5);
40 1 : list_view_set_count(&lv, 10);
41 1 : list_view_set_count(&lv, 0);
42 1 : ASSERT(lv.selected == -1, "empty list has no selection");
43 1 : ASSERT(lv.scroll_top == 0, "scroll reset");
44 : }
45 :
46 1 : static void test_move_down_advances_and_scrolls(void) {
47 1 : ListView lv; list_view_init(&lv);
48 1 : list_view_set_viewport(&lv, 3);
49 1 : list_view_set_count(&lv, 10);
50 4 : for (int i = 0; i < 3; i++) list_view_move_down(&lv);
51 1 : ASSERT(lv.selected == 3, "selected = 3");
52 1 : ASSERT(lv.scroll_top == 1, "scroll followed selection");
53 1 : ASSERT(list_view_is_visible(&lv, 3), "selection visible");
54 : }
55 :
56 1 : static void test_move_down_stops_at_last(void) {
57 1 : ListView lv; list_view_init(&lv);
58 1 : list_view_set_viewport(&lv, 5);
59 1 : list_view_set_count(&lv, 3);
60 11 : for (int i = 0; i < 10; i++) list_view_move_down(&lv);
61 1 : ASSERT(lv.selected == 2, "pinned at last");
62 : }
63 :
64 1 : static void test_move_up_stops_at_first(void) {
65 1 : ListView lv; list_view_init(&lv);
66 1 : list_view_set_viewport(&lv, 3);
67 1 : list_view_set_count(&lv, 10);
68 6 : for (int i = 0; i < 5; i++) list_view_move_down(&lv);
69 11 : for (int i = 0; i < 10; i++) list_view_move_up(&lv);
70 1 : ASSERT(lv.selected == 0, "pinned at first");
71 1 : ASSERT(lv.scroll_top == 0, "scroll back to top");
72 : }
73 :
74 1 : static void test_page_down_jumps_by_viewport(void) {
75 1 : ListView lv; list_view_init(&lv);
76 1 : list_view_set_viewport(&lv, 4);
77 1 : list_view_set_count(&lv, 20);
78 1 : list_view_page_down(&lv);
79 1 : ASSERT(lv.selected == 4, "selected jumped by 4");
80 1 : list_view_page_down(&lv);
81 1 : ASSERT(lv.selected == 8, "second page");
82 1 : ASSERT(list_view_is_visible(&lv, 8), "selection in viewport after page");
83 : }
84 :
85 1 : static void test_page_up_jumps_back(void) {
86 1 : ListView lv; list_view_init(&lv);
87 1 : list_view_set_viewport(&lv, 4);
88 1 : list_view_set_count(&lv, 20);
89 1 : lv.selected = 12;
90 1 : lv.scroll_top = 9;
91 1 : list_view_page_up(&lv);
92 1 : ASSERT(lv.selected == 8, "selected -= viewport");
93 : }
94 :
95 1 : static void test_home_end(void) {
96 1 : ListView lv; list_view_init(&lv);
97 1 : list_view_set_viewport(&lv, 5);
98 1 : list_view_set_count(&lv, 30);
99 1 : list_view_end(&lv);
100 1 : ASSERT(lv.selected == 29, "end selects last");
101 1 : ASSERT(list_view_is_visible(&lv, 29), "last visible");
102 1 : list_view_home(&lv);
103 1 : ASSERT(lv.selected == 0, "home selects first");
104 1 : ASSERT(lv.scroll_top == 0, "scroll to top");
105 : }
106 :
107 1 : static void test_reveal_keeps_selection_in_view(void) {
108 1 : ListView lv; list_view_init(&lv);
109 1 : list_view_set_viewport(&lv, 5);
110 1 : list_view_set_count(&lv, 30);
111 1 : lv.selected = 20;
112 1 : list_view_reveal_selected(&lv);
113 1 : ASSERT(list_view_is_visible(&lv, 20), "selection revealed");
114 1 : ASSERT(lv.scroll_top == 16, "minimum scroll for visibility");
115 : }
116 :
117 1 : static void test_set_viewport_reveals(void) {
118 1 : ListView lv; list_view_init(&lv);
119 1 : list_view_set_viewport(&lv, 10);
120 1 : list_view_set_count(&lv, 50);
121 1 : lv.selected = 40;
122 1 : list_view_reveal_selected(&lv);
123 1 : ASSERT(lv.scroll_top == 31, "scroll matches big viewport");
124 : /* Shrinking the viewport must keep selection visible. */
125 1 : list_view_set_viewport(&lv, 3);
126 1 : ASSERT(lv.rows_visible == 3, "viewport shrunk");
127 1 : ASSERT(list_view_is_visible(&lv, 40), "selection still visible");
128 : }
129 :
130 1 : static void test_move_on_empty_is_noop(void) {
131 1 : ListView lv; list_view_init(&lv);
132 1 : list_view_move_up(&lv);
133 1 : list_view_move_down(&lv);
134 1 : list_view_page_up(&lv);
135 1 : list_view_page_down(&lv);
136 1 : list_view_home(&lv);
137 1 : list_view_end(&lv);
138 1 : ASSERT(lv.selected == -1, "empty navigation left alone");
139 1 : ASSERT(lv.count == 0, "still empty");
140 : }
141 :
142 1 : static void test_is_visible_rejects_out_of_range(void) {
143 1 : ListView lv; list_view_init(&lv);
144 1 : list_view_set_viewport(&lv, 3);
145 1 : list_view_set_count(&lv, 5);
146 1 : ASSERT(list_view_is_visible(&lv, 0), "first visible");
147 1 : ASSERT(list_view_is_visible(&lv, 2), "last of viewport visible");
148 1 : ASSERT(!list_view_is_visible(&lv, 3), "row 3 not visible");
149 : }
150 :
151 1 : void test_tui_list_view_run(void) {
152 1 : RUN_TEST(test_init_is_empty);
153 1 : RUN_TEST(test_set_count_selects_first_when_unset);
154 1 : RUN_TEST(test_set_count_clamps_selected);
155 1 : RUN_TEST(test_set_count_zero_resets_selection);
156 1 : RUN_TEST(test_move_down_advances_and_scrolls);
157 1 : RUN_TEST(test_move_down_stops_at_last);
158 1 : RUN_TEST(test_move_up_stops_at_first);
159 1 : RUN_TEST(test_page_down_jumps_by_viewport);
160 1 : RUN_TEST(test_page_up_jumps_back);
161 1 : RUN_TEST(test_home_end);
162 1 : RUN_TEST(test_reveal_keeps_selection_in_view);
163 1 : RUN_TEST(test_set_viewport_reveals);
164 1 : RUN_TEST(test_move_on_empty_is_noop);
165 1 : RUN_TEST(test_is_visible_rejects_out_of_range);
166 1 : }
|