1#!./perl -w 2 3# 4# test method calls and autoloading. 5# 6 7BEGIN { 8 chdir 't' if -d 't'; 9 require "./test.pl"; 10 set_up_inc( qw(. ../lib ../cpan/parent/lib) ); 11 require './charset_tools.pl'; 12} 13 14use strict; 15use utf8; 16use open qw( :utf8 :std ); 17no warnings 'once'; 18 19plan(tests => 62); 20 21#Can't use bless yet, as it might not be clean 22 23sub F::b { ::is shift, "F"; "UTF8 meth" } 24sub F::b { ::is shift, "F"; "UTF8 Stash" } 25sub F::b { ::is shift, "F"; "UTF8 Stash&meth" } 26 27is(F->b, "UTF8 meth", "If the method is in UTF-8, lookup works through explicitly named methods"); 28is(F->${\"b"}, "UTF8 meth", '..as does for ->${\""}'); 29eval { F->${\"b\0nul"} }; 30ok $@, "If the method is in UTF-8, lookup is nul-clean"; 31 32is(F->b, "UTF8 Stash", "If the stash is in UTF-8, lookup works through explicitly named methods"); 33is(F->${\"b"}, "UTF8 Stash", '..as does for ->${\""}'); 34eval { F->${\"b\0nul"} }; 35ok $@, "If the stash is in UTF-8, lookup is nul-clean"; 36 37is(F->b, "UTF8 Stash&meth", "If both stash and method are in UTF-8, lookup works through explicitly named methods"); 38is(F->${\"b"}, "UTF8 Stash&meth", '..as does for ->${\""}'); 39eval { F->${\"b\0nul"} }; 40ok $@, "Even if both stash and method are in UTF-8, lookup is nul-clean"; 41 42eval { my $ref = \my $var; $ref->method }; 43like $@, qr/Can't call method "method" on unblessed reference /u; 44 45{ 46 use utf8; 47 use open qw( :utf8 :std ); 48 49 my $e; 50 51 eval '$e = bless {}, "E::A"; E::A->foo()'; 52 like ($@, qr/^\QCan't locate object method "foo" via package "E::A" at/u); 53 eval '$e = bless {}, "E::B"; $e->foo()'; 54 like ($@, qr/^\QCan't locate object method "foo" via package "E::B" at/u); 55 eval 'E::C->foo()'; 56 like ($@, qr/^\QCan't locate object method "foo" via package "E::C" (perhaps /u); 57 58 eval 'UNIVERSAL->E::D::foo()'; 59 like ($@, qr/^\QCan't locate object method "foo" via package "E::D" (perhaps /u); 60 eval 'my $e = bless {}, "UNIVERSAL"; $e->E::E::foo()'; 61 like ($@, qr/^\QCan't locate object method "foo" via package "E::E" (perhaps /u); 62 63 $e = bless {}, "E::F"; # force package to exist 64 eval 'UNIVERSAL->E::F::foo()'; 65 like ($@, qr/^\QCan't locate object method "foo" via package "E::F" at/u); 66 eval '$e = bless {}, "UNIVERSAL"; $e->E::F::foo()'; 67 like ($@, qr/^\QCan't locate object method "foo" via package "E::F" at/u); 68} 69 70is(do { use utf8; use open qw( :utf8 :std ); eval 'Foo->boogie()'; 71 $@ =~ /^\QCan't locate object method "boogie" via package "Foo" (perhaps /u ? 1 : $@}, 1); 72 73#This reimplements a bit of _fresh_perl() from test.pl, as we want to decode 74#the output of that program before using it. 75SKIP: { 76 skip_if_miniperl('no dynamic loading on miniperl, no Encode'); 77 78 my $prog = q!use utf8; use open qw( :utf8 :std ); sub T::DESTROY { $x = $_[0]; } bless [], "T";!; 79 utf8::decode($prog); 80 81 my $tmpfile = tempfile(); 82 my $runperl_args = {}; 83 $runperl_args->{progfile} = $tmpfile; 84 $runperl_args->{stderr} = 1; 85 86 open TEST, '>', $tmpfile or die "Cannot open $tmpfile: $!"; 87 88 print TEST $prog; 89 close TEST or die "Cannot close $tmpfile: $!"; 90 91 my $results = runperl(%$runperl_args); 92 93 require Encode; 94 $results = Encode::decode("UTF-8", $results); 95 96 like($results, 97 qr/DESTROY created new reference to dead object 'T' during global destruction./u, 98 "DESTROY creating a new reference to the object generates a warning in UTF-8."); 99} 100 101package Føø::Bær { 102 sub new { bless {}, shift } 103 sub nèw { bless {}, shift } 104} 105 106like( Føø::Bær::new("Føø::Bær"), qr/Føø::Bær=HASH/u, 'Can access new directly through a UTF-8 package.' ); 107like( Føø::Bær->new, qr/Føø::Bær=HASH/u, 'Can access new as a method through a UTF-8 package.' ); 108like( Føø::Bær::nèw("Føø::Bær"), qr/Føø::Bær=HASH/u, 'Can access nèw directly through a UTF-8 package.' ); 109like( Føø::Bær->nèw, qr/Føø::Bær=HASH/u, 'Can access nèw as a method through a UTF-8 package.' ); 110 111is( ref Føø::Bær->new, 'Føø::Bær'); 112 113my $new_ascii = "new"; 114my $new_latin = "nèw"; 115my $e_with_grave = byte_utf8a_to_utf8n("\303\250"); 116my $e_with_grave_escaped= $e_with_grave=~s/\x{a8}/\\\\x\\{a8\\}/r; 117my $new_utf8 = "n${e_with_grave}w"; 118my $newoct = "n${e_with_grave}w"; 119utf8::decode($new_utf8); 120 121like( 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." ); 122like( 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." ); 123like( 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." ); 124{ 125 local $@; 126 eval { Føø::Bær->$newoct }; 127 like($@, qr/Can't locate object method "n${e_with_grave_escaped}w" via package "Føø::Bær"/u, 128 "Can't access [$newoct], stored in a scalar, as a method through a UTF-8 package." ); 129} 130 131 132like( 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."); 133 134my $pkg_latin_1 = 'Føø::Bær'; 135 136like( $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.'); 137like( $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.'); 138 139like( $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."); 140like( $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."); 141like( $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." ); 142{ 143 local $@; 144 145 eval { $pkg_latin_1->$newoct }; 146 like($@, qr/Can't locate object method "n${e_with_grave_escaped}w" via package "Føø::Bær"/u, 147 "Can't access [$newoct], stored in a scalar, as a method, when the UTF-8 package name is also in a scalar."); 148} 149 150ok !!Føø::Bær->can($new_ascii), "->can works for [$new_ascii]"; 151ok !!Føø::Bær->can($new_latin), "->can works for [$new_latin]"; 152ok((not !!Føø::Bær->can($newoct)), "->can doesn't work for [$newoct]"); 153 154package クラス { 155 sub new { bless {}, shift } 156 sub ニュー { bless {}, shift } 157} 158 159like( クラス::new("クラス"), qr/クラス=HASH/u); 160like( クラス->new, qr/クラス=HASH/u); 161 162like( クラス::ニュー("クラス"), qr/クラス=HASH/u); 163like( クラス->ニュー, qr/クラス=HASH/u); 164 165like( ニュー クラス, qr/クラス=HASH/u, "Indirect object is UTF-8, as is the class."); 166 167is( ref クラス->new, 'クラス'); 168is( ref クラス->ニュー, 'クラス'); 169 170package Foo::Bar { 171 our @ISA = qw( Føø::Bær ); 172} 173 174package Foo::Bàz { 175 use parent qw( -norequire Føø::Bær ); 176} 177 178package ฟọ::バッズ { 179 use parent qw( -norequire Føø::Bær クラス ); 180} 181 182ok(Foo::Bar->new, 'Simple inheritance works by pushing into @ISA,'); 183ok(Foo::Bar->nèw, 'Even with UTF-8 methods'); 184 185ok(Foo::Bàz->new, 'Simple inheritance works with parent using -norequire,'); 186ok(Foo::Bàz->nèw, 'Even with UTF-8 methods'); 187 188ok(ฟọ::バッズ->new, 'parent using -norequire, in a UTF-8 package.'); 189ok(ฟọ::バッズ->nèw, 'Also works with UTF-8 methods'); 190ok(ฟọ::バッズ->ニュー, 'Even methods from an UTF-8 parent'); 191 192BEGIN {no strict 'refs'; 193 ++${"\xff::foo"} if $::IS_ASCII; 194 ++${"\xdf::foo"} if $::IS_EBCDIC; 195 } # autovivify the package 196package ÿ { # without UTF8 197 sub AUTOLOAD { 198 if ($::IS_ASCII) { 199 ::is our $AUTOLOAD, 200 "\xff::\x{100}", '$AUTOLOAD made from Latin1 package + UTF8 sub'; 201 } 202 else { 203 ::is our $AUTOLOAD, 204 "\xdf::\x{100}", '$AUTOLOAD made from Latin1 package + UTF8 sub'; 205 } 206 } 207} 208ÿ->${\"\x{100}"}; 209 210#This test should go somewhere else. 211#DATA was being generated in the wrong package. 212package ʑ; 213no strict 'refs'; 214 215::ok( *{"ʑ::DATA"}{IO}, "DATA is generated in the right glob"); 216::ok !defined(*{"main::DATA"}{IO}); 217::is scalar <DATA>, "Some data\n"; 218 219__DATA__ 220Some data 221