Commit | Line | Data |
---|---|---|
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 | ||
7 | use warnings; | |
8 | use strict; | |
9 | ||
d77cab04 | 10 | use Test::More tests => 80; |
9c540340 DM |
11 | use 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 | } |