// sarray_test.cpp
// Glenn G. Chappell
// 9 Feb 2008
//
// For CS 311 Spring 2008
// Test program for class SArray
// Used in Assignment 2, Exercise A

// Includes for code to be tested
#include "sarray.h"     // For class SArray
#include "sarray.h"     // Double inclusion test

// Includes for testing package
#include <iostream>     // for std::cout, std::endl
#include <string>       // for std::string
#include <stdexcept>    // for std::runtime_error

// Includes for this test program
#include <cstdlib>      // for std::size_t, std::ptrdiff_t


// ************************************************************************
// Testing Package:
//     Class Tester - For Tracking Tests
// ************************************************************************


// class Tester
// For extremely simple unit testing.
// Keeps track of number of tests and number of passes.
// Use test (with success/failure parameter) to do a test.
// Get results with numTests, numPassed, numFailed, allPassed.
// Restart testing with reset.
// Invariants:
//     countTests_ == number of tests (calls to test) since last reset.
//     countPasses_ == number of times function test called with true param
//      since last reset.
//     0 <= countPasses_ <= countTests_.
//     tolerance_ >= 0.
class Tester {

// ***** Tester: ctors, dctor, op= *****
public:

    // Default ctor
    // Sets countTests_, countPasses_ to zero, tolerance_ to given value
    // Pre: None.
    // Post:
    //     numTests == 0, countPasses == 0, tolerance_ == abs(theTolerance)
    // Does not throw (No-Throw Guarantee)
    Tester(double theTolerance = 0.0000001)
        :countTests_(0),
         countPasses_(0),
         tolerance_(theTolerance >= 0 ? theTolerance : -theTolerance)
    {}

    // Compiler-generated copy ctor, copy op=, dctor are used

// ***** Tester: general public functions *****
public:

    // test
    // Handles single test, param indicates pass/fail
    // Pre: None.
    // Post:
    //     countTests_ incremented
    //     countPasses_ incremented if (success)
    //     Message indicating test name (if given)
    //      and pass/fail printed to cout
    // Does not throw (No-Throw Guarantee)
    //  - Assuming exceptions have not been turned on for cout.
    void test(bool success,
              const std::string & testName = "")
    {
        ++countTests_;
        if (success) ++countPasses_;

        std::cout << "    ";
        if (testName != "")
        {
            std::cout << "Test: "
                      << testName
                      << " - ";
        }
        std::cout << (success ? "passed" : "********** FAILED **********")
                  << std::endl;
    }

    // ftest
    // Does single floating-point test.
    // Tests passes iff difference of first two values is <= tolerance.
    // Pre: None.
    // Post:
    //     countTests_ incremented
    //     countPasses_ incremented if (abs(val1-val2) <= tolerance_)
    //     Message indicating test name (if given)
    //      and pass/fail printed to cout
    // Does not throw (No-Throw Guarantee)
    void ftest(double val1,
               double val2,
               const std::string & testName = "")
    { test(val1-val2 <= tolerance_ && val2-val1 <= tolerance_, testName); }

    // reset
    // Resets *this to default constructed state
    // Pre: None.
    // Post:
    //     countTests_ == 0, countPasses_ == 0
    // Does not throw (No-Throw Guarantee)
    void reset()
    {
        countTests_ = 0;
        countPasses_ = 0;
    }

    // numTests
    // Returns the number of tests that have been done since last reset 
    // Pre: None.
    // Post:
    //     return == countTests_
    // Does not throw (No-Throw Guarantee)
    int numTests() const
    { return countTests_; }

    // numPassed
    // Returns the number of tests that have passed since last reset
    // Pre: None.
    // Post:
    //     return == countPasses_
    // Does not throw (No-Throw Guarantee)
    int numPassed() const
    { return countPasses_; }

    // numFailed
    // Returns the number of tests that have not passed since last reset
    // Pre: None.
    // Post:
    //     return + countPasses_ == numTests_
    // Does not throw (No-Throw Guarantee)
    int numFailed() const
    { return countTests_ - countPasses_; }

    // allPassed
    // Returns true if all tests since last reset have passed
    // Pre: None.
    // Post:
    //     return == (countPasses_ == countTests_)
    // Does not throw (No-Throw Guarantee)
    bool allPassed() const
    { return countPasses_ == countTests_; }

