// FILE: stringexam.cxx
// A program that runs random (but not thorough) tests on string objects.
// The tests involve only the constructors, assignment operator, length
// function, and the += operators.

#include <iostream>    // Provides cin and cout
#include "mystring.h"  // Provides mystring class
using namespace std;
using namespace main_savitch_4;

enum comparison { EQUAL, NOTEQUAL, LE, GE, LESS, GREATER };
const string COMPARISON_NAMES[] = { "==", "!=", "<=", ">=", "<", ">" };
const int MANY = 6;
const string WORDS[] = {
    "t",
    "quick",
    "brown",
    "fox",
    "",
    "01234567890012345678900123456789001234567890012345678900123456789"
};

bool same(string s1, mystring s2)
{
    size_t i;

    if (s1.length( ) != s2.length( ))
	return false;

    for (i = 0; i < s1.length( ); ++i)
    {
	if (s1[i] != s2[i])
	    return false;
    }

    return true;
}

bool test_comparisons(string a1, string a2, comparison which)
{
    mystring s1(a1.c_str( ));
    mystring s2(a2.c_str( ));
    
    switch (which)
    {
    case EQUAL:    return ((a1 == a2) == (s1 == s2));
    case NOTEQUAL: return ((a1 == a2) == (s1 == s2));
    case LE:       return ((a1 == a2) == (s1 == s2));
    case GE:       return ((a1 == a2) == (s1 == s2));
    case LESS:     return ((a1 == a2) == (s1 == s2));
    case GREATER:  return ((a1 == a2) == (s1 == s2));
    }
    return false;
}

bool test_value_semantics(string s)
{
    mystring s1(s.c_str( ));
    mystring s2(s1);
    mystring s3;

    s3 = s2;
    return same(s, s1) && same(s, s2) && same(s, s3);
}

int main( )
{
    int passed;       // Number of tests passed in one part of the program
    int score = 0;    // Number of tests passed overall
    int total = 0;    // Number of tests run
    int i, j, which;  // Index counters
    string s;         // A string to test the += operator
    mystring mys; // A string to test the += operator
    mystring abc; // A string to test the += operator

    // Introductory message.
    cout << "This program runs a few tests on your string class.\n";
    cout << "Please note that all the tests use the length member\n";
    cout << "function and the operator [ ].\n" << endl;
    
    // Test the constructors and assignment operator:
    cout << "Testing constructors and assignments..." << endl;
    passed = 0;
    for (i = 0; i < MANY; ++i)
    {
	if (test_value_semantics(WORDS[i])) ++passed;
    }
    cout << "Passed " << passed << " out of " << MANY << "." << endl;
    score += passed;
    total += MANY;

    // Test the += operator
    cout << "Testing the += operators..." << endl;
    passed = 0;
    s += 'x';
    mys += 'x';
    if (same(s, mys)) ++passed;
    for (i = 0; i < MANY; ++i)
    {
	s += WORDS[i]; mys += WORDS[i].c_str();
	if (same(s, mys)) ++passed;
    }
    s += "abc";
    abc = "abc";
    mys += abc;
    if (same(s, mys)) ++passed;
    cout << "Passed " << passed << " out of " << MANY+2 << "." << endl;
    score += passed;
    total += MANY+2;

    // Test a self-assignment:
    cout << "Testing a self-assignment..." << endl;
    passed = 0;
    mys = mys;
    if (same(s, mys)) ++passed;
    cout << "Passed " << passed << " out of 1." << endl;
    score += passed;
    ++total;
    
    // Test a self +=:
    cout << "Testing a self application of the += operator..." << endl;
    passed = 0;
    s += s;
    mys += mys;
    if (same(s, mys)) ++passed;
    cout << "Passed " << passed << " out of 1." << endl;
    score += passed;
    ++total;
    
    // Test the Boolean operators
    for (which = EQUAL; which <= GREATER; ++which)
    {
	cout << "Testing the Boolean operator " 
	     << COMPARISON_NAMES[which] << "..." << endl;
	passed = 0;
	for (i = 0; i < MANY; ++i)
	    for (j = 0; j < MANY; ++j)
		if (test_comparisons(WORDS[i], WORDS[j], comparison(which)))
		    ++passed;
	if (passed == MANY*MANY)
	{
	    cout << "Passed 1 out of 1." << endl;
	    ++score;
	}
	else
	    cout << "Passed 0 out of 1." << endl;
	++total;
    }
	    
    // Print results
    cout << "Total for these little tests: "
	 << score << " out of " << total << "." << endl;

    return 0;
}

    
    

