1 | /* Test for wchar_t/multi-byte conversion and precision in vfprintf. |
2 | Copyright (C) 2017-2022 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 | #include <locale.h> |
20 | #include <stdbool.h> |
21 | #include <stdint.h> |
22 | #include <stdio.h> |
23 | #include <string.h> |
24 | #include <support/check.h> |
25 | #include <support/test-driver.h> |
26 | #include <wchar.h> |
27 | |
28 | #define DYNARRAY_STRUCT str |
29 | #define DYNARRAY_ELEMENT char |
30 | #define DYNARRAY_PREFIX str_ |
31 | #include <malloc/dynarray-skeleton.c> |
32 | |
33 | #define DYNARRAY_STRUCT wstr |
34 | #define DYNARRAY_ELEMENT wchar_t |
35 | #define DYNARRAY_PREFIX wstr_ |
36 | #include <malloc/dynarray-skeleton.c> |
37 | |
38 | #define DYNARRAY_STRUCT len |
39 | #define DYNARRAY_ELEMENT size_t |
40 | #define DYNARRAY_PREFIX len_ |
41 | #include <malloc/dynarray-skeleton.c> |
42 | |
43 | /* This should be larger than the internal buffer in vfprintf. The |
44 | constant needs to be kept in sync with the format strings in |
45 | test_mbs_long and test_wide_long. */ |
46 | enum { WIDE_STRING_LENGTH = 1000 }; |
47 | |
48 | /* Creates two large, random strings used for truncation testing. |
49 | After the call, *MBS will be encoded in UTF-8, and *WIDE will |
50 | contain the same string in the internal UCS-32 encoding. Both |
51 | strings are null-terminated. The array *LENGTH counts the number |
52 | of multi-byte characters for each prefix string of *WIDE: The first |
53 | N wide characters of *WIDE correspond the first (*LENGTH)[N] bytes |
54 | of *MBS. The caller should deallocate all three arrays using |
55 | free. */ |
56 | static void |
57 | make_random_string (char **mbs, wchar_t **wide, size_t **length) |
58 | { |
59 | struct str str; |
60 | str_init (list: &str); |
61 | struct wstr wstr; |
62 | wstr_init (list: &wstr); |
63 | struct len len; |
64 | len_init (list: &len); |
65 | |
66 | for (int i = 0; i < WIDE_STRING_LENGTH; ++i) |
67 | { |
68 | len_add (list: &len, item: str_size (list: &str)); |
69 | /* Cover some multi-byte UTF-8 sequences. Avoid the null |
70 | character. */ |
71 | uint32_t ch = 1 + (rand () % 521); |
72 | wstr_add (list: &wstr, item: ch); |
73 | |
74 | /* Limited UTF-8 conversion. */ |
75 | if (ch <= 127) |
76 | str_add (list: &str, item: ch); |
77 | else |
78 | { |
79 | /* We only implement two-byte sequences. */ |
80 | uint32_t first = ch >> 6; |
81 | TEST_VERIFY (first < 32); |
82 | str_add (list: &str, item: 0xC0 | first); |
83 | str_add (list: &str, item: 0x80 | (ch & 0x3f)); |
84 | } |
85 | } |
86 | len_add (list: &len, item: str_size (list: &str)); |
87 | wstr_add (list: &wstr, item: L'\0'); |
88 | str_add (list: &str, item: '\0'); |
89 | |
90 | *mbs = str_finalize (list: &str, NULL); |
91 | TEST_VERIFY_EXIT (*mbs != NULL); |
92 | *wide = wstr_finalize (list: &wstr, NULL); |
93 | TEST_VERIFY_EXIT (*wide != NULL); |
94 | *length = len_finalize (list: &len, NULL); |
95 | TEST_VERIFY_EXIT (*length != NULL); |
96 | } |
97 | |
98 | /* snprintf tests (multi-byte result). */ |
99 | static void |
100 | test_mbs_result (void) |
101 | { |
102 | char buf[200]; |
103 | |
104 | /* ASCII wide string. */ |
105 | memset (buf, '@', sizeof (buf)); |
106 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%ls" , L"xyz" ) == 3); |
107 | TEST_VERIFY (strcmp (buf, "xyz" ) == 0); |
108 | |
109 | /* Unicode wide string. */ |
110 | memset (buf, '@', sizeof (buf)); |
111 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%ls" , L"x\u00DFz" ) == 4); |
112 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
113 | |
114 | /* Varying precisions. */ |
115 | memset (buf, '@', sizeof (buf)); |
116 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%.1ls" , L"x\u00DFz" ) == 1); |
117 | TEST_VERIFY (strcmp (buf, "x" ) == 0); |
118 | memset (buf, '@', sizeof (buf)); |
119 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%.2ls" , L"x\u00DFz" ) == 1); |
120 | TEST_VERIFY (strcmp (buf, "x" ) == 0); |
121 | memset (buf, '@', sizeof (buf)); |
122 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%.3ls" , L"x\u00DFz" ) == 3); |
123 | TEST_VERIFY (strcmp (buf, "x\xC3\x9F" ) == 0); |
124 | memset (buf, '@', sizeof (buf)); |
125 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%.4ls" , L"x\u00DFz" ) == 4); |
126 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
127 | memset (buf, '@', sizeof (buf)); |
128 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%.5ls" , L"x\u00DFz" ) == 4); |
129 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
130 | |
131 | /* Varying precisions with width 2, right-justified. */ |
132 | memset (buf, '@', sizeof (buf)); |
133 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.1ls" , L"x\u00DFz" ) == 2); |
134 | TEST_VERIFY (strcmp (buf, " x" ) == 0); |
135 | memset (buf, '@', sizeof (buf)); |
136 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.2ls" , L"x\u00DFz" ) == 2); |
137 | TEST_VERIFY (strcmp (buf, " x" ) == 0); |
138 | memset (buf, '@', sizeof (buf)); |
139 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.3ls" , L"x\u00DFz" ) == 3); |
140 | TEST_VERIFY (strcmp (buf, "x\xC3\x9F" ) == 0); |
141 | memset (buf, '@', sizeof (buf)); |
142 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.4ls" , L"x\u00DFz" ) == 4); |
143 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
144 | memset (buf, '@', sizeof (buf)); |
145 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.5ls" , L"x\u00DFz" ) == 4); |
146 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
147 | |
148 | /* Varying precisions with width 2, left-justified. */ |
149 | memset (buf, '@', sizeof (buf)); |
150 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.1ls" , L"x\u00DFz" ) == 2); |
151 | TEST_VERIFY (strcmp (buf, "x " ) == 0); |
152 | memset (buf, '@', sizeof (buf)); |
153 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.2ls" , L"x\u00DFz" ) == 2); |
154 | TEST_VERIFY (strcmp (buf, "x " ) == 0); |
155 | memset (buf, '@', sizeof (buf)); |
156 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.3ls" , L"x\u00DFz" ) == 3); |
157 | TEST_VERIFY (strcmp (buf, "x\xC3\x9F" ) == 0); |
158 | memset (buf, '@', sizeof (buf)); |
159 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.4ls" , L"x\u00DFz" ) == 4); |
160 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
161 | memset (buf, '@', sizeof (buf)); |
162 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.5ls" , L"x\u00DFz" ) == 4); |
163 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
164 | |
165 | /* Varying precisions with width 3, right-justified. */ |
166 | memset (buf, '@', sizeof (buf)); |
167 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.1ls" , L"x\u00DFz" ) == 3); |
168 | TEST_VERIFY (strcmp (buf, " x" ) == 0); |
169 | memset (buf, '@', sizeof (buf)); |
170 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.2ls" , L"x\u00DFz" ) == 3); |
171 | TEST_VERIFY (strcmp (buf, " x" ) == 0); |
172 | memset (buf, '@', sizeof (buf)); |
173 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.3ls" , L"x\u00DFz" ) == 3); |
174 | TEST_VERIFY (strcmp (buf, "x\xC3\x9F" ) == 0); |
175 | memset (buf, '@', sizeof (buf)); |
176 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.4ls" , L"x\u00DFz" ) == 4); |
177 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
178 | memset (buf, '@', sizeof (buf)); |
179 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.5ls" , L"x\u00DFz" ) == 4); |
180 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
181 | |
182 | /* Varying precisions with width 3, left-justified. */ |
183 | memset (buf, '@', sizeof (buf)); |
184 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.1ls" , L"x\u00DFz" ) == 3); |
185 | TEST_VERIFY (strcmp (buf, "x " ) == 0); |
186 | memset (buf, '@', sizeof (buf)); |
187 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.2ls" , L"x\u00DFz" ) == 3); |
188 | TEST_VERIFY (strcmp (buf, "x " ) == 0); |
189 | memset (buf, '@', sizeof (buf)); |
190 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.3ls" , L"x\u00DFz" ) == 3); |
191 | TEST_VERIFY (strcmp (buf, "x\xC3\x9F" ) == 0); |
192 | memset (buf, '@', sizeof (buf)); |
193 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.4ls" , L"x\u00DFz" ) == 4); |
194 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
195 | memset (buf, '@', sizeof (buf)); |
196 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.5ls" , L"x\u00DFz" ) == 4); |
197 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
198 | |
199 | /* Varying precisions with width 4, right-justified. */ |
200 | memset (buf, '@', sizeof (buf)); |
201 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.1ls" , L"x\u00DFz" ) == 4); |
202 | TEST_VERIFY (strcmp (buf, " x" ) == 0); |
203 | memset (buf, '@', sizeof (buf)); |
204 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.2ls" , L"x\u00DFz" ) == 4); |
205 | TEST_VERIFY (strcmp (buf, " x" ) == 0); |
206 | memset (buf, '@', sizeof (buf)); |
207 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.3ls" , L"x\u00DFz" ) == 4); |
208 | TEST_VERIFY (strcmp (buf, " x\xC3\x9F" ) == 0); |
209 | memset (buf, '@', sizeof (buf)); |
210 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.4ls" , L"x\u00DFz" ) == 4); |
211 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
212 | memset (buf, '@', sizeof (buf)); |
213 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.5ls" , L"x\u00DFz" ) == 4); |
214 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
215 | |
216 | /* Varying precisions with width 4, left-justified. */ |
217 | memset (buf, '@', sizeof (buf)); |
218 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.1ls" , L"x\u00DFz" ) == 4); |
219 | TEST_VERIFY (strcmp (buf, "x " ) == 0); |
220 | memset (buf, '@', sizeof (buf)); |
221 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.2ls" , L"x\u00DFz" ) == 4); |
222 | TEST_VERIFY (strcmp (buf, "x " ) == 0); |
223 | memset (buf, '@', sizeof (buf)); |
224 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.3ls" , L"x\u00DFz" ) == 4); |
225 | TEST_VERIFY (strcmp (buf, "x\xC3\x9F " ) == 0); |
226 | memset (buf, '@', sizeof (buf)); |
227 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.4ls" , L"x\u00DFz" ) == 4); |
228 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
229 | memset (buf, '@', sizeof (buf)); |
230 | TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.5ls" , L"x\u00DFz" ) == 4); |
231 | TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz" ) == 0); |
232 | } |
233 | |
234 | /* swprintf tests (wide string result). */ |
235 | static void |
236 | test_wide_result (void) |
237 | { |
238 | enum { size = 20 }; |
239 | wchar_t buf[20]; |
240 | |
241 | /* ASCII wide string. */ |
242 | wmemset (buf, '@', size); |
243 | TEST_VERIFY (swprintf (buf, size, L"%s" , "xyz" ) == 3); |
244 | TEST_VERIFY (wcscmp (buf, L"xyz" ) == 0); |
245 | |
246 | /* Unicode wide string. */ |
247 | wmemset (buf, '@', size); |
248 | TEST_VERIFY (swprintf (buf, size, L"%s" , "x\xC3\x9Fz" ) == 3); |
249 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz" ) == 0); |
250 | |
251 | /* Varying precisions. */ |
252 | wmemset (buf, '@', size); |
253 | TEST_VERIFY (swprintf (buf, size, L"%.1s" , "x\xC3\x9Fz" ) == 1); |
254 | TEST_VERIFY (wcscmp (buf, L"x" ) == 0); |
255 | wmemset (buf, '@', size); |
256 | TEST_VERIFY (swprintf (buf, size, L"%.2s" , "x\xC3\x9Fz" ) == 2); |
257 | TEST_VERIFY (wcscmp (buf, L"x\u00DF" ) == 0); |
258 | wmemset (buf, '@', size); |
259 | TEST_VERIFY (swprintf (buf, size, L"%.3s" , "x\xC3\x9Fz" ) == 3); |
260 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz" ) == 0); |
261 | wmemset (buf, '@', size); |
262 | TEST_VERIFY (swprintf (buf, size, L"%.4s" , "x\xC3\x9Fz" ) == 3); |
263 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz" ) == 0); |
264 | |
265 | /* Varying precisions with width 2, right-justified. */ |
266 | wmemset (buf, '@', size); |
267 | TEST_VERIFY (swprintf (buf, size, L"%2.1s" , "x\xC3\x9Fz" ) == 2); |
268 | TEST_VERIFY (wcscmp (buf, L" x" ) == 0); |
269 | wmemset (buf, '@', size); |
270 | TEST_VERIFY (swprintf (buf, size, L"%2.2s" , "x\xC3\x9Fz" ) == 2); |
271 | TEST_VERIFY (wcscmp (buf, L"x\u00DF" ) == 0); |
272 | wmemset (buf, '@', size); |
273 | TEST_VERIFY (swprintf (buf, size, L"%2.3s" , "x\xC3\x9Fz" ) == 3); |
274 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz" ) == 0); |
275 | wmemset (buf, '@', size); |
276 | TEST_VERIFY (swprintf (buf, size, L"%2.4s" , "x\xC3\x9Fz" ) == 3); |
277 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz" ) == 0); |
278 | |
279 | /* Varying precisions with width 2, left-justified. */ |
280 | wmemset (buf, '@', size); |
281 | TEST_VERIFY (swprintf (buf, size, L"%-2.1s" , "x\xC3\x9Fz" ) == 2); |
282 | TEST_VERIFY (wcscmp (buf, L"x " ) == 0); |
283 | wmemset (buf, '@', size); |
284 | TEST_VERIFY (swprintf (buf, size, L"%-2.2s" , "x\xC3\x9Fz" ) == 2); |
285 | TEST_VERIFY (wcscmp (buf, L"x\u00DF" ) == 0); |
286 | wmemset (buf, '@', size); |
287 | TEST_VERIFY (swprintf (buf, size, L"%-2.3s" , "x\xC3\x9Fz" ) == 3); |
288 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz" ) == 0); |
289 | wmemset (buf, '@', size); |
290 | TEST_VERIFY (swprintf (buf, size, L"%-2.4s" , "x\xC3\x9Fz" ) == 3); |
291 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz" ) == 0); |
292 | |
293 | /* Varying precisions with width 3, right-justified. */ |
294 | wmemset (buf, '@', size); |
295 | TEST_VERIFY (swprintf (buf, size, L"%3.1s" , "x\xC3\x9Fz" ) == 3); |
296 | TEST_VERIFY (wcscmp (buf, L" x" ) == 0); |
297 | wmemset (buf, '@', size); |
298 | TEST_VERIFY (swprintf (buf, size, L"%3.2s" , "x\xC3\x9Fz" ) == 3); |
299 | TEST_VERIFY (wcscmp (buf, L" x\u00DF" ) == 0); |
300 | wmemset (buf, '@', size); |
301 | TEST_VERIFY (swprintf (buf, size, L"%3.3s" , "x\xC3\x9Fz" ) == 3); |
302 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz" ) == 0); |
303 | wmemset (buf, '@', size); |
304 | TEST_VERIFY (swprintf (buf, size, L"%3.4s" , "x\xC3\x9Fz" ) == 3); |
305 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz" ) == 0); |
306 | |
307 | /* Varying precisions with width 3, left-justified. */ |
308 | wmemset (buf, '@', size); |
309 | TEST_VERIFY (swprintf (buf, size, L"%-3.1s" , "x\xC3\x9Fz" ) == 3); |
310 | TEST_VERIFY (wcscmp (buf, L"x " ) == 0); |
311 | wmemset (buf, '@', size); |
312 | TEST_VERIFY (swprintf (buf, size, L"%-3.2s" , "x\xC3\x9Fz" ) == 3); |
313 | TEST_VERIFY (wcscmp (buf, L"x\u00DF " ) == 0); |
314 | wmemset (buf, '@', size); |
315 | TEST_VERIFY (swprintf (buf, size, L"%-3.3s" , "x\xC3\x9Fz" ) == 3); |
316 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz" ) == 0); |
317 | wmemset (buf, '@', size); |
318 | TEST_VERIFY (swprintf (buf, size, L"%-3.4s" , "x\xC3\x9Fz" ) == 3); |
319 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz" ) == 0); |
320 | |
321 | /* Varying precisions with width 4, right-justified. */ |
322 | wmemset (buf, '@', size); |
323 | TEST_VERIFY (swprintf (buf, size, L"%4.1s" , "x\xC3\x9Fz" ) == 4); |
324 | TEST_VERIFY (wcscmp (buf, L" x" ) == 0); |
325 | wmemset (buf, '@', size); |
326 | TEST_VERIFY (swprintf (buf, size, L"%4.2s" , "x\xC3\x9Fz" ) == 4); |
327 | TEST_VERIFY (wcscmp (buf, L" x\u00DF" ) == 0); |
328 | wmemset (buf, '@', size); |
329 | TEST_VERIFY (swprintf (buf, size, L"%4.3s" , "x\xC3\x9Fz" ) == 4); |
330 | TEST_VERIFY (wcscmp (buf, L" x\u00DFz" ) == 0); |
331 | wmemset (buf, '@', size); |
332 | TEST_VERIFY (swprintf (buf, size, L"%4.4s" , "x\xC3\x9Fz" ) == 4); |
333 | TEST_VERIFY (wcscmp (buf, L" x\u00DFz" ) == 0); |
334 | wmemset (buf, '@', size); |
335 | TEST_VERIFY (swprintf (buf, size, L"%4.5s" , "x\xC3\x9Fz" ) == 4); |
336 | TEST_VERIFY (wcscmp (buf, L" x\u00DFz" ) == 0); |
337 | |
338 | /* Varying precisions with width 4, left-justified. */ |
339 | wmemset (buf, '@', size); |
340 | TEST_VERIFY (swprintf (buf, size, L"%-4.1s" , "x\xC3\x9Fz" ) == 4); |
341 | TEST_VERIFY (wcscmp (buf, L"x " ) == 0); |
342 | wmemset (buf, '@', size); |
343 | TEST_VERIFY (swprintf (buf, size, L"%-4.2s" , "x\xC3\x9Fz" ) == 4); |
344 | TEST_VERIFY (wcscmp (buf, L"x\u00DF " ) == 0); |
345 | wmemset (buf, '@', size); |
346 | TEST_VERIFY (swprintf (buf, size, L"%-4.3s" , "x\xC3\x9Fz" ) == 4); |
347 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz " ) == 0); |
348 | wmemset (buf, '@', size); |
349 | TEST_VERIFY (swprintf (buf, size, L"%-4.4s" , "x\xC3\x9Fz" ) == 4); |
350 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz " ) == 0); |
351 | wmemset (buf, '@', size); |
352 | TEST_VERIFY (swprintf (buf, size, L"%-4.5s" , "x\xC3\x9Fz" ) == 4); |
353 | TEST_VERIFY (wcscmp (buf, L"x\u00DFz " ) == 0); |
354 | } |
355 | |
356 | /* Test with long strings and multi-byte result. */ |
357 | static void |
358 | test_mbs_long (const char *mbs, const wchar_t *wide, const size_t *length) |
359 | { |
360 | char buf[4000]; |
361 | _Static_assert (sizeof (buf) > 3 * WIDE_STRING_LENGTH, |
362 | "buffer size consistent with string length" ); |
363 | const char *suffix = "||TERM" ; |
364 | TEST_VERIFY_EXIT (sizeof (buf) |
365 | > length[WIDE_STRING_LENGTH] + strlen (suffix)); |
366 | |
367 | /* Test formatting of the entire string. */ |
368 | { |
369 | int ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%ls%s" , wide, suffix); |
370 | TEST_VERIFY (ret == length[WIDE_STRING_LENGTH] + strlen (suffix)); |
371 | TEST_VERIFY (memcmp (buf, mbs, length[WIDE_STRING_LENGTH]) == 0); |
372 | TEST_VERIFY (strcmp (buf + length[WIDE_STRING_LENGTH], suffix) == 0); |
373 | |
374 | /* Left-justified string, printed in full. */ |
375 | ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%-3500ls%s" , wide, suffix); |
376 | TEST_VERIFY (ret == 3500 + strlen (suffix)); |
377 | TEST_VERIFY (memcmp (buf, mbs, length[WIDE_STRING_LENGTH]) == 0); |
378 | for (size_t i = length[WIDE_STRING_LENGTH]; i < 3500; ++i) |
379 | TEST_VERIFY (buf[i] == ' '); |
380 | TEST_VERIFY (strcmp (buf + 3500, suffix) == 0); |
381 | |
382 | /* Right-justified string, printed in full. */ |
383 | ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%3500ls%s" , wide, suffix); |
384 | TEST_VERIFY (ret == 3500 + strlen (suffix)); |
385 | size_t padding = 3500 - length[WIDE_STRING_LENGTH]; |
386 | for (size_t i = 0; i < padding; ++i) |
387 | TEST_VERIFY (buf[i] == ' '); |
388 | TEST_VERIFY (memcmp (buf + padding, mbs, length[WIDE_STRING_LENGTH]) == 0); |
389 | TEST_VERIFY (strcmp (buf + 3500, suffix) == 0); |
390 | } |
391 | |
392 | size_t wide_characters_converted = 0; |
393 | for (int mbs_len = 0; mbs_len <= length[WIDE_STRING_LENGTH] + 1; |
394 | ++mbs_len) |
395 | { |
396 | if (wide_characters_converted < WIDE_STRING_LENGTH |
397 | && mbs_len >= length[wide_characters_converted + 1]) |
398 | /* The requested prefix length contains room for another wide |
399 | character. */ |
400 | ++wide_characters_converted; |
401 | if (test_verbose > 0) |
402 | printf (format: "info: %s: mbs_len=%d wide_chars_converted=%zu length=%zu\n" , |
403 | __func__, mbs_len, wide_characters_converted, |
404 | length[wide_characters_converted]); |
405 | TEST_VERIFY (length[wide_characters_converted] <= mbs_len); |
406 | TEST_VERIFY (wide_characters_converted == 0 |
407 | || length[wide_characters_converted - 1] < mbs_len); |
408 | |
409 | int ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%.*ls%s" , mbs_len, wide, suffix); |
410 | TEST_VERIFY (ret == length[wide_characters_converted] + strlen (suffix)); |
411 | TEST_VERIFY (memcmp (buf, mbs, length[wide_characters_converted]) == 0); |
412 | TEST_VERIFY (strcmp (buf + length[wide_characters_converted], |
413 | suffix) == 0); |
414 | |
415 | /* Left-justified string, printed in full. */ |
416 | if (test_verbose) |
417 | printf (format: "info: %s: left-justified\n" , __func__); |
418 | ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%-3500.*ls%s" , |
419 | mbs_len, wide, suffix); |
420 | TEST_VERIFY (ret == 3500 + strlen (suffix)); |
421 | TEST_VERIFY (memcmp (buf, mbs, length[wide_characters_converted]) == 0); |
422 | for (size_t i = length[wide_characters_converted]; i < 3500; ++i) |
423 | TEST_VERIFY (buf[i] == ' '); |
424 | TEST_VERIFY (strcmp (buf + 3500, suffix) == 0); |
425 | |
426 | /* Right-justified string, printed in full. */ |
427 | if (test_verbose) |
428 | printf (format: "info: %s: right-justified\n" , __func__); |
429 | ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%3500.*ls%s" , mbs_len, wide, suffix); |
430 | TEST_VERIFY (ret == 3500 + strlen (suffix)); |
431 | size_t padding = 3500 - length[wide_characters_converted]; |
432 | for (size_t i = 0; i < padding; ++i) |
433 | TEST_VERIFY (buf[i] == ' '); |
434 | TEST_VERIFY (memcmp (buf + padding, mbs, |
435 | length[wide_characters_converted]) == 0); |
436 | TEST_VERIFY (strcmp (buf + 3500, suffix) == 0); |
437 | } |
438 | } |
439 | |
440 | /* Test with long strings and wide string result. */ |
441 | static void |
442 | test_wide_long (const char *mbs, const wchar_t *wide, const size_t *length) |
443 | { |
444 | wchar_t buf[2000]; |
445 | _Static_assert (sizeof (buf) > sizeof (wchar_t) * WIDE_STRING_LENGTH, |
446 | "buffer size consistent with string length" ); |
447 | const wchar_t *suffix = L"||TERM" ; |
448 | TEST_VERIFY_EXIT (sizeof (buf) |
449 | > length[WIDE_STRING_LENGTH] + wcslen (suffix)); |
450 | |
451 | /* Test formatting of the entire string. */ |
452 | { |
453 | int ret = swprintf (s: buf, n: sizeof (buf), format: L"%s%ls" , mbs, suffix); |
454 | TEST_VERIFY (ret == WIDE_STRING_LENGTH + wcslen (suffix)); |
455 | TEST_VERIFY (wmemcmp (buf, wide, WIDE_STRING_LENGTH) == 0); |
456 | TEST_VERIFY (wcscmp (buf + WIDE_STRING_LENGTH, suffix) == 0); |
457 | |
458 | /* Left-justified string, printed in full. */ |
459 | ret = swprintf (s: buf, n: sizeof (buf), format: L"%-1500s%ls" , mbs, suffix); |
460 | TEST_VERIFY (ret == 1500 + wcslen (suffix)); |
461 | TEST_VERIFY (wmemcmp (buf, wide, WIDE_STRING_LENGTH) == 0); |
462 | for (size_t i = WIDE_STRING_LENGTH; i < 1500; ++i) |
463 | TEST_VERIFY (buf[i] == L' '); |
464 | TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0); |
465 | |
466 | /* Right-justified string, printed in full. */ |
467 | ret = swprintf (s: buf, n: sizeof (buf), format: L"%1500s%ls" , mbs, suffix); |
468 | TEST_VERIFY (ret == 1500 + wcslen (suffix)); |
469 | size_t padding = 1500 - WIDE_STRING_LENGTH; |
470 | for (size_t i = 0; i < padding; ++i) |
471 | TEST_VERIFY (buf[i] == ' '); |
472 | TEST_VERIFY (wmemcmp (buf + padding, wide, WIDE_STRING_LENGTH) == 0); |
473 | TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0); |
474 | } |
475 | |
476 | for (int wide_len = 0; wide_len <= WIDE_STRING_LENGTH + 1; ++wide_len) |
477 | { |
478 | size_t actual_wide_len; |
479 | if (wide_len < WIDE_STRING_LENGTH) |
480 | actual_wide_len = wide_len; |
481 | else |
482 | actual_wide_len = WIDE_STRING_LENGTH; |
483 | if (test_verbose > 0) |
484 | printf (format: "info: %s: wide_len=%d actual_wide_len=%zu\n" , |
485 | __func__, wide_len, actual_wide_len); |
486 | |
487 | int ret = swprintf (s: buf, n: sizeof (buf), format: L"%.*s%ls" , |
488 | wide_len, mbs, suffix); |
489 | TEST_VERIFY (ret == actual_wide_len + wcslen (suffix)); |
490 | TEST_VERIFY (wmemcmp (buf, wide, actual_wide_len) == 0); |
491 | TEST_VERIFY (wcscmp (buf + actual_wide_len, suffix) == 0); |
492 | |
493 | /* Left-justified string, printed in full. */ |
494 | ret = swprintf (s: buf, n: sizeof (buf), format: L"%-1500.*s%ls" , |
495 | wide_len, mbs, suffix); |
496 | TEST_VERIFY (ret == 1500 + wcslen (suffix)); |
497 | TEST_VERIFY (wmemcmp (buf, wide, actual_wide_len) == 0); |
498 | for (size_t i = actual_wide_len; i < 1500; ++i) |
499 | TEST_VERIFY (buf[i] == L' '); |
500 | TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0); |
501 | |
502 | /* Right-justified string, printed in full. */ |
503 | ret = swprintf (s: buf, n: sizeof (buf), format: L"%1500.*s%ls" , |
504 | wide_len, mbs, suffix); |
505 | TEST_VERIFY (ret == 1500 + wcslen (suffix)); |
506 | size_t padding = 1500 - actual_wide_len; |
507 | for (size_t i = 0; i < padding; ++i) |
508 | TEST_VERIFY (buf[i] == L' '); |
509 | TEST_VERIFY (wmemcmp (buf + padding, wide, actual_wide_len) == 0); |
510 | TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0); |
511 | } |
512 | } |
513 | |
514 | static int |
515 | do_test (void) |
516 | { |
517 | /* This test only covers UTF-8 as a multi-byte character set. A |
518 | locale with a multi-byte character set with shift state would be |
519 | a relevant test target as well, but glibc currently does not ship |
520 | such a locale. */ |
521 | TEST_VERIFY (setlocale (LC_CTYPE, "de_DE.UTF-8" ) != NULL); |
522 | |
523 | test_mbs_result (); |
524 | test_wide_result (); |
525 | |
526 | char *mbs; |
527 | wchar_t *wide; |
528 | size_t *length; |
529 | make_random_string (mbs: &mbs, wide: &wide, length: &length); |
530 | TEST_VERIFY (strlen (mbs) == length[WIDE_STRING_LENGTH]); |
531 | if (test_verbose > 0) |
532 | printf (format: "info: long multi-byte string contains %zu characters\n" , |
533 | length[WIDE_STRING_LENGTH]); |
534 | test_mbs_long (mbs, wide, length); |
535 | test_wide_long (mbs, wide, length); |
536 | free (ptr: mbs); |
537 | free (ptr: wide); |
538 | free (ptr: length); |
539 | |
540 | return 0; |
541 | } |
542 | |
543 | #include <support/test-driver.c> |
544 | |