Unicode plugin: import tests and update current ones
Wallace Reis [Sat, 4 May 2013 17:28:58 +0000 (19:28 +0200)]
17 files changed:
t/aggregate/live_plugin_loaded.t
t/aggregate/unit_core_plugin.t
t/lib/PluginTestApp.pm
t/lib/PluginTestApp/Controller/Root.pm
t/lib/TestApp.pm
t/lib/TestApp/Controller/Root.pm
t/lib/TestApp2.pm [new file with mode: 0644]
t/lib/TestApp2/Controller/Root.pm [new file with mode: 0644]
t/lib/TestAppUnicode.pm [new file with mode: 0644]
t/lib/TestAppUnicode/Controller/Root.pm [new file with mode: 0644]
t/lib/TestLogger.pm [new file with mode: 0644]
t/live_redirect_body.t
t/unicode_plugin_charset_utf8.t [new file with mode: 0644]
t/unicode_plugin_config.t [new file with mode: 0644]
t/unicode_plugin_live.t [new file with mode: 0644]
t/unicode_plugin_nested_params.t [new file with mode: 0644]
t/unicode_plugin_request_decode.t [new file with mode: 0644]

index 6795043..64161aa 100644 (file)
@@ -15,6 +15,7 @@ my @expected = qw[
   Catalyst::Plugin::Test::Inline
   Catalyst::Plugin::Test::MangleDollarUnderScore
   Catalyst::Plugin::Test::Plugin
+  Catalyst::Plugin::Unicode::Encoding
   TestApp::Plugin::AddDispatchTypes
   TestApp::Plugin::FullyQualified
 ];
index 16a5e24..becc3c1 100644 (file)
@@ -53,6 +53,7 @@ my @expected = qw(
   Catalyst::Plugin::Test::Inline
   Catalyst::Plugin::Test::MangleDollarUnderScore
   Catalyst::Plugin::Test::Plugin
+  Catalyst::Plugin::Unicode::Encoding
   TestApp::Plugin::AddDispatchTypes
   TestApp::Plugin::FullyQualified
 );
index 29a02cd..7af690d 100644 (file)
@@ -14,8 +14,9 @@ sub _test_plugins {
     is_deeply [ $c->registered_plugins ],
     [
         qw/Catalyst::Plugin::Test::Plugin
+        Catalyst::Plugin::Unicode::Encoding
         TestApp::Plugin::FullyQualified/
-        ],
+    ],
     '... and it should report the correct plugins';
     ok $c->registered_plugins('Catalyst::Plugin::Test::Plugin'),
     '... or if we have a particular plugin';
index 7bec366..94f4378 100644 (file)
@@ -49,6 +49,7 @@ sub run_time_plugins : Local {
     is_deeply [ $c->registered_plugins ],
     [
         qw/Catalyst::Plugin::Test::Plugin
+        Catalyst::Plugin::Unicode::Encoding
         Faux::Plugin
         TestApp::Plugin::FullyQualified/
         ],
index a99301c..e548872 100644 (file)
@@ -49,7 +49,7 @@ TestApp->config(
         action_args => {
             action_action_nine => { another_extra_arg => 13 }
         }
-    }
+    },
 );
 
 # Test bug found when re-adjusting the metaclass compat code in Moose
index f2acb21..b626bdb 100644 (file)
@@ -2,6 +2,7 @@ package TestApp::Controller::Root;
 use strict;
 use warnings;
 use base 'Catalyst::Controller';
+use utf8;
 
 __PACKAGE__->config->{namespace} = '';
 