    // setTolerance
    // Sets tolerance_ to given value
    // Pre: None.
    // Post:
    //     tolerance_ = abs(theTolerance)
    // Does not throw (No-Throw Guarantee)
    void setTolerance(double theTolerance)
    { tolerance_ = (theTolerance >= 0 ? theTolerance : -theTolerance); }

// ***** Tester: data members *****
private:

    int countTests_;    // Number of tests done since last reset
    int countPasses_;   // Number of tests passed since last reset
    double tolerance_;  // Tolerance for floating-point near-equality tests

};  // end class Tester


// ************************************************************************
// Testing Package:
//     Class TypeCheck - Helper Class for Type Checking
// ************************************************************************


// class TypeCheck
// This class exists in order to have static member function check, which
// takes a parameter of a given type, by reference. Objects of type
// TypeCheck<T> cannot be created.
// Usage:
//     TypeCheck<MyType>::check(x)
//     returns true if the type of x is (MyType) or (const MyType),
//     otherwise false.
// Invariants: None.
// Requirements on Types: None.
template<typename T>
class TypeCheck {

private:

    // Uncopyable class. Do not define copy ctor, copy assn.
    TypeCheck(const TypeCheck &);
    TypeCheck<T> & operator=(const TypeCheck &);

    // Compiler-generated dctor is used (but irrelevant).

public:

    // check
    // The function and function template below simulate a single function
    // that takes a single parameter, and returns true iff the parameter has
    // type T or (const T).

    // check (reference-to-const T)
    // Pre: None.
    // Post:
    //     Return is true.
    // Does not throw (No-Throw Guarantee)
    static bool check(const T & param)
    { return true; }

    // check (reference-to-const non-T)
    // Pre: None.
    // Post:
    //     Return is false.
    // Requirements on types: None.
    // Does not throw (No-Throw Guarantee)
    template <typename OtherType>
    static bool check(const OtherType & param)
    { return false; }

};  // End class TypeCheck


// ************************************************************************
// Testing Package:
//     Class Counter - Helper Class for Counting Calls & Objects, Throwing
// ************************************************************************


// class Counter
// Item type for counting ctor, dctor, op= calls, counting existing
//  objects, and possibly throwing on copy.
// If static member copyThrow_ is set, then copy ctor and copy assn throw
//  std::runtime_error. Increments static data member ctorCount_ on default
//  construction and successful copy construction. Increments static data
//  member assnCount_ on successful copy assignment. Increments static
//  data member dctorCount_ on destruction. Increments static data member
//  existing_ on construction, and decrements it on destruction.
// Invariants:
//     Counter::existing_ is number of existing objects of this class.
//     Counter::ctorCount_ is number of successful ctor calls since
//      most recent call to reset, or start of program if reset has never
//      been called.
//     Counter::dctorCount_ is (similarly) number of dctor calls.
//     Counter::assnCount_ is (similarly) number of copy assn calls.
class Counter {

// ***** Counter: Ctors, dctor, op= *****
public:

    // Default ctor
    // Pre: None.
    // Post:
    //     (ctorCount_ has been incremented.)
    //     (existing_ has been incremented.)
    Counter()
    { ++existing_; ++ctorCount_; }

    // Copy ctor
    // Pre: None.
    // Post:
    //     (ctorCount_ has been incremented.)
    //     (existing_ has been incremented.)
    Counter(const Counter & other)
    {
        if (copyThrow_)
            throw std::runtime_error("C");
        ++existing_;
        ++ctorCount_;
    }

    // Copy assignment
    // Pre: None.
    // Post:
    //     Return value is *this.
    //     (assnCount_ has been incremented.)
    Counter & operator=(const Counter & rhs)
    {
        if (copyThrow_)
            throw std::runtime_error("A");
        ++assnCount_;
        return *this;
    }

    // Dctor
    // Pre: None.
    // Post:
    //     (dctorCount_ has been incremented.)
    //     (existing_ has been decremented.)
    ~Counter()
    { --existing_; ++dctorCount_; }

// ***** Counter: Functions dealing with count *****
public:

    // resetCount
    // Pre: None.
    // Post:
    //     ctorCount_ == 0.
    //     dctorCount_ == 0.
    //     assnCount_ == 0.
    //     copyThrow_ == shouldThrow.
    static void reset(bool shouldThrow = false)
    {
        ctorCount_ = 0;
        dctorCount_ = 0;
        assnCount_ = 0;
        copyThrow_ = shouldThrow;
    }

    // getExisting
    // Pre: None.
    // Post:
    //     return == existing_.
    static int getExisting()
    { return existing_; }

