DEATH TO ALL zionist ELLIPSES
[gitmo/Moose.git] / t / 030_roles / 009_more_role_edge_cases.t
CommitLineData
92768c49 1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
7ff56534 6use Test::More tests => 74;
e39d707f 7use Test::Exception;
8
7ff56534 9
92768c49 10
11{
e39d707f 12 # NOTE:
d03bd989 13 # this tests that repeated role
14 # composition will not cause
e39d707f 15 # a conflict between two methods
16 # which are actually the same anyway
d03bd989 17
92768c49 18 {
19 package RootA;
20 use Moose::Role;
21
e39d707f 22 sub foo { "RootA::foo" }
92768c49 23
24 package SubAA;
25 use Moose::Role;
26
27 with "RootA";
28
e39d707f 29 sub bar { "SubAA::bar" }
92768c49 30
31 package SubAB;
32 use Moose;
33
d03bd989 34 ::lives_ok {
35 with "SubAA", "RootA";
1808c2da 36 } 'role was composed as expected';
92768c49 37 }
38
39 ok( SubAB->does("SubAA"), "does SubAA");
40 ok( SubAB->does("RootA"), "does RootA");
41
42 isa_ok( my $i = SubAB->new, "SubAB" );
43
44 can_ok( $i, "bar" );
e39d707f 45 is( $i->bar, "SubAA::bar", "... got thr right bar rv" );
92768c49 46
47 can_ok( $i, "foo" );
e39d707f 48 my $foo_rv;
d03bd989 49 lives_ok {
50 $foo_rv = $i->foo;
1808c2da 51 } 'called foo successfully';
e39d707f 52 is($foo_rv, "RootA::foo", "... got the right foo rv");
92768c49 53}
54
0558683c 55{
56 # NOTE:
d03bd989 57 # this edge cases shows the application of
58 # an after modifier over a method which
0558683c 59 # was added during role composotion.
60 # The way this will work is as follows:
d03bd989 61 # role SubBA will consume RootB and
62 # get a local copy of RootB::foo, it
0558683c 63 # will also store a deferred after modifier
d03bd989 64 # to be applied to whatever class SubBA is
0558683c 65 # composed into.
66 # When class SubBB comsumed role SubBA, the
d03bd989 67 # RootB::foo method is added to SubBB, then
68 # the deferred after modifier from SubBA is
0558683c 69 # applied to it.
d03bd989 70 # It is important to note that the application
71 # of the after modifier does not happen until
0558683c 72 # role SubBA is composed into SubAA.
d03bd989 73
0558683c 74 {
75 package RootB;
76 use Moose::Role;
77
78 sub foo { "RootB::foo" }
79
80 package SubBA;
81 use Moose::Role;
82
83 with "RootB";
84
85 has counter => (
86 isa => "Num",
87 is => "rw",
88 default => 0,
89 );
90
91 after foo => sub {
92 $_[0]->counter( $_[0]->counter + 1 );
93 };
94
95 package SubBB;
96 use Moose;
97
d03bd989 98 ::lives_ok {
0558683c 99 with "SubBA";
1808c2da 100 } 'composed the role successfully';
0558683c 101 }
102
103 ok( SubBB->does("SubBA"), "BB does SubBA" );
104 ok( SubBB->does("RootB"), "BB does RootB" );
105
106 isa_ok( my $i = SubBB->new, "SubBB" );
107
108 can_ok( $i, "foo" );
d03bd989 109
0558683c 110 my $foo_rv;
d03bd989 111 lives_ok {
112 $foo_rv = $i->foo
1808c2da 113 } 'called foo successfully';
0558683c 114 is( $foo_rv, "RootB::foo", "foo rv" );
115 is( $i->counter, 1, "after hook called" );
d03bd989 116
1808c2da 117 lives_ok { $i->foo } 'called foo successfully (again)';
0558683c 118 is( $i->counter, 2, "after hook called (again)" );
d03bd989 119
1808c2da 120 ok(SubBA->meta->has_method('foo'), 'this has the foo method');
fb1e11d5 121 #my $subba_foo_rv;
d03bd989 122 #lives_ok {
123 # $subba_foo_rv = SubBA::foo();
1808c2da 124 #} 'called the sub as a function correctly';
125 #is($subba_foo_rv, 'RootB::foo', 'the SubBA->foo is still the RootB version');
0558683c 126}
127
128{
129 # NOTE:
130 # this checks that an override method
131 # does not try to trample over a locally
d03bd989 132 # composed in method. In this case the
133 # RootC::foo, which is composed into
134 # SubCA cannot be trampled with an
0558683c 135 # override of 'foo'
136 {
137 package RootC;
138 use Moose::Role;
139
140 sub foo { "RootC::foo" }
141
142 package SubCA;
143 use Moose::Role;
144
145 with "RootC";
146
d03bd989 147 ::dies_ok {
0558683c 148 override foo => sub { "overridden" };
1808c2da 149 } 'cannot compose an override over a local method';
0558683c 150 }
151}
152
153# NOTE:
d03bd989 154# need to talk to Yuval about the motivation behind
155# this test, I am not sure we are testing anything
0558683c 156# useful here (although more tests cant hurt)
157
158{
159 use List::Util qw/shuffle/;
160
161 {
162 package Abstract;
163 use Moose::Role;
164
165 requires "method";
166 requires "other";
167
168 sub another { "abstract" }
169
170 package ConcreteA;
171 use Moose::Role;
172 with "Abstract";
173
174 sub other { "concrete a" }
175
176 package ConcreteB;
177 use Moose::Role;
178 with "Abstract";
179
180 sub method { "concrete b" }
181
182 package ConcreteC;
183 use Moose::Role;
184 with "ConcreteA";
185
186 # NOTE:
d03bd989 187 # this was originally override, but
0558683c 188 # that wont work (see above set of tests)
189 # so I switched it to around.
d03bd989 190 # However, this may not be testing the
0558683c 191 # same thing that was originally intended
192 around other => sub {
193 return ( (shift)->() . " + c" );
194 };
195
196 package SimpleClassWithSome;
197 use Moose;
198
199 eval { with ::shuffle qw/ConcreteA ConcreteB/ };
200 ::ok( !$@, "simple composition without abstract" ) || ::diag $@;
201
202 package SimpleClassWithAll;
203 use Moose;
204
205 eval { with ::shuffle qw/ConcreteA ConcreteB Abstract/ };
206 ::ok( !$@, "simple composition with abstract" ) || ::diag $@;
207 }
208
209 foreach my $class (qw/SimpleClassWithSome SimpleClassWithAll/) {
210 foreach my $role (qw/Abstract ConcreteA ConcreteB/) {
211 ok( $class->does($role), "$class does $role");
212 }
213
214 foreach my $method (qw/method other another/) {
215 can_ok( $class, $method );
216 }
217
218 is( eval { $class->another }, "abstract", "provided by abstract" );
219 is( eval { $class->other }, "concrete a", "provided by concrete a" );
220 is( eval { $class->method }, "concrete b", "provided by concrete b" );
d03bd989 221 }
0558683c 222
223 {
224 package ClassWithSome;
225 use Moose;
d03bd989 226
0558683c 227 eval { with ::shuffle qw/ConcreteC ConcreteB/ };
228 ::ok( !$@, "composition without abstract" ) || ::diag $@;
229
230 package ClassWithAll;
231 use Moose;
232
233 eval { with ::shuffle qw/ConcreteC Abstract ConcreteB/ };
234 ::ok( !$@, "composition with abstract" ) || ::diag $@;
235
236 package ClassWithEverything;
237 use Moose;
238
239 eval { with ::shuffle qw/ConcreteC Abstract ConcreteA ConcreteB/ }; # this should clash
240 ::ok( !$@, "can compose ConcreteA and ConcreteC together" );
241 }
242
243 foreach my $class (qw/ClassWithSome ClassWithAll ClassWithEverything/) {
244 foreach my $role (qw/Abstract ConcreteA ConcreteB ConcreteC/) {
245 ok( $class->does($role), "$class does $role");
246 }
247
248 foreach my $method (qw/method other another/) {
249 can_ok( $class, $method );
250 }
251
252 is( eval { $class->another }, "abstract", "provided by abstract" );
253 is( eval { $class->other }, "concrete a + c", "provided by concrete c + a" );
254 is( eval { $class->method }, "concrete b", "provided by concrete b" );
255 }
256}