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