gmock_class_test.py 14.6 KB
Newer Older
1
2
#!/usr/bin/env python
#
Abseil Team's avatar
Abseil Team committed
3
4
# Copyright 2009, Google Inc.
# All rights reserved.
5
#
Abseil Team's avatar
Abseil Team committed
6
7
8
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
9
#
Abseil Team's avatar
Abseil Team committed
10
11
12
13
14
15
16
17
18
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
19
#
Abseil Team's avatar
Abseil Team committed
20
21
22
23
24
25
26
27
28
29
30
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32
33
34
35
36
37
38

"""Tests for gmock.scripts.generator.cpp.gmock_class."""

import os
import sys
import unittest

# Allow the cpp imports below to work when run as a standalone script.
39
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
40
41
42
43
44
45

from cpp import ast
from cpp import gmock_class


class TestCase(unittest.TestCase):
mhermas's avatar
mhermas committed
46
    """Helper class that adds assert methods."""
47

mhermas's avatar
mhermas committed
48
49
50
51
    @staticmethod
    def StripLeadingWhitespace(lines):
        """Strip leading whitespace in each line in 'lines'."""
        return '\n'.join([s.lstrip() for s in lines.split('\n')])
52

mhermas's avatar
mhermas committed
53
54
55
    def assertEqualIgnoreLeadingWhitespace(self, expected_lines, lines):
        """Specialized assert that ignores the indent level."""
        self.assertEqual(expected_lines, self.StripLeadingWhitespace(lines))
56
57
58
59


class GenerateMethodsTest(TestCase):

mhermas's avatar
mhermas committed
60
61
62
63
64
65
66
67
68
69
70
71
    @staticmethod
    def GenerateMethodSource(cpp_source):
        """Convert C++ source to Google Mock output source lines."""
        method_source_lines = []
        # <test> is a pseudo-filename, it is not read or written.
        builder = ast.BuilderFromSource(cpp_source, '<test>')
        ast_list = list(builder.Generate())
        gmock_class._GenerateMethods(method_source_lines, cpp_source, ast_list[0])
        return '\n'.join(method_source_lines)

    def testSimpleMethod(self):
        source = """
72
73
74
75
class Foo {
 public:
  virtual int Bar();
};
76
"""
mhermas's avatar
mhermas committed
77
78
79
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD0(Bar,\nint());',
            self.GenerateMethodSource(source))
80

mhermas's avatar
mhermas committed
81
82
    def testSimpleConstructorsAndDestructor(self):
        source = """
83
84
85
86
87
88
89
90
91
92
class Foo {
 public:
  Foo();
  Foo(int x);
  Foo(const Foo& f);
  Foo(Foo&& f);
  ~Foo();
  virtual int Bar() = 0;
};
"""
mhermas's avatar
mhermas committed
93
94
95
96
        # The constructors and destructor should be ignored.
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD0(Bar,\nint());',
            self.GenerateMethodSource(source))
97

mhermas's avatar
mhermas committed
98
99
    def testVirtualDestructor(self):
        source = """
100
101
102
103
104
105
class Foo {
 public:
  virtual ~Foo();
  virtual int Bar() = 0;
};
"""
mhermas's avatar
mhermas committed
106
107
108
109
        # The destructor should be ignored.
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD0(Bar,\nint());',
            self.GenerateMethodSource(source))
110

mhermas's avatar
mhermas committed
111
112
    def testExplicitlyDefaultedConstructorsAndDestructor(self):
        source = """
113
114
115
116
117
118
119
120
121
class Foo {
 public:
  Foo() = default;
  Foo(const Foo& f) = default;
  Foo(Foo&& f) = default;
  ~Foo() = default;
  virtual int Bar() = 0;
};
"""
mhermas's avatar
mhermas committed
122
123
124
125
        # The constructors and destructor should be ignored.
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD0(Bar,\nint());',
            self.GenerateMethodSource(source))
126

