lib/locale.t: Skip testing known incompatible locales
authorKarl Williamson <khw@cpan.org>
Mon, 24 Oct 2016 04:03:08 +0000 (22:03 -0600)
committerKarl Williamson <khw@cpan.org>
Wed, 26 Oct 2016 18:14:06 +0000 (12:14 -0600)
Some locales are incompatible with Perl.  The only multi-byte locales
accepted are UTF-8 ones.  ISO 646 locales can have things like a '|' be
a \w, which will create havoc with regular expressions.  This commit
causes locale.t to not test such locales, and to note which ones are
skipped, and why.

If we were to do the tests anyway, it could create segfaults.  For
example locales with state can have their states screwed up by Perl,
which knows nothing about that.  One could argue that the locale should
be immune from bad state, and not segfault, but that is not under Perl's
control, and we will get blamed initially, anyway, when a segfault
happens, so don't test them.

The multi-byte locales are more incompatible with Perl than the 7-bit
locales that aren't ASCII compatible.  So it could be argued that those
should be tested, but I don't want to undertake the work to separate out
the two causes from each other.  The ISO 646 locales are essentially
obsolete, and hence unlikely to be encountered in practice, so there
would be little pay off for doing that work.

lib/locale.t

index 4e0086b..4a2cb75 100644 (file)
@@ -751,6 +751,45 @@ debug "Scanning for locales...\n";
 require POSIX; import POSIX ':locale_h';
 
 my @Locale = find_locales([ 'LC_CTYPE', 'LC_NUMERIC', 'LC_ALL' ]);
+my @include_incompatible_locales = find_locales('LC_CTYPE',
+                                                'even incompatible locales');
+
+# The locales included in the incompatible list that aren't in the compatible
+# one.
+my @incompatible_locales;
+
+if (@Locale < @include_incompatible_locales) {
+    my %seen;
+    @seen{@Locale} = ();
+
+    foreach my $item (@include_incompatible_locales) {
+        push @incompatible_locales, $item unless exists $seen{$item};
+    }
+
+    # For each bad locale, switch into it to find out why it's incompatible
+    for my $bad_locale (@incompatible_locales) {
+        my @warnings;
+
+        use warnings 'locale';
+
+        local $SIG{__WARN__} = sub {
+            my $warning = $_[0];
+            chomp $warning;
+            push @warnings, ($warning =~ s/\n/\n# /sgr);
+        };
+
+        setlocale(&POSIX::LC_CTYPE, $bad_locale);
+
+        my $message = "testing of locale '$bad_locale' is skipped";
+        if (@warnings) {
+            skip $message . ":\n# " . join "\n# ", @warnings;
+        }
+        else {
+            fail $message . ", because it is was found to be incompatible with"
+                          . " Perl, but could not discern reason";
+        }
+    }
+}
 
 debug "Locales =\n";
 for ( @Locale ) {
@@ -940,7 +979,8 @@ sub report_multi_result {
     report_result($Locale, $i, @$results_ref == 0, $message);
 }
 
-my $first_locales_test_number = $final_without_setlocale + 1;
+my $first_locales_test_number = $final_without_setlocale
+                              + 1 + @incompatible_locales;
 my $locales_test_number;
 my $not_necessarily_a_problem_test_number;
 my $first_casing_test_number;