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 }