mhermas's avatar
mhermas committed
127
128
    def testExplicitlyDeletedConstructorsAndDestructor(self):
        source = """
129
130
131
132
133
134
135
136
137
class Foo {
 public:
  Foo() = delete;
  Foo(const Foo& f) = delete;
  Foo(Foo&& f) = delete;
  ~Foo() = delete;
  virtual int Bar() = 0;
};
"""
mhermas's avatar
mhermas committed
138
139
140
141
        # The constructors and destructor should be ignored.
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD0(Bar,\nint());',
            self.GenerateMethodSource(source))
142

mhermas's avatar
mhermas committed
143
144
    def testSimpleOverrideMethod(self):
        source = """
145
146
147
148
class Foo {
 public:
  int Bar() override;
};
149
"""
mhermas's avatar
mhermas committed
150
151
152
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD0(Bar,\nint());',
            self.GenerateMethodSource(source))
153

mhermas's avatar
mhermas committed
154
155
    def testSimpleConstMethod(self):
        source = """
156
157
158
159
160
class Foo {
 public:
  virtual void Bar(bool flag) const;
};
"""
mhermas's avatar
mhermas committed
161
162
163
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_CONST_METHOD1(Bar,\nvoid(bool flag));',
            self.GenerateMethodSource(source))
164

mhermas's avatar
mhermas committed
165
166
    def testExplicitVoid(self):
        source = """
vladlosev's avatar
vladlosev committed
167
168
169
170
171
class Foo {
 public:
  virtual int Bar(void);
};
"""
mhermas's avatar
mhermas committed
172
173
174
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD0(Bar,\nint(void));',
            self.GenerateMethodSource(source))
vladlosev's avatar
vladlosev committed
175

mhermas's avatar
mhermas committed
176
177
    def testStrangeNewlineInParameter(self):
        source = """
178
179
180
181
182
183
class Foo {
 public:
  virtual void Bar(int
a) = 0;
};
"""
mhermas's avatar
mhermas committed
184
185
186
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD1(Bar,\nvoid(int a));',
            self.GenerateMethodSource(source))
187

mhermas's avatar
mhermas committed
188
189
    def testDefaultParameters(self):
        source = """
vladlosev's avatar
vladlosev committed
190
191
192
193
194
class Foo {
 public:
  virtual void Bar(int a, char c = 'x') = 0;
};
"""
mhermas's avatar
mhermas committed
195
196
197
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD2(Bar,\nvoid(int a, char c ));',
            self.GenerateMethodSource(source))
vladlosev's avatar
vladlosev committed
198

mhermas's avatar
mhermas committed
199
200
    def testMultipleDefaultParameters(self):
        source = """
vladlosev's avatar
vladlosev committed
201
202
class Foo {
 public:
mhermas's avatar
mhermas committed
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  virtual void Bar(
        int a = 42, 
        char c = 'x', 
        const int* const p = nullptr, 
        const std::string& s = "42",
        char tab[] = {'4','2'},
        int const *& rp = aDefaultPointer) = 0;
};
"""
        self.assertEqualIgnoreLeadingWhitespace(
            "MOCK_METHOD7(Bar,\n"
            "void(int a , char c , const int* const p , const std::string& s , char tab[] , int const *& rp ));",
            self.GenerateMethodSource(source))

    def testConstDefaultParameter(self):
        source = """
class Test {
 public:
  virtual bool Bar(const int test_arg = 42) = 0;
};
"""
        expected = 'MOCK_METHOD1(Bar,\nbool(const int test_arg ));'
        self.assertEqualIgnoreLeadingWhitespace(
            expected, self.GenerateMethodSource(source))

    def testConstRefDefaultParameter(self):
        source = """
class Test {
 public:
  virtual bool Bar(const std::string& test_arg = "42" ) = 0;
vladlosev's avatar
vladlosev committed
233
234
};
"""
mhermas's avatar
mhermas committed
235
236
237
        expected = 'MOCK_METHOD1(Bar,\nbool(const std::string& test_arg ));'
        self.assertEqualIgnoreLeadingWhitespace(
            expected, self.GenerateMethodSource(source))