diff --git a/t/lib/TestApp2.pm b/t/lib/TestApp2.pm
new file mode 100644 (file)
index 0000000..552b8c6
--- /dev/null
@@ -0,0 +1,20 @@
+package TestApp2;
+use strict;
+use warnings;
+use base qw/Catalyst/;
+use Catalyst qw/Params::Nested/;
+
+__PACKAGE__->config(
+  encoding => $ENV{TESTAPP_ENCODING}
+) if $ENV{TESTAPP_ENCODING};
+
+__PACKAGE__->config('name' => 'TestApp2');
+
+__PACKAGE__->setup;
+
+sub handle_unicode_encoding_exception {
+  my ( $self, $param_value, $error_msg ) = @_;
+  return $param_value;
+}
+
+1;
diff --git a/t/lib/TestApp2/Controller/Root.pm b/t/lib/TestApp2/Controller/Root.pm
new file mode 100644 (file)
index 0000000..0fefe63
--- /dev/null
@@ -0,0 +1,16 @@
+package TestApp2::Controller::Root;
+use strict;
+use warnings;
+use utf8;
+
+__PACKAGE__->config(namespace => q{});
+
+use base 'Catalyst::Controller';
+
+# your actions replace this one
+sub main :Path('') { 
+    $_[1]->res->body('<h1>It works</h1>');
+    $_[1]->res->content_type('text/html');
+}
+
+1;
diff --git a/t/lib/TestAppUnicode.pm b/t/lib/TestAppUnicode.pm
new file mode 100644 (file)
index 0000000..50ad98a
--- /dev/null
@@ -0,0 +1,23 @@
+package TestAppUnicode;
+use strict;
+use warnings;
+use TestLogger;
+use base qw/Catalyst/;
+use Catalyst qw/Unicode::Encoding Params::Nested/;
+
+__PACKAGE__->config(
+  encoding => $ENV{TESTAPP_ENCODING}
+) if $ENV{TESTAPP_ENCODING};
+
+__PACKAGE__->config('name' => 'TestAppUnicode');
+
+__PACKAGE__->log(TestLogger->new);
+
+__PACKAGE__->setup;
+
+sub handle_unicode_encoding_exception {
+  my ( $self, $param_value, $error_msg ) = @_;
+  return $param_value;
+}
+
+1;
diff --git a/t/lib/TestAppUnicode/Controller/Root.pm b/t/lib/TestAppUnicode/Controller/Root.pm
new file mode 100644 (file)
index 0000000..a944b95
--- /dev/null
@@ -0,0 +1,80 @@
+package TestAppUnicode::Controller::Root;
+use strict;
+use warnings;
+use utf8;
+
+__PACKAGE__->config(namespace => q{});
+
+use base 'Catalyst::Controller';
+
+sub main :Path('') { 
+    my ($self, $ctx, $charset) = @_;
+    my $content_type = 'text/html';
+    if ($ctx->stash->{charset}) {
+        $content_type .= ";charset=" . $ctx->stash->{charset};
+    }
+    $ctx->res->body('<h1>It works</h1>');
+    $ctx->res->content_type($content_type);
+}
+
+sub unicode_no_enc :Local {
+    my ($self, $c) = @_;
+    my $data = "ほげ"; # hoge!
+    utf8::encode($data);
+    $c->response->body($data);
+    $c->res->content_type('text/plain');
+    $c->encoding(undef);
+}
+
+sub unicode :Local {
+    my ($self, $c) = @_;
+    my $data = "ほげ"; # hoge!
+    $c->response->body($data); # should be decoded
+    $c->res->content_type('text/plain');
+}
+
+sub not_unicode :Local {
+    my ($self, $c) = @_;
+    my $data = "\x{1234}\x{5678}";
+    utf8::encode($data); # DO NOT WANT unicode
+    $c->response->body($data); # just some octets
+    $c->res->content_type('text/plain');
+    $c->encoding(undef);
+}
+
+sub latin1 :Local {
+  my ($self, $c) = @_;
+
+  $c->res->content_type('text/plain');
+  $c->response->body('LATIN SMALL LETTER E WITH ACUTE: é');
+}
+
+sub file :Local {
+    my ($self, $c) = @_;
+    close *STDERR; # i am evil.
+    $c->response->body($main::TEST_FILE); # filehandle from test file
+}
+
+sub capture : Chained('/') CaptureArgs(1) {}
+
+sub decode_capture : Chained('capture') PathPart('') Args(0) {
+    my ( $self, $c, $cap_arg ) = @_;
+    $c->forward('main');
+}
+
+sub capture_charset : Chained('/') Args(1) {
+    my ( $self, $c, $cap_arg ) = @_;
+    $c->stash(charset => $cap_arg);
+    $c->forward('main');
+}
+
+sub shift_jis :Local {
+    my ($self, $c) = @_;
+    my $data = "ほげ"; # hoge!
+    $c->response->body($data); # should be decoded
+    $c->res->content_type('text/plain; charset=Shift_JIS');
+    $c->encoding("Shift_JIS");
+}
+
+1;
+
diff --git a/t/lib/TestLogger.pm b/t/lib/TestLogger.pm
new file mode 100644 (file)
index 0000000..f1dc7e6
--- /dev/null
@@ -0,0 +1,23 @@
+package TestLogger;
+use strict;
+use warnings;
+
+our @LOGS;
+our @ELOGS;
+
+sub new {
+    return bless {}, __PACKAGE__;
+}
+
+sub debug {
+    shift;
+    push(@LOGS, shift());
+}
+
+sub warn {
+    shift;
+    push(@ELOGS, shift());
+}
+
+1;
+
index 913f0e9..8b9d62c 100644 (file)
@@ -40,7 +40,7 @@ use Test::More;
     is( $response->code, 302, 'Response Code' );
 
     # When the developer sets both the content body and content type, the set content body and content_type should get through.
