| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "quiche/common/quiche_simple_arena.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "absl/strings/string_view.h" |
| #include "quiche/common/platform/api/quiche_test.h" |
| |
| namespace quiche { |
| namespace { |
| |
| size_t kDefaultBlockSize = 2048; |
| const char kTestString[] = "This is a decently long test string."; |
| |
| TEST(QuicheSimpleArenaTest, NoAllocationOnConstruction) { |
| QuicheSimpleArena arena(kDefaultBlockSize); |
| EXPECT_EQ(0u, arena.status().bytes_allocated()); |
| } |
| |
| TEST(QuicheSimpleArenaTest, Memdup) { |
| QuicheSimpleArena arena(kDefaultBlockSize); |
| const size_t length = strlen(kTestString); |
| char* c = arena.Memdup(kTestString, length); |
| EXPECT_NE(nullptr, c); |
| EXPECT_NE(c, kTestString); |
| EXPECT_EQ(absl::string_view(c, length), kTestString); |
| } |
| |
| TEST(QuicheSimpleArenaTest, MemdupLargeString) { |
| QuicheSimpleArena arena(10 /* block size */); |
| const size_t length = strlen(kTestString); |
| char* c = arena.Memdup(kTestString, length); |
| EXPECT_NE(nullptr, c); |
| EXPECT_NE(c, kTestString); |
| EXPECT_EQ(absl::string_view(c, length), kTestString); |
| } |
| |
| TEST(QuicheSimpleArenaTest, MultipleBlocks) { |
| QuicheSimpleArena arena(40 /* block size */); |
| std::vector<std::string> strings = { |
| "One decently long string.", "Another string.", |
| "A third string that will surely go in a different block."}; |
| std::vector<absl::string_view> copies; |
| for (const std::string& s : strings) { |
| absl::string_view sp(arena.Memdup(s.data(), s.size()), s.size()); |
| copies.push_back(sp); |
| } |
| EXPECT_EQ(strings.size(), copies.size()); |
| for (size_t i = 0; i < strings.size(); ++i) { |
| EXPECT_EQ(copies[i], strings[i]); |
| } |
| } |
| |
| TEST(QuicheSimpleArenaTest, UseAfterReset) { |
| QuicheSimpleArena arena(kDefaultBlockSize); |
| const size_t length = strlen(kTestString); |
| char* c = arena.Memdup(kTestString, length); |
| arena.Reset(); |
| c = arena.Memdup(kTestString, length); |
| EXPECT_NE(nullptr, c); |
| EXPECT_NE(c, kTestString); |
| EXPECT_EQ(absl::string_view(c, length), kTestString); |
| } |
| |
| TEST(QuicheSimpleArenaTest, Free) { |
| QuicheSimpleArena arena(kDefaultBlockSize); |
| const size_t length = strlen(kTestString); |
| // Freeing memory not owned by the arena should be a no-op, and freeing |
| // before any allocations from the arena should be a no-op. |
| arena.Free(const_cast<char*>(kTestString), length); |
| char* c1 = arena.Memdup("Foo", 3); |
| char* c2 = arena.Memdup(kTestString, length); |
| arena.Free(const_cast<char*>(kTestString), length); |
| char* c3 = arena.Memdup("Bar", 3); |
| char* c4 = arena.Memdup(kTestString, length); |
| EXPECT_NE(c1, c2); |
| EXPECT_NE(c1, c3); |
| EXPECT_NE(c1, c4); |
| EXPECT_NE(c2, c3); |
| EXPECT_NE(c2, c4); |
| EXPECT_NE(c3, c4); |
| // Freeing c4 should succeed, since it was the most recent allocation. |
| arena.Free(c4, length); |
| // Freeing c2 should be a no-op. |
| arena.Free(c2, length); |
| // c5 should reuse memory that was previously used by c4. |
| char* c5 = arena.Memdup("Baz", 3); |
| EXPECT_EQ(c4, c5); |
| } |
| |
| TEST(QuicheSimpleArenaTest, Alloc) { |
| QuicheSimpleArena arena(kDefaultBlockSize); |
| const size_t length = strlen(kTestString); |
| char* c1 = arena.Alloc(length); |
| char* c2 = arena.Alloc(2 * length); |
| char* c3 = arena.Alloc(3 * length); |
| char* c4 = arena.Memdup(kTestString, length); |
| EXPECT_EQ(c1 + length, c2); |
| EXPECT_EQ(c2 + 2 * length, c3); |
| EXPECT_EQ(c3 + 3 * length, c4); |
| EXPECT_EQ(absl::string_view(c4, length), kTestString); |
| } |
| |
| TEST(QuicheSimpleArenaTest, Realloc) { |
| QuicheSimpleArena arena(kDefaultBlockSize); |
| const size_t length = strlen(kTestString); |
| // Simple realloc that fits in the block. |
| char* c1 = arena.Memdup(kTestString, length); |
| char* c2 = arena.Realloc(c1, length, 2 * length); |
| EXPECT_TRUE(c1); |
| EXPECT_EQ(c1, c2); |
| EXPECT_EQ(absl::string_view(c1, length), kTestString); |
| // Multiple reallocs. |
| char* c3 = arena.Memdup(kTestString, length); |
| EXPECT_EQ(c2 + 2 * length, c3); |
| EXPECT_EQ(absl::string_view(c3, length), kTestString); |
| char* c4 = arena.Realloc(c3, length, 2 * length); |
| EXPECT_EQ(c3, c4); |
| EXPECT_EQ(absl::string_view(c4, length), kTestString); |
| char* c5 = arena.Realloc(c4, 2 * length, 3 * length); |
| EXPECT_EQ(c4, c5); |
| EXPECT_EQ(absl::string_view(c5, length), kTestString); |
| char* c6 = arena.Memdup(kTestString, length); |
| EXPECT_EQ(c5 + 3 * length, c6); |
| EXPECT_EQ(absl::string_view(c6, length), kTestString); |
| // Realloc that does not fit in the remainder of the first block. |
| char* c7 = arena.Realloc(c6, length, kDefaultBlockSize); |
| EXPECT_EQ(absl::string_view(c7, length), kTestString); |
| arena.Free(c7, kDefaultBlockSize); |
| char* c8 = arena.Memdup(kTestString, length); |
| EXPECT_NE(c6, c7); |
| EXPECT_EQ(c7, c8); |
| EXPECT_EQ(absl::string_view(c8, length), kTestString); |
| } |
| |
| } // namespace |
| } // namespace quiche |