summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Sokolov <sokolov@google.com>2018-02-03 23:36:19 (GMT)
committerAlexey Sokolov <sokolov@google.com>2018-02-08 01:15:42 (GMT)
commit092d0885332316ca679ac77e0f8fe1f5c368fb4f (patch)
tree8a9cae8146f8c4f93c6a59de375229034e6d8e5d
parentea31cb15f0c2ab9f5f5b18e82311eb522989d747 (diff)
downloadgoogletest-092d0885332316ca679ac77e0f8fe1f5c368fb4f.zip
googletest-092d0885332316ca679ac77e0f8fe1f5c368fb4f.tar.gz
googletest-092d0885332316ca679ac77e0f8fe1f5c368fb4f.tar.bz2
Add ability to throw from ASSERT
while not losing benefits of EXPECT, and not killing the whole test, as with --gtest_throw_on_failure. 183822976
-rw-r--r--googletest/docs/AdvancedGuide.md30
-rw-r--r--googletest/include/gtest/gtest.h16
-rw-r--r--googletest/src/gtest.cc7
-rw-r--r--googletest/test/BUILD.bazel7
-rw-r--r--googletest/test/gtest_assert_by_exception_test.cc119
5 files changed, 171 insertions, 8 deletions
diff --git a/googletest/docs/AdvancedGuide.md b/googletest/docs/AdvancedGuide.md
index e1df20d..6605f44 100644
--- a/googletest/docs/AdvancedGuide.md
+++ b/googletest/docs/AdvancedGuide.md
@@ -872,13 +872,33 @@ TEST(FooTest, Bar) {
}
```
-Since we don't use exceptions, it is technically impossible to
-implement the intended behavior here. To alleviate this, Google Test
-provides two solutions. You could use either the
-`(ASSERT|EXPECT)_NO_FATAL_FAILURE` assertions or the
-`HasFatalFailure()` function. They are described in the following two
+To alleviate this, gUnit provides three different solutions. You could use
+either exceptions, the `(ASSERT|EXPECT)_NO_FATAL_FAILURE` assertions or the
+`HasFatalFailure()` function. They are described in the following two
subsections.
+#### Asserting on Subroutines with an exception
+
+The following code can turn ASSERT-failure into an exception:
+
+```c++
+class ThrowListener : public testing::EmptyTestEventListener {
+ void OnTestPartResult(const testing::TestPartResult& result) override {
+ if (result.type() == testing::TestPartResult::kFatalFailure) {
+ throw testing::AssertionException(result);
+ }
+ }
+};
+int main(int argc, char** argv) {
+ ...
+ testing::UnitTest::GetInstance()->listeners().Append(new ThrowListener);
+ return RUN_ALL_TESTS();
+}
+```
+
+This listener should be added after other listeners if you have any, otherwise
+they won't see failed `OnTestPartResult`.
+
### Asserting on Subroutines ###
As shown above, if your test calls a subroutine that has an `ASSERT_*`
diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h
index 01994e6..26e787d 100644
--- a/googletest/include/gtest/gtest.h
+++ b/googletest/include/gtest/gtest.h
@@ -138,7 +138,7 @@ GTEST_DECLARE_int32_(stack_trace_depth);
// When this flag is specified, a failed assertion will throw an
// exception if exceptions are enabled, or exit the program with a
-// non-zero code otherwise.
+// non-zero code otherwise. For use with an external test framework.
GTEST_DECLARE_bool_(throw_on_failure);
// When this flag is set with a "host:port" string, on supported
@@ -1004,6 +1004,18 @@ class Environment {
virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
};
+#if GTEST_HAS_EXCEPTIONS
+
+// Exception which can be thrown from TestEventListener::OnTestPartResult.
+class GTEST_API_ AssertionException
+ : public internal::GoogleTestFailureException {
+ public:
+ explicit AssertionException(const TestPartResult& result)
+ : GoogleTestFailureException(result) {}
+};
+
+#endif // GTEST_HAS_EXCEPTIONS
+
// The interface for tracing execution of tests. The methods are organized in
// the order the corresponding events are fired.
class TestEventListener {
@@ -1032,6 +1044,8 @@ class TestEventListener {
virtual void OnTestStart(const TestInfo& test_info) = 0;
// Fired after a failed assertion or a SUCCEED() invocation.
+ // If you want to throw an exception from this function to skip to the next
+ // TEST, it must be AssertionException defined above, or inherited from it.
virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;
// Fired after the test ends.
diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc
index 2c25f83..54e25b2 100644
--- a/googletest/src/gtest.cc
+++ b/googletest/src/gtest.cc
@@ -293,7 +293,7 @@ GTEST_DEFINE_bool_(
internal::BoolFromGTestEnv("throw_on_failure", false),
"When this flag is specified, a failed assertion will throw an exception "
"if exceptions are enabled or exit the program with a non-zero code "
- "otherwise.");
+ "otherwise. For use with an external test framework.");
#if GTEST_USE_OWN_FLAGFILE_FLAG_
GTEST_DEFINE_string_(
@@ -2435,6 +2435,8 @@ Result HandleExceptionsInMethodIfSupported(
#if GTEST_HAS_EXCEPTIONS
try {
return HandleSehExceptionsInMethodIfSupported(object, method, location);
+ } catch (const AssertionException&) { // NOLINT
+ // This failure was reported already.
} catch (const internal::GoogleTestFailureException&) { // NOLINT
// This exception type can only be thrown by a failed Google
// Test assertion with the intention of letting another testing
@@ -5201,7 +5203,8 @@ static const char kColorEncodedHelpMessage[] =
" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n"
" Turn assertion failures into debugger break-points.\n"
" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n"
-" Turn assertion failures into C++ exceptions.\n"
+" Turn assertion failures into C++ exceptions for use by an external\n"
+" test framework.\n"
" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n"
" Do not report exceptions as test failures. Instead, allow them\n"
" to crash the program or throw a pop-up (on Windows).\n"
diff --git a/googletest/test/BUILD.bazel b/googletest/test/BUILD.bazel
index 3c700b1..1b81133 100644
--- a/googletest/test/BUILD.bazel
+++ b/googletest/test/BUILD.bazel
@@ -219,6 +219,13 @@ py_test(
deps = [":gtest_test_utils"],
)
+cc_test(
+ name = "gtest_assert_by_exception_test",
+ size = "small",
+ srcs = ["gtest_assert_by_exception_test.cc"],
+ deps = ["//:gtest"],
+)
+
cc_binary(
name = "gtest_throw_on_failure_test_",
testonly = 1,
diff --git a/googletest/test/gtest_assert_by_exception_test.cc b/googletest/test/gtest_assert_by_exception_test.cc
new file mode 100644
index 0000000..2f0e34a
--- /dev/null
+++ b/googletest/test/gtest_assert_by_exception_test.cc
@@ -0,0 +1,119 @@
+// Copyright 2009, 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 Google Test's assert-by-exception mode with exceptions enabled.
+
+#include "gtest/gtest.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdexcept>
+
+class ThrowListener : public testing::EmptyTestEventListener {
+ void OnTestPartResult(const testing::TestPartResult& result) override {
+ if (result.type() == testing::TestPartResult::kFatalFailure) {
+ throw testing::AssertionException(result);
+ }
+ }
+};
+
+// Prints the given failure message and exits the program with
+// non-zero. We use this instead of a Google Test assertion to
+// indicate a failure, as the latter is been tested and cannot be
+// relied on.
+void Fail(const char* msg) {
+ printf("FAILURE: %s\n", msg);
+ fflush(stdout);
+ exit(1);
+}
+
+static void AssertFalse() {
+ ASSERT_EQ(2, 3) << "Expected failure";
+}
+
+// Tests that an assertion failure throws a subclass of
+// std::runtime_error.
+TEST(Test, Test) {
+ // A successful assertion shouldn't throw.
+ try {
+ EXPECT_EQ(3, 3);
+ } catch(...) {
+ Fail("A successful assertion wrongfully threw.");
+ }
+
+ // A successful assertion shouldn't throw.
+ try {
+ EXPECT_EQ(3, 4);
+ } catch(...) {
+ Fail("A failed non-fatal assertion wrongfully threw.");
+ }
+
+ // A failed assertion should throw.
+ try {
+ AssertFalse();
+ } catch(const testing::AssertionException& e) {
+ if (strstr(e.what(), "Expected failure") != NULL)
+ throw;
+
+ printf("%s",
+ "A failed assertion did throw an exception of the right type, "
+ "but the message is incorrect. Instead of containing \"Expected "
+ "failure\", it is:\n");
+ Fail(e.what());
+ } catch(...) {
+ Fail("A failed assertion threw the wrong type of exception.");
+ }
+ Fail("A failed assertion should've thrown but didn't.");
+}
+
+int kTestForContinuingTest = 0;
+
+TEST(Test, Test2) {
+ // FIXME(sokolov): how to force Test2 to be after Test?
+ kTestForContinuingTest = 1;
+}
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ testing::UnitTest::GetInstance()->listeners().Append(new ThrowListener);
+
+ int result = RUN_ALL_TESTS();
+ if (result == 0) {
+ printf("RUN_ALL_TESTS returned %d\n", result);
+ Fail("Expected failure instead.");
+ }
+
+ if (kTestForContinuingTest == 0) {
+ Fail("Should have continued with other tests, but did not.");
+ }
+ return 0;
+}