diff --git a/impeller/base/validation.cc b/impeller/base/validation.cc index ebba11852489c..987ad4b4e6aa4 100644 --- a/impeller/base/validation.cc +++ b/impeller/base/validation.cc @@ -12,11 +12,16 @@ namespace impeller { static std::atomic_int32_t sValidationLogsDisabledCount = 0; static std::atomic_int32_t sValidationLogsAreFatal = 0; +static ValidationFailureCallback sValidationFailureCallback; void ImpellerValidationErrorsSetFatal(bool fatal) { sValidationLogsAreFatal = fatal; } +void ImpellerValidationErrorsSetCallback(ValidationFailureCallback callback) { + sValidationFailureCallback = std::move(callback); +} + ScopedValidationDisable::ScopedValidationDisable() { sValidationLogsDisabledCount++; } @@ -47,6 +52,10 @@ std::ostream& ValidationLog::GetStream() { } void ImpellerValidationBreak(const char* message, const char* file, int line) { + if (sValidationFailureCallback && + sValidationFailureCallback(message, file, line)) { + return; + } const auto severity = ImpellerValidationErrorsAreFatal() ? fml::LOG_FATAL : fml::LOG_ERROR; auto fml_log = fml::LogMessage{severity, file, line, nullptr}; diff --git a/impeller/base/validation.h b/impeller/base/validation.h index 47ef7c20fc559..789ea8c004aa8 100644 --- a/impeller/base/validation.h +++ b/impeller/base/validation.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_IMPELLER_BASE_VALIDATION_H_ #define FLUTTER_IMPELLER_BASE_VALIDATION_H_ +#include #include namespace impeller { @@ -37,6 +38,21 @@ void ImpellerValidationErrorsSetFatal(bool fatal); bool ImpellerValidationErrorsAreFatal(); +using ValidationFailureCallback = + std::function; + +//------------------------------------------------------------------------------ +/// @brief Sets a callback that callers (usually tests) can set to +/// intercept validation failures. +/// +/// Returning true from the callback indicates that Impeller can +/// continue and avoid any default behavior on tripping validation +/// (which could include process termination). +/// +/// @param[in] callback The callback +/// +void ImpellerValidationErrorsSetCallback(ValidationFailureCallback callback); + struct ScopedValidationDisable { ScopedValidationDisable(); diff --git a/impeller/playground/playground_test.cc b/impeller/playground/playground_test.cc index ce9cf9241b05d..2e5136336a04a 100644 --- a/impeller/playground/playground_test.cc +++ b/impeller/playground/playground_test.cc @@ -11,9 +11,26 @@ namespace impeller { PlaygroundTest::PlaygroundTest() - : Playground(PlaygroundSwitches{flutter::testing::GetArgsForProcess()}) {} + : Playground(PlaygroundSwitches{flutter::testing::GetArgsForProcess()}) { + ImpellerValidationErrorsSetCallback( + [](const char* message, const char* file, int line) -> bool { + // GTEST_MESSAGE_AT_ can only be used in a function that returns void. + // Hence the goofy lambda. The failure message and location will still + // be correct however. + // + // https://google.github.io/googletest/advanced.html#assertion-placement + [message, file, line]() -> void { + GTEST_MESSAGE_AT_(file, line, "Impeller Validation Error", + ::testing::TestPartResult::kFatalFailure) + << message; + }(); + return true; + }); +} -PlaygroundTest::~PlaygroundTest() = default; +PlaygroundTest::~PlaygroundTest() { + ImpellerValidationErrorsSetCallback(nullptr); +} namespace { bool DoesSupportWideGamutTests() { @@ -36,8 +53,6 @@ void PlaygroundTest::SetUp() { return; } - ImpellerValidationErrorsSetFatal(true); - // Test names that end with "WideGamut" will render with wide gamut support. std::string test_name = flutter::testing::GetCurrentTestName(); PlaygroundSwitches switches = switches_;