1#!/usr/bin/env python 2# 3# Copyright 2009 Neal Norwitz All Rights Reserved. 4# Portions Copyright 2009 Google Inc. All Rights Reserved. 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17 18"""Tests for gmock.scripts.generator.cpp.gmock_class.""" 19 20__author__ = 'nnorwitz@google.com (Neal Norwitz)' 21 22 23import os 24import sys 25import unittest 26 27# Allow the cpp imports below to work when run as a standalone script. 28sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 29 30from cpp import ast 31from cpp import gmock_class 32 33 34class TestCase(unittest.TestCase): 35 """Helper class that adds assert methods.""" 36 37 def StripLeadingWhitespace(self, lines): 38 """Strip leading whitespace in each line in 'lines'.""" 39 return '\n'.join([s.lstrip() for s in lines.split('\n')]) 40 41 def assertEqualIgnoreLeadingWhitespace(self, expected_lines, lines): 42 """Specialized assert that ignores the indent level.""" 43 self.assertEqual(expected_lines, self.StripLeadingWhitespace(lines)) 44 45 46class GenerateMethodsTest(TestCase): 47 48 def GenerateMethodSource(self, cpp_source): 49 """Convert C++ source to Google Mock output source lines.""" 50 method_source_lines = [] 51 # <test> is a pseudo-filename, it is not read or written. 52 builder = ast.BuilderFromSource(cpp_source, '<test>') 53 ast_list = list(builder.Generate()) 54 gmock_class._GenerateMethods(method_source_lines, cpp_source, ast_list[0]) 55 return '\n'.join(method_source_lines) 56 57 def testSimpleMethod(self): 58 source = """ 59class Foo { 60 public: 61 virtual int Bar(); 62}; 63""" 64 self.assertEqualIgnoreLeadingWhitespace( 65 'MOCK_METHOD0(Bar,\nint());', 66 self.GenerateMethodSource(source)) 67 68 def testSimpleConstructorsAndDestructor(self): 69 source = """ 70class Foo { 71 public: 72 Foo(); 73 Foo(int x); 74 Foo(const Foo& f); 75 Foo(Foo&& f); 76 ~Foo(); 77 virtual int Bar() = 0; 78}; 79""" 80 # The constructors and destructor should be ignored. 81 self.assertEqualIgnoreLeadingWhitespace( 82 'MOCK_METHOD0(Bar,\nint());', 83 self.GenerateMethodSource(source)) 84 85 def testVirtualDestructor(self): 86 source = """ 87class Foo { 88 public: 89 virtual ~Foo(); 90 virtual int Bar() = 0; 91}; 92""" 93 # The destructor should be ignored. 94 self.assertEqualIgnoreLeadingWhitespace( 95 'MOCK_METHOD0(Bar,\nint());', 96 self.GenerateMethodSource(source)) 97 98 def testExplicitlyDefaultedConstructorsAndDestructor(self): 99 source = """ 100class Foo { 101 public: 102 Foo() = default; 103 Foo(const Foo& f) = default; 104 Foo(Foo&& f) = default; 105 ~Foo() = default; 106 virtual int Bar() = 0; 107}; 108""" 109 # The constructors and destructor should be ignored. 110 self.assertEqualIgnoreLeadingWhitespace( 111 'MOCK_METHOD0(Bar,\nint());', 112 self.GenerateMethodSource(source)) 113 114 def testExplicitlyDeletedConstructorsAndDestructor(self): 115 source = """ 116class Foo { 117 public: 118 Foo() = delete; 119 Foo(const Foo& f) = delete; 120 Foo(Foo&& f) = delete; 121 ~Foo() = delete; 122 virtual int Bar() = 0; 123}; 124""" 125 # The constructors and destructor should be ignored. 126 self.assertEqualIgnoreLeadingWhitespace( 127 'MOCK_METHOD0(Bar,\nint());', 128 self.GenerateMethodSource(source)) 129 130 def testSimpleOverrideMethod(self): 131 source = """ 132class Foo { 133 public: 134 int Bar() override; 135}; 136""" 137 self.assertEqualIgnoreLeadingWhitespace( 138 'MOCK_METHOD0(Bar,\nint());', 139 self.GenerateMethodSource(source)) 140 141 def testSimpleConstMethod(self): 142 source = """ 143class Foo { 144 public: 145 virtual void Bar(bool flag) const; 146}; 147""" 148 self.assertEqualIgnoreLeadingWhitespace( 149 'MOCK_CONST_METHOD1(Bar,\nvoid(bool flag));', 150 self.GenerateMethodSource(source)) 151 152 def testExplicitVoid(self): 153 source = """ 154class Foo { 155 public: 156 virtual int Bar(void); 157}; 158""" 159 self.assertEqualIgnoreLeadingWhitespace( 160 'MOCK_METHOD0(Bar,\nint(void));', 161 self.GenerateMethodSource(source)) 162 163 def testStrangeNewlineInParameter(self): 164 source = """ 165class Foo { 166 public: 167 virtual void Bar(int 168a) = 0; 169}; 170""" 171 self.assertEqualIgnoreLeadingWhitespace( 172 'MOCK_METHOD1(Bar,\nvoid(int a));', 173 self.GenerateMethodSource(source)) 174 175 def testDefaultParameters(self): 176 source = """ 177class Foo { 178 public: 179 virtual void Bar(int a, char c = 'x') = 0; 180}; 181""" 182 self.assertEqualIgnoreLeadingWhitespace( 183 'MOCK_METHOD2(Bar,\nvoid(int, char));', 184 self.GenerateMethodSource(source)) 185 186 def testMultipleDefaultParameters(self): 187 source = """ 188class Foo { 189 public: 190 virtual void Bar(int a = 42, char c = 'x') = 0; 191}; 192""" 193 self.assertEqualIgnoreLeadingWhitespace( 194 'MOCK_METHOD2(Bar,\nvoid(int, char));', 195 self.GenerateMethodSource(source)) 196 197 def testRemovesCommentsWhenDefaultsArePresent(self): 198 source = """ 199class Foo { 200 public: 201 virtual void Bar(int a = 42 /* a comment */, 202 char /* other comment */ c= 'x') = 0; 203}; 204""" 205 self.assertEqualIgnoreLeadingWhitespace( 206 'MOCK_METHOD2(Bar,\nvoid(int, char));', 207 self.GenerateMethodSource(source)) 208 209 def testDoubleSlashCommentsInParameterListAreRemoved(self): 210 source = """ 211class Foo { 212 public: 213 virtual void Bar(int a, // inline comments should be elided. 214 int b // inline comments should be elided. 215 ) const = 0; 216}; 217""" 218 self.assertEqualIgnoreLeadingWhitespace( 219 'MOCK_CONST_METHOD2(Bar,\nvoid(int a, int b));', 220 self.GenerateMethodSource(source)) 221 222 def testCStyleCommentsInParameterListAreNotRemoved(self): 223 # NOTE(nnorwitz): I'm not sure if it's the best behavior to keep these 224 # comments. Also note that C style comments after the last parameter 225 # are still elided. 226 source = """ 227class Foo { 228 public: 229 virtual const string& Bar(int /* keeper */, int b); 230}; 231""" 232 self.assertEqualIgnoreLeadingWhitespace( 233 'MOCK_METHOD2(Bar,\nconst string&(int /* keeper */, int b));', 234 self.GenerateMethodSource(source)) 235 236 def testArgsOfTemplateTypes(self): 237 source = """ 238class Foo { 239 public: 240 virtual int Bar(const vector<int>& v, map<int, string>* output); 241};""" 242 self.assertEqualIgnoreLeadingWhitespace( 243 'MOCK_METHOD2(Bar,\n' 244 'int(const vector<int>& v, map<int, string>* output));', 245 self.GenerateMethodSource(source)) 246 247 def testReturnTypeWithOneTemplateArg(self): 248 source = """ 249class Foo { 250 public: 251 virtual vector<int>* Bar(int n); 252};""" 253 self.assertEqualIgnoreLeadingWhitespace( 254 'MOCK_METHOD1(Bar,\nvector<int>*(int n));', 255 self.GenerateMethodSource(source)) 256 257 def testReturnTypeWithManyTemplateArgs(self): 258 source = """ 259class Foo { 260 public: 261 virtual map<int, string> Bar(); 262};""" 263 # Comparing the comment text is brittle - we'll think of something 264 # better in case this gets annoying, but for now let's keep it simple. 265 self.assertEqualIgnoreLeadingWhitespace( 266 '// The following line won\'t really compile, as the return\n' 267 '// type has multiple template arguments. To fix it, use a\n' 268 '// typedef for the return type.\n' 269 'MOCK_METHOD0(Bar,\nmap<int, string>());', 270 self.GenerateMethodSource(source)) 271 272 def testSimpleMethodInTemplatedClass(self): 273 source = """ 274template<class T> 275class Foo { 276 public: 277 virtual int Bar(); 278}; 279""" 280 self.assertEqualIgnoreLeadingWhitespace( 281 'MOCK_METHOD0_T(Bar,\nint());', 282 self.GenerateMethodSource(source)) 283 284 def testPointerArgWithoutNames(self): 285 source = """ 286class Foo { 287 virtual int Bar(C*); 288}; 289""" 290 self.assertEqualIgnoreLeadingWhitespace( 291 'MOCK_METHOD1(Bar,\nint(C*));', 292 self.GenerateMethodSource(source)) 293 294 def testReferenceArgWithoutNames(self): 295 source = """ 296class Foo { 297 virtual int Bar(C&); 298}; 299""" 300 self.assertEqualIgnoreLeadingWhitespace( 301 'MOCK_METHOD1(Bar,\nint(C&));', 302 self.GenerateMethodSource(source)) 303 304 def testArrayArgWithoutNames(self): 305 source = """ 306class Foo { 307 virtual int Bar(C[]); 308}; 309""" 310 self.assertEqualIgnoreLeadingWhitespace( 311 'MOCK_METHOD1(Bar,\nint(C[]));', 312 self.GenerateMethodSource(source)) 313 314 315class GenerateMocksTest(TestCase): 316 317 def GenerateMocks(self, cpp_source): 318 """Convert C++ source to complete Google Mock output source.""" 319 # <test> is a pseudo-filename, it is not read or written. 320 filename = '<test>' 321 builder = ast.BuilderFromSource(cpp_source, filename) 322 ast_list = list(builder.Generate()) 323 lines = gmock_class._GenerateMocks(filename, cpp_source, ast_list, None) 324 return '\n'.join(lines) 325 326 def testNamespaces(self): 327 source = """ 328namespace Foo { 329namespace Bar { class Forward; } 330namespace Baz { 331 332class Test { 333 public: 334 virtual void Foo(); 335}; 336 337} // namespace Baz 338} // namespace Foo 339""" 340 expected = """\ 341namespace Foo { 342namespace Baz { 343 344class MockTest : public Test { 345public: 346MOCK_METHOD0(Foo, 347void()); 348}; 349 350} // namespace Baz 351} // namespace Foo 352""" 353 self.assertEqualIgnoreLeadingWhitespace( 354 expected, self.GenerateMocks(source)) 355 356 def testClassWithStorageSpecifierMacro(self): 357 source = """ 358class STORAGE_SPECIFIER Test { 359 public: 360 virtual void Foo(); 361}; 362""" 363 expected = """\ 364class MockTest : public Test { 365public: 366MOCK_METHOD0(Foo, 367void()); 368}; 369""" 370 self.assertEqualIgnoreLeadingWhitespace( 371 expected, self.GenerateMocks(source)) 372 373 def testTemplatedForwardDeclaration(self): 374 source = """ 375template <class T> class Forward; // Forward declaration should be ignored. 376class Test { 377 public: 378 virtual void Foo(); 379}; 380""" 381 expected = """\ 382class MockTest : public Test { 383public: 384MOCK_METHOD0(Foo, 385void()); 386}; 387""" 388 self.assertEqualIgnoreLeadingWhitespace( 389 expected, self.GenerateMocks(source)) 390 391 def testTemplatedClass(self): 392 source = """ 393template <typename S, typename T> 394class Test { 395 public: 396 virtual void Foo(); 397}; 398""" 399 expected = """\ 400template <typename T0, typename T1> 401class MockTest : public Test<T0, T1> { 402public: 403MOCK_METHOD0_T(Foo, 404void()); 405}; 406""" 407 self.assertEqualIgnoreLeadingWhitespace( 408 expected, self.GenerateMocks(source)) 409 410 def testTemplateInATemplateTypedef(self): 411 source = """ 412class Test { 413 public: 414 typedef std::vector<std::list<int>> FooType; 415 virtual void Bar(const FooType& test_arg); 416}; 417""" 418 expected = """\ 419class MockTest : public Test { 420public: 421MOCK_METHOD1(Bar, 422void(const FooType& test_arg)); 423}; 424""" 425 self.assertEqualIgnoreLeadingWhitespace( 426 expected, self.GenerateMocks(source)) 427 428 def testTemplateInATemplateTypedefWithComma(self): 429 source = """ 430class Test { 431 public: 432 typedef std::function<void( 433 const vector<std::list<int>>&, int> FooType; 434 virtual void Bar(const FooType& test_arg); 435}; 436""" 437 expected = """\ 438class MockTest : public Test { 439public: 440MOCK_METHOD1(Bar, 441void(const FooType& test_arg)); 442}; 443""" 444 self.assertEqualIgnoreLeadingWhitespace( 445 expected, self.GenerateMocks(source)) 446 447if __name__ == '__main__': 448 unittest.main() 449