import java.util.*;
/**
 * 
 * Some test methods for the Set class.
 * Some are implemented fully, one is partially implemented,
 * and the rest are blank.  Fill them in.
 * 
 * @author Charles Cusack
 * @version 1.0
 */
public class testSet
{

    Set<String> A;
    Set<String> B;
    Set<String> C;
    Set<String> D;
    Set<String> AuB;
    Set<String> empty;
    
    // Keep track of whether or not all tests are passed.
    boolean passed;

    public void setupTests() {
        A = new Set<String>(new String[] {"Blah", "Goo", "Ferzle"});
        B = new Set<String>(new String[] {"Blah", "Foo", "Stuff", "Ferzle"});
        // C is A subset of B and D
        C = new Set<String>(new String[] {"Foo", "Stuff"});
        D = new Set<String>(new String []{"Goats", "Foo", "Good", "Stuff", "Nothing"});
        // A union B
        AuB = new Set<String>( new String []{"Foo", "Goo", "Blah", "Stuff", "Ferzle"});
        empty = new Set<String>();
       // Reset.
       passed = true;
    }
    
    // A nice method that will run all of the tests.
    public void TestAll() {
        int correct = 0;
        if(testConstructors()) correct++;
        if(testContains()) correct++;
        if(testInsertAndRemove()) correct++;
        if(testToString()) correct++;
        if(testEquals()) correct++;
        if(testUnion()) correct++;
        if(testIntersect()) correct++;
        if(testSetDifference()) correct++;
        if(testSubsetStuff()) correct++;
        if(testAreDisjoint()) correct++;
        System.out.println(correct+"/10 tests passed");
    }
    
    public boolean testConstructors() {
        setupTests();
        
        // Test the ArrayList constructor with no repeats
        ArrayList<String> stuff = new ArrayList<String>();
        stuff.add("blah");
        stuff.add("foo");
        stuff.add("ferzle");
        
        Set<String> D = new Set<String>(stuff);
        if(!D.contains("blah") || !D.contains("foo") || !D.contains("ferzle") || D.getSize()!=3) {
            System.out.println("ArrayList constructor broken");
            passed = false;
        }
        
        // Test the ArrayList constructor with repeats (by adding foo again).
        stuff.add("foo");        
        D = new Set<String>(stuff);
        if(!D.contains("blah") || !D.contains("foo") || !D.contains("ferzle") || D.getSize()!=3) {
            System.out.println("ArrayList constructor broken");
            passed = false;
        }
        
        // Test the array constructor with repeats
        String[] moreStuff = new String[4];
        moreStuff[0]="blah";
        moreStuff[1]="blah1";
        moreStuff[2]="blah2";
        moreStuff[3]="blah";
        D = new Set<String>(moreStuff);
        if(!D.contains("blah") || !D.contains("blah1") || !D.contains("blah2") || D.getSize()!=3) {
            System.out.println("ArrayList constructor broken");
            passed = false;
        }      
        if(passed) {
            System.out.println("Constructors: ALL TESTS PASSED");
        }
        return passed;
    }
        
    // IMPLEMENT ME!
    // Here I give you a suggested template for yout test methods.
    // For the remainder, I leave it to you to fill in the details.
    public boolean testContains()  {
        setupTests();
        System.out.println("Contains:  NOT IMPLEMENTED");
        
        // ADD TESTS HERE
        // Make sure to test both the result of contains and the return value.
        // See testInsertAndRemove for some examples of doing this.
        // Also make sure to include at least one test with a String created
        // with more than just "Blah"--for instance by using
        //    new String("Blah")
        // This is important because it will catch use of == instead of equals
        // in the contains method.
        // Make sure to set passed=false if any of your test fail.
        
        if(passed) {
            System.out.println("Contains: ALL TESTS PASSED");
        }
        return passed;
    }
    
    public boolean testInsertAndRemove()
    {
        // setup tests re-initializes everything between tests so
        // previous errors do not effect future tests.
        setupTests();
        
        if(A.getSize()!=3) {
            System.out.println("Oops: doesn't start with 3 items as it should.");
            passed=false;
        }
        
        // Insert a duplicate. Test that the method returns false as it should.
        if(A.insert("Blah")) {
            System.out.println("Insert: does not return false when trying to insert duplicate");
            passed=false;
        }
        // After inserting, size should not change.
        if(A.getSize()!=3) {
            System.out.println("Insert: Inserts duplicate elements");
            passed=false;
        }
        // Make sure it returns true when inserting an element.
        if(!A.insert("a new one"))  {
            System.out.println("Insert: Doesn't return true when inserting a new element");
            passed=false;
        }
        if(A.getSize()!=4) {
            System.out.println("Insert: Doesn't insert a new element");
            passed=false;
        }
        // Now we test removing elements.        
        if(!A.remove("Blah")) {
            System.out.println("Remove: Doesn't return true when deleting existing element");
            passed=false;
        }     
        if(A.contains("Blah")) {
            System.out.println("Remove:didn't remove element");
            passed=false;
        }
        if(A.remove("Blah")) {
            System.out.println("Remove: Doesn't return false when deleting non-existent element");
            passed=false;
        }
        if(A.remove("Stuff")) {
            System.out.println("Remove: Doesn't return false when deleting non-existent element");
            passed=false;
        }
        A.removeAll();
        if(A.getSize()!=0) {
            System.out.println("RemoveAll: Doesn't remove all elements");
            passed=false;
        }
        if(passed){
            System.out.println("Insert, Remove, and RemoveAll: ALL TESTS PASSED");
        }
        return passed;
    }
    // No tests for getSize because it simply returns elements.size(), so it works
    // correctly, and the only reason it can be wrong is if the logic of another 
    // method (like insert or remove) is wrong.
    
