make it less easy to want moose stringy types
[catagits/Catalyst-Runtime.git] / t / arg_constraints.t
CommitLineData
d91504e3 1use warnings;
2use strict;
b4037086 3use HTTP::Request::Common;
d2b583c3 4use utf8;
842180f7 5
6BEGIN {
7 use Test::More;
8748abc5 8 eval "use Type::Tiny 1.000005; 1" || do {
ea3943b8 9 plan skip_all => "Trouble loading Type::Tiny and friends => $@";
842180f7 10 };
ea3943b8 11}
6f0b85d2 12
ea3943b8 13BEGIN {
6f0b85d2 14 package MyApp::Types;
15 $INC{'MyApp/Types.pm'} = __FILE__;
16
17 use strict;
18 use warnings;
19
20 use Type::Utils -all;
21 use Types::Standard -types;
22 use Type::Library
23 -base,
d2b583c3 24 -declare => qw( UserId Heart User ContextLike );
6f0b85d2 25
26 extends "Types::Standard";
27
28 class_type User, { class => "MyApp::Model::User::user" };
29 duck_type ContextLike, [qw/model/];
30
31 declare UserId,
32 as Int,
33 where { $_ < 5 };
34
d2b583c3 35 declare Heart,
36 as Str,
37 where { $_ eq '♥' };
38
a7ab9aa9 39 # Tests using this are skipped pending deeper thought
6f0b85d2 40 coerce User,
41 from ContextLike,
42 via { $_->model('User')->find( $_->req->args->[0] ) };
842180f7 43}
d91504e3 44
45{
6f0b85d2 46 package MyApp::Model::User;
47 $INC{'MyApp/Model/User.pm'} = __FILE__;
48
49 use base 'Catalyst::Model';
50
51 our %users = (
52 1 => { name => 'john', age => 46 },
53 2 => { name => 'mary', age => 36 },
54 3 => { name => 'ian', age => 25 },
55 4 => { name => 'visha', age => 18 },
56 );
57
58 sub find {
59 my ($self, $id) = @_;
60 my $user = $users{$id} || return;
61 return bless $user, "MyApp::Model::User::user";
62 }
63
d91504e3 64 package MyApp::Controller::Root;
65 $INC{'MyApp/Controller/Root.pm'} = __FILE__;
66
67 use Moose;
68 use MooseX::MethodAttributes;
d2b583c3 69 use MyApp::Types qw/Tuple Int Str StrMatch ArrayRef UserId User Heart/;
d91504e3 70
71 extends 'Catalyst::Controller';
72
6f0b85d2 73 sub user :Local Args(UserId) {
74 my ($self, $c, $int) = @_;
75 my $user = $c->model("User")->find($int);
76 $c->res->body("name: $user->{name}, age: $user->{age}");
77 }
78
a7ab9aa9 79 # Tests using this are current skipped pending coercion rethink
6f0b85d2 80 sub user_object :Local Args(User) Coerce(1) {
81 my ($self, $c, $user) = @_;
82 $c->res->body("name: $user->{name}, age: $user->{age}");
83 }
84
75ce30d0 85 sub stringy_enum :Local Args('Int',Int) {
86 my ($self, $c) = @_;
87 $c->res->body('enum');
88 }
89
6d62355b 90 sub an_int :Local Args(Int) {
91 my ($self, $c, $int) = @_;
6d62355b 92 $c->res->body('an_int');
93 }
94
bf4f1643 95 sub two_ints :Local Args(Int,Int) {
96 my ($self, $c, $int) = @_;
97 $c->res->body('two_ints');
98 }
99
4a0218ca 100 sub many_ints :Local Args(ArrayRef[Int]) {
101 my ($self, $c, $int) = @_;
102 $c->res->body('many_ints');
103 }
104
842180f7 105 sub tuple :Local Args(Tuple[Str,Int]) {
6f0b85d2 106 my ($self, $c, $str, $int) = @_;
842180f7 107 $c->res->body('tuple');
108 }
109
6f0b85d2 110 sub match :Local Args(StrMatch[qr{\d\d-\d\d-\d\d}]) {
111 my ($self, $c, $int) = @_;
112 $c->res->body('match');
113 }
a82c96cf 114
e5604544 115 sub any_priority :Path('priority_test') Args(1) { $_[1]->res->body('any_priority') }
842180f7 116
b7791bd7 117 sub int_priority :Path('priority_test') Args(Int) { $_[1]->res->body('int_priority') }
e5604544 118
a82c96cf 119 sub chain_base :Chained(/) CaptureArgs(1) { }
120
90102012 121 sub any_priority_chain :GET Chained(chain_base) PathPart('') Args(1) { $_[1]->res->body('any_priority_chain') }
a82c96cf 122
123 sub int_priority_chain :Chained(chain_base) PathPart('') Args(Int) { $_[1]->res->body('int_priority_chain') }
124
480d94b5 125 sub link_any :Chained(chain_base) PathPart('') CaptureArgs(1) { }
126
127 sub any_priority_link_any :Chained(link_any) PathPart('') Args(1) { $_[1]->res->body('any_priority_link_any') }
128
129 sub int_priority_link_any :Chained(link_any) PathPart('') Args(Int) { $_[1]->res->body('int_priority_link_any') }
130
a82c96cf 131 sub link_int :Chained(chain_base) PathPart('') CaptureArgs(Int) { }
132
133 sub any_priority_link :Chained(link_int) PathPart('') Args(1) { $_[1]->res->body('any_priority_link') }
134
135 sub int_priority_link :Chained(link_int) PathPart('') Args(Int) { $_[1]->res->body('int_priority_link') }
136
677c155c 137 sub link_int_int :Chained(chain_base) PathPart('') CaptureArgs(Int,Int) { }
bf4f1643 138
139 sub any_priority_link2 :Chained(link_int_int) PathPart('') Args(1) { $_[1]->res->body('any_priority_link2') }
140
141 sub int_priority_link2 :Chained(link_int_int) PathPart('') Args(Int) { $_[1]->res->body('int_priority_link2') }
142
677c155c 143 sub link_tuple :Chained(chain_base) PathPart('') CaptureArgs(Tuple[Int,Int,Int]) { }
144
145 sub any_priority_link3 :Chained(link_tuple) PathPart('') Args(1) { $_[1]->res->body('any_priority_link3') }
146
147 sub int_priority_link3 :Chained(link_tuple) PathPart('') Args(Int) { $_[1]->res->body('int_priority_link3') }
148
b6847871 149 sub link2_int :Chained(link_tuple) PathPart('') CaptureArgs(UserId) { }
150
79b7db20 151 sub finally2 :GET Chained(link2_int) PathPart('') Args { $_[1]->res->body('finally2') }
90102012 152 sub finally :GET Chained(link2_int) PathPart('') Args(Int) { $_[1]->res->body('finally') }
a82c96cf 153
aef0cb5d 154 sub chain_base2 :Chained(/) CaptureArgs(1) { }
155
70949f28 156 sub chained_zero_again : Chained(chain_base2) PathPart('') Args(0) { $_[1]->res->body('chained_zero_again') }
157 sub chained_zero_post2 : Chained(chain_base2) PathPart('') Args(0) { $_[1]->res->body('chained_zero_post2') }
aef0cb5d 158 sub chained_zero2 : Chained(chain_base2) PathPart('') Args(0) { $_[1]->res->body('chained_zero2') }
159
70949f28 160 sub chained_zero_post3 : Chained(chain_base2) PathPart('') Args(1) { $_[1]->res->body('chained_zero_post3') }
aef0cb5d 161 sub chained_zero3 : Chained(chain_base2) PathPart('') Args(1) { $_[1]->res->body('chained_zero3') }
162
163
d2b583c3 164 sub heart :Local Args(Heart) { }
165
166 sub utf8_base :Chained(/) CaptureArgs(Heart) { }
167 sub utf8_end :Chained(utf8_base) PathPart('') Args(Heart) { }
168
6d62355b 169 sub default :Default {
170 my ($self, $c, $int) = @_;
171 $c->res->body('default');
d91504e3 172 }
173
174 MyApp::Controller::Root->config(namespace=>'');
175
176 package MyApp;
177 use Catalyst;
178
179 MyApp->setup;
180}
181
182use Catalyst::Test 'MyApp';
183
184{
6d62355b 185 my $res = request '/an_int/1';
186 is $res->content, 'an_int';
187}
188
189{
337a627a 190 my $res = request '/an_int/aa';
191 is $res->content, 'default';
192}
193
194{
4a0218ca 195 my $res = request '/many_ints/1';
196 is $res->content, 'many_ints';
197}
198
199{
200 my $res = request '/many_ints/1/2';
201 is $res->content, 'many_ints';
202}
203
204{
205 my $res = request '/many_ints/1/2/3';
206 is $res->content, 'many_ints';
207}
208
209{
e5604544 210 my $res = request '/priority_test/1';
211 is $res->content, 'int_priority';
212}
842180f7 213
e5604544 214{
215 my $res = request '/priority_test/a';
216 is $res->content, 'any_priority';
217}
218
842180f7 219{
6f0b85d2 220 my $res = request '/match/11-22-33';
221 is $res->content, 'match';
222}
81436df9 223
6f0b85d2 224{
225 my $res = request '/match/aaa';
226 is $res->content, 'default';
227}
228
229{
230 my $res = request '/user/2';
231 is $res->content, 'name: mary, age: 36';
232}
233
234{
235 my $res = request '/user/20';
236 is $res->content, 'default';
237}
238
a7ab9aa9 239
240SKIP: {
241 skip "coercion support needs more thought", 1;
6f0b85d2 242 my $res = request '/user_object/20';
243 is $res->content, 'default';
244}
245
a7ab9aa9 246SKIP: {
247 skip "coercion support needs more thought", 1;
6f0b85d2 248 my $res = request '/user_object/2';
249 is $res->content, 'name: mary, age: 36';
250}
251
a82c96cf 252{
253 my $res = request '/chain_base/capture/arg';
254 is $res->content, 'any_priority_chain';
255}
256
257{
258 my $res = request '/chain_base/cap1/100/arg';
259 is $res->content, 'any_priority_link';
260}
261
262{
263 my $res = request '/chain_base/cap1/101/102';
264 is $res->content, 'int_priority_link';
265}
266
267{
268 my $res = request '/chain_base/capture/100';
269 is $res->content, 'int_priority_chain', 'got expected';
270}
271
480d94b5 272{
273 my $res = request '/chain_base/cap1/a/arg';
274 is $res->content, 'any_priority_link_any';
275}
276
277{
278 my $res = request '/chain_base/cap1/a/102';
279 is $res->content, 'int_priority_link_any';
280}
281
bf4f1643 282{
283 my $res = request '/two_ints/1/2';
284 is $res->content, 'two_ints';
285}
286
287{
288 my $res = request '/two_ints/aa/111';
289 is $res->content, 'default';
290}
291
292{
293 my $res = request '/tuple/aaa/aaa';
294 is $res->content, 'default';
295}
296
297{
298 my $res = request '/tuple/aaa/111';
299 is $res->content, 'tuple';
300}
301
302{
303 my $res = request '/many_ints/1/2/a';
304 is $res->content, 'default';
305}
306
307{
308 my $res = request '/chain_base/100/100/100/100';
309 is $res->content, 'int_priority_link2';
310}
311
312{
313 my $res = request '/chain_base/100/ss/100/100';
314 is $res->content, 'default';
315}
316
677c155c 317{
318 my $res = request '/chain_base/100/100/100/100/100';
319 is $res->content, 'int_priority_link3';
320}
321
322{
323 my $res = request '/chain_base/100/ss/100/100/100';
324 is $res->content, 'default';
325}
326
79b7db20 327{
328 my $res = request '/chain_base/1/2/3/3/3/6';
329 is $res->content, 'finally';
330}
331
332{
333 my $res = request '/chain_base/1/2/3/3/3/a';
334 is $res->content, 'finally2';
335}
bf4f1643 336
79b7db20 337{
338 my $res = request '/chain_base/1/2/3/3/3/6/7/8/9';
339 is $res->content, 'finally2';
340}
341
b4037086 342
343{
aef0cb5d 344 my $res = request PUT '/chain_base2/capture/1';
70949f28 345 is $res->content, 'chained_zero3', "request PUT '/chain_base2/capture/1'";
aef0cb5d 346}
347
348{
349 my $res = request '/chain_base2/capture/1';
70949f28 350 is $res->content, 'chained_zero3', "request '/chain_base2/capture/1'";
aef0cb5d 351}
352
353{
354 my $res = request POST '/chain_base2/capture/1';
70949f28 355 is $res->content, 'chained_zero3', "request POST '/chain_base2/capture/1'";
aef0cb5d 356}
357
358{
359 my $res = request PUT '/chain_base2/capture';
70949f28 360 is $res->content, 'chained_zero2', "request PUT '/chain_base2/capture'";
b4037086 361}
362
363{
aef0cb5d 364 my $res = request '/chain_base2/capture';
70949f28 365 is $res->content, 'chained_zero2', "request '/chain_base2/capture'";
b4037086 366}
367
368{
aef0cb5d 369 my $res = request POST '/chain_base2/capture';
70949f28 370 is $res->content, 'chained_zero2', "request POST '/chain_base2/capture'";
b4037086 371}
372
75ce30d0 373{
374 my $res = request '/stringy_enum/1/2';
375 is $res->content, 'enum', "request '/stringy_enum/a'";
376}
377
378{
379 my $res = request '/stringy_enum/b/2';
380 is $res->content, 'default', "request '/stringy_enum/a'";
381}
382
383{
384 my $res = request '/stringy_enum/1/a';
385 is $res->content, 'default', "request '/stringy_enum/a'";
386}
387
b4037086 388=over
389
390| /chain_base/*/*/*/*/*/* | /chain_base (1)
391| | -> /link_tuple (Tuple[Int,Int,Int])
392| | -> /link2_int (UserId)
393| | => GET /finally (Int)
394
b6847871 395=cut
396
397{
398 # URI testing
399 my ($res, $c) = ctx_request '/';
b6847871 400
86a399db 401 {
402 ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('user'), 2) };
403 is $url, 'http://localhost/user/2';
404 }
c1192f1e 405
86a399db 406 {
407 ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('user'), [2]) };
408 is $url, 'http://localhost/user/2';
409 }
c1192f1e 410
86a399db 411 {
412 ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('user'), [20]) };
413 }
414
415 {
416 ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('finally'), [1,2,3,4,4],6) };
417 is $url, 'http://localhost/chain_base/1/2/3/4/4/6';
418 }
419
420 {
421 ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('finally'), [1,2,3,4,4,6]) };
422 is $url, 'http://localhost/chain_base/1/2/3/4/4/6';
423 }
424
425 {
426 ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('finally'), [1,2,3,4,5,6]) };
427 }
428
429 {
430 ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('finally'), ['a',2,3,4,4,6]) };
431 is $url, 'http://localhost/chain_base/a/2/3/4/4/6';
432 }
433
434 {
435 ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('finally'), ['a','1',3,4,4,'a']) };
436 }
437
438 {
439 ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('finally'), ['a','a',3,4,4,'6']) };
440 }
c1192f1e 441
d2b583c3 442 {
443 ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('heart'), ['♥']) };
444 is $url, 'http://localhost/heart/%E2%99%A5';
445 }
cbe13760 446
d2b583c3 447 {
448 ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('heart'), ['1']) };
449 }
86a399db 450
d2b583c3 451 {
452 ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('utf8_end'), ['♥','♥']) };
453 is $url, 'http://localhost/utf8_base/%E2%99%A5/%E2%99%A5';
454 }
cbe13760 455
d2b583c3 456 {
457 ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('utf8_end'), ['2','1']) };
458 }
cbe13760 459
d2b583c3 460}
86a399db 461
d2b583c3 462done_testing;