Revert "convert all uses of Test::Exception to Test::Fatal."
[gitmo/Class-MOP.git] / t / 003_methods.t
CommitLineData
0882828e 1use strict;
2use warnings;
3
86a4d873 4use Test::More;
8371f3de 5use Test::Exception;
0882828e 6
16e960bd 7use Scalar::Util qw/reftype/;
2e13df84 8use Sub::Name;
16e960bd 9
7d682ca2 10use Class::MOP;
11use Class::MOP::Class;
12use Class::MOP::Method;
0882828e 13
49ca2e97 14{
15 # This package tries to test &has_method as exhaustively as
16 # possible. More corner cases are welcome :)
0882828e 17 package Foo;
49ca2e97 18
0882828e 19 # import a sub
49ca2e97 20 use Scalar::Util 'blessed';
21
823a5d31 22 sub pie;
23 sub cake ();
24
bfe4d0fc 25 use constant FOO_CONSTANT => 'Foo-CONSTANT';
49ca2e97 26
0882828e 27 # define a sub in package
49ca2e97 28 sub bar {'Foo::bar'}
60d90bbc 29 *baz = \&bar;
49ca2e97 30
46b23b44 31 # create something with the typeglob inside the package
49ca2e97 32 *baaz = sub {'Foo::baaz'};
bfe4d0fc 33
49ca2e97 34 { # method named with Sub::Name inside the package scope
bfe4d0fc 35 no strict 'refs';
49ca2e97 36 *{'Foo::floob'} = Sub::Name::subname 'floob' => sub {'!floob!'};
bfe4d0fc 37 }
38
60d90bbc 39 # We hateses the "used only once" warnings
49ca2e97 40 {
46b23b44 41 my $temp1 = \&Foo::baz;
49ca2e97 42 my $temp2 = \&Foo::baaz;
46b23b44 43 }
49ca2e97 44
16e960bd 45 package OinkyBoinky;
46 our @ISA = "Foo";
49ca2e97 47
48 sub elk {'OinkyBoinky::elk'}
60d90bbc 49
50 package main;
49ca2e97 51
60d90bbc 52 sub Foo::blah { $_[0]->Foo::baz() }
49ca2e97 53
60d90bbc 54 {
55 no strict 'refs';
49ca2e97 56 *{'Foo::bling'} = sub {'$$Bling$$'};
57 *{'Foo::bang'} = Sub::Name::subname 'Foo::bang' => sub {'!BANG!'};
58 *{'Foo::boom'} = Sub::Name::subname 'boom' => sub {'!BOOM!'};
59
60 eval "package Foo; sub evaled_foo { 'Foo::evaled_foo' }";
60d90bbc 61 }
0882828e 62}
63
bfe4d0fc 64my $Foo = Class::MOP::Class->initialize('Foo');
0882828e 65
130b7aff 66is join(' ', sort $Foo->get_method_list),
67 'FOO_CONSTANT baaz bang bar baz blah cake evaled_foo floob pie';
68
49ca2e97 69ok( $Foo->has_method('pie'), '... got the method stub pie' );
70ok( $Foo->has_method('cake'), '... got the constant method stub cake' );
823a5d31 71
49ca2e97 72my $foo = sub {'Foo::foo'};
0882828e 73
49ca2e97 74ok( !UNIVERSAL::isa( $foo, 'Class::MOP::Method' ),
75 '... our method is not yet blessed' );
de19f115 76
8371f3de 77lives_ok {
49ca2e97 78 $Foo->add_method( 'foo' => $foo );
8371f3de 79}
49ca2e97 80'... we added the method successfully';
0882828e 81
7855ddba 82my $foo_method = $Foo->get_method('foo');
de19f115 83
49ca2e97 84isa_ok( $foo_method, 'Class::MOP::Method' );
7855ddba 85
49ca2e97 86is( $foo_method->name, 'foo', '... got the right name for the method' );
87is( $foo_method->package_name, 'Foo',
88 '... got the right package name for the method' );
de19f115 89
49ca2e97 90ok( $Foo->has_method('foo'),
91 '... Foo->has_method(foo) (defined with Sub::Name)' );
bfe4d0fc 92
49ca2e97 93is( $Foo->get_method('foo')->body, $foo,
94 '... Foo->get_method(foo) == \&foo' );
95is( $Foo->get_method('foo')->execute, 'Foo::foo',
96 '... _method_foo->execute returns "Foo::foo"' );
97is( Foo->foo(), 'Foo::foo', '... Foo->foo() returns "Foo::foo"' );
bfe4d0fc 98
99# now check all our other items ...
100
49ca2e97 101ok( $Foo->has_method('FOO_CONSTANT'),
102 '... not Foo->has_method(FOO_CONSTANT) (defined w/ use constant)' );
103ok( !$Foo->has_method('bling'),
104 '... not Foo->has_method(bling) (defined in main:: using symbol tables (no Sub::Name))'
105);
46b23b44 106
49ca2e97 107ok( $Foo->has_method('bar'), '... Foo->has_method(bar) (defined in Foo)' );
108ok( $Foo->has_method('baz'),
109 '... Foo->has_method(baz) (typeglob aliased within Foo)' );
110ok( $Foo->has_method('baaz'),
111 '... Foo->has_method(baaz) (typeglob aliased within Foo)' );
112ok( $Foo->has_method('floob'),
113 '... Foo->has_method(floob) (defined in Foo:: using symbol tables and Sub::Name w/out package name)'
114);
115ok( $Foo->has_method('blah'),
116 '... Foo->has_method(blah) (defined in main:: using fully qualified package name)'
117);
118ok( $Foo->has_method('bang'),
119 '... Foo->has_method(bang) (defined in main:: using symbol tables and Sub::Name)'
120);
121ok( $Foo->has_method('evaled_foo'),
122 '... Foo->has_method(evaled_foo) (evaled in main::)' );
0882828e 123
16e960bd 124my $OinkyBoinky = Class::MOP::Class->initialize('OinkyBoinky');
125
49ca2e97 126ok( $OinkyBoinky->has_method('elk'),
127 "the method 'elk' is defined in OinkyBoinky" );
16e960bd 128
49ca2e97 129ok( !$OinkyBoinky->has_method('bar'),
130 "the method 'bar' is not defined in OinkyBoinky" );
16e960bd 131
49ca2e97 132ok( my $bar = $OinkyBoinky->find_method_by_name('bar'),
133 "but if you look in the inheritence chain then 'bar' does exist" );
16e960bd 134
49ca2e97 135is( reftype( $bar->body ), "CODE", "the returned value is a code ref" );
16e960bd 136
de19f115 137# calling get_method blessed them all
49ca2e97 138for my $method_name (
139 qw/baaz
140 bar
141 baz
142 floob
143 blah
144 bang
145 evaled_foo
146 FOO_CONSTANT/
147 ) {
148 isa_ok( $Foo->get_method($method_name), 'Class::MOP::Method' );
7855ddba 149 {
150 no strict 'refs';
49ca2e97 151 is( $Foo->get_method($method_name)->body,
152 \&{ 'Foo::' . $method_name },
153 '... body matches CODE ref in package for ' . $method_name );
7855ddba 154 }
155}
de19f115 156
49ca2e97 157for my $method_name (
158 qw/
159 bling
160 /
161 ) {
162 is( ref( $Foo->get_package_symbol( '&' . $method_name ) ), 'CODE',
163 '... got the __ANON__ methods' );
46b23b44 164 {
165 no strict 'refs';
49ca2e97 166 is( $Foo->get_package_symbol( '&' . $method_name ),
167 \&{ 'Foo::' . $method_name },
168 '... symbol matches CODE ref in package for ' . $method_name );
46b23b44 169 }
170}
171
49ca2e97 172ok( !$Foo->has_method('blessed'),
173 '... !Foo->has_method(blessed) (imported into Foo)' );
174ok( !$Foo->has_method('boom'),
175 '... !Foo->has_method(boom) (defined in main:: using symbol tables and Sub::Name w/out package name)'
176);
0882828e 177
49ca2e97 178ok( !$Foo->has_method('not_a_real_method'),
179 '... !Foo->has_method(not_a_real_method) (does not exist)' );
180is( $Foo->get_method('not_a_real_method'), undef,
181 '... Foo->get_method(not_a_real_method) == undef' );
bfe4d0fc 182
c9b8b7f9 183is_deeply(
184 [ sort $Foo->get_method_list ],
49ca2e97 185 [qw(FOO_CONSTANT baaz bang bar baz blah cake evaled_foo floob foo pie)],
186 '... got the right method list for Foo'
187);
c9b8b7f9 188
a5eca695 189is_deeply(
77ff94df 190 [ sort { $a->name cmp $b->name } $Foo->get_all_methods() ],
a5eca695 191 [
49ca2e97 192 map { $Foo->get_method($_) }
193 qw(
d7d3f3cb 194 FOO_CONSTANT
49ca2e97 195 baaz
196 bang
197 bar
198 baz
199 blah
c3b8d5ad 200 cake
49ca2e97 201 evaled_foo
202 floob
a5eca695 203 foo
c3b8d5ad 204 pie
49ca2e97 205 )
a5eca695 206 ],
49ca2e97 207 '... got the right list of applicable methods for Foo'
208);
a5eca695 209
49ca2e97 210is( $Foo->remove_method('foo')->body, $foo, '... removed the foo method' );
211ok( !$Foo->has_method('foo'),
212 '... !Foo->has_method(foo) we just removed it' );
8371f3de 213dies_ok { Foo->foo } '... cannot call Foo->foo because it is not there';
c9b8b7f9 214
215is_deeply(
216 [ sort $Foo->get_method_list ],
49ca2e97 217 [qw(FOO_CONSTANT baaz bang bar baz blah cake evaled_foo floob pie)],
218 '... got the right method list for Foo'
219);
c9b8b7f9 220
49ca2e97 221# ... test our class creator
bfe4d0fc 222
223my $Bar = Class::MOP::Class->create(
99b84658 224 package => 'Bar',
49ca2e97 225 superclasses => ['Foo'],
3976fb78 226 methods => {
49ca2e97 227 foo => sub {'Bar::foo'},
228 bar => sub {'Bar::bar'},
3976fb78 229 }
230);
49ca2e97 231isa_ok( $Bar, 'Class::MOP::Class' );
bfe4d0fc 232
49ca2e97 233ok( $Bar->has_method('foo'), '... Bar->has_method(foo)' );
234ok( $Bar->has_method('bar'), '... Bar->has_method(bar)' );
bfe4d0fc 235
49ca2e97 236is( Bar->foo, 'Bar::foo', '... Bar->foo == Bar::foo' );
237is( Bar->bar, 'Bar::bar', '... Bar->bar == Bar::bar' );
bfe4d0fc 238
8371f3de 239lives_ok {
49ca2e97 240 $Bar->add_method( 'foo' => sub {'Bar::foo v2'} );
8371f3de 241}
49ca2e97 242'... overwriting a method is fine';
bfe4d0fc 243
49ca2e97 244is_deeply( [ Class::MOP::get_code_info( $Bar->get_method('foo')->body ) ],
245 [ "Bar", "foo" ], "subname applied to anonymous method" );
bfa0d9f8 246
49ca2e97 247ok( $Bar->has_method('foo'), '... Bar-> (still) has_method(foo)' );
248is( Bar->foo, 'Bar::foo v2', '... Bar->foo == "Bar::foo v2"' );
c9b8b7f9 249
250is_deeply(
251 [ sort $Bar->get_method_list ],
49ca2e97 252 [qw(bar foo meta)],
253 '... got the right method list for Bar'
254);
255
a5eca695 256is_deeply(
77ff94df 257 [ sort { $a->name cmp $b->name } $Bar->get_all_methods() ],
a5eca695 258 [
77ff94df 259 $Foo->get_method('FOO_CONSTANT'),
260 $Foo->get_method('baaz'),
261 $Foo->get_method('bang'),
262 $Bar->get_method('bar'),
49ca2e97 263 (
264 map { $Foo->get_method($_) }
265 qw(
266 baz
267 blah
268 cake
269 evaled_foo
270 floob
271 )
272 ),
77ff94df 273 $Bar->get_method('foo'),
274 $Bar->get_method('meta'),
c3b8d5ad 275 $Foo->get_method('pie'),
a5eca695 276 ],
49ca2e97 277 '... got the right list of applicable methods for Bar'
278);
a5eca695 279
7d682ca2 280my $method = Class::MOP::Method->wrap(
281 name => 'objecty',
282 package_name => 'Whatever',
283 body => sub {q{I am an object, and I feel an object's pain}},
284);
285
286Bar->meta->add_method( $method->name, $method );
287
288my $new_method = Bar->meta->get_method('objecty');
a5eca695 289
49ca2e97 290isnt( $method, $new_method,
291 'add_method clones method objects as they are added' );
292is( $new_method->original_method, $method,
55039f82 293 '... the cloned method has the correct original method' )
294 or diag $new_method->dump;
c41df5a9 295
296{
c41df5a9 297 package CustomAccessor;
298
299 use Class::MOP;
300
301 my $meta = Class::MOP::Class->initialize(__PACKAGE__);
302
303 $meta->add_attribute(
304 foo => (
305 accessor => 'foo',
306 )
307 );
308
309 {
f675e129 310 no warnings 'redefine', 'once';
c41df5a9 311 *foo = sub {
312 my $self = shift;
313 $self->{custom_store} = $_[0];
314 };
315 }
316
317 $meta->add_around_method_modifier(
318 'foo',
319 sub {
320 my $orig = shift;
321 $orig->(@_);
322 }
323 );
324
5327fc78 325 sub new {
326 return bless {}, shift;
327 }
c41df5a9 328}
329
330{
331 my $o = CustomAccessor->new;
332 my $str = 'string';
333
334 $o->foo($str);
335
49ca2e97 336 is(
337 $o->{custom_store}, $str,
5327fc78 338 'Custom glob-assignment-created accessor still has method modifier'
49ca2e97 339 );
c41df5a9 340}
5327fc78 341
342{
343 # Since the sub reference below is not a closure, Perl caches it and uses
344 # the same reference each time through the loop. See RT #48985 for the
345 # bug.
346 foreach my $ns ( qw( Foo2 Bar2 Baz2 ) ) {
347 my $meta = Class::MOP::Class->create($ns);
348
349 my $sub = sub { };
350
351 $meta->add_method( 'foo', $sub );
352
353 my $method = $meta->get_method('foo');
354 ok( $method, 'Got the foo method back' );
355 }
356}
86a4d873 357
7f9ef61e 358{
359 package HasConstants;
360
adb2de7d 361 use constant FOO => 1;
362 use constant BAR => [];
363 use constant BAZ => {};
364 use constant UNDEF => undef;
7f9ef61e 365
366 sub quux {1}
367 sub thing {1}
368}
369
370my $HC = Class::MOP::Class->initialize('HasConstants');
371
372is_deeply(
373 [ sort $HC->get_method_list ],
adb2de7d 374 [qw( BAR BAZ FOO UNDEF quux thing )],
7f9ef61e 375 'get_method_list handles constants properly'
376);
377
378is_deeply(
379 [ sort map { $_->name } $HC->_get_local_methods ],
adb2de7d 380 [qw( BAR BAZ FOO UNDEF quux thing )],
7f9ef61e 381 '_get_local_methods handles constants properly'
382);
383
384
86a4d873 385done_testing;