package pp.s1184725.boppi.test;

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

/**
 * Test cases for fixed-size arrays.
 * 
 * @author Frank Wibbelink
 */
public class ArrayTest {

	/**
	 * Correct array parsing
	 */
	@Test
	public void correctArrayParsing() {
		BoppiTests.parseFile("programs/simpleArray.boppi");
		assertThat(BoppiTests.log, empty());
	}

	/**
	 * Arrays with syntax errors
	 */
	@Test
	public void wrongArrayParsing() {
		BoppiTests.parseString("var []int arr; 0");
		assertThat(BoppiTests.log, not(empty()));

		BoppiTests.parseString("var int[6] arr; 0");
		assertThat(BoppiTests.log, not(empty()));

		BoppiTests.parseString("var int[[]] a; 0");
		assertThat(BoppiTests.log, not(empty()));

		BoppiTests.parseString("var int[] arr; (arr)[5]");
		assertThat(BoppiTests.log, hasSize(1));

		BoppiTests.parseString("var int[] arr; arr := array(5)");
		assertThat(BoppiTests.log, hasSize(1));
	}

	/**
	 * Correct array checking
	 */
	@Test
	public void correctArrayChecking() {
		BoppiTests.checkFile("programs/simpleArray.boppi");
		assertThat(BoppiTests.log, is(empty()));
	}

	/**
	 * Arrays with type errors
	 */
	@Test
	public void wrongArrayChecking() {
		BoppiTests.checkString("var int a; a[5]");
		assertThat(BoppiTests.log, not(empty()));

		BoppiTests.checkString("var int[] arr; arr := 5");
		assertThat(BoppiTests.log, not(empty()));

		BoppiTests.checkString("var int[] arr; arr[4][2] := 5");
		assertThat(BoppiTests.log, not(empty()));

		BoppiTests.checkString("var int a; var int[] arr; a := arr");
		assertThat(BoppiTests.log, not(empty()));

		BoppiTests.checkString("var int[] arr; arr := array(char, 5)");
		assertThat(BoppiTests.log, not(empty()));

		BoppiTests.checkString("var int[] arr; arr := ['a', 'c']");
		assertThat(BoppiTests.log, not(empty()));
	}

	/**
	 * Uninitialized arrays
	 */
	@Test
	public void wrongArrayChecking2() {
		BoppiTests.checkString("var int[] a; a[5]");
		assertThat(BoppiTests.log, not(empty()));

		BoppiTests.checkString("var int[] a; var int[] b; a := b; a[0]");
		assertThat(BoppiTests.log, not(empty()));
	}

	/**
	 * Correct array generation
	 */
	@Test
	public void correctArrayGeneration() {
		BoppiTests.compileAndRunString("var int n; read(n); var int[] arr; arr := array(int, n); print(arr.length)", "7");
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("7")));

		BoppiTests.compileAndRunFile("programs/simpleArray.boppi");
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("9", "H", "a", "Y")));

		BoppiTests.compileAndRunFile("programs/complexArray.boppi");
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("1337", "13", "2", "15")));
		
		BoppiTests.compileAndRunString("var int[][] m; m := [[1,3]]; m[0]; var int[] a; a := [8,9]; print(m[0][1])");
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("3")));
		
		BoppiTests.compileAndRunString("print([1,2]==[1,2],[1,2]<>[1,2],[1]==[1,2],[0]<>[2])");
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("true", "false", "false", "true")));
		
		BoppiTests.compileAndRunFile("programs/arrayFunctions.boppi", "Hello");
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("Hi;Hello;1337")));
	}

	/**
	 * Out of bounds checking
	 */
	@Test
	public void wrongArrayGeneration() {
		BoppiTests.compileAndRunString("var int[] arr; arr := array(int, 10); arr[10] := 5");
		assertThat(BoppiTests.vm.getInterrupt(), is(not(0)));

		BoppiTests.compileAndRunString("var int[] arr; arr := array(int, 10); arr[-1]");
		assertThat(BoppiTests.vm.getInterrupt(), is(not(0)));

		BoppiTests.compileAndRunString("var int[] arr; arr := array(int, -1)");
		assertThat(BoppiTests.vm.getInterrupt(), is(not(0)));
	}

}
