1 #include <stic.h>
2
3 #include <locale.h> /* setlocale() */
4 #include <stddef.h> /* NULL size_t */
5 #include <string.h>
6
7 #include "../../src/utils/utf8.h"
8 #include "../../src/utils/utils.h"
9 #include "../../src/ui/column_view.h"
10
11 #include "test.h"
12
13 static void column_line_print(const void *data, int column_id, const char buf[],
14 size_t offset, AlignType align);
15 static void column1_func(int id, const void *data, size_t buf_len, char buf[]);
16 static void column2_func(int id, const void *data, size_t buf_len, char buf[]);
17 static int locale_works(void);
18
19 static const size_t MAX_WIDTH = 20;
20 static char print_buffer[80 + 1];
21
22 static const char *col1_str;
23
SETUP_ONCE()24 SETUP_ONCE()
25 {
26 (void)setlocale(LC_ALL, "");
27 if(!locale_works())
28 {
29 (void)setlocale(LC_ALL, "en_US.utf8");
30 }
31 }
32
SETUP()33 SETUP()
34 {
35 print_next = &column_line_print;
36 col1_next = &column1_func;
37 col2_next = &column2_func;
38
39 col1_str = "师从螺丝刀йклмнопрстуфхцчшщьыъэюя";
40 }
41
TEARDOWN()42 TEARDOWN()
43 {
44 print_next = NULL;
45 col1_next = NULL;
46 col2_next = NULL;
47 }
48
49 static void
column_line_print(const void * data,int column_id,const char buf[],size_t offset,AlignType align)50 column_line_print(const void *data, int column_id, const char buf[],
51 size_t offset, AlignType align)
52 {
53 strncpy(print_buffer +
54 utf8_nstrsnlen(print_buffer, offset), buf, strlen(buf));
55 }
56
57 static void
column1_func(int id,const void * data,size_t buf_len,char buf[])58 column1_func(int id, const void *data, size_t buf_len, char buf[])
59 {
60 snprintf(buf, buf_len + 1, "%s", col1_str);
61 }
62
63 static void
column2_func(int id,const void * data,size_t buf_len,char buf[])64 column2_func(int id, const void *data, size_t buf_len, char buf[])
65 {
66 snprintf(buf, buf_len + 1, "%s", "яюэъыьщшчцхфутсрпонмлкйизжёедгв推");
67 }
68
69 static void
perform_test(column_info_t column_infos[],size_t count,size_t max_width)70 perform_test(column_info_t column_infos[], size_t count, size_t max_width)
71 {
72 size_t i;
73
74 columns_t *const cols = columns_create();
75 for(i = 0U; i < count; ++i)
76 {
77 columns_add_column(cols, column_infos[i]);
78 }
79
80 memset(print_buffer, '\0', sizeof(print_buffer));
81 columns_format_line(cols, NULL, max_width);
82
83 columns_free(cols);
84 }
85
TEST(not_truncating_short_utf8_ok,IF (locale_works))86 TEST(not_truncating_short_utf8_ok, IF(locale_works))
87 {
88 static column_info_t column_infos[1] = {
89 { .column_id = COL1_ID, .full_width = 33UL, .text_width = 33UL,
90 .align = AT_LEFT, .sizing = ST_ABSOLUTE, .cropping = CT_TRUNCATE, },
91 };
92 static const char expected[] = "师从螺丝刀йклмнопрстуфхцчшщьыъэюя ";
93
94 perform_test(column_infos, 1, 40);
95
96 assert_string_equal(expected, print_buffer);
97 }
98
TEST(donot_add_ellipsis_short_utf8_ok,IF (locale_works))99 TEST(donot_add_ellipsis_short_utf8_ok, IF(locale_works))
100 {
101 static column_info_t column_infos[1] = {
102 { .column_id = COL1_ID, .full_width = 33UL, .text_width = 33UL,
103 .align = AT_LEFT, .sizing = ST_ABSOLUTE, .cropping = CT_ELLIPSIS, },
104 };
105 static const char expected[] = "师从螺丝刀йклмнопрстуфхцчшщьыъэюя ";
106
107 perform_test(column_infos, 1, 40);
108
109 assert_string_equal(expected, print_buffer);
110 }
111
TEST(truncating_ok,IF (locale_works))112 TEST(truncating_ok, IF(locale_works))
113 {
114 static column_info_t column_infos[2] = {
115 { .column_id = COL1_ID, .full_width = 10UL, .text_width = 10UL,
116 .align = AT_LEFT, .sizing = ST_ABSOLUTE, .cropping = CT_TRUNCATE, },
117 { .column_id = COL2_ID, .full_width = 10UL, .text_width = 10UL,
118 .align = AT_RIGHT, .sizing = ST_ABSOLUTE, .cropping = CT_TRUNCATE, },
119 };
120 static const char expected[] = "师从螺丝刀изжёедгв推";
121
122 perform_test(column_infos, 2, MAX_WIDTH);
123
124 assert_string_equal(expected, print_buffer);
125 }
126
TEST(none_cropping_allows_for_correct_gaps,IF (locale_works))127 TEST(none_cropping_allows_for_correct_gaps, IF(locale_works))
128 {
129 static column_info_t column_infos[2] = {
130 { .column_id = COL1_ID, .full_width = 10UL, .text_width = 10UL,
131 .align = AT_LEFT, .sizing = ST_AUTO, .cropping = CT_NONE, },
132 { .column_id = COL2_ID, .full_width = 4UL, .text_width = 4UL,
133 .align = AT_RIGHT, .sizing = ST_AUTO, .cropping = CT_NONE, },
134 };
135 static const char expected[] = "师从 яюэъыьщшчцхфутсрпонмлкйизжёедгв推";
136
137 perform_test(column_infos, 2, 38);
138
139 assert_string_equal(expected, print_buffer);
140 }
141
TEST(add_ellipsis_ok,IF (locale_works))142 TEST(add_ellipsis_ok, IF(locale_works))
143 {
144 static column_info_t column_infos[2] = {
145 { .column_id = COL1_ID, .full_width = 10UL, .text_width = 10UL,
146 .align = AT_LEFT, .sizing = ST_ABSOLUTE, .cropping = CT_ELLIPSIS, },
147 { .column_id = COL2_ID, .full_width = 10UL, .text_width = 10UL,
148 .align = AT_RIGHT, .sizing = ST_ABSOLUTE, .cropping = CT_ELLIPSIS, },
149 };
150 static const char expected[] = "师从螺... ...ёедгв推";
151
152 perform_test(column_infos, 2, MAX_WIDTH);
153
154 assert_string_equal(expected, print_buffer);
155 }
156
TEST(wide_ellipsis_work,IF (locale_works))157 TEST(wide_ellipsis_work, IF(locale_works))
158 {
159 static column_info_t column_infos[2] = {
160 { .column_id = COL1_ID, .full_width = 10UL, .text_width = 10UL,
161 .align = AT_LEFT, .sizing = ST_ABSOLUTE, .cropping = CT_ELLIPSIS, },
162 { .column_id = COL2_ID, .full_width = 10UL, .text_width = 10UL,
163 .align = AT_RIGHT, .sizing = ST_ABSOLUTE, .cropping = CT_ELLIPSIS, },
164 };
165 static const char expected[] = "师从螺丝… …зжёедгв推";
166
167 columns_set_ellipsis("…");
168 perform_test(column_infos, 2, MAX_WIDTH);
169
170 assert_string_equal(expected, print_buffer);
171 }
172
TEST(filling,IF (locale_works))173 TEST(filling, IF(locale_works))
174 {
175 static column_info_t column_infos[1] = {
176 { .column_id = COL1_ID, .full_width = 0UL, .text_width = 0UL,
177 .align = AT_LEFT, .sizing = ST_AUTO, .cropping = CT_NONE, },
178 };
179 static const char expected[] = "师从螺丝刀йклмнопрстуфхцчшщьыъэюя ";
180
181 columns_t *const cols = columns_create();
182 columns_add_column(cols, column_infos[0]);
183
184 memset(print_buffer, '\0', 80);
185 columns_format_line(cols, NULL, 40);
186
187 columns_free(cols);
188
189 assert_string_equal(expected, print_buffer);
190 }
191
TEST(right_filling,IF (locale_works))192 TEST(right_filling, IF(locale_works))
193 {
194 static column_info_t column_infos[1] = {
195 { .column_id = COL2_ID, .full_width = 0UL, .text_width = 0UL,
196 .align = AT_RIGHT, .sizing = ST_AUTO, .cropping = CT_ELLIPSIS, },
197 };
198 static const char expected[] = ".";
199
200 columns_t *const cols = columns_create();
201 columns_add_column(cols, column_infos[0]);
202
203 memset(print_buffer, '\0', 80);
204 columns_format_line(cols, NULL, 1);
205
206 columns_free(cols);
207
208 assert_string_equal(expected, print_buffer);
209 }
210
TEST(wide_right_ellipsis_ok,IF (locale_works))211 TEST(wide_right_ellipsis_ok, IF(locale_works))
212 {
213 /* A gap might appear after removing several characters to insert ellipsis in
214 * their place, make sure that it's filled with spaces to obtain requested
215 * width. */
216
217 static column_info_t column_infos[1] = {
218 { .column_id = COL1_ID, .full_width = 0UL, .text_width = 0UL,
219 .align = AT_RIGHT, .sizing = ST_AUTO, .cropping = CT_ELLIPSIS, },
220 };
221 static const char expected[] = " ...螺丝刀师从螺丝刀";
222
223 col1_str = ",师从螺丝刀师从螺丝刀";
224 perform_test(column_infos, ARRAY_LEN(column_infos), MAX_WIDTH);
225
226 assert_string_equal(expected, print_buffer);
227 }
228
229 static int
locale_works(void)230 locale_works(void)
231 {
232 return (vifm_wcwidth(L'丝') == 2);
233 }
234
235 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
236 /* vim: set cinoptions+=t0 filetype=c : */
237