1 | /* Test for struct grouping_iterator. |
2 | Copyright (C) 2022-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | /* Rebuild the fail to access internal-only functions. */ |
20 | #include <grouping_iterator.c> |
21 | |
22 | #include <stdio.h> |
23 | #include <support/check.h> |
24 | #include <support/support.h> |
25 | #include <support/test-driver.h> |
26 | |
27 | static void |
28 | check (int lineno, const char *groupings, |
29 | const char *input, const char *expected) |
30 | { |
31 | if (test_verbose) |
32 | { |
33 | printf (format: "info: %s:%d: \"%s\" via \"" , __FILE__, lineno, input); |
34 | for (const char *p = groupings; *p != 0; ++p) |
35 | printf (format: "\\%o" , *p & 0xff); |
36 | printf (format: "\" to \"%s\"\n" , expected); |
37 | } |
38 | |
39 | size_t initial_group = strchrnul (s: expected, c: '\'') - expected; |
40 | size_t separators = 0; |
41 | for (const char *p = expected; *p != '\0'; ++p) |
42 | separators += *p == '\''; |
43 | |
44 | size_t digits = strlen (input); |
45 | char *out = xmalloc (n: 2 * digits + 1); |
46 | |
47 | struct grouping_iterator it; |
48 | TEST_COMPARE (grouping_iterator_setup (&it, digits, groupings), |
49 | strchr (expected, '\'') != NULL); |
50 | TEST_COMPARE (it.remaining, digits); |
51 | TEST_COMPARE (it.remaining_in_current_group, initial_group); |
52 | TEST_COMPARE (it.separators, separators); |
53 | |
54 | char *p = out; |
55 | while (*input != '\0') |
56 | { |
57 | if (__grouping_iterator_next (it: &it)) |
58 | *p++ = '\''; |
59 | TEST_COMPARE (it.separators, separators); |
60 | *p++ = *input++; |
61 | } |
62 | *p++ = '\0'; |
63 | |
64 | TEST_COMPARE (it.remaining, 0); |
65 | TEST_COMPARE (it.remaining_in_current_group, 0); |
66 | |
67 | TEST_COMPARE_STRING (out, expected); |
68 | |
69 | free (ptr: out); |
70 | } |
71 | |
72 | static int |
73 | do_test (void) |
74 | { |
75 | check (__LINE__, groupings: "" , input: "1" , expected: "1" ); |
76 | check (__LINE__, groupings: "" , input: "12" , expected: "12" ); |
77 | check (__LINE__, groupings: "" , input: "123" , expected: "123" ); |
78 | check (__LINE__, groupings: "" , input: "1234" , expected: "1234" ); |
79 | |
80 | check (__LINE__, groupings: "\3" , input: "1" , expected: "1" ); |
81 | check (__LINE__, groupings: "\3" , input: "12" , expected: "12" ); |
82 | check (__LINE__, groupings: "\3" , input: "123" , expected: "123" ); |
83 | check (__LINE__, groupings: "\3" , input: "1234" , expected: "1'234" ); |
84 | check (__LINE__, groupings: "\3" , input: "12345" , expected: "12'345" ); |
85 | check (__LINE__, groupings: "\3" , input: "123456" , expected: "123'456" ); |
86 | check (__LINE__, groupings: "\3" , input: "1234567" , expected: "1'234'567" ); |
87 | check (__LINE__, groupings: "\3" , input: "12345678" , expected: "12'345'678" ); |
88 | check (__LINE__, groupings: "\3" , input: "123456789" , expected: "123'456'789" ); |
89 | check (__LINE__, groupings: "\3" , input: "1234567890" , expected: "1'234'567'890" ); |
90 | |
91 | check (__LINE__, groupings: "\2\3" , input: "1" , expected: "1" ); |
92 | check (__LINE__, groupings: "\2\3" , input: "12" , expected: "12" ); |
93 | check (__LINE__, groupings: "\2\3" , input: "123" , expected: "1'23" ); |
94 | check (__LINE__, groupings: "\2\3" , input: "1234" , expected: "12'34" ); |
95 | check (__LINE__, groupings: "\2\3" , input: "12345" , expected: "123'45" ); |
96 | check (__LINE__, groupings: "\2\3" , input: "123456" , expected: "1'234'56" ); |
97 | check (__LINE__, groupings: "\2\3" , input: "1234567" , expected: "12'345'67" ); |
98 | check (__LINE__, groupings: "\2\3" , input: "12345678" , expected: "123'456'78" ); |
99 | check (__LINE__, groupings: "\2\3" , input: "123456789" , expected: "1'234'567'89" ); |
100 | check (__LINE__, groupings: "\2\3" , input: "1234567890" , expected: "12'345'678'90" ); |
101 | |
102 | check (__LINE__, groupings: "\3\2" , input: "1" , expected: "1" ); |
103 | check (__LINE__, groupings: "\3\2" , input: "12" , expected: "12" ); |
104 | check (__LINE__, groupings: "\3\2" , input: "123" , expected: "123" ); |
105 | check (__LINE__, groupings: "\3\2" , input: "1234" , expected: "1'234" ); |
106 | check (__LINE__, groupings: "\3\2" , input: "12345" , expected: "12'345" ); |
107 | check (__LINE__, groupings: "\3\2" , input: "123456" , expected: "1'23'456" ); |
108 | check (__LINE__, groupings: "\3\2" , input: "1234567" , expected: "12'34'567" ); |
109 | check (__LINE__, groupings: "\3\2" , input: "12345678" , expected: "1'23'45'678" ); |
110 | check (__LINE__, groupings: "\3\2" , input: "123456789" , expected: "12'34'56'789" ); |
111 | check (__LINE__, groupings: "\3\2" , input: "1234567890" , expected: "1'23'45'67'890" ); |
112 | |
113 | check (__LINE__, groupings: "\3\2\1" , input: "1" , expected: "1" ); |
114 | check (__LINE__, groupings: "\3\2\1" , input: "12" , expected: "12" ); |
115 | check (__LINE__, groupings: "\3\2\1" , input: "123" , expected: "123" ); |
116 | check (__LINE__, groupings: "\3\2\1" , input: "1234" , expected: "1'234" ); |
117 | check (__LINE__, groupings: "\3\2\1" , input: "12345" , expected: "12'345" ); |
118 | check (__LINE__, groupings: "\3\2\1" , input: "123456" , expected: "1'23'456" ); |
119 | check (__LINE__, groupings: "\3\2\1" , input: "1234567" , expected: "1'2'34'567" ); |
120 | check (__LINE__, groupings: "\3\2\1" , input: "12345678" , expected: "1'2'3'45'678" ); |
121 | check (__LINE__, groupings: "\3\2\1" , input: "123456789" , expected: "1'2'3'4'56'789" ); |
122 | check (__LINE__, groupings: "\3\2\1" , input: "1234567890" , expected: "1'2'3'4'5'67'890" ); |
123 | |
124 | check (__LINE__, groupings: "\2\3\1" , input: "1" , expected: "1" ); |
125 | check (__LINE__, groupings: "\2\3\1" , input: "12" , expected: "12" ); |
126 | check (__LINE__, groupings: "\2\3\1" , input: "123" , expected: "1'23" ); |
127 | check (__LINE__, groupings: "\2\3\1" , input: "1234" , expected: "12'34" ); |
128 | check (__LINE__, groupings: "\2\3\1" , input: "12345" , expected: "123'45" ); |
129 | check (__LINE__, groupings: "\2\3\1" , input: "123456" , expected: "1'234'56" ); |
130 | check (__LINE__, groupings: "\2\3\1" , input: "1234567" , expected: "1'2'345'67" ); |
131 | check (__LINE__, groupings: "\2\3\1" , input: "12345678" , expected: "1'2'3'456'78" ); |
132 | check (__LINE__, groupings: "\2\3\1" , input: "123456789" , expected: "1'2'3'4'567'89" ); |
133 | check (__LINE__, groupings: "\2\3\1" , input: "1234567890" , expected: "1'2'3'4'5'678'90" ); |
134 | |
135 | /* No repeats. */ |
136 | check (__LINE__, groupings: "\3\377" , input: "1" , expected: "1" ); |
137 | check (__LINE__, groupings: "\3\377" , input: "12" , expected: "12" ); |
138 | check (__LINE__, groupings: "\3\377" , input: "123" , expected: "123" ); |
139 | check (__LINE__, groupings: "\3\377" , input: "1234" , expected: "1'234" ); |
140 | check (__LINE__, groupings: "\3\377" , input: "12345" , expected: "12'345" ); |
141 | check (__LINE__, groupings: "\3\377" , input: "123456" , expected: "123'456" ); |
142 | check (__LINE__, groupings: "\3\377" , input: "1234567" , expected: "1234'567" ); |
143 | check (__LINE__, groupings: "\3\377" , input: "12345678" , expected: "12345'678" ); |
144 | |
145 | check (__LINE__, groupings: "\2\3\377" , input: "1" , expected: "1" ); |
146 | check (__LINE__, groupings: "\2\3\377" , input: "12" , expected: "12" ); |
147 | check (__LINE__, groupings: "\2\3\377" , input: "123" , expected: "1'23" ); |
148 | check (__LINE__, groupings: "\2\3\377" , input: "1234" , expected: "12'34" ); |
149 | check (__LINE__, groupings: "\2\3\377" , input: "12345" , expected: "123'45" ); |
150 | check (__LINE__, groupings: "\2\3\377" , input: "123456" , expected: "1'234'56" ); |
151 | check (__LINE__, groupings: "\2\3\377" , input: "1234567" , expected: "12'345'67" ); |
152 | check (__LINE__, groupings: "\2\3\377" , input: "12345678" , expected: "123'456'78" ); |
153 | check (__LINE__, groupings: "\2\3\377" , input: "123456789" , expected: "1234'567'89" ); |
154 | check (__LINE__, groupings: "\2\3\377" , input: "1234567890" , expected: "12345'678'90" ); |
155 | |
156 | check (__LINE__, groupings: "\3\2\377" , input: "1" , expected: "1" ); |
157 | check (__LINE__, groupings: "\3\2\377" , input: "12" , expected: "12" ); |
158 | check (__LINE__, groupings: "\3\2\377" , input: "123" , expected: "123" ); |
159 | check (__LINE__, groupings: "\3\2\377" , input: "1234" , expected: "1'234" ); |
160 | check (__LINE__, groupings: "\3\2\377" , input: "12345" , expected: "12'345" ); |
161 | check (__LINE__, groupings: "\3\2\377" , input: "123456" , expected: "1'23'456" ); |
162 | check (__LINE__, groupings: "\3\2\377" , input: "1234567" , expected: "12'34'567" ); |
163 | check (__LINE__, groupings: "\3\2\377" , input: "12345678" , expected: "123'45'678" ); |
164 | check (__LINE__, groupings: "\3\2\377" , input: "123456789" , expected: "1234'56'789" ); |
165 | check (__LINE__, groupings: "\3\2\377" , input: "1234567890" , expected: "12345'67'890" ); |
166 | |
167 | /* Locale-based tests. */ |
168 | |
169 | locale_t loc; |
170 | struct lc_ctype_data *ctype; |
171 | struct grouping_iterator it; |
172 | |
173 | loc = newlocale (LC_ALL_MASK, locale: "de_DE.UTF-8" , base: 0); |
174 | TEST_VERIFY_EXIT (loc != 0); |
175 | ctype = loc->__locales[LC_CTYPE]->private; |
176 | TEST_VERIFY (!ctype->outdigit_translation_needed); |
177 | for (int i = 0; i <= 9; ++i) |
178 | TEST_COMPARE (ctype->outdigit_bytes[i], 1); |
179 | TEST_COMPARE (ctype->outdigit_bytes_all_equal, 1); |
180 | TEST_COMPARE (__grouping_iterator_init (&it, LC_NUMERIC, loc, 8), true); |
181 | TEST_COMPARE (it.remaining_in_current_group, 2); |
182 | TEST_COMPARE (it.remaining, 8); |
183 | TEST_COMPARE (*it.groupings, 3); |
184 | TEST_COMPARE (it.non_repeating_groups, 0); |
185 | TEST_COMPARE (it.separators, 2); |
186 | TEST_COMPARE (__grouping_iterator_init (&it, LC_MONETARY, loc, 8), true); |
187 | TEST_COMPARE (it.remaining_in_current_group, 2); |
188 | TEST_COMPARE (it.remaining, 8); |
189 | TEST_COMPARE (*it.groupings, 3); |
190 | TEST_COMPARE (it.non_repeating_groups, 0); |
191 | TEST_COMPARE (it.separators, 2); |
192 | freelocale (dataset: loc); |
193 | |
194 | loc = newlocale (LC_ALL_MASK, locale: "tg_TJ.UTF-8" , base: 0); |
195 | TEST_VERIFY_EXIT (loc != 0); |
196 | ctype = loc->__locales[LC_CTYPE]->private; |
197 | TEST_VERIFY (!ctype->outdigit_translation_needed); |
198 | for (int i = 0; i <= 9; ++i) |
199 | TEST_COMPARE (ctype->outdigit_bytes[i], 1); |
200 | TEST_COMPARE (ctype->outdigit_bytes_all_equal, 1); |
201 | TEST_COMPARE (__grouping_iterator_init (&it, LC_NUMERIC, loc, 8), true); |
202 | TEST_COMPARE (it.remaining_in_current_group, 2); |
203 | TEST_COMPARE (it.remaining, 8); |
204 | TEST_COMPARE (*it.groupings, 3); |
205 | TEST_COMPARE (it.non_repeating_groups, 0); |
206 | TEST_COMPARE (it.separators, 2); |
207 | TEST_COMPARE (__grouping_iterator_init (&it, LC_MONETARY, loc, 8), true); |
208 | TEST_COMPARE (it.remaining_in_current_group, 2); |
209 | TEST_COMPARE (it.remaining, 8); |
210 | TEST_COMPARE (*it.groupings, 3); |
211 | TEST_COMPARE (it.non_repeating_groups, 0); |
212 | TEST_COMPARE (it.separators, 2); |
213 | freelocale (dataset: loc); |
214 | |
215 | loc = newlocale (LC_ALL_MASK, locale: "hi_IN.UTF-8" , base: 0); |
216 | TEST_VERIFY_EXIT (loc != 0); |
217 | ctype = loc->__locales[LC_CTYPE]->private; |
218 | TEST_VERIFY (ctype->outdigit_translation_needed); |
219 | for (int i = 0; i <= 9; ++i) |
220 | /* Locale uses Devanagari digits. */ |
221 | TEST_COMPARE (ctype->outdigit_bytes[i], 3); |
222 | TEST_COMPARE (ctype->outdigit_bytes_all_equal, 3); |
223 | TEST_COMPARE (__grouping_iterator_init (&it, LC_NUMERIC, loc, 8), true); |
224 | TEST_COMPARE (it.remaining_in_current_group, 2); |
225 | TEST_COMPARE (it.remaining, 8); |
226 | TEST_COMPARE (*it.groupings, 3); |
227 | TEST_COMPARE (it.non_repeating_groups, 0); |
228 | TEST_COMPARE (it.separators, 2); |
229 | TEST_COMPARE (__grouping_iterator_init (&it, LC_MONETARY, loc, 8), true); |
230 | TEST_COMPARE (it.remaining_in_current_group, 1); |
231 | TEST_COMPARE (it.remaining, 8); |
232 | TEST_COMPARE (*it.groupings, 2); |
233 | TEST_COMPARE (it.non_repeating_groups, 3); |
234 | TEST_COMPARE (it.separators, 3); |
235 | freelocale (dataset: loc); |
236 | |
237 | loc = newlocale (LC_ALL_MASK, locale: "ps_AF.UTF-8" , base: 0); |
238 | TEST_VERIFY_EXIT (loc != 0); |
239 | ctype = loc->__locales[LC_CTYPE]->private; |
240 | TEST_VERIFY (ctype->outdigit_translation_needed); |
241 | for (int i = 0; i <= 9; ++i) |
242 | /* Locale uses non-ASCII digits. */ |
243 | TEST_COMPARE (ctype->outdigit_bytes[i], 2); |
244 | TEST_COMPARE (ctype->outdigit_bytes_all_equal, 2); |
245 | TEST_COMPARE (__grouping_iterator_init (&it, LC_NUMERIC, loc, 8), true); |
246 | TEST_COMPARE (it.remaining_in_current_group, 2); |
247 | TEST_COMPARE (it.remaining, 8); |
248 | TEST_COMPARE (*it.groupings, 3); |
249 | TEST_COMPARE (it.non_repeating_groups, 0); |
250 | TEST_COMPARE (it.separators, 2); |
251 | TEST_COMPARE (__grouping_iterator_init (&it, LC_MONETARY, loc, 8), true); |
252 | TEST_COMPARE (it.remaining_in_current_group, 2); |
253 | TEST_COMPARE (it.remaining, 8); |
254 | TEST_COMPARE (*it.groupings, 3); |
255 | TEST_COMPARE (it.non_repeating_groups, 0); |
256 | TEST_COMPARE (it.separators, 2); |
257 | freelocale (dataset: loc); |
258 | |
259 | loc = newlocale (LC_ALL_MASK, locale: "bn_BD.UTF-8" , base: 0); |
260 | TEST_VERIFY_EXIT (loc != 0); |
261 | ctype = loc->__locales[LC_CTYPE]->private; |
262 | TEST_VERIFY (ctype->outdigit_translation_needed); |
263 | for (int i = 0; i <= 9; ++i) |
264 | /* Locale uses Bengali digits. */ |
265 | TEST_COMPARE (ctype->outdigit_bytes[i], 3); |
266 | TEST_COMPARE (ctype->outdigit_bytes_all_equal, 3); |
267 | TEST_COMPARE (__grouping_iterator_init (&it, LC_NUMERIC, loc, 8), true); |
268 | TEST_COMPARE (it.remaining_in_current_group, 1); |
269 | TEST_COMPARE (it.remaining, 8); |
270 | TEST_COMPARE (*it.groupings, 2); |
271 | TEST_COMPARE (it.non_repeating_groups, 3); |
272 | TEST_COMPARE (it.separators, 3); |
273 | TEST_COMPARE (__grouping_iterator_init (&it, LC_MONETARY, loc, 8), true); |
274 | TEST_COMPARE (it.remaining_in_current_group, 1); |
275 | TEST_COMPARE (it.remaining, 8); |
276 | TEST_COMPARE (*it.groupings, 2); |
277 | TEST_COMPARE (it.non_repeating_groups, 3); |
278 | TEST_COMPARE (it.separators, 3); |
279 | freelocale (dataset: loc); |
280 | |
281 | loc = newlocale (LC_ALL_MASK, locale: "unm_US.UTF-8" , base: 0); |
282 | TEST_VERIFY_EXIT (loc != 0); |
283 | ctype = loc->__locales[LC_CTYPE]->private; |
284 | TEST_VERIFY (!ctype->outdigit_translation_needed); |
285 | for (int i = 0; i <= 9; ++i) |
286 | TEST_COMPARE (ctype->outdigit_bytes[i], 1); |
287 | TEST_COMPARE (ctype->outdigit_bytes_all_equal, 1); |
288 | TEST_COMPARE (__grouping_iterator_init (&it, LC_NUMERIC, loc, 8), true); |
289 | TEST_COMPARE (it.remaining_in_current_group, 2); |
290 | TEST_COMPARE (it.remaining, 8); |
291 | TEST_COMPARE (*it.groupings, 3); |
292 | TEST_COMPARE (it.non_repeating_groups, 9); |
293 | TEST_COMPARE (it.separators, 3); |
294 | TEST_COMPARE (__grouping_iterator_init (&it, LC_MONETARY, loc, 8), true); |
295 | TEST_COMPARE (it.remaining_in_current_group, 2); |
296 | TEST_COMPARE (it.remaining, 8); |
297 | TEST_COMPARE (*it.groupings, 3); |
298 | TEST_COMPARE (it.non_repeating_groups, 0); |
299 | TEST_COMPARE (it.separators, 2); |
300 | freelocale (dataset: loc); |
301 | |
302 | loc = newlocale (LC_ALL_MASK, locale: "rw_RW.UTF-8" , base: 0); |
303 | TEST_VERIFY_EXIT (loc != 0); |
304 | ctype = loc->__locales[LC_CTYPE]->private; |
305 | TEST_VERIFY (!ctype->outdigit_translation_needed); |
306 | for (int i = 0; i <= 9; ++i) |
307 | TEST_COMPARE (ctype->outdigit_bytes[i], 1); |
308 | TEST_COMPARE (ctype->outdigit_bytes_all_equal, 1); |
309 | /* rw_RW has grouping -1 in LC_NUMERIC */ |
310 | TEST_COMPARE (__grouping_iterator_init (&it, LC_NUMERIC, loc, 8), false); |
311 | TEST_COMPARE (it.remaining_in_current_group, 8); |
312 | TEST_COMPARE (it.remaining, 8); |
313 | TEST_COMPARE (__grouping_iterator_init (&it, LC_MONETARY, loc, 8), true); |
314 | TEST_COMPARE (it.remaining_in_current_group, 2); |
315 | TEST_COMPARE (it.remaining, 8); |
316 | TEST_COMPARE (*it.groupings, 3); |
317 | TEST_COMPARE (it.non_repeating_groups, 0); |
318 | TEST_COMPARE (it.separators, 2); |
319 | freelocale (dataset: loc); |
320 | |
321 | return 0; |
322 | } |
323 | |
324 | #include <support/test-driver.c> |
325 | |