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 {
19     string methodBodies = "";
20 
21     static if (is(typeof(__traits(getOverloads, T, methodName))))
22     {
23         foreach (overloadIndex, method; __traits(getOverloads, T, methodName))
24         {
25             static if (!__traits(isStaticFunction, method) && !(methodName[0 .. 2] == "__") &&
26                     !(INHERITANCE && __traits(isFinalFunction, method)) &&
27                     __traits(getProtection, method) != "private" &&
28                     __traits(getProtection, method) != "package")
29                 methodBodies ~= BuildMethodOverloads!(T.stringof, methodName, overloadIndex, method, INHERITANCE);
30         }
31     }
32     return methodBodies;
33 }
34 
35 /++
36 Returns a string containing the overload for a single function.
37 This function has a return value.
38 ++/
39 string BuildMethodOverloads(string objectType, string methodName, int overloadIndex, alias method, bool inheritance)()
40 {
41     alias FunctionTypeOf!(method) METHOD_TYPE;
42     enum returns = !is(ReturnType!(METHOD_TYPE) == void);
43 
44     enum self = `__traits(getOverloads, T, "` ~ methodName ~ `")[` ~ overloadIndex.to!string ~ `]`;
45     enum selfType = "FunctionTypeOf!(" ~ self ~ ")";
46     enum ret = returns ? `ReturnType!(` ~ selfType ~ `)` : `void`;
47     enum paramTypes = `ParameterTypeTuple!(` ~ selfType ~ `)`;
48     enum dynVarArgs = variadicFunctionStyle!method == Variadic.d;
49     enum varargsString = dynVarArgs ? ", ..." : "";
50     enum qualified = objectType ~ `.` ~ methodName;
51     enum bool override_ = is(typeof(mixin(`Object.` ~ methodName))) && !__traits(isFinalFunction, method);
52     enum header = ((inheritance || override_) ? `override ` : `final `) ~ ret ~ ` ` ~ methodName ~ `
53         (`
54         ~ paramTypes ~ ` params` ~ varargsString ~ `) ` ~ formatQualifiers!(method);
55 
56     string delegate_ = `delegate ` ~ ret ~ ` (` ~ paramTypes ~ ` args, TypeInfo[] varArgsList, void* varArgsPtr){ `
57         ~ BuildForwardCall!(methodName, dynVarArgs) ~ `}`;
58 
59     enum varargsValueString = dynVarArgs ? ", _arguments, _argptr" : ", null, null";
60     return header ~ ` {  return mockMethodCall!(` ~ self ~ `, "` ~ methodName ~ `", T)(this, _owner, ` ~
61         delegate_ ~ varargsValueString ~ `, params); ` ~ `} `;
62 }
63 
64 string BuildForwardCall(string methodName, bool dynamicVarArgs)()
65 {
66     enum methodString = dynamicVarArgs ? "v" ~ methodName : methodName;
67     enum argsPassed = dynamicVarArgs ? "(args, varArgsList, varArgsPtr)" : "(args)";
68 
69     return `static if (is(typeof(mocked___.` ~ methodString ~ argsPassed ~ `)))
70             {
71                 return (mocked___.`
72         ~ methodString ~ argsPassed ~ `);
73             }
74             else static if (is(typeof(super.`
75         ~ methodString ~ argsPassed ~ `)))
76             {
77                 return (super.`
78         ~ methodString ~ argsPassed ~ `);
79             }
80             else
81             {
82                 assert(false, "Cannot pass the call through - there's no `
83         ~ methodString
84         ~ ` implementation in base object!");
85             }`;
86 }