[dawn] Add more tests of buffer mapping and device loss/destroy

Bug: 42240407, 492139412
Change-Id: Ifef5b6a0e0219c7833a364b629d03b357ed42b89
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/297055
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/tests/end2end/DeviceLostTests.cpp b/src/dawn/tests/end2end/DeviceLostTests.cpp
index a2befd3..df99544 100644
--- a/src/dawn/tests/end2end/DeviceLostTests.cpp
+++ b/src/dawn/tests/end2end/DeviceLostTests.cpp
@@ -407,6 +407,9 @@
     ExpectObjectIsError(buffer);
 
     ASSERT_NE(buffer.GetMappedRange(), nullptr);
+
+    // Write to the range as it should still point to valid memory.
+    *static_cast<uint32_t*>(buffer.GetMappedRange()) = 42;
 }
 
 // Test that device loss doesn't change the result of GetMappedRange, mappedAtCreation version.
@@ -422,6 +425,9 @@
 
     ASSERT_NE(buffer.GetMappedRange(), nullptr);
     ASSERT_EQ(buffer.GetMappedRange(), rangeBeforeLoss);
+
+    // Write to the range as it should still point to valid memory.
+    *static_cast<uint32_t*>(buffer.GetMappedRange()) = 42;
 }
 
 // Test that device loss doesn't change the result of GetMappedRange, mapping for reading version.
@@ -439,6 +445,14 @@
 
     ASSERT_NE(buffer.GetConstMappedRange(), nullptr);
     ASSERT_EQ(buffer.GetConstMappedRange(), rangeBeforeLoss);
+
+    if (!IsNull()) {
+        // Read from the range as it should still point to valid memory. Also check the value to
+        // force the compiler to keep the read. The null backend doesn't do zero init so we skip
+        // there.
+        uint32_t zero = *static_cast<const uint32_t*>(buffer.GetConstMappedRange());
+        ASSERT_EQ(zero, 0u);
+    }
 }
 
 // Test that device loss doesn't change the result of GetMappedRange, mapping for writing version.
@@ -456,6 +470,9 @@
 
     ASSERT_NE(buffer.GetConstMappedRange(), nullptr);
     ASSERT_EQ(buffer.GetConstMappedRange(), rangeBeforeLoss);
+
+    // Write to the range as it should still point to valid memory.
+    *static_cast<uint32_t*>(buffer.GetMappedRange()) = 42;
 }
 
 // TODO(dawn:929): mapasync read + resolve + loss getmappedrange != nullptr.
diff --git a/src/dawn/tests/unittests/validation/BufferValidationTests.cpp b/src/dawn/tests/unittests/validation/BufferValidationTests.cpp
index 2fb47dc..716f0bf 100644
--- a/src/dawn/tests/unittests/validation/BufferValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/BufferValidationTests.cpp
@@ -562,6 +562,42 @@
     WaitForAllOperations();
 }
 
+// Test that destroying the device cancels the mapping operation.
+TEST_P(BufferMappingValidationTest, DestroyDeviceWhilePending) {
+    wgpu::Buffer buffer = CreateBuffer(4);
+
+    MockMapAsyncCallback mockCb;
+    EXPECT_CALL(mockCb, Call(wgpu::MapAsyncStatus::Aborted, _)).Times(1);
+    buffer.MapAsync(GetParam(), 0, 4, wgpu::CallbackMode::AllowProcessEvents, mockCb.Callback());
+
+    ExpectDeviceDestruction();
+    device.Destroy();
+
+    WaitForAllOperations();
+    ASSERT_EQ(wgpu::BufferMapState::Unmapped, buffer.GetMapState());
+}
+
+// Test that destroying the device cancels the mapping operation.
+TEST_P(BufferMappingValidationTest, DestroyDeviceAfterMapping) {
+    // TODO(https://crbug.com/42240407): Unmap buffers in the wire client when
+    // device.Destroy() is called.
+    DAWN_SKIP_TEST_IF(UsesWire());
+
+    wgpu::Buffer buffer = CreateBuffer(4);
+
+    MockMapAsyncCallback mockCb;
+    EXPECT_CALL(mockCb, Call(wgpu::MapAsyncStatus::Success, _)).Times(1);
+    buffer.MapAsync(GetParam(), 0, 4, wgpu::CallbackMode::AllowProcessEvents, mockCb.Callback());
+    WaitForAllOperations();
+
+    ASSERT_EQ(wgpu::BufferMapState::Mapped, buffer.GetMapState());
+
+    ExpectDeviceDestruction();
+    device.Destroy();
+
+    ASSERT_EQ(wgpu::BufferMapState::Unmapped, buffer.GetMapState());
+}
+
 // Test the success case for mappedAtCreation
 TEST_F(BufferValidationTest, MappedAtCreationSuccess) {
     BufferMappedAtCreation(4, wgpu::BufferUsage::MapWrite);
@@ -596,6 +632,22 @@
     }
 }
 
+// Test that destroying the device cancels the mapping operation.
+TEST_F(BufferValidationTest, MappedAtCreationThenDestroyDevice) {
+    // TODO(https://crbug.com/42240407): Unmap buffers in the wire client when
+    // device.Destroy() is called.
+    DAWN_SKIP_TEST_IF(UsesWire());
+
+    wgpu::Buffer buffer = BufferMappedAtCreation(4, wgpu::BufferUsage::CopySrc);
+
+    ASSERT_EQ(wgpu::BufferMapState::Mapped, buffer.GetMapState());
+
+    ExpectDeviceDestruction();
+    device.Destroy();
+
+    ASSERT_EQ(wgpu::BufferMapState::Unmapped, buffer.GetMapState());
+}
+
 // Test that it is valid to destroy an error buffer
 TEST_F(BufferValidationTest, DestroyErrorBuffer) {
     wgpu::BufferDescriptor desc;
diff --git a/src/dawn/tests/unittests/validation/CommandBufferValidationTests.cpp b/src/dawn/tests/unittests/validation/CommandBufferValidationTests.cpp
index 55244d5..b4bd8ff 100644
--- a/src/dawn/tests/unittests/validation/CommandBufferValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/CommandBufferValidationTests.cpp
@@ -414,11 +414,10 @@
     }
 }
 
+// Test having the device destroyed before encoding.
 TEST_F(CommandBufferValidationTest, EncodeAfterDeviceDestroyed) {
     PlaceholderRenderPass placeholderRenderPass(device);
 
-    // Device destroyed before encoding.
-    {
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
         ExpectDeviceDestruction();
         device.Destroy();
@@ -427,19 +426,20 @@
         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
         pass.End();
         encoder.Finish();
-    }
+}
 
-    // Device destroyed after encoding.
-    {
-        ExpectDeviceDestruction();
-        device.Destroy();
-        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
-        // The encoder should not accessing any device info if device is destroyed when try
-        // encoding.
-        wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
-        pass.End();
-        encoder.Finish();
-    }
+// Test having the device destroyed after encoding but before Finish().
+TEST_F(CommandBufferValidationTest, FinishAfterDeviceDestroyed) {
+    PlaceholderRenderPass placeholderRenderPass(device);
+
+    ExpectDeviceDestruction();
+    device.Destroy();
+    wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+    // The encoder should not accessing any device info if device is destroyed when try
+    // encoding.
+    wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
+    pass.End();
+    encoder.Finish();
 }
 
 // Test that an error is produced when encoding happens after ending a pass.