Implement distributivity in $scalar ~~ @array
[p5sagit/p5-mst-13.2.git] / t / op / smartmatch.t
1 #!./perl
2
3 BEGIN {
4     chdir 't';
5     @INC = '../lib';
6     require './test.pl';
7 }
8 use strict;
9
10 use Tie::Array;
11 use Tie::Hash;
12
13 # Predeclare vars used in the tests:
14 my @empty;
15 my %empty;
16 my @sparse; $sparse[2] = 2;
17
18 my $deep1 = []; push @$deep1, \$deep1;
19 my $deep2 = []; push @$deep2, \$deep2;
20
21 my @nums = (1..10);
22 tie my @tied_nums, 'Tie::StdArray';
23 @tied_nums =  (1..10);
24
25 my %hash = (foo => 17, bar => 23);
26 tie my %tied_hash, 'Tie::StdHash';
27 %tied_hash = %hash;
28
29 {
30     package Test::Object::NoOverload;
31     sub new { bless { key => 1 } }
32 }
33
34 {
35     package Test::Object::CopyOverload;
36     sub new { bless { key => 'magic' } }
37     use overload '~~' => sub { my %hash = %{ $_[0] }; $_[1] eq $hash{key} };
38 }
39
40 our $ov_obj = Test::Object::CopyOverload->new;
41 our $obj = Test::Object::NoOverload->new;
42
43 my @keyandmore = qw(key and more);
44 my @fooormore = qw(foo or more);
45 my %keyandmore = map { $_ => 0 } @keyandmore;
46 my %fooormore = map { $_ => 0 } @fooormore;
47
48 # Load and run the tests
49 plan "no_plan";
50
51 while (<DATA>) {
52     next if /^#/ || !/\S/;
53     chomp;
54     my ($yn, $left, $right, $note) = split /\t+/;
55
56     local $::TODO = $note =~ /TODO/;
57
58     die "Bad test spec: ($yn, $left, $right)" if $yn =~ /[^!@=]/;
59
60     my $tstr = "$left ~~ $right";
61
62     test_again:
63     my $res = eval $tstr;
64
65     chomp $@;
66
67     if ( $yn =~ /@/ ) {
68         ok( $@ ne '', "$tstr dies" )
69             and print "# \$\@ was: $@\n";
70     } else {
71         my $test_name = $tstr . ($yn =~ /!/ ? " does not match" : " matches");
72         if ( $@ ne '' ) {
73             fail($test_name);
74             print "# \$\@ was: $@\n";
75         } else {
76             ok( ($yn =~ /!/ xor $res), $test_name );
77         }
78     }
79
80     if ( $yn =~ s/=// ) {
81         $tstr = "$right ~~ $left";
82         goto test_again;
83     }
84 }
85
86 sub foo {}
87 sub bar {42}
88 sub gorch {42}
89 sub fatal {die "fatal sub\n"}
90
91 # to test constant folding
92 sub FALSE() { 0 }
93 sub TRUE() { 1 }
94 sub NOT_DEF() { undef }
95
96 # Prefix character :
97 #   - expected to match
98 # ! - expected to not match
99 # @ - expected to be a compilation failure
100 # = - expected to match symmetrically (runs test twice)
101 # Data types to test :
102 #   undef
103 #   Object-overloaded
104 #   Object
105 #   Coderef
106 #   Hash
107 #   Hashref
108 #   Array
109 #   Arrayref
110 #   Tied arrays and hashes
111 #   Arrays that reference themselves
112 #   Regex (// and qr//)
113 #   Range
114 #   Num
115 #   Str
116 # Other syntactic items of interest:
117 #   Constants
118 #   Values returned by a sub call
119 __DATA__
120 # Any ~~ undef
121 !       $ov_obj         undef
122 !       $obj            undef
123 !       sub {}          undef
124 !       %hash           undef
125 !       \%hash          undef
126 !       {}              undef
127 !       @nums           undef
128 !       \@nums          undef
129 !       []              undef
130 !       %tied_hash      undef
131 !       @tied_nums      undef
132 !       $deep1          undef
133 !       /foo/           undef
134 !       qr/foo/         undef
135 !       21..30          undef
136 !       189             undef
137 !       "foo"           undef
138 !       ""              undef
139 !       !1              undef
140         undef           undef
141         (my $u)         undef
142         NOT_DEF         undef
143         &NOT_DEF        undef
144
145 # Any ~~ object overloaded
146 !       \&fatal         $ov_obj
147         'magic'         $ov_obj
148 !       'not magic'     $ov_obj
149 !       $obj            $ov_obj
150 !       undef           $ov_obj
151
152 # regular object
153 @       $obj            $obj
154 @       $ov_obj         $obj
155 @       \&fatal         $obj
156 @       \&FALSE         $obj
157 @       \&foo           $obj
158 @       sub { 1 }       $obj
159 @       sub { 0 }       $obj
160 @       %keyandmore     $obj
161 @       {"key" => 1}    $obj
162 @       @fooormore      $obj
163 @       ["key" => 1]    $obj
164 @       /key/           $obj
165 @       qr/key/         $obj
166 @       "key"           $obj
167 @       FALSE           $obj
168
169 # object (overloaded or not) ~~ Any
170 # TODO
171
172 # ~~ Coderef
173         sub{0}          sub { ref $_[0] eq "CODE" }
174         %fooormore      sub { $_[0] =~ /^(foo|or|more)$/ }
175 !       %fooormore      sub { $_[0] =~ /^(foo|or|less)$/ }
176         \%fooormore     sub { $_[0] =~ /^(foo|or|more)$/ }
177 !       \%fooormore     sub { $_[0] =~ /^(foo|or|less)$/ }
178         +{%fooormore}   sub { $_[0] =~ /^(foo|or|more)$/ }
179 !       +{%fooormore}   sub { $_[0] =~ /^(foo|or|less)$/ }
180         @fooormore      sub { $_[0] =~ /^(foo|or|more)$/ }
181 !       @fooormore      sub { $_[0] =~ /^(foo|or|less)$/ }
182         \@fooormore     sub { $_[0] =~ /^(foo|or|more)$/ }
183 !       \@fooormore     sub { $_[0] =~ /^(foo|or|less)$/ }
184         [@fooormore]    sub { $_[0] =~ /^(foo|or|more)$/ }
185 !       [@fooormore]    sub { $_[0] =~ /^(foo|or|less)$/ }
186         %fooormore      sub{@_==1}
187         @fooormore      sub{@_==1}
188         "foo"           sub { $_[0] =~ /^(foo|or|more)$/ }
189 !       "more"          sub { $_[0] =~ /^(foo|or|less)$/ }
190         /fooormore/     sub{ref $_[0] eq 'Regexp'}
191         qr/fooormore/   sub{ref $_[0] eq 'Regexp'}
192         1               sub{shift}
193 !       0               sub{shift}
194 !       undef           sub{shift}
195         undef           sub{not shift}
196         NOT_DEF         sub{not shift}
197         &NOT_DEF        sub{not shift}
198         FALSE           sub{not shift}
199         [1]             \&bar
200         {a=>1}          \&bar
201         qr//            \&bar
202 !       [1]             \&foo
203 !       {a=>1}          \&foo
204         $obj            sub { ref $_[0] =~ /NoOverload/ }       TODO
205         $ov_obj         sub { ref $_[0] =~ /CopyOverload/ }     TODO
206 # empty stuff matches, because the sub is never called:
207         []              \&foo
208         {}              \&foo
209         @empty          \&foo
210         %empty          \&foo
211 !       qr//            \&foo
212 !       undef           \&foo
213         undef           \&bar
214 @       undef           \&fatal
215 @       1               \&fatal
216 @       [1]             \&fatal
217 @       {a=>1}          \&fatal
218 @       "foo"           \&fatal
219 @       qr//            \&fatal
220 # sub is not called on empty hashes / arrays
221         []              \&fatal
222         +{}             \&fatal
223         @empty          \&fatal
224         %empty          \&fatal
225
226 # HASH ref against:
227 #   - another hash ref
228         {}              {}
229 =!      {}              {1 => 2}
230         {1 => 2}        {1 => 2}
231         {1 => 2}        {1 => 3}
232 =!      {1 => 2}        {2 => 3}
233 =       \%main::        {map {$_ => 'x'} keys %main::}
234
235 #  - tied hash ref
236 =       \%hash          \%tied_hash
237         \%tied_hash     \%tied_hash
238 !=      {"a"=>"b"}      \%tied_hash
239 =       %hash           %tied_hash
240         %tied_hash      %tied_hash
241 !=      {"a"=>"b"}      %tied_hash
242
243 #  - an array ref
244 #  (since this is symmetrical, tests as well hash~~array)
245 =       [keys %main::]  \%::
246 =       [qw[STDIN STDOUT]]      \%::
247 =!      []              \%::
248 =!      [""]            {}
249 =!      []              {}
250 =!      @empty          {}
251 =       [undef]         {"" => 1}
252 =       [""]            {"" => 1}
253 =       ["foo"]         { foo => 1 }
254 =       ["foo", "bar"]  { foo => 1 }
255 =       ["foo", "bar"]  \%hash
256 =       ["foo"]         \%hash
257 =!      ["quux"]        \%hash
258 =       [qw(foo quux)]  \%hash
259 =       @fooormore      { foo => 1, or => 2, more => 3 }
260 =       @fooormore      %fooormore
261 =       @fooormore      \%fooormore
262 =       \@fooormore     %fooormore
263
264 #  - a regex
265 # TODO those should be symmetrical
266         qr/^(fo[ox])$/          {foo => 1}
267         /^(fo[ox])$/            %fooormore
268 =!      qr/[13579]$/            +{0..99}
269 !       qr/a*/                  {}
270 =       qr/a*/                  {b=>2}
271         qr/B/i                  {b=>2}
272         /B/i                    {b=>2}
273 !       qr/a+/                  {b=>2}
274         qr/^à/                 {"à"=>2}
275
276 #  - a scalar
277         "foo"           +{foo => 1, bar => 2}
278         "foo"           %fooormore
279 !       "baz"           +{foo => 1, bar => 2}
280 !       "boz"           %fooormore
281 !       1               +{foo => 1, bar => 2}
282 !       1               %fooormore
283         1               { 1 => 3 }
284         1.0             { 1 => 3 }
285 !       "1.0"           { 1 => 3 }
286 !       "1.0"           { 1.0 => 3 }
287         "1.0"           { "1.0" => 3 }
288         "à"            { "à" => "À" }
289
290 #  - undef
291 !       undef           { hop => 'zouu' }
292 !       undef           %hash
293 !       undef           +{"" => "empty key"}
294 !       undef           {}
295
296 # ARRAY ref against:
297 #  - another array ref
298         []                      []
299 =!      []                      [1]
300 !       [["foo"], ["bar"]]      [qr/o/, qr/a/]
301         [["foo"], ["bar"]]      [qr/ARRAY/, qr/ARRAY/]
302         ["foo", "bar"]          [qr/o/, qr/a/]
303 !       [qr/o/, qr/a/]          ["foo", "bar"]
304         ["foo", "bar"]          [["foo"], ["bar"]]
305 !       ["foo", "bar"]          [qr/o/, "foo"]
306         ["foo", undef, "bar"]   [qr/o/, undef, "bar"]
307         ["foo", undef, "bar"]   [qr/o/, "",    "bar"]
308 !       ["foo", "", "bar"]      [qr/o/, undef, "bar"]
309         $deep1                  $deep1
310         @$deep1                 @$deep1
311 !       $deep1                  $deep2
312
313 =       \@nums                  \@tied_nums
314 =       @nums                   \@tied_nums
315 =       \@nums                  @tied_nums
316 =       @nums                   @tied_nums
317
318 #  - an object
319 !       $obj            @fooormore
320         $obj            [sub{ref shift}]        TODO
321
322 #  - works with lists instead of arrays
323         "foo"                   qw(foo bar)     TODO
324         "foo"                   ('foo','bar')   TODO
325
326 #  - a regex
327         qr/x/           [qw(foo bar baz quux)]
328 !       qr/y/           [qw(foo bar baz quux)]
329         /x/             [qw(foo bar baz quux)]
330 !       /y/             [qw(foo bar baz quux)]
331         /FOO/i          @fooormore
332 !       /bar/           @fooormore
333
334 # - a number
335         2               [qw(1.00 2.00)]
336         2               [qw(foo 2)]
337         2.0_0e+0        [qw(foo 2)]
338 !       2               [qw(1foo bar2)]
339
340 # - a string
341 !       "2"             [qw(1foo 2bar)]
342         "2bar"          [qw(1foo 2bar)]
343
344 # - undef
345         undef           [1, 2, undef, 4]
346 !       undef           [1, 2, [undef], 4]
347 !       undef           @fooormore
348         undef           @sparse
349
350 # - nested arrays and ~~ distributivity
351         11              [[11]]
352 !       11              [[12]]
353         "foo"           [{foo => "bar"}]
354 !       "bar"           [{foo => "bar"}]
355
356 # Number against number
357         2               2
358         20              2_0
359 !       2               3
360         0               FALSE
361         3-2             TRUE
362         undef           0
363
364 # Number against string
365 =       2               "2"
366 =       2               "2.0"
367 !       2               "2bananas"
368 !=      2_3             "2_3"
369         FALSE           "0"
370
371 # Regex against string
372         "x"             qr/x/
373 !       "x"             qr/y/
374
375 # Regex against number
376         12345           qr/3/
377 !       12345           qr/7/
378
379 # TODO ranges
380
381 # array/hash against string
382         @fooormore      "".\@fooormore
383 !       @keyandmore     "".\@fooormore
384         %fooormore      "".\%fooormore
385 !       %keyandmore     "".\%fooormore
386
387 # Test the implicit referencing
388         7               @nums
389         @nums           \@nums
390 !       @nums           \\@nums
391         @nums           [1..10]
392 !       @nums           [0..9]
393
394         "foo"           %hash
395         /bar/           %hash
396         [qw(bar)]       %hash
397 !       [qw(a b c)]     %hash
398         %hash           %hash
399         %hash           +{%hash}
400         %hash           \%hash
401         %hash           %tied_hash
402         %tied_hash      %tied_hash
403         %hash           { foo => 5, bar => 10 }
404 !       %hash           { foo => 5, bar => 10, quux => 15 }
405
406         @nums           {  1, '',  2, '' }
407         @nums           {  1, '', 12, '' }
408 !       @nums           { 11, '', 12, '' }