This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Follow-up on a149d118.
[perl5.git] / t / op / smartmatch.t
CommitLineData
0d863452
RH
1#!./perl
2
3BEGIN {
a817e89d 4 chdir 't' if -d 't';
0d863452 5 require './test.pl';
43ece5b1 6 set_up_inc('../lib');
0d863452
RH
7}
8use strict;
289d21b2
RGS
9use warnings;
10no warnings 'uninitialized';
0f539b13 11no warnings 'experimental::smartmatch';
0d863452 12
b1741c2a
TC
13++$|;
14
0d863452
RH
15use Tie::Array;
16use Tie::Hash;
17
0d863452 18# Predeclare vars used in the tests:
031a44ed
RGS
19my @empty;
20my %empty;
015eb7b9 21my @sparse; $sparse[2] = 2;
031a44ed 22
1144115d
RGS
23my $deep1 = []; push @$deep1, $deep1;
24my $deep2 = []; push @$deep2, $deep2;
0d863452 25
0d863452
RH
26my @nums = (1..10);
27tie my @tied_nums, 'Tie::StdArray';
28@tied_nums = (1..10);
29
30my %hash = (foo => 17, bar => 23);
31tie my %tied_hash, 'Tie::StdHash';
32%tied_hash = %hash;
33
1cfb7049
YK
34{
35 package Test::Object::NoOverload;
36 sub new { bless { key => 1 } }
37}
38
39{
6fbc735b
RGS
40 package Test::Object::StringOverload;
41 use overload '""' => sub { "object" }, fallback => 1;
42 sub new { bless { key => 1 } }
43}
44
45{
90a32bcb 46 package Test::Object::WithOverload;
6fbc735b 47 sub new { bless { key => ($_[1] // 'magic') } }
2c9d2554
RGS
48 use overload '~~' => sub {
49 my %hash = %{ $_[0] };
50 if ($_[2]) { # arguments reversed ?
51 return $_[1] eq reverse $hash{key};
52 }
53 else {
54 return $_[1] eq $hash{key};
55 }
56 };
0483c672 57 use overload '""' => sub { "stringified" };
90a32bcb 58 use overload 'eq' => sub {"$_[0]" eq "$_[1]"};
1cfb7049
YK
59}
60
90a32bcb 61our $ov_obj = Test::Object::WithOverload->new;
6fbc735b 62our $ov_obj_2 = Test::Object::WithOverload->new("object");
1cfb7049 63our $obj = Test::Object::NoOverload->new;
6fbc735b 64our $str_obj = Test::Object::StringOverload->new;
1cfb7049 65
c5836baf 66my %refh;
d3d1232e
NC
67unless (is_miniperl()) {
68 require Tie::RefHash;
c5836baf
RGS
69 tie %refh, 'Tie::RefHash';
70 $refh{$ov_obj} = 1;
71}
b15feb55 72
73aec0b1
RGS
73my @keyandmore = qw(key and more);
74my @fooormore = qw(foo or more);
75my %keyandmore = map { $_ => 0 } @keyandmore;
76my %fooormore = map { $_ => 0 } @fooormore;
77
0d863452 78# Load and run the tests
e8fe1b7c 79plan tests => 349+2;
0d863452 80
9e079ace 81while (<DATA>) {
c5836baf 82 SKIP: {
9e079ace
RGS
83 next if /^#/ || !/\S/;
84 chomp;
73aec0b1 85 my ($yn, $left, $right, $note) = split /\t+/;
0d863452 86
73aec0b1 87 local $::TODO = $note =~ /TODO/;
0d863452 88
85af77a5 89 die "Bad test spec: ($yn, $left, $right)" if $yn =~ /[^!@=]/;
9e079ace 90
0d863452 91 my $tstr = "$left ~~ $right";
9e079ace 92
85af77a5 93 test_again:
289d21b2
RGS
94 my $res;
95 if ($note =~ /NOWARNINGS/) {
96 $res = eval "no warnings; $tstr";
97 }
98 else {
d3d1232e
NC
99 skip_if_miniperl("Doesn't work with miniperl", $yn =~ /=/ ? 2 : 1)
100 if $note =~ /MINISKIP/;
289d21b2
RGS
101 $res = eval $tstr;
102 }
0d863452 103
a86f5011
YK
104 chomp $@;
105
85af77a5 106 if ( $yn =~ /@/ ) {
9e079ace
RGS
107 ok( $@ ne '', "$tstr dies" )
108 and print "# \$\@ was: $@\n";
a86f5011 109 } else {
85af77a5 110 my $test_name = $tstr . ($yn =~ /!/ ? " does not match" : " matches");
a86f5011 111 if ( $@ ne '' ) {
9e079ace
RGS
112 fail($test_name);
113 print "# \$\@ was: $@\n";
a86f5011 114 } else {
85af77a5 115 ok( ($yn =~ /!/ xor $res), $test_name );
a86f5011
YK
116 }
117 }
85af77a5
RGS
118
119 if ( $yn =~ s/=// ) {
120 $tstr = "$right ~~ $left";
121 goto test_again;
122 }
c5836baf 123 }
0d863452
RH
124}
125
0d863452 126sub foo {}
73aec0b1
RGS
127sub bar {42}
128sub gorch {42}
1cfb7049 129sub fatal {die "fatal sub\n"}
0d863452 130
0cfbf1ea 131# to test constant folding
18d11902
RGS
132sub FALSE() { 0 }
133sub TRUE() { 1 }
2522c35a 134sub NOT_DEF() { undef }
0d863452 135
b1741c2a
TC
136{
137 # [perl #123860]
138 # this can but might not crash
b1741c2a
TC
139 # This can but might not crash
140 #
141 # The second smartmatch would leave a &PL_sv_no on the stack for
142 # each key it checked in %!, this could then cause various types of
143 # crash or assertion failure.
144 #
145 # This isn't guaranteed to crash, but if the stack issue is
146 # re-introduced it will probably crash in one of the many smoke
147 # builds.
148 fresh_perl_is('print (q(x) ~~ q(x)) | (/x/ ~~ %!)', "1",
149 { switches => [ "-MErrno", "-M-warnings=experimental::smartmatch" ] },
150 "don't fill the stack with rubbish");
151}
152
e8fe1b7c
DM
153{
154 # [perl #123860] continued;
155 # smartmatch was failing to SPAGAIN after pushing an SV and calling
156 # pp_match, which may have resulted in the stack being realloced
157 # in the meantime. Test this by filling the stack with pregressively
158 # larger amounts of data. At some point the stack will get realloced.
159 my @a = qw(x);
160 my %h = qw(x 1);
161 my @args;
162 my $x = 1;
163 my $bad = -1;
164 for (1..1000) {
165 push @args, $_;
166 my $exp_n = join '-', (@args, $x == 0);
167 my $exp_y = join '-', (@args, $x == 1);
168
169 my $got_an = join '-', (@args, (/X/ ~~ @a));
170 my $got_ay = join '-', (@args, (/x/ ~~ @a));
171 my $got_hn = join '-', (@args, (/X/ ~~ %h));
172 my $got_hy = join '-', (@args, (/x/ ~~ %h));
173
174 if ( $exp_n ne $got_an || $exp_n ne $got_hn
175 || $exp_y ne $got_ay || $exp_y ne $got_hy
176 ) {
177 $bad = $_;
178 last;
179 }
180 }
181 is($bad, -1, "RT 123860: stack realloc");
182}
183
184
e5de85fa
RGS
185# Prefix character :
186# - expected to match
187# ! - expected to not match
188# @ - expected to be a compilation failure
85af77a5 189# = - expected to match symmetrically (runs test twice)
73aec0b1 190# Data types to test :
85af77a5 191# undef
73aec0b1
RGS
192# Object-overloaded
193# Object
73aec0b1
RGS
194# Coderef
195# Hash
196# Hashref
197# Array
198# Arrayref
85af77a5
RGS
199# Tied arrays and hashes
200# Arrays that reference themselves
73aec0b1 201# Regex (// and qr//)
85af77a5 202# Range
73aec0b1
RGS
203# Num
204# Str
85af77a5
RGS
205# Other syntactic items of interest:
206# Constants
207# Values returned by a sub call
0d863452 208__DATA__
85af77a5 209# Any ~~ undef
ad0781bc 210! $ov_obj undef
85af77a5
RGS
211! $obj undef
212! sub {} undef
213! %hash undef
214! \%hash undef
215! {} undef
216! @nums undef
217! \@nums undef
218! [] undef
219! %tied_hash undef
220! @tied_nums undef
221! $deep1 undef
222! /foo/ undef
223! qr/foo/ undef
224! 21..30 undef
225! 189 undef
226! "foo" undef
227! "" undef
228! !1 undef
229 undef undef
62ec5f58 230 (my $u) undef
2522c35a
RGS
231 NOT_DEF undef
232 &NOT_DEF undef
85af77a5
RGS
233
234# Any ~~ object overloaded
ad0781bc 235! \&fatal $ov_obj
2c9d2554
RGS
236 'cigam' $ov_obj
237! 'cigam on' $ov_obj
532217f1
RGS
238! ['cigam'] $ov_obj
239! ['stringified'] $ov_obj
240! { cigam => 1 } $ov_obj
241! { stringified => 1 } $ov_obj
ad0781bc
RGS
242! $obj $ov_obj
243! undef $ov_obj
1cfb7049
YK
244
245# regular object
ad0781bc 246@ $obj $obj
6d743019 247@ $ov_obj $obj
2c9d2554 248=@ \&fatal $obj
ad0781bc
RGS
249@ \&FALSE $obj
250@ \&foo $obj
251@ sub { 1 } $obj
252@ sub { 0 } $obj
253@ %keyandmore $obj
254@ {"key" => 1} $obj
255@ @fooormore $obj
256@ ["key" => 1] $obj
257@ /key/ $obj
258@ qr/key/ $obj
259@ "key" $obj
260@ FALSE $obj
261
6fbc735b
RGS
262# regular object with "" overload
263@ $obj $str_obj
264=@ \&fatal $str_obj
265@ \&FALSE $str_obj
266@ \&foo $str_obj
267@ sub { 1 } $str_obj
268@ sub { 0 } $str_obj
269@ %keyandmore $str_obj
270@ {"object" => 1} $str_obj
271@ @fooormore $str_obj
272@ ["object" => 1] $str_obj
273@ /object/ $str_obj
274@ qr/object/ $str_obj
275@ "object" $str_obj
276@ FALSE $str_obj
277# Those will treat the $str_obj as a string because of fallback:
6fbc735b 278
ad0781bc 279# object (overloaded or not) ~~ Any
0483c672
RGS
280 $obj qr/NoOverload/
281 $ov_obj qr/^stringified$/
532217f1 282= "$ov_obj" "stringified"
6fbc735b 283= "$str_obj" "object"
532217f1 284!= $ov_obj "stringified"
6fbc735b 285 $str_obj "object"
2c9d2554
RGS
286 $ov_obj 'magic'
287! $ov_obj 'not magic'
1cfb7049 288
a4a197da
RGS
289# ~~ Coderef
290 sub{0} sub { ref $_[0] eq "CODE" }
291 %fooormore sub { $_[0] =~ /^(foo|or|more)$/ }
292! %fooormore sub { $_[0] =~ /^(foo|or|less)$/ }
293 \%fooormore sub { $_[0] =~ /^(foo|or|more)$/ }
294! \%fooormore sub { $_[0] =~ /^(foo|or|less)$/ }
295 +{%fooormore} sub { $_[0] =~ /^(foo|or|more)$/ }
296! +{%fooormore} sub { $_[0] =~ /^(foo|or|less)$/ }
297 @fooormore sub { $_[0] =~ /^(foo|or|more)$/ }
298! @fooormore sub { $_[0] =~ /^(foo|or|less)$/ }
299 \@fooormore sub { $_[0] =~ /^(foo|or|more)$/ }
300! \@fooormore sub { $_[0] =~ /^(foo|or|less)$/ }
301 [@fooormore] sub { $_[0] =~ /^(foo|or|more)$/ }
302! [@fooormore] sub { $_[0] =~ /^(foo|or|less)$/ }
303 %fooormore sub{@_==1}
304 @fooormore sub{@_==1}
305 "foo" sub { $_[0] =~ /^(foo|or|more)$/ }
306! "more" sub { $_[0] =~ /^(foo|or|less)$/ }
73aec0b1 307 /fooormore/ sub{ref $_[0] eq 'Regexp'}
a4a197da
RGS
308 qr/fooormore/ sub{ref $_[0] eq 'Regexp'}
309 1 sub{shift}
310! 0 sub{shift}
311! undef sub{shift}
312 undef sub{not shift}
031a44ed
RGS
313 NOT_DEF sub{not shift}
314 &NOT_DEF sub{not shift}
a4a197da
RGS
315 FALSE sub{not shift}
316 [1] \&bar
317 {a=>1} \&bar
318 qr// \&bar
319! [1] \&foo
320! {a=>1} \&foo
41e726ac 321 $obj sub { ref($_[0]) =~ /NoOverload/ }
90a32bcb 322 $ov_obj sub { ref($_[0]) =~ /WithOverload/ }
a4a197da 323# empty stuff matches, because the sub is never called:
07edf497
RGS
324 [] \&foo
325 {} \&foo
031a44ed
RGS
326 @empty \&foo
327 %empty \&foo
a4a197da
RGS
328! qr// \&foo
329! undef \&foo
330 undef \&bar
331@ undef \&fatal
332@ 1 \&fatal
333@ [1] \&fatal
203d1e89 334@ {a=>1} \&fatal
a4a197da
RGS
335@ "foo" \&fatal
336@ qr// \&fatal
203d1e89 337# sub is not called on empty hashes / arrays
07edf497
RGS
338 [] \&fatal
339 +{} \&fatal
031a44ed
RGS
340 @empty \&fatal
341 %empty \&fatal
532217f1
RGS
342# sub is not special on the left
343 sub {0} qr/^CODE/
344 sub {0} sub { ref shift eq "CODE" }
0d863452 345
0d863452
RH
346# HASH ref against:
347# - another hash ref
348 {} {}
2a37c5e7 349=! {} {1 => 2}
0d863452
RH
350 {1 => 2} {1 => 2}
351 {1 => 2} {1 => 3}
031a44ed
RGS
352=! {1 => 2} {2 => 3}
353= \%main:: {map {$_ => 'x'} keys %main::}
0d863452
RH
354
355# - tied hash ref
2522c35a 356= \%hash \%tied_hash
0d863452 357 \%tied_hash \%tied_hash
031a44ed
RGS
358!= {"a"=>"b"} \%tied_hash
359= %hash %tied_hash
360 %tied_hash %tied_hash
361!= {"a"=>"b"} %tied_hash
c5836baf
RGS
362 $ov_obj %refh MINISKIP
363! "$ov_obj" %refh MINISKIP
364 [$ov_obj] %refh MINISKIP
365! ["$ov_obj"] %refh MINISKIP
366 %refh %refh MINISKIP
0d863452
RH
367
368# - an array ref
031a44ed
RGS
369# (since this is symmetrical, tests as well hash~~array)
370= [keys %main::] \%::
371= [qw[STDIN STDOUT]] \%::
372=! [] \%::
373=! [""] {}
374=! [] {}
375=! @empty {}
376= [undef] {"" => 1}
377= [""] {"" => 1}
378= ["foo"] { foo => 1 }
379= ["foo", "bar"] { foo => 1 }
380= ["foo", "bar"] \%hash
381= ["foo"] \%hash
382=! ["quux"] \%hash
383= [qw(foo quux)] \%hash
384= @fooormore { foo => 1, or => 2, more => 3 }
385= @fooormore %fooormore
386= @fooormore \%fooormore
387= \@fooormore %fooormore
0d863452
RH
388
389# - a regex
ea0c2dbd
RGS
390= qr/^(fo[ox])$/ {foo => 1}
391= /^(fo[ox])$/ %fooormore
031a44ed 392=! qr/[13579]$/ +{0..99}
ea0c2dbd 393=! qr/a*/ {}
031a44ed 394= qr/a*/ {b=>2}
ea0c2dbd
RGS
395= qr/B/i {b=>2}
396= /B/i {b=>2}
397=! qr/a+/ {b=>2}
398= qr/^à/ {"à"=>2}
0d863452 399
031a44ed 400# - a scalar
2e0e16c9 401 "foo" +{foo => 1, bar => 2}
031a44ed 402 "foo" %fooormore
2e0e16c9 403! "baz" +{foo => 1, bar => 2}
031a44ed
RGS
404! "boz" %fooormore
405! 1 +{foo => 1, bar => 2}
406! 1 %fooormore
407 1 { 1 => 3 }
408 1.0 { 1 => 3 }
409! "1.0" { 1 => 3 }
410! "1.0" { 1.0 => 3 }
411 "1.0" { "1.0" => 3 }
412 "à" { "à" => "À" }
0d863452 413
61a621c6 414# - undef
2522c35a 415! undef { hop => 'zouu' }
61a621c6
RGS
416! undef %hash
417! undef +{"" => "empty key"}
2a37c5e7 418! undef {}
0d863452
RH
419
420# ARRAY ref against:
421# - another array ref
1cfb7049 422 [] []
2522c35a 423=! [] [1]
ea0c2dbd
RGS
424 [["foo"], ["bar"]] [qr/o/, qr/a/]
425! [["foo"], ["bar"]] [qr/ARRAY/, qr/ARRAY/]
0d863452 426 ["foo", "bar"] [qr/o/, qr/a/]
031a44ed 427! [qr/o/, qr/a/] ["foo", "bar"]
2522c35a 428 ["foo", "bar"] [["foo"], ["bar"]]
71b0fb34 429! ["foo", "bar"] [qr/o/, "foo"]
2522c35a 430 ["foo", undef, "bar"] [qr/o/, undef, "bar"]
fb51372e 431! ["foo", undef, "bar"] [qr/o/, "", "bar"]
2522c35a 432! ["foo", "", "bar"] [qr/o/, undef, "bar"]
1cfb7049 433 $deep1 $deep1
031a44ed 434 @$deep1 @$deep1
1cfb7049 435! $deep1 $deep2
0d863452 436
031a44ed
RGS
437= \@nums \@tied_nums
438= @nums \@tied_nums
439= \@nums @tied_nums
440= @nums @tied_nums
441
d0b243e3
RGS
442# - an object
443! $obj @fooormore
41e726ac 444 $obj [sub{ref shift}]
d0b243e3 445
0d863452 446# - a regex
ea0c2dbd
RGS
447= qr/x/ [qw(foo bar baz quux)]
448=! qr/y/ [qw(foo bar baz quux)]
449= /x/ [qw(foo bar baz quux)]
450=! /y/ [qw(foo bar baz quux)]
451= /FOO/i @fooormore
452=! /bar/ @fooormore
0d863452
RH
453
454# - a number
015eb7b9 455 2 [qw(1.00 2.00)]
b0138e99
RGS
456 2 [qw(foo 2)]
457 2.0_0e+0 [qw(foo 2)]
458! 2 [qw(1foo bar2)]
0d863452
RH
459
460# - a string
b0138e99
RGS
461! "2" [qw(1foo 2bar)]
462 "2bar" [qw(1foo 2bar)]
0d863452 463
015eb7b9
RGS
464# - undef
465 undef [1, 2, undef, 4]
466! undef [1, 2, [undef], 4]
467! undef @fooormore
468 undef @sparse
fb51372e
RGS
469 undef [undef]
470! 0 [undef]
471! "" [undef]
472! undef [0]
473! undef [""]
015eb7b9
RGS
474
475# - nested arrays and ~~ distributivity
476 11 [[11]]
477! 11 [[12]]
478 "foo" [{foo => "bar"}]
479! "bar" [{foo => "bar"}]
480
0d863452
RH
481# Number against number
482 2 2
33ed63a2 483 20 2_0
0d863452 484! 2 3
18d11902
RGS
485 0 FALSE
486 3-2 TRUE
fb51372e
RGS
487! undef 0
488! (my $u) 0
0d863452
RH
489
490# Number against string
33ed63a2
RGS
491= 2 "2"
492= 2 "2.0"
0d863452 493! 2 "2bananas"
289d21b2 494!= 2_3 "2_3" NOWARNINGS
18d11902 495 FALSE "0"
fb51372e
RGS
496! undef "0"
497! undef ""
0d863452
RH
498
499# Regex against string
a566f585
RGS
500 "x" qr/x/
501! "x" qr/y/
0d863452
RH
502
503# Regex against number
504 12345 qr/3/
2522c35a 505! 12345 qr/7/
0d863452 506
031a44ed 507# array/hash against string
d444f7e3
RGS
508 @fooormore "".\@fooormore
509! @keyandmore "".\@fooormore
510 %fooormore "".\%fooormore
511! %keyandmore "".\%fooormore
f1bef09e 512
0d863452 513# Test the implicit referencing
b0138e99 514 7 @nums
0d863452
RH
515 @nums \@nums
516! @nums \\@nums
517 @nums [1..10]
518! @nums [0..9]
519
2e0e16c9
RGS
520 "foo" %hash
521 /bar/ %hash
522 [qw(bar)] %hash
523! [qw(a b c)] %hash
71b0fb34 524 %hash %hash
fceebc47 525 %hash +{%hash}
73aec0b1 526 %hash \%hash
71b0fb34
DK
527 %hash %tied_hash
528 %tied_hash %tied_hash
529 %hash { foo => 5, bar => 10 }
530! %hash { foo => 5, bar => 10, quux => 15 }
531
532 @nums { 1, '', 2, '' }
533 @nums { 1, '', 12, '' }
534! @nums { 11, '', 12, '' }
be99ef1a 535
329a333e
DL
536# array slices
537 @nums[0..-1] []
538 @nums[0..0] [1]
539! @nums[0..1] [0..2]
540 @nums[0..4] [1..5]
541
542! undef @nums[0..-1]
543 1 @nums[0..0]
544 2 @nums[0..1]
545! @nums[0..1] 2
546
547 @nums[0..1] @nums[0..1]
548
549# hash slices
550 @keyandmore{qw(not)} [undef]
551 @keyandmore{qw(key)} [0]
552
553 undef @keyandmore{qw(not)}
554 0 @keyandmore{qw(key and more)}
555! 2 @keyandmore{qw(key and)}
556
557 @fooormore{qw(foo)} @keyandmore{qw(key)}
558 @fooormore{qw(foo or more)} @keyandmore{qw(key and more)}
559
be99ef1a
YK
560# UNDEF
561! 3 undef
562! 1 undef
563! [] undef
564! {} undef
565! \%::main undef
566! [1,2] undef
567! %hash undef
568! @nums undef
569! "foo" undef
570! "" undef
571! !1 undef
572! \&foo undef
573! sub { } undef