import junit.framework.TestCase.*
import org.junit.Before
import org.junit.Test
import kotlin.test.assertEquals
class Stack<T> {
private val elements: MutableList<T> = mutableListOf()
fun push(item: T) {
elements.add(item)
}
fun pop(): T? =
if (isEmpty()) null
else elements.removeAt(elements.size - 1)
fun peek(): T? = elements.lastOrNull()
fun isEmpty(): Boolean = elements.isEmpty()
fun size(): Int = elements.size
}
fun main() {
val intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
intStack.push(3)
val stringStack = Stack<String>()
stringStack.push("A")
stringStack.push("B")
stringStack.push("C")
println(intStack.peek()) // 3
while (!intStack.isEmpty()) { // 3, 2, 1
println(intStack.pop())
}
println(intStack.peek()) // null
println(intStack.isEmpty()) // true
println(stringStack.size()) // 3
while (!stringStack.isEmpty()) { // C, B, A
println(stringStack.pop())
}
}
class StackTest {
private lateinit var stack: Stack<Int>
@Before
fun setup() {
stack = Stack()
}
@Test
fun `when push is called, an element should be added to the stack`() {
stack.push(1)
assertEquals(1, stack.size())
assertEquals(1, stack.peek())
}
@Test
fun `when pop is called on a non-empty stack, the last element should be removed`() {
stack.push(1)
stack.push(2)
val poppedElement = stack.pop()
assertEquals(2, poppedElement)
assertEquals(1, stack.size())
assertEquals(1, stack.peek())
}
@Test
fun `when pop is called on an empty stack, it should return null`() {
val poppedElement = stack.pop()
assertNull(poppedElement)
assertTrue(stack.isEmpty())
}
@Test
fun `when peek is called, it should return the last element without removing it`() {
stack.push(1)
stack.push(2)
val peekedElement = stack.peek()
assertEquals(2, peekedElement)
assertEquals(2, stack.size())
}
@Test
fun `when peek is called on an empty stack, it should return null`() {
val peekedElement = stack.peek()
assertNull(peekedElement)
}
@Test
fun `when isEmpty is called on an empty stack, it should return true`() {
assertTrue(stack.isEmpty())
}
@Test
fun `when isEmpty is called on a non-empty stack, it should return false`() {
stack.push(1)
assertFalse(stack.isEmpty())
}
@Test
fun `size should accurately report the number of elements in the stack`() {
stack.push(1)
stack.push(2)
stack.push(3)
assertEquals(3, stack.size())
}
@Test
fun `consecutive pushes and pops should maintain stack integrity`() {
stack.push(1)
stack.push(2)
stack.push(3)
assertEquals(3, stack.pop())
assertEquals(2, stack.pop())
assertEquals(1, stack.pop())
assertTrue(stack.isEmpty())
}
@Test
fun `pushing null values should be supported`() {
val nullableStack: Stack<Int?> = Stack()
nullableStack.push(null)
assertNull(nullableStack.peek())
assertEquals(1, nullableStack.size())
}
@Test
fun `peek after multiple pushes should always return the last pushed element`() {
stack.push(1)
assertEquals(1, stack.peek())
stack.push(2)
assertEquals(2, stack.peek())
stack.push(3)
assertEquals(3, stack.peek())
}
}