File Coverage

blib/lib/App/NDTools/Test.pm
Criterion Covered Total %
statement 77 90 85.5
branch 28 38 73.6
condition 12 24 50.0
subroutine 14 16 87.5
pod 0 4 0.0
total 131 172 76.1


line stmt bran cond sub pod time code
1             package App::NDTools::Test;
2              
3 15     15   1278282 use strict;
  15         172  
  15         525  
4 15     15   87 use warnings FATAL => 'all';
  15         29  
  15         589  
5 15     15   5618 use parent qw(Exporter);
  15         3838  
  15         85  
6              
7 15     15   7220 use Capture::Tiny qw(capture);
  15         332740  
  15         1029  
8 15     15   130 use Cwd qw(abs_path);
  15         32  
  15         663  
9 15     15   9337 use Data::Dumper;
  15         102193  
  15         1001  
10 15     15   128 use Scalar::Util qw(blessed);
  15         32  
  15         731  
11 15     15   255 use Test::More;
  15         32  
  15         140  
12              
13             BEGIN {
14             # relative path will be incorrect when `cd t_dir` used
15             # required by Pod::Usage
16 15     15   19482 $0 = abs_path($0);
17             }
18              
19             our @EXPORT = qw(
20             run_ok
21             t_ab_cmp
22             t_dir
23             t_dump
24             );
25              
26             sub run_ok {
27 246     246 0 418152 my %t = @_;
28              
29 246         668 local $Test::Builder::Level = $Test::Builder::Level + 1;
30              
31 246 50 33     1042 if (exists $t{skip} and $t{skip}->()) {
32 0         0 pass("Test '$t{name}' cancelled by 'skip' opt");
33 0         0 return;
34             }
35              
36 246 50       761 my @envs = exists $t{env} ? %{$t{env}} : ();
  0         0  
37             SET_ENV: # can't use loop here - env vars will be localized in it's block
38 246 50       650 @envs and local $ENV{$envs[0]} = $envs[1];
39 246 50       637 if (@envs) {
40 0         0 splice @envs, 0, 2;
41 0         0 goto SET_ENV;
42             }
43              
44 246 50 66     919 if (exists $t{pre} and not $t{pre}->()) {
45 0         0 fail("Pre hook for '$t{name}' failed");
46 0         0 return;
47             }
48              
49 246         38403 my ($out, $err, $exit);
50 246 100       589 if (eval { $t{cmd}->[0]->isa('App::NDTools::NDTool') }) {
  246         3231  
51 243         494 my $tool = shift @{$t{cmd}};
  243         707  
52              
53             ($out, $err) = capture {
54 243     243   278063 local $Log::Log4Cli::LEVEL = 0; # reset loglevel
55 243         478 eval { $tool->new(@{$t{cmd}})->exec() }
  243         434  
  243         2123  
56 243         7604 };
57              
58 243 50 33     236501 if (blessed($@) and $@->isa('Log::Log4Cli::Exception')) {
59 243         1021 $err .= $@->{LOG_MESSAGE};
60 243         622 $exit = $@->{EXIT_CODE};
61             } else {
62 0         0 $err .= $@;
63 0         0 $exit = 255;
64             }
65              
66 243         514 unshift @{$t{cmd}}, $tool;
  243         920  
67             } else { # assume it's binary
68 3     3   93 ($out, $err, $exit) = capture { system(@{$t{cmd}}) };
  3         3922  
  3         431503  
69 3         5656 $exit = $exit >> 8;
70             }
71              
72             subtest $t{name} => sub {
73              
74 246     246   229907 for my $std ('stdout', 'stderr') {
75 492 50 66     157812 next if (exists $t{$std} and not defined $t{$std}); # set to undef to skip test
76 492 100       1519 $t{$std} = '' unless (exists $t{$std}); # silence expected by default
77              
78 492         1567 my $desc = uc($std) . " check for $t{name}: [@{$t{cmd}}]";
  492         2326  
79 492 100       1471 my $data = $std eq 'stdout' ? $out : $err;
80              
81 492 100       1522 if (ref $t{$std} eq 'CODE') {
    100          
82 112         416 ok($t{$std}->($data), $desc);
83             } elsif (ref $t{$std} eq 'Regexp') {
84 52         230 like($data, $t{$std}, $desc);
85             } else {
86 328         1195 is($data, $t{$std}, $desc);
87             }
88             }
89              
90 246 50 66     99567 if (not exists $t{exit} or defined $t{exit}) { # set to undef to skip test
91 246 100       838 $t{exit} = 0 unless exists $t{exit}; # defailt exit code
92             is(
93             $exit, $t{exit},
94 246         925 "Exit code check for $t{name}: [@{$t{cmd}}]"
  246         1399  
95             );
96             }
97              
98 246 100       96679 $t{test}->() if (exists $t{test});
99              
100 246 50 33     60269 if (exists $t{post} and not $t{post}->()) {
101 0         0 fail("Post hook for '$t{name}' failed");
102 0         0 return;
103             }
104              
105 246 50 66     940 if (not exists $t{clean} or defined $t{clean}) { # set to undef to skip
106 246 100       1021 @{$t{clean}} = "$t{name}.got" unless exists $t{clean};
  239         1016  
107 246 100       562 map { unlink $_ if (-f $_) } @{$t{clean}};
  253         175064  
  246         624  
108             }
109              
110 246         1497 done_testing();
111             }
112 246         2768 }
113              
114             sub t_ab_cmp {
115 0     0 0 0 return "GOT: " . t_dump(shift) . "\nEXP: " . t_dump(shift);
116             }
117              
118             sub t_dir {
119 15   33 15 0 1355 my $tfile = shift || (caller)[1];
120 15         408 substr($tfile, 0, length($tfile) - 1) . "d";
121             }
122              
123             sub t_dump {
124 0     0 0   return Data::Dumper->new([shift])->Terse(1)->Sortkeys(1)->Quotekeys(0)->Indent(0)->Deepcopy(1)->Dump();
125             }
126              
127             1;