Explorar el Código

Fix #58: Add ability to pass chara encoding

George S. Baugh hace 10 años
padre
commit
285ed06b54

+ 9 - 1
bin/testrail-report

@@ -34,6 +34,9 @@ these in as needed, supposing you are not redirecting input
     --config [someconfig] : filter run by the provided configuration.
       This option can be passed multiple times for detailed filtering.
 
+    -e --encoding: Character encoding of arguments.  Defaults to UTF-8.
+                   See L<Encode::Supported> for supported encodings.
+
 Test plans can have runs with the same name, but different configurations, which is understandably confusing.
 You can do the same outside of plans, and without configurations; but doing so is ill advised, and the only option from there is to use IDs.
 So, try not to do that if you want to use this tool, and want sanity in your Test management system.
@@ -148,6 +151,9 @@ PARAMETERS:
     --configs [someconfigs] : filter run by the provided configuration.
       This option can be passed multiple times for detailed filtering.
 
+    -e --encoding: Character encoding of arguments.  Defaults to UTF-8.
+                   See L<Encode::Supported> for supported encodings.
+
   Test plans can have runs with the same name, but different
   configurations, which is understandably confusing.  You can do the
   same outside of plans, and without configurations; but doing so is
@@ -239,7 +245,7 @@ TESTING OPTIONS:
 
 #Main loop------------
 
-my ($help,$apiurl,$user,$password,$project,$run,$case_per_ok,$step_results,$mock,$configs,$plan,$version,$spawn,$sections,$autoclose);
+my ($help,$apiurl,$user,$password,$project,$run,$case_per_ok,$step_results,$mock,$configs,$plan,$version,$spawn,$sections,$autoclose,$encoding);
 
 #parse switches
 GetOptions(
@@ -257,6 +263,7 @@ GetOptions(
     'spawn=i'        => \$spawn,
     'section=s@'     => \$sections,
     'autoclose'      => \$autoclose,
+    'e|encoding=s'   => \$encoding,
     'help'           => \$help
 );
 
@@ -371,6 +378,7 @@ foreach my $phil (@files) {
         'spawn'        => $spawn,
         'sections'     => $sections,
         'autoclose'    => $autoclose,
+        'encoding'     => $encoding,
         'merge'        => 1
     });
     $tap->run();

+ 14 - 9
bin/testrail-runs

@@ -21,6 +21,8 @@ Groups by plan for runs which are children of a plan.
 
     -c --config [config]: configuration name to filter runs.  Can be passed multiple times.
     -s --status [status]: only list runs with one or more tests having [status] in testrail.  Can be passed multiple times.
+    -e --encoding: Character encoding of arguments.  Defaults to UTF-8.
+                   See L<Encode::Supported> for supported encodings.
 
 =head3 CONFIG OPTIONS
 
@@ -74,6 +76,8 @@ PARAMETERS:
 
     -c --config [config]: configuration name to filter runs.  Can be passed multiple times.
     -s --status [status]: only list runs with one or more tests having [status] in testrail.  Can be passed multiple times.
