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
20import os
21import sys
22import unittest
23
24# Allow the cpp imports below to work when run as a standalone script.
25sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
26
27from cpp import ast
28from cpp import gmock_class
29
30
31class TestCase(unittest.TestCase):
32  """Helper class that adds assert methods."""
33
34  @staticmethod
35  def StripLeadingWhitespace(lines):
36    """Strip leading whitespace in each line in 'lines'."""
37    return '\n'.join([s.lstrip() for s in lines.split('\n')])
38
39  def assertEqualIgnoreLeadingWhitespace(self, expected_lines, lines):
40    """Specialized assert that ignores the indent level."""
41    self.assertEqual(expected_lines, self.StripLeadingWhitespace(lines))
42
43
44class GenerateMethodsTest(TestCase):
45
46  @staticmethod
47  def GenerateMethodSource(cpp_source):
48    """Convert C++ source to Google Mock output source lines."""
49    method_source_lines = []
50    # <test> is a pseudo-filename, it is not read or written.
51    builder = ast.BuilderFromSource(cpp_source, '<test>')
52    ast_list = list(builder.Generate())
53    gmock_class._GenerateMethods(method_source_lines, cpp_source, ast_list[0])
54    return '\n'.join(method_source_lines)
55
56  def testSimpleMethod(self):
57    source = """
58class Foo {
59 public:
60  virtual int Bar();
61};
62"""
63    self.assertEqualIgnoreLeadingWhitespace(
64        'MOCK_METHOD(int, Bar, (), (override));',
65        self.GenerateMethodSource(source))
66
67  def testSimpleConstructorsAndDestructor(self):
68    source = """
69class Foo {
70 public:
71  Foo();
72  Foo(int x);
73  Foo(const Foo& f);
74  Foo(Foo&& f);
75  ~Foo();
76  virtual int Bar() = 0;
77};
78"""
79    # The constructors and destructor should be ignored.
80    self.assertEqualIgnoreLeadingWhitespace(
81        'MOCK_METHOD(int, Bar, (), (override));',
82        self.GenerateMethodSource(source))
83
84  def testVirtualDestructor(self):
85    source = """
86class Foo {
87 public:
88  virtual ~Foo();
89  virtual int Bar() = 0;
90};
91"""
92    # The destructor should be ignored.
93    self.assertEqualIgnoreLeadingWhitespace(
94        'MOCK_METHOD(int, Bar, (), (override));',
95        self.GenerateMethodSource(source))
96
97  def testExplicitlyDefaultedConstructorsAndDestructor(self):
98    source = """
99class Foo {
100 public:
101  Foo() = default;
102  Foo(const Foo& f) = default;
103  Foo(Foo&& f) = default;
104  ~Foo() = default;
105  virtual int Bar() = 0;
106};
107"""
108    # The constructors and destructor should be ignored.
109    self.assertEqualIgnoreLeadingWhitespace(
110        'MOCK_METHOD(int, Bar, (), (override));',
111        self.GenerateMethodSource(source))
112
113  def testExplicitlyDeletedConstructorsAndDestructor(self):
114    source = """
115class Foo {
116 public:
117  Foo() = delete;
118  Foo(const Foo& f) = delete;
119  Foo(Foo&& f) = delete;
120  ~Foo() = delete;
121  virtual int Bar() = 0;
122};
123"""
124    # The constructors and destructor should be ignored.
125    self.assertEqualIgnoreLeadingWhitespace(
126        'MOCK_METHOD(int, Bar, (), (override));',
127        self.GenerateMethodSource(source))
128
129  def testSimpleOverrideMethod(self):
130    source = """
131class Foo {
132 public:
133  int Bar() override;
134};
135"""
136    self.assertEqualIgnoreLeadingWhitespace(
137        'MOCK_METHOD(int, Bar, (), (override));',
138        self.GenerateMethodSource(source))
139
140  def testSimpleConstMethod(self):
141    source = """
142class Foo {
143 public:
144  virtual void Bar(bool flag) const;
145};
146"""
147    self.assertEqualIgnoreLeadingWhitespace(
148        'MOCK_METHOD(void, Bar, (bool flag), (const, override));',
149        self.GenerateMethodSource(source))
150
151  def testExplicitVoid(self):
152    source = """
153class Foo {
154 public:
155  virtual int Bar(void);
156};
157"""
158    self.assertEqualIgnoreLeadingWhitespace(
159        'MOCK_METHOD(int, Bar, (), (override));',
160        self.GenerateMethodSource(source))
161
162  def testStrangeNewlineInParameter(self):
163    source = """
164class Foo {
165 public:
166  virtual void Bar(int
167a) = 0;
168};
169"""
170    self.assertEqualIgnoreLeadingWhitespace(
171        'MOCK_METHOD(void, Bar, (int a), (override));',
172        self.GenerateMethodSource(source))
173
174  def testDefaultParameters(self):
175    source = """
176class Foo {
177 public:
178  virtual void Bar(int a, char c = 'x') = 0;
179};
180"""
181    self.assertEqualIgnoreLeadingWhitespace(
182        'MOCK_METHOD(void, Bar, (int a, char c), (override));',
183        self.GenerateMethodSource(source))
184
185  def testMultipleDefaultParameters(self):
186    source = """
187class Foo {
188 public:
189  virtual void Bar(
190        int a = 42,
191        char c = 'x',
192        const int* const p = nullptr,
193        const std::string& s = "42",
194        char tab[] = {'4','2'},
195        int const *& rp = aDefaultPointer) = 0;
196};
197"""
198    self.assertEqualIgnoreLeadingWhitespace(
199        'MOCK_METHOD(void, Bar, '
200        '(int a, char c, const int* const p, const std::string& s, char tab[], int const *& rp), '
201        '(override));', self.GenerateMethodSource(source))
202
203  def testMultipleSingleLineDefaultParameters(self):
204    source = """
205class Foo {
206 public:
207  virtual void Bar(int a = 42, int b = 43, int c = 44) = 0;
208};
209"""
210    self.assertEqualIgnoreLeadingWhitespace(
211        'MOCK_METHOD(void, Bar, (int a, int b, int c), (override));',
212        self.GenerateMethodSource(source))
213
214  def testConstDefaultParameter(self):
215    source = """
216class Test {
217 public:
218  virtual bool Bar(const int test_arg = 42) = 0;
219};
220"""
221    self.assertEqualIgnoreLeadingWhitespace(
222        'MOCK_METHOD(bool, Bar, (const int test_arg), (override));',
223        self.GenerateMethodSource(source))
224
225  def testConstRefDefaultParameter(self):
226    source = """
227class Test {
228 public:
229  virtual bool Bar(const std::string& test_arg = "42" ) = 0;
230};
231"""
232    self.assertEqualIgnoreLeadingWhitespace(
233        'MOCK_METHOD(bool, Bar, (const std::string& test_arg), (override));',
234        self.GenerateMethodSource(source))
235
236  def testRemovesCommentsWhenDefaultsArePresent(self):
237    source = """
238class Foo {
239 public:
240  virtual void Bar(int a = 42 /* a comment */,
241                   char /* other comment */ c= 'x') = 0;
242};
243"""
244    self.assertEqualIgnoreLeadingWhitespace(
245        'MOCK_METHOD(void, Bar, (int a, char c), (override));',
246        self.GenerateMethodSource(source))
247
248  def testDoubleSlashCommentsInParameterListAreRemoved(self):
249    source = """
250class Foo {
251 public:
252  virtual void Bar(int a,  // inline comments should be elided.
253                   int b   // inline comments should be elided.
254                   ) const = 0;
255};
256"""
257    self.assertEqualIgnoreLeadingWhitespace(
258        'MOCK_METHOD(void, Bar, (int a, int b), (const, override));',
259        self.GenerateMethodSource(source))
260
261  def testCStyleCommentsInParameterListAreNotRemoved(self):
262    # NOTE(nnorwitz): I'm not sure if it's the best behavior to keep these
263    # comments.  Also note that C style comments after the last parameter
264    # are still elided.
265    source = """
266class Foo {
267 public:
268  virtual const string& Bar(int /* keeper */, int b);
269};
270"""
271    self.assertEqualIgnoreLeadingWhitespace(
272        'MOCK_METHOD(const string&, Bar, (int, int b), (override));',
273        self.GenerateMethodSource(source))
274
275  def testArgsOfTemplateTypes(self):
276    source = """
277class Foo {
278 public:
279  virtual int Bar(const vector<int>& v, map<int, string>* output);
280};"""
281    self.assertEqualIgnoreLeadingWhitespace(
282        'MOCK_METHOD(int, Bar, (const vector<int>& v, (map<int, string>* output)), (override));',
283        self.GenerateMethodSource(source))
284
285  def testReturnTypeWithOneTemplateArg(self):
286    source = """
287class Foo {
288 public:
289  virtual vector<int>* Bar(int n);
290};"""
291    self.assertEqualIgnoreLeadingWhitespace(
292        'MOCK_METHOD(vector<int>*, Bar, (int n), (override));',
293        self.GenerateMethodSource(source))
294
295  def testReturnTypeWithManyTemplateArgs(self):
296    source = """
297class Foo {
298 public:
299  virtual map<int, string> Bar();
300};"""
301    self.assertEqualIgnoreLeadingWhitespace(
302        'MOCK_METHOD((map<int, string>), Bar, (), (override));',
303        self.GenerateMethodSource(source))
304
305  def testSimpleMethodInTemplatedClass(self):
306    source = """
307template<class T>
308class Foo {
309 public:
310  virtual int Bar();
311};
312"""
313    self.assertEqualIgnoreLeadingWhitespace(
314        'MOCK_METHOD(int, Bar, (), (override));',
315        self.GenerateMethodSource(source))
316
317  def testPointerArgWithoutNames(self):
318    source = """
319class Foo {
320  virtual int Bar(C*);
321};
322"""
323    self.assertEqualIgnoreLeadingWhitespace(
324        'MOCK_METHOD(int, Bar, (C*), (override));',
325        self.GenerateMethodSource(source))
326
327  def testReferenceArgWithoutNames(self):
328    source = """
329class Foo {
330  virtual int Bar(C&);
331};
332"""
333    self.assertEqualIgnoreLeadingWhitespace(
334        'MOCK_METHOD(int, Bar, (C&), (override));',
335        self.GenerateMethodSource(source))
336
337  def testArrayArgWithoutNames(self):
338    source = """
339class Foo {
340  virtual int Bar(C[]);
341};
342"""
343    self.assertEqualIgnoreLeadingWhitespace(
344        'MOCK_METHOD(int, Bar, (C[]), (override));',
345        self.GenerateMethodSource(source))
346
347
348class GenerateMocksTest(TestCase):
349
350  @staticmethod
351  def GenerateMocks(cpp_source):
352    """Convert C++ source to complete Google Mock output source."""
353    # <test> is a pseudo-filename, it is not read or written.
354    filename = '<test>'
355    builder = ast.BuilderFromSource(cpp_source, filename)
356    ast_list = list(builder.Generate())
357    lines = gmock_class._GenerateMocks(filename, cpp_source, ast_list, None)
358    return '\n'.join(lines)
359
360  def testNamespaces(self):
361    source = """
362namespace Foo {
363namespace Bar { class Forward; }
364namespace Baz::Qux {
365
366class Test {
367 public:
368  virtual void Foo();
369};
370
371}  // namespace Baz::Qux
372}  // namespace Foo
373"""
374    expected = """\
375namespace Foo {
376namespace Baz::Qux {
377
378class MockTest : public Test {
379public:
380MOCK_METHOD(void, Foo, (), (override));
381};
382
383}  // namespace Baz::Qux
384}  // namespace Foo
385"""
386    self.assertEqualIgnoreLeadingWhitespace(expected,
387                                            self.GenerateMocks(source))
388
389  def testClassWithStorageSpecifierMacro(self):
390    source = """
391class STORAGE_SPECIFIER Test {
392 public:
393  virtual void Foo();
394};
395"""
396    expected = """\
397class MockTest : public Test {
398public:
399MOCK_METHOD(void, Foo, (), (override));
400};
401"""
402    self.assertEqualIgnoreLeadingWhitespace(expected,
403                                            self.GenerateMocks(source))
404
405  def testTemplatedForwardDeclaration(self):
406    source = """
407template <class T> class Forward;  // Forward declaration should be ignored.
408class Test {
409 public:
410  virtual void Foo();
411};
412"""
413    expected = """\
414class MockTest : public Test {
415public:
416MOCK_METHOD(void, Foo, (), (override));
417};
418"""
419    self.assertEqualIgnoreLeadingWhitespace(expected,
420                                            self.GenerateMocks(source))
421
422  def testTemplatedClass(self):
423    source = """
424template <typename S, typename T>
425class Test {
426 public:
427  virtual void Foo();
428};
429"""
430    expected = """\
431template <typename S, typename T>
432class MockTest : public Test<S, T> {
433public:
434MOCK_METHOD(void, Foo, (), (override));
435};
436"""
437    self.assertEqualIgnoreLeadingWhitespace(expected,
438                                            self.GenerateMocks(source))
439
440  def testTemplateInATemplateTypedef(self):
441    source = """
442class Test {
443 public:
444  typedef std::vector<std::list<int>> FooType;
445  virtual void Bar(const FooType& test_arg);
446};
447"""
448    expected = """\
449class MockTest : public Test {
450public:
451MOCK_METHOD(void, Bar, (const FooType& test_arg), (override));
452};
453"""
454    self.assertEqualIgnoreLeadingWhitespace(expected,
455                                            self.GenerateMocks(source))
456
457  def testTemplatedClassWithTemplatedArguments(self):
458    source = """
459template <typename S, typename T, typename U, typename V, typename W>
460class Test {
461 public:
462  virtual U Foo(T some_arg);
463};
464"""
465    expected = """\
466template <typename S, typename T, typename U, typename V, typename W>
467class MockTest : public Test<S, T, U, V, W> {
468public:
469MOCK_METHOD(U, Foo, (T some_arg), (override));
470};
471"""
472    self.assertEqualIgnoreLeadingWhitespace(expected,
473                                            self.GenerateMocks(source))
474
475  def testTemplateInATemplateTypedefWithComma(self):
476    source = """
477class Test {
478 public:
479  typedef std::function<void(
480      const vector<std::list<int>>&, int> FooType;
481  virtual void Bar(const FooType& test_arg);
482};
483"""
484    expected = """\
485class MockTest : public Test {
486public:
487MOCK_METHOD(void, Bar, (const FooType& test_arg), (override));
488};
489"""
490    self.assertEqualIgnoreLeadingWhitespace(expected,
491                                            self.GenerateMocks(source))
492
493  def testParenthesizedCommaInArg(self):
494    source = """
495class Test {
496 public:
497   virtual void Bar(std::function<void(int, int)> f);
498};
499"""
500    expected = """\
501class MockTest : public Test {
502public:
503MOCK_METHOD(void, Bar, (std::function<void(int, int)> f), (override));
504};
505"""
506    self.assertEqualIgnoreLeadingWhitespace(expected,
507                                            self.GenerateMocks(source))
508
509  def testEnumType(self):
510    source = """
511class Test {
512 public:
513  enum Bar {
514    BAZ, QUX, QUUX, QUUUX
515  };
516  virtual void Foo();
517};
518"""
519    expected = """\
520class MockTest : public Test {
521public:
522MOCK_METHOD(void, Foo, (), (override));
523};
524"""
525    self.assertEqualIgnoreLeadingWhitespace(expected,
526                                            self.GenerateMocks(source))
527
528  def testEnumClassType(self):
529    source = """
530class Test {
531 public:
532  enum class Bar {
533    BAZ, QUX, QUUX, QUUUX
534  };
535  virtual void Foo();
536};
537"""
538    expected = """\
539class MockTest : public Test {
540public:
541MOCK_METHOD(void, Foo, (), (override));
542};
543"""
544    self.assertEqualIgnoreLeadingWhitespace(expected,
545                                            self.GenerateMocks(source))
546
547  def testStdFunction(self):
548    source = """
549class Test {
550 public:
551  Test(std::function<int(std::string)> foo) : foo_(foo) {}
552
553  virtual std::function<int(std::string)> foo();
554
555 private:
556  std::function<int(std::string)> foo_;
557};
558"""
559    expected = """\
560class MockTest : public Test {
561public:
562MOCK_METHOD(std::function<int (std::string)>, foo, (), (override));
563};
564"""
565    self.assertEqualIgnoreLeadingWhitespace(expected,
566                                            self.GenerateMocks(source))
567
568
569if __name__ == '__main__':
570  unittest.main()
571