xref: /aosp_15_r20/external/pigweed/pw_allocator/allocator_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_allocator/allocator.h"
16 
17 #include <cstddef>
18 
19 #include "pw_allocator/capability.h"
20 #include "pw_allocator/testing.h"
21 #include "pw_unit_test/framework.h"
22 
23 namespace {
24 
25 using ::pw::allocator::Capability;
26 using ::pw::allocator::Layout;
27 using AllocatorForTest = ::pw::allocator::test::AllocatorForTest<256>;
28 using BlockType = AllocatorForTest::BlockType;
29 static_assert(sizeof(uintptr_t) == BlockType::kAlignment);
30 
TEST(AllocatorTest,HasFlags)31 TEST(AllocatorTest, HasFlags) {
32   AllocatorForTest allocator;
33   EXPECT_TRUE(
34       allocator.HasCapability(Capability::kImplementsGetRequestedLayout));
35   EXPECT_TRUE(allocator.HasCapability(Capability::kImplementsGetUsableLayout));
36 }
37 
TEST(AllocatorTest,ResizeNull)38 TEST(AllocatorTest, ResizeNull) {
39   AllocatorForTest allocator;
40   EXPECT_FALSE(allocator.Resize(nullptr, sizeof(uintptr_t)));
41 }
42 
TEST(AllocatorTest,ResizeZero)43 TEST(AllocatorTest, ResizeZero) {
44   AllocatorForTest allocator;
45   constexpr Layout layout = Layout::Of<uintptr_t>();
46   void* ptr = allocator.Allocate(layout);
47   ASSERT_NE(ptr, nullptr);
48   EXPECT_FALSE(allocator.Resize(ptr, 0));
49 }
50 
TEST(AllocatorTest,ResizeSame)51 TEST(AllocatorTest, ResizeSame) {
52   AllocatorForTest allocator;
53   constexpr Layout layout = Layout::Of<uintptr_t>();
54   void* ptr = allocator.Allocate(layout);
55   ASSERT_NE(ptr, nullptr);
56   EXPECT_TRUE(allocator.Resize(ptr, layout.size()));
57   EXPECT_EQ(allocator.resize_ptr(), ptr);
58   EXPECT_EQ(allocator.resize_old_size(), layout.size());
59   EXPECT_EQ(allocator.resize_new_size(), layout.size());
60 }
61 
TEST(AllocatorTest,ReallocateNull)62 TEST(AllocatorTest, ReallocateNull) {
63   AllocatorForTest allocator;
64   constexpr Layout old_layout = Layout::Of<uintptr_t>();
65   constexpr Layout new_layout(old_layout.size(), old_layout.alignment());
66   void* new_ptr = allocator.Reallocate(nullptr, new_layout);
67 
68   // Resize should fail and Reallocate should call Allocate.
69   EXPECT_EQ(allocator.allocate_size(), new_layout.size());
70 
71   // Deallocate should not be called.
72   EXPECT_EQ(allocator.deallocate_ptr(), nullptr);
73   EXPECT_EQ(allocator.deallocate_size(), 0U);
74 
75   // Overall, Reallocate should succeed.
76   EXPECT_NE(new_ptr, nullptr);
77 }
78 
TEST(AllocatorTest,ReallocateZeroNewSize)79 TEST(AllocatorTest, ReallocateZeroNewSize) {
80   AllocatorForTest allocator;
81   constexpr Layout old_layout = Layout::Of<uintptr_t[3]>();
82   void* ptr = allocator.Allocate(old_layout);
83   ASSERT_EQ(allocator.allocate_size(), old_layout.size());
84   ASSERT_NE(ptr, nullptr);
85   allocator.ResetParameters();
86 
87   constexpr Layout new_layout(0, old_layout.alignment());
88   void* new_ptr = allocator.Reallocate(ptr, new_layout);
89 
90   // Reallocate does not call Resize, Allocate, or Deallocate.
91   EXPECT_EQ(allocator.resize_ptr(), nullptr);
92   EXPECT_EQ(allocator.resize_old_size(), 0U);
93   EXPECT_EQ(allocator.resize_new_size(), 0U);
94   EXPECT_EQ(allocator.allocate_size(), 0U);
95   EXPECT_EQ(allocator.deallocate_ptr(), nullptr);
96   EXPECT_EQ(allocator.deallocate_size(), 0U);
97 
98   // Overall, Reallocate should fail.
99   EXPECT_EQ(new_ptr, nullptr);
100 }
101 
TEST(AllocatorTest,ReallocateSame)102 TEST(AllocatorTest, ReallocateSame) {
103   AllocatorForTest allocator;
104   constexpr Layout layout = Layout::Of<uintptr_t[3]>();
105   void* ptr = allocator.Allocate(layout);
106   ASSERT_EQ(allocator.allocate_size(), layout.size());
107   ASSERT_NE(ptr, nullptr);
108   allocator.ResetParameters();
109 
110   void* new_ptr = allocator.Reallocate(ptr, layout);
111 
112   // Reallocate should call Resize.
113   EXPECT_EQ(allocator.resize_ptr(), ptr);
114   EXPECT_EQ(allocator.resize_old_size(), layout.size());
115   EXPECT_EQ(allocator.resize_new_size(), layout.size());
116 
117   // DoAllocate should not be called.
118   EXPECT_EQ(allocator.allocate_size(), 0U);
119 
120   // DoDeallocate should not be called.
121   EXPECT_EQ(allocator.deallocate_ptr(), nullptr);
122   EXPECT_EQ(allocator.deallocate_size(), 0U);
123 
124   // Overall, Reallocate should succeed.
125   EXPECT_EQ(new_ptr, ptr);
126 }
127 
TEST(AllocatorTest,ReallocateSmaller)128 TEST(AllocatorTest, ReallocateSmaller) {
129   AllocatorForTest allocator;
130   constexpr Layout old_layout = Layout::Of<uintptr_t[3]>();
131   void* ptr = allocator.Allocate(old_layout);
132   ASSERT_EQ(allocator.allocate_size(), old_layout.size());
133   ASSERT_NE(ptr, nullptr);
134   allocator.ResetParameters();
135 
136   constexpr Layout new_layout(sizeof(uintptr_t), old_layout.alignment());
137   void* new_ptr = allocator.Reallocate(ptr, new_layout);
138 
139   // Reallocate should call Resize.
140   EXPECT_EQ(allocator.resize_ptr(), ptr);
141   EXPECT_EQ(allocator.resize_old_size(), old_layout.size());
142   EXPECT_EQ(allocator.resize_new_size(), new_layout.size());
143 
144   // Allocate should not be called.
145   EXPECT_EQ(allocator.allocate_size(), 0U);
146 
147   // Deallocate should not be called.
148   EXPECT_EQ(allocator.deallocate_ptr(), nullptr);
149   EXPECT_EQ(allocator.deallocate_size(), 0U);
150 
151   // Overall, Reallocate should succeed.
152   EXPECT_EQ(new_ptr, ptr);
153 }
154 
TEST(AllocatorTest,ReallocateLarger)155 TEST(AllocatorTest, ReallocateLarger) {
156   AllocatorForTest allocator;
157   constexpr Layout old_layout = Layout::Of<uintptr_t>();
158   void* ptr = allocator.Allocate(old_layout);
159   ASSERT_EQ(allocator.allocate_size(), old_layout.size());
160   ASSERT_NE(ptr, nullptr);
161 
162   // The abstraction is a bit leaky here: This tests relies on the details of
163   // `Resize` in order to get it to fail and fallback to
164   // allocate/copy/deallocate. Allocate a second block, which should prevent the
165   // first one from being able to grow.
166   void* next = allocator.Allocate(old_layout);
167   ASSERT_EQ(allocator.allocate_size(), old_layout.size());
168   ASSERT_NE(next, nullptr);
169   allocator.ResetParameters();
170 
171   constexpr Layout new_layout(sizeof(uintptr_t[3]), old_layout.alignment());
172   void* new_ptr = allocator.Reallocate(ptr, new_layout);
173 
174   // Reallocate should call Resize.
175   EXPECT_EQ(allocator.resize_ptr(), ptr);
176   EXPECT_EQ(allocator.resize_old_size(), old_layout.size());
177   EXPECT_EQ(allocator.resize_new_size(), new_layout.size());
178 
179   // Resize should fail and Reallocate should call Allocate.
180   EXPECT_EQ(allocator.allocate_size(), new_layout.size());
181 
182   // Deallocate should also be called.
183   EXPECT_EQ(allocator.deallocate_ptr(), ptr);
184   EXPECT_EQ(allocator.deallocate_size(), old_layout.size());
185 
186   // Overall, Reallocate should succeed.
187   EXPECT_NE(new_ptr, nullptr);
188   EXPECT_NE(new_ptr, ptr);
189 }
190 
191 // Test fixture for IsEqual tests.
192 class BaseAllocator : public pw::Allocator {
193  public:
BaseAllocator(void * ptr)194   BaseAllocator(void* ptr) : pw::Allocator(Capabilities()), ptr_(ptr) {}
195 
196  private:
DoAllocate(Layout)197   void* DoAllocate(Layout) override {
198     void* ptr = ptr_;
199     ptr_ = nullptr;
200     return ptr;
201   }
202 
DoDeallocate(void *)203   void DoDeallocate(void*) override {}
DoDeallocate(void *,Layout)204   void DoDeallocate(void*, Layout) override {}
205 
206   void* ptr_;
207 };
208 
209 // Test fixture for IsEqual tests.
210 class DerivedAllocator : public BaseAllocator {
211  public:
DerivedAllocator(size_t value,void * ptr)212   DerivedAllocator(size_t value, void* ptr)
213       : BaseAllocator(ptr), value_(value) {}
value() const214   size_t value() const { return value_; }
215 
216  private:
217   size_t value_;
218 };
219 
TEST(AllocatorTest,IsEqualFailsWithDifferentObjects)220 TEST(AllocatorTest, IsEqualFailsWithDifferentObjects) {
221   std::array<std::byte, 8> buffer;
222   DerivedAllocator derived1(1, buffer.data());
223   DerivedAllocator derived2(2, buffer.data());
224   EXPECT_FALSE(derived1.IsEqual(derived2));
225   EXPECT_FALSE(derived2.IsEqual(derived1));
226 }
227 
TEST(AllocatorTest,IsEqualSucceedsWithSameObject)228 TEST(AllocatorTest, IsEqualSucceedsWithSameObject) {
229   std::array<std::byte, 8> buffer;
230   DerivedAllocator derived(1, buffer.data());
231   BaseAllocator* base = &derived;
232   EXPECT_TRUE(derived.IsEqual(*base));
233   EXPECT_TRUE(base->IsEqual(derived));
234 }
235 
236 }  // namespace
237