From 2dfb3f01e77d1dff4ce611fe8d00c9a11b235f78 Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Thu, 28 Feb 2019 09:45:48 +0000 Subject: [PATCH] DawnTest: Allow checking for device errors. The previous assumption is that all validation tests would be unittests and that the end2end tests would always produce valid sequences of commands. This not true because we can't test the validation of backend-specific entrypoints in the unittests. BUG=dawn:112 Change-Id: I89e2fe017bf3ecf6a83c9e8cdf4324c33f95a721 Reviewed-on: https://dawn-review.googlesource.com/c/5100 Reviewed-by: Kai Ninomiya Reviewed-by: Austin Eng Commit-Queue: Corentin Wallez --- src/tests/DawnTest.cpp | 28 +++++++++++++------ src/tests/DawnTest.h | 15 ++++++++++ src/tests/end2end/BasicTests.cpp | 12 ++++++++ .../unittests/validation/ValidationTest.cpp | 2 ++ 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp index cc667e4767..f512c8aceb 100644 --- a/src/tests/DawnTest.cpp +++ b/src/tests/DawnTest.cpp @@ -52,12 +52,6 @@ namespace { } } - // End2end tests should test valid commands produce the expected result so no error - // should happen. Failure cases should be tested in the validation tests. - void DeviceErrorCauseTestFailure(const char* message, dawnCallbackUserdata) { - FAIL() << "Device level failure: " << message; - } - struct MapReadUserdata { DawnTest* test; size_t slot; @@ -315,8 +309,8 @@ void DawnTest::SetUp() { static_cast(mBinding->GetPreferredSwapChainTextureFormat()), dawn::TextureUsageBit::OutputAttachment, 400, 400); - // The end2end tests should never cause validation errors. These should be tested in unittests. - device.SetErrorCallback(DeviceErrorCauseTestFailure, 0); + device.SetErrorCallback(OnDeviceError, + static_cast(reinterpret_cast(this))); } void DawnTest::TearDown() { @@ -330,6 +324,24 @@ void DawnTest::TearDown() { } } +void DawnTest::StartExpectDeviceError() { + mExpectError = true; + mError = false; +} +bool DawnTest::EndExpectDeviceError() { + mExpectError = false; + return mError; +} + +// static +void DawnTest::OnDeviceError(const char* message, dawnCallbackUserdata userdata) { + DawnTest* self = reinterpret_cast(static_cast(userdata)); + + ASSERT_TRUE(self->mExpectError) << "Got unexpected device error: " << message; + ASSERT_FALSE(self->mError) << "Got two errors in expect block"; + self->mError = true; +} + std::ostringstream& DawnTest::AddBufferExpectation(const char* file, int line, const dawn::Buffer& buffer, diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h index d2daa4bb71..3d2b879711 100644 --- a/src/tests/DawnTest.h +++ b/src/tests/DawnTest.h @@ -41,6 +41,13 @@ sizeof(RGBA8), \ new detail::ExpectEq(expected, (width) * (height))) +// Should only be used to test validation of function that can't be tested by regular validation +// tests; +#define ASSERT_DEVICE_ERROR(statement) \ + StartExpectDeviceError(); \ + statement; \ + ASSERT_TRUE(EndExpectDeviceError()); + struct RGBA8 { constexpr RGBA8() : RGBA8(0, 0, 0, 0) { } @@ -124,6 +131,9 @@ class DawnTest : public ::testing::TestWithParam { bool IsLinux() const; bool IsMacOS() const; + void StartExpectDeviceError(); + bool EndExpectDeviceError(); + protected: dawn::Device device; dawn::Queue queue; @@ -160,6 +170,11 @@ class DawnTest : public ::testing::TestWithParam { std::unique_ptr mS2cBuf; void FlushWire(); + // Tracking for validation errors + static void OnDeviceError(const char* message, dawnCallbackUserdata userdata); + bool mExpectError = false; + bool mError = false; + // MapRead buffers used to get data for the expectations struct ReadbackSlot { dawn::Buffer buffer; diff --git a/src/tests/end2end/BasicTests.cpp b/src/tests/end2end/BasicTests.cpp index 0400e06d3f..cd8c373c5a 100644 --- a/src/tests/end2end/BasicTests.cpp +++ b/src/tests/end2end/BasicTests.cpp @@ -33,4 +33,16 @@ TEST_P(BasicTests, BufferSetSubData) { EXPECT_BUFFER_U32_EQ(value, buffer, 0); } +// Test a validation error for buffer setSubData, but really this is the most basic test possible +// for ASSERT_DEVICE_ERROR +TEST_P(BasicTests, BufferSetSubDataError) { + dawn::BufferDescriptor descriptor; + descriptor.size = 4; + descriptor.usage = dawn::BufferUsageBit::TransferSrc | dawn::BufferUsageBit::TransferDst; + dawn::Buffer buffer = device.CreateBuffer(&descriptor); + + uint8_t value = 187; + ASSERT_DEVICE_ERROR(buffer.SetSubData(1000, sizeof(value), &value)); +} + DAWN_INSTANTIATE_TEST(BasicTests, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend); diff --git a/src/tests/unittests/validation/ValidationTest.cpp b/src/tests/unittests/validation/ValidationTest.cpp index e14a014a46..db344ef275 100644 --- a/src/tests/unittests/validation/ValidationTest.cpp +++ b/src/tests/unittests/validation/ValidationTest.cpp @@ -84,6 +84,7 @@ std::string ValidationTest::GetLastDeviceErrorMessage() const { return mDeviceErrorMessage; } +// static void ValidationTest::OnDeviceError(const char* message, dawnCallbackUserdata userdata) { auto self = reinterpret_cast(static_cast(userdata)); self->mDeviceErrorMessage = message; @@ -100,6 +101,7 @@ void ValidationTest::OnDeviceError(const char* message, dawnCallbackUserdata use self->mError = true; } +// static void ValidationTest::OnBuilderErrorStatus(dawnBuilderErrorStatus status, const char* message, dawn::CallbackUserdata userdata1, dawn::CallbackUserdata userdata2) { auto* self = reinterpret_cast(static_cast(userdata1)); size_t index = static_cast(userdata2);