    // getCtorCount
    // Pre: None.
    // Post:
    //     return == ctorCount_.
    static int getCtorCount()
    { return ctorCount_; }

    // getDctorCount
    // Pre: None.
    // Post:
    //     return == dctorCount_.
    static int getDctorCount()
    { return dctorCount_; }

    // getAssnCount
    // Pre: None.
    // Post:
    //     return == assnCount_.
    static int getAssnCount()
    { return assnCount_; }

    // setCopyThrow
    // Pre: None.
    // Post:
    //     copyThrow_ == shouldThrow
    static void setCopyThrow(bool shouldThrow)
    { copyThrow_ = shouldThrow; }

// ***** Counter: Data Members *****
private:

    static int existing_;    // # of existing objects
    static int ctorCount_;   // # of successful (non-throwing) ctor calls
    static int dctorCount_;  // # of dctor calls
    static int assnCount_;   // # of successful (non-throwing) copy = calls
    static bool copyThrow_;  // true if copy operations (ctor, =) throw

};  // End class Counter

// Definition of static data member of class Counter
int Counter::existing_ = 0;
int Counter::ctorCount_ = 0;
int Counter::dctorCount_ = 0;
int Counter::assnCount_ = 0;
bool Counter::copyThrow_ = false;


// ************************************************************************
// Utility Functions/Classes for This Testing Program
// ************************************************************************


// (NONE)


// ************************************************************************
// Test Suite Functions
// ************************************************************************


// test_class_SArray_types
// Test suite for class SArray, types
// Pre: None.
// Post:
//     Pass/fail status of tests have been registered with t.
//     Appropriate messages have been printed to cout.
void test_class_SArray_types(Tester & t)
{
    std::cout << "Test Suite: class SArray - types" << std::endl;

    bool correctType;  // result of type checking

    // value_type test #1: int
    SArray<int>::value_type i1 = 0;
    correctType = TypeCheck<int>::check(i1);
    t.test(correctType, "value_type test #1");

    // value_type test #2: double
    SArray<double>::value_type d1 = 0.;
    correctType = TypeCheck<double>::check(d1);
    t.test(correctType, "value_type test #2");

    // value_type check modifiability (only needs to compile)
    SArray<double>::value_type d2;
    d2 = 0.;
    t.test(true, "value_type check modifiability");

    // size_type test
    SArray<Counter>::size_type s1 = 0;
    correctType = TypeCheck<std::size_t>::check(s1)
               || TypeCheck<std::ptrdiff_t>::check(s1);
    t.test(correctType, "size_type test");

    // size_type check modifiability (only needs to compile)
    SArray<Counter>::size_type s2;
    s2 = 0;
    t.test(true, "size_type check modifiability");
}


// test_class_SArray_size_empty_and_ctor_from_size
// Test suite for class SArray, function size and ctor from size
// Pre: None.
// Post:
//     Pass/fail status of tests have been registered with t.
//     Appropriate messages have been printed to cout.
void test_class_SArray_size_empty_and_ctor_from_size(Tester & t)
{
    std::cout << "Test Suite: class SArray - functions size & empty, ctor from size" << std::endl;

    bool correctType;  // result of type checking

    const SArray<int> ssai1(1);

    correctType = TypeCheck<SArray<int>::size_type>::check(ssai1.size());
    t.test(correctType, "size, return type");

    correctType = TypeCheck<bool>::check(ssai1.empty());
    t.test(correctType, "empty, return type");

    t.test(ssai1.size() == 1, "ctor from size (const) #1, check size");
    t.test(!ssai1.empty(), "ctor from size (const) #1, check empty");

    const SArray<int> ssai2(10);
    t.test(ssai2.size() == 10, "ctor from size (const) #2, check size");
    t.test(!ssai2.empty(), "ctor from size (const) #2, check empty");

    const SArray<double> ssad(100);
    t.test(ssad.size() == 100, "ctor from size (const) #3, check size");
    t.test(!ssad.empty(), "ctor from size (const) #3, check empty");

    SArray<int> ssai3(20);
    t.test(ssai3.size() == 20, "ctor from size (non-const), check size");
    t.test(!ssai3.empty(), "ctor from size (non-const), check empty");

    const SArray<int> ssai4(0);
    t.test(ssai4.size() == 0, "ctor from size (size 0), check size");
    t.test(ssai4.empty(), "ctor from size (size 0), check empty");
}


