DEATH TO ALL zionist ELLIPSES
[gitmo/Moose.git] / t / 040_type_constraints / 001_util_type_constraints.t
CommitLineData
a15dff8d 1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
f75f625d 6use Test::More tests => 85;
a15dff8d 7use Test::Exception;
8
9use Scalar::Util ();
10
e3979c3e 11use Moose::Util::TypeConstraints;
12
a15dff8d 13
5a4c5493 14type Number => where { Scalar::Util::looks_like_number($_) };
d03bd989 15type String
c899258b 16 => where { !ref($_) && !Number($_) }
17 => message { "This is not a string ($_)" };
a15dff8d 18
d03bd989 19subtype Natural
20 => as Number
4ed9b9b4 21 => where { $_ > 0 };
a15dff8d 22
d03bd989 23subtype NaturalLessThanTen
4ed9b9b4 24 => as Natural
25 => where { $_ < 10 }
26 => message { "The number '$_' is not less than 10" };
d03bd989 27
d9b40005 28Moose::Util::TypeConstraints->export_type_constraints_as_functions();
a15dff8d 29
1808c2da 30ok(Number(5), 'this is a Num');
31ok(!defined(Number('Foo')), 'this is not a Num');
900466d6 32{
33 my $number_tc = Moose::Util::TypeConstraints::find_type_constraint('Number');
1808c2da 34 is("$number_tc", 'Number', 'type constraint stringifies to name');
900466d6 35}
a15dff8d 36
1808c2da 37ok(String('Foo'), 'this is a Str');
38ok(!defined(String(5)), 'this is not a Str');
a15dff8d 39
1808c2da 40ok(Natural(5), 'this is a Natural');
41is(Natural(-5), undef, 'this is not a Natural');
42is(Natural('Foo'), undef, 'this is not a Natural');
a15dff8d 43
1808c2da 44ok(NaturalLessThanTen(5), 'this is a NaturalLessThanTen');
45is(NaturalLessThanTen(12), undef, 'this is not a NaturalLessThanTen');
46is(NaturalLessThanTen(-5), undef, 'this is not a NaturalLessThanTen');
47is(NaturalLessThanTen('Foo'), undef, 'this is not a NaturalLessThanTen');
d03bd989 48
49# anon sub-typing
50
4ed9b9b4 51my $negative = subtype Number => where { $_ < 0 };
1808c2da 52ok(defined $negative, 'got a value back from negative');
66811d63 53isa_ok($negative, 'Moose::Meta::TypeConstraint');
a15dff8d 54
1808c2da 55ok($negative->check(-5), 'this is a negative number');
56ok(!defined($negative->check(5)), 'this is not a negative number');
57is($negative->check('Foo'), undef, 'this is not a negative number');
a27aa600 58
1808c2da 59ok($negative->is_subtype_of('Number'), '$negative is a subtype of Number');
60ok(!$negative->is_subtype_of('String'), '$negative is not a subtype of String');
cce8198b 61
e3979c3e 62my $negative2 = subtype Number => where { $_ < 0 } => message {"$_ is not a negative number"};
63
1808c2da 64ok(defined $negative2, 'got a value back from negative');
e3979c3e 65isa_ok($negative2, 'Moose::Meta::TypeConstraint');
66
1808c2da 67ok($negative2->check(-5), 'this is a negative number');
68ok(!defined($negative2->check(5)), 'this is not a negative number');
69is($negative2->check('Foo'), undef, 'this is not a negative number');
e3979c3e 70
1808c2da 71ok($negative2->is_subtype_of('Number'), '$negative2 is a subtype of Number');
72ok(!$negative2->is_subtype_of('String'), '$negative is not a subtype of String');
e3979c3e 73
1808c2da 74ok($negative2->has_message, 'it has a message');
d03bd989 75is($negative2->validate(2),
e3979c3e 76 '2 is not a negative number',
1808c2da 77 'validated unsuccessfully (got error)');
e3979c3e 78
76d37e5a 79# check some meta-details
80
81my $natural_less_than_ten = find_type_constraint('NaturalLessThanTen');
82isa_ok($natural_less_than_ten, 'Moose::Meta::TypeConstraint');
83
1808c2da 84ok($natural_less_than_ten->is_subtype_of('Natural'), 'NaturalLessThanTen is subtype of Natural');
85ok($natural_less_than_ten->is_subtype_of('Number'), 'NaturalLessThanTen is subtype of Number');
86ok(!$natural_less_than_ten->is_subtype_of('String'), 'NaturalLessThanTen is not subtype of String');
cce8198b 87
1808c2da 88ok($natural_less_than_ten->has_message, 'it has a message');
76d37e5a 89
1808c2da 90ok(!defined($natural_less_than_ten->validate(5)), 'validated successfully (no error)');
76d37e5a 91
d03bd989 92is($natural_less_than_ten->validate(15),
93 "The number '15' is not less than 10",
1808c2da 94 'validated unsuccessfully (got error)');
76d37e5a 95
96my $natural = find_type_constraint('Natural');
97isa_ok($natural, 'Moose::Meta::TypeConstraint');
98
1808c2da 99ok($natural->is_subtype_of('Number'), 'Natural is a subtype of Number');
100ok(!$natural->is_subtype_of('String'), 'Natural is not a subtype of String');
cce8198b 101
1808c2da 102ok(!$natural->has_message, 'it does not have a message');
76d37e5a 103
1808c2da 104ok(!defined($natural->validate(5)), 'validated successfully (no error)');
76d37e5a 105
d03bd989 106is($natural->validate(-5),
107 "Validation failed for 'Natural' failed with value -5",
1808c2da 108 'validated unsuccessfully (got error)');
a27aa600 109
c899258b 110my $string = find_type_constraint('String');
111isa_ok($string, 'Moose::Meta::TypeConstraint');
a27aa600 112
1808c2da 113ok($string->has_message, 'it does have a message');
c899258b 114
1808c2da 115ok(!defined($string->validate("Five")), 'validated successfully (no error)');
c899258b 116
d03bd989 117is($string->validate(5),
118"This is not a string (5)",
1808c2da 119'validated unsuccessfully (got error)');
8c4acc60 120
121lives_ok { Moose::Meta::Attribute->new('bob', isa => 'Spong') }
122 'meta-attr construction ok even when type constraint utils loaded first';
9758af8a 123
124# Test type constraint predicate return values.
125
126foreach my $predicate (qw/equals is_subtype_of is_a_type_of/) {
127 ok( !defined $string->$predicate('DoesNotExist'), "$predicate predicate returns undef for non existant constraint");
128}
129
130# Test adding things which don't look like types to the registry throws an exception
131
132my $r = Moose::Util::TypeConstraints->get_type_constraint_registry;
133throws_ok {$r->add_type_constraint()} qr/not a valid type constraint/, '->add_type_constraint(undef) throws';
134throws_ok {$r->add_type_constraint('foo')} qr/not a valid type constraint/, '->add_type_constraint("foo") throws';
135throws_ok {$r->add_type_constraint(bless {}, 'SomeClass')} qr/not a valid type constraint/, '->add_type_constraint(SomeClass->new) throws';
136
9a63faba 137# Test some specific things that in the past did not work,
138# specifically weird variations on anon subtypes.
139
140{
141 my $subtype = subtype as 'Str';
142 isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got an anon subtype' );
143 is( $subtype->parent->name, 'Str', 'parent is Str' );
144 # This test sucks but is the best we can do
145 is( $subtype->constraint->(), 1,
146 'subtype has the null constraint' );
147 ok( ! $subtype->has_message, 'subtype has no message' );
148}
149
150{
f75f625d 151 my $subtype = subtype as 'ArrayRef[Num|Str]';
9a63faba 152 isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got an anon subtype' );
153 is( $subtype->parent->name, 'ArrayRef[Num|Str]', 'parent is ArrayRef[Num|Str]' );
154 ok( ! $subtype->has_message, 'subtype has no message' );
155}
156
157{
158 my $subtype = subtype 'ArrayRef[Num|Str]' => message { 'foo' };
159 isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got an anon subtype' );
160 is( $subtype->parent->name, 'ArrayRef[Num|Str]', 'parent is ArrayRef[Num|Str]' );
161 ok( $subtype->has_message, 'subtype does have a message' );
162}
163
9e856c83 164# alternative sugar-less calling style which is documented as legit:
165{
166 my $subtype = subtype( 'MyStr', { as => 'Str' } );
167 isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got a subtype' );
168 is( $subtype->name, 'MyStr', 'name is MyStr' );
169 is( $subtype->parent->name, 'Str', 'parent is Str' );
170}
171
172{
173 my $subtype = subtype( { as => 'Str' } );
174 isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got a subtype' );
175 is( $subtype->name, '__ANON__', 'name is __ANON__' );
176 is( $subtype->parent->name, 'Str', 'parent is Str' );
177}
178
179{
180 my $subtype = subtype( { as => 'Str', where => sub { /X/ } } );
181 isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got a subtype' );
182 is( $subtype->name, '__ANON__', 'name is __ANON__' );
183 is( $subtype->parent->name, 'Str', 'parent is Str' );
184 ok( $subtype->check('FooX'), 'constraint accepts FooX' );
185 ok( ! $subtype->check('Foo'), 'constraint reject Foo' );
186}
187
f75f625d 188{
189 throws_ok { subtype 'Foo' } qr/cannot consist solely of a name/,
190 'Cannot call subtype with a single string argument';
191}
9e856c83 192
9a63faba 193# Back-compat for being called without sugar. Previously, calling with
194# sugar was indistinguishable from calling directly.
195
196{
197 my $type = type( 'Number2', sub { Scalar::Util::looks_like_number($_) } );
198
1808c2da 199 ok( $type->check(5), 'this is a Num' );
200 ok( ! $type->check('Foo'), 'this is not a Num' );
9a63faba 201}
202
203{
204 # anon subtype
205 my $subtype = subtype( 'Number2', sub { $_ > 0 } );
206
1808c2da 207 ok( $subtype->check(5), 'this is a Natural');
208 ok( ! $subtype->check(-5), 'this is not a Natural');
209 ok( ! $subtype->check('Foo'), 'this is not a Natural');
9a63faba 210}
211
212{
213 my $subtype = subtype( 'Natural2', 'Number2', sub { $_ > 0 } );
214
1808c2da 215 ok( $subtype->check(5), 'this is a Natural');
216 ok( ! $subtype->check(-5), 'this is not a Natural');
217 ok( ! $subtype->check('Foo'), 'this is not a Natural');
9a63faba 218}
219
220{
221 my $subtype = subtype( 'Natural3', 'Number2' );
222
1808c2da 223 ok( $subtype->check(5), 'this is a Natural');
224 ok( $subtype->check(-5), 'this is a Natural');
225 ok( ! $subtype->check('Foo'), 'this is not a Natural');
9a63faba 226}
227