• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TEST(AllocatorTest,HasFlags)29 TEST(AllocatorTest, HasFlags) {
30   AllocatorForTest allocator;
31   EXPECT_TRUE(
32       allocator.HasCapability(Capability::kImplementsGetRequestedLayout));
33   EXPECT_TRUE(allocator.HasCapability(Capability::kImplementsGetUsableLayout));
34 }
35 
TEST(AllocatorTest,ResizeNull)36 TEST(AllocatorTest, ResizeNull) {
37   AllocatorForTest allocator;
38   EXPECT_FALSE(allocator.Resize(nullptr, sizeof(uint32_t)));
39 }
40 
TEST(AllocatorTest,ResizeZero)41 TEST(AllocatorTest, ResizeZero) {
42   AllocatorForTest allocator;
43   constexpr Layout layout = Layout::Of<uint32_t>();
44   void* ptr = allocator.Allocate(layout);
45   ASSERT_NE(ptr, nullptr);
46   EXPECT_FALSE(allocator.Resize(ptr, 0));
47 }
48 
TEST(AllocatorTest,ResizeSame)49 TEST(AllocatorTest, ResizeSame) {
50   AllocatorForTest allocator;
51   constexpr Layout layout = Layout::Of<uint32_t>();
52   void* ptr = allocator.Allocate(layout);
53   ASSERT_NE(ptr, nullptr);
54   EXPECT_TRUE(allocator.Resize(ptr, layout.size()));
55   EXPECT_EQ(allocator.resize_ptr(), ptr);
56   EXPECT_EQ(allocator.resize_old_size(), layout.size());
57   EXPECT_EQ(allocator.resize_new_size(), layout.size());
58 }
59 
TEST(AllocatorTest,ReallocateNull)60 TEST(AllocatorTest, ReallocateNull) {
61   AllocatorForTest allocator;
62   constexpr Layout old_layout = Layout::Of<uint32_t>();
63   size_t new_size = old_layout.size();
64   void* new_ptr = allocator.Reallocate(nullptr, new_size);
65 
66   // Resize should fail and Reallocate should call Allocate.
67   EXPECT_EQ(allocator.allocate_size(), new_size);
68 
69   // Deallocate should not be called.
70   EXPECT_EQ(allocator.deallocate_ptr(), nullptr);
71   EXPECT_EQ(allocator.deallocate_size(), 0U);
72 
73   // Overall, Reallocate should succeed.
74   EXPECT_NE(new_ptr, nullptr);
75 }
76 
TEST(AllocatorTest,ReallocateZeroNewSize)77 TEST(AllocatorTest, ReallocateZeroNewSize) {
78   AllocatorForTest allocator;
79   constexpr Layout old_layout = Layout::Of<uint32_t[3]>();
80   void* ptr = allocator.Allocate(old_layout);
81   ASSERT_EQ(allocator.allocate_size(), old_layout.size());
82   ASSERT_NE(ptr, nullptr);
83   allocator.ResetParameters();
84 
85   size_t new_size = 0;
86   void* new_ptr = allocator.Reallocate(ptr, new_size);
87 
88   // Reallocate does not call Resize, Allocate, or Deallocate.
89   EXPECT_EQ(allocator.resize_ptr(), nullptr);
90   EXPECT_EQ(allocator.resize_old_size(), 0U);
91   EXPECT_EQ(allocator.resize_new_size(), 0U);
92   EXPECT_EQ(allocator.allocate_size(), 0U);
93   EXPECT_EQ(allocator.deallocate_ptr(), nullptr);
94   EXPECT_EQ(allocator.deallocate_size(), 0U);
95 
96   // Overall, Reallocate should fail.
97   EXPECT_EQ(new_ptr, nullptr);
98 }
99 
TEST(AllocatorTest,ReallocateSame)100 TEST(AllocatorTest, ReallocateSame) {
101   AllocatorForTest allocator;
102   constexpr Layout layout = Layout::Of<uint32_t[3]>();
103   void* ptr = allocator.Allocate(layout);
104   ASSERT_EQ(allocator.allocate_size(), layout.size());
105   ASSERT_NE(ptr, nullptr);
106   allocator.ResetParameters();
107 
108   void* new_ptr = allocator.Reallocate(ptr, layout);
109 
110   // Reallocate should call Resize.
111   EXPECT_EQ(allocator.resize_ptr(), ptr);
112   EXPECT_EQ(allocator.resize_old_size(), layout.size());
113   EXPECT_EQ(allocator.resize_new_size(), layout.size());
114 
115   // DoAllocate should not be called.
116   EXPECT_EQ(allocator.allocate_size(), 0U);
117 
118   // DoDeallocate should not be called.
119   EXPECT_EQ(allocator.deallocate_ptr(), nullptr);
120   EXPECT_EQ(allocator.deallocate_size(), 0U);
121 
122   // Overall, Reallocate should succeed.
123   EXPECT_EQ(new_ptr, ptr);
124 }
125 
TEST(AllocatorTest,ReallocateSmaller)126 TEST(AllocatorTest, ReallocateSmaller) {
127   AllocatorForTest allocator;
128   constexpr Layout old_layout = Layout::Of<uint32_t[3]>();
129   void* ptr = allocator.Allocate(old_layout);
130   ASSERT_EQ(allocator.allocate_size(), old_layout.size());
131   ASSERT_NE(ptr, nullptr);
132   allocator.ResetParameters();
133 
134   size_t new_size = sizeof(uint32_t);
135   void* new_ptr = allocator.Reallocate(ptr, new_size);
136 
137   // Reallocate should call Resize.
138   EXPECT_EQ(allocator.resize_ptr(), ptr);
139   EXPECT_EQ(allocator.resize_old_size(), old_layout.size());
140   EXPECT_EQ(allocator.resize_new_size(), new_size);
141 
142   // Allocate should not be called.
143   EXPECT_EQ(allocator.allocate_size(), 0U);
144 
145   // Deallocate should not be called.
146   EXPECT_EQ(allocator.deallocate_ptr(), nullptr);
147   EXPECT_EQ(allocator.deallocate_size(), 0U);
148 
149   // Overall, Reallocate should succeed.
150   EXPECT_EQ(new_ptr, ptr);
151 }
152 
TEST(AllocatorTest,ReallocateLarger)153 TEST(AllocatorTest, ReallocateLarger) {
154   AllocatorForTest allocator;
155   constexpr Layout old_layout = Layout::Of<uint32_t>();
156   void* ptr = allocator.Allocate(old_layout);
157   ASSERT_EQ(allocator.allocate_size(), old_layout.size());
158   ASSERT_NE(ptr, nullptr);
159 
160   // The abstraction is a bit leaky here: This tests relies on the details of
161   // `Resize` in order to get it to fail and fallback to
162   // allocate/copy/deallocate. Allocate a second block, which should prevent the
163   // first one from being able to grow.
164   void* next = allocator.Allocate(old_layout);
165   ASSERT_EQ(allocator.allocate_size(), old_layout.size());
166   ASSERT_NE(next, nullptr);
167   allocator.ResetParameters();
168 
169   size_t new_size = sizeof(uint32_t[3]);
170   void* new_ptr = allocator.Reallocate(ptr, new_size);
171 
172   // Reallocate should call Resize.
173   EXPECT_EQ(allocator.resize_ptr(), ptr);
174   EXPECT_EQ(allocator.resize_old_size(), old_layout.size());
175   EXPECT_EQ(allocator.resize_new_size(), new_size);
176 
177   // Resize should fail and Reallocate should call Allocate.
178   EXPECT_EQ(allocator.allocate_size(), new_size);
179 
180   // Deallocate should also be called.
181   EXPECT_EQ(allocator.deallocate_ptr(), ptr);
182   EXPECT_EQ(allocator.deallocate_size(), old_layout.size());
183 
184   // Overall, Reallocate should succeed.
185   EXPECT_NE(new_ptr, nullptr);
186   EXPECT_NE(new_ptr, ptr);
187 }
188 
189 // Test fixture for IsEqual tests.
190 class BaseAllocator : public pw::Allocator {
191  public:
BaseAllocator(void * ptr)192   BaseAllocator(void* ptr) : pw::Allocator(Capabilities()), ptr_(ptr) {}
193 
194  private:
DoAllocate(Layout)195   void* DoAllocate(Layout) override {
196     void* ptr = ptr_;
197     ptr_ = nullptr;
198     return ptr;
199   }
200 
DoDeallocate(void *)201   void DoDeallocate(void*) override {}
DoDeallocate(void *,Layout)202   void DoDeallocate(void*, Layout) override {}
203 
204   void* ptr_;
205 };
206 
207 // Test fixture for IsEqual tests.
208 class DerivedAllocator : public BaseAllocator {
209  public:
DerivedAllocator(size_t value,void * ptr)210   DerivedAllocator(size_t value, void* ptr)
211       : BaseAllocator(ptr), value_(value) {}
value() const212   size_t value() const { return value_; }
213 
214  private:
215   size_t value_;
216 };
217 
TEST(AllocatorTest,IsEqualFailsWithDifferentObjects)218 TEST(AllocatorTest, IsEqualFailsWithDifferentObjects) {
219   std::array<std::byte, 8> buffer;
220   DerivedAllocator derived1(1, buffer.data());
221   DerivedAllocator derived2(2, buffer.data());
222   EXPECT_FALSE(derived1.IsEqual(derived2));
223   EXPECT_FALSE(derived2.IsEqual(derived1));
224 }
225 
TEST(AllocatorTest,IsEqualSucceedsWithSameObject)226 TEST(AllocatorTest, IsEqualSucceedsWithSameObject) {
227   std::array<std::byte, 8> buffer;
228   DerivedAllocator derived(1, buffer.data());
229   BaseAllocator* base = &derived;
230   EXPECT_TRUE(derived.IsEqual(*base));
231   EXPECT_TRUE(base->IsEqual(derived));
232 }
233 
234 }  // namespace
235