// test_class_SArray_default_ctor
// Test suite for class SArray, default ctor
// Pre: None.
// Post:
//     Pass/fail status of tests have been registered with t.
//     Appropriate have been messages printed to cout.
void test_class_SArray_default_ctor(Tester & t)
{
    std::cout << "Test Suite: class SArray - default ctor" << std::endl;

    const SArray<int> ssai1;
    t.test(ssai1.size() == 10, "default ctor, size");
    t.test(!ssai1.empty(), "default ctor, empty");
}


// test_class_SArray_bracket_op
// Test suite for class SArray, bracket operator
// Pre: None.
// Post:
//     Pass/fail status of tests have been registered with t.
//     Appropriate messages have been printed to cout.
void test_class_SArray_bracket_op(Tester & t)
{
    std::cout << "Test Suite: class SArray, bracket operator" << std::endl;

    bool correctType;  // result of type checking

    const int theSize = 10;
    bool noErrors;  // True if no errors encountered
    int i;          // Counter

    SArray<double> ssad1;
    correctType = TypeCheck<SArray<double>::value_type>::check(ssad1[1]);
    t.test(correctType, "Bracket operator (non-const), return type");

    SArray<int> ssai(theSize);
    for (i = 0; i < theSize; ++i)
        ssai[i] = 15 - i * i;

    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssai[i] != 15 - i * i)
            noErrors = false;
    }
    t.test(noErrors, "Bracket operator (non-const) #1");

    ssai[2] = 1000;
    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssai[i] != ((i == 2) ? 1000 : 15 - i * i))
            noErrors = false;
    }
    t.test(noErrors, "Bracket operator (non-const) #2");

    // Make const version, no copy
    const SArray<int> & ssaiRef = ssai;

    const SArray<double> ssad2;
    correctType = TypeCheck<SArray<double>::value_type>::check(ssad2[1]);
    t.test(correctType, "Bracket operator (const), return type");

    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssaiRef[i] != ((i == 2) ? 1000 : 15 - i * i))
            noErrors = false;
    }
    t.test(noErrors, "Bracket operator (const)");

}


// test_class_SArray_copy_ctor
// Test suite for class SArray, copy ctor
// Pre: None.
// Post:
//     Pass/fail status of tests have been registered with t.
//     Appropriate messages have been printed to cout.
void test_class_SArray_copy_ctor(Tester & t)
{
    std::cout << "Test Suite: class SArray - copy ctor" << std::endl;

    const int theSize = 10;
    bool noErrors;  // True if no errors encountered
    int i;          // Counter

    SArray<int> ssai(theSize);
    for (i = 0; i < theSize; ++i)
        ssai[i] = 15 - i * i;

    // Make const version, no copy
    const SArray<int> & ssaiRef = ssai;
    // Make copy (copy ctor)
    SArray<int> ssaiCopy(ssaiRef);

    t.test(ssaiCopy.size() == theSize, "Copy ctor - check size, copy");
    t.test(!ssaiCopy.empty(), "Copy ctor - check empty, copy");

    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssaiCopy[i] != 15 - i * i)
            noErrors = false;
    }
    t.test(noErrors, "Copy ctor - check values, copy");

    // Change original
    ssai[2] = 1000;

    // Check original
    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssai[i] != ((i == 2) ? 1000 : 15 - i * i))
            noErrors = false;
    }
    t.test(noErrors, "Copy ctor - change original, check values, original");

    // Check copy
    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssaiCopy[i] != 15 - i * i)
            noErrors = false;
    }
    t.test(noErrors, "Copy ctor - change original, check values, copy");

    // Change copy
    ssaiCopy[3] = 2000;

    // Check original
    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssai[i] != ((i == 2) ? 1000 : 15 - i * i))
            noErrors = false;
    }
    t.test(noErrors, "Copy ctor - change copy, check values, original");

    // Check copy
    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssaiCopy[i] != ((i == 3) ? 2000 : 15 - i * i))
            noErrors = false;
    }
    t.test(noErrors, "Copy ctor - change copy, check values, copy");
}


