// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/device_signals/core/system_signals/win/com_fakes.h"
#include "base/check.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device_signals {
#define IMPL_IUNKOWN_NOQI_WITH_REF(cls) \
IFACEMETHODIMP cls::QueryInterface(REFIID riid, void** ppv) { \
return E_NOTIMPL; \
} \
ULONG cls::AddRef() { return ::InterlockedIncrement(&ref_count_); } \
ULONG cls::Release(void) { \
DCHECK(ref_count_ > 0); \
return ::InterlockedDecrement(&ref_count_); \
}
#define IMPL_IDISPATCH(cls) \
IMPL_IUNKOWN_NOQI_WITH_REF(cls) \
IFACEMETHODIMP cls::GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; } \
IFACEMETHODIMP cls::GetTypeInfo(UINT iTInfo, LCID lcid, \
ITypeInfo** ppTInfo) { \
return E_NOTIMPL; \
} \
IFACEMETHODIMP cls::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, \
UINT cNames, LCID lcid, \
DISPID* rgDispId) { \
return E_NOTIMPL; \
} \
IFACEMETHODIMP cls::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, \
WORD wFlags, DISPPARAMS* pDispParams, \
VARIANT* pVarResult, EXCEPINFO* pExcepInfo, \
UINT* puArgErr) { \
return E_NOTIMPL; \
}
// FakeEnumWbemClassObject
FakeEnumWbemClassObject::FakeEnumWbemClassObject() = default;
FakeEnumWbemClassObject::~FakeEnumWbemClassObject() = default;
HRESULT FakeEnumWbemClassObject::Next(long lTimeout,
ULONG uCount,
IWbemClassObject** apObjects,
ULONG* puReturned) {
// This fake implementation only supports moving through items one by one.
DCHECK(uCount == 1);
if (!iterator_.has_value()) {
iterator_ = items_.begin();
}
if (iterator_.value() == items_.end()) {
// Reached the end of the vector.
*puReturned = 0;
return WBEM_S_FALSE;
}
*puReturned = iterator_.value()->second;
// If the next item is nullptr, then return an error code.
HRESULT result = WBEM_S_FALSE;
if (iterator_.value()->first) {
result = WBEM_S_NO_ERROR;
*apObjects = iterator_.value()->first;
}
++iterator_.value();
return result;
}
HRESULT FakeEnumWbemClassObject::Clone(IEnumWbemClassObject** ppEnum) {
return E_NOTIMPL;
}
HRESULT FakeEnumWbemClassObject::NextAsync(ULONG uCount,
IWbemObjectSink* pSink) {
return E_NOTIMPL;
}
HRESULT FakeEnumWbemClassObject::Reset() {
return E_NOTIMPL;
}
HRESULT FakeEnumWbemClassObject::Skip(long lTimeout, ULONG nCount) {
return E_NOTIMPL;
}
IMPL_IUNKOWN_NOQI_WITH_REF(FakeEnumWbemClassObject)
// FakeWbemClassObject
FakeWbemClassObject::FakeWbemClassObject() = default;
FakeWbemClassObject::FakeWbemClassObject(FakeWbemClassObject&&) = default;
FakeWbemClassObject& FakeWbemClassObject::operator=(FakeWbemClassObject&&) =
default;
FakeWbemClassObject::~FakeWbemClassObject() = default;
HRESULT FakeWbemClassObject::Get(LPCWSTR wszName,
long lFlags,
VARIANT* pVal,
CIMTYPE* pType,
long* plFlavor) {
EXPECT_EQ(0, lFlags);
std::wstring key(wszName);
auto iterator = map_.find(key);
if (iterator == map_.end()) {
// Not found, return any HRESULT that is not 0.
return WBEM_S_FALSE;
}
*pVal = iterator->second.Copy();
return WBEM_S_NO_ERROR;
}
HRESULT FakeWbemClassObject::Delete(LPCWSTR wszName) {
map_.erase(wszName);
return WBEM_S_NO_ERROR;
}
HRESULT FakeWbemClassObject::BeginEnumeration(long lEnumFlags) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::BeginMethodEnumeration(long lEnumFlags) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::Clone(IWbemClassObject** ppCopy) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::CompareTo(long lFlags,
IWbemClassObject* pCompareTo) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::DeleteMethod(LPCWSTR wszName) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::EndEnumeration() {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::EndMethodEnumeration() {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::GetMethod(LPCWSTR wszName,
long lFlags,
IWbemClassObject** ppInSignature,
IWbemClassObject** ppOutSignature) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::GetMethodOrigin(LPCWSTR wszMethodName,
BSTR* pstrClassName) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::GetMethodQualifierSet(
LPCWSTR wszMethod,
IWbemQualifierSet** ppQualSet) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::GetNames(LPCWSTR wszQualifierName,
long lFlags,
VARIANT* pQualifierVal,
SAFEARRAY** pNames) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::GetObjectText(long lFlags, BSTR* pstrObjectText) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::GetPropertyOrigin(LPCWSTR wszName,
BSTR* pstrClassName) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::GetPropertyQualifierSet(
LPCWSTR wszProperty,
IWbemQualifierSet** ppQualSet) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::GetQualifierSet(IWbemQualifierSet** ppQualSet) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::InheritsFrom(LPCWSTR strAncestor) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::Next(long lFlags,
BSTR* strName,
VARIANT* pVal,
CIMTYPE* pType,
long* plFlavor) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::NextMethod(long lFlags,
BSTR* pstrName,
IWbemClassObject** ppInSignature,
IWbemClassObject** ppOutSignature) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::Put(LPCWSTR wszName,
long lFlags,
VARIANT* pVal,
CIMTYPE Type) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::PutMethod(LPCWSTR wszName,
long lFlags,
IWbemClassObject* pInSignature,
IWbemClassObject* pOutSignature) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::SpawnDerivedClass(long lFlags,
IWbemClassObject** ppNewClass) {
return E_NOTIMPL;
}
HRESULT FakeWbemClassObject::SpawnInstance(long lFlags,
IWbemClassObject** ppNewInstance) {
return E_NOTIMPL;
}
IMPL_IUNKOWN_NOQI_WITH_REF(FakeWbemClassObject)
// FakeWscProduct
FakeWscProduct::FakeWscProduct() = default;
FakeWscProduct::FakeWscProduct(const wchar_t* name,
const wchar_t* id,
WSC_SECURITY_PRODUCT_STATE state)
: name_(name), id_(id), state_(state) {}
FakeWscProduct::FakeWscProduct(FakeWscProduct&& other)
: failed_step_(other.failed_step_), state_(other.state_) {
name_.Reset(other.name_.Release());
id_.Reset(other.id_.Release());
}
FakeWscProduct& FakeWscProduct::operator=(FakeWscProduct&& other) {
failed_step_ = other.failed_step_;
state_ = other.state_;
name_.Reset(other.name_.Release());
id_.Reset(other.id_.Release());
return *this;
}
FakeWscProduct::~FakeWscProduct() = default;
HRESULT FakeWscProduct::get_ProductName(BSTR* pVal) {
if (ShouldFail(FailureStep::kProductName)) {
return E_FAIL;
}
*pVal = name_.Get();
return S_OK;
}
HRESULT FakeWscProduct::get_ProductGuid(BSTR* pVal) {
if (ShouldFail(FailureStep::kProductId)) {
return E_FAIL;
}
*pVal = id_.Get();
return S_OK;
}
HRESULT FakeWscProduct::get_ProductState(WSC_SECURITY_PRODUCT_STATE* pVal) {
if (ShouldFail(FailureStep::kProductState)) {
return E_FAIL;
}
*pVal = state_;
return S_OK;
}
HRESULT FakeWscProduct::get_ProductStateTimestamp(BSTR* pVal) {
return E_NOTIMPL;
}
HRESULT FakeWscProduct::get_RemediationPath(BSTR* pVal) {
return E_NOTIMPL;
}
HRESULT FakeWscProduct::get_SignatureStatus(
WSC_SECURITY_SIGNATURE_STATUS* pVal) {
return E_NOTIMPL;
}
HRESULT FakeWscProduct::get_ProductIsDefault(BOOL* pVal) {
return E_NOTIMPL;
}
bool FakeWscProduct::ShouldFail(FakeWscProduct::FailureStep step) {
return failed_step_.has_value() && failed_step_.value() == step;
}
IMPL_IDISPATCH(FakeWscProduct)
// FakeWSCProductList
FakeWSCProductList::FakeWSCProductList() = default;
FakeWSCProductList::~FakeWSCProductList() = default;
HRESULT FakeWSCProductList::get_Count(LONG* pVal) {
if (ShouldFail(FailureStep::kGetCount)) {
return E_FAIL;
}
*pVal = products_.size();
return S_OK;
}
HRESULT FakeWSCProductList::get_Item(ULONG index, IWscProduct** pVal) {
if (ShouldFail(FailureStep::kGetItem)) {
return E_FAIL;
}
if (index < 0 || index >= products_.size()) {
return E_FAIL;
}
*pVal = products_[index];
return S_OK;
}
HRESULT FakeWSCProductList::Initialize(ULONG provider) {
if (ShouldFail(FailureStep::kInitialize)) {
return E_FAIL;
}
// Initialize can only be called once.
DCHECK(!provider_.has_value());
provider_ = provider;
return S_OK;
}
bool FakeWSCProductList::ShouldFail(FakeWSCProductList::FailureStep step) {
return failed_step_.has_value() && failed_step_.value() == step;
}
IMPL_IDISPATCH(FakeWSCProductList)
} // namespace device_signals