Convert all tests to done_testing.
[gitmo/Moose.git] / t / 040_type_constraints / 001_util_type_constraints.t
CommitLineData
a15dff8d 1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
a28e50e4 6use Test::More;
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
5a4c5493 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');
b644e331 34 is("$number_tc", 'Number', '... type constraint stringifies to name');
900466d6 35}
a15dff8d 36
5a4c5493 37ok(String('Foo'), '... this is a Str');
a15dff8d 38ok(!defined(String(5)), '... this is not a Str');
39
5a4c5493 40ok(Natural(5), '... this is a Natural');
a15dff8d 41is(Natural(-5), undef, '... this is not a Natural');
42is(Natural('Foo'), undef, '... this is not a Natural');
43
5a4c5493 44ok(NaturalLessThanTen(5), '... this is a NaturalLessThanTen');
a15dff8d 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 };
a15dff8d 52ok(defined $negative, '... got a value back from negative');
66811d63 53isa_ok($negative, 'Moose::Meta::TypeConstraint');
a15dff8d 54
5a4c5493 55ok($negative->check(-5), '... this is a negative number');
a27aa600 56ok(!defined($negative->check(5)), '... this is not a negative number');
57is($negative->check('Foo'), undef, '... this is not a negative number');
58
cce8198b 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');
61
e3979c3e 62my $negative2 = subtype Number => where { $_ < 0 } => message {"$_ is not a negative number"};
63
64ok(defined $negative2, '... got a value back from negative');
65isa_ok($negative2, 'Moose::Meta::TypeConstraint');
66
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');
70
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');
73
74ok($negative2->has_message, '... it has a message');
d03bd989 75is($negative2->validate(2),
e3979c3e 76 '2 is not a negative number',
77 '... validated unsuccessfully (got error)');
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
cce8198b 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');
87
76d37e5a 88ok($natural_less_than_ten->has_message, '... it has a message');
89
90ok(!defined($natural_less_than_ten->validate(5)), '... validated successfully (no error)');
91
d03bd989 92is($natural_less_than_ten->validate(15),
93 "The number '15' is not less than 10",
76d37e5a 94 '... validated unsuccessfully (got error)');
95
96my $natural = find_type_constraint('Natural');
97isa_ok($natural, 'Moose::Meta::TypeConstraint');
98
cce8198b 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');
101
76d37e5a 102ok(!$natural->has_message, '... it does not have a message');
103
104ok(!defined($natural->validate(5)), '... validated successfully (no error)');
105
d03bd989 106is($natural->validate(-5),
107 "Validation failed for 'Natural' failed with value -5",
76d37e5a 108 '... validated unsuccessfully (got error)');
a27aa600 109
c899258b 110my $string = find_type_constraint('String');
111isa_ok($string, 'Moose::Meta::TypeConstraint');
a27aa600 112
c899258b 113ok($string->has_message, '... it does have a message');
114
115ok(!defined($string->validate("Five")), '... validated successfully (no error)');
116
d03bd989 117is($string->validate(5),
118"This is not a string (5)",
c899258b 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
199 ok( $type->check(5), '... this is a Num' );
200 ok( ! $type->check('Foo'), '... this is not a Num' );
201}
202
203{
204 # anon subtype
205 my $subtype = subtype( 'Number2', sub { $_ > 0 } );
206
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');
210}
211
212{
213 my $subtype = subtype( 'Natural2', 'Number2', sub { $_ > 0 } );
214
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');
218}
219
220{
221 my $subtype = subtype( 'Natural3', 'Number2' );
222
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');
226}
227
a28e50e4 228done_testing;