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