1 /*
2 * Example program for the Allegro library.
3 *
4 * Test UTF-8 string routines.
5 */
6
7 /* TODO: we should also be checking on inputs with surrogate characters
8 * (which are not allowed)
9 */
10
11 #include <allegro5/allegro.h>
12 #include <allegro5/utf8.h>
13 #include <stdarg.h>
14 #include <stdio.h>
15
16 #include "common.c"
17
18 #ifdef ALLEGRO_MSVC
19 #pragma warning (disable: 4066)
20 #endif
21
22 /* Some unicode characters */
23 #define U_ae 0x00e6 /* æ */
24 #define U_i_acute 0x00ed /* í */
25 #define U_eth 0x00f0 /* ð */
26 #define U_o_dia 0x00f6 /* ö */
27 #define U_thorn 0x00fe /* þ */
28 #define U_z_bar 0x01b6 /* ƶ */
29 #define U_schwa 0x0259 /* ə */
30 #define U_beta 0x03b2 /* β */
31 #define U_1d08 0x1d08 /* ᴈ */
32 #define U_1ff7 0x1ff7 /* ῷ */
33 #define U_2051 0x2051 /* ⁑ */
34 #define U_euro 0x20ac /* € */
35
36 typedef void (*test_t)(void);
37
38 int error = 0;
39
40 #define CHECK(x) \
41 do { \
42 bool ok = (x); \
43 if (!ok) { \
44 log_printf("FAIL %s\n", #x); \
45 error++; \
46 } else { \
47 log_printf("OK %s\n", #x); \
48 } \
49 } while (0)
50
51 /* Test that we can create and destroy strings and get their data and size. */
t1(void)52 static void t1(void)
53 {
54 ALLEGRO_USTR *us1 = al_ustr_new("");
55 ALLEGRO_USTR *us2 = al_ustr_new("áƵ");
56
57 CHECK(0 == strcmp(al_cstr(us1), ""));
58 CHECK(0 == strcmp(al_cstr(us2), "áƵ"));
59 CHECK(4 == al_ustr_size(us2));
60
61 al_ustr_free(us1);
62 al_ustr_free(us2);
63 }
64
t2(void)65 static void t2(void)
66 {
67 CHECK(0 == al_ustr_size(al_ustr_empty_string()));
68 CHECK(0 == strcmp(al_cstr(al_ustr_empty_string()), ""));
69 }
70
71 /* Test that we make strings which reference other C strings. */
72 /* No memory needs to be freed. */
t3(void)73 static void t3(void)
74 {
75 ALLEGRO_USTR_INFO info;
76 const ALLEGRO_USTR *us = al_ref_cstr(&info, "A static string.");
77
78 CHECK(0 == strcmp(al_cstr(us), "A static string."));
79 }
80
81 /* Test that we can make strings which reference arbitrary memory blocks. */
82 /* No memory needs to be freed. */
t4(void)83 static void t4(void)
84 {
85 const char s[] = "This contains an embedded NUL: \0 <-- here";
86 ALLEGRO_USTR_INFO info;
87 const ALLEGRO_USTR *us = al_ref_buffer(&info, s, sizeof(s));
88
89 CHECK(al_ustr_size(us) == sizeof(s));
90 CHECK(0 == memcmp(al_cstr(us), s, sizeof(s)));
91 }
92
93 /* Test that we can make strings which reference (parts of) other strings. */
t5(void)94 static void t5(void)
95 {
96 ALLEGRO_USTR *us1;
97 const ALLEGRO_USTR *us2;
98 ALLEGRO_USTR_INFO us2_info;
99
100 us1 = al_ustr_new("aábdðeéfghiíjklmnoóprstuúvxyýþæö");
101
102 us2 = al_ref_ustr(&us2_info, us1, 36, 36 + 4);
103 CHECK(0 == memcmp(al_cstr(us2), "þæ", al_ustr_size(us2)));
104
105 /* Start pos underflow */
106 us2 = al_ref_ustr(&us2_info, us1, -10, 7);
107 CHECK(0 == memcmp(al_cstr(us2), "aábdð", al_ustr_size(us2)));
108
109 /* End pos overflow */
110 us2 = al_ref_ustr(&us2_info, us1, 36, INT_MAX);
111 CHECK(0 == memcmp(al_cstr(us2), "þæö", al_ustr_size(us2)));
112
113 /* Start > end */
114 us2 = al_ref_ustr(&us2_info, us1, 36 + 4, 36);
115 CHECK(0 == al_ustr_size(us2));
116
117 al_ustr_free(us1);
118 }
119
120 /* Test al_ustr_dup. */
t6(void)121 static void t6(void)
122 {
123 ALLEGRO_USTR *us1 = al_ustr_new("aábdðeéfghiíjklmnoóprstuúvxyýþæö");
124 ALLEGRO_USTR *us2 = al_ustr_dup(us1);
125
126 CHECK(al_ustr_size(us1) == al_ustr_size(us2));
127 CHECK(0 == memcmp(al_cstr(us1), al_cstr(us2), al_ustr_size(us1)));
128
129 al_ustr_free(us1);
130 al_ustr_free(us2);
131 }
132
133 /* Test al_ustr_dup_substr. */
t7(void)134 static void t7(void)
135 {
136 ALLEGRO_USTR *us1;
137 ALLEGRO_USTR *us2;
138
139 us1 = al_ustr_new("aábdðeéfghiíjklmnoóprstuúvxyýþæö");
140
141 /* Cut out part of a string. Check for NUL terminator. */
142 us2 = al_ustr_dup_substr(us1, 36, 36 + 4);
143 CHECK(al_ustr_size(us2) == 4);
144 CHECK(0 == strcmp(al_cstr(us2), "þæ"));
145 al_ustr_free(us2);
146
147 /* Under and overflow */
148 us2 = al_ustr_dup_substr(us1, INT_MIN, INT_MAX);
149 CHECK(al_ustr_size(us2) == al_ustr_size(us1));
150 CHECK(0 == strcmp(al_cstr(us2), al_cstr(us1)));
151 al_ustr_free(us2);
152
153 /* Start > end */
154 us2 = al_ustr_dup_substr(us1, INT_MAX, INT_MIN);
155 CHECK(0 == al_ustr_size(us2));
156 al_ustr_free(us2);
157
158 al_ustr_free(us1);
159 }
160
161 /* Test al_ustr_append, al_ustr_append_cstr. */
t8(void)162 static void t8(void)
163 {
164 ALLEGRO_USTR *us1 = al_ustr_new("aábdðeéfghiíjklm");
165 ALLEGRO_USTR *us2 = al_ustr_new("noóprstuú");
166
167 CHECK(al_ustr_append(us1, us2));
168 CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjklmnoóprstuú"));
169
170 CHECK(al_ustr_append_cstr(us1, "vxyýþæö"));
171 CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjklmnoóprstuúvxyýþæö"));
172
173 al_ustr_free(us1);
174 al_ustr_free(us2);
175 }
176
177 /* Test al_ustr_append with aliased strings. */
t9(void)178 static void t9(void)
179 {
180 ALLEGRO_USTR *us1;
181 ALLEGRO_USTR_INFO us2_info;
182 const ALLEGRO_USTR *us2;
183
184 /* Append a string to itself. */
185 us1 = al_ustr_new("aábdðeéfghiíjklm");
186 CHECK(al_ustr_append(us1, us1));
187 CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjklmaábdðeéfghiíjklm"));
188 al_ustr_free(us1);
189
190 /* Append a substring of a string to itself. */
191 us1 = al_ustr_new("aábdðeéfghiíjklm");
192 us2 = al_ref_ustr(&us2_info, us1, 5, 5 + 11); /* ð...í */
193 CHECK(al_ustr_append(us1, us2));
194 CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjklmðeéfghií"));
195 al_ustr_free(us1);
196 }
197
198 /* Test al_ustr_equal. */
t10(void)199 static void t10(void)
200 {
201 ALLEGRO_USTR *us1;
202 ALLEGRO_USTR *us2;
203 const ALLEGRO_USTR *us3;
204 ALLEGRO_USTR_INFO us3_info;
205 const char us3_data[] = "aábdð\0eéfgh";
206
207 us1 = al_ustr_new("aábdð");
208 us2 = al_ustr_dup(us1);
209 us3 = al_ref_buffer(&us3_info, us3_data, sizeof(us3_data));
210
211 CHECK(al_ustr_equal(us1, us2));
212 CHECK(!al_ustr_equal(us1, al_ustr_empty_string()));
213
214 /* Check comparison doesn't stop at embedded NUL. */
215 CHECK(!al_ustr_equal(us1, us3));
216
217 al_ustr_free(us1);
218 al_ustr_free(us2);
219 }
220
221 /* Test al_ustr_insert. */
t11(void)222 static void t11(void)
223 {
224 ALLEGRO_USTR *us1;
225 ALLEGRO_USTR *us2;
226 size_t sz;
227
228 /* Insert in middle. */
229 us1 = al_ustr_new("aábdðeéfghiíjkprstuúvxyýþæö");
230 us2 = al_ustr_new("lmnoó");
231 al_ustr_insert(us1, 18, us2);
232 CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjklmnoóprstuúvxyýþæö"));
233
234 /* Insert into itself. */
235 al_ustr_insert(us2, 3, us2);
236 CHECK(0 == strcmp(al_cstr(us2), "lmnlmnoóoó"));
237
238 /* Insert before start (not allowed). */
239 CHECK(!al_ustr_insert(us2, -1, us2));
240
241 /* Insert past end (will be padded with NULs). */
242 sz = al_ustr_size(us2);
243 al_ustr_insert(us2, sz + 3, us2);
244 CHECK(al_ustr_size(us2) == sz + sz + 3);
245 CHECK(0 == memcmp(al_cstr(us2), "lmnlmnoóoó\0\0\0lmnlmnoóoó", sz + sz + 3));
246
247 al_ustr_free(us1);
248 al_ustr_free(us2);
249 }
250
251 /* Test al_ustr_insert_cstr. */
t12(void)252 static void t12(void)
253 {
254 ALLEGRO_USTR *us1 = al_ustr_new("aábeéf");
255 CHECK(al_ustr_insert_cstr(us1, 4, "dð"));
256 CHECK(0 == strcmp(al_cstr(us1), "aábdðeéf"));
257 al_ustr_free(us1);
258 }
259
260 /* Test al_ustr_remove_range. */
t13(void)261 static void t13(void)
262 {
263 ALLEGRO_USTR *us1 = al_ustr_new("aábdðeéfghiíjkprstuúvxyýþæö");
264
265 /* Remove from middle of string. */
266 CHECK(al_ustr_remove_range(us1, 5, 30));
267 CHECK(0 == strcmp(al_cstr(us1), "aábdþæö"));
268
269 /* Removing past end. */
270 CHECK(al_ustr_remove_range(us1, 100, 120));
271 CHECK(0 == strcmp(al_cstr(us1), "aábdþæö"));
272
273 /* Start > End. */
274 CHECK(! al_ustr_remove_range(us1, 3, 0));
275 CHECK(0 == strcmp(al_cstr(us1), "aábdþæö"));
276
277 al_ustr_free(us1);
278 }
279
280 /* Test al_ustr_truncate. */
t14(void)281 static void t14(void)
282 {
283 ALLEGRO_USTR *us1 = al_ustr_new("aábdðeéfghiíjkprstuúvxyýþæö");
284
285 /* Truncate from middle of string. */
286 CHECK(al_ustr_truncate(us1, 30));
287 CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjkprstuúvxyý"));
288
289 /* Truncate past end (allowed). */
290 CHECK(al_ustr_truncate(us1, 100));
291 CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjkprstuúvxyý"));
292
293 /* Truncate before start (not allowed). */
294 CHECK(! al_ustr_truncate(us1, -1));
295 CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjkprstuúvxyý"));
296
297 al_ustr_free(us1);
298 }
299
300 /* Test whitespace trim functions. */
t15(void)301 static void t15(void)
302 {
303 ALLEGRO_USTR *us1 = al_ustr_new(" \f\n\r\t\vhello \f\n\r\t\v");
304 ALLEGRO_USTR *us2 = al_ustr_new(" \f\n\r\t\vhello \f\n\r\t\v");
305
306 CHECK(al_ustr_ltrim_ws(us1));
307 CHECK(0 == strcmp(al_cstr(us1), "hello \f\n\r\t\v"));
308
309 CHECK(al_ustr_rtrim_ws(us1));
310 CHECK(0 == strcmp(al_cstr(us1), "hello"));
311
312 CHECK(al_ustr_trim_ws(us2));
313 CHECK(0 == strcmp(al_cstr(us2), "hello"));
314
315 al_ustr_free(us1);
316 al_ustr_free(us2);
317 }
318
319 /* Test whitespace trim functions (edge cases). */
t16(void)320 static void t16(void)
321 {
322 ALLEGRO_USTR *us1;
323
324 /* Check return value when passed empty strings. */
325 us1 = al_ustr_new("");
326 CHECK(al_ustr_ltrim_ws(us1));
327 CHECK(al_ustr_rtrim_ws(us1));
328 CHECK(al_ustr_trim_ws(us1));
329 al_ustr_free(us1);
330
331 /* Check nothing bad happens if the whole string is whitespace. */
332 us1 = al_ustr_new(" \f\n\r\t\v");
333 CHECK(al_ustr_ltrim_ws(us1));
334 CHECK(al_ustr_size(us1) == 0);
335 al_ustr_free(us1);
336
337 us1 = al_ustr_new(" \f\n\r\t\v");
338 CHECK(al_ustr_rtrim_ws(us1));
339 CHECK(al_ustr_size(us1) == 0);
340 al_ustr_free(us1);
341
342 us1 = al_ustr_new(" \f\n\r\t\v");
343 CHECK(al_ustr_trim_ws(us1));
344 CHECK(al_ustr_size(us1) == 0);
345 al_ustr_free(us1);
346 }
347
348 /* Test al_utf8_width. */
t17(void)349 static void t17(void)
350 {
351 CHECK(al_utf8_width(0x000000) == 1);
352 CHECK(al_utf8_width(0x00007f) == 1);
353 CHECK(al_utf8_width(0x000080) == 2);
354 CHECK(al_utf8_width(0x0007ff) == 2);
355 CHECK(al_utf8_width(0x000800) == 3);
356 CHECK(al_utf8_width(0x00ffff) == 3);
357 CHECK(al_utf8_width(0x010000) == 4);
358 CHECK(al_utf8_width(0x10ffff) == 4);
359
360 /* These are illegal. */
361 CHECK(al_utf8_width(0x110000) == 0);
362 CHECK(al_utf8_width(0xffffff) == 0);
363 }
364
365 /* Test al_utf8_encode. */
t18(void)366 static void t18(void)
367 {
368 char buf[4];
369
370 CHECK(al_utf8_encode(buf, 0) == 1);
371 CHECK(0 == memcmp(buf, "\x00", 1));
372
373 CHECK(al_utf8_encode(buf, 0x7f) == 1);
374 CHECK(0 == memcmp(buf, "\x7f", 1));
375
376 CHECK(al_utf8_encode(buf, 0x80) == 2);
377 CHECK(0 == memcmp(buf, "\xC2\x80", 2));
378
379 CHECK(al_utf8_encode(buf, 0x7ff) == 2);
380 CHECK(0 == memcmp(buf, "\xDF\xBF", 2));
381
382 CHECK(al_utf8_encode(buf, 0x000800) == 3);
383 CHECK(0 == memcmp(buf, "\xE0\xA0\x80", 3));
384
385 CHECK(al_utf8_encode(buf, 0x00ffff) == 3);
386 CHECK(0 == memcmp(buf, "\xEF\xBF\xBF", 3));
387
388 CHECK(al_utf8_encode(buf, 0x010000) == 4);
389 CHECK(0 == memcmp(buf, "\xF0\x90\x80\x80", 4));
390
391 CHECK(al_utf8_encode(buf, 0x10ffff) == 4);
392 CHECK(0 == memcmp(buf, "\xF4\x8f\xBF\xBF", 4));
393
394 /* These are illegal. */
395 CHECK(al_utf8_encode(buf, 0x110000) == 0);
396 CHECK(al_utf8_encode(buf, 0xffffff) == 0);
397 }
398
399 /* Test al_ustr_insert_chr. */
t19(void)400 static void t19(void)
401 {
402 ALLEGRO_USTR *us = al_ustr_new("");
403
404 CHECK(al_ustr_insert_chr(us, 0, 'a') == 1);
405 CHECK(al_ustr_insert_chr(us, 0, U_ae) == 2);
406 CHECK(al_ustr_insert_chr(us, 2, U_euro) == 3);
407 CHECK(0 == strcmp(al_cstr(us), "æ€a"));
408
409 /* Past end. */
410 CHECK(al_ustr_insert_chr(us, 8, U_o_dia) == 2);
411 CHECK(0 == memcmp(al_cstr(us), "æ€a\0\0ö", 9));
412
413 /* Invalid code points. */
414 CHECK(al_ustr_insert_chr(us, 0, -1) == 0);
415 CHECK(al_ustr_insert_chr(us, 0, 0x110000) == 0);
416
417 al_ustr_free(us);
418 }
419
420 /* Test al_ustr_append_chr. */
t20(void)421 static void t20(void)
422 {
423 ALLEGRO_USTR *us = al_ustr_new("");
424
425 CHECK(al_ustr_append_chr(us, 'a') == 1);
426 CHECK(al_ustr_append_chr(us, U_ae) == 2);
427 CHECK(al_ustr_append_chr(us, U_euro) == 3);
428 CHECK(0 == strcmp(al_cstr(us), "aæ€"));
429
430 /* Invalid code points. */
431 CHECK(al_ustr_append_chr(us, -1) == 0);
432 CHECK(al_ustr_append_chr(us, 0x110000) == 0);
433
434 al_ustr_free(us);
435 }
436
437 /* Test al_ustr_get. */
t21(void)438 static void t21(void)
439 {
440 ALLEGRO_USTR_INFO info;
441 const ALLEGRO_USTR *us;
442
443 us = al_ref_buffer(&info, "", 1);
444 CHECK(al_ustr_get(us, 0) == 0);
445
446 us = al_ref_cstr(&info, "\x7f");
447 CHECK(al_ustr_get(us, 0) == 0x7f);
448
449 us = al_ref_cstr(&info, "\xC2\x80");
450 CHECK(al_ustr_get(us, 0) == 0x80);
451
452 us = al_ref_cstr(&info, "\xDF\xBf");
453 CHECK(al_ustr_get(us, 0) == 0x7ff);
454
455 us = al_ref_cstr(&info, "\xE0\xA0\x80");
456 CHECK(al_ustr_get(us, 0) == 0x800);
457
458 us = al_ref_cstr(&info, "\xEF\xBF\xBF");
459 CHECK(al_ustr_get(us, 0) == 0xffff);
460
461 us = al_ref_cstr(&info, "\xF0\x90\x80\x80");
462 CHECK(al_ustr_get(us, 0) == 0x010000);
463
464 us = al_ref_cstr(&info, "\xF4\x8F\xBF\xBF");
465 CHECK(al_ustr_get(us, 0) == 0x10ffff);
466 }
467
468 /* Test al_ustr_get on invalid sequences. */
t22(void)469 static void t22(void)
470 {
471 ALLEGRO_USTR_INFO info;
472 const ALLEGRO_USTR *us;
473
474 /* Empty string. */
475 al_set_errno(0);
476 CHECK(al_ustr_get(al_ustr_empty_string(), 0) < 0);
477 CHECK(al_get_errno() == ERANGE);
478
479 /* 5-byte sequence. */
480 us = al_ref_cstr(&info, "\xf8\x88\x80\x80\x80");
481 al_set_errno(0);
482 CHECK(al_ustr_get(us, 0) < 0);
483 CHECK(al_get_errno() == EILSEQ);
484
485 /* Start in trail byte. */
486 us = al_ref_cstr(&info, "ð");
487 al_set_errno(0);
488 CHECK(al_ustr_get(us, 1) < 0);
489 CHECK(al_get_errno() == EILSEQ);
490
491 /* Truncated 3-byte sequence. */
492 us = al_ref_cstr(&info, "\xEF\xBF");
493 al_set_errno(0);
494 CHECK(al_ustr_get(us, 0) < 0);
495 CHECK(al_get_errno() == EILSEQ);
496 }
497
498 /* Test al_ustr_get on invalid sequences (part 2). */
499 /* Get more ideas for tests from
500 * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
501 */
t23(void)502 static void t23(void)
503 {
504 ALLEGRO_USTR_INFO info;
505 const ALLEGRO_USTR *us;
506
507 /* Examples of an overlong ASCII character */
508 us = al_ref_cstr(&info, "\xc0\xaf");
509 CHECK(al_ustr_get(us, 0) < 0);
510 us = al_ref_cstr(&info, "\xe0\x80\xaf");
511 CHECK(al_ustr_get(us, 0) < 0);
512 us = al_ref_cstr(&info, "\xf0\x80\x80\xaf");
513 CHECK(al_ustr_get(us, 0) < 0);
514 us = al_ref_cstr(&info, "\xf8\x80\x80\x80\xaf");
515 CHECK(al_ustr_get(us, 0) < 0);
516 us = al_ref_cstr(&info, "\xfc\x80\x80\x80\x80\xaf");
517 CHECK(al_ustr_get(us, 0) < 0);
518
519 /* Maximum overlong sequences */
520 us = al_ref_cstr(&info, "\xc1\xbf");
521 CHECK(al_ustr_get(us, 0) < 0);
522
523 us = al_ref_cstr(&info, "\xe0\x9f\xbf");
524 CHECK(al_ustr_get(us, 0) < 0);
525
526 us = al_ref_cstr(&info, "\xf0\x8f\xbf\xbf");
527 CHECK(al_ustr_get(us, 0) < 0);
528
529 us = al_ref_cstr(&info, "\xf8\x87\xbf\xbf\xbf");
530 CHECK(al_ustr_get(us, 0) < 0);
531
532 us = al_ref_cstr(&info, "\xfc\x83\xbf\xbf\xbf\xbf");
533 CHECK(al_ustr_get(us, 0) < 0);
534
535 /* Overlong representation of the NUL character */
536 us = al_ref_cstr(&info, "\xc0\x80");
537 CHECK(al_ustr_get(us, 0) < 0);
538
539 us = al_ref_cstr(&info, "\xe0\x80\x80");
540 CHECK(al_ustr_get(us, 0) < 0);
541
542 us = al_ref_cstr(&info, "\xf0\x80\x80");
543 CHECK(al_ustr_get(us, 0) < 0);
544
545 us = al_ref_cstr(&info, "\xf8\x80\x80\x80");
546 CHECK(al_ustr_get(us, 0) < 0);
547
548 us = al_ref_cstr(&info, "\xfc\x80\x80\x80\x80");
549 CHECK(al_ustr_get(us, 0) < 0);
550 }
551
552 /* Test al_ustr_next. */
t24(void)553 static void t24(void)
554 {
555 const char str[] = "a\0þ€\xf4\x8f\xbf\xbf";
556 ALLEGRO_USTR_INFO info;
557 const ALLEGRO_USTR *us = al_ref_buffer(&info, str, sizeof(str) - 1);
558 int pos = 0;
559
560 CHECK(al_ustr_next(us, &pos)); /* a */
561 CHECK(pos == 1);
562
563 CHECK(al_ustr_next(us, &pos)); /* NUL */
564 CHECK(pos == 2);
565
566 CHECK(al_ustr_next(us, &pos)); /* þ */
567 CHECK(pos == 4);
568
569 CHECK(al_ustr_next(us, &pos)); /* € */
570 CHECK(pos == 7);
571
572 CHECK(al_ustr_next(us, &pos)); /* U+10FFFF */
573 CHECK(pos == 11);
574
575 CHECK(! al_ustr_next(us, &pos)); /* end */
576 CHECK(pos == 11);
577 }
578
579 /* Test al_ustr_next with invalid input. */
t25(void)580 static void t25(void)
581 {
582 const char str[] = "þ\xf4\x8f\xbf.";
583 ALLEGRO_USTR_INFO info;
584 const ALLEGRO_USTR *us = al_ref_buffer(&info, str, sizeof(str) - 1);
585 int pos;
586
587 /* Starting in middle of a sequence. */
588 pos = 1;
589 CHECK(al_ustr_next(us, &pos));
590 CHECK(pos == 2);
591
592 /* Unexpected end of 4-byte sequence. */
593 CHECK(al_ustr_next(us, &pos));
594 CHECK(pos == 5);
595 }
596
597 /* Test al_ustr_prev. */
t26(void)598 static void t26(void)
599 {
600 ALLEGRO_USTR *us = al_ustr_new("aþ€\xf4\x8f\xbf\xbf");
601 int pos = al_ustr_size(us);
602
603 CHECK(al_ustr_prev(us, &pos)); /* U+10FFFF */
604 CHECK(pos == 6);
605
606 CHECK(al_ustr_prev(us, &pos)); /* € */
607 CHECK(pos == 3);
608
609 CHECK(al_ustr_prev(us, &pos)); /* þ */
610 CHECK(pos == 1);
611
612 CHECK(al_ustr_prev(us, &pos)); /* a */
613 CHECK(pos == 0);
614
615 CHECK(!al_ustr_prev(us, &pos)); /* begin */
616 CHECK(pos == 0);
617
618 al_ustr_free(us);
619 }
620
621 /* Test al_ustr_length. */
t27(void)622 static void t27(void)
623 {
624 ALLEGRO_USTR *us = al_ustr_new("aþ€\xf4\x8f\xbf\xbf");
625
626 CHECK(0 == al_ustr_length(al_ustr_empty_string()));
627 CHECK(4 == al_ustr_length(us));
628
629 al_ustr_free(us);
630 }
631
632 /* Test al_ustr_offset. */
t28(void)633 static void t28(void)
634 {
635 ALLEGRO_USTR *us = al_ustr_new("aþ€\xf4\x8f\xbf\xbf");
636
637 CHECK(al_ustr_offset(us, 0) == 0);
638 CHECK(al_ustr_offset(us, 1) == 1);
639 CHECK(al_ustr_offset(us, 2) == 3);
640 CHECK(al_ustr_offset(us, 3) == 6);
641 CHECK(al_ustr_offset(us, 4) == 10);
642 CHECK(al_ustr_offset(us, 5) == 10);
643
644 CHECK(al_ustr_offset(us, -1) == 6);
645 CHECK(al_ustr_offset(us, -2) == 3);
646 CHECK(al_ustr_offset(us, -3) == 1);
647 CHECK(al_ustr_offset(us, -4) == 0);
648 CHECK(al_ustr_offset(us, -5) == 0);
649
650 al_ustr_free(us);
651 }
652
653 /* Test al_ustr_get_next. */
t29(void)654 static void t29(void)
655 {
656 ALLEGRO_USTR *us = al_ustr_new("aþ€");
657 int pos;
658
659 pos = 0;
660 CHECK(al_ustr_get_next(us, &pos) == 'a');
661 CHECK(al_ustr_get_next(us, &pos) == U_thorn);
662 CHECK(al_ustr_get_next(us, &pos) == U_euro);
663 CHECK(al_ustr_get_next(us, &pos) == -1);
664 CHECK(pos == (int) al_ustr_size(us));
665
666 /* Start in the middle of þ. */
667 pos = 2;
668 CHECK(al_ustr_get_next(us, &pos) == -2);
669 CHECK(al_ustr_get_next(us, &pos) == U_euro);
670
671 al_ustr_free(us);
672 }
673
674 /* Test al_ustr_prev_get. */
t30(void)675 static void t30(void)
676 {
677 ALLEGRO_USTR *us = al_ustr_new("aþ€");
678 int pos;
679
680 pos = al_ustr_size(us);
681 CHECK(al_ustr_prev_get(us, &pos) == U_euro);
682 CHECK(al_ustr_prev_get(us, &pos) == U_thorn);
683 CHECK(al_ustr_prev_get(us, &pos) == 'a');
684 CHECK(al_ustr_prev_get(us, &pos) == -1);
685
686 /* Start in the middle of þ. */
687 pos = 2;
688 CHECK(al_ustr_prev_get(us, &pos) == U_thorn);
689
690 al_ustr_free(us);
691 }
692
693 /* Test al_ustr_find_chr. */
t31(void)694 static void t31(void)
695 {
696 ALLEGRO_USTR *us = al_ustr_new("aábdðeéfghiíaábdðeéfghií");
697
698 /* Find ASCII. */
699 CHECK(al_ustr_find_chr(us, 0, 'e') == 7);
700 CHECK(al_ustr_find_chr(us, 7, 'e') == 7); /* start_pos is inclusive */
701 CHECK(al_ustr_find_chr(us, 8, 'e') == 23);
702 CHECK(al_ustr_find_chr(us, 0, '.') == -1);
703
704 /* Find non-ASCII. */
705 CHECK(al_ustr_find_chr(us, 0, U_eth) == 5);
706 CHECK(al_ustr_find_chr(us, 5, U_eth) == 5); /* start_pos is inclusive */
707 CHECK(al_ustr_find_chr(us, 6, U_eth) == 21);
708 CHECK(al_ustr_find_chr(us, 0, U_z_bar) == -1);
709
710 al_ustr_free(us);
711 }
712
713 /* Test al_ustr_rfind_chr. */
t32(void)714 static void t32(void)
715 {
716 ALLEGRO_USTR *us = al_ustr_new("aábdðeéfghiíaábdðeéfghií");
717 int end = al_ustr_size(us);
718
719 /* Find ASCII. */
720 CHECK(al_ustr_rfind_chr(us, end, 'e') == 23);
721 CHECK(al_ustr_rfind_chr(us, 23, 'e') == 7); /* end_pos exclusive */
722 CHECK(al_ustr_rfind_chr(us, end, '.') == -1);
723
724 /* Find non-ASCII. */
725 CHECK(al_ustr_rfind_chr(us, end, U_i_acute) == 30);
726 CHECK(al_ustr_rfind_chr(us, end - 1, U_i_acute) == 14); /* end_pos exclusive */
727 CHECK(al_ustr_rfind_chr(us, end, U_z_bar) == -1);
728
729 al_ustr_free(us);
730 }
731
732 /* Test al_ustr_find_set, al_ustr_find_set_cstr. */
t33(void)733 static void t33(void)
734 {
735 ALLEGRO_USTR *us = al_ustr_new("aábdðeéfghiíaábdðeéfghií");
736
737 /* al_ustr_find_set_cstr is s simple wrapper for al_ustr_find_set
738 * so we test using that.
739 */
740
741 /* Find ASCII. */
742 CHECK(al_ustr_find_set_cstr(us, 0, "gfe") == 7);
743 CHECK(al_ustr_find_set_cstr(us, 7, "gfe") == 7); /* start_pos inclusive */
744 CHECK(al_ustr_find_set_cstr(us, 0, "") == -1);
745 CHECK(al_ustr_find_set_cstr(us, 0, "xyz") == -1);
746
747 /* Find non-ASCII. */
748 CHECK(al_ustr_find_set_cstr(us, 0, "éðf") == 5);
749 CHECK(al_ustr_find_set_cstr(us, 5, "éðf") == 5); /* start_pos inclusive */
750 CHECK(al_ustr_find_set_cstr(us, 0, "ẋỹƶ") == -1);
751
752 al_ustr_free(us);
753 }
754
755 /* Test al_ustr_find_set, al_ustr_find_set_cstr (invalid values). */
t34(void)756 static void t34(void)
757 {
758 ALLEGRO_USTR *us = al_ustr_new("a\x80ábdðeéfghií");
759
760 /* Invalid byte sequence in search string. */
761 CHECK(al_ustr_find_set_cstr(us, 0, "gfe") == 8);
762
763 /* Invalid byte sequence in accept set. */
764 CHECK(al_ustr_find_set_cstr(us, 0, "é\x80ðf") == 6);
765
766 al_ustr_free(us);
767 }
768
769 /* Test al_ustr_find_cset, al_ustr_find_cset_cstr. */
t35(void)770 static void t35(void)
771 {
772 ALLEGRO_USTR *us;
773
774 /* al_ustr_find_cset_cstr is s simple wrapper for al_ustr_find_cset
775 * so we test using that.
776 */
777
778 /* Find ASCII. */
779 us = al_ustr_new("alphabetagamma");
780 CHECK(al_ustr_find_cset_cstr(us, 0, "alphbet") == 9);
781 CHECK(al_ustr_find_cset_cstr(us, 9, "alphbet") == 9);
782 CHECK(al_ustr_find_cset_cstr(us, 0, "") == -1);
783 CHECK(al_ustr_find_cset_cstr(us, 0, "alphbetgm") == -1);
784 al_ustr_free(us);
785
786 /* Find non-ASCII. */
787 us = al_ustr_new("αλφαβεταγαμμα");
788 CHECK(al_ustr_find_cset_cstr(us, 0, "αλφβετ") == 16);
789 CHECK(al_ustr_find_cset_cstr(us, 16, "αλφβετ") == 16);
790 CHECK(al_ustr_find_cset_cstr(us, 0, "αλφβετγμ") == -1);
791 al_ustr_free(us);
792 }
793
794 /* Test al_ustr_find_cset, al_ustr_find_set_cstr (invalid values). */
t36(void)795 static void t36(void)
796 {
797 ALLEGRO_USTR *us = al_ustr_new("a\x80ábdðeéfghií");
798
799 /* Invalid byte sequence in search string. */
800 CHECK(al_ustr_find_cset_cstr(us, 0, "aábd") == 6);
801
802 /* Invalid byte sequence in reject set. */
803 CHECK(al_ustr_find_cset_cstr(us, 0, "a\x80ábd") == 6);
804
805 al_ustr_free(us);
806 }
807
808 /* Test al_ustr_find_str, al_ustr_find_cstr. */
t37(void)809 static void t37(void)
810 {
811 ALLEGRO_USTR *us = al_ustr_new("aábdðeéfghiíaábdðeéfghií");
812
813 /* al_ustr_find_cstr is s simple wrapper for al_ustr_find_str
814 * so we test using that.
815 */
816
817 CHECK(al_ustr_find_cstr(us, 0, "") == 0);
818 CHECK(al_ustr_find_cstr(us, 10, "") == 10);
819 CHECK(al_ustr_find_cstr(us, 0, "ábd") == 1);
820 CHECK(al_ustr_find_cstr(us, 10, "ábd") == 17);
821 CHECK(al_ustr_find_cstr(us, 0, "ábz") == -1);
822
823 al_ustr_free(us);
824 }
825
826 /* Test al_ustr_rfind_str, al_ustr_rfind_cstr. */
t38(void)827 static void t38(void)
828 {
829 ALLEGRO_USTR *us = al_ustr_new("aábdðeéfghiíaábdðeéfghií");
830 int end = al_ustr_size(us);
831
832 /* al_ustr_find_cstr is s simple wrapper for al_ustr_find_str
833 * so we test using that.
834 */
835
836 CHECK(al_ustr_rfind_cstr(us, 0, "") == 0);
837 CHECK(al_ustr_rfind_cstr(us, 1, "") == 1);
838 CHECK(al_ustr_rfind_cstr(us, end, "hií") == end - 4);
839 CHECK(al_ustr_rfind_cstr(us, end - 1, "hií") == 12);
840 CHECK(al_ustr_rfind_cstr(us, end, "ábz") == -1);
841
842 al_ustr_free(us);
843 }
844
845 /* Test al_ustr_new_from_buffer, al_cstr_dup. */
t39(void)846 static void t39(void)
847 {
848 const char s1[] = "Корабът ми на въздушна възглавница\0е пълен със змиорки";
849 ALLEGRO_USTR *us;
850 char *s2;
851
852 us = al_ustr_new_from_buffer(s1, sizeof(s1) - 1); /* missing NUL term. */
853 s2 = al_cstr_dup(us);
854 al_ustr_free(us);
855
856 CHECK(0 == strcmp(s1, s2));
857 CHECK(0 == memcmp(s1, s2, sizeof(s1))); /* including NUL terminator */
858
859 al_free(s2);
860 }
861
862 /* Test al_ustr_assign, al_ustr_assign_cstr. */
t40(void)863 static void t40(void)
864 {
865 ALLEGRO_USTR *us1 = al_ustr_new("我隻氣墊船裝滿晒鱔");
866 ALLEGRO_USTR *us2 = al_ustr_new("Τὸ χόβερκράφτ μου εἶναι γεμᾶτο χέλια");
867
868 CHECK(al_ustr_assign(us1, us2));
869 CHECK(0 == strcmp(al_cstr(us1), "Τὸ χόβερκράφτ μου εἶναι γεμᾶτο χέλια"));
870
871 CHECK(al_ustr_assign_cstr(us1, "私のホバークラフトは鰻でいっぱいです"));
872 CHECK(54 == al_ustr_size(us1));
873
874 al_ustr_free(us1);
875 al_ustr_free(us2);
876 }
877
878 /* Test al_ustr_assign_cstr. */
t41(void)879 static void t41(void)
880 {
881 ALLEGRO_USTR *us1 = al_ustr_new("Моја лебдилица је пуна јегуља");
882 ALLEGRO_USTR *us2 = al_ustr_new("");
883
884 CHECK(al_ustr_assign_substr(us2, us1, 9, 27));
885 CHECK(0 == strcmp(al_cstr(us2), "лебдилица"));
886
887 /* Start > End */
888 CHECK(al_ustr_assign_substr(us2, us1, 9, 0));
889 CHECK(0 == strcmp(al_cstr(us2), ""));
890
891 /* Start, end out of bounds */
892 CHECK(al_ustr_assign_substr(us2, us1, -INT_MAX, INT_MAX));
893 CHECK(0 == strcmp(al_cstr(us2), "Моја лебдилица је пуна јегуља"));
894
895 al_ustr_free(us1);
896 al_ustr_free(us2);
897 }
898
899 /* Test al_ustr_set_chr. */
t42(void)900 static void t42(void)
901 {
902 ALLEGRO_USTR *us = al_ustr_new("abcdef");
903
904 /* Same size (ASCII). */
905 CHECK(al_ustr_set_chr(us, 1, 'B') == 1);
906 CHECK(0 == strcmp(al_cstr(us), "aBcdef"));
907 CHECK(6 == al_ustr_size(us));
908
909 /* Enlarge to 2-bytes. */
910 CHECK(al_ustr_set_chr(us, 1, U_beta) == 2);
911 CHECK(0 == strcmp(al_cstr(us), "aβcdef"));
912 CHECK(7 == al_ustr_size(us));
913
914 /* Enlarge to 3-bytes. */
915 CHECK(al_ustr_set_chr(us, 5, U_1d08) == 3);
916 CHECK(0 == strcmp(al_cstr(us), "aβcdᴈf"));
917 CHECK(9 == al_ustr_size(us));
918
919 /* Reduce to 2-bytes. */
920 CHECK(al_ustr_set_chr(us, 5, U_schwa) == 2);
921 CHECK(0 == strcmp(al_cstr(us), "aβcdəf"));
922 CHECK(8 == al_ustr_size(us));
923
924 /* Set at end of string. */
925 CHECK(al_ustr_set_chr(us, al_ustr_size(us), U_1ff7) == 3);
926 CHECK(0 == strcmp(al_cstr(us), "aβcdəfῷ"));
927 CHECK(11 == al_ustr_size(us));
928
929 /* Set past end of string. */
930 CHECK(al_ustr_set_chr(us, al_ustr_size(us) + 2, U_2051) == 3);
931 CHECK(0 == memcmp(al_cstr(us), "aβcdəfῷ\0\0⁑", 16));
932 CHECK(16 == al_ustr_size(us));
933
934 /* Set before start of string (not allowed). */
935 CHECK(al_ustr_set_chr(us, -1, U_2051) == 0);
936 CHECK(16 == al_ustr_size(us));
937
938 al_ustr_free(us);
939 }
940
941 /* Test al_ustr_remove_chr. */
t43(void)942 static void t43(void)
943 {
944 ALLEGRO_USTR *us = al_ustr_new("«aβῷ»");
945
946 CHECK(al_ustr_remove_chr(us, 2));
947 CHECK(0 == strcmp(al_cstr(us), "«βῷ»"));
948
949 CHECK(al_ustr_remove_chr(us, 2));
950 CHECK(0 == strcmp(al_cstr(us), "«ῷ»"));
951
952 CHECK(al_ustr_remove_chr(us, 2));
953 CHECK(0 == strcmp(al_cstr(us), "«»"));
954
955 /* Not at beginning of code point. */
956 CHECK(! al_ustr_remove_chr(us, 1));
957
958 /* Out of bounds. */
959 CHECK(! al_ustr_remove_chr(us, -1));
960 CHECK(! al_ustr_remove_chr(us, al_ustr_size(us)));
961
962 al_ustr_free(us);
963 }
964
965 /* Test al_ustr_replace_range. */
t44(void)966 static void t44(void)
967 {
968 ALLEGRO_USTR *us1 = al_ustr_new("Šis kungs par visu samaksās");
969 ALLEGRO_USTR *us2 = al_ustr_new("ī kundze");
970
971 CHECK(al_ustr_replace_range(us1, 2, 10, us2));
972 CHECK(0 == strcmp(al_cstr(us1), "Šī kundze par visu samaksās"));
973
974 /* Insert into itself. */
975 CHECK(al_ustr_replace_range(us1, 5, 11, us1));
976 CHECK(0 == strcmp(al_cstr(us1),
977 "Šī Šī kundze par visu samaksās par visu samaksās"));
978
979 al_ustr_free(us1);
980 al_ustr_free(us2);
981 }
982
983 /* Test al_ustr_replace_range (part 2). */
t45(void)984 static void t45(void)
985 {
986 ALLEGRO_USTR *us1 = al_ustr_new("abcdef");
987 ALLEGRO_USTR *us2 = al_ustr_new("ABCDEF");
988
989 /* Start1 < 0 [not allowed] */
990 CHECK(! al_ustr_replace_range(us1, -1, 1, us2));
991
992 /* Start1 > end(us1) [padded] */
993 CHECK(al_ustr_replace_range(us1, 8, 100, us2));
994 CHECK(0 == memcmp(al_cstr(us1), "abcdef\0\0ABCDEF", 15));
995
996 /* Start1 > end1 [not allowed] */
997 CHECK(! al_ustr_replace_range(us1, 8, 1, us2));
998 CHECK(0 == memcmp(al_cstr(us1), "abcdef\0\0ABCDEF", 15));
999
1000 al_ustr_free(us1);
1001 al_ustr_free(us2);
1002 }
1003
1004 extern bool call_vappendf(ALLEGRO_USTR *us, const char *fmt, ...);
1005
1006 /* Test al_ustr_newf, al_ustr_appendf, al_ustr_vappendf. */
t46(void)1007 static void t46(void)
1008 {
1009 ALLEGRO_USTR *us;
1010
1011 us = al_ustr_newf("%s %c %.2f %.02d", "hõljuk", 'c', ALLEGRO_PI, 42);
1012 CHECK(0 == strcmp(al_cstr(us), "hõljuk c 3.14 42"));
1013
1014 CHECK(al_ustr_appendf(us, " %s", "Luftchüssiboot"));
1015 CHECK(0 == strcmp(al_cstr(us), "hõljuk c 3.14 42 Luftchüssiboot"));
1016
1017 CHECK(call_vappendf(us, " %s", "χόβερκράφτ"));
1018 CHECK(0 == strcmp(al_cstr(us), "hõljuk c 3.14 42 Luftchüssiboot χόβερκράφτ"));
1019
1020 al_ustr_free(us);
1021
1022 us = al_ustr_new("");
1023 call_vappendf(us, "%s", "test");
1024 CHECK(0 == strcmp(al_cstr(us), "test"));
1025 al_ustr_free(us);
1026 }
1027
call_vappendf(ALLEGRO_USTR * us,const char * fmt,...)1028 bool call_vappendf(ALLEGRO_USTR *us, const char *fmt, ...)
1029 {
1030 va_list ap;
1031 bool rc;
1032
1033 va_start(ap, fmt);
1034 rc = al_ustr_vappendf(us, fmt, ap);
1035 va_end(ap);
1036 return rc;
1037 }
1038
1039 /* Test al_ustr_compare, al_ustr_ncompare. */
t47(void)1040 static void t47(void)
1041 {
1042 ALLEGRO_USTR_INFO i1;
1043 ALLEGRO_USTR_INFO i2;
1044
1045 CHECK(al_ustr_compare(
1046 al_ref_cstr(&i1, "Thú mỏ vịt"),
1047 al_ref_cstr(&i2, "Thú mỏ vịt")) == 0);
1048
1049 CHECK(al_ustr_compare(
1050 al_ref_cstr(&i1, "Thú mỏ vị"),
1051 al_ref_cstr(&i2, "Thú mỏ vịt")) < 0);
1052
1053 CHECK(al_ustr_compare(
1054 al_ref_cstr(&i1, "Thú mỏ vịt"),
1055 al_ref_cstr(&i2, "Thú mỏ vit")) > 0);
1056
1057 CHECK(al_ustr_compare(
1058 al_ref_cstr(&i1, "abc"),
1059 al_ref_cstr(&i2, "abc\001")) < 0);
1060
1061 CHECK(al_ustr_compare(
1062 al_ref_cstr(&i1, "abc\001"),
1063 al_ref_cstr(&i2, "abc")) > 0);
1064
1065 CHECK(al_ustr_ncompare(
1066 al_ref_cstr(&i1, "Thú mỏ vịt"),
1067 al_ref_cstr(&i2, "Thú mỏ vit"), 8) == 0);
1068
1069 CHECK(al_ustr_ncompare(
1070 al_ref_cstr(&i1, "Thú mỏ vịt"),
1071 al_ref_cstr(&i2, "Thú mỏ vit"), 9) > 0);
1072
1073 CHECK(al_ustr_ncompare(
1074 al_ref_cstr(&i1, "Thú mỏ vịt"),
1075 al_ref_cstr(&i2, "platypus"), 0) == 0);
1076
1077 CHECK(al_ustr_ncompare(
1078 al_ref_cstr(&i1, "abc"),
1079 al_ref_cstr(&i2, "abc\001"), 4) < 0);
1080
1081 CHECK(al_ustr_ncompare(
1082 al_ref_cstr(&i1, "abc\001"),
1083 al_ref_cstr(&i2, "abc"), 4) > 0);
1084
1085 }
1086
1087 /* Test al_ustr_has_prefix, al_ustr_has_suffix. */
t48(void)1088 static void t48(void)
1089 {
1090 ALLEGRO_USTR_INFO i1;
1091 const ALLEGRO_USTR *us1 = al_ref_cstr(&i1, "Thú mỏ vịt");
1092
1093 /* The _cstr versions are simple wrappers around the real functions so its
1094 * okay to test them only.
1095 */
1096
1097 CHECK(al_ustr_has_prefix_cstr(us1, ""));
1098 CHECK(al_ustr_has_prefix_cstr(us1, "Thú"));
1099 CHECK(! al_ustr_has_prefix_cstr(us1, "Thú mỏ vịt."));
1100
1101 CHECK(al_ustr_has_suffix_cstr(us1, ""));
1102 CHECK(al_ustr_has_suffix_cstr(us1, "vịt"));
1103 CHECK(! al_ustr_has_suffix_cstr(us1, "Thú mỏ vịt."));
1104 }
1105
1106 /* Test al_ustr_find_replace, al_ustr_find_replace_cstr. */
t49(void)1107 static void t49(void)
1108 {
1109 ALLEGRO_USTR *us;
1110 ALLEGRO_USTR_INFO findi;
1111 ALLEGRO_USTR_INFO repli;
1112 const ALLEGRO_USTR *find;
1113 const ALLEGRO_USTR *repl;
1114
1115 us = al_ustr_new("aábdðeéfghiíaábdðeéfghií");
1116 find = al_ref_cstr(&findi, "ðeéf");
1117 repl = al_ref_cstr(&repli, "deef");
1118
1119 CHECK(al_ustr_find_replace(us, 0, find, repl));
1120 CHECK(0 == strcmp(al_cstr(us), "aábddeefghiíaábddeefghií"));
1121
1122 find = al_ref_cstr(&findi, "aá");
1123 repl = al_ref_cstr(&repli, "AÁ");
1124
1125 CHECK(al_ustr_find_replace(us, 14, find, repl));
1126 CHECK(0 == strcmp(al_cstr(us), "aábddeefghiíAÁbddeefghií"));
1127
1128 CHECK(al_ustr_find_replace_cstr(us, 0, "dd", "đ"));
1129 CHECK(0 == strcmp(al_cstr(us), "aábđeefghiíAÁbđeefghií"));
1130
1131 /* Not allowed */
1132 find = al_ustr_empty_string();
1133 CHECK(! al_ustr_find_replace(us, 0, find, repl));
1134 CHECK(0 == strcmp(al_cstr(us), "aábđeefghiíAÁbđeefghií"));
1135
1136 al_ustr_free(us);
1137 }
1138
1139 /* Test UTF-16 conversion. */
t50(void)1140 static void t50(void)
1141 {
1142 ALLEGRO_USTR *us;
1143 char utf8[] = "⅛-note: , domino: ";
1144 uint16_t *utf16;
1145 size_t s;
1146 uint16_t little[8];
1147 /* Only native byte order supported right now, so have to specify
1148 * elements as uint16_t and not as char.
1149 */
1150 uint16_t utf16_ref[] = {
1151 0x215b, 0x002d, 0x006e, 0x006f, 0x0074,
1152 0x0065, 0x003a, 0x0020, 0xd834, 0xdd60,
1153 0x002c, 0x0020, 0x0064, 0x006f, 0x006d,
1154 0x0069, 0x006e, 0x006f, 0x003a, 0x0020,
1155 0xd83c, 0xdc61, 0x0000};
1156 uint16_t truncated[] = {
1157 0x215b, 0x002d, 0x006e, 0x006f, 0x0074,
1158 0x0065, 0x003a, 0x0000};
1159
1160 us = al_ustr_new_from_utf16(utf16_ref);
1161 CHECK(20 == al_ustr_length(us));
1162 CHECK(0 == strcmp(utf8, al_cstr(us)));
1163 al_ustr_free(us);
1164
1165 us = al_ustr_new(utf8);
1166 s = al_ustr_size_utf16(us);
1167 CHECK(46 == s);
1168 utf16 = malloc(s);
1169 al_ustr_encode_utf16(us, utf16, s);
1170 CHECK(0 == memcmp(utf16, utf16_ref, s));
1171 free(utf16);
1172
1173 s = al_ustr_encode_utf16(us, little, sizeof little);
1174 CHECK(16 == s);
1175 CHECK(0 == memcmp(truncated, little, s));
1176 al_ustr_free(us);
1177 }
1178
1179 /* Test al_ustr_to_buffer */
t51(void)1180 static void t51(void)
1181 {
1182 char str[256];
1183 const ALLEGRO_USTR *us;
1184 ALLEGRO_USTR_INFO info;
1185
1186 us = al_ref_buffer(&info, "Allegro", 3);
1187 al_ustr_to_buffer(us, str, 10);
1188 CHECK(0 == memcmp(str, "All", 4));
1189 al_ustr_to_buffer(us, str, 4);
1190 CHECK(0 == memcmp(str, "All", 4));
1191 al_ustr_to_buffer(us, str, 3);
1192 CHECK(0 == memcmp(str, "Al", 3));
1193 }
1194
1195 /*---------------------------------------------------------------------------*/
1196
1197 const test_t all_tests[] =
1198 {
1199 NULL, t1, t2, t3, t4, t5, t6, t7, t8, t9,
1200 t10, t11, t12, t13, t14, t15, t16, t17, t18, t19,
1201 t20, t21, t22, t23, t24, t25, t26, t27, t28, t29,
1202 t30, t31, t32, t33, t34, t35, t36, t37, t38, t39,
1203 t40, t41, t42, t43, t44, t45, t46, t47, t48, t49,
1204 t50, t51
1205 };
1206
1207 #define NUM_TESTS (int)(sizeof(all_tests) / sizeof(all_tests[0]))
1208
main(int argc,char ** argv)1209 int main(int argc, char **argv)
1210 {
1211 int i;
1212
1213 if (!al_init()) {
1214 abort_example("Could not init Allegro.\n");
1215 }
1216 open_log_monospace();
1217
1218 if (argc < 2) {
1219 for (i = 1; i < NUM_TESTS; i++) {
1220 log_printf("# t%d\n\n", i);
1221 all_tests[i]();
1222 log_printf("\n");
1223 }
1224 }
1225 else {
1226 i = atoi(argv[1]);
1227 if (i > 0 && i < NUM_TESTS) {
1228 all_tests[i]();
1229 }
1230 }
1231 log_printf("Done\n");
1232
1233 close_log(true);
1234
1235 if (error) {
1236 exit(EXIT_FAILURE);
1237 }
1238
1239 return 0;
1240 }
1241
1242 /* vim: set sts=3 sw=3 et: */
1243