Skip to content

Commit a30d0af

Browse files
committed
Fixing defect where sharedtestsuites always log the first sentence regardless of which one is executed
1 parent 437862e commit a30d0af

16 files changed

+160
-130
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
<groupId>com.google.pdsl</groupId>
77
<artifactId>pdsl</artifactId>
8-
<version>1.10.0</version>
8+
<version>1.10.1</version>
99

1010
<name>pdsl</name>
1111
<url>http://www.github.com/google/polymorphicDSL</url>

src/main/java/com/pdsl/executors/ColorizedLoggerObserver.java

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.pdsl.logging.PdslThreadSafeOutputStream;
55
import com.pdsl.reports.MetadataTestRunResults;
66
import com.pdsl.specifications.PolymorphicDslTransformationException;
7+
import com.pdsl.testcases.SharedTestCase;
78
import com.pdsl.testcases.TestCase;
89
import com.pdsl.testcases.TestSection;
910
import org.antlr.v4.runtime.tree.ParseTreeListener;
@@ -14,6 +15,7 @@
1415
import java.io.InputStream;
1516
import java.nio.charset.Charset;
1617
import java.util.Collection;
18+
import java.util.Iterator;
1719

1820
/**
1921
* A logger for the progress of test execution where the output has color.
@@ -26,6 +28,14 @@ public class ColorizedLoggerObserver implements ExecutorObserver {
2628
private static final String exceptionMessage = "Could not log!";
2729
private final Charset charset;
2830
private final byte[] RESET;
31+
private Strategy strategy = Strategy.HIDE_INTERPRETER;
32+
// Avoid race conditions in logic
33+
// where a sharedtestsuite might be running with normal test suites in concurrent environment
34+
private int concurrencyCounter = 0;
35+
private enum Strategy {
36+
LOG_INTERPRETER,
37+
HIDE_INTERPRETER;
38+
}
2939

3040
public ColorizedLoggerObserver() {
3141
this.charset = Charset.defaultCharset();
@@ -61,11 +71,24 @@ private void notifyStreams(String str) {
6171
}
6272
}
6373

74+
@Override
75+
public void onBeforeTestSuite(Collection<? extends SharedTestCase> testCases,
76+
String context) {
77+
strategy = Strategy.LOG_INTERPRETER;
78+
logBeforeSuite();
79+
}
80+
6481
@Override
6582
public void onBeforeTestCase(TestCase testCase) {
6683
notifyStreams(AnsiTerminalColorHelper.YELLOW
6784
+ String.format("%s%n%s%n", testCase.getOriginalSource(), testCase.getTestTitle()
6885
+ AnsiTerminalColorHelper.RESET));
86+
Object longDescription = testCase.getMetadata().get(TestCase.STANDARD_LONG_DESCRIPTION_KEY);
87+
if (longDescription instanceof InputStream descriptionStream) {
88+
notifyStreams(AnsiTerminalColorHelper.CYAN.getBytes(charset));
89+
notifyStreams(descriptionStream);
90+
notifyStreams(RESET);
91+
}
6992
}
7093

7194
@Override
@@ -75,27 +98,25 @@ public void onTestCaseSuccess(TestCase testCase) {
7598
+ AnsiTerminalColorHelper.RESET).getBytes(charset));
7699
}
77100

78-
private void beforePhrase(TestSection testSection) {
79-
if (testSection.getMetaData().isPresent()) {
80-
notifyStreams(AnsiTerminalColorHelper.CYAN.getBytes(charset));
81-
notifyStreams(testSection.getMetaData().get());
82-
notifyStreams(RESET);
101+
private void notateInterpreter(Class<?> interpreter) {
102+
if (strategy.equals(Strategy.LOG_INTERPRETER)) {
103+
notifyStreams(AnsiTerminalColorHelper.GREY);
104+
notifyStreams(String.format("^ %s %n", interpreter));
105+
notifyStreams(AnsiTerminalColorHelper.RESET);
83106
}
84107
}
85108

86-
@Override
87-
public void onBeforePhrase(ParseTreeVisitor<?> visitor, TestSection testSection) {
88-
beforePhrase(testSection);
89-
}
90-
91109
@Override
92110
public void onAfterPhrase(ParseTreeListener listener, ParseTreeWalker walker, TestSection testSection) {
93111
afterPhrase(testSection);
112+
notateInterpreter(listener.getClass());
94113
}
95114

96115
@Override
97116
public void onAfterPhrase(ParseTreeVisitor<?> visitor, TestSection testSection) {
117+
98118
afterPhrase(testSection);
119+
notateInterpreter(visitor.getClass());
99120
}
100121

101122
private void afterPhrase(TestSection testSection) {
@@ -138,6 +159,10 @@ public void onAfterTestSuite(Collection<? extends TestCase> testCases, ParseTree
138159
@Override
139160
public void onAfterTestSuite(Collection<? extends TestCase> testCases, ParseTreeListener listener, MetadataTestRunResults results, String context) {
140161
logAfterSuite(results);
162+
concurrencyCounter--;
163+
if (concurrencyCounter <= 0) {
164+
strategy = Strategy.HIDE_INTERPRETER;
165+
}
141166
}
142167

143168
@Override
@@ -159,5 +184,6 @@ private void logAfterSuite(MetadataTestRunResults results) {
159184

160185
private void logBeforeSuite() {
161186
notifyStreams(AnsiTerminalColorHelper.BRIGHT_YELLOW + "Running tests..." + AnsiTerminalColorHelper.RESET);
187+
concurrencyCounter++;
162188
}
163189
}

src/main/java/com/pdsl/executors/DefaultPolymorphicDslTestExecutor.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.util.*;
2222
import java.util.concurrent.CopyOnWriteArrayList;
23+
import java.util.stream.Collectors;
2324

2425
/**
2526
* An executor that runs PDSL tests create from a TestCaseFactory.
@@ -191,6 +192,8 @@ public MetadataTestRunResults runTestsWithMetadata(Collection<SharedTestCase> sh
191192
List<TestCase> listOfTestCases = sharedTestCase.getSharedTestCaseWithInterpreters().stream()
192193
.map(SharedTestCaseWithInterpreter::getTestCase).toList();
193194
int size = listOfTestCases.getFirst().getUnfilteredPhraseBody().size();
195+
// The first phrase in a test case has metadata (arbitrarilly decided by standard implementation,
196+
// not because it necessarily should be that way)
194197
TestCase testCase = listOfTestCases.stream().findFirst().orElseThrow();
195198
notifyBeforeTestCase(sharedTestCase);
196199
// Create each visitor/listener one time per test case
@@ -209,6 +212,11 @@ public MetadataTestRunResults runTestsWithMetadata(Collection<SharedTestCase> sh
209212
.map(Iterator::next)
210213
.findFirst()
211214
.orElseThrow(() -> new IllegalStateException("No executable phrases were found!"));
215+
Map<SharedTestCaseWithInterpreter, Iterator<TestSection>> interpreter2Iterator = sharedTestCase.getSharedTestCaseWithInterpreters()
216+
.stream()
217+
.collect(Collectors.toMap(interpreter -> interpreter,
218+
interpreter -> interpreter.getTestCase().getContextFilteredTestSectionIterator()
219+
));
212220

213221
try {
214222
for (int j = 0;
@@ -221,8 +229,13 @@ public MetadataTestRunResults runTestsWithMetadata(Collection<SharedTestCase> sh
221229
//TODO - Add implementation for the duplication checking
222230
Optional<ParseTree> parseTree = filteredPhrase.getParseTree();
223231
if (parseTree.isPresent()) {
232+
if (!interpreter2Iterator.get(interpreter).hasNext()) {
233+
// If a parse tree was found there should definitely be a new test section or something
234+
// is wrong
235+
throw new IllegalStateException("PDSL Framework error: The context filtered interpreters are out of sync!");
236+
}
237+
testSection = interpreter2Iterator.get(interpreter).next();
224238
phrase = Optional.of(new DefaultPhrase(parseTree.get(), phraseIndex));
225-
226239
interpreterObj = Optional.of(interpreter.getInterpreterObj());
227240

228241
if (interpreterObj.get().getListenerSupplier().isPresent()) {
@@ -241,7 +254,6 @@ public MetadataTestRunResults runTestsWithMetadata(Collection<SharedTestCase> sh
241254
visitor.visit(parseTree.get());
242255
notifyAfterVisitor(visitor, testSection);
243256
}
244-
245257
}
246258
}
247259
phraseIndex++;

src/main/java/com/pdsl/testcases/DefaultPdslTestCase.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.antlr.v4.runtime.tree.ParseTree;
99

1010
import java.util.*;
11+
import java.util.concurrent.ConcurrentHashMap;
1112
import java.util.stream.Collectors;
1213
import java.util.stream.Stream;
1314

@@ -22,6 +23,8 @@ public class DefaultPdslTestCase implements TestCase {
2223
private final List<String> contextFilteredPhraseBody;
2324
private final List<FilteredPhrase> phrasesToTestSections;
2425
private final URI source;
26+
private final Map<String, Object> metadata;
27+
private static final String errMessage = "Test case title cannot be empty or null!";
2528

2629
public static final PdslTestCaseComparator DEFAULT_TEST_CASE_COMPARATOR = new PdslTestCaseComparator();
2730

@@ -33,7 +36,7 @@ public class DefaultPdslTestCase implements TestCase {
3336
* @param source the original source this test case was created from
3437
*/
3538
public DefaultPdslTestCase(String testCaseTitle, List<TestBodyFragment> testBodyFragments, URI source) {
36-
String errMessage = "Test case title cannot be empty or null!";
39+
3740
Preconditions.checkNotNull(testCaseTitle, errMessage);
3841
Preconditions.checkNotNull(source);
3942
Preconditions.checkArgument(!testCaseTitle.isEmpty(), errMessage);
@@ -55,6 +58,39 @@ public DefaultPdslTestCase(String testCaseTitle, List<TestBodyFragment> testBody
5558
.map(Optional::get)
5659
.map(ParseTree::getText)
5760
.toList();
61+
metadata = new ConcurrentHashMap<>();
62+
}
63+
64+
public DefaultPdslTestCase(String testCaseTitle, List<TestBodyFragment> testBodyFragments, URI source,
65+
Map<String, Object> metadata) {
66+
Preconditions.checkNotNull(testCaseTitle, errMessage);
67+
Preconditions.checkNotNull(source);
68+
Preconditions.checkArgument(!testCaseTitle.isEmpty(), errMessage);
69+
Preconditions.checkNotNull(testBodyFragments, errMessage);
70+
Preconditions.checkArgument(!testBodyFragments.isEmpty(), errMessage);
71+
Preconditions.checkNotNull(metadata);
72+
this.source = source;
73+
this.testBodyFragments = testBodyFragments;
74+
this.testCaseTitle = testCaseTitle;
75+
this.phrasesToTestSections = testBodyFragments.stream()
76+
.map(TestBodyFragment::getTestPhrases)
77+
.flatMap(Collection::stream)
78+
.toList();
79+
this.unfilteredPhraseBody = phrasesToTestSections.stream()
80+
.map(FilteredPhrase::getPhrase)
81+
.toList();
82+
this.contextFilteredPhraseBody = phrasesToTestSections.stream()
83+
.map(FilteredPhrase::getParseTree)
84+
.filter(Optional::isPresent)
85+
.map(Optional::get)
86+
.map(ParseTree::getText)
87+
.toList();
88+
this.metadata = metadata;
89+
}
90+
91+
@Override
92+
public Map<String, Object> getMetadata() {
93+
return metadata;
5894
}
5995

6096
@Override

src/main/java/com/pdsl/testcases/DefaultTaggedTestCase.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@
66
import java.util.Collection;
77
import java.util.Iterator;
88
import java.util.List;
9+
import java.util.Map;
910

1011
/** A test case that has arbitrary tags associated with it. */
1112
public class DefaultTaggedTestCase implements TaggedTestCase {
1213

1314
private final TestCase testCase;
14-
private final Collection<String> tags;
15-
15+
private final Collection<String> tags; // Keep to avoid the need for casting and checking generic types
1616
public DefaultTaggedTestCase(TestCase testCase, Collection<String> tags) {
1717
this.testCase = testCase;
1818
this.tags = tags;
19+
testCase.getMetadata().put(TestCase.DEFAULT_TAGS, this.tags); // Add a reference just to be thorough
1920
}
2021

2122
@Override
2223
public Collection<String> getTags() {
23-
return tags;
24+
return tags;
2425
}
2526

2627
@Override
@@ -52,4 +53,9 @@ public Iterator<TestSection> getContextFilteredTestSectionIterator() {
5253
public List<FilteredPhrase> getFilteredPhrases() {
5354
return testCase.getFilteredPhrases();
5455
}
56+
57+
@Override
58+
public Map<String, Object> getMetadata() {
59+
return testCase.getMetadata();
60+
}
5561
}

src/main/java/com/pdsl/testcases/DefaultTestSection.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
import com.pdsl.specifications.Phrase;
44

55
import java.io.InputStream;
6+
import java.util.Map;
67
import java.util.Optional;
8+
import java.util.concurrent.ConcurrentHashMap;
79

810
/**
911
* A container of phrases representing a chunk of a test case.
@@ -13,18 +15,22 @@
1315
*/
1416
public class DefaultTestSection implements TestSection {
1517

16-
private final Optional<InputStream> metaData;
17-
private final Phrase phrase;
1818

19+
private final Phrase phrase;
20+
private final Optional<Map<String, Object>> metadata;
21+
private final Optional<InputStream> longDescription;
1922
/**
2023
* Creates a test section with the provided phrase.
2124
*
22-
* @param metaData additional information about the phrase
25+
* @param longDescription additional information about the phrase
2326
* @param phrase an arbitrary sentence recognized by a parser
2427
*/
25-
public DefaultTestSection(InputStream metaData, Phrase phrase) {
26-
this.metaData = Optional.ofNullable(metaData);
28+
public DefaultTestSection(InputStream longDescription, Phrase phrase) {
29+
Map<String, Object> metadataMap = new ConcurrentHashMap<>(1);
30+
metadataMap.put(TestCase.STANDARD_LONG_DESCRIPTION_KEY, longDescription);
31+
this.metadata = Optional.of(metadataMap);
2732
this.phrase = phrase;
33+
this.longDescription = Optional.ofNullable(longDescription);
2834
}
2935

3036
/**
@@ -33,13 +39,19 @@ public DefaultTestSection(InputStream metaData, Phrase phrase) {
3339
* @param phrase an arbitrary sentence recognized by a parser
3440
*/
3541
public DefaultTestSection(Phrase phrase) {
36-
this.metaData = Optional.empty();
42+
this.metadata = Optional.empty();
3743
this.phrase = phrase;
44+
this.longDescription = Optional.empty();
3845
}
3946

4047
@Override
4148
public Optional<InputStream> getMetaData() {
42-
return metaData;
49+
return longDescription;
50+
}
51+
52+
@Override
53+
public Optional<Map<String, Object>> getSectionMetadata() {
54+
return metadata;
4355
}
4456

4557
@Override

src/main/java/com/pdsl/testcases/PreorderTestCaseFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ private List<TestCase> recursiveWalkAndCreateOnLeaf(TestSpecification testSpecif
6464
}
6565
// Add phrases in this node if present
6666
if (testSpecification.getFilteredPhrases().isPresent()) {
67-
childTestBodyFragments.add(new TestBodyFragment(childMetaData.isPresent() ? childMetaData.get() : null, testSpecification.getFilteredPhrases().get()));
67+
childTestBodyFragments.add(new TestBodyFragment(null, testSpecification.getFilteredPhrases().get()));
6868
}
6969
// Add phrases in child node if present
7070
if (testSpecification.nestedTestSpecifications().isPresent()) {
@@ -74,6 +74,7 @@ private List<TestCase> recursiveWalkAndCreateOnLeaf(TestSpecification testSpecif
7474
return testCases;
7575
} else {
7676
TestCase testCase = new DefaultPdslTestCase(testSpecification.getName(), childTestBodyFragments, testSpecification.getOriginalTestResource());
77+
testCase.getMetadata().put(TestCase.STANDARD_LONG_DESCRIPTION_KEY, childMetaData);
7778
if (!tags.isEmpty()) {
7879
testCase = new DefaultTaggedTestCase(testCase, tags);
7980
}

src/main/java/com/pdsl/testcases/SharedTestCase.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*/
1717
public final class SharedTestCase implements TestCase {
1818

19-
List<SharedTestCaseWithInterpreter> sharedTestCaseWithInterpreters;
19+
private final List<SharedTestCaseWithInterpreter> sharedTestCaseWithInterpreters;
2020

2121
public SharedTestCase(List<SharedTestCaseWithInterpreter> sharedTestCaseWithInterpreters) {
2222
this.sharedTestCaseWithInterpreters = sharedTestCaseWithInterpreters;
@@ -54,4 +54,9 @@ public Iterator<TestSection> getContextFilteredTestSectionIterator() {
5454
public List<FilteredPhrase> getFilteredPhrases() {
5555
return sharedTestCaseWithInterpreters.getFirst().getTestCase().getFilteredPhrases();
5656
}
57+
58+
@Override
59+
public Map<String, Object> getMetadata() {
60+
return sharedTestCaseWithInterpreters.getFirst().getTestCase().getMetadata();
61+
}
5762
}

0 commit comments

Comments
 (0)