1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2025 Bill Sommerfeld
14 */
15
16 /*
17 * Tests for localeconv(3C) and localeconv_l(3C). The libc tests depends on
18 * locale/ar, locale/de, locale/en, and locale/ja. We limit ourselves to
19 * these locales, plus C.UTF-8.
20 */
21
22 #include <err.h>
23 #include <stdlib.h>
24 #include <xlocale.h>
25 #include <locale.h>
26 #include <sys/sysmacros.h>
27 #include <sys/debug.h>
28 #include <stdbool.h>
29 #include <string.h>
30
31
32 static struct test_locale {
33 const char *name;
34 locale_t loc;
35 struct lconv lconv;
36 } locales[] = {
37 { "C.UTF-8"},
38 { "ja_JP.UTF-8" },
39 { "de_DE.UTF-8" },
40 { "en_US.UTF-8" },
41 { "en_GB.UTF-8" },
42 };
43
44 static bool
compare_lconv(const char * name,const struct lconv * a,const struct lconv * b)45 compare_lconv(const char *name, const struct lconv *a, const struct lconv *b)
46 {
47 bool all_match = true;
48
49 #define FAIL(field, fmt) { warnx("TEST FAILED: %s %s mismatched" \
50 " (" fmt " vs " fmt ")", \
51 name, #field, a->field, b->field); all_match = false; }
52
53 #define COMPARE_INT(field) if (a->field != b->field) FAIL(field, "%d")
54 #define COMPARE_STR(field) if (strcmp(a->field, b->field)) FAIL(field, "'%s'")
55 /* grouping encodes an array of int8_t's; punt on printing them */
56 #define COMPARE_GRP(field) if (strcmp(a->field, b->field)) FAIL(field, "%p")
57
58 COMPARE_STR(decimal_point);
59 COMPARE_STR(thousands_sep);
60 COMPARE_GRP(grouping);
61 COMPARE_STR(int_curr_symbol);
62 COMPARE_STR(currency_symbol);
63 COMPARE_STR(mon_decimal_point);
64 COMPARE_STR(mon_thousands_sep);
65 COMPARE_GRP(mon_grouping);
66 COMPARE_STR(positive_sign);
67 COMPARE_STR(negative_sign);
68
69 COMPARE_INT(int_frac_digits);
70 COMPARE_INT(frac_digits);
71 COMPARE_INT(p_cs_precedes);
72 COMPARE_INT(p_sep_by_space);
73 COMPARE_INT(n_cs_precedes);
74 COMPARE_INT(n_sep_by_space);
75 COMPARE_INT(p_sign_posn);
76 COMPARE_INT(n_sign_posn);
77
78 COMPARE_INT(int_p_cs_precedes);
79 COMPARE_INT(int_p_sep_by_space);
80 COMPARE_INT(int_n_cs_precedes);
81 COMPARE_INT(int_n_sep_by_space);
82 COMPARE_INT(int_p_sign_posn);
83 COMPARE_INT(int_n_sign_posn);
84
85 return (all_match);
86 }
87 int
main(void)88 main(void)
89 {
90 int ret = EXIT_SUCCESS;
91
92 for (size_t i = 0; i < ARRAY_SIZE(locales); i++) {
93 locales[i].loc = newlocale(LC_ALL_MASK, locales[i].name, NULL);
94 if (locales[i].loc == NULL) {
95 err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
96 "construct locale %s", locales[i].name);
97 }
98
99 if (uselocale(locales[i].loc) == NULL) {
100 err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
101 "set locale %s", locales[i].name);
102 }
103
104 locales[i].lconv = *localeconv();
105 }
106 for (size_t i = 0; i < ARRAY_SIZE(locales); i++) {
107 if (!compare_lconv(locales[i].name,
108 localeconv_l(locales[i].loc),
109 &locales[i].lconv)) {
110 ret = EXIT_FAILURE;
111 }
112 }
113
114 if (ret == EXIT_SUCCESS) {
115 (void) printf("All tests completed successfully\n");
116 }
117
118 return (ret);
119 }
120