1 module specd.specification;
2 
3 import specd.matchers;
4 
5 import std.stdio;
6 
7 auto describe(string title) {	
8 	return new SpecificationGroup(title);
9 }
10 
11 version(SpecDTests) unittest {
12 
13 	int executionSequence = 0;
14 	int executionFlag = 0;
15 	bool executionRan = false;
16 
17 	describe("A SpecificationGroup with ordered parts").as(
18 		(it) { it.should("execute each part", (executionSequence++).must.equal(0)); },
19 		(it) { it.should("execute its parts in order", (executionSequence++).must.equal(1)); }
20 	);
21 
22 	describe("A SpecificationGroup with unordered parts").should([
23 		"execute each part": {
24 			executionFlag |= 1;
25 		},
26 		"execute its parts in any order": {
27 			executionFlag |= 2;
28 		}		
29 	])
30 	;
31 
32 	assert(executionFlag == 3, "Did not execute all parts of the unordered SpecificationGroup");
33 
34 	describe("A SpecificationGroup with a single part")
35 		.should("execute the part", executionRan = true);
36 
37 	assert(executionRan, "Did not execute the single specification");
38 }
39 
40 class Specification {
41 package:
42 	string test;
43 	MatchException exception;
44 
45 	this(string test) {
46 		this.test = test;
47 		this.exception = null;
48 	}
49 
50 	this(string test, MatchException exception) {
51 		this.test = test;
52 		this.exception = exception;
53 	}
54 public:
55 	@property bool isSuccess() { return exception is null; }
56 }
57 
58 class SpecificationGroup {
59 package:
60 	alias Block = void delegate();
61 	alias ItBlock = void delegate(SpecificationGroup);
62 
63 	static SpecificationGroup[] allSpecs;
64 
65 	string title;
66 	Specification[] results;
67 
68 	this(string title) {
69 		this.title = title;
70 		allSpecs ~= this;
71 	}
72 
73 public:
74 	@property bool isSuccess() {
75 		foreach(result; results) {
76 			if (!result.isSuccess)
77 				return false;
78 		}
79 		return true;
80 	}
81 
82 	@property Specification[] specifications() { return results; }
83 
84 	void as(ItBlock[] parts ...) {			
85 		foreach(part; parts) {
86 			part(this);
87 		}
88 	}
89 
90 	auto should(Block[string] parts) {
91 		foreach (key, value; parts) {
92 			try {
93 				value();
94 				results ~= new Specification(key);
95 			} catch (MatchException e) {
96 				results ~= new Specification(key, e);
97 			}
98 		}
99 		return this;
100 	}
101 	auto should(string text, lazy void test) {
102 		try {
103 			test();
104 			results ~= new Specification(text);
105 		} catch (MatchException e) {
106 			results ~= new Specification(text, e);
107 		}
108 		return this;
109 	}
110 	auto should(string text, ItBlock test) {
111 		try {
112 			test(this);
113 			results ~= new Specification(text);
114 		} catch (MatchException e) {
115 			results ~= new Specification(text, e);
116 		}
117 		return this;
118 	}
119 }