354 lines
9.5 KiB
C++
354 lines
9.5 KiB
C++
// Copyright 2011 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include <stdint.h>
|
|
#include <wrl/client.h>
|
|
#include <wrl/implements.h>
|
|
|
|
#include <utility>
|
|
|
|
#include "base/win/dispatch_stub.h"
|
|
#include "base/win/scoped_variant.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
using base::win::test::DispatchStub;
|
|
|
|
namespace base {
|
|
namespace win {
|
|
|
|
namespace {
|
|
|
|
constexpr wchar_t kTestString[] = L"Test string for BSTRs.";
|
|
|
|
void InitializeVariantWithBstr(VARIANT* var) {
|
|
if (!var) {
|
|
ADD_FAILURE() << "|var| cannot be null.";
|
|
return;
|
|
}
|
|
|
|
var->vt = VT_BSTR;
|
|
V_BSTR(var) = ::SysAllocString(kTestString);
|
|
}
|
|
|
|
void ExpectRefCount(ULONG expected_refcount, IUnknown* object) {
|
|
// In general, code should not check the values of AddRef() and Release().
|
|
// However, tests need to validate that ScopedVariant safely owns a COM object
|
|
// so they are checked for this unit test.
|
|
EXPECT_EQ(expected_refcount + 1, object->AddRef());
|
|
EXPECT_EQ(expected_refcount, object->Release());
|
|
}
|
|
|
|
void ExpectVariantType(VARENUM var_type, const ScopedVariant& var) {
|
|
EXPECT_EQ(var_type, var.type());
|
|
EXPECT_EQ(var_type, V_VT(var.ptr()));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(ScopedVariantTest, Empty) {
|
|
ScopedVariant var;
|
|
ExpectVariantType(VT_EMPTY, var);
|
|
}
|
|
|
|
TEST(ScopedVariantTest, ConstructBstr) {
|
|
ScopedVariant var(kTestString);
|
|
ExpectVariantType(VT_BSTR, var);
|
|
EXPECT_STREQ(kTestString, V_BSTR(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetBstr) {
|
|
ScopedVariant var;
|
|
var.Set(kTestString);
|
|
ExpectVariantType(VT_BSTR, var);
|
|
EXPECT_STREQ(kTestString, V_BSTR(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, ReleaseBstr) {
|
|
ScopedVariant var;
|
|
var.Set(kTestString);
|
|
VARIANT released_variant = var.Release();
|
|
ExpectVariantType(VT_EMPTY, var);
|
|
EXPECT_EQ(VT_BSTR, V_VT(&released_variant));
|
|
EXPECT_STREQ(kTestString, V_BSTR(&released_variant));
|
|
::VariantClear(&released_variant);
|
|
}
|
|
|
|
TEST(ScopedVariantTest, ResetToEmptyBstr) {
|
|
ScopedVariant var(kTestString);
|
|
ExpectVariantType(VT_BSTR, var);
|
|
var.Reset();
|
|
ExpectVariantType(VT_EMPTY, var);
|
|
}
|
|
|
|
TEST(ScopedVariantTest, TakeOwnershipBstr) {
|
|
VARIANT bstr_variant;
|
|
bstr_variant.vt = VT_BSTR;
|
|
bstr_variant.bstrVal = ::SysAllocString(kTestString);
|
|
|
|
ScopedVariant var;
|
|
var.Reset(bstr_variant);
|
|
ExpectVariantType(VT_BSTR, var);
|
|
EXPECT_EQ(bstr_variant.bstrVal, V_BSTR(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SwapBstr) {
|
|
ScopedVariant from(kTestString);
|
|
ScopedVariant to;
|
|
to.Swap(from);
|
|
ExpectVariantType(VT_EMPTY, from);
|
|
ExpectVariantType(VT_BSTR, to);
|
|
EXPECT_STREQ(kTestString, V_BSTR(to.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, CompareBstr) {
|
|
ScopedVariant var_bstr1;
|
|
InitializeVariantWithBstr(var_bstr1.Receive());
|
|
ScopedVariant var_bstr2(V_BSTR(var_bstr1.ptr()));
|
|
EXPECT_EQ(0, var_bstr1.Compare(var_bstr2));
|
|
|
|
var_bstr2.Reset();
|
|
EXPECT_NE(0, var_bstr1.Compare(var_bstr2));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, ReceiveAndCopyBstr) {
|
|
ScopedVariant var_bstr1;
|
|
InitializeVariantWithBstr(var_bstr1.Receive());
|
|
ScopedVariant var_bstr2;
|
|
var_bstr2.Reset(var_bstr1.Copy());
|
|
EXPECT_EQ(0, var_bstr1.Compare(var_bstr2));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetBstrFromBstrVariant) {
|
|
ScopedVariant var_bstr1;
|
|
InitializeVariantWithBstr(var_bstr1.Receive());
|
|
ScopedVariant var_bstr2;
|
|
var_bstr2.Set(V_BSTR(var_bstr1.ptr()));
|
|
EXPECT_EQ(0, var_bstr1.Compare(var_bstr2));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetDate) {
|
|
ScopedVariant var;
|
|
SYSTEMTIME sys_time;
|
|
::GetSystemTime(&sys_time);
|
|
DATE date;
|
|
::SystemTimeToVariantTime(&sys_time, &date);
|
|
var.SetDate(date);
|
|
ExpectVariantType(VT_DATE, var);
|
|
EXPECT_EQ(date, V_DATE(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetSigned1Byte) {
|
|
ScopedVariant var;
|
|
var.Set(static_cast<int8_t>('v'));
|
|
ExpectVariantType(VT_I1, var);
|
|
EXPECT_EQ('v', V_I1(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetSigned2Byte) {
|
|
ScopedVariant var;
|
|
var.Set(static_cast<int16_t>(123));
|
|
ExpectVariantType(VT_I2, var);
|
|
EXPECT_EQ(123, V_I2(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetSigned4Byte) {
|
|
ScopedVariant var;
|
|
var.Set(123);
|
|
ExpectVariantType(VT_I4, var);
|
|
EXPECT_EQ(123, V_I4(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetSigned8Byte) {
|
|
ScopedVariant var;
|
|
var.Set(static_cast<int64_t>(123));
|
|
ExpectVariantType(VT_I8, var);
|
|
EXPECT_EQ(123, V_I8(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetUnsigned1Byte) {
|
|
ScopedVariant var;
|
|
var.Set(static_cast<uint8_t>(123));
|
|
ExpectVariantType(VT_UI1, var);
|
|
EXPECT_EQ(123u, V_UI1(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetUnsigned2Byte) {
|
|
ScopedVariant var;
|
|
var.Set(static_cast<uint16_t>(123));
|
|
ExpectVariantType(VT_UI2, var);
|
|
EXPECT_EQ(123u, V_UI2(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetUnsigned4Byte) {
|
|
ScopedVariant var;
|
|
var.Set(static_cast<uint32_t>(123));
|
|
ExpectVariantType(VT_UI4, var);
|
|
EXPECT_EQ(123u, V_UI4(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetUnsigned8Byte) {
|
|
ScopedVariant var;
|
|
var.Set(static_cast<uint64_t>(123));
|
|
ExpectVariantType(VT_UI8, var);
|
|
EXPECT_EQ(123u, V_UI8(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetReal4Byte) {
|
|
ScopedVariant var;
|
|
var.Set(123.123f);
|
|
ExpectVariantType(VT_R4, var);
|
|
EXPECT_EQ(123.123f, V_R4(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetReal8Byte) {
|
|
ScopedVariant var;
|
|
var.Set(static_cast<double>(123.123));
|
|
ExpectVariantType(VT_R8, var);
|
|
EXPECT_EQ(123.123, V_R8(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetBooleanTrue) {
|
|
ScopedVariant var;
|
|
var.Set(true);
|
|
ExpectVariantType(VT_BOOL, var);
|
|
EXPECT_EQ(VARIANT_TRUE, V_BOOL(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetBooleanFalse) {
|
|
ScopedVariant var;
|
|
var.Set(false);
|
|
ExpectVariantType(VT_BOOL, var);
|
|
EXPECT_EQ(VARIANT_FALSE, V_BOOL(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetComIDispatch) {
|
|
ScopedVariant var;
|
|
Microsoft::WRL::ComPtr<IDispatch> dispatch_stub =
|
|
Microsoft::WRL::Make<DispatchStub>();
|
|
ExpectRefCount(1U, dispatch_stub.Get());
|
|
var.Set(dispatch_stub.Get());
|
|
ExpectVariantType(VT_DISPATCH, var);
|
|
EXPECT_EQ(dispatch_stub.Get(), V_DISPATCH(var.ptr()));
|
|
ExpectRefCount(2U, dispatch_stub.Get());
|
|
var.Reset();
|
|
ExpectRefCount(1U, dispatch_stub.Get());
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetComNullIDispatch) {
|
|
ScopedVariant var;
|
|
var.Set(static_cast<IDispatch*>(nullptr));
|
|
ExpectVariantType(VT_DISPATCH, var);
|
|
EXPECT_EQ(nullptr, V_DISPATCH(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetComIUnknown) {
|
|
ScopedVariant var;
|
|
Microsoft::WRL::ComPtr<IUnknown> unknown_stub =
|
|
Microsoft::WRL::Make<DispatchStub>();
|
|
ExpectRefCount(1U, unknown_stub.Get());
|
|
var.Set(unknown_stub.Get());
|
|
ExpectVariantType(VT_UNKNOWN, var);
|
|
EXPECT_EQ(unknown_stub.Get(), V_UNKNOWN(var.ptr()));
|
|
ExpectRefCount(2U, unknown_stub.Get());
|
|
var.Reset();
|
|
ExpectRefCount(1U, unknown_stub.Get());
|
|
}
|
|
|
|
TEST(ScopedVariantTest, SetComNullIUnknown) {
|
|
ScopedVariant var;
|
|
var.Set(static_cast<IUnknown*>(nullptr));
|
|
ExpectVariantType(VT_UNKNOWN, var);
|
|
EXPECT_EQ(nullptr, V_UNKNOWN(var.ptr()));
|
|
}
|
|
|
|
TEST(ScopedVariant, ScopedComIDispatchConstructor) {
|
|
Microsoft::WRL::ComPtr<IDispatch> dispatch_stub =
|
|
Microsoft::WRL::Make<DispatchStub>();
|
|
{
|
|
ScopedVariant var(dispatch_stub.Get());
|
|
ExpectVariantType(VT_DISPATCH, var);
|
|
EXPECT_EQ(dispatch_stub.Get(), V_DISPATCH(var.ptr()));
|
|
ExpectRefCount(2U, dispatch_stub.Get());
|
|
}
|
|
ExpectRefCount(1U, dispatch_stub.Get());
|
|
}
|
|
|
|
TEST(ScopedVariant, ScopedComIDispatchMove) {
|
|
Microsoft::WRL::ComPtr<IDispatch> dispatch_stub =
|
|
Microsoft::WRL::Make<DispatchStub>();
|
|
{
|
|
ScopedVariant var1(dispatch_stub.Get());
|
|
ExpectRefCount(2U, dispatch_stub.Get());
|
|
ScopedVariant var2(std::move(var1));
|
|
ExpectRefCount(2U, dispatch_stub.Get());
|
|
ScopedVariant var3;
|
|
var3 = std::move(var2);
|
|
ExpectRefCount(2U, dispatch_stub.Get());
|
|
}
|
|
ExpectRefCount(1U, dispatch_stub.Get());
|
|
}
|
|
|
|
TEST(ScopedVariant, ScopedComIDispatchCopy) {
|
|
Microsoft::WRL::ComPtr<IDispatch> dispatch_stub =
|
|
Microsoft::WRL::Make<DispatchStub>();
|
|
{
|
|
ScopedVariant var1(dispatch_stub.Get());
|
|
ExpectRefCount(2U, dispatch_stub.Get());
|
|
ScopedVariant var2(static_cast<const VARIANT&>(var1));
|
|
ExpectRefCount(3U, dispatch_stub.Get());
|
|
ScopedVariant var3;
|
|
var3 = static_cast<const VARIANT&>(var2);
|
|
ExpectRefCount(4U, dispatch_stub.Get());
|
|
}
|
|
ExpectRefCount(1U, dispatch_stub.Get());
|
|
}
|
|
|
|
TEST(ScopedVariant, ScopedComIUnknownConstructor) {
|
|
Microsoft::WRL::ComPtr<IUnknown> unknown_stub =
|
|
Microsoft::WRL::Make<DispatchStub>();
|
|
{
|
|
ScopedVariant unk_var(unknown_stub.Get());
|
|
ExpectVariantType(VT_UNKNOWN, unk_var);
|
|
EXPECT_EQ(unknown_stub.Get(), V_UNKNOWN(unk_var.ptr()));
|
|
ExpectRefCount(2U, unknown_stub.Get());
|
|
}
|
|
ExpectRefCount(1U, unknown_stub.Get());
|
|
}
|
|
|
|
TEST(ScopedVariant, ScopedComIUnknownWithRawVariant) {
|
|
ScopedVariant var;
|
|
Microsoft::WRL::ComPtr<IUnknown> unknown_stub =
|
|
Microsoft::WRL::Make<DispatchStub>();
|
|
VARIANT raw;
|
|
raw.vt = VT_UNKNOWN;
|
|
raw.punkVal = unknown_stub.Get();
|
|
ExpectRefCount(1U, unknown_stub.Get());
|
|
var.Set(raw);
|
|
ExpectRefCount(2U, unknown_stub.Get());
|
|
var.Reset();
|
|
ExpectRefCount(1U, unknown_stub.Get());
|
|
}
|
|
|
|
TEST(ScopedVariant, SetSafeArray) {
|
|
SAFEARRAY* sa = ::SafeArrayCreateVector(VT_UI1, 0, 100);
|
|
ASSERT_TRUE(sa);
|
|
|
|
ScopedVariant var;
|
|
var.Set(sa);
|
|
EXPECT_TRUE(ScopedVariant::IsLeakableVarType(var.type()));
|
|
ExpectVariantType(static_cast<VARENUM>(VT_ARRAY | VT_UI1), var);
|
|
EXPECT_EQ(sa, V_ARRAY(var.ptr()));
|
|
// The array is destroyed in the destructor of var.
|
|
sa = nullptr;
|
|
}
|
|
|
|
TEST(ScopedVariant, SetNullSafeArray) {
|
|
ScopedVariant var;
|
|
var.Set(static_cast<SAFEARRAY*>(nullptr));
|
|
ExpectVariantType(VT_EMPTY, var);
|
|
}
|
|
|
|
} // namespace win
|
|
} // namespace base
|