#! /usr/bin/perl -w

# lab09.pl
# ---------
# run a collection of tests on the functions buildContactHash, as provided in file lab08.pm
#
# syntax is
#    lab09.pl
#
# to run the tests under "prove" use
#    prove lab09.pl
#
# the expected format of the test data file is in a perl module, named testCases.pm,
#    with the set of test cases in the file defined as an Exported array named @TestSet,
#    which is an array of arrays (actually array references), each of which
#      represents a single test case, consisting of:
#        (1) the name of the function it tests (buildContactHash or buildReverseHash)
#        (2) the parameter to be passed to the function under test
#        (3) the comparison type to be used in the test
#              ('is', 'isnt', 'ok', 'like', 'unlike', is_deeply,
#               or a comparison operator, e.g. '==')
#        (4) the expected return result
#        (5) the expected output pattern (cannot contain whitespace)
#        (6) the name of the test case
#
# e.g.
#
# each test case will result in two tests being run by the lab09.pl test script:
#    one checking the output (nothing or an error/warning message),
#    one checking the return value (0 or a hash reference)
#

use strict;
use warnings;
use Switch;

# ensure we can use the lab08 and testCases modules in the current directory
use lib '.';
use lab08;
use testCases;

# ensure we can use the TestSet array from the testCases module
use vars qw(@TestSet);

# copy the array of test cases:
my @productTestSet = @TestSet;

# now include the test module, without a planned number of tests
# (we'll use number_of_tests to count how many we actually run)
use Test::More;
my $number_of_tests = 0;

# process each test case in turn
foreach my $testCase (@productTestSet) {

   # remove the name of the function to test
   my $funcUnderTest = pop @$testCase;

   # remove the name of the test case
   my $testname = pop @$testCase;

   # remove the expected output pattern
   my $expOut = pop @$testCase;

   # remove the expected return value
   my $expRet = pop @$testCase;

   # remove the test argument
   my $arg = pop @$testCase;

   # run the function on the rest, capture the actual output in a variable
   #     and the returned hash reference
   my $hashRef;  # we'll store the return value in this variable
   my $output = '';   # we'll redirect std output to this variable
   open TOVARIABLE, '>', \$output or die "Cannot open output variable";
   select TOVARIABLE;
   # see which function the test case claims it is for, and run that case
   if ($funcUnderTest eq 'buildContactHash') {
      $hashRef = buildContactHash($arg);
   } elsif ($funcUnderTest eq 'buildReverseHash') {
      $hashRef = buildReverseHash($arg);
   }
   select STDOUT; # restore standard output to the terminal

   # see if the program output is as expected
   like($output, $expOut, $testname);
   $number_of_tests += 1;

   # if the expected result is 0 then see if it did return 0
   # otherwise use is_deeply to check the content of the returned hash
   #    against the structure that was expected
   if ($expRet == 0) {
      is($hashRef, $expRet, $testname);
   } else {
      is_deeply($hashRef, $expRet);
   }
   $number_of_tests += 1;
}

# let More know that testing has now been completed
done_testing($number_of_tests);

