Преглед изворни кода

Transform all binaries into modulinos to appease the smoker gods

George S. Baugh пре 10 година
родитељ
комит
86b4343df1

+ 1 - 0
Changes

@@ -7,6 +7,7 @@ Revision history for Perl module TestRail::API
     - Add TestRail::API::updateCase
     - Add new TestRail::Utils::Find functions; getCases, findCases
     - Add new script bin/testrail-cases
+    - Change all binaries into modulinos.
 
 0.031 2015-08-14 TEODESIAN
     - Update getCases to use testRail 4.0 filters, change filter args to HASHREF

+ 58 - 41
bin/testrail-bulk-mark-results

@@ -1,17 +1,22 @@
 #!/usr/bin/env perl
 # ABSTRACT: Bulk mark entire runs/plans (or groups of tests therein) as the provided status.
-# PODNAME: testrail-bulk-mark-results
+# PODNAME: TestRail::Bin::BulkMarkResults
 
 =head1 USAGE
 
   testrail-bulk-mark-results [OPTIONS] status [reason]
 
+  require `which testrail-bulk-mark-results`;
+  TestRail::Bin::BulkMarkResults::run(@args);
+
 =head1 DESCRIPTION
 
 Sometimes it is useful to mark entire runs of tests when, for example, a prerequisite test in a sequence invalidates all further tests.
 For example, if a binary produced for test fails to run at all, more detailed testing will be impossible;
 it would save time to just mark everything as blocked.
 
+Can be used as the modulino TestRail::Bin::BulkMarkResults.
+
 =head1 PARAMETERS:
 
 =head2 MANDATORY PARAMETERS
@@ -70,6 +75,8 @@ All options specified thereby are overridden by passing the command-line switche
 
 =cut
 
+package TestRail::Bin::BulkMarkResults;
+
 use strict;
 use warnings;
 use utf8;
@@ -78,53 +85,63 @@ use TestRail::API;
 use TestRail::Utils;
 use TestRail::Utils::Results;
 
-use Getopt::Long;
+use Getopt::Long qw{GetOptionsFromArray};
 Getopt::Long::Configure('pass_through');
 
 use File::HomeDir qw{my_home};
 
