Improves gmock generator and adds a test for it (by Neal Norwitz).
This commit is contained in:
		@@ -782,7 +782,7 @@ class AstBuilder(object):
 | 
				
			|||||||
                parts = self.converter.DeclarationToParts(temp_tokens, True)
 | 
					                parts = self.converter.DeclarationToParts(temp_tokens, True)
 | 
				
			||||||
                (name, type_name, templated_types, modifiers, default,
 | 
					                (name, type_name, templated_types, modifiers, default,
 | 
				
			||||||
                 unused_other_tokens) = parts
 | 
					                 unused_other_tokens) = parts
 | 
				
			||||||
                      
 | 
					
 | 
				
			||||||
                t0 = temp_tokens[0]
 | 
					                t0 = temp_tokens[0]
 | 
				
			||||||
                names = [t.name for t in temp_tokens]
 | 
					                names = [t.name for t in temp_tokens]
 | 
				
			||||||
                if templated_types:
 | 
					                if templated_types:
 | 
				
			||||||
@@ -1551,18 +1551,22 @@ class AstBuilder(object):
 | 
				
			|||||||
            token = self._GetNextToken()
 | 
					            token = self._GetNextToken()
 | 
				
			||||||
        self.namespace_stack.append(name)
 | 
					        self.namespace_stack.append(name)
 | 
				
			||||||
        assert token.token_type == tokenize.SYNTAX, token
 | 
					        assert token.token_type == tokenize.SYNTAX, token
 | 
				
			||||||
 | 
					        # Create an internal token that denotes when the namespace is complete.
 | 
				
			||||||
 | 
					        internal_token = tokenize.Token(_INTERNAL_TOKEN, _NAMESPACE_POP,
 | 
				
			||||||
 | 
					                                        None, None)
 | 
				
			||||||
 | 
					        internal_token.whence = token.whence
 | 
				
			||||||
        if token.name == '=':
 | 
					        if token.name == '=':
 | 
				
			||||||
            # TODO(nnorwitz): handle aliasing namespaces.
 | 
					            # TODO(nnorwitz): handle aliasing namespaces.
 | 
				
			||||||
            name, next_token = self.GetName()
 | 
					            name, next_token = self.GetName()
 | 
				
			||||||
            assert next_token.name == ';', next_token
 | 
					            assert next_token.name == ';', next_token
 | 
				
			||||||
 | 
					            self._AddBackToken(internal_token)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            assert token.name == '{', token
 | 
					            assert token.name == '{', token
 | 
				
			||||||
            tokens = list(self.GetScope())
 | 
					            tokens = list(self.GetScope())
 | 
				
			||||||
            del tokens[-1]              # Remove trailing '}'.
 | 
					            # Replace the trailing } with the internal namespace pop token.
 | 
				
			||||||
 | 
					            tokens[-1] = internal_token
 | 
				
			||||||
            # Handle namespace with nothing in it.
 | 
					            # Handle namespace with nothing in it.
 | 
				
			||||||
            self._AddBackTokens(tokens)
 | 
					            self._AddBackTokens(tokens)
 | 
				
			||||||
        token = tokenize.Token(_INTERNAL_TOKEN, _NAMESPACE_POP, None, None)
 | 
					 | 
				
			||||||
        self._AddBackToken(token)
 | 
					 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def handle_using(self):
 | 
					    def handle_using(self):
 | 
				
			||||||
@@ -1672,7 +1676,7 @@ def PrintIndentifiers(filename, should_print):
 | 
				
			|||||||
            if should_print(node):
 | 
					            if should_print(node):
 | 
				
			||||||
                print(node.name)
 | 
					                print(node.name)
 | 
				
			||||||
    except KeyboardInterrupt:
 | 
					    except KeyboardInterrupt:
 | 
				
			||||||
      return
 | 
					        return
 | 
				
			||||||
    except:
 | 
					    except:
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
#!/usr/bin/env python
 | 
					#!/usr/bin/env python
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Copyright 2008 Google Inc.
 | 
					# Copyright 2008 Google Inc.  All Rights Reserved.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
					# Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
# you may not use this file except in compliance with the License.
 | 
					# you may not use this file except in compliance with the License.
 | 
				
			||||||
