Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'release/1.3019_01'

  • Loading branch information...
commit c5d2b36077cde97f6f3a3fb33f95f5eb840a7552 2 parents efbfd6b + 7f242e4
@xsawyerx xsawyerx authored
View
46 .gitignore
@@ -1,12 +1,6 @@
-Makefile
-.last_cover_stats
-MANIFEST.bak
+# Dancer Specific
*.old
-*.swp
*~
-blib
-pm_to_blib
-cover_db
example/logs
t/*/logs
t/*/sessions
@@ -15,3 +9,41 @@ TestApp
t/sessions/
tags
MYMETA.yml
+
+
+# From: https://github.com/github/gitignore/blob/master/Global/Linux.gitignore
+.*
+!.gitignore
+*~
+*.sw[a-p]
+.directory
+
+
+# From: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
+Thumbs.db
+Desktop.ini
+
+
+# From https://github.com/github/gitignore/blob/master/Global/OSX.gitignore
+.DS_Store
+Icon?
+._*
+.Spotlight-V100
+.Trashes
+
+
+# From https://github.com/github/gitignore/blob/master/Perl.gitignore
+blib/
+_build/
+cover_db/
+inc/
+Build
+Build.bat
+.last_cover_stats
+Makefile
+Makefile.old
+MANIFEST.bak
+META.yml
+MYMETA.yml
+nytprof.out
+pm_to_blib
View
18 CHANGES
@@ -1,5 +1,23 @@
{{$NEXT}}
+1.3019_01 13.03.2011
+
+ [ BUG FIXES ]
+ * GH #393: Reset vars for each new request.
+ (Franck Cuny)
+
+ [ ENHANCEMENTS ]
+ * GH #391: Dancer::Logger::Note now exists. :)
+ (Sawyer X)
+ * Porting documentation on WRAPPER to Dancer::Template::TemplateToolkit.
+ (Sawyer X)
+ * GH #387: Document views and appdir in Dancer::Config.
+ (Michael G. Schwern)
+ * Add a new symbol to exporter ':script'.
+ (Franck Cuny)
+ * GH #397: Support cookie expire times like "+2h".
+ (Michael G. Schwern)
+
1.3014_01 10.03.2011
[ BUG FIXES ]
View
6 MANIFEST
@@ -37,6 +37,7 @@ lib/Dancer/Logger/Capture/Trap.pm
lib/Dancer/Logger/Console.pm
lib/Dancer/Logger/Diag.pm
lib/Dancer/Logger/File.pm
+lib/Dancer/Logger/Note.pm
lib/Dancer/Logger/Null.pm
lib/Dancer/MIME.pm
lib/Dancer/ModuleLoader.pm
@@ -87,6 +88,7 @@ t/00_base/005_module_loader.t
t/00_base/007_load_syntax.t
t/00_base/008_export.t
t/00_base/009_syntax_export.t
+t/00_base/010_export_script.t
t/00_base/06_dancer_object.t
t/00_base/08_pod_coverage_dancer.t
t/00_base/09_load_app.t
@@ -161,6 +163,8 @@ t/03_route_handler/29_forward.t
t/03_route_handler/29_redirect_immediately.t
t/03_route_handler/30_bug_gh190.t
t/03_route_handler/31_infinite_loop.t
+t/03_route_handler/32_gh_393.t
+t/03_route_handler/33_vars.t
t/03_route_handler/public/404.html
t/03_route_handler/views/hello.tt
t/04_static_file/001_base.t
@@ -214,6 +218,7 @@ t/09_cookies/02_cookie_object.t
t/09_cookies/03_persistence.t
t/09_cookies/04_secure.t
t/09_cookies/05_api.t
+t/09_cookies/06_expires.t
t/10_template/000_create_fake_env.t
t/10_template/01_factory.t
t/10_template/02_abstract_class.t
@@ -233,6 +238,7 @@ t/11_logger/06_null.t
t/11_logger/07_diag.t
t/11_logger/08_serialize.t
t/11_logger/09_capture.t
+t/11_logger/10_note.t
t/12_response/000_create_fake_env.t
t/12_response/01_CRLF_injection.t
t/12_response/02_headers.t
View
18 lib/Dancer.pm
@@ -5,7 +5,7 @@ use warnings;
use Carp;
use Cwd 'realpath';
-our $VERSION = '1.3014_01';
+our $VERSION = '1.3019_01';
our $AUTHORITY = 'SUKRIA';
use Dancer::App;
@@ -168,6 +168,7 @@ sub import {
my @final_args;
my $syntax_only = 0;
+ my $as_script = 0;
foreach (@args) {
if ( $_ eq ':moose' ) {
push @final_args, '!before', '!after';
@@ -178,7 +179,9 @@ sub import {
elsif ( $_ eq ':syntax' ) {
$syntax_only = 1;
}
- else {
+ elsif ($_ eq ':script') {
+ $as_script = 1;
+ } else {
push @final_args, $_;
}
}
@@ -188,7 +191,7 @@ sub import {
# if :syntax option exists, don't change settings
return if $syntax_only;
- Dancer::GetOpt->process_args();
+ Dancer::GetOpt->process_args() if !$as_script;
_init_script_dir($script);
Dancer::Config->load;
@@ -434,6 +437,15 @@ These can be combined. For example, while testing...
use Test::Most qw(!set !any);
use Dancer qw(:syntax :tests);
+=head2 :script
+
+This will export all the keywords, and will also load the configuration.
+
+This is useful when you want to use your Dancer application from a script.
+
+ use MyApp;
+ use Dancer ':script';
+ MyApp::schema('DBSchema')->deploy();
=head1 FUNCTIONS
View
35 lib/Dancer/Config.pm
@@ -312,19 +312,34 @@ Also, since automatically serialized JSON responses have
C<application/json> Content-Type, you should always encode them by
hand.
-=head2 public (string)
+=head2 appdir (directory)
-This is the path of the public directory, where static files are stored. Any
-existing file in that directory will be served as a static file, before
-mathcing any route.
+This is the path where your application will live. It's where Dancer
+will look by default for your config files, templates and static
+content.
-By default, it points to APPDIR/public where APPDIR is the directory that
-contains your Dancer script.
+It is typically set by C<use Dancer> to use the same directory as your
+script.
+
+=head2 public (directory)
+
+This is the directory, where static files are stored. Any existing
+file in that directory will be served as a static file, before
+matching any route.
+
+By default, it points to $appdir/public.
+
+=head2 views (directory)
+
+This is the directory where your templates and layouts live. It's the
+"view" part of MVC (model, view, controller).
+
+This defaults to $appdir/views.
=head2 layout (string)
-name of the layout to use when rendering view. Dancer will look for
-a matching template in the directory $appdir/views/layout.
+The name of the layout to use when rendering view. Dancer will look for
+a matching template in the directory $views/layout.
=head2 warnings (boolean)
@@ -338,10 +353,12 @@ occurs. (Internally sets Carp::Verbose). Default to false.
=head2 log (enum)
Tells which log messages should be actullay logged. Possible values are
-B<debug>, B<warning> or B<error>.
+B<core>, B<debug>, B<warning> or B<error>.
=over 4
+=item B<core> : all messages are logged, including some from Dancer itself
+
=item B<debug> : all messages are logged
=item B<warning> : only warning and error messages are logged
View
6 lib/Dancer/Cookbook.pod
@@ -578,9 +578,9 @@ config.yml will look like this:
=head3 TT's WRAPPER directive in Dancer (META variables, SETs)
-Dancer provides a WRAPPER ability, which we call a "layout". The reason we do
-not use TT's WRAPPER (and that it is incompatible with it) is since not all
-template systems support it. Actually, most don't.
+Dancer already provides a WRAPPER-like ability, which we call a "layout". The
+reason we do not use TT's WRAPPER (which also makes it incompatible with it) is
+because not all template systems support it. Actually, most don't.
However, you might want to use it, and be able to define META variables and
regular L<Template::Toolkit> variables.
View
80 lib/Dancer/Cookie.pm
@@ -10,9 +10,14 @@ __PACKAGE__->attributes('name', 'expires', 'domain', 'path', "secure");
sub init {
my ($self, %args) = @_;
$self->value($args{value});
- if ($self->expires) {
- $self->expires(_epoch_to_gmtstring($self->expires))
- if $self->expires =~ /^\d+$/;
+ if (my $time = $self->expires) {
+ # First, normalize things like +2h to # of seconds
+ $time = _parse_duration($time) if $time !~ /^\d+$/;
+
+ # Then translate to a gmt string, if it isn't one already
+ $time = _epoch_to_gmtstring($time) if $time =~ /^\d+$/;
+
+ $self->expires($time);
}
$self->path('/') unless defined $self->path;
}
@@ -60,6 +65,52 @@ sub _epoch_to_gmtstring {
$hour, $min, $sec;
}
+# This map is taken from Cache and Cache::Cache
+# map of expiration formats to their respective time in seconds
+my %Units = ( map(($_, 1), qw(s second seconds sec secs)),
+ map(($_, 60), qw(m minute minutes min mins)),
+ map(($_, 60*60), qw(h hr hour hours)),
+ map(($_, 60*60*24), qw(d day days)),
+ map(($_, 60*60*24*7), qw(w week weeks)),
+ map(($_, 60*60*24*30), qw(M month months)),
+ map(($_, 60*60*24*365), qw(y year years)) );
+
+# This code is taken from Time::Duration::Parse, except if it isn't
+# understood it just passes it through and it adds the current time.
+sub _parse_duration {
+ my $timespec = shift;
+ my $orig_timespec = $timespec;
+
+ # Treat a plain number as a number of seconds (and parse it later)
+ if ($timespec =~ /^\s*([-+]?\d+(?:[.,]\d+)?)\s*$/) {
+ $timespec = "$1s";
+ }
+
+ # Convert hh:mm(:ss)? to something we understand
+ $timespec =~ s/\b(\d+):(\d\d):(\d\d)\b/$1h $2m $3s/g;
+ $timespec =~ s/\b(\d+):(\d\d)\b/$1h $2m/g;
+
+ my $duration = 0;
+ while ($timespec =~ s/^\s*([-+]?\d+(?:[.,]\d+)?)\s*([a-zA-Z]+)(?:\s*(?:,|and)\s*)*//i) {
+ my($amount, $unit) = ($1, $2);
+ $unit = lc($unit) unless length($unit) == 1;
+
+ if (my $value = $Units{$unit}) {
+ $amount =~ s/,/./;
+ $duration += $amount * $value;
+ } else {
+ return $orig_timespec;
+ }
+ }
+
+ if ($timespec =~ /\S/) {
+ return $orig_timespec;
+ }
+
+ return sprintf "%.0f", $duration + time;
+}
+
+
1;
__END__
@@ -94,7 +145,24 @@ The cookie's value.
=head2 expires
-The cookie's expiration date.
+The cookie's expiration date. There are several formats.
+
+Unix epoch time like 1288817656 to mean "Wed, 03-Nov-2010 20:54:16 GMT"
+
+A human readable offset from the current time such as "2 hours". It currently
+understands...
+
+ s second seconds sec secs
+ m minute minutes min mins
+ h hr hour hours
+ d day days
+ w week weeks
+ M month months
+ y year years
+
+Months and years are currently fixed at 30 and 365 days. This may change.
+
+Anything else is used verbatum.
=head2 domain
@@ -125,10 +193,6 @@ Runs an expiration test and sets a default path if not set.
Creates a proper HTTP cookie header from the content.
-=head2 _epoch_to_gmtstring
-
-Internal method to convert the time from Epoch to GMT.
-
=head1 AUTHOR
Alexis Sukrieh
View
4 lib/Dancer/Handler.pm
@@ -46,8 +46,8 @@ sub handle_request {
my ($self, $request) = @_;
my $ip_addr = $request->remote_address || '-';
- Dancer::SharedData->reset_response();
- Dancer::SharedData->reset_timer;
+ Dancer::SharedData->reset_all();
+
Dancer::Logger::core("request: "
. $request->method . " "
. $request->path_info
View
2  lib/Dancer/Logger/Diag.pm
@@ -43,7 +43,7 @@ lazily.
=head2 _log
-Use Test::More's diag() to poutput the log message.
+Use Test::More's diag() to output the log message.
=head1 AUTHOR
View
64 lib/Dancer/Logger/Note.pm
@@ -0,0 +1,64 @@
+package Dancer::Logger::Note;
+use strict;
+use warnings;
+use base 'Dancer::Logger::Abstract';
+
+sub init {
+ my $self = shift;
+ $self->SUPER::init(@_);
+ require Test::More;
+}
+
+sub _log {
+ my ($self, $level, $message) = @_;
+
+ Test::More::note(
+ $self->format_message( $level => $message )
+ );
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Dancer::Logger::Note - Test::More note() logging engine for Dancer
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+This logging engine uses L<Test::More>'s note() to output as TAP comments.
+
+This is very useful in case you're writing a test and want to have logging
+messages as part of your TAP.
+
+"Like C<diag()>, except the message will not be seen when the test is run in a
+harness. It will only be visible in the verbose TAP stream." -- Test::More.
+
+=head1 METHODS
+
+=head2 init
+
+This method is called when C<< ->new() >> is called. It just loads Test::More
+lazily.
+
+=head2 _log
+
+Use Test::More's note() to output the log message.
+
+=head1 AUTHOR
+
+Alexis Sukrieh
+
+=head1 LICENSE AND COPYRIGHT
+
+Copyright 2009-2010 Alexis Sukrieh.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of either: the GNU General Public License as published
+by the Free Software Foundation; or the Artistic License.
+
+See http://dev.perl.org/licenses/ for more information.
+
View
38 lib/Dancer/Template/TemplateToolkit.pm
@@ -100,6 +100,44 @@ subclass with the C<subclass> option.
subclass: My::Template
+=head1 WRAPPER, META variables, SETs
+
+Dancer already provides a WRAPPER-like ability, which we call a "layout". The
+reason we do not use TT's WRAPPER (which also makes it incompatible with it) is
+because not all template systems support it. Actually, most don't.
+
+However, you might want to use it, and be able to define META variables and
+regular L<Template::Toolkit> variables.
+
+These few steps will get you there:
+
+=over 4
+
+=item * Disable the layout in Dancer
+
+You can do this by simply commenting (or removing) the C<layout> configuration
+in the F<config.yml> file.
+
+=item * Use Template Toolkit template engine
+
+Change the configuration of the template to Template Toolkit:
+
+ # in config.yml
+ template: "template_toolkit"
+
+=item * Tell the Template Toolkit engine who's your wrapper
+
+ # in config.yml
+ # ...
+ engines:
+ template_toolkit:
+ WRAPPER: layouts/main.tt
+
+=back
+
+Done! Everything will work fine out of the box, including variables and META
+variables.
+
=head1 SEE ALSO
L<Dancer>, L<Template>
View
4 lib/Dancer/Test.pm
@@ -222,6 +222,10 @@ sub dancer_response {
$params, $body, HTTP::Headers->new(@$headers)
);
+ # first, reset the current state
+ Dancer::SharedData->reset_all();
+
+ # then store the request
Dancer::SharedData->request($request);
my $get_action = Dancer::Renderer::get_action_response();
View
9 t/00_base/010_export_script.t
@@ -0,0 +1,9 @@
+use Test::More import => ["!pass"];
+use Dancer ':script';
+
+plan tests => 2;
+
+ok(exists($::{'get'}), "symbol `get' is exported");
+
+use Cwd;
+ok setting("appdir"), ":script with exports allow app setup";
View
20 t/03_route_handler/04_wildcards.t
@@ -1,13 +1,7 @@
-use strict;
-use warnings;
-use Test::More import => ['!pass'];
+use Dancer ':tests';
+use Test::More;
-use File::Spec;
-use lib File::Spec->catdir( 't', 'lib' );
-use TestUtils;
-
-use Dancer ':syntax';
-use Dancer::Route;
+use Dancer::Test;
my @paths = (
'/hello/*',
@@ -38,15 +32,11 @@ ok(get($_ => sub { [splat] }), "route $_ is set") for @paths;
foreach my $test (@tests) {
my $path = $test->{path};
my $expected = $test->{expected};
-
- my $request = fake_request(GET => $path);
- Dancer::SharedData->request($request);
- my $response = Dancer::Renderer::get_action_response();
+ my $response = dancer_response(GET => $path);
ok( defined($response), "route handler found for path `$path'");
is_deeply(
- $response->{content}, $expected,
+ $response->content, $expected,
"match data for path `$path' looks good");
- Dancer::SharedData->reset_all();
}
View
15 t/03_route_handler/32_gh_393.t
@@ -0,0 +1,15 @@
+use Dancer ':tests';
+use Test::More;
+use Dancer::Test;
+
+# Test that vars are reset between each request by Dancer::Test
+
+plan tests => 10;
+
+var foo => 0;
+
+get '/' => sub { vars->{foo} += 1; vars->{foo} };
+
+for(1..10) {
+ response_content_is [GET => '/'], 1, "foo is 1";
+}
View
41 t/03_route_handler/33_vars.t
@@ -0,0 +1,41 @@
+use strict;
+use warnings;
+
+# Test that vars are really reset between each request
+
+use Test::More;
+
+use LWP::UserAgent;
+
+plan skip_all => "Test::TCP is needed for this test"
+ unless Dancer::ModuleLoader->load("Test::TCP");
+
+plan tests => 10;
+Test::TCP::test_tcp(
+ client => sub {
+ my $port = shift;
+ my $ua = LWP::UserAgent->new;
+ for (1..10) {
+ my $req = HTTP::Request->new( GET => "http://0.0:$port/getvarfoo" );
+ my $res = $ua->request($req);
+ is $res->content, 1;
+ }
+ },
+ server => sub {
+ my $port = shift;
+
+ use Dancer ":tests";
+
+ # vars should be reset before the handler is called
+ var foo => 42;
+
+ set access_log => 0;
+ set port => $port;
+
+ get "/getvarfoo" => sub {
+ return ++vars->{foo};
+ };
+
+ Dancer->dance;
+ },
+);
View
17 t/05_views/002_view_rendering.t
@@ -1,11 +1,6 @@
-use Test::More import => ['!pass'];
-use strict;
-use warnings;
-
-use Dancer ':syntax';
-use File::Spec;
-use lib File::Spec->catdir( 't', 'lib' );
-use TestUtils;
+use Dancer ':tests';
+use Test::More;
+use Dancer::Test;
set views => path(dirname(__FILE__), 'views');
@@ -56,10 +51,6 @@ foreach my $test (@tests) {
my $path = $test->{path};
my $expected = $test->{expected};
- my $request = fake_request(GET => $path);
- Dancer::SharedData->request($request);
-
- my $resp = Dancer::Renderer::get_action_response();
+ my $resp = dancer_response(GET => $path);
is($resp->content, $expected, "content rendered looks good for $path");
- Dancer::SharedData->reset_all;
}
View
16 t/05_views/03_layout.t
@@ -1,16 +1,13 @@
-use Test::More import => ['!pass'];
-
BEGIN {
+ use Dancer ':tests';
+ use Test::More;
use Dancer::ModuleLoader;
plan skip_all => "Template is needed to run this tests"
unless Dancer::ModuleLoader->load('Template');
};
-use Dancer ':syntax';
-use File::Spec;
-use lib File::Spec->catdir( 't', 'lib' );
-use TestUtils;
+use Dancer::Test;
set views => path(dirname(__FILE__), 'views');
@@ -72,12 +69,7 @@ SKIP: {
my $path = $test->{path};
my $expected = $test->{expected};
- my $request = fake_request(GET => $path);
-
- Dancer::SharedData->request($request);
- my $resp = Dancer::Renderer::get_action_response();
-
+ my $resp = dancer_response(GET => $path);
is($resp->content, $expected, "content rendered looks good for $path");
- Dancer::SharedData->reset_all;
}
};
View
21 t/06_helpers/03_content_type.t
@@ -1,8 +1,6 @@
-use Test::More import => ['!pass'];
-use File::Spec;
-use lib File::Spec->catdir( 't', 'lib' );
-use TestUtils;
-use Dancer ':syntax';
+use Dancer ':tests';
+use Test::More;
+use Dancer::Test;
get '/' => sub {
"hello"
@@ -23,7 +21,6 @@ get '/png' => sub {
"blergh";
};
-
my @tests = (
{ path => '/', expected => setting('content_type')},
{ path => '/text', expected => 'text/plain'},
@@ -36,15 +33,7 @@ my @tests = (
plan tests => scalar(@tests) * 2;
foreach my $test (@tests) {
- my $request = fake_request(GET => $test->{path});
- Dancer::SharedData->request($request);
- my $response = Dancer::Renderer::get_action_response();
-
+ my $response = dancer_response(GET => $test->{path});
ok(defined($response), "route handler found for ".$test->{path});
- my %headers = @{$response->headers_to_array};
- is($headers{'Content-Type'},
- $test->{expected},
- "content_type looks good for ".$test->{path});
- Dancer::SharedData->reset_all();
+ is $response->header('Content-Type'), $test->{expected};
}
-
View
16 t/06_helpers/04_status.t
@@ -1,9 +1,6 @@
-use Test::More import => ['!pass'];
-use File::Spec;
-use lib File::Spec->catdir( 't', 'lib' );
-use TestUtils;
-
-use Dancer ':syntax';
+use Dancer ':tests';
+use Test::More;
+use Dancer::Test;
get '/' => sub {
"hello"
@@ -25,14 +22,11 @@ my @tests = (
plan tests => scalar(@tests) * 2;
foreach my $test (@tests) {
- my $request = fake_request(GET => $test->{path});
- Dancer::SharedData->request($request);
- my $response = Dancer::Renderer::get_action_response();
+ my $response = dancer_response(GET => $test->{path});
ok(defined($response), "route handler found for ".$test->{path});
- is($response->{status},
+ is($response->status,
$test->{expected},
"status looks good for ".$test->{path});
- Dancer::SharedData->reset_all();
}
View
25 t/09_cookies/02_cookie_object.t
@@ -1,6 +1,6 @@
use strict;
use warnings;
-use Test::More tests => 13;
+use Test::More tests => 5;
use Dancer::Cookie;
my $c = Dancer::Cookie->new(
@@ -14,29 +14,6 @@ is(ref($c), 'Dancer::Cookie',
is($c->to_header, 'dancer.slot=42; path=/; HttpOnly',
"simple cookie header looks good");
-my %tests = (
- 1288817656 => "Wed, 03-Nov-2010 20:54:16 GMT",
- 1288731256 => "Tue, 02-Nov-2010 20:54:16 GMT",
- 1288644856 => "Mon, 01-Nov-2010 20:54:16 GMT",
- 1288558456 => "Sun, 31-Oct-2010 20:54:16 GMT",
- 1288472056 => "Sat, 30-Oct-2010 20:54:16 GMT",
- 1288385656 => "Fri, 29-Oct-2010 20:54:16 GMT",
- 1288299256 => "Thu, 28-Oct-2010 20:54:16 GMT",
- 1288212856 => "Wed, 27-Oct-2010 20:54:16 GMT",
-);
-
-while(my ($time, $expected) = each %tests) {
- $c = Dancer::Cookie->new(
- name => 'dancer.slot',
- value => 42,
- expires => $time,
- );
-
- is($c->to_header,
- "dancer.slot=42; path=/; expires=$expected; HttpOnly",
- "header with expires looks good ($time)");
-}
-
$c = Dancer::Cookie->new(
name => 'dancer.slot',
value => 42,
View
59 t/09_cookies/06_expires.t
@@ -0,0 +1,59 @@
+use strict;
+use warnings;
+use Test::More;
+
+BEGIN {
+ # Freeze time at Tue, 15-Jun-2010 00:00:00 GMT
+ *CORE::GLOBAL::time = sub { return 1276560000 }
+}
+
+use Dancer::Cookie;
+
+my $min = 60;
+my $hour = 60 * $min;
+my $day = 24 * $hour;
+my $week = 7 * $day;
+my $mon = 30 * $day;
+my $year = 365 * $day;
+
+note "expiration times"; {
+ my %times = (
+ "+2h" => "Tue, 15-Jun-2010 02:00:00 GMT",
+ "-2h" => "Mon, 14-Jun-2010 22:00:00 GMT",
+ "1 hour" => "Tue, 15-Jun-2010 01:00:00 GMT",
+ "3 weeks 4 days 2 hours 99 min 0 secs" => "Sat, 10-Jul-2010 03:39:00 GMT",
+ "2 months" => "Sat, 14-Aug-2010 00:00:00 GMT",
+ "12 years" => "Sun, 12-Jun-2022 00:00:00 GMT",
+
+ 1288817656 => "Wed, 03-Nov-2010 20:54:16 GMT",
+ 1288731256 => "Tue, 02-Nov-2010 20:54:16 GMT",
+ 1288644856 => "Mon, 01-Nov-2010 20:54:16 GMT",
+ 1288558456 => "Sun, 31-Oct-2010 20:54:16 GMT",
+ 1288472056 => "Sat, 30-Oct-2010 20:54:16 GMT",
+ 1288385656 => "Fri, 29-Oct-2010 20:54:16 GMT",
+ 1288299256 => "Thu, 28-Oct-2010 20:54:16 GMT",
+ 1288212856 => "Wed, 27-Oct-2010 20:54:16 GMT",
+
+ # Anything not understood is passed through
+ "basset hounds got long ears" => "basset hounds got long ears",
+ );
+
+ for my $exp (keys %times) {
+ my $want = $times{$exp};
+ note $want;
+
+ my $cookie = Dancer::Cookie->new(
+ name => "shut.up.and.dance",
+ value => "FMV",
+ expires => $exp
+ );
+
+ is($cookie->to_header,
+ "shut.up.and.dance=FMV; path=/; expires=$want; HttpOnly",
+ "header with expires");
+
+ is $cookie->expires, $want, "expires";
+ }
+}
+
+done_testing;
View
28 t/11_logger/10_note.t
@@ -0,0 +1,28 @@
+use Test::More tests => 6, import => ['!pass'];
+
+use strict;
+use warnings;
+
+use File::Spec;
+use lib File::Spec->catdir( 't', 'lib' );
+use EasyMocker;
+
+use_ok 'Dancer::Logger::Note';
+
+my $l = Dancer::Logger::Note->new;
+
+ok defined($l), 'Dancer::Logger::Note object';
+isa_ok $l, 'Dancer::Logger::Note';
+can_ok $l, qw(init _log debug warning error);
+
+my $format = $l->format_message('debug', 'test');
+like $format, qr/\[\d+\] debug @.+> test in/,
+ "format looks good";
+
+my $noted = 0;
+
+mock 'Test::More::note' => sub { $noted++ };
+
+$l->_log( debug => 'Perl Dancer test message' );
+
+ok( $noted, 'Reached note() of Test::More' );
View
65 t/12_response/02_headers.t
@@ -2,30 +2,28 @@
# I really suck ass at tests, pardon my French :) - damog
#
-use Test::More import => ['!pass'];
-use File::Spec;
-use lib File::Spec->catdir( 't', 'lib' );
-use TestUtils;
+use Dancer ':tests';
-use Dancer ':syntax';
+use Test::More;
+use Dancer::Test;
get '/header', sub {
- header 'X-Foo' => 'xfoo';
+ header 'X-Foo' => 'xfoo';
};
get '/headers', sub {
- headers 'X-A' => 'a', 'X-B' => 'b';
+ headers 'X-A' => 'a', 'X-B' => 'b';
};
get '/headers/more', sub {
- headers 'X-Foo' => 'bar';
- header 'X-Bar' => 'schmuk', 'X-XXX' => 'porn';
- header 'Content-Type', 'text/css'; # this gets overriden
+ headers 'X-Foo' => 'bar';
+ header 'X-Bar' => 'schmuk', 'X-XXX' => 'porn';
+ header 'Content-Type', 'text/css'; # this gets overriden
};
get '/headers/content_type', sub {
- content_type 'text/xml';
- headers 'Content-Type' => 'text/css';
+ content_type 'text/xml';
+ headers 'Content-Type' => 'text/css';
};
get '/headers/multiple' => sub {
@@ -35,47 +33,31 @@ get '/headers/multiple' => sub {
plan tests => 10;
# /header
-my $req = fake_request(GET => '/header');
-Dancer::SharedData->request($req);
-my $res = Dancer::Renderer::get_action_response();
-my %headers = @{$res->headers_to_array};
-is($headers{'X-Foo'},
+my $res = dancer_response(GET => '/header');
+is($res->header('X-Foo'),
'xfoo',
"X-Foo looks good for /header");
# /headers
-$req = fake_request(GET => '/headers');
-Dancer::SharedData->request($req);
-$res = Dancer::Renderer::get_action_response();
-%headers = @{$res->headers_to_array};
-is($headers{'X-A'},
+$res = dancer_response(GET => '/headers');
+is($res->header('X-A'),
'a',
"X-A looks good for /headers");
-is($headers{'X-B'}, 'b', 'X-B looks good for /headers');
+is($res->header('X-B'), 'b', 'X-B looks good for /headers');
# /headers/more
-$req = fake_request(GET => '/headers/more');
-Dancer::SharedData->request($req);
-$res = Dancer::Renderer::get_action_response();
-%headers = @{$res->headers_to_array};
-is($headers{'X-Foo'}, 'bar', "X-Foo looks good for /headers/more");
-is($headers{'X-Bar'}, 'schmuk', "X-Bar looks good for /headers/more");
-is($headers{'X-XXX'}, 'porn', "X-XXX looks good for /headers/more");
-is($headers{'Content-Type'}, 'text/css', "Content-Type looks good for /headers/more");
-Dancer::SharedData->reset_all();
+$res = dancer_response(GET => '/headers/more');
+is($res->header('X-Foo'), 'bar', "X-Foo looks good for /headers/more");
+is($res->header('X-Bar'), 'schmuk', "X-Bar looks good for /headers/more");
+is($res->header('X-XXX'), 'porn', "X-XXX looks good for /headers/more");
+is($res->header('Content-Type'), 'text/css', "Content-Type looks good for /headers/more");
# /headers/content_type
-$req = fake_request(GET => '/headers/content_type');
-Dancer::SharedData->request($req);
-$res = Dancer::Renderer::get_action_response();
-%headers = @{$res->headers_to_array};
-is($headers{'Content-Type'}, 'text/css', "Content-Type looks good for /headers/content_type");
-Dancer::SharedData->reset_all();
+$res = dancer_response(GET => '/headers/content_type');
+is($res->header('Content-Type'), 'text/css', "Content-Type looks good for /headers/content_type");
# /headers/multiple
-$req = fake_request(GET => '/headers/multiple');
-Dancer::SharedData->request($req);
-$res = Dancer::Renderer::get_action_response();
+$res = dancer_response(GET => '/headers/multiple');
is_deeply $res->headers_to_array, [
'Content-Type' => 'text/html',
Bar => 3,
@@ -83,7 +65,6 @@ is_deeply $res->headers_to_array, [
Foo => 2,
Foo => 4,
], 'multiple headers are kept';
-Dancer::SharedData->reset_all();
# Dancer::Response header's API
$res = Dancer::Response->new(
Please sign in to comment.
Something went wrong with that request. Please try again.