• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_METHOD0(Bar,\nint());',
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_METHOD0(Bar,\nint());',
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_METHOD0(Bar,\nint());',
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_METHOD0(Bar,\nint());',
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_METHOD0(Bar,\nint());',
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_METHOD0(Bar,\nint());',
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_CONST_METHOD1(Bar,\nvoid(bool flag));',
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_METHOD0(Bar,\nint(void));',
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_METHOD1(Bar,\nvoid(int a));',
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_METHOD2(Bar,\nvoid(int a, char c ));',
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_METHOD7(Bar,\n"
200            "void(int a , char c , const int* const p , const std::string& s , char tab[] , int const *& rp ));",
201            self.GenerateMethodSource(source))
202
203    def testConstDefaultParameter(self):
204        source = """
205class Test {
206 public:
207  virtual bool Bar(const int test_arg = 42) = 0;
208};
209"""
210        expected = 'MOCK_METHOD1(Bar,\nbool(const int test_arg ));'
211        self.assertEqualIgnoreLeadingWhitespace(
212            expected, self.GenerateMethodSource(source))
213
214    def testConstRefDefaultParameter(self):
215        source = """
216class Test {
217 public:
218  virtual bool Bar(const std::string& test_arg = "42" ) = 0;
219};
220"""
221        expected = 'MOCK_METHOD1(Bar,\nbool(const std::string& test_arg ));'
222        self.assertEqualIgnoreLeadingWhitespace(
223            expected, self.GenerateMethodSource(source))
224
225    def testRemovesCommentsWhenDefaultsArePresent(self):
226        source = """
227class Foo {
228 public:
229  virtual void Bar(int a = 42 /* a comment */,
230                   char /* other comment */ c= 'x') = 0;
231};
232"""
233        self.assertEqualIgnoreLeadingWhitespace(
234            'MOCK_METHOD2(Bar,\nvoid(int a , char c));',
235            self.GenerateMethodSource(source))
236
237    def testDoubleSlashCommentsInParameterListAreRemoved(self):
238        source = """
239class Foo {
240 public:
241  virtual void Bar(int a,  // inline comments should be elided.
242                   int b   // inline comments should be elided.
243                   ) const = 0;
244};
245"""
246        self.assertEqualIgnoreLeadingWhitespace(
247            'MOCK_CONST_METHOD2(Bar,\nvoid(int a, int b));',
248            self.GenerateMethodSource(source))
249
250    def testCStyleCommentsInParameterListAreNotRemoved(self):
251        # NOTE(nnorwitz): I'm not sure if it's the best behavior to keep these
252        # comments.  Also note that C style comments after the last parameter
253        # are still elided.
254        source = """
255class Foo {
256 public:
257  virtual const string& Bar(int /* keeper */, int b);
258};
259"""
260        self.assertEqualIgnoreLeadingWhitespace(
261            'MOCK_METHOD2(Bar,\nconst string&(int , int b));',
262            self.GenerateMethodSource(source))
263
264    def testArgsOfTemplateTypes(self):
265        source = """
266class Foo {
267 public:
268  virtual int Bar(const vector<int>& v, map<int, string>* output);
269};"""
270        self.assertEqualIgnoreLeadingWhitespace(
271            'MOCK_METHOD2(Bar,\n'
272            'int(const vector<int>& v, map<int, string>* output));',
273            self.GenerateMethodSource(source))
274
275    def testReturnTypeWithOneTemplateArg(self):
276        source = """
277class Foo {
278 public:
279  virtual vector<int>* Bar(int n);
280};"""
281        self.assertEqualIgnoreLeadingWhitespace(
282            'MOCK_METHOD1(Bar,\nvector<int>*(int n));',
283            self.GenerateMethodSource(source))
284
285    def testReturnTypeWithManyTemplateArgs(self):
286        source = """
287class Foo {
288 public:
289  virtual map<int, string> Bar();
290};"""
291        # Comparing the comment text is brittle - we'll think of something
292        # better in case this gets annoying, but for now let's keep it simple.
293        self.assertEqualIgnoreLeadingWhitespace(
294            '// The following line won\'t really compile, as the return\n'
295            '// type has multiple template arguments.  To fix it, use a\n'
296            '// typedef for the return type.\n'
297            'MOCK_METHOD0(Bar,\nmap<int, string>());',
298            self.GenerateMethodSource(source))
299
300    def testSimpleMethodInTemplatedClass(self):
301        source = """
302template<class T>
303class Foo {
304 public:
305  virtual int Bar();
306};
307"""
308        self.assertEqualIgnoreLeadingWhitespace(
309            'MOCK_METHOD0_T(Bar,\nint());',
310            self.GenerateMethodSource(source))
311
312    def testPointerArgWithoutNames(self):
313        source = """
314class Foo {
315  virtual int Bar(C*);
316};
317"""
318        self.assertEqualIgnoreLeadingWhitespace(
319            'MOCK_METHOD1(Bar,\nint(C*));',
320            self.GenerateMethodSource(source))
321
322    def testReferenceArgWithoutNames(self):
323        source = """
324class Foo {
325  virtual int Bar(C&);
326};
327"""
328        self.assertEqualIgnoreLeadingWhitespace(
329            'MOCK_METHOD1(Bar,\nint(C&));',
330            self.GenerateMethodSource(source))
331
332    def testArrayArgWithoutNames(self):
333        source = """
334class Foo {
335  virtual int Bar(C[]);
336};
337"""
338        self.assertEqualIgnoreLeadingWhitespace(
339            'MOCK_METHOD1(Bar,\nint(C[]));',
340            self.GenerateMethodSource(source))
341
342
343class GenerateMocksTest(TestCase):
344
345    @staticmethod
346    def GenerateMocks(cpp_source):
347        """Convert C++ source to complete Google Mock output source."""
348        # <test> is a pseudo-filename, it is not read or written.
349        filename = '<test>'
350        builder = ast.BuilderFromSource(cpp_source, filename)
351        ast_list = list(builder.Generate())
352        lines = gmock_class._GenerateMocks(filename, cpp_source, ast_list, None)
353        return '\n'.join(lines)
354
355    def testNamespaces(self):
356        source = """
357namespace Foo {
358namespace Bar { class Forward; }
359namespace Baz {
360
361class Test {
362 public:
363  virtual void Foo();
364};
365
366}  // namespace Baz
367}  // namespace Foo
368"""
369        expected = """\
370namespace Foo {
371namespace Baz {
372
373class MockTest : public Test {
374public:
375MOCK_METHOD0(Foo,
376void());
377};
378
379}  // namespace Baz
380}  // namespace Foo
381"""
382        self.assertEqualIgnoreLeadingWhitespace(
383            expected, self.GenerateMocks(source))
384
385    def testClassWithStorageSpecifierMacro(self):
386        source = """
387class STORAGE_SPECIFIER Test {
388 public:
389  virtual void Foo();
390};
391"""
392        expected = """\
393class MockTest : public Test {
394public:
395MOCK_METHOD0(Foo,
396void());
397};
398"""
399        self.assertEqualIgnoreLeadingWhitespace(
400            expected, self.GenerateMocks(source))
401
402    def testTemplatedForwardDeclaration(self):
403        source = """
404template <class T> class Forward;  // Forward declaration should be ignored.
405class Test {
406 public:
407  virtual void Foo();
408};
409"""
410        expected = """\
411class MockTest : public Test {
412public:
413MOCK_METHOD0(Foo,
414void());
415};
416"""
417        self.assertEqualIgnoreLeadingWhitespace(
418            expected, self.GenerateMocks(source))
419
420    def testTemplatedClass(self):
421        source = """
422template <typename S, typename T>
423class Test {
424 public:
425  virtual void Foo();
426};
427"""
428        expected = """\
429template <typename T0, typename T1>
430class MockTest : public Test<T0, T1> {
431public:
432MOCK_METHOD0_T(Foo,
433void());
434};
435"""
436        self.assertEqualIgnoreLeadingWhitespace(
437            expected, self.GenerateMocks(source))
438
439    def testTemplateInATemplateTypedef(self):
440        source = """
441class Test {
442 public:
443  typedef std::vector<std::list<int>> FooType;
444  virtual void Bar(const FooType& test_arg);
445};
446"""
447        expected = """\
448class MockTest : public Test {
449public:
450MOCK_METHOD1(Bar,
451void(const FooType& test_arg));
452};
453"""
454        self.assertEqualIgnoreLeadingWhitespace(
455            expected, self.GenerateMocks(source))
456
457    def testTemplateInATemplateTypedefWithComma(self):
458        source = """
459class Test {
460 public:
461  typedef std::function<void(
462      const vector<std::list<int>>&, int> FooType;
463  virtual void Bar(const FooType& test_arg);
464};
465"""
466        expected = """\
467class MockTest : public Test {
468public:
469MOCK_METHOD1(Bar,
470void(const FooType& test_arg));
471};
472"""
473        self.assertEqualIgnoreLeadingWhitespace(
474            expected, self.GenerateMocks(source))
475
476    def testEnumType(self):
477        source = """
478class Test {
479 public:
480  enum Bar {
481    BAZ, QUX, QUUX, QUUUX
482  };
483  virtual void Foo();
484};
485"""
486        expected = """\
487class MockTest : public Test {
488public:
489MOCK_METHOD0(Foo,
490void());
491};
492"""
493        self.assertEqualIgnoreLeadingWhitespace(
494            expected, self.GenerateMocks(source))
495
496    def testEnumClassType(self):
497        source = """
498class Test {
499 public:
500  enum class Bar {
501    BAZ, QUX, QUUX, QUUUX
502  };
503  virtual void Foo();
504};
505"""
506        expected = """\
507class MockTest : public Test {
508public:
509MOCK_METHOD0(Foo,
510void());
511};
512"""
513        self.assertEqualIgnoreLeadingWhitespace(
514            expected, self.GenerateMocks(source))
515
516    def testStdFunction(self):
517        source = """
518class Test {
519 public:
520  Test(std::function<int(std::string)> foo) : foo_(foo) {}
521
522  virtual std::function<int(std::string)> foo();
523
524 private:
525  std::function<int(std::string)> foo_;
526};
527"""
528        expected = """\
529class MockTest : public Test {
530public:
531MOCK_METHOD0(foo,
532std::function<int (std::string)>());
533};
534"""
535        self.assertEqualIgnoreLeadingWhitespace(
536            expected, self.GenerateMocks(source))
537
538
539if __name__ == '__main__':
540    unittest.main()
541