// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_FRAME_TEST_HELPER_GMOCK_H_ #define CHROME_FRAME_TEST_HELPER_GMOCK_H_ // This intention of this file is to make possible gmock WithArgs<> in // Chromium code base. // MutantImpl is like CallbackImpl, but also has prebound arguments (like Task) // There is also functor wrapper around it that should be used with // testing::Invoke, for example: // testing::WithArgs<0, 2>( // testing::Invoke(CBF(&mock_object, &MockObject::Something, &tmp_obj, 12))); // This will invoke MockObject::Something(tmp_obj, 12, arg_0, arg_2) // DispatchToMethod supporting two sets of arguments - // prebound (P) and calltime (C) // 1 - 1 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1& p, const Tuple1& c) { (obj->*method)(p.a, c.a); } // 2 - 1 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple2& p, const Tuple1& c) { (obj->*method)(p.a, p.b, c.a); } // 3 - 1 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple3& p, const Tuple1& c) { (obj->*method)(p.a, p.b, p.c, c.a); } // 4 - 1 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple4& p, const Tuple1& c) { (obj->*method)(p.a, p.b, p.c, p.d, c.a); } // 1 - 2 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1& p, const Tuple2& c) { (obj->*method)(p.a, c.a, c.b); } // 2 - 2 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple2& p, const Tuple2& c) { (obj->*method)(p.a, p.b, c.a, c.b); } // 3 - 2 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple3& p, const Tuple2& c) { (obj->*method)(p.a, p.b, p.c, c.a, c.b); } // 4 - 2 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple4& p, const Tuple2& c) { (obj->*method)(p.a, p.b, p.c, p.d, c.a, c.b); } // 1 - 3 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1& p, const Tuple3& c) { (obj->*method)(p.a, c.a, c.b, c.c); } // 2 - 3 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple2& p, const Tuple3& c) { (obj->*method)(p.a, p.b, c.a, c.b, c.c); } // 3 - 3 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple3& p, const Tuple3& c) { (obj->*method)(p.a, p.b, p.c, c.a, c.b, c.c); } // 4 - 3 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple4& p, const Tuple3& c) { (obj->*method)(p.a, p.b, p.c, p.d, c.a, c.b, c.c); } // 1 - 4 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1& p, const Tuple4& c) { (obj->*method)(p.a, c.a, c.b, c.c, c.d); } // 2 - 4 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple2& p, const Tuple4& c) { (obj->*method)(p.a, p.b, c.a, c.b, c.c, c.d); } // 3 - 4 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple3& p, const Tuple4& c) { (obj->*method)(p.a, p.b, p.c, c.a, c.b, c.c, c.d); } // 4 - 4 template inline void DispatchToMethod(ObjT* obj, Method method, const Tuple4& p, const Tuple4& c) { (obj->*method)(p.a, p.b, p.c, p.d, c.a, c.b, c.c, c.d); } //////////////////////////////////////////////////////////////////////////////// // Like CallbackImpl but has prebound arguments (like Task) template class MutantImpl : public CallbackStorage, public CallbackRunner { public: MutantImpl(T* obj, Method meth, const PreBound& pb) : CallbackStorage(obj, meth), pb_(pb) { } virtual void RunWithParams(const Params& params) { // use "this->" to force C++ to look inside our templatized base class; see // Effective C++, 3rd Ed, item 43, p210 for details. DispatchToMethod(this->obj_, this->meth_, pb_, params); } PreBound pb_; }; //////////////////////////////////////////////////////////////////////////////// // Mutant creation simplification // 1 - 1 template inline typename Callback1::Type* NewMutant(T* obj, void (T::*method)(P1, A1), P1 p1) { return new MutantImpl(obj, method, MakeTuple(p1)); } // 1 - 2 template inline typename Callback2::Type* NewMutant(T* obj, void (T::*method)(P1, A1, A2), P1 p1) { return new MutantImpl, Tuple2 > (obj, method, MakeTuple(p1)); } // 1 - 3 template inline typename Callback3::Type* NewMutant(T* obj, void (T::*method)(P1, A1, A2, A3), P1 p1) { return new MutantImpl, Tuple3 >(obj, method, MakeTuple(p1)); } // 1 - 4 template inline typename Callback4::Type* NewMutant(T* obj, void (T::*method)(P1, A1, A2, A3, A4), P1 p1) { return new MutantImpl, Tuple4 >(obj, method, MakeTuple(p1)); } // 2 - 1 template inline typename Callback1::Type* NewMutant(T* obj, void (T::*method)(P1, P2, A1), P1 p1, P2 p2) { return new MutantImpl, Tuple1 >(obj, method, MakeTuple(p1, p2)); } // 2 - 2 template inline typename Callback2::Type* NewMutant(T* obj, void (T::*method)(P1, P2, A1, A2), P1 p1, P2 p2) { return new MutantImpl, Tuple2 >(obj, method, MakeTuple(p1, p2)); } // 2 - 3 template inline typename Callback3::Type* NewMutant(T* obj, void (T::*method)(P1, P2, A1, A2, A3), P1 p1, P2 p2) { return new MutantImpl, Tuple3 >(obj, method, MakeTuple(p1, p2)); } // 2 - 4 template inline typename Callback4::Type* NewMutant(T* obj, void (T::*method)(P1, P2, A1, A2, A3, A4), P1 p1, P2 p2) { return new MutantImpl, Tuple3 >(obj, method, MakeTuple(p1, p2)); } // 3 - 1 template inline typename Callback1::Type* NewMutant(T* obj, void (T::*method)(P1, P2, P3, A1), P1 p1, P2 p2, P3 p3) { return new MutantImpl, Tuple1 >(obj, method, MakeTuple(p1, p2, p3)); } // 3 - 2 template inline typename Callback2::Type* NewMutant(T* obj, void (T::*method)(P1, P2, P3, A1, A2), P1 p1, P2 p2, P3 p3) { return new MutantImpl, Tuple2 >(obj, method, MakeTuple(p1, p2, p3)); } // 3 - 3 template inline typename Callback3::Type* NewMutant(T* obj, void (T::*method)(P1, P2, P3, A1, A2, A3), P1 p1, P2 p2, P3 p3) { return new MutantImpl, Tuple3 >(obj, method, MakeTuple(p1, p2, p3)); } // 3 - 4 template inline typename Callback4::Type* NewMutant(T* obj, void (T::*method)(P1, P2, P3, A1, A2, A3, A4), P1 p1, P2 p2, P3 p3) { return new MutantImpl, Tuple3 >(obj, method, MakeTuple(p1, p2, p3)); } // 4 - 1 template inline typename Callback1::Type* NewMutant(T* obj, void (T::*method)(P1, P2, P3, P4, A1), P1 p1, P2 p2, P3 p3, P4 p4) { return new MutantImpl, Tuple1 >(obj, method, MakeTuple(p1, p2, p3, p4)); } // 4 - 2 template inline typename Callback2::Type* NewMutant(T* obj, void (T::*method)(P1, P2, P3, P4, A1, A2), P1 p1, P2 p2, P3 p3, P4 p4) { return new MutantImpl, Tuple2 >(obj, method, MakeTuple(p1, p2, p3, p4)); } // 4 - 3 template inline typename Callback3::Type* NewMutant(T* obj, void (T::*method)(P1, P2, P3, P4, A1, A2, A3), P1 p1, P2 p2, P3 p3, P4 p4) { return new MutantImpl, Tuple3 >(obj, method, MakeTuple(p1, p2, p3, p4)); } // 4 - 4 template inline typename Callback4::Type* NewMutant(T* obj, void (T::*method)(P1, P2, P3, P4, A1, A2, A3, A4), P1 p1, P2 p2, P3 p3, P4 p4) { return new MutantImpl, Tuple3 >(obj, method, MakeTuple(p1, p2, p3, p4)); } //////////////////////////////////////////////////////////////////////////////// // Simple callback wrapper acting as a functor. // Redirects operator() to CallbackRunner::Run // We cannot delete the inner impl_ in object's destructor because // this object is copied few times inside from GMock machinery. template struct CallbackFunctor { explicit CallbackFunctor(CallbackRunner* cb) : impl_(cb) {} template inline void operator()(const Arg1& a) { impl_->Run(a); delete impl_; impl_ = NULL; } template inline void operator()(const Arg1& a, const Arg2& b) { impl_->Run(a, b); delete impl_; impl_ = NULL; } template inline void operator()(const Arg1& a, const Arg2& b, const Arg3& c) { impl_->Run(a, b, c); delete impl_; impl_ = NULL; } template inline void operator()(const Arg1& a, const Arg2& b, const Arg3& c, const Arg4& d) { impl_->Run(a, b, c, d); delete impl_; impl_ = NULL; } private: CallbackFunctor(); CallbackRunner* impl_; }; /////////////////////////////////////////////////////////////////////////////// // CallbackFunctors creation // 0 - 1 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(A1)) { return CallbackFunctor >(NewCallback(obj, method)); } // 0 - 2 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(A1, A2)) { return CallbackFunctor >(NewCallback(obj, method)); } // 0 - 3 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(A1, A2, A3)) { return CallbackFunctor >(NewCallback(obj, method)); } // 0 - 4 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(A1, A2, A3, A4)) { return CallbackFunctor >(NewCallback(obj, method)); } // 1 - 1 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, A1), P1 p1) { Callback1::Type* t = new MutantImpl, Tuple1 >(obj, method, MakeTuple(p1)); return CallbackFunctor >(t); } // 1 - 2 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, A1, A2), P1 p1) { Callback2::Type* t = new MutantImpl, Tuple2 >(obj, method, MakeTuple(p1)); return CallbackFunctor >(t); } // 1 - 3 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, A1, A2, A3), P1 p1) { Callback3::Type* t = new MutantImpl, Tuple3 >(obj, method, MakeTuple(p1)); return CallbackFunctor >(t); } // 1 - 4 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, A1, A2, A3, A4), P1 p1) { Callback4::Type* t = new MutantImpl, Tuple4 >(obj, method, MakeTuple(p1)); return CallbackFunctor >(t); } // 2 - 1 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, A1), P1 p1, P2 p2) { Callback1::Type* t = new MutantImpl, Tuple1 >(obj, method, MakeTuple(p1, p2)); return CallbackFunctor >(t); } // 2 - 2 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, A1, A2), P1 p1, P2 p2) { Callback2::Type* t = new MutantImpl, Tuple2 >(obj, method, MakeTuple(p1, p2)); return CallbackFunctor >(t); } // 2 - 3 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, A1, A2, A3), P1 p1, P2 p2) { Callback3::Type* t = new MutantImpl, Tuple3 >(obj, method, MakeTuple(p1, p2)); return CallbackFunctor >(t); } // 2 - 4 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, A1, A2, A3, A4), P1 p1, P2 p2) { Callback4::Type* t = new MutantImpl, Tuple4 >(obj, method, MakeTuple(p1, p2)); return CallbackFunctor >(t); } // 3 - 1 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, P3, A1), P1 p1, P2 p2, P3 p3) { Callback1::Type* t = new MutantImpl, Tuple1 >(obj, method, MakeTuple(p1, p2, p3)); return CallbackFunctor >(t); } // 3 - 2 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, P3, A1, A2), P1 p1, P2 p2, P3 p3) { Callback2::Type* t = new MutantImpl, Tuple2 >(obj, method, MakeTuple(p1, p2, p3)); return CallbackFunctor >(t); } // 3 - 3 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, P3, A1, A2, A3), P1 p1, P2 p2, P3 p3) { Callback3::Type* t = new MutantImpl, Tuple3 >(obj, method, MakeTuple(p1, p2, p3)); return CallbackFunctor >(t); } // 3 - 4 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, P3, A1, A2, A3, A4), P1 p1, P2 p2, P3 p3) { Callback4::Type* t = new MutantImpl, Tuple4 >(obj, method, MakeTuple(p1, p2, p3)); return CallbackFunctor >(t); } // 4 - 1 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, P3, P4, A1), P1 p1, P2 p2, P3 p3, P4 p4) { Callback1::Type* t = new MutantImpl, Tuple1 > (obj, method, MakeTuple(p1, p2, p3, p4)); return CallbackFunctor >(t); } // 4 - 2 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, P3, P4, A1, A2), P1 p1, P2 p2, P3 p3, P4 p4) { Callback2::Type* t = new MutantImpl, Tuple2 >(obj, method, MakeTuple(p1, p2, p3, p4)); return CallbackFunctor >(t); } // 4 - 3 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, P3, P4, A1, A2, A3), P1 p1, P2 p2, P3 p3, P4 p4) { Callback3::Type* t = new MutantImpl, Tuple3 > (obj, method, MakeTuple(p1, p2, p3, p4)); return CallbackFunctor >(t); } // 4 - 4 template inline CallbackFunctor > CBF(T* obj, void (T::*method)(P1, P2, P3, P4, A1, A2, A3, A4), P1 p1, P2 p2, P3 p3, P4 p4) { Callback4::Type* t = new MutantImpl, Tuple4 >(obj, method, MakeTuple(p1, p2, p3, p4)); return CallbackFunctor >(t); } // Simple task wrapper acting as a functor. // Redirects operator() to Task::Run. We cannot delete the inner impl_ object // in object's destructor because this object is copied few times inside // from GMock machinery. struct TaskHolder { explicit TaskHolder(Task* impl) : impl_(impl) {} void operator()() { impl_->Run(); delete impl_; impl_ = NULL; } private: TaskHolder(); Task* impl_; }; #endif // CHROME_FRAME_TEST_HELPER_GMOCK_H_