File Coverage

blib/lib/Test/Mock/ExternalCommand.pm
Criterion Covered Total %
statement 89 91 97.8
branch 7 10 70.0
condition n/a
subroutine 23 23 100.0
pod 6 6 100.0
total 125 130 96.1


line stmt bran cond sub pod time code
1             package Test::Mock::ExternalCommand;
2 6     6   173366 use strict;
  6         13  
  6         222  
3 6     6   32 use warnings;
  6         13  
  6         169  
4 6     6   30 use Config;
  6         46  
  6         250  
5 6     6   31 use Carp;
  6         11  
  6         715  
6 6     6   5688 use Variable::Expand::AnyLevel qw(expand_variable);
  6         24782  
  6         1628  
7              
8 6     6   306 use 5.010;
  6         20  
  6         2041  
9             our $VERSION = '0.03';
10              
11             my $command_registry = {};
12             my $command_history = {};
13              
14             BEGIN {
15             sub _command_and_args {
16 14     14   26 my ( $command, @args ) = @_;
17 14         94 my ( $command_real, @args2 ) = split qr/\s+/, $command;
18 14         42 my @args_real = (@args2, @args);
19 14         43 return ($command_real, @args_real);
20             }
21              
22             *CORE::GLOBAL::system = sub {
23 7     7   1385 my ( $command, @args ) = _command_and_args(@_);
24 7 50       58 if ( defined $command_registry->{$command} ) {
25 7         24 return $command_registry->{$command}->{system}->(@args);
26             }
27 0         0 CORE::system(@_);
28 6     6   38 };
29              
30             *CORE::GLOBAL::readpipe = sub {
31             # readpipe receives variable name if variable is used in backquote string ...
32             # so it is need to expand using Variable::Expand::AnyLevel::expand_variable
33 7     7   881 my @new_args = map { expand_variable($_, 1) } @_;
  7         31  
34 7         1734 my ( $command, @command_args ) = _command_and_args(@new_args);
35 7 50       2410 if ( defined $command_registry->{$command} ) {
36 7         48 return $command_registry->{$command}->{readpipe}->(@command_args);
37             }
38 0         0 CORE::readpipe(@_);
39 6         4506 };
40             }
41              
42              
43             =head1 NAME
44              
45             Test::Mock::ExternalCommand - Create mock external-command easily
46              
47             =head1 SYNOPSIS
48              
49             use Test::Mock::ExternalCommand;
50             my $m = Test::Mock::ExternalCommand->new();
51             $m->set_command( 'my-command-aaa', 'command-output', 0);
52             # use 'my-command-aaa' in your test.
53              
54             =head1 DESCRIPTION
55              
56             Test::Mock::ExternalCommand enable to make mock-external command in easy way.
57              
58             =head1 Methods
59              
60             =cut
61              
62             =head2 new()
63              
64             =cut
65              
66             sub new {
67 9     9 1 3791 my ( $class ) = @_;
68 9         28 my $self = {
69             my_commands => {},
70             };
71 9         28 bless $self, $class;
72 9         36 my $address = $self + 0;
73 9         34 $command_history->{$address} = [];
74 9         26 return $self;
75             }
76              
77             =head2 set_command( $command_name, $command_output_string, $command_exit_status )
78              
79             set mock external command command.
80              
81             =cut
82              
83             sub set_command {
84 12     12 1 2984 my ( $self, $command_name, $command_output, $command_exit_status ) = @_;
85              
86 12 100       257 carp "${command_name}: already defined\n" if ( defined $command_registry->{$command_name} );
87 12         229 $self->{my_commands}->{$command_name} = $command_name;
88              
89 12         25 my $address = $self + 0; # address is calculated in this scope avoiding refcount increment
90              
91             $command_registry->{$command_name}->{system} = sub {
92 4     4   9 my ( @args ) = @_;
93 4         6 push @{ $command_history->{$address} }, [$command_name, @args];
  4         17  
94 4         340 print $command_output;
95 4         35 return $command_exit_status << 8;
96 12         92 };
97              
98             $command_registry->{$command_name}->{readpipe} = sub {
99 3     3   9 my ( @args ) = @_;
100 3         5 push @{ $command_history->{$address} }, [$command_name, @args];
  3         12  
101 3         19 return $command_output;
102 12         84 };
103             }
104              
105             =head2 set_command_by_coderef( $command_name, $command_behavior_subref )
106              
107             set mock external command command using subroutine reference(coderef).
108              
109             =cut
110              
111             sub set_command_by_coderef {
112 9     9 1 2479 my ( $self, $command_name, $command_behavior_subref ) = @_;
113              
114 9 100       131 carp "${command_name}: already defined\n" if ( defined $command_registry->{$command_name} );
115 9         101 $self->{my_commands}->{$command_name} = $command_name;
116              
117 9         16 my $address = $self + 0; # address is calculated in this scope avoiding refcount increment
118              
119             $command_registry->{$command_name}->{system} = sub {
120 3     3   6 my ( @args ) = @_;
121 3         4 push @{ $command_history->{$address} }, [$command_name, @args];
  3         8  
122 3         8 my $ret = $command_behavior_subref->(@args);
123 3         15 return $ret << 8;
124 9         49 };
125             $command_registry->{$command_name}->{readpipe} = sub {
126 4     4   643 my ( @args ) = @_;
127 4         7 push @{ $command_history->{$address} }, [$command_name, @args];
  4         17  
128 4         15 return $command_behavior_subref->(@args);
129 9         60 };
130             }
131              
132             =head2 history()
133              
134             return command history.
135              
136             =cut
137              
138             sub history {
139 3     3 1 19 my ( $self ) = @_;
140 3         6 my $address = $self + 0;
141 3         6 return @{ $command_history->{$address} };
  3         18  
142             }
143              
144             =head2 reset_history()
145              
146             reset command history.
147              
148             =cut
149              
150             sub reset_history {
151 11     11 1 18 my ( $self ) = @_;
152 11         24 my $address = $self + 0;
153 11         438 $command_history->{$address} = [];
154             }
155              
156             =head2 commands()
157              
158             return overridden command names
159              
160             =cut
161              
162             sub commands {
163 13     13 1 1054 my ( $self ) = @_;
164 13         32 my @result = sort keys %{ $self->{my_commands} };
  13         79  
165 13         575 return @result;
166             }
167              
168             # commands registered in global structure
169             sub _registered_commands {
170 4     4   11 my @result = sort keys %{ $command_registry };
  4         17  
171 4         24 return @result;
172             }
173              
174             sub _unset_all_commands {
175 10     10   22 my ( $self ) = @_;
176 10         706 for my $command ( $self->commands() ) {
177 18         218 delete $command_registry->{$command};
178             }
179 10         28 $self->{my_commands} = {};
180 10         36 $self->reset_history();
181             }
182              
183             sub DESTROY {
184 8     8   7628 my ( $self ) = @_;
185 8 50       44 $self->_unset_all_commands() if ( defined $self );
186             }
187              
188             1;
189             __END__