cord_rep_btree_reader_test.cc
Go to the documentation of this file.
1 // Copyright 2021 The Abseil Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of 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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
17 #include <iostream>
18 #include <random>
19 #include <string>
20 #include <vector>
21 
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/base/config.h"
25 #include "absl/base/internal/raw_logging.h"
26 #include "absl/strings/cord.h"
27 #include "absl/strings/internal/cord_internal.h"
30 #include "absl/strings/string_view.h"
31 
32 namespace absl {
34 namespace cord_internal {
35 namespace {
36 
41 
47 
49 
50 TEST(CordRepBtreeReaderTest, Next) {
51  constexpr size_t kChars = 3;
52  const size_t cap = CordRepBtree::kMaxCapacity;
53  int counts[] = {1, 2, cap, cap * cap, cap * cap + 1, cap * cap * 2 + 17};
54 
55  for (int count : counts) {
57  std::vector<CordRep*> flats = CreateFlatsFromString(data, kChars);
58  CordRepBtree* node = CordRepBtreeFromFlats(flats);
59 
60  CordRepBtreeReader reader;
61  size_t remaining = data.length();
62  absl::string_view chunk = reader.Init(node);
63  EXPECT_THAT(chunk, Eq(data.substr(0, chunk.length())));
64 
65  remaining -= chunk.length();
66  EXPECT_THAT(reader.remaining(), Eq(remaining));
67 
68  while (remaining > 0) {
69  const size_t offset = data.length() - remaining;
70  chunk = reader.Next();
71  EXPECT_THAT(chunk, Eq(data.substr(offset, chunk.length())));
72 
73  remaining -= chunk.length();
74  EXPECT_THAT(reader.remaining(), Eq(remaining));
75  }
76 
77  EXPECT_THAT(reader.remaining(), Eq(0));
78 
79  // Verify trying to read beyond EOF returns empty string_view
81 
82  CordRep::Unref(node);
83  }
84 }
85 
86 TEST(CordRepBtreeReaderTest, Skip) {
87  constexpr size_t kChars = 3;
88  const size_t cap = CordRepBtree::kMaxCapacity;
89  int counts[] = {1, 2, cap, cap * cap, cap * cap + 1, cap * cap * 2 + 17};
90 
91  for (int count : counts) {
93  std::vector<CordRep*> flats = CreateFlatsFromString(data, kChars);
94  CordRepBtree* node = CordRepBtreeFromFlats(flats);
95 
96  for (size_t skip1 = 0; skip1 < data.length() - kChars; ++skip1) {
97  for (size_t skip2 = 0; skip2 < data.length() - kChars; ++skip2) {
98  CordRepBtreeReader reader;
99  size_t remaining = data.length();
100  absl::string_view chunk = reader.Init(node);
101  remaining -= chunk.length();
102 
103  chunk = reader.Skip(skip1);
104  size_t offset = data.length() - remaining;
105  ASSERT_THAT(chunk, Eq(data.substr(offset + skip1, chunk.length())));
106  remaining -= chunk.length() + skip1;
107  ASSERT_THAT(reader.remaining(), Eq(remaining));
108 
109  if (remaining == 0) continue;
110 
111  size_t skip = std::min(remaining - 1, skip2);
112  chunk = reader.Skip(skip);
113  offset = data.length() - remaining;
114  ASSERT_THAT(chunk, Eq(data.substr(offset + skip, chunk.length())));
115  }
116  }
117 
118  CordRep::Unref(node);
119  }
120 }
121 
122 TEST(CordRepBtreeReaderTest, SkipBeyondLength) {
123  CordRepBtree* tree = CordRepBtree::Create(MakeFlat("abc"));
124  tree = CordRepBtree::Append(tree, MakeFlat("def"));
125  CordRepBtreeReader reader;
126  reader.Init(tree);
127  EXPECT_THAT(reader.Skip(100), IsEmpty());
128  EXPECT_THAT(reader.remaining(), Eq(0));
129  CordRep::Unref(tree);
130 }
131 
132 TEST(CordRepBtreeReaderTest, Seek) {
133  constexpr size_t kChars = 3;
134  const size_t cap = CordRepBtree::kMaxCapacity;
135  int counts[] = {1, 2, cap, cap * cap, cap * cap + 1, cap * cap * 2 + 17};
136 
137  for (int count : counts) {
139  std::vector<CordRep*> flats = CreateFlatsFromString(data, kChars);
140  CordRepBtree* node = CordRepBtreeFromFlats(flats);
141 
142  for (size_t seek = 0; seek < data.length() - 1; ++seek) {
143  CordRepBtreeReader reader;
144  reader.Init(node);
145  absl::string_view chunk = reader.Seek(seek);
146  ASSERT_THAT(chunk, Not(IsEmpty()));
147  ASSERT_THAT(chunk, Eq(data.substr(seek, chunk.length())));
148  ASSERT_THAT(reader.remaining(),
149  Eq(data.length() - seek - chunk.length()));
150  }
151 
152  CordRep::Unref(node);
153  }
154 }
155 
156 TEST(CordRepBtreeReaderTest, SeekBeyondLength) {
157  CordRepBtree* tree = CordRepBtree::Create(MakeFlat("abc"));
158  tree = CordRepBtree::Append(tree, MakeFlat("def"));
159  CordRepBtreeReader reader;
160  reader.Init(tree);
161  EXPECT_THAT(reader.Seek(6), IsEmpty());
162  EXPECT_THAT(reader.remaining(), Eq(0));
163  EXPECT_THAT(reader.Seek(100), IsEmpty());
164  EXPECT_THAT(reader.remaining(), Eq(0));
165  CordRep::Unref(tree);
166 }
167 
168 TEST(CordRepBtreeReaderTest, Read) {
169  std::string data = "abcdefghijklmno";
170  std::vector<CordRep*> flats = CreateFlatsFromString(data, 5);
171  CordRepBtree* node = CordRepBtreeFromFlats(flats);
172 
173  CordRep* tree;
174  CordRepBtreeReader reader;
175  absl::string_view chunk;
176 
177  // Read zero bytes
178  chunk = reader.Init(node);
179  chunk = reader.Read(0, chunk.length(), tree);
180  EXPECT_THAT(tree, Eq(nullptr));
181  EXPECT_THAT(chunk, Eq("abcde"));
182  EXPECT_THAT(reader.remaining(), Eq(10));
183  EXPECT_THAT(reader.Next(), Eq("fghij"));
184 
185  // Read in full
186  chunk = reader.Init(node);
187  chunk = reader.Read(15, chunk.length(), tree);
188  EXPECT_THAT(tree, Ne(nullptr));
189  EXPECT_THAT(CordToString(tree), Eq("abcdefghijklmno"));
190  EXPECT_THAT(chunk, Eq(""));
191  EXPECT_THAT(reader.remaining(), Eq(0));
192  CordRep::Unref(tree);
193 
194  // Read < chunk bytes
195  chunk = reader.Init(node);
196  chunk = reader.Read(3, chunk.length(), tree);
197  ASSERT_THAT(tree, Ne(nullptr));
198  EXPECT_THAT(CordToString(tree), Eq("abc"));
199  EXPECT_THAT(chunk, Eq("de"));
200  EXPECT_THAT(reader.remaining(), Eq(10));
201  EXPECT_THAT(reader.Next(), Eq("fghij"));
202  CordRep::Unref(tree);
203 
204  // Read < chunk bytes at offset
205  chunk = reader.Init(node);
206  chunk = reader.Read(2, chunk.length() - 2, tree);
207  ASSERT_THAT(tree, Ne(nullptr));
208  EXPECT_THAT(CordToString(tree), Eq("cd"));
209  EXPECT_THAT(chunk, Eq("e"));
210  EXPECT_THAT(reader.remaining(), Eq(10));
211  EXPECT_THAT(reader.Next(), Eq("fghij"));
212  CordRep::Unref(tree);
213 
214  // Read from consumed chunk
215  chunk = reader.Init(node);
216  chunk = reader.Read(3, 0, tree);
217  ASSERT_THAT(tree, Ne(nullptr));
218  EXPECT_THAT(CordToString(tree), Eq("fgh"));
219  EXPECT_THAT(chunk, Eq("ij"));
220  EXPECT_THAT(reader.remaining(), Eq(5));
221  EXPECT_THAT(reader.Next(), Eq("klmno"));
222  CordRep::Unref(tree);
223 
224  // Read across chunks
225  chunk = reader.Init(node);
226  chunk = reader.Read(12, chunk.length() - 2, tree);
227  ASSERT_THAT(tree, Ne(nullptr));
228  EXPECT_THAT(CordToString(tree), Eq("cdefghijklmn"));
229  EXPECT_THAT(chunk, Eq("o"));
230  EXPECT_THAT(reader.remaining(), Eq(0));
231  CordRep::Unref(tree);
232 
233  // Read across chunks landing on exact edge boundary
234  chunk = reader.Init(node);
235  chunk = reader.Read(10 - 2, chunk.length() - 2, tree);
236  ASSERT_THAT(tree, Ne(nullptr));
237  EXPECT_THAT(CordToString(tree), Eq("cdefghij"));
238  EXPECT_THAT(chunk, Eq("klmno"));
239  EXPECT_THAT(reader.remaining(), Eq(0));
240  CordRep::Unref(tree);
241 
242  CordRep::Unref(node);
243 }
244 
245 TEST(CordRepBtreeReaderTest, ReadExhaustive) {
246  constexpr size_t kChars = 3;
247  const size_t cap = CordRepBtree::kMaxCapacity;
248  int counts[] = {1, 2, cap, cap * cap + 1, cap * cap * cap * 2 + 17};
249 
250  for (int count : counts) {
252  std::vector<CordRep*> flats = CreateFlatsFromString(data, kChars);
253  CordRepBtree* node = CordRepBtreeFromFlats(flats);
254 
255  for (size_t read_size : {kChars - 1, kChars, kChars + 7, cap * cap}) {
256  CordRepBtreeReader reader;
257  absl::string_view chunk = reader.Init(node);
258 
259  // `consumed` tracks the end of last consumed chunk which is the start of
260  // the next chunk: we always read with `chunk_size = chunk.length()`.
261  size_t consumed = 0;
262  size_t remaining = data.length();
263  while (remaining > 0) {
264  CordRep* tree;
265  size_t n = (std::min)(remaining, read_size);
266  chunk = reader.Read(n, chunk.length(), tree);
267  EXPECT_THAT(tree, Ne(nullptr));
268  if (tree) {
269  EXPECT_THAT(CordToString(tree), Eq(data.substr(consumed, n)));
270  CordRep::Unref(tree);
271  }
272 
273  consumed += n;
274  remaining -= n;
275  EXPECT_THAT(reader.remaining(), Eq(remaining - chunk.length()));
276 
277  if (remaining > 0) {
278  ASSERT_FALSE(chunk.empty());
279  ASSERT_THAT(chunk, Eq(data.substr(consumed, chunk.length())));
280  } else {
281  ASSERT_TRUE(chunk.empty()) << chunk;
282  }
283  }
284  }
285 
286  CordRep::Unref(node);
287  }
288 }
289 
290 } // namespace
291 } // namespace cord_internal
293 } // namespace absl
absl::cordrep_testing::CreateRandomString
std::string CreateRandomString(size_t n)
Definition: cord_rep_test_util.h:69
absl::cord_internal::CordRepBtree::kMaxCapacity
static constexpr size_t kMaxCapacity
Definition: cord_rep_btree.h:81
testing::Not
internal::NotMatcher< InnerMatcher > Not(InnerMatcher m)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8926
absl::cord_internal::CordRep::Unref
static void Unref(CordRep *rep)
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:642
EXPECT_THAT
#define EXPECT_THAT(value, matcher)
mkowners.skip
bool skip
Definition: mkowners.py:224
testing::Ne
internal::NeMatcher< Rhs > Ne(Rhs x)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8609
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
absl::cord_internal::CordRepBtreeReader::ReadResult
CordRepBtreeNavigator::ReadResult ReadResult
Definition: cord_rep_btree_reader.h:81
absl::TEST
TEST(NotificationTest, SanityTest)
Definition: abseil-cpp/absl/synchronization/notification_test.cc:126
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::base_internal::Next
static AllocList * Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena)
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:453
absl::string_view::length
constexpr size_type length() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:282
cord_rep_btree_reader.h
absl::cordrep_testing::CreateFlatsFromString
std::vector< cord_internal::CordRep * > CreateFlatsFromString(absl::string_view data, size_t chunk_size)
Definition: cord_rep_test_util.h:86
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::ABSL_NAMESPACE_BEGIN::MakeFlat
CordRep * MakeFlat(absl::string_view s, size_t extra=0)
Definition: abseil-cpp/absl/strings/cord_ring_test.cc:197
testing::internal::posix::Read
int Read(int fd, void *buf, unsigned int count)
Definition: bloaty/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:2044
ASSERT_THAT
#define ASSERT_THAT(value, matcher)
testing::Eq
internal::EqMatcher< T > Eq(T x)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8561
cord_rep_btree.h
absl::cordrep_testing::CordRepBtreeFromFlats
cord_internal::CordRepBtree * CordRepBtreeFromFlats(absl::Span< cord_internal::CordRep *const > flats)
Definition: cord_rep_test_util.h:96
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
absl::cord_internal::CordRepBtree::Create
static CordRepBtree * Create(CordRep *rep)
Definition: cord_rep_btree.h:831
min
#define min(a, b)
Definition: qsort.h:83
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
absl::cord_internal::CordRepBtree::Append
static CordRepBtree * Append(CordRepBtree *tree, CordRep *rep)
Definition: cord_rep_btree.h:892
absl::cord_internal::ReadResult
CordRepBtreeNavigator::ReadResult ReadResult
Definition: cord_rep_btree_navigator.cc:27
absl::Skip
static PerThreadSynch * Skip(PerThreadSynch *x)
Definition: abseil-cpp/absl/synchronization/mutex.cc:837
count
int * count
Definition: bloaty/third_party/googletest/googlemock/test/gmock_stress_test.cc:96
absl::container_internal::IsEmpty
bool IsEmpty(ctrl_t c)
Definition: abseil-cpp/absl/container/internal/raw_hash_set.h:489
ASSERT_TRUE
#define ASSERT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1973
ASSERT_FALSE
#define ASSERT_FALSE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1976
absl::string_view::empty
constexpr bool empty() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:292
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
read_size
static int read_size
Definition: test-tcp-close-reset.c:48
absl::cordrep_testing::CordToString
void CordToString(cord_internal::CordRep *rep, std::string &s)
Definition: cord_rep_test_util.h:138
cord_rep_test_util.h
reader
void reader(void *n)
Definition: libuv/docs/code/locks/main.c:8
offset
voidpf uLong offset
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:142


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:03