Commit | Line | Data |
0f24a39d |
1 | package SharedTests; |
2 | |
3 | use strict; |
4 | use warnings; |
5 | |
6 | use Scalar::Util qw( isweak ); |
54a288bd |
7 | use Test::More; |
8 | |
963254e0 |
9 | use vars qw($Lazy); |
10 | $Lazy = 0; |
0f24a39d |
11 | |
963254e0 |
12 | our %Attrs = ( |
13 | ObjectCount => { |
09f9282e |
14 | is => 'rw', |
15 | isa => 'Int', |
16 | default => 0, |
963254e0 |
17 | }, |
18 | WeakAttribute => { |
09f9282e |
19 | is => 'rw', |
20 | isa => 'Object', |
21 | weak_ref => 1, |
963254e0 |
22 | }, |
23 | LazyAttribute => { |
09f9282e |
24 | is => 'rw', |
25 | isa => 'Int', |
26 | lazy => 1, |
09f9282e |
27 | # The side effect is used to test that this was called |
28 | # lazily. |
29 | default => sub { $Lazy = 1 }, |
963254e0 |
30 | }, |
31 | ReadOnlyAttribute => { |
09f9282e |
32 | is => 'ro', |
33 | isa => 'Int', |
34 | default => 10, |
963254e0 |
35 | }, |
36 | ManyNames => { |
09f9282e |
37 | is => 'rw', |
38 | isa => 'Int', |
39 | reader => 'M', |
40 | writer => 'SetM', |
41 | clearer => 'ClearM', |
42 | predicate => 'HasM', |
963254e0 |
43 | }, |
44 | Delegatee => { |
09f9282e |
45 | is => 'rw', |
46 | isa => 'Delegatee', |
47 | handles => [ 'units', 'color' ], |
09f9282e |
48 | # if it's not lazy it makes a new object before we define |
49 | # Delegatee's attributes. |
50 | lazy => 1, |
51 | default => sub { Delegatee->new() }, |
963254e0 |
52 | }, |
53 | Mapping => { |
54 | traits => ['Hash'], |
55 | is => 'rw', |
56 | isa => 'HashRef[Str]', |
57 | default => sub { {} }, |
58 | handles => { |
59 | 'ExistsInMapping' => 'exists', |
60 | 'IdsInMapping' => 'keys', |
61 | 'GetMapping' => 'get', |
62 | 'SetMapping' => 'set', |
09f9282e |
63 | }, |
963254e0 |
64 | }, |
65 | Built => { |
09f9282e |
66 | is => 'ro', |
67 | builder => '_BuildIt', |
963254e0 |
68 | }, |
69 | LazyBuilt => { |
09f9282e |
70 | is => 'ro', |
71 | lazy => 1, |
72 | builder => '_BuildIt', |
963254e0 |
73 | }, |
74 | Triggerish => { |
09f9282e |
75 | is => 'rw', |
76 | trigger => sub { shift->_CallTrigger(@_) }, |
963254e0 |
77 | }, |
78 | ); |
79 | |
80 | { |
81 | package HasClassAttribute; |
82 | |
83 | use Moose qw( has ); |
84 | use MooseX::ClassAttribute; |
85 | |
86 | while ( my ( $name, $def ) = each %SharedTests::Attrs ) { |
87 | class_has $name => %{$def}; |
88 | } |
09f9282e |
89 | |
90 | has 'size' => ( |
91 | is => 'rw', |
92 | isa => 'Int', |
93 | default => 5, |
94 | ); |
0f24a39d |
95 | |
54a288bd |
96 | no Moose; |
54a288bd |
97 | |
09f9282e |
98 | sub BUILD { |
6b059c78 |
99 | my $self = shift; |
0f24a39d |
100 | |
6b059c78 |
101 | $self->ObjectCount( $self->ObjectCount() + 1 ); |
0f24a39d |
102 | } |
54a288bd |
103 | |
09f9282e |
104 | sub _BuildIt {42} |
6048a053 |
105 | |
8207dfe7 |
106 | our @Triggered; |
09f9282e |
107 | |
108 | sub _CallTrigger { |
8207dfe7 |
109 | push @Triggered, [@_]; |
110 | } |
111 | |
09f9282e |
112 | sub make_immutable { |
54a288bd |
113 | my $class = shift; |
114 | |
115 | $class->meta()->make_immutable(); |
54a288bd |
116 | Delegatee->meta()->make_immutable(); |
117 | } |
118 | } |
119 | |
120 | { |
121 | package Delegatee; |
122 | |
123 | use Moose; |
124 | |
09f9282e |
125 | has 'units' => ( |
126 | is => 'ro', |
127 | default => 5, |
128 | ); |
54a288bd |
129 | |
09f9282e |
130 | has 'color' => ( |
131 | is => 'ro', |
132 | default => 'blue', |
133 | ); |
7a8e32bc |
134 | |
135 | no Moose; |
54a288bd |
136 | } |
137 | |
138 | { |
139 | package Child; |
140 | |
141 | use Moose; |
142 | use MooseX::ClassAttribute; |
143 | |
144 | extends 'HasClassAttribute'; |
145 | |
09f9282e |
146 | class_has '+ReadOnlyAttribute' => ( default => 30 ); |
7a8e32bc |
147 | |
09f9282e |
148 | class_has 'YetAnotherAttribute' => ( |
149 | is => 'ro', |
150 | default => 'thing', |
151 | ); |
7a4a3b1e |
152 | |
7a8e32bc |
153 | no Moose; |
0f24a39d |
154 | } |
155 | |
09f9282e |
156 | sub run_tests { |
2840c8ab |
157 | my $class = shift || 'HasClassAttribute'; |
158 | |
0f24a39d |
159 | local $Test::Builder::Level = $Test::Builder::Level + 1; |
160 | |
161 | { |
09f9282e |
162 | is( |
2840c8ab |
163 | $class->ObjectCount(), 0, |
09f9282e |
164 | 'ObjectCount() is 0' |
165 | ); |
0f24a39d |
166 | |
2840c8ab |
167 | my $hca1 = $class->new(); |
09f9282e |
168 | is( |
169 | $hca1->size(), 5, |
170 | 'size is 5 - object attribute works as expected' |
171 | ); |
172 | is( |
2840c8ab |
173 | $class->ObjectCount(), 1, |
09f9282e |
174 | 'ObjectCount() is 1' |
175 | ); |
0f24a39d |
176 | |
2840c8ab |
177 | my $hca2 = $class->new( size => 10 ); |
09f9282e |
178 | is( |
179 | $hca2->size(), 10, |
180 | 'size is 10 - object attribute can be set via constructor' |
181 | ); |
182 | is( |
2840c8ab |
183 | $class->ObjectCount(), 2, |
09f9282e |
184 | 'ObjectCount() is 2' |
185 | ); |
186 | is( |
187 | $hca2->ObjectCount(), 2, |
188 | 'ObjectCount() is 2 - can call class attribute accessor on object' |
189 | ); |
0f24a39d |
190 | } |
191 | |
192 | { |
2840c8ab |
193 | my $hca3 = $class->new( ObjectCount => 20 ); |
09f9282e |
194 | is( |
195 | $hca3->ObjectCount(), 3, |
196 | 'class attributes passed to the constructor do not get set in the object' |
197 | ); |
198 | is( |
2840c8ab |
199 | $class->ObjectCount(), 3, |
09f9282e |
200 | 'class attributes are not affected by constructor params' |
201 | ); |
0f24a39d |
202 | } |
203 | |
204 | { |
205 | my $object = bless {}, 'Thing'; |
206 | |
2840c8ab |
207 | $class->WeakAttribute($object); |
0f24a39d |
208 | |
6b059c78 |
209 | undef $object; |
210 | |
09f9282e |
211 | ok( |
2840c8ab |
212 | !defined $class->WeakAttribute(), |
09f9282e |
213 | 'weak class attributes are weak' |
214 | ); |
0f24a39d |
215 | } |
54a288bd |
216 | |
217 | { |
09f9282e |
218 | is( |
963254e0 |
219 | $SharedTests::Lazy, 0, |
220 | '$SharedTests::Lazy is 0' |
09f9282e |
221 | ); |
54a288bd |
222 | |
09f9282e |
223 | is( |
2840c8ab |
224 | $class->LazyAttribute(), 1, |
225 | '$class->LazyAttribute() is 1' |
09f9282e |
226 | ); |
54a288bd |
227 | |
09f9282e |
228 | is( |
963254e0 |
229 | $SharedTests::Lazy, 1, |
230 | '$SharedTests::Lazy is 1 after calling LazyAttribute' |
09f9282e |
231 | ); |
54a288bd |
232 | } |
233 | |
234 | { |
2840c8ab |
235 | eval { $class->ReadOnlyAttribute(20) }; |
09f9282e |
236 | like( |
237 | $@, qr/\QCannot assign a value to a read-only accessor/, |
238 | 'cannot set read-only class attribute' |
239 | ); |
54a288bd |
240 | } |
241 | |
242 | { |
09f9282e |
243 | is( |
244 | Child->ReadOnlyAttribute(), 30, |
245 | q{Child class can extend parent's class attribute} |
246 | ); |
54a288bd |
247 | } |
248 | |
249 | { |
09f9282e |
250 | ok( |
2840c8ab |
251 | !$class->HasM(), |
09f9282e |
252 | 'HasM() returns false before M is set' |
253 | ); |
54a288bd |
254 | |
2840c8ab |
255 | $class->SetM(22); |
54a288bd |
256 | |
09f9282e |
257 | ok( |
2840c8ab |
258 | $class->HasM(), |
09f9282e |
259 | 'HasM() returns true after M is set' |
260 | ); |
261 | is( |
2840c8ab |
262 | $class->M(), 22, |
09f9282e |
263 | 'M() returns 22' |
264 | ); |
54a288bd |
265 | |
2840c8ab |
266 | $class->ClearM(); |
54a288bd |
267 | |
09f9282e |
268 | ok( |
2840c8ab |
269 | !$class->HasM(), |
09f9282e |
270 | 'HasM() returns false after M is cleared' |
271 | ); |
54a288bd |
272 | } |
273 | |
274 | { |
09f9282e |
275 | isa_ok( |
2840c8ab |
276 | $class->Delegatee(), 'Delegatee', |
09f9282e |
277 | 'has a Delegetee object' |
278 | ); |
279 | is( |
2840c8ab |
280 | $class->units(), 5, |
09f9282e |
281 | 'units() delegates to Delegatee and returns 5' |
282 | ); |
54a288bd |
283 | } |
284 | |
54a288bd |
285 | { |
2840c8ab |
286 | my @ids = $class->IdsInMapping(); |
09f9282e |
287 | is( |
288 | scalar @ids, 0, |
289 | 'there are no keys in the mapping yet' |
290 | ); |
54a288bd |
291 | |
09f9282e |
292 | ok( |
2840c8ab |
293 | !$class->ExistsInMapping('a'), |
09f9282e |
294 | 'key does not exist in mapping' |
295 | ); |
54a288bd |
296 | |
2840c8ab |
297 | $class->SetMapping( a => 20 ); |
54a288bd |
298 | |
09f9282e |
299 | ok( |
2840c8ab |
300 | $class->ExistsInMapping('a'), |
09f9282e |
301 | 'key does exist in mapping' |
302 | ); |
54a288bd |
303 | |
09f9282e |
304 | is( |
2840c8ab |
305 | $class->GetMapping('a'), 20, |
09f9282e |
306 | 'value for a in mapping is 20' |
307 | ); |
54a288bd |
308 | } |
6048a053 |
309 | |
310 | { |
09f9282e |
311 | is( |
2840c8ab |
312 | $class->Built(), 42, |
09f9282e |
313 | 'attribute with builder works' |
314 | ); |
6048a053 |
315 | |
09f9282e |
316 | is( |
2840c8ab |
317 | $class->LazyBuilt(), 42, |
09f9282e |
318 | 'attribute with lazy builder works' |
319 | ); |
6048a053 |
320 | } |
8207dfe7 |
321 | |
322 | { |
2840c8ab |
323 | $class->Triggerish(42); |
324 | my $triggered = do { no strict 'refs'; \@{ $class . '::Triggered' } }; |
325 | is( scalar @{$triggered}, 1, 'trigger was called' ); |
326 | is( $class->Triggerish(), 42, 'Triggerish is now 42' ); |
8207dfe7 |
327 | |
2840c8ab |
328 | $class->Triggerish(84); |
329 | is( $class->Triggerish(), 84, 'Triggerish is now 84' ); |
8207dfe7 |
330 | |
09f9282e |
331 | is_deeply( |
2840c8ab |
332 | $triggered, |
09f9282e |
333 | [ |
2840c8ab |
334 | [ $class, qw( 42 ) ], |
335 | [ $class, qw( 84 42 ) ], |
09f9282e |
336 | ], |
337 | 'trigger passes old value correctly' |
338 | ); |
8207dfe7 |
339 | } |
ee29de7b |
340 | |
341 | done_testing(); |
0f24a39d |
342 | } |
343 | |
0f24a39d |
344 | 1; |