1 module dmocks.action; 2 3 import dmocks.dynamic; 4 import dmocks.util; 5 import std.traits; 6 7 package: 8 9 interface IAction 10 { 11 bool passThrough (); 12 13 void passThrough (bool value); 14 15 Dynamic returnValue (); 16 17 void returnValue (Dynamic value); 18 19 void action (Dynamic value); 20 21 Dynamic action (); 22 23 Exception toThrow (); 24 25 void toThrow (Exception value); 26 27 bool hasAction (); 28 29 Actor getActor (); 30 } 31 32 enum ActionStatus 33 { 34 Success, 35 FailBadAction, 36 } 37 38 struct ReturnOrPass(T) 39 { 40 static if (!is(T == void)) 41 { 42 static if (is(typeof({ Unqual!T value; }))) 43 { 44 Unqual!T value; 45 } 46 else 47 { 48 auto value = Unqual!T.init; 49 } 50 } 51 52 bool pass; 53 ActionStatus status = ActionStatus.Success; 54 } 55 56 struct Actor 57 { 58 IAction self; 59 60 ReturnOrPass!(TReturn) act (TReturn, ArgTypes...) (ArgTypes args) 61 { 62 debugLog("Actor:act"); 63 64 ReturnOrPass!(TReturn) rope; 65 if (self.passThrough) 66 { 67 rope.pass = true; 68 return rope; 69 } 70 if (self.toThrow) 71 { 72 throw self.toThrow; 73 } 74 static if (is (TReturn == void)) 75 { 76 if (self.action !is null) 77 { 78 debugLog("action found, type: %s", self.action().type); 79 80 if (self.action().type == typeid(void delegate(ArgTypes))) 81 { 82 self.action().get!(void delegate(ArgTypes))()(args); 83 } 84 else 85 { 86 rope.status = ActionStatus.FailBadAction; 87 } 88 } 89 } 90 else 91 { 92 if (self.returnValue !is null) 93 { 94 rope.value = self.returnValue().get!(Unqual!TReturn); 95 } 96 else if (self.action !is null) 97 { 98 debugLog("action found, type: %s", self.action().type); 99 if (self.action().type == typeid(TReturn delegate(ArgTypes))) 100 { 101 rope.value = self.action().get!(Unqual!TReturn delegate(ArgTypes))()(args); 102 } 103 else 104 { 105 rope.status = ActionStatus.FailBadAction; 106 } 107 } 108 } 109 110 return rope; 111 } 112 } 113 114 //TODO: make action parameters orthogonal or disallow certain combinations of them 115 class Action : IAction 116 { 117 private 118 { 119 bool _passThrough; 120 Dynamic _returnValue; 121 Dynamic _action; 122 Exception _toThrow; 123 TypeInfo _returnType; 124 } 125 126 this(TypeInfo returnType) 127 { 128 this._returnType = returnType; 129 } 130 131 bool hasAction () 132 { 133 return (_returnType is typeid(void)) || (_passThrough) || (_returnValue !is null) || (_action !is null) || (_toThrow !is null); 134 } 135 136 bool passThrough () 137 { 138 return _passThrough; 139 } 140 141 void passThrough (bool value) 142 { 143 _passThrough = value; 144 } 145 146 Dynamic returnValue () 147 { 148 return _returnValue; 149 } 150 151 void returnValue (Dynamic value) 152 { 153 _returnValue = value; 154 } 155 156 void action (Dynamic value) 157 { 158 _action = value; 159 } 160 161 Dynamic action () 162 { 163 return _action; 164 } 165 166 Exception toThrow () 167 { 168 return _toThrow; 169 } 170 171 void toThrow (Exception value) 172 { 173 _toThrow = value; 174 } 175 176 Actor getActor () 177 { 178 Actor act; 179 act.self = this; 180 return act; 181 } 182 } 183 184 @("action returnValue") 185 unittest 186 { 187 Dynamic v = dynamic(5); 188 Action act = new Action(typeid(int)); 189 assert (act.returnValue is null); 190 act.returnValue = v; 191 assert (act.returnValue() == dynamic(5)); 192 } 193 194 @("action action") 195 unittest 196 { 197 Dynamic v = dynamic(5); 198 Action act = new Action(typeid(int)); 199 assert (act.action is null); 200 act.action = v; 201 assert (act.action() == v); 202 } 203 204 @("action exception") 205 unittest 206 { 207 Exception ex = new Exception("boogah"); 208 Action act = new Action(typeid(int)); 209 assert (act.toThrow is null); 210 act.toThrow = ex; 211 assert (act.toThrow is ex); 212 } 213 214 @("action passthrough") 215 unittest 216 { 217 Action act = new Action(typeid(int)); 218 act.passThrough = true; 219 assert (act.passThrough()); 220 act.passThrough = false; 221 assert (!act.passThrough()); 222 } 223 224 @("action hasAction") 225 unittest 226 { 227 Action act = new Action(typeid(int)); 228 act.returnValue(dynamic(5)); 229 assert(act.hasAction); 230 }