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 %I:%M:%S %p %Z" }, 80 { D_FMT, "%m/%e/%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])?))" }, 102 { NOEXPR, "^(([nN]([oO])?))" }, 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 %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])?))" }, 132 { NOEXPR, "^(([nN]([oO])?))" }, 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])?))" }, 162 { NOEXPR, "^(([нН]([еЕ][тТ])?)|([nN]([oO])?))" }, 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 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 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 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 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 }