From 355f8b021d2911904085d71ae5e279386219a411 Mon Sep 17 00:00:00 2001 From: Sam Bishop <11415640+sambishop@users.noreply.github.com> Date: Fri, 2 Feb 2024 08:04:42 -0700 Subject: [PATCH] Ignore spaces after items in "Needs:" and "Tags:" lists (#373) Co-authored-by: Sam Bishop Co-authored-by: kaklakariada --- .../api/core/SpecificationItemId.java | 6 +- .../openfasttrace/api/core/TracedLink.java | 8 +- .../matcher/SpecificationItemIdMatcher.java | 5 +- .../matcher/SpecificationItemMatcher.java | 9 +- doc/changes/changes.md | 3 +- doc/changes/changes_3.7.2.md | 11 + doc/developer_guide.md | 18 +- .../importer/markdown/MarkdownImporter.java | 16 +- .../importer/markdown/MdPattern.java | 4 +- .../importer/markdown/ITMarkdownImporter.java | 243 ++++++++++++++++++ .../markdown/TestMarkdownImporter.java | 40 ++- .../importer/tag/TestTagImporter.java | 8 +- parent/pom.xml | 8 +- .../TestSpecobjectExportImport.java | 21 +- .../TestSpecobjectImportExport.java | 5 +- 15 files changed, 328 insertions(+), 77 deletions(-) create mode 100644 doc/changes/changes_3.7.2.md create mode 100644 importer/markdown/src/test/java/org/itsallcode/openfasttrace/importer/markdown/ITMarkdownImporter.java diff --git a/api/src/main/java/org/itsallcode/openfasttrace/api/core/SpecificationItemId.java b/api/src/main/java/org/itsallcode/openfasttrace/api/core/SpecificationItemId.java index 59d2f090a..9f101343e 100644 --- a/api/src/main/java/org/itsallcode/openfasttrace/api/core/SpecificationItemId.java +++ b/api/src/main/java/org/itsallcode/openfasttrace/api/core/SpecificationItemId.java @@ -137,11 +137,7 @@ else if (!this.name.equals(other.name)) { return false; } - if ((other.revision != REVISION_WILDCARD) && (this.revision != other.revision)) - { - return false; - } - return true; + return (other.revision == REVISION_WILDCARD) || (this.revision == other.revision); } @Override diff --git a/api/src/main/java/org/itsallcode/openfasttrace/api/core/TracedLink.java b/api/src/main/java/org/itsallcode/openfasttrace/api/core/TracedLink.java index 2c5762a55..2b770ee83 100644 --- a/api/src/main/java/org/itsallcode/openfasttrace/api/core/TracedLink.java +++ b/api/src/main/java/org/itsallcode/openfasttrace/api/core/TracedLink.java @@ -100,10 +100,6 @@ else if (!this.otherLinkEnd.equals(other.otherLinkEnd)) { return false; } - if (this.status != other.status) - { - return false; - } - return true; + return this.status == other.status; } -} \ No newline at end of file +} diff --git a/core/src/test/java/org/itsallcode/openfasttrace/core/matcher/SpecificationItemIdMatcher.java b/core/src/test/java/org/itsallcode/openfasttrace/core/matcher/SpecificationItemIdMatcher.java index d437984b1..18973f179 100644 --- a/core/src/test/java/org/itsallcode/openfasttrace/core/matcher/SpecificationItemIdMatcher.java +++ b/core/src/test/java/org/itsallcode/openfasttrace/core/matcher/SpecificationItemIdMatcher.java @@ -8,11 +8,10 @@ import org.hamcrest.Matcher; import org.hamcrest.collection.IsEmptyIterable; import org.hamcrest.collection.IsIterableContainingInAnyOrder; +import org.itsallcode.matcher.config.ConfigurableMatcher; +import org.itsallcode.matcher.config.MatcherConfig; import org.itsallcode.openfasttrace.api.core.SpecificationItemId; -import com.github.hamstercommunity.matcher.config.ConfigurableMatcher; -import com.github.hamstercommunity.matcher.config.MatcherConfig; - /** * {@link Matcher} for {@link SpecificationItemId} */ diff --git a/core/src/test/java/org/itsallcode/openfasttrace/core/matcher/SpecificationItemMatcher.java b/core/src/test/java/org/itsallcode/openfasttrace/core/matcher/SpecificationItemMatcher.java index 53300407e..762e90970 100644 --- a/core/src/test/java/org/itsallcode/openfasttrace/core/matcher/SpecificationItemMatcher.java +++ b/core/src/test/java/org/itsallcode/openfasttrace/core/matcher/SpecificationItemMatcher.java @@ -5,16 +5,13 @@ import java.util.Collection; import java.util.stream.StreamSupport; -import org.hamcrest.Factory; -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; +import org.hamcrest.*; import org.hamcrest.collection.IsEmptyIterable; import org.hamcrest.collection.IsIterableContainingInAnyOrder; +import org.itsallcode.matcher.config.ConfigurableMatcher; +import org.itsallcode.matcher.config.MatcherConfig; import org.itsallcode.openfasttrace.api.core.SpecificationItem; -import com.github.hamstercommunity.matcher.config.ConfigurableMatcher; -import com.github.hamstercommunity.matcher.config.MatcherConfig; - /** * {@link Matcher} for {@link SpecificationItem} */ diff --git a/doc/changes/changes.md b/doc/changes/changes.md index a9377ccf6..4194c8ca4 100644 --- a/doc/changes/changes.md +++ b/doc/changes/changes.md @@ -1,5 +1,6 @@ # Changes +* [3.7.2](changes_3.7.2.md) * [3.7.1](changes_3.7.1.md) * [3.7.0](changes_3.7.0.md) * [3.6.0](changes_3.6.0.md) @@ -37,4 +38,4 @@ * 0.4.0 * 0.3.0 * 0.2.0 -* 0.1.0 \ No newline at end of file +* 0.1.0 diff --git a/doc/changes/changes_3.7.2.md b/doc/changes/changes_3.7.2.md new file mode 100644 index 000000000..0770a62c2 --- /dev/null +++ b/doc/changes/changes_3.7.2.md @@ -0,0 +1,11 @@ +# OpenFastTrace 3.7.2, released 2024-??-?? + +Code name: Bugfixes for parsing `Needs` and `Tags` in Markdown + +## Summary + +This release fixes parsing of `Needs` and `Tags` entries in Markdown. OFT now ignores whitespace in both and also correctly parses `Tags` in beginning of a requirement item. + +## Bugfixes + +* #373: Ignore spaces after items in "Needs:" and "Tags:" lists (thanks to [@sambishop](https://github.com/sambishop) for his contribution!) diff --git a/doc/developer_guide.md b/doc/developer_guide.md index 9d2a492b0..e9f40f5ae 100644 --- a/doc/developer_guide.md +++ b/doc/developer_guide.md @@ -134,19 +134,19 @@ Add the following to your `~/.m2/settings.xml`: ### Prepare the Release 1. Checkout the `main` branch. -1. Create a new "prepare-release" branch. -1. Update version in - * `openfasttrace-parent/pom.xml` (`revision` property) - * `README.md` - * `doc/developer_guide.md` -1. Add changes in new version to `CHANGELOG.md` and update the release date. -1. Verify that build runs successfully: +2. Create a new "prepare-release" branch. +3. Update version in + * `openfasttrace-parent/pom.xml` (`revision` property) + * `README.md` + * `doc/developer_guide.md` +4. Add changes in new version to `doc/changes/changes.md` and `doc/changes/changes_$VERSION.md` and update the release date. +5. Verify that build runs successfully: ```bash mvn clean verify ``` -1. Commit and push changes. -1. Create a new Pull Request, have it reviewed and merged. +6. Commit and push changes. +7. Create a new Pull Request, have it reviewed and merged. ### Perform the Release diff --git a/importer/markdown/src/main/java/org/itsallcode/openfasttrace/importer/markdown/MarkdownImporter.java b/importer/markdown/src/main/java/org/itsallcode/openfasttrace/importer/markdown/MarkdownImporter.java index 45cce480c..1845a0322 100644 --- a/importer/markdown/src/main/java/org/itsallcode/openfasttrace/importer/markdown/MarkdownImporter.java +++ b/importer/markdown/src/main/java/org/itsallcode/openfasttrace/importer/markdown/MarkdownImporter.java @@ -8,9 +8,7 @@ import org.itsallcode.openfasttrace.api.core.ItemStatus; import org.itsallcode.openfasttrace.api.core.SpecificationItemId; -import org.itsallcode.openfasttrace.api.importer.ImportEventListener; -import org.itsallcode.openfasttrace.api.importer.Importer; -import org.itsallcode.openfasttrace.api.importer.ImporterException; +import org.itsallcode.openfasttrace.api.importer.*; import org.itsallcode.openfasttrace.api.importer.input.InputFile; class MarkdownImporter implements Importer @@ -42,10 +40,10 @@ class MarkdownImporter implements Importer transition(SPEC_ITEM , DEPENDS , MdPattern.DEPENDS , () -> {} ), transition(SPEC_ITEM , NEEDS , MdPattern.NEEDS_INT , this::addNeeds ), transition(SPEC_ITEM , NEEDS , MdPattern.NEEDS , () -> {} ), - transition(SPEC_ITEM , DESCRIPTION, MdPattern.DESCRIPTION, this::beginDescription ), - transition(SPEC_ITEM , DESCRIPTION, MdPattern.NOT_EMPTY , this::beginDescription ), transition(SPEC_ITEM , TAGS , MdPattern.TAGS_INT , this::addTag ), transition(SPEC_ITEM , TAGS , MdPattern.TAGS , () -> {} ), + transition(SPEC_ITEM , DESCRIPTION, MdPattern.DESCRIPTION, this::beginDescription ), + transition(SPEC_ITEM , DESCRIPTION, MdPattern.NOT_EMPTY , this::beginDescription ), transition(DESCRIPTION, SPEC_ITEM , MdPattern.ID , () -> {endDescription(); beginItem();} ), transition(DESCRIPTION, TITLE , MdPattern.TITLE , () -> {endDescription(); endItem(); rememberTitle(); }), @@ -301,9 +299,9 @@ private void addDependency() private void addNeeds() { final String artifactTypes = this.stateMachine.getLastToken(); - for (final String artifactType : artifactTypes.split(",\\s*")) + for (final String artifactType : artifactTypes.split(",")) { - this.listener.addNeededArtifactType(artifactType); + this.listener.addNeededArtifactType(artifactType.trim()); } } @@ -326,9 +324,9 @@ private void addCoverage() private void addTag() { final String tags = this.stateMachine.getLastToken(); - for (final String tag : tags.split(",\\s*")) + for (final String tag : tags.split(",")) { - this.listener.addTag(tag); + this.listener.addTag(tag.trim()); } } diff --git a/importer/markdown/src/main/java/org/itsallcode/openfasttrace/importer/markdown/MdPattern.java b/importer/markdown/src/main/java/org/itsallcode/openfasttrace/importer/markdown/MdPattern.java index de65dc1f8..2986964bb 100644 --- a/importer/markdown/src/main/java/org/itsallcode/openfasttrace/importer/markdown/MdPattern.java +++ b/importer/markdown/src/main/java/org/itsallcode/openfasttrace/importer/markdown/MdPattern.java @@ -37,7 +37,7 @@ enum MdPattern + SpecificationItemId.ID_PATTERN + ").*?"), ID("`?((?:" + SpecificationItemId.ID_PATTERN + ")|(?:" + SpecificationItemId.LEGACY_ID_PATTERN + "))`?.*"), - NEEDS_INT("Needs:\\s*(\\w+(?:,\\s*\\w+)*)"), + NEEDS_INT("Needs:(\\s*\\w+\\s*(?:,\\s*\\w+\\s*)*)"), NEEDS("Needs:\\s*"), NEEDS_REF(PatternConstants.UP_TO_3_WHITESPACES + PatternConstants.BULLETS + "(?:.*\\W)?" // @@ -46,7 +46,7 @@ enum MdPattern NOT_EMPTY("([^\n\r]+)"), RATIONALE("Rationale:\\s*"), STATUS("Status:\\s*(approved|proposed|draft)\\s*"), - TAGS_INT("Tags:\\s*(\\w+(?:,\\s*\\w+)*)"), + TAGS_INT("Tags:(\\s*\\w+\\s*(?:,\\s*\\w+\\s*)*)"), TAGS("Tags:\\s*"), TAG_ENTRY(PatternConstants.UP_TO_3_WHITESPACES + PatternConstants.BULLETS + "\\s*" // diff --git a/importer/markdown/src/test/java/org/itsallcode/openfasttrace/importer/markdown/ITMarkdownImporter.java b/importer/markdown/src/test/java/org/itsallcode/openfasttrace/importer/markdown/ITMarkdownImporter.java new file mode 100644 index 000000000..3862af5bb --- /dev/null +++ b/importer/markdown/src/test/java/org/itsallcode/openfasttrace/importer/markdown/ITMarkdownImporter.java @@ -0,0 +1,243 @@ +package org.itsallcode.openfasttrace.importer.markdown; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.itsallcode.openfasttrace.importer.markdown.MarkdownTestConstants.*; + +import java.io.BufferedReader; +import java.io.StringReader; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Stream; + +import org.itsallcode.matcher.auto.AutoMatcher; +import org.itsallcode.openfasttrace.api.core.*; +import org.itsallcode.openfasttrace.api.importer.Importer; +import org.itsallcode.openfasttrace.api.importer.SpecificationListBuilder; +import org.itsallcode.openfasttrace.api.importer.input.InputFile; +import org.itsallcode.openfasttrace.testutil.importer.input.StreamInput; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + + +class ITMarkdownImporter +{ + private static final String NL = System.lineSeparator(); + private static final String TAG2 = "Tag2"; + private static final String TAG1 = "Tag1"; + private static final String FILENAME = "file name"; + + @Test + void testFindRequirement() + { + assertThat(runImporterOnText(createCompleteSpecificationItemInMarkdownFormat()), + AutoMatcher.contains(SpecificationItem.builder().id(ID1).title("Requirement Title") + .comment("Comment" + NL + "More comment") + .description("Description" + NL + NL + "More description") + .rationale("Rationale" + NL + "More rationale") + .addNeedsArtifactType("artA").addNeedsArtifactType("artB") + .addCoveredId(SpecificationItemId.parseId(COVERED_ID1)) + .addCoveredId(SpecificationItemId.parseId(COVERED_ID2)) + .addDependOnId(SpecificationItemId.parseId(DEPENDS_ON_ID1)) + .addDependOnId(SpecificationItemId.parseId(DEPENDS_ON_ID2)) + .location("file name", 2) + .build())); + + } + + // [utest->dsn~md.needs-coverage-list-compact~1] + private String createCompleteSpecificationItemInMarkdownFormat() + { + return "# " + TITLE // + + "\n" // + + "`" + ID1 + "` " // + + "\n" // + + DESCRIPTION_LINE1 + "\n" // + + DESCRIPTION_LINE2 + "\n" // + + DESCRIPTION_LINE3 + "\n" // + + "\nRationale:\n" // + + RATIONALE_LINE1 + "\n" // + + RATIONALE_LINE2 + "\n" // + + "\nCovers:\n\n" // + + " * " + COVERED_ID1 + "\n" // + + " + " + "[Link to baz2](#" + COVERED_ID2 + ")\n" // + + "\nDepends:\n\n" // + + " + " + DEPENDS_ON_ID1 + "\n" // + + " - " + DEPENDS_ON_ID2 + "\n" // + + "\nComment:\n\n" // + + COMMENT_LINE1 + "\n" // + + COMMENT_LINE2 + "\n" // + + "\nNeeds: " + NEEDS_ARTIFACT_TYPE1 // + + " , " + NEEDS_ARTIFACT_TYPE2 + " "; + } + + private List runImporterOnText(final String text) + { + final BufferedReader reader = new BufferedReader(new StringReader(text)); + final InputFile file = StreamInput.forReader(Paths.get(FILENAME), reader); + final SpecificationListBuilder specItemBuilder = SpecificationListBuilder.create(); + final Importer importer = new MarkdownImporterFactory().createImporter(file, + specItemBuilder); + importer.runImport(); + return specItemBuilder.build(); + } + + @Test + void testTwoConsecutiveSpecificationItems() + { + assertThat(runImporterOnText(createTwoConsecutiveItemsInMarkdownFormat()), + AutoMatcher + .contains(SpecificationItem.builder().id(ID1).title(TITLE).location("file name", 2).build(), + SpecificationItem.builder().id(ID2).title("").location("file name", 4).build())); + } + + private String createTwoConsecutiveItemsInMarkdownFormat() + { + return "# " + TITLE // + + "\n" // + + ID1 + "\n" // + + "\n" + ID2 + "\n" // + + "# Irrelevant Title"; + } + + @Test + void testSingleNeeds() + { + final String singleNeedsItem = "`foo~bar~1`\n\nNeeds: " + NEEDS_ARTIFACT_TYPE1; + final List items = runImporterOnText(singleNeedsItem); + assertThat(items.get(0).getNeedsArtifactTypes(), contains(NEEDS_ARTIFACT_TYPE1)); + } + + @Test + void testFindLegacyRequirement() + { + final String completeItem = createCompleteSpecificationItemInLegacyMarkdownFormat(); + assertThat(runImporterOnText(completeItem), + AutoMatcher.contains(SpecificationItem.builder().id(SpecificationItemId.parseId(LEGACY_ID)) + .title("Requirement Title") + .status(ItemStatus.PROPOSED) + .comment("Comment" + NL + "More comment") + .description("Description" + NL + NL + "More description") + .rationale("Rationale" + NL + "More rationale") + .addNeedsArtifactType("artA").addNeedsArtifactType("artB") + .addCoveredId(SpecificationItemId.parseId(LEGACY_COVERED_ID1)) + .addCoveredId(SpecificationItemId.parseId(LEGACY_COVERED_ID2)) + .addDependOnId(SpecificationItemId.parseId(LEGACY_DEPENDS_ON_ID1)) + .addDependOnId(SpecificationItemId.parseId(LEGACY_DEPENDS_ON_ID2)) + .addTag("Tag1").addTag("Tag2") + .location("file name", 2) + .build())); + } + + // [utest->dsn~md.needs-coverage-list~2] + private String createCompleteSpecificationItemInLegacyMarkdownFormat() + { + return "# " + TITLE // + + "\n" // + + "`" + LEGACY_ID + "`" // + + "\n" // + + "\nStatus: proposed\n" // + + "\nDescription:\n" + DESCRIPTION_LINE1 + "\n" // + + DESCRIPTION_LINE2 + "\n" // + + DESCRIPTION_LINE3 + "\n" // + + "\nRationale:\n" // + + RATIONALE_LINE1 + "\n" // + + RATIONALE_LINE2 + "\n" // + + "\nDepends:\n\n" // + + " + `" + LEGACY_DEPENDS_ON_ID1 + "`\n" // + + " - `" + LEGACY_DEPENDS_ON_ID2 + "`\n" // + + "\nCovers:\n\n" // + + " * `" + LEGACY_COVERED_ID1 + "`\n" // + + " + `" + LEGACY_COVERED_ID2 + "`\n" // + + "\nComment:\n\n" // + + COMMENT_LINE1 + "\n" // + + COMMENT_LINE2 + "\n" // + + "\nNeeds:\n" // + + " * " + NEEDS_ARTIFACT_TYPE1 + "\n"// + + "+ " + NEEDS_ARTIFACT_TYPE2 + "\n" // + + "\nTags: " + TAG1 + ", " + TAG2; + } + + // [utest->dsn~md.artifact-forwarding-notation~1] + @Test + void testForwardRequirement() + { + final List items = runImporterOnText("arch-->dsn:req~foobar~2\n" // + + " * `dsn --> impl, utest,itest : arch~bar.zoo~123`"); + assertThat(items, + AutoMatcher.contains(SpecificationItem.builder().id(SpecificationItemId.parseId("arch~foobar~2")) + .forwards(true) + .addCoveredId(SpecificationItemId.parseId("req~foobar~2")) + .addNeedsArtifactType("dsn") + .build(), + SpecificationItem.builder().id(SpecificationItemId.parseId("dsn~bar.zoo~123")) + .addCoveredId(SpecificationItemId.parseId("arch~bar.zoo~123")) + .addNeedsArtifactType("impl").addNeedsArtifactType("utest") + .addNeedsArtifactType("itest") + .forwards(true) + .build())); + } + + // [utest->dsn~md.specification-item-title~1] + @Test + void testFindTitleAfterTitle() + { + assertThat(runImporterOnText("## This title should be ignored\n\n" // + + "### Title\n" // + + "`a~b~1`"), + AutoMatcher.contains(SpecificationItem.builder().id(SpecificationItemId.parseId("a~b~1")) + .title("Title").location("file name", 4) + .build())); + } + + @ParameterizedTest + @MethodSource("needsCoverage") + void testNeedsCoverage(final String mdContent, final List expected) + { + final List items = runImporterOnText("`a~b~1`\n" + mdContent); + assertThat(items.get(0).getNeedsArtifactTypes(), equalTo(expected)); + } + + static Stream needsCoverage() + { + return Stream.of( + Arguments.of("Needs: req , dsn ", List.of("req", "dsn")), + Arguments.of("Needs: req ", List.of("req")), + Arguments.of("Needs: req,dsn ", List.of("req", "dsn")), + Arguments.of("Needs: req ,dsn", List.of("req", "dsn")), + Arguments.of("Needs: req,dsn", List.of("req", "dsn")), + Arguments.of("Needs: req,\tdsn\n", List.of("req", "dsn")), + Arguments.of("Needs:req,dsn", List.of("req", "dsn")), + Arguments.of("Needs:\n* req\n* dsn", List.of("req", "dsn")), + Arguments.of("Needs:\n * req\n * dsn", List.of("req", "dsn")), + Arguments.of("Needs:\n* req \n\t* dsn ", List.of("req", "dsn")), + Arguments.of("Needs:\n* req\n* dsn", List.of("req", "dsn"))); + } + + @ParameterizedTest + @MethodSource("tags") + void testTags(final String mdContent, final List expected) + { + final List items = runImporterOnText("`a~b~1`\n" + mdContent); + assertThat(items.get(0).getTags(), equalTo(expected)); + } + + static Stream tags() + { + return Stream.of( + Arguments.of("Tags: req , dsn ", List.of("req", "dsn")), + Arguments.of("Tags: req ", List.of("req")), + Arguments.of("Tags: req,dsn ", List.of("req", "dsn")), + Arguments.of("Tags: req ,dsn", List.of("req", "dsn")), + Arguments.of("Tags: req,dsn", List.of("req", "dsn")), + Arguments.of("Tags: req,\tdsn\n", List.of("req", "dsn")), + Arguments.of("Tags:req,dsn", List.of("req", "dsn")), + Arguments.of("Tags:\n* req\n* dsn", List.of("req", "dsn")), + Arguments.of("Tags:\n * req\n * dsn\n", List.of("req", "dsn")), + Arguments.of("Tags:\n* req \n\t* dsn ", List.of("req", "dsn")), + Arguments.of("Tags:\n* req\n* dsn", List.of("req", "dsn"))); + } +} diff --git a/importer/markdown/src/test/java/org/itsallcode/openfasttrace/importer/markdown/TestMarkdownImporter.java b/importer/markdown/src/test/java/org/itsallcode/openfasttrace/importer/markdown/TestMarkdownImporter.java index d0bbdbe46..00487ee4d 100644 --- a/importer/markdown/src/test/java/org/itsallcode/openfasttrace/importer/markdown/TestMarkdownImporter.java +++ b/importer/markdown/src/test/java/org/itsallcode/openfasttrace/importer/markdown/TestMarkdownImporter.java @@ -3,13 +3,10 @@ import static org.itsallcode.openfasttrace.importer.markdown.MarkdownAsserts.assertMatch; import static org.itsallcode.openfasttrace.importer.markdown.MarkdownAsserts.assertMismatch; import static org.itsallcode.openfasttrace.importer.markdown.MarkdownTestConstants.*; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.Mockito.*; -import java.io.BufferedReader; -import java.io.Reader; -import java.io.StringReader; +import java.io.*; import java.nio.file.Paths; import org.itsallcode.openfasttrace.api.core.ItemStatus; @@ -41,18 +38,33 @@ class TestMarkdownImporter @Test void testIdentifyId() { - assertMatch(MdPattern.ID, "req~foo~1", "a~b~0", "req~test~1", - "req~test~999", "req~test.requirement~1", "req~test_underscore~1", - "`req~test1~1`arbitrary text"); - assertMismatch(MdPattern.ID, "test~1", "req-test~1", "req~4test~1"); + assertAll( + () -> assertMatch(MdPattern.ID, "req~foo~1", "a~b~0", "req~test~1", + "req~test~999", "req~test.requirement~1", "req~test_underscore~1", + "`req~test1~1`arbitrary text"), + () -> assertMismatch(MdPattern.ID, "test~1", "req-test~1", "req~4test~1")); } // [utest->dsn~md.specification-item-title~1] @Test void testIdentifyTitle() { - assertMatch(MdPattern.TITLE, "#Title", "# Title", "###### Title", "# Title"); - assertMismatch(MdPattern.TITLE, "Title", "Title #", " # Title"); + assertAll(() -> assertMatch(MdPattern.TITLE, "#Title", "# Title", "###### Title", "# Title"), + () -> assertMismatch(MdPattern.TITLE, "Title", "Title #", " # Title")); + } + + @Test + void testIdentifyNeeds() + { + assertAll(() -> assertMatch(MdPattern.NEEDS_INT, "Needs: req, dsn", "Needs:req,dsn", "Needs: \treq , dsn "), + () -> assertMismatch(MdPattern.NEEDS_INT, "Needs:")); + } + + @Test + void testIdentifyTags() + { + assertAll(() -> assertMatch(MdPattern.TAGS_INT, "Tags: req, dsn", "Tags:req,dsn", "Tags: \treq , dsn "), + () -> assertMismatch(MdPattern.TAGS_INT, "Tags:")); } @Test @@ -86,7 +98,7 @@ private String createCompleteSpecificationItemInMarkdownFormat() + COMMENT_LINE1 + "\n" // + COMMENT_LINE2 + "\n" // + "\nNeeds: " + NEEDS_ARTIFACT_TYPE1 // - + ", " + NEEDS_ARTIFACT_TYPE2; + + " , " + NEEDS_ARTIFACT_TYPE2 + " "; } private void runImporterOnText(final String text) @@ -279,4 +291,4 @@ void testFindTitleAfterTitle() inOrder.verify(this.listenerMock).setTitle("Title"); inOrder.verify(this.listenerMock).endSpecificationItem(); } -} \ No newline at end of file +} diff --git a/importer/tag/src/test/java/org/itsallcode/openfasttrace/importer/tag/TestTagImporter.java b/importer/tag/src/test/java/org/itsallcode/openfasttrace/importer/tag/TestTagImporter.java index 30977dbeb..b9fda6b5d 100644 --- a/importer/tag/src/test/java/org/itsallcode/openfasttrace/importer/tag/TestTagImporter.java +++ b/importer/tag/src/test/java/org/itsallcode/openfasttrace/importer/tag/TestTagImporter.java @@ -2,7 +2,6 @@ import static java.util.Collections.emptyList; import static org.hamcrest.MatcherAssert.assertThat; - import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.hasSize; @@ -13,6 +12,7 @@ import java.util.List; import java.util.zip.CRC32; +import org.itsallcode.matcher.auto.AutoMatcher; import org.itsallcode.openfasttrace.api.core.SpecificationItem; import org.itsallcode.openfasttrace.api.core.SpecificationItem.Builder; import org.itsallcode.openfasttrace.api.core.SpecificationItemId; @@ -22,8 +22,6 @@ import org.itsallcode.openfasttrace.testutil.importer.input.StreamInput; import org.junit.jupiter.api.Test; -import com.github.hamstercommunity.matcher.auto.AutoMatcher; - // [utest->dsn~import.full-coverage-tag~1] class TestTagImporter { @@ -304,7 +302,7 @@ private static SpecificationItem item(final String artifactType, final int lineN } private static SpecificationItem itemWithReadableName(final String artifactType, final int lineNumber, - final SpecificationItemId coveredId, List neededArtifactTypes) + final SpecificationItemId coveredId, final List neededArtifactTypes) { final SpecificationItemId generatedId = SpecificationItemId.createId(artifactType, coveredId.getName(), 0); @@ -317,7 +315,7 @@ private static SpecificationItem itemWithReadableName(final String artifactType, } private static SpecificationItem item(final String artifactType, final int lineNumber, - final int counter, final SpecificationItemId coveredId, List neededArtifactTypes) + final int counter, final SpecificationItemId coveredId, final List neededArtifactTypes) { final SpecificationItemId generatedId = SpecificationItemId.createId(artifactType, generateName(coveredId, lineNumber, counter), 0); diff --git a/parent/pom.xml b/parent/pom.xml index a997194c0..a05ef2517 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -8,7 +8,7 @@ Free requirement tracking suite https://github.com/itsallcode/openfasttrace - 3.7.1 + 3.7.2 11 5.10.1 3.2.5 @@ -202,7 +202,7 @@ org.mockito mockito-junit-jupiter - 5.9.0 + 5.10.0 test @@ -214,7 +214,7 @@ org.itsallcode hamcrest-auto-matcher - 0.5.0 + 0.6.0 test @@ -590,4 +590,4 @@ - \ No newline at end of file + diff --git a/product/src/test/java/org/itsallcode/openfasttrace/exporter/specobject/TestSpecobjectExportImport.java b/product/src/test/java/org/itsallcode/openfasttrace/exporter/specobject/TestSpecobjectExportImport.java index b26f872e4..c71d844ae 100644 --- a/product/src/test/java/org/itsallcode/openfasttrace/exporter/specobject/TestSpecobjectExportImport.java +++ b/product/src/test/java/org/itsallcode/openfasttrace/exporter/specobject/TestSpecobjectExportImport.java @@ -3,17 +3,15 @@ import static java.util.Arrays.asList; import static org.hamcrest.MatcherAssert.assertThat; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; +import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.util.List; import javax.xml.stream.*; +import org.itsallcode.matcher.auto.AutoMatcher; import org.itsallcode.openfasttrace.api.core.*; -import org.itsallcode.openfasttrace.api.core.Location; import org.itsallcode.openfasttrace.api.importer.SpecificationListBuilder; import org.itsallcode.openfasttrace.api.importer.input.InputFile; import org.itsallcode.openfasttrace.importer.specobject.SpecobjectImporterFactory; @@ -21,8 +19,6 @@ import org.itsallcode.openfasttrace.testutil.xml.IndentingXMLStreamWriter; import org.junit.jupiter.api.Test; -import com.github.hamstercommunity.matcher.auto.AutoMatcher; - class TestSpecobjectExportImport { @Test @@ -32,7 +28,7 @@ void testExportImportSimpleSpecObjectWithMandatoryElements() final SpecificationItem item = SpecificationItem.builder() // .id(SpecificationItemId.createId("foo", "bar", 1)) // .description("the description") // - .location(Location.create("dummy.xml", 4)) // + .location(location(4)) // .build(); assertExportAndImport(item); } @@ -51,7 +47,7 @@ void testExportImportSpecObjectWithOptionalElements() throws IOException, XMLStr .addDependOnId("req", "depend-on", 1) // .addNeedsArtifactType("impl") // .addTag("the tag") // - .location(Location.create("dummy.xml", 4)) // + .location(location(4)) // .build(); assertExportAndImport(item); } @@ -65,7 +61,7 @@ void testExportImportTwoSpecObjects() throws IOException, XMLStreamException .description("the description") // .rationale("the rationale") // .comment("the comment") // - .location(Location.create("dummy.xml", 4)) // + .location(location(4)) // .build(); final SpecificationItem itemB = SpecificationItem.builder() // .id(SpecificationItemId.createId("baz", "zoo", 2)) // @@ -73,11 +69,16 @@ void testExportImportTwoSpecObjects() throws IOException, XMLStreamException .description("another\ndescription") // .rationale("another\nrationale") // .comment("another\ncomment") // - .location(Location.create("dummy.xml", 5)) // + .location(location(5)) // .build(); assertExportAndImport(itemA, itemB); } + private org.itsallcode.openfasttrace.api.core.Location location(final int line) + { + return org.itsallcode.openfasttrace.api.core.Location.create("dummy.xml", line); + } + private void assertExportAndImport(final SpecificationItem... items) { final String exportedItems = exportToString(items); diff --git a/product/src/test/java/org/itsallcode/openfasttrace/importer/specobject/TestSpecobjectImportExport.java b/product/src/test/java/org/itsallcode/openfasttrace/importer/specobject/TestSpecobjectImportExport.java index 66c25ca94..1dcac7a24 100644 --- a/product/src/test/java/org/itsallcode/openfasttrace/importer/specobject/TestSpecobjectImportExport.java +++ b/product/src/test/java/org/itsallcode/openfasttrace/importer/specobject/TestSpecobjectImportExport.java @@ -9,6 +9,7 @@ import java.nio.file.Paths; import java.util.List; +import org.itsallcode.matcher.auto.AutoMatcher; import org.itsallcode.openfasttrace.api.core.*; import org.itsallcode.openfasttrace.api.importer.Importer; import org.itsallcode.openfasttrace.api.importer.SpecificationListBuilder; @@ -18,8 +19,6 @@ import org.itsallcode.openfasttrace.testutil.importer.input.StreamInput; import org.junit.jupiter.api.Test; -import com.github.hamstercommunity.matcher.auto.AutoMatcher; - class TestSpecobjectImportExport { @Test @@ -98,4 +97,4 @@ private List parse(final String content) importer.runImport(); return listener.build(); } -} \ No newline at end of file +}