1 module cucumber.feature; 2 3 import cucumber.ctutils; 4 import cucumber.reflection; 5 6 import std.regex; 7 import std.conv; 8 import std.algorithm; 9 import std.traits; 10 import std.encoding: sanitize; 11 12 struct FeatureResults { 13 int numScenarios; 14 int numPassing; 15 int numFailing; 16 int numPending; 17 int numUndefined; 18 19 string toString() const pure { 20 assert(numPassing ^ numFailing ^ numPending ^ numUndefined, 21 text(numPassing, numFailing, numPending, numUndefined)); 22 const suffix = numFailing ? text(numFailing, " failed)") : 23 numPending ? text(numPending, " pending)") : 24 numUndefined ? text(numUndefined, " undefined)") : 25 text(numPassing, " passed)"); 26 return "1 scenario (" ~ suffix; 27 } 28 } 29 30 class PendingException: Exception { 31 this(string msg) { super(msg); } 32 } 33 34 35 auto runFeature(Modules...)(string[] input) { 36 foreach(line; input.map!(l => std..string.stripLeft(l))) { 37 38 if(line.startsWith("Feature:")) continue; 39 if(line.startsWith("Scenario:")) continue; 40 41 auto func = findMatch!Modules(line); 42 if(!func) { 43 import std.stdio; 44 stderr.writeln("Could not find match for ", line); 45 } 46 if(!func) return FeatureResults(1, 0, 0, 0, 1); 47 48 try { 49 func(); 50 } catch(PendingException) { 51 return FeatureResults(1, 0, 0, 1); 52 } catch(Throwable e) { 53 import std.stdio; 54 stderr.writeln("Exception: ", e.msg.sanitize); 55 return FeatureResults(1, 0, 1, 0); 56 } 57 } 58 return FeatureResults(1, 1, 0, 0); 59 } 60 61 62 void pending(in string msg = "") { 63 throw new PendingException(msg); 64 }