diff --git a/googlemock/test/gmock-generated-matchers_nc.cc b/googlemock/test/gmock-generated-matchers_nc.cc new file mode 100644 index 00000000..84d98845 --- /dev/null +++ b/googlemock/test/gmock-generated-matchers_nc.cc @@ -0,0 +1,72 @@ +// 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. + + +// Google Mock - a framework for writing C++ mock classes. +// +// This file contains negative compilation tests for script-generated +// Google Mock matchers. + +#include "gmock/gmock.h" + +#if defined(TEST_WRONG_ARG_TYPE_IN_MATCHER_MACRO) + +// Tests using an MATCHER definition to match a value of an +// incompatible type. +MATCHER(WrongArgType, "") { return 10/arg > 2; } + +void Test() { + testing::Matcher m = WrongArgType(); +} + +#elif defined(TEST_MATCHER_MACRO_IN_CLASS) + +// Tests using MATCHER in a class scope. +class Foo { + public: + // This won't compile as C++ doesn't allow defining a method of a + // nested class out-of-line in the enclosing class. + MATCHER(Bar, "") { return arg > 0; } +}; + +#elif defined(TEST_MATCHER_MACRO_IN_FUNCTION) + +// Tests using MATCHER in a function body. +void Test() { + // This won't compile as C++ doesn't allow member templates in local + // classes. We may want to revisit this when C++0x is widely + // implemented. + MATCHER(Bar, "") { return arg > 0; } +} + +#else + +// Sanity check - this should compile. + +#endif diff --git a/googlemock/test/gmock_generated_matchers_nc_test.py b/googlemock/test/gmock_generated_matchers_nc_test.py new file mode 100755 index 00000000..1a2b3b8b --- /dev/null +++ b/googlemock/test/gmock_generated_matchers_nc_test.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# +# 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. + +# Google Mock - a framework for writing C++ mock classes. +# +# This file drives the negative compilation tests for script-generated +# Google Mock matchers. + +"""Driver for the NC tests for script-generated Google Mock matchers.""" + +import os +import sys + +IS_LINUX = os.name == "posix" and os.uname()[0] == "Linux" +if not IS_LINUX: + sys.stderr.write( + "WARNING: Negative compilation tests are not supported on this platform") + sys.exit(0) + +# Suppresses the 'Import not at the top of the file' lint complaint. +# pylint: disable-msg=C6204 +from google3.testing.pybase import fake_target_util +from google3.testing.pybase import googletest +# pylint: enable-msg=C6204 + + +class GMockGeneratedMatcherTest(googletest.TestCase): + """Negative compilation tests for generated Google Mock matchers.""" + + def testCompilerErrors(self): + """Verifies that erroneous code leads to expected compiler messages.""" + + # Defines a list of test specs, where each element is a tuple + # (test name, list of regexes for matching the compiler errors). + test_specs = [ + ("WRONG_ARG_TYPE_IN_MATCHER_MACRO", + [r"invalid operands", + ]), + ("MATCHER_MACRO_IN_CLASS", + [r"cannot define member function.*Bar.*within.*Foo", # GCC + r"MATCHER\(Bar, .*\)", # Clang + ]), + ("MATCHER_MACRO_IN_FUNCTION", + [r"invalid declaration of member template in local class", # GCC + r"templates cannot be declared inside of a local class", # Clang + ]), + ("SANITY", + None), + ] + + fake_target_util.AssertCcCompilerErrors( + self, # The current test case. + "google3/third_party/googletest/googlemock/test/" + "gmock-generated-matchers_nc", # The fake target file. + "gmock-generated-matchers_nc.o", # The sub-target to build. + test_specs # List of test specs. + ) + +if __name__ == "__main__": + googletest.main() diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index 028f21eb..d09ac0a2 100644 --- a/googletest/include/gtest/internal/gtest-internal.h +++ b/googletest/include/gtest/internal/gtest-internal.h @@ -1291,41 +1291,90 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } } else /* NOLINT */ \ static_assert(true, "") // User must have a semicolon after expansion. -#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::ConstCharPtr gtest_msg = "") { \ - bool gtest_caught_expected = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (expected_exception const&) { \ - gtest_caught_expected = true; \ - } \ - catch (...) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws a different type."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - if (!gtest_caught_expected) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws nothing."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ - fail(gtest_msg.value) +#if GTEST_HAS_EXCEPTIONS + +namespace testing { +namespace internal { + +class NeverThrown { + public: + const char* what() const noexcept { + return "this exception should never be thrown"; + } +}; + +} // namespace internal +} // namespace testing + +#if GTEST_HAS_RTTI + +#define GTEST_EXCEPTION_TYPE_(e) ::testing::internal::GetTypeName(typeid(e)) + +#else // GTEST_HAS_RTTI + +#define GTEST_EXCEPTION_TYPE_(e) \ + std::string { "an std::exception-derived error" } + +#endif // GTEST_HAS_RTTI + +#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \ + catch (typename std::conditional< \ + std::is_same::type>::type, \ + std::exception>::value, \ + const ::testing::internal::NeverThrown&, const std::exception&>::type \ + e) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws "; \ + gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \ + gtest_msg.value += " with description \""; \ + gtest_msg.value += e.what(); \ + gtest_msg.value += "\"."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } + +#else // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) + +#endif // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::TrueWithString gtest_msg{}) { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \ + catch (...) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws a different type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else /*NOLINT*/ \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \ + : fail(gtest_msg.value.c_str()) #if GTEST_HAS_EXCEPTIONS -#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ - catch (std::exception const& e) { \ - gtest_msg.value = ( \ - "it throws std::exception-derived exception with description: \"" \ - ); \ - gtest_msg.value += e.what(); \ - gtest_msg.value += "\"."; \ +#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ + catch (std::exception const& e) { \ + gtest_msg.value = "it throws "; \ + gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \ + gtest_msg.value += " with description \""; \ + gtest_msg.value += e.what(); \ + gtest_msg.value += "\"."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index a6d44abd..c5e2def8 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -3345,6 +3345,16 @@ TEST_F(SingleEvaluationTest, OtherCases) { #if GTEST_HAS_EXCEPTIONS +#if GTEST_HAS_RTTI + +#define ERROR_DESC "std::runtime_error" + +#else // GTEST_HAS_RTTI + +#define ERROR_DESC "an std::exception-derived error" + +#endif // GTEST_HAS_RTTI + void ThrowAnInteger() { throw 1; } @@ -3368,31 +3378,38 @@ TEST_F(SingleEvaluationTest, ExceptionTests) { }, bool), "throws a different type"); EXPECT_EQ(2, a_); + // failed EXPECT_THROW, throws runtime error + EXPECT_NONFATAL_FAILURE(EXPECT_THROW({ // NOLINT + a_++; + ThrowRuntimeError("A description"); + }, bool), "throws " ERROR_DESC " with description \"A description\""); + EXPECT_EQ(3, a_); + // failed EXPECT_THROW, throws nothing EXPECT_NONFATAL_FAILURE(EXPECT_THROW(a_++, bool), "throws nothing"); - EXPECT_EQ(3, a_); + EXPECT_EQ(4, a_); // successful EXPECT_NO_THROW EXPECT_NO_THROW(a_++); - EXPECT_EQ(4, a_); + EXPECT_EQ(5, a_); // failed EXPECT_NO_THROW EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW({ // NOLINT a_++; ThrowAnInteger(); }), "it throws"); - EXPECT_EQ(5, a_); + EXPECT_EQ(6, a_); // successful EXPECT_ANY_THROW EXPECT_ANY_THROW({ // NOLINT a_++; ThrowAnInteger(); }); - EXPECT_EQ(6, a_); + EXPECT_EQ(7, a_); // failed EXPECT_ANY_THROW EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(a_++), "it doesn't"); - EXPECT_EQ(7, a_); + EXPECT_EQ(8, a_); } #endif // GTEST_HAS_EXCEPTIONS @@ -3812,6 +3829,12 @@ TEST(AssertionTest, ASSERT_THROW) { ASSERT_THROW(ThrowAnInteger(), bool), "Expected: ThrowAnInteger() throws an exception of type bool.\n" " Actual: it throws a different type."); + EXPECT_FATAL_FAILURE( + ASSERT_THROW(ThrowRuntimeError("A description"), std::logic_error), + "Expected: ThrowRuntimeError(\"A description\") " + "throws an exception of type std::logic_error.\n " + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); # endif EXPECT_FATAL_FAILURE( @@ -3829,8 +3852,8 @@ TEST(AssertionTest, ASSERT_NO_THROW) { EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowRuntimeError("A description")), "Expected: ThrowRuntimeError(\"A description\") " "doesn't throw an exception.\n " - "Actual: it throws std::exception-derived exception " - "with description: \"A description\"."); + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); } // Tests ASSERT_ANY_THROW. @@ -4140,6 +4163,10 @@ TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) { EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(n++), ""); } +TEST(ExpectThrowTest, DoesNotGenerateDuplicateCatchClauseWarning) { + EXPECT_THROW(throw std::exception(), std::exception); +} + TEST(AssertionSyntaxTest, ExceptionAssertionsBehavesLikeSingleStatement) { if (AlwaysFalse()) EXPECT_THROW(ThrowNothing(), bool); @@ -4550,6 +4577,12 @@ TEST(ExpectTest, EXPECT_THROW) { EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool), "Expected: ThrowAnInteger() throws an exception of " "type bool.\n Actual: it throws a different type."); + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowRuntimeError("A description"), + std::logic_error), + "Expected: ThrowRuntimeError(\"A description\") " + "throws an exception of type std::logic_error.\n " + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); EXPECT_NONFATAL_FAILURE( EXPECT_THROW(ThrowNothing(), bool), "Expected: ThrowNothing() throws an exception of type bool.\n" @@ -4565,8 +4598,8 @@ TEST(ExpectTest, EXPECT_NO_THROW) { EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowRuntimeError("A description")), "Expected: ThrowRuntimeError(\"A description\") " "doesn't throw an exception.\n " - "Actual: it throws std::exception-derived exception " - "with description: \"A description\"."); + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); } // Tests EXPECT_ANY_THROW.