Improves gmock generator and adds a test for it (by Neal Norwitz).
diff --git a/scripts/generator/cpp/ast.py b/scripts/generator/cpp/ast.py
index 6d1c8d3..47dc9a0 100755
--- a/scripts/generator/cpp/ast.py
+++ b/scripts/generator/cpp/ast.py
@@ -782,7 +782,7 @@
                 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 @@
             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 @@
             if should_print(node):
                 print(node.name)
     except KeyboardInterrupt:
-      return
+        return
     except:
         pass
 
diff --git a/scripts/generator/cpp/gmock_class.py b/scripts/generator/cpp/gmock_class.py
index 2920424..3ad0bcd 100755
--- a/scripts/generator/cpp/gmock_class.py
+++ b/scripts/generator/cpp/gmock_class.py
@@ -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 @@
         # 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 @@
           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 @@
       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 @@
     # 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__':
diff --git a/scripts/generator/cpp/gmock_class_test.py b/scripts/generator/cpp/gmock_class_test.py
new file mode 100755
index 0000000..0132eef
--- /dev/null
+++ b/scripts/generator/cpp/gmock_class_test.py
@@ -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()