package ge.edu.freeuni.sdp.snake.view.terminal;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import ge.edu.freeuni.sdp.snake.presenter.GameOverPresenter;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;

import com.googlecode.lanterna.input.Key;
import com.googlecode.lanterna.input.Key.Kind;
import com.googlecode.lanterna.terminal.Terminal;
import com.googlecode.lanterna.terminal.TerminalSize;

public class TerminalGameOverViewTest {

	private static Key key;
	private static Terminal terminal;
	private static TerminalSize terminalSize;
	private static GameOverPresenter presenter;
	private static TerminalGameOverView gameOver;

	@Before
	public void setUp() throws Exception {
		key = Mockito.mock(Key.class);
		terminal = Mockito.mock(Terminal.class);
		terminalSize = Mockito.mock(TerminalSize.class);
		presenter = Mockito.mock(GameOverPresenter.class);
		gameOver = Mockito.spy(new TerminalGameOverView(presenter, terminal));

		Mockito.when(terminalSize.getRows()).thenReturn(100);
		Mockito.when(terminalSize.getColumns()).thenReturn(100);
		Mockito.when(terminal.getTerminalSize()).thenReturn(terminalSize);
	}

	/*
	 * Should throw null pointer runtime exception if terminal size is null.
	 * (P.S Don't know how correct it is but its so in this code.)
	 */
	@Test(expected = NullPointerException.class)
	public void testShowNullPointerException() {
		Mockito.when(terminal.getTerminalSize()).thenReturn(null);
		gameOver.show();
	}

	/*
	 * This method is used mainly for getting information from user after
	 * loosing game. It should change boolean continueGame. I'll test different
	 * cases of getting user input in other methods.
	 */

	@Test
	public void testShowWithUserAsnwerNoCharacter() {
		// First this boolean should be false
		assertFalse(gameOver.continueGameOrNot());
		// Stub key to return yes
		Mockito.when(key.getCharacter()).thenReturn('n');
		Mockito.when(terminal.readInput()).thenReturn(key);
		gameOver.show();
		// Second call of this boolean should be false
		assertFalse(gameOver.continueGameOrNot());
	}

	@Test
	public void testShowWithUserAsnwerNoEscape() {
		// First this boolean should be false
		assertFalse(gameOver.continueGameOrNot());
		// Stub key to return yes
		Mockito.when(key.getKind()).thenReturn(Kind.Escape);
		Mockito.when(terminal.readInput()).thenReturn(key);
		gameOver.show();
		// Second call of this boolean should be false
		assertFalse(gameOver.continueGameOrNot());
	}

	@Test
	public void testShowWithUserAsnwerStrangeSymbol() {
		// First this boolean should be false
		assertFalse(gameOver.continueGameOrNot());
		// Stub key to return yes
		Mockito.when(key.getCharacter()).thenReturn('\n').thenReturn('n');
		Mockito.when(terminal.readInput()).thenReturn(key);
		gameOver.show();
		// Second call of this boolean should be false
		assertFalse(gameOver.continueGameOrNot());
	}

	@Test
	public void testShowWithTerminalSizeChanges() {
		// First this boolean should be false
		assertFalse(gameOver.continueGameOrNot());
		// Prepare stub for terminal size
		Mockito.when(terminalSize.getRows()).thenReturn(0).thenReturn(10);
		Mockito.when(terminalSize.getColumns()).thenReturn(0).thenReturn(10);
		// Stub key to return yes
		Mockito.when(key.getCharacter()).thenReturn('y');
		Mockito.when(terminal.getTerminalSize()).thenReturn(terminalSize);
		Mockito.when(terminal.readInput()).thenReturn(null).thenReturn(key);
		gameOver.show();
		assertTrue(gameOver.continueGameOrNot());
	}

	/*
	 * After construction without interacting to this class first call of method
	 * continueGameOrNot() should return false.
	 */

	@Test
	public void testContinueGameOrNotFalse() {
		assertFalse(gameOver.continueGameOrNot());
	}

	/*
	 * After construction when user will select continue game (Y/y)
	 * continueGameOrNot() should return true.
	 */

	@Test
	public void testContinueGameOrNotTrue() {
		// Stub key to return 'y'
		Mockito.when(key.getCharacter()).thenReturn('y');
		Mockito.when(terminal.readInput()).thenReturn(key);
		// Call necessary methods in this case show
		gameOver.show();
		// Verify method calls occurrence
		Mockito.verify(key).getCharacter();
		Mockito.verify(terminal).readInput();
		Mockito.verify(terminal).getTerminalSize();
		Mockito.verify(terminalSize, Mockito.atLeast(1)).getRows();
		Mockito.verify(terminalSize, Mockito.atLeast(1)).getColumns();
		// Check if method worked correctly
		assertTrue(gameOver.continueGameOrNot());
	}

}

@@ -699,16 +699,171 @@
 eOver;%0A%0A
+%09/*%0A%09 * General setup for tests some of these stubbed methods will be overridden%0A%09 * in the test methods but generally this return values will work.%0A%09 */%0A%0A
 %09@Before
@@ -863,16 +863,16 @@
 @Before%0A
-
 %09public 
@@ -1467,16 +1467,17 @@
 s but it
+'
 s so in 
@@ -2036,35 +2036,34 @@
 b key to return 
-yes
+no
 %0A%09%09Mockito.when(
@@ -2426,35 +2426,34 @@
 b key to return 
-yes
+no
 %0A%09%09Mockito.when(
@@ -2818,37 +2818,63 @@
 // Stub key 
+firs
 t
-o
  return
- yes
+s strange character then no
 %0A%09%09Mockito.w
@@ -4009,16 +4009,16 @@
 e (Y/y)%0A
-
 %09 * cont
@@ -4053,16 +4053,62 @@
 n true.%0A
+%09 * %0A%09 * (P.S doesn't work on upper case 'Y')%0A
 %09 */%0A%0A%09@

Update TerminalGameOverViewTest.java