5bceb08d18c00a8575b00475f9ce6243e2d523cb
[gitmo/MooseX-Types-Structured.git] / t / 02-constraints.t
1 BEGIN {
2         use strict;
3         use warnings;
4         use Test::More tests=>47;
5         use Test::Exception;
6 }
7
8 {
9     package Test::MooseX::Meta::TypeConstraint::Structured;
10
11     use Moose;
12     use MooseX::Types::Structured qw(Tuple Dict Optional);
13         use Moose::Util::TypeConstraints;
14
15     subtype 'MyString',
16      as 'Str',
17      where { $_=~m/abc/};
18
19     has 'tuple' => (is=>'rw', isa=>Tuple['Int', 'Str', 'MyString']);
20     has 'dict' => (is=>'rw', isa=>Dict[name=>'Str', age=>'Int']);
21     has 'dict_with_maybe' => (is=>'rw', isa=>Dict[name=>'Str', age=>'Maybe[Int]']);     
22         has 'tuple_with_param' => (is=>'rw', isa=>Tuple['Int', 'Str', 'ArrayRef[Int]']);
23         has 'tuple_with_maybe' => (is=>'rw', isa=>Tuple['Int', 'Str', 'Maybe[Int]']);
24         has 'dict_with_tuple' => (is=>'rw', isa=>Dict[key1=>'Str', key2=>Tuple['Int','Str']]);
25     has 'optional_tuple' => (is=>'rw', isa=>Tuple['Int', 'Int', Optional['Int']] );
26     has 'optional_dict' => (is=>'rw', isa=>Dict[key1=>'Int', Optional[key2=>'Int']] );
27     has 'dict_with_tuple_with_union' => (is=>'rw', isa=>Dict[key1=>'Str|Object', key2=>Tuple['Int','Str|Object']] );
28         
29     has 'crazy' => (
30         is=>'rw',
31         isa=>Tuple
32             ## First ArrayRef Arg is the required type constraints for the top
33             ## level Tuple.
34             [
35                 'Int',
36                 'MyString',
37                 ## The third required element is a Dict type constraint, which
38                 ## itself has two required keys and a third optional key.
39                 Dict[name=>'Str',age=>'Int', Optional[visits=>'Int']],
40                 Optional[
41                     'Int',
42                     ## This Tuple has one required type constraint and two optional.
43                     Tuple['Int', Optional['Int','HashRef']],                    
44                 ],
45             ],      
46     );
47 }
48
49 ## Instantiate a new test object
50
51 ok my $record = Test::MooseX::Meta::TypeConstraint::Structured->new
52  => 'Instantiated new Record test class.';
53  
54 isa_ok $record => 'Test::MooseX::Meta::TypeConstraint::Structured'
55  => 'Created correct object type.';
56  
57 ## Test crazy
58
59 lives_ok sub {
60     $record->crazy([1,'hello.abc.world', {name=>'John', age=>39}]);
61 } => 'Set crazy attribute with no optionals used';
62
63 is_deeply $record->crazy, [1, 'hello.abc.world', {name=>'John', age=>39}]
64  => 'correct values for crazy attributes no optionals';
65  
66 lives_ok sub {
67     $record->crazy([1,'hello.abc.world', {name=>'John', age=>39, visits=>10},10, [1,2,{key=>'value'}]]);
68 } => 'Set crazy attribute with all optionals used';
69
70 is_deeply $record->crazy, [1,'hello.abc.world', {name=>'John', age=>39, visits=>10},10, [1,2,{key=>'value'}]]
71  => 'correct values for crazy attributes all optionals';
72
73 lives_ok sub {
74     $record->crazy([1,'hello.abc.world', {name=>'John', age=>39},10, [1,2]]);
75 } => 'Set crazy attribute with some optionals used';
76
77 throws_ok sub {
78     $record->crazy([1,'hello', 'test.xxx.test']);    
79 }, qr/Validation failed for 'MyString'/
80  => 'Properly failed for bad value in crazy attribute 01';
81
82 throws_ok sub {
83     $record->crazy([1,'hello.abc.world', {notname=>'John', notage=>39}]);    
84 }, qr/Validation failed for 'Str'/
85  => 'Properly failed for bad value in crazy attribute 02';
86  
87 ## Test Tuple type constraint
88
89 lives_ok sub {
90     $record->tuple([1,'hello', 'test.abc.test']);
91 } => 'Set tuple attribute without error';
92
93 is $record->tuple->[0], 1
94  => 'correct set the tuple attribute index 0';
95
96 is $record->tuple->[1], 'hello'
97  => 'correct set the tuple attribute index 1';
98
99 is $record->tuple->[2], 'test.abc.test'
100  => 'correct set the tuple attribute index 2';
101
102 throws_ok sub {
103     $record->tuple([1,'hello', 'test.xxx.test']);    
104 }, qr/Validation failed for 'MyString'/
105  => 'Properly failed for bad value in custom type constraint';
106  
107 throws_ok sub {
108     $record->tuple(['asdasd',2, 'test.abc.test']);      
109 }, qr/Validation failed for 'Int'/
110  => 'Got Expected Error for violating constraints';
111
112 ## Test the Dictionary type constraint
113  
114 lives_ok sub {
115     $record->dict({name=>'frith', age=>23});
116 } => 'Set dict attribute without error';
117
118 is $record->dict->{name}, 'frith'
119  => 'correct set the dict attribute name';
120
121 is $record->dict->{age}, 23
122  => 'correct set the dict attribute age';
123  
124 throws_ok sub {
125     $record->dict({name=>[1,2,3], age=>'sdfsdfsd'});      
126 }, qr/Validation failed for 'Str'/
127  => 'Got Expected Error for bad value in dict';
128
129 ## Test tuple_with_maybe
130
131 lives_ok sub {
132     $record->tuple_with_maybe([1,'hello', 1]);
133 } => 'Set tuple attribute without error';
134
135 throws_ok sub {
136     $record->tuple_with_maybe([1,'hello', 'a']);
137 }, qr/Validation failed for 'Maybe\[Int\]'/
138  => 'Properly failed for bad value parameterized constraint';
139
140 lives_ok sub {
141     $record->tuple_with_maybe([1,'hello']);
142 } => 'Set tuple attribute without error skipping optional parameter';
143
144 ## Test Tuple with parameterized type
145
146 lives_ok sub {
147     $record->tuple_with_param([1,'hello', [1,2,3]]);
148 } => 'Set tuple attribute without error';
149
150 throws_ok sub {
151     $record->tuple_with_param([1,'hello', [qw/a b c/]]);
152 }, qr/Validation failed for 'ArrayRef\[Int\]'/
153  => 'Properly failed for bad value parameterized constraint';
154
155 ## Test dict_with_maybe
156
157 lives_ok sub {
158     $record->dict_with_maybe({name=>'frith', age=>23});
159 } => 'Set dict attribute without error';
160
161 is $record->dict_with_maybe->{name}, 'frith'
162  => 'correct set the dict attribute name';
163
164 is $record->dict_with_maybe->{age}, 23
165  => 'correct set the dict attribute age';
166  
167 throws_ok sub {
168     $record->dict_with_maybe({name=>[1,2,3], age=>'sdfsdfsd'});      
169 }, qr/Validation failed for 'Str'/
170  => 'Got Expected Error for bad value in dict';
171
172 throws_ok sub {
173     $record->dict_with_maybe({age=>30});      
174 }, qr/Validation failed for 'Str'/
175  => 'Got Expected Error for missing named parameter';
176
177 lives_ok sub {
178     $record->dict_with_maybe({name=>'usal'});
179 } => 'Set dict attribute without error, skipping optional';
180
181 ## Test dict_with_tuple
182
183 lives_ok sub {
184     $record->dict_with_tuple({key1=>'Hello', key2=>[1,'World']});
185 } => 'Set tuple attribute without error';
186
187 throws_ok sub {
188     $record->dict_with_tuple({key1=>'Hello', key2=>['World',2]});
189 }, qr/Validation failed for 'Int'/
190  => 'Threw error on bad constraint';
191
192 ## Test optional_tuple
193
194 lives_ok sub {
195     $record->optional_tuple([1,2,3]);
196 } => 'Set tuple attribute with optional bits';
197
198 is_deeply $record->optional_tuple, [1,2,3]
199  => 'correct values set';
200  
201 lives_ok sub {
202     $record->optional_tuple([4,5]);
203 } => 'Set tuple attribute withOUT optional bits';
204
205 is_deeply $record->optional_tuple, [4,5]
206  => 'correct values set again';
207  
208 throws_ok sub {
209     $record->optional_tuple([1,2,'bad']);   
210 }, qr/Validation failed for 'Int'/
211  => 'Properly failed for bad value in optional bit';
212
213 # Test optional_dict
214
215 lives_ok sub {
216     $record->optional_dict({key1=>1,key2=>2});
217 } => 'Set tuple attribute with optional bits';
218
219 is_deeply $record->optional_dict, {key1=>1,key2=>2}
220  => 'correct values set';
221  
222 lives_ok sub {
223     $record->optional_dict({key1=>3});
224 } => 'Set tuple attribute withOUT optional bits';
225
226 is_deeply $record->optional_dict, {key1=>3}
227  => 'correct values set again';
228  
229 throws_ok sub {
230     $record->optional_dict({key1=>1,key2=>'bad'});   
231 }, qr/Validation failed for 'Int'/
232  => 'Properly failed for bad value in optional bit';
233
234
235 ## Test dict_with_tuple_with_union: Dict[key1=>'Str|Object', key2=>Tuple['Int','Str|Object']]
236
237 lives_ok sub {
238     $record->dict_with_tuple_with_union({key1=>'Hello', key2=>[1,'World']});
239 } => 'Set tuple attribute without error';
240
241 throws_ok sub {
242     $record->dict_with_tuple_with_union({key1=>'Hello', key2=>['World',2]});
243 }, qr/Validation failed for 'Int'/
244  => 'Threw error on bad constraint';
245  
246 lives_ok sub {
247     $record->dict_with_tuple_with_union({key1=>$record, key2=>[1,'World']});
248 } => 'Set tuple attribute without error';
249
250 lives_ok sub {
251     $record->dict_with_tuple_with_union({key1=>'Hello', key2=>[1,$record]});
252 } => 'Set tuple attribute without error';
253
254 throws_ok sub {
255     $record->dict_with_tuple_with_union({key1=>1, key2=>['World',2]});
256 }, qr/Validation failed for 'Int'/
257  => 'Threw error on bad constraint';