Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
yangql
googletest
Commits
c306ef2e
Commit
c306ef2e
authored
Sep 06, 2013
by
zhanyong.wan
Browse files
supports a protocol for catching tests that prematurely exit
parent
492986a5
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
247 additions
and
22 deletions
+247
-22
CHANGES
CHANGES
+4
-0
CMakeLists.txt
CMakeLists.txt
+2
-0
Makefile.am
Makefile.am
+1
-0
src/gtest.cc
src/gtest.cc
+57
-3
test/gtest_break_on_failure_unittest.py
test/gtest_break_on_failure_unittest.py
+9
-15
test/gtest_catch_exceptions_test.py
test/gtest_catch_exceptions_test.py
+18
-4
test/gtest_premature_exit_test.cc
test/gtest_premature_exit_test.cc
+141
-0
test/gtest_test_utils.py
test/gtest_test_utils.py
+15
-0
No files found.
CHANGES
View file @
c306ef2e
...
...
@@ -2,6 +2,10 @@ Changes for 1.7.0:
* New feature: death tests are supported on OpenBSD and in iOS
simulator now.
* New feature: Google Test now implements a protocol to allow
a test runner to detect that a test program has exited
prematurely and report it as a failure (before it would be
falsely reported as a success if the exit code is 0).
* New feature: Test::RecordProperty() can now be used outside of the
lifespan of a test method, in which case it will be attributed to
the current test case or the test program in the XML report.
...
...
CMakeLists.txt
View file @
c306ef2e
...
...
@@ -124,6 +124,8 @@ if (gtest_build_tests)
test/gtest-param-test2_test.cc
)
cxx_test
(
gtest-port_test gtest_main
)
cxx_test
(
gtest_pred_impl_unittest gtest_main
)
cxx_test
(
gtest_premature_exit_test gtest
test/gtest_premature_exit_test.cc
)
cxx_test
(
gtest-printers_test gtest_main
)
cxx_test
(
gtest_prod_test gtest_main
test/production.cc
)
...
...
Makefile.am
View file @
c306ef2e
...
...
@@ -58,6 +58,7 @@ EXTRA_DIST += \
test
/gtest-param-test_test.cc
\
test
/gtest-param-test_test.h
\
test
/gtest-port_test.cc
\
test
/gtest_premature_exit_test.cc
\
test
/gtest-printers_test.cc
\
test
/gtest-test-part_test.cc
\
test
/gtest-tuple_test.cc
\
...
...
src/gtest.cc
View file @
c306ef2e
...
...
@@ -3523,6 +3523,35 @@ const char* const
OsStackTraceGetter
::
kElidedFramesMarker
=
"... "
GTEST_NAME_
" internal frames ..."
;
// A helper class that creates the premature-exit file in its
// constructor and deletes the file in its destructor.
class
ScopedPrematureExitFile
{
public:
explicit
ScopedPrematureExitFile
(
const
char
*
premature_exit_filepath
)
:
premature_exit_filepath_
(
premature_exit_filepath
)
{
// If a path to the premature-exit file is specified...
if
(
premature_exit_filepath
!=
NULL
&&
*
premature_exit_filepath
!=
'\0'
)
{
// create the file with a single "0" character in it. I/O
// errors are ignored as there's nothing better we can do and we
// don't want to fail the test because of this.
FILE
*
pfile
=
posix
::
FOpen
(
premature_exit_filepath
,
"w"
);
fwrite
(
"0"
,
1
,
1
,
pfile
);
fclose
(
pfile
);
}
}
~
ScopedPrematureExitFile
()
{
if
(
premature_exit_filepath_
!=
NULL
&&
*
premature_exit_filepath_
!=
'\0'
)
{
remove
(
premature_exit_filepath_
);
}
}
private:
const
char
*
const
premature_exit_filepath_
;
GTEST_DISALLOW_COPY_AND_ASSIGN_
(
ScopedPrematureExitFile
);
};
}
// namespace internal
// class TestEventListeners
...
...
@@ -3823,14 +3852,39 @@ void UnitTest::RecordProperty(const std::string& key,
// We don't protect this under mutex_, as we only support calling it
// from the main thread.
int
UnitTest
::
Run
()
{
const
bool
in_death_test_child_process
=
internal
::
GTEST_FLAG
(
internal_run_death_test
).
length
()
>
0
;
// Google Test implements this protocol for catching that a test
// program exits before returning control to Google Test:
//
// 1. Upon start, Google Test creates a file whose absolute path
// is specified by the environment variable
// TEST_PREMATURE_EXIT_FILE.
// 2. When Google Test has finished its work, it deletes the file.
//
// This allows a test runner to set TEST_PREMATURE_EXIT_FILE before
// running a Google-Test-based test program and check the existence
// of the file at the end of the test execution to see if it has
// exited prematurely.
// If we are in the child process of a death test, don't
// create/delete the premature exit file, as doing so is unnecessary
// and will confuse the parent process. Otherwise, create/delete
// the file upon entering/leaving this function. If the program
// somehow exits before this function has a chance to return, the
// premature-exit file will be left undeleted, causing a test runner
// that understands the premature-exit-file protocol to report the
// test as having failed.
const
internal
::
ScopedPrematureExitFile
premature_exit_file
(
in_death_test_child_process
?
NULL
:
internal
::
posix
::
GetEnv
(
"TEST_PREMATURE_EXIT_FILE"
));
// Captures the value of GTEST_FLAG(catch_exceptions). This value will be
// used for the duration of the program.
impl
()
->
set_catch_exceptions
(
GTEST_FLAG
(
catch_exceptions
));
#if GTEST_HAS_SEH
const
bool
in_death_test_child_process
=
internal
::
GTEST_FLAG
(
internal_run_death_test
).
length
()
>
0
;
// Either the user wants Google Test to catch exceptions thrown by the
// tests or this is executing in the context of death test child
// process. In either case the user does not want to see pop-up dialogs
...
...
test/gtest_break_on_failure_unittest.py
View file @
c306ef2e
...
...
@@ -66,21 +66,15 @@ EXE_PATH = gtest_test_utils.GetTestExecutablePath(
'gtest_break_on_failure_unittest_'
)
# Utilities.
environ
=
os
.
environ
.
copy
()
def
SetEnvVar
(
env_var
,
value
):
"""Sets an environment variable to a given value; unsets it when the
given value is None.
"""
if
value
is
not
None
:
environ
[
env_var
]
=
value
elif
env_var
in
environ
:
del
environ
[
env_var
]
environ
=
gtest_test_utils
.
environ
SetEnvVar
=
gtest_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
(
gtest_test_utils
.
PREMATURE_EXIT_FILE_ENV_VAR
,
None
)
def
Run
(
command
):
...
...
test/gtest_catch_exceptions_test.py
View file @
c306ef2e
...
...
@@ -57,14 +57,27 @@ EX_EXE_PATH = gtest_test_utils.GetTestExecutablePath(
EXE_PATH
=
gtest_test_utils
.
GetTestExecutablePath
(
'gtest_catch_exceptions_no_ex_test_'
)
TEST_LIST
=
gtest_test_utils
.
Subprocess
([
EXE_PATH
,
LIST_TESTS_FLAG
]).
output
environ
=
gtest_test_utils
.
environ
SetEnvVar
=
gtest_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
(
gtest_test_utils
.
PREMATURE_EXIT_FILE_ENV_VAR
,
None
)
TEST_LIST
=
gtest_test_utils
.
Subprocess
(
[
EXE_PATH
,
LIST_TESTS_FLAG
],
env
=
environ
).
output
SUPPORTS_SEH_EXCEPTIONS
=
'ThrowsSehException'
in
TEST_LIST
if
SUPPORTS_SEH_EXCEPTIONS
:
BINARY_OUTPUT
=
gtest_test_utils
.
Subprocess
([
EXE_PATH
]).
output
BINARY_OUTPUT
=
gtest_test_utils
.
Subprocess
([
EXE_PATH
],
env
=
environ
).
output
EX_BINARY_OUTPUT
=
gtest_test_utils
.
Subprocess
(
[
EX_EXE_PATH
],
env
=
environ
).
output
EX_BINARY_OUTPUT
=
gtest_test_utils
.
Subprocess
([
EX_EXE_PATH
]).
output
# The tests.
if
SUPPORTS_SEH_EXCEPTIONS
:
...
...
@@ -212,7 +225,8 @@ class CatchCxxExceptionsTest(gtest_test_utils.TestCase):
uncaught_exceptions_ex_binary_output
=
gtest_test_utils
.
Subprocess
(
[
EX_EXE_PATH
,
NO_CATCH_EXCEPTIONS_FLAG
,
FITLER_OUT_SEH_TESTS_FLAG
]).
output
FITLER_OUT_SEH_TESTS_FLAG
],
env
=
environ
).
output
self
.
assert_
(
'Unhandled C++ exception terminating the program'
in
uncaught_exceptions_ex_binary_output
)
...
...
test/gtest_premature_exit_test.cc
0 → 100644
View file @
c306ef2e
// Copyright 2013, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)
//
// Tests that Google Test manipulates the premature-exit-detection
// file correctly.
#include <stdio.h>
#include "gtest/gtest.h"
using
::
testing
::
InitGoogleTest
;
using
::
testing
::
Test
;
using
::
testing
::
internal
::
posix
::
GetEnv
;
using
::
testing
::
internal
::
posix
::
Stat
;
using
::
testing
::
internal
::
posix
::
StatStruct
;
namespace
{
// Is the TEST_PREMATURE_EXIT_FILE environment variable expected to be
// set?
const
bool
kTestPrematureExitFileEnvVarShouldBeSet
=
false
;
class
PrematureExitTest
:
public
Test
{
public:
// Returns true iff the given file exists.
static
bool
FileExists
(
const
char
*
filepath
)
{
StatStruct
stat
;
return
Stat
(
filepath
,
&
stat
)
==
0
;
}
protected:
PrematureExitTest
()
{
premature_exit_file_path_
=
GetEnv
(
"TEST_PREMATURE_EXIT_FILE"
);
// Normalize NULL to "" for ease of handling.
if
(
premature_exit_file_path_
==
NULL
)
{
premature_exit_file_path_
=
""
;
}
}
// Returns true iff the premature-exit file exists.
bool
PrematureExitFileExists
()
const
{
return
FileExists
(
premature_exit_file_path_
);
}
const
char
*
premature_exit_file_path_
;
};
typedef
PrematureExitTest
PrematureExitDeathTest
;
// Tests that:
// - the premature-exit file exists during the execution of a
// death test (EXPECT_DEATH*), and
// - a death test doesn't interfere with the main test process's
// handling of the premature-exit file.
TEST_F
(
PrematureExitDeathTest
,
FileExistsDuringExecutionOfDeathTest
)
{
if
(
*
premature_exit_file_path_
==
'\0'
)
{
return
;
}
EXPECT_DEATH_IF_SUPPORTED
({
// If the file exists, crash the process such that the main test
// process will catch the (expected) crash and report a success;
// otherwise don't crash, which will cause the main test process
// to report that the death test has failed.
if
(
PrematureExitFileExists
())
{
exit
(
1
);
}
},
""
);
}
// Tests that TEST_PREMATURE_EXIT_FILE is set where it's expected to
// be set.
TEST_F
(
PrematureExitTest
,
TestPrematureExitFileEnvVarIsSet
)
{
if
(
kTestPrematureExitFileEnvVarShouldBeSet
)
{
const
char
*
const
filepath
=
GetEnv
(
"TEST_PREMATURE_EXIT_FILE"
);
ASSERT_TRUE
(
filepath
!=
NULL
);
ASSERT_NE
(
*
filepath
,
'\0'
);
}
}
// Tests that the premature-exit file exists during the execution of a
// normal (non-death) test.
TEST_F
(
PrematureExitTest
,
PrematureExitFileExistsDuringTestExecution
)
{
if
(
*
premature_exit_file_path_
==
'\0'
)
{
return
;
}
EXPECT_TRUE
(
PrematureExitFileExists
())
<<
" file "
<<
premature_exit_file_path_
<<
" should exist during test execution, but doesn't."
;
}
}
// namespace
int
main
(
int
argc
,
char
**
argv
)
{
InitGoogleTest
(
&
argc
,
argv
);
const
int
exit_code
=
RUN_ALL_TESTS
();
// Test that the premature-exit file is deleted upon return from
// RUN_ALL_TESTS().
const
char
*
const
filepath
=
GetEnv
(
"TEST_PREMATURE_EXIT_FILE"
);
if
(
filepath
!=
NULL
&&
*
filepath
!=
'\0'
)
{
if
(
PrematureExitTest
::
FileExists
(
filepath
))
{
printf
(
"File %s shouldn't exist after the test program finishes, but does."
,
filepath
);
return
1
;
}
}
return
exit_code
;
}
test/gtest_test_utils.py
View file @
c306ef2e
...
...
@@ -56,6 +56,21 @@ GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT'
IS_WINDOWS
=
os
.
name
==
'nt'
IS_CYGWIN
=
os
.
name
==
'posix'
and
'CYGWIN'
in
os
.
uname
()[
0
]
# The environment variable for specifying the path to the premature-exit file.
PREMATURE_EXIT_FILE_ENV_VAR
=
'TEST_PREMATURE_EXIT_FILE'
environ
=
os
.
environ
.
copy
()
def
SetEnvVar
(
env_var
,
value
):
"""Sets/unsets an environment variable to a given value."""
if
value
is
not
None
:
environ
[
env_var
]
=
value
elif
env_var
in
environ
:
del
environ
[
env_var
]
# Here we expose a class from a particular module, depending on the
# environment. The comment suppresses the 'Invalid variable name' lint
# complaint.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment