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 }