localename: more tests
[gnulib.git] / tests / test-localename.c
1 /* Test of gl_locale_name function and its variants.
2    Copyright (C) 2007-2009 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
18
19 #include <config.h>
20
21 #include "localename.h"
22
23 #include <locale.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #define SIZEOF(array) (sizeof (array) / sizeof (array[0]))
29 #define ASSERT(expr) \
30   do                                                                         \
31     {                                                                        \
32       if (!(expr))                                                           \
33         {                                                                    \
34           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
35           fflush (stderr);                                                   \
36           abort ();                                                          \
37         }                                                                    \
38     }                                                                        \
39   while (0)
40
41 static struct { int cat; int mask; const char *string; } const categories[] =
42   {
43       { LC_CTYPE,          LC_CTYPE_MASK },
44       { LC_NUMERIC,        LC_NUMERIC_MASK },
45       { LC_TIME,           LC_TIME_MASK },
46       { LC_COLLATE,        LC_COLLATE_MASK },
47       { LC_MONETARY,       LC_MONETARY_MASK },
48       { LC_MESSAGES,       LC_MESSAGES_MASK }
49 # ifdef LC_PAPER
50     , { LC_PAPER,          LC_PAPER_MASK }
51 # endif
52 # ifdef LC_NAME
53     , { LC_NAME,           LC_NAME_MASK }
54 # endif
55 # ifdef LC_ADDRESS
56     , { LC_ADDRESS,        LC_ADDRESS_MASK }
57 # endif
58 # ifdef LC_TELEPHONE
59     , { LC_TELEPHONE,      LC_TELEPHONE_MASK }
60 # endif
61 # ifdef LC_MEASUREMENT
62     , { LC_MEASUREMENT,    LC_MEASUREMENT_MASK }
63 # endif
64 # ifdef LC_IDENTIFICATION
65     , { LC_IDENTIFICATION, LC_IDENTIFICATION_MASK }
66 # endif
67   };
68
69 /* Test the gl_locale_name() function.  */
70 static void
71 test_locale_name (void)
72 {
73   const char *name;
74
75   /* Check that gl_locale_name returns non-NULL.  */
76   ASSERT (gl_locale_name (LC_MESSAGES, "LC_MESSAGES") != NULL);
77
78   /* Get into a defined state,  */
79   setlocale (LC_ALL, "en_US.UTF-8");
80 #if HAVE_NEWLOCALE
81   uselocale (LC_GLOBAL_LOCALE);
82 #endif
83
84   /* Check that when all environment variables are unset,
85      gl_locale_name returns the default locale.  */
86   unsetenv ("LC_ALL");
87   unsetenv ("LC_CTYPE");
88   unsetenv ("LC_MESSAGES");
89   unsetenv ("LC_NUMERIC");
90   unsetenv ("LANG");
91   setlocale (LC_ALL, "");
92   ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"),
93                   gl_locale_name_default ()) == 0);
94   ASSERT (strcmp (gl_locale_name (LC_NUMERIC, "LC_NUMERIC"),
95                   gl_locale_name_default ()) == 0);
96
97   /* Check that an empty environment variable is treated like an unset
98      environment variable.  */
99
100   setenv ("LC_ALL", "", 1);
101   unsetenv ("LC_CTYPE");
102   unsetenv ("LC_MESSAGES");
103   unsetenv ("LANG");
104   setlocale (LC_ALL, "");
105   ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"),
106                   gl_locale_name_default ()) == 0);
107
108   unsetenv ("LC_ALL");
109   setenv ("LC_CTYPE", "", 1);
110   unsetenv ("LC_MESSAGES");
111   unsetenv ("LANG");
112   setlocale (LC_ALL, "");
113   ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"),
114                   gl_locale_name_default ()) == 0);
115
116   unsetenv ("LC_ALL");
117   unsetenv ("LC_CTYPE");
118   setenv ("LC_MESSAGES", "", 1);
119   unsetenv ("LANG");
120   setlocale (LC_ALL, "");
121   ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"),
122                   gl_locale_name_default ()) == 0);
123
124   unsetenv ("LC_ALL");
125   unsetenv ("LC_CTYPE");
126   unsetenv ("LC_MESSAGES");
127   setenv ("LANG", "", 1);
128   setlocale (LC_ALL, "");
129   ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"),
130                   gl_locale_name_default ()) == 0);
131
132   /* Check that LC_ALL overrides the others, and LANG is overridden by the
133      others.  */
134
135   setenv ("LC_ALL", "C", 1);
136   unsetenv ("LC_CTYPE");
137   unsetenv ("LC_MESSAGES");
138   unsetenv ("LANG");
139   setlocale (LC_ALL, "");
140   ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), "C") == 0);
141
142   unsetenv ("LC_ALL");
143   setenv ("LC_CTYPE", "C", 1);
144   setenv ("LC_MESSAGES", "C", 1);
145   unsetenv ("LANG");
146   setlocale (LC_ALL, "");
147   ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), "C") == 0);
148
149   unsetenv ("LC_ALL");
150   unsetenv ("LC_CTYPE");
151   unsetenv ("LC_MESSAGES");
152   setenv ("LANG", "C", 1);
153   setlocale (LC_ALL, "");
154   ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), "C") == 0);
155
156   /* Check mixed situations.  */
157
158   unsetenv ("LC_ALL");
159   unsetenv ("LC_CTYPE");
160   setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
161   setenv ("LANG", "de_DE.UTF-8", 1);
162   if (setlocale (LC_ALL, "") != NULL)
163     {
164       name = gl_locale_name (LC_CTYPE, "LC_CTYPE");
165       ASSERT (strcmp (name, "de_DE.UTF-8") == 0);
166       name = gl_locale_name (LC_MESSAGES, "LC_MESSAGES");
167       ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
168     }
169
170   unsetenv ("LC_ALL");
171   unsetenv ("LC_CTYPE");
172   setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
173   unsetenv ("LANG");
174   if (setlocale (LC_ALL, "") != NULL)
175     {
176       name = gl_locale_name (LC_CTYPE, "LC_CTYPE");
177       ASSERT (strcmp (name, gl_locale_name_default ()) == 0);
178       name = gl_locale_name (LC_MESSAGES, "LC_MESSAGES");
179       ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
180     }
181
182 #if HAVE_NEWLOCALE
183   /* Check that gl_locale_name considers the thread locale.  */
184   {
185     locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
186     if (locale != NULL)
187       {
188         uselocale (locale);
189         name = gl_locale_name (LC_CTYPE, "LC_CTYPE");
190         ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
191         name = gl_locale_name (LC_MESSAGES, "LC_MESSAGES");
192         ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
193       }
194   }
195
196   /* Check that gl_locale_name distinguishes different categories of the
197      thread locale, and that the name is the right one for each.  */
198   {
199     unsigned int i;
200
201     for (i = 0; i < SIZEOF (categories); i++)
202       {
203         int category_mask = categories[i].mask;
204         locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
205         if (locale != NULL)
206           {
207             locale = newlocale (category_mask, "de_DE.UTF-8", locale);
208             if (locale != NULL)
209               {
210                 unsigned int j;
211
212                 uselocale (locale);
213                 for (j = 0; j < SIZEOF (categories); j++)
214                   {
215                     const char *name_j =
216                       gl_locale_name (categories[j].cat, categories[j].string);
217                     if (j == i)
218                       ASSERT (strcmp (name_j, "de_DE.UTF-8") == 0);
219                     else
220                       ASSERT (strcmp (name_j, "fr_FR.UTF-8") == 0);
221                   }
222               }
223           }
224       }
225   }
226 #endif
227 }
228
229 /* Test the gl_locale_name_thread() function.  */
230 static void
231 test_locale_name_thread (void)
232 {
233   /* Get into a defined state,  */
234   setlocale (LC_ALL, "en_US.UTF-8");
235
236 #if HAVE_NEWLOCALE
237   /* Check that gl_locale_name_thread returns NULL when no thread locale is
238      set.  */
239   uselocale (LC_GLOBAL_LOCALE);
240   ASSERT (gl_locale_name_thread (LC_CTYPE, "LC_CTYPE") == NULL);
241   ASSERT (gl_locale_name_thread (LC_MESSAGES, "LC_MESSAGES") == NULL);
242
243   /* Check that gl_locale_name_thread considers the thread locale.  */
244   {
245     locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
246     if (locale != NULL)
247       {
248         const char *name;
249
250         uselocale (locale);
251         name = gl_locale_name_thread (LC_CTYPE, "LC_CTYPE");
252         ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
253         name = gl_locale_name_thread (LC_MESSAGES, "LC_MESSAGES");
254         ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
255       }
256   }
257
258   /* Check that gl_locale_name_thread distinguishes different categories of the
259      thread locale, and that the name is the right one for each.  */
260   {
261     unsigned int i;
262
263     for (i = 0; i < SIZEOF (categories); i++)
264       {
265         int category_mask = categories[i].mask;
266         locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
267         if (locale != NULL)
268           {
269             locale = newlocale (category_mask, "de_DE.UTF-8", locale);
270             if (locale != NULL)
271               {
272                 unsigned int j;
273
274                 uselocale (locale);
275                 for (j = 0; j < SIZEOF (categories); j++)
276                   {
277                     const char *name_j =
278                       gl_locale_name_thread (categories[j].cat,
279                                              categories[j].string);
280                     if (j == i)
281                       ASSERT (strcmp (name_j, "de_DE.UTF-8") == 0);
282                     else
283                       ASSERT (strcmp (name_j, "fr_FR.UTF-8") == 0);
284                   }
285               }
286           }
287       }
288   }
289 #else
290   /* Check that gl_locale_name_thread always returns NULL.  */
291   ASSERT (gl_locale_name_thread (LC_CTYPE, "LC_CTYPE") == NULL);
292   ASSERT (gl_locale_name_thread (LC_MESSAGES, "LC_MESSAGES") == NULL);
293 #endif
294 }
295
296 /* Test the gl_locale_name_posix() function.  */
297 static void
298 test_locale_name_posix (void)
299 {
300   const char *name;
301
302   /* Get into a defined state,  */
303   setlocale (LC_ALL, "en_US.UTF-8");
304 #if HAVE_NEWLOCALE
305   uselocale (LC_GLOBAL_LOCALE);
306 #endif
307
308   /* Check that when all environment variables are unset,
309      gl_locale_name_posix returns either NULL or the default locale.  */
310   unsetenv ("LC_ALL");
311   unsetenv ("LC_CTYPE");
312   unsetenv ("LC_MESSAGES");
313   unsetenv ("LC_NUMERIC");
314   unsetenv ("LANG");
315   setlocale (LC_ALL, "");
316   name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
317   ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
318   name = gl_locale_name_posix (LC_NUMERIC, "LC_NUMERIC");
319   ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
320
321   /* Check that an empty environment variable is treated like an unset
322      environment variable.  */
323
324   setenv ("LC_ALL", "", 1);
325   unsetenv ("LC_CTYPE");
326   unsetenv ("LC_MESSAGES");
327   unsetenv ("LANG");
328   setlocale (LC_ALL, "");
329   name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
330   ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
331
332   unsetenv ("LC_ALL");
333   setenv ("LC_CTYPE", "", 1);
334   unsetenv ("LC_MESSAGES");
335   unsetenv ("LANG");
336   setlocale (LC_ALL, "");
337   name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
338   ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
339
340   unsetenv ("LC_ALL");
341   unsetenv ("LC_CTYPE");
342   setenv ("LC_MESSAGES", "", 1);
343   unsetenv ("LANG");
344   setlocale (LC_ALL, "");
345   name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
346   ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
347
348   unsetenv ("LC_ALL");
349   unsetenv ("LC_CTYPE");
350   unsetenv ("LC_MESSAGES");
351   setenv ("LANG", "", 1);
352   setlocale (LC_ALL, "");
353   name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
354   ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
355
356   /* Check that LC_ALL overrides the others, and LANG is overridden by the
357      others.  */
358
359   setenv ("LC_ALL", "C", 1);
360   unsetenv ("LC_CTYPE");
361   unsetenv ("LC_MESSAGES");
362   unsetenv ("LANG");
363   setlocale (LC_ALL, "");
364   name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
365   ASSERT (strcmp (name, "C") == 0);
366
367   unsetenv ("LC_ALL");
368   setenv ("LC_CTYPE", "C", 1);
369   setenv ("LC_MESSAGES", "C", 1);
370   unsetenv ("LANG");
371   setlocale (LC_ALL, "");
372   name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
373   ASSERT (strcmp (name, "C") == 0);
374
375   unsetenv ("LC_ALL");
376   unsetenv ("LC_CTYPE");
377   unsetenv ("LC_MESSAGES");
378   setenv ("LANG", "C", 1);
379   setlocale (LC_ALL, "");
380   name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
381   ASSERT (strcmp (name, "C") == 0);
382
383   /* Check mixed situations.  */
384
385   unsetenv ("LC_ALL");
386   unsetenv ("LC_CTYPE");
387   setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
388   setenv ("LANG", "de_DE.UTF-8", 1);
389   if (setlocale (LC_ALL, "") != NULL)
390     {
391       name = gl_locale_name_posix (LC_CTYPE, "LC_CTYPE");
392       ASSERT (strcmp (name, "de_DE.UTF-8") == 0);
393       name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
394       ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
395     }
396
397   unsetenv ("LC_ALL");
398   unsetenv ("LC_CTYPE");
399   setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
400   unsetenv ("LANG");
401   if (setlocale (LC_ALL, "") != NULL)
402     {
403       name = gl_locale_name_posix (LC_CTYPE, "LC_CTYPE");
404       ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
405       name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
406       ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
407     }
408
409 #if HAVE_NEWLOCALE
410   /* Check that gl_locale_name_posix ignores the thread locale.  */
411   {
412     locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
413     if (locale != NULL)
414       {
415         unsetenv ("LC_ALL");
416         unsetenv ("LC_CTYPE");
417         unsetenv ("LC_MESSAGES");
418         setenv ("LANG", "C", 1);
419         setlocale (LC_ALL, "");
420         uselocale (locale);
421         name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
422         ASSERT (strcmp (name, "C") == 0);
423       }
424   }
425 #endif
426 }
427
428 /* Test the gl_locale_name_environ() function.  */
429 static void
430 test_locale_name_environ (void)
431 {
432   const char *name;
433
434   /* Get into a defined state,  */
435   setlocale (LC_ALL, "en_US.UTF-8");
436 #if HAVE_NEWLOCALE
437   uselocale (LC_GLOBAL_LOCALE);
438 #endif
439
440   /* Check that when all environment variables are unset,
441      gl_locale_name_environ returns NULL.  */
442   unsetenv ("LC_ALL");
443   unsetenv ("LC_CTYPE");
444   unsetenv ("LC_MESSAGES");
445   unsetenv ("LC_NUMERIC");
446   unsetenv ("LANG");
447   ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL);
448   ASSERT (gl_locale_name_environ (LC_NUMERIC, "LC_NUMERIC") == NULL);
449
450   /* Check that an empty environment variable is treated like an unset
451      environment variable.  */
452
453   setenv ("LC_ALL", "", 1);
454   unsetenv ("LC_CTYPE");
455   unsetenv ("LC_MESSAGES");
456   unsetenv ("LANG");
457   ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL);
458
459   unsetenv ("LC_ALL");
460   setenv ("LC_CTYPE", "", 1);
461   unsetenv ("LC_MESSAGES");
462   unsetenv ("LANG");
463   ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL);
464
465   unsetenv ("LC_ALL");
466   unsetenv ("LC_CTYPE");
467   setenv ("LC_MESSAGES", "", 1);
468   unsetenv ("LANG");
469   ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL);
470
471   unsetenv ("LC_ALL");
472   unsetenv ("LC_CTYPE");
473   unsetenv ("LC_MESSAGES");
474   setenv ("LANG", "", 1);
475   ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL);
476
477   /* Check that LC_ALL overrides the others, and LANG is overridden by the
478      others.  */
479
480   setenv ("LC_ALL", "C", 1);
481   unsetenv ("LC_CTYPE");
482   unsetenv ("LC_MESSAGES");
483   unsetenv ("LANG");
484   name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
485   ASSERT (strcmp (name, "C") == 0);
486
487   unsetenv ("LC_ALL");
488   setenv ("LC_CTYPE", "C", 1);
489   setenv ("LC_MESSAGES", "C", 1);
490   unsetenv ("LANG");
491   name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
492   ASSERT (strcmp (name, "C") == 0);
493
494   unsetenv ("LC_ALL");
495   unsetenv ("LC_CTYPE");
496   unsetenv ("LC_MESSAGES");
497   setenv ("LANG", "C", 1);
498   name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
499   ASSERT (strcmp (name, "C") == 0);
500
501   /* Check mixed situations.  */
502
503   unsetenv ("LC_ALL");
504   unsetenv ("LC_CTYPE");
505   setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
506   setenv ("LANG", "de_DE.UTF-8", 1);
507   name = gl_locale_name_environ (LC_CTYPE, "LC_CTYPE");
508   ASSERT (strcmp (name, "de_DE.UTF-8") == 0);
509   name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
510   ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
511
512   unsetenv ("LC_ALL");
513   unsetenv ("LC_CTYPE");
514   setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
515   unsetenv ("LANG");
516   name = gl_locale_name_environ (LC_CTYPE, "LC_CTYPE");
517   ASSERT (name == NULL);
518   name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
519   ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
520
521 #if HAVE_NEWLOCALE
522   /* Check that gl_locale_name_environ ignores the thread locale.  */
523   {
524     locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
525     if (locale != NULL)
526       {
527         unsetenv ("LC_ALL");
528         unsetenv ("LC_CTYPE");
529         unsetenv ("LC_MESSAGES");
530         setenv ("LANG", "C", 1);
531         setlocale (LC_ALL, "");
532         uselocale (locale);
533         name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
534         ASSERT (strcmp (name, "C") == 0);
535       }
536   }
537 #endif
538 }
539
540 /* Test the gl_locale_name_default() function.  */
541 static void
542 test_locale_name_default (void)
543 {
544   const char *name = gl_locale_name_default ();
545
546   ASSERT (name != NULL);
547
548   /* Only MacOS X and Windows have a facility for the user to set the default
549      locale.  */
550 #if !((defined __APPLE__ && defined __MACH__) || (defined _WIN32 || defined __WIN32__ || defined __CYGWIN__))
551   ASSERT (strcmp (name, "C") == 0);
552 #endif
553
554 #if HAVE_NEWLOCALE
555   /* Check that gl_locale_name_default ignores the thread locale.  */
556   {
557     locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
558     if (locale != NULL)
559       {
560         uselocale (locale);
561         ASSERT (strcmp (gl_locale_name_default (), name) == 0);
562       }
563   }
564 #endif
565 }
566
567 int
568 main ()
569 {
570   test_locale_name ();
571   test_locale_name_thread ();
572   test_locale_name_posix ();
573   test_locale_name_environ ();
574   test_locale_name_default ();
575
576   return 0;
577 }