xref: /illumos-gate/usr/src/test/libc-tests/tests/wcsftime.c (revision 4f2483e5d0c339c7ac30db66a67c108da0b33ca6)
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 2025 Oxide Computer Company
14  * Copyright 2025 Bill Sommerfeld
15  */
16 
17 /*
18  * Tests for modern wcsftime (XPG5 and later) and wcsftime_l.   The libc tests
19  * depend on locale/ar, locale/de, locale/en, and locale/ja. We limit
20  * ourselves to these locales, plus C.UTF-8.
21  */
22 
23 #include <err.h>
24 #include <stdlib.h>
25 #include <xlocale.h>
26 #include <locale.h>
27 #include <sys/sysmacros.h>
28 #include <sys/debug.h>
29 #include <stdbool.h>
30 #include <string.h>
31 
32 
33 /*
34  * We're just testing that the desired locale reaches the underlying
35  * formatter so we only look at one attribute: the full month name.
36  */
37 static const struct test_locale {
38 	const char *name;
39 	const char *monthname;
40 } locales[] = {
41 	{ "C.UTF-8", "December"},
42 	{"ja_JP.UTF-8", "12月"},
43 	{"de_DE.UTF-8", "Dezember"},
44 	{"en_US.UTF-8", "December"},
45 };
46 
47 struct tm sample_tm = { .tm_mon = 11 };
48 
49 #define	WCSSIZE 100
50 #define	CSIZE 200
51 
52 /*
53  * Test that the correct decimal point is recognized.
54  */
55 bool
test_locale(const char * name,const char * monthname)56 test_locale(const char *name, const char *monthname)
57 {
58 	bool result_ok = true;
59 	wchar_t wfmt[WCSSIZE];
60 	wchar_t wcs[WCSSIZE];
61 	char cstring[CSIZE];
62 
63 	size_t len;
64 
65 	locale_t loc = newlocale(LC_ALL_MASK, name, NULL);
66 
67 	if (loc == NULL) {
68 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
69 		    "construct locale %s", name);
70 	}
71 
72 	if (mbstowcs_l(wfmt, "%B", WCSSIZE, loc) == (size_t)-1) {
73 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
74 		    "construct wide char format string");
75 	}
76 
77 	len = wcsftime_l(wcs, WCSSIZE, wfmt, &sample_tm, loc);
78 	if (len == (size_t)-1) {
79 		warn("wcsftime_l returned -1");
80 		result_ok = false;
81 	}
82 
83 	if (wcstombs_l(cstring, wcs, CSIZE, loc) == (size_t)-1) {
84 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
85 		    "convert wide char string back to multibyte string");
86 	}
87 
88 	if (strcmp(cstring, monthname)) {
89 		warn("Wrong monthname for locale %s month %d: "
90 		    "got %s expected %s", name, sample_tm.tm_mon+1,
91 		    cstring, monthname);
92 		result_ok = false;
93 	}
94 
95 	(void) memset(wcs, 0, sizeof (wcs));
96 	(void) memset(cstring, 0, sizeof (cstring));
97 
98 	if (uselocale(loc) == NULL) {
99 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
100 		    "set locale %s", name);
101 	}
102 
103 	len = wcsftime(wcs, WCSSIZE, wfmt, &sample_tm);
104 	if (len == (size_t)-1) {
105 		warn("wcsftime_l returned -1");
106 		result_ok = false;
107 	}
108 
109 	if (wcstombs(cstring, wcs, CSIZE) == (size_t)-1) {
110 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
111 		    "convert wide char string back to multibyte string");
112 	}
113 
114 	if (strcmp(cstring, monthname)) {
115 		warn("Wrong monthname for locale %s month %d: "
116 		    "got %s expected %s", name, sample_tm.tm_mon+1,
117 		    cstring, monthname);
118 		result_ok = false;
119 	}
120 
121 	return (result_ok);
122 }
123 
124 
125 int
main(void)126 main(void)
127 {
128 	int ret = EXIT_SUCCESS;
129 
130 	for (size_t i = 0; i < ARRAY_SIZE(locales); i++) {
131 		if (!test_locale(locales[i].name, locales[i].monthname))
132 			ret = EXIT_FAILURE;
133 	}
134 
135 	if (ret == EXIT_SUCCESS) {
136 		(void) printf("All tests completed successfully\n");
137 	}
138 
139 	return (ret);
140 }
141