1 module dmocks.expectation; 2 3 import dmocks.action; 4 import dmocks.arguments; 5 import dmocks.call; 6 import dmocks.model; 7 import dmocks.name_match; 8 import dmocks.qualifiers; 9 import dmocks.util; 10 import std.conv; 11 import std.range; 12 import std.traits; 13 14 package: 15 16 class CallExpectation : Expectation 17 { 18 this(MockId object, NameMatch name, QualifierMatch qualifiers, ArgumentsMatch args, TypeInfo returnType) 19 { 20 this.object = object; 21 this.name = name; 22 this.repeatInterval = Interval(1,1); 23 this.arguments = args; 24 this.qualifiers = qualifiers; 25 this.action = new Action(returnType); 26 _matchedCalls = []; 27 } 28 MockId object; 29 NameMatch name; 30 QualifierMatch qualifiers; 31 ArgumentsMatch arguments; 32 private Call[] _matchedCalls; 33 Interval repeatInterval; 34 35 Action action; 36 37 override string toString(string indentation) 38 { 39 auto apndr = appender!(string); 40 apndr.put(indentation); 41 apndr.put("Expectation: "); 42 bool details = !satisfied; 43 44 if (!details) 45 apndr.put("satisfied, "); 46 else 47 apndr.put("not satisfied, "); 48 49 apndr.put("Method: " ~ name.toString() ~ " " ~ arguments.toString() ~ " " ~ qualifiers.toString() ~ " ExpectedCalls: " ~ repeatInterval.toString()); 50 if (details) 51 { 52 apndr.put("\n" ~ indentation ~ "Calls: " ~ _matchedCalls.length.to!string); 53 foreach(Call call; _matchedCalls) 54 { 55 apndr.put("\n" ~ indentation ~ " " ~ call.toString()); 56 } 57 } 58 return apndr.data; 59 } 60 61 62 override string toString() 63 { 64 return toString(""); 65 } 66 67 CallExpectation match(Call call) 68 { 69 debugLog("Expectation.match:"); 70 if (object != call.object) 71 { 72 debugLog("object doesn't match"); 73 return null; 74 } 75 if (!name.matches(call.name)) 76 { 77 debugLog("name doesn't match"); 78 return null; 79 } 80 if (!qualifiers.matches(call.qualifiers)) 81 { 82 debugLog("qualifiers don't match"); 83 return null; 84 } 85 if (!arguments.matches(call.arguments)) 86 { 87 debugLog("arguments don't match"); 88 return null; 89 } 90 if (_matchedCalls.length >= repeatInterval.Max) 91 { 92 debugLog("repeat interval desn't match"); 93 return null; 94 } 95 debugLog("full match"); 96 _matchedCalls ~= call; 97 return this; 98 } 99 100 bool satisfied() 101 { 102 return _matchedCalls.length <= repeatInterval.Max && _matchedCalls.length >= repeatInterval.Min; 103 } 104 } 105 106 class GroupExpectation : Expectation 107 { 108 this() 109 { 110 repeatInterval = Interval(1,1); 111 expectations = []; 112 } 113 Expectation[] expectations; 114 bool ordered; 115 Interval repeatInterval; 116 117 CallExpectation match(Call call) 118 { 119 // match call to expectation 120 foreach(Expectation expectation; expectations) 121 { 122 CallExpectation e = expectation.match(call); 123 if (e !is null) 124 return e; 125 if (ordered && !expectation.satisfied()) 126 return null; 127 } 128 return null; 129 } 130 131 void addExpectation(Expectation expectation) 132 { 133 expectations ~= expectation; 134 } 135 136 bool satisfied() 137 { 138 foreach(Expectation expectation; expectations) 139 { 140 if (!expectation.satisfied()) 141 return false; 142 } 143 return true; 144 } 145 146 override string toString(string indentation) 147 { 148 auto apndr = appender!(string); 149 apndr.put(indentation); 150 apndr.put("GroupExpectation: "); 151 bool details = !satisfied; 152 153 if (!details) 154 apndr.put("satisfied, "); 155 else 156 apndr.put("not satisfied, "); 157 158 if (ordered) 159 apndr.put("ordered, "); 160 else 161 apndr.put("unordered, "); 162 163 apndr.put("Interval: "); 164 apndr.put(repeatInterval.toString()); 165 166 if (details) 167 { 168 foreach(Expectation expectation; expectations) 169 { 170 apndr.put("\n"); 171 apndr.put(expectation.toString(indentation ~ " ")); 172 } 173 } 174 return apndr.data; 175 } 176 177 override string toString() 178 { 179 return toString(""); 180 } 181 } 182 183 GroupExpectation createGroupExpectation(bool ordered) 184 { 185 auto ret = new GroupExpectation(); 186 ret.ordered = ordered; 187 return ret; 188 } 189 190 // composite design pattern 191 interface Expectation 192 { 193 CallExpectation match(Call call); 194 bool satisfied(); 195 string toString(string indentation); 196 string toString(); 197 } 198 199 CallExpectation createExpectation(alias METHOD, ARGS...)(MockId object, string name, ARGS args) 200 { 201 auto ret = new CallExpectation(object, new NameMatchText(name), qualifierMatch!METHOD, 202 new StrictArgumentsMatch(arguments(args)), typeid(ReturnType!(FunctionTypeOf!(METHOD)))); 203 return ret; 204 }