vladlosev's avatar
vladlosev committed
238

mhermas's avatar
mhermas committed
239
240
    def testRemovesCommentsWhenDefaultsArePresent(self):
        source = """
vladlosev's avatar
vladlosev committed
241
242
243
244
245
246
class Foo {
 public:
  virtual void Bar(int a = 42 /* a comment */,
                   char /* other comment */ c= 'x') = 0;
};
"""
mhermas's avatar
mhermas committed
247
248
249
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD2(Bar,\nvoid(int a , char c));',
            self.GenerateMethodSource(source))
vladlosev's avatar
vladlosev committed
250

mhermas's avatar
mhermas committed
251
252
    def testDoubleSlashCommentsInParameterListAreRemoved(self):
        source = """
253
254
255
256
257
258
259
class Foo {
 public:
  virtual void Bar(int a,  // inline comments should be elided.
                   int b   // inline comments should be elided.
                   ) const = 0;
};
"""
mhermas's avatar
mhermas committed
260
261
262
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_CONST_METHOD2(Bar,\nvoid(int a, int b));',
            self.GenerateMethodSource(source))
263

mhermas's avatar
mhermas committed
264
265
266
267
268
    def testCStyleCommentsInParameterListAreNotRemoved(self):
        # NOTE(nnorwitz): I'm not sure if it's the best behavior to keep these
        # comments.  Also note that C style comments after the last parameter
        # are still elided.
        source = """
269
270
271
272
273
class Foo {
 public:
  virtual const string& Bar(int /* keeper */, int b);
};
"""
mhermas's avatar
mhermas committed
274
275
276
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD2(Bar,\nconst string&(int , int b));',
            self.GenerateMethodSource(source))
277

mhermas's avatar
mhermas committed
278
279
    def testArgsOfTemplateTypes(self):
        source = """
280
281
282
283
class Foo {
 public:
  virtual int Bar(const vector<int>& v, map<int, string>* output);
};"""
mhermas's avatar
mhermas committed
284
285
286
287
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD2(Bar,\n'
            'int(const vector<int>& v, map<int, string>* output));',
            self.GenerateMethodSource(source))
288

mhermas's avatar
mhermas committed
289
290
    def testReturnTypeWithOneTemplateArg(self):
        source = """
291
292
293
294
class Foo {
 public:
  virtual vector<int>* Bar(int n);
};"""
mhermas's avatar
mhermas committed
295
296
297
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD1(Bar,\nvector<int>*(int n));',
            self.GenerateMethodSource(source))
298

mhermas's avatar
mhermas committed
299
300
    def testReturnTypeWithManyTemplateArgs(self):
        source = """
301
302
303
304
class Foo {
 public:
  virtual map<int, string> Bar();
};"""
mhermas's avatar
mhermas committed
305
306
307
308
309
310
311
312
313
314
315
        # Comparing the comment text is brittle - we'll think of something
        # better in case this gets annoying, but for now let's keep it simple.
        self.assertEqualIgnoreLeadingWhitespace(
            '// The following line won\'t really compile, as the return\n'
            '// type has multiple template arguments.  To fix it, use a\n'
            '// typedef for the return type.\n'
            'MOCK_METHOD0(Bar,\nmap<int, string>());',
            self.GenerateMethodSource(source))

    def testSimpleMethodInTemplatedClass(self):
        source = """
316
317
318
319
320
321
template<class T>
class Foo {
 public:
  virtual int Bar();
};
"""
mhermas's avatar
mhermas committed
322
323
324
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD0_T(Bar,\nint());',
            self.GenerateMethodSource(source))
325

mhermas's avatar
mhermas committed
326
327
    def testPointerArgWithoutNames(self):
        source = """
328
329
330
331
class Foo {
  virtual int Bar(C*);
};
"""
mhermas's avatar
mhermas committed
332
333
334
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD1(Bar,\nint(C*));',
            self.GenerateMethodSource(source))
