/**
 * Tester class for ArrayHeap
 * Written for Programming Assignment 3, Summer 2014
 */
import java.util.*;
public class HeapTester {
	private static int randArr[] = {5,2,7,6,4,1,9,8,3,0 };
	public static void main(String[] args) {
		testEmpty();
		testOne();
		testInsert();
		testExpand();
		System.out.println("Done testing ArrayHeap");
	}
	
	private static void testEmpty() {
		// test normal construction		
		ArrayHeap<PriorityInt> heap = new ArrayHeap<PriorityInt>();

		if (!(heap instanceof PriorityQueueADT))
			error("ArrayHeap doesn't implement PriorityQueueADT interface");
		
		if (!heap.isEmpty()) {
			error("isEmpty() incorrect on empty heap (0-arg ctor)");
		}
		if (heap.size() != 0) {
			error("size() incorrect on empty heap (0-arg ctor)");
		}

		try {
			heap.getMax();
			error("getMax() did not throw exception on empty heap");
		} catch (NoSuchElementException e) {
			// expected
		} catch (Exception e) {
			error("getMax() on empty heap threw wrong exception");
		}

		try {
			heap.removeMax();
			error("removeMax() did not throw exception on empty heap");
		} catch (NoSuchElementException e) {
			// expected
		} catch (Exception e) {
			error("removeMax() on empty heap threw wrong exception");
		}
		
		heap = new ArrayHeap<PriorityInt>(10);
		
		if (!heap.isEmpty()) {
			error("isEmpty() incorrect on empty heap (1-arg ctor)");
		}
		if (heap.size() != 0) {
			error("size() incorrect on empty heap (1-arg ctor)");
		}
		
		try {
			heap = new ArrayHeap<PriorityInt>(-10);
			error("ctor did not throw exception when passed negative number");
		} catch (IllegalArgumentException e) {
			// expected
		} catch (Exception e) {
			error("ctor threw wrong exception when passed negative number");
		}
	}
	
	private static void testOne() {
		ArrayHeap<PriorityInt> heap = new ArrayHeap<PriorityInt>();
		PriorityInt p1 = new PriorityInt(1);
		PriorityInt p2 = new PriorityInt(1);
		
		// test normal insert/lookup
		int beforeSize = heap.size();
		heap.insert(p1);
		if (heap.size() != beforeSize + 1)
			error("size() not updated correctly after insert");
		if (heap.isEmpty())
			error("isEmpty() incorrect after inserting one item");
		
		try {
			beforeSize = heap.size();
			PriorityInt p3 = heap.getMax();	
			if (p3 != p1)
				error("getMax() on 1-elt heap returned returned wrong value");	
			if (heap.size() != beforeSize)
				error("size() changed by call to getMax()"); 
		} catch (NoSuchElementException e) {
			error("getMax)_ threw NoSuchElementException when it should not have");
		} catch (Exception e) {
			error("getMax() threw unexpected exception");
		}
		
		try {
			beforeSize = heap.size();
			PriorityInt p3 = heap.removeMax();	
			if (p3 != p1)
				error("removeMax() on 1-elt heap returned returned wrong value");
			if (heap.size() != beforeSize - 1)
				error("size() not changed correctly by call to removeMax()");
			if (!heap.isEmpty())
				error("isEmpty() incorrect after removing only item");
		} catch (NoSuchElementException e) {
			error("removeMax() threw NoSuchElementException when it should not have");
		} catch (Exception e) {
			error("removeMax() threw unexpected exception");
		}
		
		heap = new ArrayHeap<PriorityInt>();
		heap.insert(p1);
		beforeSize = heap.size();
		try {
			heap.insert(p1);
			if (heap.size() != beforeSize + 1)
				error("inserting duplicate item did not update size correctly");
		} catch (Exception e) {
			error("inserting duplicate item resulted in exception");
		}
	}
	
	private static void testInsert() {
		ArrayHeap<PriorityInt> heap = new ArrayHeap<PriorityInt>();
		try {
			for (int i = 0; i < 10; i++) {
				heap.insert(new PriorityInt(randArr[i]));
			}
			
			if (heap.isEmpty())
				error("isEmpty() incorrect on heap with 10 items");
			if (heap.size() != 10)
				error("size() incorrect on heap with 10 items");
			
			try {
				for (int i = 9; i >= 0; i--) {
					PriorityInt p1 = heap.getMax();
					PriorityInt p2 = heap.removeMax();
					if (p1 != p2) 
						error("removeMax() did not return same value as getMax");
					if (p2.getPriority() != i)
						error("removeMax() returned item with wrong priority");
				}
				if (!heap.isEmpty()) 
					error("isEmpty() incorrect after removing all items");
				if (heap.size() != 0)
					error("size() incorrect after removing all items");
				try {
					heap.getMax();
					error("getMax() did not throw exception after removing all items");
				} catch (NoSuchElementException e) {
					// expected
				} catch (Exception e) {
					error("getMax() threw wrong exception after removing all items");
				}
			} catch (Exception e) {
				error("unexpected error thrown while testing getMax/removeMax");
			}
			
		} catch (Exception e) {
			error("unexpected exception thrown while testing insert");
		}
		
		heap = new ArrayHeap<PriorityInt>();
		try {
			for (int i = 0; i < 10; i++) {
				heap.insert(new PriorityInt(10));
			}
		} catch (Exception e) {
			error("unexpected exception thrown while adding multiple duplicate priorities");
		}
		while (!heap.isEmpty()) {
			PriorityInt p = heap.removeMax();
			if (p.getPriority() != 10)
				error("removeMax() incorrect when removing duplicate priorities");
		}
	}
	
	private static void testExpand() {
		ArrayHeap<PriorityInt> heap = new ArrayHeap<PriorityInt>();
		try {
			for (int i = 0; i < 150; i++)
				heap.insert(new PriorityInt(i));
		} catch (Exception e) {
			error("inserting until expansion threw exception");
		}
		heap = new ArrayHeap<PriorityInt>(10);
		try {
			for (int i = 0; i < 15; i++)
				heap.insert(new PriorityInt(i));
		} catch (Exception e) {
			error("inserting until expansion threw exception");
		}
	}
	
	private static void error(String msg) {
		System.out.println(msg);
	}
}