t_sprintf.c revision 1.2 1 /* $NetBSD: t_sprintf.c,v 1.2 2017/06/07 22:59:42 perseant Exp $ */
2
3 /*-
4 * Copyright (c) 2017 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Konrad Schroder.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __COPYRIGHT("@(#) Copyright (c) 2017\
34 The NetBSD Foundation, inc. All rights reserved.");
35 __RCSID("$NetBSD: t_sprintf.c,v 1.2 2017/06/07 22:59:42 perseant Exp $");
36
37 #include <locale.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <limits.h>
42 #include <ctype.h>
43
44 #include <atf-c.h>
45
46 static struct test {
47 const char *locale;
48 const int int_value;
49 const char *int_result;
50 const char *int_input;
51 const double double_value;
52 const char *double_result;
53 const char *double_input;
54 } tests[] = {
55 {
56 "en_US.UTF-8",
57 -12345,
58 "-12,345",
59 "-12345",
60 -12345.6789,
61 "-12,345.678900",
62 "-12345.678900",
63 }, {
64 "fr_FR.ISO8859-1",
65 -12345,
66 "-12\240345",
67 "-12345",
68 -12345.6789,
69 "-12\240345,678900",
70 "-12345,678900",
71 }, {
72 "it_IT.ISO8859-1",
73 -12345,
74 "-12.345",
75 "-12345",
76 -12345.6789,
77 "-12.345,678900",
78 "-12345,678900",
79 }, {
80 "POSIX",
81 /*
82 * POSIX-1.2008 specifies that the C and POSIX
83 * locales shall be identical (section 7.2) and
84 * that the POSIX locale shall have an empty
85 * thousands separator and "<period>" as its
86 * decimal point (section 7.3.4). *printf
87 * ought to honor these settings.
88 */
89 -12345,
90 "-12345",
91 "-12345",
92 -12345.6789,
93 "-12345.678900",
94 "-12345.678900",
95 }, {
96 NULL,
97 0,
98 NULL,
99 NULL,
100 0.0,
101 NULL,
102 NULL,
103 }
104 };
105
106 static void
107 h_sprintf(const struct test *t)
108 {
109 char buf[1024];
110
111 ATF_REQUIRE_STREQ(setlocale(LC_ALL, "C"), "C");
112 printf("Trying locale %s...\n", t->locale);
113 ATF_REQUIRE(setlocale(LC_NUMERIC, t->locale) != NULL);
114 printf("Using locale: %s\n", setlocale(LC_ALL, NULL));
115
116 if (!strcmp("POSIX", t->locale))
117 atf_tc_expect_fail("%s", "PR standards/52282, printf doesn't respect empty thousands separator");
118
119 sprintf(buf, "%'f", t->double_value);
120 ATF_REQUIRE_STREQ(buf, t->double_result);
121
122 sprintf(buf, "%'d", t->int_value);
123 ATF_REQUIRE_STREQ(buf, t->int_result);
124
125 atf_tc_expect_pass();
126 }
127
128 static void
129 h_strto(const struct test *t)
130 {
131 ATF_REQUIRE_STREQ(setlocale(LC_ALL, "C"), "C");
132 printf("Trying locale %s...\n", t->locale);
133 ATF_REQUIRE(setlocale(LC_NUMERIC, t->locale) != NULL);
134
135 ATF_REQUIRE_EQ((int)strtol(t->int_input, NULL, 10), t->int_value);
136 ATF_REQUIRE_EQ(strtod(t->double_input, NULL), t->double_value);
137 }
138
139 static void
140 h_sscanf(const struct test *t)
141 {
142 int int_reported;
143 double double_reported;
144
145 ATF_REQUIRE_STREQ(setlocale(LC_ALL, "C"), "C");
146 printf("Trying locale %s...\n", t->locale);
147 ATF_REQUIRE(setlocale(LC_NUMERIC, t->locale) != NULL);
148
149 sscanf(t->int_input, "%d", &int_reported);
150 ATF_REQUIRE_EQ(int_reported, t->int_value);
151 sscanf(t->double_input, "%lf", &double_reported);
152 ATF_REQUIRE_EQ(double_reported, t->double_value);
153 }
154
155 ATF_TC(sprintf);
156 ATF_TC_HEAD(sprintf, tc)
157 {
158 atf_tc_set_md_var(tc, "descr",
159 "Checks sprintf %%'d and %%'f under diferent locales");
160 }
161 ATF_TC_BODY(sprintf, tc)
162 {
163 struct test *t;
164
165 for (t = &tests[0]; t->locale != NULL; ++t)
166 h_sprintf(t);
167 }
168
169 ATF_TC(strto);
170 ATF_TC_HEAD(strto, tc)
171 {
172 atf_tc_set_md_var(tc, "descr",
173 "Checks strtol and strtod under diferent locales");
174 }
175 ATF_TC_BODY(strto, tc)
176 {
177 struct test *t;
178
179 for (t = &tests[0]; t->locale != NULL; ++t)
180 h_strto(t);
181 }
182
183 ATF_TC(sscanf);
184 ATF_TC_HEAD(sscanf, tc)
185 {
186 atf_tc_set_md_var(tc, "descr",
187 "Checks sscanf under diferent locales");
188 }
189 ATF_TC_BODY(sscanf, tc)
190 {
191 struct test *t;
192
193 for (t = &tests[0]; t->locale != NULL; ++t)
194 h_sscanf(t);
195 }
196
197 ATF_TP_ADD_TCS(tp)
198 {
199
200 ATF_TP_ADD_TC(tp, sprintf);
201 ATF_TP_ADD_TC(tp, sscanf);
202 ATF_TP_ADD_TC(tp, strto);
203
204 return atf_no_error();
205 }
206