diff options
-rwxr-xr-x | googlemock/scripts/generator/cpp/ast.py | 55 | ||||
-rwxr-xr-x | googlemock/scripts/generator/cpp/gmock_class.py | 364 | ||||
-rwxr-xr-x | googlemock/scripts/generator/cpp/gmock_class_test.py | 415 |
3 files changed, 440 insertions, 394 deletions
diff --git a/googlemock/scripts/generator/cpp/ast.py b/googlemock/scripts/generator/cpp/ast.py index 77bbec9..0d0c984 100755 --- a/googlemock/scripts/generator/cpp/ast.py +++ b/googlemock/scripts/generator/cpp/ast.py @@ -1,19 +1,33 @@ #!/usr/bin/env python # -# Copyright 2007 Neal Norwitz -# Portions Copyright 2007 Google Inc. +# Copyright 2008, 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 +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: # -# http://www.apache.org/licenses/LICENSE-2.0 +# * 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. # -# 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. +# 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. """Generate an Abstract Syntax Tree (AST) for C++.""" @@ -518,7 +532,7 @@ class TypeConverter(object): elif token.name == '&': reference = True elif token.name == '[': - pointer = True + pointer = True elif token.name == ']': pass else: @@ -576,7 +590,7 @@ class TypeConverter(object): elif p.name not in ('*', '&', '>'): # Ensure that names have a space between them. if (type_name and type_name[-1].token_type == tokenize.NAME and - p.token_type == tokenize.NAME): + p.token_type == tokenize.NAME): type_name.append(tokenize.Token(tokenize.SYNTAX, ' ', 0, 0)) type_name.append(p) else: @@ -652,7 +666,7 @@ class TypeConverter(object): start = return_type_seq[0].start end = return_type_seq[-1].end _, name, templated_types, modifiers, default, other_tokens = \ - self.DeclarationToParts(return_type_seq, False) + self.DeclarationToParts(return_type_seq, False) names = [n.name for n in other_tokens] reference = '&' in names pointer = '*' in names @@ -816,7 +830,7 @@ class AstBuilder(object): # self.in_class can contain A::Name, but the dtor will only # be Name. Make sure to compare against the right value. if (token.token_type == tokenize.NAME and - token.name == self.in_class_name_only): + token.name == self.in_class_name_only): return self._GetMethod([token], FUNCTION_DTOR, None, True) # TODO(nnorwitz): handle a lot more syntax. elif token.token_type == tokenize.PREPROCESSOR: @@ -929,7 +943,10 @@ class AstBuilder(object): def _GetNextToken(self): if self.token_queue: return self.token_queue.pop() - return next(self.tokens) + try: + return next(self.tokens) + except StopIteration: + return def _AddBackToken(self, token): if token.whence == tokenize.WHENCE_STREAM: @@ -1129,7 +1146,7 @@ class AstBuilder(object): # Looks like we got a method, not a function. if len(return_type) > 2 and return_type[-1].name == '::': return_type, in_class = \ - self._GetReturnTypeAndClassName(return_type) + self._GetReturnTypeAndClassName(return_type) return Method(indices.start, indices.end, name.name, in_class, return_type, parameters, modifiers, templated_types, body, self.namespace_stack) @@ -1374,7 +1391,7 @@ class AstBuilder(object): def handle_typedef(self): token = self._GetNextToken() if (token.token_type == tokenize.NAME and - keywords.IsKeyword(token.name)): + keywords.IsKeyword(token.name)): # Token must be struct/enum/union/class. method = getattr(self, 'handle_' + token.name) self._handling_typedef = True @@ -1397,7 +1414,7 @@ class AstBuilder(object): if name.name == ')': # HACK(nnorwitz): Handle pointers to functions "properly". if (len(tokens) >= 4 and - tokens[1].name == '(' and tokens[2].name == '*'): + tokens[1].name == '(' and tokens[2].name == '*'): tokens.append(name) name = tokens[3] elif name.name == ']': diff --git a/googlemock/scripts/generator/cpp/gmock_class.py b/googlemock/scripts/generator/cpp/gmock_class.py index 86dcedb..ce30d0c 100755 --- a/googlemock/scripts/generator/cpp/gmock_class.py +++ b/googlemock/scripts/generator/cpp/gmock_class.py @@ -50,10 +50,11 @@ from cpp import utils # Preserve compatibility with Python 2.3. try: - _dummy = set + _dummy = set except NameError: - import sets - set = sets.Set + import sets + + 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. @@ -61,7 +62,7 @@ _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. @@ -70,198 +71,193 @@ def _RenderType(ast_type): Rendered string and a boolean to indicate whether we have multiple args (which is not handled correctly). """ - 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 + 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 + 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. - 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: - # Due to the parser limitations, it is impossible to keep comments - # while stripping the default parameters. When defaults are - # present, we choose to strip them and comments (and produce - # compilable code). - # TODO(nnorwitz@google.com): Investigate whether it is possible to - # preserve parameter name when reconstructing parameter text from - # the AST. - if len([param for param in node.parameters if param.default]) > 0: - args = ', '.join(param.type.name for param in node.parameters) - else: - # 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]) - # 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)]) + 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 0505162..bd12f7e 100755 --- a/googlemock/scripts/generator/cpp/gmock_class_test.py +++ b/googlemock/scripts/generator/cpp/gmock_class_test.py @@ -43,41 +43,43 @@ from cpp import gmock_class class TestCase(unittest.TestCase): - """Helper class that adds assert methods.""" + """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')]) + @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): - 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 = """ + @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_METHOD0(Bar,\nint());', - self.GenerateMethodSource(source)) + self.assertEqualIgnoreLeadingWhitespace( + 'MOCK_METHOD0(Bar,\nint());', + self.GenerateMethodSource(source)) - def testSimpleConstructorsAndDestructor(self): - source = """ + def testSimpleConstructorsAndDestructor(self): + source = """ class Foo { public: Foo(); @@ -88,26 +90,26 @@ class Foo { virtual int Bar() = 0; }; """ - # The constructors and destructor should be ignored. - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD0(Bar,\nint());', - 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_METHOD0(Bar,\nint());', - 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; @@ -117,13 +119,13 @@ class Foo { virtual int Bar() = 0; }; """ - # The constructors and destructor should be ignored. - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD0(Bar,\nint());', - 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; @@ -133,92 +135,121 @@ class Foo { virtual int Bar() = 0; }; """ - # The constructors and destructor should be ignored. - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD0(Bar,\nint());', - 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_METHOD0(Bar,\nint());', - 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_CONST_METHOD1(Bar,\nvoid(bool flag));', - 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_METHOD0(Bar,\nint(void));', - 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_METHOD1(Bar,\nvoid(int a));', - 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_METHOD2(Bar,\nvoid(int, char));', - 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(int a = 42, char c = 'x') = 0; + 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; }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_METHOD2(Bar,\nvoid(int, char));', - 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_METHOD2(Bar,\nvoid(int, char));', - 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. @@ -226,116 +257,117 @@ class Foo { ) const = 0; }; """ - self.assertEqualIgnoreLeadingWhitespace( - 'MOCK_CONST_METHOD2(Bar,\nvoid(int a, int b));', - 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_METHOD2(Bar,\nconst string&(int /* keeper */, int b));', - 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_METHOD2(Bar,\n' - 'int(const vector<int>& v, map<int, string>* output));', - 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_METHOD1(Bar,\nvector<int>*(int n));', - 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(); };""" - # 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 = """ + # 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)) + 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_METHOD1(Bar,\nint(C*));', - 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_METHOD1(Bar,\nint(C&));', - 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_METHOD1(Bar,\nint(C[]));', - self.GenerateMethodSource(source)) + 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 = """ + @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 { @@ -348,7 +380,7 @@ class Test { } // namespace Baz } // namespace Foo """ - expected = """\ + expected = """\ namespace Foo { namespace Baz { @@ -361,53 +393,53 @@ 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_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_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: @@ -415,29 +447,29 @@ 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_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( @@ -445,18 +477,18 @@ class Test { virtual void Bar(const FooType& test_arg); }; """ - expected = """\ + expected = """\ class MockTest : public Test { public: 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 { @@ -465,18 +497,18 @@ class Test { virtual void Foo(); }; """ - expected = """\ + expected = """\ class MockTest : public Test { public: 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 { @@ -485,18 +517,18 @@ class Test { virtual void Foo(); }; """ - expected = """\ + expected = """\ class MockTest : public Test { public: 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) {} @@ -507,15 +539,16 @@ class Test { std::function<int(std::string)> foo_; }; """ - expected = """\ + expected = """\ class MockTest : public Test { public: 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() |