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