1898184e3Ssthen#!perl -w 2898184e3Ssthen 3898184e3Ssthen# test the MULTICALL macros 4898184e3Ssthen# Note: as of Oct 2010, there are not yet comprehensive tests 5898184e3Ssthen# for these macros. 6898184e3Ssthen 7898184e3Ssthenuse warnings; 8898184e3Ssthenuse strict; 9898184e3Ssthen 10b8851fccSafresh1use Test::More tests => 80; 11898184e3Ssthenuse XS::APItest; 12898184e3Ssthen 13898184e3Ssthen 14898184e3Ssthen{ 15898184e3Ssthen my $sum = 0; 16898184e3Ssthen sub add { $sum += $_++ } 17898184e3Ssthen 18898184e3Ssthen my @a = (1..3); 19898184e3Ssthen XS::APItest::multicall_each \&add, @a; 20898184e3Ssthen is($sum, 6, "sum okay"); 21898184e3Ssthen is($a[0], 2, "a[0] okay"); 22898184e3Ssthen is($a[1], 3, "a[1] okay"); 23898184e3Ssthen is($a[2], 4, "a[2] okay"); 24898184e3Ssthen} 25898184e3Ssthen 26898184e3Ssthen# [perl #78070] 27b8851fccSafresh1# multicall using a sub that already has CvDEPTH > 1 caused sub 28898184e3Ssthen# to be prematurely freed 29898184e3Ssthen 30898184e3Ssthen{ 31898184e3Ssthen my $destroyed = 0; 32898184e3Ssthen sub REC::DESTROY { $destroyed = 1 } 33898184e3Ssthen 34898184e3Ssthen my $closure_var; 35898184e3Ssthen { 36898184e3Ssthen my $f = sub { 37898184e3Ssthen no warnings 'void'; 38898184e3Ssthen $closure_var; 39898184e3Ssthen my $sub = shift; 40898184e3Ssthen if (defined $sub) { 41898184e3Ssthen XS::APItest::multicall_each \&$sub, 1,2,3; 42898184e3Ssthen } 43898184e3Ssthen }; 44898184e3Ssthen bless $f, 'REC'; 45898184e3Ssthen $f->($f); 46898184e3Ssthen is($destroyed, 0, "f not yet destroyed"); 47898184e3Ssthen } 48898184e3Ssthen is($destroyed, 1, "f now destroyed"); 49898184e3Ssthen 50898184e3Ssthen} 5191f110e0Safresh1 5291f110e0Safresh1# [perl #115602] 5391f110e0Safresh1# deep recursion realloced the CX stack, but the dMULTICALL local var 5491f110e0Safresh1# 'cx' still pointed to the old one. 55b8851fccSafresh1# This doesn't actually test the failure (I couldn't think of a way to 56b8851fccSafresh1# get the failure to show at the perl level) but it allows valgrind or 5791f110e0Safresh1# similar to spot any errors. 5891f110e0Safresh1 5991f110e0Safresh1{ 6091f110e0Safresh1 sub rec { my $c = shift; rec($c-1) if $c > 0 }; 6191f110e0Safresh1 my @r = XS::APItest::multicall_each { rec(90) } 1,2,3; 6291f110e0Safresh1 pass("recursion"); 6391f110e0Safresh1} 64b8851fccSafresh1 65b8851fccSafresh1 66b8851fccSafresh1 67b8851fccSafresh1# Confirm that MULTICALL handles arg return correctly in the various 68b8851fccSafresh1# contexts. Also check that lvalue subs are handled the same way, as 69b8851fccSafresh1# these take different code paths. 70b8851fccSafresh1# Whenever an explicit 'return' is used, it is followed by '1;' to avoid 71b8851fccSafresh1# the return being optimised into a leavesub. 7256d68f1eSafresh1# Adding a 'for' loop pushes extra junk on the stack, which we want to 73b8851fccSafresh1# avoid being interpreted as a return arg. 74b8851fccSafresh1 75b8851fccSafresh1{ 76b8851fccSafresh1 package Ret; 77b8851fccSafresh1 78*eac174f2Safresh1 use XS::APItest qw(multicall_return G_VOID G_SCALAR G_LIST); 79b8851fccSafresh1 80b8851fccSafresh1 # Helper function for the block that follows: 81b8851fccSafresh1 # check that @$got matches what would be expected if a function returned 82b8851fccSafresh1 # the items in @$args in $gimme context. 83b8851fccSafresh1 84b8851fccSafresh1 sub gimme_check { 85b8851fccSafresh1 my ($gimme, $got, $args, $desc) = @_; 86b8851fccSafresh1 87b8851fccSafresh1 if ($gimme == G_VOID) { 88b8851fccSafresh1 ::is (scalar @$got, 0, "G_VOID: $desc"); 89b8851fccSafresh1 } 90b8851fccSafresh1 elsif ($gimme == G_SCALAR) { 91b8851fccSafresh1 ::is (scalar @$got, 1, "G_SCALAR: $desc: expect 1 arg"); 92b8851fccSafresh1 ::is ($got->[0], (@$args ? $args->[-1] : undef), 93b8851fccSafresh1 "G_SCALAR: $desc: correct arg"); 94b8851fccSafresh1 } 95b8851fccSafresh1 else { 96*eac174f2Safresh1 ::is (join('-',@$got), join('-', @$args), "G_LIST: $desc"); 97b8851fccSafresh1 } 98b8851fccSafresh1 } 99b8851fccSafresh1 100*eac174f2Safresh1 for my $gimme (G_VOID, G_SCALAR, G_LIST) { 101b8851fccSafresh1 my @a; 102b8851fccSafresh1 103b8851fccSafresh1 # zero args 104b8851fccSafresh1 105b8851fccSafresh1 @a = multicall_return {()} $gimme; 106b8851fccSafresh1 gimme_check($gimme, \@a, [], "()"); 107b8851fccSafresh1 sub f1 :lvalue { () } 108b8851fccSafresh1 @a = multicall_return \&f1, $gimme; 109b8851fccSafresh1 gimme_check($gimme, \@a, [], "() lval"); 110b8851fccSafresh1 111b8851fccSafresh1 @a = multicall_return { return; 1 } $gimme; 112b8851fccSafresh1 gimme_check($gimme, \@a, [], "return"); 113b8851fccSafresh1 sub f2 :lvalue { return; 1 } 114b8851fccSafresh1 @a = multicall_return \&f2, $gimme; 115b8851fccSafresh1 gimme_check($gimme, \@a, [], "return lval"); 116b8851fccSafresh1 117b8851fccSafresh1 118b8851fccSafresh1 @a = multicall_return { for (1,2) { return; 1 } } $gimme; 119b8851fccSafresh1 gimme_check($gimme, \@a, [], "for-return"); 120b8851fccSafresh1 sub f3 :lvalue { for (1,2) { return; 1 } } 121b8851fccSafresh1 @a = multicall_return \&f3, $gimme; 122b8851fccSafresh1 gimme_check($gimme, \@a, [], "for-return lval"); 123b8851fccSafresh1 124b8851fccSafresh1 # one arg 125b8851fccSafresh1 126b8851fccSafresh1 @a = multicall_return {"one"} $gimme; 127b8851fccSafresh1 gimme_check($gimme, \@a, ["one"], "one arg"); 128b8851fccSafresh1 sub f4 :lvalue { "one" } 129b8851fccSafresh1 @a = multicall_return \&f4, $gimme; 130b8851fccSafresh1 gimme_check($gimme, \@a, ["one"], "one arg lval"); 131b8851fccSafresh1 132b8851fccSafresh1 @a = multicall_return { return "one"; 1} $gimme; 133b8851fccSafresh1 gimme_check($gimme, \@a, ["one"], "return one arg"); 134b8851fccSafresh1 sub f5 :lvalue { return "one"; 1 } 135b8851fccSafresh1 @a = multicall_return \&f5, $gimme; 136b8851fccSafresh1 gimme_check($gimme, \@a, ["one"], "return one arg lval"); 137b8851fccSafresh1 138b8851fccSafresh1 @a = multicall_return { for (1,2) { return "one"; 1} } $gimme; 139b8851fccSafresh1 gimme_check($gimme, \@a, ["one"], "for-return one arg"); 140b8851fccSafresh1 sub f6 :lvalue { for (1,2) { return "one"; 1 } } 141b8851fccSafresh1 @a = multicall_return \&f6, $gimme; 142b8851fccSafresh1 gimme_check($gimme, \@a, ["one"], "for-return one arg lval"); 143b8851fccSafresh1 144b8851fccSafresh1 # two args 145b8851fccSafresh1 146b8851fccSafresh1 @a = multicall_return {"one", "two" } $gimme; 147b8851fccSafresh1 gimme_check($gimme, \@a, ["one", "two"], "two args"); 148b8851fccSafresh1 sub f7 :lvalue { "one", "two" } 149b8851fccSafresh1 @a = multicall_return \&f7, $gimme; 150b8851fccSafresh1 gimme_check($gimme, \@a, ["one", "two"], "two args lval"); 151b8851fccSafresh1 152b8851fccSafresh1 @a = multicall_return { return "one", "two"; 1} $gimme; 153b8851fccSafresh1 gimme_check($gimme, \@a, ["one", "two"], "return two args"); 154b8851fccSafresh1 sub f8 :lvalue { return "one", "two"; 1 } 155b8851fccSafresh1 @a = multicall_return \&f8, $gimme; 156b8851fccSafresh1 gimme_check($gimme, \@a, ["one", "two"], "return two args lval"); 157b8851fccSafresh1 158b8851fccSafresh1 @a = multicall_return { for (1,2) { return "one", "two"; 1} } $gimme; 159b8851fccSafresh1 gimme_check($gimme, \@a, ["one", "two"], "for-return two args"); 160b8851fccSafresh1 sub f9 :lvalue { for (1,2) { return "one", "two"; 1 } } 161b8851fccSafresh1 @a = multicall_return \&f9, $gimme; 162b8851fccSafresh1 gimme_check($gimme, \@a, ["one", "two"], "for-return two args lval"); 163b8851fccSafresh1 } 164b8851fccSafresh1 165b8851fccSafresh1 # MULTICALL *shouldn't* clear savestack after each call 166b8851fccSafresh1 167b8851fccSafresh1 sub f10 { my $x = 1; $x }; 168b8851fccSafresh1 my @a = XS::APItest::multicall_return \&f10, G_SCALAR; 169b8851fccSafresh1 ::is($a[0], 1, "leave scope"); 170b8851fccSafresh1} 171