/*
 * Copyright 2017 Romuald OUATTARA
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.ouattararomuald.datastructures

import org.junit.Before
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue

internal class StackTest {
  val NUMBER_OF_ITEMS_TO_INSERT = 10

  private lateinit var stack: Stack<Int>

  @Before
  fun setUp() {
    stack = Stack()
  }

  @Test
  fun isEmpty() {
    assertTrue(stack.isEmpty)
    for (i in 1..NUMBER_OF_ITEMS_TO_INSERT) {
      stack.push(i)
    }
    assertFalse(stack.isEmpty)
    for (i in 1..NUMBER_OF_ITEMS_TO_INSERT) {
      stack.pop()
    }
    assertTrue(stack.isEmpty)
  }

  @Test
  fun peek() {
    for (i in 1..NUMBER_OF_ITEMS_TO_INSERT) {
      stack.push(i)
    }
    (NUMBER_OF_ITEMS_TO_INSERT downTo 1).forEach {
      assertEquals(it, stack.peek())
      stack.pop()
    }
  }

  @Test
  fun peekWhenEmptyShouldFail() {
    assertTrue(stack.isEmpty)
    assertFailsWith(UnderflowException::class) {
      stack.peek()
    }

  }

  @Test
  fun pop() {
    for (i in 1..NUMBER_OF_ITEMS_TO_INSERT) {
      stack.push(i)
    }
    (NUMBER_OF_ITEMS_TO_INSERT downTo 1).forEach { assertEquals(it, stack.pop()) }
  }

  @Test
  fun popWhenEmptyShouldFail() {
    assertTrue(stack.isEmpty)
    assertFailsWith(UnderflowException::class) {
      stack.pop()
    }
  }

  @Test
  fun push() {
    assertTrue(stack.isEmpty)
    for (i in 1..NUMBER_OF_ITEMS_TO_INSERT) {
      stack.push(i)
      assertEquals(i, stack.size)
    }
    assertFalse(stack.isEmpty)
    assertEquals(NUMBER_OF_ITEMS_TO_INSERT, stack.size)
  }
}