1 | /* Test of the gettext functions. |
2 | Copyright (C) 2000-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 <libintl.h> |
20 | #include <locale.h> |
21 | #include <mcheck.h> |
22 | #include <stdio.h> |
23 | #include <stdlib.h> |
24 | #include <string.h> |
25 | #include <error.h> |
26 | #include <errno.h> |
27 | |
28 | |
29 | const struct |
30 | { |
31 | const char *msgid; |
32 | const char *msgstr; |
33 | } msgs[] = |
34 | { |
35 | #define INPUT(Str) { Str, |
36 | #define OUTPUT(Str) Str }, |
37 | #include TESTSTRS_H |
38 | }; |
39 | |
40 | const char *catname[] = |
41 | { |
42 | [LC_MESSAGES] = "LC_MESSAGES" , |
43 | [LC_TIME] = "LC_TIME" , |
44 | [LC_NUMERIC] = "LC_NUMERIC" |
45 | }; |
46 | |
47 | |
48 | static int positive_gettext_test (void); |
49 | static int negative_gettext_test (void); |
50 | static int positive_dgettext_test (const char *domain); |
51 | static int positive_dcgettext_test (const char *domain, int category); |
52 | static int negative_dcgettext_test (const char *domain, int category); |
53 | |
54 | |
55 | #define check_setlocale(cat, name) do { \ |
56 | if (setlocale (cat, name) == NULL) \ |
57 | { \ |
58 | printf ("%s:%u: setlocale (%s, \"%s\"): %m\n", \ |
59 | __FILE__, __LINE__, #cat, name); \ |
60 | result = 1; \ |
61 | } \ |
62 | } while (0) |
63 | |
64 | int |
65 | main (int argc, char *argv[]) |
66 | { |
67 | int result = 0; |
68 | |
69 | /* For debugging. */ |
70 | mtrace (); |
71 | |
72 | /* This is the place where the .mo files are placed. */ |
73 | if (argc > 1) |
74 | { |
75 | bindtextdomain (domainname: "existing-domain" , dirname: argv[1]); |
76 | bindtextdomain (domainname: "existing-time-domain" , dirname: argv[1]); |
77 | bindtextdomain (domainname: "non-existing-domain" , dirname: argv[1]); |
78 | } |
79 | |
80 | /* The locale the catalog is created for is "existing-category". Now |
81 | set the various variables in question to this value and run the |
82 | test. */ |
83 | setenv (name: "LANGUAGE" , value: "existing-locale" , replace: 1); |
84 | setenv (name: "LC_ALL" , value: "non-existing-locale" , replace: 1); |
85 | setenv (name: "LC_MESSAGES" , value: "non-existing-locale" , replace: 1); |
86 | setenv (name: "LC_CTYPE" , value: "non-existing-locale" , replace: 1); |
87 | setenv (name: "LANG" , value: "non-existing-locale" , replace: 1); |
88 | check_setlocale (LC_CTYPE, "de_DE.UTF-8" ); |
89 | check_setlocale (LC_MESSAGES, "de_DE.UTF-8" ); |
90 | unsetenv (name: "OUTPUT_CHARSET" ); |
91 | /* This is the name of the existing domain with a catalog for the |
92 | LC_MESSAGES category. */ |
93 | textdomain (domainname: "existing-domain" ); |
94 | puts (s: "test `gettext' with LANGUAGE set" ); |
95 | if (positive_gettext_test () != 0) |
96 | { |
97 | puts (s: "FAILED" ); |
98 | result = 1; |
99 | } |
100 | /* This is the name of a non-existing domain with a catalog for the |
101 | LC_MESSAGES category. We leave this value set for the `dgettext' |
102 | and `dcgettext' tests. */ |
103 | textdomain (domainname: "non-existing-domain" ); |
104 | puts (s: "test `gettext' with LANGUAGE set" ); |
105 | if (negative_gettext_test () != 0) |
106 | { |
107 | puts (s: "FAILED" ); |
108 | result = 1; |
109 | } |
110 | puts (s: "test `dgettext' with LANGUAGE set" ); |
111 | if (positive_dgettext_test (domain: "existing-domain" ) != 0) |
112 | { |
113 | puts (s: "FAILED" ); |
114 | result = 1; |
115 | } |
116 | |
117 | /* Now the same tests with LC_ALL deciding. */ |
118 | unsetenv (name: "LANGUAGE" ); |
119 | setenv (name: "LC_ALL" , value: "existing-locale" , replace: 1); |
120 | check_setlocale (LC_ALL, "" ); |
121 | puts (s: "test `gettext' with LC_ALL set" ); |
122 | /* This is the name of the existing domain with a catalog for the |
123 | LC_MESSAGES category. */ |
124 | textdomain (domainname: "existing-domain" ); |
125 | if (positive_gettext_test () != 0) |
126 | { |
127 | puts (s: "FAILED" ); |
128 | result = 1; |
129 | } |
130 | /* This is the name of a non-existing domain with a catalog for the |
131 | LC_MESSAGES category. We leave this value set for the `dgettext' |
132 | and `dcgettext' tests. */ |
133 | textdomain (domainname: "non-existing-domain" ); |
134 | puts (s: "test `gettext' with LC_ALL deciding" ); |
135 | if (negative_gettext_test () != 0) |
136 | { |
137 | puts (s: "FAILED" ); |
138 | result = 1; |
139 | } |
140 | puts (s: "test `dgettext' with LC_ALL deciding" ); |
141 | if (positive_dgettext_test (domain: "existing-domain" ) != 0) |
142 | { |
143 | puts (s: "FAILED" ); |
144 | result = 1; |
145 | } |
146 | |
147 | /* Now the same tests with LC_MESSAGES deciding. */ |
148 | unsetenv (name: "LC_ALL" ); |
149 | setenv (name: "LC_MESSAGES" , value: "existing-locale" , replace: 1); |
150 | check_setlocale (LC_MESSAGES, "" ); |
151 | setenv (name: "LC_TIME" , value: "existing-locale" , replace: 1); |
152 | check_setlocale (LC_TIME, "" ); |
153 | setenv (name: "LC_NUMERIC" , value: "non-existing-locale" , replace: 1); |
154 | char *what = setlocale (LC_NUMERIC, "" ); |
155 | if (what != NULL) |
156 | { |
157 | printf (format: "setlocale succeeded (%s), expected failure\n" , what); |
158 | result = 1; |
159 | } |
160 | |
161 | puts (s: "test `gettext' with LC_MESSAGES set" ); |
162 | /* This is the name of the existing domain with a catalog for the |
163 | LC_MESSAGES category. */ |
164 | textdomain (domainname: "existing-domain" ); |
165 | if (positive_gettext_test () != 0) |
166 | { |
167 | puts (s: "FAILED" ); |
168 | result = 1; |
169 | } |
170 | /* This is the name of a non-existing domain with a catalog for the |
171 | LC_MESSAGES category. We leave this value set for the `dgettext' |
172 | and `dcgettext' tests. */ |
173 | textdomain (domainname: "non-existing-domain" ); |
174 | puts (s: "test `gettext' with LC_MESSAGES deciding" ); |
175 | if (negative_gettext_test () != 0) |
176 | { |
177 | puts (s: "FAILED" ); |
178 | result = 1; |
179 | } |
180 | puts (s: "test `dgettext' with LC_MESSAGES deciding" ); |
181 | if (positive_dgettext_test (domain: "existing-domain" ) != 0) |
182 | { |
183 | puts (s: "FAILED" ); |
184 | result = 1; |
185 | } |
186 | puts (s: "test `dcgettext' with category == LC_MESSAGES" ); |
187 | if (positive_dcgettext_test (domain: "existing-domain" , LC_MESSAGES) != 0) |
188 | { |
189 | puts (s: "FAILED" ); |
190 | result = 1; |
191 | } |
192 | /* Try a different category. For this we also switch the domain. */ |
193 | puts (s: "test `dcgettext' with LANGUAGE == LC_TIME" ); |
194 | if (positive_dcgettext_test (domain: "existing-time-domain" , LC_TIME) != 0) |
195 | { |
196 | puts (s: "FAILED" ); |
197 | result = 1; |
198 | } |
199 | /* This time use a category for which there is no catalog. */ |
200 | puts (s: "test `dcgettext' with LANGUAGE == LC_NUMERIC" ); |
201 | if (negative_dcgettext_test (domain: "existing-domain" , LC_NUMERIC) != 0) |
202 | { |
203 | puts (s: "FAILED" ); |
204 | result = 1; |
205 | } |
206 | |
207 | /* Now the same tests with LANG deciding. */ |
208 | unsetenv (name: "LC_MESSAGES" ); |
209 | unsetenv (name: "LC_CTYPE" ); |
210 | unsetenv (name: "LC_TIME" ); |
211 | unsetenv (name: "LC_NUMERIC" ); |
212 | setenv (name: "LANG" , value: "existing-locale" , replace: 1); |
213 | check_setlocale (LC_ALL, "" ); |
214 | /* This is the name of the existing domain with a catalog for the |
215 | LC_MESSAGES category. */ |
216 | textdomain (domainname: "existing-domain" ); |
217 | puts (s: "test `gettext' with LANG set" ); |
218 | if (positive_gettext_test () != 0) |
219 | { |
220 | puts (s: "FAILED" ); |
221 | result = 1; |
222 | } |
223 | /* This is the name of a non-existing domain with a catalog for the |
224 | LC_MESSAGES category. We leave this value set for the `dgettext' |
225 | and `dcgettext' tests. */ |
226 | textdomain (domainname: "non-existing-domain" ); |
227 | puts (s: "test `gettext' with LANG set" ); |
228 | if (negative_gettext_test () != 0) |
229 | { |
230 | puts (s: "FAILED" ); |
231 | result = 1; |
232 | } |
233 | puts (s: "test `dgettext' with LANG set" ); |
234 | if (positive_dgettext_test (domain: "existing-domain" ) != 0) |
235 | { |
236 | puts (s: "FAILED" ); |
237 | result = 1; |
238 | } |
239 | |
240 | check_setlocale (LC_ALL, "C" ); |
241 | |
242 | return result; |
243 | } |
244 | |
245 | |
246 | static int |
247 | positive_gettext_test (void) |
248 | { |
249 | size_t cnt; |
250 | int result = 0; |
251 | |
252 | for (cnt = 0; cnt < sizeof (msgs) / sizeof (msgs[0]); ++cnt) |
253 | { |
254 | const char *found = gettext (msgs[cnt].msgid); |
255 | |
256 | if (found == NULL |
257 | || (msgs[cnt].msgstr[0] != '\0' |
258 | && strcmp (found, msgs[cnt].msgstr) != 0)) |
259 | { |
260 | /* Oops, shouldn't happen. */ |
261 | printf (format: "\ |
262 | gettext (\"%s\") failed, returned \"%s\", expected \"%s\"\n" , |
263 | msgs[cnt].msgid, found, msgs[cnt].msgstr); |
264 | result = 1; |
265 | } |
266 | } |
267 | |
268 | return result; |
269 | } |
270 | |
271 | |
272 | static int |
273 | negative_gettext_test (void) |
274 | { |
275 | size_t cnt; |
276 | int result = 0; |
277 | |
278 | for (cnt = 0; cnt < sizeof (msgs) / sizeof (msgs[0]); ++cnt) |
279 | { |
280 | const char *found = gettext (msgs[cnt].msgid); |
281 | |
282 | if (found != msgs[cnt].msgid) |
283 | { |
284 | /* Oops, shouldn't happen. */ |
285 | printf (format: " gettext (\"%s\") failed\n" , msgs[cnt].msgid); |
286 | result = 1; |
287 | } |
288 | } |
289 | |
290 | return result; |
291 | } |
292 | |
293 | |
294 | static int |
295 | positive_dgettext_test (const char *domain) |
296 | { |
297 | size_t cnt; |
298 | int result = 0; |
299 | |
300 | for (cnt = 0; cnt < sizeof (msgs) / sizeof (msgs[0]); ++cnt) |
301 | { |
302 | const char *found = dgettext (domain, msgs[cnt].msgid); |
303 | |
304 | if (found == NULL |
305 | || (msgs[cnt].msgstr[0] != '\0' |
306 | && strcmp (found, msgs[cnt].msgstr) != 0)) |
307 | { |
308 | /* Oops, shouldn't happen. */ |
309 | printf (format: "\ |
310 | dgettext (\"%s\", \"%s\") failed, returned \"%s\", expected \"%s\"\n" , |
311 | domain, msgs[cnt].msgid, found, msgs[cnt].msgstr); |
312 | result = 1; |
313 | } |
314 | } |
315 | |
316 | return result; |
317 | } |
318 | |
319 | |
320 | static int |
321 | positive_dcgettext_test (const char *domain, int category) |
322 | { |
323 | size_t cnt; |
324 | int result = 0; |
325 | |
326 | for (cnt = 0; cnt < sizeof (msgs) / sizeof (msgs[0]); ++cnt) |
327 | { |
328 | const char *found = dcgettext (domainname: domain, msgid: msgs[cnt].msgid, category: category); |
329 | |
330 | if (found == NULL |
331 | || (msgs[cnt].msgstr[0] != '\0' |
332 | && strcmp (found, msgs[cnt].msgstr) != 0)) |
333 | { |
334 | /* Oops, shouldn't happen. */ |
335 | printf (format: "\ |
336 | dcgettext (\"%s\", \"%s\", %s) failed, returned \"%s\", expected \"%s\"\n" , |
337 | domain, msgs[cnt].msgid, catname[category], found, |
338 | msgs[cnt].msgstr); |
339 | result = 1; |
340 | } |
341 | } |
342 | |
343 | return result; |
344 | } |
345 | |
346 | |
347 | static int |
348 | negative_dcgettext_test (const char *domain, int category) |
349 | { |
350 | size_t cnt; |
351 | int result = 0; |
352 | |
353 | for (cnt = 0; cnt < sizeof (msgs) / sizeof (msgs[0]); ++cnt) |
354 | { |
355 | const char *found = dcgettext (domainname: domain, msgid: msgs[cnt].msgid, category: category); |
356 | |
357 | if (found != msgs[cnt].msgid) |
358 | { |
359 | /* Oops, shouldn't happen. */ |
360 | printf (format: " dcgettext (\"%s\", \"%s\", %s) failed\n" , |
361 | domain, msgs[cnt].msgid, catname[category]); |
362 | result = 1; |
363 | } |
364 | } |
365 | |
366 | return result; |
367 | } |
368 | |