// test_class_SArray_copy_assn
// Test suite for class SArray, copy assignment
// Pre: None.
// Post:
//     Pass/fail status of tests have been registered with t.
//     Appropriate messages have been printed to cout.
void test_class_SArray_copy_assn(Tester & t)
{
    std::cout << "Test Suite: class SArray - copy assignment" << std::endl;

    const int theSize = 10;
    bool noErrors;  // True if no errors encountered
    int i;          // Counter

    SArray<int> ssai(theSize);
    for (i = 0; i < theSize; ++i)
        ssai[i] = 15 - i * i;

    // Make const version, no copy
    const SArray<int> & ssaiRef = ssai;
    // Make copy (copy ctor)
    SArray<int> ssaiCopy(1);
    ssaiCopy = ssaiRef;

    t.test(ssaiCopy.size() == theSize, "Copy assn - check size, copy");
    t.test(!ssaiCopy.empty(), "Copy assn - check empty, copy");

    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssaiCopy[i] != 15 - i * i)
            noErrors = false;
    }
    t.test(noErrors, "Copy assn - check values, copy");

    // Change original
    ssai[2] = 1000;

    // Check original
    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssai[i] != ((i == 2) ? 1000 : 15 - i * i))
            noErrors = false;
    }
    t.test(noErrors, "Copy assn - change original, check values, original");

    // Check copy
    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssaiCopy[i] != 15 - i * i)
            noErrors = false;
    }
    t.test(noErrors, "Copy assn - change original, check values, copy");

    // Change copy
    ssaiCopy[3] = 2000;

    // Check original
    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssai[i] != ((i == 2) ? 1000 : 15 - i * i))
            noErrors = false;
    }
    t.test(noErrors, "Copy assn - change copy, check values, original");

    // Check copy
    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssaiCopy[i] != ((i == 3) ? 2000 : 15 - i * i))
            noErrors = false;
    }
    t.test(noErrors, "Copy assn - change copy, check values, copy");

    // Check self-assignment
    ssaiCopy = ssaiCopy;

    noErrors = true;
    for (i = 0; i < theSize; ++i)
    {
        if (ssaiCopy[i] != ((i == 3) ? 2000 : 15 - i * i))
            noErrors = false;
    }
    t.test(noErrors, "Copy assn - values after self-assignment");
}


// test_class_SArray_begin_end
// Test suite for class SArray, functions begin & end
// Pre: None.
// Post:
//     Pass/fail status of tests have been registered with t.
//     Appropriate messages have been printed to cout.
void test_class_SArray_begin_end(Tester & t)
{
    std::cout << "Test Suite: class SArray - functions begin & end" << std::endl;

    bool correctType;  // result of type checking

    const int theSize = 10;
    bool noErrors;      // True if no errors encountered
    int i;              // Counter
    int * iter;         // iterator
    const int * citer;  // const_iterator

    SArray<int> ssai(theSize);
    for (iter = ssai.begin(), i = 0; iter != ssai.end(); ++iter, ++i)
        *iter = 15 - i * i;

    // Non-const test
    SArray<double> ssad1;

    correctType = TypeCheck<SArray<double>::value_type *>::check(ssad1.begin());
    t.test(correctType, "begin (non-const), return type");
    
    correctType = TypeCheck<SArray<double>::value_type *>::check(ssad1.end());
    t.test(correctType, "end (non-const), return type");

    t.test(ssai.begin() != ssai.end(), "begin/end - inequality (non-const)");
    t.test (ssai.end() - ssai.begin() == theSize, "begin/end - check difference (non-const)");
    noErrors = true;
    for (iter = ssai.begin(), i = 0; iter != ssai.end(); ++iter, ++i)
    {
        if (*iter != 15 - i * i)
            noErrors = false;
    }
    t.test(noErrors, "begin/end - check values (non-const)");

    // Make const version, no copy
    const SArray<int> & ssaiRef = ssai;

    // Const test
    const SArray<double> ssad2;

    correctType = TypeCheck<const SArray<double>::value_type *>::check(ssad2.begin());
    t.test(correctType, "begin (const), return type");
    
    correctType = TypeCheck<const SArray<double>::value_type *>::check(ssad2.end());
    t.test(correctType, "end (const), return type");
    
    t.test(ssaiRef.end() - ssaiRef.begin() == theSize, "begin/end - check difference (const)");
    noErrors = true;
    for (citer = ssaiRef.begin(), i = 0; citer != ssaiRef.end(); ++citer, ++i)
    {
        if (*citer != 15 - i * i)
            noErrors = false;
    }
    t.test(noErrors, "begin/end - check values (const)");
}


