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 12     12   878654 use strict;
  12         108  
  12         344  
4 12     12   63 use warnings FATAL => 'all';
  12         21  
  12         427  
5 12     12   3921 use parent qw(Exporter);
  12         2620  
  12         61  
6              
7 12     12   4921 use Capture::Tiny qw(capture);
  12         221325  
  12         676  
8 12     12   87 use Cwd qw(abs_path);
  12         21  
  12         411  
9 12     12   6499 use Data::Dumper;
  12         71064  
  12         698  
10 12     12   82 use Scalar::Util qw(blessed);
  12         21  
  12         455  
11 12     12   62 use Test::More;
  12         20  
  12         89  
12              
13             BEGIN {
14             # relative path will be incorrect when `cd t_dir` used
15             # required by Pod::Usage
16 12     12   13248 $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 215     215 0 296199 my %t = @_;
28              
29 215         476 local $Test::Builder::Level = $Test::Builder::Level + 1;
30              
31 215 50 33     730 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 215 50       580 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 215 50       445 @envs and local $ENV{$envs[0]} = $envs[1];
39 215 50       520 if (@envs) {
40 0         0 splice @envs, 0, 2;
41 0         0 goto SET_ENV;
42             }
43              
44 215 50 66     716 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 215         24230 my ($out, $err, $exit);
50 215 100       378 if (eval { $t{cmd}->[0]->isa('App::NDTools::NDTool') }) {
  215         2189  
51 212         343 my $tool = shift @{$t{cmd}};
  212         474  
52              
53             ($out, $err) = capture {
54 212     212   204894 local $Log::Log4Cli::LEVEL = 0; # reset loglevel
55 212         366 eval { $tool->new(@{$t{cmd}})->exec() }
  212         333  
  212         1511  
56 212         5564 };
57              
58 212 50 33     178523 if (blessed($@) and $@->isa('Log::Log4Cli::Exception')) {
59 212         685 $err .= $@->{LOG_MESSAGE};
60 212         456 $exit = $@->{EXIT_CODE};
61             } else {
62 0         0 $err .= $@;
63 0         0 $exit = 255;
64             }
65              
66 212         336 unshift @{$t{cmd}}, $tool;
  212         696  
67             } else { # assume it's binary
68 3     3   77 ($out, $err, $exit) = capture { system(@{$t{cmd}}) };
  3         3131  
  3         379921  
69 3         4446 $exit = $exit >> 8;
70             }
71              
72             subtest $t{name} => sub {
73              
74 215     215   172301 for my $std ('stdout', 'stderr') {
75 430 50 66     116731 next if (exists $t{$std} and not defined $t{$std}); # set to undef to skip test
76 430 100       1121 $t{$std} = '' unless (exists $t{$std}); # silence expected by default
77              
78 430         1169 my $desc = uc($std) . " check for $t{name}: [@{$t{cmd}}]";
  430         1620  
79 430 100       1171 my $data = $std eq 'stdout' ? $out : $err;
80              
81 430 100       1147 if (ref $t{$std} eq 'CODE') {
    100          
82 110         351 ok($t{$std}->($data), $desc);
83             } elsif (ref $t{$std} eq 'Regexp') {
84 40         156 like($data, $t{$std}, $desc);
85             } else {
86 280         845 is($data, $t{$std}, $desc);
87             }
88             }
89              
90 215 50 66     69696 if (not exists $t{exit} or defined $t{exit}) { # set to undef to skip test
91 215 100       674 $t{exit} = 0 unless exists $t{exit}; # defailt exit code
92             is(
93             $exit, $t{exit},
94 215         658 "Exit code check for $t{name}: [@{$t{cmd}}]"
  215         986  
95             );
96             }
97              
98 215 100       67992 $t{test}->() if (exists $t{test});
99              
100 215 50 33     39247 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 215 50 66     753 if (not exists $t{clean} or defined $t{clean}) { # set to undef to skip
106 215 100       800 @{$t{clean}} = "$t{name}.got" unless exists $t{clean};
  208         721  
107 215 100       339 map { unlink $_ if (-f $_) } @{$t{clean}};
  222         26704  
  215         434  
108             }
109              
110 215         1101 done_testing();
111             }
112 215         2109 }
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 12   33 12 0 965 my $tfile = shift || (caller)[1];
120 12         278 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;