package evaluator;
import static org.junit.jupiter.api.Assertions.*;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

import org.junit.jupiter.api.Test;

import evaluator.Evaluator.Lexer;

class EvaluatorTest {

	@Test
	void lexerGoodInputTest() {
		InputStream input = new ByteArrayInputStream("x1x = 10.34 10 +\n".getBytes(StandardCharsets.UTF_8));
		
		Lexer lexer = new Lexer(input);
		
		assertEquals(Lexer.VARIABLE, lexer.nextToken());
		assertEquals("x1x", lexer.getText());
		
		assertEquals(Lexer.ASSIGN_OP, lexer.nextToken());
		assertEquals("=", lexer.getText());
		
		assertEquals(Lexer.NUMBER, lexer.nextToken());
		assertEquals("10.34", lexer.getText());
		
		assertEquals(Lexer.NUMBER, lexer.nextToken());
		assertEquals("10", lexer.getText());
		
		assertEquals(Lexer.ADD_OP, lexer.nextToken());
		assertEquals("+", lexer.getText());
		
		assertEquals(Lexer.EOL, lexer.nextToken());
		assertEquals("\n", lexer.getText());
	}
	
	@Test
	void lexerBadInputTest() {
		InputStream input = new ByteArrayInputStream("y,!g !=   34.67  16! ".getBytes(StandardCharsets.UTF_8));
		
		Lexer lexer = new Lexer(input);
		
		assertEquals(Lexer.VARIABLE, lexer.nextToken());
		assertEquals("y", lexer.getText());
		
		assertEquals(Lexer.BAD_TOKEN, lexer.nextToken());
		assertEquals(",", lexer.getText());
		
		assertEquals(Lexer.BAD_TOKEN, lexer.nextToken());
		assertEquals("!", lexer.getText());
		
		assertEquals(Lexer.VARIABLE, lexer.nextToken());
		assertEquals("g", lexer.getText());
		
		assertEquals(Lexer.BAD_TOKEN, lexer.nextToken());
		assertEquals("!", lexer.getText());
		
		assertEquals(Lexer.ASSIGN_OP, lexer.nextToken());
		assertEquals("=", lexer.getText());
		
		assertEquals(Lexer.NUMBER, lexer.nextToken());
		assertEquals("34.67", lexer.getText());
		
		assertEquals(Lexer.NUMBER, lexer.nextToken());
		assertEquals("16", lexer.getText());
		
		assertEquals(Lexer.BAD_TOKEN, lexer.nextToken());
		assertEquals("!", lexer.getText());
	}

	@Test
	void lexerExtraWhiteSpaceTest() {
		InputStream input = new ByteArrayInputStream("    y    =    17.5  + 34   * ".getBytes(StandardCharsets.UTF_8));
		
		Lexer lexer = new Lexer(input);
		
		assertEquals(Lexer.VARIABLE, lexer.nextToken());
		assertEquals("y", lexer.getText());
		
		assertEquals(Lexer.ASSIGN_OP, lexer.nextToken());
		assertEquals("=", lexer.getText());
		
		assertEquals(Lexer.NUMBER, lexer.nextToken());
		assertEquals("17.5", lexer.getText());
		
		assertEquals(Lexer.ADD_OP, lexer.nextToken());
		assertEquals("+", lexer.getText());
		
		assertEquals(Lexer.NUMBER, lexer.nextToken());
		assertEquals("34", lexer.getText());
		
		assertEquals(Lexer.MULTIPLY_OP, lexer.nextToken());
		assertEquals("*", lexer.getText());
	}
	
	@Test
	void lexerNoWhiteSpaceTest() {
		InputStream input = new ByteArrayInputStream("10+17=!13x78y*\n".getBytes(StandardCharsets.UTF_8));
		
		Lexer lexer = new Lexer(input);
		
		assertEquals(Lexer.NUMBER, lexer.nextToken());
		assertEquals("10", lexer.getText());
		
		assertEquals(Lexer.ADD_OP, lexer.nextToken());
		assertEquals("+", lexer.getText());
		
		assertEquals(Lexer.NUMBER, lexer.nextToken());
		assertEquals("17", lexer.getText());
		
		assertEquals(Lexer.ASSIGN_OP, lexer.nextToken());
		assertEquals("=", lexer.getText());
		
		assertEquals(Lexer.BAD_TOKEN, lexer.nextToken());
		assertEquals("!", lexer.getText());
		
		assertEquals(Lexer.NUMBER, lexer.nextToken());
		assertEquals("13", lexer.getText());
		
		assertEquals(Lexer.VARIABLE, lexer.nextToken());
		assertEquals("x78y", lexer.getText());
		
		assertEquals(Lexer.MULTIPLY_OP, lexer.nextToken());
		assertEquals("*", lexer.getText());
		
		assertEquals(Lexer.EOL, lexer.nextToken());
		assertEquals("\n", lexer.getText());
	}
	
	@Test
	void evaluatorSimpleExpressionTest() {
		InputStream input = new ByteArrayInputStream("10 10 *\n".getBytes(StandardCharsets.UTF_8));
		
		Evaluator eval = new Evaluator(new Lexer(input));
		
		assertEquals(100, eval.evaluate());
	}
}
