Googletest export
Accept gmock matchers in EXPECT_EXIT and friends to allow matches other than simple regex matches on death output. PiperOrigin-RevId: 223035409
This commit is contained in:
parent
191f9336bc
commit
b22d23667b
@ -97,77 +97,6 @@ class StringMatchResultListener : public MatchResultListener {
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener);
|
||||
};
|
||||
|
||||
// The PolymorphicMatcher class template makes it easy to implement a
|
||||
// polymorphic matcher (i.e. a matcher that can match values of more
|
||||
// than one type, e.g. Eq(n) and NotNull()).
|
||||
//
|
||||
// To define a polymorphic matcher, a user should provide an Impl
|
||||
// class that has a DescribeTo() method and a DescribeNegationTo()
|
||||
// method, and define a member function (or member function template)
|
||||
//
|
||||
// bool MatchAndExplain(const Value& value,
|
||||
// MatchResultListener* listener) const;
|
||||
//
|
||||
// See the definition of NotNull() for a complete example.
|
||||
template <class Impl>
|
||||
class PolymorphicMatcher {
|
||||
public:
|
||||
explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {}
|
||||
|
||||
// Returns a mutable reference to the underlying matcher
|
||||
// implementation object.
|
||||
Impl& mutable_impl() { return impl_; }
|
||||
|
||||
// Returns an immutable reference to the underlying matcher
|
||||
// implementation object.
|
||||
const Impl& impl() const { return impl_; }
|
||||
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
return Matcher<T>(new MonomorphicImpl<GTEST_REFERENCE_TO_CONST_(T)>(impl_));
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
class MonomorphicImpl : public MatcherInterface<T> {
|
||||
public:
|
||||
explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
|
||||
|
||||
virtual void DescribeTo(::std::ostream* os) const {
|
||||
impl_.DescribeTo(os);
|
||||
}
|
||||
|
||||
virtual void DescribeNegationTo(::std::ostream* os) const {
|
||||
impl_.DescribeNegationTo(os);
|
||||
}
|
||||
|
||||
virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
|
||||
return impl_.MatchAndExplain(x, listener);
|
||||
}
|
||||
|
||||
private:
|
||||
const Impl impl_;
|
||||
|
||||
GTEST_DISALLOW_ASSIGN_(MonomorphicImpl);
|
||||
};
|
||||
|
||||
Impl impl_;
|
||||
|
||||
GTEST_DISALLOW_ASSIGN_(PolymorphicMatcher);
|
||||
};
|
||||
|
||||
// Creates a polymorphic matcher from its implementation. This is
|
||||
// easier to use than the PolymorphicMatcher<Impl> constructor as it
|
||||
// doesn't require you to explicitly write the template argument, e.g.
|
||||
//
|
||||
// MakePolymorphicMatcher(foo);
|
||||
// vs
|
||||
// PolymorphicMatcher<TypeOfFoo>(foo);
|
||||
template <class Impl>
|
||||
inline PolymorphicMatcher<Impl> MakePolymorphicMatcher(const Impl& impl) {
|
||||
return PolymorphicMatcher<Impl>(impl);
|
||||
}
|
||||
|
||||
// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION
|
||||
// and MUST NOT BE USED IN USER CODE!!!
|
||||
namespace internal {
|
||||
@ -976,62 +905,6 @@ class EndsWithMatcher {
|
||||
GTEST_DISALLOW_ASSIGN_(EndsWithMatcher);
|
||||
};
|
||||
|
||||
// Implements polymorphic matchers MatchesRegex(regex) and
|
||||
// ContainsRegex(regex), which can be used as a Matcher<T> as long as
|
||||
// T can be converted to a string.
|
||||
class MatchesRegexMatcher {
|
||||
public:
|
||||
MatchesRegexMatcher(const RE* regex, bool full_match)
|
||||
: regex_(regex), full_match_(full_match) {}
|
||||
|
||||
#if GTEST_HAS_ABSL
|
||||
bool MatchAndExplain(const absl::string_view& s,
|
||||
MatchResultListener* listener) const {
|
||||
return MatchAndExplain(string(s), listener);
|
||||
}
|
||||
#endif // GTEST_HAS_ABSL
|
||||
|
||||
// Accepts pointer types, particularly:
|
||||
// const char*
|
||||
// char*
|
||||
// const wchar_t*
|
||||
// wchar_t*
|
||||
template <typename CharType>
|
||||
bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
|
||||
return s != nullptr && MatchAndExplain(std::string(s), listener);
|
||||
}
|
||||
|
||||
// Matches anything that can convert to std::string.
|
||||
//
|
||||
// This is a template, not just a plain function with const std::string&,
|
||||
// because absl::string_view has some interfering non-explicit constructors.
|
||||
template <class MatcheeStringType>
|
||||
bool MatchAndExplain(const MatcheeStringType& s,
|
||||
MatchResultListener* /* listener */) const {
|
||||
const std::string& s2(s);
|
||||
return full_match_ ? RE::FullMatch(s2, *regex_) :
|
||||
RE::PartialMatch(s2, *regex_);
|
||||
}
|
||||
|
||||
void DescribeTo(::std::ostream* os) const {
|
||||
*os << (full_match_ ? "matches" : "contains")
|
||||
<< " regular expression ";
|
||||
UniversalPrinter<std::string>::Print(regex_->pattern(), os);
|
||||
}
|
||||
|
||||
void DescribeNegationTo(::std::ostream* os) const {
|
||||
*os << "doesn't " << (full_match_ ? "match" : "contain")
|
||||
<< " regular expression ";
|
||||
UniversalPrinter<std::string>::Print(regex_->pattern(), os);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::shared_ptr<const RE> regex_;
|
||||
const bool full_match_;
|
||||
|
||||
GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher);
|
||||
};
|
||||
|
||||
// Implements a matcher that compares the two fields of a 2-tuple
|
||||
// using one of the ==, <=, <, etc, operators. The two fields being
|
||||
// compared don't have to have the same type.
|
||||
@ -3935,28 +3808,6 @@ inline PolymorphicMatcher<internal::EndsWithMatcher<std::string> > EndsWith(
|
||||
return MakePolymorphicMatcher(internal::EndsWithMatcher<std::string>(suffix));
|
||||
}
|
||||
|
||||
// Matches a string that fully matches regular expression 'regex'.
|
||||
// The matcher takes ownership of 'regex'.
|
||||
inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
|
||||
const internal::RE* regex) {
|
||||
return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true));
|
||||
}
|
||||
inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
|
||||
const std::string& regex) {
|
||||
return MatchesRegex(new internal::RE(regex));
|
||||
}
|
||||
|
||||
// Matches a string that contains regular expression 'regex'.
|
||||
// The matcher takes ownership of 'regex'.
|
||||
inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
|
||||
const internal::RE* regex) {
|
||||
return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false));
|
||||
}
|
||||
inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
|
||||
const std::string& regex) {
|
||||
return ContainsRegex(new internal::RE(regex));
|
||||
}
|
||||
|
||||
#if GTEST_HAS_GLOBAL_WSTRING || GTEST_HAS_STD_WSTRING
|
||||
// Wide string matchers.
|
||||
|
||||
|
@ -43,9 +43,9 @@
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest-printers.h"
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/gtest-printers.h"
|
||||
|
||||
GTEST_DISABLE_MSC_WARNINGS_PUSH_(
|
||||
4251 5046 /* class A needs to have dll-interface to be used by clients of
|
||||
@ -508,6 +508,63 @@ std::ostream& operator<<(std::ostream& os, const Matcher<T>& matcher) {
|
||||
return os;
|
||||
}
|
||||
|
||||
// The PolymorphicMatcher class template makes it easy to implement a
|
||||
// polymorphic matcher (i.e. a matcher that can match values of more
|
||||
// than one type, e.g. Eq(n) and NotNull()).
|
||||
//
|
||||
// To define a polymorphic matcher, a user should provide an Impl
|
||||
// class that has a DescribeTo() method and a DescribeNegationTo()
|
||||
// method, and define a member function (or member function template)
|
||||
//
|
||||
// bool MatchAndExplain(const Value& value,
|
||||
// MatchResultListener* listener) const;
|
||||
//
|
||||
// See the definition of NotNull() for a complete example.
|
||||
template <class Impl>
|
||||
class PolymorphicMatcher {
|
||||
public:
|
||||
explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {}
|
||||
|
||||
// Returns a mutable reference to the underlying matcher
|
||||
// implementation object.
|
||||
Impl& mutable_impl() { return impl_; }
|
||||
|
||||
// Returns an immutable reference to the underlying matcher
|
||||
// implementation object.
|
||||
const Impl& impl() const { return impl_; }
|
||||
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
return Matcher<T>(new MonomorphicImpl<GTEST_REFERENCE_TO_CONST_(T)>(impl_));
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
class MonomorphicImpl : public MatcherInterface<T> {
|
||||
public:
|
||||
explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
|
||||
|
||||
virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); }
|
||||
|
||||
virtual void DescribeNegationTo(::std::ostream* os) const {
|
||||
impl_.DescribeNegationTo(os);
|
||||
}
|
||||
|
||||
virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
|
||||
return impl_.MatchAndExplain(x, listener);
|
||||
}
|
||||
|
||||
private:
|
||||
const Impl impl_;
|
||||
|
||||
GTEST_DISALLOW_ASSIGN_(MonomorphicImpl);
|
||||
};
|
||||
|
||||
Impl impl_;
|
||||
|
||||
GTEST_DISALLOW_ASSIGN_(PolymorphicMatcher);
|
||||
};
|
||||
|
||||
// Creates a matcher from its implementation. This is easier to use
|
||||
// than the Matcher<T> constructor as it doesn't require you to
|
||||
// explicitly write the template argument, e.g.
|
||||
@ -520,6 +577,18 @@ inline Matcher<T> MakeMatcher(const MatcherInterface<T>* impl) {
|
||||
return Matcher<T>(impl);
|
||||
}
|
||||
|
||||
// Creates a polymorphic matcher from its implementation. This is
|
||||
// easier to use than the PolymorphicMatcher<Impl> constructor as it
|
||||
// doesn't require you to explicitly write the template argument, e.g.
|
||||
//
|
||||
// MakePolymorphicMatcher(foo);
|
||||
// vs
|
||||
// PolymorphicMatcher<TypeOfFoo>(foo);
|
||||
template <class Impl>
|
||||
inline PolymorphicMatcher<Impl> MakePolymorphicMatcher(const Impl& impl) {
|
||||
return PolymorphicMatcher<Impl>(impl);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
// Implements a matcher that compares a given value with a
|
||||
// pre-supplied value using one of the ==, <=, <, etc, operators. The
|
||||
@ -613,8 +682,85 @@ class GeMatcher : public ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe> {
|
||||
static const char* Desc() { return "is >="; }
|
||||
static const char* NegatedDesc() { return "isn't >="; }
|
||||
};
|
||||
|
||||
// Implements polymorphic matchers MatchesRegex(regex) and
|
||||
// ContainsRegex(regex), which can be used as a Matcher<T> as long as
|
||||
// T can be converted to a string.
|
||||
class MatchesRegexMatcher {
|
||||
public:
|
||||
MatchesRegexMatcher(const RE* regex, bool full_match)
|
||||
: regex_(regex), full_match_(full_match) {}
|
||||
|
||||
#if GTEST_HAS_ABSL
|
||||
bool MatchAndExplain(const absl::string_view& s,
|
||||
MatchResultListener* listener) const {
|
||||
return MatchAndExplain(string(s), listener);
|
||||
}
|
||||
#endif // GTEST_HAS_ABSL
|
||||
|
||||
// Accepts pointer types, particularly:
|
||||
// const char*
|
||||
// char*
|
||||
// const wchar_t*
|
||||
// wchar_t*
|
||||
template <typename CharType>
|
||||
bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
|
||||
return s != nullptr && MatchAndExplain(std::string(s), listener);
|
||||
}
|
||||
|
||||
// Matches anything that can convert to std::string.
|
||||
//
|
||||
// This is a template, not just a plain function with const std::string&,
|
||||
// because absl::string_view has some interfering non-explicit constructors.
|
||||
template <class MatcheeStringType>
|
||||
bool MatchAndExplain(const MatcheeStringType& s,
|
||||
MatchResultListener* /* listener */) const {
|
||||
const std::string& s2(s);
|
||||
return full_match_ ? RE::FullMatch(s2, *regex_)
|
||||
: RE::PartialMatch(s2, *regex_);
|
||||
}
|
||||
|
||||
void DescribeTo(::std::ostream* os) const {
|
||||
*os << (full_match_ ? "matches" : "contains") << " regular expression ";
|
||||
UniversalPrinter<std::string>::Print(regex_->pattern(), os);
|
||||
}
|
||||
|
||||
void DescribeNegationTo(::std::ostream* os) const {
|
||||
*os << "doesn't " << (full_match_ ? "match" : "contain")
|
||||
<< " regular expression ";
|
||||
UniversalPrinter<std::string>::Print(regex_->pattern(), os);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::shared_ptr<const RE> regex_;
|
||||
const bool full_match_;
|
||||
|
||||
GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher);
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
// Matches a string that fully matches regular expression 'regex'.
|
||||
// The matcher takes ownership of 'regex'.
|
||||
inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
|
||||
const internal::RE* regex) {
|
||||
return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true));
|
||||
}
|
||||
inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
|
||||
const std::string& regex) {
|
||||
return MatchesRegex(new internal::RE(regex));
|
||||
}
|
||||
|
||||
// Matches a string that contains regular expression 'regex'.
|
||||
// The matcher takes ownership of 'regex'.
|
||||
inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
|
||||
const internal::RE* regex) {
|
||||
return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false));
|
||||
}
|
||||
inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
|
||||
const std::string& regex) {
|
||||
return ContainsRegex(new internal::RE(regex));
|
||||
}
|
||||
|
||||
// Creates a polymorphic matcher that matches anything equal to x.
|
||||
// Note: if the parameter of Eq() were declared as const T&, Eq("foo")
|
||||
// wouldn't compile.
|
||||
|
@ -36,6 +36,7 @@
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
||||
|
||||
#include "gtest/gtest-matchers.h"
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@ -79,7 +80,7 @@ class GTEST_API_ DeathTest {
|
||||
// argument is set. If the death test should be skipped, the pointer
|
||||
// is set to NULL; otherwise, it is set to the address of a new concrete
|
||||
// DeathTest object that controls the execution of the current test.
|
||||
static bool Create(const char* statement, const RE* regex,
|
||||
static bool Create(const char* statement, Matcher<const std::string&> matcher,
|
||||
const char* file, int line, DeathTest** test);
|
||||
DeathTest();
|
||||
virtual ~DeathTest() { }
|
||||
@ -145,21 +146,51 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
|
||||
class DeathTestFactory {
|
||||
public:
|
||||
virtual ~DeathTestFactory() { }
|
||||
virtual bool Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test) = 0;
|
||||
virtual bool Create(const char* statement,
|
||||
Matcher<const std::string&> matcher, const char* file,
|
||||
int line, DeathTest** test) = 0;
|
||||
};
|
||||
|
||||
// A concrete DeathTestFactory implementation for normal use.
|
||||
class DefaultDeathTestFactory : public DeathTestFactory {
|
||||
public:
|
||||
virtual bool Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test);
|
||||
virtual bool Create(const char* statement,
|
||||
Matcher<const std::string&> matcher, const char* file,
|
||||
int line, DeathTest** test);
|
||||
};
|
||||
|
||||
// Returns true if exit_status describes a process that was terminated
|
||||
// by a signal, or exited normally with a nonzero exit code.
|
||||
GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
||||
|
||||
// A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads
|
||||
// and interpreted as a regex (rather than an Eq matcher) for legacy
|
||||
// compatibility.
|
||||
inline Matcher<const ::std::string&> MakeDeathTestMatcher(
|
||||
::testing::internal::RE regex) {
|
||||
return ContainsRegex(regex.pattern());
|
||||
}
|
||||
inline Matcher<const ::std::string&> MakeDeathTestMatcher(const char* regex) {
|
||||
return ContainsRegex(regex);
|
||||
}
|
||||
inline Matcher<const ::std::string&> MakeDeathTestMatcher(
|
||||
const ::std::string& regex) {
|
||||
return ContainsRegex(regex);
|
||||
}
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
inline Matcher<const ::std::string&> MakeDeathTestMatcher(
|
||||
const ::string& regex) {
|
||||
return ContainsRegex(regex);
|
||||
}
|
||||
#endif
|
||||
|
||||
// If a Matcher<const ::std::string&> is passed to EXPECT_DEATH (etc.), it's
|
||||
// used directly.
|
||||
inline Matcher<const ::std::string&> MakeDeathTestMatcher(
|
||||
Matcher<const ::std::string&> matcher) {
|
||||
return matcher;
|
||||
}
|
||||
|
||||
// Traps C++ exceptions escaping statement and reports them as test
|
||||
// failures. Note that trapping SEH exceptions is not implemented here.
|
||||
# if GTEST_HAS_EXCEPTIONS
|
||||
@ -187,37 +218,37 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
||||
|
||||
// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
|
||||
// ASSERT_EXIT*, and EXPECT_EXIT*.
|
||||
#define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
const ::testing::internal::RE& gtest_regex = (regex); \
|
||||
::testing::internal::DeathTest* gtest_dt; \
|
||||
if (!::testing::internal::DeathTest::Create( \
|
||||
#statement, >est_regex, __FILE__, __LINE__, >est_dt)) { \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||
} \
|
||||
if (gtest_dt != nullptr) { \
|
||||
std::unique_ptr< ::testing::internal::DeathTest> \
|
||||
gtest_dt_ptr(gtest_dt); \
|
||||
switch (gtest_dt->AssumeRole()) { \
|
||||
case ::testing::internal::DeathTest::OVERSEE_TEST: \
|
||||
if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||
} \
|
||||
break; \
|
||||
case ::testing::internal::DeathTest::EXECUTE_TEST: { \
|
||||
::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \
|
||||
gtest_dt); \
|
||||
GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
|
||||
gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else \
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \
|
||||
#define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
::testing::internal::DeathTest* gtest_dt; \
|
||||
if (!::testing::internal::DeathTest::Create( \
|
||||
#statement, \
|
||||
::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \
|
||||
__FILE__, __LINE__, >est_dt)) { \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||
} \
|
||||
if (gtest_dt != nullptr) { \
|
||||
std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \
|
||||
switch (gtest_dt->AssumeRole()) { \
|
||||
case ::testing::internal::DeathTest::OVERSEE_TEST: \
|
||||
if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||
} \
|
||||
break; \
|
||||
case ::testing::internal::DeathTest::EXECUTE_TEST: { \
|
||||
::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \
|
||||
gtest_dt); \
|
||||
GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
|
||||
gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else \
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \
|
||||
: fail(::testing::internal::DeathTest::LastMessage())
|
||||
// The symbol "fail" here expands to something into which a message
|
||||
// can be streamed.
|
||||
@ -227,14 +258,13 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
||||
// must accept a streamed message even though the message is never printed.
|
||||
// The regex object is not evaluated, but it is used to prevent "unused"
|
||||
// warnings and to avoid an expression that doesn't compile in debug mode.
|
||||
#define GTEST_EXECUTE_STATEMENT_(statement, regex) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} else if (!::testing::internal::AlwaysTrue()) { \
|
||||
const ::testing::internal::RE& gtest_regex = (regex); \
|
||||
static_cast<void>(gtest_regex); \
|
||||
} else \
|
||||
#define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} else if (!::testing::internal::AlwaysTrue()) { \
|
||||
::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \
|
||||
} else \
|
||||
::testing::Message()
|
||||
|
||||
// A class representing the parsed contents of the
|
||||
|
@ -31,6 +31,9 @@
|
||||
// This file implements death tests.
|
||||
|
||||
#include "gtest/gtest-death-test.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/internal/custom/gtest.h"
|
||||
|
||||
@ -374,10 +377,11 @@ DeathTest::DeathTest() {
|
||||
|
||||
// Creates and returns a death test by dispatching to the current
|
||||
// death test factory.
|
||||
bool DeathTest::Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test) {
|
||||
bool DeathTest::Create(const char* statement,
|
||||
Matcher<const std::string&> matcher, const char* file,
|
||||
int line, DeathTest** test) {
|
||||
return GetUnitTestImpl()->death_test_factory()->Create(
|
||||
statement, regex, file, line, test);
|
||||
statement, std::move(matcher), file, line, test);
|
||||
}
|
||||
|
||||
const char* DeathTest::LastMessage() {
|
||||
@ -393,9 +397,9 @@ std::string DeathTest::last_death_test_message_;
|
||||
// Provides cross platform implementation for some death functionality.
|
||||
class DeathTestImpl : public DeathTest {
|
||||
protected:
|
||||
DeathTestImpl(const char* a_statement, const RE* a_regex)
|
||||
DeathTestImpl(const char* a_statement, Matcher<const std::string&> matcher)
|
||||
: statement_(a_statement),
|
||||
regex_(a_regex),
|
||||
matcher_(std::move(matcher)),
|
||||
spawned_(false),
|
||||
status_(-1),
|
||||
outcome_(IN_PROGRESS),
|
||||
@ -409,7 +413,6 @@ class DeathTestImpl : public DeathTest {
|
||||
virtual bool Passed(bool status_ok);
|
||||
|
||||
const char* statement() const { return statement_; }
|
||||
const RE* regex() const { return regex_; }
|
||||
bool spawned() const { return spawned_; }
|
||||
void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
|
||||
int status() const { return status_; }
|
||||
@ -434,9 +437,8 @@ class DeathTestImpl : public DeathTest {
|
||||
// The textual content of the code this object is testing. This class
|
||||
// doesn't own this string and should not attempt to delete it.
|
||||
const char* const statement_;
|
||||
// The regular expression which test output must match. DeathTestImpl
|
||||
// doesn't own this object and should not attempt to delete it.
|
||||
const RE* const regex_;
|
||||
// A matcher that's expected to match the stderr output by the child process.
|
||||
Matcher<const std::string&> matcher_;
|
||||
// True if the death test child process has been successfully spawned.
|
||||
bool spawned_;
|
||||
// The exit status of the child process.
|
||||
@ -555,9 +557,8 @@ static ::std::string FormatDeathTestOutput(const ::std::string& output) {
|
||||
// in the format specified by wait(2). On Windows, this is the
|
||||
// value supplied to the ExitProcess() API or a numeric code
|
||||
// of the exception that terminated the program.
|
||||
// regex: A regular expression object to be applied to
|
||||
// the test's captured standard error output; the death test
|
||||
// fails if it does not match.
|
||||
// matcher_: A matcher that's expected to match the stderr output by the child
|
||||
// process.
|
||||
//
|
||||
// Argument:
|
||||
// status_ok: true if exit_status is acceptable in the context of
|
||||
@ -591,18 +592,15 @@ bool DeathTestImpl::Passed(bool status_ok) {
|
||||
break;
|
||||
case DIED:
|
||||
if (status_ok) {
|
||||
# if GTEST_USES_PCRE
|
||||
// PCRE regexes support embedded NULs.
|
||||
const bool matched = RE::PartialMatch(error_message, *regex());
|
||||
# else
|
||||
const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
|
||||
# endif // GTEST_USES_PCRE
|
||||
if (matched) {
|
||||
if (matcher_.Matches(error_message)) {
|
||||
success = true;
|
||||
} else {
|
||||
std::ostringstream stream;
|
||||
matcher_.DescribeTo(&stream);
|
||||
buffer << " Result: died but not with expected error.\n"
|
||||
<< " Expected: " << regex()->pattern() << "\n"
|
||||
<< "Actual msg:\n" << FormatDeathTestOutput(error_message);
|
||||
<< " Expected: " << stream.str() << "\n"
|
||||
<< "Actual msg:\n"
|
||||
<< FormatDeathTestOutput(error_message);
|
||||
}
|
||||
} else {
|
||||
buffer << " Result: died but not with expected exit code:\n"
|
||||
@ -651,11 +649,11 @@ bool DeathTestImpl::Passed(bool status_ok) {
|
||||
//
|
||||
class WindowsDeathTest : public DeathTestImpl {
|
||||
public:
|
||||
WindowsDeathTest(const char* a_statement,
|
||||
const RE* a_regex,
|
||||
const char* file,
|
||||
int line)
|
||||
: DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
|
||||
WindowsDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
|
||||
const char* file, int line)
|
||||
: DeathTestImpl(a_statement, std::move(matcher)),
|
||||
file_(file),
|
||||
line_(line) {}
|
||||
|
||||
// All of these virtual functions are inherited from DeathTest.
|
||||
virtual int Wait();
|
||||
@ -815,11 +813,11 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
|
||||
|
||||
class FuchsiaDeathTest : public DeathTestImpl {
|
||||
public:
|
||||
FuchsiaDeathTest(const char* a_statement,
|
||||
const RE* a_regex,
|
||||
const char* file,
|
||||
int line)
|
||||
: DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
|
||||
FuchsiaDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
|
||||
const char* file, int line)
|
||||
: DeathTestImpl(a_statement, std::move(matcher)),
|
||||
file_(file),
|
||||
line_(line) {}
|
||||
|
||||
// All of these virtual functions are inherited from DeathTest.
|
||||
int Wait() override;
|
||||
@ -1064,7 +1062,7 @@ std::string FuchsiaDeathTest::GetErrorLogs() {
|
||||
// left undefined.
|
||||
class ForkingDeathTest : public DeathTestImpl {
|
||||
public:
|
||||
ForkingDeathTest(const char* statement, const RE* regex);
|
||||
ForkingDeathTest(const char* statement, Matcher<const std::string&> matcher);
|
||||
|
||||
// All of these virtual functions are inherited from DeathTest.
|
||||
virtual int Wait();
|
||||
@ -1078,9 +1076,9 @@ class ForkingDeathTest : public DeathTestImpl {
|
||||
};
|
||||
|
||||
// Constructs a ForkingDeathTest.
|
||||
ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
|
||||
: DeathTestImpl(a_statement, a_regex),
|
||||
child_pid_(-1) {}
|
||||
ForkingDeathTest::ForkingDeathTest(const char* a_statement,
|
||||
Matcher<const std::string&> matcher)
|
||||
: DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {}
|
||||
|
||||
// Waits for the child in a death test to exit, returning its exit
|
||||
// status, or 0 if no child process exists. As a side effect, sets the
|
||||
@ -1101,8 +1099,8 @@ int ForkingDeathTest::Wait() {
|
||||
// in the child process.
|
||||
class NoExecDeathTest : public ForkingDeathTest {
|
||||
public:
|
||||
NoExecDeathTest(const char* a_statement, const RE* a_regex) :
|
||||
ForkingDeathTest(a_statement, a_regex) { }
|
||||
NoExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher)
|
||||
: ForkingDeathTest(a_statement, std::move(matcher)) {}
|
||||
virtual TestRole AssumeRole();
|
||||
};
|
||||
|
||||
@ -1156,9 +1154,11 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() {
|
||||
// only this specific death test to be run.
|
||||
class ExecDeathTest : public ForkingDeathTest {
|
||||
public:
|
||||
ExecDeathTest(const char* a_statement, const RE* a_regex,
|
||||
const char* file, int line) :
|
||||
ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
|
||||
ExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
|
||||
const char* file, int line)
|
||||
: ForkingDeathTest(a_statement, std::move(matcher)),
|
||||
file_(file),
|
||||
line_(line) {}
|
||||
virtual TestRole AssumeRole();
|
||||
private:
|
||||
static ::std::vector<std::string> GetArgvsForDeathTestChildProcess() {
|
||||
@ -1447,7 +1447,8 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
|
||||
// by the "test" argument to its address. If the test should be
|
||||
// skipped, sets that pointer to NULL. Returns true, unless the
|
||||
// flag is set to an invalid value.
|
||||
bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
|
||||
bool DefaultDeathTestFactory::Create(const char* statement,
|
||||
Matcher<const std::string&> matcher,
|
||||
const char* file, int line,
|
||||
DeathTest** test) {
|
||||
UnitTestImpl* const impl = GetUnitTestImpl();
|
||||
@ -1476,22 +1477,22 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
|
||||
|
||||
if (GTEST_FLAG(death_test_style) == "threadsafe" ||
|
||||
GTEST_FLAG(death_test_style) == "fast") {
|
||||
*test = new WindowsDeathTest(statement, regex, file, line);
|
||||
*test = new WindowsDeathTest(statement, std::move(matcher), file, line);
|
||||
}
|
||||
|
||||
# elif GTEST_OS_FUCHSIA
|
||||
|
||||
if (GTEST_FLAG(death_test_style) == "threadsafe" ||
|
||||
GTEST_FLAG(death_test_style) == "fast") {
|
||||
*test = new FuchsiaDeathTest(statement, regex, file, line);
|
||||
*test = new FuchsiaDeathTest(statement, std::move(matcher), file, line);
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
if (GTEST_FLAG(death_test_style) == "threadsafe") {
|
||||
*test = new ExecDeathTest(statement, regex, file, line);
|
||||
*test = new ExecDeathTest(statement, std::move(matcher), file, line);
|
||||
} else if (GTEST_FLAG(death_test_style) == "fast") {
|
||||
*test = new NoExecDeathTest(statement, regex);
|
||||
*test = new NoExecDeathTest(statement, std::move(matcher));
|
||||
}
|
||||
|
||||
# endif // GTEST_OS_WINDOWS
|
||||
|
@ -31,6 +31,8 @@
|
||||
// Tests for death tests.
|
||||
|
||||
#include "gtest/gtest-death-test.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "gtest/internal/gtest-filepath.h"
|
||||
|
||||
@ -59,6 +61,8 @@ using testing::internal::AlwaysTrue;
|
||||
|
||||
namespace posix = ::testing::internal::posix;
|
||||
|
||||
using testing::HasSubstr;
|
||||
using testing::Matcher;
|
||||
using testing::Message;
|
||||
using testing::internal::DeathTest;
|
||||
using testing::internal::DeathTestFactory;
|
||||
@ -97,6 +101,8 @@ class ReplaceDeathTestFactory {
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
namespace {
|
||||
|
||||
void DieWithMessage(const ::std::string& message) {
|
||||
fprintf(stderr, "%s", message.c_str());
|
||||
fflush(stderr); // Make sure the text is printed before the process exits.
|
||||
@ -452,16 +458,12 @@ TEST_F(TestForDeathTest, MixedStyles) {
|
||||
|
||||
# if GTEST_HAS_CLONE && GTEST_HAS_PTHREAD
|
||||
|
||||
namespace {
|
||||
|
||||
bool pthread_flag;
|
||||
|
||||
void SetPthreadFlag() {
|
||||
pthread_flag = true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(TestForDeathTest, DoesNotExecuteAtforkHooks) {
|
||||
if (!testing::GTEST_FLAG(death_test_use_fork)) {
|
||||
testing::GTEST_FLAG(death_test_style) = "threadsafe";
|
||||
@ -885,7 +887,7 @@ class MockDeathTestFactory : public DeathTestFactory {
|
||||
public:
|
||||
MockDeathTestFactory();
|
||||
virtual bool Create(const char* statement,
|
||||
const ::testing::internal::RE* regex,
|
||||
testing::Matcher<const std::string&> matcher,
|
||||
const char* file, int line, DeathTest** test);
|
||||
|
||||
// Sets the parameters for subsequent calls to Create.
|
||||
@ -1000,11 +1002,9 @@ void MockDeathTestFactory::SetParameters(bool create,
|
||||
// Sets test to NULL (if create_ is false) or to the address of a new
|
||||
// MockDeathTest object with parameters taken from the last call
|
||||
// to SetParameters (if create_ is true). Always returns true.
|
||||
bool MockDeathTestFactory::Create(const char* /*statement*/,
|
||||
const ::testing::internal::RE* /*regex*/,
|
||||
const char* /*file*/,
|
||||
int /*line*/,
|
||||
DeathTest** test) {
|
||||
bool MockDeathTestFactory::Create(
|
||||
const char* /*statement*/, testing::Matcher<const std::string&> /*matcher*/,
|
||||
const char* /*file*/, int /*line*/, DeathTest** test) {
|
||||
test_deleted_ = false;
|
||||
if (create_) {
|
||||
*test = new MockDeathTest(this, role_, status_, passed_);
|
||||
@ -1326,8 +1326,60 @@ TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInThreadSafeStyle) {
|
||||
}, "Inside");
|
||||
}
|
||||
|
||||
void DieWithMessage(const char* message) {
|
||||
fputs(message, stderr);
|
||||
fflush(stderr); // Make sure the text is printed before the process exits.
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
TEST(MatcherDeathTest, DoesNotBreakBareRegexMatching) {
|
||||
// googletest tests this, of course; here we ensure that including googlemock
|
||||
// has not broken it.
|
||||
EXPECT_DEATH(DieWithMessage("O, I die, Horatio."), "I d[aeiou]e");
|
||||
}
|
||||
|
||||
TEST(MatcherDeathTest, MonomorphicMatcherMatches) {
|
||||
EXPECT_DEATH(DieWithMessage("Behind O, I am slain!"),
|
||||
Matcher<const std::string&>(HasSubstr("I am slain")));
|
||||
}
|
||||
|
||||
TEST(MatcherDeathTest, MonomorphicMatcherDoesNotMatch) {
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_DEATH(DieWithMessage("Behind O, I am slain!"),
|
||||
Matcher<const std::string&>(HasSubstr("Ow, I am slain"))),
|
||||
"Expected: has substring \"Ow, I am slain\"");
|
||||
}
|
||||
|
||||
TEST(MatcherDeathTest, PolymorphicMatcherMatches) {
|
||||
EXPECT_DEATH(DieWithMessage("The rest is silence."),
|
||||
HasSubstr("rest is silence"));
|
||||
}
|
||||
|
||||
TEST(MatcherDeathTest, PolymorphicMatcherDoesNotMatch) {
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(DieWithMessage("The rest is silence."),
|
||||
HasSubstr("rest is science")),
|
||||
"Expected: has substring \"rest is science\"");
|
||||
}
|
||||
|
||||
TEST(MatcherDeathTest, CompositeMatcherMatches) {
|
||||
EXPECT_DEATH(DieWithMessage("Et tu, Brute! Then fall, Caesar."),
|
||||
AllOf(HasSubstr("Et tu"), HasSubstr("fall, Caesar")));
|
||||
}
|
||||
|
||||
TEST(MatcherDeathTest, CompositeMatcherDoesNotMatch) {
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_DEATH(DieWithMessage("The rest is silence."),
|
||||
AnyOf(HasSubstr("Eat two"), HasSubstr("lol Caesar"))),
|
||||
"Expected: (has substring \"Eat two\") or "
|
||||
"(has substring \"lol Caesar\")");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#else // !GTEST_HAS_DEATH_TEST follows
|
||||
|
||||
namespace {
|
||||
|
||||
using testing::internal::CaptureStderr;
|
||||
using testing::internal::GetCapturedStderr;
|
||||
|
||||
@ -1376,8 +1428,12 @@ TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported) {
|
||||
EXPECT_EQ(1, n);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // !GTEST_HAS_DEATH_TEST
|
||||
|
||||
namespace {
|
||||
|
||||
// Tests that the death test macros expand to code which may or may not
|
||||
// be followed by operator<<, and that in either case the complete text
|
||||
// comprises only a single C++ statement.
|
||||
@ -1428,3 +1484,5 @@ TEST(ConditionalDeathMacrosSyntaxDeathTest, SwitchStatement) {
|
||||
TEST(NotADeathTest, Test) {
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
Loading…
Reference in New Issue
Block a user