7 use lib "$FindBin::Bin/../lib";
11 BEGIN { $iters = $ENV{CAT_BENCH_ITERS} || 1; }
16 use Catalyst::Test 'TestApp';
18 if ( $ENV{CAT_BENCHMARK} ) {
20 Benchmark::timethis( $iters, \&run_tests );
29 my ($run_number) = @_;
32 # This is a simple test where the parent and child actions are
33 # within the same controller.
37 TestApp::Controller::Action::Chained->begin
38 TestApp::Controller::Action::Chained->foo
39 TestApp::Controller::Action::Chained->endpoint
40 TestApp::Controller::Action::Chained->end
43 my $expected = join( ", ", @expected );
45 ok( my $response = request('http://localhost/chained/foo/1/end/2'), 'chained + local endpoint' );
46 is( $response->header('X-Catalyst-Executed'),
47 $expected, 'Executed actions' );
48 is( $response->content, '1; 2', 'Content OK' );
52 # This makes sure the above isn't found if the argument for the
53 # end action isn't supplied.
58 ok( my $response = request('http://localhost/chained/foo/1/end'),
59 'chained + local endpoint; missing last argument' );
60 is( $response->header('X-Catalyst-Executed'),
61 $expected, 'Executed actions' );
62 is( $response->code, 500, 'Status OK' );
66 # Tests the case when the child action is placed in a subcontroller.
70 TestApp::Controller::Action::Chained->begin
71 TestApp::Controller::Action::Chained->foo
72 TestApp::Controller::Action::Chained::Foo->spoon
73 TestApp::Controller::Action::Chained->end
76 my $expected = join( ", ", @expected );
78 ok( my $response = request('http://localhost/chained/foo/1/spoon'), 'chained + subcontroller endpoint' );
79 is( $response->header('X-Catalyst-Executed'),
80 $expected, 'Executed actions' );
81 is( $response->content, '1; ', 'Content OK' );
85 # Tests if the relative specification (e.g.: Chained('bar') ) works
90 TestApp::Controller::Action::Chained->begin
91 TestApp::Controller::Action::Chained->bar
92 TestApp::Controller::Action::Chained->finale
93 TestApp::Controller::Action::Chained->end
96 my $expected = join( ", ", @expected );
98 ok( my $response = request('http://localhost/chained/bar/1/spoon'), 'chained + relative endpoint' );
99 is( $response->header('X-Catalyst-Executed'),
100 $expected, 'Executed actions' );
101 is( $response->content, '; 1, spoon', 'Content OK' );
105 # Just a test for multiple arguments.
109 TestApp::Controller::Action::Chained->begin
110 TestApp::Controller::Action::Chained->foo2
111 TestApp::Controller::Action::Chained->endpoint2
112 TestApp::Controller::Action::Chained->end
115 my $expected = join( ", ", @expected );
117 ok( my $response = request('http://localhost/chained/foo2/10/20/end2/15/25'),
118 'chained + local (2 args each)' );
119 is( $response->header('X-Catalyst-Executed'),
120 $expected, 'Executed actions' );
121 is( $response->content, '10, 20; 15, 25', 'Content OK' );
125 # The first three-chain test tries to call the action with :Args(1)
126 # specification. There's also a one action with a :CaptureArgs(1)
127 # attribute, that should not be dispatched to.
131 TestApp::Controller::Action::Chained->begin
132 TestApp::Controller::Action::Chained->one_end
133 TestApp::Controller::Action::Chained->end
136 my $expected = join( ", ", @expected );
138 ok( my $response = request('http://localhost/chained/one/23'),
139 'three-chain (only first)' );
140 is( $response->header('X-Catalyst-Executed'),
141 $expected, 'Executed actions' );
142 is( $response->content, '; 23', 'Content OK' );
146 # This is the second three-chain test, it goes for the action that
147 # handles "/one/$cap/two/$arg1/$arg2" paths. Should be the two action
148 # having :Args(2), not the one having :CaptureArgs(2).
152 TestApp::Controller::Action::Chained->begin
153 TestApp::Controller::Action::Chained->one
154 TestApp::Controller::Action::Chained->two_end
155 TestApp::Controller::Action::Chained->end
158 my $expected = join( ", ", @expected );
160 ok( my $response = request('http://localhost/chained/one/23/two/23/46'),
161 'three-chain (up to second)' );
162 is( $response->header('X-Catalyst-Executed'),
163 $expected, 'Executed actions' );
164 is( $response->content, '23; 23, 46', 'Content OK' );
168 # Last of the three-chain tests. Has no concurrent action with :CaptureArgs
169 # and is more thought to simply test the chain as a whole and the 'two'
170 # action specifying :CaptureArgs.
174 TestApp::Controller::Action::Chained->begin
175 TestApp::Controller::Action::Chained->one
176 TestApp::Controller::Action::Chained->two
177 TestApp::Controller::Action::Chained->three_end
178 TestApp::Controller::Action::Chained->end
181 my $expected = join( ", ", @expected );
183 ok( my $response = request('http://localhost/chained/one/23/two/23/46/three/1/2/3'),
184 'three-chain (all three)' );
185 is( $response->header('X-Catalyst-Executed'),
186 $expected, 'Executed actions' );
187 is( $response->content, '23, 23, 46; 1, 2, 3', 'Content OK' );
191 # Tests dispatching on number of arguments for :Args. This should be
192 # dispatched to the action expecting one argument.
196 TestApp::Controller::Action::Chained->begin
197 TestApp::Controller::Action::Chained->multi1
198 TestApp::Controller::Action::Chained->end
201 my $expected = join( ", ", @expected );
203 ok( my $response = request('http://localhost/chained/multi/23'),
204 'multi-action (one arg)' );
205 is( $response->header('X-Catalyst-Executed'),
206 $expected, 'Executed actions' );
207 is( $response->content, '; 23', 'Content OK' );
211 # Belongs to the former test and goes for the action expecting two arguments.
215 TestApp::Controller::Action::Chained->begin
216 TestApp::Controller::Action::Chained->multi2
217 TestApp::Controller::Action::Chained->end
220 my $expected = join( ", ", @expected );
222 ok( my $response = request('http://localhost/chained/multi/23/46'),
223 'multi-action (two args)' );
224 is( $response->header('X-Catalyst-Executed'),
225 $expected, 'Executed actions' );
226 is( $response->content, '; 23, 46', 'Content OK' );
230 # Dispatching on argument count again, this time we provide too many
231 # arguments, so dispatching should fail.
234 my $expected = undef;
236 ok( my $response = request('http://localhost/chained/multi/23/46/67'),
237 'multi-action (three args, should lead to error)' );
238 is( $response->header('X-Catalyst-Executed'),
239 $expected, 'Executed actions' );
240 is( $response->code, 500, 'Status OK' );
244 # This tests the case when an action says it's the child of an action in
249 TestApp::Controller::Action::Chained->begin
250 TestApp::Controller::Action::Chained::Foo->higher_root
251 TestApp::Controller::Action::Chained->higher_root
252 TestApp::Controller::Action::Chained->end
255 my $expected = join( ", ", @expected );
257 ok( my $response = request('http://localhost/chained/higher_root/23/bar/11'),
258 'root higher than child' );
259 is( $response->header('X-Catalyst-Executed'),
260 $expected, 'Executed actions' );
261 is( $response->content, '23; 11', 'Content OK' );
265 # Just a more complex version of the former test. It tests if a controller ->
266 # subcontroller -> controller dispatch works.
270 TestApp::Controller::Action::Chained->begin
271 TestApp::Controller::Action::Chained->pcp1
272 TestApp::Controller::Action::Chained::Foo->pcp2
273 TestApp::Controller::Action::Chained->pcp3
274 TestApp::Controller::Action::Chained->end
277 my $expected = join( ", ", @expected );
279 ok( my $response = request('http://localhost/chained/pcp1/1/pcp2/2/pcp3/3'),
280 'parent -> child -> parent' );
281 is( $response->header('X-Catalyst-Executed'),
282 $expected, 'Executed actions' );
283 is( $response->content, '1, 2; 3', 'Content OK' );
287 # Tests dispatch on capture number. This test is for a one capture action.
291 TestApp::Controller::Action::Chained->begin
292 TestApp::Controller::Action::Chained->multi_cap1
293 TestApp::Controller::Action::Chained->multi_cap_end1
294 TestApp::Controller::Action::Chained->end
297 my $expected = join( ", ", @expected );
299 ok( my $response = request('http://localhost/chained/multi_cap/1/baz'),
300 'dispatch on capture num 1' );
301 is( $response->header('X-Catalyst-Executed'),
302 $expected, 'Executed actions' );
303 is( $response->content, '1; ', 'Content OK' );
307 # Belongs to the former test. This one goes for the action expecting two
312 TestApp::Controller::Action::Chained->begin
313 TestApp::Controller::Action::Chained->multi_cap2
314 TestApp::Controller::Action::Chained->multi_cap_end2
315 TestApp::Controller::Action::Chained->end
318 my $expected = join( ", ", @expected );
320 ok( my $response = request('http://localhost/chained/multi_cap/1/2/baz'),
321 'dispatch on capture num 2' );
322 is( $response->header('X-Catalyst-Executed'),
323 $expected, 'Executed actions' );
324 is( $response->content, '1, 2; ', 'Content OK' );
328 # Tests the priority of a slurpy arguments action (with :Args) against
329 # two actions chained together. The two actions should win.
333 TestApp::Controller::Action::Chained->begin
334 TestApp::Controller::Action::Chained->priority_a2
335 TestApp::Controller::Action::Chained->priority_a2_end
336 TestApp::Controller::Action::Chained->end
339 my $expected = join( ", ", @expected );
341 ok( my $response = request('http://localhost/chained/priority_a/1/end/2'),
342 'priority - slurpy args vs. parent/child' );
343 is( $response->header('X-Catalyst-Executed'),
344 $expected, 'Executed actions' );
345 is( $response->content, '1; 2', 'Content OK' );
349 # This belongs to the former test but tests if two chained actions have
350 # priority over an action with the exact arguments.
354 TestApp::Controller::Action::Chained->begin
355 TestApp::Controller::Action::Chained->priority_b2
356 TestApp::Controller::Action::Chained->priority_b2_end
357 TestApp::Controller::Action::Chained->end
360 my $expected = join( ", ", @expected );
362 ok( my $response = request('http://localhost/chained/priority_b/1/end/2'),
363 'priority - fixed args vs. parent/child' );
364 is( $response->header('X-Catalyst-Executed'),
365 $expected, 'Executed actions' );
366 is( $response->content, '1; 2', 'Content OK' );
370 # This belongs to the former test but tests if two chained actions have
371 # priority over an action with one child action not having the Args() attr set.
375 TestApp::Controller::Action::Chained->begin
376 TestApp::Controller::Action::Chained->priority_c1
377 TestApp::Controller::Action::Chained->priority_c2_xyz
378 TestApp::Controller::Action::Chained->end
381 my $expected = join( ", ", @expected );
383 ok( my $response = request('http://localhost/chained/priority_c/1/xyz/'),
384 'priority - no Args() order mismatch' );
385 is( $response->header('X-Catalyst-Executed'),
386 $expected, 'Executed actions' );
387 is( $response->content, '1; ', 'Content OK' );
391 # Test dispatching between two controllers that are on the same level and
392 # therefor have no parent/child relationship.
396 TestApp::Controller::Action::Chained->begin
397 TestApp::Controller::Action::Chained::Bar->cross1
398 TestApp::Controller::Action::Chained::Foo->cross2
399 TestApp::Controller::Action::Chained->end
402 my $expected = join( ", ", @expected );
404 ok( my $response = request('http://localhost/chained/cross/1/end/2'),
405 'cross controller w/o par/child relation' );
406 is( $response->header('X-Catalyst-Executed'),
407 $expected, 'Executed actions' );
408 is( $response->content, '1; 2', 'Content OK' );
412 # This is for testing if the arguments got passed to the actions
417 TestApp::Controller::Action::Chained->begin
418 TestApp::Controller::Action::Chained::PassedArgs->first
419 TestApp::Controller::Action::Chained::PassedArgs->second
420 TestApp::Controller::Action::Chained::PassedArgs->third
421 TestApp::Controller::Action::Chained::PassedArgs->end
424 my $expected = join( ", ", @expected );
426 ok( my $response = request('http://localhost/chained/passedargs/a/1/b/2/c/3'),
427 'Correct arguments passed to actions' );
428 is( $response->header('X-Catalyst-Executed'),
429 $expected, 'Executed actions' );
430 is( $response->content, '1; 2; 3', 'Content OK' );
434 # The :Args attribute is optional, we check the action not specifying
435 # it with these tests.
439 TestApp::Controller::Action::Chained->begin
440 TestApp::Controller::Action::Chained->opt_args
441 TestApp::Controller::Action::Chained->end
444 my $expected = join( ", ", @expected );
446 ok( my $response = request('http://localhost/chained/opt_args/1/2/3'),
447 'Optional :Args attribute working' );
448 is( $response->header('X-Catalyst-Executed'),
449 $expected, 'Executed actions' );
450 is( $response->content, '; 1, 2, 3', 'Content OK' );
454 # Tests for optional PathPart attribute.
458 TestApp::Controller::Action::Chained->begin
459 TestApp::Controller::Action::Chained->opt_pp_start
460 TestApp::Controller::Action::Chained->opt_pathpart
461 TestApp::Controller::Action::Chained->end
464 my $expected = join( ", ", @expected );
466 ok( my $response = request('http://localhost/chained/optpp/1/opt_pathpart/2'),
467 'Optional :PathName attribute working' );
468 is( $response->header('X-Catalyst-Executed'),
469 $expected, 'Executed actions' );
470 is( $response->content, '1; 2', 'Content OK' );
474 # Tests for optional PathPart *and* Args attributes.
478 TestApp::Controller::Action::Chained->begin
479 TestApp::Controller::Action::Chained->opt_all_start
480 TestApp::Controller::Action::Chained->oa
481 TestApp::Controller::Action::Chained->end
484 my $expected = join( ", ", @expected );
486 ok( my $response = request('http://localhost/chained/optall/1/oa/2/3'),
487 'Optional :PathName *and* :Args attributes working' );
488 is( $response->header('X-Catalyst-Executed'),
489 $expected, 'Executed actions' );
490 is( $response->content, '1; 2, 3', 'Content OK' );
494 # Test if :Chained is the same as :Chained('/')
498 TestApp::Controller::Action::Chained->begin
499 TestApp::Controller::Action::Chained->rootdef
500 TestApp::Controller::Action::Chained->end
503 my $expected = join( ", ", @expected );
505 ok( my $response = request('http://localhost/chained/rootdef/23'),
506 ":Chained is the same as :Chained('/')" );
507 is( $response->header('X-Catalyst-Executed'),
508 $expected, 'Executed actions' );
509 is( $response->content, '; 23', 'Content OK' );
513 # Test if :Chained('.') is working
517 TestApp::Controller::Action::Chained->begin
518 TestApp::Controller::Action::Chained->parentchain
519 TestApp::Controller::Action::Chained::ParentChain->child
520 TestApp::Controller::Action::Chained->end
523 my $expected = join( ", ", @expected );
525 ok( my $response = request('http://localhost/chained/parentchain/1/child/2'),
526 ":Chained('.') chains to parent controller action" );
527 is( $response->header('X-Catalyst-Executed'),
528 $expected, 'Executed actions' );
529 is( $response->content, '1; 2', 'Content OK' );
533 # Test if :Chained('../act') is working
537 TestApp::Controller::Action::Chained->begin
538 TestApp::Controller::Action::Chained->one
539 TestApp::Controller::Action::Chained::ParentChain->chained_rel
540 TestApp::Controller::Action::Chained->end
543 my $expected = join( ", ", @expected );
545 ok( my $response = request('http://localhost/chained/one/1/chained_rel/3/2'),
546 ":Chained('../action') chains to correct action" );
547 is( $response->header('X-Catalyst-Executed'),
548 $expected, 'Executed actions' );
549 is( $response->content, '1; 3, 2', 'Content OK' );
553 # Test if ../ works to go up more than one level
557 TestApp::Controller::Action::Chained->begin
558 TestApp::Controller::Action::Chained->one
559 TestApp::Controller::Action::Chained::ParentChain::Relative->chained_rel_two
560 TestApp::Controller::Action::Chained->end
563 my $expected = join( ", ", @expected );
565 ok( my $response = request('http://localhost/chained/one/1/chained_rel_two/42/23'),
566 "../ works to go up more than one level" );
567 is( $response->header('X-Catalyst-Executed'),
568 $expected, 'Executed actions' );
569 is( $response->content, '1; 42, 23', 'Content OK' );
573 # Test if :ChainedParent is working
577 TestApp::Controller::Action::Chained->begin
578 TestApp::Controller::Action::Chained->loose
579 TestApp::Controller::Action::Chained::ParentChain->loose
580 TestApp::Controller::Action::Chained->end
583 my $expected = join( ", ", @expected );
585 ok( my $response = request('http://localhost/chained/loose/4/loose/a/b'),
586 ":Chained('../action') chains to correct action" );
587 is( $response->header('X-Catalyst-Executed'),
588 $expected, 'Executed actions' );
589 is( $response->content, '4; a, b', 'Content OK' );
593 # Test if :Chained('../name/act') is working
597 TestApp::Controller::Action::Chained->begin
598 TestApp::Controller::Action::Chained::Bar->cross1
599 TestApp::Controller::Action::Chained::ParentChain->up_down
600 TestApp::Controller::Action::Chained->end
603 my $expected = join( ", ", @expected );
605 ok( my $response = request('http://localhost/chained/cross/4/up_down/5'),
606 ":Chained('../action') chains to correct action" );
607 is( $response->header('X-Catalyst-Executed'),
608 $expected, 'Executed actions' );
609 is( $response->content, '4; 5', 'Content OK' );
613 # Test behaviour of auto actions returning '1' for the chain.
617 TestApp::Controller::Action::Chained->begin
618 TestApp::Controller::Action::Chained::Auto->auto
619 TestApp::Controller::Action::Chained::Auto::Foo->auto
620 TestApp::Controller::Action::Chained::Auto->foo
621 TestApp::Controller::Action::Chained::Auto::Foo->fooend
622 TestApp::Controller::Action::Chained->end
625 my $expected = join( ", ", @expected );
627 ok( my $response = request('http://localhost/chained/autochain1/1/fooend/2'),
628 "Behaviour when auto returns 1 correct" );
629 is( $response->header('X-Catalyst-Executed'),
630 $expected, 'Executed actions' );
631 is( $response->content, '1; 2', 'Content OK' );
635 # Test behaviour of auto actions returning '0' for the chain.
639 TestApp::Controller::Action::Chained->begin
640 TestApp::Controller::Action::Chained::Auto->auto
641 TestApp::Controller::Action::Chained::Auto::Bar->auto
642 TestApp::Controller::Action::Chained->end
645 my $expected = join( ", ", @expected );
647 ok( my $response = request('http://localhost/chained/autochain2/1/barend/2'),
648 "Behaviour when auto returns 0 correct" );
649 is( $response->header('X-Catalyst-Executed'),
650 $expected, 'Executed actions' );
651 is( $response->content, '1; 2', 'Content OK' );
655 # Test what auto actions are run when namespaces are changed
660 TestApp::Controller::Action::Chained->begin
661 TestApp::Controller::Action::Chained::Auto->auto
662 TestApp::Controller::Action::Chained::Auto::Foo->auto
663 TestApp::Controller::Action::Chained::Auto::Bar->crossloose
664 TestApp::Controller::Action::Chained::Auto::Foo->crossend
665 TestApp::Controller::Action::Chained->end
668 my $expected = join( ", ", @expected );
670 ok( my $response = request('http://localhost/chained/auto_cross/1/crossend/2'),
671 "Correct auto actions are run on cross controller dispatch" );
672 is( $response->header('X-Catalyst-Executed'),
673 $expected, 'Executed actions' );
674 is( $response->content, '1; 2', 'Content OK' );
678 # Test forwarding from auto action in chain dispatch.
682 TestApp::Controller::Action::Chained->begin
683 TestApp::Controller::Action::Chained::Auto->auto
684 TestApp::Controller::Action::Chained::Auto::Forward->auto
685 TestApp::Controller::Action::Chained::Auto->fw3
686 TestApp::Controller::Action::Chained::Auto->fw1
687 TestApp::Controller::Action::Chained::Auto::Forward->forwardend
688 TestApp::Controller::Action::Chained->end
691 my $expected = join( ", ", @expected );
693 ok( my $response = request('http://localhost/chained/auto_forward/1/forwardend/2'),
694 "Forwarding out of auto in chain" );
695 is( $response->header('X-Catalyst-Executed'),
696 $expected, 'Executed actions' );
697 is( $response->content, '1; 2', 'Content OK' );
701 # Detaching out of the auto action of a chain.
705 TestApp::Controller::Action::Chained->begin
706 TestApp::Controller::Action::Chained::Auto->auto
707 TestApp::Controller::Action::Chained::Auto::Detach->auto
708 TestApp::Controller::Action::Chained::Auto->fw3
709 TestApp::Controller::Action::Chained->end
712 my $expected = join( ", ", @expected );
714 ok( my $response = request('http://localhost/chained/auto_detach/1/detachend/2'),
715 "Detaching out of auto in chain" );
716 is( $response->header('X-Catalyst-Executed'),
717 $expected, 'Executed actions' );
718 is( $response->content, '1; 2', 'Content OK' );
722 # Test forwarding from auto action in chain dispatch.
725 my $expected = undef;
727 ok( my $response = request('http://localhost/chained/loose/23'),
728 "Loose end is not callable" );
729 is( $response->header('X-Catalyst-Executed'),
730 $expected, 'Executed actions' );
731 is( $response->code, 500, 'Status OK' );
735 # Test forwarding out of a chain.
739 TestApp::Controller::Action::Chained->begin
740 TestApp::Controller::Action::Chained->chain_fw_a
741 TestApp::Controller::Action::Chained->fw_dt_target
742 TestApp::Controller::Action::Chained->chain_fw_b
743 TestApp::Controller::Action::Chained->end
746 my $expected = join( ", ", @expected );
748 ok( my $response = request('http://localhost/chained/chain_fw/1/end/2'),
749 "Forwarding out a chain" );
750 is( $response->header('X-Catalyst-Executed'),
751 $expected, 'Executed actions' );
752 is( $response->content, '1; 2', 'Content OK' );
756 # Test detaching out of a chain.
760 TestApp::Controller::Action::Chained->begin
761 TestApp::Controller::Action::Chained->chain_dt_a
762 TestApp::Controller::Action::Chained->fw_dt_target
763 TestApp::Controller::Action::Chained->end
766 my $expected = join( ", ", @expected );
768 ok( my $response = request('http://localhost/chained/chain_dt/1/end/2'),
769 "Forwarding out a chain" );
770 is( $response->header('X-Catalyst-Executed'),
771 $expected, 'Executed actions' );
772 is( $response->content, '1; 2', 'Content OK' );
776 # Tests that an uri_for to a chained root index action
777 # returns the right value.
780 ok( my $response = request(
781 'http://localhost/action/chained/to_root' ),
782 'uri_for with chained root action as arg' );
783 like( $response->content,
784 qr(URI:https?://[^/]+/),
785 'Correct URI generated' );
789 # Test interception of recursive chains. This test was added because at
790 # one point during the :Chained development, Catalyst used to hang on
794 eval { require 'TestAppChainedRecursive.pm' };
795 if ($run_number == 1) {
796 ok( ! $@, "Interception of recursive chains" );
798 else { pass( "Interception of recursive chains already tested" ) }
802 # Test failure of absolute path part arguments.
805 eval { require 'TestAppChainedAbsolutePathPart.pm' };
806 if ($run_number == 1) {
807 like( $@, qr(foo/foo),
808 "Usage of absolute path part argument emits error" );
810 else { pass( "Error on absolute path part arguments already tested" ) }
814 # Test chained actions in the root controller
818 TestApp::Controller::Action::Chained::Root->rootsub
819 TestApp::Controller::Action::Chained::Root->endpointsub
820 TestApp::Controller::Root->end
823 my $expected = join( ", ", @expected );
825 ok( my $response = request('http://localhost/rootsub/1/endpointsub/2'), 'chained in root namespace' );
826 is( $response->header('X-Catalyst-Executed'),
827 $expected, 'Executed actions' );
828 is( $response->content, '', 'Content OK' );
832 # Complex path with multiple empty pathparts
836 TestApp::Controller::Action::Chained->begin
837 TestApp::Controller::Action::Chained->mult_nopp_base
838 TestApp::Controller::Action::Chained->mult_nopp_all
839 TestApp::Controller::Action::Chained->end
842 my $expected = join( ", ", @expected );
844 ok( my $response = request('http://localhost/chained/mult_nopp'),
845 "Complex path with multiple empty pathparts" );
846 is( $response->header('X-Catalyst-Executed'),
847 $expected, 'Executed actions' );
848 is( $response->content, '; ', 'Content OK' );
852 # Complex path with multiple non-capturing pathparts
853 # PathPart('') CaptureArgs(0), PathPart('foo') CaptureArgs(0), PathPart('') Args(0)
854 # should win over PathPart('') CaptureArgs(1), PathPart('') Args(0)
858 TestApp::Controller::Action::Chained->begin
859 TestApp::Controller::Action::Chained->mult_nopp2_base
860 TestApp::Controller::Action::Chained->mult_nopp2_nocap
861 TestApp::Controller::Action::Chained->mult_nopp2_action
862 TestApp::Controller::Action::Chained->mult_nopp2_action_default
863 TestApp::Controller::Action::Chained->end
866 my $expected = join( ", ", @expected );
868 ok( my $response = request('http://localhost/chained/mult_nopp2/action'),
869 "Complex path with multiple non-capturing pathparts" );
870 is( $response->header('X-Catalyst-Executed'),
871 $expected, 'Executed actions' );
872 is( $response->content, '; ', 'Content OK' );
876 # Higher Args() hiding more specific CaptureArgs chains sections
880 TestApp::Controller::Action::Chained->begin
881 TestApp::Controller::Action::Chained->cc_base
882 TestApp::Controller::Action::Chained->cc_link
883 TestApp::Controller::Action::Chained->cc_anchor
884 TestApp::Controller::Action::Chained->end
887 my $expected = join ', ', @expected;
889 ok( my $response = request('http://localhost/chained/choose_capture/anchor.html'),
890 'Choose between an early Args() and a later more ideal chain' );
891 is( $response->header('X-Catalyst-Executed') => $expected, 'Executed actions');
892 is( $response->content => '; ', 'Content OK' );
896 # Less specific chain not being seen correctly due to earlier looser capture
900 TestApp::Controller::Action::Chained->begin
901 TestApp::Controller::Action::Chained->cc_base
902 TestApp::Controller::Action::Chained->cc_b
903 TestApp::Controller::Action::Chained->cc_b_link
904 TestApp::Controller::Action::Chained->cc_b_anchor
905 TestApp::Controller::Action::Chained->end
908 my $expected = join ', ', @expected;
910 ok( my $response = request('http://localhost/chained/choose_capture/b/a/anchor.html'),
911 'Choose between a more specific chain and an earlier looser one' );
912 is( $response->header('X-Catalyst-Executed') => $expected, 'Executed actions');
913 is( $response->content => 'a; ', 'Content OK' );
917 # Check we get the looser one when it's the correct match
921 TestApp::Controller::Action::Chained->begin
922 TestApp::Controller::Action::Chained->cc_base
923 TestApp::Controller::Action::Chained->cc_a
924 TestApp::Controller::Action::Chained->cc_a_link
925 TestApp::Controller::Action::Chained->cc_a_anchor
926 TestApp::Controller::Action::Chained->end
929 my $expected = join ', ', @expected;
931 ok( my $response = request('http://localhost/chained/choose_capture/a/a/anchor.html'),
932 'Choose between a more specific chain and an earlier looser one' );
933 is( $response->header('X-Catalyst-Executed') => $expected, 'Executed actions');
934 is( $response->content => 'a; anchor.html', 'Content OK' );
937 # CaptureArgs(1) PathPart('...') should win over CaptureArgs(2) PathPart('')
940 TestApp::Controller::Action::Chained->begin
941 TestApp::Controller::Action::Chained::CaptureArgs->base
942 TestApp::Controller::Action::Chained::CaptureArgs->one_arg
943 TestApp::Controller::Action::Chained::CaptureArgs->edit_one_arg
944 TestApp::Controller::Action::Chained::CaptureArgs->end
947 my $expected = join( ", ", @expected );
949 # should dispatch to /base/one_args/edit_one_arg
950 ok( my $response = request('http://localhost/captureargs/one/edit'),
951 'Correct arg order ran' );
953 local $TODO = 'Known bug';
954 is( $response->header('X-Catalyst-Executed'),
955 $expected, 'Executed actions' );
956 is( $response->content, 'base; one_arg; edit_one_arg', 'Content OK' );
960 # PathPart('...') Args(1) should win over CaptureArgs(2) PathPart('')
963 TestApp::Controller::Action::Chained->begin
964 TestApp::Controller::Action::Chained::CaptureArgs->base
965 TestApp::Controller::Action::Chained::CaptureArgs->test_one_arg
966 TestApp::Controller::Action::Chained::CaptureArgs->end
969 my $expected = join( ", ", @expected );
971 # should dispatch to /base/test_one_arg
972 ok( my $response = request('http://localhost/captureargs/test/one'),
973 'Correct pathpart/arg ran' );
975 local $TODO = 'Known bug';
976 is( $response->header('X-Catalyst-Executed'),
977 $expected, 'Executed actions' );
978 is( $response->content, 'base; test_plus_arg; one;', 'Content OK' );
983 # Args(0) should win over Args() if we actually have no arguments.
986 TestApp::Controller::Action::Chained->begin
987 TestApp::Controller::Action::Chained::ArgsOrder->base
988 TestApp::Controller::Action::Chained::ArgsOrder->index
989 TestApp::Controller::Action::Chained::ArgsOrder->end
992 my $expected = join( ", ", @expected );
994 # With no args, we should run "index"
995 ok( my $response = request('http://localhost/argsorder/'),
996 'Correct arg order ran' );
997 is( $response->header('X-Catalyst-Executed'),
998 $expected, 'Executed actions' );
999 is( $response->content, 'base; ; index; ', 'Content OK' );
1001 # With args given, run "all"
1002 ok( $response = request('http://localhost/argsorder/X'),
1003 'Correct arg order ran' );
1004 is( $response->header('X-Catalyst-Executed'),
1007 TestApp::Controller::Action::Chained->begin
1008 TestApp::Controller::Action::Chained::ArgsOrder->base
1009 TestApp::Controller::Action::Chained::ArgsOrder->all
1010 TestApp::Controller::Action::Chained::ArgsOrder->end
1013 is( $response->content, 'base; ; all; X', 'Content OK' );
1022 TestApp::Controller::Action::Chained->begin
1023 TestApp::Controller::Action::Chained::PathPrefix->instance
1024 TestApp::Controller::Action::Chained->end
1027 my $expected = join( ", ", @expected );
1029 ok( my $response = request('http://localhost/action/chained/pathprefix/1'),
1030 "PathPrefix (as an endpoint)" );
1031 is( $response->header('X-Catalyst-Executed'),
1032 $expected, 'Executed actions' );
1033 is( $response->content, '; 1', 'Content OK' );
1037 # static paths vs. captures
1041 TestApp::Controller::Action::Chained->begin
1042 TestApp::Controller::Action::Chained->apan
1043 TestApp::Controller::Action::Chained->korv
1044 TestApp::Controller::Action::Chained->static_end
1045 TestApp::Controller::Action::Chained->end
1048 my $expected = join( ", ", @expected );
1050 ok( my $response = request('http://localhost/action/chained/static_end'),
1051 "static paths are prefered over captures" );
1052 is( $response->header('X-Catalyst-Executed'),
1053 $expected, 'Executed actions' );
1060 # request for doc/search should end up in doc/*
1063 TestApp::Controller::Action::Chained->begin
1064 TestApp::Controller::Action::Chained->doc_star
1065 TestApp::Controller::Action::Chained->end
1068 my $expected = join( ", ", @expected );
1070 ok( my $response = request('http://localhost/chained/doc/search'),
1071 "we prefer static path parts earlier in the chain" );
1073 local $TODO = 'gbjk never got off his ass and fixed this';
1074 is( $response->header('X-Catalyst-Executed'),
1075 $expected, 'Executed actions' );
1081 get('http://localhost/chained/capture%2Farg%3B/return_arg/foo%2Fbar%3B'),
1082 'request with URI-encoded arg' );
1083 like( $content, qr{foo/bar;\z}, 'args decoded' );
1084 like( $content, qr{capture/arg;}, 'captureargs decoded' );
1088 get('http://localhost/chained/return_arg_decoded/foo%2Fbar%3B'),
1089 'request with URI-encoded arg' );
1090 like( $content, qr{foo/bar;\z}, 'args decoded' );
1093 # Test round tripping, specifically the / character %2F in uri_for:
1094 # not being able to feed it back action + captureargs and args into uri for
1095 # and result in the original request uri is a major piece of suck ;)
1098 ['foo%2Fbar', 'baz'],
1099 ['foo', 'bar%2Fbaz'],
1100 ['foo%2Fbar', 'baz%2Fquux'],
1101 ['foo%2Fbar', 'baz%2Fquux', { foo => 'bar', 'baz' => 'quux%2Ffrood'}],
1102 ['foo%2Fbar', 'baz%2Fquux', { foo => 'bar', 'baz%2Ffnoo' => 'quux%2Ffrood'}],
1103 ['h%C3%BCtte', 'h%C3%BCtte', { test => 'h%C3%BCtte' } ],
1105 my $path = '/chained/roundtrip_urifor/' .
1106 $thing->[0] . '/' . $thing->[1];
1107 $path .= '?' . join('&',
1108 map { $_ .'='. $thing->[2]->{$_}}
1109 sort keys %{$thing->[2]}) if $thing->[2];
1111 get('http://localhost/' . $path),
1112 'request ' . $path . ' ok');
1113 my $exp = URI->new('http://localhost:3000' . $path);
1114 my ($want) = $content =~ m{/chained/(.*)};
1115 my $got = URI->new('http://localhost:3000/chained/' . $want);
1116 # Just check that the path matches, as who the hell knows or cares
1117 # where the app is based (live tests etc)
1118 is $got->path, $exp->path, "uri $path can round trip through uri_for (path)"
1119 or diag("Expected $path, got $content");
1120 is_deeply $got->query_form_hash, $exp->query_form_hash, "uri $path can round trip through uri_for (query)"
1121 or diag("Expected $path, got $content");
1129 ok( my $response = request('http://localhost/chained/match_captures/foo/bar'), 'match_captures: falling through' );
1130 is($response->header('X-TestAppActionTestMatchCaptures'), 'fallthrough', 'match_captures: fell through');
1132 ok($response = request('http://localhost/chained/match_captures/force/bar'), 'match_captures: *not* falling through' );
1133 is($response->header('X-TestAppActionTestMatchCaptures'), 'forcing', 'match_captures: forced');
1134 is($response->header('X-TestAppActionTestMatchCapturesHasRan'), 'yes', 'match_captures: actually ran');