12d08521bSGarrett D'Amore /* 22d08521bSGarrett D'Amore * This file and its contents are supplied under the terms of the 32d08521bSGarrett D'Amore * Common Development and Distribution License ("CDDL"), version 1.0. 42d08521bSGarrett D'Amore * You may only use this file in accordance with the terms of version 52d08521bSGarrett D'Amore * 1.0 of the CDDL. 62d08521bSGarrett D'Amore * 72d08521bSGarrett D'Amore * A full copy of the text of the CDDL should have accompanied this 82d08521bSGarrett D'Amore * source. A copy of the CDDL is also available via the Internet at 92d08521bSGarrett D'Amore * http://www.illumos.org/license/CDDL. 102d08521bSGarrett D'Amore */ 112d08521bSGarrett D'Amore 122d08521bSGarrett D'Amore /* 132d08521bSGarrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org> 142d08521bSGarrett D'Amore */ 152d08521bSGarrett D'Amore 162d08521bSGarrett D'Amore /* 172d08521bSGarrett D'Amore * This program tests that newlocale and uselocale work properly in 182d08521bSGarrett D'Amore * multi-threaded programs. In order for it to work, it requires that 192d08521bSGarrett D'Amore * some additional locales be installed. 202d08521bSGarrett D'Amore */ 212d08521bSGarrett D'Amore 222d08521bSGarrett D'Amore #include <stdio.h> 232d08521bSGarrett D'Amore #include <stdlib.h> 242d08521bSGarrett D'Amore #include <string.h> 252d08521bSGarrett D'Amore #include <locale.h> 262d08521bSGarrett D'Amore #include <libintl.h> 272d08521bSGarrett D'Amore #include <langinfo.h> 282d08521bSGarrett D'Amore #include <nl_types.h> 292d08521bSGarrett D'Amore #include <err.h> 302d08521bSGarrett D'Amore #include <unistd.h> 312d08521bSGarrett D'Amore #include <pthread.h> 32*538aa54dSGarrett D'Amore #include <note.h> 33*538aa54dSGarrett D'Amore #include "test_common.h" 342d08521bSGarrett D'Amore 352d08521bSGarrett D'Amore /* 362d08521bSGarrett D'Amore * Note that on some platforms, different symbols are used. For example, 372d08521bSGarrett D'Amore * MacOS Mavericks uses "Eu" for Euro symbol, instead of €. If the locale 382d08521bSGarrett D'Amore * data changes, then this program will need to update to reflect that. 392d08521bSGarrett D'Amore */ 402d08521bSGarrett D'Amore struct ldata { 412d08521bSGarrett D'Amore const char *locale; 422d08521bSGarrett D'Amore const char *day1; 432d08521bSGarrett D'Amore const char *cursym; 442d08521bSGarrett D'Amore } ldata[] = { 452d08521bSGarrett D'Amore { "C", "Sunday", "" }, 462d08521bSGarrett D'Amore { "en_US.UTF-8", "Sunday", "$" }, 472d08521bSGarrett D'Amore { "de_DE.UTF-8", "Sonntag", "€" }, 482d08521bSGarrett D'Amore { "ru_RU.UTF-8", "воскресенье", "руб." }, 492d08521bSGarrett D'Amore { "ja_JP.UTF-8", "日曜日", "¥" }, 502d08521bSGarrett D'Amore }; 512d08521bSGarrett D'Amore 522d08521bSGarrett D'Amore #define NUM_LDATA 5 532d08521bSGarrett D'Amore #define NUMTHR 20 542d08521bSGarrett D'Amore #define NUMITR 200 552d08521bSGarrett D'Amore 56*538aa54dSGarrett D'Amore int extra_debug = 0; 57*538aa54dSGarrett D'Amore 58*538aa54dSGarrett D'Amore void 59*538aa54dSGarrett D'Amore testlocale_thr_one(test_t t, void *arg) 602d08521bSGarrett D'Amore { 61*538aa54dSGarrett D'Amore _NOTE(ARGUNUSED(arg)); 622d08521bSGarrett D'Amore locale_t cloc, loc; 632d08521bSGarrett D'Amore struct lconv *lc; 642d08521bSGarrett D'Amore char *day; 652d08521bSGarrett D'Amore 662d08521bSGarrett D'Amore for (int i = 0; i < NUMITR; i++) { 672d08521bSGarrett D'Amore struct ldata *l = &ldata[i % NUM_LDATA]; 682d08521bSGarrett D'Amore cloc = uselocale(NULL); 692d08521bSGarrett D'Amore 702d08521bSGarrett D'Amore loc = newlocale(LC_ALL_MASK, l->locale, NULL); 712d08521bSGarrett D'Amore if (loc == NULL) { 72*538aa54dSGarrett D'Amore test_failed(t, "newlocale %s failed", l->locale); 732d08521bSGarrett D'Amore } 742d08521bSGarrett D'Amore day = nl_langinfo_l(DAY_1, loc); 752d08521bSGarrett D'Amore if (strcmp(day, l->day1) != 0) { 76*538aa54dSGarrett D'Amore test_failed(t, "newlocale data mismatch (%s != %s)", 772d08521bSGarrett D'Amore day, l->day1); 782d08521bSGarrett D'Amore } 79*538aa54dSGarrett D'Amore if (extra_debug) 80*538aa54dSGarrett D'Amore test_debugf(t, "DAY1: %s", day); 812d08521bSGarrett D'Amore 822d08521bSGarrett D'Amore day = nl_langinfo(DAY_1); 832d08521bSGarrett D'Amore if (strcmp(day, "Sunday") != 0) { 84*538aa54dSGarrett D'Amore test_failed(t, "C locale day wrong %s != Sunday", 852d08521bSGarrett D'Amore day); 862d08521bSGarrett D'Amore } 872d08521bSGarrett D'Amore lc = localeconv(); 882d08521bSGarrett D'Amore if (strcmp(lc->currency_symbol, "") != 0) { 89*538aa54dSGarrett D'Amore test_failed(t, "C cursym mismatch (%s != %s)", 902d08521bSGarrett D'Amore lc->currency_symbol, ""); 912d08521bSGarrett D'Amore } 922d08521bSGarrett D'Amore 932d08521bSGarrett D'Amore /* we sleep a random bit to mix it up */ 942d08521bSGarrett D'Amore (void) usleep(rand() % 10); 952d08521bSGarrett D'Amore 962d08521bSGarrett D'Amore (void) uselocale(loc); 972d08521bSGarrett D'Amore day = nl_langinfo(DAY_1); 982d08521bSGarrett D'Amore if (strcmp(day, l->day1) != 0) { 99*538aa54dSGarrett D'Amore test_failed(t, "uselocale data mismatch (%s != %s)", 1002d08521bSGarrett D'Amore day, l->day1); 1012d08521bSGarrett D'Amore } 1022d08521bSGarrett D'Amore 1032d08521bSGarrett D'Amore lc = localeconv(); 1042d08521bSGarrett D'Amore if (strcmp(lc->currency_symbol, l->cursym) != 0) { 105*538aa54dSGarrett D'Amore test_failed(t, "uselocal cursym %s != %s", 1062d08521bSGarrett D'Amore lc->currency_symbol, l->cursym); 1072d08521bSGarrett D'Amore } 108*538aa54dSGarrett D'Amore if (extra_debug) 109*538aa54dSGarrett D'Amore test_debugf(t, "CSYM: %s", lc->currency_symbol); 1102d08521bSGarrett D'Amore 1112d08521bSGarrett D'Amore /* we sleep a random bit to mix it up */ 1122d08521bSGarrett D'Amore (void) usleep(rand() % 10); 1132d08521bSGarrett D'Amore 1142d08521bSGarrett D'Amore if (uselocale(cloc) != loc) { 115*538aa54dSGarrett D'Amore test_failed(t, "revert old locale mismatch"); 1162d08521bSGarrett D'Amore } 1172d08521bSGarrett D'Amore freelocale(loc); 1182d08521bSGarrett D'Amore if (uselocale(LC_GLOBAL_LOCALE) != cloc) { 119*538aa54dSGarrett D'Amore test_failed(t, "revert GLOBAL_LOCALE mismatch"); 1202d08521bSGarrett D'Amore } 1212d08521bSGarrett D'Amore } 122*538aa54dSGarrett D'Amore test_passed(t); 1232d08521bSGarrett D'Amore } 1242d08521bSGarrett D'Amore 1252d08521bSGarrett D'Amore 1262d08521bSGarrett D'Amore void 127*538aa54dSGarrett D'Amore test_newlocale_threaded(void) 1282d08521bSGarrett D'Amore { 129*538aa54dSGarrett D'Amore test_run(NUMTHR, testlocale_thr_one, NULL, "newlocale_threaded"); 1302d08521bSGarrett D'Amore } 1312d08521bSGarrett D'Amore 132*538aa54dSGarrett D'Amore void 133*538aa54dSGarrett D'Amore test_newlocale_negative(void) 134*538aa54dSGarrett D'Amore { 135*538aa54dSGarrett D'Amore locale_t loc, bad; 136*538aa54dSGarrett D'Amore char *day; 137*538aa54dSGarrett D'Amore char *tname = "newlocale_negative"; 138*538aa54dSGarrett D'Amore test_t t; 139*538aa54dSGarrett D'Amore 140*538aa54dSGarrett D'Amore t = test_start(tname); 141*538aa54dSGarrett D'Amore loc = newlocale(LC_ALL_MASK, "de_DE.UTF-8", NULL); 142*538aa54dSGarrett D'Amore if (loc == NULL) { 143*538aa54dSGarrett D'Amore test_failed(t, "cannot set de_DE.UTF-8"); 1442d08521bSGarrett D'Amore } 145*538aa54dSGarrett D'Amore day = nl_langinfo_l(DAY_1, loc); 146*538aa54dSGarrett D'Amore if (strcmp(day, "Sonntag") != 0) { 147*538aa54dSGarrett D'Amore test_failed(t, "incorrect Sonntag != %s", day); 148*538aa54dSGarrett D'Amore } 149*538aa54dSGarrett D'Amore 150*538aa54dSGarrett D'Amore bad = newlocale(LC_ALL_MASK, "cn_US.BIZRRE", loc); 151*538aa54dSGarrett D'Amore if (bad != NULL) { 152*538aa54dSGarrett D'Amore test_failed(t, "passed setting bogus locale"); 153*538aa54dSGarrett D'Amore } 154*538aa54dSGarrett D'Amore day = nl_langinfo_l(DAY_1, loc); 155*538aa54dSGarrett D'Amore if (strcmp(day, "Sonntag") != 0) { 156*538aa54dSGarrett D'Amore test_failed(t, "incorrect Sonntag != %s", day); 157*538aa54dSGarrett D'Amore } 158*538aa54dSGarrett D'Amore test_passed(t); 159*538aa54dSGarrett D'Amore } 160*538aa54dSGarrett D'Amore 161*538aa54dSGarrett D'Amore void 162*538aa54dSGarrett D'Amore test_newlocale_categories(void) 163*538aa54dSGarrett D'Amore { 164*538aa54dSGarrett D'Amore locale_t loc; 165*538aa54dSGarrett D'Amore char *day, *cur, *yes; 166*538aa54dSGarrett D'Amore char *tname = "newlocale_categories"; 167*538aa54dSGarrett D'Amore test_t t; 168*538aa54dSGarrett D'Amore 169*538aa54dSGarrett D'Amore t = test_start(tname); 170*538aa54dSGarrett D'Amore 171*538aa54dSGarrett D'Amore loc = NULL; 172*538aa54dSGarrett D'Amore loc = newlocale(LC_TIME_MASK, "de_DE.UTF-8", loc); 173*538aa54dSGarrett D'Amore loc = newlocale(LC_MESSAGES_MASK, "ru_RU.UTF-8", loc); 174*538aa54dSGarrett D'Amore loc = newlocale(LC_MONETARY_MASK, "en_US.UTF-8", loc); 175*538aa54dSGarrett D'Amore 176*538aa54dSGarrett D'Amore if (loc == NULL) { 177*538aa54dSGarrett D'Amore test_failed(t, "failed to set locale"); 178*538aa54dSGarrett D'Amore } 179*538aa54dSGarrett D'Amore 180*538aa54dSGarrett D'Amore day = nl_langinfo_l(DAY_1, loc); 181*538aa54dSGarrett D'Amore if ((day == NULL) || (strcmp(day, "Sonntag") != 0)) { 182*538aa54dSGarrett D'Amore test_failed(t, "day1 mismatch %s != %s", day, "Sonntag"); 183*538aa54dSGarrett D'Amore } 184*538aa54dSGarrett D'Amore yes = nl_langinfo_l(YESSTR, loc); 185*538aa54dSGarrett D'Amore if ((yes == NULL) || (strcmp(yes, "да") != 0)) { 186*538aa54dSGarrett D'Amore test_failed(t, "currency mismatch"); 187*538aa54dSGarrett D'Amore } 188*538aa54dSGarrett D'Amore cur = nl_langinfo_l(CRNCYSTR, loc); 189*538aa54dSGarrett D'Amore if ((cur == NULL) || (strcmp(cur, "-$") != 0)) { 190*538aa54dSGarrett D'Amore test_failed(t, "currency mismatch [%s] != [%s]", cur, "-$"); 191*538aa54dSGarrett D'Amore } 192*538aa54dSGarrett D'Amore 193*538aa54dSGarrett D'Amore test_passed(t); 194*538aa54dSGarrett D'Amore } 195*538aa54dSGarrett D'Amore 196*538aa54dSGarrett D'Amore void 197*538aa54dSGarrett D'Amore test_newlocale_composite(void) 198*538aa54dSGarrett D'Amore { 199*538aa54dSGarrett D'Amore locale_t loc; 200*538aa54dSGarrett D'Amore char *day, *cur, *yes; 201*538aa54dSGarrett D'Amore char *tname = "newlocale_composite"; 202*538aa54dSGarrett D'Amore test_t t; 203*538aa54dSGarrett D'Amore 204*538aa54dSGarrett D'Amore t = test_start(tname); 205*538aa54dSGarrett D'Amore 206*538aa54dSGarrett D'Amore /* order: CTYPE/NUMERIC/TIME/COLLATE/MONETARY/MESSAGES */ 207*538aa54dSGarrett D'Amore loc = newlocale(LC_ALL_MASK, 208*538aa54dSGarrett D'Amore "C/C/de_DE.UTF-8/C/en_US.UTF-8/ru_RU.UTF-8", NULL); 209*538aa54dSGarrett D'Amore 210*538aa54dSGarrett D'Amore if (loc == NULL) { 211*538aa54dSGarrett D'Amore test_failed(t, "failed to set composite locale"); 212*538aa54dSGarrett D'Amore } 213*538aa54dSGarrett D'Amore 214*538aa54dSGarrett D'Amore day = nl_langinfo_l(DAY_1, loc); 215*538aa54dSGarrett D'Amore if ((day == NULL) || (strcmp(day, "Sonntag") != 0)) { 216*538aa54dSGarrett D'Amore test_failed(t, "day1 mismatch %s != %s", day, "Sonntag"); 217*538aa54dSGarrett D'Amore } 218*538aa54dSGarrett D'Amore yes = nl_langinfo_l(YESSTR, loc); 219*538aa54dSGarrett D'Amore if ((yes == NULL) || (strcmp(yes, "да") != 0)) { 220*538aa54dSGarrett D'Amore test_failed(t, "currency mismatch"); 221*538aa54dSGarrett D'Amore } 222*538aa54dSGarrett D'Amore cur = nl_langinfo_l(CRNCYSTR, loc); 223*538aa54dSGarrett D'Amore if ((cur == NULL) || (strcmp(cur, "-$") != 0)) { 224*538aa54dSGarrett D'Amore test_failed(t, "currency mismatch [%s] != [%s]", cur, "-$"); 225*538aa54dSGarrett D'Amore } 226*538aa54dSGarrett D'Amore 227*538aa54dSGarrett D'Amore test_passed(t); 2282d08521bSGarrett D'Amore } 2292d08521bSGarrett D'Amore 2302d08521bSGarrett D'Amore int 2312d08521bSGarrett D'Amore main(int argc, char **argv) 2322d08521bSGarrett D'Amore { 2332d08521bSGarrett D'Amore int optc; 2342d08521bSGarrett D'Amore 235*538aa54dSGarrett D'Amore while ((optc = getopt(argc, argv, "Ddf")) != EOF) { 2362d08521bSGarrett D'Amore switch (optc) { 2372d08521bSGarrett D'Amore case 'd': 238*538aa54dSGarrett D'Amore test_set_debug(); 239*538aa54dSGarrett D'Amore break; 240*538aa54dSGarrett D'Amore case 'f': 241*538aa54dSGarrett D'Amore test_set_force(); 242*538aa54dSGarrett D'Amore break; 243*538aa54dSGarrett D'Amore case 'D': 244*538aa54dSGarrett D'Amore test_set_debug(); 245*538aa54dSGarrett D'Amore extra_debug++; 2462d08521bSGarrett D'Amore break; 2472d08521bSGarrett D'Amore default: 248*538aa54dSGarrett D'Amore (void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]); 2492d08521bSGarrett D'Amore exit(1); 2502d08521bSGarrett D'Amore } 2512d08521bSGarrett D'Amore } 2522d08521bSGarrett D'Amore 253*538aa54dSGarrett D'Amore test_newlocale_threaded(); 254*538aa54dSGarrett D'Amore test_newlocale_negative(); 255*538aa54dSGarrett D'Amore test_newlocale_categories(); 256*538aa54dSGarrett D'Amore test_newlocale_composite(); 2572d08521bSGarrett D'Amore 2582d08521bSGarrett D'Amore exit(0); 2592d08521bSGarrett D'Amore } 260