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