Add more tests, including some that won't pass until we can make
[gitmo/Moose.git] / t / 050_metaclasses / 015_metarole.t
CommitLineData
231be3be 1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
4fed6bbc 6use Test::More tests => 59;
231be3be 7
8use Moose::Util::MetaRole;
9
10
11{
12 package My::Meta::Class;
13 use Moose;
14 extends 'Moose::Meta::Class';
15}
16
17{
18 package My::Meta::Attribute;
19 use Moose;
20 extends 'Moose::Meta::Attribute';
21}
22
23{
24 package My::Meta::Method;
25 use Moose;
26 extends 'Moose::Meta::Method';
27}
28
29{
30 package My::Meta::Instance;
31 use Moose;
32 extends 'Moose::Meta::Instance';
33}
34
35{
36 package My::Meta::MethodConstructor;
37 use Moose;
38 extends 'Moose::Meta::Method::Constructor';
39}
40
41{
42 package My::Meta::MethodDestructor;
43 use Moose;
44 extends 'Moose::Meta::Method::Destructor';
45}
46
47{
48 package Role::Foo;
49 use Moose::Role;
50 has 'foo' => ( is => 'ro', default => 10 );
51}
52
53{
54 package My::Class;
55
56 use Moose;
57}
58
59{
60 Moose::Util::MetaRole::apply_metaclass_roles(
61 for_class => 'My::Class',
62 metaclass_roles => ['Role::Foo'],
63 );
64
65 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
66 'apply Role::Foo to My::Class->meta()' );
67 is( My::Class->meta()->foo(), 10,
68 '... and call foo() on that meta object' );
69}
70
71{
72 Moose::Util::MetaRole::apply_metaclass_roles(
73 for_class => 'My::Class',
74 attribute_metaclass_roles => ['Role::Foo'],
75 );
76
77 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
78 q{apply Role::Foo to My::Class->meta()'s attribute metaclass} );
79 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
80 '... My::Class->meta() still does Role::Foo' );
81
82 My::Class->meta()->add_attribute( 'size', is => 'ro' );
83 is( My::Class->meta()->get_attribute('size')->foo(), 10,
84 '... call foo() on an attribute metaclass object' );
85}
86
87{
88 Moose::Util::MetaRole::apply_metaclass_roles(
89 for_class => 'My::Class',
90 method_metaclass_roles => ['Role::Foo'],
91 );
92
93 ok( My::Class->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
94 q{apply Role::Foo to My::Class->meta()'s method metaclass} );
95 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
96 '... My::Class->meta() still does Role::Foo' );
97 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
98 q{... My::Class->meta()'s attribute metaclass still does Role::Foo} );
99
100 My::Class->meta()->add_method( 'bar' => sub { 'bar' } );
101 is( My::Class->meta()->get_method('bar')->foo(), 10,
102 '... call foo() on a method metaclass object' );
103}
104
105{
106 Moose::Util::MetaRole::apply_metaclass_roles(
107 for_class => 'My::Class',
108 instance_metaclass_roles => ['Role::Foo'],
109 );
110
111 ok( My::Class->meta()->instance_metaclass()->meta()->does_role('Role::Foo'),
112 q{apply Role::Foo to My::Class->meta()'s instance metaclass} );
113 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
114 '... My::Class->meta() still does Role::Foo' );
115 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
116 q{... My::Class->meta()'s attribute metaclass still does Role::Foo} );
117 ok( My::Class->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
118 q{... My::Class->meta()'s method metaclass still does Role::Foo} );
119
120 is( My::Class->meta()->get_meta_instance()->foo(), 10,
121 '... call foo() on an instance metaclass object' );
122}
123
124{
125 Moose::Util::MetaRole::apply_metaclass_roles(
126 for_class => 'My::Class',
127 constructor_class_roles => ['Role::Foo'],
128 );
129
130 ok( My::Class->meta()->constructor_class()->meta()->does_role('Role::Foo'),
131 q{apply Role::Foo to My::Class->meta()'s constructor class} );
132 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
133 '... My::Class->meta() still does Role::Foo' );
134 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
135 q{... My::Class->meta()'s attribute metaclass still does Role::Foo} );
136 ok( My::Class->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
137 q{... My::Class->meta()'s method metaclass still does Role::Foo} );
138 ok( My::Class->meta()->instance_metaclass()->meta()->does_role('Role::Foo'),
139 q{... My::Class->meta()'s instance metaclass still does Role::Foo} );
140
141 # Actually instantiating the constructor class is too freaking hard!
142 ok( My::Class->meta()->constructor_class()->can('foo'),
143 '... constructor class has a foo method' );
144}
145
146{
147 Moose::Util::MetaRole::apply_metaclass_roles(
148 for_class => 'My::Class',
149 destructor_class_roles => ['Role::Foo'],
150 );
151
152 ok( My::Class->meta()->destructor_class()->meta()->does_role('Role::Foo'),
153 q{apply Role::Foo to My::Class->meta()'s destructor class} );
154 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
155 '... My::Class->meta() still does Role::Foo' );
156 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
157 q{... My::Class->meta()'s attribute metaclass still does Role::Foo} );
158 ok( My::Class->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
159 q{... My::Class->meta()'s method metaclass still does Role::Foo} );
160 ok( My::Class->meta()->instance_metaclass()->meta()->does_role('Role::Foo'),
161 q{... My::Class->meta()'s instance metaclass still does Role::Foo} );
162 ok( My::Class->meta()->constructor_class()->meta()->does_role('Role::Foo'),
163 q{... My::Class->meta()'s constructor class still does Role::Foo} );
164
165 # same problem as the constructor class
166 ok( My::Class->meta()->destructor_class()->can('foo'),
167 '... destructor class has a foo method' );
168}
169
170{
171 Moose::Util::MetaRole::apply_base_class_roles(
172 for_class => 'My::Class',
173 roles => ['Role::Foo'],
174 );
175
176 ok( My::Class->meta()->does_role('Role::Foo'),
177 'apply Role::Foo to My::Class base class' );
178 is( My::Class->new()->foo(), 10,
179 '... call foo() on a My::Class object' );
180}
181
182{
183 package My::Class2;
184
185 use Moose;
186}
187
188{
189 Moose::Util::MetaRole::apply_metaclass_roles(
190 for_class => 'My::Class2',
191 metaclass_roles => ['Role::Foo'],
192 attribute_metaclass_roles => ['Role::Foo'],
193 method_metaclass_roles => ['Role::Foo'],
194 instance_metaclass_roles => ['Role::Foo'],
195 constructor_class_roles => ['Role::Foo'],
196 destructor_class_roles => ['Role::Foo'],
197 );
198
199 ok( My::Class2->meta()->meta()->does_role('Role::Foo'),
200 'apply Role::Foo to My::Class2->meta()' );
201 is( My::Class2->meta()->foo(), 10,
202 '... and call foo() on that meta object' );
203 ok( My::Class2->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
204 q{apply Role::Foo to My::Class2->meta()'s attribute metaclass} );
205 My::Class2->meta()->add_attribute( 'size', is => 'ro' );
206
207 is( My::Class2->meta()->get_attribute('size')->foo(), 10,
208 '... call foo() on an attribute metaclass object' );
209
210 ok( My::Class2->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
211 q{apply Role::Foo to My::Class2->meta()'s method metaclass} );
212
213 My::Class2->meta()->add_method( 'bar' => sub { 'bar' } );
214 is( My::Class2->meta()->get_method('bar')->foo(), 10,
215 '... call foo() on a method metaclass object' );
216
217 ok( My::Class2->meta()->instance_metaclass()->meta()->does_role('Role::Foo'),
218 q{apply Role::Foo to My::Class2->meta()'s instance metaclass} );
219 is( My::Class2->meta()->get_meta_instance()->foo(), 10,
220 '... call foo() on an instance metaclass object' );
221
222 ok( My::Class2->meta()->constructor_class()->meta()->does_role('Role::Foo'),
223 q{apply Role::Foo to My::Class2->meta()'s constructor class} );
224 ok( My::Class2->meta()->constructor_class()->can('foo'),
225 '... constructor class has a foo method' );
226
227 ok( My::Class2->meta()->destructor_class()->meta()->does_role('Role::Foo'),
228 q{apply Role::Foo to My::Class2->meta()'s destructor class} );
229 ok( My::Class2->meta()->destructor_class()->can('foo'),
230 '... destructor class has a foo method' );
231}
232
233
234{
235 package My::Meta;
236
237 use Moose::Exporter;
238 Moose::Exporter->setup_import_methods( also => 'Moose' );
239
240 sub init_meta {
241 shift;
242 my %p = @_;
243
244 Moose->init_meta( %p, metaclass => 'My::Meta::Class' );
245 }
246}
247
248{
249 package My::Class3;
250
251 My::Meta->import();
252}
253
254
255{
256 Moose::Util::MetaRole::apply_metaclass_roles(
257 for_class => 'My::Class3',
258 metaclass_roles => ['Role::Foo'],
259 );
260
261 ok( My::Class3->meta()->meta()->does_role('Role::Foo'),
262 'apply Role::Foo to My::Class3->meta()' );
263 is( My::Class3->meta()->foo(), 10,
264 '... and call foo() on that meta object' );
265 ok( ( grep { $_ eq 'My::Meta::Class' } My::Class3->meta()->meta()->superclasses() ),
266 'apply_metaclass_roles() does not interfere with metaclass set via Moose->init_meta()' );
267}
82b388d5 268
269{
270 package Role::Bar;
271 use Moose::Role;
272 has 'bar' => ( is => 'ro', default => 200 );
273}
274
275{
276 package My::Class4;
277 use Moose;
278}
279
280{
281 Moose::Util::MetaRole::apply_metaclass_roles(
282 for_class => 'My::Class4',
283 metaclass_roles => ['Role::Foo'],
284 );
285
286 ok( My::Class4->meta()->meta()->does_role('Role::Foo'),
287 'apply Role::Foo to My::Class4->meta()' );
288
289 Moose::Util::MetaRole::apply_metaclass_roles(
290 for_class => 'My::Class4',
291 metaclass_roles => ['Role::Bar'],
292 );
293
294 ok( My::Class4->meta()->meta()->does_role('Role::Bar'),
295 'apply Role::Bar to My::Class4->meta()' );
296 ok( My::Class4->meta()->meta()->does_role('Role::Foo'),
297 '... and My::Class4->meta() still does Role::Foo' );
298}
4fed6bbc 299
300{
301 package My::Class5;
302 use Moose;
303
304 extends 'My::Class';
305}
306
307{
308 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
309 q{My::Class5->meta()'s does Role::Foo because it extends My::Class} );
310 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
311 q{My::Class5->meta()'s attribute metaclass also does Role::Foo} );
312 ok( My::Class->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
313 q{My::Class5->meta()'s method metaclass also does Role::Foo} );
314 ok( My::Class->meta()->instance_metaclass()->meta()->does_role('Role::Foo'),
315 q{My::Class5->meta()'s instance metaclass also does Role::Foo} );
316 ok( My::Class->meta()->constructor_class()->meta()->does_role('Role::Foo'),
317 q{My::Class5->meta()'s constructor class also does Role::Foo} );
318 ok( My::Class->meta()->destructor_class()->meta()->does_role('Role::Foo'),
319 q{My::Class->meta()'s destructor class also does Role::Foo} );
320}
321
322{
323 Moose::Util::MetaRole::apply_metaclass_roles(
324 for_class => 'My::Class5',
325 metaclass_roles => ['Role::Bar'],
326 );
327
328 ok( My::Class5->meta()->meta()->does_role('Role::Bar'),
329 q{apply Role::Bar My::Class5->meta()} );
330 ok( My::Class5->meta()->meta()->does_role('Role::Foo'),
331 q{... and My::Class5->meta() still does Role::Foo} );
332}
333
334SKIP:
335{
336 skip
337 'These tests will fail until Moose::Meta::Class->_fix_metaclass_incompatibility is much smarter.',
338 2;
339{
340 package My::Class6;
341 use Moose;
342
343 Moose::Util::MetaRole::apply_metaclass_roles(
344 for_class => 'My::Class6',
345 metaclass_roles => ['Role::Bar'],
346 );
347
348 extends 'My::Class';
349}
350
351{
352 ok( My::Class6->meta()->meta()->does_role('Role::Bar'),
353 q{apply Role::Bar My::Class6->meta() before extends} );
354 ok( My::Class6->meta()->meta()->does_role('Role::Foo'),
355 q{... and My::Class6->meta() does Role::Foo because it extends My::Class} );
356}
357}
358
359# This is the hack needed to work around the
360# _fix_metaclass_incompatibility problem. You must call extends()
361# (which in turn calls _fix_metaclass_imcompatibility) _before_ you
362# apply more extensions in the subclass.
363{
364 package My::Class7;
365 use Moose;
366
367 # In real usage this would go in a BEGIN block so it happened
368 # before apply_metaclass_roles was called by an extension.
369 extends 'My::Class';
370
371 Moose::Util::MetaRole::apply_metaclass_roles(
372 for_class => 'My::Class7',
373 metaclass_roles => ['Role::Bar'],
374 );
375}
376
377{
378 ok( My::Class7->meta()->meta()->does_role('Role::Bar'),
379 q{apply Role::Bar My::Class7->meta() before extends} );
380 ok( My::Class7->meta()->meta()->does_role('Role::Foo'),
381 q{... and My::Class7->meta() does Role::Foo because it extends My::Class} );
382}