Skip to content

Commit cf24a44

Browse files
authored
Merge pull request #360 from code-dot-org/molly/validation-system-out-tracker
Add validation api for checking system out messages
2 parents 9da6bc9 + a29832d commit cf24a44

File tree

9 files changed

+158
-14
lines changed

9 files changed

+158
-14
lines changed

org-code-javabuilder/lib/src/main/java/org/code/javabuilder/ValidationRunner.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.code.javabuilder.util.ProjectLoadUtils;
77
import org.code.protocol.*;
88
import org.code.validation.support.NeighborhoodTracker;
9+
import org.code.validation.support.SystemOutTracker;
910
import org.code.validation.support.ValidationProtocol;
1011

1112
public class ValidationRunner extends BaseTestRunner {
@@ -49,6 +50,6 @@ private void setUpForValidation(URLClassLoader urlClassLoader) throws UserInitia
4950
JavabuilderContext.getInstance()
5051
.register(
5152
ValidationProtocol.class,
52-
new ValidationProtocol(mainMethod, new NeighborhoodTracker()));
53+
new ValidationProtocol(mainMethod, new NeighborhoodTracker(), new SystemOutTracker()));
5354
}
5455
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.code.validation;
2+
3+
import java.util.List;
4+
import org.code.protocol.JavabuilderContext;
5+
import org.code.validation.support.ValidationProtocol;
6+
7+
public class SystemOutTestRunner {
8+
// Run the main method of the user's program and return a list
9+
// of all system.out messages in order.
10+
public static List<String> run() {
11+
ValidationProtocol protocolInstance =
12+
(ValidationProtocol) JavabuilderContext.getInstance().get(ValidationProtocol.class);
13+
protocolInstance.invokeMainMethod();
14+
return protocolInstance.getSystemOutMessages();
15+
}
16+
}

org-code-javabuilder/validation/src/main/java/org/code/validation/support/NeighborhoodTracker.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import org.code.validation.Position;
1919

2020
public class NeighborhoodTracker {
21-
private final Map<String, PainterTracker> painterTrackers;
21+
private Map<String, PainterTracker> painterTrackers;
2222
private String[][] neighborhoodState;
2323
private boolean isInitialized;
2424

@@ -83,6 +83,11 @@ public void trackEvent(ClientMessage message) {
8383
}
8484
}
8585

86+
public void reset() {
87+
this.painterTrackers = new HashMap<>();
88+
this.isInitialized = false;
89+
}
90+
8691
private void initializeGrid() {
8792
World world = (World) JavabuilderContext.getInstance().get(World.class);
8893
final int gridSize = world.getGrid().getSize();
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.code.validation.support;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import org.code.protocol.ClientMessage;
6+
import org.code.protocol.ClientMessageType;
7+
8+
public class SystemOutTracker {
9+
private List<String> messages;
10+
11+
public SystemOutTracker() {
12+
this.messages = new ArrayList<>();
13+
}
14+
15+
public List<String> getSystemOutMessages() {
16+
return this.messages;
17+
}
18+
19+
// Track a single client message event. It will only be tracked if it is a system out message
20+
// that is not just a newline, otherwise it will be ignored.
21+
public void trackEvent(ClientMessage message) {
22+
if (message.getType() != ClientMessageType.SYSTEM_OUT) {
23+
return;
24+
}
25+
String value = message.getValue();
26+
// Ignore new lines as those are indications of a println vs a print.
27+
// For validation we don't care which is used.
28+
if (!value.equals("\n")) {
29+
this.messages.add(message.getValue());
30+
}
31+
}
32+
33+
public void reset() {
34+
this.messages = new ArrayList<>();
35+
}
36+
}

org-code-javabuilder/validation/src/main/java/org/code/validation/support/UserTestOutputAdapter.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ public void sendMessage(ClientMessage message) {
2929
delegateOutputAdapter.sendMessage(message);
3030
}
3131
break;
32-
case NEIGHBORHOOD:
33-
if (this.isValidation) {
34-
ValidationProtocol protocolInstance =
35-
(ValidationProtocol) JavabuilderContext.getInstance().get(ValidationProtocol.class);
36-
protocolInstance.trackEvent(message);
37-
}
38-
break;
3932
default:
4033
break;
4134
}
35+
// If this is validation, send all messages to the validation protocol, which will decide
36+
// whether or not to track them.
37+
if (this.isValidation) {
38+
ValidationProtocol protocolInstance =
39+
(ValidationProtocol) JavabuilderContext.getInstance().get(ValidationProtocol.class);
40+
protocolInstance.trackEvent(message);
41+
}
4242
}
4343

