File Coverage

blib/lib/Test/BoostUnit.pm
Criterion Covered Total %
statement 30 294 10.2
branch 0 90 0.0
condition 0 15 0.0
subroutine 10 50 20.0
pod 21 21 100.0
total 61 470 12.9


line stmt bran cond sub pod time code
1             package Test::BoostUnit;
2              
3 1     1   20343 use 5.006;
  1         4  
  1         36  
4 1     1   6 use strict;
  1         2  
  1         32  
5 1     1   6 use warnings;
  1         6  
  1         40  
6              
7             #use Format::PrintUtils qw(:ALL);
8 1     1   6 use List::Util qw(first max maxstr min minstr reduce shuffle sum);
  1         2  
  1         158  
9 1     1   8 use File::Find;
  1         2  
  1         52  
10 1     1   5 use Digest::MD5;
  1         2  
  1         30  
11 1     1   833 use Getopt::CommandLineExports qw(:ALL);
  1         32633  
  1         183  
12              
13             =head1 NAME
14              
15             Test::BoostUnit - Allow Tests to output Boost C++ XML format test reports
16              
17             =head1 VERSION
18              
19             Version 0.05
20              
21             =cut
22              
23             our $VERSION = '0.05';
24              
25              
26             =head1 SYNOPSIS
27              
28             A collection of routines to aid in automated testing
29              
30             =head1 EXPORT
31              
32             compareTwoDirecoryTrees
33             compareTwoLists
34             makeCheck
35             makeCheckEqual
36             makeError
37             makeInfo
38             makeCDATA
39             makeCloseTestSuite
40             linearRegression
41             correlateTwoHashes
42             matchTwoHashes
43             generateConfusionMatrix
44             makeComment
45             makeOpenTestCase
46             makeCloseTestCase
47             makeOpenTestSuite
48             makeOpenTestLog
49             makeCloseTestLog
50             calculateErrorMetricForTwoHashes
51             calculateWeightedKappaOnConfusionMatrix
52              
53             =head1 SUBROUTINES/METHODS
54              
55              
56              
57             =cut
58              
59             package Test::BoostUnit;
60              
61             #my $CLASS = __PACKAGE__;
62             BEGIN {
63             # use Test::More;
64 1     1   10 use Exporter();
  1         3  
  1         114  
65 1     1   2 our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
66 1         12 @ISA = qw( Exporter);
67 1         2 @EXPORT_OK = qw();
68 1         6 %EXPORT_TAGS = ( ALL => [
69             qw!&compareTwoDirecoryTrees
70             &compareTwoLists
71             &makeCheck
72             &makeCheckEqual
73             &makeError
74             &makeInfo
75             &makeCDATA
76             &makeCloseTestSuite
77             &linearRegression
78             &correlateTwoHashes
79             &matchTwoHashes
80             &generateConfusionMatrix
81             &makeComment
82             &makeOpenTestCase
83             &makeCloseTestCase
84             &makeOpenTestSuite
85             &makeOpenTestLog
86             &makeCloseTestLog
87             &calculateErrorMetricForTwoHashes
88             &calculateWeightedKappaOnConfusionMatrix! ],
89             ); # eg: TAG => [ qw!name1 name2! ],
90              
91             #your exported package globals go here,
92             #as well as any optionally exported functions
93 1         3836 @EXPORT_OK = qw(&compareTwoDirecoryTrees
94             &compareTwoLists
95             &makeCheck
96             &makeCheckEqual
97             &makeError
98             &makeInfo
99             &makeCDATA
100             &makeCloseTestSuite
101             &linearRegression
102             &correlateTwoHashes
103             &matchTwoHashes
104             &generateConfusionMatrix
105             &makeComment
106             &makeOpenTestCase
107             &makeCloseTestCase
108             &makeOpenTestSuite
109             &makeOpenTestLog
110             &makeCloseTestLog
111             &calculateErrorMetricForTwoHashes
112             &calculateWeightedKappaOnConfusionMatrix
113             );
114              
115             }
116              
117             =head2 calculateErrorMetricForTwoHashes
118              
119             Runs two hashes through a set of functions to return a single metric value
120              
121             Assume N matching keys in both hashes (V1 and V2):
122             foreach n in N:
123             Run a COMPARE_FUNC C(V1(n), V2(n))
124             Run a ACCUMULATION_FUNC A(n) = A(A(n-1),C(V1(n), V2(n)))
125              
126             Finally:
127              
128             Return a SUMMARY_FUNC S(A(N),N)
129              
130             The default calculates the L2 Norm
131              
132             =cut
133              
134             sub calculateErrorMetricForTwoHashes
135             {
136 0     0     my %h = (
137             METRIC => "",
138             VECTOR1 => undef,
139             VECTOR2 => undef,
140 0           COMPARE_FUNC => sub {my ($a, $b) = @_; return [($a-$b)*($a-$b)];},
141 0     0     ACCUMULATION_FUNC => sub {my ($previousTotal, $currentValue) = @_;
142 0           return [${$previousTotal}[0] + ${$currentValue}[0]];},
  0            
  0            
143 0     0     SUMMARY_FUNC => sub {my ($totalMetric, $totalPoints)= @_;
144 0 0         return 0 unless $totalPoints;
145 0 0         return ($$totalMetric[0]/$totalPoints) if $totalPoints;},
146 0     0 1   ( parseArgs \@_, 'METRIC=s', 'VECTOR1=s%', 'VECTOR2=s%', 'COMPARE_FUNC=c&', 'ACCUMULATION_FUNC=c&', 'SUMMARY_FUNC=c&'),
147             );
148 0           my $V1 = $h{VECTOR1};
149 0           my $V2 = $h{VECTOR2}; #Two Hash references
150 0           my $numPoints = 0;
151 0           my $totalMetric = [0];
152 0 0         if ($h{METRIC} eq "RMS")
153             {
154 0     0     $h{SUMMARY_FUNC} = sub {my ($totalMetric, $totalPoints)= @_;
155 0 0         return 0 unless $totalPoints;
156 0 0         return sqrt($$totalMetric[0]/$totalPoints) if $totalPoints;};
  0            
157            
158             }
159 0 0         if ($h{METRIC} eq "Mean")
160             {
161 0     0     $h{COMPARE_FUNC} = sub {my ($a, $b) = @_; return [($a-$b)];};
  0            
  0            
162             }
163 0 0         if ($h{METRIC} eq "MeanL1Norm")
164             {
165 0     0     $h{COMPARE_FUNC} = sub {my ($a, $b) = @_; return [abs($a-$b)];};
  0            
  0            
166             }
167 0 0         if ($h{METRIC} eq "RelativeMean")
168             {
169 0 0   0     $h{COMPARE_FUNC} = sub {my ($a, $b) = @_; return [($a-$b)/$b] if $b;return [($a-$b)];};
  0            
  0            
  0            
170             }
171 0 0         if ($h{METRIC} eq "RelativeL1Norm")
172             {
173 0 0   0     $h{COMPARE_FUNC} = sub {my ($a, $b) = @_; return [abs($a-$b)/$b] if $b;return [abs($a-$b)];};
  0            
  0            
  0            
174             }
175 0 0         if ($h{METRIC} eq "RelativeMaxL1Norm")
176             {
177 0     0     $h{SUMMARY_FUNC} = sub {my ($totalMetric, $totalPoints)= @_; return $$totalMetric[0];};
  0            
  0            
178 0 0   0     $h{ACCUMULATION_FUNC} = sub {my ($previousTotal, $currentValue) = @_; return $$currentValue[0] > $$previousTotal[0] ? [$$currentValue[0]] : [$$previousTotal[0]];};
  0            
  0            
179 0 0   0     $h{COMPARE_FUNC} = sub {my ($a, $b) = @_; return [abs(($a-$b)/$b)] if $b;return [abs($a-$b)];};
  0            
  0            
  0            
180            
181             }
182 0 0         if ($h{METRIC} eq "MaxL1Norm")
183             {
184 0     0     $h{SUMMARY_FUNC} = sub {my ($totalMetric, $totalPoints)= @_; return $$totalMetric[0];};
  0            
  0            
185 0 0   0     $h{ACCUMULATION_FUNC} = sub {my ($previousTotal, $currentValue) = @_; return $$currentValue[0] > $$previousTotal[0] ? [$$currentValue[0]] : [$$previousTotal[0]];};
  0            
  0            
186 0     0     $h{COMPARE_FUNC} = sub {my ($a, $b) = @_; return [abs($a-$b)];};
  0            
  0            
187             }
188            
189 0           foreach my $key ( sort keys %$V1 ) {
190 0 0         if (exists $V2->{$key}) {
191 0           my $XVal = $V1->{$key};
192 0           my $YVal = $V2->{$key};
193 0           ++$numPoints;
194 0           $totalMetric = &{$h{ACCUMULATION_FUNC}}($totalMetric, &{$h{COMPARE_FUNC}}($XVal,$YVal));
  0            
  0            
195             }
196             }
197 0           return &{$h{SUMMARY_FUNC}}($totalMetric, $numPoints);
  0            
198             }
199              
200             =head2 matchTwoHashes
201              
202             Return the % of matching keys in Two hashes (VECTOR1 and VECTOR2):
203              
204             =cut
205              
206             sub matchTwoHashes
207             {
208 0     0 1   my %h = (
209             VECTOR1 => undef,
210             VECTOR2 => undef,
211             ( parseArgs \@_, 'VECTOR1=s%', 'VECTOR2=s%'),
212             );
213              
214 0           my $V1 = $h{VECTOR1};
215 0           my $V2 = $h{VECTOR2}; #Two Hash references
216 0           my $numPoints = 0;
217 0           my $numMatches = 0;
218 0           foreach my $key ( sort keys %$V1 ) {
219 0 0         if (exists $V2->{$key}) {
220 0           my $XBD = $V1->{$key};
221 0           my $YBD = $V2->{$key};
222 0           ++$numPoints;
223 0 0         ++$numMatches if $XBD eq $YBD;
224             }
225             }
226 0 0         return $numMatches/$numPoints if $numPoints;
227 0 0         return 0 unless $numPoints;
228             }
229              
230             =head2 generateConfusionMatrix
231              
232             Generates a confusion matrix between two vectors VECTOR1 and VECTOR2
233             VECTOR1 being an "expected" map between keys and values
234             VECTOR2 being an "observed" map between keys and values
235              
236             =cut
237              
238             sub generateConfusionMatrix
239             {
240 0     0 1   my %h = (
241             VECTOR1 => undef,
242             VECTOR2 => undef,
243             ( parseArgs \@_, 'VECTOR1=s%', 'VECTOR2=s%'),
244             );
245              
246 0           my %r;
247 0           my $V1 = $h{VECTOR1};
248 0           my $V2 = $h{VECTOR2}; #Two Hash references
249 0           my $numPoints = 0;
250 0           my $numMatches = 0;
251              
252 0           my $V2Copy = {};
253 0           foreach my $v1Key (keys %$V1) {
254 0 0 0       $V2Copy->{$v1Key} = $V2->{$v1Key} if defined $V2->{$v1Key} and $V2->{$v1Key} ne "";
255             }
256 0           foreach my $xVal (values %$V1 ) {
257 0           foreach my $yVal (values %$V2Copy ) {
258 0           $r{$xVal}{$yVal} = 0;
259             }
260             }
261 0           foreach my $v1Key (keys %$V1 ) {
262 0 0         if (exists $V2Copy->{$v1Key}) {
263 0           my $xVal = $V1->{$v1Key};
264 0           my $yVal = $V2Copy->{$v1Key};
265 0           ++$numPoints;
266 0           ++$r{$xVal}{$yVal};
267             }
268             }
269 0           return %r;
270             }
271              
272             =head2 calculateWeightedKappaOnConfusionMatrix
273              
274             Given a confusion matrix and a weight matrix, generates a Kappa result
275              
276             =cut
277              
278             sub calculateWeightedKappaOnConfusionMatrix
279             {
280 0     0 1   my %h = (
281             CONFUSION_MATRIX => undef,
282             WEIGHT_MATRIX => undef,
283             ( parseArgs \@_, 'CONFUSION_MATRIX=s%', 'WEIGHT_MATRIX=s%'),
284             );
285 0           my $CM = $h{CONFUSION_MATRIX};
286 0           my $WT = $h{WEIGHT_MATRIX}; #Two Hash references
287              
288 0           my %rowSums;
289 0           foreach my $rowKey (keys %{$CM}) #rows
  0            
290             {
291 0 0         $rowSums{$rowKey} = 0 unless defined $rowSums{$rowKey};
292 0           $rowSums{$rowKey} += $_ foreach (values %{$CM->{$rowKey}});
  0            
293             }
294 0           my @rowKeys = keys %{$CM};
  0            
295 0           my %colSums;
296             my @colKeysList;
297 0           push @colKeysList, keys %{$CM->{$_}} foreach (@rowKeys);
  0            
298 0           my %colKeys = map {$_ => 1} @colKeysList;
  0            
299 0           foreach my $colKey (keys %colKeys) #cols
300             {
301 0 0         $colSums{$colKey} = 0 unless defined $colSums{$colKey};
302 0 0         $colSums{$colKey} += (defined $CM->{$_}{$colKey}) ? $CM->{$_}{$colKey} : 0 foreach (keys %{$CM});
  0            
303             }
304 0           my $numObs = 0;
305 0           $numObs += $_ foreach (values %rowSums);
306 0           my %ObsRandomChance;
307 0           foreach my $rowKey (@rowKeys)
308             {
309 0           foreach my $colKey (keys %colKeys)
310             {
311 0 0         $ObsRandomChance{$rowKey}{$colKey} = 0 unless defined $ObsRandomChance{$rowKey}{$colKey};
312 0           $ObsRandomChance{$rowKey}{$colKey} = $rowSums{$rowKey} * $colSums{$colKey} / $numObs;
313             }
314             }
315 0           my $CMDiagonalSum = 0;
316 0           my $ChanceDiagonalSum = 0;
317 0 0         $CMDiagonalSum += defined $CM->{$_}{$_} ? $CM->{$_}{$_} : 0 foreach (keys %{$CM});
  0            
318 0 0         $ChanceDiagonalSum += defined $ObsRandomChance{$_}{$_} ? $ObsRandomChance{$_}{$_} : 0 foreach (keys %ObsRandomChance);
319 0           my $deltaCorrect = $CMDiagonalSum - $ChanceDiagonalSum;
320 0 0         my $kappa = $deltaCorrect / ($numObs - $ChanceDiagonalSum) unless $numObs - $ChanceDiagonalSum == 0;
321 0 0         $kappa = 1 if $numObs - $ChanceDiagonalSum == 0;
322 0           my %weightedCM;
323             my %weightedObsRandomChance;
324 0           foreach my $rowKey (@rowKeys)
325             {
326 0           foreach my $colKey (keys %colKeys)
327             {
328 0           $weightedCM{$rowKey}{$colKey} = $WT->{$rowKey}{$colKey} * $CM->{$rowKey}{$colKey};
329 0           $weightedObsRandomChance{$rowKey}{$colKey} = $WT->{$rowKey}{$colKey} * $ObsRandomChance{$rowKey}{$colKey};
330             }
331             }
332 0           my $WtCMSum = 0;
333 0           my $WtChanceSum = 0;
334 0           $WtCMSum += sum 0, values %{$_} foreach (values %weightedCM);
  0            
335 0           $WtChanceSum += sum 0, values %{$_} foreach (values %weightedObsRandomChance);
  0            
336 0 0         my $WtKappa = 1 - $WtCMSum / $WtChanceSum unless $WtCMSum == 0;
337 0 0         $WtKappa = 1 if $WtCMSum == 0;
338 0           return {KAPPA => $kappa, WEIGHTED_KAPPA => $WtKappa, DELTA_CORRECT => $deltaCorrect};
339             }
340              
341             =head2 correlateTwoHashes
342              
343             Given two vectors, calculates the common correlation between them
344              
345             =cut
346              
347             sub correlateTwoHashes
348             {
349 0     0 1   my %h = (
350             VECTOR1 => undef,
351             VECTOR2 => undef,
352             ( parseArgs \@_, 'VECTOR1=s%', 'VECTOR2=s%'),
353             );
354              
355 0           my $V1 = $h{VECTOR1};
356 0           my $V2 = $h{VECTOR2}; #Two Hash references
357 0           my $numPoints = 0;
358 0           my $XiYi = 0;
359 0           my $Xi = 0;
360 0           my $Yi = 0;
361 0           my $Xi2 = 0;
362 0           my $Yi2 = 0;
363 0           foreach my $key ( sort keys %$V1 ) {
364 0           my $val = $V1->{$key};
365 0           my $val2 = $V2->{$key};
366             }
367 0           foreach my $key2 ( sort keys %$V1 ) {
368 0 0         if (exists $V2->{$key2}) {
369 0           my $XBD = $V1->{$key2};
370 0           my $YBD = $V2->{$key2};
371 0           ++$numPoints;
372 0           $XiYi += $XBD * $YBD;
373 0           $Xi += $XBD;
374 0           $Yi += $YBD;
375 0           $Xi2 += $XBD * $XBD;
376 0           $Yi2 += $YBD * $YBD;
377             }
378             }
379 0           my $Corr = 0;
380 0 0         if ((sqrt($numPoints * $Xi2 - $Xi * $Xi)*sqrt($numPoints * $Yi2 - $Yi * $Yi)) ne 0) {
381 0           $Corr = $numPoints * $XiYi - $Xi * $Yi;
382 0           $Corr = $Corr / (sqrt($numPoints * $Xi2 - $Xi * $Xi)*sqrt($numPoints * $Yi2 - $Yi * $Yi));
383             }
384 0           return $Corr;
385             }
386              
387             =head2 linearRegression
388              
389              
390             Performs a linear regression of a CDF in Y (in a COUNT and TOTAL_Y hash)
391             against an X_HASH
392              
393             =cut
394              
395             sub linearRegression
396             {
397 0     0 1   my %h = (
398             COUNT => undef,
399             TOTAL_Y => undef,
400             X_HASH => undef,
401             ( parseArgs \@_, 'COUNT=s%', 'TOTAL_Y=s%', 'X_HASH=s%'),
402             );
403              
404 0           my $Count = $h{COUNT}; #hash reference
405 0           my $TotalY = $h{TOTAL_Y}; #hash reference
406 0           my $XHash = $h{X_HASH}; #hash reference
407 0           my $X2 = 0;
408 0           my $XY = 0;
409 0           my $SX = 0;
410 0           my $SY = 0;
411 0           my $N = scalar (keys %$XHash);
412 0           while (my ($key, $X) = each %$XHash)
413             {
414 0           my $N = $Count->{$key};
415 0           my $Y = $TotalY->{$key}/$N;
416              
417 0           $XY += $X * $Y;
418 0           $X2 += $X * $X;
419 0           $SX += $X;
420 0           $SY += $Y;
421             }
422 0           my $slope = ($XY - ($SX * $SY)/$N) / ($X2 - ($SX * $SX)/$N);
423 0           return $slope;
424             }
425              
426             =head2 makeError
427              
428             Generates an XML boost unit test V1.4.5 Error Node
429              
430             =cut
431              
432             sub makeError
433             {
434 0     0 1   my %h = (
435             ERROR => undef,
436             FILE => "None",
437             LINE => "1",
438             ( parseArgs \@_, 'ERROR=s', 'FILE=s', 'LINE=i'),
439             );
440             return
441 0           "" . makeCDATA($h{ERROR}) . "\n";
442             }
443              
444             =head2 makeInfo
445              
446             Generates an XML boost unit test V1.4.5 Info Node
447              
448             =cut
449              
450             sub makeInfo
451             {
452 0     0 1   my %h = (
453             INFO => undef,
454             FILE => "None",
455             LINE => "1",
456             ( parseArgs \@_, 'INFO=s', 'FILE=s', 'LINE=i'),
457             );
458 0           return "" . makeCDATA($h{INFO}) . "\n";
459              
460             }
461              
462             =head2 makeCDATA
463              
464             Generates an XML CDATA Node
465              
466             =cut
467              
468             sub makeCDATA
469             {
470 0     0 1   return join('',"\n");
471             }
472              
473             =head2 makeComment
474              
475             Generates an XML Comment Node
476              
477             =cut
478              
479             sub makeComment
480             {
481 0     0 1   return join('',"\n");
482             }
483              
484             =head2 makeOpenTestCase
485              
486             Generates an XML boost unit test V1.4.5 Test Case open tag
487              
488             =cut
489              
490             sub makeOpenTestCase
491             {
492 0     0 1   my %h = (
493             NAME => undef,
494             ( parseArgs \@_, 'NAME=s'),
495             );
496 0           return "\n";
497             }
498              
499             =head2 makeCloseTestCase
500              
501             Generates an XML boost unit test V1.4.5 Test Case close tag
502              
503             =cut
504              
505             sub makeCloseTestCase
506             {
507 0     0 1   my %h = (
508             TIME => '0',
509             ( parseArgs \@_, 'TIME=s'),
510             );
511 0           return "$h{TIME}\n\n";
512             }
513              
514             =head2 makeOpenTestSuite
515              
516             Generates an XML boost unit test V1.4.5 Test Suite Open tag
517              
518             =cut
519              
520             sub makeOpenTestSuite
521             {
522 0     0 1   my %h = (
523             NAME => undef,
524             ( parseArgs \@_, 'NAME=s'),
525             );
526 0           return "\n";
527             }
528              
529             =head2 makeCloseTestSuite
530              
531             Generates an XML boost unit test V1.4.5 Test Suite Close tag
532              
533             =cut
534              
535             sub makeCloseTestSuite
536             {
537 0     0 1   return "\n";
538             }
539              
540             =head2 makeOpenTestLog
541              
542             Generates an XML boost unit test V1.4.5 Test log open tag
543              
544             =cut
545              
546             sub makeOpenTestLog
547             {
548 0     0 1   return "\n";
549             }
550              
551             =head2 makeCloseTestLog
552              
553             Generates an XML boost unit test V1.4.5 Test log close tag
554              
555             =cut
556              
557             sub makeCloseTestLog
558             {
559 0     0 1   return "\n";
560             }
561              
562             =head2 compareTwoLists
563              
564             Compares Two Lists with some COMPARE_CODE
565              
566             Default compares for equality ignoring whitespace
567              
568             =cut
569              
570             sub compareTwoLists
571             {
572             my %h = (
573             FIRST => undef,
574             SECOND => undef,
575             COMPARE_CODE => sub {
576 0     0     s/^\s*// foreach (@{$_[0]},@{$_[1]});
  0            
  0            
577 0           s/\s*$// foreach (@{$_[0]},@{$_[1]});
  0            
  0            
578 0           return join('A',@{$_[0]}) eq join('A',@{$_[1]});
  0            
  0            
579             },
580 0     0 1   %{$_[0]},
  0            
581             );
582 0           return $h{COMPARE_CODE}->( $h{FIRST}, $h{SECOND} );
583             }
584              
585              
586             =head2 compareTwoDirecoryTrees
587              
588             Compares the contents of two directory trees file by file
589              
590             =cut
591              
592             sub compareTwoDirecoryTrees
593             {
594             my %h = (
595             FIRST => undef,
596             SECOND => undef,
597             FIRST_FILE_REGEX => '.*',
598             FIRST_PRUNE_REGEX => '$NeverMatch^',
599             SECOND_FILE_REGEX => '.*',
600             SECOND_PRUNE_REGEX => '$NeverMatch^',
601             COMPARE_CODE => sub {
602 0     0     return join('A',@{$_[0]}) eq join('A',@{$_[1]});
  0            
  0            
603             },
604 0     0 1   %{$_[0]},
  0            
605             );
606 0           my %firstMD5Hash;
607             my %secondMD5Hash;
608             find(sub {
609 0 0   0     ($File::Find::Prune = 1 , return) if m/$h{FIRST_PRUNE_REGEX}/;
610 0 0 0       if (m/$h{FIRST_FILE_REGEX}/ and -f)
611             {
612 0           open(FILE, $_);
613 0           binmode(FILE);
614 0           my $hash = Digest::MD5->new->addfile(*FILE)->hexdigest;
615 0           $firstMD5Hash{File::Spec->abs2rel( $File::Find::name, $h{FIRST} )} = $hash;
616 0           close(FILE);
617             }
618 0           }, $h{FIRST});
619             find(sub {
620 0 0   0     ($File::Find::Prune = 1 , return) if m/$h{SECOND_PRUNE_REGEX}/;
621 0 0 0       if (m/$h{SECOND_FILE_REGEX}/ and -f)
622             {
623 0           open(FILE, $_);
624 0           binmode(FILE);
625 0           my $hash = Digest::MD5->new->addfile(*FILE)->hexdigest;
626 0           $secondMD5Hash{File::Spec->abs2rel( $File::Find::name, $h{SECOND} )} = $hash;
627 0           close(FILE);
628             }
629 0           }, $h{SECOND});
630 0           my %firstNotInSecond;
631             my %secondNotInFirst;
632 0           foreach (keys %firstMD5Hash)
633             {
634 0 0 0       next if exists $secondMD5Hash{$_} and ( $secondMD5Hash{$_} eq $firstMD5Hash{$_});
635 0           $firstNotInSecond{$_} = $firstMD5Hash{$_};
636             }
637 0           foreach (keys %secondMD5Hash)
638             {
639 0 0 0       next if exists $firstMD5Hash{$_} and ( $secondMD5Hash{$_} eq $firstMD5Hash{$_});
640 0           $secondNotInFirst{$_} = $secondMD5Hash{$_};
641             }
642            
643 0           return (\%firstNotInSecond, \%secondNotInFirst);
644             }
645              
646             =head2 makeCheck
647              
648             Checks a test condition and generates either
649             an XML boost unit test V1.4.5 Info Node
650             Or
651             an XML boost unit test V1.4.5 Error Node
652             =cut
653              
654             sub makeCheck
655             {
656 0     0     my %h = (
657             FIRST => undef,
658             SECOND => undef,
659             OK => q/Condition satisfied /,
660             NOT_OK => q/Condition not satisfied /,
661             COMPARE_CODE => sub {return ($_[0] eq $_[1]);},
662 0     0 1   %{$_[0]},
  0            
663             );
664 0 0         return makeInfo "$h{OK}" if ( $h{COMPARE_CODE}->( $h{FIRST}, $h{SECOND} ) );
665 0 0         return makeError "$h{NOT_OK}" unless( $h{COMPARE_CODE}->( $h{FIRST}, $h{SECOND} ) );
666             }
667              
668              
669             =head2 formatList
670              
671             private helper function for printing lists
672              
673             =cut
674             sub formatList
675             {
676 0     0 1   return "(" . join (", ",@_) . ")";
677             }
678              
679             =head2 makeCheckEqual
680              
681             Checks two lists for equality and generates either
682             an XML boost unit test V1.4.5 Info Node
683             Or
684             an XML boost unit test V1.4.5 Error Node
685              
686             =cut
687             sub makeCheckEqual
688             {
689 0     0 1   my %h = (
690             FIRST => undef,
691             SECOND => undef,
692             OK => q/Condition satisfied /,
693             NOT_OK => q/Condition not satisfied /,
694             ( parseArgs \@_, 'FIRST=s@', 'SECOND=s@', 'OK=s','NOT_OK=s',),
695             );
696 0 0         return makeInfo "$h{OK}\n" . formatList( @{$h{FIRST}}) . "\nEquals\n" . formatList( @{$h{SECOND}}) if ( compareTwoLists { FIRST => $h{FIRST}, SECOND => $h{SECOND} });
  0            
  0            
697 0 0         return makeError "$h{NOT_OK}\n" . formatList( @{$h{FIRST}}) . "\nNot Equal\n" . formatList( @{$h{SECOND}}) unless( compareTwoLists { FIRST => $h{FIRST}, SECOND => $h{SECOND} });
  0            
  0            
698             }
699              
700              
701              
702              
703 1     1   261 END { } # module clean-up code here (global destructor)
704              
705              
706             =head1 AUTHOR
707              
708             Robert Haxton, C<< >>
709              
710             =head1 BUGS
711              
712             Please report any bugs or feature requests to C, or through
713             the web interface at L. I will be notified, and then you'll
714             automatically be notified of progress on your bug as I make changes.
715              
716              
717              
718              
719             =head1 SUPPORT
720              
721             You can find documentation for this module with the perldoc command.
722              
723             perldoc Test::BoostUnit
724              
725              
726             You can also look for information at:
727              
728             =over 4
729              
730             =item * RT: CPAN's request tracker (report bugs here)
731              
732             L
733              
734             =item * AnnoCPAN: Annotated CPAN documentation
735              
736             L
737              
738             =item * CPAN Ratings
739              
740             L
741              
742             =item * Search CPAN
743              
744             L
745              
746             =back
747              
748              
749             =head1 ACKNOWLEDGEMENTS
750              
751              
752             =head1 LICENSE AND COPYRIGHT
753              
754             Copyright 2011 Robert Haxton.
755              
756             This program is free software; you can redistribute it and/or modify it
757             under the terms of either: the GNU General Public License as published
758             by the Free Software Foundation; or the Artistic License.
759              
760             See http://dev.perl.org/licenses/ for more information.
761              
762              
763             =cut
764              
765             1; # End of TestTools::BoostUnitTest