package pp.s1184725.boppi.test;

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

/**
 * Tests for function closures, mostly testing runtime correctness and garbage
 * collection.
 * 
 * @author Frank Wibbelink
 */
public class ClosureTest {
	private int fib(int n) {
		return (n < 2) ? 1 : fib(n - 1) + fib(n - 2);
	}

	/**
	 * Correct closure parsing
	 */
	@Test
	public void correctClosureParsing() {
		BoppiTests.parseFile("programs/closure1.boppi");
		assertThat(BoppiTests.log, is(empty()));

		BoppiTests.parseFile("programs/closure2.boppi");
		assertThat(BoppiTests.log, is(empty()));
	}

	/**
	 * Correct closure checking
	 */
	@Test
	public void correctClosureChecking() {
		BoppiTests.checkFile("programs/closure1.boppi");
		assertThat(BoppiTests.log, is(empty()));

		BoppiTests.checkFile("programs/closure2.boppi");
		assertThat(BoppiTests.log, is(empty()));
	}

	/**
	 * Correct closure use
	 */
	@Test
	public void correctClosureGeneration() {
		BoppiTests.compileAndRunFile("programs/closure1.boppi");
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("8", "9")));

		BoppiTests.compileAndRunFile("programs/closure2.boppi");
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("8", "7", "15", "2")));

		BoppiTests.compileAndRunFile("programs/closure3.boppi");
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining("7", "15", "2")));

		BoppiTests.compileAndRunFile("programs/fibonacciRecursive.boppi", "1", "20", "30", "31", "0");
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
		assertThat(BoppiTests.log, is(empty()));
		assertThat(BoppiTests.out, is(arrayContaining(Integer.toString(fib(1)), Integer.toString(fib(20)),
				Integer.toString(fib(30)), Integer.toString(fib(31)))));
	}

	/**
	 * Test garbage collection. Nothing must be allocated at the end of the
	 * program.
	 */
	@Ignore("Disabled as long as closures do not nicely clean memory.")
	@Test
	public void correctClosureCleanup() {
		BoppiTests.compileAndRunFile("programs/closure1.boppi");
		assertThat(BoppiTests.vm.load(0), is(4));

		BoppiTests.compileAndRunFile("programs/closure2.boppi");
		assertThat(BoppiTests.vm.load(0), is(4));

		BoppiTests.compileAndRunFile("programs/closure3.boppi");
		assertThat(BoppiTests.vm.load(0), is(4));
	}

}
