xref: /illumos-gate/usr/src/test/libc-tests/tests/strtox.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 locale interaction with strto{f,d,ld}(3C) and
19*4f2483e5SBill Sommerfeld  * strto{f,d,ld}_l(3C). The libc tests depend on locale/ar, locale/de,
20*4f2483e5SBill Sommerfeld  * locale/en, and locale/ja. We limit ourselves to these locales, plus
21*4f2483e5SBill Sommerfeld  * C.UTF-8.
22*4f2483e5SBill Sommerfeld  */
23*4f2483e5SBill Sommerfeld 
24*4f2483e5SBill Sommerfeld #include <err.h>
25*4f2483e5SBill Sommerfeld #include <stdlib.h>
26*4f2483e5SBill Sommerfeld #include <xlocale.h>
27*4f2483e5SBill Sommerfeld #include <locale.h>
28*4f2483e5SBill Sommerfeld #include <sys/sysmacros.h>
29*4f2483e5SBill Sommerfeld #include <sys/debug.h>
30*4f2483e5SBill Sommerfeld #include <stdbool.h>
31*4f2483e5SBill Sommerfeld #include <string.h>
32*4f2483e5SBill Sommerfeld 
33*4f2483e5SBill Sommerfeld /*
34*4f2483e5SBill Sommerfeld  * We use a value with a fractional part that can be represented exactly
35*4f2483e5SBill Sommerfeld  * as a binary floating point number
36*4f2483e5SBill Sommerfeld  */
37*4f2483e5SBill Sommerfeld 
38*4f2483e5SBill Sommerfeld static struct test_locale {
39*4f2483e5SBill Sommerfeld 	char *name;
40*4f2483e5SBill Sommerfeld 	char *number;
41*4f2483e5SBill Sommerfeld } locales[] = {
42*4f2483e5SBill Sommerfeld 	{ "C.UTF-8", "1.5"},
43*4f2483e5SBill Sommerfeld 	{"ja_JP.UTF-8", "1.5"},
44*4f2483e5SBill Sommerfeld 	{"de_DE.UTF-8", "1,5"},
45*4f2483e5SBill Sommerfeld 	{"en_US.UTF-8", "1.5"},
46*4f2483e5SBill Sommerfeld 	{"en_GB.UTF-8", "1.5" },
47*4f2483e5SBill Sommerfeld };
48*4f2483e5SBill Sommerfeld 
49*4f2483e5SBill Sommerfeld /*
50*4f2483e5SBill Sommerfeld  * Test that the correct decimal point is recognized.
51*4f2483e5SBill Sommerfeld  */
52*4f2483e5SBill Sommerfeld bool
test_locale(char * name,char * number)53*4f2483e5SBill Sommerfeld test_locale(char *name, char *number)
54*4f2483e5SBill Sommerfeld {
55*4f2483e5SBill Sommerfeld 	bool result_ok = true;
56*4f2483e5SBill Sommerfeld 	const float expected_f = 1.5;
57*4f2483e5SBill Sommerfeld 	const double expected_d = 1.5;
58*4f2483e5SBill Sommerfeld 	const long double expected_ld = 1.5;
59*4f2483e5SBill Sommerfeld 	char *expected_end = number + strlen(number);
60*4f2483e5SBill Sommerfeld 	char *actual_end;
61*4f2483e5SBill Sommerfeld 	float actual_f;
62*4f2483e5SBill Sommerfeld 	double actual_d;
63*4f2483e5SBill Sommerfeld 	long double actual_ld;
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 #define	CHECK_END(fn) \
73*4f2483e5SBill Sommerfeld 	if (actual_end != expected_end) {				\
74*4f2483e5SBill Sommerfeld 		warn("Locale %s, function %s: consumed %td characters"	\
75*4f2483e5SBill Sommerfeld 		    " (%td expected)", name, #fn,			\
76*4f2483e5SBill Sommerfeld 		    actual_end - number, expected_end - number);	\
77*4f2483e5SBill Sommerfeld 		result_ok = false;					\
78*4f2483e5SBill Sommerfeld 	}
79*4f2483e5SBill Sommerfeld 
80*4f2483e5SBill Sommerfeld 	actual_f = strtof_l(number, &actual_end, loc);
81*4f2483e5SBill Sommerfeld 	if (actual_f != expected_f) {
82*4f2483e5SBill Sommerfeld 		result_ok = false;
83*4f2483e5SBill Sommerfeld 		warn("Locale %s: strtof_l: mismatched value %f vs %f",
84*4f2483e5SBill Sommerfeld 		    name, actual_f, expected_f);
85*4f2483e5SBill Sommerfeld 	}
86*4f2483e5SBill Sommerfeld 	CHECK_END(strtof_l);
87*4f2483e5SBill Sommerfeld 
88*4f2483e5SBill Sommerfeld 	actual_d = strtod_l(number, &actual_end, loc);
89*4f2483e5SBill Sommerfeld 	if (actual_d != expected_d) {
90*4f2483e5SBill Sommerfeld 		result_ok = false;
91*4f2483e5SBill Sommerfeld 		warn("Locale %s: strtod_l: mismatched value %f vs %f",
92*4f2483e5SBill Sommerfeld 		    name, actual_d, expected_d);
93*4f2483e5SBill Sommerfeld 	}
94*4f2483e5SBill Sommerfeld 	CHECK_END(strtod_l);
95*4f2483e5SBill Sommerfeld 
96*4f2483e5SBill Sommerfeld 	actual_ld = strtold_l(number, &actual_end, loc);
97*4f2483e5SBill Sommerfeld 	if (actual_ld != expected_ld) {
98*4f2483e5SBill Sommerfeld 		result_ok = false;
99*4f2483e5SBill Sommerfeld 		warn("Locale %s: strtold_l: mismatched value %Lf vs %Lf",
100*4f2483e5SBill Sommerfeld 		    name, actual_ld, expected_ld);
101*4f2483e5SBill Sommerfeld 	}
102*4f2483e5SBill Sommerfeld 	CHECK_END(strtold_l);
103*4f2483e5SBill Sommerfeld 
104*4f2483e5SBill Sommerfeld 	if (uselocale(loc) == NULL) {
105*4f2483e5SBill Sommerfeld 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
106*4f2483e5SBill Sommerfeld 		    "set locale %s", name);
107*4f2483e5SBill Sommerfeld 	}
108*4f2483e5SBill Sommerfeld 
109*4f2483e5SBill Sommerfeld 	actual_f = strtod(number, &actual_end);
110*4f2483e5SBill Sommerfeld 	if (actual_f != expected_f) {
111*4f2483e5SBill Sommerfeld 		result_ok = false;
112*4f2483e5SBill Sommerfeld 		warn("Locale %s: strtof: mismatched value %f vs %f",
113*4f2483e5SBill Sommerfeld 		    name, actual_f, expected_f);
114*4f2483e5SBill Sommerfeld 	}
115*4f2483e5SBill Sommerfeld 	CHECK_END(strtof);
116*4f2483e5SBill Sommerfeld 
117*4f2483e5SBill Sommerfeld 	actual_d = strtod(number, &actual_end);
118*4f2483e5SBill Sommerfeld 	if (actual_d != expected_d) {
119*4f2483e5SBill Sommerfeld 		result_ok = false;
120*4f2483e5SBill Sommerfeld 		warn("Locale %s: strtod: mismatched value %f vs %f",
121*4f2483e5SBill Sommerfeld 		    name, actual_d, expected_d);
122*4f2483e5SBill Sommerfeld 	}
123*4f2483e5SBill Sommerfeld 	CHECK_END(strtod);
124*4f2483e5SBill Sommerfeld 
125*4f2483e5SBill Sommerfeld 	actual_ld = strtold(number, &actual_end);
126*4f2483e5SBill Sommerfeld 	if (actual_ld != expected_ld) {
127*4f2483e5SBill Sommerfeld 		result_ok = false;
128*4f2483e5SBill Sommerfeld 		warn("Locale %s: strtold: mismatched value %Lf vs %Lf",
129*4f2483e5SBill Sommerfeld 		    name, actual_ld, expected_ld);
130*4f2483e5SBill Sommerfeld 	}
131*4f2483e5SBill Sommerfeld 	CHECK_END(strtold);
132*4f2483e5SBill Sommerfeld 
133*4f2483e5SBill Sommerfeld 	return (result_ok);
134*4f2483e5SBill Sommerfeld }
135*4f2483e5SBill Sommerfeld 
136*4f2483e5SBill Sommerfeld 
137*4f2483e5SBill Sommerfeld int
main(void)138*4f2483e5SBill Sommerfeld main(void)
139*4f2483e5SBill Sommerfeld {
140*4f2483e5SBill Sommerfeld 	int ret = EXIT_SUCCESS;
141*4f2483e5SBill Sommerfeld 
142*4f2483e5SBill Sommerfeld 	for (size_t i = 0; i < ARRAY_SIZE(locales); i++) {
143*4f2483e5SBill Sommerfeld 		if (!test_locale(locales[i].name, locales[i].number))
144*4f2483e5SBill Sommerfeld 			ret = EXIT_FAILURE;
145*4f2483e5SBill Sommerfeld 	}
146*4f2483e5SBill Sommerfeld 
147*4f2483e5SBill Sommerfeld 	if (ret == EXIT_SUCCESS) {
148*4f2483e5SBill Sommerfeld 		(void) printf("All tests completed successfully\n");
149*4f2483e5SBill Sommerfeld 	}
150*4f2483e5SBill Sommerfeld 
151*4f2483e5SBill Sommerfeld 	return (ret);
152*4f2483e5SBill Sommerfeld }
153