| #!/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.""" | |
| __author__ = 'nnorwitz@google.com (Neal Norwitz)' | |
| 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.""" | |
| def StripLeadingWhitespace(self, 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): | |
| def GenerateMethodSource(self, 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 = """ | |
| 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, char));', | |
| self.GenerateMethodSource(source)) | |
| def testMultipleDefaultParameters(self): | |
| source = """ | |
| class Foo { | |
| public: | |
| virtual void Bar(int a = 42, char c = 'x') = 0; | |
| }; | |
| """ | |
| self.assertEqualIgnoreLeadingWhitespace( | |
| 'MOCK_METHOD2(Bar,\nvoid(int, char));', | |
| 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, char));', | |
| 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 /* keeper */, int b));', | |
| self.GenerateMethodSource(source)) | |
| def testArgsOfTemplateTypes(self): | |
| source = """ | |
| class Foo { | |
| public: | |
| virtual int Bar(const vector<int>& v, map<int, string>* output); | |
| };""" | |
| self.assertEqualIgnoreLeadingWhitespace( | |
| 'MOCK_METHOD2(Bar,\n' | |
| 'int(const vector<int>& v, map<int, string>* output));', | |
| self.GenerateMethodSource(source)) | |
| def testReturnTypeWithOneTemplateArg(self): | |
| source = """ | |
| class Foo { | |
| public: | |
| virtual vector<int>* Bar(int n); | |
| };""" | |
| self.assertEqualIgnoreLeadingWhitespace( | |
| 'MOCK_METHOD1(Bar,\nvector<int>*(int n));', | |
| self.GenerateMethodSource(source)) | |
| def testReturnTypeWithManyTemplateArgs(self): | |
| source = """ | |
| class Foo { | |
| public: | |
| virtual map<int, string> 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<int, string>());', | |
| self.GenerateMethodSource(source)) | |
| def testSimpleMethodInTemplatedClass(self): | |
| source = """ | |
| template<class T> | |
| 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): | |
| def GenerateMocks(self, 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 = """ | |
| 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 T> 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 <typename S, typename T> | |
| class Test { | |
| public: | |
| virtual void Foo(); | |
| }; | |
| """ | |
| expected = """\ | |
| template <typename T0, typename T1> | |
| class MockTest : public Test<T0, T1> { | |
| public: | |
| MOCK_METHOD0_T(Foo, | |
| void()); | |
| }; | |
| """ | |
| self.assertEqualIgnoreLeadingWhitespace( | |
| expected, self.GenerateMocks(source)) | |
| def testTemplateInATemplateTypedef(self): | |
| source = """ | |
| class Test { | |
| public: | |
| typedef std::vector<std::list<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 testTemplateInATemplateTypedefWithComma(self): | |
| source = """ | |
| class Test { | |
| public: | |
| typedef std::function<void( | |
| const vector<std::list<int>>&, 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)) | |
| if __name__ == '__main__': | |
| unittest.main() |