makes googlemock generator handle some class templates; pulls in gtest r662
This commit is contained in:
parent
778358e3f1
commit
45fef502fa
2
CHANGES
2
CHANGES
|
@ -23,6 +23,8 @@ Changes for 1.7.0:
|
||||||
* Improvement: the ElementsAreArray() matcher can now take a vector or
|
* Improvement: the ElementsAreArray() matcher can now take a vector or
|
||||||
iterator range as input, and makes a copy of its input elements
|
iterator range as input, and makes a copy of its input elements
|
||||||
before the conversion to a Matcher.
|
before the conversion to a Matcher.
|
||||||
|
* Improvement: the Google Mock Generator can now generate mocks for
|
||||||
|
some class templates.
|
||||||
* Bug fix: mock object destruction triggerred by another mock object's
|
* Bug fix: mock object destruction triggerred by another mock object's
|
||||||
destruction no longer hangs.
|
destruction no longer hangs.
|
||||||
* Improvement: Google Mock Doctor works better with newer Clang and
|
* Improvement: Google Mock Doctor works better with newer Clang and
|
||||||
|
|
|
@ -1546,7 +1546,7 @@ class AstBuilder(object):
|
||||||
self._AddBackToken(token)
|
self._AddBackToken(token)
|
||||||
|
|
||||||
return class_type(class_token.start, class_token.end, class_name,
|
return class_type(class_token.start, class_token.end, class_name,
|
||||||
bases, None, body, self.namespace_stack)
|
bases, templated_types, body, self.namespace_stack)
|
||||||
|
|
||||||
def handle_namespace(self):
|
def handle_namespace(self):
|
||||||
token = self._GetNextToken()
|
token = self._GetNextToken()
|
||||||
|
|
|
@ -88,7 +88,11 @@ def _GenerateMethods(output_lines, source, class_node):
|
||||||
if source[first_param.start:first_param.end].strip() == 'void':
|
if source[first_param.start:first_param.end].strip() == 'void':
|
||||||
# We must treat T(void) as a function with no parameters.
|
# We must treat T(void) as a function with no parameters.
|
||||||
num_parameters = 0
|
num_parameters = 0
|
||||||
mock_method_macro = 'MOCK_%sMETHOD%d' % (const, num_parameters)
|
tmpl = ''
|
||||||
|
if class_node.templated_types:
|
||||||
|
tmpl = '_T'
|
||||||
|
mock_method_macro = 'MOCK_%sMETHOD%d%s' % (const, num_parameters, tmpl)
|
||||||
|
|
||||||
args = ''
|
args = ''
|
||||||
if node.parameters:
|
if node.parameters:
|
||||||
# Due to the parser limitations, it is impossible to keep comments
|
# Due to the parser limitations, it is impossible to keep comments
|
||||||
|
@ -126,6 +130,7 @@ def _GenerateMocks(filename, source, ast_list, desired_class_names):
|
||||||
# desired_class_names being None means that all classes are selected.
|
# desired_class_names being None means that all classes are selected.
|
||||||
(not desired_class_names or node.name in desired_class_names)):
|
(not desired_class_names or node.name in desired_class_names)):
|
||||||
class_name = node.name
|
class_name = node.name
|
||||||
|
parent_name = class_name
|
||||||
processed_class_names.add(class_name)
|
processed_class_names.add(class_name)
|
||||||
class_node = node
|
class_node = node
|
||||||
# Add namespace before the class.
|
# Add namespace before the class.
|
||||||
|
@ -133,8 +138,21 @@ def _GenerateMocks(filename, source, ast_list, desired_class_names):
|
||||||
lines.extend(['namespace %s {' % n for n in class_node.namespace]) # }
|
lines.extend(['namespace %s {' % n for n in class_node.namespace]) # }
|
||||||
lines.append('')
|
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.
|
# Add the class prolog.
|
||||||
lines.append('class Mock%s : public %s {' % (class_name, class_name)) # }
|
lines.append('class Mock%s : public %s {' # }
|
||||||
|
% (class_name, parent_name))
|
||||||
lines.append('%spublic:' % (' ' * (_INDENT // 2)))
|
lines.append('%spublic:' % (' ' * (_INDENT // 2)))
|
||||||
|
|
||||||
# Add all the methods.
|
# Add all the methods.
|
||||||
|
|
|
@ -196,6 +196,18 @@ class Foo {
|
||||||
'MOCK_METHOD0(Bar,\nmap<int, string>());',
|
'MOCK_METHOD0(Bar,\nmap<int, string>());',
|
||||||
self.GenerateMethodSource(source))
|
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))
|
||||||
|
|
||||||
|
|
||||||
class GenerateMocksTest(TestCase):
|
class GenerateMocksTest(TestCase):
|
||||||
|
|
||||||
|
@ -255,5 +267,43 @@ void());
|
||||||
self.assertEqualIgnoreLeadingWhitespace(
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
expected, self.GenerateMocks(source))
|
expected, self.GenerateMocks(source))
|
||||||
|
|
||||||
|
def testTemplatedForwardDeclaration(self):
|
||||||
|
source = """
|
||||||
|
template <class T> class Forward; // Forward declaration should be ignored.
|
||||||
|
class Test {
|
||||||
|
public:
|
||||||
|
virtual void Foo();
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
expected = """\
|
||||||
|
class MockTest : public Test {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD0(Foo,
|
||||||
|
void());
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
expected, self.GenerateMocks(source))
|
||||||
|
|
||||||
|
def testTemplatedClass(self):
|
||||||
|
source = """
|
||||||
|
template <typename S, typename T>
|
||||||
|
class Test {
|
||||||
|
public:
|
||||||
|
virtual void Foo();
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
expected = """\
|
||||||
|
template <typename T0, typename T1>
|
||||||
|
class MockTest : public Test<T0, T1> {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD0_T(Foo,
|
||||||
|
void());
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
expected, self.GenerateMocks(source))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -42,48 +42,66 @@ TEST_WITH_EXPECT_CALL = [PROGRAM_PATH, '--gtest_filter=*ExpectCall*']
|
||||||
TEST_WITH_ON_CALL = [PROGRAM_PATH, '--gtest_filter=*OnCall*']
|
TEST_WITH_ON_CALL = [PROGRAM_PATH, '--gtest_filter=*OnCall*']
|
||||||
TEST_MULTIPLE_LEAKS = [PROGRAM_PATH, '--gtest_filter=*MultipleLeaked*']
|
TEST_MULTIPLE_LEAKS = [PROGRAM_PATH, '--gtest_filter=*MultipleLeaked*']
|
||||||
|
|
||||||
|
environ = gmock_test_utils.environ
|
||||||
|
SetEnvVar = gmock_test_utils.SetEnvVar
|
||||||
|
|
||||||
|
# Tests in this file run a Google-Test-based test program and expect it
|
||||||
|
# to terminate prematurely. Therefore they are incompatible with
|
||||||
|
# the premature-exit-file protocol by design. Unset the
|
||||||
|
# premature-exit filepath to prevent Google Test from creating
|
||||||
|
# the file.
|
||||||
|
SetEnvVar(gmock_test_utils.PREMATURE_EXIT_FILE_ENV_VAR, None)
|
||||||
|
|
||||||
|
|
||||||
class GMockLeakTest(gmock_test_utils.TestCase):
|
class GMockLeakTest(gmock_test_utils.TestCase):
|
||||||
|
|
||||||
def testCatchesLeakedMockByDefault(self):
|
def testCatchesLeakedMockByDefault(self):
|
||||||
self.assertNotEqual(
|
self.assertNotEqual(
|
||||||
0,
|
0,
|
||||||
gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL).exit_code)
|
gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL,
|
||||||
|
env=environ).exit_code)
|
||||||
self.assertNotEqual(
|
self.assertNotEqual(
|
||||||
0,
|
0,
|
||||||
gmock_test_utils.Subprocess(TEST_WITH_ON_CALL).exit_code)
|
gmock_test_utils.Subprocess(TEST_WITH_ON_CALL,
|
||||||
|
env=environ).exit_code)
|
||||||
|
|
||||||
def testDoesNotCatchLeakedMockWhenDisabled(self):
|
def testDoesNotCatchLeakedMockWhenDisabled(self):
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
0,
|
0,
|
||||||
gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL +
|
gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL +
|
||||||
['--gmock_catch_leaked_mocks=0']).exit_code)
|
['--gmock_catch_leaked_mocks=0'],
|
||||||
|
env=environ).exit_code)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
0,
|
0,
|
||||||
gmock_test_utils.Subprocess(TEST_WITH_ON_CALL +
|
gmock_test_utils.Subprocess(TEST_WITH_ON_CALL +
|
||||||
['--gmock_catch_leaked_mocks=0']).exit_code)
|
['--gmock_catch_leaked_mocks=0'],
|
||||||
|
env=environ).exit_code)
|
||||||
|
|
||||||
def testCatchesLeakedMockWhenEnabled(self):
|
def testCatchesLeakedMockWhenEnabled(self):
|
||||||
self.assertNotEqual(
|
self.assertNotEqual(
|
||||||
0,
|
0,
|
||||||
gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL +
|
gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL +
|
||||||
['--gmock_catch_leaked_mocks']).exit_code)
|
['--gmock_catch_leaked_mocks'],
|
||||||
|
env=environ).exit_code)
|
||||||
self.assertNotEqual(
|
self.assertNotEqual(
|
||||||
0,
|
0,
|
||||||
gmock_test_utils.Subprocess(TEST_WITH_ON_CALL +
|
gmock_test_utils.Subprocess(TEST_WITH_ON_CALL +
|
||||||
['--gmock_catch_leaked_mocks']).exit_code)
|
['--gmock_catch_leaked_mocks'],
|
||||||
|
env=environ).exit_code)
|
||||||
|
|
||||||
def testCatchesLeakedMockWhenEnabledWithExplictFlagValue(self):
|
def testCatchesLeakedMockWhenEnabledWithExplictFlagValue(self):
|
||||||
self.assertNotEqual(
|
self.assertNotEqual(
|
||||||
0,
|
0,
|
||||||
gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL +
|
gmock_test_utils.Subprocess(TEST_WITH_EXPECT_CALL +
|
||||||
['--gmock_catch_leaked_mocks=1']).exit_code)
|
['--gmock_catch_leaked_mocks=1'],
|
||||||
|
env=environ).exit_code)
|
||||||
|
|
||||||
def testCatchesMultipleLeakedMocks(self):
|
def testCatchesMultipleLeakedMocks(self):
|
||||||
self.assertNotEqual(
|
self.assertNotEqual(
|
||||||
0,
|
0,
|
||||||
gmock_test_utils.Subprocess(TEST_MULTIPLE_LEAKS +
|
gmock_test_utils.Subprocess(TEST_MULTIPLE_LEAKS +
|
||||||
['--gmock_catch_leaked_mocks']).exit_code)
|
['--gmock_catch_leaked_mocks'],
|
||||||
|
env=environ).exit_code)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -96,11 +96,12 @@ def GetExitStatus(exit_code):
|
||||||
# Suppresses the "Invalid const name" lint complaint
|
# Suppresses the "Invalid const name" lint complaint
|
||||||
# pylint: disable-msg=C6409
|
# pylint: disable-msg=C6409
|
||||||
|
|
||||||
# Exposes Subprocess from gtest_test_utils.
|
# Exposes utilities from gtest_test_utils.
|
||||||
Subprocess = gtest_test_utils.Subprocess
|
Subprocess = gtest_test_utils.Subprocess
|
||||||
|
|
||||||
# Exposes TestCase from gtest_test_utils.
|
|
||||||
TestCase = gtest_test_utils.TestCase
|
TestCase = gtest_test_utils.TestCase
|
||||||
|
environ = gtest_test_utils.environ
|
||||||
|
SetEnvVar = gtest_test_utils.SetEnvVar
|
||||||
|
PREMATURE_EXIT_FILE_ENV_VAR = gtest_test_utils.PREMATURE_EXIT_FILE_ENV_VAR
|
||||||
|
|
||||||
# pylint: enable-msg=C6409
|
# pylint: enable-msg=C6409
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user