1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/base/sidecar_list_container.h"
9 #include "base/logging.h"
10 #include "testing/gtest/include/gtest/gtest.h"
15 const size_t kNumInitiallyReservedElements
= 2;
16 const size_t kNumElementsForTest
= 100;
18 class DestructionNotifier
{
20 DestructionNotifier() : flag_(nullptr) {}
21 explicit DestructionNotifier(bool* flag
) { set_flag(flag
); }
22 ~DestructionNotifier() {
26 void set_flag(bool* flag
) {
39 virtual ~TestElement() {}
40 void set_destruction_flag(bool* flag
) { notifier_
.set_flag(flag
); }
43 DestructionNotifier notifier_
;
46 class DerivedTestElement
: public TestElement
{
48 int additional_field
= 0;
54 explicit TestSidecar(bool* destruction_flag
) : notifier_(destruction_flag
) {}
56 static void Destroy(void* sidecar
) {
57 static_cast<TestSidecar
*>(sidecar
)->~TestSidecar();
61 virtual ~TestSidecar() {}
64 DestructionNotifier notifier_
;
67 class DerivedTestSidecar
: public TestSidecar
{
69 DerivedTestSidecar() {}
70 explicit DerivedTestSidecar(bool* destruction_flag
)
71 : TestSidecar(destruction_flag
) {}
72 int additional_field
= 0;
75 ~DerivedTestSidecar() override
{}
78 class TestContainer
: public SidecarListContainer
<TestElement
> {
81 : SidecarListContainer(
82 std::max(sizeof(TestElement
), sizeof(DerivedTestElement
)),
83 std::max(sizeof(TestSidecar
), sizeof(DerivedTestSidecar
)),
84 kNumInitiallyReservedElements
,
85 &TestSidecar::Destroy
) {}
88 TEST(SidecarListContainerTest
, Destructor
) {
89 bool element_destroyed
= false;
90 bool sidecar_destroyed
= false;
93 TestContainer container
;
95 TestElement
* element
= container
.AllocateAndConstruct
<TestElement
>();
96 TestSidecar
* sidecar
=
97 new (container
.GetSidecar(element
)) TestSidecar(&sidecar_destroyed
);
98 element
->set_destruction_flag(&element_destroyed
);
100 // They shouldn't be destroyed yet. And they shouldn't overlap in memory.
101 ASSERT_FALSE(element_destroyed
);
102 ASSERT_FALSE(sidecar_destroyed
);
103 ASSERT_GE(reinterpret_cast<char*>(sidecar
),
104 reinterpret_cast<char*>(element
) + sizeof(TestElement
));
107 // They should, however, be destroyed when going out of scope.
108 ASSERT_TRUE(element_destroyed
);
109 ASSERT_TRUE(sidecar_destroyed
);
112 TEST(SidecarListContainerTest
, Clear
) {
113 bool element_destroyed
= false;
114 bool sidecar_destroyed
= false;
116 TestContainer container
;
118 TestElement
* element
= container
.AllocateAndConstruct
<TestElement
>();
119 new (container
.GetSidecar(element
)) TestSidecar(&sidecar_destroyed
);
120 element
->set_destruction_flag(&element_destroyed
);
122 // They shouldn't be destroyed yet.
123 ASSERT_FALSE(element_destroyed
);
124 ASSERT_FALSE(sidecar_destroyed
);
126 // They should, however, be destroyed after clearing.
128 EXPECT_TRUE(element_destroyed
);
129 EXPECT_TRUE(sidecar_destroyed
);
132 TEST(SidecarListContainerTest
, DerivedTypes
) {
133 bool element_destroyed
= false;
134 bool sidecar_destroyed
= false;
137 TestContainer container
;
139 DerivedTestElement
* element
=
140 container
.AllocateAndConstruct
<DerivedTestElement
>();
141 DerivedTestSidecar
* sidecar
= new (container
.GetSidecar(element
))
142 DerivedTestSidecar(&sidecar_destroyed
);
143 element
->set_destruction_flag(&element_destroyed
);
144 element
->additional_field
= 12;
145 sidecar
->additional_field
= 13;
147 // They shouldn't be destroyed yet.
148 ASSERT_FALSE(element_destroyed
);
149 ASSERT_FALSE(sidecar_destroyed
);
152 // They should, however, be destroyed when going out of scope.
153 EXPECT_TRUE(element_destroyed
);
154 EXPECT_TRUE(sidecar_destroyed
);
157 TEST(SidecarListContainerTest
, AddingAndRemovingElements
) {
158 TestContainer container
;
159 EXPECT_TRUE(container
.empty());
160 EXPECT_EQ(0u, container
.size());
161 EXPECT_EQ(container
.end(), container
.begin());
163 for (size_t i
= 1; i
<= kNumElementsForTest
; i
++) {
164 TestElement
* element
= container
.AllocateAndConstruct
<TestElement
>();
165 new (container
.GetSidecar(element
)) TestSidecar();
167 ASSERT_FALSE(container
.empty());
168 ASSERT_EQ(i
, container
.size());
169 ASSERT_NE(container
.end(), container
.begin());
172 size_t num_elements
= 0;
173 for (const auto* element
: container
) {
177 EXPECT_EQ(kNumElementsForTest
, num_elements
);
180 EXPECT_TRUE(container
.empty());
181 EXPECT_EQ(0u, container
.size());
182 EXPECT_EQ(container
.end(), container
.begin());
185 TEST(SidecarListContainerTest
, RemoveLast
) {
186 // We need only ensure that the sidecar is also destroyed on RemoveLast.
187 // The rest is logic already present in ListContainer.
188 bool sidecar_destroyed
= false;
189 TestContainer container
;
190 TestElement
* element
= container
.AllocateAndConstruct
<TestElement
>();
191 new (container
.GetSidecar(element
)) TestSidecar(&sidecar_destroyed
);
192 ASSERT_FALSE(sidecar_destroyed
);
193 container
.RemoveLast();
194 ASSERT_TRUE(sidecar_destroyed
);