-my $opts = {};
-
-# Parse config file
-my $homedir = my_home() || '.';
-if (-e $homedir . '/.testrailrc') {
-    $opts = TestRail::Utils::parseConfig($homedir);
+if (!caller()) {
+    my ($out,$code) = run(@ARGV);
+    print $out;
+    exit $code;
 }
 
-# Override configuration with switches
-GetOptions(
-    'apiurl=s'        => \$opts->{'apiurl'},
-    'password=s'      => \$opts->{'password'},
-    'user=s'          => \$opts->{'user'},
-    'assignedto=s@'   => \$opts->{'users'},
-    'status=s@'       => \$opts->{'statuses'},
-    'j|project=s'     => \$opts->{'project'},
-    'p|plan=s'        => \$opts->{'plan'},
-    'r|run=s'         => \$opts->{'run'},
-    'c|config=s@'     => \$opts->{'configs'},
-    'a|assignedto=s@' => \$opts->{'users'},
-    'e|encoding=s'    => \$opts->{'encoding'},
-    'h|help'          => \$opts->{'help'},
-    'mock'            => \$opts->{'mock'}
-);
-
-if ($opts->{help}) { TestRail::Utils::help(); }
-
-my $status = $ARGV[0];
-my $reason = $ARGV[1];
-
-die("No status to set provided.") unless $status;
-TestRail::Utils::interrogateUser($opts,qw{apiurl user password project run});
-
-my $tr = TestRail::Utils::getHandle($opts);
-
-$opts->{'set_status_to'} = $status;
-$opts->{'reason'} = $reason;
-my $results = TestRail::Utils::Results::bulkMarkResults($opts,$tr);
-
-print "Successfully set the status of ".scalar(@$results)." cases to $status.\n" if $results;
+sub run {
+    my $args = \@_;
+    my $opts = {};
+
+    # Parse config file
+    my $homedir = my_home() || '.';
+    if (-e $homedir . '/.testrailrc') {
+        $opts = TestRail::Utils::parseConfig($homedir);
+    }
+
+    # Override configuration with switches
+    GetOptionsFromArray($args,
+        'apiurl=s'        => \$opts->{'apiurl'},
+        'password=s'      => \$opts->{'password'},
+        'user=s'          => \$opts->{'user'},
+        'assignedto=s@'   => \$opts->{'users'},
+        'status=s@'       => \$opts->{'statuses'},
+        'j|project=s'     => \$opts->{'project'},
+        'p|plan=s'        => \$opts->{'plan'},
+        'r|run=s'         => \$opts->{'run'},
+        'c|config=s@'     => \$opts->{'configs'},
+        'a|assignedto=s@' => \$opts->{'users'},
+        'e|encoding=s'    => \$opts->{'encoding'},
+        'h|help'          => \$opts->{'help'},
+        'mock'            => \$opts->{'mock'}
+    );
+
+    if ($opts->{help}) { return ('',TestRail::Utils::help()); }
+
+    my $status = $args->[0];
+    my $reason = $args->[1];
+
+    die("No status to set provided.") unless $status;
+    TestRail::Utils::interrogateUser($opts,qw{apiurl user password project run});
+
+    my $tr = TestRail::Utils::getHandle($opts);
+
+    $opts->{'set_status_to'} = $status;
+    $opts->{'reason'} = $reason;
+    my $results = TestRail::Utils::Results::bulkMarkResults($opts,$tr);
+
+    return ("Successfully set the status of ".scalar(@$results)." cases to $status.\n",0) if $results;
+    return ("Could find no cases to set results for.\n",255);
+}
 
-exit 0;
+1;
 
 __END__
 

+ 73 - 53
bin/testrail-cases

@@ -1,17 +1,22 @@
 #!/usr/bin/env perl
 # ABSTRACT: get information about cases inside various testsuites/sections.
-# PODNAME: testrail-cases
+# PODNAME: TestRail::Bin::Cases
 
 =head1 SYNOPSIS
 
   testrail-cases [OPTIONS]
 
+  require `which testrail-cases`;
+  TestRail::Bin::Cases::run(@args);
+
 =head1 DESCRIPTION
 
 testrail-cases - get information about cases inside various testsuites/sections.
 
 By default will tell you which cases are in both the testsuite and directory passed.
 
+Can be used as the modulino TestRail::Bin::Cases.
+
 =head1 PARAMETERS:
 
 =head2 MANDATORY PARAMETERS
@@ -78,6 +83,8 @@ All options specified thereby are overridden by passing the command-line switche
 
 =cut
 
+package TestRail::Bin::Cases;
+
 use strict;
 use warnings;
 use utf8;
@@ -86,63 +93,76 @@ use TestRail::API;
 use TestRail::Utils;
 use TestRail::Utils::Find;
 
-use Getopt::Long;
+use Getopt::Long qw{GetOptionsFromArray};
 use File::HomeDir qw{my_home};
 
-my $opts ={};
+if (!caller()) {
+    my ($out,$code) = run(@ARGV);
+    print $out;
+    exit $code;
+}
 
-#Parse config file if we are missing api url/key or user
-my $homedir = my_home() || '.';
-if (-e $homedir . '/.testrailrc') {
-    $opts = TestRail::Utils::parseConfig($homedir);
+sub run {
+    my $args = \@_;
+    my $opts ={};
+
+    #Parse config file if we are missing api url/key or user
+    my $homedir = my_home() || '.';
+    if (-e $homedir . '/.testrailrc') {
+        $opts = TestRail::Utils::parseConfig($homedir);
+    }
+
+    GetOptionsFromArray($args,
+        'apiurl=s'        => \$opts->{'apiurl'},
+        'password=s'      => \$opts->{'password'},
+        'user=s'          => \$opts->{'user'},
+        'j|project=s'     => \$opts->{'project'},
+        't|testsuite=s'   => \$opts->{'testsuite'},
+        'd|directory=s'   => \$opts->{'directory'},
+        'm|missing'       => \$opts->{'missing'},
+        'o|orphans'       => \$opts->{'orphans'},
+        'n|no-recurse'    => \$opts->{'no-recurse'},
+        'e|encoding=s'    => \$opts->{'encoding'},
+        'section=s'       => \$opts->{'section'},
+        'type=s@'         => \$opts->{'types'},
+        'extension=s'     => \$opts->{'extension'},
+        'h|help'          => \$opts->{'help'},
+        'test'            => \$opts->{'test'},
+        'mock'            => \$opts->{'mock'} #actually do something, but bogusly
+    );
+
+    if ($opts->{help}) { return ('',TestRail::Utils::help()); }
+
+    #Mutual exclusivity
+    $opts->{'no-missing'} = !$opts->{'missing'};
+    $opts->{'update'} = !($opts->{'orphans'} || $opts->{'missing'});
+    die("orphans and mising options are mutually exclusive.") if $opts->{'orphans'} && $opts->{'missing'};
+    delete $opts->{'missing'};
+
+    TestRail::Utils::interrogateUser($opts,qw{apiurl user password project testsuite directory});
+
+    my $tr = TestRail::Utils::getHandle($opts);
+
+    my $cases = TestRail::Utils::Find::getCases($opts,$tr);
+    die "No cases in TestRail!\n" unless $cases;
+
+    my $tests = TestRail::Utils::Find::findCases($opts,@$cases);
+
+    my (@update,@add,@orphan);
+    @update = map {$_->{'title'}} @{$tests->{'update'}}  if ref $tests->{'update'}  eq 'ARRAY';
+    @add = map {$_->{'title'}} @{$tests->{'orphans'}} if ref $tests->{'orphans'} eq 'ARRAY';
+    @orphan = @{$tests->{'missing'}} if ref $tests->{'missing'} eq 'ARRAY';
+
+    my $out = '';
+    $out .= join("\n",@update);
+    $out .= join("\n",@add);
+    $out .= join("\n",@orphan);
+    $out .= "\n";
+
+    return ($out,0);
 }
 
-GetOptions(
-    'apiurl=s'        => \$opts->{'apiurl'},
-    'password=s'      => \$opts->{'password'},
-    'user=s'          => \$opts->{'user'},
-    'j|project=s'     => \$opts->{'project'},
-    't|testsuite=s'   => \$opts->{'testsuite'},
-    'd|directory=s'   => \$opts->{'directory'},
-    'm|missing'       => \$opts->{'missing'},
-    'o|orphans'       => \$opts->{'orphans'},
-    'n|no-recurse'    => \$opts->{'no-recurse'},
-    'e|encoding=s'    => \$opts->{'encoding'},
-    'section=s'       => \$opts->{'section'},
-    'type=s@'         => \$opts->{'types'},
-    'extension=s'     => \$opts->{'extension'},
-    'h|help'          => \$opts->{'help'},
-    'test'            => \$opts->{'test'},
-    'mock'            => \$opts->{'mock'} #actually do something, but bogusly
-);
-
-if ($opts->{help}) { TestRail::Utils::help(); }
-
-#Mutual exclusivity
-$opts->{'no-missing'} = !$opts->{'missing'};
-$opts->{'update'} = !($opts->{'orphans'} || $opts->{'missing'});
-die("orphans and mising options are mutually exclusive.") if $opts->{'orphans'} && $opts->{'missing'};
-delete $opts->{'missing'};
-
-TestRail::Utils::interrogateUser($opts,qw{apiurl user password project testsuite directory});
-
-my $tr = TestRail::Utils::getHandle($opts);
-
-my $cases = TestRail::Utils::Find::getCases($opts,$tr);
-die "No cases in TestRail!\n" unless $cases;
-
-my $tests = TestRail::Utils::Find::findCases($opts,@$cases);
-
-my (@update,@add,@orphan);
-@update = map {$_->{'title'}} @{$tests->{'update'}}  if ref $tests->{'update'}  eq 'ARRAY';
-@add = map {$_->{'title'}} @{$tests->{'orphans'}} if ref $tests->{'orphans'} eq 'ARRAY';
-@orphan = @{$tests->{'missing'}} if ref $tests->{'missing'} eq 'ARRAY';
-
-print join("\n",@update);
-print join("\n",@add);
-print join("\n",@orphan);
-print "\n";
-exit 0;
+1;
 
 __END__
 

+ 56 - 38
bin/testrail-lock

@@ -1,12 +1,15 @@
 #!/usr/bin/env perl
 # ABSTRACT: Lock a test in a TestRail, and return the test name if successful.
-# PODNAME: testrail-lock
+# PODNAME: TestRail::Bin::Lock
 
 =head1 SYNOPSIS
 
   # Lock a group of tests and execute them
   testrail-tests [OPTIONS] | xargs testrail-lock [OPTIONS] | xargs prove -PTestrail=...
 
+  require `which testrail-lock`;
+  TestRail::Bin::Lock::run(@args);
+
 =head1 DESCRIPTION
 
 testrail-lock - pick an untested/retest test in TestRail, lock it, and return the test name if successful.
@@ -19,6 +22,8 @@ Will respect test priority when making the choice of what test to lock.
 
 This obviously does not make sense with case_per_ok test upload; support for locking entire sections when in case_per_ok upload mode is not supported at this time.
 
+Can also be used as the modulino TestRail::Bin::Lock.
+
 =head1 PARAMETERS:
 
 =head2 MANDATORY PARAMETERS
@@ -83,55 +88,68 @@ All options specified thereby are overridden by passing the command-line switche
 
 =cut
 
+package TestRail::Bin::Lock;
+
 use strict;
 use warnings;
 use utf8;
 
 use TestRail::Utils;
 
-use Getopt::Long;
+use Getopt::Long qw{GetOptionsFromArray};
 use File::HomeDir qw{my_home};
 use Sys::Hostname qw{hostname};
 
-my $opts = {};
+if (!caller()) {
+    my ($out,$code) = run(@ARGV);
+    print $out;
+    exit $code;
+}
+
+sub run {
+    my $args = \@_;
+    my $opts = {};
+
+    #Parse config file if we are missing api url/key or user
+    my $homedir = my_home() || '.';
+    if (-e $homedir . '/.testrailrc') {
+        $opts = TestRail::Utils::parseConfig($homedir);
+    }
+
+    GetOptionsFromArray($args,
+        'apiurl=s'        => \$opts->{'apiurl'},
+        'password=s'      => \$opts->{'password'},
+        'user=s'          => \$opts->{'user'},
+        'l|lockname=s'    => \$opts->{'lockname'},
+        'j|project=s'     => \$opts->{'project'},
+        'p|plan=s'        => \$opts->{'plan'},
+        'r|run=s'         => \$opts->{'run'},
+        'c|config=s@'     => \$opts->{'configs'},
+        'm|match=s'       => \$opts->{'match'},
+        'no-match=s'      => \$opts->{'no-match'},
+        'n|no-recurse'    => \$opts->{'no-recurse'},
+        't|case-type=s@'  => \$opts->{'case-types'},
+        'e|encoding=s'    => \$opts->{'encoding'},
+        'h|help'          => \$opts->{'help'},
+        'mock'            => \$opts->{'mock'}
+    );
+
+    if ($opts->{help}) { return ('',TestRail::Utils::help()); }
+
+    $opts->{'hostname'} = hostname;
+
+    TestRail::Utils::interrogateUser($opts,qw{apiurl user password project run lockname});
+
+    my $tr = TestRail::Utils::getHandle($opts);
+
+    my $ret = TestRail::Utils::pickAndLockTest($opts,$tr);
+
+    return ('Could not lock case.', 255) if !$ret;
 
-#Parse config file if we are missing api url/key or user
-my $homedir = my_home() || '.';
-if (-e $homedir . '/.testrailrc') {
-    $opts = TestRail::Utils::parseConfig($homedir);
+    return ($ret->{'path'}."\n",0);
 }
 
-GetOptions(
-    'apiurl=s'        => \$opts->{'apiurl'},
-    'password=s'      => \$opts->{'password'},
-    'user=s'          => \$opts->{'user'},
-    'l|lockname=s'    => \$opts->{'lockname'},
-    'j|project=s'     => \$opts->{'project'},
-    'p|plan=s'        => \$opts->{'plan'},
-    'r|run=s'         => \$opts->{'run'},
-    'c|config=s@'     => \$opts->{'configs'},
-    'm|match=s'       => \$opts->{'match'},
-    'no-match=s'      => \$opts->{'no-match'},
-    'n|no-recurse'    => \$opts->{'no-recurse'},
-    't|case-type=s@'  => \$opts->{'case-types'},
-    'e|encoding=s'    => \$opts->{'encoding'},
-    'h|help'          => \$opts->{'help'},
-    'mock'            => \$opts->{'mock'}
-);
-
-if ($opts->{help}) { TestRail::Utils::help(); }
-$opts->{'hostname'} = hostname;
-
-TestRail::Utils::interrogateUser($opts,qw{apiurl user password project run lockname});
-
-my $tr = TestRail::Utils::getHandle($opts);
-
-my $ret = TestRail::Utils::pickAndLockTest($opts,$tr);
-
-exit 255 if !$ret;
-
-print $ret->{'path'}."\n";
-exit 0;
+1;
 
 __END__
 

+ 96 - 80
bin/testrail-report

@@ -1,6 +1,6 @@
 #!/usr/bin/env perl
 # ABSTRACT: Upload your TAP results to TestRail after they've finished
-# PODNAME: testrail-report
+# PODNAME: TestRail::Bin::Report
 
 =head1 SYNOPSIS
 
@@ -11,10 +11,15 @@
 
   prove -PTestRail='apiurl=http://some.testlink.install/,user=someUser,password=somePassword,project=TestProject,run=TestRun,plan=TestPlan,configs=Config1:Config2:Config3,version=0.014' sometest.t
 
+  require `which testrail-report`;
+  TestRail::Bin::Report::run(@args);
+
 =head1 DESCRIPTION
 
 testrail-report - report raw TAP results to a TestRail install
 
+Can be used as the modulino TestRail::Bin::Report.
+
 =head2 PARAMETERS:
 
 =head3 MANDATORY PARAMETERS
@@ -104,96 +109,107 @@ This will cause the preceding characters to be interpreted as a test name, which
 
 =cut
 
+package TestRail::Bin::Report;
+
 use strict;
 use warnings;
 
 use TestRail::Utils;
-use Getopt::Long;
+use Getopt::Long qw{GetOptionsFromArray};
 use Test::Rail::Parser;
 use File::HomeDir qw{my_home};
 
-print "testrail-report\n----------------------\n";
-
-#Main loop------------
-my %opts;
-
-#parse switches
-GetOptions(
-    'run=s'          => \$opts{run},
-    'apiurl=s'       => \$opts{apiurl},
-    'password=s'     => \$opts{password},
-    'user=s'         => \$opts{user},
-    'project=s'      => \$opts{project},
-    'case-ok'        => \$opts{case_per_ok},
-    'step-results=s' => \$opts{step_results},
-    'config=s@'      => \$opts{configs},
-    'plan=s'         => \$opts{plan},
-    'version=s'      => \$opts{version},
-    'testsuite_id=i' => \$opts{testsuite_id},
-    'testsuite=s'    => \$opts{testsuite},
-    'section=s@'     => \$opts{sections},
-    'autoclose'      => \$opts{autoclose},
-    'e|encoding=s'   => \$opts{encoding},
-    'help'           => \$opts{help},
-    'mock'           => \$opts{mock}
-);
-
-if ($opts{help}) { TestRail::Utils::help(); }
-
-#Parse config file if we are missing api url/key or user
-my $homedir = my_home() || '.';
-if (-e $homedir . '/.testrailrc' && (!$opts{apiurl} || !$opts{password} || !$opts{user}) ) {
-    ($opts{apiurl},$opts{password},$opts{user}) = TestRail::Utils::parseConfig($homedir,1);
-}
-
-#If argument is passed use it instead of stdin
-my $file = $ARGV[0];
-die "No Such File $file" if ($file && !-e $file);
-
-die "ERROR: Interactive mode not allowed when piping input.  See --help for options." if ( !$opts{run} || !$opts{apiurl} || !$opts{password} || !$opts{user} || !$opts{project} );
-
-my @files = TestRail::Utils::TAP2TestFiles($file);
-
-TestRail::Utils::interrogateUser(\%opts,qw{apiurl user password project run});
-
-$opts{result_options} = {'version' => $opts{version}} if $opts{version};
-
-if ($opts{'mock'}) {
-    require 't/lib/Test/LWP/UserAgent/TestRailMock.pm'; ## no critic
-    $opts{'browser'} = $Test::LWP::UserAgent::TestRailMock::mockObject;
-    $opts{'debug'} = 1;
+if (!caller()) {
+    my ($out,$code) = run(@ARGV);
+    print $out;
+    exit $code;
 }
 
-my $tap;
-foreach my $phil (@files) {
-    $tap = Test::Rail::Parser->new({
-        'tap'            => $phil,
-        'apiurl'         => $opts{apiurl},
-        'user'           => $opts{user},
-        'pass'           => $opts{password},
-        'run'            => $opts{run},
-        'project'        => $opts{project},
-        'case_per_ok'    => $opts{case_per_ok},
-        'step_results'   => $opts{step_results},
-        'debug'          => $opts{debug},
-        'browser'        => $opts{browser},
-        'plan'           => $opts{plan},
-        'configs'        => $opts{configs},
-        'result_options' => $opts{result_options},
-        'testsuite_id'   => $opts{testsuite_id},
-        'testsuite'      => $opts{testsuite},
-        'sections'       => $opts{sections},
-        'autoclose'      => $opts{autoclose},
-        'encoding'       => $opts{encoding},
-        'merge'          => 1
-    });
-    $tap->run();
+#Main loop------------
+sub run {
+    my $args = \@_;
+    my %opts;
+
+    print "testrail-report\n----------------------\n";
+
+    #parse switches
+    GetOptionsFromArray($args,
+        'run=s'          => \$opts{run},
+        'apiurl=s'       => \$opts{apiurl},
+        'password=s'     => \$opts{password},
+        'user=s'         => \$opts{user},
+        'project=s'      => \$opts{project},
+        'case-ok'        => \$opts{case_per_ok},
+        'step-results=s' => \$opts{step_results},
+        'config=s@'      => \$opts{configs},
+        'plan=s'         => \$opts{plan},
+        'version=s'      => \$opts{version},
+        'testsuite_id=i' => \$opts{testsuite_id},
+        'testsuite=s'    => \$opts{testsuite},
+        'section=s@'     => \$opts{sections},
+        'autoclose'      => \$opts{autoclose},
+        'e|encoding=s'   => \$opts{encoding},
+        'help'           => \$opts{help},
+        'mock'           => \$opts{mock}
+    );
+
+    if ($opts{help}) { return ('',TestRail::Utils::help()); }
+
+    #Parse config file if we are missing api url/key or user
+    my $homedir = my_home() || '.';
+    if (-e $homedir . '/.testrailrc' && (!$opts{apiurl} || !$opts{password} || !$opts{user}) ) {
+        ($opts{apiurl},$opts{password},$opts{user}) = TestRail::Utils::parseConfig($homedir,1);
+    }
+
+    #If argument is passed use it instead of stdin
+    my $file = $args->[0];
+    die "No Such File $file" if ($file && !-e $file);
+
+    die "ERROR: Interactive mode not allowed when piping input.  See --help for options." if ( !$opts{run} || !$opts{apiurl} || !$opts{password} || !$opts{user} || !$opts{project} );
+
+    my @files = TestRail::Utils::TAP2TestFiles($file);
+
+    TestRail::Utils::interrogateUser(\%opts,qw{apiurl user password project run});
+
+    $opts{result_options} = {'version' => $opts{version}} if $opts{version};
+
+    if ($opts{'mock'}) {
+        require 't/lib/Test/LWP/UserAgent/TestRailMock.pm'; ## no critic
+        $opts{'browser'} = $Test::LWP::UserAgent::TestRailMock::mockObject;
+        $opts{'debug'} = 1;
+    }
+
+    my $tap;
+    foreach my $phil (@files) {
+        $tap = Test::Rail::Parser->new({
+            'tap'            => $phil,
+            'apiurl'         => $opts{apiurl},
+            'user'           => $opts{user},
+            'pass'           => $opts{password},
+            'run'            => $opts{run},
+            'project'        => $opts{project},
+            'case_per_ok'    => $opts{case_per_ok},
+            'step_results'   => $opts{step_results},
+            'debug'          => $opts{debug},
+            'browser'        => $opts{browser},
+            'plan'           => $opts{plan},
+            'configs'        => $opts{configs},
+            'result_options' => $opts{result_options},
+            'testsuite_id'   => $opts{testsuite_id},
+            'testsuite'      => $opts{testsuite},
+            'sections'       => $opts{sections},
+            'autoclose'      => $opts{autoclose},
+            'encoding'       => $opts{encoding},
+            'merge'          => 1
+        });
+        $tap->run();
+    }
+
+    #all done
+    return ("Done.\n",0);
 }
 
-print "Done.\n";
-
-#all done
-0;
+1;
 
 __END__
 

+ 50 - 34
bin/testrail-runs

@@ -1,16 +1,21 @@
 #!/usr/bin/env perl
 # ABSTRACT: List runs in a TestRail project matching the provided filters
-# PODNAME: testrail-runs
+# PODNAME: TestRail::Bin::Runs
 
 =head1 SYNOPSIS
 
   testrail-runs [OPTIONS] | xargs prove -PTestrail=...
 
+  require `which testrail-runs`;
+  TestRail::Bin::Run::run(@args);
+
 =head1 DESCRIPTION
 
-testrail-tests - list runs in a TestRail project matching the provided filters.
+testrail-runs - list runs in a TestRail project matching the provided filters.
 Groups by plan for runs which are children of a plan.
 
+Can be used as the modulino TestRail::Bin::Runs.
+
 =head1 PARAMETERS:
 
 =head2 MANDATORY PARAMETERS
@@ -64,6 +69,8 @@ All options specified thereby are overridden by passing the command-line switche
 
 =cut
 
+package TestRail::Bin::Runs;
+
 use strict;
 use warnings;
 use utf8;
@@ -72,43 +79,52 @@ use TestRail::API;
 use TestRail::Utils;
 use TestRail::Utils::Find;
 
-use Getopt::Long;
+use Getopt::Long qw{GetOptionsFromArray};
 use File::HomeDir qw{my_home};
 
-my $opts ={};
-
-# Parse config file
-my $homedir = my_home() || '.';
-if (-e $homedir . '/.testrailrc') {
-    $opts = TestRail::Utils::parseConfig($homedir);
+if (!caller()) {
+    my ($out,$code) = run(@ARGV);
+    print $out;
+    exit $code;
 }
 
-GetOptions(
-    'apiurl=s'     => \$opts->{'apiurl'},
-    'password=s'   => \$opts->{'password'},
-    'user=s'       => \$opts->{'user'},
-    'j|project=s'  => \$opts->{'project'},
-    'c|config=s@'  => \$opts->{'configs'},
-    's|status=s@'  => \$opts->{'statuses'},
-    'e|encoding=s' => \$opts->{'encoding'},
-    'l|lifo'       => \$opts->{'lifo'},
-    'm|milesort'   => \$opts->{'milesort'},
-    'h|help'       => \$opts->{'help'},
-    'mock'         => \$opts->{'mock'}
-);
-
-if ($opts->{help}) { TestRail::Utils::help(); }
-
-TestRail::Utils::interrogateUser($opts,qw{apiurl user password project});
-
-my $tr = TestRail::Utils::getHandle($opts);
-
-my $runs = TestRail::Utils::Find::findRuns($opts,$tr);
-
-@$runs = map {$_->{name}} @$runs;
-print join("\n",@$runs)."\n" if scalar(@$runs);
-exit 0;
+sub run {
+    my $args = \@_;
+    my $opts = {};
+
+    # Parse config file
+    my $homedir = my_home() || '.';
+    if (-e $homedir . '/.testrailrc') {
+        $opts = TestRail::Utils::parseConfig($homedir);
+    }
+
+    GetOptionsFromArray($args,
+        'apiurl=s'     => \$opts->{'apiurl'},
+        'password=s'   => \$opts->{'password'},
+        'user=s'       => \$opts->{'user'},
+        'j|project=s'  => \$opts->{'project'},
+        'c|config=s@'  => \$opts->{'configs'},
+        's|status=s@'  => \$opts->{'statuses'},
+        'e|encoding=s' => \$opts->{'encoding'},
+        'l|lifo'       => \$opts->{'lifo'},
+        'm|milesort'   => \$opts->{'milesort'},
+        'h|help'       => \$opts->{'help'},
+        'mock'         => \$opts->{'mock'}
+    );
+
+    if ($opts->{help}) { return ('',TestRail::Utils::help()); }
+
+    TestRail::Utils::interrogateUser($opts,qw{apiurl user password project});
+
+    my $tr = TestRail::Utils::getHandle($opts);
+    my $runs = TestRail::Utils::Find::findRuns($opts,$tr);
+
+    @$runs = map {$_->{name}} @$runs;
+    return (join("\n",@$runs)."\n", 0) if scalar(@$runs);
+    return ("No runs found matching your criterion.\n",255);
+}
 
+1;
 __END__
 
 L<TestRail::API>

+ 58 - 42
bin/testrail-tests

@@ -1,15 +1,19 @@
 #!/usr/bin/env perl
 # ABSTRACT: List tests in a TestRail run matching the provided filters
-# PODNAME: testrail-tests
+# PODNAME: TestRail::Bin::Tests
 
 =head1 SYNOPSIS
 
   testrail-tests [OPTIONS] | xargs prove -PTestrail=...
 
+  require `which testrail-tests`;
+  TestRail::Bin::Test::run(@args);
+
 =head1 DESCRIPTION
 
 testrail-tests - list tests in a run matching the provided filters.
 
+Can be used as the modulino TestRail::Bin::Tests.
 
 =head1 PARAMETERS:
 
@@ -81,6 +85,8 @@ All options specified thereby are overridden by passing the command-line switche
 
 =cut
 
+package TestRail::Bin::Tests;
+
 use strict;
 use warnings;
 use utf8;
@@ -89,52 +95,62 @@ use TestRail::API;
 use TestRail::Utils;
 use TestRail::Utils::Find;
 
-use Getopt::Long;
+use Getopt::Long qw{GetOptionsFromArray};
 use File::HomeDir qw{my_home};
 
-my $opts ={};
+if (!caller()) {
+    my ($out,$code) = run(@ARGV);
+    print $out;
+    exit $code;
+}
 
-#Parse config file if we are missing api url/key or user
-my $homedir = my_home() || '.';
-if (-e $homedir . '/.testrailrc') {
-    $opts = TestRail::Utils::parseConfig($homedir);
+sub run {
+    my $args = \@_;
+    my $opts ={};
+
+    #Parse config file if we are missing api url/key or user
+    my $homedir = my_home() || '.';
+    if (-e $homedir . '/.testrailrc') {
+        $opts = TestRail::Utils::parseConfig($homedir);
+    }
+
+    GetOptionsFromArray($args,
+        'apiurl=s'        => \$opts->{'apiurl'},
+        'password=s'      => \$opts->{'password'},
+        'user=s'          => \$opts->{'user'},
+        'j|project=s'     => \$opts->{'project'},
+        'p|plan=s'        => \$opts->{'plan'},
+        'r|run=s'         => \$opts->{'run'},
+        'c|config=s@'     => \$opts->{'configs'},
+        's|status=s@'     => \$opts->{'statuses'},
+        'a|assignedto=s@' => \$opts->{'users'},
+        'm|match=s'       => \$opts->{'match'},
+        'no-match=s'      => \$opts->{'no-match'},
+        'orphans=s'       => \$opts->{'orphans'},
+        'n|no-recurse'    => \$opts->{'no-recurse'},
+        'e|encoding=s'    => \$opts->{'encoding'},
+        'extension=s'     => \$opts->{'extension'},
+        'h|help'          => \$opts->{'help'},
+        'mock'            => \$opts->{'mock'}
+    );
+
+    if ($opts->{help}) { return ('',TestRail::Utils::help()); }
+
+    TestRail::Utils::interrogateUser($opts,qw{apiurl user password project run});
+
+    my $tr = TestRail::Utils::getHandle($opts);
+
+    my ($cases) = TestRail::Utils::Find::getTests($opts,$tr);
+    die "No cases in TestRail!\n" unless $cases;
+
+    $opts->{'names-only'} = 1;
+    my @tests = TestRail::Utils::Find::findTests($opts,@$cases);
+
+    return (join("\n",@tests)."\n", 0) if scalar(@tests);
+    return ('',255);
 }
 
-GetOptions(
-    'apiurl=s'        => \$opts->{'apiurl'},
-    'password=s'      => \$opts->{'password'},
-    'user=s'          => \$opts->{'user'},
-    'j|project=s'     => \$opts->{'project'},
-    'p|plan=s'        => \$opts->{'plan'},
-    'r|run=s'         => \$opts->{'run'},
-    'c|config=s@'     => \$opts->{'configs'},
-    's|status=s@'     => \$opts->{'statuses'},
-    'a|assignedto=s@' => \$opts->{'users'},
-    'm|match=s'       => \$opts->{'match'},
-    'no-match=s'      => \$opts->{'no-match'},
-    'orphans=s'       => \$opts->{'orphans'},
-    'n|no-recurse'    => \$opts->{'no-recurse'},
-    'e|encoding=s'    => \$opts->{'encoding'},
-    'extension=s'     => \$opts->{'extension'},
-    'h|help'          => \$opts->{'help'},
-    'mock'            => \$opts->{'mock'}
-);
-
-if ($opts->{help}) { TestRail::Utils::help(); }
-
-TestRail::Utils::interrogateUser($opts,qw{apiurl user password project run});
-
-my $tr = TestRail::Utils::getHandle($opts);
-
-my ($cases) = TestRail::Utils::Find::getTests($opts,$tr);
-die "No cases in TestRail!\n" unless $cases;
-
-$opts->{'names-only'} = 1;
-my @tests = TestRail::Utils::Find::findTests($opts,@$cases);
-
-print join("\n",@tests)."\n" if scalar(@tests);
-
-exit 0;
+1;
 
 __END__
 

+ 2 - 1
lib/Test/Rail/Harness.pm

@@ -64,7 +64,8 @@ sub make_parser {
 
     #for Testability of plugin
     if ($ENV{'TESTRAIL_MOCKED'}) {
-        require 't/lib/Test/LWP/UserAgent/TestRailMock.pm'; ## no critic
+        use lib 't/lib'; #Unit tests will always run from the main dir during make test
+        require 't/lib/Test/LWP/UserAgent/TestRailMock.pm' unless defined $Test::LWP::UserAgent::TestRailMock::mockObject; ## no critic
         $args->{'debug'} = 1;
         $args->{'browser'} = $Test::LWP::UserAgent::TestRailMock::mockObject;
     }

+ 2 - 2
lib/TestRail/Utils.pm

@@ -24,7 +24,7 @@ Print the perldoc for $0 and exit.
 sub help {
     @ARGV = ($0);
     Pod::Perldoc->run();
-    exit 0;
+    return 0;
 }
 
 =head2 userInput
@@ -227,7 +227,7 @@ sub getHandle {
     my $tr = TestRail::API->new($opts->{apiurl},$opts->{user},$opts->{password},$opts->{'encoding'},$opts->{'debug'});
     if ($opts->{'mock'}) {
         use lib 't/lib'; #Unit tests will always run from the main dir during make test
-        require 't/lib/Test/LWP/UserAgent/TestRailMock.pm'; ## no critic
+        require 't/lib/Test/LWP/UserAgent/TestRailMock.pm' unless defined $Test::LWP::UserAgent::TestRailMock::mockObject; ## no critic
         $tr->{'browser'} = $Test::LWP::UserAgent::TestRailMock::mockObject;
         $tr->{'debug'} = 0;
     }

+ 11 - 1
t/TestRail-Utils.t

@@ -1,10 +1,16 @@
+=head1 POD TEST
+
+Bogus bogus
+
+=cut
+
 use strict;
 use warnings;
 
 use FindBin;
 use lib "$FindBin::Bin/lib";
 
-use Test::More 'tests' => 25;
+use Test::More 'tests' => 26;
 use Test::Fatal;
 
 use TestRail::API;
@@ -15,6 +21,10 @@ use File::Basename qw{dirname};
 
 my ($apiurl,$user,$password);
 
+#check help output
+
+is(TestRail::Utils::help(),0,"Help works OK");
+
 #check the binary output mode
 is(exception {($apiurl,$password,$user) = TestRail::Utils::parseConfig(dirname(__FILE__),1)}, undef, "No exceptions thrown by parseConfig in array mode");
 is($apiurl,'http://hokum.bogus',"APIURL parse OK");

+ 13 - 7
t/testrail-bulk-mark-results.t

@@ -2,17 +2,23 @@ use strict;
 use warnings;
 
 use Test::More "tests" => 4;
+use FindBin;
+use IO::CaptureOutput qw{capture};
 
-my @args = ($^X,qw{bin/testrail-bulk-mark-results --help});
-my $out = `@args`;
-is($? >> 8, 0, "Exit code OK asking for help");
-like($out,qr/encoding of arguments/i,"Help output OK");
+use lib $FindBin::Bin.'/../bin';
+require 'testrail-bulk-mark-results';
 
 #check plan mode
-@args = ($^X,qw{bin/testrail-bulk-mark-results --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j "CRUSH ALL HUMANS" -r "SEND T-1000 INFILTRATION UNITS BACK IN TIME" --mock blocked "Build was bad."});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK running against normal run");
+my @args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j },"CRUSH ALL HUMANS", '-r', "SEND T-1000 INFILTRATION UNITS BACK IN TIME", qw{--mock blocked}, "Build was bad.");
+my ($out,$code) = TestRail::Bin::BulkMarkResults::run(@args);
+is($code, 0, "Exit code OK running against normal run");
 chomp $out;
 like($out,qr/set the status of 1 cases to blocked/,"Sets test correctly in single run mode");
 
+@args = qw{--help};
+$0 = $FindBin::Bin.'/../bin/testrail-bulk-mark-results';
+(undef,$code) = capture {TestRail::Bin::BulkMarkResults::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK asking for help");
+like($out,qr/encoding of arguments/i,"Help output OK");
+
 #TODO more thorough testing

+ 17 - 10
t/testrail-cases.t

@@ -1,27 +1,34 @@
 use strict;
 use warnings;
 
+use FindBin;
+
+use lib $FindBin::Bin.'/../bin';
+require 'testrail-cases';
+
 use Test::More "tests" => 6;
+use IO::CaptureOutput qw{capture};
 
 #check plan mode
-my @args = ($^X,qw{bin/testrail-cases -j "TestProject" -t "HAMBURGER-IZE HUMANITY" -d t --mock --test --extension ".test"});
-my $out = `@args`;
-is($? >> 8, 0, "Exit code OK running add, update, orphans");
+my @args = (qw{-j TestProject -t}, 'HAMBURGER-IZE HUMANITY', qw{-d t --mock --test --extension .test});
+my ($out,$code) = TestRail::Bin::Cases::run(@args);
+is($code, 0, "Exit code OK running add, update, orphans");
 chomp $out;
 like($out,qr/fake\.test/,"Shows existing tests by default");
 
-@args = ($^X,qw{bin/testrail-cases -j "TestProject" -t "HAMBURGER-IZE HUMANITY" -d t --mock  -o --extension ".test"});
-$out = `@args`;
+@args = (qw{-j TestProject -t}, 'HAMBURGER-IZE HUMANITY', qw{-d t --mock  -o --extension .test});
+($out,$code) = TestRail::Bin::Cases::run(@args);
 chomp $out;
 like($out,qr/nothere\.test/,"Shows orphan tests");
 
-@args = ($^X,qw{bin/testrail-cases -j "TestProject" -t "HAMBURGER-IZE HUMANITY" -d t --mock  -m --extension ".test"});
-$out = `@args`;
+@args = (qw{-j TestProject -t}, 'HAMBURGER-IZE HUMANITY', qw{-d t --mock  -m --extension .test});
+($out,$code) = TestRail::Bin::Cases::run(@args);
 chomp $out;
 like($out,qr/t\/skipall\.test/,"Shows missing tests");
 
 #Verify no-match returns non path
-@args = ($^X,qw{bin/testrail-cases --help});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK asking for help");
+@args = qw{--help};
+$0 = $FindBin::Bin.'/../bin/testrail-cases';
+(undef,$code) = capture {TestRail::Bin::Cases::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK asking for help");
 like($out,qr/encoding of arguments/i,"Help output OK");

+ 12 - 5
t/testrail-lock.t

@@ -2,11 +2,18 @@ use strict;
 use warnings;
 
 use Test::More "tests" => 2;
+use FindBin;
+use IO::CaptureOutput qw{capture};
+
+use lib $FindBin::Bin.'/../bin';
+require 'testrail-lock';
 
 #VERY rudimentray checking
-my @args = ($^X,qw{bin/testrail-lock --help});
-my $out = `@args`;
-is($? >> 8, 0, "Can get help output OK");
-chomp $out;
-like($out,qr/useful to lock the test/,"Help Output looks as expected");
+my @args = qw{--help};
+$0 = $FindBin::Bin.'/../bin/testrail-lock';
+my $out;
+my (undef,$code) = capture {TestRail::Bin::Lock::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK asking for help");
+like($out,qr/encoding of arguments/i,"Help output OK");
+
 

+ 32 - 28
t/testrail-report.t

@@ -1,59 +1,63 @@
 use strict;
 use warnings;
+use FindBin;
+
+use lib $FindBin::Bin.'/../bin';
+require 'testrail-report';
 
 use Test::More 'tests' => 16;
+use IO::CaptureOutput qw{capture};
 
-my @args = ($^X,qw{bin/testrail-report --apiurl http://testrail.local --user "test@fake.fake" --password "fake" --project "CRUSH ALL HUMANS" --run "SEND T-1000 INFILTRATION UNITS BACK IN TIME" --mock t/test_multiple_files.tap});
-my $out = `@args`;
-is($? >> 8, 0, "Exit code OK reported with multiple files");
+my @args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake --project}, "CRUSH ALL HUMANS", '--run', "SEND T-1000 INFILTRATION UNITS BACK IN TIME", qw{--mock t/test_multiple_files.tap});
+my $out;
+my (undef,$code) = capture {TestRail::Bin::Report::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK reported with multiple files");
 my $matches = () = $out =~ m/Reporting result of case/ig;
 is($matches,2,"Attempts to upload multiple times");
 
-@args = ($^X,qw{bin/testrail-report --apiurl http://testrail.local --user "test@fake.fake" --password "fake" --project "CRUSH ALL HUMANS" --run "SEND T-1000 INFILTRATION UNITS BACK IN TIME" --case-ok --mock t/test_multiple_files.tap});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK reported with multiple files (case-ok mode)");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake --project}, "CRUSH ALL HUMANS", '--run', "SEND T-1000 INFILTRATION UNITS BACK IN TIME", qw{--case-ok --mock t/test_multiple_files.tap});
+(undef,$code) = capture {TestRail::Bin::Report::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK reported with multiple files (case-ok mode)");
 $matches = () = $out =~ m/Reporting result of case/ig;
 is($matches,4,"Attempts to upload multiple times (case-ok mode)");
 
 #Test version, case-ok
-@args = ($^X,qw{bin/testrail-report --apiurl http://testrail.local --user "test@fake.fake" --password "fake" --project "TestProject" --run "TestingSuite" --case-ok --version '1.0.14' --mock t/test_subtest.tap});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK reported with subtests (case-ok mode)");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake --project TestProject --run TestingSuite --case-ok --version 1.0.14 --mock t/test_subtest.tap});
+(undef,$code) = capture {TestRail::Bin::Report::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK reported with subtests (case-ok mode)");
 $matches = () = $out =~ m/Reporting result of case/ig;
 is($matches,2,"Attempts to upload do not do subtests (case-ok mode)");
 
 #Test plans/configs
-@args = ($^X,qw{bin/testrail-report --apiurl http://testrail.local --user "test@fake.fake" --password "fake" --project "TestProject" --run "Executing the great plan" --plan "GosPlan" --config "testConfig"  --case-ok --mock t/test_subtest.tap});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK reported with plans");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake --project TestProject --run}, "Executing the great plan", qw{--plan GosPlan --config testConfig --case-ok --mock t/test_subtest.tap});
+(undef,$code) = capture {TestRail::Bin::Report::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK reported with plans");
 $matches = () = $out =~ m/Reporting result of case.*OK/ig;
 is($matches,2,"Attempts to to plans work");
 
 #Test that spawn works
-@args = ($^X,qw{bin/testrail-report --apiurl http://testrail.local --user "test@fake.fake" --password "fake" --project "TestProject" --run "TestingSuite2" --testsuite_id 9 --case-ok --mock t/test_subtest.tap});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK reported with spawn");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake --project TestProject --run TestingSuite2 --testsuite_id 9 --case-ok --mock t/test_subtest.tap});
+(undef,$code) = capture {TestRail::Bin::Report::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK reported with spawn");
 $matches = () = $out =~ m/Reporting result of case.*OK/ig;
 is($matches,2,"Attempts to spawn work: testsuite_id");
 
 #Test that spawn works w/sections
-@args = ($^X,qw{bin/testrail-report --apiurl http://testrail.local --user "test@fake.fake" --password "fake" --project "TestProject" --run "TestingSuite2" --testsuite "HAMBURGER-IZE HUMANITY" --case-ok --section "CARBON LIQUEFACTION" --mock t/test_subtest.tap});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK reported with spawn");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake --project TestProject --run TestingSuite2 --testsuite}, "HAMBURGER-IZE HUMANITY", qw{--case-ok --section}, "CARBON LIQUEFACTION", qw{--mock t/test_subtest.tap});
+(undef,$code) = capture {TestRail::Bin::Report::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK reported with spawn");
 $matches = () = $out =~ m/with specified sections/ig;
 is($matches,1,"Attempts to spawn work: testsuite name");
 
 #Test that the autoclose option works
-@args = ($^X,qw{bin/testrail-report --apiurl http://testrail.local --user "test@fake.fake" --password "fake" --project "TestProject" --run "FinalRun" --plan "FinalPlan" --config "testConfig" --case-ok --autoclose --mock t/fake.tap});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK when doing autoclose");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake --project TestProject --run FinalRun --plan FinalPlan --config testConfig --case-ok --autoclose --mock t/fake.tap});
+(undef,$code) = capture {TestRail::Bin::Report::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK when doing autoclose");
 like($out,qr/closing plan/i,"Run closure reported to user");
 
 #Test that help works
-@args = ($^X,qw{bin/testrail-report --help});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK reported with help");
-$matches = () = $out =~ m/encoding of arguments/ig;
-is($matches,1,"Help output OK");
-
-
+@args = qw{--help};
+$0 = $FindBin::Bin.'/../bin/testrail-report';
+(undef,$code) = capture {TestRail::Bin::Report::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK asking for help");
+like($out,qr/encoding of arguments/i,"Help output OK");

+ 28 - 21
t/testrail-runs.t

@@ -1,46 +1,53 @@
 use strict;
 use warnings;
 
+use FindBin;
+
+use lib $FindBin::Bin.'/../bin';
+require 'testrail-runs';
+
 use Test::More 'tests' => 12;
+use IO::CaptureOutput qw{capture};
 
 #check status filters
-my @args = ($^X,qw{bin/testrail-runs --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j "TestProject" --mock});
-my $out = `@args`;
-is($? >> 8, 0, "Exit code OK looking for runs with passes");
+my @args = qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject --mock};
+my ($out,$code) = TestRail::Bin::Runs::run(@args);
+is($code, 0, "Exit code OK looking for runs with passes");
 chomp $out;
 like($out,qr/^OtherOtherSuite\nTestingSuite\nFinalRun\nlockRun\nClosedRun$/,"Gets run correctly looking for passes");
 
 #check LIFO sort
-@args = ($^X,qw{bin/testrail-runs --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j "TestProject" --lifo --mock});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK looking for runs with passes");
+@args = qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject --lifo --mock};
+($out,$code) = TestRail::Bin::Runs::run(@args);
+is($code, 0, "Exit code OK looking for runs with passes");
 chomp $out;
 like($out,qr/^lockRun\nClosedRun\nTestingSuite\nFinalRun\nOtherOtherSuite$/,"LIFO sort works");
 
 #check milesort
-@args = ($^X,qw{bin/testrail-runs --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j "TestProject" --milesort --mock});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK looking for runs with passes");
+@args = qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject --milesort --mock};
+($out,$code) = TestRail::Bin::Runs::run(@args);
+is($code, 0, "Exit code OK looking for runs with passes");
 chomp $out;
 like($out,qr/^TestingSuite\nFinalRun\nlockRun\nClosedRun\nOtherOtherSuite$/,"milesort works");
 
 
 #check status filters
-@args = ($^X,qw{bin/testrail-runs --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j "TestProject" --mock --status passed});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK looking for runs with passes, which should fail to return results");
+@args = qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject --mock --status passed};
+($out,$code) = TestRail::Bin::Runs::run(@args);
+is($code, 255, "Exit code OK looking for runs with passes, which should fail to return results");
 chomp $out;
-is($out,'',"Gets no runs correctly looking for passes");
+like($out,qr/no runs found/i,"Gets no runs correctly looking for passes");
 
 #TODO check configs for real next time
-@args = ($^X,qw{bin/testrail-runs --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j "TestProject" --mock --config testConfig --config eee});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK looking for runs with passes");
+@args = qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject --mock --config testConfig --config eee};
+($out,$code) = TestRail::Bin::Runs::run(@args);
+is($code, 255, "Exit code OK looking for runs with passes");
 chomp $out;
-is($out,'',"Gets no run correctly when filtering by unassigned config");
+like($out,qr/no runs found/i,"Gets no run correctly when filtering by unassigned config");
 
-#help options
-@args = ($^X,qw{bin/testrail-runs --help});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK looking for help");
+#Verify no-match returns non path
+@args = qw{--help};
+$0 = $FindBin::Bin.'/../bin/testrail-runs';
+(undef,$code) = capture {TestRail::Bin::Runs::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK asking for help");
 like($out,qr/encoding of arguments/i,"Help output OK");

+ 49 - 49
t/testrail-tests.t

@@ -1,103 +1,103 @@
 use strict;
 use warnings;
 
-use Test::More "tests" => 32;
+use Test::More "tests" => 31;
+use Test::Fatal;
+use FindBin;
+use IO::CaptureOutput qw{capture};
+
+use lib $FindBin::Bin.'/../bin';
+require 'testrail-tests';
 
 #check plan mode
-my @args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -p "GosPlan" -r "Executing the great plan" -m t --config testConfig --mock --no-recurse});
-my $out = `@args`;
-is($? >> 8, 0, "Exit code OK running plan mode, no recurse");
+my @args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject -p GosPlan -r}, "Executing the great plan", qw{-m t --config testConfig --mock --no-recurse});
+my ($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 0, "Exit code OK running plan mode, no recurse");
 chomp $out;
 like($out,qr/skipall\.test$/,"Gets test correctly in plan mode, no recurse");
 
 #check no-match
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -p "GosPlan" -r "Executing the great plan" --no-match t --config testConfig --mock});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK running plan mode, no match");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject -p GosPlan -r}, "Executing the great plan", qw{--no-match t --config testConfig --mock});
+($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 0, "Exit code OK running plan mode, no match");
 chomp $out;
 unlike($out,qr/skipall\.test/,"Omits test correctly in plan mode, recurse, no-match");
 unlike($out,qr/NOT SO SEARED AFTER ARR/,"Omits non-file test correctly in plan mode, recurse, no-match");
 like($out,qr/faker\.test/,"Omits non-file test correctly in plan mode, recurse, no-match");
 
 #check no-match, no recurse
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -p "GosPlan" -r "Executing the great plan" --no-match t --config testConfig --mock --no-recurse});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK running plan mode, no match, no recurse");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject -p GosPlan -r}, "Executing the great plan", qw{--no-match t --config testConfig --mock --no-recurse});
+($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 0, "Exit code OK running plan mode, no match, no recurse");
 chomp $out;
 unlike($out,qr/skipall\.test/,"Omits test correctly in plan mode, no recurse, no-match");
 unlike($out,qr/NOT SO SEARED AFTER ARR/,"Omits non-file test correctly in plan mode, no recurse, no-match");
 like($out,qr/faker\.test/,"Omits non-file test correctly in plan mode, no recurse, no-match");
 
-
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -p "GosPlan" -r "Executing the great plan" --config testConfig -m t --mock});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK running plan mode, recurse");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject -p GosPlan -r}, "Executing the great plan", qw{--config testConfig -m t --mock});
+($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 0, "Exit code OK running plan mode, recurse");
 chomp $out;
 like($out,qr/skipall\.test$/,"Gets test correctly in plan mode, recurse");
 
 #check non plan mode
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -r "TestingSuite" -m t --mock --no-recurse});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK running no plan mode, no recurse");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject  -r TestingSuite -m t --mock --no-recurse});
+($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 0, "Exit code OK running no plan mode, no recurse");
 chomp $out;
 like($out,qr/skipall\.test$/,"Gets test correctly in no plan mode, no recurse");
 
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -r "TestingSuite" -m t --mock});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK running no plan mode, recurse");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject  -r TestingSuite -m t --mock});
+($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 0, "Exit code OK running no plan mode, recurse");
 chomp $out;
 like($out,qr/skipall\.test$/,"Gets test correctly in no plan mode, recurse");
 
 #Negative case, filtering by config
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -p "GosPlan" -r "Executing the great plan" -m t --mock --config testPlatform1});
-$out = `@args`;
-isnt($? >> 8, 0, "Exit code not OK when passing invalid configs for plan");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject -p GosPlan -r}, "Executing the great plan", qw{-m t --mock --config testPlatform1});
+isnt(exception {TestRail::Bin::Tests::run(@args)}, undef, "Exit code not OK when passing invalid configs for plan");
 
 #check assignedto filters
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -p "GosPlan" -r "Executing the great plan" --mock --config "testConfig" --assignedto teodesian});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK when filtering by assignment");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject -p GosPlan -r}, "Executing the great plan", qw{--mock --config testConfig --assignedto teodesian});
+($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 0, "Exit code OK when filtering by assignment");
 like($out,qr/skipall\.test$/,"Gets test correctly when filtering by assignment");
 
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -p "GosPlan" -r "Executing the great plan" --mock --config "testConfig" --assignedto billy});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK when filtering by assignment");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject -p GosPlan -r}, "Executing the great plan", qw{--mock --config testConfig --assignedto billy});
+($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 255, "Exit code OK when filtering by assignment");
 chomp $out;
 is($out,"","Gets no tests correctly when filtering by wrong assignment");
 
 #check status filters
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -p "GosPlan" -r "Executing the great plan" -m t --mock --config "testConfig" --status "passed"});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK when filtering by status");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject -p GosPlan -r}, "Executing the great plan", qw{-m t --mock --config testConfig --status passed});
+($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 0, "Exit code OK when filtering by status");
 like($out,qr/skipall\.test$/,"Gets test correctly when filtering by status");
 
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -p "GosPlan" -r "Executing the great plan" --mock --config "testConfig" --status "failed"});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK when filtering by status");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject -p GosPlan -r}, "Executing the great plan", qw{--mock --config testConfig --status failed});
+($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 255, "Exit code OK when filtering by status");
 chomp $out;
 is($out,"","Gets no tests correctly when filtering by wrong status");
 
 #Verify no-match returns non path
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -r "TestingSuite" --mock});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK running no plan mode, no-match");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject  -r TestingSuite --mock});
+($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 0, "Exit code OK running no plan mode, no-match");
 chomp $out;
 like($out,qr/\nskipall\.test$/,"Gets test correctly in no plan mode, no-match");
 
 #Verify no-match returns non path
