This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
d9d149bc58fee534bbf15e86bf8dcec910dbdedf
[perl5.git] / dist / Devel-PPPort / t / utf8.t
1 ################################################################################
2 #
3 #            !!!!!   Do NOT edit this file directly!   !!!!!
4 #
5 #            Edit mktests.PL and/or parts/inc/utf8 instead.
6 #
7 #  This file was automatically generated from the definition files in the
8 #  parts/inc/ subdirectory by mktests.PL. To learn more about how all this
9 #  works, please read the F<HACKERS> file that came with this distribution.
10 #
11 ################################################################################
12
13 BEGIN {
14   if ($ENV{'PERL_CORE'}) {
15     chdir 't' if -d 't';
16     @INC = ('../lib', '../ext/Devel-PPPort/t') if -d '../lib' && -d '../ext';
17     require Config; import Config;
18     use vars '%Config';
19     if (" $Config{'extensions'} " !~ m[ Devel/PPPort ]) {
20       print "1..0 # Skip -- Perl configured without Devel::PPPort module\n";
21       exit 0;
22     }
23   }
24   else {
25     unshift @INC, 't';
26   }
27
28   sub load {
29     eval "use Test";
30     require 'testutil.pl' if $@;
31   }
32
33   if (81) {
34     load();
35     plan(tests => 81);
36   }
37 }
38
39 use Devel::PPPort;
40 use strict;
41 BEGIN { $^W = 1; }
42
43 package Devel::PPPort;
44 use vars '@ISA';
45 require DynaLoader;
46 @ISA = qw(DynaLoader);
47 bootstrap Devel::PPPort;
48
49 package main;
50
51 BEGIN { require warnings if "$]" gt '5.006' }
52
53 # skip tests on 5.6.0 and earlier, plus 7.0
54 if ("$]" <= '5.006' || "$]" == '5.007' ) {
55     for (1..81) {
56         skip 'skip: broken utf8 support', 0;
57     }
58     exit;
59 }
60
61 ok(&Devel::PPPort::UTF8_SAFE_SKIP("A", 0), 1);
62 ok(&Devel::PPPort::UTF8_SAFE_SKIP("A", -1), 0);
63
64 ok(&Devel::PPPort::isUTF8_CHAR("A", -1), 0);
65 ok(&Devel::PPPort::isUTF8_CHAR("A",  0), 1);
66 ok(&Devel::PPPort::isUTF8_CHAR("\x{100}",  -1), 0);
67 ok(&Devel::PPPort::isUTF8_CHAR("\x{100}",  0), 2);
68
69 if ("$]" lt '5.008') {
70     ok(1, 1) for 1 ..3
71 }
72 else {
73     ok(&Devel::PPPort::foldEQ_utf8("A\x{100}", 3, 1, "a\x{101}", 3, 1), 1);
74     ok(&Devel::PPPort::foldEQ_utf8("A\x{100}", 3, 1, "a\x{102}", 3, 1), 0);
75     ok(&Devel::PPPort::foldEQ_utf8("A\x{100}", 3, 1, "b\x{101}", 3, 1), 0);
76 }
77
78 my $ret = &Devel::PPPort::utf8_to_uvchr("A");
79 ok($ret->[0], ord("A"));
80 ok($ret->[1], 1);
81
82 $ret = &Devel::PPPort::utf8_to_uvchr("\0");
83 ok($ret->[0], 0);
84 ok($ret->[1], 1);
85
86 $ret = &Devel::PPPort::utf8_to_uvchr_buf("A", 0);
87 ok($ret->[0], ord("A"));
88 ok($ret->[1], 1);
89
90 $ret = &Devel::PPPort::utf8_to_uvchr_buf("\0", 0);
91 ok($ret->[0], 0);
92 ok($ret->[1], 1);
93
94 if (ord("A") != 65) {   # tests not valid for EBCDIC
95     ok(1, 1) for 1 .. (2 + 4 + (7 * 5));
96 }
97 else {
98     $ret = &Devel::PPPort::utf8_to_uvchr_buf("\xc4\x80", 0);
99     ok($ret->[0], 0x100);
100     ok($ret->[1], 2);
101
102     my @warnings;
103     local $SIG{__WARN__} = sub { push @warnings, @_; };
104
105     {
106         BEGIN { 'warnings'->import('utf8') if "$]" gt '5.006' }
107         $ret = &Devel::PPPort::utf8_to_uvchr("\xe0\0\x80");
108         ok($ret->[0], 0);
109         ok($ret->[1], -1);
110
111         BEGIN { 'warnings'->unimport() if "$]" gt '5.006' }
112         $ret = &Devel::PPPort::utf8_to_uvchr("\xe0\0\x80");
113         ok($ret->[0], 0xFFFD);
114         ok($ret->[1], 1);
115     }
116
117     my @buf_tests = (
118         {
119             input      => "A",
120             adjustment => -1,
121             warning    => eval "qr/empty/",
122             no_warnings_returned_length => 0,
123         },
124         {
125             input      => "\xc4\xc5",
126             adjustment => 0,
127             warning    => eval "qr/non-continuation/",
128             no_warnings_returned_length => 1,
129         },
130         {
131             input      => "\xc4\x80",
132             adjustment => -1,
133             warning    => eval "qr/short|1 byte, need 2/",
134             no_warnings_returned_length => 1,
135         },
136         {
137             input      => "\xc0\x81",
138             adjustment => 0,
139             warning    => eval "qr/overlong|2 bytes, need 1/",
140             no_warnings_returned_length => 2,
141         },
142         {
143             input      => "\xe0\x80\x81",
144             adjustment => 0,
145             warning    => eval "qr/overlong|3 bytes, need 1/",
146             no_warnings_returned_length => 3,
147         },
148         {
149             input      => "\xf0\x80\x80\x81",
150             adjustment => 0,
151             warning    => eval "qr/overlong|4 bytes, need 1/",
152             no_warnings_returned_length => 4,
153         },
154         {                 # Old algorithm failed to detect this
155             input      => "\xff\x80\x90\x90\x90\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf",
156             adjustment => 0,
157             warning    => eval "qr/overflow/",
158             no_warnings_returned_length => 13,
159         },
160     );
161
162     # An empty input is an assertion failure on debugging builds.  It is
163     # deliberately the first test.
164     require Config; import Config;
165     use vars '%Config';
166     if ($Config{ccflags} =~ /-DDEBUGGING/) {
167         shift @buf_tests;
168         ok(1, 1) for 1..5;
169     }
170
171     for my $test (@buf_tests) {
172         my $input = $test->{'input'};
173         my $adjustment = $test->{'adjustment'};
174         my $display = 'utf8_to_uvchr_buf("';
175         for (my $i = 0; $i < length($input) + $adjustment; $i++) {
176             $display .= sprintf "\\x%02x", ord substr($input, $i, 1);
177         }
178
179         $display .= '")';
180         my $warning = $test->{'warning'};
181
182         undef @warnings;
183         BEGIN { 'warnings'->import('utf8') if "$]" gt '5.006' }
184         $ret = &Devel::PPPort::utf8_to_uvchr_buf($input, $adjustment);
185         ok($ret->[0], 0,  "returned value $display; warnings enabled");
186         ok($ret->[1], -1, "returned length $display; warnings enabled");
187         my $all_warnings = join "; ", @warnings;
188         my $contains = grep { $_ =~ $warning } $all_warnings;
189         ok($contains, 1, $display
190                     . "; Got: '$all_warnings', which should contain '$warning'");
191
192         undef @warnings;
193         BEGIN { 'warnings'->unimport('utf8') if "$]" gt '5.006' }
194         $ret = &Devel::PPPort::utf8_to_uvchr_buf($input, $adjustment);
195         ok($ret->[0], 0xFFFD,  "returned value $display; warnings disabled");
196         ok($ret->[1], $test->{'no_warnings_returned_length'},
197                       "returned length $display; warnings disabled");
198     }
199 }
200
201 if ("$]" ge '5.008') {
202     BEGIN { if ("$]" ge '5.008') { require utf8; "utf8"->import() } }
203
204     ok(Devel::PPPort::sv_len_utf8("aščť"), 4);
205     ok(Devel::PPPort::sv_len_utf8_nomg("aščť"), 4);
206
207     my $str = "áíé";
208     utf8::downgrade($str);
209     ok(Devel::PPPort::sv_len_utf8($str), 3);
210     utf8::downgrade($str);
211     ok(Devel::PPPort::sv_len_utf8_nomg($str), 3);
212     utf8::upgrade($str);
213     ok(Devel::PPPort::sv_len_utf8($str), 3);
214     utf8::upgrade($str);
215     ok(Devel::PPPort::sv_len_utf8_nomg($str), 3);
216
217     tie my $scalar, 'TieScalarCounter', "é";
218
219     ok(tied($scalar)->{fetch}, 0);
220     ok(tied($scalar)->{store}, 0);
221     ok(Devel::PPPort::sv_len_utf8($scalar), 2);
222     ok(tied($scalar)->{fetch}, 1);
223     ok(tied($scalar)->{store}, 0);
224     ok(Devel::PPPort::sv_len_utf8($scalar), 3);
225     ok(tied($scalar)->{fetch}, 2);
226     ok(tied($scalar)->{store}, 0);
227     ok(Devel::PPPort::sv_len_utf8($scalar), 4);
228     ok(tied($scalar)->{fetch}, 3);
229     ok(tied($scalar)->{store}, 0);
230     ok(Devel::PPPort::sv_len_utf8_nomg($scalar), 4);
231     ok(tied($scalar)->{fetch}, 3);
232     ok(tied($scalar)->{store}, 0);
233     ok(Devel::PPPort::sv_len_utf8_nomg($scalar), 4);
234     ok(tied($scalar)->{fetch}, 3);
235     ok(tied($scalar)->{store}, 0);
236 } else {
237     for (1..23) {
238         skip 'skip: no SV_NOSTEAL support', 0;
239     }
240 }
241
242 package TieScalarCounter;
243
244 sub TIESCALAR {
245     my ($class, $value) = @_;
246     return bless { fetch => 0, store => 0, value => $value }, $class;
247 }
248
249 sub FETCH {
250     BEGIN { if ("$]" ge '5.008') { require utf8; "utf8"->import() } }
251     my ($self) = @_;
252     $self->{fetch}++;
253     return $self->{value} .= "é";
254 }
255
256 sub STORE {
257     my ($self, $value) = @_;
258     $self->{store}++;
259     $self->{value} = $value;
260 }
261