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 }