-    is( $response->header( 'Content-Type' ), 'text/plain', 'Content Type' );
+    like( $response->header( 'Content-Type' ), qr{text/plain}, 'Content Type' );
     like( $response->content, qr/kind sir/, 'Content contains content set by the Controller' );
 }
 
diff --git a/t/unicode_plugin_charset_utf8.t b/t/unicode_plugin_charset_utf8.t
new file mode 100644 (file)
index 0000000..9700b73
--- /dev/null
@@ -0,0 +1,32 @@
+use strict;
+use warnings;
+use Test::More;
+use FindBin qw/ $Bin /;
+use lib "$Bin/lib";
+use Data::Dumper;
+
+BEGIN {
+    $ENV{TESTAPP_ENCODING} = 'UTF-8';
+    $ENV{TESTAPP_DEBUG} = 0;
+    $ENV{CATALYST_DEBUG} = 0;
+}
+
+use Catalyst::Test 'TestAppUnicode';
+
+ok request('/capture_charset/utf-8');
+is scalar(@TestLogger::LOGS), 0;
+
+ok request('/capture_charset/latin1');
+is scalar(@TestLogger::LOGS), 1
+    or diag Dumper(\@TestLogger::LOGS);
+
+@TestLogger::LOGS = ();
+
+ok request('/capture_charset/iso-8859-1; header=present');
+is scalar(@TestLogger::LOGS), 1
+    or diag Dumper(\@TestLogger::LOGS);
+like $TestLogger::LOGS[0], qr/content type is 'iso-8859-1'/;
+
+like $TestLogger::ELOGS[0], qr/plugin is now part of core/;
+
+done_testing;
diff --git a/t/unicode_plugin_config.t b/t/unicode_plugin_config.t
new file mode 100644 (file)
index 0000000..513c978
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use Test::More;
+
+BEGIN { $ENV{TESTAPP_ENCODING} = 'UTF-8' };
+
+# setup library path
+use FindBin qw($Bin);
+use lib "$Bin/lib";
+
+BEGIN {
+if ( !eval { require Test::WWW::Mechanize::Catalyst } || ! Test::WWW::Mechanize::Catalyst->VERSION('0.51') ) {
+    plan skip_all => 'Need Test::WWW::Mechanize::Catalyst for this test';
+}
+}
+
+# make sure testapp works
+use_ok('TestAppUnicode');
+
+use Test::WWW::Mechanize::Catalyst 'TestAppUnicode';
+my $mech = Test::WWW::Mechanize::Catalyst->new;
+
+{
+    TestAppUnicode->encoding('UTF-8');
+    $mech->get_ok('http://localhost/unicode', 'encoding configured ok');
+}
+
+done_testing;
+
diff --git a/t/unicode_plugin_live.t b/t/unicode_plugin_live.t
new file mode 100644 (file)
index 0000000..de810aa
--- /dev/null
@@ -0,0 +1,93 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use Test::More;
+use IO::Scalar;
+
+# setup library path
+use FindBin qw($Bin);
+use lib "$Bin/lib";
+
+BEGIN {
+if ( !eval { require Test::WWW::Mechanize::Catalyst } || ! Test::WWW::Mechanize::Catalyst->VERSION('0.51') ) {
+    plan skip_all => 'Need Test::WWW::Mechanize::Catalyst for this test';
+}
+}
+
+# make sure testapp works
+use_ok('TestAppUnicode') or BAIL_OUT($@);
+
+our $TEST_FILE = IO::Scalar->new(\"this is a test");
+sub IO::Scalar::FILENO { -1 }; # needed?
+
+# a live test against TestAppUnicode, the test application
+use Test::WWW::Mechanize::Catalyst 'TestAppUnicode';
+my $mech = Test::WWW::Mechanize::Catalyst->new;
+$mech->get_ok('http://localhost/', 'get main page');
+$mech->content_like(qr/it works/i, 'see if it has our text');
+is ($mech->response->header('Content-Type'), 'text/html; charset=UTF-8',
+    'Content-Type with charset'
+);
+
+{
+    $mech->get_ok('http://localhost/unicode_no_enc', 'get unicode_no_enc');
+
+    my $exp = "\xE3\x81\xBB\xE3\x81\x92";
+    my $got = Encode::encode_utf8($mech->content);
+
+    is ($mech->response->header('Content-Type'), 'text/plain',
+        'Content-Type with no charset');
+
+    is($got, $exp, 'content contains hoge');
+}
+
+{
+    $mech->get_ok('http://localhost/unicode', 'get unicode');
+
+    is ($mech->response->header('Content-Type'), 'text/plain; charset=UTF-8',
+        'Content-Type with charset');
+
+    my $exp = "\xE3\x81\xBB\xE3\x81\x92";
+    my $got = Encode::encode_utf8($mech->content);
+
+    is($got, $exp, 'content contains hoge');
+}
+
+{
+    $mech->get_ok('http://localhost/not_unicode', 'get bytes');
+    my $exp = "\xE1\x88\xB4\xE5\x99\xB8";
+    my $got = Encode::encode_utf8($mech->content);
+
+    is($got, $exp, 'got 1234 5678');
+}
+
+{
+    $mech->get_ok('http://localhost/file', 'get file');
+    $mech->content_like(qr/this is a test/, 'got filehandle contents');
+}
+
+{
+    # The latin 1 case is the one everyone forgets. I want to really make sure
+    # its right, so lets check the damn bytes.
+    $mech->get_ok('http://localhost/latin1', 'get latin1');
+    is ($mech->response->header('Content-Type'), 'text/plain; charset=UTF-8',
+        'Content-Type with charset');
+
+
+    my $exp = "LATIN SMALL LETTER E WITH ACUTE: \xC3\xA9";
+    my $got = Encode::encode_utf8($mech->content);
+
+    is ($got, $exp, 'content octets are UTF-8');
+}
+
+{
+    $mech->get_ok('http://localhost/shift_jis', 'get shift_jis');
+    is ($mech->response->header('Content-Type'), 'text/plain; charset=Shift_JIS', 'Content-Type with charset');
+    my $exp = "\xE3\x81\xBB\xE3\x81\x92";
+    my $got = Encode::encode_utf8($mech->content);
+    is ($got, $exp, 'content octets are Shift_JIS');
+}
+
+done_testing;
+
diff --git a/t/unicode_plugin_nested_params.t b/t/unicode_plugin_nested_params.t
new file mode 100644 (file)
index 0000000..b31f4ce
--- /dev/null
@@ -0,0 +1,71 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use Test::More;
+use utf8;
+
+# setup library path
+use FindBin qw($Bin);
+use lib "$Bin/lib";
+
+BEGIN { eval { require Catalyst::Plugin::Params::Nested; 1; } ||
+    plan skip_all => 'Need Catalyst::Plugin::Params::Nested' }
+
+use Catalyst::Test 'TestApp2';
+use Encode;
+use HTTP::Request::Common;
+use URI::Escape qw/uri_escape_utf8/;
+use HTTP::Status 'is_server_error';
+
+my $encode_str = "\x{e3}\x{81}\x{82}"; # e38182 is japanese 'あ'
+my $decode_str = Encode::decode('utf-8' => $encode_str);
+my $escape_str = uri_escape_utf8($decode_str);
+
+BEGIN {
+    eval 'require Catalyst::Plugin::Params::Nested';
+    plan skip_all => 'Catalyst::Plugin::Params::Nested is required' if $@;
+}
+
+{
+    my ($res, $c) = ctx_request("/?foo.1=bar&foo.2=$escape_str");
+    is( $c->res->output, '<h1>It works</h1>', 'Content displayed' );
+    
+    my $got = $c->request->parameters;
+    my $expected = {
+        'foo.1' => 'bar',
+        'foo.2' => $decode_str,
+        'foo'   => [undef, 'bar', $decode_str],
+    };
+    
+    is( $got->{foo}->[0], undef, '{foo}->[0] is undef' );
+    is( $got->{foo}->[1], 'bar', '{foo}->[1] is bar' );
+    ok( utf8::is_utf8( $got->{'foo.2'}       ), '{foo.2} is utf8' );
+    ok( utf8::is_utf8( $got->{foo}->[2]      ), '{foo}->[2] is utf8' );
+    is_deeply($got, $expected, 'nested params' );
+}
+
+{
+    my ($res, $c) = ctx_request("/?foo.1=bar&foo.2=$escape_str&bar.baz=$escape_str&baz.bar.foo=$escape_str&&arr.0.1=$escape_str");
+    
+    my $got = $c->request->parameters;
+    my $expected = {
+        'foo.1'       => 'bar',
+        'foo.2'       => $decode_str,
+        'bar.baz'     => $decode_str,
+        'baz.bar.foo' => $decode_str,
+        'arr.0.1'     => $decode_str,
+        'arr'         => [ [undef, $decode_str] ],
+        'foo'         => [undef, 'bar', $decode_str],
+        'bar'         => { baz => $decode_str },
+        'baz'         => { bar => { foo => $decode_str } },
+    };
+    
+    is( ref $got->{arr}->[0], 'ARRAY', '{arr}->[0] is ARRAY' );
+    ok( utf8::is_utf8( $got->{arr}->[0]->[1] ), '{arr}->[0]->[1] is utf8' );
+    ok( utf8::is_utf8( $got->{bar}{baz}      ), '{bar}{baz} is utf8' );
+    ok( utf8::is_utf8( $got->{baz}{bar}{foo} ), '{baz}{bar}{foo} is utf8' );
+    is_deeply($got, $expected, 'nested params' );
+}
+
+done_testing();
diff --git a/t/unicode_plugin_request_decode.t b/t/unicode_plugin_request_decode.t
new file mode 100644 (file)
index 0000000..a3bab97
--- /dev/null
@@ -0,0 +1,82 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use Test::More tests => 5 * 5;
+use utf8;
+
+# setup library path
+use FindBin qw($Bin);
+use lib "$Bin/lib";
+
+use Catalyst::Test 'TestAppUnicode';
+use Encode;
+use HTTP::Request::Common;
+use URI::Escape qw/uri_escape_utf8/;
+use HTTP::Status 'is_server_error';
+
+my $encode_str = "\x{e3}\x{81}\x{82}"; # e38182 is japanese 'あ'
+my $decode_str = Encode::decode('utf-8' => $encode_str);
+my $escape_str = uri_escape_utf8($decode_str);
+
+check_parameter(GET "/?foo=$escape_str");
+check_parameter(POST '/', ['foo' => $encode_str]);
+check_parameter(POST '/',
+    Content_Type => 'form-data',
+    Content => [
+        'foo' => [
+            "$Bin/unicode_plugin_request_decode.t",
+            $encode_str,
+        ]
+    ],
+);
+
+check_argument(GET "/$escape_str");
+check_capture(GET "/capture/$escape_str");
+
+# sending non-utf8 data
+my $non_utf8_data = "%C3%E6%CB%AA";
+check_fallback(GET "/?q=${non_utf8_data}");
+check_fallback(GET "/${non_utf8_data}");
+check_fallback(GET "/capture/${non_utf8_data}");
+check_fallback(POST '/', ['foo' => $non_utf8_data]);
+
+sub check_parameter {
+    my ( undef, $c ) = ctx_request(shift);
+    is $c->res->output => '<h1>It works</h1>';
+
+    my $foo = $c->req->param('foo');
+    ok utf8::is_utf8($foo);
+    is $foo => $decode_str;
+
+    my $other_foo = $c->req->method eq 'POST'
+        ? $c->req->upload('foo')
+            ? $c->req->upload('foo')->filename
+            : $c->req->body_parameters->{foo}
+        : $c->req->query_parameters->{foo};
+    ok utf8::is_utf8($other_foo);
+    is $other_foo => $decode_str;
+}
+
+sub check_argument {
+    my ( undef, $c ) = ctx_request(shift);
+    is $c->res->output => '<h1>It works</h1>';
+
+    my $foo = $c->req->args->[0];
+    ok utf8::is_utf8($foo);
+    is $foo => $decode_str;
+}
+
+sub check_capture {
+    my ( undef, $c ) = ctx_request(shift);
+    is $c->res->output => '<h1>It works</h1>';
+
+    my $foo = $c->req->captures->[0];
+    ok utf8::is_utf8($foo);
+    is $foo => $decode_str;
+}
+
+sub check_fallback {
+  my ( $res, $c ) = ctx_request(shift);
+  ok(!is_server_error($res->code)) or diag('Response code is: ' . $res->code);
+}