@@ -73,7 +73,13 @@ def _GenerateMethods(output_lines, source, class_node):
 | 
				
			|||||||
        # of the first parameter to the end of the last parameter.
 | 
					        # of the first parameter to the end of the last parameter.
 | 
				
			||||||
        start = node.parameters[0].start
 | 
					        start = node.parameters[0].start
 | 
				
			||||||
        end = node.parameters[-1].end
 | 
					        end = node.parameters[-1].end
 | 
				
			||||||
        args = re.sub('  +', ' ', source[start:end].replace('\n', ''))
 | 
					        # 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 prototype.
 | 
					      # Create the prototype.
 | 
				
			||||||
      indent = ' ' * _INDENT
 | 
					      indent = ' ' * _INDENT
 | 
				
			||||||
@@ -120,8 +126,6 @@ def _GenerateMocks(filename, source, ast_list, desired_class_names):
 | 
				
			|||||||
          lines.append('}  // namespace %s' % class_node.namespace[i])
 | 
					          lines.append('}  // namespace %s' % class_node.namespace[i])
 | 
				
			||||||
        lines.append('')  # Add an extra newline.
 | 
					        lines.append('')  # Add an extra newline.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sys.stdout.write('\n'.join(lines))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if desired_class_names:
 | 
					  if desired_class_names:
 | 
				
			||||||
    missing_class_name_list = list(desired_class_names - processed_class_names)
 | 
					    missing_class_name_list = list(desired_class_names - processed_class_names)
 | 
				
			||||||
    if missing_class_name_list:
 | 
					    if missing_class_name_list:
 | 
				
			||||||
@@ -129,7 +133,9 @@ def _GenerateMocks(filename, source, ast_list, desired_class_names):
 | 
				
			|||||||
      sys.stderr.write('Class(es) not found in %s: %s\n' %
 | 
					      sys.stderr.write('Class(es) not found in %s: %s\n' %
 | 
				
			||||||
                       (filename, ', '.join(missing_class_name_list)))
 | 
					                       (filename, ', '.join(missing_class_name_list)))
 | 
				
			||||||
  elif not processed_class_names:
 | 
					  elif not processed_class_names:
 | 
				
			||||||
      sys.stderr.write('No class found in %s\n' % filename)
 | 
					    sys.stderr.write('No class found in %s\n' % filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return lines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main(argv=sys.argv):
 | 
					def main(argv=sys.argv):
 | 
				
			||||||
@@ -164,7 +170,8 @@ def main(argv=sys.argv):
 | 
				
			|||||||
    # An error message was already printed since we couldn't parse.
 | 
					    # An error message was already printed since we couldn't parse.
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
  else:
 | 
					  else:
 | 
				
			||||||
    _GenerateMocks(filename, source, entire_ast, desired_class_names)
 | 
					    lines = _GenerateMocks(filename, source, entire_ast, desired_class_names)
 | 
				
			||||||
 | 
					    sys.stdout.write('\n'.join(lines))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										137
									
								
								scripts/generator/cpp/gmock_class_test.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										137
									
								
								scripts/generator/cpp/gmock_class_test.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,137 @@
 | 
				
			|||||||
 | 
					#!/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.dirname(os.path.dirname(__file__)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpp import ast
 | 
				
			||||||
 | 
					from cpp import gmock_class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestCase(unittest.TestCase):
 | 
				
			||||||
 | 
					  """Helper class that adds assert methods."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def assertEqualIgnoreLeadingWhitespace(self, expected_lines, lines):
 | 
				
			||||||
 | 
					    """Specialized assert that ignores the indent level."""
 | 
				
			||||||
 | 
					    stripped_lines = '\n'.join([s.lstrip() for s in lines.split('\n')])
 | 
				
			||||||
 | 
					    self.assertEqual(expected_lines, stripped_lines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GenerateMethodsTest(TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def GenerateMethodSource(self, cpp_source):
 | 
				
			||||||
 | 
					    """Helper method to convert C++ source to gMock 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 ''.join(method_source_lines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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 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))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GenerateMocksTest(TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def GenerateMocks(self, cpp_source):
 | 
				
			||||||
 | 
					    """Helper method to convert C++ source to complete gMock 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))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					  unittest.main()
 | 
				
			||||||
		Reference in New Issue
	
	Block a user