#!/usr/bin/pugs use v6; use Test; =kwid `undef` and `undefine` tests This test file contains two sections: a port of the perl5 `undef.t` tests, and perl6-specific tests. =cut # Note: See thread "Undef issues" by Adrian Taylor on p6l # L<"http://groups.google.com/groups?threadm=20050601002444.GB32060@wall.org"> # On Tue, May 24, 2005 at 10:53:59PM +1000, Stuart Cook wrote: # : I'm not sure whether this behaviour is supposed to be changing. # # It is. I think we decided to make the value undef, and the function # undefine(). (But these days most values of undef really ought to # be constructed and returned (or thrown) using flunk().) # # Larry plan 72; our $GLOBAL; is(undef, undef, "undef is equal to undef"); ok(!defined(undef), "undef is not defined"); { my $a; is($a, undef, "uninitialized lexicals are undef"); is($GLOBAL, undef, "uninitialized globals are undef"); $a += 1; # should not emit a warning. how to test that? ok(defined($a), "initialized var is defined"); undefine $a; ok(!defined($a), "undefine($a) does"); $a = "hi"; ok(defined($a), "string"); my $b; $a = $b; ok(!defined($a), "assigning another undef lexical"); $a = $GLOBAL; ok(!defined($a), "assigning another undef global"); } { my @ary = "arg1"; my $a = @ary.pop; ok(defined($a), "pop from array"); $a = @ary.pop; ok(!defined($a), "pop from empty array"); @ary = "arg1"; $a = @ary.shift; ok(defined($a), "shift from array"); $a = @ary.shift; ok(!defined($a), "shift from empty array"); my %hash = ( bar => 'baz', quux => 'quuz' ); ok(defined(%hash<bar>), "hash subscript"); ok(!defined(%hash<bargho>), "non-existent hash subscript"); undefine %hash<bar>; ok(!defined(%hash<bar>), "undefine hash subscript"); %hash<bar> = "baz"; %hash.delete("bar"); ok(!defined(%hash<bar>), "delete hash subscript"); ok(defined(@ary), "aggregate array defined"); ok(defined(%hash), "aggregate hash defined"); undefine(@ary); ok(!defined(@ary), "undefine array",:todo<bug>); undefine(%hash); ok(!defined(%hash), "undefine hash",:todo<bug>); @ary = (1); ok(defined(@ary), "define array again"); %hash = (1,1); ok(defined(%hash), "define hash again"); } { sub a_sub { "møøse" } ok(defined(&a_sub), "defined sub"); eval_ok('defined(%«$?PACKAGE\::»<&a_sub>)', "defined sub (symbol table)", :todo<parsefail>); eval_ok('!defined(&a_subwoofer)', "undefined sub",:todo<feature>); eval_ok('!defined(%«$?PACKAGE\::»<&a_subwoofer>)', "undefined sub (symbol table)", :todo<feature>); } # TODO: find a read-only value to try and assign to, since we don't # have rules right now to play around with (the p5 version used $1) #eval { "constant" = "something else"; }; #is($!, "Modification of a read", "readonly write yields exception"); # skipped tests for tied things # skipped test for attempt to undef a bareword -- no barewords here. # TODO: p5 "bugid 3096 # undefing a hash may free objects with destructors that then try to # modify the hash. To them, the hash should appear empty." # Test LHS assignment to undef: my $interesting; (undef, undef, $interesting) = (1,2,3); is($interesting, 3, "Undef on LHS of list assignment"); (undef, $interesting, undef) = (1,2,3); is($interesting, 2, "Undef on LHS of list assignment"); ($interesting, undef, undef) = (1,2,3); is($interesting, 1, "Undef on LHS of list assignment"); sub two_elements() { (1,2) }; (undef,$interesting) = two_elements(); is($interesting, 2, "Undef on LHS of function assignment"); ($interesting, undef) = two_elements(); is($interesting, 1, "Undef on LHS of function assignment"); =kwid Perl6-specific tests =cut { # aggregate references my @ary = (<a b c d e>); my $ary_r = @ary; # ref isa_ok($ary_r, "Array"); ok(defined($ary_r), "array reference"); undefine @ary; ok(!+$ary_r, "undef array referent"); is(+$ary_r, 0, "dangling array reference"); my %hash = (1, 2, 3, 4); my $hash_r = %hash; isa_ok($hash_r, "Hash"); ok(defined($hash_r), "hash reference"); undefine %hash; ok(defined($hash_r), "undefine hash referent:"); is(+$hash_r.keys, 0, "dangling hash reference"); } { # types # TODO: waiting on my Dog $spot; my Array $an_ary; ok(!defined($an_ary), "my Array"); ok(try { !defined($an_ary[0]) }, "my Array subscript - undef"); try { $an_ary.push("blergh") }; ok(try { defined($an_ary.pop) }, "push"); ok(try { !defined($an_ary.pop) }, "comes to shove"); my Hash $a_hash; ok(!defined($a_hash), "my Hash"); ok(try { !defined($a_hash<blergh>) }, "my Hash subscript - undef"); ok(try { !defined($a_hash<blergh>) }, "my Hash subscript - undef, no autovivification happened"); try { $a_hash<blergh> = 1 }; ok(try { defined($a_hash.delete("blergh")) }, "delete", :todo<bug>); ok(try { !defined($a_hash.delete("blergh")) }, " - once only"); eval ' class Dog {}; my Dog $spot; '; ok(eval('!defined $spot'), "Unelaborated mutt", :todo); eval '$spot .= .new();'; ok(eval('defined $spot'), " - now real", :todo); } # rules # TODO. refer to S05 # L<S05/"Hypothetical variables" /backtracks past the closure/> if(!eval('("a" ~~ /a/)')) { skip 8, "skipped tests - rules support appears to be missing"; } else { # - unmatched alternative should bind to undef my($num, $alpha); my($rx1, $rx2); eval ' $rx1 = rx / [ (\d+) { let $<num> := $0 } | (<alpha>+) { let $<alpha> := $1 } ] /; $rx2 = rx / [ $<num> := (\d+) | $<alpha>:= (<alpha>+) ] /; '; for (<rx1 rx2>) { # I want symbolic lookups because I need the rx names for test results. eval '"1" ~~ %MY::{$_}'; ok(defined($num), "{$_}: successful hypothetical", :todo); ok(!defined($alpha), "{$_}: failed hypothetical"); eval '"A" ~~ %MY::{$_}'; ok(!defined($num), "{$_}: failed hypothetical (2nd go)"); ok(defined($alpha), "{$_}: successful hypothetical (2nd go)", :todo); } } unless eval '"a" ~~ /a/' { skip 2, "skipped tests - rules support appears to be missing"; } else { # - binding to hash keys only would leave values undef eval '"a=b\nc=d\n" ~~ / $<matches> := [ (\w) = \N+ ]* /'; ok(eval('$<matches> ~~ all(<a b>)'), "match keys exist", :todo); #ok(!defined($<matches><a>) && !defined($<matches><b>), "match values don't", :todo); ok(0 , "match values don't", :todo); } { # - $0, $1 etc. should all be undef after a failed match # (except for special circumstances) "abcde" ~~ rx:perl5/(.)(.)(.)/; "abcde" ~~ rx:perl5/(\d)/; ok((!try { grep { defined($_) }, ($0, $1, $2, $3, $4, $5) }), "all submatches undefined after failed match") or diag("match state: " ~ eval '$/'); # XXX write me: "special circumstances" } # subroutines { sub bar ($bar, $baz?, :$quux) { is($bar, "BAR", "defined param"); # sanity # L<<S06/"Optional parameters" /Missing optional arguments/>> ok(!defined($baz), "unspecified optional param"); # L<<S06/"Named parameters" /Named parameters are optional/>> ok(!defined($quux), "unspecified optional param"); } bar("BAR"); } # autoloading # L<S10/Autoloading> flunk("FIXME (autoload tests)", :todo<parsefail>); # Currently waiting on # - packages # - symtable hash # - autoloading itself #{ # package AutoMechanic { # AUTOSCALAR { \my $_scalar } # AUTOARRAY { \my @_array } # AUTOHASH { \my %_hash } # AUTOSUB { { "code" } } # AUTOMETH { { "code" } } # # AUTOSCALARDEF { %::«{'$' ~ $_}» = "autoscalardef" } # AUTOARRAYDEF { %::«{'@' ~ $_}» = "autoarraydef".split("") } # AUTOHASHDEF { %::«{'%' ~ $_}» = <autohashdef yes> } # AUTOSUBDEF { %::«{'&' ~ $_}» = { "autosubdef" } } # AUTOMETHDEF { %::«{'&' ~ $_}» = { "automethdef" } } # } # # is(ref $AutoMechanic::scalar0, "Scalar", "autoload - scalar"); # is(ref @AutoMechanic::array0, "Array", "autoload - array"); # is(ref %AutoMechanic::hash, "Hash", "autoload - hash"); # is(ref &AutoMechanic::sub0, "Code", "autoload - sub"); # is(ref AutoMechanic.can("meth0"), "Code", "autoload - meth"); # # is($AutoMechanic::scalar, "autoscalardef", "autoloaddef - scalar"); # is(~@AutoMechanic::ary, ~("autoarraydef".split(""), "autoloaddef - array"); # is(~%AutoMechanic::hash, ~<autohashdef yes>, "autoloaddef - hash"); # is(&AutoMechanic::sub.(), "autosubdef", "autoloaddef - sub"); # is(AutoMechanic.meth(), "automethdef", "autoloaddef - method"); #} # Extra tests added due to apparent bugs is((undef) + 1, 1, 'undef + 1'); is(1 + (undef), 1, '1 + undef'); is((undef) * 2, 0, 'undef * 2'); is(2 * (undef), 0, '2 * undef'); is((undef) xx 2, [undef, undef], 'undef xx 2'); is((undef) * (undef), 0, 'undef * undef');