1f2a19305Safresh1#!./perl 2f2a19305Safresh1 3f2a19305Safresh1BEGIN { 4f2a19305Safresh1 chdir 't' if -d 't'; 5f2a19305Safresh1 require './test.pl'; 6f2a19305Safresh1 set_up_inc('../lib'); 7f2a19305Safresh1 require Config; 8f2a19305Safresh1} 9f2a19305Safresh1 10f2a19305Safresh1use v5.36; 11f2a19305Safresh1use feature 'class'; 12f2a19305Safresh1no warnings 'experimental::class'; 13f2a19305Safresh1 14f2a19305Safresh1# We can't test fields in isolation without having at least one method to 15f2a19305Safresh1# use them from. We'll try to keep most of the heavy testing of method 16f2a19305Safresh1# abilities to t/class/method.t 17f2a19305Safresh1 18f2a19305Safresh1# field in method 19f2a19305Safresh1{ 20*5486feefSafresh1 class Testcase1 { 21f2a19305Safresh1 field $f; 22f2a19305Safresh1 method incr { return ++$f; } 23f2a19305Safresh1 } 24f2a19305Safresh1 25*5486feefSafresh1 my $obj = Testcase1->new; 26f2a19305Safresh1 $obj->incr; 27f2a19305Safresh1 is($obj->incr, 2, 'Field $f incremented twice'); 28f2a19305Safresh1 29*5486feefSafresh1 my $obj2 = Testcase1->new; 30f2a19305Safresh1 is($obj2->incr, 1, 'Fields are distinct between instances'); 31f2a19305Safresh1} 32f2a19305Safresh1 33f2a19305Safresh1# fields are distinct 34f2a19305Safresh1{ 35*5486feefSafresh1 class Testcase2 { 36f2a19305Safresh1 field $x; 37f2a19305Safresh1 field $y; 38f2a19305Safresh1 39f2a19305Safresh1 method setpos { $x = $_[0]; $y = $_[1] } 40f2a19305Safresh1 method x { return $x; } 41f2a19305Safresh1 method y { return $y; } 42f2a19305Safresh1 } 43f2a19305Safresh1 44*5486feefSafresh1 my $obj = Testcase2->new; 45f2a19305Safresh1 $obj->setpos(10, 20); 46f2a19305Safresh1 is($obj->x, 10, '$pos->x'); 47f2a19305Safresh1 is($obj->y, 20, '$pos->y'); 48f2a19305Safresh1} 49f2a19305Safresh1 50f2a19305Safresh1# fields of all variable types 51f2a19305Safresh1{ 52*5486feefSafresh1 class Testcase3 { 53f2a19305Safresh1 field $s; 54f2a19305Safresh1 field @a; 55f2a19305Safresh1 field %h; 56f2a19305Safresh1 57f2a19305Safresh1 method setup { 58f2a19305Safresh1 $s = "scalar"; 59f2a19305Safresh1 @a = ( "array" ); 60f2a19305Safresh1 %h = ( key => "hash" ); 61f2a19305Safresh1 return $self; # test chaining 62f2a19305Safresh1 } 63f2a19305Safresh1 method test { 64f2a19305Safresh1 ::is($s, "scalar", 'scalar storage'); 65f2a19305Safresh1 ::is($a[0], "array", 'array storage'); 66f2a19305Safresh1 ::is($h{key}, "hash", 'hash storage'); 67f2a19305Safresh1 } 68f2a19305Safresh1 } 69f2a19305Safresh1 70*5486feefSafresh1 Testcase3->new->setup->test; 71f2a19305Safresh1} 72f2a19305Safresh1 73f2a19305Safresh1# fields can be captured by anon subs 74f2a19305Safresh1{ 75*5486feefSafresh1 class Testcase4 { 76f2a19305Safresh1 field $count; 77f2a19305Safresh1 78f2a19305Safresh1 method make_incrsub { 79f2a19305Safresh1 return sub { $count++ }; 80f2a19305Safresh1 } 81f2a19305Safresh1 82f2a19305Safresh1 method count { return $count } 83f2a19305Safresh1 } 84f2a19305Safresh1 85*5486feefSafresh1 my $obj = Testcase4->new; 86f2a19305Safresh1 my $incr = $obj->make_incrsub; 87f2a19305Safresh1 88f2a19305Safresh1 $incr->(); 89f2a19305Safresh1 $incr->(); 90f2a19305Safresh1 $incr->(); 91f2a19305Safresh1 92f2a19305Safresh1 is($obj->count, 3, '$obj->count after invoking closure x 3'); 93f2a19305Safresh1} 94f2a19305Safresh1 95f2a19305Safresh1# fields can be captured by anon methods 96f2a19305Safresh1{ 97*5486feefSafresh1 class Testcase5 { 98f2a19305Safresh1 field $count; 99f2a19305Safresh1 100f2a19305Safresh1 method make_incrmeth { 101f2a19305Safresh1 return method { $count++ }; 102f2a19305Safresh1 } 103f2a19305Safresh1 104f2a19305Safresh1 method count { return $count } 105f2a19305Safresh1 } 106f2a19305Safresh1 107*5486feefSafresh1 my $obj = Testcase5->new; 108f2a19305Safresh1 my $incr = $obj->make_incrmeth; 109f2a19305Safresh1 110f2a19305Safresh1 $obj->$incr; 111f2a19305Safresh1 $obj->$incr; 112f2a19305Safresh1 $obj->$incr; 113f2a19305Safresh1 114f2a19305Safresh1 is($obj->count, 3, '$obj->count after invoking method-closure x 3'); 115f2a19305Safresh1} 116f2a19305Safresh1 117f2a19305Safresh1# fields of multiple unit classes are distinct 118f2a19305Safresh1{ 119*5486feefSafresh1 class Testcase6::A; 120f2a19305Safresh1 field $x = "A"; 121f2a19305Safresh1 method m { return "unit-$x" } 122f2a19305Safresh1 123*5486feefSafresh1 class Testcase6::B; 124f2a19305Safresh1 field $x = "B"; 125f2a19305Safresh1 method m { return "unit-$x" } 126f2a19305Safresh1 127f2a19305Safresh1 package main; 128*5486feefSafresh1 ok(eq_array([Testcase6::A->new->m, Testcase6::B->new->m], ["unit-A", "unit-B"]), 129f2a19305Safresh1 'Fields of multiple unit classes remain distinct'); 130f2a19305Safresh1} 131f2a19305Safresh1 132f2a19305Safresh1# fields can be initialised with constant expressions 133f2a19305Safresh1{ 134*5486feefSafresh1 class Testcase7 { 135f2a19305Safresh1 field $scalar = 123; 136f2a19305Safresh1 method scalar { return $scalar; } 137f2a19305Safresh1 138f2a19305Safresh1 field @array = (4, 5, 6); 139f2a19305Safresh1 method array { return @array; } 140f2a19305Safresh1 141f2a19305Safresh1 field %hash = (7 => 89); 142f2a19305Safresh1 method hash { return %hash; } 143f2a19305Safresh1 } 144f2a19305Safresh1 145*5486feefSafresh1 my $obj = Testcase7->new; 146f2a19305Safresh1 147f2a19305Safresh1 is($obj->scalar, 123, 'Scalar field can be constant initialised'); 148f2a19305Safresh1 149f2a19305Safresh1 ok(eq_array([$obj->array], [4, 5, 6]), 'Array field can be constant initialised'); 150f2a19305Safresh1 151f2a19305Safresh1 ok(eq_hash({$obj->hash}, {7 => 89}), 'Hash field can be constant initialised'); 152f2a19305Safresh1} 153f2a19305Safresh1 154f2a19305Safresh1# field initialiser expressions are evaluated within the constructor of each 155f2a19305Safresh1# instance 156f2a19305Safresh1{ 157f2a19305Safresh1 my $next_x = 1; 158f2a19305Safresh1 my @items; 159f2a19305Safresh1 my %mappings; 160f2a19305Safresh1 161*5486feefSafresh1 class Testcase8 { 162f2a19305Safresh1 field $x = $next_x++; 163f2a19305Safresh1 method x { return $x; } 164f2a19305Safresh1 165f2a19305Safresh1 field @y = ("more", @items); 166f2a19305Safresh1 method y { return @y; } 167f2a19305Safresh1 168f2a19305Safresh1 field %z = (first => "value", %mappings); 169f2a19305Safresh1 method z { return %z; } 170f2a19305Safresh1 } 171f2a19305Safresh1 172f2a19305Safresh1 is($next_x, 1, '$next_x before any objects'); 173f2a19305Safresh1 174f2a19305Safresh1 @items = ("values"); 175f2a19305Safresh1 $mappings{second} = "here"; 176f2a19305Safresh1 177*5486feefSafresh1 my $obj1 = Testcase8->new; 178*5486feefSafresh1 my $obj2 = Testcase8->new; 179f2a19305Safresh1 180f2a19305Safresh1 is($obj1->x, 1, 'Object 1 has x == 1'); 181f2a19305Safresh1 is($obj2->x, 2, 'Object 2 has x == 2'); 182f2a19305Safresh1 183f2a19305Safresh1 is($next_x, 3, '$next_x after constructing two'); 184f2a19305Safresh1 185f2a19305Safresh1 ok(eq_array([$obj1->y], ["more", "values"]), 186f2a19305Safresh1 'Object 1 has correct array field'); 187f2a19305Safresh1 ok(eq_hash({$obj1->z}, {first => "value", second => "here"}), 188f2a19305Safresh1 'Object 1 has correct hash field'); 189f2a19305Safresh1} 190f2a19305Safresh1 191f2a19305Safresh1# fields are visible during initialiser expressions of later fields 192f2a19305Safresh1{ 193*5486feefSafresh1 class Testcase9 { 194f2a19305Safresh1 field $one = 1; 195f2a19305Safresh1 field $two = $one + 1; 196f2a19305Safresh1 field $three = $two + 1; 197f2a19305Safresh1 198f2a19305Safresh1 field @four = $one; 199f2a19305Safresh1 field @five = (@four, $two, $three); 200f2a19305Safresh1 field @six = grep { $_ > 1 } @five; 201f2a19305Safresh1 202f2a19305Safresh1 method three { return $three; } 203f2a19305Safresh1 204f2a19305Safresh1 method six { return @six; } 205f2a19305Safresh1 } 206f2a19305Safresh1 207*5486feefSafresh1 my $obj = Testcase9->new; 208f2a19305Safresh1 is($obj->three, 3, 'Scalar fields initialised from earlier fields'); 209f2a19305Safresh1 ok(eq_array([$obj->six], [2, 3]), 'Array fields initialised from earlier fields'); 210f2a19305Safresh1} 211f2a19305Safresh1 212f2a19305Safresh1# fields can take :param attributes to consume constructor parameters 213f2a19305Safresh1{ 214f2a19305Safresh1 my $next_gamma = 4; 215f2a19305Safresh1 216*5486feefSafresh1 class Testcase10 { 217f2a19305Safresh1 field $alpha :param = undef; 218f2a19305Safresh1 field $beta :param = 123; 219f2a19305Safresh1 field $gamma :param(delta) = $next_gamma++; 220f2a19305Safresh1 221f2a19305Safresh1 method values { return ($alpha, $beta, $gamma); } 222f2a19305Safresh1 } 223f2a19305Safresh1 224*5486feefSafresh1 my $obj = Testcase10->new( 225f2a19305Safresh1 alpha => "A", 226f2a19305Safresh1 beta => "B", 227f2a19305Safresh1 delta => "G", 228f2a19305Safresh1 ); 229f2a19305Safresh1 ok(eq_array([$obj->values], [qw(A B G)]), 230f2a19305Safresh1 'Field initialised by :params'); 231f2a19305Safresh1 is($next_gamma, 4, 'Defaulting expression not evaluated for passed value'); 232f2a19305Safresh1 233*5486feefSafresh1 $obj = Testcase10->new(); 234f2a19305Safresh1 ok(eq_array([$obj->values], [undef, 123, 4]), 235f2a19305Safresh1 'Field initialised by defaulting expressions'); 236f2a19305Safresh1 is($next_gamma, 5, 'Defaulting expression evaluated for missing value'); 237f2a19305Safresh1} 238f2a19305Safresh1 239f2a19305Safresh1# fields can be made non-optional 240f2a19305Safresh1{ 241*5486feefSafresh1 class Testcase11 { 242f2a19305Safresh1 field $x :param; 243f2a19305Safresh1 field $y :param; 244f2a19305Safresh1 } 245f2a19305Safresh1 246*5486feefSafresh1 Testcase11->new(x => 1, y => 1); 247f2a19305Safresh1 248*5486feefSafresh1 ok(!eval { Testcase11->new(x => 2) }, 249f2a19305Safresh1 'Constructor fails without y'); 250*5486feefSafresh1 like($@, qr/^Required parameter 'y' is missing for "Testcase11" constructor at /, 251f2a19305Safresh1 'Failure from missing y argument'); 252f2a19305Safresh1} 253f2a19305Safresh1 254f2a19305Safresh1# field assignment expressions on :param can use //= and ||= 255f2a19305Safresh1{ 256*5486feefSafresh1 class Testcase12 { 257f2a19305Safresh1 field $if_exists :param(e) = "DEF"; 258f2a19305Safresh1 field $if_defined :param(d) //= "DEF"; 259f2a19305Safresh1 field $if_true :param(t) ||= "DEF"; 260f2a19305Safresh1 261f2a19305Safresh1 method values { return ($if_exists, $if_defined, $if_true); } 262f2a19305Safresh1 } 263f2a19305Safresh1 264f2a19305Safresh1 ok(eq_array( 265*5486feefSafresh1 [Testcase12->new(e => "yes", d => "yes", t => "yes")->values], 266f2a19305Safresh1 ["yes", "yes", "yes"]), 267f2a19305Safresh1 'Values for "yes"'); 268f2a19305Safresh1 269f2a19305Safresh1 ok(eq_array( 270*5486feefSafresh1 [Testcase12->new(e => 0, d => 0, t => 0)->values], 271f2a19305Safresh1 [0, 0, "DEF"]), 272f2a19305Safresh1 'Values for 0'); 273f2a19305Safresh1 274f2a19305Safresh1 ok(eq_array( 275*5486feefSafresh1 [Testcase12->new(e => undef, d => undef, t => undef)->values], 276f2a19305Safresh1 [undef, "DEF", "DEF"]), 277f2a19305Safresh1 'Values for undef'); 278f2a19305Safresh1 279f2a19305Safresh1 ok(eq_array( 280*5486feefSafresh1 [Testcase12->new()->values], 281f2a19305Safresh1 ["DEF", "DEF", "DEF"]), 282f2a19305Safresh1 'Values for missing'); 283f2a19305Safresh1} 284f2a19305Safresh1 285f2a19305Safresh1# field initialiser expressions permit `goto` in do {} blocks 286f2a19305Safresh1{ 287*5486feefSafresh1 class Testcase13 { 288f2a19305Safresh1 field $forwards = do { goto HERE; HERE: 1 }; 289f2a19305Safresh1 field $backwards = do { my $x; HERE: ; goto HERE if !$x++; 2 }; 290f2a19305Safresh1 291f2a19305Safresh1 method values { return ($forwards, $backwards) } 292f2a19305Safresh1 } 293f2a19305Safresh1 294f2a19305Safresh1 ok(eq_array( 295*5486feefSafresh1 [Testcase13->new->values], 296f2a19305Safresh1 [1, 2], 297f2a19305Safresh1 'Values for goto inside do {} blocks in field initialisers')); 298f2a19305Safresh1} 299f2a19305Safresh1 300*5486feefSafresh1# field initialiser expressions permit a __CLASS__ 301*5486feefSafresh1{ 302*5486feefSafresh1 class Testcase14 { 303*5486feefSafresh1 field $classname = __CLASS__; 304*5486feefSafresh1 305*5486feefSafresh1 method classname { return $classname } 306*5486feefSafresh1 } 307*5486feefSafresh1 308*5486feefSafresh1 is(Testcase14->new->classname, "Testcase14", '__CLASS__ in field initialisers'); 309*5486feefSafresh1} 310*5486feefSafresh1 311f2a19305Safresh1done_testing; 312