chromium/base/win/vector_unittest.cc

// 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 <windows.foundation.h>
#include <wrl/client.h>

#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<int> : IObservableVector_impl<int> {};

template <>
struct __declspec(uuid("86b0071e-5e72-4d3d-82d3-420ebd2b2716"))
    VectorChangedEventHandler<int> : VectorChangedEventHandler_impl<int> {};

namespace {
using UriPtrAggregate = Internal::AggregateType<Uri*, IUriRuntimeClass*>;
}

template <>
struct __declspec(uuid("12311764-f245-4245-9dc9-bab258eddd4e"))
    IObservableVector<Uri*> : IObservableVector_impl<UriPtrAggregate> {};

template <>
struct __declspec(uuid("050e4b78-71b2-43ff-bf7c-f6ba589aced9"))
    VectorChangedEventHandler<Uri*>
    : VectorChangedEventHandler_impl<UriPtrAggregate> {};

#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<int>
    : IVector_impl<int> {};

template <>
struct __declspec(uuid("8d720cdf-3934-5d3f-9a55-40e8063b086a")) IVectorView<int>
    : IVectorView_impl<int> {};

template <>
struct __declspec(uuid("bfea7f78-50c2-5f1d-a6ea-9e978d2699ff")) IIterator<int>
    : IIterator_impl<int> {};

template <>
struct __declspec(uuid("81a643fb-f51c-5565-83c4-f96425777b66")) IIterable<int>
    : IIterable_impl<int> {};

template <>
struct __declspec(uuid("0d82bd8d-fe62-5d67-a7b9-7886dd75bc4e")) IVector<Uri*>
    : IVector_impl<Internal::AggregateType<Uri*, IUriRuntimeClass*>> {};

template <>
struct __declspec(uuid("4b8385bd-a2cd-5ff1-bf74-7ea580423e50"))
    IVectorView<Uri*>
    : IVectorView_impl<Internal::AggregateType<Uri*, IUriRuntimeClass*>> {};

template <>
struct __declspec(uuid("1c157d0f-5efe-5cec-bbd6-0c6ce9af07a5")) IIterator<Uri*>
    : IIterator_impl<Internal::AggregateType<Uri*, IUriRuntimeClass*>> {};

template <>
struct __declspec(uuid("b0d63b78-78ad-5e31-b6d8-e32a0e16c447")) IIterable<Uri*>
    : IIterable_impl<Internal::AggregateType<Uri*, IUriRuntimeClass*>> {};
#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 <typename T>
class FakeVectorChangedEventHandler
    : public RuntimeClass<
          RuntimeClassFlags<ClassicCom | InhibitRoOriginateError>,
          VectorChangedEventHandler<T>> {
 public:
  explicit FakeVectorChangedEventHandler(ComPtr<IObservableVector<T>> 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<T>* sender,
                        IVectorChangedEventArgs* e) {
    sender_ = sender;
    EXPECT_TRUE(SUCCEEDED(e->get_CollectionChange(&change_)));
    EXPECT_TRUE(SUCCEEDED(e->get_Index(&index_)));
    return S_OK;
  }

  IObservableVector<T>* sender() { return sender_; }
  CollectionChange change() { return change_; }
  unsigned int index() { return index_; }

 private:
  ComPtr<IObservableVector<T>> vector_;
  EventRegistrationToken token_;
  raw_ptr<IObservableVector<T>> 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<int> g_empty;
std::vector<int> g_one = {1};
std::vector<int> g_one_two = {1, 2};
std::vector<int> g_one_two_three = {1, 2, 3};

}  // namespace

TEST(VectorTest, GetAt_Empty) {
  auto vec = Make<Vector<int>>();
  int value;
  HRESULT hr = vec->GetAt(0, &value);
  EXPECT_EQ(E_BOUNDS, hr);
}

TEST(VectorTest, GetAt_One) {
  auto vec = Make<Vector<int>>(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<Vector<int>>(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<Vector<int>>(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<Vector<int>>();
  unsigned size;
  HRESULT hr = vec->get_Size(&size);
  EXPECT_TRUE(SUCCEEDED(hr));
  EXPECT_EQ(0u, size);
}

TEST(VectorTest, get_Size_One) {
  auto vec = Make<Vector<int>>(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<Vector<int>>(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<Vector<int>>(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<Vector<int>>(g_one_two_three);
  ComPtr<IVectorView<int>> 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<int> 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<Vector<int>>();
  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<Vector<int>>(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<Vector<int>>(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<Vector<int>>(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<Vector<int>>(g_one_two_three);
  auto handler = Make<FakeVectorChangedEventHandler<int>>(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<Vector<int>>(g_one_two_three);
  auto handler = Make<FakeVectorChangedEventHandler<int>>(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<Vector<int>>(g_one_two_three);
  auto handler = Make<FakeVectorChangedEventHandler<int>>(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<Vector<int>>();
  auto handler = Make<FakeVectorChangedEventHandler<int>>(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<Vector<int>>(g_one_two_three);
  auto handler = Make<FakeVectorChangedEventHandler<int>>(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<Vector<int>>(g_one_two_three);
  auto handler = Make<FakeVectorChangedEventHandler<int>>(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<Vector<int>>(g_one_two_three);
  std::vector<int> 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<Vector<int>>(g_one_two_three);
  auto handler = Make<FakeVectorChangedEventHandler<int>>(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<Vector<Uri*>>();
  unsigned size;
  HRESULT hr = vec->get_Size(&size);
  EXPECT_TRUE(SUCCEEDED(hr));
  EXPECT_EQ(0u, size);
}

TEST(VectorTest, First) {
  auto vec = Make<Vector<int>>(g_one_two_three);
  ComPtr<IIterator<int>> 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(&current);
  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(&current);
  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(&current);
  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(&current);
  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<int> 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<Vector<int>>(g_one_two_three);
  ComPtr<IIterator<int>> 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<Vector<int>>(g_one);
  ComPtr<IIterator<int>> 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<Vector<int>>(g_one_two_three);
  ComPtr<IIterator<int>> 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<Vector<int>>(g_one);
  ComPtr<IIterator<int>> 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<Vector<int>>(g_one);
  ComPtr<IIterator<int>> 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<Vector<int>>(g_one_two_three);
  ComPtr<IIterator<int>> 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<Vector<int>>(g_one_two);
  ComPtr<IIterator<int>> 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<Vector<int>>(g_one);
  ComPtr<IIterator<int>> 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<Vector<int>>(g_one);
  ComPtr<IIterator<int>> 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<Vector<int>>(g_one_two);
  ComPtr<IIterator<int>> 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