diff --git a/sentry/src/test/java/io/sentry/CircularFifoQueueTest.kt b/sentry/src/test/java/io/sentry/CircularFifoQueueTest.kt new file mode 100644 index 0000000000..7a744ba95f --- /dev/null +++ b/sentry/src/test/java/io/sentry/CircularFifoQueueTest.kt @@ -0,0 +1,224 @@ +package io.sentry + +import java.util.NoSuchElementException +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertNull +import kotlin.test.assertTrue + +class CircularFifoQueueTest { + + @Test + fun `constructor with size creates empty queue with given max size`() { + val queue = CircularFifoQueue(5) + assertEquals(0, queue.size) + assertEquals(5, queue.maxSize()) + assertTrue(queue.isEmpty()) + } + + @Test + fun `constructor rejects zero size`() { + assertFailsWith { CircularFifoQueue(0) } + } + + @Test + fun `constructor rejects negative size`() { + assertFailsWith { CircularFifoQueue(-1) } + } + + @Test + fun `default constructor creates queue with max size 32`() { + val queue = CircularFifoQueue() + assertEquals(32, queue.maxSize()) + } + + @Test + fun `add increases size`() { + val queue = CircularFifoQueue(3) + queue.add("a") + assertEquals(1, queue.size) + queue.add("b") + assertEquals(2, queue.size) + } + + @Test + fun `peek returns first element without removing it`() { + val queue = CircularFifoQueue(3) + queue.add("a") + queue.add("b") + assertEquals("a", queue.peek()) + assertEquals(2, queue.size) + } + + @Test + fun `peek returns null on empty queue`() { + val queue = CircularFifoQueue(3) + assertNull(queue.peek()) + } + + @Test + fun `poll removes and returns first element`() { + val queue = CircularFifoQueue(3) + queue.add("a") + queue.add("b") + assertEquals("a", queue.poll()) + assertEquals(1, queue.size) + } + + @Test + fun `poll returns null on empty queue`() { + val queue = CircularFifoQueue(3) + assertNull(queue.poll()) + } + + @Test + fun `remove throws on empty queue`() { + val queue = CircularFifoQueue(3) + assertFailsWith { queue.remove() } + } + + @Test + fun `element throws on empty queue`() { + val queue = CircularFifoQueue(3) + assertFailsWith { queue.element() } + } + + @Test + fun `element returns first element without removing it`() { + val queue = CircularFifoQueue(3) + queue.add("a") + assertEquals("a", queue.element()) + assertEquals(1, queue.size) + } + + @Test + fun `overflow evicts oldest element`() { + val queue = CircularFifoQueue(3) + queue.add("a") + queue.add("b") + queue.add("c") + queue.add("d") // evicts "a" + assertEquals(3, queue.size) + assertEquals("b", queue.peek()) + } + + @Test + fun `isAtFullCapacity returns true when queue is full`() { + val queue = CircularFifoQueue(2) + assertFalse(queue.isAtFullCapacity) + queue.add("a") + assertFalse(queue.isAtFullCapacity) + queue.add("b") + assertTrue(queue.isAtFullCapacity) + } + + @Test + fun `isFull always returns false`() { + val queue = CircularFifoQueue(2) + assertFalse(queue.isFull) + queue.add("a") + queue.add("b") + assertFalse(queue.isFull) + } + + @Test + fun `get returns element at index`() { + val queue = CircularFifoQueue(5) + queue.add("a") + queue.add("b") + queue.add("c") + assertEquals("a", queue.get(0)) + assertEquals("b", queue.get(1)) + assertEquals("c", queue.get(2)) + } + + @Test + fun `get throws for negative index`() { + val queue = CircularFifoQueue(3) + queue.add("a") + assertFailsWith { queue.get(-1) } + } + + @Test + fun `get throws for index out of range`() { + val queue = CircularFifoQueue(3) + queue.add("a") + assertFailsWith { queue.get(1) } + } + + @Test + fun `clear resets the queue`() { + val queue = CircularFifoQueue(3) + queue.add("a") + queue.add("b") + queue.clear() + assertEquals(0, queue.size) + assertTrue(queue.isEmpty()) + assertNull(queue.peek()) + } + + @Test + fun `iterator returns elements in insertion order`() { + val queue = CircularFifoQueue(5) + queue.add("a") + queue.add("b") + queue.add("c") + assertEquals(listOf("a", "b", "c"), queue.toList()) + } + + @Test + fun `iterator returns elements in order after overflow`() { + val queue = CircularFifoQueue(3) + queue.add("a") + queue.add("b") + queue.add("c") + queue.add("d") // evicts "a" + queue.add("e") // evicts "b" + assertEquals(listOf("c", "d", "e"), queue.toList()) + } + + @Test + fun `offer delegates to add`() { + val queue = CircularFifoQueue(3) + assertTrue(queue.offer("a")) + assertEquals(1, queue.size) + assertEquals("a", queue.peek()) + } + + @Test + fun `constructor from collection copies elements`() { + val source = listOf("a", "b", "c") + val queue = CircularFifoQueue(source) + assertEquals(3, queue.size) + assertEquals(3, queue.maxSize()) + assertEquals(listOf("a", "b", "c"), queue.toList()) + } + + @Test + fun `get works correctly after wrap-around`() { + val queue = CircularFifoQueue(3) + queue.add("a") + queue.add("b") + queue.add("c") + queue.add("d") // wraps: [d, b, c] with start=1 + assertEquals("b", queue.get(0)) + assertEquals("c", queue.get(1)) + assertEquals("d", queue.get(2)) + } + + @Test + fun `multiple add and remove cycles work correctly`() { + val queue = CircularFifoQueue(3) + queue.add("a") + queue.add("b") + assertEquals("a", queue.remove()) + queue.add("c") + queue.add("d") + assertEquals("b", queue.remove()) + assertEquals("c", queue.remove()) + assertEquals("d", queue.remove()) + assertTrue(queue.isEmpty()) + } +}