@isTest
private class StringStackTest {
  
  /* Verifies that push(), pop() and peak() work correctly
   * when there is only 1 object on the Stack. */
  static testMethod void basicTest() {
        // Instantiate a StringStack.
        StringStack stack = new StringStack();
        
        // Verify the initial state is as expected.
        System.assert(stack.isEmpty());
        
        // Set up some test data.
        String onlyString = 'Only String';
        
        // Call the push() method and verify the Stack is no longer empty
        stack.push(onlyString);
        System.assert(!stack.isEmpty());
        
        // Verify that the value we pushed on the Stack is the one we expected
        String peakValue = stack.peak();
        System.assertEquals(onlyString, peakValue);
        System.assert(!stack.isEmpty());
        
        // Verify the Stack state after pop() is called.
        String popValue = stack.pop();
        System.assertEquals(onlyString, popValue);
        System.assert(stack.isEmpty());
  }
    
  /* Verifies that push(), pop() and peak() work correctly
   * when there are multiple objects on the Stack. */
  static testMethod void verifyCorrectOrderTest() {
        // Instantiate a StringStack.
        StringStack stack = new StringStack();
        
        // Set up some test data.
        String bottomString = 'Bottom String';
        String middleString = 'Middle String';
        String topString = 'Top String';
        
        // Call the push() method with multiple objects
        stack.push(bottomString);
        stack.push(middleString);
        stack.push(topString);
        
        // Verify that the 'top' object is the object we expected 
        String peakValue = stack.peak();
        System.assertEquals(topString, peakValue);
        
        // Verify that the order of the objects is as we expected
        String popValue = stack.pop();
        System.assertEquals(topString, popValue);
        popValue = stack.pop();
        System.assertEquals(middleString, popValue);
        popValue = stack.pop();
        System.assertEquals(bottomString, popValue);
        System.assert(stack.isEmpty());
  }    
    
  static testMethod void nullValueNotAllowedExceptionTest() {
        StringStack stack = new StringStack();
        
        try{        
        	stack.push(null);
        }catch (StringStack.NullValueNotAllowedException e){
        	// Exit the test if the expected NullValueNotAllowedException is thrown.
        	return;
        }
        // Fail the test if the expected NullValueNotAllowedException is not thrown.
        System.assert(false,
                   'A NullValueNotAllowedException was expected, but was not thrown.');       
  }
    
  static testMethod void stackOverflowTest() {
        StringStack stack = new StringStack();
        
        try{        
        	for(Integer i = 0; i < StringStack.MAX_STACK_DEPTH + 1; i++){
        		stack.push('String ' + i);
        	}
        }catch (StringStack.StackOverflowException e){
        	// Exit the test if the expected StackOverflowException is thrown.
        	return;
        }
        // Fail the test if the expected StackOverflowException is not thrown.
        System.assert(false, 
                     'A StackOverflowException was expected, but was not thrown.');       
  }
    
  static testMethod void stackPopUnderflowTest() {
        StringStack stack = new StringStack();
        
        try{        
        	stack.pop();
        }catch (StringStack.StackUnderflowException e){
        	// Exit the test if the expected StackUnderflowException is thrown.
        	return;
        }
        // Fail the test if the expected StackUnderflowException is not thrown.
        System.assert(false, 
                     'A StackUnderflowException was expected, but was not thrown.');       
  }
    
  static testMethod void stackPeakUnderflowTest() {
        StringStack stack = new StringStack();
        
        try{        
        	stack.peak();
        }catch (StringStack.StackUnderflowException e){
        	// Exit the test if the expected StackUnderflowException is thrown.
        	return;
        }
        // Fail the test if the expected StackUnderflowException is not thrown.
        System.assert(false, 
                     'A StackUnderflowException was expected, but was not thrown.');       
  }
}