diff options
Diffstat (limited to '')
| -rw-r--r-- | src/regress/lib/libc/locale/uselocale/Makefile | 3 | ||||
| -rw-r--r-- | src/regress/lib/libc/locale/uselocale/uselocale.c | 228 | 
2 files changed, 117 insertions, 114 deletions
| diff --git a/src/regress/lib/libc/locale/uselocale/Makefile b/src/regress/lib/libc/locale/uselocale/Makefile index 45c3b7e807..3c3f487df8 100644 --- a/src/regress/lib/libc/locale/uselocale/Makefile +++ b/src/regress/lib/libc/locale/uselocale/Makefile | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | # $OpenBSD: Makefile,v 1.1 2017/08/10 14:45:42 schwarze Exp $ | 1 | # $OpenBSD: Makefile,v 1.2 2017/08/15 23:46:51 schwarze Exp $ | 
| 2 | 2 | ||
| 3 | PROG = uselocale | 3 | PROG = uselocale | 
| 4 | CFLAGS += -Wno-macro-redefined | ||
| 4 | LDFLAGS += -pthread | 5 | LDFLAGS += -pthread | 
| 5 | 6 | ||
| 6 | run-regress-${PROG}: ${PROG} | 7 | run-regress-${PROG}: ${PROG} | 
| diff --git a/src/regress/lib/libc/locale/uselocale/uselocale.c b/src/regress/lib/libc/locale/uselocale/uselocale.c index a40f77397a..c33c1e21fa 100644 --- a/src/regress/lib/libc/locale/uselocale/uselocale.c +++ b/src/regress/lib/libc/locale/uselocale/uselocale.c | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | /* $OpenBSD: uselocale.c,v 1.1 2017/08/10 14:45:42 schwarze Exp $ */ | 1 | /* $OpenBSD: uselocale.c,v 1.2 2017/08/15 23:46:51 schwarze Exp $ */ | 
| 2 | /* | 2 | /* | 
| 3 | * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> | 3 | * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> | 
| 4 | * Copyright (c) 2015 Sebastien Marie <semarie@openbsd.org> | ||
| 5 | * | 4 | * | 
| 6 | * Permission to use, copy, modify, and distribute this software for any | 5 | * Permission to use, copy, modify, and distribute this software for any | 
| 7 | * purpose with or without fee is hereby granted, provided that the above | 6 | * purpose with or without fee is hereby granted, provided that the above | 
| @@ -22,93 +21,96 @@ | |||
| 22 | #include <pthread.h> | 21 | #include <pthread.h> | 
| 23 | #include <stdlib.h> | 22 | #include <stdlib.h> | 
| 24 | #include <string.h> | 23 | #include <string.h> | 
| 25 | #include <time.h> | ||
| 26 | 24 | ||
| 25 | /* Keep in sync with /usr/src/lib/libc/locale/rune.h. */ | ||
| 27 | #define _LOCALE_NONE (locale_t)0 | 26 | #define _LOCALE_NONE (locale_t)0 | 
| 28 | #define _LOCALE_C (locale_t)1 | 27 | #define _LOCALE_C (locale_t)1 | 
| 29 | #define _LOCALE_UTF8 (locale_t)2 | 28 | #define _LOCALE_UTF8 (locale_t)2 | 
| 30 | #define _LOCALE_BAD (locale_t)3 | 29 | #define _LOCALE_BAD (locale_t)3 | 
| 31 | 30 | ||
| 32 | #define SWITCH_SIGNAL 1 | 31 | /* Options for switch_thread() below. */ | 
| 33 | #define SWITCH_WAIT 2 | 32 | #define SWITCH_SIGNAL 1 /* Call pthread_cond_signal(3). */ | 
| 33 | #define SWITCH_WAIT 2 /* Call pthread_cond_timedwait(3). */ | ||
| 34 | |||
| 35 | /* Options for TESTFUNC(). */ | ||
| 36 | #define TOPT_ERR (1 << 0) | ||
| 37 | #define TOPT_STR (1 << 1) | ||
| 34 | 38 | ||
| 35 | /* | 39 | /* | 
| 36 | * test helpers for __LINE__ | 40 | * Generate one test function for a specific interface. | 
| 41 | * Fn = function name | ||
| 42 | * Ft = function return type | ||
| 43 | * FUNCPARA = function parameter list with types and names | ||
| 44 | * FUNCARGS = function argument list, names only, no types | ||
| 45 | * Af = format string to print the arguments | ||
| 46 | * Rf = format string to print the return value | ||
| 47 | * Op = options for the test function, see above | ||
| 48 | * line = source code line number in this test file | ||
| 49 | * ee = expected error number | ||
| 50 | * er = expected return value | ||
| 51 | * ar = actual return value | ||
| 52 | * errno = actual error number (global) | ||
| 37 | */ | 53 | */ | 
| 38 | #define test_newlocale(_e, _ee, _m, _l) \ | 54 | #define TESTFUNC(Fn, Ft, Af, Rf, Op) \ | 
| 39 | _test_newlocale(_e, _ee, _m, _l, __LINE__) | 55 | static void \ | 
| 40 | #define test_duplocale(_e, _ee, _l) _test_duplocale(_e, _ee, _l, __LINE__) | 56 | _test_##Fn(int line, int ee, Ft er, FUNCPARA) \ | 
| 41 | #define test_uselocale(_e, _ee, _l) _test_uselocale(_e, _ee, _l, __LINE__) | 57 | { \ | 
| 42 | #define test_setlocale(_e, _c, _l) _test_setlocale(_e, _c, _l, __LINE__) | 58 | Ft ar; \ | 
| 43 | #define test_MB_CUR_MAX(_e) _test_MB_CUR_MAX(_e, __LINE__) | 59 | errno = 0; \ | 
| 44 | 60 | ar = Fn(FUNCARGS); \ | |
| 45 | 61 | if (Op & TOPT_STR) { \ | |
| 46 | static void | 62 | if (er == (Ft)NULL) \ | 
| 47 | _test_newlocale(locale_t expected, int exp_err, | 63 | er = (Ft)"NULL"; \ | 
| 48 | int mask, const char *locname, int line) | 64 | if (ar == (Ft)NULL) \ | 
| 49 | { | 65 | ar = (Ft)"NULL"; \ | 
| 50 | locale_t result = newlocale(mask, locname, _LOCALE_NONE); | 66 | } \ | 
| 51 | 67 | if (Op & TOPT_STR ? strcmp((const char *)er, (const char *)ar) \ | |
| 52 | if (result != expected) | 68 | : ar != er) \ | 
| 53 | errx(1, "[%d] newlocale(%d, \"%s\")=\"%d\" [expected: \"%d\"]", | 69 | errx(1, "[%d] %s(" Af ")=" Rf " [exp: " Rf "]", \ | 
| 54 | line, mask, locname, (int)result, (int)expected); | 70 | line, #Fn, FUNCARGS, ar, er); \ | 
| 55 | if (errno != exp_err) | 71 | if (Op & TOPT_ERR && errno != ee) \ | 
| 56 | errx(1, "[%d] newlocale(%d, \"%s\") errno=\"%d\" [expected:" | 72 | errx(1, "[%d] %s(" Af ") errno=%d [exp: %d]", \ | 
| 57 | " \"%d\"]", line, mask, locname, errno, exp_err); | 73 | line, #Fn, FUNCARGS, errno, ee); \ | 
| 58 | errno = 0; | ||
| 59 | } | 74 | } | 
| 60 | 75 | ||
| 61 | static void | 76 | /* | 
| 62 | _test_duplocale(locale_t expected, int exp_err, locale_t oldloc, int line) | 77 | * Test functions for all tested interfaces. | 
| 63 | { | 78 | */ | 
| 64 | locale_t result = duplocale(oldloc); | 79 | #define FUNCPARA int mask, const char *locname | 
| 80 | #define FUNCARGS mask, locname, _LOCALE_NONE | ||
| 81 | TESTFUNC(newlocale, locale_t, "%d, %s, %p", "%p", TOPT_ERR) | ||
| 65 | 82 | ||
| 66 | if (result != expected) | 83 | #define FUNCPARA locale_t locale | 
| 67 | errx(1, "[%d] duplocale(%d)=\"%d\" [expected: \"%d\"]", | 84 | #define FUNCARGS locale | 
| 68 | line, (int)oldloc, (int)result, (int)expected); | 85 | TESTFUNC(duplocale, locale_t, "%p", "%p", TOPT_ERR) | 
| 69 | if (errno != exp_err) | 86 | TESTFUNC(uselocale, locale_t, "%p", "%p", TOPT_ERR) | 
| 70 | errx(1, "[%d] duplocale(%d) errno=\"%d\" [expected:" | ||
| 71 | " \"%d\"]", line, (int)oldloc, errno, exp_err); | ||
| 72 | errno = 0; | ||
| 73 | } | ||
| 74 | 87 | ||
| 75 | static void | 88 | #define FUNCPARA int category, char *locname | 
| 76 | _test_uselocale(locale_t expected, int exp_err, locale_t newloc, int line) | 89 | #define FUNCARGS category, locname | 
| 77 | { | 90 | TESTFUNC(setlocale, const char *, "%d, %s", "%s", TOPT_STR) | 
| 78 | locale_t result = uselocale(newloc); | ||
| 79 | |||
| 80 | if (result != expected) | ||
| 81 | errx(1, "[%d] uselocale(%d)=\"%d\" [expected: \"%d\"]", | ||
| 82 | line, (int)newloc, (int)result, (int)expected); | ||
| 83 | if (errno != exp_err) | ||
| 84 | errx(1, "[%d] uselocale(%d) errno=\"%d\" [expected:" | ||
| 85 | " \"%d\"]", line, (int)newloc, errno, exp_err); | ||
| 86 | errno = 0; | ||
| 87 | } | ||
| 88 | 91 | ||
| 89 | static void | 92 | static void | 
| 90 | _test_setlocale(const char *expected, int category, char *locale, int line) | 93 | _test_MB_CUR_MAX(int line, int ee, size_t ar) | 
| 91 | { | 94 | { | 
| 92 | const char *result = setlocale(category, locale); | 95 | if (MB_CUR_MAX != ar) | 
| 93 | 96 | errx(1, "[%d] MB_CUR_MAX=%zd [exp: %zd]", | |
| 94 | if (expected == NULL) | 97 | line, MB_CUR_MAX, ar); | 
| 95 | expected = "(null)"; | ||
| 96 | if (result == NULL) | ||
| 97 | result = "(null)"; | ||
| 98 | if (strcmp(expected, result) != 0) | ||
| 99 | errx(1, "[%d] setlocale(%d, \"%s\")=\"%s\" [expected: \"%s\"]", | ||
| 100 | line, category, locale, result, expected); | ||
| 101 | errno = 0; | ||
| 102 | } | 98 | } | 
| 103 | 99 | ||
| 104 | static void | 100 | /* | 
| 105 | _test_MB_CUR_MAX(size_t expected, int line) | 101 | * Test macros: | 
| 106 | { | 102 | * TEST_R(funcname, er, arguments) if you expect errno == 0. | 
| 107 | if (MB_CUR_MAX != expected) | 103 | * TEST_ER(funcname, ee, er, arguments) otherwise. | 
| 108 | errx(1, "[%d] MB_CUR_MAX=%ld [expected %ld]", | 104 | */ | 
| 109 | line, MB_CUR_MAX, expected); | 105 | #define TEST_R(Fn, ...) _test_##Fn(__LINE__, 0, __VA_ARGS__) | 
| 110 | } | 106 | #define TEST_ER(Fn, ...) _test_##Fn(__LINE__, __VA_ARGS__) | 
| 111 | 107 | ||
| 108 | /* | ||
| 109 | * SWITCH_SIGNAL wakes the other thread. | ||
| 110 | * SWITCH_WAIT goes to sleep. | ||
| 111 | * Both can be combined. | ||
| 112 | * The step argument is used for error reporting only. | ||
| 113 | */ | ||
| 112 | static void | 114 | static void | 
| 113 | switch_thread(int step, int flags) | 115 | switch_thread(int step, int flags) | 
| 114 | { | 116 | { | 
| @@ -154,67 +156,67 @@ static void * | |||
| 154 | child_func(void *arg) | 156 | child_func(void *arg) | 
| 155 | { | 157 | { | 
| 156 | /* Test invalid newlocale(3) arguments. */ | 158 | /* Test invalid newlocale(3) arguments. */ | 
| 157 | test_newlocale(_LOCALE_NONE, EINVAL, LC_CTYPE_MASK, NULL); | 159 | TEST_ER(newlocale, EINVAL, _LOCALE_NONE, LC_CTYPE_MASK, NULL); | 
| 158 | test_MB_CUR_MAX(1); | 160 | TEST_R(MB_CUR_MAX, 1); | 
| 159 | test_newlocale(_LOCALE_NONE, EINVAL, LC_ALL_MASK + 1, "C.UTF-8"); | 161 | TEST_ER(newlocale, EINVAL, _LOCALE_NONE, LC_ALL_MASK + 1, "C.UTF-8"); | 
| 160 | test_MB_CUR_MAX(1); | 162 | TEST_R(MB_CUR_MAX, 1); | 
| 161 | test_newlocale(_LOCALE_NONE, ENOENT, LC_COLLATE_MASK, "C.INV"); | 163 | TEST_ER(newlocale, ENOENT, _LOCALE_NONE, LC_COLLATE_MASK, "C.INV"); | 
| 162 | test_MB_CUR_MAX(1); | 164 | TEST_R(MB_CUR_MAX, 1); | 
| 163 | setenv("LC_TIME", "C.INV", 1); | 165 | setenv("LC_TIME", "C.INV", 1); | 
| 164 | test_newlocale(_LOCALE_NONE, ENOENT, LC_TIME_MASK, ""); | 166 | TEST_ER(newlocale, ENOENT, _LOCALE_NONE, LC_TIME_MASK, ""); | 
| 165 | unsetenv("LC_TIME"); | 167 | unsetenv("LC_TIME"); | 
| 166 | test_MB_CUR_MAX(1); | 168 | TEST_R(MB_CUR_MAX, 1); | 
| 167 | setenv("LC_CTYPE", "C.INV", 1); | 169 | setenv("LC_CTYPE", "C.INV", 1); | 
| 168 | test_newlocale(_LOCALE_NONE, ENOENT, LC_CTYPE_MASK, ""); | 170 | TEST_ER(newlocale, ENOENT, _LOCALE_NONE, LC_CTYPE_MASK, ""); | 
| 169 | test_MB_CUR_MAX(1); | 171 | TEST_R(MB_CUR_MAX, 1); | 
| 170 | 172 | ||
| 171 | /* Test duplocale(3). */ | 173 | /* Test duplocale(3). */ | 
| 172 | test_duplocale(_LOCALE_NONE, EINVAL, _LOCALE_UTF8); | 174 | TEST_ER(duplocale, EINVAL, _LOCALE_NONE, _LOCALE_UTF8); | 
| 173 | test_duplocale(_LOCALE_C, 0, _LOCALE_C); | 175 | TEST_R(duplocale, _LOCALE_C, _LOCALE_C); | 
| 174 | test_duplocale(_LOCALE_C, 0, LC_GLOBAL_LOCALE); | 176 | TEST_R(duplocale, _LOCALE_C, LC_GLOBAL_LOCALE); | 
| 175 | 177 | ||
| 176 | /* Test premature UTF-8 uselocale(3). */ | 178 | /* Test premature UTF-8 uselocale(3). */ | 
| 177 | test_uselocale(_LOCALE_NONE, EINVAL, _LOCALE_UTF8); | 179 | TEST_ER(uselocale, EINVAL, _LOCALE_NONE, _LOCALE_UTF8); | 
| 178 | test_MB_CUR_MAX(1); | 180 | TEST_R(MB_CUR_MAX, 1); | 
| 179 | test_uselocale(LC_GLOBAL_LOCALE, 0, _LOCALE_NONE); | 181 | TEST_R(uselocale, LC_GLOBAL_LOCALE, _LOCALE_NONE); | 
| 180 | 182 | ||
| 181 | /* Test UTF-8 initialization. */ | 183 | /* Test UTF-8 initialization. */ | 
| 182 | setenv("LC_CTYPE", "C.UTF-8", 1); | 184 | setenv("LC_CTYPE", "C.UTF-8", 1); | 
| 183 | test_newlocale(_LOCALE_UTF8, 0, LC_CTYPE_MASK, ""); | 185 | TEST_R(newlocale, _LOCALE_UTF8, LC_CTYPE_MASK, ""); | 
| 184 | unsetenv("LC_CTYPE"); | 186 | unsetenv("LC_CTYPE"); | 
| 185 | test_MB_CUR_MAX(1); | 187 | TEST_R(MB_CUR_MAX, 1); | 
| 186 | test_duplocale(_LOCALE_UTF8, 0, _LOCALE_UTF8); | 188 | TEST_R(duplocale, _LOCALE_UTF8, _LOCALE_UTF8); | 
| 187 | 189 | ||
| 188 | /* Test invalid uselocale(3) argument. */ | 190 | /* Test invalid uselocale(3) argument. */ | 
| 189 | test_uselocale(_LOCALE_NONE, EINVAL, _LOCALE_BAD); | 191 | TEST_ER(uselocale, EINVAL, _LOCALE_NONE, _LOCALE_BAD); | 
| 190 | test_MB_CUR_MAX(1); | 192 | TEST_R(MB_CUR_MAX, 1); | 
| 191 | test_uselocale(LC_GLOBAL_LOCALE, 0, _LOCALE_NONE); | 193 | TEST_R(uselocale, LC_GLOBAL_LOCALE, _LOCALE_NONE); | 
| 192 | 194 | ||
| 193 | /* Test switching the thread locale. */ | 195 | /* Test switching the thread locale. */ | 
| 194 | test_uselocale(LC_GLOBAL_LOCALE, 0, _LOCALE_UTF8); | 196 | TEST_R(uselocale, LC_GLOBAL_LOCALE, _LOCALE_UTF8); | 
| 195 | test_MB_CUR_MAX(4); | 197 | TEST_R(MB_CUR_MAX, 4); | 
| 196 | test_uselocale(_LOCALE_UTF8, 0, _LOCALE_NONE); | 198 | TEST_R(uselocale, _LOCALE_UTF8, _LOCALE_NONE); | 
| 197 | 199 | ||
| 198 | /* Test non-ctype newlocale(3). */ | 200 | /* Test non-ctype newlocale(3). */ | 
| 199 | test_newlocale(_LOCALE_C, 0, LC_MESSAGES_MASK, "en_US.UTF-8"); | 201 | TEST_R(newlocale, _LOCALE_C, LC_MESSAGES_MASK, "en_US.UTF-8"); | 
| 200 | 202 | ||
| 201 | /* Temporarily switch to the main thread. */ | 203 | /* Temporarily switch to the main thread. */ | 
| 202 | switch_thread(2, SWITCH_SIGNAL | SWITCH_WAIT); | 204 | switch_thread(2, SWITCH_SIGNAL | SWITCH_WAIT); | 
| 203 | 205 | ||
| 204 | /* Test displaying the global locale while a local one is set. */ | 206 | /* Test displaying the global locale while a local one is set. */ | 
| 205 | test_setlocale("C/C.UTF-8/C/C/C/C", LC_ALL, NULL); | 207 | TEST_R(setlocale, "C/C.UTF-8/C/C/C/C", LC_ALL, NULL); | 
| 206 | 208 | ||
| 207 | /* Test switching the thread locale back. */ | 209 | /* Test switching the thread locale back. */ | 
| 208 | test_MB_CUR_MAX(4); | 210 | TEST_R(MB_CUR_MAX, 4); | 
| 209 | test_duplocale(_LOCALE_UTF8, 0, LC_GLOBAL_LOCALE); | 211 | TEST_R(duplocale, _LOCALE_UTF8, LC_GLOBAL_LOCALE); | 
| 210 | test_uselocale(_LOCALE_UTF8, 0, _LOCALE_C); | 212 | TEST_R(uselocale, _LOCALE_UTF8, _LOCALE_C); | 
| 211 | test_MB_CUR_MAX(1); | 213 | TEST_R(MB_CUR_MAX, 1); | 
| 212 | test_uselocale(_LOCALE_C, 0, _LOCALE_NONE); | 214 | TEST_R(uselocale, _LOCALE_C, _LOCALE_NONE); | 
| 213 | 215 | ||
| 214 | /* Test switching back to the global locale. */ | 216 | /* Test switching back to the global locale. */ | 
| 215 | test_uselocale(_LOCALE_C, 0, LC_GLOBAL_LOCALE); | 217 | TEST_R(uselocale, _LOCALE_C, LC_GLOBAL_LOCALE); | 
| 216 | test_MB_CUR_MAX(4); | 218 | TEST_R(MB_CUR_MAX, 4); | 
| 217 | test_uselocale(LC_GLOBAL_LOCALE, 0, _LOCALE_NONE); | 219 | TEST_R(uselocale, LC_GLOBAL_LOCALE, _LOCALE_NONE); | 
| 218 | 220 | ||
| 219 | /* Hand control back to the main thread. */ | 221 | /* Hand control back to the main thread. */ | 
| 220 | switch_thread(4, SWITCH_SIGNAL); | 222 | switch_thread(4, SWITCH_SIGNAL); | 
| @@ -243,13 +245,13 @@ main(void) | |||
| 243 | switch_thread(1, SWITCH_WAIT); | 245 | switch_thread(1, SWITCH_WAIT); | 
| 244 | 246 | ||
| 245 | /* Check that the global locale is undisturbed. */ | 247 | /* Check that the global locale is undisturbed. */ | 
| 246 | test_setlocale("C", LC_ALL, NULL); | 248 | TEST_R(setlocale, "C", LC_ALL, NULL); | 
| 247 | test_MB_CUR_MAX(1); | 249 | TEST_R(MB_CUR_MAX, 1); | 
| 248 | 250 | ||
| 249 | /* Test setting the globale locale. */ | 251 | /* Test setting the globale locale. */ | 
| 250 | test_setlocale("C.UTF-8", LC_CTYPE, "C.UTF-8"); | 252 | TEST_R(setlocale, "C.UTF-8", LC_CTYPE, "C.UTF-8"); | 
| 251 | test_MB_CUR_MAX(4); | 253 | TEST_R(MB_CUR_MAX, 4); | 
| 252 | test_uselocale(LC_GLOBAL_LOCALE, 0, _LOCALE_NONE); | 254 | TEST_R(uselocale, LC_GLOBAL_LOCALE, _LOCALE_NONE); | 
| 253 | 255 | ||
| 254 | /* Let the child do some more tests, then clean up. */ | 256 | /* Let the child do some more tests, then clean up. */ | 
| 255 | switch_thread(3, SWITCH_SIGNAL); | 257 | switch_thread(3, SWITCH_SIGNAL); | 
