Resolve a todo
[gitmo/Mouse.git] / t / 030_roles / failing / 011_overriding.t
CommitLineData
67199842 1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
6use Test::More tests => 39;
7use Test::Exception;
8
9
10
c2d7552a 11{
67199842 12 # test no conflicts here
13 package Role::A;
14 use Mouse::Role;
15
16 sub bar { 'Role::A::bar' }
17
18 package Role::B;
19 use Mouse::Role;
20
21 sub xxy { 'Role::B::xxy' }
22
23 package Role::C;
24 use Mouse::Role;
c2d7552a 25
67199842 26 ::lives_ok {
27 with qw(Role::A Role::B); # no conflict here
28 } "define role C";
29
30 sub foo { 'Role::C::foo' }
31 sub zot { 'Role::C::zot' }
32
33 package Class::A;
34 use Mouse;
35
36 ::lives_ok {
37 with qw(Role::C);
38 } "define class A";
c2d7552a 39
67199842 40 sub zot { 'Class::A::zot' }
41}
42
43can_ok( Class::A->new, qw(foo bar xxy zot) );
44
45is( Class::A->new->foo, "Role::C::foo", "... got the right foo method" );
46is( Class::A->new->zot, "Class::A::zot", "... got the right zot method" );
47is( Class::A->new->bar, "Role::A::bar", "... got the right bar method" );
48is( Class::A->new->xxy, "Role::B::xxy", "... got the right xxy method" );
49
50{
51 # check that when a role is added to another role
c2d7552a 52 # and they conflict and the method they conflict
53 # with is then required.
54
67199842 55 package Role::A::Conflict;
56 use Mouse::Role;
c2d7552a 57
67199842 58 with 'Role::A';
c2d7552a 59
67199842 60 sub bar { 'Role::A::Conflict::bar' }
c2d7552a 61
67199842 62 package Class::A::Conflict;
63 use Mouse;
c2d7552a 64
67199842 65 ::throws_ok {
66 with 'Role::A::Conflict';
c2d7552a 67 } qr/Due to a method name conflict in roles 'Role::A' and 'Role::A::Conflict', the method 'bar' must be implemented or excluded by 'Class::A::Conflict'/, '... did not fufill the requirement of &bar method';
68
67199842 69 package Class::A::Resolved;
70 use Mouse;
c2d7552a 71
67199842 72 ::lives_ok {
73 with 'Role::A::Conflict';
c2d7552a 74 } '... did fufill the requirement of &bar method';
75
67199842 76 sub bar { 'Class::A::Resolved::bar' }
77}
78
79ok(Role::A::Conflict->meta->requires_method('bar'), '... Role::A::Conflict created the bar requirement');
80
81can_ok( Class::A::Resolved->new, qw(bar) );
82
83is( Class::A::Resolved->new->bar, 'Class::A::Resolved::bar', "... got the right bar method" );
84
85{
86 # check that when two roles are composed, they conflict
87 # but the composing role can resolve that conflict
c2d7552a 88
67199842 89 package Role::D;
90 use Mouse::Role;
91
92 sub foo { 'Role::D::foo' }
c2d7552a 93 sub bar { 'Role::D::bar' }
67199842 94
95 package Role::E;
96 use Mouse::Role;
97
98 sub foo { 'Role::E::foo' }
99 sub xxy { 'Role::E::xxy' }
100
101 package Role::F;
102 use Mouse::Role;
103
104 ::lives_ok {
105 with qw(Role::D Role::E); # conflict between 'foo's here
106 } "define role Role::F";
c2d7552a 107
67199842 108 sub foo { 'Role::F::foo' }
c2d7552a 109 sub zot { 'Role::F::zot' }
110
67199842 111 package Class::B;
112 use Mouse;
c2d7552a 113
67199842 114 ::lives_ok {
115 with qw(Role::F);
116 } "define class Class::B";
c2d7552a 117
67199842 118 sub zot { 'Class::B::zot' }
119}
120
121can_ok( Class::B->new, qw(foo bar xxy zot) );
122
123is( Class::B->new->foo, "Role::F::foo", "... got the &foo method okay" );
124is( Class::B->new->zot, "Class::B::zot", "... got the &zot method okay" );
125is( Class::B->new->bar, "Role::D::bar", "... got the &bar method okay" );
126is( Class::B->new->xxy, "Role::E::xxy", "... got the &xxy method okay" );
127
128ok(!Role::F->meta->requires_method('foo'), '... Role::F fufilled the &foo requirement');
129
130{
131 # check that a conflict can be resolved
c2d7552a 132 # by a role, but also new ones can be
67199842 133 # created just as easily ...
c2d7552a 134
67199842 135 package Role::D::And::E::Conflict;
136 use Mouse::Role;
137
138 ::lives_ok {
139 with qw(Role::D Role::E); # conflict between 'foo's here
140 } "... define role Role::D::And::E::Conflict";
c2d7552a 141
67199842 142 sub foo { 'Role::D::And::E::Conflict::foo' } # this overrides ...
c2d7552a 143
144 # but these conflict
145 sub xxy { 'Role::D::And::E::Conflict::xxy' }
146 sub bar { 'Role::D::And::E::Conflict::bar' }
67199842 147
148}
149
150ok(!Role::D::And::E::Conflict->meta->requires_method('foo'), '... Role::D::And::E::Conflict fufilled the &foo requirement');
151ok(Role::D::And::E::Conflict->meta->requires_method('xxy'), '... Role::D::And::E::Conflict adds the &xxy requirement');
152ok(Role::D::And::E::Conflict->meta->requires_method('bar'), '... Role::D::And::E::Conflict adds the &bar requirement');
153
154{
155 # conflict propagation
c2d7552a 156
67199842 157 package Role::H;
158 use Mouse::Role;
159
160 sub foo { 'Role::H::foo' }
c2d7552a 161 sub bar { 'Role::H::bar' }
67199842 162
163 package Role::J;
164 use Mouse::Role;
165
166 sub foo { 'Role::J::foo' }
167 sub xxy { 'Role::J::xxy' }
168
169 package Role::I;
170 use Mouse::Role;
171
172 ::lives_ok {
173 with qw(Role::J Role::H); # conflict between 'foo's here
174 } "define role Role::I";
c2d7552a 175
67199842 176 sub zot { 'Role::I::zot' }
177 sub zzy { 'Role::I::zzy' }
178
179 package Class::C;
180 use Mouse;
c2d7552a 181
67199842 182 ::throws_ok {
183 with qw(Role::I);
c2d7552a 184 } qr/Due to a method name conflict in roles 'Role::H' and 'Role::J', the method 'foo' must be implemented or excluded by 'Class::C'/, "defining class Class::C fails";
67199842 185
186 sub zot { 'Class::C::zot' }
187
188 package Class::E;
189 use Mouse;
190
191 ::lives_ok {
192 with qw(Role::I);
c2d7552a 193 } "resolved with method";
67199842 194
195 sub foo { 'Class::E::foo' }
c2d7552a 196 sub zot { 'Class::E::zot' }
67199842 197}
198
199can_ok( Class::E->new, qw(foo bar xxy zot) );
200
201is( Class::E->new->foo, "Class::E::foo", "... got the right &foo method" );
202is( Class::E->new->zot, "Class::E::zot", "... got the right &zot method" );
203is( Class::E->new->bar, "Role::H::bar", "... got the right &bar method" );
204is( Class::E->new->xxy, "Role::J::xxy", "... got the right &xxy method" );
205
206ok(Role::I->meta->requires_method('foo'), '... Role::I still have the &foo requirement');
207
208{
209 lives_ok {
210 package Class::D;
211 use Mouse;
212
213 has foo => ( default => __PACKAGE__ . "::foo", is => "rw" );
214
215 sub zot { 'Class::D::zot' }
216
217 with qw(Role::I);
218
219 } "resolved with attr";
220
221 can_ok( Class::D->new, qw(foo bar xxy zot) );
222 is( eval { Class::D->new->bar }, "Role::H::bar", "bar" );
223 is( eval { Class::D->new->zzy }, "Role::I::zzy", "zzy" );
224
225 is( eval { Class::D->new->foo }, "Class::D::foo", "foo" );
226 is( eval { Class::D->new->zot }, "Class::D::zot", "zot" );
227
228}
229