From 42c08ad9aea94010456feb22bbf92e5a1bee1088 Mon Sep 17 00:00:00 2001 From: Timur Saglam Date: Mon, 7 Aug 2023 13:46:40 +0200 Subject: [PATCH 1/4] Use names instead of paths for the test source files to improve readability. --- .../java/de/jplag/testutils/datacollector/FileTestData.java | 4 ++-- .../de/jplag/testutils/datacollector/TestDataCollector.java | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/language-testutils/src/test/java/de/jplag/testutils/datacollector/FileTestData.java b/language-testutils/src/test/java/de/jplag/testutils/datacollector/FileTestData.java index 7d9043bb9..f2facf796 100644 --- a/language-testutils/src/test/java/de/jplag/testutils/datacollector/FileTestData.java +++ b/language-testutils/src/test/java/de/jplag/testutils/datacollector/FileTestData.java @@ -33,7 +33,7 @@ public String[] getSourceLines() throws IOException { @Override public String describeTestSource() { - return "(File: " + this.file.getPath() + ")"; + return "(File: " + this.file.getName() + ")"; } @Override @@ -53,6 +53,6 @@ public int hashCode() { @Override public String toString() { - return this.file.getPath(); + return this.file.getName(); } } diff --git a/language-testutils/src/test/java/de/jplag/testutils/datacollector/TestDataCollector.java b/language-testutils/src/test/java/de/jplag/testutils/datacollector/TestDataCollector.java index b1abce180..fa9daa260 100644 --- a/language-testutils/src/test/java/de/jplag/testutils/datacollector/TestDataCollector.java +++ b/language-testutils/src/test/java/de/jplag/testutils/datacollector/TestDataCollector.java @@ -98,6 +98,11 @@ public List getAllTestData() { * @param data The test data */ public record TokenListTest(List tokens, TestData data) { + + @Override + public String toString() { + return data.toString(); // readable test name + } } /** From ba2d8fc8abf8599a1528b9f28a48aaca29806e6a Mon Sep 17 00:00:00 2001 From: Timur Saglam Date: Mon, 7 Aug 2023 13:51:21 +0200 Subject: [PATCH 2/4] Employ display names, match JUnit syntax, and check token sequences via line matching. --- .../jplag/testutils/LanguageModuleTest.java | 56 +++++++++++++------ 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java b/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java index 62b997c12..47420afce 100644 --- a/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java +++ b/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java @@ -1,22 +1,33 @@ package de.jplag.testutils; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertLinesMatch; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.File; import java.io.IOException; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import de.jplag.*; +import de.jplag.Language; +import de.jplag.ParsingException; +import de.jplag.SharedTokenType; +import de.jplag.Token; +import de.jplag.TokenPrinter; +import de.jplag.TokenType; import de.jplag.testutils.datacollector.TestData; import de.jplag.testutils.datacollector.TestDataCollector; import de.jplag.testutils.datacollector.TestSourceIgnoredLinesCollector; @@ -71,6 +82,7 @@ public & TokenType> LanguageModuleTest(Language language, Cla */ @ParameterizedTest @MethodSource("sourceCoverageFiles") + @DisplayName("Test that every line leads to at least one token") final void testSourceCoverage(TestData data) throws ParsingException, IOException { List tokens = parseTokens(data); @@ -81,7 +93,7 @@ final void testSourceCoverage(TestData data) throws ParsingException, IOExceptio tokens.stream().map(Token::getLine).forEach(relevantLines::remove); - Assertions.assertTrue(relevantLines.isEmpty(), + assertTrue(relevantLines.isEmpty(), "Test test source " + data.describeTestSource() + " contained uncovered lines:" + System.lineSeparator() + relevantLines); } @@ -101,14 +113,14 @@ final List sourceCoverageFiles() { */ @ParameterizedTest @MethodSource("tokenCoverageFiles") + @DisplayName("Test that every token occurs at least once") final void testTokenCoverage(TestData data) throws ParsingException, IOException { List foundTokens = extractTokenTypes(data); List languageTokens = new ArrayList<>(this.languageTokens); languageTokens.removeAll(foundTokens); - Assertions.assertTrue(languageTokens.isEmpty(), - "Some tokens were not found in " + data.describeTestSource() + System.lineSeparator() + languageTokens); + assertTrue(languageTokens.isEmpty(), "Some tokens were not found in " + data.describeTestSource() + System.lineSeparator() + languageTokens); } /** @@ -120,23 +132,25 @@ final List tokenCoverageFiles() { } /** - * Tests the configured test sources for contained tokens + * Tests the configured test sources for contained tokens. The tokens neither have to occur exclusively nor in the given + * order. * @param test The source to test * @throws ParsingException If the parser throws some error * @throws IOException If any IO Exception occurs */ @ParameterizedTest @MethodSource("testTokensContainedData") + @DisplayName("Test that the specified tokens at least occur") final void testTokensContained(TestDataCollector.TokenListTest test) throws ParsingException, IOException { List foundTokens = extractTokenTypes(test.data()); - List requiredTokens = new ArrayList<>(test.tokens()); + List expectedTokens = new ArrayList<>(test.tokens()); for (TokenType foundToken : foundTokens) { - requiredTokens.remove(foundToken); + expectedTokens.remove(foundToken); } - Assertions.assertTrue(requiredTokens.isEmpty(), - "Some required tokens were not found in " + test.data().describeTestSource() + System.lineSeparator() + requiredTokens); + assertTrue(expectedTokens.isEmpty(), + "Some expected tokens were not found in " + test.data().describeTestSource() + System.lineSeparator() + expectedTokens); } /** @@ -155,15 +169,21 @@ final List testTokensContainedData() { */ @ParameterizedTest @MethodSource("testTokenSequenceData") + @DisplayName("Test if extracted token sequence matches") final void testTokenSequence(TestDataCollector.TokenListTest test) throws ParsingException, IOException { List extracted = extractTokenTypes(test.data()); - List required = new ArrayList<>(test.tokens()); - if (required.get(required.size() - 1) != SharedTokenType.FILE_END) { - required.add(SharedTokenType.FILE_END); + List expected = new ArrayList<>(test.tokens()); + if (expected.get(expected.size() - 1) != SharedTokenType.FILE_END) { + expected.add(SharedTokenType.FILE_END); } + assertTokensMatch(expected, extracted, "Extracted token from " + test.data().describeTestSource() + " does not match expected sequence."); + } - Assertions.assertEquals(required, extracted, - "Extracted token from " + test.data().describeTestSource() + " does not match required sequence."); + /** + * Convenience method for using assertLinesMatch with token lists. + */ + private void assertTokensMatch(List expected, List extracted, String message) { + assertLinesMatch(expected.stream().map(Object::toString), extracted.stream().map(Object::toString), message); } /** @@ -182,6 +202,7 @@ final List testTokenSequenceData() { */ @ParameterizedTest @MethodSource("getAllTestData") + @DisplayName("Test that the tokens map to ascending line numbers") final void testMonotoneTokenOrder(TestData data) throws ParsingException, IOException { List extracted = parseTokens(data); @@ -204,10 +225,11 @@ final void testMonotoneTokenOrder(TestData data) throws ParsingException, IOExce */ @ParameterizedTest @MethodSource("getAllTestData") + @DisplayName("Test that the last token is the file end token") final void testTokenSequencesEndsWithFileEnd(TestData data) throws ParsingException, IOException { List extracted = parseTokens(data); - Assertions.assertEquals(SharedTokenType.FILE_END, extracted.get(extracted.size() - 1).getType(), + assertEquals(SharedTokenType.FILE_END, extracted.get(extracted.size() - 1).getType(), "Last token in " + data.describeTestSource() + " is not file end."); } From 7dd17fe79339b26e2f6218b84dec63299d92361a Mon Sep 17 00:00:00 2001 From: Timur Saglam Date: Tue, 8 Aug 2023 09:16:00 +0200 Subject: [PATCH 3/4] Add a fall back assertion for cases where the textual representation erroneously matches. --- .../src/test/java/de/jplag/testutils/LanguageModuleTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java b/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java index 47420afce..30e2e577c 100644 --- a/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java +++ b/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java @@ -1,6 +1,7 @@ package de.jplag.testutils; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; import static org.junit.jupiter.api.Assertions.assertLinesMatch; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -177,6 +178,7 @@ final void testTokenSequence(TestDataCollector.TokenListTest test) throws Parsin expected.add(SharedTokenType.FILE_END); } assertTokensMatch(expected, extracted, "Extracted token from " + test.data().describeTestSource() + " does not match expected sequence."); + assertIterableEquals(expected, extracted); } /** From 3fccf53021c68693d3aa2338154d94e972bb6819 Mon Sep 17 00:00:00 2001 From: Timur Saglam Date: Tue, 8 Aug 2023 09:21:07 +0200 Subject: [PATCH 4/4] Adapt naming. --- .../jplag/testutils/LanguageModuleTest.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java b/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java index 30e2e577c..46133a743 100644 --- a/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java +++ b/language-testutils/src/test/java/de/jplag/testutils/LanguageModuleTest.java @@ -116,10 +116,10 @@ final List sourceCoverageFiles() { @MethodSource("tokenCoverageFiles") @DisplayName("Test that every token occurs at least once") final void testTokenCoverage(TestData data) throws ParsingException, IOException { - List foundTokens = extractTokenTypes(data); + List actualTokens = extractTokenTypes(data); List languageTokens = new ArrayList<>(this.languageTokens); - languageTokens.removeAll(foundTokens); + languageTokens.removeAll(actualTokens); assertTrue(languageTokens.isEmpty(), "Some tokens were not found in " + data.describeTestSource() + System.lineSeparator() + languageTokens); } @@ -143,10 +143,10 @@ final List tokenCoverageFiles() { @MethodSource("testTokensContainedData") @DisplayName("Test that the specified tokens at least occur") final void testTokensContained(TestDataCollector.TokenListTest test) throws ParsingException, IOException { - List foundTokens = extractTokenTypes(test.data()); + List actualTokens = extractTokenTypes(test.data()); List expectedTokens = new ArrayList<>(test.tokens()); - for (TokenType foundToken : foundTokens) { + for (TokenType foundToken : actualTokens) { expectedTokens.remove(foundToken); } @@ -172,20 +172,20 @@ final List testTokensContainedData() { @MethodSource("testTokenSequenceData") @DisplayName("Test if extracted token sequence matches") final void testTokenSequence(TestDataCollector.TokenListTest test) throws ParsingException, IOException { - List extracted = extractTokenTypes(test.data()); + List actual = extractTokenTypes(test.data()); List expected = new ArrayList<>(test.tokens()); if (expected.get(expected.size() - 1) != SharedTokenType.FILE_END) { expected.add(SharedTokenType.FILE_END); } - assertTokensMatch(expected, extracted, "Extracted token from " + test.data().describeTestSource() + " does not match expected sequence."); - assertIterableEquals(expected, extracted); + assertTokensMatch(expected, actual, "Extracted token from " + test.data().describeTestSource() + " does not match expected sequence."); + assertIterableEquals(expected, actual); } /** * Convenience method for using assertLinesMatch with token lists. */ - private void assertTokensMatch(List expected, List extracted, String message) { - assertLinesMatch(expected.stream().map(Object::toString), extracted.stream().map(Object::toString), message); + private void assertTokensMatch(List expected, List actual, String message) { + assertLinesMatch(expected.stream().map(Object::toString), actual.stream().map(Object::toString), message); } /** @@ -206,11 +206,11 @@ final List testTokenSequenceData() { @MethodSource("getAllTestData") @DisplayName("Test that the tokens map to ascending line numbers") final void testMonotoneTokenOrder(TestData data) throws ParsingException, IOException { - List extracted = parseTokens(data); + List tokens = parseTokens(data); - for (int i = 0; i < extracted.size() - 2; i++) { - Token first = extracted.get(i); - Token second = extracted.get(i + 1); + for (int i = 0; i < tokens.size() - 2; i++) { + Token first = tokens.get(i); + Token second = tokens.get(i + 1); if (first.getLine() > second.getLine()) { fail(String.format("Invalid token order. Token %s has a higher line number (%s) than token %s (%s).", first.getType(), @@ -229,9 +229,9 @@ final void testMonotoneTokenOrder(TestData data) throws ParsingException, IOExce @MethodSource("getAllTestData") @DisplayName("Test that the last token is the file end token") final void testTokenSequencesEndsWithFileEnd(TestData data) throws ParsingException, IOException { - List extracted = parseTokens(data); + List tokens = parseTokens(data); - assertEquals(SharedTokenType.FILE_END, extracted.get(extracted.size() - 1).getType(), + assertEquals(SharedTokenType.FILE_END, tokens.get(tokens.size() - 1).getType(), "Last token in " + data.describeTestSource() + " is not file end."); }