blob: 743377b2a88321fa4ee98d0cc871ddd647ab308f [file] [log] [blame] [edit]
// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
#include <initializer_list>
#include <unordered_set>
#include <vector>
#include "dawn/common/Constants.h"
#include "dawn/common/StringViewUtils.h"
#include "dawn/tests/MockCallback.h"
#include "dawn/tests/StringViewMatchers.h"
#include "dawn/tests/unittests/wire/WireFutureTest.h"
#include "dawn/tests/unittests/wire/WireTest.h"
#include "dawn/wire/WireClient.h"
#include "dawn/wire/WireServer.h"
#include "webgpu/webgpu_cpp.h"
namespace dawn::wire {
namespace {
using testing::_;
using testing::EmptySizedString;
using testing::InvokeWithoutArgs;
using testing::IsNull;
using testing::NonEmptySizedString;
using testing::NotNull;
using testing::Return;
using testing::SizedString;
using testing::StrEq;
using testing::WithArg;
class WireInstanceBasicTest : public WireTest {};
// Test that an Instance can be reserved and injected into the wire.
TEST_F(WireInstanceBasicTest, ReserveAndInject) {
auto reserved = GetWireClient()->ReserveInstance();
wgpu::Instance instance = wgpu::Instance::Acquire(reserved.instance);
WGPUInstance apiInstance = api.GetNewInstance();
EXPECT_CALL(api, InstanceAddRef(apiInstance));
EXPECT_TRUE(GetWireServer()->InjectInstance(apiInstance, reserved.handle));
instance = nullptr;
EXPECT_CALL(api, InstanceRelease(apiInstance));
FlushClient();
}
using WireInstanceTestBase = WireFutureTest<wgpu::RequestAdapterCallback<void>*>;
class WireInstanceTests : public WireInstanceTestBase {
protected:
void RequestAdapter(wgpu::RequestAdapterOptions const* options) {
this->mFutureIDs.push_back(
instance
.RequestAdapter(options, this->GetParam().callbackMode, this->mMockCb.Callback())
.id);
}
};
DAWN_INSTANTIATE_WIRE_FUTURE_TEST_P(WireInstanceTests);
// Test that RequestAdapterOptions are passed from the client to the server.
TEST_P(WireInstanceTests, RequestAdapterPassesOptions) {
for (auto powerPreference :
{wgpu::PowerPreference::LowPower, wgpu::PowerPreference::HighPerformance}) {
wgpu::RequestAdapterOptions options = {};
options.powerPreference = powerPreference;
RequestAdapter(&options);
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), _))
.WillOnce(WithArg<1>([&](const WGPURequestAdapterOptions* apiOptions) {
EXPECT_EQ(apiOptions->powerPreference,
static_cast<WGPUPowerPreference>(options.powerPreference));
EXPECT_EQ(apiOptions->forceFallbackAdapter, options.forceFallbackAdapter);
api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Error,
nullptr, kEmptyOutputStringView);
}));
FlushClient();
FlushFutures();
ExpectWireCallbacksWhen([&](auto& mockCb) {
EXPECT_CALL(mockCb, Call).Times(1);
FlushCallbacks();
});
}
}
// Test that RequestAdapter forwards the adapter information to the client.
TEST_P(WireInstanceTests, RequestAdapterSuccess) {
wgpu::RequestAdapterOptions options = {};
RequestAdapter(&options);
WGPUAdapterInfo fakeInfo = {};
fakeInfo.vendor = ToOutputStringView("fake-vendor");
fakeInfo.architecture = ToOutputStringView("fake-architecture");
fakeInfo.device = ToOutputStringView("fake-device");
fakeInfo.description = ToOutputStringView("fake-description");
fakeInfo.backendType = WGPUBackendType_D3D12;
fakeInfo.adapterType = WGPUAdapterType_IntegratedGPU;
fakeInfo.vendorID = 0x134;
fakeInfo.deviceID = 0x918;
fakeInfo.subgroupMinSize = kDefaultSubgroupMinSize;
fakeInfo.subgroupMaxSize = kDefaultSubgroupMaxSize;
wgpu::Limits fakeLimits = {};
fakeLimits.maxTextureDimension1D = 433;
fakeLimits.maxVertexAttributes = 1243;
std::initializer_list<WGPUFeatureName> fakeFeaturesList = {
WGPUFeatureName_Depth32FloatStencil8,
WGPUFeatureName_TextureCompressionBC,
};
WGPUSupportedFeatures fakeFeatures = {fakeFeaturesList.size(), std::data(fakeFeaturesList)};
// Expect the server to receive the message. Then, mock a fake reply.
WGPUAdapter apiAdapter = api.GetNewAdapter();
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), _))
.WillOnce(InvokeWithoutArgs([&] {
EXPECT_CALL(api, AdapterHasFeature(apiAdapter, _)).WillRepeatedly(Return(false));
EXPECT_CALL(api, AdapterGetInfo(apiAdapter, NotNull()))
.WillOnce(WithArg<1>([&](WGPUAdapterInfo* info) {
*info = fakeInfo;
return WGPUStatus_Success;
}));
EXPECT_CALL(api, AdapterGetLimits(apiAdapter, NotNull()))
.WillOnce(WithArg<1>([&](WGPULimits* limits) {
*reinterpret_cast<wgpu::Limits*>(limits) = fakeLimits;
return WGPUStatus_Success;
}));
EXPECT_CALL(api, AdapterGetFeatures(apiAdapter, NotNull()))
.WillOnce(
WithArg<1>([&](WGPUSupportedFeatures* features) { *features = fakeFeatures; }));
api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Success,
apiAdapter, kEmptyOutputStringView);
}));
FlushClient();
FlushFutures();
// Expect the callback in the client and all the adapter information to match.
ExpectWireCallbacksWhen([&](auto& mockCb) {
EXPECT_CALL(mockCb,
Call(wgpu::RequestAdapterStatus::Success, NotNull(), EmptySizedString()))
.WillOnce(WithArg<1>([&](wgpu::Adapter adapter) {
WGPUAdapterInfo info = {};
adapter.GetInfo(reinterpret_cast<wgpu::AdapterInfo*>(&info));
EXPECT_NE(info.vendor.length, WGPU_STRLEN);
EXPECT_EQ(info.vendor, fakeInfo.vendor);
EXPECT_NE(info.architecture.length, WGPU_STRLEN);
EXPECT_EQ(info.architecture, fakeInfo.architecture);
EXPECT_NE(info.device.length, WGPU_STRLEN);
EXPECT_EQ(info.device, fakeInfo.device);
EXPECT_NE(info.description.length, WGPU_STRLEN);
EXPECT_EQ(info.description, fakeInfo.description);
EXPECT_EQ(info.backendType, fakeInfo.backendType);
EXPECT_EQ(info.adapterType, fakeInfo.adapterType);
EXPECT_EQ(info.vendorID, fakeInfo.vendorID);
EXPECT_EQ(info.deviceID, fakeInfo.deviceID);
EXPECT_EQ(info.subgroupMinSize, fakeInfo.subgroupMinSize);
EXPECT_EQ(info.subgroupMaxSize, fakeInfo.subgroupMaxSize);
wgpu::Limits limits = {};
EXPECT_EQ(adapter.GetLimits(&limits), wgpu::Status::Success);
EXPECT_EQ(limits.maxTextureDimension1D, fakeLimits.maxTextureDimension1D);
EXPECT_EQ(limits.maxVertexAttributes, fakeLimits.maxVertexAttributes);
WGPUSupportedFeatures features = {};
adapter.GetFeatures(reinterpret_cast<wgpu::SupportedFeatures*>(&features));
std::vector<WGPUFeatureName> featuresList(
features.features, features.features + features.featureCount);
ASSERT_EQ(featuresList.size(), fakeFeaturesList.size());
std::unordered_set<WGPUFeatureName> featureSet(fakeFeaturesList);
for (WGPUFeatureName feature : featuresList) {
EXPECT_EQ(featureSet.erase(feature), 1u);
}
}));
FlushCallbacks();
});
}
// Test that RequestAdapter forwards all chained properties to the client.
TEST_P(WireInstanceTests, RequestAdapterPassesChainedProperties) {
wgpu::RequestAdapterOptions options = {};
RequestAdapter(&options);
WGPUMemoryHeapInfo fakeHeapInfo[3] = {
{WGPUHeapProperty_DeviceLocal, 64},
{WGPUHeapProperty_DeviceLocal | WGPUHeapProperty_HostVisible, 136},
{WGPUHeapProperty_HostCached | WGPUHeapProperty_HostVisible, 460},
};
WGPUAdapterPropertiesMemoryHeaps fakeMemoryHeapProperties = {};
fakeMemoryHeapProperties.chain.sType = WGPUSType_AdapterPropertiesMemoryHeaps;
fakeMemoryHeapProperties.heapCount = 3;
fakeMemoryHeapProperties.heapInfo = fakeHeapInfo;
WGPUAdapterPropertiesD3D fakeD3DProperties = {};
fakeD3DProperties.chain.sType = WGPUSType_AdapterPropertiesD3D;
fakeD3DProperties.shaderModel = 61;
WGPUAdapterPropertiesVk fakeVkProperties = {};
fakeVkProperties.chain.sType = WGPUSType_AdapterPropertiesVk;
fakeVkProperties.driverVersion = 0x801F6000;
WGPUSubgroupMatrixConfig fakeMatrixConfigs[3] = {
{WGPUSubgroupMatrixComponentType_F32, WGPUSubgroupMatrixComponentType_F32, 8, 4, 2},
{WGPUSubgroupMatrixComponentType_U32, WGPUSubgroupMatrixComponentType_I32, 4, 8, 16},
{WGPUSubgroupMatrixComponentType_F16, WGPUSubgroupMatrixComponentType_F32, 2, 16, 4},
};
WGPUAdapterPropertiesSubgroupMatrixConfigs fakeSubgroupMatrixConfigs = {};
fakeSubgroupMatrixConfigs.chain.sType = WGPUSType_AdapterPropertiesSubgroupMatrixConfigs;
fakeSubgroupMatrixConfigs.configCount = 3;
fakeSubgroupMatrixConfigs.configs = fakeMatrixConfigs;
WGPUDawnAdapterPropertiesPowerPreference fakePowerProperties = {};
fakePowerProperties.chain.sType = WGPUSType_DawnAdapterPropertiesPowerPreference;
fakePowerProperties.powerPreference = WGPUPowerPreference::WGPUPowerPreference_LowPower;
WGPUAdapterPropertiesExplicitComputeSubgroupSizeConfigs fakeExplicitComputeSubgroupSizeConfigs =
{};
fakeExplicitComputeSubgroupSizeConfigs.chain.sType =
WGPUSType_AdapterPropertiesExplicitComputeSubgroupSizeConfigs;
fakeExplicitComputeSubgroupSizeConfigs.minExplicitComputeSubgroupSize = 8;
fakeExplicitComputeSubgroupSizeConfigs.maxExplicitComputeSubgroupSize = 32;
std::initializer_list<WGPUFeatureName> fakeFeaturesList = {
WGPUFeatureName_AdapterPropertiesMemoryHeaps,
WGPUFeatureName_AdapterPropertiesD3D,
WGPUFeatureName_AdapterPropertiesVk,
WGPUFeatureName_ChromiumExperimentalSubgroupMatrix,
WGPUFeatureName_ChromiumExperimentalSubgroupSizeControl,
};
WGPUSupportedFeatures fakeFeatures = {fakeFeaturesList.size(), std::data(fakeFeaturesList)};
// Expect the server to receive the message. Then, mock a fake reply.
WGPUAdapter apiAdapter = api.GetNewAdapter();
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), _))
.WillOnce(InvokeWithoutArgs([&] {
EXPECT_CALL(api, AdapterGetLimits(apiAdapter, NotNull())).Times(1);
EXPECT_CALL(api, AdapterGetFeatures(apiAdapter, NotNull()))
.WillOnce(
WithArg<1>([&](WGPUSupportedFeatures* features) { *features = fakeFeatures; }));
for (WGPUFeatureName feature : fakeFeaturesList) {
EXPECT_CALL(api, AdapterHasFeature(apiAdapter, feature)).WillOnce(Return(true));
}
EXPECT_CALL(api, AdapterGetInfo(apiAdapter, NotNull()))
.WillOnce(WithArg<1>([&](WGPUAdapterInfo* info) {
WGPUChainedStruct* chain = info->nextInChain;
while (chain != nullptr) {
auto* next = chain->next;
switch (chain->sType) {
case WGPUSType_AdapterPropertiesMemoryHeaps:
*reinterpret_cast<WGPUAdapterPropertiesMemoryHeaps*>(chain) =
fakeMemoryHeapProperties;
break;
case WGPUSType_AdapterPropertiesD3D:
*reinterpret_cast<WGPUAdapterPropertiesD3D*>(chain) =
fakeD3DProperties;
break;
case WGPUSType_AdapterPropertiesVk:
*reinterpret_cast<WGPUAdapterPropertiesVk*>(chain) =
fakeVkProperties;
break;
case WGPUSType_AdapterPropertiesSubgroupMatrixConfigs:
*reinterpret_cast<WGPUAdapterPropertiesSubgroupMatrixConfigs*>(
chain) = fakeSubgroupMatrixConfigs;
break;
case WGPUSType_DawnAdapterPropertiesPowerPreference:
*reinterpret_cast<WGPUDawnAdapterPropertiesPowerPreference*>(
chain) = fakePowerProperties;
break;
case WGPUSType_AdapterPropertiesExplicitComputeSubgroupSizeConfigs:
*reinterpret_cast<
WGPUAdapterPropertiesExplicitComputeSubgroupSizeConfigs*>(
chain) = fakeExplicitComputeSubgroupSizeConfigs;
break;
default:
ADD_FAILURE() << "Unexpected chain";
return WGPUStatus_Error;
}
// Update next pointer back to the original since it would be overwritten
// in the switch statement
chain->next = next;
chain = next;
}
return WGPUStatus_Success;
}));
api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Success,
apiAdapter, kEmptyOutputStringView);
}));
FlushClient();
FlushFutures();
// Expect the callback in the client and the adapter information to match.
ExpectWireCallbacksWhen([&](auto& mockCb) {
EXPECT_CALL(mockCb,
Call(wgpu::RequestAdapterStatus::Success, NotNull(), EmptySizedString()))
.WillOnce(WithArg<1>([&](wgpu::Adapter adapter) {
// Request info without a chained struct.
// It should be nullptr.
WGPUAdapterInfo info = {};
adapter.GetInfo(reinterpret_cast<wgpu::AdapterInfo*>(&info));
EXPECT_EQ(info.nextInChain, nullptr);
// Request the memory heap properties.
WGPUAdapterPropertiesMemoryHeaps memoryHeapProperties = {};
memoryHeapProperties.chain.sType = WGPUSType_AdapterPropertiesMemoryHeaps;
info.nextInChain = &memoryHeapProperties.chain;
adapter.GetInfo(reinterpret_cast<wgpu::AdapterInfo*>(&info));
// Expect everything matches the fake properties returned by the server.
EXPECT_EQ(memoryHeapProperties.heapCount, fakeMemoryHeapProperties.heapCount);
for (size_t i = 0; i < fakeMemoryHeapProperties.heapCount; ++i) {
EXPECT_EQ(memoryHeapProperties.heapInfo[i].properties,
fakeMemoryHeapProperties.heapInfo[i].properties);
EXPECT_EQ(memoryHeapProperties.heapInfo[i].size,
fakeMemoryHeapProperties.heapInfo[i].size);
}
// Get the D3D properties.
WGPUAdapterPropertiesD3D d3dProperties = {};
d3dProperties.chain.sType = WGPUSType_AdapterPropertiesD3D;
info.nextInChain = &d3dProperties.chain;
adapter.GetInfo(reinterpret_cast<wgpu::AdapterInfo*>(&info));
// Expect them to match.
EXPECT_EQ(d3dProperties.shaderModel, fakeD3DProperties.shaderModel);
// Get the Vulkan properties.
WGPUAdapterPropertiesVk vkProperties = {};
vkProperties.chain.sType = WGPUSType_AdapterPropertiesVk;
info.nextInChain = &vkProperties.chain;
adapter.GetInfo(reinterpret_cast<wgpu::AdapterInfo*>(&info));
// Expect them to match.
EXPECT_EQ(vkProperties.driverVersion, fakeVkProperties.driverVersion);
// Get the subgroup matrix properties.
WGPUAdapterPropertiesSubgroupMatrixConfigs subgroupMatrixConfigs = {};
subgroupMatrixConfigs.chain.sType =
WGPUSType_AdapterPropertiesSubgroupMatrixConfigs;
info.nextInChain = &subgroupMatrixConfigs.chain;
adapter.GetInfo(reinterpret_cast<wgpu::AdapterInfo*>(&info));
// Expect everything matches the fake properties returned by the server.
EXPECT_EQ(subgroupMatrixConfigs.configCount, fakeSubgroupMatrixConfigs.configCount);
for (size_t i = 0; i < fakeSubgroupMatrixConfigs.configCount; ++i) {
EXPECT_EQ(subgroupMatrixConfigs.configs[i].componentType,
fakeSubgroupMatrixConfigs.configs[i].componentType);
EXPECT_EQ(subgroupMatrixConfigs.configs[i].resultComponentType,
fakeSubgroupMatrixConfigs.configs[i].resultComponentType);
EXPECT_EQ(subgroupMatrixConfigs.configs[i].M,
fakeSubgroupMatrixConfigs.configs[i].M);
EXPECT_EQ(subgroupMatrixConfigs.configs[i].N,
fakeSubgroupMatrixConfigs.configs[i].N);
EXPECT_EQ(subgroupMatrixConfigs.configs[i].K,
fakeSubgroupMatrixConfigs.configs[i].K);
}
// Get the power properties.
WGPUDawnAdapterPropertiesPowerPreference powerProperties = {};
powerProperties.chain.sType = WGPUSType_DawnAdapterPropertiesPowerPreference;
info.nextInChain = &powerProperties.chain;
adapter.GetInfo(reinterpret_cast<wgpu::AdapterInfo*>(&info));
// Expect them to match.
EXPECT_EQ(powerProperties.powerPreference, fakePowerProperties.powerPreference);
// Get the explicit compute subgroup size properties
WGPUAdapterPropertiesExplicitComputeSubgroupSizeConfigs subgroupSizeConfigs = {};
subgroupSizeConfigs.chain.sType =
WGPUSType_AdapterPropertiesExplicitComputeSubgroupSizeConfigs;
info.nextInChain = &subgroupSizeConfigs.chain;
adapter.GetInfo(reinterpret_cast<wgpu::AdapterInfo*>(&info));
// Expect them to match
EXPECT_EQ(subgroupSizeConfigs.minExplicitComputeSubgroupSize,
fakeExplicitComputeSubgroupSizeConfigs.minExplicitComputeSubgroupSize);
EXPECT_EQ(subgroupSizeConfigs.maxExplicitComputeSubgroupSize,
fakeExplicitComputeSubgroupSizeConfigs.maxExplicitComputeSubgroupSize);
}));
FlushCallbacks();
});
}
// Test that features returned by the implementation that aren't supported in the wire are not
// exposed.
TEST_P(WireInstanceTests, RequestAdapterWireLacksFeatureSupport) {
wgpu::RequestAdapterOptions options = {};
RequestAdapter(&options);
std::initializer_list<WGPUFeatureName> fakeFeaturesList = {
WGPUFeatureName_Depth32FloatStencil8,
// Default feature is an undefined feature.
{},
};
WGPUSupportedFeatures fakeFeatures = {fakeFeaturesList.size(), std::data(fakeFeaturesList)};
// Expect the server to receive the message. Then, mock a fake reply.
WGPUAdapter apiAdapter = api.GetNewAdapter();
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), _))
.WillOnce(InvokeWithoutArgs([&] {
EXPECT_CALL(api, AdapterHasFeature(apiAdapter, _)).WillRepeatedly(Return(false));
EXPECT_CALL(api, AdapterGetInfo(apiAdapter, NotNull())).Times(1);
EXPECT_CALL(api, AdapterGetLimits(apiAdapter, NotNull())).Times(1);
EXPECT_CALL(api, AdapterGetFeatures(apiAdapter, NotNull()))
.WillOnce(
WithArg<1>([&](WGPUSupportedFeatures* features) { *features = fakeFeatures; }));
api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Success,
apiAdapter, kEmptyOutputStringView);
}));
FlushClient();
FlushFutures();
// Expect the callback in the client and all the adapter information to match.
ExpectWireCallbacksWhen([&](auto& mockCb) {
EXPECT_CALL(mockCb,
Call(wgpu::RequestAdapterStatus::Success, NotNull(), EmptySizedString()))
.WillOnce(WithArg<1>([&](wgpu::Adapter adapter) {
WGPUSupportedFeatures features = {};
adapter.GetFeatures(reinterpret_cast<wgpu::SupportedFeatures*>(&features));
ASSERT_EQ(features.featureCount, 1u);
EXPECT_EQ(*features.features, WGPUFeatureName_Depth32FloatStencil8);
}));
FlushCallbacks();
});
}
// Test that RequestAdapter errors forward to the client.
TEST_P(WireInstanceTests, RequestAdapterError) {
wgpu::RequestAdapterOptions options = {};
RequestAdapter(&options);
// Expect the server to receive the message. Then, mock an error.
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), _))
.WillOnce(InvokeWithoutArgs([&] {
api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Error,
nullptr, ToOutputStringView("Some error"));
}));
FlushClient();
FlushFutures();
// Expect the callback in the client.
ExpectWireCallbacksWhen([&](auto& mockCb) {
EXPECT_CALL(mockCb,
Call(wgpu::RequestAdapterStatus::Error, IsNull(), SizedString("Some error")))
.Times(1);
FlushCallbacks();
});
}
// Test that RequestAdapter receives unknown status if the instance is deleted before the callback
// happens.
TEST_P(WireInstanceTests, RequestAdapterInstanceDestroyedBeforeCallback) {
// For spontaneous, dropping the instance does not immediately call the callback because it is
// allowed to resolve later.
DAWN_SKIP_TEST_IF(IsSpontaneous());
wgpu::RequestAdapterOptions options = {};
RequestAdapter(&options);
ExpectWireCallbacksWhen([&](auto& mockCb) {
EXPECT_CALL(mockCb, Call(wgpu::RequestAdapterStatus::CallbackCancelled, IsNull(),
NonEmptySizedString()))
.Times(1);
instance = nullptr;
});
}
// Test that RequestAdapter receives unknown status if the wire is disconnected
// before the callback happens.
TEST_P(WireInstanceTests, RequestAdapterWireDisconnectBeforeCallback) {
wgpu::RequestAdapterOptions options = {};
RequestAdapter(&options);
ExpectWireCallbacksWhen([&](auto& mockCb) {
EXPECT_CALL(mockCb, Call(wgpu::RequestAdapterStatus::CallbackCancelled, IsNull(),
NonEmptySizedString()))
.Times(1);
GetWireClient()->Disconnect();
});
}
} // anonymous namespace
} // namespace dawn::wire