Skip to content

Commit 3a0bd53

Browse files
committed
added some comments, made code more DRY
Signed-off-by: Konstantin Läufer <[email protected]>
1 parent 70acc1c commit 3a0bd53

File tree

9 files changed

+30
-40
lines changed

9 files changed

+30
-40
lines changed

src/main/java/edu/luc/cs/consoleapp/Main.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ public static void main(final String[] args) {
3737
final var input = new Scanner(System.in).useDelimiter("(?U)[^\\p{Alpha}0-9']+");
3838
final var queue = new CircularFifoQueue<String>(lastNWords);
3939

40+
// this is the core functionality, but it mixes
41+
// I/O and core processing logic and therefore is hard to test
4042
input.forEachRemaining(
4143
word -> {
4244
queue.add(word); // the oldest item automatically gets evicted

src/main/java/edu/luc/cs/consoleapp/MainLeaky.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package edu.luc.cs.consoleapp;
22

3+
import java.util.Collections;
34
import java.util.Iterator;
45
import java.util.LinkedList;
56
import java.util.List;
@@ -8,6 +9,8 @@
89

910
import org.apache.commons.collections4.queue.CircularFifoQueue;
1011

12+
import edu.luc.cs.consoleapp.MainLeaky.LeakyQueue;
13+
1114
// see https://stackoverflow.com/questions/1963806/#21699069
1215
// why we're using this implementation instead of java.util.ArrayQueue!
1316

@@ -16,9 +19,6 @@ public class MainLeaky {
1619
public static final int LAST_N_WORDS = 10;
1720

1821
public static void main(final String[] args) {
19-
20-
// TODO consider using a command-line option library
21-
2222
// perform argument validity checking
2323
if (args.length > 1) {
2424
System.err.println("usage: ./target/universal/stage/bin/consoleapp [ last_n_words ]");
@@ -51,6 +51,11 @@ public static void main(final String[] args) {
5151
});
5252
}
5353

54+
/**
55+
* A sliding window queue that retains the last N elements.
56+
* This component is independent of the user interface and can be tested independently.
57+
* Nevertheless, it violates an important nonfunctional requirement: it leaks memory.
58+
*/
5459
static class LeakyQueue {
5560

5661
private final Queue<String> queue;
@@ -70,7 +75,7 @@ public List<Queue<String>> process() {
7075
final var snapshot = new LinkedList<>(queue);
7176
result.add(snapshot);
7277
});
73-
return result;
78+
return Collections.unmodifiableList(result);
7479
}
7580
}
7681
}

src/main/java/edu/luc/cs/consoleapp/MainStream.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ public class MainStream {
1212
public static final int LAST_N_WORDS = 10;
1313

1414
public static void main(final String[] args) {
15-
16-
// TODO consider using a command-line option library
17-
1815
// perform argument validity checking
1916
if (args.length > 1) {
2017
System.err.println("usage: ./target/universal/stage/bin/consoleapp [ last_n_words ]");

src/main/java/edu/luc/cs/consoleapp/MainTestable.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ public class MainTestable {
1010
public static final int LAST_N_WORDS = 10;
1111

1212
public static void main(final String[] args) {
13-
14-
// TODO consider using a command-line option library
15-
1613
// perform argument validity checking
1714
if (args.length > 1) {
1815
System.err.println("usage: ./target/universal/stage/bin/consoleapp [ last_n_words ]");
@@ -42,8 +39,10 @@ public static void main(final String[] args) {
4239
System.exit(1);
4340
}
4441
};
42+
// the main functionality (excluding I/O) is now implemented in SlidingQueue
4543
final var slidingQueue = new SlidingQueue(lastNWords, input, outputToConsole);
4644

45+
// finally invoke the main functionality
4746
slidingQueue.process();
4847
}
4948
}

src/main/java/edu/luc/cs/consoleapp/OutputHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import java.util.function.Consumer;
55

66
/**
7-
* Observer for decoupling sliding window logic from routing updates. The consumer processes the
8-
* output and returns void.
7+
* Observer for decoupling sliding window logic from routing updates.
8+
* The consumer processes the output and returns void.
99
*/
1010
interface OutputHandler extends Consumer<Queue<String>> {}

src/main/java/edu/luc/cs/consoleapp/SlidingQueue.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55

66
import org.apache.commons.collections4.queue.CircularFifoQueue;
77

8+
/**
9+
* A sliding window queue that retains the last N elements.
10+
* This component is independent of the user interface and can be tested independently.
11+
* It takes an OutputHandler to route updates to the appropriate destination.
12+
*/
813
class SlidingQueue {
914

1015
protected final Queue<String> queue;

src/test/java/edu/luc/cs/consoleapp/TestMainNotDRY.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,4 @@ public void testSlidingWindowNonempty() {
4444
assertEquals(List.of("asdf", "qwer", "oiui"), result.get(2));
4545
assertEquals(List.of("qwer", "oiui", "zxcv"), result.get(3));
4646
}
47-
48-
private static class OutputToList implements OutputHandler {
49-
50-
final List<Queue<String>> result = new ArrayList<>();
51-
52-
@Override
53-
public void accept(final Queue<String> value) {
54-
final var snapshot = new LinkedList<>(value);
55-
result.add(snapshot);
56-
}
57-
}
5847
}

src/test/java/edu/luc/cs/consoleapp/TestSlidingQueue.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,4 @@ public void testSlidingWindowNonempty() {
3434
assertEquals(List.of("asdf", "qwer", "oiui"), result.get(2));
3535
assertEquals(List.of("qwer", "oiui", "zxcv"), result.get(3));
3636
}
37-
38-
private static class OutputToList implements OutputHandler {
39-
40-
final List<Queue<String>> result = new ArrayList<>();
41-
42-
@Override
43-
public void accept(final Queue<String> value) {
44-
final var snapshot = new LinkedList<>(value);
45-
result.add(snapshot);
46-
}
47-
}
4837
}

src/test/java/edu/luc/cs/consoleapp/TestSlidingQueueInteractive.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package edu.luc.cs.consoleapp;
22

3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
35
import java.util.Arrays;
46
import java.util.Collection;
57
import java.util.Collections;
@@ -16,7 +18,7 @@ public void testInteractiveBehavior() {
1618
// the test input
1719
final var input = List.of("asdf", "qwer", "oiui", "zxcv");
1820
// the expected interaction trace
19-
final var expectedTrace = List.<TraceEvent>of(
21+
final var expectedTrace = List.<IOEvent>of(
2022
new InputEvent("asdf"),
2123
new OutputEvent("asdf"),
2224
new InputEvent("qwer"),
@@ -31,23 +33,25 @@ public void testInteractiveBehavior() {
3133
sut.process();
3234
// // make sure the expected and actual traces match
3335
final var actualTrace = sut.getTrace();
36+
assertEquals(expectedTrace, actualTrace);
3437
}
3538
}
3639

3740
// A mini-framework for trace-based testing of interactive behavior (WIP)
3841

39-
interface TraceEvent {}
42+
/** A common interface for user I/O events. */
43+
interface IOEvent {}
4044

4145
/** A trace event representing user input. */
42-
record InputEvent(String value) implements TraceEvent {
46+
record InputEvent(String value) implements IOEvent {
4347
@Override
4448
public String toString() {
4549
return "InputEvent(" + value + ")";
4650
}
4751
}
4852

4953
/** A trace event representing system output. */
50-
record OutputEvent(List<String> value) implements TraceEvent {
54+
record OutputEvent(List<String> value) implements IOEvent {
5155
public OutputEvent(String... values) {
5256
this(Arrays.asList(values));
5357
}
@@ -68,7 +72,7 @@ public String toString() {
6872
class SUTWithTracing {
6973
private final SlidingQueue sut;
7074

71-
private final LinkedList<TraceEvent> trace = new LinkedList<>();
75+
private final LinkedList<IOEvent> trace = new LinkedList<>();
7276

7377
SUTWithTracing(final int capacity, final Collection<String> input) {
7478
this.sut = new SlidingQueue(capacity, wrapInput(input), outputToTrace());
@@ -78,7 +82,7 @@ void process() {
7882
sut.process();
7983
}
8084

81-
List<TraceEvent> getTrace() {
85+
List<IOEvent> getTrace() {
8286
return Collections.unmodifiableList(trace);
8387
}
8488

0 commit comments

Comments
 (0)