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