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 2014 Garrett D'Amore <garrett@damore.org>
14 */
15
16 /*
17 * This program tests that newlocale and uselocale work properly in
18 * multi-threaded programs. In order for it to work, it requires that
19 * some additional locales be installed.
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <locale.h>
26 #include <libintl.h>
27 #include <langinfo.h>
28 #include <nl_types.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include "test_common.h"
33
34 /*
35 * Note that on some platforms, different symbols are used. For example,
36 * MacOS Mavericks uses "Eu" for Euro symbol, instead of €. If the locale
37 * data changes, then this program will need to update to reflect that.
38 *
39 * Note also that this file is easiest edited with a UTF-8 capable editor,
40 * as there are embedded UTF-8 symbols in some of the strings.
41 */
42 struct langinfo_test {
43 nl_item param;
44 const char *value;
45 };
46
47 struct langinfo_test C_data[] = {
48 { CODESET, "646" },
49 { D_T_FMT, "%a %b %e %H:%M:%S %Y" },
50 { D_FMT, "%m/%d/%y" },
51 { T_FMT, "%H:%M:%S" },
52 { T_FMT_AMPM, "%I:%M:%S %p" },
53 { AM_STR, "AM" },
54 { PM_STR, "PM" },
55 { ERA, "" },
56 { ERA_D_FMT, "" },
57 { ERA_D_T_FMT, "" },
58 { ERA_T_FMT, "" },
59 { DAY_1, "Sunday" },
60 { DAY_7, "Saturday" },
61 { ABDAY_1, "Sun" },
62 { ABDAY_7, "Sat" },
63 { MON_1, "January" },
64 { MON_12, "December" },
65 { ABMON_1, "Jan" },
66 { ABMON_12, "Dec" },
67 { RADIXCHAR, "." },
68 { THOUSEP, "" },
69 { YESSTR, "yes" },
70 { NOSTR, "no" },
71 { YESEXPR, "^[yY]" },
72 { NOEXPR, "^[nN]" },
73 { CRNCYSTR, "" },
74 { -1, NULL }
75 };
76
77 struct langinfo_test en_us_utf8_data[] = {
78 { CODESET, "UTF-8" },
79 { D_T_FMT, "%B %e, %Y at %I:%M:%S %p %Z" },
80 { D_FMT, "%m/%d/%y" },
81 { T_FMT, "%I:%M:%S %p" },
82 { T_FMT_AMPM, "%I:%M:%S %p" },
83 { AM_STR, "AM" },
84 { PM_STR, "PM" },
85 { ERA, "" },
86 { ERA_D_FMT, "" },
87 { ERA_D_T_FMT, "" },
88 { ERA_T_FMT, "" },
89 { DAY_1, "Sunday" },
90 { DAY_7, "Saturday" },
91 { ABDAY_1, "Sun" },
92 { ABDAY_7, "Sat" },
93 { MON_1, "January" },
94 { MON_12, "December" },
95 { ABMON_1, "Jan" },
96 { ABMON_12, "Dec" },
97 { RADIXCHAR, "." },
98 { THOUSEP, "," },
99 { YESSTR, "yes" },
100 { NOSTR, "no" },
101 { YESEXPR, "^(([yY]([eE][sS])?)|([yY]))" },
102 { NOEXPR, "^(([nN]([oO])?)|([nN]))" },
103 { CRNCYSTR, "-$" },
104 { -1, NULL }
105 };
106
107 struct langinfo_test en_gb_latin15_data[] = {
108 { CODESET, "ISO8859-15" },
109 { D_T_FMT, "%e %B %Y at %H:%M:%S %Z" },
110 { D_FMT, "%d/%m/%Y" },
111 { T_FMT, "%H:%M:%S" },
112 { T_FMT_AMPM, "%I:%M:%S %p" },
113 { AM_STR, "am" },
114 { PM_STR, "pm" },
115 { ERA, "" },
116 { ERA_D_FMT, "" },
117 { ERA_D_T_FMT, "" },
118 { ERA_T_FMT, "" },
119 { DAY_1, "Sunday" },
120 { DAY_7, "Saturday" },
121 { ABDAY_1, "Sun" },
122 { ABDAY_7, "Sat" },
123 { MON_1, "January" },
124 { MON_12, "December" },
125 { ABMON_1, "Jan" },
126 { ABMON_12, "Dec" },
127 { RADIXCHAR, "." },
128 { THOUSEP, "," },
129 { YESSTR, "yes" },
130 { NOSTR, "no" },
131 { YESEXPR, "^(([yY]([eE][sS])?)|([yY]))" },
132 { NOEXPR, "^(([nN]([oO])?)|([nN]))" },
133 { CRNCYSTR, "-\243" },
134 { -1, NULL }
135 };
136
137 struct langinfo_test ru_ru_utf8_data[] = {
138 { CODESET, "UTF-8" },
139 { D_T_FMT, "%e %B %Y г., %H:%M:%S %Z"},
140 { D_FMT, "%d.%m.%Y" },
141 { T_FMT, "%H:%M:%S" },
142 { T_FMT_AMPM, "%I:%M:%S %p" },
143 { AM_STR, "ДП" },
144 { PM_STR, "ПП" },
145 { ERA, "" },
146 { ERA_D_FMT, "" },
147 { ERA_D_T_FMT, "" },
148 { ERA_T_FMT, "" },
149 { DAY_1, "воскресенье" },
150 { DAY_7, "суббота" },
151 { ABDAY_1, "вс" },
152 { ABDAY_7, "сб" },
153 { MON_1, "января" },
154 { MON_12, "декабря" },
155 { ABMON_1, "янв." },
156 { ABMON_12, "дек." },
157 { RADIXCHAR, "," },
158 { THOUSEP, " " },
159 { YESSTR, "да" },
160 { NOSTR, "нет" },
161 { YESEXPR, "^(([дД]([аА])?)|([дД])|([yY]([eE][sS])?)|([yY]))" },
162 { NOEXPR, "^(([нН]([еЕ][тТ])?)|([нН])|([nN]([oO])?)|([nN]))" },
163 { CRNCYSTR, "+₽" },
164 { -1, NULL }
165 };
166
167 struct {
168 const char *locale;
169 struct langinfo_test *loctest;
170 } locales[] = {
171 { "C", C_data },
172 { "en_US.UTF-8", en_us_utf8_data },
173 { "en_GB.ISO8859-15", en_gb_latin15_data },
174 { "ru_RU.UTF-8", ru_ru_utf8_data },
175 { NULL, NULL }
176 };
177
178 void
test_nl_langinfo_1(const char * locale,struct langinfo_test * test)179 test_nl_langinfo_1(const char *locale, struct langinfo_test *test)
180 {
181 char tname[128];
182 char *v;
183 test_t t;
184
185 (void) snprintf(tname, sizeof (tname), "nl_langinfo (locale %s)",
186 locale);
187 t = test_start(tname);
188
189 v = setlocale(LC_ALL, locale);
190 if (v == NULL) {
191 test_failed(t, "setlocale failed: %s", strerror(errno));
192 }
193 if (strcmp(v, locale) != 0) {
194 test_failed(t, "setlocale got %s instead of %s", v, locale);
195 }
196
197 for (int i = 0; test[i].value != NULL; i++) {
198 v = nl_langinfo(test[i].param);
199 test_debugf(t, "%d: expect [%s], got [%s]",
200 test[i].param, test[i].value, v);
201 if (strcmp(v, test[i].value) != 0) {
202 test_failed(t,
203 "param %d wrong, expected [%s], got [%s]",
204 test[i].param, test[i].value, v);
205 }
206 }
207 test_passed(t);
208 }
209
210 void
test_nl_langinfo_l(const char * locale,struct langinfo_test * test)211 test_nl_langinfo_l(const char *locale, struct langinfo_test *test)
212 {
213 char tname[128];
214 char *v;
215 test_t t;
216 locale_t loc;
217
218 (void) snprintf(tname, sizeof (tname), "nl_langinfo_l (locale %s)",
219 locale);
220 t = test_start(tname);
221
222 v = setlocale(LC_ALL, "C");
223 if (v == NULL) {
224 test_failed(t, "setlocale failed: %s", strerror(errno));
225 }
226 if (strcmp(v, "C") != 0) {
227 test_failed(t, "setlocale got %s instead of %s", v, "C");
228 }
229
230 loc = newlocale(LC_ALL_MASK, locale, NULL);
231 if (loc == NULL) {
232 test_failed(t, "newlocale failed: %s", strerror(errno));
233 }
234
235 for (int i = 0; test[i].value != NULL; i++) {
236 v = nl_langinfo_l(test[i].param, loc);
237 test_debugf(t, "%d: expect [%s], got [%s]",
238 test[i].param, test[i].value, v);
239 if (strcmp(v, test[i].value) != 0) {
240 test_failed(t,
241 "param %d wrong, expected [%s], got [%s]",
242 test[i].param, test[i].value, v);
243 }
244 }
245 test_passed(t);
246 }
247 void
test_nl_langinfo(void)248 test_nl_langinfo(void)
249 {
250 for (int i = 0; locales[i].locale != NULL; i++) {
251 test_nl_langinfo_1(locales[i].locale, locales[i].loctest);
252 test_nl_langinfo_l(locales[i].locale, locales[i].loctest);
253 }
254 }
255
256 int
main(int argc,char ** argv)257 main(int argc, char **argv)
258 {
259 int optc;
260
261 while ((optc = getopt(argc, argv, "df")) != EOF) {
262 switch (optc) {
263 case 'd':
264 test_set_debug();
265 break;
266 case 'f':
267 test_set_force();
268 break;
269 default:
270 (void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]);
271 exit(1);
272 }
273 }
274
275 test_nl_langinfo();
276
277 exit(0);
278 }
279