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 }