1b89a7cc2SEnji Cooper#!/usr/bin/env python
2b89a7cc2SEnji Cooper#
3b89a7cc2SEnji Cooper# Copyright 2010 Google Inc.  All Rights Reserved.
4b89a7cc2SEnji Cooper#
5b89a7cc2SEnji Cooper# Redistribution and use in source and binary forms, with or without
6b89a7cc2SEnji Cooper# modification, are permitted provided that the following conditions are
7b89a7cc2SEnji Cooper# met:
8b89a7cc2SEnji Cooper#
9b89a7cc2SEnji Cooper#     * Redistributions of source code must retain the above copyright
10b89a7cc2SEnji Cooper# notice, this list of conditions and the following disclaimer.
11b89a7cc2SEnji Cooper#     * Redistributions in binary form must reproduce the above
12b89a7cc2SEnji Cooper# copyright notice, this list of conditions and the following disclaimer
13b89a7cc2SEnji Cooper# in the documentation and/or other materials provided with the
14b89a7cc2SEnji Cooper# distribution.
15b89a7cc2SEnji Cooper#     * Neither the name of Google Inc. nor the names of its
16b89a7cc2SEnji Cooper# contributors may be used to endorse or promote products derived from
17b89a7cc2SEnji Cooper# this software without specific prior written permission.
18b89a7cc2SEnji Cooper#
19b89a7cc2SEnji Cooper# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20b89a7cc2SEnji Cooper# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21b89a7cc2SEnji Cooper# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22b89a7cc2SEnji Cooper# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23b89a7cc2SEnji Cooper# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24b89a7cc2SEnji Cooper# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25b89a7cc2SEnji Cooper# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26b89a7cc2SEnji Cooper# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27b89a7cc2SEnji Cooper# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28b89a7cc2SEnji Cooper# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29b89a7cc2SEnji Cooper# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30b89a7cc2SEnji Cooper
31b89a7cc2SEnji Cooper"""Tests Google Test's exception catching behavior.
32b89a7cc2SEnji Cooper
33b89a7cc2SEnji CooperThis script invokes googletest-catch-exceptions-test_ and
34b89a7cc2SEnji Coopergoogletest-catch-exceptions-ex-test_ (programs written with
35b89a7cc2SEnji CooperGoogle Test) and verifies their output.
36b89a7cc2SEnji Cooper"""
37b89a7cc2SEnji Cooper
3828f6c2f2SEnji Cooperfrom googletest.test import gtest_test_utils
39b89a7cc2SEnji Cooper
40b89a7cc2SEnji Cooper# Constants.
41b89a7cc2SEnji CooperFLAG_PREFIX = '--gtest_'
42b89a7cc2SEnji CooperLIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests'
43b89a7cc2SEnji CooperNO_CATCH_EXCEPTIONS_FLAG = FLAG_PREFIX + 'catch_exceptions=0'
44b89a7cc2SEnji CooperFILTER_FLAG = FLAG_PREFIX + 'filter'
45b89a7cc2SEnji Cooper
46b89a7cc2SEnji Cooper# Path to the googletest-catch-exceptions-ex-test_ binary, compiled with
47b89a7cc2SEnji Cooper# exceptions enabled.
48b89a7cc2SEnji CooperEX_EXE_PATH = gtest_test_utils.GetTestExecutablePath(
4928f6c2f2SEnji Cooper    'googletest-catch-exceptions-ex-test_'
5028f6c2f2SEnji Cooper)
51b89a7cc2SEnji Cooper
52b89a7cc2SEnji Cooper# Path to the googletest-catch-exceptions-test_ binary, compiled with
53b89a7cc2SEnji Cooper# exceptions disabled.
54b89a7cc2SEnji CooperEXE_PATH = gtest_test_utils.GetTestExecutablePath(
5528f6c2f2SEnji Cooper    'googletest-catch-exceptions-no-ex-test_'
5628f6c2f2SEnji Cooper)
57b89a7cc2SEnji Cooper
58b89a7cc2SEnji Cooperenviron = gtest_test_utils.environ
59b89a7cc2SEnji CooperSetEnvVar = gtest_test_utils.SetEnvVar
60b89a7cc2SEnji Cooper
61b89a7cc2SEnji Cooper# Tests in this file run a Google-Test-based test program and expect it
62b89a7cc2SEnji Cooper# to terminate prematurely.  Therefore they are incompatible with
63b89a7cc2SEnji Cooper# the premature-exit-file protocol by design.  Unset the
64b89a7cc2SEnji Cooper# premature-exit filepath to prevent Google Test from creating
65b89a7cc2SEnji Cooper# the file.
66b89a7cc2SEnji CooperSetEnvVar(gtest_test_utils.PREMATURE_EXIT_FILE_ENV_VAR, None)
67b89a7cc2SEnji Cooper
68b89a7cc2SEnji CooperTEST_LIST = gtest_test_utils.Subprocess(
6928f6c2f2SEnji Cooper    [EXE_PATH, LIST_TESTS_FLAG], env=environ
7028f6c2f2SEnji Cooper).output
71b89a7cc2SEnji Cooper
72b89a7cc2SEnji CooperSUPPORTS_SEH_EXCEPTIONS = 'ThrowsSehException' in TEST_LIST
73b89a7cc2SEnji Cooper
74b89a7cc2SEnji Cooperif SUPPORTS_SEH_EXCEPTIONS:
75b89a7cc2SEnji Cooper  BINARY_OUTPUT = gtest_test_utils.Subprocess([EXE_PATH], env=environ).output
76b89a7cc2SEnji Cooper
77b89a7cc2SEnji CooperEX_BINARY_OUTPUT = gtest_test_utils.Subprocess(
7828f6c2f2SEnji Cooper    [EX_EXE_PATH], env=environ
7928f6c2f2SEnji Cooper).output
80b89a7cc2SEnji Cooper
81b89a7cc2SEnji Cooper
82b89a7cc2SEnji Cooper# The tests.
83b89a7cc2SEnji Cooperif SUPPORTS_SEH_EXCEPTIONS:
8428f6c2f2SEnji Cooper
85b89a7cc2SEnji Cooper  class CatchSehExceptionsTest(gtest_test_utils.TestCase):
86b89a7cc2SEnji Cooper    """Tests exception-catching behavior."""
87b89a7cc2SEnji Cooper
88b89a7cc2SEnji Cooper    def TestSehExceptions(self, test_output):
8928f6c2f2SEnji Cooper      self.assertIn(
9028f6c2f2SEnji Cooper          (
9128f6c2f2SEnji Cooper              'SEH exception with code 0x2a thrown '
9228f6c2f2SEnji Cooper              "in the test fixture's constructor"
9328f6c2f2SEnji Cooper          ),
9428f6c2f2SEnji Cooper          test_output,
9528f6c2f2SEnji Cooper      )
9628f6c2f2SEnji Cooper      self.assertIn(
9728f6c2f2SEnji Cooper          (
9828f6c2f2SEnji Cooper              'SEH exception with code 0x2a thrown '
9928f6c2f2SEnji Cooper              "in the test fixture's destructor"
10028f6c2f2SEnji Cooper          ),
10128f6c2f2SEnji Cooper          test_output,
10228f6c2f2SEnji Cooper      )
10328f6c2f2SEnji Cooper      self.assertIn(
10428f6c2f2SEnji Cooper          'SEH exception with code 0x2a thrown in SetUpTestSuite()', test_output
10528f6c2f2SEnji Cooper      )
10628f6c2f2SEnji Cooper      self.assertIn(
10728f6c2f2SEnji Cooper          'SEH exception with code 0x2a thrown in TearDownTestSuite()',
10828f6c2f2SEnji Cooper          test_output,
10928f6c2f2SEnji Cooper      )
11028f6c2f2SEnji Cooper      self.assertIn(
11128f6c2f2SEnji Cooper          'SEH exception with code 0x2a thrown in SetUp()', test_output
11228f6c2f2SEnji Cooper      )
11328f6c2f2SEnji Cooper      self.assertIn(
11428f6c2f2SEnji Cooper          'SEH exception with code 0x2a thrown in TearDown()', test_output
11528f6c2f2SEnji Cooper      )
11628f6c2f2SEnji Cooper      self.assertIn(
11728f6c2f2SEnji Cooper          'SEH exception with code 0x2a thrown in the test body', test_output
11828f6c2f2SEnji Cooper      )
119b89a7cc2SEnji Cooper
120b89a7cc2SEnji Cooper    def testCatchesSehExceptionsWithCxxExceptionsEnabled(self):
121b89a7cc2SEnji Cooper      self.TestSehExceptions(EX_BINARY_OUTPUT)
122b89a7cc2SEnji Cooper
123b89a7cc2SEnji Cooper    def testCatchesSehExceptionsWithCxxExceptionsDisabled(self):
124b89a7cc2SEnji Cooper      self.TestSehExceptions(BINARY_OUTPUT)
125b89a7cc2SEnji Cooper
126b89a7cc2SEnji Cooper
127b89a7cc2SEnji Cooperclass CatchCxxExceptionsTest(gtest_test_utils.TestCase):
128b89a7cc2SEnji Cooper  """Tests C++ exception-catching behavior.
129b89a7cc2SEnji Cooper
130b89a7cc2SEnji Cooper  Tests in this test case verify that:
131b89a7cc2SEnji Cooper  * C++ exceptions are caught and logged as C++ (not SEH) exceptions
132b89a7cc2SEnji Cooper  * Exception thrown affect the remainder of the test work flow in the
133b89a7cc2SEnji Cooper    expected manner.
134b89a7cc2SEnji Cooper  """
135b89a7cc2SEnji Cooper
136b89a7cc2SEnji Cooper  def testCatchesCxxExceptionsInFixtureConstructor(self):
13728f6c2f2SEnji Cooper    self.assertTrue(
13828f6c2f2SEnji Cooper        'C++ exception with description '
139b89a7cc2SEnji Cooper        '"Standard C++ exception" thrown '
14028f6c2f2SEnji Cooper        "in the test fixture's constructor"
14128f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
14228f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
14328f6c2f2SEnji Cooper    )
14428f6c2f2SEnji Cooper    self.assertTrue(
14528f6c2f2SEnji Cooper        'unexpected' not in EX_BINARY_OUTPUT,
14628f6c2f2SEnji Cooper        (
147b89a7cc2SEnji Cooper            'This failure belongs in this test only if '
148b89a7cc2SEnji Cooper            '"CxxExceptionInConstructorTest" (no quotes) '
14928f6c2f2SEnji Cooper            'appears on the same line as words "called unexpectedly"'
15028f6c2f2SEnji Cooper        ),
15128f6c2f2SEnji Cooper    )
152b89a7cc2SEnji Cooper
15328f6c2f2SEnji Cooper  if (
15428f6c2f2SEnji Cooper      'CxxExceptionInDestructorTest.ThrowsExceptionInDestructor'
15528f6c2f2SEnji Cooper      in EX_BINARY_OUTPUT
15628f6c2f2SEnji Cooper  ):
157b89a7cc2SEnji Cooper
158b89a7cc2SEnji Cooper    def testCatchesCxxExceptionsInFixtureDestructor(self):
15928f6c2f2SEnji Cooper      self.assertTrue(
16028f6c2f2SEnji Cooper          'C++ exception with description '
161b89a7cc2SEnji Cooper          '"Standard C++ exception" thrown '
16228f6c2f2SEnji Cooper          "in the test fixture's destructor"
16328f6c2f2SEnji Cooper          in EX_BINARY_OUTPUT,
16428f6c2f2SEnji Cooper          EX_BINARY_OUTPUT,
16528f6c2f2SEnji Cooper      )
16628f6c2f2SEnji Cooper      self.assertTrue(
16728f6c2f2SEnji Cooper          'CxxExceptionInDestructorTest::TearDownTestSuite() '
168b89a7cc2SEnji Cooper          'called as expected.'
16928f6c2f2SEnji Cooper          in EX_BINARY_OUTPUT,
17028f6c2f2SEnji Cooper          EX_BINARY_OUTPUT,
17128f6c2f2SEnji Cooper      )
172b89a7cc2SEnji Cooper
173b89a7cc2SEnji Cooper  def testCatchesCxxExceptionsInSetUpTestCase(self):
17428f6c2f2SEnji Cooper    self.assertTrue(
17528f6c2f2SEnji Cooper        'C++ exception with description "Standard C++ exception"'
17628f6c2f2SEnji Cooper        ' thrown in SetUpTestSuite()'
17728f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
17828f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
17928f6c2f2SEnji Cooper    )
18028f6c2f2SEnji Cooper    self.assertTrue(
18128f6c2f2SEnji Cooper        'CxxExceptionInConstructorTest::TearDownTestSuite() called as expected.'
18228f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
18328f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
18428f6c2f2SEnji Cooper    )
18528f6c2f2SEnji Cooper    self.assertFalse(
18628f6c2f2SEnji Cooper        'CxxExceptionInSetUpTestSuiteTest constructor called as expected.'
18728f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
18828f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
18928f6c2f2SEnji Cooper    )
19028f6c2f2SEnji Cooper    self.assertFalse(
19128f6c2f2SEnji Cooper        'CxxExceptionInSetUpTestSuiteTest destructor called as expected.'
19228f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
19328f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
19428f6c2f2SEnji Cooper    )
19528f6c2f2SEnji Cooper    self.assertFalse(
19628f6c2f2SEnji Cooper        'CxxExceptionInSetUpTestSuiteTest::SetUp() called as expected.'
19728f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
19828f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
19928f6c2f2SEnji Cooper    )
20028f6c2f2SEnji Cooper    self.assertFalse(
20128f6c2f2SEnji Cooper        'CxxExceptionInSetUpTestSuiteTest::TearDown() called as expected.'
20228f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
20328f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
20428f6c2f2SEnji Cooper    )
20528f6c2f2SEnji Cooper    self.assertFalse(
20628f6c2f2SEnji Cooper        'CxxExceptionInSetUpTestSuiteTest test body called as expected.'
20728f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
20828f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
20928f6c2f2SEnji Cooper    )
210b89a7cc2SEnji Cooper
211b89a7cc2SEnji Cooper  def testCatchesCxxExceptionsInTearDownTestCase(self):
21228f6c2f2SEnji Cooper    self.assertTrue(
21328f6c2f2SEnji Cooper        'C++ exception with description "Standard C++ exception"'
21428f6c2f2SEnji Cooper        ' thrown in TearDownTestSuite()'
21528f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
21628f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
21728f6c2f2SEnji Cooper    )
218b89a7cc2SEnji Cooper
219b89a7cc2SEnji Cooper  def testCatchesCxxExceptionsInSetUp(self):
22028f6c2f2SEnji Cooper    self.assertTrue(
22128f6c2f2SEnji Cooper        'C++ exception with description "Standard C++ exception"'
222b89a7cc2SEnji Cooper        ' thrown in SetUp()'
22328f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
22428f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
22528f6c2f2SEnji Cooper    )
22628f6c2f2SEnji Cooper    self.assertTrue(
22728f6c2f2SEnji Cooper        'CxxExceptionInSetUpTest::TearDownTestSuite() called as expected.'
22828f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
22928f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
23028f6c2f2SEnji Cooper    )
23128f6c2f2SEnji Cooper    self.assertTrue(
23228f6c2f2SEnji Cooper        'CxxExceptionInSetUpTest destructor called as expected.'
23328f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
23428f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
23528f6c2f2SEnji Cooper    )
23628f6c2f2SEnji Cooper    self.assertTrue(
23728f6c2f2SEnji Cooper        'CxxExceptionInSetUpTest::TearDown() called as expected.'
23828f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
23928f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
24028f6c2f2SEnji Cooper    )
24128f6c2f2SEnji Cooper    self.assertTrue(
24228f6c2f2SEnji Cooper        'unexpected' not in EX_BINARY_OUTPUT,
24328f6c2f2SEnji Cooper        (
244b89a7cc2SEnji Cooper            'This failure belongs in this test only if '
245b89a7cc2SEnji Cooper            '"CxxExceptionInSetUpTest" (no quotes) '
24628f6c2f2SEnji Cooper            'appears on the same line as words "called unexpectedly"'
24728f6c2f2SEnji Cooper        ),
24828f6c2f2SEnji Cooper    )
249b89a7cc2SEnji Cooper
250b89a7cc2SEnji Cooper  def testCatchesCxxExceptionsInTearDown(self):
25128f6c2f2SEnji Cooper    self.assertTrue(
25228f6c2f2SEnji Cooper        'C++ exception with description "Standard C++ exception"'
253b89a7cc2SEnji Cooper        ' thrown in TearDown()'
25428f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
25528f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
25628f6c2f2SEnji Cooper    )
25728f6c2f2SEnji Cooper    self.assertTrue(
25828f6c2f2SEnji Cooper        'CxxExceptionInTearDownTest::TearDownTestSuite() called as expected.'
25928f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
26028f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
26128f6c2f2SEnji Cooper    )
26228f6c2f2SEnji Cooper    self.assertTrue(
26328f6c2f2SEnji Cooper        'CxxExceptionInTearDownTest destructor called as expected.'
26428f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
26528f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
26628f6c2f2SEnji Cooper    )
267b89a7cc2SEnji Cooper
268b89a7cc2SEnji Cooper  def testCatchesCxxExceptionsInTestBody(self):
26928f6c2f2SEnji Cooper    self.assertTrue(
27028f6c2f2SEnji Cooper        'C++ exception with description "Standard C++ exception"'
271b89a7cc2SEnji Cooper        ' thrown in the test body'
27228f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
27328f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
27428f6c2f2SEnji Cooper    )
27528f6c2f2SEnji Cooper    self.assertTrue(
27628f6c2f2SEnji Cooper        'CxxExceptionInTestBodyTest::TearDownTestSuite() called as expected.'
27728f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
27828f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
27928f6c2f2SEnji Cooper    )
28028f6c2f2SEnji Cooper    self.assertTrue(
28128f6c2f2SEnji Cooper        'CxxExceptionInTestBodyTest destructor called as expected.'
28228f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
28328f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
28428f6c2f2SEnji Cooper    )
28528f6c2f2SEnji Cooper    self.assertTrue(
28628f6c2f2SEnji Cooper        'CxxExceptionInTestBodyTest::TearDown() called as expected.'
28728f6c2f2SEnji Cooper        in EX_BINARY_OUTPUT,
28828f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
28928f6c2f2SEnji Cooper    )
290b89a7cc2SEnji Cooper
291b89a7cc2SEnji Cooper  def testCatchesNonStdCxxExceptions(self):
29228f6c2f2SEnji Cooper    self.assertTrue(
29328f6c2f2SEnji Cooper        'Unknown C++ exception thrown in the test body' in EX_BINARY_OUTPUT,
29428f6c2f2SEnji Cooper        EX_BINARY_OUTPUT,
29528f6c2f2SEnji Cooper    )
296b89a7cc2SEnji Cooper
297b89a7cc2SEnji Cooper  def testUnhandledCxxExceptionsAbortTheProgram(self):
298b89a7cc2SEnji Cooper    # Filters out SEH exception tests on Windows. Unhandled SEH exceptions
299b89a7cc2SEnji Cooper    # cause tests to show pop-up windows there.
30028f6c2f2SEnji Cooper    filter_out_seh_tests_flag = FILTER_FLAG + '=-*Seh*'
301b89a7cc2SEnji Cooper    # By default, Google Test doesn't catch the exceptions.
302b89a7cc2SEnji Cooper    uncaught_exceptions_ex_binary_output = gtest_test_utils.Subprocess(
30328f6c2f2SEnji Cooper        [EX_EXE_PATH, NO_CATCH_EXCEPTIONS_FLAG, filter_out_seh_tests_flag],
30428f6c2f2SEnji Cooper        env=environ,
30528f6c2f2SEnji Cooper    ).output
306b89a7cc2SEnji Cooper
30728f6c2f2SEnji Cooper    self.assertIn(
30828f6c2f2SEnji Cooper        'Unhandled C++ exception terminating the program',
30928f6c2f2SEnji Cooper        uncaught_exceptions_ex_binary_output,
31028f6c2f2SEnji Cooper    )
31128f6c2f2SEnji Cooper    self.assertNotIn('unexpected', uncaught_exceptions_ex_binary_output)
312b89a7cc2SEnji Cooper
313b89a7cc2SEnji Cooper
314b89a7cc2SEnji Cooperif __name__ == '__main__':
315b89a7cc2SEnji Cooper  gtest_test_utils.Main()
316