package lab.util; import static org.junit.Assert.*; import java.math.BigInteger; import org.junit.Test; public class FibonacciStackFrameTest { @Test public void testConstructor() { FibonacciStackFrame f = new FibonacciStackFrame(100, null); assertEquals("constructor failed to set this.n correctly", 100, f.getN()); assertNull("constructor failed to set this.caller correctly", f.getCaller()); BigInteger fMinus1 = f.getfMinus1(); if (fMinus1 != null) { assertTrue("constructor failed to set this.fMinus1 to null or a value less than zero", fMinus1.compareTo(BigInteger.ZERO) < 0); } BigInteger fMinus2 = f.getfMinus2(); if (fMinus2 != null) { assertTrue("constructor failed to set this.fMinus2 to null or a value less than zero", fMinus2.compareTo(BigInteger.ZERO) < 0); } BigInteger sum = f.getSum(); if (sum != null) { assertTrue("constructor failed to set this.sum to null or a value less than or equal to zero", sum.compareTo(BigInteger.ZERO) <= 0); } } @Test public void testConstructorThrows() { try { FibonacciStackFrame f = new FibonacciStackFrame(-1, null); fail("constructor failed throw an exception"); } catch (IllegalArgumentException x) { // ok, this exception is expected } } @Test public void testReceiveReturnValue() { FibonacciStackFrame f = new FibonacciStackFrame(100, null); f.receiveReturnValue(BigInteger.TEN); if (f.getfMinus1() != null && f.getfMinus2() != null) { assertTrue("receiveReturnValue failed to set this.fMinus1 or this.fMinus2 correctly", f.getfMinus1().equals(BigInteger.TEN) || f.getfMinus2().equals(BigInteger.TEN)); } else if (f.getfMinus1() != null) { assertTrue("receiveReturnValue failed to set this.fMinus1 correctly", f.getfMinus1().equals(BigInteger.TEN)); } else if (f.getfMinus2() != null) { assertTrue("receiveReturnValue failed to set this.fMinus2 correctly", f.getfMinus2().equals(BigInteger.TEN)); } else { fail("receiveReturnValue failed to set this.fMinus1 or this.fMinus2 correctly"); } f.receiveReturnValue(BigInteger.TEN); if (f.getfMinus1() != null && f.getfMinus2() != null) { assertTrue("receiveReturnValue failed to set this.fMinus1 or this.fMinus2 correctly", f.getfMinus1().equals(BigInteger.TEN) && f.getfMinus2().equals(BigInteger.TEN)); } else { fail("receiveReturnValue failed to set this.fMinus1 or this.fMinus2 correctly"); } } @Test public void testReceiveReturnValueThrows() { FibonacciStackFrame f = new FibonacciStackFrame(100, null); f.receiveReturnValue(BigInteger.ONE); f.receiveReturnValue(BigInteger.ONE); try { f.receiveReturnValue(BigInteger.ONE); fail("receiveReturnValue should have thrown an exception"); } catch (IllegalStateException ex) { // ok, this exception is expected } } @Test public void testReturnValueToCaller() { Stack callStack = new Stack(); FibonacciStackFrame f1 = new FibonacciStackFrame(100, null); FibonacciStackFrame f2 = new FibonacciStackFrame(100, f1); callStack.push(f1); callStack.push(f2); f2.returnValueToCaller(BigInteger.TEN, callStack); assertTrue("returnValueToCaller failed to return the correct value to the caller", BigInteger.TEN.equals(f1.getfMinus1()) || BigInteger.TEN.equals(f1.getfMinus2())); assertTrue("returnValueToCaller failed to pop the call stack correctly", callStack.peek() == f1); } @Test public void testGetSum() { // compute F(10000); BigInteger f[] = new BigInteger[10001]; f[0] = BigInteger.ZERO; f[1] = BigInteger.ONE; for (int i = 2; i < f.length; i++) { f[i] = f[i - 1].add(f[i - 2]); } BigInteger got = Fibonacci.fib2(10000); assertEquals("", got, Fibonacci.fib2(10000)); } @Test public void testExecute() { Stack callStack = new Stack(); FibonacciStackFrame f0 = new FibonacciStackFrame(0, null); callStack.push(f0); f0.execute(callStack); assertTrue("execute did not set this.sum correctly for F(0)", BigInteger.ZERO.equals(f0.getSum())); assertTrue("execute did not invoke returnValueToCaller for F(0)", callStack.isEmpty()); FibonacciStackFrame f1 = new FibonacciStackFrame(1, null); callStack.push(f1); f1.execute(callStack); assertTrue("execute did not set this.sum correctly for F(1)", BigInteger.ONE.equals(f1.getSum())); assertTrue("execute did not invoke returnValueToCaller for F(1)", callStack.isEmpty()); // must clear the cache before testing the next part FibonacciStackFrame.getCache().clear(); FibonacciStackFrame f2 = new FibonacciStackFrame(2, null); callStack.push(f2); f2.execute(callStack); assertEquals("execute did not push a new frame for F(1) onto the call stack when executing F(2)", 2, callStack.size()); assertEquals("execute did not push a new frame for F(1) onto the call stack when executing F(2)", 1, callStack.peek().getN()); callStack.peek().execute(callStack); // should pop F(1) callStack.peek().execute(callStack); // should resume execution of F(2) assertEquals("execute did not push a new frame for F(0) onto the call stack when executing F(2)", 2, callStack.size()); assertEquals("execute did not push a new frame for F(0) onto the call stack when executing F(2)", 0, callStack.peek().getN()); callStack.peek().execute(callStack); // should pop F(0) callStack.peek().execute(callStack); // should complete execution of F(2) assertTrue("execute did not set this.sum correctly for F(2)", BigInteger.ONE.equals(f2.getSum())); assertTrue("execute did not invoke returnValueToCaller for F(2)", callStack.isEmpty()); FibonacciStackFrame f2again = new FibonacciStackFrame(2, null); // result should be in cache callStack.push(f2again); f2again.execute(callStack); assertTrue("execute did not set this.sum correctly for F(2)", BigInteger.ONE.equals(f2again.getSum())); assertTrue("execute did not return the value of F(2) from the cache", callStack.isEmpty()); } }