• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 //
8 // This file defines tests for the internal StringBlock class
9 
10 #include "google/protobuf/string_block.h"
11 
12 #include <cstddef>
13 #include <memory>
14 #include <string>
15 #include <vector>
16 
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 
20 // Must be included last
21 #include "google/protobuf/port_def.inc"
22 
23 using ::testing::Eq;
24 using ::testing::Ne;
25 
26 namespace google {
27 namespace protobuf {
28 namespace internal {
29 namespace {
30 
EffectiveSizeFor(int size)31 size_t EffectiveSizeFor(int size) {
32   size -= sizeof(StringBlock);
33   return static_cast<size_t>(size - (size % sizeof(std::string)));
34 }
35 
AllocatedSizeFor(int size)36 size_t AllocatedSizeFor(int size) {
37   return EffectiveSizeFor(size) + sizeof(StringBlock);
38 }
39 
TEST(StringBlockTest,HeapAllocateOneBlock)40 TEST(StringBlockTest, HeapAllocateOneBlock) {
41   StringBlock* block = StringBlock::New(nullptr);
42 
43   ASSERT_THAT(block, Ne(nullptr));
44   EXPECT_THAT(block->next(), Eq(nullptr));
45   ASSERT_TRUE(block->heap_allocated());
46   EXPECT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(256)));
47   EXPECT_THAT(block->effective_size(), Eq(EffectiveSizeFor(256)));
48   EXPECT_THAT(block->begin(), Eq(block->AtOffset(0)));
49   EXPECT_THAT(block->end(), Eq(block->AtOffset(block->effective_size())));
50 
51   EXPECT_THAT(StringBlock::Delete(block), Eq(AllocatedSizeFor(256)));
52 }
53 
TEST(StringBlockTest,EmplaceOneBlock)54 TEST(StringBlockTest, EmplaceOneBlock) {
55   // NextSize() returns unrounded 'min_size()' on first call.
56   size_t size = StringBlock::NextSize(nullptr);
57   EXPECT_THAT(size, Eq(256));
58 
59   auto buffer = std::make_unique<char[]>(size);
60   StringBlock* block = StringBlock::Emplace(buffer.get(), size, nullptr);
61 
62   ASSERT_THAT(block, Ne(nullptr));
63   EXPECT_THAT(block->next(), Eq(nullptr));
64   ASSERT_FALSE(block->heap_allocated());
65   EXPECT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(256)));
66   EXPECT_THAT(block->effective_size(), Eq(EffectiveSizeFor(256)));
67   EXPECT_THAT(block->begin(), Eq(block->AtOffset(0)));
68   EXPECT_THAT(block->end(), Eq(block->AtOffset(block->effective_size())));
69 
70   EXPECT_THAT(StringBlock::Delete(block), Eq(0));
71 }
72 
TEST(StringBlockTest,HeapAllocateMultipleBlocks)73 TEST(StringBlockTest, HeapAllocateMultipleBlocks) {
74   // Note: first two blocks are 256
75   StringBlock* previous = StringBlock::New(nullptr);
76 
77   for (int size = 256; size <= 8192; size *= 2) {
78     StringBlock* block = StringBlock::New(previous);
79     ASSERT_THAT(block, Ne(nullptr));
80     ASSERT_THAT(block->next(), Eq(previous));
81     ASSERT_TRUE(block->heap_allocated());
82     ASSERT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(size)));
83     ASSERT_THAT(block->effective_size(), Eq(EffectiveSizeFor(size)));
84     ASSERT_THAT(block->begin(), Eq(block->AtOffset(0)));
85     ASSERT_THAT(block->end(), Eq(block->AtOffset(block->effective_size())));
86     previous = block;
87   }
88 
89   // Capped at 8K from here on
90   StringBlock* block = StringBlock::New(previous);
91   ASSERT_THAT(block, Ne(nullptr));
92   ASSERT_THAT(block->next(), Eq(previous));
93   ASSERT_TRUE(block->heap_allocated());
94   ASSERT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(8192)));
95   ASSERT_THAT(block->effective_size(), Eq(EffectiveSizeFor(8192)));
96   ASSERT_THAT(block->begin(), Eq(block->AtOffset(0)));
97   ASSERT_THAT(block->end(), Eq(block->AtOffset(block->effective_size())));
98 
99   while (block) {
100     size_t size = block->allocated_size();
101     StringBlock* next = block->next();
102     EXPECT_THAT(StringBlock::Delete(block), Eq(AllocatedSizeFor(size)));
103     block = next;
104   }
105 }
106 
TEST(StringBlockTest,EmplaceMultipleBlocks)107 TEST(StringBlockTest, EmplaceMultipleBlocks) {
108   std::vector<std::unique_ptr<char[]>> buffers;
109 
110   // Convenience lambda to allocate a buffer and invoke Emplace on it.
111   auto EmplaceBlock = [&](StringBlock* previous) {
112     size_t size = StringBlock::NextSize(previous);
113     buffers.push_back(std::make_unique<char[]>(size));
114     return StringBlock::Emplace(buffers.back().get(), size, previous);
115   };
116 
117   // Note: first two blocks are 256
118   StringBlock* previous = EmplaceBlock(nullptr);
119 
120   for (int size = 256; size <= 8192; size *= 2) {
121     StringBlock* block = EmplaceBlock(previous);
122     ASSERT_THAT(block, Ne(nullptr));
123     ASSERT_THAT(block->next(), Eq(previous));
124     ASSERT_FALSE(block->heap_allocated());
125     ASSERT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(size)));
126     ASSERT_THAT(block->effective_size(), Eq(EffectiveSizeFor(size)));
127     ASSERT_THAT(block->begin(), Eq(block->AtOffset(0)));
128     ASSERT_THAT(block->end(), Eq(block->AtOffset(block->effective_size())));
129     previous = block;
130   }
131 
132   // Capped at 8K from here on
133   StringBlock* block = EmplaceBlock(previous);
134   ASSERT_THAT(block, Ne(nullptr));
135   EXPECT_THAT(block->next(), Eq(previous));
136   ASSERT_FALSE(block->heap_allocated());
137   ASSERT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(8192)));
138   ASSERT_THAT(block->effective_size(), Eq(EffectiveSizeFor(8192)));
139   ASSERT_THAT(block->begin(), Eq(block->AtOffset(0)));
140   ASSERT_THAT(block->end(), Eq(block->AtOffset(block->effective_size())));
141 
142   while (block) {
143     StringBlock* next = block->next();
144     EXPECT_THAT(StringBlock::Delete(block), Eq(0));
145     block = next;
146   }
147 }
148 
149 }  // namespace
150 }  // namespace internal
151 }  // namespace protobuf
152 }  // namespace google
153 
154 #include "google/protobuf/port_undef.inc"
155