4444
public void setIsValidation(boolean isValidation) {

org-code-javabuilder/validation/src/main/java/org/code/validation/support/ValidationProtocol.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,44 @@
22

33
import java.lang.reflect.InvocationTargetException;
44
import java.lang.reflect.Method;
5+
import java.util.List;
56
import org.code.protocol.ClientMessage;
67
import org.code.protocol.JavabuilderSharedObject;
78
import org.code.validation.NeighborhoodLog;
89

910
public class ValidationProtocol extends JavabuilderSharedObject {
1011
private final Method mainMethod;
1112
private final NeighborhoodTracker neighborhoodTracker;
13+
private final SystemOutTracker systemOutTracker;
1214

13-
public ValidationProtocol(Method mainMethod, NeighborhoodTracker neighborhoodTracker) {
15+
public ValidationProtocol(
16+
Method mainMethod,
17+
NeighborhoodTracker neighborhoodTracker,
18+
SystemOutTracker systemOutTracker) {
1419
this.mainMethod = mainMethod;
1520
this.neighborhoodTracker = neighborhoodTracker;
21+
this.systemOutTracker = systemOutTracker;
1622
}
1723

1824
public NeighborhoodLog getNeighborhoodLog() {
1925
return this.neighborhoodTracker.getNeighborhoodLog();
2026
}
2127

28+
public List<String> getSystemOutMessages() {
29+
return this.systemOutTracker.getSystemOutMessages();
30+
}
31+
2232
public void trackEvent(ClientMessage message) {
2333
this.neighborhoodTracker.trackEvent(message);
34+
this.systemOutTracker.trackEvent(message);
2435
}
2536

2637
public void invokeMainMethod() {
2738
if (this.mainMethod == null) {
2839
throw new ValidationRuntimeException(ExceptionKey.NO_MAIN_METHOD_VALIDATION);
2940
}
41+
this.neighborhoodTracker.reset();
42+
this.systemOutTracker.reset();
3043
try {
3144
this.mainMethod.invoke(null, new Object[] {null});
3245
} catch (IllegalAccessException e) {

org-code-javabuilder/validation/src/test/java/org/code/validation/support/NeighborhoodTrackerTest.java

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public void testInitializeMessageCreatesNewPainterTracker() {
4747

4848
@Test
4949
public void testUpdatesPainterTrackerWithPainterMessages() {
50-
final String id = "id";
50+
final String id = "id1";
5151
// Initialize
5252
unitUnderTest.trackEvent(createInitEvent(id, Direction.EAST, 5, 10, 20));
5353

@@ -66,7 +66,7 @@ public void testUpdatesPainterTrackerWithPainterMessages() {
6666

6767
final PainterLog painterLog = unitUnderTest.getNeighborhoodLog().getPainterLogs()[0];
6868

69-
assertEquals(ID, painterLog.getPainterId());
69+
assertEquals(id, painterLog.getPainterId());
7070
assertEquals(4, painterLog.getEndingPosition().getX());
7171
assertEquals(10, painterLog.getEndingPosition().getY());
7272
assertEquals(21, painterLog.getEndingPaintCount());
@@ -132,7 +132,7 @@ public void testSelectsCorrectPainterTrackerById() {
132132

133133
@Test
134134
public void testUpdatesPainterLogWithNonAnimatedMoves() {
135-
final String id = "id";
135+
final String id = "id1";
136136
// Initialize
137137
unitUnderTest.trackEvent(createInitEvent(id, Direction.EAST, 5, 10, 20));
138138

@@ -144,11 +144,38 @@ public void testUpdatesPainterLogWithNonAnimatedMoves() {
144144

145145
final PainterLog painterLog = unitUnderTest.getNeighborhoodLog().getPainterLogs()[0];
146146

147-
assertEquals(ID, painterLog.getPainterId());
147+
assertEquals(id, painterLog.getPainterId());
148148
assertTrue(painterLog.didActionOnce(NeighborhoodActionType.IS_ON_BUCKET));
149149
assertFalse(painterLog.didActionAtLeast(NeighborhoodActionType.CAN_MOVE, 1));
150150
}
151151

152+
@Test
153+
public void resetsSuccessfully() {
154+
final String id = "id1";
155+
// Initialize
156+
unitUnderTest.trackEvent(createInitEvent(id, Direction.EAST, 5, 10, 20));
157+
// create paint event
158+
final HashMap<String, String> paintDetails = new HashMap<>();
159+
paintDetails.put(COLOR, "orange");
160+
paintDetails.put(ID, id);
161+
unitUnderTest.trackEvent(
162+
new NeighborhoodSignalMessage(NeighborhoodSignalKey.PAINT, paintDetails));
163+
unitUnderTest.reset();
164+
// re-initialize
165+
unitUnderTest.trackEvent(createInitEvent(id, Direction.EAST, 5, 10, 20));
166+
// create move event
167+
final HashMap<String, String> moveDetails = new HashMap<>();
168+
moveDetails.put(DIRECTION, Direction.WEST.getDirectionString());
169+
moveDetails.put(ID, id);
170+
unitUnderTest.trackEvent(
171+
new NeighborhoodSignalMessage(NeighborhoodSignalKey.MOVE, moveDetails));
172+
173+
final PainterLog painterLog = unitUnderTest.getNeighborhoodLog().getPainterLogs()[0];
174+
175+
assertEquals(false, painterLog.didActionOnce(NeighborhoodActionType.PAINT));
176+
assertEquals(true, painterLog.didActionOnce(NeighborhoodActionType.MOVE));
177+
}
178+
152179
private NeighborhoodSignalMessage createInitEvent(
153180
String id, Direction direction, int x, int y, int paint) {
154181
final HashMap<String, String> details = new HashMap<>();
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.code.validation.support;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.util.List;
6+
import org.code.protocol.ClientMessageType;
7+
import org.code.validation.ClientMessageHelper;
8+
import org.junit.jupiter.api.Test;
9+
10+
public class SystemOutTrackerTest {
11+
private SystemOutTracker unitUnderTest;
12+
13+
@Test
14+
public void tracksAllNonNewlineMessages() {
15+
unitUnderTest = new SystemOutTracker();
16+
// should be tracked
17+
unitUnderTest.trackEvent(new ClientMessageHelper(ClientMessageType.SYSTEM_OUT, "hello"));
18+
// should be ignored
19+
unitUnderTest.trackEvent(new ClientMessageHelper(ClientMessageType.SYSTEM_OUT, "\n"));
20+
// should be tracked
21+
unitUnderTest.trackEvent(new ClientMessageHelper(ClientMessageType.SYSTEM_OUT, "hello world"));
22+
23+
List<String> messages = unitUnderTest.getSystemOutMessages();
24+
assertEquals(2, messages.size());
25+
assertEquals("hello world", messages.get(1));
26+
}
27+
28+
@Test
29+
public void resetsSuccessfully() {
30+
unitUnderTest = new SystemOutTracker();
31+
unitUnderTest.trackEvent(new ClientMessageHelper(ClientMessageType.SYSTEM_OUT, "hello"));
32+
// should reset message list
33+
unitUnderTest.reset();
34+
unitUnderTest.trackEvent(
35+
new ClientMessageHelper(ClientMessageType.SYSTEM_OUT, "a new message"));
36+
unitUnderTest.trackEvent(new ClientMessageHelper(ClientMessageType.SYSTEM_OUT, "hello world"));
37+
unitUnderTest.trackEvent(
38+
new ClientMessageHelper(ClientMessageType.SYSTEM_OUT, "a third message"));
39+
40+
List<String> messages = unitUnderTest.getSystemOutMessages();
41+
assertEquals(3, messages.size());
42+
assertEquals("a new message", messages.get(0));
43+
}
44+
}

org-code-javabuilder/validation/src/test/java/org/code/validation/support/UserTestOutputAdapterTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public class UserTestOutputAdapterTest {
1515
@BeforeEach
1616
public void setUp() {
1717
testOutputAdapter = new UserTestOutputAdapter(delegateOutputAdapter);
18+
JavabuilderContext.getInstance()
19+
.register(ValidationProtocol.class, mock(ValidationProtocol.class));
1820
}
1921

2022
@Test

0 commit comments

Comments
 (0)