This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
t/loc_tools.pl: Consider thread 0 always locale-safe
[perl5.git] / t / run / locale.t
CommitLineData
9c6df44e
NT
1#!./perl
2BEGIN {
3 chdir 't' if -d 't';
4 @INC = '../lib';
5 require './test.pl'; # for fresh_perl_is() etc
a5dfa8d3 6 require './loc_tools.pl'; # to find locales
9c6df44e
NT
7}
8
9use strict;
10
11########
903eb63f 12# These tests are here instead of lib/locale.t because
05760874 13# some bugs depend on the internal state of the locale
9c6df44e 14# settings and pragma/locale messes up that state pretty badly.
903eb63f 15# We need "fresh runs".
9c6df44e 16BEGIN {
903eb63f 17 eval { require POSIX; POSIX->import("locale_h") };
9c6df44e
NT
18 if ($@) {
19 skip_all("could not load the POSIX module"); # running minitest?
20 }
21}
22use Config;
371d5d44 23my $have_strtod = $Config{d_strtod} eq 'define';
cd1f7080 24my @locales = find_locales( [ 'LC_ALL', 'LC_CTYPE', 'LC_NUMERIC' ]);
9c6df44e 25skip_all("no locales available") unless @locales;
238fb9b3 26note("locales available: @locales");
9c6df44e 27
40f10af4
KW
28my $debug = 0;
29my $switches = "";
30if (defined $ARGV[0] && $ARGV[0] ne "") {
31 if ($ARGV[0] ne 'debug') {
32 print STDERR "Usage: $0 [ debug ]\n";
33 exit 1
34 }
35 $debug = 1;
36 $switches = "switches => [ '-DLv' ]";
37}
38
c53481e7 39# reset the locale environment
d5e32b93 40delete local @ENV{'LANG', (grep /^LC_[A-Z]+$/, keys %ENV)};
c53481e7 41
40f10af4
KW
42# If user wants this to happen, they set the environment variable AND use
43# 'debug'
44delete local $ENV{'PERL_DEBUG_LOCALE_INIT'} unless $debug;
45
385130eb
KW
46{
47 fresh_perl_is(<<"EOF",
48 use locale;
49 use POSIX;
50 POSIX::setlocale(POSIX::LC_CTYPE(),"C");
51 print "h" =~ /[g\\w]/i || 0;
52 print "\\n";
53EOF
54 1, { stderr => 'devnull' }, "/il matching of [bracketed] doesn't skip POSIX class if fails individ char");
55}
56
57{
58 fresh_perl_is(<<"EOF",
59 use locale;
60 use POSIX;
61 POSIX::setlocale(POSIX::LC_CTYPE(),"C");
62 print "0" =~ /[\\d[:punct:]]/l || 0;
63 print "\\n";
64EOF
65 1, { stderr => 'devnull' }, "/l matching of [bracketed] doesn't skip non-first POSIX class");
66
67}
49efabc8 68
a7fa5053 69my $non_C_locale;
49efabc8 70foreach my $locale (@locales) {
8e13243a 71 next if $locale eq "C" || $locale eq 'POSIX' || $locale eq "C.UTF-8";
a7fa5053 72 $non_C_locale = $locale;
49efabc8
KW
73 last;
74}
75
385130eb 76if ($non_C_locale) {
238fb9b3 77 note("using non-C locale '$non_C_locale'");
a7fa5053
KW
78 setlocale(LC_NUMERIC, $non_C_locale);
79 isnt(setlocale(LC_NUMERIC), "C", "retrieving current non-C LC_NUMERIC doesn't give 'C'");
80 setlocale(LC_ALL, $non_C_locale);
81 isnt(setlocale(LC_ALL), "C", "retrieving current non-C LC_ALL doesn't give 'C'");
a7fa5053 82
385130eb 83 my @test_numeric_locales = @locales;
dc51aebe 84
238fb9b3 85 # Skip this locale on these cygwin versions as the returned radix character
385130eb
KW
86 # length is wrong
87 if ( $^O eq 'cygwin'
88 && version->new(($Config{'osvers'} =~ /^(\d+(?:\.\d+)+)/)[0]) le v2.4.1)
89 {
90 @test_numeric_locales = grep { $_ !~ m/ps_AF/i } @test_numeric_locales;
91 }
9c6df44e 92
e3e8c0d6
KW
93 # Similarly the arabic locales on solaris don't work right on the
94 # multi-byte radix character, generating malformed UTF-8.
95 if ($^O eq 'solaris') {
96 @test_numeric_locales = grep { $_ !~ m/ ^ ( ar_ | pa_ ) /x }
97 @test_numeric_locales;
98 }
99
385130eb 100 fresh_perl_is("for (qw(@test_numeric_locales)) {\n" . <<'EOF',
5be9e824
KW
101 use POSIX qw(locale_h);
102 use locale;
385130eb
KW
103 setlocale(LC_NUMERIC, "$_") or next;
104 my $s = sprintf "%g %g", 3.1, 3.1;
105 next if $s eq '3.1 3.1' || $s =~ /^(3.+1) \1$/;
6ec573cf 106 no warnings "utf8";
5be9e824
KW
107 print "$_ $s\n";
108 }
903eb63f 109EOF
385130eb 110 "", { eval $switches }, "no locales where LC_NUMERIC breaks");
903eb63f 111
385130eb
KW
112 SKIP: {
113 skip("Windows stores locale defaults in the registry", 1 )
114 if $^O eq 'MSWin32';
115 fresh_perl_is("for (qw(@locales)) {\n" . <<'EOF',
116 use POSIX qw(locale_h);
117 use locale;
118 my $in = 4.2;
119 my $s = sprintf "%g", $in; # avoid any constant folding bugs
120 next if $s eq "4.2";
6ec573cf 121 no warnings "utf8";
385130eb 122 print "$_ $s\n";
c1284011 123 }
385130eb
KW
124EOF
125 "", { eval $switches }, "LC_NUMERIC without environment nor setlocale() has no effect in any locale");
903eb63f
NT
126 }
127
385130eb
KW
128 # try to find out a locale where LC_NUMERIC makes a difference
129 my $original_locale = setlocale(LC_NUMERIC);
903eb63f 130
385130eb
KW
131 my ($base, $different, $comma, $difference, $utf8_radix);
132 my $radix_encoded_as_utf8;
133 for ("C", @locales) { # prefer C for the base if available
134 use locale;
135 setlocale(LC_NUMERIC, $_) or next;
136 my $in = 4.2; # avoid any constant folding bugs
137 if ((my $s = sprintf("%g", $in)) eq "4.2") {
138 $base ||= $_;
139 } else {
140 $different ||= $_;
141 $difference ||= $s;
142 my $radix = localeconv()->{decimal_point};
143
144 # For utf8 locales with a non-ascii radix, it should be encoded as
145 # UTF-8 with the internal flag so set.
146 if (! defined $utf8_radix
8dcd53c9 147 && $radix =~ /[[:^ascii:]]/u # /u because /l can raise warnings
385130eb
KW
148 && is_locale_utf8($_))
149 {
150 $utf8_radix = $_;
151 $radix_encoded_as_utf8 = utf8::is_utf8($radix);
152 }
153 else {
154 $comma ||= $_ if $radix eq ',';
155 }
156 }
c1284011 157
385130eb
KW
158 last if $base && $different && $comma && $utf8_radix;
159 }
160 setlocale(LC_NUMERIC, $original_locale);
903eb63f 161
385130eb
KW
162 SKIP: {
163 skip("no UTF-8 locale available where LC_NUMERIC radix isn't ASCII", 1 )
164 unless $utf8_radix;
165 ok($radix_encoded_as_utf8 == 1, "UTF-8 locale '$utf8_radix' with non-ASCII"
166 . " radix is marked UTF-8");
167 }
168
46814e9b
JK
169 SKIP: {
170 skip("no locale available where LC_NUMERIC radix isn't '.'", 30) unless $different;
385130eb
KW
171 note("using the '$different' locale for LC_NUMERIC tests");
172 {
173 local $ENV{LC_NUMERIC} = $different;
174
175 fresh_perl_is(<<'EOF', "4.2", { eval $switches },
176 format STDOUT =
903eb63f
NT
177@.#
1784.179
179.
385130eb 180 write;
903eb63f 181EOF
385130eb 182 "format() does not look at LC_NUMERIC without 'use locale'");
903eb63f 183
385130eb
KW
184 {
185 fresh_perl_is(<<'EOF', "$difference\n", { eval $switches },
186 use POSIX;
187 use locale;
188 format STDOUT =
903eb63f
NT
189@.#
1904.179
191.
385130eb 192 write;
903eb63f 193EOF
385130eb
KW
194 "format() looks at LC_NUMERIC with 'use locale'");
195 }
903eb63f 196
385130eb
KW
197 {
198 fresh_perl_is(<<'EOF', ",,", { eval $switches },
199 use POSIX;
6ec573cf 200 no warnings "utf8";
385130eb
KW
201 print localeconv()->{decimal_point};
202 use locale;
203 print localeconv()->{decimal_point};
a835cd47 204EOF
385130eb
KW
205 "localeconv() looks at LC_NUMERIC with and without 'use locale'");
206 }
a835cd47 207
385130eb
KW
208 {
209 my $categories = ":collate :characters :collate :ctype :monetary :time";
210 fresh_perl_is(<<"EOF", "4.2", { eval $switches },
211 use locale qw($categories);
212 format STDOUT =
d6ded950
KW
213@.#
2144.179
215.
385130eb 216 write;
d6ded950 217EOF
385130eb
KW
218 "format() does not look at LC_NUMERIC with 'use locale qw($categories)'");
219 }
d6ded950 220
385130eb
KW
221 {
222 fresh_perl_is(<<'EOF', $difference, { eval $switches },
223 use locale;
224 format STDOUT =
d6ded950
KW
225@.#
2264.179
227.
385130eb 228 write;
d6ded950 229EOF
385130eb
KW
230 "format() looks at LC_NUMERIC with 'use locale'");
231 }
d6ded950 232
385130eb
KW
233 for my $category (qw(collate characters collate ctype monetary time)) {
234 for my $negation ("!", "not_") {
235 fresh_perl_is(<<"EOF", $difference, { eval $switches },
236 use locale ":$negation$category";
d6ded950
KW
237format STDOUT =
238@.#
2394.179
240.
385130eb 241 write;
d6ded950 242EOF
385130eb
KW
243 "format() looks at LC_NUMERIC with 'use locale \":"
244 . "$negation$category\"'");
245 }
d6ded950 246 }
d6ded950 247
385130eb
KW
248 {
249 fresh_perl_is(<<'EOF', $difference, { eval $switches },
250 use locale ":numeric";
b34856cb
KW
251format STDOUT =
252@.#
2534.179
254.
385130eb 255 write;
b34856cb 256EOF
385130eb
KW
257 "format() looks at LC_NUMERIC with 'use locale \":numeric\"'");
258 }
b34856cb 259
385130eb
KW
260 {
261 fresh_perl_is(<<'EOF', "4.2", { eval $switches },
903eb63f
NT
262format STDOUT =
263@.#
2644.179
265.
385130eb 266 { use locale; write; }
903eb63f 267EOF
385130eb
KW
268 "too late to look at the locale at write() time");
269 }
903eb63f 270
385130eb
KW
271 {
272 fresh_perl_is(<<'EOF', $difference, { eval $switches },
273 use locale;
274 format STDOUT =
903eb63f
NT
275@.#
2764.179
277.
385130eb 278 { no locale; write; }
903eb63f 279EOF
385130eb
KW
280 "too late to ignore the locale at write() time");
281 }
903eb63f 282 }
8d0b139e 283
385130eb
KW
284 {
285 # do not let "use 5.000" affect the locale!
286 # this test is to prevent regression of [rt.perl.org #105784]
287 fresh_perl_is(<<"EOF",
288 use locale;
289 use POSIX;
290 my \$i = 0.123;
291 POSIX::setlocale(POSIX::LC_NUMERIC(),"$different");
292 \$a = sprintf("%.2f", \$i);
293 require version;
294 \$b = sprintf("%.2f", \$i);
6ec573cf 295 no warnings "utf8";
385130eb 296 print ".\$a \$b" unless \$a eq \$b
8d0b139e 297EOF
385130eb 298 "", { eval $switches }, "version does not clobber version");
8d0b139e 299
385130eb
KW
300 fresh_perl_is(<<"EOF",
301 use locale;
302 use POSIX;
303 my \$i = 0.123;
304 POSIX::setlocale(POSIX::LC_NUMERIC(),"$different");
305 \$a = sprintf("%.2f", \$i);
306 eval "use v5.0.0";
307 \$b = sprintf("%.2f", \$i);
6ec573cf 308 no warnings "utf8";
385130eb 309 print "\$a \$b" unless \$a eq \$b
b3fd6149 310EOF
385130eb
KW
311 "", { eval $switches }, "version does not clobber version (via eval)");
312 }
02aba72f 313
385130eb
KW
314 {
315 local $ENV{LC_NUMERIC} = $different;
316 fresh_perl_is(<<'EOF', "$difference "x4, { eval $switches },
317 use locale;
318 use POSIX qw(locale_h);
319 my $in = 4.2;
320 printf("%g %g %s %s ", $in, 4.2, sprintf("%g", $in), sprintf("%g", 4.2));
481465ea 321EOF
385130eb
KW
322 "sprintf() and printf() look at LC_NUMERIC regardless of constant folding");
323 }
ff4377fe 324
0ba5b45d 325 {
385130eb
KW
326 local $ENV{LC_NUMERIC} = $different;
327 fresh_perl_is(<<'EOF', "$difference "x4, { eval $switches },
250680e3
DM
328 use locale;
329 use POSIX qw(locale_h);
385130eb
KW
330 my $in = 4.2;
331 printf("%g %g %s %s ", $in, 4.2, sprintf("%g", $in), sprintf("%g", 4.2));
65ebb059 332EOF
385130eb 333 "Uses the above test to verify that on Windows the system default locale has lower priority than LC_NUMERIC");
65ebb059 334 }
65ebb059 335
385130eb
KW
336
337 # within this block, STDERR is closed. This is because fresh_perl_is()
338 # forks a shell, and some shells (like bash) can complain noisily when
339 # LC_ALL or similar is set to an invalid value
340
341 {
342 open my $saved_stderr, ">&STDERR" or die "Can't dup STDERR: $!";
343 close STDERR;
344
345 {
68021d02
KW
346 local $ENV{LC_ALL} = "invalid";
347 local $ENV{LC_NUMERIC} = "invalid";
385130eb 348 local $ENV{LANG} = $different;
62fe37a7 349 local $ENV{PERL_BADLANG} = 0;
250680e3 350
385130eb 351 if (! fresh_perl_is(<<"EOF", "$difference", { eval $switches },
68021d02 352 if (\$ENV{LC_ALL} ne "invalid") {
385130eb 353 # Make the test pass if the sh didn't accept the ENV set
6ec573cf 354 no warnings "utf8";
68021d02
KW
355 print "$difference\n";
356 exit 0;
357 }
358 use locale;
359 use POSIX qw(locale_h);
68021d02
KW
360 my \$in = 4.2;
361 printf("%g", \$in);
65ebb059 362EOF
385130eb
KW
363 "LANG is used if LC_ALL, LC_NUMERIC are invalid"))
364 {
365 note "To see details change this .t, do not close STDERR";
366 }
65ebb059 367 }
ff4377fe 368
385130eb
KW
369 SKIP: {
370 if ($^O eq 'MSWin32') {
371 skip("Win32 uses system default locale in preference to \"C\"",
372 1);
373 }
374 else {
375 local $ENV{LC_ALL} = "invalid";
376 local $ENV{LC_NUMERIC} = "invalid";
377 local $ENV{LANG} = "invalid";
378 local $ENV{PERL_BADLANG} = 0;
379
380 if (! fresh_perl_is(<<"EOF", 4.2, { eval $switches },
381 if (\$ENV{LC_ALL} ne "invalid") {
6ec573cf 382 no warnings "utf8";
385130eb
KW
383 print "$difference\n";
384 exit 0;
385 }
386 use locale;
387 use POSIX qw(locale_h);
388 my \$in = 4.2;
389 printf("%g", \$in);
bc8ec7cc 390EOF
385130eb
KW
391 'C locale is used if LC_ALL, LC_NUMERIC, LANG are invalid'))
392 {
393 note "To see details change this .t, do not close STDERR";
394 }
395 }
396 }
bc8ec7cc 397
385130eb
KW
398 open STDERR, ">&", $saved_stderr or die "Can't dup \$saved_stderr: $!";
399 }
02aba72f 400
385130eb
KW
401 {
402 local $ENV{LC_NUMERIC} = $different;
403 fresh_perl_is(<<"EOF",
404 use POSIX qw(locale_h);
02aba72f 405
385130eb
KW
406 BEGIN { setlocale(LC_NUMERIC, \"$different\"); };
407 setlocale(LC_ALL, "C");
408 use 5.008;
409 print setlocale(LC_NUMERIC);
02aba72f 410EOF
385130eb
KW
411 "C", { stderr => 'devnull' },
412 "No compile error on v-strings when setting the locale to non-dot radix at compile time when default environment has non-dot radix");
413 }
371d5d44 414
385130eb
KW
415 unless ($comma) {
416 skip("no locale available where LC_NUMERIC is a comma", 3);
371d5d44
KW
417 }
418 else {
385130eb 419
371d5d44 420 fresh_perl_is(<<"EOF",
385130eb
KW
421 my \$i = 1.5;
422 {
423 use locale;
424 use POSIX;
425 POSIX::setlocale(POSIX::LC_NUMERIC(),"$comma");
426 print \$i, "\n";
427 }
428 print \$i, "\n";
371d5d44 429EOF
385130eb 430 "1,5\n1.5", { stderr => 'devnull' }, "Radix print properly in locale scope, and without");
02aba72f 431
385130eb
KW
432 fresh_perl_is(<<"EOF",
433 my \$i = 1.5; # Should be exactly representable as a base 2
434 # fraction, so can use 'eq' below
ee48a02a
KW
435 use locale;
436 use POSIX;
385130eb
KW
437 POSIX::setlocale(POSIX::LC_NUMERIC(),"$comma");
438 print \$i, "\n";
439 \$i += 1;
440 print \$i, "\n";
ee48a02a 441EOF
385130eb 442 "1,5\n2,5", { stderr => 'devnull' }, "Can do math when radix is a comma"); # [perl 115800]
ee48a02a 443
c4fe5c4d 444 SKIP: {
385130eb
KW
445 unless ($have_strtod) {
446 skip("no strtod()", 1);
447 }
448 else {
449 fresh_perl_is(<<"EOF",
450 use POSIX;
451 POSIX::setlocale(POSIX::LC_NUMERIC(),"$comma");
452 my \$one_point_5 = POSIX::strtod("1,5");
453 \$one_point_5 =~ s/0+\$//; # Remove any trailing zeros
454 print \$one_point_5, "\n";
6e79ab66 455EOF
385130eb
KW
456 "1.5", { stderr => 'devnull' }, "POSIX::strtod() uses underlying locale");
457 }
c4fe5c4d 458 }
385130eb 459 }
6e79ab66
KW
460 }
461
8f6aacbb 462SKIP: {
8e13243a
KW
463 # Note: the setlocale Configure probe could be enhanced to give us the
464 # syntax to use, but khw doesn't think it's worth it at this time, as
465 # the current outliers seem to be skipped by the test just below
466 # anyway. If the POSIX 2008 locale functions are being used, the
467 # syntax becomes mostly irrelevant, so do the test anyway if they are.
468 # It's a lot of trouble to figure out in a perl script.
469 if ($Config{d_setlocale_accepts_any_locale_name} eq 'true')
8f6aacbb 470 {
8e13243a 471 skip("Can't distinguish between valid and invalid locale names on this system", 2);
8f6aacbb
KW
472 }
473
385130eb 474 my @valid_categories = valid_locale_categories();
0945d175 475
385130eb
KW
476 my $valid_string = "";
477 my $invalid_string = "";
0945d175 478
385130eb
KW
479 # Deliberately don't include all categories, so as to test this situation
480 for my $i (0 .. @valid_categories - 2) {
481 my $category = $valid_categories[$i];
482 if ($category ne "LC_ALL") {
483 $invalid_string .= ";" if $invalid_string ne "";
484 $invalid_string .= "$category=foo_BAR";
0945d175 485
385130eb
KW
486 next unless $non_C_locale;
487 $valid_string .= ";" if $valid_string ne "";
488 $valid_string .= "$category=$non_C_locale";
489 }
0945d175 490 }
bee74f4b 491
385130eb
KW
492 fresh_perl(<<"EOF",
493 use locale;
494 use POSIX;
495 POSIX::setlocale(LC_ALL, "$invalid_string");
0945d175 496EOF
385130eb
KW
497 {});
498 is ($?, 0, "In setting complicated invalid LC_ALL, final individ category doesn't need a \';'");
0945d175 499
385130eb
KW
500 skip("no non-C locale available", 1 ) unless $non_C_locale;
501 fresh_perl(<<"EOF",
502 use locale;
503 use POSIX;
504 POSIX::setlocale(LC_ALL, "$valid_string");
0945d175 505EOF
385130eb
KW
506 {});
507 is ($?, 0, "In setting complicated valid LC_ALL, final individ category doesn't need a \';'");
508
509 }
0945d175
KW
510
511}
512
385130eb 513done_testing();