1#!./perl 2 3BEGIN { 4 chdir 't' if -d 't'; 5 @INC = '../lib'; 6} 7 8use strict; 9use warnings; 10 11use Test::More tests => 108; 12 13# The behaviour of the feature pragma should be tested by lib/switch.t 14# using the tests in t/lib/switch/*. This file tests the behaviour of 15# the switch ops themselves. 16 17 18use feature 'switch'; 19no warnings "numeric"; 20 21eval { continue }; 22like($@, qr/^Can't "continue" outside/, "continue outside"); 23 24eval { break }; 25like($@, qr/^Can't "break" outside/, "break outside"); 26 27# Scoping rules 28 29{ 30 my $x = "foo"; 31 given(my $x = "bar") { 32 is($x, "bar", "given scope starts"); 33 } 34 is($x, "foo", "given scope ends"); 35} 36 37sub be_true {1} 38 39given(my $x = "foo") { 40 when(be_true(my $x = "bar")) { 41 is($x, "bar", "given scope starts"); 42 } 43 is($x, "foo", "given scope ends"); 44} 45 46$_ = "outside"; 47given("inside") { check_outside1() } 48sub check_outside1 { is($_, "outside", "\$_ lexically scoped") } 49 50{ 51 my $_ = "outside"; 52 given("inside") { check_outside2() } 53 sub check_outside2 { 54 is($_, "outside", "\$_ lexically scoped (lexical \$_)") 55 } 56} 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 my $ok = 1; 137 given (undef) { when(0) {$ok = 0} } 138 is($ok, 1, "Given(undef) when(0)"); 139} 140{ 141 my $undef; 142 my $ok = 1; 143 given ($undef) { when(0) {$ok = 0} } 144 is($ok, 1, 'Given($undef) when(0)'); 145} 146######## 147{ 148 my $ok = 1; 149 given ("") { when(undef) {$ok = 0} } 150 is($ok, 1, 'Given("") when(undef)'); 151} 152{ 153 my $undef; 154 my $ok = 1; 155 given ("") { when($undef) {$ok = 0} } 156 is($ok, 1, 'Given("") when($undef)'); 157} 158{ 159 my $ok = 1; 160 given (undef) { when("") {$ok = 0} } 161 is($ok, 1, 'Given(undef) when("")'); 162} 163{ 164 my $undef; 165 my $ok = 1; 166 given ($undef) { when("") {$ok = 0} } 167 is($ok, 1, 'Given($undef) when("")'); 168} 169######## 170{ 171 my $ok = 0; 172 given (undef) { when(undef) {$ok = 1} } 173 is($ok, 1, "Given(undef) when(undef)"); 174} 175{ 176 my $undef; 177 my $ok = 0; 178 given (undef) { when($undef) {$ok = 1} } 179 is($ok, 1, 'Given(undef) when($undef)'); 180} 181{ 182 my $undef; 183 my $ok = 0; 184 given ($undef) { when(undef) {$ok = 1} } 185 is($ok, 1, 'Given($undef) when(undef)'); 186} 187{ 188 my $undef; 189 my $ok = 0; 190 given ($undef) { when($undef) {$ok = 1} } 191 is($ok, 1, 'Given($undef) when($undef)'); 192} 193 194 195# Regular expressions 196{ 197 my ($ok1, $ok2); 198 given("Hello, world!") { 199 when(/lo/) 200 { $ok1 = 'y'; continue} 201 when(/no/) 202 { $ok1 = 'n'; continue} 203 when(/^(Hello,|Goodbye cruel) world[!.?]/) 204 { $ok2 = 'Y'; continue} 205 when(/^(Hello cruel|Goodbye,) world[!.?]/) 206 { $ok2 = 'n'; continue} 207 } 208 is($ok1, 'y', "regex 1"); 209 is($ok2, 'Y', "regex 2"); 210} 211 212# Comparisons 213{ 214 my $test = "explicit numeric comparison (<)"; 215 my $twenty_five = 25; 216 my $ok; 217 given($twenty_five) { 218 when ($_ < 10) { $ok = "ten" } 219 when ($_ < 20) { $ok = "twenty" } 220 when ($_ < 30) { $ok = "thirty" } 221 when ($_ < 40) { $ok = "forty" } 222 default { $ok = "default" } 223 } 224 is($ok, "thirty", $test); 225} 226 227{ 228 use integer; 229 my $test = "explicit numeric comparison (integer <)"; 230 my $twenty_five = 25; 231 my $ok; 232 given($twenty_five) { 233 when ($_ < 10) { $ok = "ten" } 234 when ($_ < 20) { $ok = "twenty" } 235 when ($_ < 30) { $ok = "thirty" } 236 when ($_ < 40) { $ok = "forty" } 237 default { $ok = "default" } 238 } 239 is($ok, "thirty", $test); 240} 241 242{ 243 my $test = "explicit numeric comparison (<=)"; 244 my $twenty_five = 25; 245 my $ok; 246 given($twenty_five) { 247 when ($_ <= 10) { $ok = "ten" } 248 when ($_ <= 20) { $ok = "twenty" } 249 when ($_ <= 30) { $ok = "thirty" } 250 when ($_ <= 40) { $ok = "forty" } 251 default { $ok = "default" } 252 } 253 is($ok, "thirty", $test); 254} 255 256{ 257 use integer; 258 my $test = "explicit numeric comparison (integer <=)"; 259 my $twenty_five = 25; 260 my $ok; 261 given($twenty_five) { 262 when ($_ <= 10) { $ok = "ten" } 263 when ($_ <= 20) { $ok = "twenty" } 264 when ($_ <= 30) { $ok = "thirty" } 265 when ($_ <= 40) { $ok = "forty" } 266 default { $ok = "default" } 267 } 268 is($ok, "thirty", $test); 269} 270 271 272{ 273 my $test = "explicit numeric comparison (>)"; 274 my $twenty_five = 25; 275 my $ok; 276 given($twenty_five) { 277 when ($_ > 40) { $ok = "forty" } 278 when ($_ > 30) { $ok = "thirty" } 279 when ($_ > 20) { $ok = "twenty" } 280 when ($_ > 10) { $ok = "ten" } 281 default { $ok = "default" } 282 } 283 is($ok, "twenty", $test); 284} 285 286{ 287 my $test = "explicit numeric comparison (>=)"; 288 my $twenty_five = 25; 289 my $ok; 290 given($twenty_five) { 291 when ($_ >= 40) { $ok = "forty" } 292 when ($_ >= 30) { $ok = "thirty" } 293 when ($_ >= 20) { $ok = "twenty" } 294 when ($_ >= 10) { $ok = "ten" } 295 default { $ok = "default" } 296 } 297 is($ok, "twenty", $test); 298} 299 300{ 301 use integer; 302 my $test = "explicit numeric comparison (integer >)"; 303 my $twenty_five = 25; 304 my $ok; 305 given($twenty_five) { 306 when ($_ > 40) { $ok = "forty" } 307 when ($_ > 30) { $ok = "thirty" } 308 when ($_ > 20) { $ok = "twenty" } 309 when ($_ > 10) { $ok = "ten" } 310 default { $ok = "default" } 311 } 312 is($ok, "twenty", $test); 313} 314 315{ 316 use integer; 317 my $test = "explicit numeric comparison (integer >=)"; 318 my $twenty_five = 25; 319 my $ok; 320 given($twenty_five) { 321 when ($_ >= 40) { $ok = "forty" } 322 when ($_ >= 30) { $ok = "thirty" } 323 when ($_ >= 20) { $ok = "twenty" } 324 when ($_ >= 10) { $ok = "ten" } 325 default { $ok = "default" } 326 } 327 is($ok, "twenty", $test); 328} 329 330 331{ 332 my $test = "explicit string comparison (lt)"; 333 my $twenty_five = "25"; 334 my $ok; 335 given($twenty_five) { 336 when ($_ lt "10") { $ok = "ten" } 337 when ($_ lt "20") { $ok = "twenty" } 338 when ($_ lt "30") { $ok = "thirty" } 339 when ($_ lt "40") { $ok = "forty" } 340 default { $ok = "default" } 341 } 342 is($ok, "thirty", $test); 343} 344 345{ 346 my $test = "explicit string comparison (le)"; 347 my $twenty_five = "25"; 348 my $ok; 349 given($twenty_five) { 350 when ($_ le "10") { $ok = "ten" } 351 when ($_ le "20") { $ok = "twenty" } 352 when ($_ le "30") { $ok = "thirty" } 353 when ($_ le "40") { $ok = "forty" } 354 default { $ok = "default" } 355 } 356 is($ok, "thirty", $test); 357} 358 359{ 360 my $test = "explicit string comparison (gt)"; 361 my $twenty_five = 25; 362 my $ok; 363 given($twenty_five) { 364 when ($_ ge "40") { $ok = "forty" } 365 when ($_ ge "30") { $ok = "thirty" } 366 when ($_ ge "20") { $ok = "twenty" } 367 when ($_ ge "10") { $ok = "ten" } 368 default { $ok = "default" } 369 } 370 is($ok, "twenty", $test); 371} 372 373{ 374 my $test = "explicit string comparison (ge)"; 375 my $twenty_five = 25; 376 my $ok; 377 given($twenty_five) { 378 when ($_ ge "40") { $ok = "forty" } 379 when ($_ ge "30") { $ok = "thirty" } 380 when ($_ ge "20") { $ok = "twenty" } 381 when ($_ ge "10") { $ok = "ten" } 382 default { $ok = "default" } 383 } 384 is($ok, "twenty", $test); 385} 386 387# Make sure it still works with a lexical $_: 388{ 389 my $_; 390 my $test = "explicit comparison with lexical \$_"; 391 my $twenty_five = 25; 392 my $ok; 393 given($twenty_five) { 394 when ($_ ge "40") { $ok = "forty" } 395 when ($_ ge "30") { $ok = "thirty" } 396 when ($_ ge "20") { $ok = "twenty" } 397 when ($_ ge "10") { $ok = "ten" } 398 default { $ok = "default" } 399 } 400 is($ok, "twenty", $test); 401} 402 403# Optimized-away comparisons 404{ 405 my $ok; 406 given(23) { 407 when (2 + 2 == 4) { $ok = 'y'; continue } 408 when (2 + 2 == 5) { $ok = 'n' } 409 } 410 is($ok, 'y', "Optimized-away comparison"); 411} 412 413# File tests 414# (How to be both thorough and portable? Pinch a few ideas 415# from t/op/filetest.t. We err on the side of portability for 416# the time being.) 417 418{ 419 my ($ok_d, $ok_f, $ok_r); 420 given("op") { 421 when(-d) {$ok_d = 1; continue} 422 when(!-f) {$ok_f = 1; continue} 423 when(-r) {$ok_r = 1; continue} 424 } 425 ok($ok_d, "Filetest -d"); 426 ok($ok_f, "Filetest -f"); 427 ok($ok_r, "Filetest -r"); 428} 429 430# Sub and method calls 431sub bar {"bar"} 432{ 433 my $ok = 0; 434 given("foo") { 435 when(bar()) {$ok = 1} 436 } 437 ok($ok, "Sub call acts as boolean") 438} 439 440{ 441 my $ok = 0; 442 given("foo") { 443 when(main->bar()) {$ok = 1} 444 } 445 ok($ok, "Class-method call acts as boolean") 446} 447 448{ 449 my $ok = 0; 450 my $obj = bless []; 451 given("foo") { 452 when($obj->bar()) {$ok = 1} 453 } 454 ok($ok, "Object-method call acts as boolean") 455} 456 457# Other things that should not be smart matched 458{ 459 my $ok = 0; 460 given(12) { 461 when( /(\d+)/ and ( 1 <= $1 and $1 <= 12 ) ) { 462 $ok = 1; 463 } 464 } 465 ok($ok, "bool not smartmatches"); 466} 467 468{ 469 my $ok = 0; 470 given(0) { 471 when(eof(DATA)) { 472 $ok = 1; 473 } 474 } 475 ok($ok, "eof() not smartmatched"); 476} 477 478{ 479 my $ok = 0; 480 my %foo = ("bar", 0); 481 given(0) { 482 when(exists $foo{bar}) { 483 $ok = 1; 484 } 485 } 486 ok($ok, "exists() not smartmatched"); 487} 488 489{ 490 my $ok = 0; 491 given(0) { 492 when(defined $ok) { 493 $ok = 1; 494 } 495 } 496 ok($ok, "defined() not smartmatched"); 497} 498 499{ 500 my $ok = 1; 501 given("foo") { 502 when((1 == 1) && "bar") { 503 $ok = 0; 504 } 505 when((1 == 1) && $_ eq "foo") { 506 $ok = 2; 507 } 508 } 509 is($ok, 2, "((1 == 1) && \"bar\") not smartmatched"); 510} 511 512{ 513 my $ok = 0; 514 given("foo") { 515 when((1 == $ok) || "foo") { 516 $ok = 1; 517 } 518 } 519 ok($ok, '((1 == $ok) || "foo") smartmatched'); 520} 521 522 523# Make sure we aren't invoking the get-magic more than once 524 525{ # A helper class to count the number of accesses. 526 package FetchCounter; 527 sub TIESCALAR { 528 my ($class) = @_; 529 bless {value => undef, count => 0}, $class; 530 } 531 sub STORE { 532 my ($self, $val) = @_; 533 $self->{count} = 0; 534 $self->{value} = $val; 535 } 536 sub FETCH { 537 my ($self) = @_; 538 # Avoid pre/post increment here 539 $self->{count} = 1 + $self->{count}; 540 $self->{value}; 541 } 542 sub count { 543 my ($self) = @_; 544 $self->{count}; 545 } 546} 547 548my $f = tie my $v, "FetchCounter"; 549 550{ my $test_name = "Only one FETCH (in given)"; 551 my $ok; 552 given($v = 23) { 553 when(undef) {} 554 when(sub{0}->()) {} 555 when(21) {} 556 when("22") {} 557 when(23) {$ok = 1} 558 when(/24/) {$ok = 0} 559 } 560 is($ok, 1, "precheck: $test_name"); 561 is($f->count(), 1, $test_name); 562} 563 564{ my $test_name = "Only one FETCH (numeric when)"; 565 my $ok; 566 $v = 23; 567 is($f->count(), 0, "Sanity check: $test_name"); 568 given(23) { 569 when(undef) {} 570 when(sub{0}->()) {} 571 when(21) {} 572 when("22") {} 573 when($v) {$ok = 1} 574 when(/24/) {$ok = 0} 575 } 576 is($ok, 1, "precheck: $test_name"); 577 is($f->count(), 1, $test_name); 578} 579 580{ my $test_name = "Only one FETCH (string when)"; 581 my $ok; 582 $v = "23"; 583 is($f->count(), 0, "Sanity check: $test_name"); 584 given("23") { 585 when(undef) {} 586 when(sub{0}->()) {} 587 when("21") {} 588 when("22") {} 589 when($v) {$ok = 1} 590 when(/24/) {$ok = 0} 591 } 592 is($ok, 1, "precheck: $test_name"); 593 is($f->count(), 1, $test_name); 594} 595 596{ my $test_name = "Only one FETCH (undef)"; 597 my $ok; 598 $v = undef; 599 is($f->count(), 0, "Sanity check: $test_name"); 600 given(my $undef) { 601 when(sub{0}->()) {} 602 when("21") {} 603 when("22") {} 604 when($v) {$ok = 1} 605 when(undef) {$ok = 0} 606 } 607 is($ok, 1, "precheck: $test_name"); 608 is($f->count(), 1, $test_name); 609} 610 611# Loop topicalizer 612{ 613 my $first = 1; 614 for (1, "two") { 615 when ("two") { 616 is($first, 0, "Loop: second"); 617 eval {break}; 618 like($@, qr/^Can't "break" in a loop topicalizer/, 619 q{Can't "break" in a loop topicalizer}); 620 } 621 when (1) { 622 is($first, 1, "Loop: first"); 623 $first = 0; 624 # Implicit break is okay 625 } 626 } 627} 628 629{ 630 my $first = 1; 631 for $_ (1, "two") { 632 when ("two") { 633 is($first, 0, "Explicit \$_: second"); 634 eval {break}; 635 like($@, qr/^Can't "break" in a loop topicalizer/, 636 q{Can't "break" in a loop topicalizer}); 637 } 638 when (1) { 639 is($first, 1, "Explicit \$_: first"); 640 $first = 0; 641 # Implicit break is okay 642 } 643 } 644} 645 646{ 647 my $first = 1; 648 my $_; 649 for (1, "two") { 650 when ("two") { 651 is($first, 0, "Implicitly lexical loop: second"); 652 eval {break}; 653 like($@, qr/^Can't "break" in a loop topicalizer/, 654 q{Can't "break" in a loop topicalizer}); 655 } 656 when (1) { 657 is($first, 1, "Implicitly lexical loop: first"); 658 $first = 0; 659 # Implicit break is okay 660 } 661 } 662} 663 664{ 665 my $first = 1; 666 my $_; 667 for $_ (1, "two") { 668 when ("two") { 669 is($first, 0, "Implicitly lexical, explicit \$_: second"); 670 eval {break}; 671 like($@, qr/^Can't "break" in a loop topicalizer/, 672 q{Can't "break" in a loop topicalizer}); 673 } 674 when (1) { 675 is($first, 1, "Implicitly lexical, explicit \$_: first"); 676 $first = 0; 677 # Implicit break is okay 678 } 679 } 680} 681 682{ 683 my $first = 1; 684 for my $_ (1, "two") { 685 when ("two") { 686 is($first, 0, "Lexical loop: second"); 687 eval {break}; 688 like($@, qr/^Can't "break" in a loop topicalizer/, 689 q{Can't "break" in a loop topicalizer}); 690 } 691 when (1) { 692 is($first, 1, "Lecical loop: first"); 693 $first = 0; 694 # Implicit break is okay 695 } 696 } 697} 698 699 700# Code references 701{ 702 no warnings "redefine"; 703 my $called_foo = 0; 704 sub foo {$called_foo = 1} 705 my $called_bar = 0; 706 sub bar {$called_bar = 1} 707 my ($matched_foo, $matched_bar) = (0, 0); 708 given(\&foo) { 709 when(\&bar) {$matched_bar = 1} 710 when(\&foo) {$matched_foo = 1} 711 } 712 is($called_foo, 0, "Code ref comparison: foo not called"); 713 is($called_bar, 0, "Code ref comparison: bar not called"); 714 is($matched_bar, 0, "Code ref didn't match different one"); 715 is($matched_foo, 1, "Code ref did match itself"); 716} 717 718sub contains_x { 719 my $x = shift; 720 return ($x =~ /x/); 721} 722{ 723 my ($ok1, $ok2) = (0,0); 724 given("foxy!") { 725 when(contains_x($_)) 726 { $ok1 = 1; continue } 727 when(\&contains_x) 728 { $ok2 = 1; continue } 729 } 730 is($ok1, 1, "Calling sub directly (true)"); 731 is($ok2, 1, "Calling sub indirectly (true)"); 732 733 given("foggy") { 734 when(contains_x($_)) 735 { $ok1 = 2; continue } 736 when(\&contains_x) 737 { $ok2 = 2; continue } 738 } 739 is($ok1, 1, "Calling sub directly (false)"); 740 is($ok2, 1, "Calling sub indirectly (false)"); 741} 742 743# Test overloading 744{ package OverloadTest; 745 746 use overload '""' => sub{"string value of obj"}; 747 748 use overload "~~" => sub { 749 my ($self, $other, $reversed) = @_; 750 if ($reversed) { 751 $self->{left} = $other; 752 $self->{right} = $self; 753 $self->{reversed} = 1; 754 } else { 755 $self->{left} = $self; 756 $self->{right} = $other; 757 $self->{reversed} = 0; 758 } 759 $self->{called} = 1; 760 return $self->{retval}; 761 }; 762 763 sub new { 764 my ($pkg, $retval) = @_; 765 bless { 766 called => 0, 767 retval => $retval, 768 }, $pkg; 769 } 770} 771 772{ 773 my $test = "Overloaded obj in given (true)"; 774 my $obj = OverloadTest->new(1); 775 my $matched; 776 given($obj) { 777 when ("other arg") {$matched = 1} 778 default {$matched = 0} 779 } 780 781 is($obj->{called}, 1, "$test: called"); 782 ok($matched, "$test: matched"); 783 is($obj->{left}, "string value of obj", "$test: left"); 784 is($obj->{right}, "other arg", "$test: right"); 785 ok(!$obj->{reversed}, "$test: not reversed"); 786} 787 788{ 789 my $test = "Overloaded obj in given (false)"; 790 my $obj = OverloadTest->new(0); 791 my $matched; 792 given($obj) { 793 when ("other arg") {$matched = 1} 794 } 795 796 is($obj->{called}, 1, "$test: called"); 797 ok(!$matched, "$test: not matched"); 798 is($obj->{left}, "string value of obj", "$test: left"); 799 is($obj->{right}, "other arg", "$test: right"); 800 ok(!$obj->{reversed}, "$test: not reversed"); 801} 802 803{ 804 my $test = "Overloaded obj in when (true)"; 805 my $obj = OverloadTest->new(1); 806 my $matched; 807 given("topic") { 808 when ($obj) {$matched = 1} 809 default {$matched = 0} 810 } 811 812 is($obj->{called}, 1, "$test: called"); 813 ok($matched, "$test: matched"); 814 is($obj->{left}, "topic", "$test: left"); 815 is($obj->{right}, "string value of obj", "$test: right"); 816 ok($obj->{reversed}, "$test: reversed"); 817} 818 819{ 820 my $test = "Overloaded obj in when (false)"; 821 my $obj = OverloadTest->new(0); 822 my $matched; 823 given("topic") { 824 when ($obj) {$matched = 1} 825 default {$matched = 0} 826 } 827 828 is($obj->{called}, 1, "$test: called"); 829 ok(!$matched, "$test: not matched"); 830 is($obj->{left}, "topic", "$test: left"); 831 is($obj->{right}, "string value of obj", "$test: right"); 832 ok($obj->{reversed}, "$test: reversed"); 833} 834 835# Okay, that'll do for now. The intricacies of the smartmatch 836# semantics are tested in t/op/smartmatch.t 837__END__ 838