xref: /openbsd-src/gnu/usr.bin/perl/ext/XS-APItest/t/multicall.t (revision eac174f2741a08d8deb8aae59a7f778ef9b5d770)
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