xref: /openbsd-src/gnu/usr.bin/perl/ext/XS-APItest/t/autoload.t (revision 898184e3e61f9129feb5978fad5a8c6865f00b92)
1*898184e3Ssthen#!perl
2*898184e3Ssthen
3*898184e3Ssthen# This script tests not only the interface for XS AUTOLOAD routines to find
4*898184e3Ssthen# out the sub name, but also that that interface does not interfere with
5*898184e3Ssthen# prototypes, the way it did before 5.15.4.
6*898184e3Ssthen
7*898184e3Ssthenuse strict;
8*898184e3Ssthenuse warnings;
9*898184e3Ssthen
10*898184e3Ssthenuse Test::More tests => 26;
11*898184e3Ssthen
12*898184e3Ssthenuse XS::APItest;
13*898184e3Ssthen
14*898184e3Ssthenis XS::APItest::AutoLoader::frob(), 'frob', 'name passed to XS AUTOLOAD';
15*898184e3Ssthenis "XS::APItest::AutoLoader::fr\0b"->(), "fr\0b",
16*898184e3Ssthen  'name with embedded null passed to XS AUTOLOAD';
17*898184e3Ssthenis "XS::APItest::AutoLoader::fr\x{1ed9}b"->(), "fr\x{1ed9}b",
18*898184e3Ssthen  'Unicode name passed to XS AUTOLOAD';
19*898184e3Ssthen
20*898184e3Ssthen*AUTOLOAD = *XS::APItest::AutoLoader::AUTOLOADp;
21*898184e3Ssthen
22*898184e3Ssthenis frob(), 'frob', 'name passed to XS AUTOLOAD with proto';
23*898184e3Ssthenis prototype \&AUTOLOAD, '*$', 'prototype is unchanged';
24*898184e3Ssthenis "fr\0b"->(), "fr\0b",
25*898184e3Ssthen  'name with embedded null passed to XS AUTOLOAD with proto';
26*898184e3Ssthenis prototype \&AUTOLOAD, '*$', 'proto unchanged after embedded-null call';
27*898184e3Ssthenis "fr\x{1ed9}b"->(), "fr\x{1ed9}b",
28*898184e3Ssthen  'Unicode name passed to XS AUTOLOAD with proto';
29*898184e3Ssthenis prototype \&AUTOLOAD, '*$', 'prototype is unchanged after Unicode call';
30*898184e3Ssthen
31*898184e3Ssthen# Test that the prototype was preserved from the parser’s point of view
32*898184e3Ssthen
33*898184e3Ssthenok !eval "sub { ::AUTOLOAD(1) }",
34*898184e3Ssthen   'parse failure due to AUTOLOAD prototype';
35*898184e3Ssthenok eval "sub { ::AUTOLOAD(1,2) }", 'successful parse respecting prototype'
36*898184e3Ssthen  or diag $@;
37*898184e3Ssthen
38*898184e3Ssthenpackage fribble { sub a { return 7 } }
39*898184e3Ssthenno warnings 'once';
40*898184e3Ssthen*a = \&AUTOLOAD;
41*898184e3Ssthen'$'->();
42*898184e3Ssthen# &a('fribble') will return '$'
43*898184e3Ssthen# But if intuit_method does not see the (*...) proto, this compiles as
44*898184e3Ssthen# fribble->a
45*898184e3Ssthenno strict;
46*898184e3Ssthenis eval 'a fribble, 3', '$', 'intuit_method sees * in AUTOLOAD proto'
47*898184e3Ssthen  or diag $@;
48*898184e3Ssthen
49*898184e3Ssthen# precedence check
50*898184e3Ssthen# *$ should parse as a list operator, but right now the AUTOLOAD
51*898184e3Ssthen# sub name is $
52*898184e3Ssthenis join(" ", eval 'a "b", "c"'), '$',
53*898184e3Ssthen   'precedence determination respects prototype of AUTOLOAD sub';
54*898184e3Ssthen
55*898184e3Ssthen{
56*898184e3Ssthen    my $w;
57*898184e3Ssthen    local $SIG{__WARN__} = sub { $w .= shift };
58*898184e3Ssthen    eval 'sub a($){}';
59*898184e3Ssthen    like $w, qr/^Prototype mismatch: sub main::a \(\*\$\) vs \(\$\)/m,
60*898184e3Ssthen        'proto warnings respect AUTOLOAD prototypes';
61*898184e3Ssthen    undef $w;
62*898184e3Ssthen    *a = \&AUTOLOAD;
63*898184e3Ssthen    like $w, qr/^Prototype mismatch: sub main::a \(\$\) vs \(\*\$\)/m,
64*898184e3Ssthen        'GV assignment proto warnings respect AUTOLOAD prototypes';
65*898184e3Ssthen}
66*898184e3Ssthen
67*898184e3Ssthen
68*898184e3Ssthen#
69*898184e3Ssthen# This is a test for AUTOLOAD implemented as an XSUB.
70*898184e3Ssthen# It tests that $AUTOLOAD is set correctly, including the
71*898184e3Ssthen# case of inheritance.
72*898184e3Ssthen#
73*898184e3Ssthen# Rationale: Due to change ed850460, $AUTOLOAD is not currently set
74*898184e3Ssthen# for XSUB AUTOLOADs at all.  Instead, as of adb5a9ae the PV of the
75*898184e3Ssthen# AUTOLOAD XSUB is set to the name of the method. We cruelly test it
76*898184e3Ssthen# regardless.
77*898184e3Ssthen#
78*898184e3Ssthen
79*898184e3Ssthen# First, make sure we have the XS AUTOLOAD available for testing
80*898184e3Ssthenok(XS::APItest::AUTOLOADtest->can('AUTOLOAD'), 'Test class ->can AUTOLOAD');
81*898184e3Ssthen
82*898184e3Ssthen# Used to communicate from the XS AUTOLOAD to Perl land
83*898184e3Ssthenuse vars '$the_method';
84*898184e3Ssthen
85*898184e3Ssthen# First, set up the Perl equivalent to what we're testing in
86*898184e3Ssthen# XS so we have a comparison
87*898184e3Ssthenpackage PerlBase;
88*898184e3Ssthenuse vars '$AUTOLOAD';
89*898184e3Ssthensub AUTOLOAD {
90*898184e3Ssthen  Test::More::ok(defined $AUTOLOAD);
91*898184e3Ssthen  return 1 if not defined $AUTOLOAD;
92*898184e3Ssthen  $main::the_method = $AUTOLOAD;
93*898184e3Ssthen  return 0;
94*898184e3Ssthen}
95*898184e3Ssthen
96*898184e3Ssthenpackage PerlDerived;
97*898184e3Ssthenuse vars '@ISA';
98*898184e3Ssthen@ISA = qw(PerlBase);
99*898184e3Ssthen
100*898184e3Ssthenpackage Derived;
101*898184e3Ssthenuse vars '@ISA';
102*898184e3Ssthen@ISA = qw(XS::APItest::AUTOLOADtest);
103*898184e3Ssthen
104*898184e3Ssthenpackage main;
105*898184e3Ssthen
106*898184e3Ssthen# Test Perl AUTOLOAD in base class directly
107*898184e3Ssthen$the_method = undef;
108*898184e3Ssthenis(PerlBase->Blah(), 0,
109*898184e3Ssthen   "Perl AUTOLOAD gets called and returns success");
110*898184e3Ssthenis($the_method, 'PerlBase::Blah',
111*898184e3Ssthen   'Scalar set to correct class/method name');
112*898184e3Ssthen
113*898184e3Ssthen# Test Perl AUTOLOAD in derived class
114*898184e3Ssthen$the_method = undef;
115*898184e3Ssthenis(PerlDerived->Boo(), 0,
116*898184e3Ssthen   'Perl AUTOLOAD on derived class gets called and returns success');
117*898184e3Ssthenis($the_method, 'PerlDerived::Boo',
118*898184e3Ssthen   'Scalar set to correct class/method name');
119*898184e3Ssthen
120*898184e3Ssthen# Test XS AUTOLOAD in base class directly
121*898184e3Ssthen$the_method = undef;
122*898184e3Ssthenis(XS::APItest::AUTOLOADtest->Blah(), 0,
123*898184e3Ssthen     'XS AUTOLOAD gets called and returns success');
124*898184e3Ssthenis($the_method, 'XS::APItest::AUTOLOADtest::Blah',
125*898184e3Ssthen     'Scalar set to correct class/method name');
126*898184e3Ssthen
127*898184e3Ssthen# Test XS AUTOLOAD in derived class directly
128*898184e3Ssthen$the_method = undef;
129*898184e3Ssthenis(Derived->Foo(), 0,
130*898184e3Ssthen     'XS AUTOLOAD gets called and returns success');
131*898184e3Ssthenis($the_method, 'Derived::Foo',
132*898184e3Ssthen     'Scalar set to correct class/method name');
133