d4c24eb8d6b9f36445615ccc1bea7786664c59b6
[gitmo/Moose.git] / t / 030_roles / 011_overriding.t
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use Test::More tests => 44;
7 use Test::Exception;
8 use Test::Output;
9
10
11
12
13     # test no conflicts here
14     package Role::A;
15     use Moose::Role;
16
17     sub bar { 'Role::A::bar' }
18
19     package Role::B;
20     use Moose::Role;
21
22     sub xxy { 'Role::B::xxy' }
23
24     package Role::C;
25     use Moose::Role;
26     
27     ::lives_ok {
28         with qw(Role::A Role::B); # no conflict here
29     } "define role C";
30
31     sub foo { 'Role::C::foo' }
32     sub zot { 'Role::C::zot' }
33
34     package Class::A;
35     use Moose;
36
37     ::lives_ok {
38         ::stderr_like {
39             with qw(Role::C);
40         } qr/The Class::A class has implicitly overridden the method \(zot\) from role Role::C\./;
41     } "define class A";
42     
43     sub zot { 'Class::A::zot' }
44 }
45
46 can_ok( Class::A->new, qw(foo bar xxy zot) );
47
48 is( Class::A->new->foo, "Role::C::foo",  "... got the right foo method" );
49 is( Class::A->new->zot, "Class::A::zot", "... got the right zot method" );
50 is( Class::A->new->bar, "Role::A::bar",  "... got the right bar method" );
51 is( Class::A->new->xxy, "Role::B::xxy",  "... got the right xxy method" );
52
53 {
54     # check that when a role is added to another role
55     # and they conflict and the method they conflicted
56     # with is then required. 
57     
58     package Role::A::Conflict;
59     use Moose::Role;
60     
61     with 'Role::A';
62     
63     sub bar { 'Role::A::Conflict::bar' }
64     
65     package Class::A::Conflict;
66     use Moose;
67     
68     ::throws_ok {
69         with 'Role::A::Conflict';
70     }  qr/requires.*'bar'/, '... did not fufill the requirement of &bar method';
71     
72     package Class::A::Resolved;
73     use Moose;
74     
75     ::lives_ok {
76         ::stderr_like {
77             with 'Role::A::Conflict';
78         } qr/The Class::A::Resolved class has implicitly overridden the method \(bar\) from role Role::A::Conflict\./;
79     } '... did fufill the requirement of &bar method';    
80     
81     sub bar { 'Class::A::Resolved::bar' }
82 }
83
84 ok(Role::A::Conflict->meta->requires_method('bar'), '... Role::A::Conflict created the bar requirement');
85
86 can_ok( Class::A::Resolved->new, qw(bar) );
87
88 is( Class::A::Resolved->new->bar, 'Class::A::Resolved::bar', "... got the right bar method" );
89
90 {
91     # check that when two roles are composed, they conflict
92     # but the composing role can resolve that conflict
93     
94     package Role::D;
95     use Moose::Role;
96
97     sub foo { 'Role::D::foo' }
98     sub bar { 'Role::D::bar' }    
99
100     package Role::E;
101     use Moose::Role;
102
103     sub foo { 'Role::E::foo' }
104     sub xxy { 'Role::E::xxy' }
105
106     package Role::F;
107     use Moose::Role;
108
109     ::lives_ok {
110         with qw(Role::D Role::E); # conflict between 'foo's here
111     } "define role Role::F";
112     
113     sub foo { 'Role::F::foo' }
114     sub zot { 'Role::F::zot' }    
115     
116     package Class::B;
117     use Moose;
118     
119     ::lives_ok {
120         ::stderr_like {
121             with qw(Role::F);
122         } qr/The Class::B class has implicitly overridden the method \(zot\) from role Role::F\./;
123     } "define class Class::B";
124     
125     sub zot { 'Class::B::zot' }
126 }
127
128 can_ok( Class::B->new, qw(foo bar xxy zot) );
129
130 is( Class::B->new->foo, "Role::F::foo",  "... got the &foo method okay" );
131 is( Class::B->new->zot, "Class::B::zot", "... got the &zot method okay" );
132 is( Class::B->new->bar, "Role::D::bar",  "... got the &bar method okay" );
133 is( Class::B->new->xxy, "Role::E::xxy",  "... got the &xxy method okay" );
134
135 ok(!Role::F->meta->requires_method('foo'), '... Role::F fufilled the &foo requirement');
136
137 {
138     # check that a conflict can be resolved
139     # by a role, but also new ones can be 
140     # created just as easily ...
141     
142     package Role::D::And::E::Conflict;
143     use Moose::Role;
144
145     ::lives_ok {
146         with qw(Role::D Role::E); # conflict between 'foo's here
147     } "... define role Role::D::And::E::Conflict";
148     
149     sub foo { 'Role::D::And::E::Conflict::foo' }  # this overrides ...
150       
151     # but these conflict      
152     sub xxy { 'Role::D::And::E::Conflict::xxy' }  
153     sub bar { 'Role::D::And::E::Conflict::bar' }        
154
155 }
156
157 ok(!Role::D::And::E::Conflict->meta->requires_method('foo'), '... Role::D::And::E::Conflict fufilled the &foo requirement');
158 ok(Role::D::And::E::Conflict->meta->requires_method('xxy'), '... Role::D::And::E::Conflict adds the &xxy requirement');
159 ok(Role::D::And::E::Conflict->meta->requires_method('bar'), '... Role::D::And::E::Conflict adds the &bar requirement');
160
161 {
162     # conflict propagation
163     
164     package Role::H;
165     use Moose::Role;
166
167     sub foo { 'Role::H::foo' }
168     sub bar { 'Role::H::bar' }    
169
170     package Role::J;
171     use Moose::Role;
172
173     sub foo { 'Role::J::foo' }
174     sub xxy { 'Role::J::xxy' }
175
176     package Role::I;
177     use Moose::Role;
178
179     ::lives_ok {
180         with qw(Role::J Role::H); # conflict between 'foo's here
181     } "define role Role::I";
182     
183     sub zot { 'Role::I::zot' }
184     sub zzy { 'Role::I::zzy' }
185
186     package Class::C;
187     use Moose;
188     
189     ::throws_ok {
190         with qw(Role::I);
191     } qr/requires.*'foo'/, "defining class Class::C fails";
192
193     sub zot { 'Class::C::zot' }
194
195     package Class::E;
196     use Moose;
197
198     ::lives_ok {
199         ::stderr_like {
200             with qw(Role::I);
201         } qr/The Class::E class has implicitly overridden the method \(zot\) from role Role::I\./;
202     } "resolved with method";        
203
204     sub foo { 'Class::E::foo' }
205     sub zot { 'Class::E::zot' }    
206 }
207
208 can_ok( Class::E->new, qw(foo bar xxy zot) );
209
210 is( Class::E->new->foo, "Class::E::foo", "... got the right &foo method" );
211 is( Class::E->new->zot, "Class::E::zot", "... got the right &zot method" );
212 is( Class::E->new->bar, "Role::H::bar",  "... got the right &bar method" );
213 is( Class::E->new->xxy, "Role::J::xxy",  "... got the right &xxy method" );
214
215 ok(Role::I->meta->requires_method('foo'), '... Role::I still have the &foo requirement');
216
217 {
218     lives_ok {
219         package Class::D;
220         use Moose;
221
222         has foo => ( default => __PACKAGE__ . "::foo", is => "rw" );
223
224         sub zot { 'Class::D::zot' }
225
226         ::stderr_like {
227             with qw(Role::I);
228         } qr/The Class::D class has implicitly overridden the method \(zot\) from role Role::I\./;
229
230     } "resolved with attr";
231
232     can_ok( Class::D->new, qw(foo bar xxy zot) );
233     is( eval { Class::D->new->bar }, "Role::H::bar", "bar" );
234     is( eval { Class::D->new->zzy }, "Role::I::zzy", "zzy" );
235
236     is( eval { Class::D->new->foo }, "Class::D::foo", "foo" );
237     is( eval { Class::D->new->zot }, "Class::D::zot", "zot" );
238
239 }
240