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){ mixin(BuildForwardCall!(name ~ "!Args", false)()); }; 38 return mockMethodCall!(METHOD, name, typeof(mocked___))(this, this._owner, del, null, null, params); 39 } 40 41 mixin ((Body!(T, false))); 42 } 43 44 unittest 45 { 46 class A 47 { 48 void asd(T)(int a) 49 { 50 } 51 } 52 53 class Overloads 54 { 55 private int _foo; 56 57 T foot(T)() 58 { 59 static if (is(T == int)) 60 { 61 return _foo; 62 } 63 else 64 return T.init; 65 } 66 67 void foot(T)(T i) 68 { 69 static if (is(T == int)) 70 { 71 _foo = i; 72 } 73 } 74 } 75 auto f = new MockedFinal!A(new A); 76 static assert(__traits(compiles, f.opDispatch!("asd")(1))); 77 78 //auto p = new MockedFinal!Overloads(new Overloads); 79 //p.opDispatch!("foot")(5); 80 } 81 82 struct MockedStruct(T) 83 { 84 package T mocked___; 85 package MockRepository _owner; 86 package MockId mockId___; 87 88 package this(T t) 89 { 90 mockId___ = new MockId; 91 mocked___ = t; 92 } 93 94 auto ref opDispatch(string name, Args...)(auto ref Args params) 95 { 96 //TODO: how do i get an alias to a template overloaded on args? 97 mixin("alias this.mocked___."~name~"!Args METHOD;"); 98 auto del = delegate ReturnType!(FunctionTypeOf!METHOD) (Args args, TypeInfo[] varArgsList, void* varArgsPtr){ mixin(BuildForwardCall!(name ~ "!Args", false)()); }; 99 return mockMethodCall!(METHOD, name, typeof(mocked___))(this, this._owner, del, null, null, params); 100 } 101 102 mixin ((Body!(T, false))); 103 } 104 105 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) 106 { 107 if (_owner is null) 108 { 109 assert(false, "owner cannot be null! Contact the stupid mocks developer."); 110 } 111 dmocks.action.ReturnOrPass!(ReturnType!(FunctionTypeOf!(self))) rope; 112 void setRope() 113 { 114 // CAST CHEATS here - can't operate on const/shared refs without cheating on typesystem. this makes these calls threadunsafe 115 // because of fullyQualifiedName bug we need to pass name to the function 116 rope = (cast()_owner).MethodCall!(self, ParameterTypeTuple!self)(cast(MockId)(obj.mockId___), __traits(identifier, T) ~ "." ~ name, params); 117 } 118 static if (functionAttributes!(FunctionTypeOf!(self)) & FunctionAttribute.nothrow_) 119 { 120 try { 121 setRope(); 122 } 123 catch (Exception ex) 124 { 125 assert(false, "Throwing in a mock of a nothrow method!"); 126 } 127 } 128 else 129 { 130 setRope(); 131 } 132 if (rope.pass) 133 { 134 return forwardCall(params, varArgsList, varArgsPtr); 135 } 136 else 137 { 138 static if (!is (ReturnType!(FunctionTypeOf!(self)) == void)) 139 { 140 return rope.value; 141 } 142 } 143 } 144 145 template Body (T, bool INHERITANCE) 146 { 147 enum Body = BodyPart!(T, 0); 148 149 template BodyPart (T, int i) 150 { 151 static if (i < __traits(allMembers, T).length) 152 { 153 //pragma(msg, __traits(allMembers, T)[i]); 154 enum BodyPart = Methods!(T, INHERITANCE, __traits(allMembers, T)[i]) ~ BodyPart!(T, i + 1); 155 } 156 else 157 { 158 enum BodyPart = ``; 159 } 160 } 161 }