more refactoring to prep for class attrs in roles
[gitmo/MooseX-ClassAttribute.git] / t / lib / SharedTests.pm
CommitLineData
0f24a39d 1package SharedTests;
2
3use strict;
4use warnings;
5
6use Scalar::Util qw( isweak );
54a288bd 7use Test::More;
8
963254e0 9use vars qw($Lazy);
10$Lazy = 0;
0f24a39d 11
963254e0 12our %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 156sub 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 3441;