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