package monads;

import static org.junit.Assert.assertEquals;
import static monads.Stack.*;
import static monads.Pair.*;

import org.junit.Test;

public class StackTest {
	
	private static final Object A = new Object();
	private static final Object B = new Object();

	private Pair pair = pair(empty());

	@Test public void
	starts_empty() {
		assertEquals(empty(), pair.stack);
	}
	
	@Test(expected = Exception.class) public void
	forbids_pop_when_empty() {
		Stack.pop(pair.stack);
	}
	
	private static interface StackFunction {
		Pair eval(Stack stack);
	}
	private static class StackPush implements StackFunction {
		private Object value;

		public StackPush(Object value) {
			this.value = value;
		}

		public Pair eval(Stack stack) {
			return Stack.push(stack, value);
		}
	}
	private StackPush push(Object value) {
		return new StackPush(value);
	}
	
	private static class StackPop implements StackFunction {
		public Pair eval(Stack stack) {
			return Stack.pop(stack);
		}
	}
	private StackPop pop() {
		return new StackPop();
	}
	
	@Test public void
	pushes_and_pops_an_objects() {	
		pair = push(A).eval(pair.stack);
		pair = pop().eval(pair.stack);

		assertEquals(A, pair.value);
		assertEquals(empty(), pair.stack);
	}

	@Test public void
	pops_objects_in_reverse_push_order() {
		pair = push(A).eval(pair.stack);
		pair = push(B).eval(pair.stack);
		
		pair = pop().eval(pair.stack);
		assertEquals(B, pair.value);

		pair = pop().eval(pair.stack);
		assertEquals(A, pair.value);

		assertEquals(empty(), pair.stack);
	}
}

@@ -454,26 +454,400 @@
 y() %7B%0A%09%09
-Stack.pop(
+do_(pop());%0A%09%7D%0A%09%0A%09%0A%09@Test public void%0A%09pushes_and_pops_an_objects() %7B%09%0A%09%09do_(push(A));%0A%09%09do_(pop());%0A%0A%09%09assertEquals(A, pair.value);%0A%09%09assertEquals(empty(), pair.stack);%0A%09%7D%0A%0A%09@Test public void%0A%09pops_objects_in_reverse_push_order() %7B%0A%09%09do_(push(A));%0A%09%09do_(push(B));%0A%09%09%0A%09%09do_(pop());%0A%09%09assertEquals(B, pair.value);%0A%0A%09%09do_(pop());%0A%09%09assertEquals(A, pair.value);%0A%0A%09%09assertEquals(empty(), 
 pair.sta
@@ -850,25 +850,24 @@
 .stack);%0A%09%7D%0A
-%09
 %0A%09private st
@@ -922,24 +922,111 @@
  stack);%0A%09%7D%0A
+%0A%09private void do_(StackFunction operation) %7B%0A%09%09pair = operation.eval(pair.stack);%0A%09%7D%0A%0A
 %09private sta
@@ -1498,503 +1498,6 @@
 %0A%09%7D%0A
-%09%0A%09@Test public void%0A%09pushes_and_pops_an_objects() %7B%09%0A%09%09pair = push(A).eval(pair.stack);%0A%09%09pair = pop().eval(pair.stack);%0A%0A%09%09assertEquals(A, pair.value);%0A%09%09assertEquals(empty(), pair.stack);%0A%09%7D%0A%0A%09@Test public void%0A%09pops_objects_in_reverse_push_order() %7B%0A%09%09pair = push(A).eval(pair.stack);%0A%09%09pair = push(B).eval(pair.stack);%0A%09%09%0A%09%09pair = pop().eval(pair.stack);%0A%09%09assertEquals(B, pair.value);%0A%0A%09%09pair = pop().eval(pair.stack);%0A%09%09assertEquals(A, pair.value);%0A%0A%09%09assertEquals(empty(), pair.stack);%0A%09%7D%0A
 %7D%0A

Use a do_ method to execute the stack operations