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   1266518 use strict;
  15         168  
  15         514  
4 15     15   83 use warnings FATAL => 'all';
  15         27  
  15         590  
5 15     15   5709 use parent qw(Exporter);
  15         3723  
  15         96  
6              
7 15     15   7223 use Capture::Tiny qw(capture);
  15         331663  
  15         978  
8 15     15   117 use Cwd qw(abs_path);
  15         34  
  15         603  
9 15     15   9009 use Data::Dumper;
  15         101014  
  15         968  
10 15     15   117 use Scalar::Util qw(blessed);
  15         33  
  15         657  
11 15     15   91 use Test::More;
  15         33  
  15         124  
12              
13             BEGIN {
14             # relative path will be incorrect when `cd t_dir` used
15             # required by Pod::Usage
16 15     15   19232 $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 239     239 0 391473 my %t = @_;
28              
29 239         659 local $Test::Builder::Level = $Test::Builder::Level + 1;
30              
31 239 50 33     934 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 239 50       734 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 239 50       625 @envs and local $ENV{$envs[0]} = $envs[1];
39 239 50       613 if (@envs) {
40 0         0 splice @envs, 0, 2;
41 0         0 goto SET_ENV;
42             }
43              
44 239 50 66     925 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 239         35579 my ($out, $err, $exit);
50 239 100       539 if (eval { $t{cmd}->[0]->isa('App::NDTools::NDTool') }) {
  239         2922  
51 236         424 my $tool = shift @{$t{cmd}};
  236         635  
52              
53             ($out, $err) = capture {
54 236     236   261113 local $Log::Log4Cli::LEVEL = 0; # reset loglevel
55 236         467 eval { $tool->new(@{$t{cmd}})->exec() }
  236         382  
  236         1878  
56 236         7179 };
57              
58 236 50 33     224308 if (blessed($@) and $@->isa('Log::Log4Cli::Exception')) {
59 236         997 $err .= $@->{LOG_MESSAGE};
60 236         653 $exit = $@->{EXIT_CODE};
61             } else {
62 0         0 $err .= $@;
63 0         0 $exit = 255;
64             }
65              
66 236         462 unshift @{$t{cmd}}, $tool;
  236         857  
67             } else { # assume it's binary
68 3     3   90 ($out, $err, $exit) = capture { system(@{$t{cmd}}) };
  3         4080  
  3         440567  
69 3         5329 $exit = $exit >> 8;
70             }
71              
72             subtest $t{name} => sub {
73              
74 239     239   215307 for my $std ('stdout', 'stderr') {
75 478 50 66     151075 next if (exists $t{$std} and not defined $t{$std}); # set to undef to skip test
76 478 100       1473 $t{$std} = '' unless (exists $t{$std}); # silence expected by default
77              
78 478         1529 my $desc = uc($std) . " check for $t{name}: [@{$t{cmd}}]";
  478         2115  
79 478 100       1386 my $data = $std eq 'stdout' ? $out : $err;
80              
81 478 100       1514 if (ref $t{$std} eq 'CODE') {
    100          
82 111         405 ok($t{$std}->($data), $desc);
83             } elsif (ref $t{$std} eq 'Regexp') {
84 50         237 like($data, $t{$std}, $desc);
85             } else {
86 317         1063 is($data, $t{$std}, $desc);
87             }
88             }
89              
90 239 50 66     93841 if (not exists $t{exit} or defined $t{exit}) { # set to undef to skip test
91 239 100       889 $t{exit} = 0 unless exists $t{exit}; # defailt exit code
92             is(
93             $exit, $t{exit},
94 239         908 "Exit code check for $t{name}: [@{$t{cmd}}]"
  239         1322  
95             );
96             }
97              
98 239 100       91330 $t{test}->() if (exists $t{test});
99              
100 239 50 33     54551 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 239 50 66     918 if (not exists $t{clean} or defined $t{clean}) { # set to undef to skip
106 239 100       899 @{$t{clean}} = "$t{name}.got" unless exists $t{clean};
  232         974  
107 239 100       461 map { unlink $_ if (-f $_) } @{$t{clean}};
  246         15994  
  239         548  
108             }
109              
110 239         1405 done_testing();
111             }
112 239         2646 }
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 1399 my $tfile = shift || (caller)[1];
120 15         400 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;