Skip to content

Commit a2c3409

Browse files
author
Arun Prasaad
committed
Add another stack example, with slightly different reading style
1 parent d5bec12 commit a2c3409

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
package org.example;
2+
3+
import org.junit.jupiter.api.DisplayNameGeneration;
4+
import org.junit.jupiter.api.DisplayNameGenerator;
5+
import org.junit.jupiter.api.Nested;
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.util.*;
9+
10+
import static org.assertj.core.api.BDDAssertions.then;
11+
import static org.assertj.core.api.BDDAssertions.thenThrownBy;
12+
13+
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
14+
class SimpleStackTest {
15+
16+
@Nested
17+
class Given_an_empty_stack {
18+
19+
@Test
20+
void it_has_depth_zero() {
21+
var stack = SimpleStack.empty();
22+
then(stack.depth()).isZero();
23+
}
24+
25+
@Test
26+
void it_has_no_elements() {
27+
var stack = SimpleStack.empty();
28+
then(stack.isEmpty()).isTrue();
29+
then(stack.asList()).isEmpty();
30+
}
31+
32+
@Test
33+
void pushing_makes_it_non_empty() {
34+
var stack = SimpleStack.empty();
35+
stack.push("item");
36+
then(stack.isEmpty()).isFalse();
37+
}
38+
39+
@Test
40+
void popping_is_not_allowed() {
41+
var stack = SimpleStack.empty();
42+
thenThrownBy(stack::pop).isInstanceOf(IllegalStateException.class);
43+
}
44+
45+
@Test
46+
void retrieving_the_top_element_is_not_allowed() {
47+
var stack = SimpleStack.empty();
48+
thenThrownBy(stack::top).isInstanceOf(IllegalStateException.class);
49+
}
50+
}
51+
52+
@Nested
53+
class Given_any_stack {
54+
55+
@Test
56+
void pushing_increases_depth() {
57+
var stack = SimpleStack.empty();
58+
stack.push("item");
59+
then(stack.depth()).isEqualTo(1);
60+
}
61+
62+
@Test
63+
void pushing_places_new_item_on_top_and_preserves_existing_items() {
64+
var stack = SimpleStack.of("first");
65+
stack.push("second");
66+
then(stack.asList()).containsExactly("first", "second");
67+
}
68+
}
69+
70+
@Nested
71+
class Given_a_non_empty_stack {
72+
73+
@Test
74+
void popping_returns_the_top_element() {
75+
var stack = SimpleStack.of("A", "B");
76+
then(stack.pop()).isEqualTo("B");
77+
}
78+
79+
@Test
80+
void popping_decreases_depth_by_one() {
81+
var stack = SimpleStack.of("A", "B");
82+
stack.pop();
83+
then(stack.depth()).isEqualTo(1);
84+
}
85+
86+
@Test
87+
void the_popped_item_is_removed() {
88+
var stack = SimpleStack.of("A", "B");
89+
var popped = stack.pop();
90+
then(stack.asList()).doesNotContain(popped);
91+
}
92+
93+
@Test
94+
void popping_removes_only_the_top_item() {
95+
var stack = SimpleStack.of("A", "B", "C");
96+
var popped = stack.pop();
97+
then(popped).isEqualTo("C");
98+
then(stack.asList()).containsExactly("A", "B");
99+
}
100+
101+
@Test
102+
void items_are_popped_in_reverse_order() {
103+
var stack = SimpleStack.of("A", "B", "C");
104+
then(stack.pop()).isEqualTo("C");
105+
then(stack.pop()).isEqualTo("B");
106+
then(stack.pop()).isEqualTo("A");
107+
}
108+
109+
@Test
110+
void its_top_item_is_the_last_pushed() {
111+
var stack = SimpleStack.of("A", "B");
112+
then(stack.top()).isEqualTo("B");
113+
then(stack.depth()).isEqualTo(2);
114+
}
115+
116+
@Test
117+
void its_list_view_is_unmodifiable() {
118+
var stack = SimpleStack.of("A", "B");
119+
then(stack.asList()).isUnmodifiable();
120+
}
121+
122+
@Test
123+
void its_list_view_contains_items_in_insertion_order() {
124+
var stack = SimpleStack.of("A", "B", "C");
125+
then(stack.asList()).containsExactly("A", "B", "C");
126+
}
127+
}
128+
129+
static final class SimpleStack<T> {
130+
private final List<T> elements = new ArrayList<>();
131+
132+
private SimpleStack() {}
133+
134+
static <T> SimpleStack<T> empty() {
135+
return new SimpleStack<>();
136+
}
137+
138+
@SafeVarargs
139+
static <T> SimpleStack<T> of(T... items) {
140+
var stack = new SimpleStack<T>();
141+
for (var item : items) {
142+
stack.push(item);
143+
}
144+
return stack;
145+
}
146+
147+
void push(T item) {
148+
elements.add(item);
149+
}
150+
151+
T pop() {
152+
if (elements.isEmpty()) throw new IllegalStateException("Cannot pop from empty stack");
153+
return elements.removeLast();
154+
}
155+
156+
T top() {
157+
if (elements.isEmpty()) throw new IllegalStateException("Cannot access top of empty stack");
158+
return elements.getLast();
159+
}
160+
161+
boolean isEmpty() {
162+
return elements.isEmpty();
163+
}
164+
165+
int depth() {
166+
return elements.size();
167+
}
168+
169+
List<T> asList() {
170+
return List.copyOf(elements);
171+
}
172+
}
173+
}

0 commit comments

Comments
 (0)