// Copyright 2018 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/win/vector.h" #include #include #include "base/memory/raw_ptr.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace ABI { namespace Windows { namespace Foundation { namespace Collections { // Note: As UWP does not provide int specializations for IObservableVector and // VectorChangedEventHandler we need to supply our own. UUIDs were generated // using `uuidgen`. template <> struct __declspec(uuid("21c2c195-91a4-4fce-8346-2a85f4478e26")) IObservableVector : IObservableVector_impl {}; template <> struct __declspec(uuid("86b0071e-5e72-4d3d-82d3-420ebd2b2716")) VectorChangedEventHandler : VectorChangedEventHandler_impl {}; namespace { using UriPtrAggregate = Internal::AggregateType; } template <> struct __declspec(uuid("12311764-f245-4245-9dc9-bab258eddd4e")) IObservableVector : IObservableVector_impl {}; template <> struct __declspec(uuid("050e4b78-71b2-43ff-bf7c-f6ba589aced9")) VectorChangedEventHandler : VectorChangedEventHandler_impl {}; #ifdef NTDDI_WIN10_VB // Windows 10.0.19041 // Specialization templates that used to be in windows.foundation.h, removed in // the 10.0.19041.0 SDK, so placed here instead. template <> struct __declspec(uuid("b939af5b-b45d-5489-9149-61442c1905fe")) IVector : IVector_impl {}; template <> struct __declspec(uuid("8d720cdf-3934-5d3f-9a55-40e8063b086a")) IVectorView : IVectorView_impl {}; template <> struct __declspec(uuid("bfea7f78-50c2-5f1d-a6ea-9e978d2699ff")) IIterator : IIterator_impl {}; template <> struct __declspec(uuid("81a643fb-f51c-5565-83c4-f96425777b66")) IIterable : IIterable_impl {}; template <> struct __declspec(uuid("0d82bd8d-fe62-5d67-a7b9-7886dd75bc4e")) IVector : IVector_impl> {}; template <> struct __declspec(uuid("4b8385bd-a2cd-5ff1-bf74-7ea580423e50")) IVectorView : IVectorView_impl> {}; template <> struct __declspec(uuid("1c157d0f-5efe-5cec-bbd6-0c6ce9af07a5")) IIterator : IIterator_impl> {}; template <> struct __declspec(uuid("b0d63b78-78ad-5e31-b6d8-e32a0e16c447")) IIterable : IIterable_impl> {}; #endif } // namespace Collections } // namespace Foundation } // namespace Windows } // namespace ABI namespace base { namespace win { namespace { using ABI::Windows::Foundation::Uri; using ABI::Windows::Foundation::Collections::CollectionChange; using ABI::Windows::Foundation::Collections::CollectionChange_ItemChanged; using ABI::Windows::Foundation::Collections::CollectionChange_ItemInserted; using ABI::Windows::Foundation::Collections::CollectionChange_ItemRemoved; using ABI::Windows::Foundation::Collections::CollectionChange_Reset; using ABI::Windows::Foundation::Collections::IIterator; using ABI::Windows::Foundation::Collections::IObservableVector; using ABI::Windows::Foundation::Collections::IVectorChangedEventArgs; using ABI::Windows::Foundation::Collections::IVectorView; using ABI::Windows::Foundation::Collections::VectorChangedEventHandler; using Microsoft::WRL::ClassicCom; using Microsoft::WRL::ComPtr; using Microsoft::WRL::InhibitRoOriginateError; using Microsoft::WRL::Make; using Microsoft::WRL::RuntimeClass; using Microsoft::WRL::RuntimeClassFlags; using ::testing::ElementsAre; using ::testing::IsEmpty; template class FakeVectorChangedEventHandler : public RuntimeClass< RuntimeClassFlags, VectorChangedEventHandler> { public: explicit FakeVectorChangedEventHandler(ComPtr> vector) : vector_(std::move(vector)) { EXPECT_TRUE(SUCCEEDED(vector_->add_VectorChanged(this, &token_))); } ~FakeVectorChangedEventHandler() override { EXPECT_TRUE(SUCCEEDED(vector_->remove_VectorChanged(token_))); } // VectorChangedEventHandler: IFACEMETHODIMP Invoke(IObservableVector* sender, IVectorChangedEventArgs* e) { sender_ = sender; EXPECT_TRUE(SUCCEEDED(e->get_CollectionChange(&change_))); EXPECT_TRUE(SUCCEEDED(e->get_Index(&index_))); return S_OK; } IObservableVector* sender() { return sender_; } CollectionChange change() { return change_; } unsigned int index() { return index_; } private: ComPtr> vector_; EventRegistrationToken token_; raw_ptr> sender_ = nullptr; CollectionChange change_ = CollectionChange_Reset; unsigned int index_ = 0; }; // The ReplaceAll test requires a non-const data() member, thus these vectors // are not declared const, even though no test mutates them. std::vector g_empty; std::vector g_one = {1}; std::vector g_one_two = {1, 2}; std::vector g_one_two_three = {1, 2, 3}; } // namespace TEST(VectorTest, GetAt_Empty) { auto vec = Make>(); int value; HRESULT hr = vec->GetAt(0, &value); EXPECT_EQ(E_BOUNDS, hr); } TEST(VectorTest, GetAt_One) { auto vec = Make>(g_one); int value; HRESULT hr = vec->GetAt(0, &value); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1, value); hr = vec->GetAt(1, &value); EXPECT_EQ(E_BOUNDS, hr); } TEST(VectorTest, GetAt_OneTwo) { auto vec = Make>(g_one_two); int value; HRESULT hr = vec->GetAt(0, &value); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1, value); hr = vec->GetAt(1, &value); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(2, value); hr = vec->GetAt(2, &value); EXPECT_EQ(E_BOUNDS, hr); } TEST(VectorTest, GetAt_OneTwoThree) { auto vec = Make>(g_one_two_three); int value; HRESULT hr = vec->GetAt(0, &value); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1, value); hr = vec->GetAt(1, &value); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(2, value); hr = vec->GetAt(2, &value); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(3, value); hr = vec->GetAt(3, &value); EXPECT_EQ(E_BOUNDS, hr); } TEST(VectorTest, get_Size_Empty) { auto vec = Make>(); unsigned size; HRESULT hr = vec->get_Size(&size); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, size); } TEST(VectorTest, get_Size_One) { auto vec = Make>(g_one); unsigned size; HRESULT hr = vec->get_Size(&size); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1u, size); } TEST(VectorTest, get_Size_OneTwo) { auto vec = Make>(g_one_two); unsigned size; HRESULT hr = vec->get_Size(&size); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(2u, size); } TEST(VectorTest, get_Size_OneTwoThree) { auto vec = Make>(g_one_two_three); unsigned size; HRESULT hr = vec->get_Size(&size); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(3u, size); } TEST(VectorTest, GetView) { auto vec = Make>(g_one_two_three); ComPtr> view; HRESULT hr = vec->GetView(&view); EXPECT_TRUE(SUCCEEDED(hr)); int value; hr = view->GetAt(0, &value); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1, value); hr = view->GetAt(1, &value); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(2, value); hr = view->GetAt(2, &value); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(3, value); hr = view->GetAt(3, &value); EXPECT_EQ(E_BOUNDS, hr); unsigned size; hr = view->get_Size(&size); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(3u, size); unsigned index; boolean found; hr = view->IndexOf(1, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, index); EXPECT_TRUE(found); hr = view->IndexOf(2, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1u, index); EXPECT_TRUE(found); hr = view->IndexOf(3, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(2u, index); EXPECT_TRUE(found); hr = view->IndexOf(4, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, index); EXPECT_FALSE(found); std::vector copy(3); unsigned actual; hr = view->GetMany(0, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(3u, actual); EXPECT_THAT(copy, ElementsAre(1, 2, 3)); hr = vec->Append(4); EXPECT_TRUE(SUCCEEDED(hr)); // The view is supposed to be a snapshot of the vector when it's created. // Further modifications to the vector will invalidate the view. hr = view->GetAt(3, &value); EXPECT_EQ(E_CHANGED_STATE, hr); hr = view->get_Size(&size); EXPECT_EQ(E_CHANGED_STATE, hr); hr = view->IndexOf(1, &index, &found); EXPECT_EQ(E_CHANGED_STATE, hr); hr = view->GetMany(0, copy.size(), copy.data(), &actual); EXPECT_EQ(E_CHANGED_STATE, hr); } TEST(VectorTest, IndexOf_Empty) { auto vec = Make>(); unsigned index; boolean found; HRESULT hr = vec->IndexOf(1, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, index); EXPECT_FALSE(found); } TEST(VectorTest, IndexOf_One) { auto vec = Make>(g_one); unsigned index; boolean found; HRESULT hr = vec->IndexOf(1, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, index); EXPECT_TRUE(found); hr = vec->IndexOf(2, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, index); EXPECT_FALSE(found); } TEST(VectorTest, IndexOf_OneTwo) { auto vec = Make>(g_one_two); unsigned index; boolean found; HRESULT hr = vec->IndexOf(1, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, index); EXPECT_TRUE(found); hr = vec->IndexOf(2, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1u, index); EXPECT_TRUE(found); hr = vec->IndexOf(3, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, index); EXPECT_FALSE(found); } TEST(VectorTest, IndexOf_OneTwoThree) { auto vec = Make>(g_one_two_three); unsigned index; boolean found; HRESULT hr = vec->IndexOf(1, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, index); EXPECT_TRUE(found); hr = vec->IndexOf(2, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1u, index); EXPECT_TRUE(found); hr = vec->IndexOf(3, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(2u, index); EXPECT_TRUE(found); hr = vec->IndexOf(4, &index, &found); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, index); EXPECT_FALSE(found); } TEST(VectorTest, SetAt) { auto vec = Make>(g_one_two_three); auto handler = Make>(vec.Get()); HRESULT hr = vec->SetAt(0, 4); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(4, 2, 3)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemChanged, handler->change()); EXPECT_EQ(0u, handler->index()); hr = vec->SetAt(1, 5); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(4, 5, 3)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemChanged, handler->change()); EXPECT_EQ(1u, handler->index()); hr = vec->SetAt(2, 6); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(4, 5, 6)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemChanged, handler->change()); EXPECT_EQ(2u, handler->index()); hr = vec->SetAt(3, 7); EXPECT_EQ(E_BOUNDS, hr); } TEST(VectorTest, InsertAt) { auto vec = Make>(g_one_two_three); auto handler = Make>(vec.Get()); HRESULT hr = vec->InsertAt(4, 4); EXPECT_EQ(E_BOUNDS, hr); hr = vec->InsertAt(3, 4); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1, 2, 3, 4)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemInserted, handler->change()); EXPECT_EQ(3u, handler->index()); hr = vec->InsertAt(2, 5); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1, 2, 5, 3, 4)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemInserted, handler->change()); EXPECT_EQ(2u, handler->index()); hr = vec->InsertAt(1, 6); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1, 6, 2, 5, 3, 4)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemInserted, handler->change()); EXPECT_EQ(1u, handler->index()); hr = vec->InsertAt(0, 7); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(7, 1, 6, 2, 5, 3, 4)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemInserted, handler->change()); EXPECT_EQ(0u, handler->index()); } TEST(VectorTest, RemoveAt) { auto vec = Make>(g_one_two_three); auto handler = Make>(vec.Get()); HRESULT hr = vec->RemoveAt(3); EXPECT_EQ(E_BOUNDS, hr); hr = vec->RemoveAt(2); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1, 2)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemRemoved, handler->change()); EXPECT_EQ(2u, handler->index()); hr = vec->RemoveAt(2); EXPECT_EQ(E_BOUNDS, hr); hr = vec->RemoveAt(1); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemRemoved, handler->change()); EXPECT_EQ(1u, handler->index()); hr = vec->RemoveAt(1); EXPECT_EQ(E_BOUNDS, hr); hr = vec->RemoveAt(0); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), IsEmpty()); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemRemoved, handler->change()); EXPECT_EQ(0u, handler->index()); hr = vec->RemoveAt(0); EXPECT_EQ(E_BOUNDS, hr); } TEST(VectorTest, Append) { auto vec = Make>(); auto handler = Make>(vec.Get()); HRESULT hr = vec->Append(1); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemInserted, handler->change()); EXPECT_EQ(0u, handler->index()); hr = vec->Append(2); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1, 2)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemInserted, handler->change()); EXPECT_EQ(1u, handler->index()); hr = vec->Append(3); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1, 2, 3)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemInserted, handler->change()); EXPECT_EQ(2u, handler->index()); } TEST(VectorTest, RemoveAtEnd) { auto vec = Make>(g_one_two_three); auto handler = Make>(vec.Get()); HRESULT hr = vec->RemoveAtEnd(); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1, 2)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemRemoved, handler->change()); EXPECT_EQ(2u, handler->index()); hr = vec->RemoveAtEnd(); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemRemoved, handler->change()); EXPECT_EQ(1u, handler->index()); hr = vec->RemoveAtEnd(); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), IsEmpty()); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_ItemRemoved, handler->change()); EXPECT_EQ(0u, handler->index()); hr = vec->RemoveAtEnd(); EXPECT_EQ(E_BOUNDS, hr); } TEST(VectorTest, Clear) { auto vec = Make>(g_one_two_three); auto handler = Make>(vec.Get()); HRESULT hr = vec->Clear(); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), IsEmpty()); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_Reset, handler->change()); EXPECT_EQ(0u, handler->index()); } TEST(VectorTest, GetMany) { auto vec = Make>(g_one_two_three); std::vector copy; unsigned actual; HRESULT hr = vec->GetMany(0, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, actual); EXPECT_THAT(copy, IsEmpty()); copy.resize(1); hr = vec->GetMany(0, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1u, actual); EXPECT_THAT(copy, ElementsAre(1)); copy.resize(2); hr = vec->GetMany(0, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(2u, actual); EXPECT_THAT(copy, ElementsAre(1, 2)); copy.resize(3); hr = vec->GetMany(0, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(3u, actual); EXPECT_THAT(copy, ElementsAre(1, 2, 3)); copy.resize(4); hr = vec->GetMany(0, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(3u, actual); EXPECT_THAT(copy, ElementsAre(1, 2, 3, 0)); copy.resize(0); hr = vec->GetMany(1, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, actual); EXPECT_THAT(copy, IsEmpty()); copy.resize(1); hr = vec->GetMany(1, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1u, actual); EXPECT_THAT(copy, ElementsAre(2)); copy.resize(2); hr = vec->GetMany(1, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(2u, actual); EXPECT_THAT(copy, ElementsAre(2, 3)); copy.resize(3); hr = vec->GetMany(1, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(2u, actual); EXPECT_THAT(copy, ElementsAre(2, 3, 0)); copy.resize(0); hr = vec->GetMany(2, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, actual); EXPECT_THAT(copy, IsEmpty()); copy.resize(1); hr = vec->GetMany(2, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1u, actual); EXPECT_THAT(copy, ElementsAre(3)); copy.resize(2); hr = vec->GetMany(2, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1u, actual); EXPECT_THAT(copy, ElementsAre(3, 0)); hr = vec->GetMany(3, copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, actual); hr = vec->GetMany(4, copy.size(), copy.data(), &actual); EXPECT_EQ(E_BOUNDS, hr); } TEST(VectorTest, ReplaceAll) { auto vec = Make>(g_one_two_three); auto handler = Make>(vec.Get()); HRESULT hr = vec->ReplaceAll(g_empty.size(), g_empty.data()); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), IsEmpty()); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_Reset, handler->change()); EXPECT_EQ(0u, handler->index()); hr = vec->ReplaceAll(g_one.size(), g_one.data()); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_Reset, handler->change()); EXPECT_EQ(0u, handler->index()); hr = vec->ReplaceAll(g_one_two.size(), g_one_two.data()); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1, 2)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_Reset, handler->change()); EXPECT_EQ(0u, handler->index()); hr = vec->ReplaceAll(g_one_two_three.size(), g_one_two_three.data()); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_THAT(vec->vector_for_testing(), ElementsAre(1, 2, 3)); EXPECT_EQ(vec.Get(), handler->sender()); EXPECT_EQ(CollectionChange_Reset, handler->change()); EXPECT_EQ(0u, handler->index()); } // Uri* is an AggregateType which ABI representation is IUriRuntimeClass*. TEST(VectorTest, ConstructWithAggregateType) { auto vec = Make>(); unsigned size; HRESULT hr = vec->get_Size(&size); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(0u, size); } TEST(VectorTest, First) { auto vec = Make>(g_one_two_three); ComPtr> iterator; HRESULT hr = vec->First(&iterator); EXPECT_TRUE(SUCCEEDED(hr)); boolean has_current; hr = iterator->get_HasCurrent(&has_current); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_TRUE(has_current); int current; hr = iterator->get_Current(¤t); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(1, current); hr = iterator->MoveNext(&has_current); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_TRUE(has_current); hr = iterator->get_Current(¤t); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(2, current); hr = iterator->MoveNext(&has_current); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_TRUE(has_current); hr = iterator->get_Current(¤t); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(3, current); hr = iterator->MoveNext(&has_current); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_FALSE(has_current); hr = iterator->get_Current(¤t); EXPECT_FALSE(SUCCEEDED(hr)); EXPECT_EQ(E_BOUNDS, hr); hr = iterator->MoveNext(&has_current); EXPECT_FALSE(SUCCEEDED(hr)); EXPECT_EQ(E_BOUNDS, hr); EXPECT_FALSE(has_current); hr = vec->First(&iterator); EXPECT_TRUE(SUCCEEDED(hr)); std::vector copy(3); unsigned actual; hr = iterator->GetMany(copy.size(), copy.data(), &actual); EXPECT_TRUE(SUCCEEDED(hr)); EXPECT_EQ(3u, actual); EXPECT_THAT(copy, ElementsAre(1, 2, 3)); } TEST(VectorTest, MoveNext_S_OK_ValidItem) { auto vec = Make>(g_one_two_three); ComPtr> iterator; vec->First(&iterator); boolean has_current; // Moving next to a valid item should return S_OK: // [1, 2, 3] // |->| EXPECT_EQ(S_OK, iterator->MoveNext(&has_current)); } TEST(VectorTest, MoveNext_S_OK_FromLastItem) { auto vec = Make>(g_one); ComPtr> iterator; vec->First(&iterator); boolean has_current; // Moving next past the last item should return S_OK: // [1] // |->| EXPECT_EQ(S_OK, iterator->MoveNext(&has_current)); } TEST(VectorTest, MoveNext_E_CHANGED_STATE_ValidItem) { auto vec = Make>(g_one_two_three); ComPtr> iterator; vec->First(&iterator); boolean has_current; vec->Append(4); // Moving next after changing the vector should return E_CHANGED_STATE: EXPECT_EQ(E_CHANGED_STATE, iterator->MoveNext(&has_current)); } TEST(VectorTest, MoveNext_E_CHANGED_STATE_AfterLastItem) { auto vec = Make>(g_one); ComPtr> iterator; vec->First(&iterator); boolean has_current; iterator->MoveNext(&has_current); vec->Append(4); // Moving next after changing the vector should return E_CHANGED_STATE: EXPECT_EQ(E_CHANGED_STATE, iterator->MoveNext(&has_current)); } TEST(VectorTest, MoveNext_E_BOUNDS) { auto vec = Make>(g_one); ComPtr> iterator; vec->First(&iterator); boolean has_current; iterator->MoveNext(&has_current); // Moving next when already past the last item should return E_BOUNDS: // [1] // |->| EXPECT_EQ(E_BOUNDS, iterator->MoveNext(&has_current)); } TEST(VectorTest, MoveNext_HasCurrent_ValidItem) { auto vec = Make>(g_one_two_three); ComPtr> iterator; vec->First(&iterator); boolean has_current; // Moving next to a valid item should set |has_current| to true: // [1, 2, 3] // |->| iterator->MoveNext(&has_current); EXPECT_TRUE(has_current); } TEST(VectorTest, MoveNext_HasCurrent_LastItem) { auto vec = Make>(g_one_two); ComPtr> iterator; vec->First(&iterator); boolean has_current; // Moving next to the last item should set |has_current| to true: // [1, 2] // |->| iterator->MoveNext(&has_current); EXPECT_TRUE(has_current); } TEST(VectorTest, MoveNext_HasCurrent_FromLastItem) { auto vec = Make>(g_one); ComPtr> iterator; vec->First(&iterator); boolean has_current; iterator->MoveNext(&has_current); // Moving next when already past the end should set |has_current| to false: // [1] // |->| iterator->MoveNext(&has_current); EXPECT_FALSE(has_current); } TEST(VectorTest, MoveNext_HasCurrent_AfterLastItem) { auto vec = Make>(g_one); ComPtr> iterator; vec->First(&iterator); // Moving next from the last item should set |has_current| to false: // [1] // |->| boolean has_current; iterator->MoveNext(&has_current); EXPECT_FALSE(has_current); } TEST(VectorTest, MoveNext_HasCurrent_Changed) { auto vec = Make>(g_one_two); ComPtr> iterator; vec->First(&iterator); boolean has_current; vec->Append(4); // Moving next after changing the vector should set |has_current| to false: iterator->MoveNext(&has_current); EXPECT_FALSE(has_current); } } // namespace win } // namespace base