Fixed bug in the immutable constructor. It now redispatches to
[gitmo/Mouse.git] / t / 030_roles / failing / 005_role_conflict_detection.t
CommitLineData
67199842 1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
6use Test::More tests => 87; # it's really 124 with kolibrie's tests;
7use Test::Exception;
8
9=pod
10
11Mutually recursive roles.
12
13=cut
14
15{
16 package Role::Foo;
17 use Mouse::Role;
18
19 requires 'foo';
20
21 sub bar { 'Role::Foo::bar' }
22
23 package Role::Bar;
24 use Mouse::Role;
25
26 requires 'bar';
27
28 sub foo { 'Role::Bar::foo' }
29}
30
31{
32 package My::Test1;
33 use Mouse;
34
35 ::lives_ok {
36 with 'Role::Foo', 'Role::Bar';
37 } '... our mutually recursive roles combine okay';
38
39 package My::Test2;
40 use Mouse;
41
42 ::lives_ok {
43 with 'Role::Bar', 'Role::Foo';
44 } '... our mutually recursive roles combine okay (no matter what order)';
45}
46
47my $test1 = My::Test1->new;
48isa_ok($test1, 'My::Test1');
49
50ok($test1->does('Role::Foo'), '... $test1 does Role::Foo');
51ok($test1->does('Role::Bar'), '... $test1 does Role::Bar');
52
53can_ok($test1, 'foo');
54can_ok($test1, 'bar');
55
56is($test1->foo, 'Role::Bar::foo', '... $test1->foo worked');
57is($test1->bar, 'Role::Foo::bar', '... $test1->bar worked');
58
59my $test2 = My::Test2->new;
60isa_ok($test2, 'My::Test2');
61
62ok($test2->does('Role::Foo'), '... $test2 does Role::Foo');
63ok($test2->does('Role::Bar'), '... $test2 does Role::Bar');
64
65can_ok($test2, 'foo');
66can_ok($test2, 'bar');
67
68is($test2->foo, 'Role::Bar::foo', '... $test2->foo worked');
69is($test2->bar, 'Role::Foo::bar', '... $test2->bar worked');
70
71# check some meta-stuff
72
73TODO: { todo_skip "Mouse: not yet implemented" => 4;
74ok(Role::Foo->meta->has_method('bar'), '... it still has the bar method');
75ok(Role::Foo->meta->requires_method('foo'), '... it still has the required foo method');
76
77ok(Role::Bar->meta->has_method('foo'), '... it still has the foo method');
78ok(Role::Bar->meta->requires_method('bar'), '... it still has the required bar method');
79}
80
81=pod
82
83Role method conflicts
84
85=cut
86
87{
88 package Role::Bling;
89 use Mouse::Role;
90
91 sub bling { 'Role::Bling::bling' }
92
93 package Role::Bling::Bling;
94 use Mouse::Role;
95
96 sub bling { 'Role::Bling::Bling::bling' }
97}
98
99{
100 package My::Test3;
101 use Mouse;
102
103 ::throws_ok {
104 with 'Role::Bling', 'Role::Bling::Bling';
105 } qr/requires the method \'bling\' to be implemented/, '... role methods conflicted and method was required';
106
107 package My::Test4;
108 use Mouse;
109
110 ::lives_ok {
111 with 'Role::Bling';
112 with 'Role::Bling::Bling';
113 } '... role methods didnt conflict when manually combined';
114
115 package My::Test5;
116 use Mouse;
117
118 ::lives_ok {
119 with 'Role::Bling::Bling';
120 with 'Role::Bling';
121 } '... role methods didnt conflict when manually combined (in opposite order)';
122
123 package My::Test6;
124 use Mouse;
125
126 ::lives_ok {
127 with 'Role::Bling::Bling', 'Role::Bling';
128 } '... role methods didnt conflict when manually resolved';
129
130 sub bling { 'My::Test6::bling' }
131}
132
133TODO: { todo_skip "Mouse: not yet implemented" => 4;
134ok(!My::Test3->meta->has_method('bling'), '... we didnt get any methods in the conflict');
135ok(My::Test4->meta->has_method('bling'), '... we did get the method when manually dealt with');
136ok(My::Test5->meta->has_method('bling'), '... we did get the method when manually dealt with');
137ok(My::Test6->meta->has_method('bling'), '... we did get the method when manually dealt with');
138}
139
140ok(!My::Test3->does('Role::Bling'), '... our class does() the correct roles');
141ok(!My::Test3->does('Role::Bling::Bling'), '... our class does() the correct roles');
142ok(My::Test4->does('Role::Bling'), '... our class does() the correct roles');
143ok(My::Test4->does('Role::Bling::Bling'), '... our class does() the correct roles');
144ok(My::Test5->does('Role::Bling'), '... our class does() the correct roles');
145ok(My::Test5->does('Role::Bling::Bling'), '... our class does() the correct roles');
146ok(My::Test6->does('Role::Bling'), '... our class does() the correct roles');
147ok(My::Test6->does('Role::Bling::Bling'), '... our class does() the correct roles');
148
149is(My::Test4->bling, 'Role::Bling::bling', '... and we got the first method that was added');
150is(My::Test5->bling, 'Role::Bling::Bling::bling', '... and we got the first method that was added');
151is(My::Test6->bling, 'My::Test6::bling', '... and we got the local method');
152
153# check how this affects role compostion
154
155{
156 package Role::Bling::Bling::Bling;
157 use Mouse::Role;
158
159 with 'Role::Bling::Bling';
160
161 sub bling { 'Role::Bling::Bling::Bling::bling' }
162}
163
164TODO: { todo_skip "Mouse: not yet implemented" => 1;
165ok(Role::Bling::Bling->meta->has_method('bling'), '... still got the bling method in Role::Bling::Bling');
166 }
167ok(Role::Bling::Bling->meta->does_role('Role::Bling::Bling'), '... our role correctly does() the other role');
168TODO: { todo_skip "Mouse: not yet implemented" => 2;
169ok(Role::Bling::Bling::Bling->meta->has_method('bling'), '... dont have the bling method in Role::Bling::Bling::Bling');
170is(Role::Bling::Bling::Bling->meta->get_method('bling')->(),
171 'Role::Bling::Bling::Bling::bling',
172 '... still got the bling method in Role::Bling::Bling::Bling');
173}
174
175=pod
176
177Role attribute conflicts
178
179=cut
180
181{
182 package Role::Boo;
183 use Mouse::Role;
184
185 has 'ghost' => (is => 'ro', default => 'Role::Boo::ghost');
186
187 package Role::Boo::Hoo;
188 use Mouse::Role;
189
190 has 'ghost' => (is => 'ro', default => 'Role::Boo::Hoo::ghost');
191}
192
193{
194 package My::Test7;
195 use Mouse;
196
197 ::throws_ok {
198 with 'Role::Boo', 'Role::Boo::Hoo';
199 } qr/We have encountered an attribute conflict/,
200 '... role attrs conflicted and method was required';
201
202 package My::Test8;
203 use Mouse;
204
205 ::lives_ok {
206 with 'Role::Boo';
207 with 'Role::Boo::Hoo';
208 } '... role attrs didnt conflict when manually combined';
209
210 package My::Test9;
211 use Mouse;
212
213 ::lives_ok {
214 with 'Role::Boo::Hoo';
215 with 'Role::Boo';
216 } '... role attrs didnt conflict when manually combined';
217
218 package My::Test10;
219 use Mouse;
220
221 has 'ghost' => (is => 'ro', default => 'My::Test10::ghost');
222
223 ::throws_ok {
224 with 'Role::Boo', 'Role::Boo::Hoo';
225 } qr/We have encountered an attribute conflict/,
226 '... role attrs conflicted and cannot be manually disambiguted';
227
228}
229
230ok(!My::Test7->meta->has_attribute('ghost'), '... we didnt get any attributes in the conflict');
231ok(My::Test8->meta->has_attribute('ghost'), '... we did get an attributes when manually composed');
232ok(My::Test9->meta->has_attribute('ghost'), '... we did get an attributes when manually composed');
233ok(My::Test10->meta->has_attribute('ghost'), '... we did still have an attribute ghost (conflict does not mess with class)');
234
235ok(!My::Test7->does('Role::Boo'), '... our class does() the correct roles');
236ok(!My::Test7->does('Role::Boo::Hoo'), '... our class does() the correct roles');
237ok(My::Test8->does('Role::Boo'), '... our class does() the correct roles');
238ok(My::Test8->does('Role::Boo::Hoo'), '... our class does() the correct roles');
239ok(My::Test9->does('Role::Boo'), '... our class does() the correct roles');
240ok(My::Test9->does('Role::Boo::Hoo'), '... our class does() the correct roles');
241ok(!My::Test10->does('Role::Boo'), '... our class does() the correct roles');
242ok(!My::Test10->does('Role::Boo::Hoo'), '... our class does() the correct roles');
243
244can_ok('My::Test8', 'ghost');
245can_ok('My::Test9', 'ghost');
246can_ok('My::Test10', 'ghost');
247
248is(My::Test8->new->ghost, 'Role::Boo::ghost', '... got the expected default attr value');
249is(My::Test9->new->ghost, 'Role::Boo::Hoo::ghost', '... got the expected default attr value');
250is(My::Test10->new->ghost, 'My::Test10::ghost', '... got the expected default attr value');
251
252=pod
253
254Role override method conflicts
255
256=cut
257
258{
259 package Role::Plot;
260 use Mouse::Role;
261
262 override 'twist' => sub {
263 super() . ' -> Role::Plot::twist';
264 };
265
266 package Role::Truth;
267 use Mouse::Role;
268
269 override 'twist' => sub {
270 super() . ' -> Role::Truth::twist';
271 };
272}
273
274{
275 package My::Test::Base;
276 use Mouse;
277
278 sub twist { 'My::Test::Base::twist' }
279
280 package My::Test11;
281 use Mouse;
282
283 extends 'My::Test::Base';
284
285 ::lives_ok {
286 with 'Role::Truth';
287 } '... composed the role with override okay';
288
289 package My::Test12;
290 use Mouse;
291
292 extends 'My::Test::Base';
293
294 ::lives_ok {
295 with 'Role::Plot';
296 } '... composed the role with override okay';
297
298 package My::Test13;
299 use Mouse;
300
301 ::dies_ok {
302 with 'Role::Plot';
303 } '... cannot compose it because we have no superclass';
304
305 package My::Test14;
306 use Mouse;
307
308 extends 'My::Test::Base';
309
310 ::throws_ok {
311 with 'Role::Plot', 'Role::Truth';
312 } qr/Two \'override\' methods of the same name encountered/,
313 '... cannot compose it because we have no superclass';
314}
315
316ok(My::Test11->meta->has_method('twist'), '... the twist method has been added');
317ok(My::Test12->meta->has_method('twist'), '... the twist method has been added');
318ok(!My::Test13->meta->has_method('twist'), '... the twist method has not been added');
319ok(!My::Test14->meta->has_method('twist'), '... the twist method has not been added');
320
321ok(!My::Test11->does('Role::Plot'), '... our class does() the correct roles');
322ok(My::Test11->does('Role::Truth'), '... our class does() the correct roles');
323ok(!My::Test12->does('Role::Truth'), '... our class does() the correct roles');
324ok(My::Test12->does('Role::Plot'), '... our class does() the correct roles');
325ok(!My::Test13->does('Role::Plot'), '... our class does() the correct roles');
326ok(!My::Test14->does('Role::Truth'), '... our class does() the correct roles');
327ok(!My::Test14->does('Role::Plot'), '... our class does() the correct roles');
328
329is(My::Test11->twist(), 'My::Test::Base::twist -> Role::Truth::twist', '... got the right method return');
330is(My::Test12->twist(), 'My::Test::Base::twist -> Role::Plot::twist', '... got the right method return');
331ok(!My::Test13->can('twist'), '... no twist method here at all');
332is(My::Test14->twist(), 'My::Test::Base::twist', '... got the right method return (from superclass)');
333
334{
335 package Role::Reality;
336 use Mouse::Role;
337
338 ::throws_ok {
339 with 'Role::Plot';
340 } qr/A local method of the same name as been found/,
341 '... could not compose roles here, it dies';
342
343 sub twist {
344 'Role::Reality::twist';
345 }
346}
347
348ok(Role::Reality->meta->has_method('twist'), '... the twist method has not been added');
4e145304 349ok(!Role::Reality->meta->does_role('Role::Plot'), '... our role does() the correct roles');
67199842 350is(Role::Reality->meta->get_method('twist')->(),
351 'Role::Reality::twist',
352 '... the twist method returns the right value');
353
354=pod
355
356Role conflicts between attributes and methods
357
358[15:23] <kolibrie> when class defines method and role defines method, class wins
359[15:24] <kolibrie> when class 'has' method and role defines method, class wins
360[15:24] <kolibrie> when class defines method and role 'has' method, role wins
361[15:24] <kolibrie> when class 'has' method and role 'has' method, role wins
362[15:24] <kolibrie> which means when class 'has' method and two roles 'has' method, no tiebreak is detected
363[15:24] <perigrin> this is with role and has declaration in the exact same order in every case?
364[15:25] <kolibrie> yes
365[15:25] <perigrin> interesting
366[15:25] <kolibrie> that's what I thought
367[15:26] <kolibrie> does that sound like something I should write a test for?
368[15:27] <perigrin> stevan, ping?
369[15:27] <perigrin> I'm not sure what the right answer for composition is.
370[15:27] <perigrin> who should win
371[15:27] <perigrin> if I were to guess I'd say the class should always win.
372[15:27] <kolibrie> that would be my guess, but I thought I would ask to make sure
373[15:29] <stevan> kolibrie: please write a test
374[15:29] <stevan> I am not exactly sure who should win either,.. but I suspect it is not working correctly right now
375[15:29] <stevan> I know exactly why it is doing what it is doing though
376
377Now I have to decide actually what happens, and how to fix it.
378- SL
379
380{
381 package Role::Method;
382 use Mouse::Role;
383
384 sub ghost { 'Role::Method::ghost' }
385
386 package Role::Method2;
387 use Mouse::Role;
388
389 sub ghost { 'Role::Method2::ghost' }
390
391 package Role::Attribute;
392 use Mouse::Role;
393
394 has 'ghost' => (is => 'ro', default => 'Role::Attribute::ghost');
395
396 package Role::Attribute2;
397 use Mouse::Role;
398
399 has 'ghost' => (is => 'ro', default => 'Role::Attribute2::ghost');
400}
401
402{
403 package My::Test15;
404 use Mouse;
405
406 ::lives_ok {
407 with 'Role::Method';
408 } '... composed the method role into the method class';
409
410 sub ghost { 'My::Test15::ghost' }
411
412 package My::Test16;
413 use Mouse;
414
415 ::lives_ok {
416 with 'Role::Method';
417 } '... composed the method role into the attribute class';
418
419 has 'ghost' => (is => 'ro', default => 'My::Test16::ghost');
420
421 package My::Test17;
422 use Mouse;
423
424 ::lives_ok {
425 with 'Role::Attribute';
426 } '... composed the attribute role into the method class';
427
428 sub ghost { 'My::Test17::ghost' }
429
430 package My::Test18;
431 use Mouse;
432
433 ::lives_ok {
434 with 'Role::Attribute';
435 } '... composed the attribute role into the attribute class';
436
437 has 'ghost' => (is => 'ro', default => 'My::Test18::ghost');
438
439 package My::Test19;
440 use Mouse;
441
442 ::lives_ok {
443 with 'Role::Method', 'Role::Method2';
444 } '... composed method roles into class with method tiebreaker';
445
446 sub ghost { 'My::Test19::ghost' }
447
448 package My::Test20;
449 use Mouse;
450
451 ::lives_ok {
452 with 'Role::Method', 'Role::Method2';
453 } '... composed method roles into class with attribute tiebreaker';
454
455 has 'ghost' => (is => 'ro', default => 'My::Test20::ghost');
456
457 package My::Test21;
458 use Mouse;
459
460 ::lives_ok {
461 with 'Role::Attribute', 'Role::Attribute2';
462 } '... composed attribute roles into class with method tiebreaker';
463
464 sub ghost { 'My::Test21::ghost' }
465
466 package My::Test22;
467 use Mouse;
468
469 ::lives_ok {
470 with 'Role::Attribute', 'Role::Attribute2';
471 } '... composed attribute roles into class with attribute tiebreaker';
472
473 has 'ghost' => (is => 'ro', default => 'My::Test22::ghost');
474
475 package My::Test23;
476 use Mouse;
477
478 ::lives_ok {
479 with 'Role::Method', 'Role::Attribute';
480 } '... composed method and attribute role into class with method tiebreaker';
481
482 sub ghost { 'My::Test23::ghost' }
483
484 package My::Test24;
485 use Mouse;
486
487 ::lives_ok {
488 with 'Role::Method', 'Role::Attribute';
489 } '... composed method and attribute role into class with attribute tiebreaker';
490
491 has 'ghost' => (is => 'ro', default => 'My::Test24::ghost');
492
493 package My::Test25;
494 use Mouse;
495
496 ::lives_ok {
497 with 'Role::Attribute', 'Role::Method';
498 } '... composed attribute and method role into class with method tiebreaker';
499
500 sub ghost { 'My::Test25::ghost' }
501
502 package My::Test26;
503 use Mouse;
504
505 ::lives_ok {
506 with 'Role::Attribute', 'Role::Method';
507 } '... composed attribute and method role into class with attribute tiebreaker';
508
509 has 'ghost' => (is => 'ro', default => 'My::Test26::ghost');
510}
511
512my $test15 = My::Test15->new;
513isa_ok($test15, 'My::Test15');
514is($test15->ghost, 'My::Test15::ghost', '... we access the method from the class and ignore the role method');
515
516my $test16 = My::Test16->new;
517isa_ok($test16, 'My::Test16');
518is($test16->ghost, 'My::Test16::ghost', '... we access the attribute from the class and ignore the role method');
519
520my $test17 = My::Test17->new;
521isa_ok($test17, 'My::Test17');
522is($test17->ghost, 'My::Test17::ghost', '... we access the method from the class and ignore the role attribute');
523
524my $test18 = My::Test18->new;
525isa_ok($test18, 'My::Test18');
526is($test18->ghost, 'My::Test18::ghost', '... we access the attribute from the class and ignore the role attribute');
527
528my $test19 = My::Test19->new;
529isa_ok($test19, 'My::Test19');
530is($test19->ghost, 'My::Test19::ghost', '... we access the method from the class and ignore the role methods');
531
532my $test20 = My::Test20->new;
533isa_ok($test20, 'My::Test20');
534is($test20->ghost, 'My::Test20::ghost', '... we access the attribute from the class and ignore the role methods');
535
536my $test21 = My::Test21->new;
537isa_ok($test21, 'My::Test21');
538is($test21->ghost, 'My::Test21::ghost', '... we access the method from the class and ignore the role attributes');
539
540my $test22 = My::Test22->new;
541isa_ok($test22, 'My::Test22');
542is($test22->ghost, 'My::Test22::ghost', '... we access the attribute from the class and ignore the role attributes');
543
544my $test23 = My::Test23->new;
545isa_ok($test23, 'My::Test23');
546is($test23->ghost, 'My::Test23::ghost', '... we access the method from the class and ignore the role method and attribute');
547
548my $test24 = My::Test24->new;
549isa_ok($test24, 'My::Test24');
550is($test24->ghost, 'My::Test24::ghost', '... we access the attribute from the class and ignore the role method and attribute');
551
552my $test25 = My::Test25->new;
553isa_ok($test25, 'My::Test25');
554is($test25->ghost, 'My::Test25::ghost', '... we access the method from the class and ignore the role attribute and method');
555
556my $test26 = My::Test26->new;
557isa_ok($test26, 'My::Test26');
558is($test26->ghost, 'My::Test26::ghost', '... we access the attribute from the class and ignore the role attribute and method');
559
560=cut