package pp.s1184725.boppi.test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

import java.util.logging.Level;

import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import pp.s1184725.boppi.util.RegisterPool;

/**
 * Test cases for the basic expression language.
 * 
 * @author Frank Wibbelink
 */
public class ExpressionTest {

	/**
	 * Correct basic expressions
	 */
	@Test
	public void correctExpressionParsing() {
		BoppiTests.parseFile("programs/simpleExpression.boppi");
		assertThat(BoppiTests.log, empty());
	}

	/**
	 * Basic expressions with syntax errors
	 */
	@Test
	public void wrongExpressionParsing() {
		BoppiTests.parseString("");
		assertThat(BoppiTests.log, not(empty()));

		BoppiTests.parseString("~");
		assertThat(BoppiTests.log, not(empty()));

		BoppiTests.parseString("0A");
		assertThat(BoppiTests.log, hasSize(1));

		BoppiTests.parseString("do");
		assertThat(BoppiTests.log, hasSize(1));

		BoppiTests.parseString("true true");
		assertThat(BoppiTests.log, hasSize(1));
	}

	/**
	 * Correct basic expressions
	 */
	@Test
	public void correctExpressionChecking() {
		BoppiTests.checkFile("programs/simpleExpression.boppi");
		assertThat(BoppiTests.log, is(empty()));
	}

	/**
	 * Basic expressions with type errors
	 */
	@Test
	public void wrongExpressionChecking() {
		BoppiTests.checkString("+true");
		assertThat(BoppiTests.log, hasSize(1));

		BoppiTests.checkString("5 || true");
		assertThat(BoppiTests.log, hasSize(1));

		BoppiTests.checkString("6 + 'c'");
		assertThat(BoppiTests.log, hasSize(1));

		BoppiTests.checkString("4 + print(5, 6)");
		assertThat(BoppiTests.log, hasSize(1));

		BoppiTests.checkString("print(print(3, 5))");
		assertThat(BoppiTests.log, hasSize(1));
	}

	/**
	 * Correct basic expressions
	 */
	@Test
	public void correctExpressionGeneration() {
		BoppiTests.compileAndRunString("print(5*3)");
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("15")));

		BoppiTests.compileAndRunString("print('T', 'e', 's', 't', '!')");
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("T", "e", "s", "t", "!")));

		BoppiTests.compileAndRunFile("programs/simpleExpression.boppi");
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("1", "1", "3", "A", "false")));

		int n = RegisterPool.RECOMMENDED_REGISTER_COUNT+3;
		String expression = StringUtils.repeat("1+(", n) + "0" + StringUtils.repeat(")", n);

		BoppiTests.withWarnings(() -> {
			BoppiTests.compileAndRunString("print(" + expression + ")", "" + n);
			assertThat(BoppiTests.log, hasSize(1));
			assertThat(BoppiTests.log.get(0).getLevel(), is(Level.WARNING));
			assertThat(BoppiTests.out, is(arrayContaining(Integer.toString(n))));
		});
	}

	/**
	 * Basic expression with run-time error
	 */
	@Test
	public void wrongExpressionGeneration() {
		BoppiTests.compileAndRunString("1/0");
		assertThat(BoppiTests.log, hasSize(1));
		assertThat(BoppiTests.log.get(0).getMessage(), containsString("zero"));
	}

}
