/*
 * Copyright (c) 2012 Ray A. Conner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package com.github.rconner.util;

import com.google.common.collect.Lists;
import org.junit.Test;

import java.util.Arrays;
import java.util.EmptyStackException;

import static com.github.rconner.util.IterableTest.assertIteratorContains;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

public class ImmutableStackTest {

    private static <E> void assertStackContains(ImmutableStack<E> stack, E... elements) {

        // These are repeated intentionally, to make sure invoking iterator() or reverse() does not change state.

        assertIteratorContains(stack.iterator(), elements);
        assertIteratorContains(stack.iterator(), elements);

        Iterable<E> reverse = stack.reverse();
        Object[] expectedReverse = Lists.reverse(Lists.newArrayList(elements)).toArray();
        assertIteratorContains(reverse.iterator(), expectedReverse);
        assertIteratorContains(reverse.iterator(), expectedReverse);

        assertThat(stack.size(), is(elements.length));

        if (elements.length == 0) {
            try {
                stack.peek();
                fail("Should throw EmptyStackException.");
            } catch (EmptyStackException ignored) {
                // expected
            }
            try {
                stack.pop();
                fail("Should throw EmptyStackException.");
            } catch (EmptyStackException ignored) {
                // expected
            }
        } else {
            assertThat(stack.peek(), is(elements[0]));
            assertStackContains(stack.pop(), Arrays.copyOfRange(elements, 1, elements.length));
        }

        // Test them again to make sure following the head/tail references didn't change state.

        assertIteratorContains(stack.iterator(), elements);
        assertIteratorContains(stack.reverse().iterator(), expectedReverse);
        assertThat(stack.size(), is(elements.length));
    }

    @Test
    @SuppressWarnings("unchecked")
    public void testEmpty() {
        ImmutableStack<Integer> stack = ImmutableStack.of();
        assertStackContains(stack);
        assertStackContains(stack.push(101).push(102), 102, 101);
        assertStackContains(stack);
    }

    @Test
    public void testSingle() {
        ImmutableStack<Integer> stack = ImmutableStack.of(42);
        assertStackContains(stack, 42);
        assertStackContains(stack.push(101).push(102), 102, 101, 42);
        assertStackContains(stack, 42);
    }

    @Test
    public void testMany() {
        ImmutableStack<Integer> stack = ImmutableStack.of(11, 7, 5, 3, 2);
        assertStackContains(stack, 2, 3, 5, 7, 11);
        assertStackContains(stack.push(101).push(102), 102, 101, 2, 3, 5, 7, 11);
        assertStackContains(stack, 2, 3, 5, 7, 11);
    }

    // TODO: test other methods
}

@@ -1710,32 +1710,200 @@
  change state.%0A%0A
+        for (E element : elements) %7B%0A            assertThat(stack.contains(element), is(true));%0A        %7D%0A        assertThat(stack.contains(new Object()), is(false));%0A%0A
         assertIt
@@ -1938,32 +1938,32 @@
 r(), elements);%0A
-
         assertIt
@@ -2371,24 +2371,75 @@
 gth == 0) %7B%0A
+            assertThat(stack.isEmpty(), is(true));%0A
             
@@ -2819,32 +2819,32 @@
 d%0A            %7D%0A
-
         %7D else %7B
@@ -2844,16 +2844,68 @@
  else %7B%0A
+            assertThat(stack.isEmpty(), is(false));%0A
         
@@ -4205,40 +4205,7 @@
    %7D
-%0A%0A    // TODO: test other methods
 %0A%7D%0A

Test new methods.