| // 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 |