//
// FILE: testSparseVector.cc
//
//       Test suite for the SparseVector class.
//

#include "SparseVector.hh"
#include <iostream>
#include <string>

using namespace std;


void
test_result(int& ntest, string s, bool passed, int& npassed)
{
    ntest++;

    if (passed)
    {
        npassed++;
        cout << "Test " << ntest << ": " << s << "   PASSED" << endl;
    }
    else
    {
        cout << "Test " << ntest << ": " << s << "   FAILED" << endl;
    }
}


int 
main()
{
    cout << "-------------------------------------------------" << endl;

    int  ntest = 0, npassed = 0;
    bool result;

    SparseVector s(10000);

    // Test: size of vector is correct.

    result = (s.getSize() == 10000);

    test_result(ntest, 
                "getSize : Does getSize() return the correct size?", 
                result, npassed);

    // Test: elements are zero to start with.

    result = (s.getElem(100) == 0)
        && (s.getElem(1000) == 0)
        && (s.getElem(5993) == 0)
        && (s.getElem(9999) == 0);

    test_result(ntest, 
                "getElem : Are initial vector elements zero?", 
                result, npassed);

    // Test: getElem() returns what setElem() sets.

    s.setElem(100, 10);
    s.setElem(200, -201);

    int e1 = s.getElem(100);
    int e2 = s.getElem(200);

    result = (e1 == 10) && (e2 == -201);

    test_result(ntest, 
                "getElem, setElem : "
                "Does getElem() return what setElem() set?",
                result, npassed);

    // Test: Adding elements to a SparseVector increases the nonzero count.

    SparseVector s1(10000);
    int count1 = s1.getNonZeroSize();
    s1.setElem(100, 0);
    int count2 = s1.getNonZeroSize();
    s1.setElem(101, 10);
    int count3 = s1.getNonZeroSize();

    result = (count1 == 0) && (count2 == 0) && (count3 == 1);

    test_result(ntest, 
                "getNonZeroSize, setElem : "
                "Does setElem() of a nonzero element\n"
                "\tincrease nonzero size?",
                result, npassed);

    // Test: Replacing nonzeros with zeros decreases nonzero size.

    s1.setElem(101, 0);
    int count4 = s1.getNonZeroSize();
    s1.setElem(0, 1000);
    int count5 = s1.getNonZeroSize();

    result = (count4 == 0) && (count5 == 1);

    test_result(ntest, 
                "getNonZeroSize, setElem : "
                "Does setElem() of a zero element\n"
                "\tdecrease nonzero size?",
                result, npassed);

    // Test: a SparseVector is equal to itself.
    
    result = (s == s);
    
    test_result(ntest, 
                "operator== : Is sparse vector equal to itself?",
                result, npassed);

    // Test: a SparseVector is equal to a copy of itself.

    SparseVector s2(s);
    result = (s == s2);

    test_result(ntest, 
                "copy constructor, operator== : \n"
                "\tIs sparse vector equal to a copy of itself?",
                result, npassed);

    // Test: self-assignment of a SparseVector doesn't change it.

    s = s;
    result = (s == s2);

    test_result(ntest, 
                "operator= : \n"
                "\tDoes self-assignment do nothing to a sparse vector?",
                result, npassed);

    // Test: a SparseVector is not equal to a vector with more
    // elements.

    s2.setElem(0, 1000);
    result = (s != s2);

    test_result(ntest, 
                "operator!= : Is sparse vector not equal to a longer vector?",
                result, npassed);

    // Test: a SparseVector is not equal to a vector with more
    // elements.  This time add the element to the other end.

    SparseVector s2b(s);
    s2b.setElem(9000, 1000);
    result = (s != s2b);

    test_result(ntest, 
                "operator!= : "
                "Is sparse vector not equal to a longer vector (2)?",
                result, npassed);

    // Test: mutating an element changes a vector.

    s2.setElem(12, 100);
    result = (s2 != s);

    test_result(ntest,
                "operator!= : Does mutating an element change a vector?",
                result, npassed);

    // Test: overloaded = operator.

    SparseVector s3(1);  // NOTE: different size.
    s2 = s3 = s;
    result = (s == s2) && (s == s3);

    test_result(ntest,
                "operator= : Does operator= assign a vector correctly?",
                result, npassed);

    // Test: overloaded += operator.
    bool result1, result2;

    SparseVector s4(10000), s5(10000);
    s4.setElem(0, 1000);
    s4.setElem(100, -s.getElem(100));
    s4.setElem(200, 1000);
    s4.setElem(5678, 31415);
    s5 += s4 += s;
    result1 = (s4 == s5);
    s4 += s;
    result2 = (s4.getElem(0) == 1000)
        && (s4.getElem(100) == 10)
        && (s4.getElem(200) == 598)
        && (s4.getElem(5678) == 31415);
    result = result1 && result2;
    
    test_result(ntest,
                "operator+= : Does operator+= work correctly?",
                result, npassed);

    // Test: overloaded + operator.

    SparseVector s6(10000);
    s6 = s4 + s4;
    result = (s6.getElem(0) == 2 * s4.getElem(0))
        && (s6.getElem(100) == 2 * s4.getElem(100))
        && (s6.getElem(200) == 2 * s4.getElem(200))
        && (s6.getElem(5678) == 2 * s4.getElem(5678));

    test_result(ntest,
                "operator+ : Does operator+ work correctly?",
                result, npassed);

    // Test: overloaded -= operator.

    SparseVector s7(10000), s8(10000), s9(10000);
    s7 -= s;
    result = (s + s7 == s8);

    test_result(ntest,
                "operator-= : Does operator-= work correctly?",
                result, npassed);

    s9 = s;
    s9 += s;
    s8 -= s;

    test_result(ntest,
                "operator+=, operator-= : \n"
                "\tDo operator += and operator-= "
                "reverse each others' effects?",
                result, npassed);

    s7 = s;
    s8 = s + s;
    s9 = s + s + s;
    s9 -= s8 -= s7;
    result = (s7 == s8) && (s9 == s7 + s7);

    test_result(ntest,
                "operator-= : Does operator-= chain correctly?",
                result, npassed);

    // Test: overloaded - operator.

    s7 = s;
    s8 = s + s;
    s9 = s + s + s;
    SparseVector s10(5), s11(10000);
    s10 = s9 - s8 - s7;
    result = (s10 == s11);

    test_result(ntest,
                "operator- : Does operator- work correctly?",
                result, npassed);

    // Test: adding and subtracting empty vectors.

    SparseVector s12(0), s13(0), s14(0);

    s14 = s12 + s13;
    s12 = s13 - s14;

    result = (s12.getSize() == s13.getSize() == s14.getSize() == 0);

    test_result(ntest,
                "Empty vectors: Do operator+/-/= work correctly?",
                result, npassed);


    // Test: subtracting a vector from itself.

    SparseVector s15(100), s16(100);

    s15.setElem(0,  100);
    s15.setElem(10, 222);
    s15.setElem(22, 542);
    s15.setElem(45, 134);
    s15.setElem(89, -994);

    s15 -= s15;
    
    result = (s15 == s16);

    test_result(ntest,
                "Does subtracting a vector from itself yield the zero vector?",
                result, npassed);


    //
    // Print out results.
    //

    cout << "-------------------------------------------------" << endl;
    cout << "Passed " << npassed << " out of " 
         << ntest << " tests." << endl;
    cout << "-------------------------------------------------" << endl;

    return 0;
}

