File Coverage

inc/Test/Number/Delta.pm
Criterion Covered Total %
statement 50 77 64.9
branch 15 38 39.4
condition 3 9 33.3
subroutine 9 12 75.0
pod 0 4 0.0
total 77 140 55.0


line stmt bran cond sub pod time code
1             #line 1
2 3     3   2159 package Test::Number::Delta;
  3         5  
  3         116  
3             use strict;
4             #use warnings; bah -- not supported before 5.006
5 3     3   14
  3         4  
  3         228  
6             use vars qw ($VERSION @EXPORT @ISA);
7             $VERSION = "1.03";
8            
9 3     3   13 # Required modules
  3         5  
  3         318  
10 3     3   16 use Carp;
  3         6  
  3         123  
11 3     3   15 use Test::Builder;
  3         5  
  3         3236  
12             use Exporter;
13            
14             @ISA = qw( Exporter );
15             @EXPORT = qw( delta_not_ok delta_ok delta_within delta_not_within );
16            
17             #line 116
18            
19             my $Test = Test::Builder->new;
20             my $Epsilon = 1e-6;
21             my $Relative = undef;
22            
23             sub import {
24             my $self = shift;
25             my $pack = caller;
26             my $found = grep /within|relative/, @_;
27             croak "Can't specify more than one of 'within' or 'relative'"
28             if $found > 1;
29             if ($found) {
30             my ($param,$value) = splice @_, 0, 2;
31             croak "'$param' parameter must be non-zero"
32             if $value == 0;
33             if ($param eq 'within') {
34             $Epsilon = abs($value);
35             }
36             elsif ($param eq 'relative') {
37             $Relative = abs($value);
38             }
39             else {
40             croak "Test::Number::Delta parameters must come first";
41             }
42             }
43             $Test->exported_to($pack);
44             $Test->plan(@_);
45             $self->export_to_level(1, $self, $_) for @EXPORT;
46             }
47            
48             #--------------------------------------------------------------------------#
49             # _check -- recursive function to perform comparison
50             #--------------------------------------------------------------------------#
51            
52             sub _check {
53             my ($p, $q, $epsilon, $name, @indices) = @_;
54             my ($ok, $diag) = ( 1, q{} ); # assume true
55             if ( ref $p eq 'ARRAY' || ref $q eq 'ARRAY' ) {
56             if ( @$p == @$q ) {
57             for my $i ( 0 .. $#{$p} ) {
58             my @new_indices;
59             ($ok, $diag, @new_indices) = _check(
60             $p->[$i],
61             $q->[$i],
62             $epsilon,
63             $name,
64             scalar @indices ? @indices : (),
65             $i,
66             );
67             if ( not $ok ) {
68             @indices = @new_indices;
69             last;
70             }
71             }
72             }
73             else {
74             $ok = 0;
75             $diag = "Got an array of length " . scalar(@$p) .
76             ", but expected an array of length " . scalar(@$q);
77             }
78             }
79             else {
80             $ok = abs($p - $q) < $epsilon;
81             if ( ! $ok ) {
82             my ($ep, $dp) = _ep_dp( $epsilon );
83             $diag = sprintf("%.${dp}f and %.${dp}f are not equal" .
84             " to within %.${ep}f", $p, $q, $epsilon
85             );
86             }
87             }
88             return ( $ok, $diag, scalar(@indices) ? @indices : () );
89             }
90            
91             sub _ep_dp {
92             my $epsilon = shift;
93             my ($exp) = sprintf("%e",$epsilon) =~ m/e(.+)/;
94             my $ep = $exp < 0 ? -$exp : 1;
95             my $dp = $ep + 1;
96             return ($ep, $dp);
97             }
98            
99             #line 200
100            
101             #--------------------------------------------------------------------------#
102             # delta_within()
103             #--------------------------------------------------------------------------#
104            
105             #line 237
106            
107             sub delta_within($$$;$) {
108             my ($p, $q, $epsilon, $name) = @_;
109             croak "Value of epsilon to delta_within must be non-zero"
110             if $epsilon == 0;
111             $epsilon = abs($epsilon);
112             my ($ok, $diag, @indices) = _check( $p, $q, $epsilon, $name );
113             if ( @indices ) {
114             $diag = "At [" . join( "][", @indices ) . "]: $diag";
115             }
116             return $Test->ok($ok,$name) || $Test->diag( $diag );
117             }
118            
119             #--------------------------------------------------------------------------#
120             # delta_ok()
121             #--------------------------------------------------------------------------#
122 3     3   22
123 3         34 #line 264
124 3         67
125 3 50       14 sub delta_ok($$;$) {
126             my ($p, $q, $name) = @_;
127 3 50       9 {
128 3         12 local $Test::Builder::Level = $Test::Builder::Level + 1;
129 3 50       15 my $e = $Relative
130             ? $Relative * (abs($p) > abs($q) ? abs($p) : abs($q))
131 3 50       10 : $Epsilon;
    0          
132 3         8 delta_within( $p, $q, $e, $name );
133             }
134             }
135 0         0
136             #--------------------------------------------------------------------------#
137             # delta_not_ok()
138 0         0 #--------------------------------------------------------------------------#
139            
140             #line 292
141 3         15
142 3         12 sub delta_not_within($$$;$) {
143 3         3985 my ($p, $q, $epsilon, $name) = @_;
144             croak "Value of epsilon to delta_not_within must be non-zero"
145             if $epsilon == 0;
146             $epsilon = abs($epsilon);
147             my ($ok, undef, @indices) = _check( $p, $q, $epsilon, $name );
148             $ok = !$ok;
149             my ($ep, $dp) = _ep_dp( $epsilon );
150             my $diag = sprintf("Arguments are equal to within %.${ep}f", $epsilon);
151 100016     100016   156870 return $Test->ok($ok,$name) || $Test->diag( $diag );
152 100016         117138 }
153 100016 100 66     341040
154 5 50       14 #line 315
155 5         7
  5         18  
156 100011         94800 sub delta_not_ok($$;$) {
157 100011 50       252216 my ($p, $q, $name) = @_;
158             {
159             local $Test::Builder::Level = $Test::Builder::Level + 1;
160             my $e = $Relative
161             ? $Relative * (abs($p) > abs($q) ? abs($p) : abs($q))
162             : $Epsilon;
163             delta_not_within( $p, $q, $e, $name );
164             }
165 100011 50       233383 }
166 0         0
167 0         0
168             1; #this line is important and will help the module return a true value
169             __END__