1/* Test for localedef path name handling and normalization.
2 Copyright (C) 2020-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19/* The test runs localedef with various named paths to test for expected
20 behaviours dealing with codeset name normalization. That is to say that use
21 of UTF-8, and it's variations, are normalized to utf8. Likewise that values
22 after the @ are not normalized and left as-is. The test needs to run
23 localedef with known input values and then check that the generated path
24 matches the expected value after normalization. */
25
26/* Note: In some cases adding -v (verbose) to localedef changes the exit
27 status to a non-zero value because some warnings are only enabled in verbose
28 mode. This should probably be changed so warnings are either present or not
29 present, regardless of verbosity. POSIX requires that any warnings cause the
30 exit status to be non-zero. */
31
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <unistd.h>
35
36#include <support/capture_subprocess.h>
37#include <support/check.h>
38#include <support/support.h>
39#include <support/xunistd.h>
40
41/* Full path to localedef. */
42char *prog;
43
44/* Execute localedef in a subprocess. */
45static void
46execv_wrapper (void *args)
47{
48 char **argv = args;
49
50 execv (path: prog, argv: argv);
51 FAIL_EXIT1 ("execv: %m");
52}
53
54struct test_closure
55{
56 /* Arguments for running localedef. */
57 const char *const argv[16];
58 /* Expected directory name for compiled locale. */
59 const char *exp;
60 /* Expected path to compiled locale. */
61 const char *complocaledir;
62};
63
64/* Run localedef with DATA.ARGV arguments (NULL terminated), and expect path to
65 the compiled locale is "DATA.COMPLOCALEDIR/DATA.EXP". */
66static void
67run_test (struct test_closure data)
68{
69 const char * const *args = data.argv;
70 const char *exp = data.exp;
71 const char *complocaledir = data.complocaledir;
72 struct stat64 fs;
73
74 /* Expected output path. */
75 const char *path = xasprintf (format: "%s/%s", complocaledir, exp);
76
77 /* Run test. */
78 struct support_capture_subprocess result;
79 result = support_capture_subprocess (callback: execv_wrapper, closure: (void *)args);
80 support_capture_subprocess_check (&result, context: "execv", status_or_signal: 0, allowed: sc_allow_none);
81 support_capture_subprocess_free (&result);
82
83 /* Verify path is present and is a directory. */
84 xstat (path, &fs);
85 TEST_VERIFY_EXIT (S_ISDIR (fs.st_mode));
86 printf (format: "info: Directory '%s' exists.\n", path);
87}
88
89static int
90do_test (void)
91{
92 /* We are running as root inside the container. */
93 prog = xasprintf (format: "%s/localedef", support_bindir_prefix);
94
95 /* We need an arbitrary absolute path for localedef output.
96 Writing to a non-default absolute path disables any kind
97 of path normalization since we expect the user wants the path
98 exactly as they specified it. */
99#define ABSDIR "/output"
100 xmkdirp (ABSDIR, 0777);
101
102 /* It takes ~10 seconds to serially execute 9 localedef test. We
103 could run the compilations in parallel if we want to reduce test
104 time. We don't want to split this out into distinct tests because
105 it would require multiple chroots. Batching the same localedef
106 tests saves disk space during testing. */
107
108 /* Test 1: Expected normalization.
109 Run localedef and expect output in $(complocaledir)/en_US1.utf8,
110 with normalization changing UTF-8 to utf8. */
111 run_test (data: (struct test_closure)
112 {
113 .argv = { prog,
114 "--no-archive",
115 "-i", "en_US",
116 "-f", "UTF-8",
117 "en_US1.UTF-8", NULL },
118 .exp = "en_US1.utf8",
119 .complocaledir = support_complocaledir_prefix
120 });
121
122 /* Test 2: No normalization past '@'.
123 Run localedef and expect output in $(complocaledir)/en_US2.utf8@tEsT,
124 with normalization changing UTF-8@tEsT to utf8@tEsT (everything after
125 @ is untouched). */
126 run_test (data: (struct test_closure)
127 {
128 .argv = { prog,
129 "--no-archive",
130 "-i", "en_US",
131 "-f", "UTF-8",
132 "en_US2.UTF-8@tEsT", NULL },
133 .exp = "en_US2.utf8@tEsT",
134 .complocaledir = support_complocaledir_prefix
135 });
136
137 /* Test 3: No normalization past '@' despite period.
138 Run localedef and expect output in $(complocaledir)/en_US3@tEsT.UTF-8,
139 with normalization changing nothing (everything after @ is untouched)
140 despite there being a period near the end. */
141 run_test (data: (struct test_closure)
142 {
143 .argv = { prog,
144 "--no-archive",
145 "-i", "en_US",
146 "-f", "UTF-8",
147 "en_US3@tEsT.UTF-8", NULL },
148 .exp = "en_US3@tEsT.UTF-8",
149 .complocaledir = support_complocaledir_prefix
150 });
151
152 /* Test 4: Normalize numeric codeset by adding 'iso' prefix.
153 Run localedef and expect output in $(complocaledir)/en_US4.88591,
154 with normalization changing 88591 to iso88591. */
155 run_test (data: (struct test_closure)
156 {
157 .argv = { prog,
158 "--no-archive",
159 "-i", "en_US",
160 "-f", "UTF-8",
161 "en_US4.88591", NULL },
162 .exp = "en_US4.iso88591",
163 .complocaledir = support_complocaledir_prefix
164 });
165
166 /* Test 5: Don't add 'iso' prefix if first char is alpha.
167 Run localedef and expect output in $(complocaledir)/en_US5.a88591,
168 with normalization changing nothing. */
169 run_test (data: (struct test_closure)
170 {
171 .argv = { prog,
172 "--no-archive",
173 "-i", "en_US",
174 "-f", "UTF-8",
175 "en_US5.a88591", NULL },
176 .exp = "en_US5.a88591",
177 .complocaledir = support_complocaledir_prefix
178 });
179
180 /* Test 6: Don't add 'iso' prefix if last char is alpha.
181 Run localedef and expect output in $(complocaledir)/en_US6.88591a,
182 with normalization changing nothing. */
183 run_test (data: (struct test_closure)
184 {
185 .argv = { prog,
186 "--no-archive",
187 "-i", "en_US",
188 "-f", "UTF-8",
189 "en_US6.88591a", NULL },
190 .exp = "en_US6.88591a",
191 .complocaledir = support_complocaledir_prefix
192 });
193
194 /* Test 7: Don't normalize anything with an absolute path.
195 Run localedef and expect output in ABSDIR/en_US7.UTF-8,
196 with normalization changing nothing. */
197 run_test (data: (struct test_closure)
198 {
199 .argv = { prog,
200 "--no-archive",
201 "-i", "en_US",
202 "-f", "UTF-8",
203 ABSDIR "/en_US7.UTF-8", NULL },
204 .exp = "en_US7.UTF-8",
205 .complocaledir = ABSDIR
206 });
207
208 /* Test 8: Don't normalize anything with an absolute path.
209 Run localedef and expect output in ABSDIR/en_US8.UTF-8@tEsT,
210 with normalization changing nothing. */
211 run_test (data: (struct test_closure)
212 {
213 .argv = { prog,
214 "--no-archive",
215 "-i", "en_US",
216 "-f", "UTF-8",
217 ABSDIR "/en_US8.UTF-8@tEsT", NULL },
218 .exp = "en_US8.UTF-8@tEsT",
219 .complocaledir = ABSDIR
220 });
221
222 /* Test 9: Don't normalize anything with an absolute path.
223 Run localedef and expect output in ABSDIR/en_US9@tEsT.UTF-8,
224 with normalization changing nothing. */
225 run_test (data: (struct test_closure)
226 {
227 .argv = { prog,
228 "--no-archive",
229 "-i", "en_US",
230 "-f", "UTF-8",
231 ABSDIR "/en_US9@tEsT.UTF-8", NULL },
232 .exp = "en_US9@tEsT.UTF-8",
233 .complocaledir = ABSDIR
234 });
235
236 return 0;
237}
238
239#define TIMEOUT 30
240#include <support/test-driver.c>
241

source code of glibc/locale/tst-localedef-path-norm.c