This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Deprecate isFOO_utf8() macros
[perl5.git] / ext / XS-APItest / t / call.t
CommitLineData
d1f347d7
DM
1#!perl -w
2
3# test the various call-into-perl-from-C functions
4# DAPM Aug 2004
5
d1f347d7
DM
6use warnings;
7use strict;
8
43d2322d 9# Test::More doesn't have fresh_perl_is() yet
7ce09284 10# use Test::More tests => 342;
d1f347d7 11
dedbcade 12BEGIN {
2adbc9b6 13 require '../../t/test.pl';
c06180d6 14 plan(527);
dedbcade
DM
15 use_ok('XS::APItest')
16};
d1f347d7
DM
17
18#########################
19
4aca2f62
DM
20# f(): general test sub to be called by call_sv() etc.
21# Return the called args, but with the first arg replaced with 'b',
22# and the last arg replaced with x/y/z depending on context
23#
d1f347d7
DM
24sub f {
25 shift;
26 unshift @_, 'b';
27 pop @_;
28 @_, defined wantarray ? wantarray ? 'x' : 'y' : 'z';
29}
30
a85ce6f0
DD
31our $call_sv_count = 0;
32sub i {
33 $call_sv_count++;
34}
35call_sv_C();
36is($call_sv_count, 6, "call_sv_C passes");
37
d1f347d7 38sub d {
d1f347d7
DM
39 die "its_dead_jim\n";
40}
41
42my $obj = bless [], 'Foo';
43
44sub Foo::meth {
45 return 'bad_self' unless @_ && ref $_[0] && ref($_[0]) eq 'Foo';
46 shift;
47 shift;
48 unshift @_, 'b';
49 pop @_;
50 @_, defined wantarray ? wantarray ? 'x' : 'y' : 'z';
51}
52
53sub Foo::d {
d1f347d7
DM
54 die "its_dead_jim\n";
55}
56
57for my $test (
58 # flags args expected description
2e2d7405
DM
59 [ G_VOID, [ ], [ 0 ], '0 args, G_VOID' ],
60 [ G_VOID, [ qw(a p q) ], [ 0 ], '3 args, G_VOID' ],
d1f347d7
DM
61 [ G_SCALAR, [ ], [ qw(y 1) ], '0 args, G_SCALAR' ],
62 [ G_SCALAR, [ qw(a p q) ], [ qw(y 1) ], '3 args, G_SCALAR' ],
63 [ G_ARRAY, [ ], [ qw(x 1) ], '0 args, G_ARRAY' ],
64 [ G_ARRAY, [ qw(a p q) ], [ qw(b p x 3) ], '3 args, G_ARRAY' ],
65 [ G_DISCARD, [ ], [ qw(0) ], '0 args, G_DISCARD' ],
66 [ G_DISCARD, [ qw(a p q) ], [ qw(0) ], '3 args, G_DISCARD' ],
67)
68{
69 my ($flags, $args, $expected, $description) = @$test;
70
71 ok(eq_array( [ call_sv(\&f, $flags, @$args) ], $expected),
72 "$description call_sv(\\&f)");
73
74 ok(eq_array( [ call_sv(*f, $flags, @$args) ], $expected),
75 "$description call_sv(*f)");
76
77 ok(eq_array( [ call_sv('f', $flags, @$args) ], $expected),
78 "$description call_sv('f')");
79
80 ok(eq_array( [ call_pv('f', $flags, @$args) ], $expected),
81 "$description call_pv('f')");
82
c06180d6
FC
83 ok(eq_array( [ call_argv('f', $flags, @$args) ], $expected),
84 "$description call_argv('f')") or warn "@{[call_argv('f', $flags, @$args)]}";
85
d1f347d7 86 ok(eq_array( [ eval_sv('f(' . join(',',map"'$_'",@$args) . ')', $flags) ],
2e2d7405 87 $expected), "$description eval_sv('f(args)')");
d1f347d7
DM
88
89 ok(eq_array( [ call_method('meth', $flags, $obj, @$args) ], $expected),
90 "$description call_method('meth')");
91
b8d2d791
NC
92 my $returnval = ((($flags & G_WANT) == G_ARRAY) || ($flags & G_DISCARD))
93 ? [0] : [ undef, 1 ];
d1f347d7
DM
94 for my $keep (0, G_KEEPERR) {
95 my $desc = $description . ($keep ? ' G_KEEPERR' : '');
7ce09284
Z
96 my $exp_warn = $keep ? "\t(in cleanup) its_dead_jim\n" : "";
97 my $exp_err = $keep ? "before\n"
d1f347d7 98 : "its_dead_jim\n";
7ce09284
Z
99 my $warn;
100 local $SIG{__WARN__} = sub { $warn .= $_[0] };
d1f347d7 101 $@ = "before\n";
7ce09284 102 $warn = "";
d1f347d7 103 ok(eq_array( [ call_sv('d', $flags|G_EVAL|$keep, @$args) ],
b8d2d791 104 $returnval),
d1f347d7
DM
105 "$desc G_EVAL call_sv('d')");
106 is($@, $exp_err, "$desc G_EVAL call_sv('d') - \$@");
7ce09284 107 is($warn, $exp_warn, "$desc G_EVAL call_sv('d') - warning");
d1f347d7
DM
108
109 $@ = "before\n";
7ce09284 110 $warn = "";
d1f347d7 111 ok(eq_array( [ call_pv('d', $flags|G_EVAL|$keep, @$args) ],
b8d2d791 112 $returnval),
d1f347d7
DM
113 "$desc G_EVAL call_pv('d')");
114 is($@, $exp_err, "$desc G_EVAL call_pv('d') - \$@");
7ce09284 115 is($warn, $exp_warn, "$desc G_EVAL call_pv('d') - warning");
d1f347d7
DM
116
117 $@ = "before\n";
7ce09284 118 $warn = "";
c06180d6
FC
119 ok(eq_array( [ call_argv('d', $flags|G_EVAL|$keep, @$args) ],
120 $returnval),
121 "$desc G_EVAL call_argv('d')");
122 is($@, $exp_err, "$desc G_EVAL call_argv('d') - \$@");
123 is($warn, $exp_warn, "$desc G_EVAL call_argv('d') - warning");
124
125 $@ = "before\n";
126 $warn = "";
d1f347d7 127 ok(eq_array( [ eval_sv('d()', $flags|$keep) ],
b8d2d791 128 $returnval),
d1f347d7
DM
129 "$desc eval_sv('d()')");
130 is($@, $exp_err, "$desc eval_sv('d()') - \$@");
7ce09284 131 is($warn, $exp_warn, "$desc G_EVAL eval_sv('d') - warning");
d1f347d7
DM
132
133 $@ = "before\n";
7ce09284 134 $warn = "";
d1f347d7 135 ok(eq_array( [ call_method('d', $flags|G_EVAL|$keep, $obj, @$args) ],
b8d2d791 136 $returnval),
d1f347d7
DM
137 "$desc G_EVAL call_method('d')");
138 is($@, $exp_err, "$desc G_EVAL call_method('d') - \$@");
7ce09284 139 is($warn, $exp_warn, "$desc G_EVAL call_method('d') - warning");
d1f347d7
DM
140 }
141
142 ok(eq_array( [ sub { call_sv('f', $flags|G_NOARGS, "bad") }->(@$args) ],
143 $expected), "$description G_NOARGS call_sv('f')");
144
145 ok(eq_array( [ sub { call_pv('f', $flags|G_NOARGS, "bad") }->(@$args) ],
146 $expected), "$description G_NOARGS call_pv('f')");
147
c06180d6
FC
148 ok(eq_array( [ sub { call_argv('f', $flags|G_NOARGS, "bad") }->(@$args) ],
149 $expected), "$description G_NOARGS call_argv('f')");
150
d1f347d7 151 ok(eq_array( [ sub { eval_sv('f(@_)', $flags|G_NOARGS) }->(@$args) ],
2e2d7405 152 $expected), "$description G_NOARGS eval_sv('f(@_)')");
d1f347d7
DM
153
154 # XXX call_method(G_NOARGS) isn't tested: I'm assuming
155 # it's not a sensible combination. DAPM.
156
157 ok(eq_array( [ eval { call_sv('d', $flags, @$args)}, $@ ],
158 [ "its_dead_jim\n" ]), "$description eval { call_sv('d') }");
159
160 ok(eq_array( [ eval { call_pv('d', $flags, @$args) }, $@ ],
161 [ "its_dead_jim\n" ]), "$description eval { call_pv('d') }");
162
c06180d6
FC
163 ok(eq_array( [ eval { call_argv('d', $flags, @$args) }, $@ ],
164 [ "its_dead_jim\n" ]), "$description eval { call_argv('d') }");
165
d1f347d7 166 ok(eq_array( [ eval { eval_sv('d', $flags), $@ }, $@ ],
b8d2d791 167 [ @$returnval,
dedbcade 168 "its_dead_jim\n", '' ]),
d1f347d7
DM
169 "$description eval { eval_sv('d') }");
170
171 ok(eq_array( [ eval { call_method('d', $flags, $obj, @$args) }, $@ ],
172 [ "its_dead_jim\n" ]), "$description eval { call_method('d') }");
173
174};
175
0b06a753
NT
176{
177 # these are the ones documented in perlcall.pod
178 my @flags = (G_DISCARD, G_NOARGS, G_EVAL, G_KEEPERR);
179 my $mask = 0;
180 $mask |= $_ for (@flags);
181 is(unpack('%32b*', pack('l', $mask)), @flags,
182 "G_DISCARD and the rest are separate bits");
183}
184
7ce09284
Z
185foreach my $inx ("", "aabbcc\n", [qw(aa bb cc)]) {
186 foreach my $outx ("", "xxyyzz\n", [qw(xx yy zz)]) {
187 my $warn;
188 local $SIG{__WARN__} = sub { $warn .= $_[0] };
189 $@ = $outx;
190 $warn = "";
191 call_sv(sub { die $inx if $inx }, G_VOID|G_EVAL);
192 ok ref($@) eq ref($inx) && $@ eq $inx;
193 $warn =~ s/ at [^\n]*\n\z//;
194 is $warn, "";
195 $@ = $outx;
196 $warn = "";
197 call_sv(sub { die $inx if $inx }, G_VOID|G_EVAL|G_KEEPERR);
198 ok ref($@) eq ref($outx) && $@ eq $outx;
199 $warn =~ s/ at [^\n]*\n\z//;
200 is $warn, $inx ? "\t(in cleanup) $inx" : "";
201 }
202}
203
204{
205 no warnings "misc";
206 my $warn = "";
207 local $SIG{__WARN__} = sub { $warn .= $_[0] };
208 call_sv(sub { die "aa\n" }, G_VOID|G_EVAL|G_KEEPERR);
209 is $warn, "";
210}
211
212{
fc941f37 213 no warnings "misc";
7ce09284
Z
214 my $warn = "";
215 local $SIG{__WARN__} = sub { $warn .= $_[0] };
fc941f37 216 call_sv(sub { use warnings "misc"; die "aa\n" }, G_VOID|G_EVAL|G_KEEPERR);
7ce09284
Z
217 is $warn, "\t(in cleanup) aa\n";
218}
219
d1f347d7
DM
220is(eval_pv('f()', 0), 'y', "eval_pv('f()', 0)");
221is(eval_pv('f(qw(a b c))', 0), 'y', "eval_pv('f(qw(a b c))', 0)");
222is(eval_pv('d()', 0), undef, "eval_pv('d()', 0)");
223is($@, "its_dead_jim\n", "eval_pv('d()', 0) - \$@");
224is(eval { eval_pv('d()', 1) } , undef, "eval { eval_pv('d()', 1) }");
225is($@, "its_dead_jim\n", "eval { eval_pv('d()', 1) } - \$@");
dedbcade 226
4aca2f62
DM
227
228# #3719 - check that the eval call variants handle exceptions correctly,
229# and do the right thing with $@, both with and without G_KEEPERR set.
230
231sub f99 { 99 };
232
a1f85fba
DM
233my @bodies = (
234 # [ code, is_fn_name, expect_success, has_inner_die, expected_err ]
4aca2f62 235
a1f85fba
DM
236 # ok
237 [ 'f99', 1, 1, 0, qr/^$/, ],
238 # compile-time err
239 [ '$x=', 0, 0, 0, qr/syntax error/, ],
240 # compile-time exception
241 [ 'BEGIN { die "die in BEGIN"}', 0, 0, 1, qr/die in BEGIN/, ],
242 # run-time exception
243 [ 'd', 1, 0, 0, qr/its_dead_jim/, ],
7051b8c3
DM
244 # success with caught exception
245 [ 'eval { die "blah" }; 99', 0, 1, 1, qr/^$/, ],
a1f85fba
DM
246);
247
248
249for my $fn_type (qw(eval_pv eval_sv call_sv)) {
4aca2f62
DM
250
251 my $warn_msg;
6b2fb389 252 local $SIG{__WARN__} = sub { $warn_msg .= $_[0] };
4aca2f62 253
a1f85fba
DM
254 for my $body (@bodies) {
255 my ($code, $is_fn_name, $expect_success,
256 $has_inner_die, $expected_err_qr) = @$body;
4aca2f62
DM
257
258 # call_sv can only handle function names, not code snippets
a1f85fba 259 next if $fn_type eq 'call_sv' and !$is_fn_name;
4aca2f62
DM
260
261 for my $keep (0, G_KEEPERR) {
4aca2f62
DM
262 my $keep_desc = $keep ? 'G_KEEPERR' : '0';
263
264 my $desc;
a1f85fba 265 my $expect = $expect_success;
4aca2f62
DM
266
267 undef $warn_msg;
268 $@ = 'pre-err';
269
270 my @ret;
a1f85fba 271 if ($fn_type eq 'eval_pv') {
4aca2f62
DM
272 # eval_pv returns its result rather than a 'succeed' boolean
273 $expect = $expect ? '99' : undef;
274
275 # eval_pv doesn't support G_KEEPERR, but it has a croak
276 # boolean arg instead, so switch on that instead
277 if ($keep) {
278 $desc = "eval { eval_pv('$code', 1) }";
279 @ret = eval { eval_pv($code, 1); '99' };
280 # die in eval returns empty list
281 push @ret, undef unless @ret;
282 }
283 else {
284 $desc = "eval_pv('$code', 0)";
285 @ret = eval_pv($code, 0);
286 }
287 }
a1f85fba 288 elsif ($fn_type eq 'eval_sv') {
4aca2f62
DM
289 $desc = "eval_sv('$code', G_ARRAY|$keep_desc)";
290 @ret = eval_sv($code, G_ARRAY|$keep);
291 }
a1f85fba 292 elsif ($fn_type eq 'call_sv') {
4aca2f62
DM
293 $desc = "call_sv('$code', G_EVAL|G_ARRAY|$keep_desc)";
294 @ret = call_sv($code, G_EVAL|G_ARRAY|$keep);
295 }
a1f85fba 296 is(scalar @ret, ($expect_success && $fn_type ne 'eval_pv') ? 2 : 1,
4aca2f62
DM
297 "$desc - number of returned args");
298 is($ret[-1], $expect, "$desc - return value");
299
a1f85fba 300 if ($keep && $fn_type ne 'eval_pv') {
6b2fb389 301 # G_KEEPERR doesn't propagate into inner evals, requires etc
a1f85fba 302 unless ($keep && $has_inner_die) {
6b2fb389
DM
303 is($@, 'pre-err', "$desc - \$@ unmodified");
304 }
4aca2f62
DM
305 $@ = $warn_msg;
306 }
307 else {
308 is($warn_msg, undef, "$desc - __WARN__ not called");
aaa63dae 309 unlike($@, qr/pre-err/, "$desc - \$@ modified");
4aca2f62 310 }
a1f85fba 311 like($@, $expected_err_qr, "$desc - the correct error message");
4aca2f62
DM
312 }
313 }
314}
315
dedbcade
DM
316# DAPM 9-Aug-04. A taint test in eval_sv() could die after setting up
317# a new jump level but before pushing an eval context, leading to
318# stack corruption
319
2adbc9b6 320fresh_perl_is(<<'EOF', "x=2", { switches => ['-T', '-I../../lib'] }, 'eval_sv() taint');
dedbcade
DM
321use XS::APItest;
322
323my $x = 0;
324sub f {
325 eval { my @a = ($^X . "x" , eval_sv(q(die "inner\n"), 0)) ; };
326 $x++;
327 $a <=> $b;
328}
329
330eval { my @a = sort f 2, 1; $x++};
331print "x=$x\n";
332EOF
333