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 }