xref: /openbsd-src/gnu/usr.bin/perl/t/uni/method.t (revision e068048151d29f2562a32185e21a8ba885482260)
1898184e3Ssthen#!./perl -w
2898184e3Ssthen
3898184e3Ssthen#
4898184e3Ssthen# test method calls and autoloading.
5898184e3Ssthen#
6898184e3Ssthen
7898184e3SsthenBEGIN {
8898184e3Ssthen    chdir 't' if -d 't';
9eac174f2Safresh1    require "./test.pl";
109f11ffb7Safresh1    set_up_inc( qw(. ../lib ../cpan/parent/lib) );
11eac174f2Safresh1	require './charset_tools.pl';
12898184e3Ssthen}
13898184e3Ssthen
14898184e3Ssthenuse strict;
15898184e3Ssthenuse utf8;
16898184e3Ssthenuse open qw( :utf8 :std );
17898184e3Ssthenno warnings 'once';
18898184e3Ssthen
19898184e3Ssthenplan(tests => 62);
20898184e3Ssthen
21898184e3Ssthen#Can't use bless yet, as it might not be clean
22898184e3Ssthen
23898184e3Ssthensub F::b { ::is shift, "F";  "UTF8 meth"       }
24898184e3Ssthensub F::b { ::is shift, "F";  "UTF8 Stash"     }
25898184e3Ssthensub F::b { ::is shift, "F"; "UTF8 Stash&meth" }
26898184e3Ssthen
27898184e3Ssthenis(F->b, "UTF8 meth", "If the method is in UTF-8, lookup works through explicitly named methods");
28898184e3Ssthenis(F->${\"b"}, "UTF8 meth", '..as does for ->${\""}');
29898184e3Sstheneval { F->${\"b\0nul"} };
30898184e3Ssthenok $@, "If the method is in UTF-8, lookup is nul-clean";
31898184e3Ssthen
32898184e3Ssthenis(F->b, "UTF8 Stash", "If the stash is in UTF-8, lookup works through explicitly named methods");
33898184e3Ssthenis(F->${\"b"}, "UTF8 Stash", '..as does for ->${\""}');
34898184e3Sstheneval { F->${\"b\0nul"} };
35898184e3Ssthenok $@, "If the stash is in UTF-8, lookup is nul-clean";
36898184e3Ssthen
37898184e3Ssthenis(F->b, "UTF8 Stash&meth", "If both stash and method are in UTF-8, lookup works through explicitly named methods");
38898184e3Ssthenis(F->${\"b"}, "UTF8 Stash&meth", '..as does for ->${\""}');
39898184e3Sstheneval { F->${\"b\0nul"} };
40898184e3Ssthenok $@, "Even if both stash and method are in UTF-8, lookup is nul-clean";
41898184e3Ssthen
42898184e3Sstheneval { my $ref = \my $var; $ref->method };
43898184e3Ssthenlike $@, qr/Can't call method "method" on unblessed reference /u;
44898184e3Ssthen
45898184e3Ssthen{
46898184e3Ssthen    use utf8;
47898184e3Ssthen    use open qw( :utf8 :std );
48898184e3Ssthen
49898184e3Ssthen    my $e;
50898184e3Ssthen
51898184e3Ssthen    eval '$e = bless {}, "E::A"; E::A->foo()';
52898184e3Ssthen    like ($@, qr/^\QCan't locate object method "foo" via package "E::A" at/u);
53898184e3Ssthen    eval '$e = bless {}, "E::B"; $e->foo()';
54898184e3Ssthen    like ($@, qr/^\QCan't locate object method "foo" via package "E::B" at/u);
55898184e3Ssthen    eval 'E::C->foo()';
56898184e3Ssthen    like ($@, qr/^\QCan't locate object method "foo" via package "E::C" (perhaps /u);
57898184e3Ssthen
58898184e3Ssthen    eval 'UNIVERSAL->E::D::foo()';
59898184e3Ssthen    like ($@, qr/^\QCan't locate object method "foo" via package "E::D" (perhaps /u);
60898184e3Ssthen    eval 'my $e = bless {}, "UNIVERSAL"; $e->E::E::foo()';
61898184e3Ssthen    like ($@, qr/^\QCan't locate object method "foo" via package "E::E" (perhaps /u);
62898184e3Ssthen
63898184e3Ssthen    $e = bless {}, "E::F";  # force package to exist
64898184e3Ssthen    eval 'UNIVERSAL->E::F::foo()';
65898184e3Ssthen    like ($@, qr/^\QCan't locate object method "foo" via package "E::F" at/u);
66898184e3Ssthen    eval '$e = bless {}, "UNIVERSAL"; $e->E::F::foo()';
67898184e3Ssthen    like ($@, qr/^\QCan't locate object method "foo" via package "E::F" at/u);
68898184e3Ssthen}
69898184e3Ssthen
70898184e3Ssthenis(do { use utf8; use open qw( :utf8 :std ); eval 'Foo->boogie()';
71898184e3Ssthen	  $@ =~ /^\QCan't locate object method "boogie" via package "Foo" (perhaps /u ? 1 : $@}, 1);
72898184e3Ssthen
73898184e3Ssthen#This reimplements a bit of _fresh_perl() from test.pl, as we want to decode
74898184e3Ssthen#the output of that program before using it.
75898184e3SsthenSKIP: {
76898184e3Ssthen    skip_if_miniperl('no dynamic loading on miniperl, no Encode');
77898184e3Ssthen
78898184e3Ssthen    my $prog = q!use utf8; use open qw( :utf8 :std ); sub T::DESTROY { $x = $_[0]; } bless [], "T";!;
79898184e3Ssthen    utf8::decode($prog);
80898184e3Ssthen
81898184e3Ssthen    my $tmpfile = tempfile();
82898184e3Ssthen    my $runperl_args = {};
83898184e3Ssthen    $runperl_args->{progfile} = $tmpfile;
84898184e3Ssthen    $runperl_args->{stderr} = 1;
85898184e3Ssthen
86898184e3Ssthen    open TEST, '>', $tmpfile or die "Cannot open $tmpfile: $!";
87898184e3Ssthen
88898184e3Ssthen    print TEST $prog;
89898184e3Ssthen    close TEST or die "Cannot close $tmpfile: $!";
90898184e3Ssthen
91898184e3Ssthen    my $results = runperl(%$runperl_args);
92898184e3Ssthen
93898184e3Ssthen    require Encode;
94898184e3Ssthen    $results = Encode::decode("UTF-8", $results);
95898184e3Ssthen
96898184e3Ssthen    like($results,
97898184e3Ssthen            qr/DESTROY created new reference to dead object 'T' during global destruction./u,
98898184e3Ssthen            "DESTROY creating a new reference to the object generates a warning in UTF-8.");
99898184e3Ssthen}
100898184e3Ssthen
101898184e3Ssthenpackage Føø::Bær {
102898184e3Ssthen    sub new { bless {}, shift }
103898184e3Ssthen    sub nèw { bless {}, shift }
104898184e3Ssthen}
105898184e3Ssthen
106898184e3Ssthenlike( Føø::Bær::new("Føø::Bær"), qr/Føø::Bær=HASH/u, 'Can access new directly through a UTF-8 package.' );
107898184e3Ssthenlike( Føø::Bær->new, qr/Føø::Bær=HASH/u, 'Can access new as a method through a UTF-8 package.' );
108898184e3Ssthenlike( Føø::Bær::nèw("Føø::Bær"), qr/Føø::Bær=HASH/u, 'Can access nèw directly through a UTF-8 package.' );
109898184e3Ssthenlike( Føø::Bær->nèw, qr/Føø::Bær=HASH/u, 'Can access nèw as a method through a UTF-8 package.' );
110898184e3Ssthen
111898184e3Ssthenis( ref Føø::Bær->new, 'Føø::Bær');
112898184e3Ssthen
113898184e3Ssthenmy $new_ascii = "new";
114898184e3Ssthenmy $new_latin = "nèw";
115b8851fccSafresh1my $e_with_grave = byte_utf8a_to_utf8n("\303\250");
116*e0680481Safresh1my $e_with_grave_escaped= $e_with_grave=~s/\x{a8}/\\\\x\\{a8\\}/r;
117b8851fccSafresh1my $new_utf8  = "n${e_with_grave}w";
118b8851fccSafresh1my $newoct    = "n${e_with_grave}w";
119898184e3Ssthenutf8::decode($new_utf8);
120898184e3Ssthen
121898184e3Ssthenlike( Føø::Bær->$new_ascii, qr/Føø::Bær=HASH/u, "Can access \$new_ascii, [$new_ascii], stored in a scalar, as a method, through a UTF-8 package." );
122898184e3Ssthenlike( Føø::Bær->$new_latin, qr/Føø::Bær=HASH/u, "Can access \$new_latin, [$new_latin], stored in a scalar, as a method, through a UTF-8 package." );
123898184e3Ssthenlike( Føø::Bær->$new_utf8, qr/Føø::Bær=HASH/u, "Can access \$new_utf8, [$new_utf8], stored in a scalar, as a method, through a UTF-8 package." );
124898184e3Ssthen{
125898184e3Ssthen    local $@;
126898184e3Ssthen    eval { Føø::Bær->$newoct };
127*e0680481Safresh1    like($@, qr/Can't locate object method "n${e_with_grave_escaped}w" via package "Føø::Bær"/u,
128*e0680481Safresh1        "Can't access [$newoct], stored in a scalar, as a method through a UTF-8 package." );
129898184e3Ssthen}
130898184e3Ssthen
131898184e3Ssthen
132898184e3Ssthenlike( nèw Føø::Bær, qr/Føø::Bær=HASH/u, "Can access [nèw] as a method through a UTF-8 indirect object package.");
133898184e3Ssthen
134898184e3Ssthenmy $pkg_latin_1 = 'Føø::Bær';
135898184e3Ssthen
136898184e3Ssthenlike( $pkg_latin_1->new, qr/Føø::Bær=HASH/u, 'Can access new as a method when the UTF-8 package name is in a scalar.');
137898184e3Ssthenlike( $pkg_latin_1->nèw, qr/Føø::Bær=HASH/u, 'Can access nèw as a method when the UTF-8 package name is in a scalar.');
138898184e3Ssthen
139898184e3Ssthenlike( $pkg_latin_1->$new_ascii, qr/Føø::Bær=HASH/u, "Can access \$new_ascii, [$new_ascii], stored in a scalar, as a method, when the UTF-8 package name is also in a scalar.");
140898184e3Ssthenlike( $pkg_latin_1->$new_latin, qr/Føø::Bær=HASH/u, "Can access \$new_latin, [$new_latin], stored in a scalar, as a method, when the UTF-8 package name is also in a scalar.");
141898184e3Ssthenlike( $pkg_latin_1->$new_utf8, qr/Føø::Bær=HASH/u, "Can access \$new_utf8, [$new_utf8], stored in a scalar, as a method, when the UTF-8 package name is also in a scalar." );
142898184e3Ssthen{
143898184e3Ssthen    local $@;
144*e0680481Safresh1
145898184e3Ssthen    eval { $pkg_latin_1->$newoct };
146*e0680481Safresh1    like($@, qr/Can't locate object method "n${e_with_grave_escaped}w" via package "Føø::Bær"/u,
147*e0680481Safresh1        "Can't access [$newoct], stored in a scalar, as a method, when the UTF-8 package name is also in a scalar.");
148898184e3Ssthen}
149898184e3Ssthen
150898184e3Ssthenok !!Føø::Bær->can($new_ascii), "->can works for [$new_ascii]";
151898184e3Ssthenok !!Føø::Bær->can($new_latin), "->can works for [$new_latin]";
152898184e3Ssthenok((not !!Føø::Bær->can($newoct)), "->can doesn't work for [$newoct]");
153898184e3Ssthen
154898184e3Ssthenpackage クラス {
155898184e3Ssthen    sub new { bless {}, shift }
156898184e3Ssthen    sub ニュー { bless {}, shift }
157898184e3Ssthen}
158898184e3Ssthen
159898184e3Ssthenlike( クラス::new("クラス"), qr/クラス=HASH/u);
160898184e3Ssthenlike( クラス->new, qr/クラス=HASH/u);
161898184e3Ssthen
162898184e3Ssthenlike( クラス::ニュー("クラス"), qr/クラス=HASH/u);
163898184e3Ssthenlike( クラス->ニュー, qr/クラス=HASH/u);
164898184e3Ssthen
165898184e3Ssthenlike( ニュー クラス, qr/クラス=HASH/u, "Indirect object is UTF-8, as is the class.");
166898184e3Ssthen
167898184e3Ssthenis( ref クラス->new, 'クラス');
168898184e3Ssthenis( ref クラス->ニュー, 'クラス');
169898184e3Ssthen
170898184e3Ssthenpackage Foo::Bar {
171898184e3Ssthen    our @ISA = qw( Føø::Bær );
172898184e3Ssthen}
173898184e3Ssthen
174898184e3Ssthenpackage Foo::Bàz {
175898184e3Ssthen    use parent qw( -norequire Føø::Bær );
176898184e3Ssthen}
177898184e3Ssthen
178898184e3Ssthenpackage ฟọ::バッズ {
179898184e3Ssthen    use parent qw( -norequire Føø::Bær クラス );
180898184e3Ssthen}
181898184e3Ssthen
182898184e3Ssthenok(Foo::Bar->new, 'Simple inheritance works by pushing into @ISA,');
183898184e3Ssthenok(Foo::Bar->nèw, 'Even with UTF-8 methods');
184898184e3Ssthen
185898184e3Ssthenok(Foo::Bàz->new, 'Simple inheritance works with parent using -norequire,');
186898184e3Ssthenok(Foo::Bàz->nèw, 'Even with UTF-8 methods');
187898184e3Ssthen
188898184e3Ssthenok(ฟọ::バッズ->new, 'parent using -norequire, in a UTF-8 package.');
189898184e3Ssthenok(ฟọ::バッズ->nèw, 'Also works with UTF-8 methods');
190898184e3Ssthenok(ฟọ::バッズ->ニュー, 'Even methods from an UTF-8 parent');
191898184e3Ssthen
192b8851fccSafresh1BEGIN {no strict 'refs';
193b8851fccSafresh1       ++${"\xff::foo"} if $::IS_ASCII;
194b8851fccSafresh1       ++${"\xdf::foo"} if $::IS_EBCDIC;
195b8851fccSafresh1       } # autovivify the package
196898184e3Ssthenpackage ÿ {                                 # without UTF8
197898184e3Ssthen sub AUTOLOAD {
198b8851fccSafresh1  if ($::IS_ASCII) {
199898184e3Ssthen    ::is our $AUTOLOAD,
200898184e3Ssthen      "\xff::\x{100}", '$AUTOLOAD made from Latin1 package + UTF8 sub';
201898184e3Ssthen  }
202b8851fccSafresh1  else {
203b8851fccSafresh1    ::is our $AUTOLOAD,
204b8851fccSafresh1      "\xdf::\x{100}", '$AUTOLOAD made from Latin1 package + UTF8 sub';
205b8851fccSafresh1    }
206b8851fccSafresh1  }
207898184e3Ssthen}
208898184e3Ssthenÿ->${\"\x{100}"};
209898184e3Ssthen
210898184e3Ssthen#This test should go somewhere else.
211898184e3Ssthen#DATA was being generated in the wrong package.
212898184e3Ssthenpackage ʑ;
213898184e3Ssthenno strict 'refs';
214898184e3Ssthen
215898184e3Ssthen::ok( *{"ʑ::DATA"}{IO}, "DATA is generated in the right glob");
216898184e3Ssthen::ok !defined(*{"main::DATA"}{IO});
217898184e3Ssthen::is scalar <DATA>, "Some data\n";
218898184e3Ssthen
219898184e3Ssthen__DATA__
220898184e3SsthenSome data
221