851 lines
24 KiB
C++
851 lines
24 KiB
C++
|
|
// 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
|