5 require './test.pl'; # for fresh_perl_is() etc
6 require './loc_tools.pl'; # to find locales
12 # These tests are here instead of lib/locale.t because
13 # some bugs depend on the internal state of the locale
14 # settings and pragma/locale messes up that state pretty badly.
15 # We need "fresh runs".
17 eval { require POSIX; POSIX->import("locale_h") };
19 skip_all("could not load the POSIX module"); # running minitest?
23 my $have_strtod = $Config{d_strtod} eq 'define';
24 my @locales = find_locales( [ 'LC_ALL', 'LC_CTYPE', 'LC_NUMERIC' ]);
25 skip_all("no locales available") unless @locales;
27 # reset the locale environment
28 delete local @ENV{'LANG', (grep /^LC_/, keys %ENV)};
33 foreach my $locale (@locales) {
34 next if $locale eq "C" || $locale eq 'POSIX';
35 $non_C_locale = $locale;
40 skip("no non-C locale available", 2 ) unless $non_C_locale;
41 setlocale(LC_NUMERIC, $non_C_locale);
42 isnt(setlocale(LC_NUMERIC), "C", "retrieving current non-C LC_NUMERIC doesn't give 'C'");
43 setlocale(LC_ALL, $non_C_locale);
44 isnt(setlocale(LC_ALL), "C", "retrieving current non-C LC_ALL doesn't give 'C'");
47 # Skip this locale on these cywgwin versions as the returned radix character
49 my @test_numeric_locales = ($^O ne 'cygwin' || version->new(($Config{'osvers'} =~ /^(\d+(?:\.\d+)+)/)[0]) gt v2.4.1)
51 : grep { $_ !~ m/ps_AF/i } @locales;
53 fresh_perl_is("for (qw(@test_numeric_locales)) {\n" . <<'EOF',
54 use POSIX qw(locale_h);
56 setlocale(LC_NUMERIC, "$_") or next;
57 my $s = sprintf "%g %g", 3.1, 3.1;
58 next if $s eq '3.1 3.1' || $s =~ /^(3.+1) \1$/;
62 "", {}, "no locales where LC_NUMERIC breaks");
65 skip("Windows stores locale defaults in the registry", 1 )
67 fresh_perl_is("for (qw(@locales)) {\n" . <<'EOF',
68 use POSIX qw(locale_h);
71 my $s = sprintf "%g", $in; # avoid any constant folding bugs
76 "", {}, "LC_NUMERIC without environment nor setlocale() has no effect in any locale");
79 # try to find out a locale where LC_NUMERIC makes a difference
80 my $original_locale = setlocale(LC_NUMERIC);
82 my ($base, $different, $comma, $difference, $utf8_radix);
83 my $radix_encoded_as_utf8;
84 for ("C", @locales) { # prefer C for the base if available
86 setlocale(LC_NUMERIC, $_) or next;
87 my $in = 4.2; # avoid any constant folding bugs
88 if ((my $s = sprintf("%g", $in)) eq "4.2") {
93 my $radix = localeconv()->{decimal_point};
95 # For utf8 locales with a non-ascii radix, it should be encoded as
96 # UTF-8 with the internal flag so set.
97 if (! defined $utf8_radix
98 && $radix =~ /[[:^ascii:]]/
99 && is_locale_utf8($_))
102 $radix_encoded_as_utf8 = utf8::is_utf8($radix);
105 $comma ||= $_ if $radix eq ',';
109 last if $base && $different && $comma && $utf8_radix;
111 setlocale(LC_NUMERIC, $original_locale);
114 skip("no UTF-8 locale available where LC_NUMERIC radix isn't ASCII", 1 )
116 ok($radix_encoded_as_utf8 == 1, "UTF-8 locale '$utf8_radix' with non-ASCII"
117 . " radix is marked UTF-8");
121 skip("no locale available where LC_NUMERIC makes a difference", &last - 7 )
122 if !$different; # -7 is 5 tests before this block; 2 after
123 note("using the '$different' locale for LC_NUMERIC tests");
125 local $ENV{LC_NUMERIC} = $different;
127 fresh_perl_is(<<'EOF', "4.2", {},
134 "format() does not look at LC_NUMERIC without 'use locale'");
137 fresh_perl_is(<<'EOF', "$difference\n", {},
146 "format() looks at LC_NUMERIC with 'use locale'");
150 fresh_perl_is(<<'EOF', ",,", {},
151 print localeconv()->{decimal_point};
154 print localeconv()->{decimal_point};
156 "localeconv() looks at LC_NUMERIC with and without 'use locale'");
160 my $categories = ":collate :characters :collate :ctype :monetary :time";
161 fresh_perl_is(<<"EOF", "4.2", {},
162 use locale qw($categories);
169 "format() does not look at LC_NUMERIC with 'use locale qw($categories)'");
173 fresh_perl_is(<<'EOF', $difference, {},
181 "format() looks at LC_NUMERIC with 'use locale'");
184 for my $category (qw(collate characters collate ctype monetary time)) {
185 for my $negation ("!", "not_") {
186 fresh_perl_is(<<"EOF", $difference, {},
187 use locale ":$negation$category";
194 "format() looks at LC_NUMERIC with 'use locale \":"
195 . "$negation$category\"'");
200 fresh_perl_is(<<'EOF', $difference, {},
201 use locale ":numeric";
208 "format() looks at LC_NUMERIC with 'use locale \":numeric\"'");
212 fresh_perl_is(<<'EOF', "4.2", {},
217 { use locale; write; }
219 "too late to look at the locale at write() time");
223 fresh_perl_is(<<'EOF', $difference, {},
229 { no locale; write; }
231 "too late to ignore the locale at write() time");
236 # do not let "use 5.000" affect the locale!
237 # this test is to prevent regression of [rt.perl.org #105784]
238 fresh_perl_is(<<"EOF",
242 POSIX::setlocale(POSIX::LC_NUMERIC(),"$different");
243 \$a = sprintf("%.2f", \$i);
245 \$b = sprintf("%.2f", \$i);
246 print ".\$a \$b" unless \$a eq \$b
248 "", {}, "version does not clobber version");
250 fresh_perl_is(<<"EOF",
254 POSIX::setlocale(POSIX::LC_NUMERIC(),"$different");
255 \$a = sprintf("%.2f", \$i);
257 \$b = sprintf("%.2f", \$i);
258 print "\$a \$b" unless \$a eq \$b
260 "", {}, "version does not clobber version (via eval)");
264 local $ENV{LC_NUMERIC} = $different;
265 fresh_perl_is(<<'EOF', "$difference "x4, {},
267 use POSIX qw(locale_h);
269 printf("%g %g %s %s ", $in, 4.2, sprintf("%g", $in), sprintf("%g", 4.2));
271 "sprintf() and printf() look at LC_NUMERIC regardless of constant folding");
275 local $ENV{LC_NUMERIC} = $different;
276 fresh_perl_is(<<'EOF', "$difference "x4, {},
278 use POSIX qw(locale_h);
280 printf("%g %g %s %s ", $in, 4.2, sprintf("%g", $in), sprintf("%g", 4.2));
282 "Uses the above test to verify that on Windows the system default locale has lower priority than LC_NUMERIC");
286 # within this block, STDERR is closed. This is because fresh_perl_is()
287 # forks a shell, and some shells (like bash) can complain noisily when
288 # LC_ALL or similar is set to an invalid value
291 open my $saved_stderr, ">&STDERR" or die "Can't dup STDERR: $!";
295 local $ENV{LC_ALL} = "invalid";
296 local $ENV{LC_NUMERIC} = "invalid";
297 local $ENV{LANG} = $different;
298 local $ENV{PERL_BADLANG} = 0;
300 if (! fresh_perl_is(<<"EOF", "$difference", { },
301 if (\$ENV{LC_ALL} ne "invalid") {
302 # Make the test pass if the sh didn't accept the ENV set
303 print "$difference\n";
307 use POSIX qw(locale_h);
311 "LANG is used if LC_ALL, LC_NUMERIC are invalid"))
313 note "To see details change this .t, do not close STDERR";
318 if ($^O eq 'MSWin32') {
319 skip("Win32 uses system default locale in preference to \"C\"",
323 local $ENV{LC_ALL} = "invalid";
324 local $ENV{LC_NUMERIC} = "invalid";
325 local $ENV{LANG} = "invalid";
326 local $ENV{PERL_BADLANG} = 0;
328 if (! fresh_perl_is(<<"EOF", 4.2, { },
329 if (\$ENV{LC_ALL} ne "invalid") {
330 print "$difference\n";
334 use POSIX qw(locale_h);
338 'C locale is used if LC_ALL, LC_NUMERIC, LANG are invalid'))
340 note "To see details change this .t, do not close STDERR";
345 open STDERR, ">&", $saved_stderr or die "Can't dup \$saved_stderr: $!";
349 local $ENV{LC_NUMERIC} = $different;
350 fresh_perl_is(<<"EOF",
351 use POSIX qw(locale_h);
353 BEGIN { setlocale(LC_NUMERIC, \"$different\"); };
354 setlocale(LC_ALL, "C");
356 print setlocale(LC_NUMERIC);
358 "C", { stderr => 'devnull' },
359 "No compile error on v-strings when setting the locale to non-dot radix at compile time when default environment has non-dot radix");
363 skip("no locale available where LC_NUMERIC is a comma", 3);
367 fresh_perl_is(<<"EOF",
372 POSIX::setlocale(POSIX::LC_NUMERIC(),"$comma");
377 "1,5\n1.5", { stderr => 'devnull' }, "Radix print properly in locale scope, and without");
379 fresh_perl_is(<<"EOF",
380 my \$i = 1.5; # Should be exactly representable as a base 2
381 # fraction, so can use 'eq' below
384 POSIX::setlocale(POSIX::LC_NUMERIC(),"$comma");
389 "1,5\n2,5", { stderr => 'devnull' }, "Can do math when radix is a comma"); # [perl 115800]
391 unless ($have_strtod) {
392 skip("no strtod()", 1);
395 fresh_perl_is(<<"EOF",
397 POSIX::setlocale(POSIX::LC_NUMERIC(),"$comma");
398 my \$one_point_5 = POSIX::strtod("1,5");
399 \$one_point_5 =~ s/0+\$//; # Remove any trailing zeros
400 print \$one_point_5, "\n";
402 "1.5", { stderr => 'devnull' }, "POSIX::strtod() uses underlying locale");
408 fresh_perl_is(<<"EOF",
411 POSIX::setlocale(POSIX::LC_CTYPE(),"C");
412 print "h" =~ /[g\\w]/i || 0;
415 1, { stderr => 'devnull' }, "/il matching of [bracketed] doesn't skip POSIX class if fails individ char");
419 fresh_perl_is(<<"EOF",
422 POSIX::setlocale(POSIX::LC_CTYPE(),"C");
423 print "0" =~ /[\\d[:punct:]]/l || 0;
426 1, { stderr => 'devnull' }, "/l matching of [bracketed] doesn't skip non-first POSIX class");
430 # IMPORTANT: When adding tests before the following line, be sure to update
432 # skip("no locale available where LC_NUMERIC makes a difference", ...)