1 module dmocks.object_mock; 2 3 import core.vararg; 4 import dmocks.method_mock; 5 import dmocks.model; 6 import dmocks.repository; 7 import std.traits; 8 9 class Mocked(T) : T 10 { 11 static if (__traits(hasMember, T, "__ctor")) 12 this(ARGS...)(ARGS args) 13 { 14 super(args); 15 } 16 17 package MockRepository _owner; 18 package MockId mockId___ = new MockId; 19 mixin((Body!(T, true))); 20 } 21 22 class MockedFinal(T) 23 { 24 package T mocked___; 25 package MockRepository _owner; 26 package MockId mockId___ = new MockId; 27 28 package this(T t) 29 { 30 mocked___ = t; 31 } 32 33 auto ref opDispatch(string name, Args...)(auto ref Args params) 34 { 35 //TODO: how do i get an alias to a template overloaded on args? 36 mixin("alias this.mocked___." ~ name ~ "!Args METHOD;"); 37 auto del = delegate ReturnType!(FunctionTypeOf!METHOD)(Args args, TypeInfo[] varArgsList, void* varArgsPtr) { 38 mixin(BuildForwardCall!(name ~ "!Args", false)()); 39 }; 40 return mockMethodCall!(METHOD, name, typeof(mocked___))(this, this._owner, del, null, null, params); 41 } 42 43 mixin((Body!(T, false))); 44 } 45 46 unittest 47 { 48 class A 49 { 50 void asd(T)(int a) 51 { 52 } 53 } 54 55 class Overloads 56 { 57 private int _foo; 58 59 T foot(T)() 60 { 61 static if (is(T == int)) 62 { 63 return _foo; 64 } 65 else 66 return T.init; 67 } 68 69 void foot(T)(T i) 70 { 71 static if (is(T == int)) 72 { 73 _foo = i; 74 } 75 } 76 } 77 78 auto f = new MockedFinal!A(new A); 79 static assert(__traits(compiles, f.opDispatch!("asd")(1))); 80 81 //auto p = new MockedFinal!Overloads(new Overloads); 82 //p.opDispatch!("foot")(5); 83 } 84 85 struct MockedStruct(T) 86 { 87 package T mocked___; 88 package MockRepository _owner; 89 package MockId mockId___; 90 91 package this(T t) 92 { 93 mockId___ = new MockId; 94 mocked___ = t; 95 } 96 97 auto ref opDispatch(string name, Args...)(auto ref Args params) 98 { 99 //TODO: how do i get an alias to a template overloaded on args? 100 mixin("alias this.mocked___." ~ name ~ "!Args METHOD;"); 101 auto del = delegate ReturnType!(FunctionTypeOf!METHOD)(Args args, TypeInfo[] varArgsList, void* varArgsPtr) { 102 mixin(BuildForwardCall!(name ~ "!Args", false)()); 103 }; 104 return mockMethodCall!(METHOD, name, typeof(mocked___))(this, this._owner, del, null, null, params); 105 } 106 107 mixin((Body!(T, false))); 108 } 109 110 auto ref mockMethodCall(alias self, string name, T, OBJ, CALLER, FORWARD, Args...)(OBJ obj, CALLER _owner, FORWARD forwardCall, TypeInfo[] varArgsList, void* varArgsPtr, auto ref Args params) 111 { 112 if (_owner is null) 113 { 114 assert(false, "owner cannot be null! Contact the stupid mocks developer."); 115 } 116 auto getRope() 117 { 118 // CAST CHEATS here - can't operate on const/shared refs without cheating on typesystem. 119 // this makes these calls threadunsafe 120 // because of fullyQualifiedName bug we need to pass name to the function 121 return (cast() _owner).MethodCall!(self, ParameterTypeTuple!self)(cast(MockId)(obj.mockId___), __traits(identifier, T) ~ "." ~ name, params); 122 } 123 124 auto rope = ({ 125 static if (functionAttributes!(FunctionTypeOf!(self)) & FunctionAttribute.nothrow_) 126 { 127 import std.exception : assertNotThrown; 128 129 return assertNotThrown(getRope, "throwing in a mock of a nothrow method!"); 130 } 131 else 132 { 133 return getRope; 134 } 135 })(); 136 if (rope.pass) 137 { 138 return forwardCall(params, varArgsList, varArgsPtr); 139 } 140 else 141 { 142 static if (!is(ReturnType!(FunctionTypeOf!(self)) == void)) 143 { 144 return rope.value; 145 } 146 } 147 } 148 149 template Body(T, bool INHERITANCE) 150 { 151 enum Body = BodyPart!(T, 0); 152 153 template BodyPart(T, int i) 154 { 155 static if (i < __traits(allMembers, T).length) 156 { 157 //pragma(msg, __traits(allMembers, T)[i]); 158 enum BodyPart = Methods!(T, INHERITANCE, __traits(allMembers, T)[i]) ~ BodyPart!(T, i + 1); 159 } 160 else 161 { 162 enum BodyPart = ``; 163 } 164 } 165 }