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