1#!./perl 2 3BEGIN { 4 chdir 't' if -d 't'; 5 require './test.pl'; 6 set_up_inc('../lib'); 7} 8 9use strict; 10use warnings; 11no warnings 'experimental::smartmatch'; 12 13plan tests => 197; 14 15# The behaviour of the feature pragma should be tested by lib/feature.t 16# using the tests in t/lib/feature/*. This file tests the behaviour of 17# the switch ops themselves. 18 19 20# Before loading feature, test the switch ops with CORE:: 21CORE::given(3) { 22 CORE::when(3) { pass "CORE::given and CORE::when"; continue } 23 CORE::default { pass "continue (without feature) and CORE::default" } 24} 25 26 27use feature 'switch'; 28 29eval { continue }; 30like($@, qr/^Can't "continue" outside/, "continue outside"); 31 32eval { break }; 33like($@, qr/^Can't "break" outside/, "break outside"); 34 35# Scoping rules 36 37{ 38 my $x = "foo"; 39 given(my $x = "bar") { 40 is($x, "bar", "given scope starts"); 41 } 42 is($x, "foo", "given scope ends"); 43} 44 45sub be_true {1} 46 47given(my $x = "foo") { 48 when(be_true(my $x = "bar")) { 49 is($x, "bar", "given scope starts"); 50 } 51 is($x, "foo", "given scope ends"); 52} 53 54$_ = "outside"; 55given("inside") { check_outside1() } 56sub check_outside1 { is($_, "inside", "\$_ is not lexically scoped") } 57 58# Basic string/numeric comparisons and control flow 59 60{ 61 my $ok; 62 given(3) { 63 when(2) { $ok = 'two'; } 64 when(3) { $ok = 'three'; } 65 when(4) { $ok = 'four'; } 66 default { $ok = 'd'; } 67 } 68 is($ok, 'three', "numeric comparison"); 69} 70 71{ 72 my $ok; 73 use integer; 74 given(3.14159265) { 75 when(2) { $ok = 'two'; } 76 when(3) { $ok = 'three'; } 77 when(4) { $ok = 'four'; } 78 default { $ok = 'd'; } 79 } 80 is($ok, 'three', "integer comparison"); 81} 82 83{ 84 my ($ok1, $ok2); 85 given(3) { 86 when(3.1) { $ok1 = 'n'; } 87 when(3.0) { $ok1 = 'y'; continue } 88 when("3.0") { $ok2 = 'y'; } 89 default { $ok2 = 'n'; } 90 } 91 is($ok1, 'y', "more numeric (pt. 1)"); 92 is($ok2, 'y', "more numeric (pt. 2)"); 93} 94 95{ 96 my $ok; 97 given("c") { 98 when("b") { $ok = 'B'; } 99 when("c") { $ok = 'C'; } 100 when("d") { $ok = 'D'; } 101 default { $ok = 'def'; } 102 } 103 is($ok, 'C', "string comparison"); 104} 105 106{ 107 my $ok; 108 given("c") { 109 when("b") { $ok = 'B'; } 110 when("c") { $ok = 'C'; continue } 111 when("c") { $ok = 'CC'; } 112 default { $ok = 'D'; } 113 } 114 is($ok, 'CC', "simple continue"); 115} 116 117# Definedness 118{ 119 my $ok = 1; 120 given (0) { when(undef) {$ok = 0} } 121 is($ok, 1, "Given(0) when(undef)"); 122} 123{ 124 my $undef; 125 my $ok = 1; 126 given (0) { when($undef) {$ok = 0} } 127 is($ok, 1, 'Given(0) when($undef)'); 128} 129{ 130 my $undef; 131 my $ok = 0; 132 given (0) { when($undef++) {$ok = 1} } 133 is($ok, 1, "Given(0) when($undef++)"); 134} 135{ 136 no warnings "uninitialized"; 137 my $ok = 1; 138 given (undef) { when(0) {$ok = 0} } 139 is($ok, 1, "Given(undef) when(0)"); 140} 141{ 142 no warnings "uninitialized"; 143 my $undef; 144 my $ok = 1; 145 given ($undef) { when(0) {$ok = 0} } 146 is($ok, 1, 'Given($undef) when(0)'); 147} 148######## 149{ 150 my $ok = 1; 151 given ("") { when(undef) {$ok = 0} } 152 is($ok, 1, 'Given("") when(undef)'); 153} 154{ 155 my $undef; 156 my $ok = 1; 157 given ("") { when($undef) {$ok = 0} } 158 is($ok, 1, 'Given("") when($undef)'); 159} 160{ 161 no warnings "uninitialized"; 162 my $ok = 1; 163 given (undef) { when("") {$ok = 0} } 164 is($ok, 1, 'Given(undef) when("")'); 165} 166{ 167 no warnings "uninitialized"; 168 my $undef; 169 my $ok = 1; 170 given ($undef) { when("") {$ok = 0} } 171 is($ok, 1, 'Given($undef) when("")'); 172} 173######## 174{ 175 my $ok = 0; 176 given (undef) { when(undef) {$ok = 1} } 177 is($ok, 1, "Given(undef) when(undef)"); 178} 179{ 180 my $undef; 181 my $ok = 0; 182 given (undef) { when($undef) {$ok = 1} } 183 is($ok, 1, 'Given(undef) when($undef)'); 184} 185{ 186 my $undef; 187 my $ok = 0; 188 given ($undef) { when(undef) {$ok = 1} } 189 is($ok, 1, 'Given($undef) when(undef)'); 190} 191{ 192 my $undef; 193 my $ok = 0; 194 given ($undef) { when($undef) {$ok = 1} } 195 is($ok, 1, 'Given($undef) when($undef)'); 196} 197 198 199# Regular expressions 200{ 201 my ($ok1, $ok2); 202 given("Hello, world!") { 203 when(/lo/) 204 { $ok1 = 'y'; continue} 205 when(/no/) 206 { $ok1 = 'n'; continue} 207 when(/^(Hello,|Goodbye cruel) world[!.?]/) 208 { $ok2 = 'Y'; continue} 209 when(/^(Hello cruel|Goodbye,) world[!.?]/) 210 { $ok2 = 'n'; continue} 211 } 212 is($ok1, 'y', "regex 1"); 213 is($ok2, 'Y', "regex 2"); 214} 215 216# Comparisons 217{ 218 my $test = "explicit numeric comparison (<)"; 219 my $twenty_five = 25; 220 my $ok; 221 given($twenty_five) { 222 when ($_ < 10) { $ok = "ten" } 223 when ($_ < 20) { $ok = "twenty" } 224 when ($_ < 30) { $ok = "thirty" } 225 when ($_ < 40) { $ok = "forty" } 226 default { $ok = "default" } 227 } 228 is($ok, "thirty", $test); 229} 230 231{ 232 use integer; 233 my $test = "explicit numeric comparison (integer <)"; 234 my $twenty_five = 25; 235 my $ok; 236 given($twenty_five) { 237 when ($_ < 10) { $ok = "ten" } 238 when ($_ < 20) { $ok = "twenty" } 239 when ($_ < 30) { $ok = "thirty" } 240 when ($_ < 40) { $ok = "forty" } 241 default { $ok = "default" } 242 } 243 is($ok, "thirty", $test); 244} 245 246{ 247 my $test = "explicit numeric comparison (<=)"; 248 my $twenty_five = 25; 249 my $ok; 250 given($twenty_five) { 251 when ($_ <= 10) { $ok = "ten" } 252 when ($_ <= 20) { $ok = "twenty" } 253 when ($_ <= 30) { $ok = "thirty" } 254 when ($_ <= 40) { $ok = "forty" } 255 default { $ok = "default" } 256 } 257 is($ok, "thirty", $test); 258} 259 260{ 261 use integer; 262 my $test = "explicit numeric comparison (integer <=)"; 263 my $twenty_five = 25; 264 my $ok; 265 given($twenty_five) { 266 when ($_ <= 10) { $ok = "ten" } 267 when ($_ <= 20) { $ok = "twenty" } 268 when ($_ <= 30) { $ok = "thirty" } 269 when ($_ <= 40) { $ok = "forty" } 270 default { $ok = "default" } 271 } 272 is($ok, "thirty", $test); 273} 274 275 276{ 277 my $test = "explicit numeric comparison (>)"; 278 my $twenty_five = 25; 279 my $ok; 280 given($twenty_five) { 281 when ($_ > 40) { $ok = "forty" } 282 when ($_ > 30) { $ok = "thirty" } 283 when ($_ > 20) { $ok = "twenty" } 284 when ($_ > 10) { $ok = "ten" } 285 default { $ok = "default" } 286 } 287 is($ok, "twenty", $test); 288} 289 290{ 291 my $test = "explicit numeric comparison (>=)"; 292 my $twenty_five = 25; 293 my $ok; 294 given($twenty_five) { 295 when ($_ >= 40) { $ok = "forty" } 296 when ($_ >= 30) { $ok = "thirty" } 297 when ($_ >= 20) { $ok = "twenty" } 298 when ($_ >= 10) { $ok = "ten" } 299 default { $ok = "default" } 300 } 301 is($ok, "twenty", $test); 302} 303 304{ 305 use integer; 306 my $test = "explicit numeric comparison (integer >)"; 307 my $twenty_five = 25; 308 my $ok; 309 given($twenty_five) { 310 when ($_ > 40) { $ok = "forty" } 311 when ($_ > 30) { $ok = "thirty" } 312 when ($_ > 20) { $ok = "twenty" } 313 when ($_ > 10) { $ok = "ten" } 314 default { $ok = "default" } 315 } 316 is($ok, "twenty", $test); 317} 318 319{ 320 use integer; 321 my $test = "explicit numeric comparison (integer >=)"; 322 my $twenty_five = 25; 323 my $ok; 324 given($twenty_five) { 325 when ($_ >= 40) { $ok = "forty" } 326 when ($_ >= 30) { $ok = "thirty" } 327 when ($_ >= 20) { $ok = "twenty" } 328 when ($_ >= 10) { $ok = "ten" } 329 default { $ok = "default" } 330 } 331 is($ok, "twenty", $test); 332} 333 334 335{ 336 my $test = "explicit string comparison (lt)"; 337 my $twenty_five = "25"; 338 my $ok; 339 given($twenty_five) { 340 when ($_ lt "10") { $ok = "ten" } 341 when ($_ lt "20") { $ok = "twenty" } 342 when ($_ lt "30") { $ok = "thirty" } 343 when ($_ lt "40") { $ok = "forty" } 344 default { $ok = "default" } 345 } 346 is($ok, "thirty", $test); 347} 348 349{ 350 my $test = "explicit string comparison (le)"; 351 my $twenty_five = "25"; 352 my $ok; 353 given($twenty_five) { 354 when ($_ le "10") { $ok = "ten" } 355 when ($_ le "20") { $ok = "twenty" } 356 when ($_ le "30") { $ok = "thirty" } 357 when ($_ le "40") { $ok = "forty" } 358 default { $ok = "default" } 359 } 360 is($ok, "thirty", $test); 361} 362 363{ 364 my $test = "explicit string comparison (gt)"; 365 my $twenty_five = 25; 366 my $ok; 367 given($twenty_five) { 368 when ($_ ge "40") { $ok = "forty" } 369 when ($_ ge "30") { $ok = "thirty" } 370 when ($_ ge "20") { $ok = "twenty" } 371 when ($_ ge "10") { $ok = "ten" } 372 default { $ok = "default" } 373 } 374 is($ok, "twenty", $test); 375} 376 377{ 378 my $test = "explicit string comparison (ge)"; 379 my $twenty_five = 25; 380 my $ok; 381 given($twenty_five) { 382 when ($_ ge "40") { $ok = "forty" } 383 when ($_ ge "30") { $ok = "thirty" } 384 when ($_ ge "20") { $ok = "twenty" } 385 when ($_ ge "10") { $ok = "ten" } 386 default { $ok = "default" } 387 } 388 is($ok, "twenty", $test); 389} 390 391# Optimized-away comparisons 392{ 393 my $ok; 394 given(23) { 395 when (2 + 2 == 4) { $ok = 'y'; continue } 396 when (2 + 2 == 5) { $ok = 'n' } 397 } 398 is($ok, 'y', "Optimized-away comparison"); 399} 400 401{ 402 my $ok; 403 given(23) { 404 when (scalar 24) { $ok = 'n'; continue } 405 default { $ok = 'y' } 406 } 407 is($ok,'y','scalar()'); 408} 409 410# File tests 411# (How to be both thorough and portable? Pinch a few ideas 412# from t/op/filetest.t. We err on the side of portability for 413# the time being.) 414 415{ 416 my ($ok_d, $ok_f, $ok_r); 417 given("op") { 418 when(-d) {$ok_d = 1; continue} 419 when(!-f) {$ok_f = 1; continue} 420 when(-r) {$ok_r = 1; continue} 421 } 422 ok($ok_d, "Filetest -d"); 423 ok($ok_f, "Filetest -f"); 424 ok($ok_r, "Filetest -r"); 425} 426 427# Sub and method calls 428sub notfoo {"bar"} 429{ 430 my $ok = 0; 431 given("foo") { 432 when(notfoo()) {$ok = 1} 433 } 434 ok($ok, "Sub call acts as boolean") 435} 436 437{ 438 my $ok = 0; 439 given("foo") { 440 when(main->notfoo()) {$ok = 1} 441 } 442 ok($ok, "Class-method call acts as boolean") 443} 444 445{ 446 my $ok = 0; 447 my $obj = bless []; 448 given("foo") { 449 when($obj->notfoo()) {$ok = 1} 450 } 451 ok($ok, "Object-method call acts as boolean") 452} 453 454# Other things that should not be smart matched 455{ 456 my $ok = 0; 457 given(12) { 458 when( /(\d+)/ and ( 1 <= $1 and $1 <= 12 ) ) { 459 $ok = 1; 460 } 461 } 462 ok($ok, "bool not smartmatches"); 463} 464 465{ 466 my $ok = 0; 467 given(0) { 468 when(eof(DATA)) { 469 $ok = 1; 470 } 471 } 472 ok($ok, "eof() not smartmatched"); 473} 474 475{ 476 my $ok = 0; 477 my %foo = ("bar", 0); 478 given(0) { 479 when(exists $foo{bar}) { 480 $ok = 1; 481 } 482 } 483 ok($ok, "exists() not smartmatched"); 484} 485 486{ 487 my $ok = 0; 488 given(0) { 489 when(defined $ok) { 490 $ok = 1; 491 } 492 } 493 ok($ok, "defined() not smartmatched"); 494} 495 496{ 497 my $ok = 1; 498 given("foo") { 499 when((1 == 1) && "bar") { 500 $ok = 0; 501 } 502 when((1 == 1) && $_ eq "foo") { 503 $ok = 2; 504 } 505 } 506 is($ok, 2, "((1 == 1) && \"bar\") not smartmatched"); 507} 508 509{ 510 my $n = 0; 511 for my $l (qw(a b c d)) { 512 given ($l) { 513 when ($_ eq "b" .. $_ eq "c") { $n = 1 } 514 default { $n = 0 } 515 } 516 ok(($n xor $l =~ /[ad]/), 'when(E1..E2) evaluates in boolean context'); 517 } 518} 519 520{ 521 my $n = 0; 522 for my $l (qw(a b c d)) { 523 given ($l) { 524 when ($_ eq "b" ... $_ eq "c") { $n = 1 } 525 default { $n = 0 } 526 } 527 ok(($n xor $l =~ /[ad]/), 'when(E1...E2) evaluates in boolean context'); 528 } 529} 530 531{ 532 my $ok = 0; 533 given("foo") { 534 when((1 == $ok) || "foo") { 535 $ok = 1; 536 } 537 } 538 ok($ok, '((1 == $ok) || "foo") smartmatched'); 539} 540 541{ 542 my $ok = 0; 543 given("foo") { 544 when((1 == $ok || undef) // "foo") { 545 $ok = 1; 546 } 547 } 548 ok($ok, '((1 == $ok || undef) // "foo") smartmatched'); 549} 550 551# Make sure we aren't invoking the get-magic more than once 552 553{ # A helper class to count the number of accesses. 554 package FetchCounter; 555 sub TIESCALAR { 556 my ($class) = @_; 557 bless {value => undef, count => 0}, $class; 558 } 559 sub STORE { 560 my ($self, $val) = @_; 561 $self->{count} = 0; 562 $self->{value} = $val; 563 } 564 sub FETCH { 565 my ($self) = @_; 566 # Avoid pre/post increment here 567 $self->{count} = 1 + $self->{count}; 568 $self->{value}; 569 } 570 sub count { 571 my ($self) = @_; 572 $self->{count}; 573 } 574} 575 576my $f = tie my $v, "FetchCounter"; 577 578{ my $test_name = "Multiple FETCHes in given, due to aliasing"; 579 my $ok; 580 given($v = 23) { 581 when(undef) {} 582 when(sub{0}->()) {} 583 when(21) {} 584 when("22") {} 585 when(23) {$ok = 1} 586 when(/24/) {$ok = 0} 587 } 588 is($ok, 1, "precheck: $test_name"); 589 is($f->count(), 4, $test_name); 590} 591 592{ my $test_name = "Only one FETCH (numeric when)"; 593 my $ok; 594 $v = 23; 595 is($f->count(), 0, "Sanity check: $test_name"); 596 given(23) { 597 when(undef) {} 598 when(sub{0}->()) {} 599 when(21) {} 600 when("22") {} 601 when($v) {$ok = 1} 602 when(/24/) {$ok = 0} 603 } 604 is($ok, 1, "precheck: $test_name"); 605 is($f->count(), 1, $test_name); 606} 607 608{ my $test_name = "Only one FETCH (string when)"; 609 my $ok; 610 $v = "23"; 611 is($f->count(), 0, "Sanity check: $test_name"); 612 given("23") { 613 when(undef) {} 614 when(sub{0}->()) {} 615 when("21") {} 616 when("22") {} 617 when($v) {$ok = 1} 618 when(/24/) {$ok = 0} 619 } 620 is($ok, 1, "precheck: $test_name"); 621 is($f->count(), 1, $test_name); 622} 623 624{ my $test_name = "Only one FETCH (undef)"; 625 my $ok; 626 $v = undef; 627 is($f->count(), 0, "Sanity check: $test_name"); 628 no warnings "uninitialized"; 629 given(my $undef) { 630 when(sub{0}->()) {} 631 when("21") {} 632 when("22") {} 633 when($v) {$ok = 1} 634 when(undef) {$ok = 0} 635 } 636 is($ok, 1, "precheck: $test_name"); 637 is($f->count(), 1, $test_name); 638} 639 640# Loop topicalizer 641{ 642 my $first = 1; 643 for (1, "two") { 644 when ("two") { 645 is($first, 0, "Loop: second"); 646 eval {break}; 647 like($@, qr/^Can't "break" in a loop topicalizer/, 648 q{Can't "break" in a loop topicalizer}); 649 } 650 when (1) { 651 is($first, 1, "Loop: first"); 652 $first = 0; 653 # Implicit break is okay 654 } 655 } 656} 657 658{ 659 my $first = 1; 660 for $_ (1, "two") { 661 when ("two") { 662 is($first, 0, "Explicit \$_: second"); 663 eval {break}; 664 like($@, qr/^Can't "break" in a loop topicalizer/, 665 q{Can't "break" in a loop topicalizer}); 666 } 667 when (1) { 668 is($first, 1, "Explicit \$_: first"); 669 $first = 0; 670 # Implicit break is okay 671 } 672 } 673} 674 675 676# Code references 677{ 678 my $called_foo = 0; 679 sub foo {$called_foo = 1; "@_" eq "foo"} 680 my $called_bar = 0; 681 sub bar {$called_bar = 1; "@_" eq "bar"} 682 my ($matched_foo, $matched_bar) = (0, 0); 683 given("foo") { 684 when(\&bar) {$matched_bar = 1} 685 when(\&foo) {$matched_foo = 1} 686 } 687 is($called_foo, 1, "foo() was called"); 688 is($called_bar, 1, "bar() was called"); 689 is($matched_bar, 0, "bar didn't match"); 690 is($matched_foo, 1, "foo did match"); 691} 692 693sub contains_x { 694 my $x = shift; 695 return ($x =~ /x/); 696} 697{ 698 my ($ok1, $ok2) = (0,0); 699 given("foxy!") { 700 when(contains_x($_)) 701 { $ok1 = 1; continue } 702 when(\&contains_x) 703 { $ok2 = 1; continue } 704 } 705 is($ok1, 1, "Calling sub directly (true)"); 706 is($ok2, 1, "Calling sub indirectly (true)"); 707 708 given("foggy") { 709 when(contains_x($_)) 710 { $ok1 = 2; continue } 711 when(\&contains_x) 712 { $ok2 = 2; continue } 713 } 714 is($ok1, 1, "Calling sub directly (false)"); 715 is($ok2, 1, "Calling sub indirectly (false)"); 716} 717 718{ 719 # Test overloading 720 { package OverloadTest; 721 722 use overload '""' => sub{"string value of obj"}; 723 use overload 'eq' => sub{"$_[0]" eq "$_[1]"}; 724 725 use overload "~~" => sub { 726 my ($self, $other, $reversed) = @_; 727 if ($reversed) { 728 $self->{left} = $other; 729 $self->{right} = $self; 730 $self->{reversed} = 1; 731 } else { 732 $self->{left} = $self; 733 $self->{right} = $other; 734 $self->{reversed} = 0; 735 } 736 $self->{called} = 1; 737 return $self->{retval}; 738 }; 739 740 sub new { 741 my ($pkg, $retval) = @_; 742 bless { 743 called => 0, 744 retval => $retval, 745 }, $pkg; 746 } 747 } 748 749 { 750 my $test = "Overloaded obj in given (true)"; 751 my $obj = OverloadTest->new(1); 752 my $matched; 753 given($obj) { 754 when ("other arg") {$matched = 1} 755 default {$matched = 0} 756 } 757 758 is($obj->{called}, 1, "$test: called"); 759 ok($matched, "$test: matched"); 760 } 761 762 { 763 my $test = "Overloaded obj in given (false)"; 764 my $obj = OverloadTest->new(0); 765 my $matched; 766 given($obj) { 767 when ("other arg") {$matched = 1} 768 } 769 770 is($obj->{called}, 1, "$test: called"); 771 ok(!$matched, "$test: not matched"); 772 } 773 774 { 775 my $test = "Overloaded obj in when (true)"; 776 my $obj = OverloadTest->new(1); 777 my $matched; 778 given("topic") { 779 when ($obj) {$matched = 1} 780 default {$matched = 0} 781 } 782 783 is($obj->{called}, 1, "$test: called"); 784 ok($matched, "$test: matched"); 785 is($obj->{left}, "topic", "$test: left"); 786 is($obj->{right}, "string value of obj", "$test: right"); 787 ok($obj->{reversed}, "$test: reversed"); 788 } 789 790 { 791 my $test = "Overloaded obj in when (false)"; 792 my $obj = OverloadTest->new(0); 793 my $matched; 794 given("topic") { 795 when ($obj) {$matched = 1} 796 default {$matched = 0} 797 } 798 799 is($obj->{called}, 1, "$test: called"); 800 ok(!$matched, "$test: not matched"); 801 is($obj->{left}, "topic", "$test: left"); 802 is($obj->{right}, "string value of obj", "$test: right"); 803 ok($obj->{reversed}, "$test: reversed"); 804 } 805} 806 807# Postfix when 808{ 809 my $ok; 810 given (undef) { 811 $ok = 1 when undef; 812 } 813 is($ok, 1, "postfix undef"); 814} 815{ 816 my $ok; 817 given (2) { 818 $ok += 1 when 7; 819 $ok += 2 when 9.1685; 820 $ok += 4 when $_ > 4; 821 $ok += 8 when $_ < 2.5; 822 } 823 is($ok, 8, "postfix numeric"); 824} 825{ 826 my $ok; 827 given ("apple") { 828 $ok = 1, continue when $_ eq "apple"; 829 $ok += 2; 830 $ok = 0 when "banana"; 831 } 832 is($ok, 3, "postfix string"); 833} 834{ 835 my $ok; 836 given ("pear") { 837 do { $ok = 1; continue } when /pea/; 838 $ok += 2; 839 $ok = 0 when /pie/; 840 default { $ok += 4 } 841 $ok = 0; 842 } 843 is($ok, 7, "postfix regex"); 844} 845# be_true is defined at the beginning of the file 846{ 847 my $x = "what"; 848 given(my $x = "foo") { 849 do { 850 is($x, "foo", "scope inside ... when my \$x = ..."); 851 continue; 852 } when be_true(my $x = "bar"); 853 is($x, "bar", "scope after ... when my \$x = ..."); 854 } 855} 856{ 857 my $x = 0; 858 given(my $x = 1) { 859 my $x = 2, continue when be_true(); 860 is($x, undef, "scope after my \$x = ... when ..."); 861 } 862} 863 864# Tests for last and next in when clauses 865my $letter; 866 867$letter = ''; 868for ("a".."e") { 869 given ($_) { 870 $letter = $_; 871 when ("b") { last } 872 } 873 $letter = "z"; 874} 875is($letter, "b", "last in when"); 876 877$letter = ''; 878LETTER1: for ("a".."e") { 879 given ($_) { 880 $letter = $_; 881 when ("b") { last LETTER1 } 882 } 883 $letter = "z"; 884} 885is($letter, "b", "last LABEL in when"); 886 887$letter = ''; 888for ("a".."e") { 889 given ($_) { 890 when (/b|d/) { next } 891 $letter .= $_; 892 } 893 $letter .= ','; 894} 895is($letter, "a,c,e,", "next in when"); 896 897$letter = ''; 898LETTER2: for ("a".."e") { 899 given ($_) { 900 when (/b|d/) { next LETTER2 } 901 $letter .= $_; 902 } 903 $letter .= ','; 904} 905is($letter, "a,c,e,", "next LABEL in when"); 906 907# Test goto with given/when 908{ 909 my $flag = 0; 910 goto GIVEN1; 911 $flag = 1; 912 GIVEN1: given ($flag) { 913 when (0) { break; } 914 $flag = 2; 915 } 916 is($flag, 0, "goto GIVEN1"); 917} 918{ 919 my $flag = 0; 920 given ($flag) { 921 when (0) { $flag = 1; } 922 goto GIVEN2; 923 $flag = 2; 924 } 925GIVEN2: 926 is($flag, 1, "goto inside given"); 927} 928{ 929 my $flag = 0; 930 given ($flag) { 931 when (0) { $flag = 1; goto GIVEN3; $flag = 2; } 932 $flag = 3; 933 } 934GIVEN3: 935 is($flag, 1, "goto inside given and when"); 936} 937{ 938 my $flag = 0; 939 for ($flag) { 940 when (0) { $flag = 1; goto GIVEN4; $flag = 2; } 941 $flag = 3; 942 } 943GIVEN4: 944 is($flag, 1, "goto inside for and when"); 945} 946{ 947 my $flag = 0; 948GIVEN5: 949 given ($flag) { 950 when (0) { $flag = 1; goto GIVEN5; $flag = 2; } 951 when (1) { break; } 952 $flag = 3; 953 } 954 is($flag, 1, "goto inside given and when to the given stmt"); 955} 956 957# test with unreified @_ in smart match [perl #71078] 958sub unreified_check { ok([@_] ~~ \@_) } # should always match 959unreified_check(1,2,"lala"); 960unreified_check(1,2,undef); 961unreified_check(undef); 962unreified_check(undef,""); 963 964# Test do { given } as a rvalue 965 966{ 967 # Simple scalar 968 my $lexical = 5; 969 my @things = (11 .. 26); # 16 elements 970 my @exp = (5, 16, 9); 971 no warnings 'void'; 972 for (0, 1, 2) { 973 my $scalar = do { given ($_) { 974 when (0) { $lexical } 975 when (2) { 'void'; 8, 9 } 976 @things; 977 } }; 978 is($scalar, shift(@exp), "rvalue given - simple scalar [$_]"); 979 } 980} 981{ 982 # Postfix scalar 983 my $lexical = 5; 984 my @exp = (5, 7, 9); 985 for (0, 1, 2) { 986 no warnings 'void'; 987 my $scalar = do { given ($_) { 988 $lexical when 0; 989 8, 9 when 2; 990 6, 7; 991 } }; 992 is($scalar, shift(@exp), "rvalue given - postfix scalar [$_]"); 993 } 994} 995{ 996 # Default scalar 997 my @exp = (5, 9, 9); 998 for (0, 1, 2) { 999 my $scalar = do { given ($_) { 1000 no warnings 'void'; 1001 when (0) { 5 } 1002 default { 8, 9 } 1003 6, 7; 1004 } }; 1005 is($scalar, shift(@exp), "rvalue given - default scalar [$_]"); 1006 } 1007} 1008{ 1009 # Simple list 1010 my @things = (11 .. 13); 1011 my @exp = ('3 4 5', '11 12 13', '8 9'); 1012 for (0, 1, 2) { 1013 my @list = do { given ($_) { 1014 when (0) { 3 .. 5 } 1015 when (2) { my $fake = 'void'; 8, 9 } 1016 @things; 1017 } }; 1018 is("@list", shift(@exp), "rvalue given - simple list [$_]"); 1019 } 1020} 1021{ 1022 # Postfix list 1023 my @things = (12); 1024 my @exp = ('3 4 5', '6 7', '12'); 1025 for (0, 1, 2) { 1026 my @list = do { given ($_) { 1027 3 .. 5 when 0; 1028 @things when 2; 1029 6, 7; 1030 } }; 1031 is("@list", shift(@exp), "rvalue given - postfix list [$_]"); 1032 } 1033} 1034{ 1035 # Default list 1036 my @things = (11 .. 20); # 10 elements 1037 my @exp = ('m o o', '8 10', '8 10'); 1038 for (0, 1, 2) { 1039 my @list = do { given ($_) { 1040 when (0) { "moo" =~ /(.)/g } 1041 default { 8, scalar(@things) } 1042 6, 7; 1043 } }; 1044 is("@list", shift(@exp), "rvalue given - default list [$_]"); 1045 } 1046} 1047{ 1048 # Switch control 1049 my @exp = ('6 7', '', '6 7'); 1050 for (0, 1, 2, 3) { 1051 my @list = do { given ($_) { 1052 continue when $_ <= 1; 1053 break when 1; 1054 next when 2; 1055 6, 7; 1056 } }; 1057 is("@list", shift(@exp), "rvalue given - default list [$_]"); 1058 } 1059} 1060{ 1061 # Context propagation 1062 my $smart_hash = sub { 1063 do { given ($_[0]) { 1064 'undef' when undef; 1065 when ([ 1 .. 3 ]) { 1 .. 3 } 1066 when (4) { my $fake; do { 4, 5 } } 1067 } }; 1068 }; 1069 1070 my $scalar; 1071 1072 $scalar = $smart_hash->(); 1073 is($scalar, 'undef', "rvalue given - scalar context propagation [undef]"); 1074 1075 $scalar = $smart_hash->(4); 1076 is($scalar, 5, "rvalue given - scalar context propagation [4]"); 1077 1078 $scalar = $smart_hash->(999); 1079 is($scalar, undef, "rvalue given - scalar context propagation [999]"); 1080 1081 my @list; 1082 1083 @list = $smart_hash->(); 1084 is("@list", 'undef', "rvalue given - list context propagation [undef]"); 1085 1086 @list = $smart_hash->(2); 1087 is("@list", '1 2 3', "rvalue given - list context propagation [2]"); 1088 1089 @list = $smart_hash->(4); 1090 is("@list", '4 5', "rvalue given - list context propagation [4]"); 1091 1092 @list = $smart_hash->(999); 1093 is("@list", '', "rvalue given - list context propagation [999]"); 1094} 1095{ 1096 # Array slices 1097 my @list = 10 .. 15; 1098 my @in_list; 1099 my @in_slice; 1100 for (5, 10, 15) { 1101 given ($_) { 1102 when (@list) { 1103 push @in_list, $_; 1104 continue; 1105 } 1106 when (@list[0..2]) { 1107 push @in_slice, $_; 1108 } 1109 } 1110 } 1111 is("@in_list", "10 15", "when(array)"); 1112 is("@in_slice", "10", "when(array slice)"); 1113} 1114{ 1115 # Hash slices 1116 my %list = map { $_ => $_ } "a" .. "f"; 1117 my @in_list; 1118 my @in_slice; 1119 for ("a", "e", "i") { 1120 given ($_) { 1121 when (%list) { 1122 push @in_list, $_; 1123 continue; 1124 } 1125 when (@list{"a".."c"}) { 1126 push @in_slice, $_; 1127 } 1128 } 1129 } 1130 is("@in_list", "a e", "when(hash)"); 1131 is("@in_slice", "a", "when(hash slice)"); 1132} 1133 1134{ # RT#84526 - Handle magical TARG 1135 my $x = my $y = "aaa"; 1136 for ($x, $y) { 1137 given ($_) { 1138 is(pos, undef, "handle magical TARG"); 1139 pos = 1; 1140 } 1141 } 1142} 1143 1144# Test that returned values are correctly propagated through several context 1145# levels (see RT #93548). 1146{ 1147 my $tester = sub { 1148 my $id = shift; 1149 1150 package fmurrr; 1151 1152 our ($when_loc, $given_loc, $ext_loc); 1153 1154 my $ext_lex = 7; 1155 our $ext_glob = 8; 1156 local $ext_loc = 9; 1157 1158 given ($id) { 1159 my $given_lex = 4; 1160 our $given_glob = 5; 1161 local $given_loc = 6; 1162 1163 when (0) { 0 } 1164 1165 when (1) { my $when_lex = 1 } 1166 when (2) { our $when_glob = 2 } 1167 when (3) { local $when_loc = 3 } 1168 1169 when (4) { $given_lex } 1170 when (5) { $given_glob } 1171 when (6) { $given_loc } 1172 1173 when (7) { $ext_lex } 1174 when (8) { $ext_glob } 1175 when (9) { $ext_loc } 1176 1177 'fallback'; 1178 } 1179 }; 1180 1181 my @descriptions = qw< 1182 constant 1183 1184 when-lexical 1185 when-global 1186 when-local 1187 1188 given-lexical 1189 given-global 1190 given-local 1191 1192 extern-lexical 1193 extern-global 1194 extern-local 1195 >; 1196 1197 for my $id (0 .. 9) { 1198 my $desc = $descriptions[$id]; 1199 1200 my $res = $tester->($id); 1201 is $res, $id, "plain call - $desc"; 1202 1203 $res = do { 1204 my $id_plus_1 = $id + 1; 1205 given ($id_plus_1) { 1206 do { 1207 when (/\d/) { 1208 --$id_plus_1; 1209 continue; 1210 456; 1211 } 1212 }; 1213 default { 1214 $tester->($id_plus_1); 1215 } 1216 'XXX'; 1217 } 1218 }; 1219 is $res, $id, "across continue and default - $desc"; 1220 } 1221} 1222 1223# Check that values returned from given/when are destroyed at the right time. 1224{ 1225 { 1226 package Fmurrr; 1227 1228 sub new { 1229 bless { 1230 flag => \($_[1]), 1231 id => $_[2], 1232 }, $_[0] 1233 } 1234 1235 sub DESTROY { 1236 ${$_[0]->{flag}}++; 1237 } 1238 } 1239 1240 my @descriptions = qw< 1241 when 1242 break 1243 continue 1244 default 1245 >; 1246 1247 for my $id (0 .. 3) { 1248 my $desc = $descriptions[$id]; 1249 1250 my $destroyed = 0; 1251 my $res_id; 1252 1253 { 1254 my $res = do { 1255 given ($id) { 1256 my $x; 1257 when (0) { Fmurrr->new($destroyed, 0) } 1258 when (1) { my $y = Fmurrr->new($destroyed, 1); break } 1259 when (2) { $x = Fmurrr->new($destroyed, 2); continue } 1260 when (2) { $x } 1261 default { Fmurrr->new($destroyed, 3) } 1262 } 1263 }; 1264 $res_id = $res->{id}; 1265 } 1266 $res_id = $id if $id == 1; # break doesn't return anything 1267 1268 is $res_id, $id, "given/when returns the right object - $desc"; 1269 is $destroyed, 1, "given/when does not leak - $desc"; 1270 }; 1271} 1272 1273# break() must reset the stack 1274{ 1275 my @res = (1, do { 1276 given ("x") { 1277 2, 3, do { 1278 when (/[a-z]/) { 1279 4, 5, 6, break 1280 } 1281 } 1282 } 1283 }); 1284 is "@res", "1", "break resets the stack"; 1285} 1286 1287# RT #94682: 1288# must ensure $_ is initialised and cleared at start/end of given block 1289 1290{ 1291 package RT94682; 1292 1293 my $d = 0; 1294 sub DESTROY { $d++ }; 1295 1296 sub f2 { 1297 local $_ = 5; 1298 given(bless [7]) { 1299 ::is($_->[0], 7, "is [7]"); 1300 } 1301 ::is($_, 5, "is 5"); 1302 ::is($d, 1, "DESTROY called once"); 1303 } 1304 f2(); 1305} 1306 1307# check that 'when' handles all 'for' loop types 1308 1309{ 1310 my $i; 1311 1312 $i = 0; 1313 for (1..3) { 1314 when (1) {$i += 1 } 1315 when (2) {$i += 10 } 1316 when (3) {$i += 100 } 1317 default { $i += 1000 } 1318 } 1319 is($i, 111, "when in for 1..3"); 1320 1321 $i = 0; 1322 for ('a'..'c') { 1323 when ('a') {$i += 1 } 1324 when ('b') {$i += 10 } 1325 when ('c') {$i += 100 } 1326 default { $i += 1000 } 1327 } 1328 is($i, 111, "when in for a..c"); 1329 1330 $i = 0; 1331 for (1,2,3) { 1332 when (1) {$i += 1 } 1333 when (2) {$i += 10 } 1334 when (3) {$i += 100 } 1335 default { $i += 1000 } 1336 } 1337 is($i, 111, "when in for 1,2,3"); 1338 1339 $i = 0; 1340 my @a = (1,2,3); 1341 for (@a) { 1342 when (1) {$i += 1 } 1343 when (2) {$i += 10 } 1344 when (3) {$i += 100 } 1345 default { $i += 1000 } 1346 } 1347 is($i, 111, 'when in for @a'); 1348} 1349 1350given("xyz") { 1351 no warnings "void"; 1352 my @a = (qw(a b c), do { when(/abc/) { qw(x y) } }, qw(d e f)); 1353 is join(",", map { $_ // "u" } @a), "a,b,c,d,e,f", 1354 "list value of false when"; 1355 @a = (qw(a b c), scalar do { when(/abc/) { qw(x y) } }, qw(d e f)); 1356 is join(",", map { $_ // "u" } @a), "a,b,c,u,d,e,f", 1357 "scalar value of false when"; 1358} 1359 1360# RT #133368 1361# index() and rindex() comparisons such as '> -1' are optimised away. Make 1362# sure that they're still treated as a direct boolean expression rather 1363# than when(X) being implicitly converted to when($_ ~~ X) 1364 1365{ 1366 my $s = "abc"; 1367 my $ok = 0; 1368 given("xyz") { 1369 when (index($s, 'a') > -1) { $ok = 1; } 1370 } 1371 ok($ok, "RT #133368 index"); 1372 1373 $ok = 0; 1374 given("xyz") { 1375 when (rindex($s, 'a') > -1) { $ok = 1; } 1376 } 1377 ok($ok, "RT #133368 rindex"); 1378} 1379 1380 1381# Okay, that'll do for now. The intricacies of the smartmatch 1382# semantics are tested in t/op/smartmatch.t. Taintedness of 1383# returned values is checked in t/op/taint.t. 1384__END__ 1385