This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
new perldelta
[perl5.git] / ext / XS-APItest / t / multicall.t
CommitLineData
9c540340
DM
1#!perl -w
2
3# test the MULTICALL macros
4# Note: as of Oct 2010, there are not yet comprehensive tests
5# for these macros.
6
7use warnings;
8use strict;
9
d77cab04 10use Test::More tests => 80;
9c540340
DM
11use XS::APItest;
12
13
14{
15 my $sum = 0;
16 sub add { $sum += $_++ }
17
18 my @a = (1..3);
19 XS::APItest::multicall_each \&add, @a;
20 is($sum, 6, "sum okay");
21 is($a[0], 2, "a[0] okay");
22 is($a[1], 3, "a[1] okay");
23 is($a[2], 4, "a[2] okay");
24}
f837477c
DM
25
26# [perl #78070]
92dfa259 27# multicall using a sub that already has CvDEPTH > 1 caused sub
f837477c
DM
28# to be prematurely freed
29
30{
31 my $destroyed = 0;
32 sub REC::DESTROY { $destroyed = 1 }
33
34 my $closure_var;
35 {
36 my $f = sub {
76a2b88f 37 no warnings 'void';
f837477c
DM
38 $closure_var;
39 my $sub = shift;
40 if (defined $sub) {
41 XS::APItest::multicall_each \&$sub, 1,2,3;
42 }
43 };
44 bless $f, 'REC';
45 $f->($f);
46 is($destroyed, 0, "f not yet destroyed");
47 }
48 is($destroyed, 1, "f now destroyed");
49
50}
3d26b81e
DM
51
52# [perl #115602]
53# deep recursion realloced the CX stack, but the dMULTICALL local var
54# 'cx' still pointed to the old one.
1f0ba93b
DM
55# This doesn't actually test the failure (I couldn't think of a way to
56# get the failure to show at the perl level) but it allows valgrind or
3d26b81e
DM
57# similar to spot any errors.
58
59{
60 sub rec { my $c = shift; rec($c-1) if $c > 0 };
61 my @r = XS::APItest::multicall_each { rec(90) } 1,2,3;
62 pass("recursion");
63}
1f0ba93b
DM
64
65
66
67# Confirm that MULTICALL handles arg return correctly in the various
68# contexts. Also check that lvalue subs are handled the same way, as
69# these take different code paths.
70# Whenever an explicit 'return' is used, it is followed by '1;' to avoid
71# the return being optimised into a leavesub.
a3815e44 72# Adding a 'for' loop pushes extra junk on the stack, which we want to
1f0ba93b
DM
73# avoid being interpreted as a return arg.
74
75{
76 package Ret;
77
eb7e169e 78 use XS::APItest qw(multicall_return G_VOID G_SCALAR G_LIST);
1f0ba93b
DM
79
80 # Helper function for the block that follows:
81 # check that @$got matches what would be expected if a function returned
82 # the items in @$args in $gimme context.
83
84 sub gimme_check {
85 my ($gimme, $got, $args, $desc) = @_;
86
87 if ($gimme == G_VOID) {
88 ::is (scalar @$got, 0, "G_VOID: $desc");
89 }
90 elsif ($gimme == G_SCALAR) {
91 ::is (scalar @$got, 1, "G_SCALAR: $desc: expect 1 arg");
92 ::is ($got->[0], (@$args ? $args->[-1] : undef),
93 "G_SCALAR: $desc: correct arg");
94 }
95 else {
eb7e169e 96 ::is (join('-',@$got), join('-', @$args), "G_LIST: $desc");
1f0ba93b
DM
97 }
98 }
99
eb7e169e 100 for my $gimme (G_VOID, G_SCALAR, G_LIST) {
1f0ba93b
DM
101 my @a;
102
103 # zero args
104
105 @a = multicall_return {()} $gimme;
106 gimme_check($gimme, \@a, [], "()");
107 sub f1 :lvalue { () }
108 @a = multicall_return \&f1, $gimme;
109 gimme_check($gimme, \@a, [], "() lval");
110
111 @a = multicall_return { return; 1 } $gimme;
112 gimme_check($gimme, \@a, [], "return");
113 sub f2 :lvalue { return; 1 }
114 @a = multicall_return \&f2, $gimme;
115 gimme_check($gimme, \@a, [], "return lval");
116
117
118 @a = multicall_return { for (1,2) { return; 1 } } $gimme;
119 gimme_check($gimme, \@a, [], "for-return");
120 sub f3 :lvalue { for (1,2) { return; 1 } }
121 @a = multicall_return \&f3, $gimme;
122 gimme_check($gimme, \@a, [], "for-return lval");
123
124 # one arg
125
126 @a = multicall_return {"one"} $gimme;
127 gimme_check($gimme, \@a, ["one"], "one arg");
128 sub f4 :lvalue { "one" }
129 @a = multicall_return \&f4, $gimme;
130 gimme_check($gimme, \@a, ["one"], "one arg lval");
131
132 @a = multicall_return { return "one"; 1} $gimme;
133 gimme_check($gimme, \@a, ["one"], "return one arg");
134 sub f5 :lvalue { return "one"; 1 }
135 @a = multicall_return \&f5, $gimme;
136 gimme_check($gimme, \@a, ["one"], "return one arg lval");
137
138 @a = multicall_return { for (1,2) { return "one"; 1} } $gimme;
139 gimme_check($gimme, \@a, ["one"], "for-return one arg");
140 sub f6 :lvalue { for (1,2) { return "one"; 1 } }
141 @a = multicall_return \&f6, $gimme;
142 gimme_check($gimme, \@a, ["one"], "for-return one arg lval");
143
144 # two args
145
146 @a = multicall_return {"one", "two" } $gimme;
147 gimme_check($gimme, \@a, ["one", "two"], "two args");
148 sub f7 :lvalue { "one", "two" }
149 @a = multicall_return \&f7, $gimme;
150 gimme_check($gimme, \@a, ["one", "two"], "two args lval");
151
152 @a = multicall_return { return "one", "two"; 1} $gimme;
153 gimme_check($gimme, \@a, ["one", "two"], "return two args");
154 sub f8 :lvalue { return "one", "two"; 1 }
155 @a = multicall_return \&f8, $gimme;
156 gimme_check($gimme, \@a, ["one", "two"], "return two args lval");
157
158 @a = multicall_return { for (1,2) { return "one", "two"; 1} } $gimme;
159 gimme_check($gimme, \@a, ["one", "two"], "for-return two args");
160 sub f9 :lvalue { for (1,2) { return "one", "two"; 1 } }
161 @a = multicall_return \&f9, $gimme;
162 gimme_check($gimme, \@a, ["one", "two"], "for-return two args lval");
163 }
d77cab04 164
35095fd0 165 # MULTICALL *shouldn't* clear savestack after each call
d77cab04 166
35095fd0
DM
167 sub f10 { my $x = 1; $x };
168 my @a = XS::APItest::multicall_return \&f10, G_SCALAR;
169 ::is($a[0], 1, "leave scope");
d77cab04 170}