]>
Commit | Line | Data |
---|---|---|
c11cfe8d | 1 | /* Test for wchar_t/multi-byte conversion and precision in vfprintf. |
2b778ceb | 2 | Copyright (C) 2017-2021 Free Software Foundation, Inc. |
c11cfe8d FW |
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 | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
c11cfe8d FW |
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 (&str); | |
61 | struct wstr wstr; | |
62 | wstr_init (&wstr); | |
63 | struct len len; | |
64 | len_init (&len); | |
65 | ||
66 | for (int i = 0; i < WIDE_STRING_LENGTH; ++i) | |
67 | { | |
68 | len_add (&len, str_size (&str)); | |
69 | /* Cover some multi-byte UTF-8 sequences. Avoid the null | |
70 | character. */ | |
71 | uint32_t ch = 1 + (rand () % 521); | |
72 | wstr_add (&wstr, ch); | |
73 | ||
74 | /* Limited UTF-8 conversion. */ | |
75 | if (ch <= 127) | |
76 | str_add (&str, 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 (&str, 0xC0 | first); | |
83 | str_add (&str, 0x80 | (ch & 0x3f)); | |
84 | } | |
85 | } | |
86 | len_add (&len, str_size (&str)); | |
87 | wstr_add (&wstr, L'\0'); | |
88 | str_add (&str, '\0'); | |
89 | ||
90 | *mbs = str_finalize (&str, NULL); | |
91 | TEST_VERIFY_EXIT (*mbs != NULL); | |
92 | *wide = wstr_finalize (&wstr, NULL); | |
93 | TEST_VERIFY_EXIT (*wide != NULL); | |
94 | *length = len_finalize (&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 (buf, sizeof (buf), "%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 (buf, sizeof (buf), "%-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 (buf, sizeof (buf), "%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 ("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 (buf, sizeof (buf), "%.*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 ("info: %s: left-justified\n", __func__); | |
418 | ret = snprintf (buf, sizeof (buf), "%-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 ("info: %s: right-justified\n", __func__); | |
429 | ret = snprintf (buf, sizeof (buf), "%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 (buf, sizeof (buf), 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 (buf, sizeof (buf), 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 (buf, sizeof (buf), 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 ("info: %s: wide_len=%d actual_wide_len=%zu\n", | |
485 | __func__, wide_len, actual_wide_len); | |
486 | ||
487 | int ret = swprintf (buf, sizeof (buf), 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 (buf, sizeof (buf), 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 (buf, sizeof (buf), 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, &wide, &length); | |
530 | TEST_VERIFY (strlen (mbs) == length[WIDE_STRING_LENGTH]); | |
531 | if (test_verbose > 0) | |
532 | printf ("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 (mbs); | |
537 | free (wide); | |
538 | free (length); | |
539 | ||
540 | return 0; | |
541 | } | |
542 | ||
543 | #include <support/test-driver.c> |