11package com .thealgorithms .datastructures .stacks ;
22
33import static org .junit .jupiter .api .Assertions .assertEquals ;
4- import static org .junit .jupiter .api .Assertions .assertFalse ;
54import static org .junit .jupiter .api .Assertions .assertThrows ;
65import static org .junit .jupiter .api .Assertions .assertTrue ;
76
7+ import org .junit .jupiter .api .BeforeEach ;
8+ import org .junit .jupiter .api .DisplayName ;
89import org .junit .jupiter .api .Test ;
910
1011class 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