use strict; use Test::More tests => 110; BEGIN{use_ok('CGI::Application');} # Need CGI.pm for tests use CGI; # bring in testing hierarchy use lib 't/lib'; use TestApp; use TestApp2; use TestApp3; use TestApp4; use TestApp5; $ENV{CGI_APP_RETURN_ONLY} = 1; sub response_like { my ($app, $header_re, $body_re, $comment) = @_; local $ENV{CGI_APP_RETURN_ONLY} = 1; my $output = $app->run; my ($header, $body) = split /\r\n\r\n/m, $output; like($header, $header_re, "$comment (header match)"); like($body, $body_re, "$comment (body match)"); } # Instantiate CGI::Application # run() CGI::Application object. Expect header + output dump_html() { my $app = CGI::Application->new(); isa_ok($app, 'CGI::Application'); $app->query(CGI->new("")); my $output = $app->run(); response_like( $app, qr{^Content-Type: text/html}, qr/Query Environment:/, 'base class response', ); } # Instantiate CGI::Application sub-class. # run() CGI::Application sub-class. # Expect HTTP header + 'Hello World: basic_test'. { my $app = TestApp->new(QUERY => CGI->new("")); isa_ok($app, 'CGI::Application'); response_like( $app, qr{^Content-Type: text/html}, qr/Hello World: basic_test/, 'TestApp, blank query', ); } # Non-hash references are invalid for PARAMS. { my $app = eval { TestApp->new(PARAMS => [ 1, 2, 3, ]); }; like($@, qr/not a hash ref/, "PARAMS must be a hashref!"); } # run() CGI::Application sub-class, in run mode 'redirect_test'. # Expect HTTP redirect header + 'Hello World: redirect_test'. { my $app = TestApp->new(); $app->query(CGI->new({'test_rm' => 'redirect_test'})); response_like( $app, qr/^Status: 302/, qr/Hello World: redirect_test/, 'TestApp, redirect_test' ); } # run() CGI::Application sub-class, in run mode 'redirect_test'. # Expect HTTP redirect header + 'Hello World: redirect_test'. # ...just like the test above, but we pass QUERY in via a hashref. { my $app = TestApp->new({ QUERY => CGI->new({'test_rm' => 'redirect_test'}) }); response_like( $app, qr/^Status: 302/, qr/Hello World: redirect_test/, 'TestApp, redirect_test' ); } # run() CGI::Application sub-class, in run mode 'dump_text'. { my $app = TestApp->new(); $app->query(CGI->new({'test_rm' => 'dump_txt'})); response_like( $app, qr{^Content-type: text/html}i, qr/Query Environment/, 'TestApp, dump_text' ); } # run() CGI::Application sub-class, in run mode 'cookie_test'. # Expect HTTP header w/ cookie: # 'c_name' => 'c_value' + 'Hello World: cookie_test'. { my $app = TestApp->new(); $app->query(CGI->new({'test_rm' => 'cookie_test'})); response_like( $app, qr/^Set-Cookie: c_name=c_value/, qr/Hello World: cookie_test/, "TestApp, cookie test", ); } # run() CGI::Application sub-class, in run mode 'tmpl_test'. # Expect HTTP header + 'Hello World: tmpl_test'. { my $app = TestApp->new(TMPL_PATH=>'t/lib/templates/'); $app->query(CGI->new({'test_rm' => 'tmpl_test'})); response_like( $app, qr{^Content-Type: text/html}, qr/---->Hello World: tmpl_test<----/, "TestApp, tmpl_test", ); } # run() CGI::Application sub-class, in run mode 'tmpl_badparam_test'. # Expect HTTP header + 'Hello World: tmpl_badparam_test'. { my $app = TestApp->new(TMPL_PATH=>'t/lib/templates/'); $app->query(CGI->new({'test_rm' => 'tmpl_badparam_test'})); response_like( $app, qr{^Content-Type: text/html}, qr/---->Hello World: tmpl_badparam_test<----/, "TestApp, tmpl_badparam_test", ); } # Instantiate and call run_mode 'eval_test'. Expect 'eval_test OK' in output. { my $app = TestApp->new(); $app->query(CGI->new({'test_rm' => 'eval_test'})); response_like( $app, qr{^Content-Type: text/html}, qr/Hello World: eval_test OK/, "TestApp, eval_test", ); } # Test to make sure cgiapp_init() was called in inherited class. { my $app = TestApp2->new(); my $init_state = $app->param('CGIAPP_INIT'); ok(defined($init_state), "TestApp2's cgiapp_init ran"); is($init_state, 'true', "TestApp2's cgiapp_init set the right value"); } # Test to make sure mode_param() can contain subref { my $app = TestApp3->new(); $app->query(CGI->new({'go_to_mode' => 'subref_modeparam'})); response_like( $app, qr{^Content-Type: text/html}, qr/Hello World: subref_modeparam OK/, "TestApp3, subref_modeparam", ); } # Test to make sure that "false" (but >0 length) run modes are valid -- will # not default to start_mode() { my $app = TestApp3->new(); $app->query(CGI->new({'go_to_mode' => '0'})); response_like( $app, qr{^Content-Type: text/html}, qr/Hello World: zero_mode OK/, "TestApp3, 0 as run mode isn't start_mode", ); } # A blank mode_param value isn't useful; we fall back to start_mode. { my $app = TestApp3->new(); $app->query(CGI->new({'go_to_mode' => ''})); response_like( $app, qr{^Content-Type: text/html}, qr/Hello World: default_mode OK/, "TestApp3, q() as run mode is start_mode", ); } # Test to make sure that undef run modes will default to start_mode() { my $app = TestApp3->new(); $app->query(CGI->new({'go_to_mode' => 'undef_rm'})); response_like( $app, qr{^Content-Type: text/html}, qr/Hello World: default_mode OK/, "TestApp3, undef run mode (goes to start_mode)", ); } # Test run modes returning scalar-refs instead of scalars { my $app = TestApp4->new(QUERY=>CGI->new("")); response_like( $app, qr{^Content-Type: text/html}, qr/Hello World: subref_test OK/, "run modes can return scalar references", ); } # Test "AUTOLOAD" run mode { my $app = TestApp4->new(); $app->query(CGI->new({'rm' => 'undefined_mode'})); response_like( $app, qr{^Content-Type: text/html}, qr/Hello World: undefined_mode OK/, "AUTOLOAD run mode", ); } # what if there is no AUTOLOAD? { my $app = TestApp->new(); $app->query(CGI->new({'test_rm' => 'undefined_mode'})); my $output = eval { $app->run }; like($@, qr/No such run mode/, "no runmode + no autoload = exception"); } # Can we incrementally add run modes? # XXX: I don't see how this code tests that question. -- rjbs, 2006-06-30 { my $app; my $output; # Mode: BasicTest $app = TestApp5->new(); $app->query(CGI->new({'rm' => 'basic_test1'})); response_like( $app, qr{^Content-Type: text/html}, qr/Hello World: basic_test1/, "force basic_test1", ); # Mode: BasicTest2 $app = TestApp5->new(); $app->query(CGI->new({'rm' => 'basic_test2'})); response_like( $app, qr{^Content-Type: text/html}, qr/Hello World: basic_test2/, "force basic_test2", ); # Mode: BasicTest3 $app = TestApp5->new(); $app->query(CGI->new({'rm' => 'basic_test3'})); response_like( $app, qr{^Content-Type: text/html}, qr/Hello World: basic_test3/, "force basic_test3", ); } # Can we add params in batches? { my $app = TestApp5->new( PARAMS => { P1 => 'one', P2 => 'two' } ); # Do params set via new still get set? my @plist = sort $app->param(); is_deeply(\@plist, ['P1', 'P2'], "Pn params set during initialization"); my @params = ( '', 'one', 'two', 'new three', 'four', 'new five', 'six', 'seven', 'eight' ); is($app->param("P$_"), $params[$_], "P$_ of 2 correct") for 1..2; # Can we still augment params one at a time? $app->param('P3', 'three'); @plist = sort $app->param(); is_deeply(\@plist, ['P1', 'P2', 'P3'], 'added one param to list'); is($app->param("P$_"), $params[$_], "P$_ of 2 correct again") for 1..2; is($app->param("P3"), 'three', "and new arg, P3, is also correct"); # Does a list of pairs work? my $pt3val = $app->param( 'P3' => 'new three', 'P4' => 'four', 'P5' => 'five' ); @plist = sort $app->param(); is_deeply(\@plist, ['P1', 'P2', 'P3', 'P4', 'P5'], "all five args set ok"); is($app->param("P$_"), $params[$_], "P$_ of 4 correct") for 1..4; is($app->param("P5"), 'five', "P5 also correct"); # XXX: Do we really want to test for this? Maybe we want to change this # behavior, on which hopefully nothing but this test depends... # -- rjbs, 2006-06-30 ok(not(defined($pt3val)), "multiple param setting returns undef (for now)"); # What about a hash-ref? (Should return undef) my $pt4val = $app->param({ 'P5' => 'new five', 'P6' => 'six', 'P7' => 'seven', }); @plist = sort $app->param(); is_deeply(\@plist, ['P1', 'P2', 'P3', 'P4', 'P5', 'P6', 'P7'], "7 params ok"); is($app->param("P$_"), $params[$_], "P$_ of 7 correct") for 1..7; ok(not(defined($pt4val)), "multiple param setting returns undef (for now)"); # What about a simple pass-through? (Should return param value) my $pt5val = $app->param('P8', 'eight'); @plist = sort $app->param(); is_deeply(\@plist, [qw(P1 P2 P3 P4 P5 P6 P7 P8)], "P1-8 all ok"); is($app->param("P$_"), $params[$_], "P$_ of 8 correct") for 1..8; is($pt5val, 'eight', "value returned on setting P8 is correct"); } # test undef param values { my $app = TestApp->new(); $app->param(foo => 10); is( $app->delete, undef, "we get undef when deleting unnamed param", ); is($app->param('foo'), 10, q(and our real param is still ok)); } # test setting header_props before header_type { my $app = TestApp->new(); $app->query(CGI->new({'test_rm' => 'props_before_redirect_test'})); my $output = $app->run(); like($output, qr/test: 1/i, "added test header before redirect"); like($output, qr/Status: 302/, "and still redirected"); } # testing setting header_props more than once { my $app = TestApp->new(); $app->query(CGI->new({'test_rm' => 'header_props_twice_nomerge'})); my $output = $app->run(); like($output, qr/test: Updated/i, "added test header"); unlike($output, qr/second-header: 1/, "no second-header header"); unlike($output, qr/Test2:/, "no Test2 header, either"); } # testing header_add with arrayref { my $app = TestApp->new(); $app->query(CGI->new({'test_rm' => 'header_add_arrayref_test'})); my $output = $app->run(); like($output, qr/Set-Cookie: cookie1=header_add/, "arrayref test: cookie1"); like($output, qr/Set-Cookie: cookie2=header_add/, "arrayref test: cookie2"); } # make sure header_add does not clobber earlier headers { my $app = TestApp->new(); $app->query(CGI->new({'test_rm' => 'header_props_before_header_add'})); my $output = $app->run(); like($output, qr/Set-Cookie: cookie1=header_props/, "header_props: cookie1"); like($output, qr/Set-Cookie: cookie2=header_add/, "header_add: cookie2"); } # make sure header_add works after header_props is called { my $app = TestApp->new(); $app->query(CGI->new({'test_rm' => 'header_add_after_header_props'})); my $output = $app->run(); like($output, qr/Set-Cookie: cookie2=header_add/, "header add after props"); } # test use of TMPL_PATH without trailing slash { my $app = TestApp->new(TMPL_PATH=>'t/lib/templates'); $app->query(CGI->new({'test_rm' => 'tmpl_badparam_test'})); response_like( $app, qr{^Content-Type: text/html}, qr/---->Hello World: tmpl_badparam_test<----/, "TMPL_PATH without trailing slash", ); } # If called "too early" we get undef for current runmode. { my $app = CGI::Application->new; eval { $app->run_modes('whatever') }; like($@, qr/odd number/i, "croak on odd number of args to run_modes"); } # If called "too early" we get undef for current runmode. { my $app = CGI::Application->new; is($app->get_current_runmode, undef, "current runmode is undef before run"); my $dump = $app->dump; like($dump, qr/^Current Run mode: ''\n/, "no current run mode in dump"); } # test delete() method by first setting some params and then deleting them { my $app = TestApp5->new(); $app->param( P1 => 'one', P2 => 'two', P3 => 'three' ); is_deeply( [ sort $app->param ], [ qw(P1 P2 P3) ], "we start with P1 P2 P3", ); #a valid delete my $p2value = $app->delete('P2'); my @params = sort $app->param(); is_deeply(\@params, ['P1', 'P3'], "P2 deletes without incident"); is($p2value, "two", "and deletion returns the deleted value"); is($app->param('P1'), 'one', 'P1 still has the right value'); ok(!defined($app->param('P2')), 'P2 is now undef'); is_deeply( [ sort $app->param ], ['P1', 'P3'], "asking for P2 didn't instantiate it", ); is($app->param('P3'), 'three', 'P3 still has the right value'); #an invalid delete my $result = $app->delete('P4'); ok(!defined($result), "we get undef back when deleting nonexistant param"); is($app->param('P1'), 'one', "and P1's value is unmolested"); ok(!defined($app->param('P4')), "and the fake param doesn't get a value"); is($app->param('P3'), 'three', "and P3 is unmolested too"); } ### my $t27_ta_obj = CGI::Application->new( TMPL_PATH => [qw(t/lib/templates /some/other/test/path)] ); my ($t1, $t2) = (0,0); my $tmpl_path = $t27_ta_obj->tmpl_path(); ok((ref $tmpl_path eq 'ARRAY'), 'tmpl_path returns array ref'); is($tmpl_path->[0], 't/lib/templates', 'tmpl_path first element is correct'); is($tmpl_path->[1], '/some/other/test/path', 'tmpl_path second element is correct'); my $tmpl = $t27_ta_obj->load_tmpl('test.tmpl'); $tmpl_path = $tmpl->{options}->{path}; ok((ref $tmpl_path eq 'ARRAY'), 'tmpl_path from H::T obj returns array ref'); ok(($tmpl_path->[0] eq 't/lib/templates'), 'tmpl_path from H::T obj first element is correct'); ok(($tmpl_path->[1] eq '/some/other/test/path'), 'tmpl_path from H::T obj second element is correct'); # All done!