Skip to content

Commit edb8167

Browse files
authored
testing: improve test coverage NodeStackTest (TheAlgorithms#6432)
* testing: improve test coverage NodeStackTest * style: fix style issues * testing: fix type * testing: fix import * testing: fix import
1 parent fc07cd8 commit edb8167

File tree

1 file changed

+179
-2
lines changed

1 file changed

+179
-2
lines changed

src/test/java/com/thealgorithms/datastructures/stacks/NodeStackTest.java

Lines changed: 179 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
11
package com.thealgorithms.datastructures.stacks;
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
4-
import static org.junit.jupiter.api.Assertions.assertFalse;
54
import static org.junit.jupiter.api.Assertions.assertThrows;
65
import static org.junit.jupiter.api.Assertions.assertTrue;
76

7+
import org.junit.jupiter.api.BeforeEach;
8+
import org.junit.jupiter.api.DisplayName;
89
import org.junit.jupiter.api.Test;
910

1011
class NodeStackTest {
1112

13+
private NodeStack<Integer> intStack;
14+
private NodeStack<String> stringStack;
15+
16+
@BeforeEach
17+
void setUp() {
18+
intStack = new NodeStack<>();
19+
stringStack = new NodeStack<>();
20+
}
21+
1222
@Test
23+
@DisplayName("Test push operation")
1324
void testPush() {
1425
NodeStack<Integer> stack = new NodeStack<>();
1526
stack.push(10);
@@ -18,6 +29,7 @@ void testPush() {
1829
}
1930

2031
@Test
32+
@DisplayName("Test pop operation")
2133
void testPop() {
2234
NodeStack<String> stack = new NodeStack<>();
2335
stack.push("First");
@@ -27,12 +39,14 @@ void testPop() {
2739
}
2840

2941
@Test
42+
@DisplayName("Test pop on empty stack throws exception")
3043
void testPopOnEmptyStack() {
3144
NodeStack<Double> stack = new NodeStack<>();
3245
assertThrows(IllegalStateException.class, stack::pop, "Popping an empty stack should throw IllegalStateException.");
3346
}
3447

3548
@Test
49+
@DisplayName("Test peek operation")
3650
void testPeek() {
3751
NodeStack<Integer> stack = new NodeStack<>();
3852
stack.push(5);
@@ -43,22 +57,25 @@ void testPeek() {
4357
}
4458

4559
@Test
60+
@DisplayName("Test peek on empty stack throws exception")
4661
void testPeekOnEmptyStack() {
4762
NodeStack<String> stack = new NodeStack<>();
4863
assertThrows(IllegalStateException.class, stack::peek, "Peeking an empty stack should throw IllegalStateException.");
4964
}
5065

5166
@Test
67+
@DisplayName("Test isEmpty method")
5268
void testIsEmpty() {
5369
NodeStack<Character> stack = new NodeStack<>();
5470
assertTrue(stack.isEmpty(), "Newly initialized stack should be empty.");
5571
stack.push('A');
56-
assertFalse(stack.isEmpty(), "Stack should not be empty after a push operation.");
72+
org.junit.jupiter.api.Assertions.assertFalse(stack.isEmpty(), "Stack should not be empty after a push operation.");
5773
stack.pop();
5874
assertTrue(stack.isEmpty(), "Stack should be empty after popping the only element.");
5975
}
6076

6177
@Test
78+
@DisplayName("Test size method")
6279
void testSize() {
6380
NodeStack<Integer> stack = new NodeStack<>();
6481
assertEquals(0, stack.size(), "Size of empty stack should be 0.");
@@ -70,4 +87,164 @@ void testSize() {
7087
stack.pop();
7188
assertEquals(0, stack.size(), "Size should be 0 after popping all elements.");
7289
}
90+
91+
@Test
92+
@DisplayName("Test push and pop with null values")
93+
void testPushPopWithNull() {
94+
stringStack.push(null);
95+
stringStack.push("not null");
96+
stringStack.push(null);
97+
98+
assertEquals(3, stringStack.size(), "Stack should contain 3 elements including nulls");
99+
org.junit.jupiter.api.Assertions.assertNull(stringStack.pop(), "Should pop null value");
100+
assertEquals("not null", stringStack.pop(), "Should pop 'not null' value");
101+
org.junit.jupiter.api.Assertions.assertNull(stringStack.pop(), "Should pop null value");
102+
assertTrue(stringStack.isEmpty(), "Stack should be empty after popping all elements");
103+
}
104+
105+
@Test
106+
@DisplayName("Test LIFO (Last In First Out) behavior")
107+
void testLifoBehavior() {
108+
int[] values = {1, 2, 3, 4, 5};
109+
110+
// Push values in order
111+
for (int value : values) {
112+
intStack.push(value);
113+
}
114+
115+
// Pop values should be in reverse order
116+
for (int i = values.length - 1; i >= 0; i--) {
117+
assertEquals(values[i], intStack.pop(), "Elements should be popped in LIFO order");
118+
}
119+
}
120+
121+
@Test
122+
@DisplayName("Test peek doesn't modify stack")
123+
void testPeekDoesNotModifyStack() {
124+
intStack.push(1);
125+
intStack.push(2);
126+
intStack.push(3);
127+
128+
int originalSize = intStack.size();
129+
int peekedValue = intStack.peek();
130+
131+
assertEquals(3, peekedValue, "Peek should return top element");
132+
assertEquals(originalSize, intStack.size(), "Peek should not change stack size");
133+
assertEquals(3, intStack.peek(), "Multiple peeks should return same value");
134+
org.junit.jupiter.api.Assertions.assertFalse(intStack.isEmpty(), "Peek should not make stack empty");
135+
}
136+
137+
@Test
138+
@DisplayName("Test mixed push and pop operations")
139+
void testMixedOperations() {
140+
// Test interleaved push/pop operations
141+
intStack.push(1);
142+
assertEquals(1, intStack.pop());
143+
assertTrue(intStack.isEmpty());
144+
145+
intStack.push(2);
146+
intStack.push(3);
147+
assertEquals(3, intStack.pop());
148+
intStack.push(4);
149+
assertEquals(4, intStack.peek());
150+
assertEquals(2, intStack.size());
151+
152+
assertEquals(4, intStack.pop());
153+
assertEquals(2, intStack.pop());
154+
assertTrue(intStack.isEmpty());
155+
}
156+
157+
@Test
158+
@DisplayName("Test stack with duplicate values")
159+
void testStackWithDuplicates() {
160+
intStack.push(1);
161+
intStack.push(1);
162+
intStack.push(1);
163+
164+
assertEquals(3, intStack.size(), "Stack should handle duplicate values");
165+
assertEquals(1, intStack.peek(), "Peek should return duplicate value");
166+
167+
assertEquals(1, intStack.pop(), "Should pop first duplicate");
168+
assertEquals(1, intStack.pop(), "Should pop second duplicate");
169+
assertEquals(1, intStack.pop(), "Should pop third duplicate");
170+
assertTrue(intStack.isEmpty(), "Stack should be empty after popping all duplicates");
171+
}
172+
173+
@Test
174+
@DisplayName("Test stack with different data types")
175+
void testDifferentDataTypes() {
176+
NodeStack<Character> charStack = new NodeStack<>();
177+
NodeStack<Boolean> booleanStack = new NodeStack<>();
178+
179+
// Test with Character
180+
charStack.push('A');
181+
charStack.push('Z');
182+
assertEquals('Z', charStack.peek(), "Should handle Character values");
183+
184+
// Test with Boolean
185+
booleanStack.push(Boolean.TRUE);
186+
booleanStack.push(Boolean.FALSE);
187+
assertEquals(Boolean.FALSE, booleanStack.peek(), "Should handle Boolean values");
188+
}
189+
190+
@Test
191+
@DisplayName("Test stack state consistency after exceptions")
192+
void testStateConsistencyAfterExceptions() {
193+
// Stack should remain consistent after exception-throwing operations
194+
intStack.push(1);
195+
intStack.push(2);
196+
197+
// Try to peek and pop normally first
198+
assertEquals(2, intStack.peek());
199+
assertEquals(2, intStack.pop());
200+
assertEquals(1, intStack.size());
201+
202+
// Pop remaining element
203+
assertEquals(1, intStack.pop());
204+
assertTrue(intStack.isEmpty());
205+
206+
// Now stack is empty, operations should throw exceptions
207+
assertThrows(IllegalStateException.class, intStack::peek);
208+
assertThrows(IllegalStateException.class, intStack::pop);
209+
210+
// Stack should still be in valid empty state
211+
assertTrue(intStack.isEmpty());
212+
assertEquals(0, intStack.size());
213+
214+
// Should be able to push after exceptions
215+
intStack.push(3);
216+
org.junit.jupiter.api.Assertions.assertFalse(intStack.isEmpty());
217+
assertEquals(1, intStack.size());
218+
assertEquals(3, intStack.peek());
219+
}
220+
221+
@Test
222+
@DisplayName("Test single element stack operations")
223+
void testSingleElementStack() {
224+
intStack.push(2);
225+
226+
org.junit.jupiter.api.Assertions.assertFalse(intStack.isEmpty(), "Stack with one element should not be empty");
227+
assertEquals(1, intStack.size(), "Size should be 1");
228+
assertEquals(2, intStack.peek(), "Peek should return the single element");
229+
assertEquals(1, intStack.size(), "Peek should not change size");
230+
231+
assertEquals(2, intStack.pop(), "Pop should return the single element");
232+
assertTrue(intStack.isEmpty(), "Stack should be empty after popping single element");
233+
assertEquals(0, intStack.size(), "Size should be 0 after popping single element");
234+
}
235+
236+
@Test
237+
@DisplayName("Test toString method if implemented")
238+
void testToString() {
239+
// This test assumes NodeStack has a toString method
240+
// If not implemented, this test can be removed or NodeStack can be enhanced
241+
intStack.push(1);
242+
intStack.push(2);
243+
intStack.push(3);
244+
245+
String stackString = intStack.toString();
246+
// Basic check that toString doesn't throw exception and returns something
247+
assertTrue(stackString != null, "toString should not return null");
248+
assertTrue(stackString.length() > 0, "toString should return non-empty string");
249+
}
73250
}

0 commit comments

Comments
 (0)