From b49ffa24bed939539b42f2d28b676dda3a1ea192 Mon Sep 17 00:00:00 2001 From: Andrew Sweet Date: Fri, 17 Apr 2020 13:16:08 +0100 Subject: [PATCH 1/8] Added support for feature ordering via a feature tag --- README.adoc | 16 +- .../github/cukedoctor/api/model/Feature.java | 723 +++++++++--------- .../com/github/cukedoctor/api/model/Tag.java | 10 +- .../bdd/cukedoctor/OrderingSteps.java | 32 +- .../bdd/cukedoctor/ordering.feature | 57 +- .../{ordered.json => ordered-comments.json} | 0 .../cukedoctor/json-output/ordered-tags.json | 76 ++ 7 files changed, 546 insertions(+), 368 deletions(-) rename cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/{ordered.json => ordered-comments.json} (100%) create mode 100644 cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered-tags.json diff --git a/README.adoc b/README.adoc index 85c4434c..cacdbd25 100755 --- a/README.adoc +++ b/README.adoc @@ -242,9 +242,9 @@ Feature: Calculator === Feature ordering -To change the order features will be rendered in living documentation you can add `order comment`: +To change the order features will be rendered in living documentation you can add an `order comment` in cucumber-jvm 1.x only: -.ordererd.feature +.ordered.feature.comment ---- # order: 1 Feature: Calculator @@ -253,6 +253,18 @@ Feature: Calculator ---- +Or in cucumber-jvm 2.x and later, with an `order tag`: + +.ordered.feature.tag +---- +@order-1 +Feature: Calculator + + Scenario: Adding numbers + +---- + + === Enriching documentation ==== Asciidoc markup in comments diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Feature.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Feature.java index c0e53089..1da6702e 100755 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Feature.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Feature.java @@ -1,356 +1,367 @@ -package com.github.cukedoctor.api.model; - - -import static com.github.cukedoctor.util.Assert.hasText; -import static com.github.cukedoctor.util.Assert.notEmpty; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Logger; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.github.cukedoctor.api.ScenarioResults; -import com.github.cukedoctor.api.StepResults; -import com.github.cukedoctor.util.Constants; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class Feature implements Comparable { - - private String id; - private String name; - private String uri; - private String description; - private String keyword; - private List elements = new ArrayList<>(); - private List scenarios = new ArrayList<>(); - private List tags = new ArrayList<>(); - private StepResults stepResults; - private ScenarioResults scenarioResults; - private List comments; - @JsonIgnore - private String language; - - @JsonIgnore - private Integer order; - - @JsonIgnore - private boolean backgroundRendered;//backgrounds runs for each scenario so we will render it only in the first one - - - public Feature() { - - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getUri() { - return this.uri; - } - - public boolean hasTags() { - return notEmpty(tags); - } - - public boolean hasScenarios() { - return !elements.isEmpty(); - } - - public Status getStatus() { - return notEmpty(scenarioResults.getFailedScenarios()) ? Status.failed : Status.passed; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - public void setName(String name) { - this.name = name; - } - - public void setUri(String uri) { - this.uri = uri; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getKeyword() { - return keyword; - } - - public void setKeyword(String keyword) { - this.keyword = keyword; - } - - public List getElements() { - return elements; - } - - public void setElements(List elements) { - this.elements = elements; - } - - public List getTags() { - return tags; - } - - public void setTags(List tags) { - this.tags = tags; - } - - public StepResults getStepResults() { - return stepResults; - } - - public ScenarioResults getScenarioResults() { - return scenarioResults; - } - - public List getComments() { - return comments; - } - - public void setComments(List comments) { - this.comments = comments; - } - - - public boolean isBackgroundRendered() { - return backgroundRendered; - } - - - public void setBackgroundRendered(boolean backgroundRendered) { - this.backgroundRendered = backgroundRendered; - } - - - /** - * @deprecated use {@link Feature#getScenarioResults()} - * @return total number of scenarios - */ - @Deprecated - public Integer getNumberOfScenarios() { - Integer result = 0; - if (scenarios != null) { - List elementList = new ArrayList(); - for (Scenario element : scenarios) { - if (!element.hasExamples()) { - elementList.add(element); - } - } - result = elementList.size(); - } - return result; - } - - public Integer getNumberOfSteps() { - return stepResults.getNumberOfSteps(); - } - - public Integer getNumberOfPasses() { - return stepResults.getNumberOfPasses(); - } - - public Integer getNumberOfFailures() { - return stepResults.getNumberOfFailures(); - } - - public Integer getNumberOfPending() { - return stepResults.getNumberOfPending(); - } - - public Integer getNumberOfSkipped() { - return stepResults.getNumberOfSkipped(); - } - - public Integer getNumberOfMissing() { - return stepResults.getNumberOfMissing(); - } - - public Integer getNumberOfUndefined() { - return stepResults.getNumberOfUndefined(); - } - - public String getDurationOfSteps() { - return stepResults.getTotalDurationAsString(); - } - - public Integer getNumberOfScenariosPassed() { - return scenarioResults.getNumberOfScenariosPassed(); - } - - public Integer getNumberOfScenariosFailed() { - return scenarioResults.getNumberOfScenariosFailed(); - } - - public List getScenarios() { - return scenarios;//scenario & scenario outline - } - - public void initScenarios() { - if (elements != null) { - for (Scenario element : elements) { - scenarios.add(element); - } - } - - } - - public void processSteps() { - if (!isCucumberFeature()) { - return; - } - List allSteps = new ArrayList(); - Map statusCounter = new HashMap<>(); - for (Status status : Status.values()) { - statusCounter.put(status, new AtomicInteger(0)); - } - List passedScenarios = new ArrayList(); - List failedScenarios = new ArrayList(); - long totalDuration = 0L; - - if (scenarios != null) { - for (Scenario scenario : scenarios) { - if (scenario.hasExamples()) { - continue; - } - calculateScenarioStats(passedScenarios, failedScenarios, scenario); - if (scenario.hasSteps()) { - for (Step step : scenario.getSteps()) { - allSteps.add(step); - statusCounter.get(step.getStatus()).incrementAndGet(); - totalDuration += step.getDuration(); - } - } - } - } - scenarioResults = new ScenarioResults(passedScenarios, failedScenarios); - stepResults = new StepResults(allSteps, statusCounter, totalDuration); - } - - private void calculateScenarioStats(List passedScenarios, List failedScenarios, Scenario element) { - if(element.isBackground()) { - return;//background scenarios are not considered as scenrario - } - if (element.getStatus() == Status.passed) { - passedScenarios.add(element); - } else if (element.getStatus() == Status.failed) { - failedScenarios.add(element); - } - } - - - public boolean isCucumberFeature() { - return this.getName() != null && this.getKeyword() != null && (this.elements != null && !this.elements.isEmpty()); - } - - public String getLanguage() { - if (language == null && comments != null) { - for (Comment comment : comments) { - if (hasText(comment.getLanguage())) { - this.language = comment.getLanguage(); - } - } - } - if (language == null) { - this.language = ""; - } - - return language; - } - - public Integer getOrder() { - if (order == null && comments != null) { - for (Comment comment : comments) { - if (hasText(comment.getOrder())) { - try { - this.order = Integer.parseInt(comment.getOrder()); - } catch (Exception e) { - Logger.getLogger(getClass().getName()).warning(String.format("Could not get order of feature %s cause: %s", name, e.getMessage())); - } - } - } - } - if (order == null) { - this.order = -1; - } - - return order; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Feature feature = (Feature) o; - - return !(id != null ? !id.equals(feature.id) : feature.id != null); - - } - - @Override - public int hashCode() { - return name != null ? name.hashCode() : 42; - } - - public boolean hasIgnoreDocsTag() { - if (hasTags()) { - for (Tag tag : tags) { - if (Constants.SKIP_DOCS.equalsIgnoreCase(tag.getName())) { - return true; - } - } - } - return false; - } - - @Override - public String toString() { - return name; - } - - @Override - public int compareTo(Feature other) { - int result = 0; - if (this.getOrder() != null && other.getOrder() != null) { - result = getOrder().compareTo(other.getOrder()); - } - - //same order or no-order use name - if (result == 0) { - result = name.compareTo(other.getName()); - } - - return result; - - } - - public Scenario getScenarioByName(String name) { - - if (hasText(name) && hasScenarios()) { - for (Scenario scenario : scenarios) { - if (hasText(scenario.getName()) && scenario.getName().trim().equals(name)) { - return scenario; - } - } - } - return null; - } -} +package com.github.cukedoctor.api.model; + + +import static com.github.cukedoctor.util.Assert.hasText; +import static com.github.cukedoctor.util.Assert.notEmpty; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Logger; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.github.cukedoctor.api.ScenarioResults; +import com.github.cukedoctor.api.StepResults; +import com.github.cukedoctor.util.Constants; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Feature implements Comparable { + + private String id; + private String name; + private String uri; + private String description; + private String keyword; + private List elements = new ArrayList<>(); + private List scenarios = new ArrayList<>(); + private List tags = new ArrayList<>(); + private StepResults stepResults; + private ScenarioResults scenarioResults; + private List comments; + @JsonIgnore + private String language; + + @JsonIgnore + private Integer order; + + @JsonIgnore + private boolean backgroundRendered;//backgrounds runs for each scenario so we will render it only in the first one + + + public Feature() { + + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUri() { + return this.uri; + } + + public boolean hasTags() { + return notEmpty(tags); + } + + public boolean hasScenarios() { + return !elements.isEmpty(); + } + + public Status getStatus() { + return notEmpty(scenarioResults.getFailedScenarios()) ? Status.failed : Status.passed; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public void setName(String name) { + this.name = name; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getKeyword() { + return keyword; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + + public List getElements() { + return elements; + } + + public void setElements(List elements) { + this.elements = elements; + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public StepResults getStepResults() { + return stepResults; + } + + public ScenarioResults getScenarioResults() { + return scenarioResults; + } + + public List getComments() { + return comments; + } + + public void setComments(List comments) { + this.comments = comments; + } + + + public boolean isBackgroundRendered() { + return backgroundRendered; + } + + + public void setBackgroundRendered(boolean backgroundRendered) { + this.backgroundRendered = backgroundRendered; + } + + + /** + * @deprecated use {@link Feature#getScenarioResults()} + * @return total number of scenarios + */ + @Deprecated + public Integer getNumberOfScenarios() { + Integer result = 0; + if (scenarios != null) { + List elementList = new ArrayList(); + for (Scenario element : scenarios) { + if (!element.hasExamples()) { + elementList.add(element); + } + } + result = elementList.size(); + } + return result; + } + + public Integer getNumberOfSteps() { + return stepResults.getNumberOfSteps(); + } + + public Integer getNumberOfPasses() { + return stepResults.getNumberOfPasses(); + } + + public Integer getNumberOfFailures() { + return stepResults.getNumberOfFailures(); + } + + public Integer getNumberOfPending() { + return stepResults.getNumberOfPending(); + } + + public Integer getNumberOfSkipped() { + return stepResults.getNumberOfSkipped(); + } + + public Integer getNumberOfMissing() { + return stepResults.getNumberOfMissing(); + } + + public Integer getNumberOfUndefined() { + return stepResults.getNumberOfUndefined(); + } + + public String getDurationOfSteps() { + return stepResults.getTotalDurationAsString(); + } + + public Integer getNumberOfScenariosPassed() { + return scenarioResults.getNumberOfScenariosPassed(); + } + + public Integer getNumberOfScenariosFailed() { + return scenarioResults.getNumberOfScenariosFailed(); + } + + public List getScenarios() { + return scenarios;//scenario & scenario outline + } + + public void initScenarios() { + if (elements != null) { + for (Scenario element : elements) { + scenarios.add(element); + } + } + + } + + public void processSteps() { + if (!isCucumberFeature()) { + return; + } + List allSteps = new ArrayList(); + Map statusCounter = new HashMap<>(); + for (Status status : Status.values()) { + statusCounter.put(status, new AtomicInteger(0)); + } + List passedScenarios = new ArrayList(); + List failedScenarios = new ArrayList(); + long totalDuration = 0L; + + if (scenarios != null) { + for (Scenario scenario : scenarios) { + if (scenario.hasExamples()) { + continue; + } + calculateScenarioStats(passedScenarios, failedScenarios, scenario); + if (scenario.hasSteps()) { + for (Step step : scenario.getSteps()) { + allSteps.add(step); + statusCounter.get(step.getStatus()).incrementAndGet(); + totalDuration += step.getDuration(); + } + } + } + } + scenarioResults = new ScenarioResults(passedScenarios, failedScenarios); + stepResults = new StepResults(allSteps, statusCounter, totalDuration); + } + + private void calculateScenarioStats(List passedScenarios, List failedScenarios, Scenario element) { + if(element.isBackground()) { + return;//background scenarios are not considered as scenrario + } + if (element.getStatus() == Status.passed) { + passedScenarios.add(element); + } else if (element.getStatus() == Status.failed) { + failedScenarios.add(element); + } + } + + + public boolean isCucumberFeature() { + return this.getName() != null && this.getKeyword() != null && (this.elements != null && !this.elements.isEmpty()); + } + + public String getLanguage() { + if (language == null && comments != null) { + for (Comment comment : comments) { + if (hasText(comment.getLanguage())) { + this.language = comment.getLanguage(); + } + } + } + if (language == null) { + this.language = ""; + } + + return language; + } + + public Integer getOrder() { + if (order == null && comments != null) { + for (Comment comment : comments) { + trySetOrder(comment.getOrder(), "comment"); + } + } + + if (order == null && hasTags()) { + for (Tag tag : getTags()) { + trySetOrder(tag.getOrder(), "tag"); + } + } + + if (order == null) { + this.order = -1; + } + + return order; + } + + private void trySetOrder(String order, String source) { + if (hasText(order)) { + try { + this.order = Integer.parseInt(order); + } catch (Exception e) { + Logger.getLogger(getClass().getName()).warning(String.format("Could not get order of feature %s from %s cause: %s", name, source, e.getMessage())); + } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Feature feature = (Feature) o; + + return !(id != null ? !id.equals(feature.id) : feature.id != null); + + } + + @Override + public int hashCode() { + return name != null ? name.hashCode() : 42; + } + + public boolean hasIgnoreDocsTag() { + if (hasTags()) { + for (Tag tag : tags) { + if (Constants.SKIP_DOCS.equalsIgnoreCase(tag.getName())) { + return true; + } + } + } + return false; + } + + @Override + public String toString() { + return name; + } + + @Override + public int compareTo(Feature other) { + int result = 0; + if (this.getOrder() != null && other.getOrder() != null) { + result = getOrder().compareTo(other.getOrder()); + } + + //same order or no-order use name + if (result == 0) { + result = name.compareTo(other.getName()); + } + + return result; + + } + + public Scenario getScenarioByName(String name) { + + if (hasText(name) && hasScenarios()) { + for (Scenario scenario : scenarios) { + if (hasText(scenario.getName()) && scenario.getName().trim().equals(name)) { + return scenario; + } + } + } + return null; + } +} diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java index d42377c6..e5973431 100755 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import static com.github.cukedoctor.util.Assert.hasText; + @JsonIgnoreProperties(ignoreUnknown = true) public class Tag { @@ -18,5 +20,11 @@ public String getName() { return name; } - + public String getOrder(){ + int indexOfOrder = name.indexOf("order-"); + if(hasText(name) && indexOfOrder != -1){ + return name.substring(indexOfOrder+6).trim(); + } + return null; + } } diff --git a/cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/OrderingSteps.java b/cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/OrderingSteps.java index 61536f77..23ebc3fd 100644 --- a/cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/OrderingSteps.java +++ b/cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/OrderingSteps.java @@ -3,7 +3,6 @@ import com.github.cukedoctor.Cukedoctor; import com.github.cukedoctor.api.model.Feature; import com.github.cukedoctor.parser.FeatureParser; -import cucumber.api.PendingException; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import cucumber.api.java.en.When; @@ -37,21 +36,38 @@ public void I_convert_the_using_default_order() throws Throwable { @Then("^Features should be ordered by name in resulting documentation$") public void Features_should_be_ordered_by_name_in_resulting_documentation(String expected) throws Throwable { - assertThat(documentation.replaceAll("\r","")).isNotNull().contains(expected.replaceAll("\r","")); - } + assertThat(documentation.replaceAll("\r", "")).isNotNull().contains(expected.replaceAll("\r", "")); + } @When("^I convert them using comment order$") public void I_convert_them__using_comment_order() throws Throwable { - URL featureFile = getClass().getResource("/com/github/cukedoctor/json-output/ordered.json"); + convert("/com/github/cukedoctor/json-output/ordered-comments.json"); + } + + @Then("^Features should be ordered respecting order comment$") + public void Features_should_be_ordered_respecting_order_comment(String expected) throws Throwable { + assertFeaturesShouldBeOrdered(expected); + } + + @When("^I convert them using tag order$") + public void I_convert_them__using_tag_order() throws Throwable { + convert("/com/github/cukedoctor/json-output/ordered-tags.json"); + } + + @Then("^Features should be ordered respecting order tag$") + public void Features_should_be_ordered_respecting_order_tag(String expected) throws Throwable { + assertFeaturesShouldBeOrdered(expected); + } + + private void convert(String featureFilePath) { + URL featureFile = getClass().getResource(featureFilePath); assertThat(featureFile).isNotNull(); List features = FeatureParser.parse(featureFile.getPath()); assertThat(features).isNotNull().hasSize(2); documentation = Cukedoctor.instance(features).renderFeatures().getDocumentation(); } - @Then("^Features should be ordered respecting order comment$") - public void Features_should_be_ordered_respecting_order_comment(String expected) throws Throwable { - assertThat(documentation.replaceAll("\r","")).isNotNull().contains(expected.replaceAll("\r","")); + private void assertFeaturesShouldBeOrdered(String expected) { + assertThat(documentation.replaceAll("\r", "")).isNotNull().contains(expected.replaceAll("\r", "")); } - } diff --git a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/ordering.feature b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/ordering.feature index aea0efb5..108db685 100644 --- a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/ordering.feature +++ b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/ordering.feature @@ -55,7 +55,8 @@ scenario step icon:thumbs-up[role="green",title="Passed"] [small right]#(000ms)# """ - Scenario: Custom ordering + Scenario: Custom ordering with comments + Supported only for cucumber-jvm 1.x #{NOTE: Ordering is done using feature comment '*#order:*'} Given The following two features: @@ -103,3 +104,57 @@ scenario step icon:thumbs-up[role="green",title="Passed"] [small right]#(313ms)# """ + + + Scenario: Custom ordering with tags + + #{NOTE: Ordering is done using feature tag '*@order-*'} + Given The following two features: +""" +@order-2 +Feature: Feature1 + + Scenario: Scenario feature 1 + + Given scenario step + +@order-1 +Feature: Feature2 + + Scenario: Scenario feature 2 + + Given scenario step +""" + When I convert them using tag order + +# cukedoctor-discrete + Then Features should be ordered respecting order tag +""" +== *Features* + +[[Feature2, Feature2]] +=== *Feature2* + +==== Scenario: Scenario feature 2 +[small]#tags: @order-1# + + +========== +Given :: +scenario step icon:thumbs-up[role="green",title="Passed"] [small right]#(000ms)# +========== + +[[Feature1, Feature1]] +=== *Feature1* + +==== Scenario: Scenario feature 1 +[small]#tags: @order-2# + + +========== +Given :: +scenario step icon:thumbs-up[role="green",title="Passed"] [small right]#(313ms)# +========== + + +""" \ No newline at end of file diff --git a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered.json b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered-comments.json similarity index 100% rename from cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered.json rename to cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered-comments.json diff --git a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered-tags.json b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered-tags.json new file mode 100644 index 00000000..5a5b7956 --- /dev/null +++ b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered-tags.json @@ -0,0 +1,76 @@ +[ + { + "line": 2, + "elements": [ + { + "line": 4, + "name": "Scenario feature 1", + "description": "", + "id": "feature1;scenario-feature-1", + "type": "scenario", + "keyword": "Scenario", + "steps": [ + { + "result": { + "duration": 313437628, + "status": "passed" + }, + "line": 6, + "name": "scenario step", + "match": { + "location": "SimpleSteps.scenario_step()" + }, + "keyword": "Given " + } + ] + } + ], + "name": "Feature1", + "description": "", + "id": "feature1", + "keyword": "Feature", + "tags": [ + { + "name": "@order-2" + } + ], + "uri": "com/github/cukedoctor/bdd/sample/simple1.feature" + }, + { + "line": 2, + "elements": [ + { + "line": 4, + "name": "Scenario feature 2", + "description": "", + "id": "feature2;scenario-feature-2", + "type": "scenario", + "keyword": "Scenario", + "steps": [ + { + "result": { + "duration": 58498, + "status": "passed" + }, + "line": 6, + "name": "scenario step", + "match": { + "location": "SimpleSteps.scenario_step()" + }, + "keyword": "Given " + } + ] + } + ], + "name": "Feature2", + "description": "", + "id": "feature2", + "keyword": "Feature", + "tags": [ + { + "name": "@order-1" + } + ], + "uri": "com/github/cukedoctor/bdd/sample/simple2.feature" + } +] \ No newline at end of file From e2620b548e043b146ad172fdfd85628274506bc5 Mon Sep 17 00:00:00 2001 From: Andrew Sweet Date: Fri, 17 Apr 2020 16:34:04 +0100 Subject: [PATCH 2/8] Removed order tags from rendered documents --- .../com/github/cukedoctor/api/model/Tag.java | 47 ++++---- .../renderer/CukedoctorScenarioRenderer.java | 2 +- .../renderer/CukedoctorTagsRenderer.java | 17 +++ .../github/cukedoctor/spi/TagsRenderer.java | 2 + .../renderer/CukedoctorTagsRendererTest.java | 103 ++++++++++++++++++ .../cukedoctor/renderer/RendererTest.java | 26 +++++ .../bdd/cukedoctor/ordering.feature | 6 +- .../cukedoctor/json-output/ordered-tags.json | 41 +++++-- 8 files changed, 207 insertions(+), 37 deletions(-) create mode 100644 cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java index e5973431..0d2b426a 100755 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java @@ -7,24 +7,29 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class Tag { - private String name; - - public Tag() { - } - - public Tag(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public String getOrder(){ - int indexOfOrder = name.indexOf("order-"); - if(hasText(name) && indexOfOrder != -1){ - return name.substring(indexOfOrder+6).trim(); - } - return null; - } -} + private String name; + + public Tag() { + } + + public Tag(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public boolean isOrder() { + return getOrder() != null; + } + + public String getOrder() { + int indexOfOrder = name.indexOf("order-"); + if (hasText(name) && indexOfOrder != -1) { + return name.substring(indexOfOrder + 6).trim(); + } + + return null; + } +} \ No newline at end of file diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java index 52543fc8..d0b499bb 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java @@ -108,7 +108,7 @@ public String renderScenario(Scenario scenario, Feature feature) { } - if (!cukedoctorConfig.isHideTags() && (feature.hasTags() || scenario.hasTags())) { + if (!cukedoctorConfig.isHideTags() && tagsRenderer.shouldRenderScenarioTags(feature, scenario)) { docBuilder.append(renderScenarioTags(scenario, feature)); } diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java index b1fd9ec2..1a39a8d5 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java @@ -32,4 +32,21 @@ public String renderScenarioTags(Feature feature, Scenario scenario) { docBuilder.newLine(); return docBuilder.toString(); } + + @Override + public boolean shouldRenderScenarioTags(Feature feature, Scenario scenario) { + if (feature.hasTags()) { + for (Tag tag : feature.getTags()) { + if (!tag.isOrder()) return true; + } + } + + if (scenario.hasTags()) { + for (Tag tag : scenario.getTags()) { + if (!tag.isOrder()) return true; + } + } + + return false; + } } diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/TagsRenderer.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/TagsRenderer.java index 2cacdc21..cceb5048 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/TagsRenderer.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/TagsRenderer.java @@ -10,4 +10,6 @@ public interface TagsRenderer extends BaseRenderer { String renderScenarioTags(Feature feature, Scenario scenario); + + boolean shouldRenderScenarioTags(Feature feature, Scenario scenario); } diff --git a/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java new file mode 100644 index 00000000..3ff0ad77 --- /dev/null +++ b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java @@ -0,0 +1,103 @@ +package com.github.cukedoctor.renderer; + +import com.github.cukedoctor.api.model.Feature; +import com.github.cukedoctor.api.model.Scenario; +import com.github.cukedoctor.api.model.Tag; +import com.github.cukedoctor.spi.TagsRenderer; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(JUnit4.class) +public class CukedoctorTagsRendererTest { + private TagsRenderer tagsRenderer = new CukedoctorTagsRenderer(); + + @Test + public void shouldNotRenderIfNeitherFeatureNorScenarioHasTags() { + Assert.assertFalse("", tagsRenderer.shouldRenderScenarioTags(createEmptyFeature(), createEmptyScenario())); + } + + + @Test + public void shouldRenderIfScenarioHasTags() { + Assert.assertTrue(tagsRenderer.shouldRenderScenarioTags(createEmptyFeature(), createScenario("@someTag"))); + } + + @Test + public void shouldRenderIfScenarioHasOrderAndNotOrderTags() { + Assert.assertTrue(tagsRenderer.shouldRenderScenarioTags(createEmptyFeature(), createScenario("@someTag", "@order-42"))); + } + + @Test + public void shouldNotRenderIfScenarioOnlyHasSingleOrderTagAndFeatureHasNoTags() { + Assert.assertFalse(tagsRenderer.shouldRenderScenarioTags(createEmptyFeature(), createScenario("@order-42"))); + } + + @Test + public void shouldNotRenderIfScenarioOnlyHasOrderTagsAndFeatureHasNoTags() { + Assert.assertFalse(tagsRenderer.shouldRenderScenarioTags(createEmptyFeature(), createScenario("@order-42", "@order-1"))); + } + + + @Test + public void shouldRenderIfFeatureHasTagsButNotOrderTags() { + Assert.assertTrue(tagsRenderer.shouldRenderScenarioTags(createFeature("@someTag"), createEmptyScenario())); + } + + @Test + public void shouldRenderIfFeatureHasOrderAndNotOrderTags() { + Assert.assertTrue(tagsRenderer.shouldRenderScenarioTags(createFeature("@someTag", "@order-42"), createEmptyScenario())); + } + + @Test + public void shouldNotRenderIfFeatureOnlyHasSingleOrderTagAndScenarioHasNoTags() { + Assert.assertFalse(tagsRenderer.shouldRenderScenarioTags(createFeature("@order-42"), createEmptyScenario())); + } + + @Test + public void shouldNotRenderIfFeatureOnlyHasOrderTagsAndScenarioHasNoTags() { + Assert.assertFalse(tagsRenderer.shouldRenderScenarioTags(createFeature("@order-42", "@order-1"), createEmptyScenario())); + } + + + private Feature createFeature(String... names) { + final Feature feature = new Feature(); + feature.setTags(createTags(names)); + return feature; + } + + private Feature createEmptyFeature() { + final Feature feature = new Feature(); + Assert.assertFalse("Feature unexpectedly has tags", feature.hasTags()); + return feature; + } + + private Scenario createScenario(String... names) { + final Scenario scenario = new Scenario(); + scenario.setTags(createTags(names)); + return scenario; + } + + private Scenario createEmptyScenario() { + final Scenario scenario = createScenario(); + Assert.assertFalse("Scenario unexpectedly has tags", scenario.hasTags()); + return scenario; + } + + private List createTags(String... names) { + if (names != null && names.length != 0) { + ArrayList tags = new ArrayList<>(names.length); + for (String name : names) { + tags.add(new Tag(name)); + } + + return tags; + } + + return new ArrayList<>(0); + } +} diff --git a/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/RendererTest.java b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/RendererTest.java index bbd3be22..4aa9cfa2 100644 --- a/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/RendererTest.java +++ b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/RendererTest.java @@ -128,6 +128,32 @@ public void shouldRenderFeatureScenariosWithTagsInFeaturesAndScenarios(){ "description 2" + newLine() + newLine()); } + @Test + public void shouldRenderFeatureScenariosOmittingTagsIfOrderFeatureTagIsTheOnlyTag() { + // cucumber-jvm-5.6.0 cascades feature tags down to scenarios. See "ordering.feature" and "order-tags.json" for an example. + final Feature feature = FeatureBuilder.instance().aFeatureWithTwoScenarios(); + final String orderTagName = "@order-42"; + feature.getTags().add(new Tag(orderTagName)); + for (Scenario scenario : feature.getScenarios()) { + ScenarioBuilder.instance(scenario).tag(new Tag(orderTagName)); + } + + CukedoctorScenarioRenderer scenarioRenderer = new CukedoctorScenarioRenderer(); + scenarioRenderer = spy(scenarioRenderer); + doReturn("").when(scenarioRenderer).renderScenarioSteps(anyListOf(Step.class)); + doReturn("").when(scenarioRenderer).renderScenarioExamples(any(Scenario.class)); + + CukedoctorFeatureRenderer featureRenderer = new CukedoctorFeatureRenderer(); + featureRenderer = spy(featureRenderer); + featureRenderer.scenarioRenderer = scenarioRenderer; + + String resultDoc = featureRenderer.renderFeatureScenarios(feature); + assertThat(resultDoc).isEqualTo("==== Scenario: scenario 1" + newLine() + + "description" + newLine() + newLine() + + "==== Scenario: scenario 2" + newLine() + + "description 2" + newLine() + newLine()); + } + @Test public void shouldRenderFeatureStepsWithOnePassingStep(){ final Feature feature = FeatureBuilder.instance().aFeatureWithOneScenarioWithOnePassingStep(); diff --git a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/ordering.feature b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/ordering.feature index 108db685..4af619e7 100644 --- a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/ordering.feature +++ b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/ordering.feature @@ -136,8 +136,6 @@ Feature: Feature2 === *Feature2* ==== Scenario: Scenario feature 2 -[small]#tags: @order-1# - ========== Given :: @@ -148,12 +146,10 @@ scenario step icon:thumbs-up[role="green",title="Passed"] [small right]#(000ms)# === *Feature1* ==== Scenario: Scenario feature 1 -[small]#tags: @order-2# - ========== Given :: -scenario step icon:thumbs-up[role="green",title="Passed"] [small right]#(313ms)# +scenario step icon:thumbs-up[role="green",title="Passed"] [small right]#(001ms)# ========== diff --git a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered-tags.json b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered-tags.json index 5a5b7956..67d4d86f 100644 --- a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered-tags.json +++ b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/ordered-tags.json @@ -3,6 +3,7 @@ "line": 2, "elements": [ { + "start_timestamp": "2020-04-17T15:02:48.477Z", "line": 4, "name": "Scenario feature 1", "description": "", @@ -12,16 +13,21 @@ "steps": [ { "result": { - "duration": 313437628, + "duration": 1998800, "status": "passed" }, "line": 6, "name": "scenario step", "match": { - "location": "SimpleSteps.scenario_step()" + "location": "org.example.StepDefinitions.scenarioStep()" }, "keyword": "Given " } + ], + "tags": [ + { + "name": "@order-2" + } ] } ], @@ -29,17 +35,23 @@ "description": "", "id": "feature1", "keyword": "Feature", + "uri": "classpath:org/example/1.feature", "tags": [ { - "name": "@order-2" + "name": "@order-2", + "type": "Tag", + "location": { + "line": 1, + "column": 1 + } } - ], - "uri": "com/github/cukedoctor/bdd/sample/simple1.feature" + ] }, { "line": 2, "elements": [ { + "start_timestamp": "2020-04-17T15:02:48.583Z", "line": 4, "name": "Scenario feature 2", "description": "", @@ -49,16 +61,20 @@ "steps": [ { "result": { - "duration": 58498, "status": "passed" }, "line": 6, "name": "scenario step", "match": { - "location": "SimpleSteps.scenario_step()" + "location": "org.example.StepDefinitions.scenarioStep()" }, "keyword": "Given " } + ], + "tags": [ + { + "name": "@order-1" + } ] } ], @@ -66,11 +82,16 @@ "description": "", "id": "feature2", "keyword": "Feature", + "uri": "classpath:org/example/2.feature", "tags": [ { - "name": "@order-1" + "name": "@order-1", + "type": "Tag", + "location": { + "line": 1, + "column": 1 + } } - ], - "uri": "com/github/cukedoctor/bdd/sample/simple2.feature" + ] } ] \ No newline at end of file From cf600603a34a75d7057e5f485cac22f4564db39a Mon Sep 17 00:00:00 2001 From: Andrew Sweet Date: Sat, 18 Apr 2020 10:41:59 +0100 Subject: [PATCH 3/8] Fixed issue #134 allowing simplification of support for order tags --- .../renderer/CukedoctorScenarioRenderer.java | 2 +- .../renderer/CukedoctorTagsRenderer.java | 42 ++++----- .../github/cukedoctor/spi/TagsRenderer.java | 1 - .../bdd/cukedoctor/TagRenderingSteps.java | 30 +++++++ .../renderer/CukedoctorTagsRendererTest.java | 80 ++++++++++++++--- .../bdd/cukedoctor/tag-rendering.feature | 50 +++++++++++ .../cukedoctor/json-output/tag-rendering.json | 86 +++++++++++++++++++ 7 files changed, 258 insertions(+), 33 deletions(-) create mode 100644 cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/TagRenderingSteps.java create mode 100644 cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/tag-rendering.feature create mode 100644 cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/tag-rendering.json diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java index d0b499bb..8a11c9a0 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java @@ -108,7 +108,7 @@ public String renderScenario(Scenario scenario, Feature feature) { } - if (!cukedoctorConfig.isHideTags() && tagsRenderer.shouldRenderScenarioTags(feature, scenario)) { + if (!cukedoctorConfig.isHideTags()) { docBuilder.append(renderScenarioTags(scenario, feature)); } diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java index 1a39a8d5..62c91056 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java @@ -5,6 +5,9 @@ import com.github.cukedoctor.api.model.Tag; import com.github.cukedoctor.spi.TagsRenderer; +import java.util.HashSet; +import java.util.List; + /** * Created by pestano on 28/02/16. */ @@ -12,41 +15,38 @@ public class CukedoctorTagsRenderer extends AbstractBaseRenderer implements Tags @Override public String renderScenarioTags(Feature feature, Scenario scenario) { + int expectedSize = (feature.hasTags() ? feature.getTags().size() : 0) + (scenario.hasTags() ? scenario.getTags().size() : 0); + if (expectedSize == 0) return ""; + + HashSet tagNames = new HashSet<>(expectedSize); + extractTagNames(tagNames, feature.getTags()); + extractTagNames(tagNames, scenario.getTags()); + if (tagNames.size() == 0) return ""; + docBuilder.clear(); StringBuilder tags = new StringBuilder("[small]#tags: "); - if (feature.hasTags()) { - for (Tag featureTag : feature.getTags()) { - tags.append(featureTag.getName()).append(","); - } - } - if (scenario.hasTags()) { - for (Tag scenarioTag : scenario.getTags()) { - tags.append(scenarioTag.getName()).append(","); - } + for (String tagName : tagNames) { + tags.append(tagName).append(","); } + if (tags.indexOf(",") != -1) {//delete last comma tags.deleteCharAt(tags.lastIndexOf(",")); } + tags.append("#"); docBuilder.textLine(tags.toString()); docBuilder.newLine(); return docBuilder.toString(); } - @Override - public boolean shouldRenderScenarioTags(Feature feature, Scenario scenario) { - if (feature.hasTags()) { - for (Tag tag : feature.getTags()) { - if (!tag.isOrder()) return true; - } - } + private void extractTagNames(HashSet tagNames, List tags) { + if (tags == null) return; - if (scenario.hasTags()) { - for (Tag tag : scenario.getTags()) { - if (!tag.isOrder()) return true; + for (Tag tag : tags) { + if (!tag.isOrder()) { + tagNames.add(tag.getName()); } } - - return false; } + } diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/TagsRenderer.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/TagsRenderer.java index cceb5048..98ac6300 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/TagsRenderer.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/TagsRenderer.java @@ -11,5 +11,4 @@ public interface TagsRenderer extends BaseRenderer { String renderScenarioTags(Feature feature, Scenario scenario); - boolean shouldRenderScenarioTags(Feature feature, Scenario scenario); } diff --git a/cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/TagRenderingSteps.java b/cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/TagRenderingSteps.java new file mode 100644 index 00000000..a1d3c486 --- /dev/null +++ b/cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/TagRenderingSteps.java @@ -0,0 +1,30 @@ +package com.github.cukedoctor.bdd.cukedoctor; + +import com.github.cukedoctor.Cukedoctor; +import com.github.cukedoctor.api.model.Feature; +import com.github.cukedoctor.parser.FeatureParser; +import cucumber.api.java.en.Then; +import cucumber.api.java.en.When; + +import java.net.URL; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TagRenderingSteps { + + String documentation; + + @When("^I render the feature$") + public void I_render_the_feature() throws Throwable { + URL featureFile = getClass().getResource("/com/github/cukedoctor/json-output/tag-rendering.json"); + assertThat(featureFile).isNotNull(); + List features = FeatureParser.parse(featureFile.getPath()); + documentation = Cukedoctor.instance(features).renderFeatures().getDocumentation(); + } + + @Then("^the tags displayed under each scenario should not have duplicates$") + public void the_tags_displayed_under_each_scenario_should_not_have_duplicates(String expected) { + assertThat(documentation.replaceAll("\r", "")).isNotNull().contains(expected.replaceAll("\r", "")); + } +} diff --git a/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java index 3ff0ad77..50ef5bc2 100644 --- a/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java +++ b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java @@ -12,55 +12,115 @@ import java.util.ArrayList; import java.util.List; +import static com.github.cukedoctor.util.Constants.newLine; +import static org.junit.Assert.assertEquals; + @RunWith(JUnit4.class) public class CukedoctorTagsRendererTest { - private TagsRenderer tagsRenderer = new CukedoctorTagsRenderer(); + private final TagsRenderer tagsRenderer = new CukedoctorTagsRenderer(); + private final String someTag = "@someTag"; + private final String order42 = "@order-42"; + private final String order1 = "@order-1"; + private final String otherTag = "@otherTag"; + @Test public void shouldNotRenderIfNeitherFeatureNorScenarioHasTags() { - Assert.assertFalse("", tagsRenderer.shouldRenderScenarioTags(createEmptyFeature(), createEmptyScenario())); + assertEquals( + "", + tagsRenderer.renderScenarioTags(createEmptyFeature(), createEmptyScenario()) + ); } @Test public void shouldRenderIfScenarioHasTags() { - Assert.assertTrue(tagsRenderer.shouldRenderScenarioTags(createEmptyFeature(), createScenario("@someTag"))); + assertEquals( + "[small]#tags: " + someTag + "#" + newLine() + newLine(), + tagsRenderer.renderScenarioTags(createEmptyFeature(), createScenario(someTag)) + ); } @Test public void shouldRenderIfScenarioHasOrderAndNotOrderTags() { - Assert.assertTrue(tagsRenderer.shouldRenderScenarioTags(createEmptyFeature(), createScenario("@someTag", "@order-42"))); + assertEquals( + "[small]#tags: " + someTag + "#" + newLine() + newLine(), + tagsRenderer.renderScenarioTags(createEmptyFeature(), createScenario(someTag, order42)) + ); } @Test public void shouldNotRenderIfScenarioOnlyHasSingleOrderTagAndFeatureHasNoTags() { - Assert.assertFalse(tagsRenderer.shouldRenderScenarioTags(createEmptyFeature(), createScenario("@order-42"))); + assertEquals( + "", + tagsRenderer.renderScenarioTags(createEmptyFeature(), createScenario(order42)) + ); } @Test public void shouldNotRenderIfScenarioOnlyHasOrderTagsAndFeatureHasNoTags() { - Assert.assertFalse(tagsRenderer.shouldRenderScenarioTags(createEmptyFeature(), createScenario("@order-42", "@order-1"))); + assertEquals( + "", + tagsRenderer.renderScenarioTags(createEmptyFeature(), createScenario(order42, order1)) + ); } @Test public void shouldRenderIfFeatureHasTagsButNotOrderTags() { - Assert.assertTrue(tagsRenderer.shouldRenderScenarioTags(createFeature("@someTag"), createEmptyScenario())); + assertEquals( + "[small]#tags: " + someTag + "#" + newLine() + newLine(), + tagsRenderer.renderScenarioTags(createFeature(someTag), createEmptyScenario()) + ); } @Test public void shouldRenderIfFeatureHasOrderAndNotOrderTags() { - Assert.assertTrue(tagsRenderer.shouldRenderScenarioTags(createFeature("@someTag", "@order-42"), createEmptyScenario())); + assertEquals( + "[small]#tags: " + someTag + "#" + newLine() + newLine(), + tagsRenderer.renderScenarioTags(createFeature(someTag, order42), createEmptyScenario()) + ); } @Test public void shouldNotRenderIfFeatureOnlyHasSingleOrderTagAndScenarioHasNoTags() { - Assert.assertFalse(tagsRenderer.shouldRenderScenarioTags(createFeature("@order-42"), createEmptyScenario())); + assertEquals( + "", + tagsRenderer.renderScenarioTags(createFeature(order42), createEmptyScenario()) + ); } @Test public void shouldNotRenderIfFeatureOnlyHasOrderTagsAndScenarioHasNoTags() { - Assert.assertFalse(tagsRenderer.shouldRenderScenarioTags(createFeature("@order-42", "@order-1"), createEmptyScenario())); + assertEquals( + "", + tagsRenderer.renderScenarioTags(createFeature(order42, order1), createEmptyScenario()) + ); + } + + + @Test + public void shouldRenderIfFeatureAndScenarioHaveTags() { + assertEquals( + "[small]#tags: " + someTag + "," + otherTag + "#" + newLine() + newLine(), + tagsRenderer.renderScenarioTags(createFeature(someTag), createScenario(otherTag)) + ); + } + + @Test + public void shouldRenderTagOnceIfPresentOnBothFeatureAndScenario() { + assertEquals( + "[small]#tags: " + someTag + "," + otherTag + "#" + newLine() + newLine(), + tagsRenderer.renderScenarioTags(createFeature(someTag), createScenario(otherTag, someTag)) + ); + } + + @Test + public void shouldNotRenderIfFeatureAndScenarioOnlyHaveOrderTags() { + assertEquals( + "", + tagsRenderer.renderScenarioTags(createFeature(order42), createScenario(order42)) + ); } diff --git a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/tag-rendering.feature b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/tag-rendering.feature new file mode 100644 index 00000000..aff8fe45 --- /dev/null +++ b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/tag-rendering.feature @@ -0,0 +1,50 @@ +# order: 4 +Feature: Tag rendering + + Scenario: Render feature tags in that feature's scenarios + + Given The following two features: +""" +@someTag +Feature: Feature1 + + @otherTag + Scenario: Scenario feature 1 + + Given scenario step + + @someTag @otherTag + Scenario: Scenario feature 2 + + Given scenario step +""" + + When I render the feature + + Then the tags displayed under each scenario should not have duplicates +""" +== *Features* + +[[Feature1, Feature1]] +=== *Feature1* + +==== Scenario: Scenario feature 1 +[small]#tags: @someTag,@otherTag# + + +========== +Given :: +scenario step icon:thumbs-up[role="green",title="Passed"] [small right]#(001ms)# +========== + +==== Scenario: Scenario feature 2 +[small]#tags: @someTag,@otherTag# + + +========== +Given :: +scenario step icon:thumbs-up[role="green",title="Passed"] [small right]#(000ms)# +========== + + +""" \ No newline at end of file diff --git a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/tag-rendering.json b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/tag-rendering.json new file mode 100644 index 00000000..31992881 --- /dev/null +++ b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/json-output/tag-rendering.json @@ -0,0 +1,86 @@ +[ + { + "line": 2, + "elements": [ + { + "start_timestamp": "2020-04-18T06:52:50.150Z", + "line": 5, + "name": "Scenario feature 1", + "description": "", + "id": "feature1;scenario-feature-1", + "type": "scenario", + "keyword": "Scenario", + "steps": [ + { + "result": { + "duration": 1998200, + "status": "passed" + }, + "line": 7, + "name": "scenario step", + "match": { + "location": "org.example.StepDefinitions.scenarioStep()" + }, + "keyword": "Given " + } + ], + "tags": [ + { + "name": "@someTag" + }, + { + "name": "@otherTag" + } + ] + }, + { + "start_timestamp": "2020-04-18T06:52:50.366Z", + "line": 10, + "name": "Scenario feature 2", + "description": "", + "id": "feature1;scenario-feature-2", + "type": "scenario", + "keyword": "Scenario", + "steps": [ + { + "result": { + "status": "passed" + }, + "line": 12, + "name": "scenario step", + "match": { + "location": "org.example.StepDefinitions.scenarioStep()" + }, + "keyword": "Given " + } + ], + "tags": [ + { + "name": "@someTag" + }, + { + "name": "@someTag" + }, + { + "name": "@otherTag" + } + ] + } + ], + "name": "Feature1", + "description": "", + "id": "feature1", + "keyword": "Feature", + "uri": "classpath:org/example/1.feature", + "tags": [ + { + "name": "@someTag", + "type": "Tag", + "location": { + "line": 1, + "column": 1 + } + } + ] + } +] \ No newline at end of file From 691eb048d53b02830eb557cd58e14d8f1f01b3c1 Mon Sep 17 00:00:00 2001 From: Andrew Sweet Date: Sun, 19 Apr 2020 13:07:05 +0100 Subject: [PATCH 4/8] Support for enrichment of docstrings via custom content type 'cukedoctor-discrete' or via feature/scenario tag '@cukedoctor-discrete'. Also fixed some test assertions which failed on Windows. --- .../cukedoctor/api/model/DocString.java | 6 + .../com/github/cukedoctor/api/model/Tag.java | 18 +- .../renderer/CukedoctorScenarioRenderer.java | 6 +- .../renderer/CukedoctorStepsRenderer.java | 462 +++++++++--------- .../renderer/CukedoctorTagsRenderer.java | 2 +- .../github/cukedoctor/spi/StepsRenderer.java | 4 +- .../bdd/cukedoctor/EnrichmentSteps.java | 40 +- .../converter/CukedoctorConverterTest.java | 14 +- .../renderer/CukedoctorTagsRendererTest.java | 17 + .../cukedoctor/renderer/RendererTest.java | 29 +- .../bdd/cukedoctor/enrichment.feature | 283 ++++++++++- .../table-and-source-content-type.json | 68 +++ .../table-and-source-feature-tag.json | 86 ++++ .../table-and-source-scenario-tag.json | 76 +++ ...son => table-and-source-step-comment.json} | 2 +- .../example/spi/CustomScenarioRenderer.java | 8 +- 16 files changed, 833 insertions(+), 288 deletions(-) create mode 100644 cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-content-type.json create mode 100644 cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-feature-tag.json create mode 100644 cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-scenario-tag.json rename cukedoctor-converter/src/test/resources/json-output/enrichment/{table-and-source.json => table-and-source-step-comment.json} (97%) diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/DocString.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/DocString.java index 4c78359f..0024d760 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/DocString.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/DocString.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.Objects; + /** * Created by rafael-pestano on 01/07/2015. */ @@ -29,6 +31,10 @@ public void setContent_type(String value) { this.content_type = value; } + public boolean isDiscrete() { + return Objects.equals(content_type, "cukedoctor-discrete"); + } + @Override public String toString() { return value; diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java index 0d2b426a..56768033 100755 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java @@ -16,6 +16,15 @@ public Tag(String name) { this.name = name; } + private static String extractPattern(String pattern, String text) { + int indexOfOrder = text.indexOf(pattern); + if (hasText(text) && indexOfOrder != -1) { + return text.substring(indexOfOrder + pattern.length()).trim(); + } + + return null; + } + public String getName() { return name; } @@ -25,11 +34,10 @@ public boolean isOrder() { } public String getOrder() { - int indexOfOrder = name.indexOf("order-"); - if (hasText(name) && indexOfOrder != -1) { - return name.substring(indexOfOrder + 6).trim(); - } + return extractPattern("order-", name); + } - return null; + public boolean isDiscrete() { + return extractPattern("cukedoctor-discrete", name) != null; } } \ No newline at end of file diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java index 8a11c9a0..85bca5f4 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorScenarioRenderer.java @@ -124,13 +124,13 @@ public String renderScenario(Scenario scenario, Feature feature) { } if (scenario.hasSteps()) { - docBuilder.append(renderScenarioSteps(scenario.getSteps())); + docBuilder.append(renderScenarioSteps(scenario.getSteps(), scenario, feature)); } return docBuilder.toString(); } - String renderScenarioSteps(List scenarioSteps) { - return stepsRenderer.renderSteps(scenarioSteps); + String renderScenarioSteps(List scenarioSteps, Scenario scenario, Feature feature) { + return stepsRenderer.renderSteps(scenarioSteps, scenario, feature); } String renderScenarioExamples(Scenario scenario) { diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorStepsRenderer.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorStepsRenderer.java index aeea6b81..5229c855 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorStepsRenderer.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorStepsRenderer.java @@ -1,227 +1,235 @@ -package com.github.cukedoctor.renderer; - -import static com.github.cukedoctor.api.CukedoctorDocumentBuilder.Factory.newInstance; -import static com.github.cukedoctor.util.Assert.hasText; -import static com.github.cukedoctor.util.Assert.notEmpty; -import static com.github.cukedoctor.util.Assert.notNull; -import static com.github.cukedoctor.util.Constants.newLine; -import static com.github.cukedoctor.util.Constants.Markup.listing; -import static com.github.cukedoctor.util.Constants.Markup.table; -import static com.github.cukedoctor.util.Constants.Markup.tableCol; - -import java.util.List; - -import com.github.cukedoctor.api.CukedoctorDocumentBuilder; -import com.github.cukedoctor.api.model.Comment; -import com.github.cukedoctor.api.model.DocString; -import com.github.cukedoctor.api.model.Output; -import com.github.cukedoctor.api.model.Result; -import com.github.cukedoctor.api.model.Row; -import com.github.cukedoctor.api.model.Status; -import com.github.cukedoctor.api.model.Step; -import com.github.cukedoctor.config.CukedoctorConfig; -import com.github.cukedoctor.spi.StepsRenderer; -import com.github.cukedoctor.util.Constants; -import com.github.cukedoctor.util.Formatter; - -/** - * Created by pestano on 28/02/16. - */ -public class CukedoctorStepsRenderer extends AbstractBaseRenderer implements StepsRenderer { - - - public CukedoctorStepsRenderer() { - } - - public CukedoctorStepsRenderer(CukedoctorConfig cukedoctorConfig) { - this.cukedoctorConfig = cukedoctorConfig; - } - - @Override - public String renderSteps(List steps) { - docBuilder.clear(); - - docBuilder.textLine("=========="); - for (Step step : steps) { - docBuilder.append(step.getKeyword(), "::", newLine()); - docBuilder.append(step.getName() + " ", Status.getStatusIcon(step.getStatus())); - if(!cukedoctorConfig.isHideStepTime()){ - docBuilder.append(renderStepTime(step.getResult())); - } - - docBuilder.append(renderStepTable(step)); - - if (notNull(step.getDocString()) && hasText(step.getDocString().getValue())) { - if(step.hasDiscreteComment()){ - //discrete step renders inside a sidebar block and has [discrete] class on every line - renderDiscreteSidebarBlock(step.getDocString()); - - } else{ - renderListingBlock(step.getDocString()); - } - - } - - if (step.getResult() != null && !Status.passed.equals(step.getStatus())) { - if (step.getResult().getErrorMessage() != null) { - docBuilder.append(newLine(), "IMPORTANT: ", step.getResult().getErrorMessage(), newLine()); - } - } - renderOutput(step); - enrichStep(step); - } - docBuilder.textLine("==========").newLine(); - - return docBuilder.toString(); - } - - void renderOutput(Step step) { - if(step.hasOutput()){ - docBuilder.textLine(listing()); - for (Output output : step.getOutput()) { - docBuilder.textLine(output.getValue()); - } - docBuilder.textLine(listing()); - } - } - - private void renderListingBlock(DocString docString) { - if(docString.getContentType() != null && !docString.getContentType().equals("")) { - docBuilder.append("[source,", docString.getContentType(), "]", newLine()); - } - docBuilder.append(listing(), newLine(), newLine()); - docBuilder.append(docString.getValue().replaceAll("\\n", newLine())); - docBuilder.append(newLine(), newLine(), listing(), newLine()); - } - - private void renderDiscreteSidebarBlock(DocString docString) { - docBuilder.append("******", newLine(), newLine()); - - String[] lines = docString.getValue().replaceAll("\\*\\*\\*\\*","*****").replaceAll(Constants.Markup.exampleBlock(),Constants.Markup.exampleBlock()+"=").split("\\n"); - - //every line that starts with \n and not contains pipe(|) will have discrete class - // pipe is skipped because it denotes table cells in asciidoc and putting - // a discrete class will break tables - //also includes are skipped - //regex try:("^(?=.*^\\n)(?!\\n\\|).*$") - boolean isListing = false; //control if line is inside a listing - boolean isTable = false;//control if line is inside a table - - for (String line : lines) { - - if(!isListing){ - line = line.replaceAll("\r", ""); - } - if(isListing){ - if(line.contains("----")){ - //end listing - isListing = false; - } - docBuilder.textLine(line); - continue; - } - - if(!isListing && line.contains("----")){ - isListing = true; - docBuilder.textLine(line); - continue; - } - - //do not add discrete to callouts - if(line.startsWith("<") && line.endsWith(">")){ - docBuilder.textLine(line); - continue; - } - //do not add discrete to complex blocks otherwise it will produce invalid markup like below: - /** - * [discrete] - [IMPORTANT] - [discrete] - ====== - */ - if(line.startsWith("======")){ - docBuilder.textLine(line); - continue; - } - - if(isTable){ - //skip discrete class when within a table - docBuilder.textLine(line); - if(line.contains(table())){ - isTable = false;//end table - } - continue; - } - - //skips discrete class for table col (it must add discrete to table itself) - if(line.contains(table())) { - isTable = true; - } - //not inside a table neither listing then add discrete class to line - docBuilder.textLine(Constants.DISCRETE).textLine(line); - } - docBuilder.append(newLine(), newLine(), "******", newLine()); - } - - private void enrichStep(Step step) { - if(step != null && step.hasComments()){ - int numComments = step.getComments().size(); - for (Comment comment : step.getComments()) { - if(hasText(comment.getValue()) && (comment.getValue().contains("{") && comment.getValue().contains("}"))){ - String line = comment.getValue(); - //do not add new line for listing, complex blocks, callouts - if(comment.getValue().contains("[source") || - line.contains("====") || line.contains(Constants.Markup.listing()) - || (line.startsWith("<") && line.endsWith(">")) - ){ - docBuilder.textLine(line.replaceAll("\\n", newLine()). - replaceAll("#\\{", "").replaceAll("# \\{", ""). - replaceAll("}", "")); - } else{ - docBuilder.textLine(line.replaceAll("\\n", newLine()). - replaceAll("#\\{", newLine()).replaceAll("# \\{", newLine()). - replaceAll("}", "")); - } - - } - //add new line to last comment - if(step.getComments().indexOf(comment) == numComments-1){ - docBuilder.newLine(); - } - } - } - - } - - String renderStepTime(Result result) { - if (result == null || result.getDuration() == null) { - return ""; - } - return " [small right]#(" + Formatter.formatTime(result.getDuration()) + ")#"; - } - - String renderStepTable(Step step) { - //TODO convert to AsciidocBuilder - CukedoctorDocumentBuilder builder = newInstance(); - builder.newLine(); - if (notEmpty(step.getRows())) { - builder.newLine(); - builder.append("[cols=\"" + step.getRows()[0].getCells().length + "*\", options=\"header\"]").newLine(); - builder.textLine(table()); - Row header = step.getRows()[0]; - for (String col : header.getCells()) { - builder.append(tableCol(), col).newLine(); - } - - for (int i = 1; i < step.getRows().length; i++) { - for (String cell : step.getRows()[i].getCells()) { - builder.append(tableCol(), cell).newLine(); - } - } - builder.textLine(table()); - builder.newLine(); - } - - return builder.toString(); - } -} +package com.github.cukedoctor.renderer; + +import com.github.cukedoctor.api.CukedoctorDocumentBuilder; +import com.github.cukedoctor.api.model.*; +import com.github.cukedoctor.config.CukedoctorConfig; +import com.github.cukedoctor.spi.StepsRenderer; +import com.github.cukedoctor.util.Constants; +import com.github.cukedoctor.util.Formatter; + +import java.util.List; + +import static com.github.cukedoctor.api.CukedoctorDocumentBuilder.Factory.newInstance; +import static com.github.cukedoctor.util.Assert.*; +import static com.github.cukedoctor.util.Constants.Markup.*; +import static com.github.cukedoctor.util.Constants.newLine; + +/** + * Created by pestano on 28/02/16. + */ +public class CukedoctorStepsRenderer extends AbstractBaseRenderer implements StepsRenderer { + + + public CukedoctorStepsRenderer() { + } + + public CukedoctorStepsRenderer(CukedoctorConfig cukedoctorConfig) { + this.cukedoctorConfig = cukedoctorConfig; + } + + @Override + public String renderSteps(List steps, Scenario scenario, Feature feature) { + docBuilder.clear(); + + docBuilder.textLine("=========="); + for (Step step : steps) { + docBuilder.append(step.getKeyword(), "::", newLine()); + docBuilder.append(step.getName() + " ", Status.getStatusIcon(step.getStatus())); + if(!cukedoctorConfig.isHideStepTime()){ + docBuilder.append(renderStepTime(step.getResult())); + } + + docBuilder.append(renderStepTable(step)); + + if (notNull(step.getDocString()) && hasText(step.getDocString().getValue())) { + if(step.getDocString().isDiscrete() || step.hasDiscreteComment() || isDiscrete(scenario) || isDiscrete(feature)) { + //discrete step renders inside a sidebar block and has [discrete] class on every line + renderDiscreteSidebarBlock(step.getDocString()); + + } else{ + renderListingBlock(step.getDocString()); + } + + } + + if (step.getResult() != null && !Status.passed.equals(step.getStatus())) { + if (step.getResult().getErrorMessage() != null) { + docBuilder.append(newLine(), "IMPORTANT: ", step.getResult().getErrorMessage(), newLine()); + } + } + renderOutput(step); + enrichStep(step); + } + docBuilder.textLine("==========").newLine(); + + return docBuilder.toString(); + } + + private boolean isDiscrete(Scenario scenario) { + if (!scenario.hasTags()) return false; + return isDiscrete(scenario.getTags()); + } + + private boolean isDiscrete(Feature feature) { + if (!feature.hasTags()) return false; + return isDiscrete(feature.getTags()); + } + + private boolean isDiscrete(Iterable tags) { + for (Tag tag : tags) { + if (tag.isDiscrete()) return true; + } + + return false; + } + + void renderOutput(Step step) { + if(step.hasOutput()){ + docBuilder.textLine(listing()); + for (Output output : step.getOutput()) { + docBuilder.textLine(output.getValue()); + } + docBuilder.textLine(listing()); + } + } + + private void renderListingBlock(DocString docString) { + if(docString.getContentType() != null && !docString.getContentType().equals("")) { + docBuilder.append("[source,", docString.getContentType(), "]", newLine()); + } + docBuilder.append(listing(), newLine(), newLine()); + docBuilder.append(docString.getValue().replaceAll("\\n", newLine())); + docBuilder.append(newLine(), newLine(), listing(), newLine()); + } + + private void renderDiscreteSidebarBlock(DocString docString) { + docBuilder.append("******", newLine(), newLine()); + + String[] lines = docString.getValue().replaceAll("\\*\\*\\*\\*","*****").replaceAll(Constants.Markup.exampleBlock(),Constants.Markup.exampleBlock()+"=").split("\\n"); + + //every line that starts with \n and not contains pipe(|) will have discrete class + // pipe is skipped because it denotes table cells in asciidoc and putting + // a discrete class will break tables + //also includes are skipped + //regex try:("^(?=.*^\\n)(?!\\n\\|).*$") + boolean isListing = false; //control if line is inside a listing + boolean isTable = false;//control if line is inside a table + + for (String line : lines) { + + if(!isListing){ + line = line.replaceAll("\r", ""); + } + if(isListing){ + if(line.contains("----")){ + //end listing + isListing = false; + } + docBuilder.textLine(line); + continue; + } + + if(!isListing && line.contains("----")){ + isListing = true; + docBuilder.textLine(line); + continue; + } + + //do not add discrete to callouts + if(line.startsWith("<") && line.endsWith(">")){ + docBuilder.textLine(line); + continue; + } + //do not add discrete to complex blocks otherwise it will produce invalid markup like below: + /** + * [discrete] + [IMPORTANT] + [discrete] + ====== + */ + if(line.startsWith("======")){ + docBuilder.textLine(line); + continue; + } + + if(isTable){ + //skip discrete class when within a table + docBuilder.textLine(line); + if(line.contains(table())){ + isTable = false;//end table + } + continue; + } + + //skips discrete class for table col (it must add discrete to table itself) + if(line.contains(table())) { + isTable = true; + } + //not inside a table neither listing then add discrete class to line + docBuilder.textLine(Constants.DISCRETE).textLine(line); + } + docBuilder.append(newLine(), newLine(), "******", newLine()); + } + + private void enrichStep(Step step) { + if(step != null && step.hasComments()){ + int numComments = step.getComments().size(); + for (Comment comment : step.getComments()) { + if(hasText(comment.getValue()) && (comment.getValue().contains("{") && comment.getValue().contains("}"))){ + String line = comment.getValue(); + //do not add new line for listing, complex blocks, callouts + if(comment.getValue().contains("[source") || + line.contains("====") || line.contains(Constants.Markup.listing()) + || (line.startsWith("<") && line.endsWith(">")) + ){ + docBuilder.textLine(line.replaceAll("\\n", newLine()). + replaceAll("#\\{", "").replaceAll("# \\{", ""). + replaceAll("}", "")); + } else{ + docBuilder.textLine(line.replaceAll("\\n", newLine()). + replaceAll("#\\{", newLine()).replaceAll("# \\{", newLine()). + replaceAll("}", "")); + } + + } + //add new line to last comment + if(step.getComments().indexOf(comment) == numComments-1){ + docBuilder.newLine(); + } + } + } + + } + + String renderStepTime(Result result) { + if (result == null || result.getDuration() == null) { + return ""; + } + return " [small right]#(" + Formatter.formatTime(result.getDuration()) + ")#"; + } + + String renderStepTable(Step step) { + //TODO convert to AsciidocBuilder + CukedoctorDocumentBuilder builder = newInstance(); + builder.newLine(); + if (notEmpty(step.getRows())) { + builder.newLine(); + builder.append("[cols=\"" + step.getRows()[0].getCells().length + "*\", options=\"header\"]").newLine(); + builder.textLine(table()); + Row header = step.getRows()[0]; + for (String col : header.getCells()) { + builder.append(tableCol(), col).newLine(); + } + + for (int i = 1; i < step.getRows().length; i++) { + for (String cell : step.getRows()[i].getCells()) { + builder.append(tableCol(), cell).newLine(); + } + } + builder.textLine(table()); + builder.newLine(); + } + + return builder.toString(); + } +} diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java index 62c91056..3d354175 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/renderer/CukedoctorTagsRenderer.java @@ -43,7 +43,7 @@ private void extractTagNames(HashSet tagNames, List tags) { if (tags == null) return; for (Tag tag : tags) { - if (!tag.isOrder()) { + if (!tag.isOrder() && !tag.isDiscrete()) { tagNames.add(tag.getName()); } } diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/StepsRenderer.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/StepsRenderer.java index 6d25d050..a9c3d93e 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/StepsRenderer.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/spi/StepsRenderer.java @@ -1,5 +1,7 @@ package com.github.cukedoctor.spi; +import com.github.cukedoctor.api.model.Feature; +import com.github.cukedoctor.api.model.Scenario; import com.github.cukedoctor.api.model.Step; import com.github.cukedoctor.renderer.BaseRenderer; @@ -10,5 +12,5 @@ */ public interface StepsRenderer extends BaseRenderer{ - String renderSteps(List steps); + String renderSteps(List steps, Scenario scenario, Feature feature); } diff --git a/cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/EnrichmentSteps.java b/cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/EnrichmentSteps.java index ba7bd1f5..55501bc8 100644 --- a/cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/EnrichmentSteps.java +++ b/cukedoctor-converter/src/test/java/com/github/cukedoctor/bdd/cukedoctor/EnrichmentSteps.java @@ -3,7 +3,6 @@ import com.github.cukedoctor.Cukedoctor; import com.github.cukedoctor.api.model.Feature; import com.github.cukedoctor.parser.FeatureParser; -import cucumber.api.PendingException; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import cucumber.api.java.en.When; @@ -11,7 +10,6 @@ import java.net.URL; import java.util.List; -import static com.github.cukedoctor.util.Constants.newLine; import static org.assertj.core.api.Assertions.assertThat; /** @@ -22,13 +20,24 @@ public class EnrichmentSteps { String documentation; - @When("^I convert docstring enriched json output using cukedoctor converter$") - public void I_convert_docstring_enriched_json_output_using_cukedoctor_converter() throws Throwable { - URL featureFile = getClass().getResource("/json-output/enrichment/table-and-source.json"); - assertThat(featureFile).isNotNull(); - List features = FeatureParser.parse(featureFile.getPath()); - assertThat(features).isNotNull().hasSize(1); - documentation = Cukedoctor.instance(features).renderFeatures().getDocumentation(); + @When("^I convert docstring enriched json output activated with a step comment using cukedoctor converter$") + public void I_convert_docstring_enriched_json_output_activated_with_a_step_comment_using_cukedoctor_converter() throws Throwable { + getFeatureFixture("/json-output/enrichment/table-and-source-step-comment.json"); + } + + @When("^I convert docstring enriched json output activated with the content type using cukedoctor converter$") + public void I_convert_docstring_enriched_json_output_activiated_with_the_content_type_using_cukedoctor_converter() throws Throwable { + getFeatureFixture("/json-output/enrichment/table-and-source-content-type.json"); + } + + @When("^I convert docstring enriched json output activated with a feature tag using cukedoctor converter$") + public void I_convert_docstring_enriched_json_output_activiated_with_a_feature_tag_using_cukedoctor_converter() throws Throwable { + getFeatureFixture("/json-output/enrichment/table-and-source-feature-tag.json"); + } + + @When("^I convert docstring enriched json output activated with a scenario tag using cukedoctor converter$") + public void I_convert_docstring_enriched_json_output_activiated_with_a_scenario_tag_using_cukedoctor_converter() throws Throwable { + getFeatureFixture("/json-output/enrichment/table-and-source-scenario-tag.json"); } @Then("^DocString asciidoc output must be rendered in my documentation$") @@ -38,11 +47,7 @@ public void DocString_asciidoc_output_must_be_rendered_in_my_documentation(Strin @When("^I convert enriched feature json output using cukedoctor$") public void I_convert_enriched_feature_json_output_using_cukedoctor() throws Throwable { - URL featureFile = getClass().getResource("/json-output/enrichment/calc.json"); - assertThat(featureFile).isNotNull(); - List features = FeatureParser.parse(featureFile.getPath()); - assertThat(features).isNotNull().hasSize(1); - documentation = Cukedoctor.instance(features).renderFeatures().getDocumentation(); + getFeatureFixture("/json-output/enrichment/calc.json"); } @Then("^Asciidoc markup on comments must be rendered in my documentation$") @@ -55,4 +60,11 @@ public void The_following_feature_with_asciidoc_markup_in_comments(String featur assertThat(features).isNotNull(); } + private void getFeatureFixture(String fixturePath) { + URL featureFile = getClass().getResource(fixturePath); + assertThat(featureFile).isNotNull(); + List features = FeatureParser.parse(featureFile.getPath()); + assertThat(features).isNotNull().hasSize(1); + documentation = Cukedoctor.instance(features).renderFeatures().getDocumentation(); + } } diff --git a/cukedoctor-converter/src/test/java/com/github/cukedoctor/converter/CukedoctorConverterTest.java b/cukedoctor-converter/src/test/java/com/github/cukedoctor/converter/CukedoctorConverterTest.java index 6f6ad6cb..4bfc1dc0 100644 --- a/cukedoctor-converter/src/test/java/com/github/cukedoctor/converter/CukedoctorConverterTest.java +++ b/cukedoctor-converter/src/test/java/com/github/cukedoctor/converter/CukedoctorConverterTest.java @@ -107,7 +107,7 @@ public void shouldRenderAttributes() { attrs.docTitle("Title"); String document = Cukedoctor.instance(features, attrs).renderAttributes(). getDocumentation().toString(); - assertEquals(expected, document); + assertEquals(expected.replace("\r", ""), document.replace("\r", "")); } @@ -214,7 +214,7 @@ public void shouldRenderAttributesWithoutToc() { attrs.docTitle("Title"); String document = Cukedoctor.instance(features, attrs).renderAttributes(). getDocumentation().toString(); - assertEquals(expected, document); + assertEquals(expected.replace("\r", ""), document.replace("\r", "")); } @Test @@ -247,7 +247,7 @@ public void shouldRenderAttributesWithoutHardbreaks() { attrs.docTitle("Title"); String document = Cukedoctor.instance(features, attrs).renderAttributes(). getDocumentation().toString(); - assertEquals(expected, document); + assertEquals(expected.replace("\r", ""), document.replace("\r", "")); } @Test @@ -321,7 +321,7 @@ public void shouldUseDocumentationTitleAsDocTitleAttribute() { attrs.docTitle("Documentation Title"); String document = Cukedoctor.instance(features, attrs).renderAttributes(). getDocumentation().toString(); - assertEquals(document, expected); + assertEquals(expected.replace("\r", ""), document.replace("\r", "")); } @@ -393,7 +393,7 @@ public void shouldGeneratePdfTheme() { features.add(feature); CukedoctorConverter converter = Cukedoctor.instance(features, new DocumentAttributes().backend("pdf")); converter.setFilename("target/pdf/living documentation.adoc"); - String pdfStylePath = Paths.get("").toAbsolutePath() + "/target/pdf/cukedoctor-pdf.yml"; + String pdfStylePath = Paths.get("").toAbsolutePath().toString().replace("\\", "/") /* Windows path hack */ + "/target/pdf/cukedoctor-pdf.yml"; FileUtil.copyFileFromClassPath("/cukedoctor-pdf-test.yml", pdfStylePath); converter.addCustomPdfTheme(); String expected = ":toc: right" + newLine() + @@ -414,7 +414,7 @@ public void shouldGeneratePdfTheme() { ":pdf-style: " + pdfStylePath + newLine(); String doc = converter.renderAttributes().getDocumentation(); - assertThat(expected).isEqualTo(doc); + assertThat(doc).isEqualTo(expected); File file = FileUtil.loadFile("target/pdf/cukedoctor-pdf.yml"); assertThat(file).exists(); assertTrue(file.delete()); @@ -712,7 +712,7 @@ public void shouldEnrichFeature() { List features = FeatureParser.parse(getClass().getResource("/json-output/enrichment/calc.json").getPath()); assertThat(features).isNotNull().hasSize(1); String output = Cukedoctor.instance(features).renderFeatures(features).getDocumentation(); - assertThat(output.replaceAll("\r", "")).contains(("[[Calculator, Calculator]]"+newLine()+ + assertThat(output.replaceAll("\r\n|\r|\n", newLine())).contains(("[[Calculator, Calculator]]"+newLine()+ "=== *Calculator*"+newLine()+ ""+newLine()+ "==== Scenario: Adding numbers"+newLine()+ diff --git a/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java index 50ef5bc2..0bffc6bb 100644 --- a/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java +++ b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java @@ -22,6 +22,7 @@ public class CukedoctorTagsRendererTest { private final String order42 = "@order-42"; private final String order1 = "@order-1"; private final String otherTag = "@otherTag"; + private final String discrete = "@cukedoctor-discrete"; @Test @@ -65,6 +66,14 @@ public void shouldNotRenderIfScenarioOnlyHasOrderTagsAndFeatureHasNoTags() { ); } + @Test + public void shouldNotRenderIfScenarioOnlyHasDiscreteTagAndFeatureHasNoTags() { + assertEquals( + "", + tagsRenderer.renderScenarioTags(createEmptyFeature(), createScenario(discrete)) + ); + } + @Test public void shouldRenderIfFeatureHasTagsButNotOrderTags() { @@ -98,6 +107,14 @@ public void shouldNotRenderIfFeatureOnlyHasOrderTagsAndScenarioHasNoTags() { ); } + @Test + public void shouldNotRenderIfFeatureOnlyHasDiscreteTagAndScenarioHasNoTags() { + assertEquals( + "", + tagsRenderer.renderScenarioTags(createFeature(discrete), createEmptyScenario()) + ); + } + @Test public void shouldRenderIfFeatureAndScenarioHaveTags() { diff --git a/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/RendererTest.java b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/RendererTest.java index 4aa9cfa2..e8169bea 100644 --- a/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/RendererTest.java +++ b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/RendererTest.java @@ -2,13 +2,10 @@ import com.github.cukedoctor.Cukedoctor; import com.github.cukedoctor.api.CukedoctorConverter; -import com.github.cukedoctor.api.DocumentAttributes; import com.github.cukedoctor.api.model.*; import com.github.cukedoctor.config.GlobalConfig; import com.github.cukedoctor.parser.FeatureParser; -import com.github.cukedoctor.spi.FeatureRenderer; import com.github.cukedoctor.spi.StepsRenderer; -import com.github.cukedoctor.util.Constants; import com.github.cukedoctor.util.Expectations; import com.github.cukedoctor.util.FileUtil; import com.github.cukedoctor.util.builder.FeatureBuilder; @@ -23,9 +20,7 @@ import static com.github.cukedoctor.util.Constants.newLine; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyListOf; -import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.*; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; @@ -59,7 +54,7 @@ public void shouldRenderFeatureScenarios(){ CukedoctorScenarioRenderer scenarioRenderer = new CukedoctorScenarioRenderer(); scenarioRenderer = spy(scenarioRenderer); - doReturn("").when(scenarioRenderer).renderScenarioSteps(anyListOf(Step.class)); + doReturn("").when(scenarioRenderer).renderScenarioSteps(anyListOf(Step.class), any(Scenario.class), any(Feature.class)); doReturn("").when(scenarioRenderer).renderScenarioExamples(any(Scenario.class)); doReturn("").when(scenarioRenderer).renderScenarioTags(any(Scenario.class),eq(feature)); @@ -82,7 +77,7 @@ public void shouldRenderFeatureScenariosWithTagsInScenarios(){ } CukedoctorScenarioRenderer scenarioRenderer = new CukedoctorScenarioRenderer(); scenarioRenderer = spy(scenarioRenderer); - doReturn("").when(scenarioRenderer).renderScenarioSteps(anyListOf(Step.class)); + doReturn("").when(scenarioRenderer).renderScenarioSteps(anyListOf(Step.class), any(Scenario.class), any(Feature.class)); doReturn("").when(scenarioRenderer).renderScenarioExamples(any(Scenario.class)); CukedoctorFeatureRenderer featureRenderer = new CukedoctorFeatureRenderer(); @@ -91,11 +86,11 @@ public void shouldRenderFeatureScenariosWithTagsInScenarios(){ String resultDoc = featureRenderer.renderFeatureScenarios(feature); assertThat(resultDoc).isEqualTo("==== Scenario: scenario 1"+newLine() + - "[small]#tags: @Tag1,@tag2#"+newLine() + + "[small]#tags: @tag2,@Tag1#"+newLine() + ""+newLine() + "description"+newLine() + newLine() + "==== Scenario: scenario 2"+newLine() + - "[small]#tags: @Tag1,@tag2#"+newLine() + + "[small]#tags: @tag2,@Tag1#"+newLine() + ""+newLine() + "description 2"+newLine() + newLine()); } @@ -110,7 +105,7 @@ public void shouldRenderFeatureScenariosWithTagsInFeaturesAndScenarios(){ CukedoctorScenarioRenderer scenarioRenderer = new CukedoctorScenarioRenderer(); scenarioRenderer = spy(scenarioRenderer); - doReturn("").when(scenarioRenderer).renderScenarioSteps(anyListOf(Step.class)); + doReturn("").when(scenarioRenderer).renderScenarioSteps(anyListOf(Step.class), any(Scenario.class), any(Feature.class)); doReturn("").when(scenarioRenderer).renderScenarioExamples(any(Scenario.class)); CukedoctorFeatureRenderer featureRenderer = new CukedoctorFeatureRenderer(); @@ -119,11 +114,11 @@ public void shouldRenderFeatureScenariosWithTagsInFeaturesAndScenarios(){ String resultDoc = featureRenderer.renderFeatureScenarios(feature); assertThat(resultDoc).isEqualTo("==== Scenario: scenario 1" + newLine() + - "[small]#tags: @FeatureTag,@Tag1,@tag2#" + newLine() + + "[small]#tags: @tag2,@FeatureTag,@Tag1#" + newLine() + "" + newLine() + "description" + newLine() + newLine() + "==== Scenario: scenario 2" + newLine() + - "[small]#tags: @FeatureTag,@Tag1,@tag2#" + newLine() + + "[small]#tags: @tag2,@FeatureTag,@Tag1#" + newLine() + "" + newLine() + "description 2" + newLine() + newLine()); } @@ -140,7 +135,7 @@ public void shouldRenderFeatureScenariosOmittingTagsIfOrderFeatureTagIsTheOnlyTa CukedoctorScenarioRenderer scenarioRenderer = new CukedoctorScenarioRenderer(); scenarioRenderer = spy(scenarioRenderer); - doReturn("").when(scenarioRenderer).renderScenarioSteps(anyListOf(Step.class)); + doReturn("").when(scenarioRenderer).renderScenarioSteps(anyListOf(Step.class), any(Scenario.class), any(Feature.class)); doReturn("").when(scenarioRenderer).renderScenarioExamples(any(Scenario.class)); CukedoctorFeatureRenderer featureRenderer = new CukedoctorFeatureRenderer(); @@ -163,7 +158,7 @@ public void shouldRenderFeatureStepsWithOnePassingStep(){ StepsRenderer stepsRenderer = new CukedoctorStepsRenderer(); List steps = feature.getScenarios().get(0).getSteps(); - String resultDoc = stepsRenderer.renderSteps(steps); + String resultDoc = stepsRenderer.renderSteps(steps, feature.getScenarios().get(0), feature); assertThat(resultDoc).isEqualTo("==========" + newLine() + "Given::" + newLine() + @@ -181,7 +176,7 @@ public void shouldRenderFeatureStepsWithOnePassingAndOneFailingStep(){ List steps = feature.getScenarios().get(0).getSteps(); StepsRenderer stepsRenderer = new CukedoctorStepsRenderer(); - String resultDoc = stepsRenderer.renderSteps(steps); + String resultDoc = stepsRenderer.renderSteps(steps, feature.getScenarios().get(0), feature); assertThat(resultDoc).isEqualTo("==========" + newLine() + "Given::" + newLine() + @@ -224,7 +219,7 @@ public void shouldRenderFeatureStepsWithOneScenarioWithMultipleStep(){ features.add(feature); List steps = feature.getScenarios().get(0).getSteps(); CukedoctorScenarioRenderer scenarioRenderer = new CukedoctorScenarioRenderer(); - String resultDoc = scenarioRenderer.renderScenarioSteps(steps); + String resultDoc = scenarioRenderer.renderScenarioSteps(steps, feature.getScenarios().get(0), feature); assertThat(resultDoc).isEqualTo("==========" + newLine() + "Given::" + newLine() + "passing step icon:thumbs-up[role=\"green\",title=\"Passed\"] [small right]#(000ms)#" + newLine() + diff --git a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/enrichment.feature b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/enrichment.feature index 72b39807..8c71a16c 100644 --- a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/enrichment.feature +++ b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/enrichment.feature @@ -8,12 +8,12 @@ Feature: Enrich features I want to render asciidoc markup inside my features. ____ ==== - Scenario: DocSting enrichment - Asciidoc markup can be used in feature *DocStrings*. To do so you need to enable it by using *[cukector-dicrete]* comment on the feature. + Scenario: DocString enrichment activated by a step comment +Asciidoc markup can be used in feature *DocStrings*. To do so you can enable it by using *[cukedoctor-discrete]* comment on the step containing the DocString. - Given The following two features: + Given The following two features: """ -Feature: Enrich feature +Feature: Discrete class feature Scenario: Render source code @@ -24,7 +24,7 @@ Feature: Enrich feature ----- public int sum(int x, int y){ int result = x + y; - return result; (1) + return result; <1> } ----- <1> We can have callouts in living documentation @@ -45,10 +45,10 @@ Feature: Enrich feature \"\"\" """ - When I convert docstring enriched json output using cukedoctor converter + When I convert docstring enriched json output activated with a step comment using cukedoctor converter # cukedoctor-discrete - Then DocString asciidoc output must be rendered in my documentation + Then DocString asciidoc output must be rendered in my documentation """ == *Features* @@ -59,7 +59,7 @@ Feature: Enrich feature ========== Given :: -the following source code icon:thumbs-up[role="green",title="Passed"] [small right]#(267ms)# +the following source code in docstrings icon:thumbs-up[role="green",title="Passed"] [small right]#(267ms)# ****** [discrete] @@ -97,6 +97,273 @@ the following table icon:thumbs-up[role="green",title="Passed"] [small right]#(0 ========== +""" + + Scenario: DocString enrichment activated by the content type + Asciidoc markup can be used in feature *DocStrings*. To do so you can enable it by using the content type *[cukedoctor-dicrete]* in the DocString. + + Given The following two features: +""" +Feature: Discrete class feature + + Scenario: Render source code + + Given the following source code in docstrings +\"\"\"cukedoctor-discrete + [source, java] + ----- + public int sum(int x, int y){ + int result = x + y; + return result; (1) + } + ----- + <1> We can have callouts in living documentation +\"\"\" + + Scenario: Render table + + Given the following table + \"\"\"cukedoctor-discrete + |=== + + | Cell in column 1, row 1 | Cell in column 2, row 1 + | Cell in column 1, row 2 | Cell in column 2, row 2 + | Cell in column 1, row 3 | Cell in column 2, row 3 + + |=== +\"\"\" +""" + + When I convert docstring enriched json output activated with the content type using cukedoctor converter + + # cukedoctor-discrete + Then DocString asciidoc output must be rendered in my documentation +""" +== *Features* + +[[Discrete-class-feature, Discrete class feature]] +=== *Discrete class feature* + +==== Scenario: Render source code + +========== +Given :: +the following source code in docstrings icon:thumbs-up[role="green",title="Passed"] [small right]#(002ms)# +****** + +[discrete] +[source, java] +----- +public int sum(int x, int y){ + int result = x + y; + return result; (1) +} +----- +[discrete] +<1> We can have callouts in living documentation + + +****** +========== + +==== Scenario: Render table + +========== +Given :: +the following table icon:thumbs-up[role="green",title="Passed"] [small right]#(000ms)# +****** + +[discrete] +|=== +| Cell in column 1, row 1 | Cell in column 2, row 1 +| Cell in column 1, row 2 | Cell in column 2, row 2 +| Cell in column 1, row 3 | Cell in column 2, row 3 +|=== + + +****** +========== + + +""" + + Scenario: DocString enrichment activated by a feature tag + Asciidoc markup can be used in feature *DocStrings*. You can enable this by applying the tag [@cukedoctor-discrete] to the feature. Note this enables the enrichment for all DocStrings within the feature. + + Given The following two features: +""" +@cukedoctor-discrete +Feature: Discrete class feature + + Scenario: Render source code + + Given the following source code in docstrings +\"\"\" + [source, java] + ----- + public int sum(int x, int y){ + int result = x + y; + return result; (1) + } + ----- + <1> We can have callouts in living documentation +\"\"\" + + Scenario: Render table + + Given the following table + \"\"\" + |=== + + | Cell in column 1, row 1 | Cell in column 2, row 1 + | Cell in column 1, row 2 | Cell in column 2, row 2 + | Cell in column 1, row 3 | Cell in column 2, row 3 + + |=== +\"\"\" +""" + + When I convert docstring enriched json output activated with a feature tag using cukedoctor converter + + # cukedoctor-discrete + Then DocString asciidoc output must be rendered in my documentation +""" +== *Features* + +[[Discrete-class-feature, Discrete class feature]] +=== *Discrete class feature* + +==== Scenario: Render source code + +========== +Given :: +the following source code in docstrings icon:thumbs-up[role="green",title="Passed"] [small right]#(011ms)# +****** + +[discrete] +[source, java] +----- +public int sum(int x, int y){ + int result = x + y; + return result; (1) +} +----- +[discrete] +<1> We can have callouts in living documentation + + +****** +========== + +==== Scenario: Render table + +========== +Given :: +the following table icon:thumbs-up[role="green",title="Passed"] [small right]#(000ms)# +****** + +[discrete] +|=== +| Cell in column 1, row 1 | Cell in column 2, row 1 +| Cell in column 1, row 2 | Cell in column 2, row 2 +| Cell in column 1, row 3 | Cell in column 2, row 3 +|=== + + +****** +========== + + +""" + + Scenario: DocString enrichment activated by a scenario tag + Asciidoc markup can be used in feature *DocStrings*. You can enable this by applying the tag [@cukedoctor-discrete] to the scenario. Note this enables the enrichment for all DocStrings within the scenario. + + Given The following two features: +""" +Feature: Discrete class feature + + @cukedoctor-discrete + Scenario: Render source code + + Given the following source code in docstrings +\"\"\" + [source, java] + ----- + public int sum(int x, int y){ + int result = x + y; + return result; (1) + } + ----- + <1> We can have callouts in living documentation +\"\"\" + + @cukedoctor-discrete + Scenario: Render table + + Given the following table + \"\"\" + |=== + + | Cell in column 1, row 1 | Cell in column 2, row 1 + | Cell in column 1, row 2 | Cell in column 2, row 2 + | Cell in column 1, row 3 | Cell in column 2, row 3 + + |=== +\"\"\" +""" + + When I convert docstring enriched json output activated with a scenario tag using cukedoctor converter + + # cukedoctor-discrete + Then DocString asciidoc output must be rendered in my documentation +""" +== *Features* + +[[Discrete-class-feature, Discrete class feature]] +=== *Discrete class feature* + +==== Scenario: Render source code + +========== +Given :: +the following source code in docstrings icon:thumbs-up[role="green",title="Passed"] [small right]#(002ms)# +****** + +[discrete] +[source, java] +----- +public int sum(int x, int y){ + int result = x + y; + return result; (1) +} +----- +[discrete] +<1> We can have callouts in living documentation + + +****** +========== + +==== Scenario: Render table + +========== +Given :: +the following table icon:thumbs-up[role="green",title="Passed"] [small right]#(000ms)# +****** + +[discrete] +|=== +| Cell in column 1, row 1 | Cell in column 2, row 1 +| Cell in column 1, row 2 | Cell in column 2, row 2 +| Cell in column 1, row 3 | Cell in column 2, row 3 +|=== + + +****** +========== + + """ Scenario: Comments enrichment diff --git a/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-content-type.json b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-content-type.json new file mode 100644 index 00000000..ebcffc16 --- /dev/null +++ b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-content-type.json @@ -0,0 +1,68 @@ +[ + { + "line": 1, + "elements": [ + { + "start_timestamp": "2020-04-18T11:57:01.454Z", + "line": 3, + "name": "Render source code", + "description": "", + "id": "enrich-feature;render-source-code", + "type": "scenario", + "keyword": "Scenario", + "steps": [ + { + "result": { + "duration": 2002900, + "status": "passed" + }, + "line": 5, + "name": "the following source code in docstrings", + "match": { + "location": "org.example.StepDefinitions.theFollowingSourceCodeInDocstrings(java.lang.String)" + }, + "keyword": "Given ", + "doc_string": { + "content_type": "cukedoctor-discrete", + "line": 6, + "value": "[source, java]\n-----\npublic int sum(int x, int y){\n int result \u003d x + y;\n return result; (1)\n}\n-----\n\u003c1\u003e We can have callouts in living documentation" + } + } + ] + }, + { + "start_timestamp": "2020-04-18T11:57:01.581Z", + "line": 17, + "name": "Render table", + "description": "", + "id": "enrich-feature;render-table", + "type": "scenario", + "keyword": "Scenario", + "steps": [ + { + "result": { + "status": "passed" + }, + "line": 19, + "name": "the following table", + "match": { + "location": "org.example.StepDefinitions.theFollowingTable(java.lang.String)" + }, + "keyword": "Given ", + "doc_string": { + "content_type": "cukedoctor-discrete", + "line": 20, + "value": "|\u003d\u003d\u003d\n\n| Cell in column 1, row 1 | Cell in column 2, row 1\n| Cell in column 1, row 2 | Cell in column 2, row 2\n| Cell in column 1, row 3 | Cell in column 2, row 3\n\n|\u003d\u003d\u003d" + } + } + ] + } + ], + "name": "Discrete class feature", + "description": "", + "id": "discrete-class-feature", + "keyword": "Feature", + "uri": "classpath:org/example/content-type.feature", + "tags": [] + } +] \ No newline at end of file diff --git a/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-feature-tag.json b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-feature-tag.json new file mode 100644 index 00000000..625ccf3d --- /dev/null +++ b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-feature-tag.json @@ -0,0 +1,86 @@ +[ + { + "line": 2, + "elements": [ + { + "start_timestamp": "2020-04-18T12:03:33.906Z", + "line": 4, + "name": "Render source code", + "description": "", + "id": "enrich-feature;render-source-code", + "type": "scenario", + "keyword": "Scenario", + "steps": [ + { + "result": { + "duration": 11993400, + "status": "passed" + }, + "line": 6, + "name": "the following source code in docstrings", + "match": { + "location": "org.example.StepDefinitions.theFollowingSourceCodeInDocstrings(java.lang.String)" + }, + "keyword": "Given ", + "doc_string": { + "line": 7, + "value": "[source, java]\n-----\npublic int sum(int x, int y){\n int result \u003d x + y;\n return result; (1)\n}\n-----\n\u003c1\u003e We can have callouts in living documentation" + } + } + ], + "tags": [ + { + "name": "@cukedoctor-discrete" + } + ] + }, + { + "start_timestamp": "2020-04-18T12:03:34.152Z", + "line": 18, + "name": "Render table", + "description": "", + "id": "enrich-feature;render-table", + "type": "scenario", + "keyword": "Scenario", + "steps": [ + { + "result": { + "duration": 998900, + "status": "passed" + }, + "line": 20, + "name": "the following table", + "match": { + "location": "org.example.StepDefinitions.theFollowingTable(java.lang.String)" + }, + "keyword": "Given ", + "doc_string": { + "line": 21, + "value": "|\u003d\u003d\u003d\n\n| Cell in column 1, row 1 | Cell in column 2, row 1\n| Cell in column 1, row 2 | Cell in column 2, row 2\n| Cell in column 1, row 3 | Cell in column 2, row 3\n\n|\u003d\u003d\u003d" + } + } + ], + "tags": [ + { + "name": "@cukedoctor-discrete" + } + ] + } + ], + "name": "Discrete class feature", + "description": "", + "id": "discrete-class-feature", + "keyword": "Feature", + "uri": "classpath:org/example/feature-tag.feature", + "tags": [ + { + "name": "@cukedoctor-discrete", + "type": "Tag", + "location": { + "line": 1, + "column": 1 + } + } + ] + } +] \ No newline at end of file diff --git a/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-scenario-tag.json b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-scenario-tag.json new file mode 100644 index 00000000..f146389d --- /dev/null +++ b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-scenario-tag.json @@ -0,0 +1,76 @@ +[ + { + "line": 1, + "elements": [ + { + "start_timestamp": "2020-04-18T12:06:16.747Z", + "line": 4, + "name": "Render source code", + "description": "", + "id": "enrich-feature;render-source-code", + "type": "scenario", + "keyword": "Scenario", + "steps": [ + { + "result": { + "duration": 2998400, + "status": "passed" + }, + "line": 6, + "name": "the following source code in docstrings", + "match": { + "location": "org.example.StepDefinitions.theFollowingSourceCodeInDocstrings(java.lang.String)" + }, + "keyword": "Given ", + "doc_string": { + "line": 7, + "value": "[source, java]\n-----\npublic int sum(int x, int y){\n int result \u003d x + y;\n return result; (1)\n}\n-----\n\u003c1\u003e We can have callouts in living documentation" + } + } + ], + "tags": [ + { + "name": "@cukedoctor-discrete" + } + ] + }, + { + "start_timestamp": "2020-04-18T12:06:16.879Z", + "line": 19, + "name": "Render table", + "description": "", + "id": "enrich-feature;render-table", + "type": "scenario", + "keyword": "Scenario", + "steps": [ + { + "result": { + "status": "passed" + }, + "line": 21, + "name": "the following table", + "match": { + "location": "org.example.StepDefinitions.theFollowingTable(java.lang.String)" + }, + "keyword": "Given ", + "doc_string": { + "line": 22, + "value": "|\u003d\u003d\u003d\n\n| Cell in column 1, row 1 | Cell in column 2, row 1\n| Cell in column 1, row 2 | Cell in column 2, row 2\n| Cell in column 1, row 3 | Cell in column 2, row 3\n\n|\u003d\u003d\u003d" + } + } + ], + "tags": [ + { + "name": "@cukedoctor-discrete" + } + ] + } + ], + "name": "Discrete class feature", + "description": "", + "id": "discrete-class-feature", + "keyword": "Feature", + "uri": "classpath:org/example/scenario-tag.feature", + "tags": [] + } +] \ No newline at end of file diff --git a/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source.json b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-step-comment.json similarity index 97% rename from cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source.json rename to cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-step-comment.json index f1f472cd..4f353615 100644 --- a/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source.json +++ b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-step-comment.json @@ -18,7 +18,7 @@ "duration": 267743605, "status": "passed" }, - "name": "the following source code", + "name": "the following source code in docstrings", "keyword": "Given ", "line": 6, "doc_string": { diff --git a/cukedoctor-spi-example/src/main/java/com/github/cukedoctor/example/spi/CustomScenarioRenderer.java b/cukedoctor-spi-example/src/main/java/com/github/cukedoctor/example/spi/CustomScenarioRenderer.java index 519e600c..2ddd19a6 100644 --- a/cukedoctor-spi-example/src/main/java/com/github/cukedoctor/example/spi/CustomScenarioRenderer.java +++ b/cukedoctor-spi-example/src/main/java/com/github/cukedoctor/example/spi/CustomScenarioRenderer.java @@ -1,14 +1,14 @@ package com.github.cukedoctor.example.spi; -import static com.github.cukedoctor.util.Assert.hasText; -import static com.github.cukedoctor.util.Constants.newLine; - import com.github.cukedoctor.api.model.Feature; import com.github.cukedoctor.api.model.Scenario; import com.github.cukedoctor.renderer.CukedoctorScenarioRenderer; import com.github.cukedoctor.renderer.CukedoctorStepsRenderer; import com.github.cukedoctor.spi.StepsRenderer; +import static com.github.cukedoctor.util.Assert.hasText; +import static com.github.cukedoctor.util.Constants.newLine; + /** * Created by pestano on 29/02/16. */ @@ -27,7 +27,7 @@ public String renderScenario(Scenario scenario, Feature feature) { //here we will reuse builtin step renderer docBuilder.textLine("+"); StepsRenderer stepsRenderer = new CukedoctorStepsRenderer(); - docBuilder.append(stepsRenderer.renderSteps(scenario.getSteps())); + docBuilder.append(stepsRenderer.renderSteps(scenario.getSteps(), scenario, feature)); } return docBuilder.toString(); } From b4a464719aff9e21437ae5c092c4582f6255c76a Mon Sep 17 00:00:00 2001 From: Andrew Sweet Date: Sun, 19 Apr 2020 13:28:30 +0100 Subject: [PATCH 5/8] README update for enrichment of DocStrings --- README.adoc | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/README.adoc b/README.adoc index cacdbd25..b464f88f 100755 --- a/README.adoc +++ b/README.adoc @@ -317,10 +317,16 @@ image::enrich.png[] ==== Asciidoc markup in DocStrings -You can use Asciidoc markup in https://www.relishapp.com/cucumber/cucumber/docs/gherkin/doc-strings[feature DocStrings], see feature below: +You can use Asciidoc markup in https://www.relishapp.com/cucumber/cucumber/docs/gherkin/doc-strings[feature DocStrings]. +The Features below show the different ways of achieving this: + +- Step comment +- Content type +- Feature tag +- Scenario tag ---- -Feature: Discrete class feature +Feature: Discrete class feature with step comment Scenario: Render source code @@ -348,6 +354,100 @@ public int sum(int x, int y){ | Cell in column 1, row 2 | Cell in column 2, row 2 | Cell in column 1, row 3 | Cell in column 2, row 3 +|==== + """ + + +Feature: Discrete class feature with content type + + Scenario: Render source code + + Given the following source code + """cukedoctor-discrete +[source, java] +----- +public int sum(int x, int y){ + int result = x + y; + return result; <1> + } +----- +<1> We can have callouts in living documentation + """ + + Scenario: Render table + + # cukedoctor-discrete + Given the following table + """cukedoctor-discrete +|==== + +| Cell in column 1, row 1 | Cell in column 2, row 1 +| Cell in column 1, row 2 | Cell in column 2, row 2 +| Cell in column 1, row 3 | Cell in column 2, row 3 + +|==== + """ + + +@cukedoctor-discrete +Feature: Discrete class feature with feature tag + + Scenario: Render source code + + Given the following source code + """ +[source, java] +----- +public int sum(int x, int y){ + int result = x + y; + return result; <1> + } +----- +<1> We can have callouts in living documentation + """ + + Scenario: Render table + + Given the following table + """ +|==== + +| Cell in column 1, row 1 | Cell in column 2, row 1 +| Cell in column 1, row 2 | Cell in column 2, row 2 +| Cell in column 1, row 3 | Cell in column 2, row 3 + +|==== + """ + + +Feature: Discrete class feature with scenario tag + + @cukedoctor-discrete + Scenario: Render source code + + Given the following source code + """ +[source, java] +----- +public int sum(int x, int y){ + int result = x + y; + return result; <1> + } +----- +<1> We can have callouts in living documentation + """ + + @cukedoctor-discrete + Scenario: Render table + + Given the following table + """ +|==== + +| Cell in column 1, row 1 | Cell in column 2, row 1 +| Cell in column 1, row 2 | Cell in column 2, row 2 +| Cell in column 1, row 3 | Cell in column 2, row 3 + |==== """ ---- From 91be3129451c5b4137e3ae63473998ff038f2a2a Mon Sep 17 00:00:00 2001 From: Andrew Sweet Date: Sun, 19 Apr 2020 14:17:38 +0100 Subject: [PATCH 6/8] README update for enrichment of DocStrings --- README.adoc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.adoc b/README.adoc index b464f88f..6809aa27 100755 --- a/README.adoc +++ b/README.adoc @@ -320,10 +320,14 @@ image::enrich.png[] You can use Asciidoc markup in https://www.relishapp.com/cucumber/cucumber/docs/gherkin/doc-strings[feature DocStrings]. The Features below show the different ways of achieving this: -- Step comment -- Content type -- Feature tag -- Scenario tag +* Step comment (cucumber-jvm 1.x only) +** Applies to all DocStrings in the commented step +* Content type +** Must be applied to each DocString you wish to be enriched +* Feature tag +** Applies to all DocStrings in the tagged feature +* Scenario tag +** Applies to all DocStrings in the tagged scenario ---- Feature: Discrete class feature with step comment From 02928b1fbbc3406039c0fcd01c3e644e0d5e0fbf Mon Sep 17 00:00:00 2001 From: rmpestano Date: Sun, 19 Apr 2020 20:45:16 +0200 Subject: [PATCH 7/8] Fix javadoc for java11 build --- .../java/com/github/cukedoctor/extension/util/FileUtil.java | 2 +- pom.xml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cukedoctor-extension/src/main/java/com/github/cukedoctor/extension/util/FileUtil.java b/cukedoctor-extension/src/main/java/com/github/cukedoctor/extension/util/FileUtil.java index 90221c97..50fd17f3 100644 --- a/cukedoctor-extension/src/main/java/com/github/cukedoctor/extension/util/FileUtil.java +++ b/cukedoctor-extension/src/main/java/com/github/cukedoctor/extension/util/FileUtil.java @@ -27,7 +27,7 @@ public class FileUtil { * * @param name file name * @param data file content - * @return + * @return saved file */ public static File saveFile(String name, String data) { if (name == null) { diff --git a/pom.xml b/pom.xml index 77e82062..ad37763d 100644 --- a/pom.xml +++ b/pom.xml @@ -234,6 +234,7 @@ maven-javadoc-plugin + 3.1.1 attach-javadocs @@ -242,6 +243,9 @@ + + 7 + From ca8c35148e1a0406f9079541b628724826ef89ef Mon Sep 17 00:00:00 2001 From: Andrew Sweet Date: Sun, 19 Apr 2020 21:43:15 +0100 Subject: [PATCH 8/8] cukedoctor-discrete to asciidoc for DocString enrichment by content type and tag --- README.adoc | 21 +++++++++---------- .../cukedoctor/api/model/DocString.java | 2 +- .../com/github/cukedoctor/api/model/Tag.java | 2 +- .../renderer/CukedoctorTagsRendererTest.java | 2 +- .../bdd/cukedoctor/enrichment.feature | 16 +++++++------- .../table-and-source-content-type.json | 4 ++-- .../table-and-source-feature-tag.json | 6 +++--- .../table-and-source-scenario-tag.json | 4 ++-- 8 files changed, 28 insertions(+), 29 deletions(-) diff --git a/README.adoc b/README.adoc index 6809aa27..553f3d15 100755 --- a/README.adoc +++ b/README.adoc @@ -320,13 +320,13 @@ image::enrich.png[] You can use Asciidoc markup in https://www.relishapp.com/cucumber/cucumber/docs/gherkin/doc-strings[feature DocStrings]. The Features below show the different ways of achieving this: -* Step comment (cucumber-jvm 1.x only) +* Step comment `#cukedoctor-discrete` (cucumber-jvm 1.x only) ** Applies to all DocStrings in the commented step -* Content type +* Content type `asciidoc` ** Must be applied to each DocString you wish to be enriched -* Feature tag +* Feature tag `@asciidoc` ** Applies to all DocStrings in the tagged feature -* Scenario tag +* Scenario tag `@asciidoc` ** Applies to all DocStrings in the tagged scenario ---- @@ -367,7 +367,7 @@ Feature: Discrete class feature with content type Scenario: Render source code Given the following source code - """cukedoctor-discrete + """asciidoc [source, java] ----- public int sum(int x, int y){ @@ -380,9 +380,8 @@ public int sum(int x, int y){ Scenario: Render table - # cukedoctor-discrete Given the following table - """cukedoctor-discrete + """asciidoc |==== | Cell in column 1, row 1 | Cell in column 2, row 1 @@ -393,7 +392,7 @@ public int sum(int x, int y){ """ -@cukedoctor-discrete +@asciidoc Feature: Discrete class feature with feature tag Scenario: Render source code @@ -426,7 +425,7 @@ public int sum(int x, int y){ Feature: Discrete class feature with scenario tag - @cukedoctor-discrete + @asciidoc Scenario: Render source code Given the following source code @@ -441,7 +440,7 @@ public int sum(int x, int y){ <1> We can have callouts in living documentation """ - @cukedoctor-discrete + @asciidoc Scenario: Render table Given the following table @@ -460,7 +459,7 @@ The docstrings will be rendered as follows: image::discrete.png[] -IMPORTANT: By default Cukedoctor will render DocStrings as http://asciidoctor.org/docs/user-manual/\#listing-blocks[asciidoc listing^]. To enable this feature use *# cukedoctor-discrete* comment. +IMPORTANT: By default Cukedoctor will render DocStrings as http://asciidoctor.org/docs/user-manual/\#listing-blocks[asciidoc listing^]. Use the above mechanism to enable this feature. === *"Stepless"* documentation diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/DocString.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/DocString.java index 0024d760..abfce6a8 100644 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/DocString.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/DocString.java @@ -32,7 +32,7 @@ public void setContent_type(String value) { } public boolean isDiscrete() { - return Objects.equals(content_type, "cukedoctor-discrete"); + return Objects.equals(content_type, "asciidoc"); } @Override diff --git a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java index 56768033..f3ec0ff3 100755 --- a/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java +++ b/cukedoctor-converter/src/main/java/com/github/cukedoctor/api/model/Tag.java @@ -38,6 +38,6 @@ public String getOrder() { } public boolean isDiscrete() { - return extractPattern("cukedoctor-discrete", name) != null; + return extractPattern("asciidoc", name) != null; } } \ No newline at end of file diff --git a/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java index 0bffc6bb..d1425649 100644 --- a/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java +++ b/cukedoctor-converter/src/test/java/com/github/cukedoctor/renderer/CukedoctorTagsRendererTest.java @@ -22,7 +22,7 @@ public class CukedoctorTagsRendererTest { private final String order42 = "@order-42"; private final String order1 = "@order-1"; private final String otherTag = "@otherTag"; - private final String discrete = "@cukedoctor-discrete"; + private final String discrete = "@asciidoc"; @Test diff --git a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/enrichment.feature b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/enrichment.feature index 8c71a16c..17970357 100644 --- a/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/enrichment.feature +++ b/cukedoctor-converter/src/test/resources/com/github/cukedoctor/bdd/cukedoctor/enrichment.feature @@ -100,7 +100,7 @@ the following table icon:thumbs-up[role="green",title="Passed"] [small right]#(0 """ Scenario: DocString enrichment activated by the content type - Asciidoc markup can be used in feature *DocStrings*. To do so you can enable it by using the content type *[cukedoctor-dicrete]* in the DocString. + Asciidoc markup can be used in feature *DocStrings*. To do so you can enable it by using the content type *[asciidoc]* in the DocString. Given The following two features: """ @@ -109,7 +109,7 @@ Feature: Discrete class feature Scenario: Render source code Given the following source code in docstrings -\"\"\"cukedoctor-discrete +\"\"\"asciidoc [source, java] ----- public int sum(int x, int y){ @@ -123,7 +123,7 @@ Feature: Discrete class feature Scenario: Render table Given the following table - \"\"\"cukedoctor-discrete + \"\"\"asciidoc |=== | Cell in column 1, row 1 | Cell in column 2, row 1 @@ -188,11 +188,11 @@ the following table icon:thumbs-up[role="green",title="Passed"] [small right]#(0 """ Scenario: DocString enrichment activated by a feature tag - Asciidoc markup can be used in feature *DocStrings*. You can enable this by applying the tag [@cukedoctor-discrete] to the feature. Note this enables the enrichment for all DocStrings within the feature. + Asciidoc markup can be used in feature *DocStrings*. You can enable this by applying the tag [@asciidoc] to the feature. Note this enables the enrichment for all DocStrings within the feature. Given The following two features: """ -@cukedoctor-discrete +@asciidoc Feature: Discrete class feature Scenario: Render source code @@ -277,13 +277,13 @@ the following table icon:thumbs-up[role="green",title="Passed"] [small right]#(0 """ Scenario: DocString enrichment activated by a scenario tag - Asciidoc markup can be used in feature *DocStrings*. You can enable this by applying the tag [@cukedoctor-discrete] to the scenario. Note this enables the enrichment for all DocStrings within the scenario. + Asciidoc markup can be used in feature *DocStrings*. You can enable this by applying the tag [@asciidoc] to the scenario. Note this enables the enrichment for all DocStrings within the scenario. Given The following two features: """ Feature: Discrete class feature - @cukedoctor-discrete + @asciidoc Scenario: Render source code Given the following source code in docstrings @@ -298,7 +298,7 @@ Feature: Discrete class feature <1> We can have callouts in living documentation \"\"\" - @cukedoctor-discrete + @asciidoc Scenario: Render table Given the following table diff --git a/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-content-type.json b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-content-type.json index ebcffc16..955447e9 100644 --- a/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-content-type.json +++ b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-content-type.json @@ -23,7 +23,7 @@ }, "keyword": "Given ", "doc_string": { - "content_type": "cukedoctor-discrete", + "content_type": "asciidoc", "line": 6, "value": "[source, java]\n-----\npublic int sum(int x, int y){\n int result \u003d x + y;\n return result; (1)\n}\n-----\n\u003c1\u003e We can have callouts in living documentation" } @@ -50,7 +50,7 @@ }, "keyword": "Given ", "doc_string": { - "content_type": "cukedoctor-discrete", + "content_type": "asciidoc", "line": 20, "value": "|\u003d\u003d\u003d\n\n| Cell in column 1, row 1 | Cell in column 2, row 1\n| Cell in column 1, row 2 | Cell in column 2, row 2\n| Cell in column 1, row 3 | Cell in column 2, row 3\n\n|\u003d\u003d\u003d" } diff --git a/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-feature-tag.json b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-feature-tag.json index 625ccf3d..f7b01e0a 100644 --- a/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-feature-tag.json +++ b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-feature-tag.json @@ -30,7 +30,7 @@ ], "tags": [ { - "name": "@cukedoctor-discrete" + "name": "@asciidoc" } ] }, @@ -62,7 +62,7 @@ ], "tags": [ { - "name": "@cukedoctor-discrete" + "name": "@asciidoc" } ] } @@ -74,7 +74,7 @@ "uri": "classpath:org/example/feature-tag.feature", "tags": [ { - "name": "@cukedoctor-discrete", + "name": "@asciidoc", "type": "Tag", "location": { "line": 1, diff --git a/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-scenario-tag.json b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-scenario-tag.json index f146389d..a5e29968 100644 --- a/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-scenario-tag.json +++ b/cukedoctor-converter/src/test/resources/json-output/enrichment/table-and-source-scenario-tag.json @@ -30,7 +30,7 @@ ], "tags": [ { - "name": "@cukedoctor-discrete" + "name": "@asciidoc" } ] }, @@ -61,7 +61,7 @@ ], "tags": [ { - "name": "@cukedoctor-discrete" + "name": "@asciidoc" } ] }