import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.hamcrest.CoreMatchers.*;

import java.awt.Point;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

/**
 * JUnit Beispieltests der Klasse {@link MyMathImpl} mit Basis-Funktionalitäten
 * aus {@link org.junit.Assert} sowie {@link org.hamcrest.CoreMatchers}. <br><br>
 * 
 * Zu beachten ist, dass man für jeden Testfall
 * eine einzelne Methode schreiben müsste, da andernfalls lediglich der erste 
 * - fehlgeschlagene - Aufruf von bspw. assertEquals() angezeigt wird 
 * (alle weiteren Aufrufe dahinter werden ignoriert). Die Mehrfachaufrufe dienen 
 * lediglich der Veranschaulichung. <br><br>
 * 
 * Mehrfache Tests einer Methode durch unterschiedliche Parameter
 * legen einen parametrisierten Test nahe (vgl. {@link MyMathTestParametrized1}, 
 * {@link MyMathTestParametrized2}, {@link MyMathTestParametrized3}).
 * 
 * @author Malte Prieß
 */
public class MyMathTest {

	MyMathImpl myMath;

	
	/*
	 * Initialization before each (!) test
	 */
	@Before
	public void setUp(){
		myMath = new MyMathImpl();
	}

	
	/*
	 * assertEquals
	 * Less readable and typeable: Think in terms of
	 * verb, object, subject (assert "equals 3 x")
	 */
	@Test
	public void testEuclideanDistance() {
		
		assertEquals("Failure - Euclidean Distance incorrect.", 5.0, 
				Math.round( myMath.euclideanDistance(new Point(0, 0), new Point(3, 4)) * 100 ) / 100.0, 0);
		
		assertEquals("Failure - Euclidean Distance incorrect.", 1.41, 
				Math.round( myMath.euclideanDistance(new Point(2, 3), new Point(3, 4)) * 100 ) / 100.0, 0);

	}	
	
	/*
	 * assertThat with hamcrest matchers
	 * More readable and typeable: this syntax allows you to think in terms of 
	 * subject, verb, object (assert "x is 3") rather than assertEquals, which 
	 * uses verb, object, subject (assert "equals 3 x")
	 */
	@Test
	public void testEuclideanDistanceMatcher() {
		double d = myMath.euclideanDistance(new Point(0, 0), new Point(3, 4));
		
		assertThat( "Failure - Euclidean Distance incorrect.", d, is(5. ) );		
		assertThat( "Failure - Euclidean Distance incorrect.", d, either( is(5.0) ).or( is( not (5.5) ) ) );		
		assertThat( "Failure - Euclidean Distance incorrect.", d, is( not(3.0) ) );		
		
	}
	

	/*
	 * Simple exception testing
	 */
	@Test(expected = IllegalArgumentException.class)
	public void testEuclideanDistanceException() {
		
		myMath.euclideanDistance(new Point(0, 0), null);
	
	}
	
	
	/*
	 * Deeper testing of the exception
	 */
	@Rule
	public ExpectedException thrown = ExpectedException.none();
	
	@Test
	public void testEuclideanDistanceExceptionAdvanced() {
		thrown.expect(IllegalArgumentException.class);
	    thrown.expectMessage("Null is not allowed as argument.");
	    // ... or using hamcrest matchers
	    thrown.expectMessage(startsWith("Null is not allowed"));
	    
		myMath.euclideanDistance(new Point(0, 0), null);
		
	}

	/*
	 * Simple test of login() using assertEquals
	 */
	@Test
	public void testLogin() {
		assertEquals( "Failure - Login incorrect (Hans, 1234)", true, myMath.login("Hans", "1234") );
		assertEquals( "Failure - Login incorrect (Hans, 1235)", false, myMath.login("Hans", "1235") );
		assertEquals( "Failure - Login incorrect (Wurst, 5678)", true, myMath.login("Wurst", "5678") );
		assertEquals( "Failure - Login incorrect (Wurst, 5688)", false, myMath.login("Wurst", "5688") );
	}

	/*
	 * Simple test of login() using assertTrue, assertFalse
	 */
	@Test
	public void testLogin2() {
		assertTrue( "Failure - Login incorrect (Hans, 1234)", myMath.login("Hans", "1234") );		
		assertFalse( "Failure - Login incorrect (Hans, 1235)", myMath.login("Hans", "1235") );		
		assertTrue ("Failure - Login incorrect (Wurst, 5678)", myMath.login("Wurst", "5678") );		
		assertFalse( "Failure - Login incorrect (wurst, 5688)", myMath.login("Wurst", "5688") );		
	}

	/*
	 * Simple test of login() using assertThat with hamcrest matchers
	 */
	@Test
	public void testLoginMatcher() {
		assertThat( "Failure - Login incorrect (Hans, 1234)", myMath.login("Hans", "1234"), is(true) );		
		assertThat( "Failure - Login incorrect (Hans, 1235)", myMath.login("Hans", "1235"), is(false) );		
		assertThat( "Failure - Login incorrect (Wurst, 5678)", myMath.login("Wurst", "5678"), is(true) );		
		assertThat( "Failure - Login incorrect (wurst, 5688)", myMath.login("Wurst", "5688"), is(false) );		
	}

}
