foo
[gitmo/Moose.git] / t / 044_role_conflict_detection.t
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use Test::More tests => 90;
7 use Test::Exception;
8
9 BEGIN {
10     use_ok('Moose');
11     use_ok('Moose::Role');    
12 }
13
14 =pod
15
16 Mutually recursive roles.
17
18 =cut
19
20 {
21     package Role::Foo;
22     use Moose::Role;
23
24     requires 'foo';
25     
26     sub bar { 'Role::Foo::bar' }
27     
28     package Role::Bar;
29     use Moose::Role;
30     
31     requires 'bar';
32     
33     sub foo { 'Role::Bar::foo' }    
34 }
35
36 {
37     package My::Test1;
38     use Moose;
39     
40     ::lives_ok {
41         with 'Role::Foo', 'Role::Bar';
42     } '... our mutually recursive roles combine okay';
43     
44     package My::Test2;
45     use Moose;
46     
47     ::lives_ok {
48         with 'Role::Bar', 'Role::Foo';
49     } '... our mutually recursive roles combine okay (no matter what order)';    
50 }
51
52 my $test1 = My::Test1->new;
53 isa_ok($test1, 'My::Test1');
54
55 ok($test1->does('Role::Foo'), '... $test1 does Role::Foo');
56 ok($test1->does('Role::Bar'), '... $test1 does Role::Bar');
57
58 can_ok($test1, 'foo');
59 can_ok($test1, 'bar');
60
61 is($test1->foo, 'Role::Bar::foo', '... $test1->foo worked');
62 is($test1->bar, 'Role::Foo::bar', '... $test1->bar worked');
63
64 my $test2 = My::Test2->new;
65 isa_ok($test2, 'My::Test2');
66
67 ok($test2->does('Role::Foo'), '... $test2 does Role::Foo');
68 ok($test2->does('Role::Bar'), '... $test2 does Role::Bar');
69
70 can_ok($test2, 'foo');
71 can_ok($test2, 'bar');
72
73 is($test2->foo, 'Role::Bar::foo', '... $test2->foo worked');
74 is($test2->bar, 'Role::Foo::bar', '... $test2->bar worked');
75
76 # check some meta-stuff
77
78 ok(Role::Foo->meta->has_method('bar'), '... it still has the bar method');
79 ok(Role::Foo->meta->requires_method('foo'), '... it still has the required foo method');
80
81 ok(Role::Bar->meta->has_method('foo'), '... it still has the foo method');
82 ok(Role::Bar->meta->requires_method('bar'), '... it still has the required bar method');
83
84 =pod
85
86 Role method conflicts
87
88 =cut
89
90 {
91     package Role::Bling;
92     use Moose::Role;
93     
94     sub bling { 'Role::Bling::bling' }
95     
96     package Role::Bling::Bling;
97     use Moose::Role;
98     
99     sub bling { 'Role::Bling::Bling::bling' }    
100 }
101
102 {
103     package My::Test3;
104     use Moose;
105     
106     ::throws_ok {
107         with 'Role::Bling', 'Role::Bling::Bling';
108     } qr/requires the method \'bling\' to be implemented/, '... role methods conflicted and method was required';
109     
110     package My::Test4;
111     use Moose;
112     
113     ::lives_ok {
114         with 'Role::Bling';
115         with 'Role::Bling::Bling';
116     } '... role methods didnt conflict when manually combined';    
117     
118     package My::Test5;
119     use Moose;
120     
121     ::lives_ok {
122         with 'Role::Bling::Bling';
123         with 'Role::Bling';
124     } '... role methods didnt conflict when manually combined (in opposite order)';    
125     
126     package My::Test6;
127     use Moose;
128     
129     ::lives_ok {
130         with 'Role::Bling::Bling', 'Role::Bling';
131     } '... role methods didnt conflict when manually resolved';    
132     
133     sub bling { 'My::Test6::bling' }
134 }
135
136 ok(!My::Test3->meta->has_method('bling'), '... we didnt get any methods in the conflict');
137 ok(My::Test4->meta->has_method('bling'), '... we did get the method when manually dealt with');
138 ok(My::Test5->meta->has_method('bling'), '... we did get the method when manually dealt with');
139 ok(My::Test6->meta->has_method('bling'), '... we did get the method when manually dealt with');
140
141 ok(!My::Test3->does('Role::Bling'), '... our class does() the correct roles');
142 ok(!My::Test3->does('Role::Bling::Bling'), '... our class does() the correct roles');
143 ok(My::Test4->does('Role::Bling'), '... our class does() the correct roles');
144 ok(My::Test4->does('Role::Bling::Bling'), '... our class does() the correct roles');
145 ok(My::Test5->does('Role::Bling'), '... our class does() the correct roles');
146 ok(My::Test5->does('Role::Bling::Bling'), '... our class does() the correct roles');
147 ok(My::Test6->does('Role::Bling'), '... our class does() the correct roles');
148 ok(My::Test6->does('Role::Bling::Bling'), '... our class does() the correct roles');
149
150 is(My::Test4->bling, 'Role::Bling::bling', '... and we got the first method that was added');
151 is(My::Test5->bling, 'Role::Bling::Bling::bling', '... and we got the first method that was added');
152 is(My::Test6->bling, 'My::Test6::bling', '... and we got the local method');
153
154 # check how this affects role compostion
155
156 {
157     package Role::Bling::Bling::Bling;
158     use Moose::Role;
159     
160     with 'Role::Bling::Bling';
161     
162     sub bling { 'Role::Bling::Bling::Bling::bling' }    
163 }
164
165 ok(Role::Bling::Bling->meta->has_method('bling'), '... still got the bling method in Role::Bling::Bling');
166 ok(Role::Bling::Bling->meta->does_role('Role::Bling::Bling'), '... our role correctly does() the other role');
167 ok(Role::Bling::Bling::Bling->meta->has_method('bling'), '... still got the bling method in Role::Bling::Bling::Bling');
168 is(Role::Bling::Bling::Bling->meta->get_method('bling')->(), 
169     'Role::Bling::Bling::Bling::bling',
170     '... still got the bling method in Role::Bling::Bling::Bling');
171
172 =pod
173
174 Role attribute conflicts
175
176 =cut
177
178 {
179     package Role::Boo;
180     use Moose::Role;
181     
182     has 'ghost' => (is => 'ro', default => 'Role::Boo::ghost');
183     
184     package Role::Boo::Hoo;
185     use Moose::Role;
186     
187     has 'ghost' => (is => 'ro', default => 'Role::Boo::Hoo::ghost');
188 }
189
190 {
191     package My::Test7;
192     use Moose;
193     
194     ::throws_ok {
195         with 'Role::Boo', 'Role::Boo::Hoo';
196     } qr/Role \'Role::Boo::Hoo\' has encountered an attribute conflict/, 
197       '... role attrs conflicted and method was required';
198
199     package My::Test8;
200     use Moose;
201
202     ::lives_ok {
203         with 'Role::Boo';
204         with 'Role::Boo::Hoo';
205     } '... role attrs didnt conflict when manually combined';
206     
207     package My::Test9;
208     use Moose;
209
210     ::lives_ok {
211         with 'Role::Boo::Hoo';
212         with 'Role::Boo';
213     } '... role attrs didnt conflict when manually combined';    
214
215     package My::Test10;
216     use Moose;
217     
218     has 'ghost' => (is => 'ro', default => 'My::Test10::ghost');    
219     
220     ::throws_ok {
221         with 'Role::Boo', 'Role::Boo::Hoo';
222     } qr/Role \'Role::Boo::Hoo\' has encountered an attribute conflict/, 
223       '... role attrs conflicted and cannot be manually disambiguted';  
224
225 }
226
227 ok(!My::Test7->meta->has_attribute('ghost'), '... we didnt get any attributes in the conflict');
228 ok(My::Test8->meta->has_attribute('ghost'), '... we did get an attributes when manually composed');
229 ok(My::Test9->meta->has_attribute('ghost'), '... we did get an attributes when manually composed');
230 ok(My::Test10->meta->has_attribute('ghost'), '... we did still have an attribute ghost (conflict does not mess with class)');
231
232 ok(!My::Test7->does('Role::Boo'), '... our class does() the correct roles');
233 ok(!My::Test7->does('Role::Boo::Hoo'), '... our class does() the correct roles');
234 ok(My::Test8->does('Role::Boo'), '... our class does() the correct roles');
235 ok(My::Test8->does('Role::Boo::Hoo'), '... our class does() the correct roles');
236 ok(My::Test9->does('Role::Boo'), '... our class does() the correct roles');
237 ok(My::Test9->does('Role::Boo::Hoo'), '... our class does() the correct roles');
238 ok(!My::Test10->does('Role::Boo'), '... our class does() the correct roles');
239 ok(!My::Test10->does('Role::Boo::Hoo'), '... our class does() the correct roles');
240
241 can_ok('My::Test8', 'ghost');
242 can_ok('My::Test9', 'ghost');
243 can_ok('My::Test10', 'ghost');
244
245 is(My::Test8->new->ghost, 'Role::Boo::ghost', '... got the expected default attr value');
246 is(My::Test9->new->ghost, 'Role::Boo::Hoo::ghost', '... got the expected default attr value');
247 is(My::Test10->new->ghost, 'My::Test10::ghost', '... got the expected default attr value');
248
249 =pod
250
251 Role override method conflicts
252
253 =cut
254
255 {
256     package Role::Plot;
257     use Moose::Role;
258     
259     override 'twist' => sub {
260         super() . ' -> Role::Plot::twist';
261     };
262     
263     package Role::Truth;
264     use Moose::Role;
265     
266     override 'twist' => sub {
267         super() . ' -> Role::Truth::twist';
268     };
269 }
270
271 {
272     package My::Test::Base;
273     use Moose;
274     
275     sub twist { 'My::Test::Base::twist' }
276         
277     package My::Test11;
278     use Moose;
279     
280     extends 'My::Test::Base';
281
282     ::lives_ok {
283         with 'Role::Truth';
284     } '... composed the role with override okay';
285        
286     package My::Test12;
287     use Moose;
288
289     extends 'My::Test::Base';
290
291     ::lives_ok {    
292        with 'Role::Plot';
293     } '... composed the role with override okay';
294               
295     package My::Test13;
296     use Moose;
297
298     ::dies_ok {
299         with 'Role::Plot';       
300     } '... cannot compose it because we have no superclass';
301     
302     package My::Test14;
303     use Moose;
304
305     extends 'My::Test::Base';
306
307     ::throws_ok {
308         with 'Role::Plot', 'Role::Truth';       
309     } qr/Two \'override\' methods of the same name encountered/, 
310       '... cannot compose it because we have no superclass';       
311 }
312
313 ok(My::Test11->meta->has_method('twist'), '... the twist method has been added');
314 ok(My::Test12->meta->has_method('twist'), '... the twist method has been added');
315 ok(!My::Test13->meta->has_method('twist'), '... the twist method has not been added');
316 ok(!My::Test14->meta->has_method('twist'), '... the twist method has not been added');
317
318 ok(!My::Test11->does('Role::Plot'), '... our class does() the correct roles');
319 ok(My::Test11->does('Role::Truth'), '... our class does() the correct roles');
320 ok(!My::Test12->does('Role::Truth'), '... our class does() the correct roles');
321 ok(My::Test12->does('Role::Plot'), '... our class does() the correct roles');
322 ok(!My::Test13->does('Role::Plot'), '... our class does() the correct roles');
323 ok(!My::Test14->does('Role::Truth'), '... our class does() the correct roles');
324 ok(!My::Test14->does('Role::Plot'), '... our class does() the correct roles');
325
326 is(My::Test11->twist(), 'My::Test::Base::twist -> Role::Truth::twist', '... got the right method return');
327 is(My::Test12->twist(), 'My::Test::Base::twist -> Role::Plot::twist', '... got the right method return');
328 ok(!My::Test13->can('twist'), '... no twist method here at all');
329 is(My::Test14->twist(), 'My::Test::Base::twist', '... got the right method return (from superclass)');
330
331 {
332     package Role::Reality;
333     use Moose::Role;
334
335     ::throws_ok {    
336         with 'Role::Plot';
337     } qr/A local method of the same name as been found/, 
338     '... could not compose roles here, it dies';
339
340     sub twist {
341         'Role::Reality::twist';
342     }
343 }    
344
345 ok(Role::Reality->meta->has_method('twist'), '... the twist method has not been added');
346 ok(!Role::Reality->meta->does_role('Role::Plot'), '... our role does() the correct roles');
347 is(Role::Reality->meta->get_method('twist')->(), 
348     'Role::Reality::twist', 
349     '... the twist method returns the right value');