1 module cucumber.formatter.json;
2 
3 import std.array : empty;
4 import std.stdio : write;
5 import std.json : toJSON, parseJSON;
6 
7 import asdf : serializeToJson, serializeToJsonPretty;
8 
9 import cucumber.formatter.base : Formatter;
10 import cucumber.formatter.color : colors, noColors;
11 import cucumber.result : Result, RunResult, ScenarioResult, StepResult;
12 import gherkin : Feature, Scenario, Step, Examples, TableRow, Comment;
13 
14 ///
15 class Json : Formatter
16 {
17     private bool noColor;
18     private bool noSnippets;
19     private bool noSource;
20     private bool pretty;
21 
22     ///
23     this(bool noColor, bool noSnippets, bool noSource, bool pretty = false)
24     {
25         this.noColor = noColor;
26         this.noSnippets = noSnippets;
27         this.noSource = noSource;
28         this.pretty = pretty;
29     }
30 
31     ///
32     override string color(string result)
33     {
34         return noColor ? noColors[result] : colors[result];
35     }
36 
37     ///
38     override void feature(Feature feature)
39     {
40         // do nothing
41     }
42 
43     ///
44     override void scenario(ref Scenario scenario)
45     {
46         // do nothing
47     }
48 
49     ///
50     override void examples(Examples examples)
51     {
52         // do nothing
53     }
54 
55     ///
56     override void tableRow(TableRow tableRow, ref TableRow[] table, string color)
57     {
58         // do nothing
59     }
60 
61     ///
62     override void tableRow(TableRow tableRow, ref TableRow[] table, ScenarioResult scenarioResult)
63     {
64         // do nothing
65     }
66 
67     ///
68     override void step(Step step, StepResult stepResult)
69     {
70         // do nothing
71     }
72 
73     ///
74     override void comment(Comment comment)
75     {
76         // do nothing
77     }
78 
79     ///
80     override void summarizeResult(RunResult result)
81     {
82         if (result.featureResults.length == 0)
83         {
84             if (pretty)
85             {
86                 "[\n\n]".write;
87             }
88             else
89             {
90                 "[]".write;
91             }
92         }
93         if (pretty)
94         {
95             result.featureResults.serializeToJsonPretty!"  ".write;
96         }
97         else
98         {
99             result.featureResults.serializeToJson.write;
100         }
101     }
102 }
103 
104 unittest
105 {
106     import std.algorithm : canFind;
107     import std.file : readText;
108     import std.json : parseJSON;
109     import std.path : baseName, dirName;
110     import std.string : replace;
111     import unit_threaded.assertions : should;
112     import cucumber.runner : CucumberRunner;
113     import gherkin.util : getFeatureFiles;
114     import gherkin.parser : Parser;
115 
116     const auto ignoredFeatureFiles = [
117         // dfmt off
118         "complex_background", // Rule included
119         "i18n_emoji",
120         "i18n_fr",
121         "i18n_no",
122         "minimal-example", // Example (related to Rule) included
123         "padded_example", // Cucumber-Ruby Scenario Outline issue
124         "rule",
125         "rule_without_name_and_description",
126         "scenario_outline", // Cucumber-Ruby Scenario Outline issue
127         "spaces_in_language",
128         // dfmt on
129     ];
130 
131     foreach (featureFile; getFeatureFiles([
132                 ``, "gherkin-d/cucumber/gherkin/testdata/good/"
133             ]))
134     {
135         if (ignoredFeatureFiles.canFind(baseName(featureFile, ".feature")))
136         {
137             continue;
138         }
139         auto gherkinDocument = Parser.parseFromFile(featureFile);
140         auto formatter = new Json(true, true, true);
141         auto runner = new CucumberRunner(formatter, true);
142         RunResult result;
143         result += runner.runFeature!"cucumber.formatter.json"(gherkinDocument);
144         string actual = result.featureResults.serializeToJson;
145         if (result.featureResults.empty)
146         {
147             actual = "[]";
148         }
149 
150         parseJSON(actual).should == parseJSON(
151                 readText("testdata/formatter/json/" ~ baseName(featureFile) ~ `.json`));
152     }
153 }