    // No tests for getElements because it simply calls elements.toArray and should
    // be correct.  To write truly accurate tests for it would be tricky since we
    // in general should NOT assume a particular ordering of elements in a set, so
    // we cannot be sure the order of the elements in the array that is returned.
    
        
    public boolean testToString() {
        setupTests();
        // Techincally, this test is incorrect since we cannot generally
        // assume a particular order of elements in the set.
        if(!A.toString().equals("{Blah, Goo, Ferzle}")) {
            System.out.println("toString: Doesn't work properly");
            System.out.println("result was: "+A.toString());
            System.out.println("Should be : "+"{Blah, Goo, Ferzle}");
            passed = false;
        }
        if(passed){
            System.out.println("toString: ALL TESTS PASSED");
        }
        return passed;
    }
    
    public boolean testEquals() {
        setupTests();
        
        //----------------------------------------------------------
        // Test when two sets are equal
        // Create the ame set as A, but put the element in the set
        // in a different order.
        Set<String> Aprime= new Set<String>();
        Aprime.insert("Blah");
        Aprime.insert("Ferzle");
        Aprime.insert("Goo");
        
        if(!A.equals(Aprime) || !Aprime.equals(A) || !A.equals(A)) {
            System.out.println("Equals: thinks two equal sets are not");
            passed = false;
        }
        
        // Test on empty sets.
        Set<String> empty2 = new Set<String>();
        if(!empty.equals(empty2)) {
            System.out.println("Equals: thinks empty sets are not equal");
            passed = false;
        }
        
        //----------------------------------------------------------
        // Test when two sets are not equal
        if(A.equals(B) || B.equals(C) || C.equals(A)) {
            System.out.println("Equals: thinks two unequal sets are equal");
            passed = false;
        }       
        
        if(passed) {
            System.out.println("Equals: ALL TESTS PASSED");
        }  
        return passed;
    }
    
    // IMPLEMENT ME!
    public boolean testUnion() {
        System.out.println("Union:  NOT IMPLEMENTED");
        return true;
    }
    
    public boolean testIntersect() {
        // Make sure past problems do not effect the current tests.
        setupTests();
        
        //----------------------------------------------------------
        // Test for when two sets have an intersection
        // Compute D intersect B.  The answer should be the set C.
        Set<String> inter = D.intersect(B);
        // If inter is not the same as C, something is wrong with intersect.
        if(!inter.equals(C)) {
           System.out.println("Intersect:  Does not compute a non-empty intersection correctly");
           passed = false;
        }
        
        //----------------------------------------------------------
        // Test the intersection of a set with itself.
        Set<String> AIntersectA = A.intersect(A); 
        if(!AIntersectA.equals(A)) {
           System.out.println("Intersect:  A set intersect itself is not itself and should be");
           passed = false;
        }
        
        //----------------------------------------------------------
        // Test for when two sets do not intersect
        Set<String> AIntersectC = A.intersect(C);
        if(!AIntersectC.equals(empty)) {
            System.out.println("Intersect: returns a non-empty set when two sets do not intersect");
            passed = false;
        }
        
        //----------------------------------------------------------
        // Test the intersection of a set with the empty set.
        if(!empty.intersect(A).equals(empty) || !A.intersect(empty).equals(empty)) {
            System.out.println("Intersect: incorrect when done with empty set");
            passed = false;
        }
       
        if(passed) {
            System.out.println("Intersect: ALL TESTS PASSED");
        }  
        return passed; 
    }
       
    // IMPLEMENT ME!
    public boolean testSetDifference() {
        System.out.println("setDifference:  NOT IMPLEMENTED");
        return true;
    }
    
    // IMPLEMENT ME!
    public boolean testSubsetStuff() {
        System.out.println("Subset and ProperSubset:  NOT IMPLEMENTED");
        return true;
    }
        
    // IMPLEMENT ME!
    public boolean testAreDisjoint() {
        System.out.println("areDisjoint:  NOT IMPLEMENTED");
        return true;
    } 
}
