1 module feature_test.core; 2 3 import feature_test.exceptions; 4 import feature_test.runner; 5 6 import colorize; 7 8 import std.stdio; 9 import std.algorithm; 10 11 alias FTImplementation = void delegate(FeatureTest); 12 alias FTDelegate = void delegate(); 13 14 struct FeatureTestScenario { 15 string name; 16 FTDelegate implementation; 17 } 18 19 class FeatureTest { 20 alias info = FeatureTestRunner.info; 21 22 @property ref string name() { return _name; } 23 @property ref string description() { return _description; } 24 @property string[] tags() { return _tags; } 25 @property ref FeatureTestScenario[] scenarios() { return _scenarios; } 26 27 void addTags(string[] tags ...) { 28 foreach(tag; tags) { if (!_tags.canFind(tag)) _tags ~= tag; } 29 } 30 31 final void addBeforeAll(FTDelegate d) { 32 _beforeAllCallbacks ~= d; 33 } 34 35 final void addBeforeEach(FTDelegate d) { 36 _beforeEachCallbacks ~= d; 37 } 38 39 final void addAfterEach(FTDelegate d) { 40 _afterEachCallbacks ~= d; 41 } 42 43 final void addAfterAll(FTDelegate d) { 44 _afterAllCallbacks ~= d; 45 } 46 47 // To be overridden 48 void beforeAll() { 49 } 50 51 // To be overridden 52 void beforeEach() { 53 } 54 55 // To be overridden 56 void afterEach() { 57 } 58 59 // To be overridden 60 void afterAll() { 61 } 62 63 void scenario(string name, FTDelegate implementation) { 64 _scenarios ~= FeatureTestScenario(name, implementation); 65 } 66 67 package: 68 void _beforeAll() { 69 beforeAll; 70 runCallbacks(_beforeAllCallbacks); 71 } 72 73 void _beforeEach() { 74 beforeEach; 75 runCallbacks(_beforeEachCallbacks); 76 } 77 78 void _afterEach() { 79 runCallbacks(_afterEachCallbacks); 80 afterEach; 81 } 82 83 void _afterAll() { 84 runCallbacks(_afterAllCallbacks); 85 afterAll; 86 } 87 88 private: 89 string _name; 90 string _description; 91 string[] _tags; 92 93 FeatureTestScenario[] _scenarios; 94 FTDelegate[] _beforeEachCallbacks, _afterEachCallbacks, _beforeAllCallbacks, _afterAllCallbacks; 95 96 void runCallbacks(FTDelegate[] callbacks) { 97 foreach(callback; callbacks) callback(); 98 } 99 } 100 101 void feature(T)(string name, string description, void delegate(T) implementation, string[] tags ...) { 102 if (FeatureTestRunner.shouldInclude(tags)) { 103 auto f = new T(); 104 f.name = name; 105 f.description = description; 106 f.addTags(tags); 107 implementation(f); 108 FeatureTestRunner.features ~= f; 109 } 110 } 111 112 void feature(T)(string name, void delegate(T) implementation, string[] tags ...) { 113 feature!T(name, "", implementation, tags); 114 } 115 116 void feature(string name, string description, void delegate(FeatureTest) implementation, string[] tags ...) { 117 feature!FeatureTest(name, description, implementation, tags); 118 } 119 120 void feature(string name, void delegate(FeatureTest) implementation, string[] tags ...) { 121 feature!FeatureTest(name, "", implementation, tags); 122 } 123 124 /// Marks a scenario as pending 125 void featureTestPending(string file = __FILE__, typeof(__LINE__) line = __LINE__) { 126 throw new FeatureTestException(file, line); 127 }