335

mhermas's avatar
mhermas committed
336
337
    def testReferenceArgWithoutNames(self):
        source = """
338
339
340
341
class Foo {
  virtual int Bar(C&);
};
"""
mhermas's avatar
mhermas committed
342
343
344
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD1(Bar,\nint(C&));',
            self.GenerateMethodSource(source))
345

mhermas's avatar
mhermas committed
346
347
    def testArrayArgWithoutNames(self):
        source = """
348
349
350
351
class Foo {
  virtual int Bar(C[]);
};
"""
mhermas's avatar
mhermas committed
352
353
354
        self.assertEqualIgnoreLeadingWhitespace(
            'MOCK_METHOD1(Bar,\nint(C[]));',
            self.GenerateMethodSource(source))
355

356
357
358

class GenerateMocksTest(TestCase):

mhermas's avatar
mhermas committed
359
360
361
362
363
364
365
366
367
368
369
370
    @staticmethod
    def GenerateMocks(cpp_source):
        """Convert C++ source to complete Google Mock output source."""
        # <test> is a pseudo-filename, it is not read or written.
        filename = '<test>'
        builder = ast.BuilderFromSource(cpp_source, filename)
        ast_list = list(builder.Generate())
        lines = gmock_class._GenerateMocks(filename, cpp_source, ast_list, None)
        return '\n'.join(lines)

    def testNamespaces(self):
        source = """
371
372
373
374
375
376
377
378
379
380
381
382
namespace Foo {
namespace Bar { class Forward; }
namespace Baz {

class Test {
 public:
  virtual void Foo();
};

}  // namespace Baz
}  // namespace Foo
"""
mhermas's avatar
mhermas committed
383
        expected = """\
384
385
386
387
388
389
390
391
392
393
394
395
namespace Foo {
namespace Baz {

class MockTest : public Test {
public:
MOCK_METHOD0(Foo,
void());
};

}  // namespace Baz
}  // namespace Foo
"""
mhermas's avatar
mhermas committed
396
397
        self.assertEqualIgnoreLeadingWhitespace(
            expected, self.GenerateMocks(source))
398

mhermas's avatar
mhermas committed
399
400
    def testClassWithStorageSpecifierMacro(self):
        source = """
401
402
403
404
405
class STORAGE_SPECIFIER Test {
 public:
  virtual void Foo();
};
"""
mhermas's avatar
mhermas committed
406
        expected = """\
407
408
409
410
411
412
class MockTest : public Test {
public:
MOCK_METHOD0(Foo,
void());
};
"""
mhermas's avatar
mhermas committed
413
414
        self.assertEqualIgnoreLeadingWhitespace(
            expected, self.GenerateMocks(source))
415

mhermas's avatar
mhermas committed
416
417
    def testTemplatedForwardDeclaration(self):
        source = """
418
419
420
421
422
423
template <class T> class Forward;  // Forward declaration should be ignored.
class Test {
 public:
  virtual void Foo();
};
"""
mhermas's avatar
mhermas committed
424
        expected = """\
425
426
427
428
429
430
class MockTest : public Test {
public:
MOCK_METHOD0(Foo,
void());
};
"""
mhermas's avatar
mhermas committed
431
432
        self.assertEqualIgnoreLeadingWhitespace(
            expected, self.GenerateMocks(source))
433

mhermas's avatar
mhermas committed
434
435
    def testTemplatedClass(self):
        source = """
436
437
438
439
440
441
template <typename S, typename T>
class Test {
 public:
  virtual void Foo();
};
"""
mhermas's avatar
mhermas committed
442
        expected = """\
443
444
445
446
447
448
449
template <typename T0, typename T1>
class MockTest : public Test<T0, T1> {
public:
MOCK_METHOD0_T(Foo,
void());
};
"""
mhermas's avatar
mhermas committed
450
451
        self.assertEqualIgnoreLeadingWhitespace(
            expected, self.GenerateMocks(source))