-@args = ($^X,qw{bin/testrail-tests --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -r "TestingSuite" --orphans t --mock});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK running no plan mode, no recurse");
+@args = (qw{--apiurl http://testrail.local --user test@fake.fake --password fake -j TestProject  -r TestingSuite --orphans t --mock});
+($out,$code) = TestRail::Bin::Tests::run(@args);
+is($code, 0, "Exit code OK running no plan mode, no recurse");
 chomp $out;
 like($out,qr/NOT SO SEARED AFTER ARR/,"Gets test correctly in orphan mode");
 
 #Verify no-match returns non path
-@args = ($^X,qw{bin/testrail-tests --help});
-$out = `@args`;
-is($? >> 8, 0, "Exit code OK asking for help");
+@args = qw{--help};
+$0 = $FindBin::Bin.'/../bin/testrail-tests';
+(undef,$code) = capture {TestRail::Bin::Tests::run(@args)} \$out, \$out;
+is($code, 0, "Exit code OK asking for help");
 like($out,qr/encoding of arguments/i,"Help output OK");
-
-#Verify no-match and match are mutually exclusive
-@args = ($^X,qw{bin/testrail-tests --no-match t --match t/qa --apiurl http://testrail.local --user "test@fake.fake" --password "fake" -j TestProject -r "TestingSuite" --mock});
-$out = `@args`;
-isnt($? >> 8, 0, "Exit code not OK asking for mutually exclusive match options");