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 <unistd.h> 31 #include <pthread.h> 32 #include <note.h> 33 #include "test_common.h" 34 35 /* 36 * Note that on some platforms, different symbols are used. For example, 37 * MacOS Mavericks uses "Eu" for Euro symbol, instead of €. If the locale 38 * data changes, then this program will need to update to reflect that. 39 */ 40 struct ldata { 41 const char *locale; 42 const char *day1; 43 const char *cursym; 44 } ldata[] = { 45 { "C", "Sunday", "" }, 46 { "en_US.UTF-8", "Sunday", "$" }, 47 { "de_DE.UTF-8", "Sonntag", "€" }, 48 { "ru_RU.UTF-8", "воскресенье", "руб." }, 49 { "ja_JP.UTF-8", "日曜日", "¥" }, 50 }; 51 52 #define NUM_LDATA 5 53 #define NUMTHR 20 54 #define NUMITR 200 55 56 int extra_debug = 0; 57 58 void 59 testlocale_thr_one(test_t t, void *arg) 60 { 61 _NOTE(ARGUNUSED(arg)); 62 locale_t cloc, loc; 63 struct lconv *lc; 64 char *day; 65 66 for (int i = 0; i < NUMITR; i++) { 67 struct ldata *l = &ldata[i % NUM_LDATA]; 68 cloc = uselocale(NULL); 69 70 loc = newlocale(LC_ALL_MASK, l->locale, NULL); 71 if (loc == NULL) { 72 test_failed(t, "newlocale %s failed", l->locale); 73 } 74 day = nl_langinfo_l(DAY_1, loc); 75 if (strcmp(day, l->day1) != 0) { 76 test_failed(t, "newlocale data mismatch (%s != %s)", 77 day, l->day1); 78 } 79 if (extra_debug) 80 test_debugf(t, "DAY1: %s", day); 81 82 day = nl_langinfo(DAY_1); 83 if (strcmp(day, "Sunday") != 0) { 84 test_failed(t, "C locale day wrong %s != Sunday", 85 day); 86 } 87 lc = localeconv(); 88 if (strcmp(lc->currency_symbol, "") != 0) { 89 test_failed(t, "C cursym mismatch (%s != %s)", 90 lc->currency_symbol, ""); 91 } 92 93 /* we sleep a random bit to mix it up */ 94 (void) usleep(rand() % 10); 95 96 (void) uselocale(loc); 97 day = nl_langinfo(DAY_1); 98 if (strcmp(day, l->day1) != 0) { 99 test_failed(t, "uselocale data mismatch (%s != %s)", 100 day, l->day1); 101 } 102 103 lc = localeconv(); 104 if (strcmp(lc->currency_symbol, l->cursym) != 0) { 105 test_failed(t, "uselocal cursym %s != %s", 106 lc->currency_symbol, l->cursym); 107 } 108 if (extra_debug) 109 test_debugf(t, "CSYM: %s", lc->currency_symbol); 110 111 /* we sleep a random bit to mix it up */ 112 (void) usleep(rand() % 10); 113 114 if (uselocale(cloc) != loc) { 115 test_failed(t, "revert old locale mismatch"); 116 } 117 freelocale(loc); 118 if (uselocale(LC_GLOBAL_LOCALE) != cloc) { 119 test_failed(t, "revert GLOBAL_LOCALE mismatch"); 120 } 121 } 122 test_passed(t); 123 } 124 125 126 void 127 test_newlocale_threaded(void) 128 { 129 test_run(NUMTHR, testlocale_thr_one, NULL, "newlocale_threaded"); 130 } 131 132 void 133 test_newlocale_negative(void) 134 { 135 locale_t loc, bad; 136 char *day; 137 char *tname = "newlocale_negative"; 138 test_t t; 139 140 t = test_start(tname); 141 loc = newlocale(LC_ALL_MASK, "de_DE.UTF-8", NULL); 142 if (loc == NULL) { 143 test_failed(t, "cannot set de_DE.UTF-8"); 144 } 145 day = nl_langinfo_l(DAY_1, loc); 146 if (strcmp(day, "Sonntag") != 0) { 147 test_failed(t, "incorrect Sonntag != %s", day); 148 } 149 150 bad = newlocale(LC_ALL_MASK, "cn_US.BIZRRE", loc); 151 if (bad != NULL) { 152 test_failed(t, "passed setting bogus locale"); 153 } 154 day = nl_langinfo_l(DAY_1, loc); 155 if (strcmp(day, "Sonntag") != 0) { 156 test_failed(t, "incorrect Sonntag != %s", day); 157 } 158 test_passed(t); 159 } 160 161 void 162 test_newlocale_categories(void) 163 { 164 locale_t loc; 165 char *day, *cur, *yes; 166 char *tname = "newlocale_categories"; 167 test_t t; 168 169 t = test_start(tname); 170 171 loc = NULL; 172 loc = newlocale(LC_TIME_MASK, "de_DE.UTF-8", loc); 173 loc = newlocale(LC_MESSAGES_MASK, "ru_RU.UTF-8", loc); 174 loc = newlocale(LC_MONETARY_MASK, "en_US.UTF-8", loc); 175 176 if (loc == NULL) { 177 test_failed(t, "failed to set locale"); 178 } 179 180 day = nl_langinfo_l(DAY_1, loc); 181 if ((day == NULL) || (strcmp(day, "Sonntag") != 0)) { 182 test_failed(t, "day1 mismatch %s != %s", day, "Sonntag"); 183 } 184 yes = nl_langinfo_l(YESSTR, loc); 185 if ((yes == NULL) || (strcmp(yes, "да") != 0)) { 186 test_failed(t, "currency mismatch"); 187 } 188 cur = nl_langinfo_l(CRNCYSTR, loc); 189 if ((cur == NULL) || (strcmp(cur, "-$") != 0)) { 190 test_failed(t, "currency mismatch [%s] != [%s]", cur, "-$"); 191 } 192 193 test_passed(t); 194 } 195 196 void 197 test_newlocale_composite(void) 198 { 199 locale_t loc; 200 char *day, *cur, *yes; 201 char *tname = "newlocale_composite"; 202 test_t t; 203 204 t = test_start(tname); 205 206 /* order: CTYPE/NUMERIC/TIME/COLLATE/MONETARY/MESSAGES */ 207 loc = newlocale(LC_ALL_MASK, 208 "C/C/de_DE.UTF-8/C/en_US.UTF-8/ru_RU.UTF-8", NULL); 209 210 if (loc == NULL) { 211 test_failed(t, "failed to set composite locale"); 212 } 213 214 day = nl_langinfo_l(DAY_1, loc); 215 if ((day == NULL) || (strcmp(day, "Sonntag") != 0)) { 216 test_failed(t, "day1 mismatch %s != %s", day, "Sonntag"); 217 } 218 yes = nl_langinfo_l(YESSTR, loc); 219 if ((yes == NULL) || (strcmp(yes, "да") != 0)) { 220 test_failed(t, "currency mismatch"); 221 } 222 cur = nl_langinfo_l(CRNCYSTR, loc); 223 if ((cur == NULL) || (strcmp(cur, "-$") != 0)) { 224 test_failed(t, "currency mismatch [%s] != [%s]", cur, "-$"); 225 } 226 227 test_passed(t); 228 } 229 230 int 231 main(int argc, char **argv) 232 { 233 int optc; 234 235 while ((optc = getopt(argc, argv, "Ddf")) != EOF) { 236 switch (optc) { 237 case 'd': 238 test_set_debug(); 239 break; 240 case 'f': 241 test_set_force(); 242 break; 243 case 'D': 244 test_set_debug(); 245 extra_debug++; 246 break; 247 default: 248 (void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]); 249 exit(1); 250 } 251 } 252 253 test_newlocale_threaded(); 254 test_newlocale_negative(); 255 test_newlocale_categories(); 256 test_newlocale_composite(); 257 258 exit(0); 259 }