confound++
[gitmo/Moose.git] / t / 030_roles / 007_roles_and_required_method_edge_cases.t
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use Test::More tests => 17;
7 use Test::Exception;
8
9 =pod
10
11 NOTE:
12 A fair amount of these tests will likely be irrelevant 
13 once we have more fine grained control over the class
14 building process. A lot of the edge cases tested here
15 are actually related to class construction order and 
16 not any real functionality.
17 - SL
18
19 =cut
20
21 BEGIN {
22     use_ok('Moose');
23     use_ok('Moose::Role');    
24 }
25
26 =pod
27
28 Role which requires a method implemented 
29 in another role as an override (it does 
30 not remove the requirement)
31
32 =cut
33
34 {
35     package Role::RequireFoo;
36     use strict;
37     use warnings;
38     use Moose::Role;
39     
40     requires 'foo';
41     
42     package Role::ProvideFoo;
43     use strict;
44     use warnings;
45     use Moose::Role;
46     
47     ::lives_ok {
48         with 'Role::RequireFoo';
49     } '... the required "foo" method will not exist yet (but we will live)';
50     
51     override 'foo' => sub { 'Role::ProvideFoo::foo' };    
52 }
53
54 is_deeply(
55     [ Role::ProvideFoo->meta->get_required_method_list ], 
56     [ 'foo' ], 
57     '... foo method is still required for Role::ProvideFoo');
58
59 =pod
60
61 Role which requires a method implemented 
62 in the consuming class as an override. 
63 It will fail since method modifiers are 
64 second class citizens.
65
66 =cut
67
68 {
69     package Class::ProvideFoo::Base;
70     use Moose;
71
72     sub foo { 'Class::ProvideFoo::Base::foo' }
73         
74     package Class::ProvideFoo::Override1;
75     use Moose;
76     
77     extends 'Class::ProvideFoo::Base';
78     
79     ::lives_ok {
80         with 'Role::RequireFoo';
81     } '... the required "foo" method will be found in the superclass';
82     
83     override 'foo' => sub { 'Class::ProvideFoo::foo' };    
84     
85     package Class::ProvideFoo::Override2;
86     use Moose;
87     
88     extends 'Class::ProvideFoo::Base';
89     
90     override 'foo' => sub { 'Class::ProvideFoo::foo' };     
91     
92     ::lives_ok {
93         with 'Role::RequireFoo';
94     } '... the required "foo" method exists, although it is overriden locally';
95
96 }
97
98 =pod
99
100 Now same thing, but with a before 
101 method modifier.
102
103 =cut
104
105 {
106     package Class::ProvideFoo::Before1;
107     use Moose;
108     
109     extends 'Class::ProvideFoo::Base';
110     
111     ::lives_ok {
112         with 'Role::RequireFoo';
113     } '... the required "foo" method will be found in the superclass';
114     
115     before 'foo' => sub { 'Class::ProvideFoo::foo:before' };    
116     
117     package Class::ProvideFoo::Before2;
118     use Moose;
119     
120     extends 'Class::ProvideFoo::Base';
121     
122     before 'foo' => sub { 'Class::ProvideFoo::foo:before' };     
123     
124     ::lives_ok {
125         with 'Role::RequireFoo';
126     } '... the required "foo" method exists, although it is a before modifier locally';    
127     
128     package Class::ProvideFoo::Before3;
129     use Moose;
130     
131     extends 'Class::ProvideFoo::Base';
132     
133     sub foo { 'Class::ProvideFoo::foo' }
134     before 'foo' => sub { 'Class::ProvideFoo::foo:before' };    
135     
136     ::lives_ok {
137         with 'Role::RequireFoo';
138     } '... the required "foo" method exists locally, and it is modified locally';    
139     
140     package Class::ProvideFoo::Before4;
141     use Moose;
142     
143     extends 'Class::ProvideFoo::Base';
144     
145     sub foo { 'Class::ProvideFoo::foo' }    
146     before 'foo' => sub { 'Class::ProvideFoo::foo:before' };     
147
148     ::isa_ok(__PACKAGE__->meta->get_method('foo'), 'Class::MOP::Method::Wrapped');
149     ::is(__PACKAGE__->meta->get_method('foo')->get_original_method->package_name, __PACKAGE__, 
150     '... but the original method is from our package');
151     
152     ::lives_ok {
153         with 'Role::RequireFoo';
154     } '... the required "foo" method exists in the symbol table (and we will live)'; 
155            
156 }    
157
158 =pod
159
160 Now same thing, but with a method from an attribute
161 method modifier.
162
163 =cut
164
165 {
166     
167     package Class::ProvideFoo::Attr1;
168     use Moose;
169     
170     extends 'Class::ProvideFoo::Base';
171     
172     ::lives_ok {
173         with 'Role::RequireFoo';
174     } '... the required "foo" method will be found in the superclass (but then overriden)';
175     
176     has 'foo' => (is => 'ro');
177     
178     package Class::ProvideFoo::Attr2;
179     use Moose;
180     
181     extends 'Class::ProvideFoo::Base';
182     
183     has 'foo' => (is => 'ro');     
184     
185     ::dies_ok {
186         with 'Role::RequireFoo';
187     } '... the required "foo" method exists, but it is a before (and we will die)';    
188 }    
189
190 # ...
191 # a method required in a role, but then 
192 # implemented in the superclass (as an 
193 # attribute accessor too)
194     
195 {
196     package Foo::Class::Base;
197     use Moose;
198     
199     has 'bar' =>  ( 
200         isa     => 'Int', 
201         is      => 'rw', 
202         default => sub { 1 }
203     );
204 }
205 {
206     package Foo::Role;
207     use Moose::Role;
208     
209     requires 'bar';
210     
211     has 'foo' => ( 
212         isa     => 'Int', 
213         is      => 'rw', 
214         lazy    => 1, 
215         default => sub { (shift)->bar + 1 } 
216     );
217 }
218 {
219     package Foo::Class::Child;
220     use Moose;
221     extends 'Foo::Class::Base';
222     
223     ::dies_ok {       
224         with 'Foo::Role';
225     } '... our role combined successfully';
226 }
227
228 # a method required in a role and implemented in a superclass, with a method
229 # modifier in the subclass.  this should live, but dies in 0.26 -- hdp,
230 # 2007-10-11
231
232 {
233     package Bar::Class::Base;
234     use Moose;
235
236     sub bar { "hello!" }
237 }
238 {
239     package Bar::Role;
240     use Moose::Role;
241     requires 'bar';
242 }
243 {
244     package Bar::Class::Child;
245     use Moose;
246     extends 'Bar::Class::Base';
247     after bar => sub { "o noes" };
248     # technically we could run lives_ok here, too, but putting it into a
249     # grandchild class makes it more obvious why this matters.
250 }
251 {
252     package Bar::Class::Grandchild;
253     use Moose;
254     extends 'Bar::Class::Child';
255     ::lives_ok {
256         with 'Bar::Role';
257     } 'required method exists in superclass as non-modifier, so we live';
258 }
259
260 {
261     package Bar2::Class::Base;
262     use Moose;
263
264     sub bar { "hello!" }
265 }
266 {
267     package Bar2::Role;
268     use Moose::Role;
269     requires 'bar';
270 }
271 {
272     package Bar2::Class::Child;
273     use Moose;
274     extends 'Bar2::Class::Base';
275     override bar => sub { "o noes" };
276     # technically we could run lives_ok here, too, but putting it into a
277     # grandchild class makes it more obvious why this matters.
278 }
279 {
280     package Bar2::Class::Grandchild;
281     use Moose;
282     extends 'Bar2::Class::Child';
283     ::lives_ok {
284         with 'Bar2::Role';
285     } 'required method exists in superclass as non-modifier, so we live';
286 }