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