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)
 | 
			
		||||
                (name, type_name, templated_types, modifiers, default,
 | 
			
		||||
                 unused_other_tokens) = parts
 | 
			
		||||
                      
 | 
			
		||||
 | 
			
		||||
                t0 = temp_tokens[0]
 | 
			
		||||
                names = [t.name for t in temp_tokens]
 | 
			
		||||
                if templated_types:
 | 
			
		||||
@@ -1551,18 +1551,22 @@ class AstBuilder(object):
 | 
			
		||||
            token = self._GetNextToken()
 | 
			
		||||
        self.namespace_stack.append(name)
 | 
			
		||||
        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 == '=':
 | 
			
		||||
            # TODO(nnorwitz): handle aliasing namespaces.
 | 
			
		||||
            name, next_token = self.GetName()
 | 
			
		||||
            assert next_token.name == ';', next_token
 | 
			
		||||
            self._AddBackToken(internal_token)
 | 
			
		||||
        else:
 | 
			
		||||
            assert token.name == '{', token
 | 
			
		||||
            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.
 | 
			
		||||
            self._AddBackTokens(tokens)
 | 
			
		||||
        token = tokenize.Token(_INTERNAL_TOKEN, _NAMESPACE_POP, None, None)
 | 
			
		||||
        self._AddBackToken(token)
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def handle_using(self):
 | 
			
		||||
@@ -1672,7 +1676,7 @@ def PrintIndentifiers(filename, should_print):
 | 
			
		||||
            if should_print(node):
 | 
			
		||||
                print(node.name)
 | 
			
		||||
    except KeyboardInterrupt:
 | 
			
		||||
      return
 | 
			
		||||
        return
 | 
			
		||||
    except:
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
#!/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");
 | 
			
		||||
# 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.
 | 
			
		||||
        start = node.parameters[0].start
 | 
			
		||||
        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.
 | 
			
		||||
      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('')  # Add an extra newline.
 | 
			
		||||
 | 
			
		||||
  sys.stdout.write('\n'.join(lines))
 | 
			
		||||
 | 
			
		||||
  if desired_class_names:
 | 
			
		||||
    missing_class_name_list = list(desired_class_names - processed_class_names)
 | 
			
		||||
    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' %
 | 
			
		||||
                       (filename, ', '.join(missing_class_name_list)))
 | 
			
		||||
  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):
 | 
			
		||||
@@ -164,7 +170,8 @@ def main(argv=sys.argv):
 | 
			
		||||
    # An error message was already printed since we couldn't parse.
 | 
			
		||||
    pass
 | 
			
		||||
  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__':
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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