@@ -117,28 +117,179 @@ struct TestRunner {
117117// Test cases to ensure correctness of StackWithMin operations.
118118void test () {
119119 TestRunner runner;
120+
121+ // 1) Empty stack behavior
122+ {
123+ StackWithMin<int > stack;
124+ runner.expectEqual (stack.min (), std::optional<int >{}, " min on empty" );
125+ runner.expectEqual (stack.top (), std::optional<int >{}, " top on empty" );
126+
127+ // If pop() is supposed to be safe on empty, this should not crash.
128+ stack.pop ();
129+ runner.expectEqual (stack.min (), std::optional<int >{}, " min still empty after pop on empty" );
130+ runner.expectEqual (stack.top (), std::optional<int >{}, " top still empty after pop on empty" );
131+ }
132+
133+ // 2) Basic push/pop + popping all the way to empty
120134 {
121135 StackWithMin<int > stack;
122136 stack.push (10 );
123137 stack.push (5 );
124138 stack.push (2 );
125139 runner.expectEqual (stack.min (), std::optional<int >(2 ), " min after push" );
126140 runner.expectEqual (stack.top (), std::optional<int >(2 ), " top after push" );
141+
127142 stack.pop ();
128143 runner.expectEqual (stack.min (), std::optional<int >(5 ), " min after pop" );
129144 runner.expectEqual (stack.top (), std::optional<int >(5 ), " top after pop" );
145+
146+ stack.pop (); // removes 5
147+ runner.expectEqual (stack.min (), std::optional<int >(10 ), " min after pop to single" );
148+ runner.expectEqual (stack.top (), std::optional<int >(10 ), " top after pop to single" );
149+
150+ stack.pop (); // removes 10 -> empty
151+ runner.expectEqual (stack.min (), std::optional<int >{}, " min after popping to empty" );
152+ runner.expectEqual (stack.top (), std::optional<int >{}, " top after popping to empty" );
130153 }
154+
155+ // 3) Negative values + restore
131156 {
132157 StackWithMin<int > stack;
133158 stack.push (-1 );
134159 stack.push (7 );
135160 stack.push (-2 );
136- runner.expectEqual (stack.min (), std::optional<int >(-2 ),
137- " min with negative " );
161+ runner.expectEqual (stack.min (), std::optional<int >(-2 ), " min with negative " );
162+
138163 stack.pop ();
139164 runner.expectEqual (stack.min (), std::optional<int >(-1 ), " min restored" );
140165 runner.expectEqual (stack.top (), std::optional<int >(7 ), " top restored" );
141166 }
167+
168+ // 4) Duplicate minimums (min should persist until ALL mins are popped)
169+ {
170+ StackWithMin<int > stack;
171+ stack.push (3 );
172+ stack.push (1 );
173+ stack.push (1 );
174+ stack.push (2 );
175+
176+ runner.expectEqual (stack.min (), std::optional<int >(1 ), " min with duplicates" );
177+ runner.expectEqual (stack.top (), std::optional<int >(2 ), " top with duplicates" );
178+
179+ stack.pop (); // pop 2
180+ runner.expectEqual (stack.min (), std::optional<int >(1 ), " min after popping non-min" );
181+ runner.expectEqual (stack.top (), std::optional<int >(1 ), " top after popping non-min" );
182+
183+ stack.pop (); // pop 1 (still another 1 remains)
184+ runner.expectEqual (stack.min (), std::optional<int >(1 ), " min remains after popping one duplicate min" );
185+ runner.expectEqual (stack.top (), std::optional<int >(1 ), " top now duplicate min" );
186+
187+ stack.pop (); // pop last 1, min should restore to 3
188+ runner.expectEqual (stack.min (), std::optional<int >(3 ), " min restores after all duplicate mins removed" );
189+ runner.expectEqual (stack.top (), std::optional<int >(3 ), " top restores after all duplicate mins removed" );
190+ }
191+
192+ // 5) All equal values
193+ {
194+ StackWithMin<int > stack;
195+ stack.push (4 );
196+ stack.push (4 );
197+ stack.push (4 );
198+
199+ runner.expectEqual (stack.min (), std::optional<int >(4 ), " min with all equal" );
200+ runner.expectEqual (stack.top (), std::optional<int >(4 ), " top with all equal" );
201+
202+ stack.pop ();
203+ runner.expectEqual (stack.min (), std::optional<int >(4 ), " min after pop with all equal" );
204+ stack.pop ();
205+ runner.expectEqual (stack.min (), std::optional<int >(4 ), " min after second pop with all equal" );
206+ stack.pop ();
207+ runner.expectEqual (stack.min (), std::optional<int >{}, " min after popping all equal to empty" );
208+ }
209+
210+ // 6) Monotonic increasing: min should stay first element until empty
211+ {
212+ StackWithMin<int > stack;
213+ stack.push (1 );
214+ stack.push (2 );
215+ stack.push (3 );
216+ stack.push (4 );
217+
218+ runner.expectEqual (stack.min (), std::optional<int >(1 ), " min in increasing sequence" );
219+ stack.pop (); // 4
220+ runner.expectEqual (stack.min (), std::optional<int >(1 ), " min after pop in increasing sequence" );
221+ stack.pop (); // 3
222+ runner.expectEqual (stack.min (), std::optional<int >(1 ), " min after second pop in increasing sequence" );
223+ }
224+
225+ // 7) Monotonic decreasing: min updates each push, restores each pop
226+ {
227+ StackWithMin<int > stack;
228+ stack.push (4 );
229+ runner.expectEqual (stack.min (), std::optional<int >(4 ), " min after push 4 (decreasing)" );
230+
231+ stack.push (3 );
232+ runner.expectEqual (stack.min (), std::optional<int >(3 ), " min after push 3 (decreasing)" );
233+
234+ stack.push (2 );
235+ runner.expectEqual (stack.min (), std::optional<int >(2 ), " min after push 2 (decreasing)" );
236+
237+ stack.push (1 );
238+ runner.expectEqual (stack.min (), std::optional<int >(1 ), " min after push 1 (decreasing)" );
239+
240+ stack.pop (); // 1
241+ runner.expectEqual (stack.min (), std::optional<int >(2 ), " min restores to 2 after popping 1" );
242+ stack.pop (); // 2
243+ runner.expectEqual (stack.min (), std::optional<int >(3 ), " min restores to 3 after popping 2" );
244+ stack.pop (); // 3
245+ runner.expectEqual (stack.min (), std::optional<int >(4 ), " min restores to 4 after popping 3" );
246+ }
247+
248+ // 8) Longer deterministic sequence: validate min after every push and pop
249+ {
250+ StackWithMin<int > stack;
251+
252+ // Push a sequence where the min changes a few times.
253+ // Values: 50, 49, ..., 26, 0, 25, 24, ..., 1
254+ int expectedMin = 1e9 ;
255+ for (int i = 50 ; i >= 26 ; --i) {
256+ stack.push (i);
257+ expectedMin = std::min (expectedMin, i);
258+ runner.expectEqual (stack.min (), std::optional<int >(expectedMin), " min after push in long sequence (part 1)" );
259+ }
260+
261+ stack.push (0 );
262+ expectedMin = 0 ;
263+ runner.expectEqual (stack.min (), std::optional<int >(0 ), " min after pushing 0 in long sequence" );
264+
265+ for (int i = 25 ; i >= 1 ; --i) {
266+ stack.push (i);
267+ runner.expectEqual (stack.min (), std::optional<int >(0 ), " min stays 0 in long sequence (part 2)" );
268+ }
269+
270+ // Now pop everything above 0; min should stay 0 until 0 is popped.
271+ for (int i = 1 ; i <= 25 ; ++i) {
272+ stack.pop ();
273+ runner.expectEqual (stack.min (), std::optional<int >(0 ), " min stays 0 while popping down to 0" );
274+ }
275+
276+ // Pop 0; min should restore to 26 (the smallest remaining from 26..50)
277+ stack.pop ();
278+ runner.expectEqual (stack.min (), std::optional<int >(26 ), " min restores after popping 0" );
279+
280+ // Pop remaining; min should climb upward as we remove 26,27,...
281+ for (int expected = 27 ; expected <= 50 ; ++expected) {
282+ stack.pop ();
283+ runner.expectEqual (stack.min (),
284+ (expected <= 50 ? std::optional<int >(expected) : std::optional<int >{}),
285+ " min after popping in long sequence tail" );
286+ }
287+
288+ // After all popped, empty
289+ runner.expectEqual (stack.min (), std::optional<int >{}, " min empty at end of long sequence" );
290+ runner.expectEqual (stack.top (), std::optional<int >{}, " top empty at end of long sequence" );
291+ }
292+
142293 runner.summary ();
143294}
144295
0 commit comments