diff options
-rwxr-xr-x | googlemock/scripts/generator/cpp/gmock_class.py | 348 | ||||
-rwxr-xr-x | googlemock/scripts/generator/cpp/gmock_class_test.py | 429 |
2 files changed, 406 insertions, 371 deletions
diff --git a/googlemock/scripts/generator/cpp/gmock_class.py b/googlemock/scripts/generator/cpp/gmock_class.py index 85a3e61..89862ae 100755 --- a/googlemock/scripts/generator/cpp/gmock_class.py +++ b/googlemock/scripts/generator/cpp/gmock_class.py @@ -35,11 +35,11 @@ from cpp import utils # Preserve compatibility with Python 2.3. try: - _dummy = set + _dummy = set except NameError: - import sets + import sets - set = sets.Set + set = sets.Set _VERSION = (1, 0, 1) # The version of this script. # How many spaces to indent. Can set me with the INDENT environment variable. @@ -47,182 +47,202 @@ _INDENT = 2 def _RenderType(ast_type): - """Renders the potentially recursively templated type into a string. + """Renders the potentially recursively templated type into a string. Args: ast_type: The AST of the type. Returns: - Rendered string of the type + Rendered string and a boolean to indicate whether we have multiple args + (which is not handled correctly). """ - # Add modifiers like 'const'. - modifiers = '' - if ast_type.modifiers: - modifiers = ' '.join(ast_type.modifiers) + ' ' - return_type = modifiers + ast_type.name - if ast_type.templated_types: - # Collect template args. - template_args = [] - for arg in ast_type.templated_types: - rendered_arg = _RenderType(arg) - template_args.append(rendered_arg) - return_type += '<' + ', '.join(template_args) + '>' - if ast_type.pointer: - return_type += '*' - if ast_type.reference: - return_type += '&' - return return_type + has_multiarg_error = False + # Add modifiers like 'const'. + modifiers = '' + if ast_type.modifiers: + modifiers = ' '.join(ast_type.modifiers) + ' ' + return_type = modifiers + ast_type.name + if ast_type.templated_types: + # Collect template args. + template_args = [] + for arg in ast_type.templated_types: + rendered_arg, e = _RenderType(arg) + if e: has_multiarg_error = True + template_args.append(rendered_arg) + return_type += '<' + ', '.join(template_args) + '>' + # We are actually not handling multi-template-args correctly. So mark it. + if len(template_args) > 1: + has_multiarg_error = True + if ast_type.pointer: + return_type += '*' + if ast_type.reference: + return_type += '&' + return return_type, has_multiarg_error + + +def _GetNumParameters(parameters, source): + num_parameters = len(parameters) + if num_parameters == 1: + first_param = parameters[0] + if source[first_param.start:first_param.end].strip() == 'void': + # We must treat T(void) as a function with no parameters. + return 0 + return num_parameters def _GenerateMethods(output_lines, source, class_node): - function_type = ( - ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL | ast.FUNCTION_OVERRIDE) - ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR - indent = ' ' * _INDENT - - for node in class_node.body: - # We only care about virtual functions. - if (isinstance(node, ast.Function) and node.modifiers & function_type and - not node.modifiers & ctor_or_dtor): - # Pick out all the elements we need from the original function. - modifiers = 'override' - if node.modifiers & ast.FUNCTION_CONST: - modifiers = 'const, ' + modifiers - - return_type = 'void' - if node.return_type: - return_type = _RenderType(node.return_type) - # commas mess with macros, so nest it in parens if it has one - if ',' in return_type: - return_type = '(' + return_type + ')' - - args = '' - if node.parameters: - # Get the full text of the parameters from the start - # of the first parameter to the end of the last parameter. - start = node.parameters[0].start - end = node.parameters[-1].end - # Remove // comments. - args_strings = re.sub(r'//.*', '', source[start:end]) - # Remove /* comments */. - args_strings = re.sub(r'/\*.*\*/', '', args_strings) - # Remove default arguments. - args_strings = re.sub(r'=.*,', ',', args_strings) - args_strings = re.sub(r'=.*', '', args_strings) - # Condense multiple spaces and eliminate newlines putting the - # parameters together on a single line. Ensure there is a - # space in an argument which is split by a newline without - # intervening whitespace, e.g.: int\nBar - args_strings = re.sub(' +', ' ', args_strings.replace('\n', ' ')) - # Remove spaces from the begining, end, and before commas - args = re.sub(' ,', ',', args_strings).strip() - - # Create the mock method definition. - output_lines.extend([ - '%sMOCK_METHOD(%s, %s, (%s), (%s));' % - (indent, return_type, node.name, args, modifiers) - ]) + function_type = (ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL | + ast.FUNCTION_OVERRIDE) + ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR + indent = ' ' * _INDENT + + for node in class_node.body: + # We only care about virtual functions. + if (isinstance(node, ast.Function) and + node.modifiers & function_type and + not node.modifiers & ctor_or_dtor): + # Pick out all the elements we need from the original function. + const = '' + if node.modifiers & ast.FUNCTION_CONST: + const = 'CONST_' + num_parameters = _GetNumParameters(node.parameters, source) + return_type = 'void' + if node.return_type: + return_type, has_multiarg_error = _RenderType(node.return_type) + if has_multiarg_error: + for line in [ + '// The following line won\'t really compile, as the return', + '// type has multiple template arguments. To fix it, use a', + '// typedef for the return type.']: + output_lines.append(indent + line) + tmpl = '' + if class_node.templated_types: + tmpl = '_T' + mock_method_macro = 'MOCK_%sMETHOD%d%s' % (const, num_parameters, tmpl) + + args = '' + if node.parameters: + # Get the full text of the parameters from the start + # of the first parameter to the end of the last parameter. + start = node.parameters[0].start + end = node.parameters[-1].end + # Remove // comments. + args_strings = re.sub(r'//.*', '', source[start:end]) + # Remove /* comments */. + args_strings = re.sub(r'/\*.*\*/', '', args_strings) + # Remove default arguments. + args_strings = re.sub(r'=.*,', ',', args_strings) + args_strings = re.sub(r'=.*', '', args_strings) + # Condense multiple spaces and eliminate newlines putting the + # parameters together on a single line. Ensure there is a + # space in an argument which is split by a newline without + # intervening whitespace, e.g.: int\nBar + args = re.sub(' +', ' ', args_strings.replace('\n', ' ')) + + # Create the mock method definition. + output_lines.extend(['%s%s(%s,' % (indent, mock_method_macro, node.name), + '%s%s(%s));' % (indent * 3, return_type, args)]) def _GenerateMocks(filename, source, ast_list, desired_class_names): - processed_class_names = set() - lines = [] - for node in ast_list: - if (isinstance(node, ast.Class) and node.body and - # desired_class_names being None means that all classes are selected. - (not desired_class_names or node.name in desired_class_names)): - class_name = node.name - parent_name = class_name - processed_class_names.add(class_name) - class_node = node - # Add namespace before the class. - if class_node.namespace: - lines.extend(['namespace %s {' % n for n in class_node.namespace]) # } - lines.append('') - - # Add template args for templated classes. - if class_node.templated_types: - # TODO(paulchang): The AST doesn't preserve template argument order, - # so we have to make up names here. - # TODO(paulchang): Handle non-type template arguments (e.g. - # template<typename T, int N>). - template_arg_count = len(class_node.templated_types.keys()) - template_args = ['T%d' % n for n in range(template_arg_count)] - template_decls = ['typename ' + arg for arg in template_args] - lines.append('template <' + ', '.join(template_decls) + '>') - parent_name += '<' + ', '.join(template_args) + '>' - - # Add the class prolog. - lines.append('class Mock%s : public %s {' # } - % (class_name, parent_name)) - lines.append('%spublic:' % (' ' * (_INDENT // 2))) - - # Add all the methods. - _GenerateMethods(lines, source, class_node) - - # Close the class. - if lines: - # If there are no virtual methods, no need for a public label. - if len(lines) == 2: - del lines[-1] - - # Only close the class if there really is a class. - lines.append('};') - lines.append('') # Add an extra newline. - - # Close the namespace. - if class_node.namespace: - for i in range(len(class_node.namespace) - 1, -1, -1): - lines.append('} // namespace %s' % class_node.namespace[i]) - lines.append('') # Add an extra newline. - - if desired_class_names: - missing_class_name_list = list(desired_class_names - processed_class_names) - if missing_class_name_list: - missing_class_name_list.sort() - sys.stderr.write('Class(es) not found in %s: %s\n' % - (filename, ', '.join(missing_class_name_list))) - elif not processed_class_names: - sys.stderr.write('No class found in %s\n' % filename) - - return lines + processed_class_names = set() + lines = [] + for node in ast_list: + if (isinstance(node, ast.Class) and node.body and + # desired_class_names being None means that all classes are selected. + (not desired_class_names or node.name in desired_class_names)): + class_name = node.name + parent_name = class_name + processed_class_names.add(class_name) + class_node = node + # Add namespace before the class. + if class_node.namespace: + lines.extend(['namespace %s {' % n for n in class_node.namespace]) # } + lines.append('') + + # Add template args for templated classes. + if class_node.templated_types: + # TODO(paulchang): The AST doesn't preserve template argument order, + # so we have to make up names here. + # TODO(paulchang): Handle non-type template arguments (e.g. + # template<typename T, int N>). + template_arg_count = len(class_node.templated_types.keys()) + template_args = ['T%d' % n for n in range(template_arg_count)] + template_decls = ['typename ' + arg for arg in template_args] + lines.append('template <' + ', '.join(template_decls) + '>') + parent_name += '<' + ', '.join(template_args) + '>' + + # Add the class prolog. + lines.append('class Mock%s : public %s {' # } + % (class_name, parent_name)) + lines.append('%spublic:' % (' ' * (_INDENT // 2))) + + # Add all the methods. + _GenerateMethods(lines, source, class_node) + + # Close the class. + if lines: + # If there are no virtual methods, no need for a public label. + if len(lines) == 2: + del lines[-1] + + # Only close the class if there really is a class. + lines.append('};') + lines.append('') # Add an extra newline. + + # Close the namespace. + if class_node.namespace: + for i in range(len(class_node.namespace) - 1, -1, -1): + lines.append('} // namespace %s' % class_node.namespace[i]) + lines.append('') # Add an extra newline. + + if desired_class_names: + missing_class_name_list = list(desired_class_names - processed_class_names) + if missing_class_name_list: + missing_class_name_list.sort() + sys.stderr.write('Class(es) not found in %s: %s\n' % + (filename, ', '.join(missing_class_name_list))) + elif not processed_class_names: + sys.stderr.write('No class found in %s\n' % filename) + + return lines def main(argv=sys.argv): - if len(argv) < 2: - sys.stderr.write('Google Mock Class Generator v%s\n\n' % - '.'.join(map(str, _VERSION))) - sys.stderr.write(__doc__) - return 1 - - global _INDENT - try: - _INDENT = int(os.environ['INDENT']) - except KeyError: - pass - except: - sys.stderr.write('Unable to use indent of %s\n' % os.environ.get('INDENT')) - - filename = argv[1] - desired_class_names = None # None means all classes in the source file. - if len(argv) >= 3: - desired_class_names = set(argv[2:]) - source = utils.ReadFile(filename) - if source is None: - return 1 - - builder = ast.BuilderFromSource(source, filename) - try: - entire_ast = filter(None, builder.Generate()) - except KeyboardInterrupt: - return - except: - # An error message was already printed since we couldn't parse. - sys.exit(1) - else: - lines = _GenerateMocks(filename, source, entire_ast, desired_class_names) - sys.stdout.write('\n'.join(lines)) + if len(argv) < 2: + sys.stderr.write('Google Mock Class Generator v%s\n\n' % + '.'.join(map(str, _VERSION))) + sys.stderr.write(__doc__) + return 1 + + global _INDENT + try: + _INDENT = int(os.environ['INDENT']) + except KeyError: + pass + except: + sys.stderr.write('Unable to use indent of %s\n' % os.environ.get('INDENT')) + + filename = argv[1] + desired_class_names = None # None means all classes in the source file. + if len(argv) >= 3: + desired_class_names = set(argv[2:]) + source = utils.ReadFile(filename) + if source is None: + return 1 + + builder = ast.BuilderFromSource(source, filename) + try: + entire_ast = filter(None, builder.Generate()) + except KeyboardInterrupt: + return + except: + # An error message was already printed since we couldn't parse. + sys.exit(1) + else: + lines = _GenerateMocks(filename, source, entire_ast, desired_class_names) + sys.stdout.write('\n'.join(lines)) if __name__ == '__main__': - main(sys.argv) + main(sys.argv) diff --git a/googlemock/scripts/generator/cpp/gmock_class_test.py b/googlemock/scripts/generator/cpp/gmock_class_test.py index 4e18a85..211a92d 100755 --- a/googlemock/scripts/generator/cpp/gmock_class_test.py +++ b/googlemock/scripts/generator/cpp/gmock_class_test.py @@ -29,43 +29,43 @@ from cpp import gmock_class class TestCase(unittest.TestCase): - """Helper class that adds assert methods.""" + """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')]) + @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)) + 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 = [] - # <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 = """ + @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 = """ class Foo { public: virtual int Bar(); }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(int, Bar, (), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD0(Bar,\nint());', + self.GenerateMethodSource(source)) - def testSimpleConstructorsAndDestructor(self): - source = """ + def testSimpleConstructorsAndDestructor(self): + source = """ class Foo { public: Foo(); @@ -76,26 +76,26 @@ class Foo { virtual int Bar() = 0; }; """ - # The constructors and destructor should be ignored. - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(int, Bar, (), (override));', - self.GenerateMethodSource(source)) + # The constructors and destructor should be ignored. + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD0(Bar,\nint());', + self.GenerateMethodSource(source)) - def testVirtualDestructor(self): - source = """ + def testVirtualDestructor(self): + source = """ class Foo { public: virtual ~Foo(); virtual int Bar() = 0; }; """ - # The destructor should be ignored. - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(int, Bar, (), (override));', - self.GenerateMethodSource(source)) + # The destructor should be ignored. + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD0(Bar,\nint());', + self.GenerateMethodSource(source)) - def testExplicitlyDefaultedConstructorsAndDestructor(self): - source = """ + def testExplicitlyDefaultedConstructorsAndDestructor(self): + source = """ class Foo { public: Foo() = default; @@ -105,13 +105,13 @@ class Foo { virtual int Bar() = 0; }; """ - # The constructors and destructor should be ignored. - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(int, Bar, (), (override));', - self.GenerateMethodSource(source)) + # The constructors and destructor should be ignored. + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD0(Bar,\nint());', + self.GenerateMethodSource(source)) - def testExplicitlyDeletedConstructorsAndDestructor(self): - source = """ + def testExplicitlyDeletedConstructorsAndDestructor(self): + source = """ class Foo { public: Foo() = delete; @@ -121,69 +121,69 @@ class Foo { virtual int Bar() = 0; }; """ - # The constructors and destructor should be ignored. - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(int, Bar, (), (override));', - self.GenerateMethodSource(source)) + # The constructors and destructor should be ignored. + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD0(Bar,\nint());', + self.GenerateMethodSource(source)) - def testSimpleOverrideMethod(self): - source = """ + def testSimpleOverrideMethod(self): + source = """ class Foo { public: int Bar() override; }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(int, Bar, (), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD0(Bar,\nint());', + self.GenerateMethodSource(source)) - def testSimpleConstMethod(self): - source = """ + def testSimpleConstMethod(self): + source = """ class Foo { public: virtual void Bar(bool flag) const; }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(void, Bar, (bool flag), (const, override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_CONST_METHOD1(Bar,\nvoid(bool flag));', + self.GenerateMethodSource(source)) - def testExplicitVoid(self): - source = """ + def testExplicitVoid(self): + source = """ class Foo { public: virtual int Bar(void); }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(int, Bar, (void), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD0(Bar,\nint(void));', + self.GenerateMethodSource(source)) - def testStrangeNewlineInParameter(self): - source = """ + def testStrangeNewlineInParameter(self): + source = """ class Foo { public: virtual void Bar(int a) = 0; }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(void, Bar, (int a), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD1(Bar,\nvoid(int a));', + self.GenerateMethodSource(source)) - def testDefaultParameters(self): - source = """ + def testDefaultParameters(self): + source = """ class Foo { public: virtual void Bar(int a, char c = 'x') = 0; }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(void, Bar, (int a, char c), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD2(Bar,\nvoid(int a, char c ));', + self.GenerateMethodSource(source)) - def testMultipleDefaultParameters(self): - source = """ + def testMultipleDefaultParameters(self): + source = """ class Foo { public: virtual void Bar( @@ -195,47 +195,47 @@ class Foo { int const *& rp = aDefaultPointer) = 0; }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(void, Bar, ' - '(int a, char c, const int* const p, const std::string& s, char tab[], int const *& rp), ' - '(override));', self.GenerateMethodSource(source)) + 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 = """ + def testConstDefaultParameter(self): + source = """ class Test { public: virtual bool Bar(const int test_arg = 42) = 0; }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(bool, Bar, (const int test_arg), (override));', - self.GenerateMethodSource(source)) + expected = 'MOCK_METHOD1(Bar,\nbool(const int test_arg ));' + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMethodSource(source)) - def testConstRefDefaultParameter(self): - source = """ + def testConstRefDefaultParameter(self): + source = """ class Test { public: virtual bool Bar(const std::string& test_arg = "42" ) = 0; }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(bool, Bar, (const std::string& test_arg), (override));', - self.GenerateMethodSource(source)) + expected = 'MOCK_METHOD1(Bar,\nbool(const std::string& test_arg ));' + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMethodSource(source)) - def testRemovesCommentsWhenDefaultsArePresent(self): - 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_METHOD(void, Bar, (int a, char c), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD2(Bar,\nvoid(int a , char c));', + self.GenerateMethodSource(source)) - def testDoubleSlashCommentsInParameterListAreRemoved(self): - source = """ + def testDoubleSlashCommentsInParameterListAreRemoved(self): + source = """ class Foo { public: virtual void Bar(int a, // inline comments should be elided. @@ -243,111 +243,117 @@ class Foo { ) const = 0; }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(void, Bar, (int a, int b), (const, override));', - self.GenerateMethodSource(source)) + 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 = """ + 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_METHOD(const string&, Bar, (int, int b), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD2(Bar,\nconst string&(int , int b));', + self.GenerateMethodSource(source)) - def testArgsOfTemplateTypes(self): - source = """ + def testArgsOfTemplateTypes(self): + source = """ class Foo { public: virtual int Bar(const vector<int>& v, map<int, string>* output); };""" - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(int, Bar, (const vector<int>& v, map<int, string>* output), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD2(Bar,\n' + 'int(const vector<int>& v, map<int, string>* output));', + self.GenerateMethodSource(source)) - def testReturnTypeWithOneTemplateArg(self): - source = """ + def testReturnTypeWithOneTemplateArg(self): + source = """ class Foo { public: virtual vector<int>* Bar(int n); };""" - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(vector<int>*, Bar, (int n), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD1(Bar,\nvector<int>*(int n));', + self.GenerateMethodSource(source)) - def testReturnTypeWithManyTemplateArgs(self): - source = """ + def testReturnTypeWithManyTemplateArgs(self): + source = """ class Foo { public: virtual map<int, string> Bar(); };""" - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD((map<int, string>), Bar, (), (override));', - self.GenerateMethodSource(source)) - - def testSimpleMethodInTemplatedClass(self): - source = """ + # 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_METHOD(int, Bar, (), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD0_T(Bar,\nint());', + self.GenerateMethodSource(source)) - def testPointerArgWithoutNames(self): - source = """ + def testPointerArgWithoutNames(self): + source = """ class Foo { virtual int Bar(C*); }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(int, Bar, (C*), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD1(Bar,\nint(C*));', + self.GenerateMethodSource(source)) - def testReferenceArgWithoutNames(self): - source = """ + def testReferenceArgWithoutNames(self): + source = """ class Foo { virtual int Bar(C&); }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(int, Bar, (C&), (override));', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD1(Bar,\nint(C&));', + self.GenerateMethodSource(source)) - def testArrayArgWithoutNames(self): - source = """ + def testArrayArgWithoutNames(self): + source = """ class Foo { virtual int Bar(C[]); }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD(int, Bar, (C[]), (override));', - self.GenerateMethodSource(source)) + 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.""" - # <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 = """ + @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 = """ namespace Foo { namespace Bar { class Forward; } namespace Baz { @@ -360,91 +366,96 @@ class Test { } // namespace Baz } // namespace Foo """ - expected = """\ + expected = """\ namespace Foo { namespace Baz { class MockTest : public Test { public: -MOCK_METHOD(void, Foo, (), (override)); +MOCK_METHOD0(Foo, +void()); }; } // namespace Baz } // namespace Foo """ - self.assertEqualIgnoreLeadingWhitespace(expected, - self.GenerateMocks(source)) + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMocks(source)) - def testClassWithStorageSpecifierMacro(self): - source = """ + def testClassWithStorageSpecifierMacro(self): + source = """ class STORAGE_SPECIFIER Test { public: virtual void Foo(); }; """ - expected = """\ + expected = """\ class MockTest : public Test { public: -MOCK_METHOD(void, Foo, (), (override)); +MOCK_METHOD0(Foo, +void()); }; """ - self.assertEqualIgnoreLeadingWhitespace(expected, - self.GenerateMocks(source)) + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMocks(source)) - def testTemplatedForwardDeclaration(self): - source = """ + def testTemplatedForwardDeclaration(self): + source = """ template <class T> class Forward; // Forward declaration should be ignored. class Test { public: virtual void Foo(); }; """ - expected = """\ + expected = """\ class MockTest : public Test { public: -MOCK_METHOD(void, Foo, (), (override)); +MOCK_METHOD0(Foo, +void()); }; """ - self.assertEqualIgnoreLeadingWhitespace(expected, - self.GenerateMocks(source)) + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMocks(source)) - def testTemplatedClass(self): - source = """ + def testTemplatedClass(self): + source = """ template <typename S, typename T> class Test { public: virtual void Foo(); }; """ - expected = """\ + expected = """\ template <typename T0, typename T1> class MockTest : public Test<T0, T1> { public: -MOCK_METHOD(void, Foo, (), (override)); +MOCK_METHOD0_T(Foo, +void()); }; """ - self.assertEqualIgnoreLeadingWhitespace(expected, - self.GenerateMocks(source)) + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMocks(source)) - def testTemplateInATemplateTypedef(self): - source = """ + def testTemplateInATemplateTypedef(self): + source = """ class Test { public: typedef std::vector<std::list<int>> FooType; virtual void Bar(const FooType& test_arg); }; """ - expected = """\ + expected = """\ class MockTest : public Test { public: -MOCK_METHOD(void, Bar, (const FooType& test_arg), (override)); +MOCK_METHOD1(Bar, +void(const FooType& test_arg)); }; """ - self.assertEqualIgnoreLeadingWhitespace(expected, - self.GenerateMocks(source)) + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMocks(source)) - def testTemplateInATemplateTypedefWithComma(self): - source = """ + def testTemplateInATemplateTypedefWithComma(self): + source = """ class Test { public: typedef std::function<void( @@ -452,17 +463,18 @@ class Test { virtual void Bar(const FooType& test_arg); }; """ - expected = """\ + expected = """\ class MockTest : public Test { public: -MOCK_METHOD(void, Bar, (const FooType& test_arg), (override)); +MOCK_METHOD1(Bar, +void(const FooType& test_arg)); }; """ - self.assertEqualIgnoreLeadingWhitespace(expected, - self.GenerateMocks(source)) + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMocks(source)) - def testEnumType(self): - source = """ + def testEnumType(self): + source = """ class Test { public: enum Bar { @@ -471,17 +483,18 @@ class Test { virtual void Foo(); }; """ - expected = """\ + expected = """\ class MockTest : public Test { public: -MOCK_METHOD(void, Foo, (), (override)); +MOCK_METHOD0(Foo, +void()); }; """ - self.assertEqualIgnoreLeadingWhitespace(expected, - self.GenerateMocks(source)) + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMocks(source)) - def testEnumClassType(self): - source = """ + def testEnumClassType(self): + source = """ class Test { public: enum class Bar { @@ -490,17 +503,18 @@ class Test { virtual void Foo(); }; """ - expected = """\ + expected = """\ class MockTest : public Test { public: -MOCK_METHOD(void, Foo, (), (override)); +MOCK_METHOD0(Foo, +void()); }; """ - self.assertEqualIgnoreLeadingWhitespace(expected, - self.GenerateMocks(source)) + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMocks(source)) - def testStdFunction(self): - source = """ + def testStdFunction(self): + source = """ class Test { public: Test(std::function<int(std::string)> foo) : foo_(foo) {} @@ -511,15 +525,16 @@ class Test { std::function<int(std::string)> foo_; }; """ - expected = """\ + expected = """\ class MockTest : public Test { public: -MOCK_METHOD(std::function<int (std::string)>, foo, (), (override)); +MOCK_METHOD0(foo, +std::function<int (std::string)>()); }; """ - self.assertEqualIgnoreLeadingWhitespace(expected, - self.GenerateMocks(source)) + self.assertEqualIgnoreLeadingWhitespace( + expected, self.GenerateMocks(source)) if __name__ == '__main__': - unittest.main() + unittest.main() |