1 module dmocks.method_mock;
2 
3 import std.stdio;
4 import std.traits;
5 import std.conv;
6 
7 import dmocks.util;
8 import dmocks.repository;
9 import dmocks.qualifiers;
10 
11 package:
12 
13 //These are too complicated for decent unittests. Can't mock templates!
14 
15 /++
16 The only method we care about externally.
17 Returns a string containing the overrides for this method
18 and all its overloads.
19 ++/
20 string Methods (T, bool INHERITANCE, string methodName) () {
21     /+version(DMocksDebug)
22     {
23         pragma(msg, methodName);
24         pragma(msg, T);
25     }+/
26     string methodBodies = "";
27 
28     static if (is (typeof(__traits(getOverloads, T, methodName))))
29     {
30         foreach (overloadIndex, method; __traits(getOverloads, T, methodName)) 
31         {
32             static if (!__traits(isStaticFunction, method) && !(methodName[0..2] == "__") && 
33                        !(INHERITANCE && __traits(isFinalFunction, method)))
34                 methodBodies ~= BuildMethodOverloads!(T.stringof, methodName, overloadIndex, method, INHERITANCE);
35         }
36     }
37     return methodBodies;
38 }
39 
40 /++
41 Returns a string containing the overload for a single function.
42 This function has a return value.
43 ++/
44 string BuildMethodOverloads (string objectType, string methodName, int overloadIndex, alias method, bool inheritance)() 
45 {
46     alias FunctionTypeOf!(method) METHOD_TYPE;
47     enum returns = !is (ReturnType!(METHOD_TYPE) == void);
48 
49     enum self = `__traits(getOverloads, T, "` ~ methodName ~ `")[` ~ overloadIndex.to!string ~ `]`;
50     enum selfType = "FunctionTypeOf!("~self~")";
51     enum ret = returns ? `ReturnType!(` ~ selfType ~ `)` : `void`;
52     enum paramTypes = `ParameterTypeTuple!(` ~ selfType ~ `)`;
53     enum dynVarArgs = variadicFunctionStyle!method == Variadic.d;
54     enum varargsString = dynVarArgs ? ", ..." : "";
55     enum qualified = objectType ~ `.` ~ methodName;
56     enum bool override_ = is(typeof(mixin (`Object.` ~ methodName))) && !__traits(isFinalFunction, method);
57     enum header = ((inheritance || override_) ? `override ` : `final `) ~ ret ~ ` ` ~ methodName ~ `
58         (` ~ paramTypes ~ ` params`~ varargsString ~`) ` ~ formatQualifiers!(method);
59 
60     string delegate_ = `delegate `~ret~` (`~paramTypes~` args, TypeInfo[] varArgsList, void* varArgsPtr){ ` ~ BuildForwardCall!(methodName, dynVarArgs) ~ `}`;
61 
62     enum varargsValueString = dynVarArgs ? ", _arguments, _argptr" : ", null, null";
63     return header ~` {  return mockMethodCall!(`~self~`, "`~methodName~`", T)(this, _owner, ` ~ delegate_ ~ varargsValueString ~`, params); `~`} `;
64 }
65 
66 string BuildForwardCall(string methodName, bool dynamicVarArgs)()
67 {
68     enum methodString = dynamicVarArgs ? "v"~methodName : methodName;
69     enum argsPassed = dynamicVarArgs ? "(args, varArgsList, varArgsPtr)" : "(args)";
70 
71     return `static if (is (typeof (mocked___.` ~ methodString~`)))
72             {
73                 return (mocked___.` ~ methodString ~ argsPassed~`);
74             }
75             else static if (is (typeof (super.` ~ methodString~`)))
76             {
77                 return (super.` ~ methodString ~ argsPassed~`);
78             }
79             else
80             {
81                 assert(false, "Cannot pass the call through - there's no `~methodString~` implementation in base object!");
82             }`;
83 }