1#!./perl -w 2 3# Regression tests for attributes.pm and the C< : attrs> syntax. 4 5BEGIN { 6 chdir 't' if -d 't'; 7 @INC = '../lib'; 8 require './test.pl'; 9} 10 11plan 'no_plan'; 12 13$SIG{__WARN__} = sub { die @_ }; 14 15sub eval_ok ($;$) { 16 eval shift; 17 is( $@, '', @_); 18} 19 20eval_ok 'sub t1 ($) : locked { $_[0]++ }'; 21eval_ok 'sub t2 : locked { $_[0]++ }'; 22eval_ok 'sub t3 ($) : locked ;'; 23eval_ok 'sub t4 : locked ;'; 24our $anon1; eval_ok '$anon1 = sub ($) : locked:method { $_[0]++ }'; 25our $anon2; eval_ok '$anon2 = sub : locked : method { $_[0]++ }'; 26our $anon3; eval_ok '$anon3 = sub : method { $_[0]->[1] }'; 27 28eval 'sub e1 ($) : plugh ;'; 29like $@, qr/^Invalid CODE attributes?: ["']?plugh["']? at/; 30 31eval 'sub e2 ($) : plugh(0,0) xyzzy ;'; 32like $@, qr/^Invalid CODE attributes: ["']?plugh\(0,0\)["']? /; 33 34eval 'sub e3 ($) : plugh(0,0 xyzzy ;'; 35like $@, qr/Unterminated attribute parameter in attribute list at/; 36 37eval 'sub e4 ($) : plugh + xyzzy ;'; 38like $@, qr/Invalid separator character '[+]' in attribute list at/; 39 40eval_ok 'my main $x : = 0;'; 41eval_ok 'my $x : = 0;'; 42eval_ok 'my $x ;'; 43eval_ok 'my ($x) : = 0;'; 44eval_ok 'my ($x) ;'; 45eval_ok 'my ($x) : ;'; 46eval_ok 'my ($x,$y) : = 0;'; 47eval_ok 'my ($x,$y) ;'; 48eval_ok 'my ($x,$y) : ;'; 49 50eval 'my ($x,$y) : plugh;'; 51like $@, qr/^Invalid SCALAR attribute: ["']?plugh["']? at/; 52 53# bug #16080 54eval '{my $x : plugh}'; 55like $@, qr/^Invalid SCALAR attribute: ["']?plugh["']? at/; 56eval '{my ($x,$y) : plugh(})}'; 57like $@, qr/^Invalid SCALAR attribute: ["']?plugh\(}\)["']? at/; 58 59# More syntax tests from the attributes manpage 60eval 'my $x : switch(10,foo(7,3)) : expensive;'; 61like $@, qr/^Invalid SCALAR attributes: ["']?switch\(10,foo\(7,3\)\) : expensive["']? at/; 62eval q/my $x : Ugly('\(") :Bad;/; 63like $@, qr/^Invalid SCALAR attributes: ["']?Ugly\('\\\("\) : Bad["']? at/; 64eval 'my $x : _5x5;'; 65like $@, qr/^Invalid SCALAR attribute: ["']?_5x5["']? at/; 66eval 'my $x : locked method;'; 67like $@, qr/^Invalid SCALAR attributes: ["']?locked : method["']? at/; 68eval 'my $x : switch(10,foo();'; 69like $@, qr/^Unterminated attribute parameter in attribute list at/; 70eval q/my $x : Ugly('(');/; 71like $@, qr/^Unterminated attribute parameter in attribute list at/; 72eval 'my $x : 5x5;'; 73like $@, qr/error/; 74eval 'my $x : Y2::north;'; 75like $@, qr/Invalid separator character ':' in attribute list at/; 76 77sub A::MODIFY_SCALAR_ATTRIBUTES { return } 78eval 'my A $x : plugh;'; 79like $@, qr/^SCALAR package attribute may clash with future reserved word: ["']?plugh["']? at/; 80 81eval 'my A $x : plugh plover;'; 82like $@, qr/^SCALAR package attributes may clash with future reserved words: ["']?plugh["']? /; 83 84eval 'package Cat; my Cat @socks;'; 85like $@, qr/^Can't declare class for non-scalar \@socks in "my"/; 86 87sub X::MODIFY_CODE_ATTRIBUTES { die "$_[0]" } 88sub X::foo { 1 } 89*Y::bar = \&X::foo; 90*Y::bar = \&X::foo; # second time for -w 91eval 'package Z; sub Y::bar : foo'; 92like $@, qr/^X at /; 93 94eval 'package Z; sub Y::baz : locked {}'; 95my @attrs = eval 'attributes::get \&Y::baz'; 96is "@attrs", "locked"; 97 98@attrs = eval 'attributes::get $anon1'; 99is "@attrs", "locked method"; 100 101sub Z::DESTROY { } 102sub Z::FETCH_CODE_ATTRIBUTES { return 'Z' } 103my $thunk = eval 'bless +sub : method locked { 1 }, "Z"'; 104is ref($thunk), "Z"; 105 106@attrs = eval 'attributes::get $thunk'; 107is "@attrs", "locked method Z"; 108 109# Test attributes on predeclared subroutines: 110eval 'package A; sub PS : lvalue'; 111@attrs = eval 'attributes::get \&A::PS'; 112is "@attrs", "lvalue"; 113 114# Test ability to modify existing sub's (or XSUB's) attributes. 115eval 'package A; sub X { $_[0] } sub X : lvalue'; 116@attrs = eval 'attributes::get \&A::X'; 117is "@attrs", "lvalue"; 118 119# Above not with just 'pure' built-in attributes. 120sub Z::MODIFY_CODE_ATTRIBUTES { (); } 121eval 'package Z; sub L { $_[0] } sub L : Z lvalue'; 122@attrs = eval 'attributes::get \&Z::L'; 123is "@attrs", "lvalue Z"; 124 125# Begin testing attributes that tie 126 127{ 128 package Ttie; 129 sub DESTROY {} 130 sub TIESCALAR { my $x = $_[1]; bless \$x, $_[0]; } 131 sub FETCH { ${$_[0]} } 132 sub STORE { 133 ::pass; 134 ${$_[0]} = $_[1]*2; 135 } 136 package Tloop; 137 sub MODIFY_SCALAR_ATTRIBUTES { tie ${$_[1]}, 'Ttie', -1; (); } 138} 139 140eval_ok ' 141 package Tloop; 142 for my $i (0..2) { 143 my $x : TieLoop = $i; 144 $x != $i*2 and ::is $x, $i*2; 145 } 146'; 147 148# bug #15898 149eval 'our ${""} : foo = 1'; 150like $@, qr/Can't declare scalar dereference in our/; 151eval 'my $$foo : bar = 1'; 152like $@, qr/Can't declare scalar dereference in my/; 153 154 155my @code = qw(lvalue locked method); 156unshift @code, 'assertion' if $] >= 5.009; 157my @other = qw(shared unique); 158my %valid; 159$valid{CODE} = {map {$_ => 1} @code}; 160$valid{SCALAR} = {map {$_ => 1} @other}; 161$valid{ARRAY} = $valid{HASH} = $valid{SCALAR}; 162 163our ($scalar, @array, %hash); 164foreach my $value (\&foo, \$scalar, \@array, \%hash) { 165 my $type = ref $value; 166 foreach my $negate ('', '-') { 167 foreach my $attr (@code, @other) { 168 my $attribute = $negate . $attr; 169 eval "use attributes __PACKAGE__, \$value, '$attribute'"; 170 if ($valid{$type}{$attr}) { 171 if ($attribute eq '-shared') { 172 like $@, qr/^A variable may not be unshared/; 173 } else { 174 is( $@, '', "$type attribute $attribute"); 175 } 176 } else { 177 like $@, qr/^Invalid $type attribute: $attribute/, 178 "Bogus $type attribute $attribute should fail"; 179 } 180 } 181 } 182} 183