// test_class_SArray_comparisons
// Test suite for class SArray, comparisons
// Pre: None.
// Post:
//     Pass/fail status of tests have been registered with t.
//     Appropriate messages have been printed to cout.
void test_class_SArray_comparisons(Tester & t)
{
    std::cout << "Test Suite: class SArray - comparisons" << std::endl;

    bool correctType;  // result of type checking

    const int theSize = 10;
    int i;          // Counter

    SArray<int> ssai1(theSize);
    for (i = 0; i < theSize; ++i)
        ssai1[i] = 15 - i * i;
    const SArray<int> & ssai1Ref = ssai1;
    SArray<int> ssai1Copy(ssai1Ref);
    SArray<int> ssai2(theSize-1);
    for (i = 0; i < theSize-1; ++i)
        ssai2[i] = 15 - i * i;
    const SArray<int> & ssai2Ref = ssai2;
    
    // operator== return type
    correctType = TypeCheck<bool>::check(ssai1 == ssai1Copy);
    t.test(correctType, "operator==, return type");

    // operator!= return type
    correctType = TypeCheck<bool>::check(ssai1 != ssai1Copy);
    t.test(correctType, "operator!=, return type");

    // Check equality of copies
    t.test(ssai1 == ssai1Copy, "Equality of copies");

    // Check inequality of copies
    t.test(!(ssai1 != ssai1Copy), "Inequality of copies");

    // Check equality of different sizes #1 (compilation checks constness of op==)
    t.test(!(ssai1Ref == ssai2Ref), "Equality of different sizes #1");

    // Check inequality of different sizes #1 (compilation checks constness of op!=)
    t.test(ssai1Ref != ssai2Ref, "Inequality of different sizes #1");

    // Check equality of different sizes #2
    t.test(!(ssai2Ref == ssai1Ref), "Equality of different sizes #2");

    // Check inequality of different sizes #2
    t.test(ssai2Ref != ssai1Ref, "Inequality of different sizes #2");

    // Modify copy
    ++ssai1Copy[theSize-1];

    // Check equality of modification of copy
    t.test(!(ssai1 == ssai1Copy), "Equality of modification of copy");

    // Check inequality of modification of copy
    t.test(ssai1 != ssai1Copy, "Inequality of modification of copy");
}


// test_class_SArray_ctor_dctor_count
// Test suite for class SArray, number of class to item type
//  ctor, dctor.
// Pre: None.
// Post:
//     Pass/fail status of tests have been registered with t.
//     Appropriate messages have been printed to cout.
void test_class_SArray_ctor_dctor_count(Tester & t)
{
    std::cout << "Test Suite: class SArray - ctor, dctor count" << std::endl;

    // Check number of value type ctor/dctor calls on array creation & destruction
    Counter::reset();
    { // Block, so we get dctor calls before function ends
        const SArray<Counter> ssacc(10);

        t.test(Counter::getCtorCount() == 10, "Counting default ctor calls due to array creation");

        Counter::reset();
    }
    t.test(Counter::getDctorCount() == 10, "Counting dctor calls due to destruction");

    // Check correct number of value type ctor & dctor calls on self-assignment
    SArray<Counter> ssacc2(10);
    Counter::reset();
    ssacc2 = ssacc2;
    int i1 = Counter::getCtorCount() + Counter::getDctorCount() + Counter::getAssnCount();
    t.test(i1 == 0 || i1 == 20, "Self-assignment ctor/dctor calls");
}


// test_class_SArray
// Test suite for class SArray
// Uses other test-suite functions
// Pre: None.
// Post:
//     Pass/fail status of tests have been registered with t.
//     Appropriate messages have been printed to cout.
void test_class_SArray(Tester & t)
{
    // Do all the test suites
    std::cout << "TEST SUITES FOR CLASS SArray" << std::endl;
    test_class_SArray_types(t);
    test_class_SArray_size_empty_and_ctor_from_size(t);
    test_class_SArray_default_ctor(t);
    test_class_SArray_bracket_op(t);
    test_class_SArray_copy_ctor(t);
    test_class_SArray_copy_assn(t);
    test_class_SArray_begin_end(t);
    test_class_SArray_comparisons(t);
    test_class_SArray_ctor_dctor_count(t);
}


// ************************************************************************
// Main program
// ************************************************************************


// main
// Runs class SArray test suite, prints results to cout.
int main()
{
    Tester t;
    test_class_SArray(t);

    std::cout << std::endl;
    if (t.allPassed())
    {
        std::cout << "All tests successful" 
                  << std::endl;
    }
    else
    {
        std::cout << "Tests ********** UNSUCCESSFUL **********"
                  << std::endl;
    }
    std::cout << std::endl;

    return 0;
}

