// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include #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('v')); ExpectVariantType(VT_I1, var); EXPECT_EQ('v', V_I1(var.ptr())); } TEST(ScopedVariantTest, SetSigned2Byte) { ScopedVariant var; var.Set(static_cast(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(123)); ExpectVariantType(VT_I8, var); EXPECT_EQ(123, V_I8(var.ptr())); } TEST(ScopedVariantTest, SetUnsigned1Byte) { ScopedVariant var; var.Set(static_cast(123)); ExpectVariantType(VT_UI1, var); EXPECT_EQ(123u, V_UI1(var.ptr())); } TEST(ScopedVariantTest, SetUnsigned2Byte) { ScopedVariant var; var.Set(static_cast(123)); ExpectVariantType(VT_UI2, var); EXPECT_EQ(123u, V_UI2(var.ptr())); } TEST(ScopedVariantTest, SetUnsigned4Byte) { ScopedVariant var; var.Set(static_cast(123)); ExpectVariantType(VT_UI4, var); EXPECT_EQ(123u, V_UI4(var.ptr())); } TEST(ScopedVariantTest, SetUnsigned8Byte) { ScopedVariant var; var.Set(static_cast(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(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 dispatch_stub = Microsoft::WRL::Make(); 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(nullptr)); ExpectVariantType(VT_DISPATCH, var); EXPECT_EQ(nullptr, V_DISPATCH(var.ptr())); } TEST(ScopedVariantTest, SetComIUnknown) { ScopedVariant var; Microsoft::WRL::ComPtr unknown_stub = Microsoft::WRL::Make(); 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(nullptr)); ExpectVariantType(VT_UNKNOWN, var); EXPECT_EQ(nullptr, V_UNKNOWN(var.ptr())); } TEST(ScopedVariant, ScopedComIDispatchConstructor) { Microsoft::WRL::ComPtr dispatch_stub = Microsoft::WRL::Make(); { 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 dispatch_stub = Microsoft::WRL::Make(); { 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 dispatch_stub = Microsoft::WRL::Make(); { ScopedVariant var1(dispatch_stub.Get()); ExpectRefCount(2U, dispatch_stub.Get()); ScopedVariant var2(static_cast(var1)); ExpectRefCount(3U, dispatch_stub.Get()); ScopedVariant var3; var3 = static_cast(var2); ExpectRefCount(4U, dispatch_stub.Get()); } ExpectRefCount(1U, dispatch_stub.Get()); } TEST(ScopedVariant, ScopedComIUnknownConstructor) { Microsoft::WRL::ComPtr unknown_stub = Microsoft::WRL::Make(); { 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 unknown_stub = Microsoft::WRL::Make(); 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(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(nullptr)); ExpectVariantType(VT_EMPTY, var); } } // namespace win } // namespace base