1 #!/usr/bin/env python 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 import string 7 import sys 8 9 HEADER = """\ 10 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 11 // Use of this source code is governed by a BSD-style license that can be 12 // found in the LICENSE file. 13 14 // This file automatically generated by testing/generate_gmock_mutant.py. 15 // DO NOT EDIT. 16 17 #ifndef TESTING_GMOCK_MUTANT_H_ 18 #define TESTING_GMOCK_MUTANT_H_ 19 20 // The intention of this file is to make possible using GMock actions in 21 // all of its syntactic beauty. Classes and helper functions can be used as 22 // more generic variants of Task and Callback classes (see base/task.h) 23 // Mutant supports both pre-bound arguments (like Task) and call-time 24 // arguments (like Callback) - hence the name. :-) 25 // 26 // DispatchToMethod/Function supports two sets of arguments: pre-bound (P) and 27 // call-time (C). The arguments as well as the return type are templatized. 28 // DispatchToMethod/Function will also try to call the selected method or 29 // function even if provided pre-bound arguments does not match exactly with 30 // the function signature hence the X1, X2 ... XN parameters in CreateFunctor. 31 // DispatchToMethod will try to invoke method that may not belong to the 32 // object's class itself but to the object's class base class. 33 // 34 // Additionally you can bind the object at calltime by binding a pointer to 35 // pointer to the object at creation time - before including this file you 36 // have to #define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING. 37 // 38 // TODO(stoyan): It's yet not clear to me should we use T& and T&* instead 39 // of T* and T** when we invoke CreateFunctor to match the EXPECT_CALL style. 40 // 41 // 42 // Sample usage with gMock: 43 // 44 // struct Mock : public ObjectDelegate { 45 // MOCK_METHOD2(string, OnRequest(int n, const string& request)); 46 // MOCK_METHOD1(void, OnQuit(int exit_code)); 47 // MOCK_METHOD2(void, LogMessage(int level, const string& message)); 48 // 49 // string HandleFlowers(const string& reply, int n, const string& request) { 50 // string result = SStringPrintf("In request of %d %s ", n, request); 51 // for (int i = 0; i < n; ++i) result.append(reply) 52 // return result; 53 // } 54 // 55 // void DoLogMessage(int level, const string& message) { 56 // } 57 // 58 // void QuitMessageLoop(int seconds) { 59 // MessageLoop* loop = MessageLoop::current(); 60 // loop->PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), 61 // 1000 * seconds); 62 // } 63 // }; 64 // 65 // Mock mock; 66 // // Will invoke mock.HandleFlowers("orchids", n, request) 67 // // "orchids" is a pre-bound argument, and <n> and <request> are call-time 68 // // arguments - they are not known until the OnRequest mock is invoked. 69 // EXPECT_CALL(mock, OnRequest(Ge(5), StartsWith("flower")) 70 // .Times(1) 71 // .WillOnce(Invoke(CreateFunctor(&mock, &Mock::HandleFlowers, 72 // string("orchids")))); 73 // 74 // 75 // // No pre-bound arguments, two call-time arguments passed 76 // // directly to DoLogMessage 77 // EXPECT_CALL(mock, OnLogMessage(_, _)) 78 // .Times(AnyNumber()) 79 // .WillAlways(Invoke(CreateFunctor, &mock, &Mock::DoLogMessage)); 80 // 81 // 82 // // In this case we have a single pre-bound argument - 3. We ignore 83 // // all of the arguments of OnQuit. 84 // EXCEPT_CALL(mock, OnQuit(_)) 85 // .Times(1) 86 // .WillOnce(InvokeWithoutArgs(CreateFunctor( 87 // &mock, &Mock::QuitMessageLoop, 3))); 88 // 89 // MessageLoop loop; 90 // loop.Run(); 91 // 92 // 93 // // Here is another example of how we can set an action that invokes 94 // // method of an object that is not yet created. 95 // struct Mock : public ObjectDelegate { 96 // MOCK_METHOD1(void, DemiurgeCreated(Demiurge*)); 97 // MOCK_METHOD2(void, OnRequest(int count, const string&)); 98 // 99 // void StoreDemiurge(Demiurge* w) { 100 // demiurge_ = w; 101 // } 102 // 103 // Demiurge* demiurge; 104 // } 105 // 106 // EXPECT_CALL(mock, DemiurgeCreated(_)).Times(1) 107 // .WillOnce(Invoke(CreateFunctor(&mock, &Mock::StoreDemiurge))); 108 // 109 // EXPECT_CALL(mock, OnRequest(_, StrEq("Moby Dick"))) 110 // .Times(AnyNumber()) 111 // .WillAlways(WithArgs<0>(Invoke( 112 // CreateFunctor(&mock->demiurge_, &Demiurge::DecreaseMonsters)))); 113 // 114 115 #include "base/memory/linked_ptr.h" 116 #include "base/tuple.h" // for Tuple 117 118 namespace testing {""" 119 120 MUTANT = """\ 121 122 // Interface that is exposed to the consumer, that does the actual calling 123 // of the method. 124 template <typename R, typename Params> 125 class MutantRunner { 126 public: 127 virtual R RunWithParams(const Params& params) = 0; 128 virtual ~MutantRunner() {} 129 }; 130 131 // Mutant holds pre-bound arguments (like Task). Like Callback 132 // allows call-time arguments. You bind a pointer to the object 133 // at creation time. 134 template <typename R, typename T, typename Method, 135 typename PreBound, typename Params> 136 class Mutant : public MutantRunner<R, Params> { 137 public: 138 Mutant(T* obj, Method method, const PreBound& pb) 139 : obj_(obj), method_(method), pb_(pb) { 140 } 141 142 // MutantRunner implementation 143 virtual R RunWithParams(const Params& params) { 144 return DispatchToMethod<R>(this->obj_, this->method_, pb_, params); 145 } 146 147 T* obj_; 148 Method method_; 149 PreBound pb_; 150 }; 151 152 template <typename R, typename Function, typename PreBound, typename Params> 153 class MutantFunction : public MutantRunner<R, Params> { 154 public: 155 MutantFunction(Function function, const PreBound& pb) 156 : function_(function), pb_(pb) { 157 } 158 159 // MutantRunner implementation 160 virtual R RunWithParams(const Params& params) { 161 return DispatchToFunction<R>(function_, pb_, params); 162 } 163 164 Function function_; 165 PreBound pb_; 166 }; 167 168 #ifdef GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING 169 // MutantLateBind is like Mutant, but you bind a pointer to a pointer 170 // to the object. This way you can create actions for an object 171 // that is not yet created (has only storage for a pointer to it). 172 template <typename R, typename T, typename Method, 173 typename PreBound, typename Params> 174 class MutantLateObjectBind : public MutantRunner<R, Params> { 175 public: 176 MutantLateObjectBind(T** obj, Method method, const PreBound& pb) 177 : obj_(obj), method_(method), pb_(pb) { 178 } 179 180 // MutantRunner implementation. 181 virtual R RunWithParams(const Params& params) { 182 EXPECT_THAT(*this->obj_, testing::NotNull()); 183 if (NULL == *this->obj_) 184 return R(); 185 return DispatchToMethod<R>( *this->obj_, this->method_, pb_, params); 186 } 187 188 T** obj_; 189 Method method_; 190 PreBound pb_; 191 }; 192 #endif 193 194 // Simple MutantRunner<> wrapper acting as a functor. 195 // Redirects operator() to MutantRunner<Params>::Run() 196 template <typename R, typename Params> 197 struct MutantFunctor { 198 explicit MutantFunctor(MutantRunner<R, Params>* cb) : impl_(cb) { 199 } 200 201 ~MutantFunctor() { 202 } 203 204 inline R operator()() { 205 return impl_->RunWithParams(Tuple0()); 206 } 207 208 template <typename Arg1> 209 inline R operator()(const Arg1& a) { 210 return impl_->RunWithParams(Params(a)); 211 } 212 213 template <typename Arg1, typename Arg2> 214 inline R operator()(const Arg1& a, const Arg2& b) { 215 return impl_->RunWithParams(Params(a, b)); 216 } 217 218 template <typename Arg1, typename Arg2, typename Arg3> 219 inline R operator()(const Arg1& a, const Arg2& b, const Arg3& c) { 220 return impl_->RunWithParams(Params(a, b, c)); 221 } 222 223 template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> 224 inline R operator()(const Arg1& a, const Arg2& b, const Arg3& c, 225 const Arg4& d) { 226 return impl_->RunWithParams(Params(a, b, c, d)); 227 } 228 229 private: 230 // We need copy constructor since MutantFunctor is copied few times 231 // inside GMock machinery, hence no DISALLOW_EVIL_CONTRUCTORS 232 MutantFunctor(); 233 linked_ptr<MutantRunner<R, Params> > impl_; 234 }; 235 """ 236 237 FOOTER = """\ 238 } // namespace testing 239 240 #endif // TESTING_GMOCK_MUTANT_H_""" 241 242 # Templates for DispatchToMethod/DispatchToFunction functions. 243 # template_params - typename P1, typename P2.. typename C1.. 244 # prebound - TupleN<P1, .. PN> 245 # calltime - TupleN<C1, .. CN> 246 # args - p.a, p.b.., c.a, c.b.. 247 DISPATCH_TO_METHOD_TEMPLATE = """\ 248 template <typename R, typename T, typename Method, %(template_params)s> 249 inline R DispatchToMethod(T* obj, Method method, 250 const %(prebound)s& p, 251 const %(calltime)s& c) { 252 return (obj->*method)(%(args)s); 253 } 254 """ 255 256 DISPATCH_TO_FUNCTION_TEMPLATE = """\ 257 template <typename R, typename Function, %(template_params)s> 258 inline R DispatchToFunction(Function function, 259 const %(prebound)s& p, 260 const %(calltime)s& c) { 261 return (*function)(%(args)s); 262 } 263 """ 264 265 # Templates for CreateFunctor functions. 266 # template_params - typename P1, typename P2.. typename C1.. typename X1.. 267 # prebound - TupleN<P1, .. PN> 268 # calltime - TupleN<A1, .. AN> 269 # params - X1,.. , A1, .. 270 # args - const P1& p1 .. 271 # call_args - p1, p2, p3.. 272 CREATE_METHOD_FUNCTOR_TEMPLATE = """\ 273 template <typename R, typename T, typename U, %(template_params)s> 274 inline MutantFunctor<R, %(calltime)s> 275 CreateFunctor(T* obj, R (U::*method)(%(params)s), %(args)s) { 276 MutantRunner<R, %(calltime)s>* t = 277 new Mutant<R, T, R (U::*)(%(params)s), 278 %(prebound)s, %(calltime)s> 279 (obj, method, MakeTuple(%(call_args)s)); 280 return MutantFunctor<R, %(calltime)s>(t); 281 } 282 """ 283 284 CREATE_FUNCTION_FUNCTOR_TEMPLATE = """\ 285 template <typename R, %(template_params)s> 286 inline MutantFunctor<R, %(calltime)s> 287 CreateFunctor(R (*function)(%(params)s), %(args)s) { 288 MutantRunner<R, %(calltime)s>* t = 289 new MutantFunction<R, R (*)(%(params)s), 290 %(prebound)s, %(calltime)s> 291 (function, MakeTuple(%(call_args)s)); 292 return MutantFunctor<R, %(calltime)s>(t); 293 } 294 """ 295 296 def SplitLine(line, width): 297 """Splits a single line at comma, at most |width| characters long.""" 298 if len(line) < width: 299 return (line, None) 300 n = 1 + line[:width].rfind(",") 301 if n == 0: # If comma cannot be found give up and return the entire line. 302 return (line, None) 303 # Assume there is a space after the comma 304 assert line[n] == " " 305 return (line[:n], line[n + 1:]) 306 307 308 def Wrap(s, width, subsequent_offset=4): 309 """Wraps a single line |s| at commas so every line is at most |width| 310 characters long. 311 """ 312 w = [] 313 spaces = " " * subsequent_offset 314 while s: 315 (f, s) = SplitLine(s, width) 316 w.append(f) 317 if s: 318 s = spaces + s 319 return "\n".join(w) 320 321 322 def Clean(s): 323 """Cleans artifacts from generated C++ code. 324 325 Our simple string formatting/concatenation may introduce extra commas. 326 """ 327 s = s.replace("<>", "") 328 s = s.replace(", >", ">") 329 s = s.replace(", )", ")") 330 s = s.replace(">>", "> >") 331 return s 332 333 334 def ExpandPattern(pattern, it): 335 """Return list of expanded pattern strings. 336 337 Each string is created by replacing all '%' in |pattern| with element of |it|. 338 """ 339 return [pattern.replace("%", x) for x in it] 340 341 342 def Gen(pattern, n): 343 """Expands pattern replacing '%' with sequential integers. 344 345 Expanded patterns will be joined with comma separator. 346 GenAlphs("X%", 3) will return "X1, X2, X3". 347 """ 348 it = string.hexdigits[1:n + 1] 349 return ", ".join(ExpandPattern(pattern, it)) 350 351 352 def GenAlpha(pattern, n): 353 """Expands pattern replacing '%' with sequential small ASCII letters. 354 355 Expanded patterns will be joined with comma separator. 356 GenAlphs("X%", 3) will return "Xa, Xb, Xc". 357 """ 358 it = string.ascii_lowercase[0:n] 359 return ", ".join(ExpandPattern(pattern, it)) 360 361 362 def Merge(a): 363 return ", ".join(filter(len, a)) 364 365 366 def GenTuple(pattern, n): 367 return Clean("Tuple%d<%s>" % (n, Gen(pattern, n))) 368 369 370 def FixCode(s): 371 lines = Clean(s).splitlines() 372 # Wrap sometimes very long 1st and 3rd line at 80th column. 373 lines[0] = Wrap(lines[0], 80, 10) 374 lines[2] = Wrap(lines[2], 80, 4) 375 return "\n".join(lines) 376 377 378 def GenerateDispatch(prebound, calltime): 379 print "\n// %d - %d" % (prebound, calltime) 380 args = { 381 "template_params": Merge([Gen("typename P%", prebound), 382 Gen("typename C%", calltime)]), 383 "prebound": GenTuple("P%", prebound), 384 "calltime": GenTuple("C%", calltime), 385 "args": Merge([GenAlpha("p.%", prebound), GenAlpha("c.%", calltime)]), 386 } 387 388 print FixCode(DISPATCH_TO_METHOD_TEMPLATE % args) 389 print FixCode(DISPATCH_TO_FUNCTION_TEMPLATE % args) 390 391 392 def GenerateCreateFunctor(prebound, calltime): 393 print "// %d - %d" % (prebound, calltime) 394 args = { 395 "calltime": GenTuple("A%", calltime), 396 "prebound": GenTuple("P%", prebound), 397 "params": Merge([Gen("X%", prebound), Gen("A%", calltime)]), 398 "args": Gen("const P%& p%", prebound), 399 "call_args": Gen("p%", prebound), 400 "template_params": Merge([Gen("typename P%", prebound), 401 Gen("typename A%", calltime), 402 Gen("typename X%", prebound)]) 403 } 404 405 mutant = FixCode(CREATE_METHOD_FUNCTOR_TEMPLATE % args) 406 print mutant 407 408 # Slightly different version for free function call. 409 print "\n", FixCode(CREATE_FUNCTION_FUNCTOR_TEMPLATE % args) 410 411 # Functor with pointer to a pointer of the object. 412 print "\n#ifdef GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING" 413 mutant2 = mutant.replace("CreateFunctor(T* obj,", "CreateFunctor(T** obj,") 414 mutant2 = mutant2.replace("new Mutant", "new MutantLateObjectBind") 415 mutant2 = mutant2.replace(" " * 17 + "Tuple", " " * 31 + "Tuple") 416 print mutant2 417 print "#endif // GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING\n" 418 419 # OS_WIN specific. Same functors but with stdcall calling conventions. 420 # These are not for WIN64 (x86_64) because there is only one calling 421 # convention in WIN64. 422 # Functor for method with __stdcall calling conventions. 423 print "#if defined (OS_WIN) && !defined (ARCH_CPU_X86_64)" 424 stdcall_method = CREATE_METHOD_FUNCTOR_TEMPLATE 425 stdcall_method = stdcall_method.replace("U::", "__stdcall U::") 426 stdcall_method = FixCode(stdcall_method % args) 427 print stdcall_method 428 # Functor for free function with __stdcall calling conventions. 429 stdcall_function = CREATE_FUNCTION_FUNCTOR_TEMPLATE 430 stdcall_function = stdcall_function.replace("R (*", "R (__stdcall *") 431 print "\n", FixCode(stdcall_function % args) 432 433 print "#ifdef GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING" 434 stdcall2 = stdcall_method 435 stdcall2 = stdcall2.replace("CreateFunctor(T* obj,", "CreateFunctor(T** obj,") 436 stdcall2 = stdcall2.replace("new Mutant", "new MutantLateObjectBind") 437 stdcall2 = stdcall2.replace(" " * 17 + "Tuple", " " * 31 + "Tuple") 438 print stdcall2 439 print "#endif // GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING" 440 print "#endif // defined (OS_WIN) && !defined (ARCH_CPU_X86_64)\n" 441 442 443 def main(): 444 print HEADER 445 for prebound in xrange(0, 6 + 1): 446 for args in xrange(0, 6 + 1): 447 GenerateDispatch(prebound, args) 448 print MUTANT 449 for prebound in xrange(0, 6 + 1): 450 for args in xrange(0, 6 + 1): 451 GenerateCreateFunctor(prebound, args) 452 print FOOTER 453 return 0 454 455 456 if __name__ == "__main__": 457 sys.exit(main()) 458