#!/usr/bin/env python # # Copyright 2009 Neal Norwitz All Rights Reserved. # Portions Copyright 2009 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """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. sys.path.append(os.path.join(os.path.dirname(__file__), '..')) from cpp import ast from cpp import gmock_class class TestCase(unittest.TestCase): """Helper class that adds assert methods.""" @staticmethod def StripLeadingWhitespace(lines): """Strip leading whitespace in each line in 'lines'.""" return '\n'.join([s.lstrip() for s in lines.split('\n')]) def assertEqualIgnoreLeadingWhitespace(self, expected_lines, lines): """Specialized assert that ignores the indent level.""" self.assertEqual(expected_lines, self.StripLeadingWhitespace(lines)) class GenerateMethodsTest(TestCase): @staticmethod def GenerateMethodSource(cpp_source): """Convert C++ source to Google Mock output source lines.""" method_source_lines = [] # is a pseudo-filename, it is not read or written. builder = ast.BuilderFromSource(cpp_source, '') 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 = """ class Foo { public: virtual int Bar(); }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD0(Bar,\nint());', self.GenerateMethodSource(source)) def testSimpleConstructorsAndDestructor(self): source = """ class Foo { public: Foo(); Foo(int x); Foo(const Foo& f); Foo(Foo&& f); ~Foo(); virtual int Bar() = 0; }; """ # The constructors and destructor should be ignored. self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD0(Bar,\nint());', self.GenerateMethodSource(source)) def testVirtualDestructor(self): source = """ class Foo { public: virtual ~Foo(); virtual int Bar() = 0; }; """ # The destructor should be ignored. self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD0(Bar,\nint());', self.GenerateMethodSource(source)) def testExplicitlyDefaultedConstructorsAndDestructor(self): source = """ class Foo { public: Foo() = default; Foo(const Foo& f) = default; Foo(Foo&& f) = default; ~Foo() = default; virtual int Bar() = 0; }; """ # The constructors and destructor should be ignored. self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD0(Bar,\nint());', self.GenerateMethodSource(source)) def testExplicitlyDeletedConstructorsAndDestructor(self): source = """ class Foo { public: Foo() = delete; Foo(const Foo& f) = delete; Foo(Foo&& f) = delete; ~Foo() = delete; virtual int Bar() = 0; }; """ # The constructors and destructor should be ignored. self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD0(Bar,\nint());', self.GenerateMethodSource(source)) def testSimpleOverrideMethod(self): source = """ class Foo { public: int Bar() override; }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD0(Bar,\nint());', self.GenerateMethodSource(source)) def testSimpleConstMethod(self): source = """ class Foo { public: virtual void Bar(bool flag) const; }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_CONST_METHOD1(Bar,\nvoid(bool flag));', self.GenerateMethodSource(source)) def testExplicitVoid(self): source = """ class Foo { public: virtual int Bar(void); }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD0(Bar,\nint(void));', self.GenerateMethodSource(source)) def testStrangeNewlineInParameter(self): source = """ class Foo { public: virtual void Bar(int a) = 0; }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD1(Bar,\nvoid(int a));', self.GenerateMethodSource(source)) def testDefaultParameters(self): source = """ class Foo { public: virtual void Bar(int a, char c = 'x') = 0; }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD2(Bar,\nvoid(int a, char c ));', self.GenerateMethodSource(source)) def testMultipleDefaultParameters(self): source = """ class Foo { public: 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; }; """ expected = 'MOCK_METHOD1(Bar,\nbool(const std::string& test_arg ));' self.assertEqualIgnoreLeadingWhitespace( expected, self.GenerateMethodSource(source)) def testRemovesCommentsWhenDefaultsArePresent(self): source = """ class Foo { public: virtual void Bar(int a = 42 /* a comment */, char /* other comment */ c= 'x') = 0; }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD2(Bar,\nvoid(int a , char c));', self.GenerateMethodSource(source)) def testDoubleSlashCommentsInParameterListAreRemoved(self): source = """ class Foo { public: virtual void Bar(int a, // inline comments should be elided. int b // inline comments should be elided. ) const = 0; }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_CONST_METHOD2(Bar,\nvoid(int a, int b));', self.GenerateMethodSource(source)) 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 = """ class Foo { public: virtual const string& Bar(int /* keeper */, int b); }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD2(Bar,\nconst string&(int , int b));', self.GenerateMethodSource(source)) def testArgsOfTemplateTypes(self): source = """ class Foo { public: virtual int Bar(const vector& v, map* output); };""" self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD2(Bar,\n' 'int(const vector& v, map* output));', self.GenerateMethodSource(source)) def testReturnTypeWithOneTemplateArg(self): source = """ class Foo { public: virtual vector* Bar(int n); };""" self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD1(Bar,\nvector*(int n));', self.GenerateMethodSource(source)) def testReturnTypeWithManyTemplateArgs(self): source = """ class Foo { public: virtual map Bar(); };""" # 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());', self.GenerateMethodSource(source)) def testSimpleMethodInTemplatedClass(self): source = """ template class Foo { public: virtual int Bar(); }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD0_T(Bar,\nint());', self.GenerateMethodSource(source)) def testPointerArgWithoutNames(self): source = """ class Foo { virtual int Bar(C*); }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD1(Bar,\nint(C*));', self.GenerateMethodSource(source)) def testReferenceArgWithoutNames(self): source = """ class Foo { virtual int Bar(C&); }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD1(Bar,\nint(C&));', self.GenerateMethodSource(source)) def testArrayArgWithoutNames(self): source = """ class Foo { virtual int Bar(C[]); }; """ self.assertEqualIgnoreLeadingWhitespace( 'MOCK_METHOD1(Bar,\nint(C[]));', self.GenerateMethodSource(source)) class GenerateMocksTest(TestCase): @staticmethod def GenerateMocks(cpp_source): """Convert C++ source to complete Google Mock output source.""" # is a pseudo-filename, it is not read or written. filename = '' 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 = """ namespace Foo { namespace Bar { class Forward; } namespace Baz { class Test { public: virtual void Foo(); }; } // namespace Baz } // namespace Foo """ expected = """\ namespace Foo { namespace Baz { class MockTest : public Test { public: MOCK_METHOD0(Foo, void()); }; } // namespace Baz } // namespace Foo """ self.assertEqualIgnoreLeadingWhitespace( expected, self.GenerateMocks(source)) def testClassWithStorageSpecifierMacro(self): source = """ class STORAGE_SPECIFIER Test { public: virtual void Foo(); }; """ expected = """\ class MockTest : public Test { public: MOCK_METHOD0(Foo, void()); }; """ self.assertEqualIgnoreLeadingWhitespace( expected, self.GenerateMocks(source)) def testTemplatedForwardDeclaration(self): source = """ template class Forward; // Forward declaration should be ignored. class Test { public: virtual void Foo(); }; """ expected = """\ class MockTest : public Test { public: MOCK_METHOD0(Foo, void()); }; """ self.assertEqualIgnoreLeadingWhitespace( expected, self.GenerateMocks(source)) def testTemplatedClass(self): source = """ template class Test { public: virtual void Foo(); }; """ expected = """\ template class MockTest : public Test { public: MOCK_METHOD0_T(Foo, void()); }; """ self.assertEqualIgnoreLeadingWhitespace( expected, self.GenerateMocks(source)) def testTemplateInATemplateTypedef(self): source = """ class Test { public: typedef std::vector> FooType; virtual void Bar(const FooType& test_arg); }; """ expected = """\ class MockTest : public Test { public: MOCK_METHOD1(Bar, void(const FooType& test_arg)); }; """ self.assertEqualIgnoreLeadingWhitespace( expected, self.GenerateMocks(source)) def testTemplateInATemplateTypedefWithComma(self): source = """ class Test { public: typedef std::function>&, int> FooType; virtual void Bar(const FooType& test_arg); }; """ expected = """\ class MockTest : public Test { public: MOCK_METHOD1(Bar, void(const FooType& test_arg)); }; """ self.assertEqualIgnoreLeadingWhitespace( expected, self.GenerateMocks(source)) def testEnumType(self): source = """ class Test { public: enum Bar { BAZ, QUX, QUUX, QUUUX }; virtual void Foo(); }; """ expected = """\ class MockTest : public Test { public: MOCK_METHOD0(Foo, void()); }; """ self.assertEqualIgnoreLeadingWhitespace( expected, self.GenerateMocks(source)) def testEnumClassType(self): source = """ class Test { public: enum class Bar { BAZ, QUX, QUUX, QUUUX }; virtual void Foo(); }; """ expected = """\ class MockTest : public Test { public: MOCK_METHOD0(Foo, void()); }; """ self.assertEqualIgnoreLeadingWhitespace( expected, self.GenerateMocks(source)) def testStdFunction(self): source = """ class Test { public: Test(std::function foo) : foo_(foo) {} virtual std::function foo(); private: std::function foo_; }; """ expected = """\ class MockTest : public Test { public: MOCK_METHOD0(foo, std::function()); }; """ self.assertEqualIgnoreLeadingWhitespace( expected, self.GenerateMocks(source)) if __name__ == '__main__': unittest.main()