452

mhermas's avatar
mhermas committed
453
454
    def testTemplateInATemplateTypedef(self):
        source = """
455
456
457
458
459
460
class Test {
 public:
  typedef std::vector<std::list<int>> FooType;
  virtual void Bar(const FooType& test_arg);
};
"""
mhermas's avatar
mhermas committed
461
        expected = """\
462
463
464
465
466
467
class MockTest : public Test {
public:
MOCK_METHOD1(Bar,
void(const FooType& test_arg));
};
"""
mhermas's avatar
mhermas committed
468
469
        self.assertEqualIgnoreLeadingWhitespace(
            expected, self.GenerateMocks(source))
470

mhermas's avatar
mhermas committed
471
472
    def testTemplateInATemplateTypedefWithComma(self):
        source = """
473
474
475
476
477
478
479
class Test {
 public:
  typedef std::function<void(
      const vector<std::list<int>>&, int> FooType;
  virtual void Bar(const FooType& test_arg);
};
"""
mhermas's avatar
mhermas committed
480
        expected = """\
481
482
483
484
485
class MockTest : public Test {
public:
MOCK_METHOD1(Bar,
void(const FooType& test_arg));
};
486
"""
mhermas's avatar
mhermas committed
487
488
        self.assertEqualIgnoreLeadingWhitespace(
            expected, self.GenerateMocks(source))
489

mhermas's avatar
mhermas committed
490
491
    def testEnumType(self):
        source = """
492
493
class Test {
 public:
Abseil Team's avatar
Abseil Team committed
494
495
496
497
  enum Bar {
    BAZ, QUX, QUUX, QUUUX
  };
  virtual void Foo();
498
499
};
"""
mhermas's avatar
mhermas committed
500
        expected = """\
501
502
class MockTest : public Test {
public:
Abseil Team's avatar
Abseil Team committed
503
504
505
506
MOCK_METHOD0(Foo,
void());
};
"""
mhermas's avatar
mhermas committed
507
508
        self.assertEqualIgnoreLeadingWhitespace(
            expected, self.GenerateMocks(source))
Abseil Team's avatar
Abseil Team committed
509

mhermas's avatar
mhermas committed
510
511
    def testEnumClassType(self):
        source = """
Abseil Team's avatar
Abseil Team committed
512
513
514
515
516
517
518
519
class Test {
 public:
  enum class Bar {
    BAZ, QUX, QUUX, QUUUX
  };
  virtual void Foo();
};
"""
mhermas's avatar
mhermas committed
520
        expected = """\
Abseil Team's avatar
Abseil Team committed
521
522
523
524
525
526
class MockTest : public Test {
public:
MOCK_METHOD0(Foo,
void());
};
"""
mhermas's avatar
mhermas committed
527
528
        self.assertEqualIgnoreLeadingWhitespace(
            expected, self.GenerateMocks(source))
Abseil Team's avatar
Abseil Team committed
529

mhermas's avatar
mhermas committed
530
531
    def testStdFunction(self):
        source = """
Abseil Team's avatar
Abseil Team committed
532
533
534
535
536
537
538
539
540
541
class Test {
 public:
  Test(std::function<int(std::string)> foo) : foo_(foo) {}

  virtual std::function<int(std::string)> foo();

 private:
  std::function<int(std::string)> foo_;
};
"""
mhermas's avatar
mhermas committed
542
        expected = """\
Abseil Team's avatar
Abseil Team committed
543
544
545
546
class MockTest : public Test {
public:
MOCK_METHOD0(foo,
std::function<int (std::string)>());
547
};
548
"""
mhermas's avatar
mhermas committed
549
550
551
        self.assertEqualIgnoreLeadingWhitespace(
            expected, self.GenerateMocks(source))

552

553
if __name__ == '__main__':
mhermas's avatar
mhermas committed
554
    unittest.main()