+    -e --encoding: Character encoding of arguments.  Defaults to UTF-8.
+                   See L<Encode::Supported> for supported encodings.
 
   [CONFIG OPTIONS]
     In your \$HOME, (or the current directory, if your system has no
@@ -101,14 +105,15 @@ TESTING OPTIONS:
 my %opts;
 
 GetOptions(
-    'apiurl=s'          => \$opts{'apiurl'},
-    'password=s'        => \$opts{'pass'},
-    'user=s'            => \$opts{'user'},
-    'j|project=s'     => \$opts{'project'},
-    'c|config=s@'     => \$opts{'configs'},
-    's|status=s@'     => \$opts{'statuses'},
-    'mock'            => \$opts{'mock'},
-    'h|help'          => \$opts{'help'}
+    'apiurl=s'     => \$opts{'apiurl'},
+    'password=s'   => \$opts{'pass'},
+    'user=s'       => \$opts{'user'},
+    'j|project=s'  => \$opts{'project'},
+    'c|config=s@'  => \$opts{'configs'},
+    's|status=s@'  => \$opts{'statuses'},
+    'mock'         => \$opts{'mock'},
+    'e|encoding=s' => \$opts{'encoding'},
+    'h|help'       => \$opts{'help'}
 );
 
 if ($opts{help}) { help(); }
@@ -152,7 +157,7 @@ if ($opts{mock}) {
     $opts{debug} = 1;
 }
 
-my $tr = TestRail::API->new($opts{apiurl},$opts{user},$opts{pass},$opts{'debug'});
+my $tr = TestRail::API->new($opts{apiurl},$opts{user},$opts{pass},$opts{'encoding'},$opts{'debug'});
 $tr->{'browser'} = $opts{'browser'} if $opts{'browser'};
 $tr->{'debug'} = 0;
 

+ 10 - 4
bin/testrail-tests

@@ -23,6 +23,8 @@ testrail-tests - list tests in a run matching the provided filters.
     -m --match [dir]: attempt to find filenames matching the test names in the provided dir.
     --no-match [dir]: attempt to find filenames that do not match test names in the provided dir.
     -n --no-recurse: if match (or no-match) passed, do not recurse subdirectories.
+    -e --encoding: Character encoding of arguments.  Defaults to UTF-8.
+                   See L<Encode::Supported> for supported encodings.
 
 =head3 OPTIONAL PARAMETERS
 
@@ -89,6 +91,9 @@ PARAMETERS:
 
     -n --no-recurse: if match passed, do not recurse subdirectories.
 
+    -e --encoding: Character encoding of arguments.  Defaults to UTF-8.
+                   See L<Encode::Supported> for supported encodings.
+
   [OPTIONAL PARAMETERS]
 
     -c --config [config]: configuration name to filter plans in run.  Can be passed multiple times.
@@ -120,9 +125,9 @@ TESTING OPTIONS:
 my %opts;
 
 GetOptions(
-    'apiurl=s'          => \$opts{'apiurl'},
-    'password=s'        => \$opts{'pass'},
-    'user=s'            => \$opts{'user'},
+    'apiurl=s'        => \$opts{'apiurl'},
+    'password=s'      => \$opts{'pass'},
+    'user=s'          => \$opts{'user'},
     'j|project=s'     => \$opts{'project'},
     'p|plan=s'        => \$opts{'plan'},
     'r|run=s'         => \$opts{'run'},
@@ -133,6 +138,7 @@ GetOptions(
     'm|match=s'       => \$opts{'match'},
     'no-match=s'      => \$opts{'no-match'},
     'n|no-recurse'    => \$opts{'no-recurse'},
+    'e|encoding=s'    => \$opts{'encoding'},
     'h|help'          => \$opts{'help'}
 );
 
@@ -188,7 +194,7 @@ if ($opts{mock}) {
     $opts{debug} = 1;
 }
 
-my $tr = TestRail::API->new($opts{apiurl},$opts{user},$opts{pass},$opts{'debug'});
+my $tr = TestRail::API->new($opts{apiurl},$opts{user},$opts{pass},$opts{'encoding'},$opts{'debug'});
 $tr->{'browser'} = $opts{'browser'} if $opts{'browser'};
 $tr->{'debug'} = 0;
 

+ 2 - 0
lib/App/Prove/Plugin/TestRail.pm

@@ -38,6 +38,7 @@ If \$HOME/.testrailrc exists, it will be parsed for any of these values in a new
     spawn=123
     sections=section1:section2:section3: ... :sectionN
     autoclose=0
+    encoding=UTF-8
 
 Note that passing configurations as filters for runs inside of plans are separated by colons.
 Values passed in via query string will override values in \$HOME/.testrailrc.
@@ -96,6 +97,7 @@ sub load {
     $ENV{'TESTRAIL_SPAWN'}     = $params->{spawn};
     $ENV{'TESTRAIL_SECTIONS'}  = $params->{sections};
     $ENV{'TESTRAIL_AUTOCLOSE'} = $params->{autoclose};
+    $ENV{'TESTRAIL_ENCODING'}  = $params->{encoding};
     return $class;
 }
 

+ 1 - 1
lib/Test/LWP/UserAgent/TestRailMock.pm

@@ -25,7 +25,7 @@ The module was mostly auto-generated, with a few manual tweaks.
 
     use Test::LWP::UserAgent::TestRailMock;
     use TestRail::API;
-    my $tr = TestRail::API->new('http://testrail.local','teodesian@cpan.org','bogus',0);
+    my $tr = TestRail::API->new('http://testrail.local','teodesian@cpan.org','bogus',undef,1);
     $tr->{'browser'} = $Test::LWP::UserAgent::TestRailMock::mockObject;
 
 =cut

+ 8 - 8
lib/Test/Rail/Harness.pm

@@ -43,20 +43,20 @@ sub make_parser {
     my @sections = ();
 
     #XXX again, don't see any way of getting this downrange to my parser :(
-    $args->{'apiurl'}  = $ENV{'TESTRAIL_APIURL'};
-    $args->{'user'}    = $ENV{'TESTRAIL_USER'};
-    $args->{'pass'}    = $ENV{'TESTRAIL_PASS'};
-    $args->{'project'} = $ENV{'TESTRAIL_PROJ'};
-    $args->{'run'}     = $ENV{'TESTRAIL_RUN'};
-    $args->{'plan'}    = $ENV{'TESTRAIL_PLAN'};
-    
+    $args->{'apiurl'}   = $ENV{'TESTRAIL_APIURL'};
+    $args->{'user'}     = $ENV{'TESTRAIL_USER'};
+    $args->{'pass'}     = $ENV{'TESTRAIL_PASS'};
+    $args->{'encoding'} = $ENV{'TESTRAIL_ENCODING'};
+    $args->{'project'}  = $ENV{'TESTRAIL_PROJ'};
+    $args->{'run'}      = $ENV{'TESTRAIL_RUN'};
+    $args->{'plan'}     = $ENV{'TESTRAIL_PLAN'};
     @configs = split(/:/,$ENV{'TESTRAIL_CONFIGS'}) if $ENV{'TESTRAIL_CONFIGS'};
     $args->{'configs'}        = \@configs if scalar(@configs);
     $args->{'result_options'} = {'version' => $ENV{'TESTRAIL_VERSION'}} if $ENV{'TESTRAIL_VERSION'};
     $args->{'case_per_ok'}    = $ENV{'TESTRAIL_CASEOK'};
     $args->{'step_results'}   = $ENV{'TESTRAIL_STEPS'};
     $args->{'spawn'}          = $ENV{'TESTRAIL_SPAWN'};
-    
+
     @sections = split(/:/,$ENV{'TESTRAIL_SECTIONS'}) if $ENV{'TESTRAIL_SECTIONS'};
     $args->{'sections'}  = \@sections if scalar(@sections);
     $args->{'autoclose'} = $ENV{'TESTRAIL_AUTOCLOSE'};

+ 4 - 1
lib/Test/Rail/Parser.pm

@@ -79,6 +79,8 @@ Get the TAP Parser ready to talk to TestRail, and register a bunch of callbacks
 
 =item B<autoclose> - BOOLEAN (optional): If no cases in the run/plan are marked 'untested' or 'retest', go ahead and close the run.  Default false.
 
+=item B<encoding> - STRING (optional): Character encoding of TAP to be parsed and the various inputs parameters for the parser.  Defaults to UTF-8, see L<Encode::Supported> for a list of supported encodings.
+
 =back
 
 =back
@@ -130,6 +132,7 @@ sub new {
         'plan'         => delete $opts->{'plan'},
         'configs'      => delete $opts->{'configs'} // [],
         'spawn'        => delete $opts->{'spawn'},
+        'encoding'     => delete $opts->{'encoding'},
         'sections'     => delete $opts->{'sections'},
         'autoclose'    => delete $opts->{'autoclose'},
         #Stubs for extension by subclassers
@@ -140,7 +143,7 @@ sub new {
     confess("case_per_ok and step_results options are mutually exclusive") if ($tropts->{'case_per_ok'} && $tropts->{'step_results'});
 
     #Allow natural confessing from constructor
-    my $tr = TestRail::API->new($tropts->{'apiurl'},$tropts->{'user'},$tropts->{'pass'},$tropts->{'debug'});
+    my $tr = TestRail::API->new($tropts->{'apiurl'},$tropts->{'user'},$tropts->{'pass'},$tropts->{'encoding'},$tropts->{'debug'});
     $tropts->{'testrail'} = $tr;
     $tr->{'browser'} = $tropts->{'browser'} if defined($tropts->{'browser'}); #allow mocks
     $tr->{'debug'} = 0; #Always suppress in production

+ 18 - 6
lib/TestRail/API.pm

@@ -38,10 +38,11 @@ use HTTP::Request;
 use LWP::UserAgent;
 use Data::Validate::URI qw{is_uri};
 use List::Util 1.33;
+use Encode ();
 
 =head1 CONSTRUCTOR
 
-=head2 B<new (api_url, user, password)>
+=head2 B<new (api_url, user, password, encoding, debug)>
 
 Creates new C<TestRail::API> object.
 
@@ -53,7 +54,9 @@ Creates new C<TestRail::API> object.
 
 =item STRING C<PASSWORD> - Your TestRail password, or a valid API key (TestRail 4.2 and above).
 
-=item BOOLEAN C<DEBUG> - Print the JSON responses from TL with your requests.
+=item STRING C<ENCODING> - The character encoding used by the caller.  Defaults to 'UTF-8', see L<Encode::Supported> and  for supported encodings.
+
+=item BOOLEAN C<DEBUG> (optional) - Print the JSON responses from TL with your requests. Default false.
 
 =back
 
@@ -67,7 +70,7 @@ Does not do above checks if debug is passed.
 =cut
 
 sub new {
-    my ($class,$apiurl,$user,$pass,$debug) = @_;
+    my ($class,$apiurl,$user,$pass,$encoding,$debug) = @_;
     confess("Constructor must be called statically, not by an instance") if ref($class);
     confess("Invalid URI passed to constructor") if !is_uri($apiurl);
     $user //= $ENV{'TESTRAIL_USER'};
@@ -79,6 +82,7 @@ sub new {
         pass             => $pass,
         apiurl           => $apiurl,
         debug            => $debug,
+        encoding         => $encoding || 'UTF-8',
         testtree         => [],
         flattree         => [],
         user_cache       => [],
@@ -90,6 +94,14 @@ sub new {
         browser          => new LWP::UserAgent()
     };
 
+    #Check chara encoding
+    $self->{'encoding-nonaliased'} = Encode::resolve_alias($self->{'encoding'});
+    confess("Invalid encoding alias '".$self->{'encoding'}."' passed, see Encoding::Supported for a list of allowed encodings")
+        unless $self->{'encoding-nonaliased'};
+
+    confess("Invalid encoding '".$self->{'encoding-nonaliased'}."' passed, see Encoding::Supported for a list of allowed encodings")
+        unless grep {$_ eq $self->{'encoding-nonaliased'}} (Encode->encodings(":all"));
+
     #Create default request to pass on to LWP::UserAgent
     $self->{'default_request'} = new HTTP::Request();
     $self->{'default_request'}->authorization_basic($user,$pass);
@@ -149,11 +161,11 @@ sub _doRequest {
 
     my $coder = JSON::MaybeXS->new;
 
-    #Data sent is JSON
-    my $content = $data ? $coder->encode($data) : '';
+    #Data sent is JSON, and encoded per user preference
+    my $content = $data ? Encode::encode( $self->{'encoding-nonaliased'}, $coder->encode($data) ) : '';
 
     $req->content($content);
-    $req->header( "Content-Type" => "application/json" );
+    $req->header( "Content-Type" => "application/json; charset=".$self->{'encoding'} );
 
     my $response = $self->{'browser'}->request($req);
 

+ 1 - 1
t/TestRail-API-mockOnly.t

@@ -9,7 +9,7 @@ use Test::LWP::UserAgent::TestRailMock;
 use Scalar::Util qw{reftype};
 
 my $browser = $Test::LWP::UserAgent::TestRailMock::mockObject;
-my $tr = TestRail::API->new('http://hokum.bogus','fake','fake',1);
+my $tr = TestRail::API->new('http://hokum.bogus','fake','fake',undef,1);
 $tr->{'browser'} = $browser;
 $tr->{'debug'} = 0;
 

+ 4 - 4
t/TestRail-API.t

@@ -19,7 +19,7 @@ my $is_mock = (!$apiurl && !$login && !$pw);
 like(exception {TestRail::API->new('trash');}, qr/invalid uri/i, "Non-URIs bounce constructor");
 
 #XXX for some insane reason 'hokum.bogus' seems to be popular with cpantesters
-my $bogoError = exception {TestRail::API->new('http://hokum.bogus','lies','moreLies',0); };
+my $bogoError = exception {TestRail::API->new('http://hokum.bogus','lies','moreLies',undef,0); };
 SKIP: {
     skip("Some CPANTesters like to randomly redirect all DNS misses to some other host, apparently", 1) if ($bogoError =~ m/404|302/);
     like($bogoError, qr/Could not communicate with TestRail Server/i,"Bogus Testrail URI rejected");
@@ -28,13 +28,13 @@ SKIP: {
 SKIP: {
     skip("Testing authentication not supported with mock",2) if ($is_mock);
 
-    like(exception {TestRail::API->new($apiurl,'lies','moreLies',0); }, qr/Bad user credentials/i,"Bogus Testrail User rejected");
-    like(exception {TestRail::API->new($apiurl,$login,'m043L13s                      ',0); }, qr/Bad user credentials/i,"Bogus Testrail Password rejected");
+    like(exception {TestRail::API->new($apiurl,'lies','moreLies',undef,0); }, qr/Bad user credentials/i,"Bogus Testrail User rejected");
+    like(exception {TestRail::API->new($apiurl,$login,'m043L13s                      ',undef,0); }, qr/Bad user credentials/i,"Bogus Testrail Password rejected");
 }
 
 ($apiurl,$login,$pw) = ('http://testrail.local','teodesian@cpan.org','fake') if $is_mock;
 
-my $tr = new TestRail::API($apiurl,$login,$pw,1);
+my $tr = new TestRail::API($apiurl,$login,$pw,undef,1);
 
 #Mock if necesary
 $tr->{'debug'} = 0;

+ 1 - 1
t/arg_types.t

@@ -8,7 +8,7 @@ use Class::Inspector;
 use Test::LWP::UserAgent;
 use HTTP::Response;
 
-my $tr = TestRail::API->new('http://hokum.bogus','bogus','bogus',1);
+my $tr = TestRail::API->new('http://hokum.bogus','bogus','bogus',undef,1);
 $tr->{'browser'} = Test::LWP::UserAgent->new();
 $tr->{'browser'}->map_response(qr/.*/, HTTP::Response->new('500', 'ERROR', ['Content-Type' => 'text/plain'], ''));
 

+ 2 - 2
t/author-classSafety.t

@@ -6,9 +6,9 @@ use Test::More;
 use Test::Fatal;
 use Class::Inspector;
 
-plan('skip_all' => "these tests are for testing by the author") unless $ENV{'AUTHOR_TESTING'};
+#plan('skip_all' => "these tests are for testing by the author") unless $ENV{'AUTHOR_TESTING'};
 
-my $tr = TestRail::API->new('http://hokum.bogus','bogus','bogus',1);
+my $tr = TestRail::API->new('http://hokum.bogus','bogus','bogus',undef,1);
 
 #Call instance methods as class and vice versa
 like( exception {$tr->new();}, qr/.*must be called statically.*/, "Calling constructor on instance dies");

+ 1 - 1
t/server_dead.t

@@ -11,7 +11,7 @@ use Class::Inspector;
 use Test::LWP::UserAgent;
 use HTTP::Response;
 
-my $tr = TestRail::API->new('http://hokum.bogus','bogus','bogus',1);
+my $tr = TestRail::API->new('http://hokum.bogus','bogus','bogus',undef,1);
 $tr->{'browser'} = Test::LWP::UserAgent->new();
 $tr->{'browser'}->map_response(qr/.*/, HTTP::Response->new('500', 'ERROR', ['Content-Type' => 'text/plain'], ''));