1 // Copyright 2020 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
15 #include "absl/strings/cord.h"
16
17 #include <algorithm>
18 #include <array>
19 #include <cassert>
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstdio>
23 #include <cstring>
24 #include <iostream>
25 #include <iterator>
26 #include <limits>
27 #include <random>
28 #include <set>
29 #include <sstream>
30 #include <string>
31 #include <type_traits>
32 #include <utility>
33 #include <vector>
34
35 #include "gmock/gmock.h"
36 #include "gtest/gtest.h"
37 #include "absl/base/attributes.h"
38 #include "absl/base/config.h"
39 #include "absl/base/internal/endian.h"
40 #include "absl/base/macros.h"
41 #include "absl/base/options.h"
42 #include "absl/container/fixed_array.h"
43 #include "absl/functional/function_ref.h"
44 #include "absl/hash/hash.h"
45 #include "absl/log/check.h"
46 #include "absl/log/log.h"
47 #include "absl/random/random.h"
48 #include "absl/strings/cord_buffer.h"
49 #include "absl/strings/cord_test_helpers.h"
50 #include "absl/strings/cordz_test_helpers.h"
51 #include "absl/strings/internal/cord_internal.h"
52 #include "absl/strings/internal/cord_rep_crc.h"
53 #include "absl/strings/internal/cord_rep_flat.h"
54 #include "absl/strings/internal/cordz_statistics.h"
55 #include "absl/strings/internal/cordz_update_tracker.h"
56 #include "absl/strings/internal/string_constant.h"
57 #include "absl/strings/match.h"
58 #include "absl/strings/str_cat.h"
59 #include "absl/strings/str_format.h"
60 #include "absl/strings/string_view.h"
61 #include "absl/types/optional.h"
62
63 // convenience local constants
64 static constexpr auto FLAT = absl::cord_internal::FLAT;
65 static constexpr auto MAX_FLAT_TAG = absl::cord_internal::MAX_FLAT_TAG;
66
67 typedef std::mt19937_64 RandomEngine;
68
69 using absl::cord_internal::CordRep;
70 using absl::cord_internal::CordRepBtree;
71 using absl::cord_internal::CordRepConcat;
72 using absl::cord_internal::CordRepCrc;
73 using absl::cord_internal::CordRepExternal;
74 using absl::cord_internal::CordRepFlat;
75 using absl::cord_internal::CordRepSubstring;
76 using absl::cord_internal::CordzUpdateTracker;
77 using absl::cord_internal::kFlatOverhead;
78 using absl::cord_internal::kMaxFlatLength;
79 using ::testing::ElementsAre;
80 using ::testing::Le;
81
82 static std::string RandomLowercaseString(RandomEngine* rng);
83 static std::string RandomLowercaseString(RandomEngine* rng, size_t length);
84
GetUniformRandomUpTo(RandomEngine * rng,int upper_bound)85 static int GetUniformRandomUpTo(RandomEngine* rng, int upper_bound) {
86 if (upper_bound > 0) {
87 std::uniform_int_distribution<int> uniform(0, upper_bound - 1);
88 return uniform(*rng);
89 } else {
90 return 0;
91 }
92 }
93
GetUniformRandomUpTo(RandomEngine * rng,size_t upper_bound)94 static size_t GetUniformRandomUpTo(RandomEngine* rng, size_t upper_bound) {
95 if (upper_bound > 0) {
96 std::uniform_int_distribution<size_t> uniform(0, upper_bound - 1);
97 return uniform(*rng);
98 } else {
99 return 0;
100 }
101 }
102
GenerateSkewedRandom(RandomEngine * rng,int max_log)103 static int32_t GenerateSkewedRandom(RandomEngine* rng, int max_log) {
104 const uint32_t base = (*rng)() % (max_log + 1);
105 const uint32_t mask = ((base < 32) ? (1u << base) : 0u) - 1u;
106 return (*rng)() & mask;
107 }
108
RandomLowercaseString(RandomEngine * rng)109 static std::string RandomLowercaseString(RandomEngine* rng) {
110 int length;
111 std::bernoulli_distribution one_in_1k(0.001);
112 std::bernoulli_distribution one_in_10k(0.0001);
113 // With low probability, make a large fragment
114 if (one_in_10k(*rng)) {
115 length = GetUniformRandomUpTo(rng, 1048576);
116 } else if (one_in_1k(*rng)) {
117 length = GetUniformRandomUpTo(rng, 10000);
118 } else {
119 length = GenerateSkewedRandom(rng, 10);
120 }
121 return RandomLowercaseString(rng, length);
122 }
123
RandomLowercaseString(RandomEngine * rng,size_t length)124 static std::string RandomLowercaseString(RandomEngine* rng, size_t length) {
125 std::string result(length, '\0');
126 std::uniform_int_distribution<int> chars('a', 'z');
127 std::generate(result.begin(), result.end(),
128 [&]() { return static_cast<char>(chars(*rng)); });
129 return result;
130 }
131
DoNothing(absl::string_view,void *)132 static void DoNothing(absl::string_view /* data */, void* /* arg */) {}
133
DeleteExternalString(absl::string_view data,void * arg)134 static void DeleteExternalString(absl::string_view data, void* arg) {
135 std::string* s = reinterpret_cast<std::string*>(arg);
136 EXPECT_EQ(data, *s);
137 delete s;
138 }
139
140 // Add "s" to *dst via `MakeCordFromExternal`
AddExternalMemory(absl::string_view s,absl::Cord * dst)141 static void AddExternalMemory(absl::string_view s, absl::Cord* dst) {
142 std::string* str = new std::string(s.data(), s.size());
143 dst->Append(absl::MakeCordFromExternal(*str, [str](absl::string_view data) {
144 DeleteExternalString(data, str);
145 }));
146 }
147
DumpGrowth()148 static void DumpGrowth() {
149 absl::Cord str;
150 for (int i = 0; i < 1000; i++) {
151 char c = 'a' + i % 26;
152 str.Append(absl::string_view(&c, 1));
153 }
154 }
155
156 // Make a Cord with some number of fragments. Return the size (in bytes)
157 // of the smallest fragment.
AppendWithFragments(const std::string & s,RandomEngine * rng,absl::Cord * cord)158 static size_t AppendWithFragments(const std::string& s, RandomEngine* rng,
159 absl::Cord* cord) {
160 size_t j = 0;
161 const size_t max_size = s.size() / 5; // Make approx. 10 fragments
162 size_t min_size = max_size; // size of smallest fragment
163 while (j < s.size()) {
164 size_t N = 1 + GetUniformRandomUpTo(rng, max_size);
165 if (N > (s.size() - j)) {
166 N = s.size() - j;
167 }
168 if (N < min_size) {
169 min_size = N;
170 }
171
172 std::bernoulli_distribution coin_flip(0.5);
173 if (coin_flip(*rng)) {
174 // Grow by adding an external-memory.
175 AddExternalMemory(absl::string_view(s.data() + j, N), cord);
176 } else {
177 cord->Append(absl::string_view(s.data() + j, N));
178 }
179 j += N;
180 }
181 return min_size;
182 }
183
184 // Add an external memory that contains the specified std::string to cord
AddNewStringBlock(const std::string & str,absl::Cord * dst)185 static void AddNewStringBlock(const std::string& str, absl::Cord* dst) {
186 char* data = new char[str.size()];
187 memcpy(data, str.data(), str.size());
188 dst->Append(absl::MakeCordFromExternal(
189 absl::string_view(data, str.size()),
190 [](absl::string_view s) { delete[] s.data(); }));
191 }
192
193 // Make a Cord out of many different types of nodes.
MakeComposite()194 static absl::Cord MakeComposite() {
195 absl::Cord cord;
196 cord.Append("the");
197 AddExternalMemory(" quick brown", &cord);
198 AddExternalMemory(" fox jumped", &cord);
199
200 absl::Cord full(" over");
201 AddExternalMemory(" the lazy", &full);
202 AddNewStringBlock(" dog slept the whole day away", &full);
203 absl::Cord substring = full.Subcord(0, 18);
204
205 // Make substring long enough to defeat the copying fast path in Append.
206 substring.Append(std::string(1000, '.'));
207 cord.Append(substring);
208 cord = cord.Subcord(0, cord.size() - 998); // Remove most of extra junk
209
210 return cord;
211 }
212
213 namespace absl {
214 ABSL_NAMESPACE_BEGIN
215
216 class CordTestPeer {
217 public:
ForEachChunk(const Cord & c,absl::FunctionRef<void (absl::string_view)> callback)218 static void ForEachChunk(
219 const Cord& c, absl::FunctionRef<void(absl::string_view)> callback) {
220 c.ForEachChunk(callback);
221 }
222
IsTree(const Cord & c)223 static bool IsTree(const Cord& c) { return c.contents_.is_tree(); }
Tree(const Cord & c)224 static CordRep* Tree(const Cord& c) { return c.contents_.tree(); }
225
GetCordzInfo(const Cord & c)226 static cord_internal::CordzInfo* GetCordzInfo(const Cord& c) {
227 return c.contents_.cordz_info();
228 }
229
MakeSubstring(Cord src,size_t offset,size_t length)230 static Cord MakeSubstring(Cord src, size_t offset, size_t length) {
231 CHECK(src.contents_.is_tree()) << "Can not be inlined";
232 CHECK(!src.ExpectedChecksum().has_value()) << "Can not be hardened";
233 Cord cord;
234 auto* tree = cord_internal::SkipCrcNode(src.contents_.tree());
235 auto* rep = CordRepSubstring::Create(CordRep::Ref(tree), offset, length);
236 cord.contents_.EmplaceTree(rep, CordzUpdateTracker::kSubCord);
237 return cord;
238 }
239 };
240
241 ABSL_NAMESPACE_END
242 } // namespace absl
243
244 // The CordTest fixture runs all tests with and without Cord Btree enabled,
245 // and with our without expected CRCs being set on the subject Cords.
246 class CordTest : public testing::TestWithParam<int> {
247 public:
248 // Returns true if test is running with btree enabled.
UseCrc() const249 bool UseCrc() const { return GetParam() == 2 || GetParam() == 3; }
MaybeHarden(absl::Cord & c)250 void MaybeHarden(absl::Cord& c) {
251 if (UseCrc()) {
252 c.SetExpectedChecksum(1);
253 }
254 }
MaybeHardened(absl::Cord c)255 absl::Cord MaybeHardened(absl::Cord c) {
256 MaybeHarden(c);
257 return c;
258 }
259
260 // Returns human readable string representation of the test parameter.
ToString(testing::TestParamInfo<int> param)261 static std::string ToString(testing::TestParamInfo<int> param) {
262 switch (param.param) {
263 case 0:
264 return "Btree";
265 case 1:
266 return "BtreeHardened";
267 default:
268 assert(false);
269 return "???";
270 }
271 }
272 };
273
274 INSTANTIATE_TEST_SUITE_P(WithParam, CordTest, testing::Values(0, 1),
275 CordTest::ToString);
276
TEST(CordRepFlat,AllFlatCapacities)277 TEST(CordRepFlat, AllFlatCapacities) {
278 // Explicitly and redundantly assert built-in min/max limits
279 static_assert(absl::cord_internal::kFlatOverhead < 32, "");
280 static_assert(absl::cord_internal::kMinFlatSize == 32, "");
281 static_assert(absl::cord_internal::kMaxLargeFlatSize == 256 << 10, "");
282 EXPECT_EQ(absl::cord_internal::TagToAllocatedSize(FLAT), 32);
283 EXPECT_EQ(absl::cord_internal::TagToAllocatedSize(MAX_FLAT_TAG), 256 << 10);
284
285 // Verify all tags to map perfectly back and forth, and
286 // that sizes are monotonically increasing.
287 size_t last_size = 0;
288 for (int tag = FLAT; tag <= MAX_FLAT_TAG; ++tag) {
289 size_t size = absl::cord_internal::TagToAllocatedSize(tag);
290 ASSERT_GT(size, last_size);
291 ASSERT_EQ(absl::cord_internal::TagToAllocatedSize(tag), size);
292 last_size = size;
293 }
294
295 // All flat size from 32 - 512 are 8 byte granularity
296 for (size_t size = 32; size <= 512; size += 8) {
297 ASSERT_EQ(absl::cord_internal::RoundUpForTag(size), size);
298 uint8_t tag = absl::cord_internal::AllocatedSizeToTag(size);
299 ASSERT_EQ(absl::cord_internal::TagToAllocatedSize(tag), size);
300 }
301
302 // All flat sizes from 512 - 8192 are 64 byte granularity
303 for (size_t size = 512; size <= 8192; size += 64) {
304 ASSERT_EQ(absl::cord_internal::RoundUpForTag(size), size);
305 uint8_t tag = absl::cord_internal::AllocatedSizeToTag(size);
306 ASSERT_EQ(absl::cord_internal::TagToAllocatedSize(tag), size);
307 }
308
309 // All flat sizes from 8KB to 256KB are 4KB granularity
310 for (size_t size = 8192; size <= 256 * 1024; size += 4 * 1024) {
311 ASSERT_EQ(absl::cord_internal::RoundUpForTag(size), size);
312 uint8_t tag = absl::cord_internal::AllocatedSizeToTag(size);
313 ASSERT_EQ(absl::cord_internal::TagToAllocatedSize(tag), size);
314 }
315 }
316
TEST(CordRepFlat,MaxFlatSize)317 TEST(CordRepFlat, MaxFlatSize) {
318 CordRepFlat* flat = CordRepFlat::New(kMaxFlatLength);
319 EXPECT_EQ(flat->Capacity(), kMaxFlatLength);
320 CordRep::Unref(flat);
321
322 flat = CordRepFlat::New(kMaxFlatLength * 4);
323 EXPECT_EQ(flat->Capacity(), kMaxFlatLength);
324 CordRep::Unref(flat);
325 }
326
TEST(CordRepFlat,MaxLargeFlatSize)327 TEST(CordRepFlat, MaxLargeFlatSize) {
328 const size_t size = 256 * 1024 - kFlatOverhead;
329 CordRepFlat* flat = CordRepFlat::New(CordRepFlat::Large(), size);
330 EXPECT_GE(flat->Capacity(), size);
331 CordRep::Unref(flat);
332 }
333
TEST(CordRepFlat,AllFlatSizes)334 TEST(CordRepFlat, AllFlatSizes) {
335 const size_t kMaxSize = 256 * 1024;
336 for (size_t size = 32; size <= kMaxSize; size *=2) {
337 const size_t length = size - kFlatOverhead - 1;
338 CordRepFlat* flat = CordRepFlat::New(CordRepFlat::Large(), length);
339 EXPECT_GE(flat->Capacity(), length);
340 memset(flat->Data(), 0xCD, flat->Capacity());
341 CordRep::Unref(flat);
342 }
343 }
344
TEST_P(CordTest,AllFlatSizes)345 TEST_P(CordTest, AllFlatSizes) {
346 using absl::strings_internal::CordTestAccess;
347
348 for (size_t s = 0; s < CordTestAccess::MaxFlatLength(); s++) {
349 // Make a string of length s.
350 std::string src;
351 while (src.size() < s) {
352 src.push_back('a' + (src.size() % 26));
353 }
354
355 absl::Cord dst(src);
356 MaybeHarden(dst);
357 EXPECT_EQ(std::string(dst), src) << s;
358 }
359 }
360
361 // We create a Cord at least 128GB in size using the fact that Cords can
362 // internally reference-count; thus the Cord is enormous without actually
363 // consuming very much memory.
TEST_P(CordTest,GigabyteCordFromExternal)364 TEST_P(CordTest, GigabyteCordFromExternal) {
365 const size_t one_gig = 1024U * 1024U * 1024U;
366 size_t max_size = 2 * one_gig;
367 if (sizeof(max_size) > 4) max_size = 128 * one_gig;
368
369 size_t length = 128 * 1024;
370 char* data = new char[length];
371 absl::Cord from = absl::MakeCordFromExternal(
372 absl::string_view(data, length),
373 [](absl::string_view sv) { delete[] sv.data(); });
374
375 // This loop may seem odd due to its combination of exponential doubling of
376 // size and incremental size increases. We do it incrementally to be sure the
377 // Cord will need rebalancing and will exercise code that, in the past, has
378 // caused crashes in production. We grow exponentially so that the code will
379 // execute in a reasonable amount of time.
380 absl::Cord c;
381 c.Append(from);
382 while (c.size() < max_size) {
383 c.Append(c);
384 c.Append(from);
385 c.Append(from);
386 c.Append(from);
387 c.Append(from);
388 MaybeHarden(c);
389 }
390
391 for (int i = 0; i < 1024; ++i) {
392 c.Append(from);
393 }
394 LOG(INFO) << "Made a Cord with " << c.size() << " bytes!";
395 // Note: on a 32-bit build, this comes out to 2,818,048,000 bytes.
396 // Note: on a 64-bit build, this comes out to 171,932,385,280 bytes.
397 }
398
MakeExternalCord(int size)399 static absl::Cord MakeExternalCord(int size) {
400 char* buffer = new char[size];
401 memset(buffer, 'x', size);
402 absl::Cord cord;
403 cord.Append(absl::MakeCordFromExternal(
404 absl::string_view(buffer, size),
405 [](absl::string_view s) { delete[] s.data(); }));
406 return cord;
407 }
408
409 // Extern to fool clang that this is not constant. Needed to suppress
410 // a warning of unsafe code we want to test.
411 extern bool my_unique_true_boolean;
412 bool my_unique_true_boolean = true;
413
TEST_P(CordTest,Assignment)414 TEST_P(CordTest, Assignment) {
415 absl::Cord x(absl::string_view("hi there"));
416 absl::Cord y(x);
417 MaybeHarden(y);
418 ASSERT_EQ(x.ExpectedChecksum(), absl::nullopt);
419 ASSERT_EQ(std::string(x), "hi there");
420 ASSERT_EQ(std::string(y), "hi there");
421 ASSERT_TRUE(x == y);
422 ASSERT_TRUE(x <= y);
423 ASSERT_TRUE(y <= x);
424
425 x = absl::string_view("foo");
426 ASSERT_EQ(std::string(x), "foo");
427 ASSERT_EQ(std::string(y), "hi there");
428 ASSERT_TRUE(x < y);
429 ASSERT_TRUE(y > x);
430 ASSERT_TRUE(x != y);
431 ASSERT_TRUE(x <= y);
432 ASSERT_TRUE(y >= x);
433
434 x = "foo";
435 ASSERT_EQ(x, "foo");
436
437 // Test that going from inline rep to tree we don't leak memory.
438 std::vector<std::pair<absl::string_view, absl::string_view>>
439 test_string_pairs = {{"hi there", "foo"},
440 {"loooooong coooooord", "short cord"},
441 {"short cord", "loooooong coooooord"},
442 {"loooooong coooooord1", "loooooong coooooord2"}};
443 for (std::pair<absl::string_view, absl::string_view> test_strings :
444 test_string_pairs) {
445 absl::Cord tmp(test_strings.first);
446 absl::Cord z(std::move(tmp));
447 ASSERT_EQ(std::string(z), test_strings.first);
448 tmp = test_strings.second;
449 z = std::move(tmp);
450 ASSERT_EQ(std::string(z), test_strings.second);
451 }
452 {
453 // Test that self-move assignment doesn't crash/leak.
454 // Do not write such code!
455 absl::Cord my_small_cord("foo");
456 absl::Cord my_big_cord("loooooong coooooord");
457 // Bypass clang's warning on self move-assignment.
458 absl::Cord* my_small_alias =
459 my_unique_true_boolean ? &my_small_cord : &my_big_cord;
460 absl::Cord* my_big_alias =
461 !my_unique_true_boolean ? &my_small_cord : &my_big_cord;
462
463 *my_small_alias = std::move(my_small_cord);
464 *my_big_alias = std::move(my_big_cord);
465 // my_small_cord and my_big_cord are in an unspecified but valid
466 // state, and will be correctly destroyed here.
467 }
468 }
469
TEST_P(CordTest,StartsEndsWith)470 TEST_P(CordTest, StartsEndsWith) {
471 absl::Cord x(absl::string_view("abcde"));
472 MaybeHarden(x);
473 absl::Cord empty("");
474
475 ASSERT_TRUE(x.StartsWith(absl::Cord("abcde")));
476 ASSERT_TRUE(x.StartsWith(absl::Cord("abc")));
477 ASSERT_TRUE(x.StartsWith(absl::Cord("")));
478 ASSERT_TRUE(empty.StartsWith(absl::Cord("")));
479 ASSERT_TRUE(x.EndsWith(absl::Cord("abcde")));
480 ASSERT_TRUE(x.EndsWith(absl::Cord("cde")));
481 ASSERT_TRUE(x.EndsWith(absl::Cord("")));
482 ASSERT_TRUE(empty.EndsWith(absl::Cord("")));
483
484 ASSERT_TRUE(!x.StartsWith(absl::Cord("xyz")));
485 ASSERT_TRUE(!empty.StartsWith(absl::Cord("xyz")));
486 ASSERT_TRUE(!x.EndsWith(absl::Cord("xyz")));
487 ASSERT_TRUE(!empty.EndsWith(absl::Cord("xyz")));
488
489 ASSERT_TRUE(x.StartsWith("abcde"));
490 ASSERT_TRUE(x.StartsWith("abc"));
491 ASSERT_TRUE(x.StartsWith(""));
492 ASSERT_TRUE(empty.StartsWith(""));
493 ASSERT_TRUE(x.EndsWith("abcde"));
494 ASSERT_TRUE(x.EndsWith("cde"));
495 ASSERT_TRUE(x.EndsWith(""));
496 ASSERT_TRUE(empty.EndsWith(""));
497
498 ASSERT_TRUE(!x.StartsWith("xyz"));
499 ASSERT_TRUE(!empty.StartsWith("xyz"));
500 ASSERT_TRUE(!x.EndsWith("xyz"));
501 ASSERT_TRUE(!empty.EndsWith("xyz"));
502 }
503
TEST_P(CordTest,Contains)504 TEST_P(CordTest, Contains) {
505 auto flat_haystack = absl::Cord("this is a flat cord");
506 auto fragmented_haystack = absl::MakeFragmentedCord(
507 {"this", " ", "is", " ", "a", " ", "fragmented", " ", "cord"});
508
509 EXPECT_TRUE(flat_haystack.Contains(""));
510 EXPECT_TRUE(fragmented_haystack.Contains(""));
511 EXPECT_TRUE(flat_haystack.Contains(absl::Cord("")));
512 EXPECT_TRUE(fragmented_haystack.Contains(absl::Cord("")));
513 EXPECT_TRUE(absl::Cord("").Contains(""));
514 EXPECT_TRUE(absl::Cord("").Contains(absl::Cord("")));
515 EXPECT_FALSE(absl::Cord("").Contains(flat_haystack));
516 EXPECT_FALSE(absl::Cord("").Contains(fragmented_haystack));
517
518 EXPECT_FALSE(flat_haystack.Contains("z"));
519 EXPECT_FALSE(fragmented_haystack.Contains("z"));
520 EXPECT_FALSE(flat_haystack.Contains(absl::Cord("z")));
521 EXPECT_FALSE(fragmented_haystack.Contains(absl::Cord("z")));
522
523 EXPECT_FALSE(flat_haystack.Contains("is an"));
524 EXPECT_FALSE(fragmented_haystack.Contains("is an"));
525 EXPECT_FALSE(flat_haystack.Contains(absl::Cord("is an")));
526 EXPECT_FALSE(fragmented_haystack.Contains(absl::Cord("is an")));
527 EXPECT_FALSE(
528 flat_haystack.Contains(absl::MakeFragmentedCord({"is", " ", "an"})));
529 EXPECT_FALSE(fragmented_haystack.Contains(
530 absl::MakeFragmentedCord({"is", " ", "an"})));
531
532 EXPECT_TRUE(flat_haystack.Contains("is a"));
533 EXPECT_TRUE(fragmented_haystack.Contains("is a"));
534 EXPECT_TRUE(flat_haystack.Contains(absl::Cord("is a")));
535 EXPECT_TRUE(fragmented_haystack.Contains(absl::Cord("is a")));
536 EXPECT_TRUE(
537 flat_haystack.Contains(absl::MakeFragmentedCord({"is", " ", "a"})));
538 EXPECT_TRUE(
539 fragmented_haystack.Contains(absl::MakeFragmentedCord({"is", " ", "a"})));
540 }
541
TEST_P(CordTest,Find)542 TEST_P(CordTest, Find) {
543 auto flat_haystack = absl::Cord("this is a flat cord");
544 auto fragmented_haystack = absl::MakeFragmentedCord(
545 {"this", " ", "is", " ", "a", " ", "fragmented", " ", "cord"});
546 auto empty_haystack = absl::Cord("");
547
548 EXPECT_EQ(flat_haystack.Find(""), flat_haystack.char_begin());
549 EXPECT_EQ(fragmented_haystack.Find(""), fragmented_haystack.char_begin());
550 EXPECT_EQ(flat_haystack.Find(absl::Cord("")), flat_haystack.char_begin());
551 EXPECT_EQ(fragmented_haystack.Find(absl::Cord("")),
552 fragmented_haystack.char_begin());
553 EXPECT_EQ(empty_haystack.Find(""), empty_haystack.char_begin());
554 EXPECT_EQ(empty_haystack.Find(absl::Cord("")), empty_haystack.char_begin());
555 EXPECT_EQ(empty_haystack.Find(flat_haystack), empty_haystack.char_end());
556 EXPECT_EQ(empty_haystack.Find(fragmented_haystack),
557 empty_haystack.char_end());
558
559 EXPECT_EQ(flat_haystack.Find("z"), flat_haystack.char_end());
560 EXPECT_EQ(fragmented_haystack.Find("z"), fragmented_haystack.char_end());
561 EXPECT_EQ(flat_haystack.Find(absl::Cord("z")), flat_haystack.char_end());
562 EXPECT_EQ(fragmented_haystack.Find(absl::Cord("z")),
563 fragmented_haystack.char_end());
564
565 EXPECT_EQ(flat_haystack.Find("is an"), flat_haystack.char_end());
566 EXPECT_EQ(fragmented_haystack.Find("is an"), fragmented_haystack.char_end());
567 EXPECT_EQ(flat_haystack.Find(absl::Cord("is an")), flat_haystack.char_end());
568 EXPECT_EQ(fragmented_haystack.Find(absl::Cord("is an")),
569 fragmented_haystack.char_end());
570 EXPECT_EQ(flat_haystack.Find(absl::MakeFragmentedCord({"is", " ", "an"})),
571 flat_haystack.char_end());
572 EXPECT_EQ(
573 fragmented_haystack.Find(absl::MakeFragmentedCord({"is", " ", "an"})),
574 fragmented_haystack.char_end());
575
576 EXPECT_EQ(flat_haystack.Find("is a"),
577 std::next(flat_haystack.char_begin(), 5));
578 EXPECT_EQ(fragmented_haystack.Find("is a"),
579 std::next(fragmented_haystack.char_begin(), 5));
580 EXPECT_EQ(flat_haystack.Find(absl::Cord("is a")),
581 std::next(flat_haystack.char_begin(), 5));
582 EXPECT_EQ(fragmented_haystack.Find(absl::Cord("is a")),
583 std::next(fragmented_haystack.char_begin(), 5));
584 EXPECT_EQ(flat_haystack.Find(absl::MakeFragmentedCord({"is", " ", "a"})),
585 std::next(flat_haystack.char_begin(), 5));
586 EXPECT_EQ(
587 fragmented_haystack.Find(absl::MakeFragmentedCord({"is", " ", "a"})),
588 std::next(fragmented_haystack.char_begin(), 5));
589 }
590
TEST_P(CordTest,Subcord)591 TEST_P(CordTest, Subcord) {
592 RandomEngine rng(GTEST_FLAG_GET(random_seed));
593 const std::string s = RandomLowercaseString(&rng, 1024);
594
595 absl::Cord a;
596 AppendWithFragments(s, &rng, &a);
597 MaybeHarden(a);
598 ASSERT_EQ(s, std::string(a));
599
600 // Check subcords of a, from a variety of interesting points.
601 std::set<size_t> positions;
602 for (int i = 0; i <= 32; ++i) {
603 positions.insert(i);
604 positions.insert(i * 32 - 1);
605 positions.insert(i * 32);
606 positions.insert(i * 32 + 1);
607 positions.insert(a.size() - i);
608 }
609 positions.insert(237);
610 positions.insert(732);
611 for (size_t pos : positions) {
612 if (pos > a.size()) continue;
613 for (size_t end_pos : positions) {
614 if (end_pos < pos || end_pos > a.size()) continue;
615 absl::Cord sa = a.Subcord(pos, end_pos - pos);
616 ASSERT_EQ(absl::string_view(s).substr(pos, end_pos - pos),
617 std::string(sa))
618 << a;
619 if (pos != 0 || end_pos != a.size()) {
620 ASSERT_EQ(sa.ExpectedChecksum(), absl::nullopt);
621 }
622 }
623 }
624
625 // Do the same thing for an inline cord.
626 const std::string sh = "short";
627 absl::Cord c(sh);
628 for (size_t pos = 0; pos <= sh.size(); ++pos) {
629 for (size_t n = 0; n <= sh.size() - pos; ++n) {
630 absl::Cord sc = c.Subcord(pos, n);
631 ASSERT_EQ(sh.substr(pos, n), std::string(sc)) << c;
632 }
633 }
634
635 // Check subcords of subcords.
636 absl::Cord sa = a.Subcord(0, a.size());
637 std::string ss = s.substr(0, s.size());
638 while (sa.size() > 1) {
639 sa = sa.Subcord(1, sa.size() - 2);
640 ss = ss.substr(1, ss.size() - 2);
641 ASSERT_EQ(ss, std::string(sa)) << a;
642 if (HasFailure()) break; // halt cascade
643 }
644
645 // It is OK to ask for too much.
646 sa = a.Subcord(0, a.size() + 1);
647 EXPECT_EQ(s, std::string(sa));
648
649 // It is OK to ask for something beyond the end.
650 sa = a.Subcord(a.size() + 1, 0);
651 EXPECT_TRUE(sa.empty());
652 sa = a.Subcord(a.size() + 1, 1);
653 EXPECT_TRUE(sa.empty());
654 }
655
TEST_P(CordTest,Swap)656 TEST_P(CordTest, Swap) {
657 absl::string_view a("Dexter");
658 absl::string_view b("Mandark");
659 absl::Cord x(a);
660 absl::Cord y(b);
661 MaybeHarden(x);
662 swap(x, y);
663 if (UseCrc()) {
664 ASSERT_EQ(x.ExpectedChecksum(), absl::nullopt);
665 ASSERT_EQ(y.ExpectedChecksum(), 1);
666 }
667 ASSERT_EQ(x, absl::Cord(b));
668 ASSERT_EQ(y, absl::Cord(a));
669 x.swap(y);
670 if (UseCrc()) {
671 ASSERT_EQ(x.ExpectedChecksum(), 1);
672 ASSERT_EQ(y.ExpectedChecksum(), absl::nullopt);
673 }
674 ASSERT_EQ(x, absl::Cord(a));
675 ASSERT_EQ(y, absl::Cord(b));
676 }
677
VerifyCopyToString(const absl::Cord & cord)678 static void VerifyCopyToString(const absl::Cord& cord) {
679 std::string initially_empty;
680 absl::CopyCordToString(cord, &initially_empty);
681 EXPECT_EQ(initially_empty, cord);
682
683 constexpr size_t kInitialLength = 1024;
684 std::string has_initial_contents(kInitialLength, 'x');
685 const char* address_before_copy = has_initial_contents.data();
686 absl::CopyCordToString(cord, &has_initial_contents);
687 EXPECT_EQ(has_initial_contents, cord);
688
689 if (cord.size() <= kInitialLength) {
690 EXPECT_EQ(has_initial_contents.data(), address_before_copy)
691 << "CopyCordToString allocated new string storage; "
692 "has_initial_contents = \""
693 << has_initial_contents << "\"";
694 }
695 }
696
TEST_P(CordTest,CopyToString)697 TEST_P(CordTest, CopyToString) {
698 VerifyCopyToString(absl::Cord()); // empty cords cannot carry CRCs
699 VerifyCopyToString(MaybeHardened(absl::Cord("small cord")));
700 VerifyCopyToString(MaybeHardened(
701 absl::MakeFragmentedCord({"fragmented ", "cord ", "to ", "test ",
702 "copying ", "to ", "a ", "string."})));
703 }
704
TEST_P(CordTest,AppendEmptyBuffer)705 TEST_P(CordTest, AppendEmptyBuffer) {
706 absl::Cord cord;
707 cord.Append(absl::CordBuffer());
708 cord.Append(absl::CordBuffer::CreateWithDefaultLimit(2000));
709 }
710
TEST_P(CordTest,AppendEmptyBufferToFlat)711 TEST_P(CordTest, AppendEmptyBufferToFlat) {
712 absl::Cord cord(std::string(2000, 'x'));
713 cord.Append(absl::CordBuffer());
714 cord.Append(absl::CordBuffer::CreateWithDefaultLimit(2000));
715 }
716
TEST_P(CordTest,AppendEmptyBufferToTree)717 TEST_P(CordTest, AppendEmptyBufferToTree) {
718 absl::Cord cord(std::string(2000, 'x'));
719 cord.Append(std::string(2000, 'y'));
720 cord.Append(absl::CordBuffer());
721 cord.Append(absl::CordBuffer::CreateWithDefaultLimit(2000));
722 }
723
TEST_P(CordTest,AppendSmallBuffer)724 TEST_P(CordTest, AppendSmallBuffer) {
725 absl::Cord cord;
726 absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(3);
727 ASSERT_THAT(buffer.capacity(), Le(15));
728 memcpy(buffer.data(), "Abc", 3);
729 buffer.SetLength(3);
730 cord.Append(std::move(buffer));
731 EXPECT_EQ(buffer.length(), 0); // NOLINT
732 EXPECT_GT(buffer.capacity(), 0); // NOLINT
733
734 buffer = absl::CordBuffer::CreateWithDefaultLimit(3);
735 memcpy(buffer.data(), "defgh", 5);
736 buffer.SetLength(5);
737 cord.Append(std::move(buffer));
738 EXPECT_EQ(buffer.length(), 0); // NOLINT
739 EXPECT_GT(buffer.capacity(), 0); // NOLINT
740
741 EXPECT_THAT(cord.Chunks(), ElementsAre("Abcdefgh"));
742 }
743
TEST_P(CordTest,AppendAndPrependBufferArePrecise)744 TEST_P(CordTest, AppendAndPrependBufferArePrecise) {
745 // Create a cord large enough to force 40KB flats.
746 std::string test_data(absl::cord_internal::kMaxFlatLength * 10, 'x');
747 absl::Cord cord1(test_data);
748 absl::Cord cord2(test_data);
749 const size_t size1 = cord1.EstimatedMemoryUsage();
750 const size_t size2 = cord2.EstimatedMemoryUsage();
751
752 absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(3);
753 memcpy(buffer.data(), "Abc", 3);
754 buffer.SetLength(3);
755 cord1.Append(std::move(buffer));
756
757 buffer = absl::CordBuffer::CreateWithDefaultLimit(3);
758 memcpy(buffer.data(), "Abc", 3);
759 buffer.SetLength(3);
760 cord2.Prepend(std::move(buffer));
761
762 #ifndef NDEBUG
763 // Allow 32 bytes new CordRepFlat, and 128 bytes for 'glue nodes'
764 constexpr size_t kMaxDelta = 128 + 32;
765 #else
766 // Allow 256 bytes extra for 'allocation debug overhead'
767 constexpr size_t kMaxDelta = 128 + 32 + 256;
768 #endif
769
770 EXPECT_LE(cord1.EstimatedMemoryUsage() - size1, kMaxDelta);
771 EXPECT_LE(cord2.EstimatedMemoryUsage() - size2, kMaxDelta);
772
773 EXPECT_EQ(cord1, absl::StrCat(test_data, "Abc"));
774 EXPECT_EQ(cord2, absl::StrCat("Abc", test_data));
775 }
776
TEST_P(CordTest,PrependSmallBuffer)777 TEST_P(CordTest, PrependSmallBuffer) {
778 absl::Cord cord;
779 absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(3);
780 ASSERT_THAT(buffer.capacity(), Le(15));
781 memcpy(buffer.data(), "Abc", 3);
782 buffer.SetLength(3);
783 cord.Prepend(std::move(buffer));
784 EXPECT_EQ(buffer.length(), 0); // NOLINT
785 EXPECT_GT(buffer.capacity(), 0); // NOLINT
786
787 buffer = absl::CordBuffer::CreateWithDefaultLimit(3);
788 memcpy(buffer.data(), "defgh", 5);
789 buffer.SetLength(5);
790 cord.Prepend(std::move(buffer));
791 EXPECT_EQ(buffer.length(), 0); // NOLINT
792 EXPECT_GT(buffer.capacity(), 0); // NOLINT
793
794 EXPECT_THAT(cord.Chunks(), ElementsAre("defghAbc"));
795 }
796
TEST_P(CordTest,AppendLargeBuffer)797 TEST_P(CordTest, AppendLargeBuffer) {
798 absl::Cord cord;
799
800 std::string s1(700, '1');
801 absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(s1.size());
802 memcpy(buffer.data(), s1.data(), s1.size());
803 buffer.SetLength(s1.size());
804 cord.Append(std::move(buffer));
805 EXPECT_EQ(buffer.length(), 0); // NOLINT
806 EXPECT_GT(buffer.capacity(), 0); // NOLINT
807
808 std::string s2(1000, '2');
809 buffer = absl::CordBuffer::CreateWithDefaultLimit(s2.size());
810 memcpy(buffer.data(), s2.data(), s2.size());
811 buffer.SetLength(s2.size());
812 cord.Append(std::move(buffer));
813 EXPECT_EQ(buffer.length(), 0); // NOLINT
814 EXPECT_GT(buffer.capacity(), 0); // NOLINT
815
816 EXPECT_THAT(cord.Chunks(), ElementsAre(s1, s2));
817 }
818
TEST_P(CordTest,PrependLargeBuffer)819 TEST_P(CordTest, PrependLargeBuffer) {
820 absl::Cord cord;
821
822 std::string s1(700, '1');
823 absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(s1.size());
824 memcpy(buffer.data(), s1.data(), s1.size());
825 buffer.SetLength(s1.size());
826 cord.Prepend(std::move(buffer));
827 EXPECT_EQ(buffer.length(), 0); // NOLINT
828 EXPECT_GT(buffer.capacity(), 0); // NOLINT
829
830 std::string s2(1000, '2');
831 buffer = absl::CordBuffer::CreateWithDefaultLimit(s2.size());
832 memcpy(buffer.data(), s2.data(), s2.size());
833 buffer.SetLength(s2.size());
834 cord.Prepend(std::move(buffer));
835 EXPECT_EQ(buffer.length(), 0); // NOLINT
836 EXPECT_GT(buffer.capacity(), 0); // NOLINT
837
838 EXPECT_THAT(cord.Chunks(), ElementsAre(s2, s1));
839 }
840
841 class CordAppendBufferTest : public testing::TestWithParam<bool> {
842 public:
is_default() const843 size_t is_default() const { return GetParam(); }
844
845 // Returns human readable string representation of the test parameter.
ToString(testing::TestParamInfo<bool> param)846 static std::string ToString(testing::TestParamInfo<bool> param) {
847 return param.param ? "DefaultLimit" : "CustomLimit";
848 }
849
limit() const850 size_t limit() const {
851 return is_default() ? absl::CordBuffer::kDefaultLimit
852 : absl::CordBuffer::kCustomLimit;
853 }
854
maximum_payload() const855 size_t maximum_payload() const {
856 return is_default() ? absl::CordBuffer::MaximumPayload()
857 : absl::CordBuffer::MaximumPayload(limit());
858 }
859
GetAppendBuffer(absl::Cord & cord,size_t capacity,size_t min_capacity=16)860 absl::CordBuffer GetAppendBuffer(absl::Cord& cord, size_t capacity,
861 size_t min_capacity = 16) {
862 return is_default()
863 ? cord.GetAppendBuffer(capacity, min_capacity)
864 : cord.GetCustomAppendBuffer(limit(), capacity, min_capacity);
865 }
866 };
867
868 INSTANTIATE_TEST_SUITE_P(WithParam, CordAppendBufferTest, testing::Bool(),
869 CordAppendBufferTest::ToString);
870
TEST_P(CordAppendBufferTest,GetAppendBufferOnEmptyCord)871 TEST_P(CordAppendBufferTest, GetAppendBufferOnEmptyCord) {
872 absl::Cord cord;
873 absl::CordBuffer buffer = GetAppendBuffer(cord, 1000);
874 EXPECT_GE(buffer.capacity(), 1000);
875 EXPECT_EQ(buffer.length(), 0);
876 }
877
TEST_P(CordAppendBufferTest,GetAppendBufferOnInlinedCord)878 TEST_P(CordAppendBufferTest, GetAppendBufferOnInlinedCord) {
879 static constexpr int kInlinedSize = sizeof(absl::CordBuffer) - 1;
880 for (int size : {6, kInlinedSize - 3, kInlinedSize - 2, 1000}) {
881 absl::Cord cord("Abc");
882 absl::CordBuffer buffer = GetAppendBuffer(cord, size, 1);
883 EXPECT_GE(buffer.capacity(), 3 + size);
884 EXPECT_EQ(buffer.length(), 3);
885 EXPECT_EQ(absl::string_view(buffer.data(), buffer.length()), "Abc");
886 EXPECT_TRUE(cord.empty());
887 }
888 }
889
TEST_P(CordAppendBufferTest,GetAppendBufferOnInlinedCordCapacityCloseToMax)890 TEST_P(CordAppendBufferTest, GetAppendBufferOnInlinedCordCapacityCloseToMax) {
891 // Cover the use case where we have a non empty inlined cord with some size
892 // 'n', and ask for something like 'uint64_max - k', assuming internal logic
893 // could overflow on 'uint64_max - k + size', and return a valid, but
894 // inefficiently smaller buffer if it would provide is the max allowed size.
895 for (size_t dist_from_max = 0; dist_from_max <= 4; ++dist_from_max) {
896 absl::Cord cord("Abc");
897 size_t size = std::numeric_limits<size_t>::max() - dist_from_max;
898 absl::CordBuffer buffer = GetAppendBuffer(cord, size, 1);
899 EXPECT_GE(buffer.capacity(), maximum_payload());
900 EXPECT_EQ(buffer.length(), 3);
901 EXPECT_EQ(absl::string_view(buffer.data(), buffer.length()), "Abc");
902 EXPECT_TRUE(cord.empty());
903 }
904 }
905
TEST_P(CordAppendBufferTest,GetAppendBufferOnFlat)906 TEST_P(CordAppendBufferTest, GetAppendBufferOnFlat) {
907 // Create a cord with a single flat and extra capacity
908 absl::Cord cord;
909 absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(500);
910 const size_t expected_capacity = buffer.capacity();
911 buffer.SetLength(3);
912 memcpy(buffer.data(), "Abc", 3);
913 cord.Append(std::move(buffer));
914
915 buffer = GetAppendBuffer(cord, 6);
916 EXPECT_EQ(buffer.capacity(), expected_capacity);
917 EXPECT_EQ(buffer.length(), 3);
918 EXPECT_EQ(absl::string_view(buffer.data(), buffer.length()), "Abc");
919 EXPECT_TRUE(cord.empty());
920 }
921
TEST_P(CordAppendBufferTest,GetAppendBufferOnFlatWithoutMinCapacity)922 TEST_P(CordAppendBufferTest, GetAppendBufferOnFlatWithoutMinCapacity) {
923 // Create a cord with a single flat and extra capacity
924 absl::Cord cord;
925 absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(500);
926 buffer.SetLength(30);
927 memset(buffer.data(), 'x', 30);
928 cord.Append(std::move(buffer));
929
930 buffer = GetAppendBuffer(cord, 1000, 900);
931 EXPECT_GE(buffer.capacity(), 1000);
932 EXPECT_EQ(buffer.length(), 0);
933 EXPECT_EQ(cord, std::string(30, 'x'));
934 }
935
TEST_P(CordAppendBufferTest,GetAppendBufferOnTree)936 TEST_P(CordAppendBufferTest, GetAppendBufferOnTree) {
937 RandomEngine rng;
938 for (int num_flats : {2, 3, 100}) {
939 // Create a cord with `num_flats` flats and extra capacity
940 absl::Cord cord;
941 std::string prefix;
942 std::string last;
943 for (int i = 0; i < num_flats - 1; ++i) {
944 prefix += last;
945 last = RandomLowercaseString(&rng, 10);
946 absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(500);
947 buffer.SetLength(10);
948 memcpy(buffer.data(), last.data(), 10);
949 cord.Append(std::move(buffer));
950 }
951 absl::CordBuffer buffer = GetAppendBuffer(cord, 6);
952 EXPECT_GE(buffer.capacity(), 500);
953 EXPECT_EQ(buffer.length(), 10);
954 EXPECT_EQ(absl::string_view(buffer.data(), buffer.length()), last);
955 EXPECT_EQ(cord, prefix);
956 }
957 }
958
TEST_P(CordAppendBufferTest,GetAppendBufferOnTreeWithoutMinCapacity)959 TEST_P(CordAppendBufferTest, GetAppendBufferOnTreeWithoutMinCapacity) {
960 absl::Cord cord;
961 for (int i = 0; i < 2; ++i) {
962 absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(500);
963 buffer.SetLength(3);
964 memcpy(buffer.data(), i ? "def" : "Abc", 3);
965 cord.Append(std::move(buffer));
966 }
967 absl::CordBuffer buffer = GetAppendBuffer(cord, 1000, 900);
968 EXPECT_GE(buffer.capacity(), 1000);
969 EXPECT_EQ(buffer.length(), 0);
970 EXPECT_EQ(cord, "Abcdef");
971 }
972
TEST_P(CordAppendBufferTest,GetAppendBufferOnSubstring)973 TEST_P(CordAppendBufferTest, GetAppendBufferOnSubstring) {
974 // Create a large cord with a single flat and some extra capacity
975 absl::Cord cord;
976 absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(500);
977 buffer.SetLength(450);
978 memset(buffer.data(), 'x', 450);
979 cord.Append(std::move(buffer));
980 cord.RemovePrefix(1);
981
982 // Deny on substring
983 buffer = GetAppendBuffer(cord, 6);
984 EXPECT_EQ(buffer.length(), 0);
985 EXPECT_EQ(cord, std::string(449, 'x'));
986 }
987
TEST_P(CordAppendBufferTest,GetAppendBufferOnSharedCord)988 TEST_P(CordAppendBufferTest, GetAppendBufferOnSharedCord) {
989 // Create a shared cord with a single flat and extra capacity
990 absl::Cord cord;
991 absl::CordBuffer buffer = absl::CordBuffer::CreateWithDefaultLimit(500);
992 buffer.SetLength(3);
993 memcpy(buffer.data(), "Abc", 3);
994 cord.Append(std::move(buffer));
995 absl::Cord shared_cord = cord;
996
997 // Deny on flat
998 buffer = GetAppendBuffer(cord, 6);
999 EXPECT_EQ(buffer.length(), 0);
1000 EXPECT_EQ(cord, "Abc");
1001
1002 buffer = absl::CordBuffer::CreateWithDefaultLimit(500);
1003 buffer.SetLength(3);
1004 memcpy(buffer.data(), "def", 3);
1005 cord.Append(std::move(buffer));
1006 shared_cord = cord;
1007
1008 // Deny on tree
1009 buffer = GetAppendBuffer(cord, 6);
1010 EXPECT_EQ(buffer.length(), 0);
1011 EXPECT_EQ(cord, "Abcdef");
1012 }
1013
TEST_P(CordTest,TryFlatEmpty)1014 TEST_P(CordTest, TryFlatEmpty) {
1015 absl::Cord c;
1016 EXPECT_EQ(c.TryFlat(), "");
1017 }
1018
TEST_P(CordTest,TryFlatFlat)1019 TEST_P(CordTest, TryFlatFlat) {
1020 absl::Cord c("hello");
1021 MaybeHarden(c);
1022 EXPECT_EQ(c.TryFlat(), "hello");
1023 }
1024
TEST_P(CordTest,TryFlatSubstrInlined)1025 TEST_P(CordTest, TryFlatSubstrInlined) {
1026 absl::Cord c("hello");
1027 c.RemovePrefix(1);
1028 MaybeHarden(c);
1029 EXPECT_EQ(c.TryFlat(), "ello");
1030 }
1031
TEST_P(CordTest,TryFlatSubstrFlat)1032 TEST_P(CordTest, TryFlatSubstrFlat) {
1033 absl::Cord c("longer than 15 bytes");
1034 absl::Cord sub = absl::CordTestPeer::MakeSubstring(c, 1, c.size() - 1);
1035 MaybeHarden(sub);
1036 EXPECT_EQ(sub.TryFlat(), "onger than 15 bytes");
1037 }
1038
TEST_P(CordTest,TryFlatConcat)1039 TEST_P(CordTest, TryFlatConcat) {
1040 absl::Cord c = absl::MakeFragmentedCord({"hel", "lo"});
1041 MaybeHarden(c);
1042 EXPECT_EQ(c.TryFlat(), absl::nullopt);
1043 }
1044
TEST_P(CordTest,TryFlatExternal)1045 TEST_P(CordTest, TryFlatExternal) {
1046 absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});
1047 MaybeHarden(c);
1048 EXPECT_EQ(c.TryFlat(), "hell");
1049 }
1050
TEST_P(CordTest,TryFlatSubstrExternal)1051 TEST_P(CordTest, TryFlatSubstrExternal) {
1052 absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});
1053 absl::Cord sub = absl::CordTestPeer::MakeSubstring(c, 1, c.size() - 1);
1054 MaybeHarden(sub);
1055 EXPECT_EQ(sub.TryFlat(), "ell");
1056 }
1057
TEST_P(CordTest,TryFlatCommonlyAssumedInvariants)1058 TEST_P(CordTest, TryFlatCommonlyAssumedInvariants) {
1059 // The behavior tested below is not part of the API contract of Cord, but it's
1060 // something we intend to be true in our current implementation. This test
1061 // exists to detect and prevent accidental breakage of the implementation.
1062 absl::string_view fragments[] = {"A fragmented test",
1063 " cord",
1064 " to test subcords",
1065 " of ",
1066 "a",
1067 " cord for",
1068 " each chunk "
1069 "returned by the ",
1070 "iterator"};
1071 absl::Cord c = absl::MakeFragmentedCord(fragments);
1072 MaybeHarden(c);
1073 int fragment = 0;
1074 int offset = 0;
1075 absl::Cord::CharIterator itc = c.char_begin();
1076 for (absl::string_view sv : c.Chunks()) {
1077 absl::string_view expected = fragments[fragment];
1078 absl::Cord subcord1 = c.Subcord(offset, sv.length());
1079 absl::Cord subcord2 = absl::Cord::AdvanceAndRead(&itc, sv.size());
1080 EXPECT_EQ(subcord1.TryFlat(), expected);
1081 EXPECT_EQ(subcord2.TryFlat(), expected);
1082 ++fragment;
1083 offset += sv.length();
1084 }
1085 }
1086
IsFlat(const absl::Cord & c)1087 static bool IsFlat(const absl::Cord& c) {
1088 return c.chunk_begin() == c.chunk_end() || ++c.chunk_begin() == c.chunk_end();
1089 }
1090
VerifyFlatten(absl::Cord c)1091 static void VerifyFlatten(absl::Cord c) {
1092 std::string old_contents(c);
1093 absl::string_view old_flat;
1094 bool already_flat_and_non_empty = IsFlat(c) && !c.empty();
1095 if (already_flat_and_non_empty) {
1096 old_flat = *c.chunk_begin();
1097 }
1098 absl::string_view new_flat = c.Flatten();
1099
1100 // Verify that the contents of the flattened Cord are correct.
1101 EXPECT_EQ(new_flat, old_contents);
1102 EXPECT_EQ(std::string(c), old_contents);
1103
1104 // If the Cord contained data and was already flat, verify that the data
1105 // wasn't copied.
1106 if (already_flat_and_non_empty) {
1107 EXPECT_EQ(old_flat.data(), new_flat.data())
1108 << "Allocated new memory even though the Cord was already flat.";
1109 }
1110
1111 // Verify that the flattened Cord is in fact flat.
1112 EXPECT_TRUE(IsFlat(c));
1113 }
1114
TEST_P(CordTest,Flatten)1115 TEST_P(CordTest, Flatten) {
1116 VerifyFlatten(absl::Cord());
1117 VerifyFlatten(MaybeHardened(absl::Cord("small cord")));
1118 VerifyFlatten(
1119 MaybeHardened(absl::Cord("larger than small buffer optimization")));
1120 VerifyFlatten(MaybeHardened(
1121 absl::MakeFragmentedCord({"small ", "fragmented ", "cord"})));
1122
1123 // Test with a cord that is longer than the largest flat buffer
1124 RandomEngine rng(GTEST_FLAG_GET(random_seed));
1125 VerifyFlatten(MaybeHardened(absl::Cord(RandomLowercaseString(&rng, 8192))));
1126 }
1127
1128 // Test data
1129 namespace {
1130 class TestData {
1131 private:
1132 std::vector<std::string> data_;
1133
1134 // Return a std::string of the specified length.
MakeString(int length)1135 static std::string MakeString(int length) {
1136 std::string result;
1137 char buf[30];
1138 snprintf(buf, sizeof(buf), "(%d)", length);
1139 while (result.size() < length) {
1140 result += buf;
1141 }
1142 result.resize(length);
1143 return result;
1144 }
1145
1146 public:
TestData()1147 TestData() {
1148 // short strings increasing in length by one
1149 for (int i = 0; i < 30; i++) {
1150 data_.push_back(MakeString(i));
1151 }
1152
1153 // strings around half kMaxFlatLength
1154 static const int kMaxFlatLength = 4096 - 9;
1155 static const int kHalf = kMaxFlatLength / 2;
1156
1157 for (int i = -10; i <= +10; i++) {
1158 data_.push_back(MakeString(kHalf + i));
1159 }
1160
1161 for (int i = -10; i <= +10; i++) {
1162 data_.push_back(MakeString(kMaxFlatLength + i));
1163 }
1164 }
1165
size() const1166 size_t size() const { return data_.size(); }
data(size_t i) const1167 const std::string& data(size_t i) const { return data_[i]; }
1168 };
1169 } // namespace
1170
TEST_P(CordTest,MultipleLengths)1171 TEST_P(CordTest, MultipleLengths) {
1172 TestData d;
1173 for (size_t i = 0; i < d.size(); i++) {
1174 std::string a = d.data(i);
1175
1176 { // Construct from Cord
1177 absl::Cord tmp(a);
1178 absl::Cord x(tmp);
1179 MaybeHarden(x);
1180 EXPECT_EQ(a, std::string(x)) << "'" << a << "'";
1181 }
1182
1183 { // Construct from absl::string_view
1184 absl::Cord x(a);
1185 MaybeHarden(x);
1186 EXPECT_EQ(a, std::string(x)) << "'" << a << "'";
1187 }
1188
1189 { // Append cord to self
1190 absl::Cord self(a);
1191 MaybeHarden(self);
1192 self.Append(self);
1193 EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";
1194 }
1195
1196 { // Prepend cord to self
1197 absl::Cord self(a);
1198 MaybeHarden(self);
1199 self.Prepend(self);
1200 EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";
1201 }
1202
1203 // Try to append/prepend others
1204 for (size_t j = 0; j < d.size(); j++) {
1205 std::string b = d.data(j);
1206
1207 { // CopyFrom Cord
1208 absl::Cord x(a);
1209 absl::Cord y(b);
1210 MaybeHarden(x);
1211 x = y;
1212 EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";
1213 }
1214
1215 { // CopyFrom absl::string_view
1216 absl::Cord x(a);
1217 MaybeHarden(x);
1218 x = b;
1219 EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";
1220 }
1221
1222 { // Cord::Append(Cord)
1223 absl::Cord x(a);
1224 absl::Cord y(b);
1225 MaybeHarden(x);
1226 x.Append(y);
1227 EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";
1228 }
1229
1230 { // Cord::Append(absl::string_view)
1231 absl::Cord x(a);
1232 MaybeHarden(x);
1233 x.Append(b);
1234 EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";
1235 }
1236
1237 { // Cord::Prepend(Cord)
1238 absl::Cord x(a);
1239 absl::Cord y(b);
1240 MaybeHarden(x);
1241 x.Prepend(y);
1242 EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";
1243 }
1244
1245 { // Cord::Prepend(absl::string_view)
1246 absl::Cord x(a);
1247 MaybeHarden(x);
1248 x.Prepend(b);
1249 EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";
1250 }
1251 }
1252 }
1253 }
1254
1255 namespace {
1256
TEST_P(CordTest,RemoveSuffixWithExternalOrSubstring)1257 TEST_P(CordTest, RemoveSuffixWithExternalOrSubstring) {
1258 absl::Cord cord = absl::MakeCordFromExternal(
1259 "foo bar baz", [](absl::string_view s) { DoNothing(s, nullptr); });
1260 EXPECT_EQ("foo bar baz", std::string(cord));
1261
1262 MaybeHarden(cord);
1263
1264 // This RemoveSuffix() will wrap the EXTERNAL node in a SUBSTRING node.
1265 cord.RemoveSuffix(4);
1266 EXPECT_EQ("foo bar", std::string(cord));
1267
1268 MaybeHarden(cord);
1269
1270 // This RemoveSuffix() will adjust the SUBSTRING node in-place.
1271 cord.RemoveSuffix(4);
1272 EXPECT_EQ("foo", std::string(cord));
1273 }
1274
TEST_P(CordTest,RemoveSuffixMakesZeroLengthNode)1275 TEST_P(CordTest, RemoveSuffixMakesZeroLengthNode) {
1276 absl::Cord c;
1277 c.Append(absl::Cord(std::string(100, 'x')));
1278 absl::Cord other_ref = c; // Prevent inplace appends
1279 MaybeHarden(c);
1280 c.Append(absl::Cord(std::string(200, 'y')));
1281 c.RemoveSuffix(200);
1282 EXPECT_EQ(std::string(100, 'x'), std::string(c));
1283 }
1284
1285 } // namespace
1286
1287 // CordSpliceTest contributed by hendrie.
1288 namespace {
1289
1290 // Create a cord with an external memory block filled with 'z'
CordWithZedBlock(size_t size)1291 absl::Cord CordWithZedBlock(size_t size) {
1292 char* data = new char[size];
1293 if (size > 0) {
1294 memset(data, 'z', size);
1295 }
1296 absl::Cord cord = absl::MakeCordFromExternal(
1297 absl::string_view(data, size),
1298 [](absl::string_view s) { delete[] s.data(); });
1299 return cord;
1300 }
1301
1302 // Establish that ZedBlock does what we think it does.
TEST_P(CordTest,CordSpliceTestZedBlock)1303 TEST_P(CordTest, CordSpliceTestZedBlock) {
1304 absl::Cord blob = CordWithZedBlock(10);
1305 MaybeHarden(blob);
1306 EXPECT_EQ(10, blob.size());
1307 std::string s;
1308 absl::CopyCordToString(blob, &s);
1309 EXPECT_EQ("zzzzzzzzzz", s);
1310 }
1311
TEST_P(CordTest,CordSpliceTestZedBlock0)1312 TEST_P(CordTest, CordSpliceTestZedBlock0) {
1313 absl::Cord blob = CordWithZedBlock(0);
1314 MaybeHarden(blob);
1315 EXPECT_EQ(0, blob.size());
1316 std::string s;
1317 absl::CopyCordToString(blob, &s);
1318 EXPECT_EQ("", s);
1319 }
1320
TEST_P(CordTest,CordSpliceTestZedBlockSuffix1)1321 TEST_P(CordTest, CordSpliceTestZedBlockSuffix1) {
1322 absl::Cord blob = CordWithZedBlock(10);
1323 MaybeHarden(blob);
1324 EXPECT_EQ(10, blob.size());
1325 absl::Cord suffix(blob);
1326 suffix.RemovePrefix(9);
1327 EXPECT_EQ(1, suffix.size());
1328 std::string s;
1329 absl::CopyCordToString(suffix, &s);
1330 EXPECT_EQ("z", s);
1331 }
1332
1333 // Remove all of a prefix block
TEST_P(CordTest,CordSpliceTestZedBlockSuffix0)1334 TEST_P(CordTest, CordSpliceTestZedBlockSuffix0) {
1335 absl::Cord blob = CordWithZedBlock(10);
1336 MaybeHarden(blob);
1337 EXPECT_EQ(10, blob.size());
1338 absl::Cord suffix(blob);
1339 suffix.RemovePrefix(10);
1340 EXPECT_EQ(0, suffix.size());
1341 std::string s;
1342 absl::CopyCordToString(suffix, &s);
1343 EXPECT_EQ("", s);
1344 }
1345
BigCord(size_t len,char v)1346 absl::Cord BigCord(size_t len, char v) {
1347 std::string s(len, v);
1348 return absl::Cord(s);
1349 }
1350
1351 // Splice block into cord.
SpliceCord(const absl::Cord & blob,int64_t offset,const absl::Cord & block)1352 absl::Cord SpliceCord(const absl::Cord& blob, int64_t offset,
1353 const absl::Cord& block) {
1354 CHECK_GE(offset, 0);
1355 CHECK_LE(static_cast<size_t>(offset) + block.size(), blob.size());
1356 absl::Cord result(blob);
1357 result.RemoveSuffix(blob.size() - offset);
1358 result.Append(block);
1359 absl::Cord suffix(blob);
1360 suffix.RemovePrefix(offset + block.size());
1361 result.Append(suffix);
1362 CHECK_EQ(blob.size(), result.size());
1363 return result;
1364 }
1365
1366 // Taking an empty suffix of a block breaks appending.
TEST_P(CordTest,CordSpliceTestRemoveEntireBlock1)1367 TEST_P(CordTest, CordSpliceTestRemoveEntireBlock1) {
1368 absl::Cord zero = CordWithZedBlock(10);
1369 MaybeHarden(zero);
1370 absl::Cord suffix(zero);
1371 suffix.RemovePrefix(10);
1372 absl::Cord result;
1373 result.Append(suffix);
1374 }
1375
TEST_P(CordTest,CordSpliceTestRemoveEntireBlock2)1376 TEST_P(CordTest, CordSpliceTestRemoveEntireBlock2) {
1377 absl::Cord zero = CordWithZedBlock(10);
1378 MaybeHarden(zero);
1379 absl::Cord prefix(zero);
1380 prefix.RemoveSuffix(10);
1381 absl::Cord suffix(zero);
1382 suffix.RemovePrefix(10);
1383 absl::Cord result(prefix);
1384 result.Append(suffix);
1385 }
1386
TEST_P(CordTest,CordSpliceTestRemoveEntireBlock3)1387 TEST_P(CordTest, CordSpliceTestRemoveEntireBlock3) {
1388 absl::Cord blob = CordWithZedBlock(10);
1389 absl::Cord block = BigCord(10, 'b');
1390 MaybeHarden(blob);
1391 MaybeHarden(block);
1392 blob = SpliceCord(blob, 0, block);
1393 }
1394
1395 struct CordCompareTestCase {
1396 template <typename LHS, typename RHS>
CordCompareTestCase__anond64eef590b11::CordCompareTestCase1397 CordCompareTestCase(const LHS& lhs, const RHS& rhs, bool use_crc)
1398 : lhs_cord(lhs), rhs_cord(rhs) {
1399 if (use_crc) {
1400 lhs_cord.SetExpectedChecksum(1);
1401 }
1402 }
1403
1404 absl::Cord lhs_cord;
1405 absl::Cord rhs_cord;
1406 };
1407
__anond64eef590d02(int x) 1408 const auto sign = [](int x) { return x == 0 ? 0 : (x > 0 ? 1 : -1); };
1409
VerifyComparison(const CordCompareTestCase & test_case)1410 void VerifyComparison(const CordCompareTestCase& test_case) {
1411 std::string lhs_string(test_case.lhs_cord);
1412 std::string rhs_string(test_case.rhs_cord);
1413 int expected = sign(lhs_string.compare(rhs_string));
1414 EXPECT_EQ(expected, test_case.lhs_cord.Compare(test_case.rhs_cord))
1415 << "LHS=" << lhs_string << "; RHS=" << rhs_string;
1416 EXPECT_EQ(expected, test_case.lhs_cord.Compare(rhs_string))
1417 << "LHS=" << lhs_string << "; RHS=" << rhs_string;
1418 EXPECT_EQ(-expected, test_case.rhs_cord.Compare(test_case.lhs_cord))
1419 << "LHS=" << rhs_string << "; RHS=" << lhs_string;
1420 EXPECT_EQ(-expected, test_case.rhs_cord.Compare(lhs_string))
1421 << "LHS=" << rhs_string << "; RHS=" << lhs_string;
1422 }
1423
TEST_P(CordTest,Compare)1424 TEST_P(CordTest, Compare) {
1425 absl::Cord subcord("aaaaaBBBBBcccccDDDDD");
1426 subcord = subcord.Subcord(3, 10);
1427
1428 absl::Cord tmp("aaaaaaaaaaaaaaaa");
1429 tmp.Append("BBBBBBBBBBBBBBBB");
1430 absl::Cord concat = absl::Cord("cccccccccccccccc");
1431 concat.Append("DDDDDDDDDDDDDDDD");
1432 concat.Prepend(tmp);
1433
1434 absl::Cord concat2("aaaaaaaaaaaaa");
1435 concat2.Append("aaaBBBBBBBBBBBBBBBBccccc");
1436 concat2.Append("cccccccccccDDDDDDDDDDDDDD");
1437 concat2.Append("DD");
1438
1439 const bool use_crc = UseCrc();
1440
1441 std::vector<CordCompareTestCase> test_cases = {{
1442 // Inline cords
1443 {"abcdef", "abcdef", use_crc},
1444 {"abcdef", "abcdee", use_crc},
1445 {"abcdef", "abcdeg", use_crc},
1446 {"bbcdef", "abcdef", use_crc},
1447 {"bbcdef", "abcdeg", use_crc},
1448 {"abcdefa", "abcdef", use_crc},
1449 {"abcdef", "abcdefa", use_crc},
1450
1451 // Small flat cords
1452 {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBcccccDDDDD", use_crc},
1453 {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBxccccDDDDD", use_crc},
1454 {"aaaaaBBBBBcxcccDDDDD", "aaaaaBBBBBcccccDDDDD", use_crc},
1455 {"aaaaaBBBBBxccccDDDDD", "aaaaaBBBBBcccccDDDDX", use_crc},
1456 {"aaaaaBBBBBcccccDDDDDa", "aaaaaBBBBBcccccDDDDD", use_crc},
1457 {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBcccccDDDDDa", use_crc},
1458
1459 // Subcords
1460 {subcord, subcord, use_crc},
1461 {subcord, "aaBBBBBccc", use_crc},
1462 {subcord, "aaBBBBBccd", use_crc},
1463 {subcord, "aaBBBBBccb", use_crc},
1464 {subcord, "aaBBBBBxcb", use_crc},
1465 {subcord, "aaBBBBBccca", use_crc},
1466 {subcord, "aaBBBBBcc", use_crc},
1467
1468 // Concats
1469 {concat, concat, use_crc},
1470 {concat,
1471 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDD",
1472 use_crc},
1473 {concat,
1474 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBcccccccccccccccxDDDDDDDDDDDDDDDD",
1475 use_crc},
1476 {concat,
1477 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBacccccccccccccccDDDDDDDDDDDDDDDD",
1478 use_crc},
1479 {concat,
1480 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDD",
1481 use_crc},
1482 {concat,
1483 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDDe",
1484 use_crc},
1485
1486 {concat, concat2, use_crc},
1487 }};
1488
1489 for (const auto& tc : test_cases) {
1490 VerifyComparison(tc);
1491 }
1492 }
1493
TEST_P(CordTest,CompareAfterAssign)1494 TEST_P(CordTest, CompareAfterAssign) {
1495 absl::Cord a("aaaaaa1111111");
1496 absl::Cord b("aaaaaa2222222");
1497 MaybeHarden(a);
1498 a = "cccccc";
1499 b = "cccccc";
1500 EXPECT_EQ(a, b);
1501 EXPECT_FALSE(a < b);
1502
1503 a = "aaaa";
1504 b = "bbbbb";
1505 a = "";
1506 b = "";
1507 EXPECT_EQ(a, b);
1508 EXPECT_FALSE(a < b);
1509 }
1510
1511 // Test CompareTo() and ComparePrefix() against string and substring
1512 // comparison methods from basic_string.
TestCompare(const absl::Cord & c,const absl::Cord & d,RandomEngine * rng)1513 static void TestCompare(const absl::Cord& c, const absl::Cord& d,
1514 RandomEngine* rng) {
1515 typedef std::basic_string<uint8_t> ustring;
1516 ustring cs(reinterpret_cast<const uint8_t*>(std::string(c).data()), c.size());
1517 ustring ds(reinterpret_cast<const uint8_t*>(std::string(d).data()), d.size());
1518 // ustring comparison is ideal because we expect Cord comparisons to be
1519 // based on unsigned byte comparisons regardless of whether char is signed.
1520 int expected = sign(cs.compare(ds));
1521 EXPECT_EQ(expected, sign(c.Compare(d))) << c << ", " << d;
1522 }
1523
TEST_P(CordTest,CompareComparisonIsUnsigned)1524 TEST_P(CordTest, CompareComparisonIsUnsigned) {
1525 RandomEngine rng(GTEST_FLAG_GET(random_seed));
1526 std::uniform_int_distribution<uint32_t> uniform_uint8(0, 255);
1527 char x = static_cast<char>(uniform_uint8(rng));
1528 TestCompare(
1529 absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100), x)),
1530 absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100), x ^ 0x80)), &rng);
1531 }
1532
TEST_P(CordTest,CompareRandomComparisons)1533 TEST_P(CordTest, CompareRandomComparisons) {
1534 const int kIters = 5000;
1535 RandomEngine rng(GTEST_FLAG_GET(random_seed));
1536
1537 int n = GetUniformRandomUpTo(&rng, 5000);
1538 absl::Cord a[] = {MakeExternalCord(n),
1539 absl::Cord("ant"),
1540 absl::Cord("elephant"),
1541 absl::Cord("giraffe"),
1542 absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100),
1543 GetUniformRandomUpTo(&rng, 100))),
1544 absl::Cord(""),
1545 absl::Cord("x"),
1546 absl::Cord("A"),
1547 absl::Cord("B"),
1548 absl::Cord("C")};
1549 for (int i = 0; i < kIters; i++) {
1550 absl::Cord c, d;
1551 for (int j = 0; j < (i % 7) + 1; j++) {
1552 c.Append(a[GetUniformRandomUpTo(&rng, ABSL_ARRAYSIZE(a))]);
1553 d.Append(a[GetUniformRandomUpTo(&rng, ABSL_ARRAYSIZE(a))]);
1554 }
1555 std::bernoulli_distribution coin_flip(0.5);
1556 MaybeHarden(c);
1557 MaybeHarden(d);
1558 TestCompare(coin_flip(rng) ? c : absl::Cord(std::string(c)),
1559 coin_flip(rng) ? d : absl::Cord(std::string(d)), &rng);
1560 }
1561 }
1562
1563 template <typename T1, typename T2>
CompareOperators()1564 void CompareOperators() {
1565 const T1 a("a");
1566 const T2 b("b");
1567
1568 EXPECT_TRUE(a == a);
1569 // For pointer type (i.e. `const char*`), operator== compares the address
1570 // instead of the string, so `a == const char*("a")` isn't necessarily true.
1571 EXPECT_TRUE(std::is_pointer<T1>::value || a == T1("a"));
1572 EXPECT_TRUE(std::is_pointer<T2>::value || a == T2("a"));
1573 EXPECT_FALSE(a == b);
1574
1575 EXPECT_TRUE(a != b);
1576 EXPECT_FALSE(a != a);
1577
1578 EXPECT_TRUE(a < b);
1579 EXPECT_FALSE(b < a);
1580
1581 EXPECT_TRUE(b > a);
1582 EXPECT_FALSE(a > b);
1583
1584 EXPECT_TRUE(a >= a);
1585 EXPECT_TRUE(b >= a);
1586 EXPECT_FALSE(a >= b);
1587
1588 EXPECT_TRUE(a <= a);
1589 EXPECT_TRUE(a <= b);
1590 EXPECT_FALSE(b <= a);
1591 }
1592
TEST_P(CordTest,ComparisonOperators_Cord_Cord)1593 TEST_P(CordTest, ComparisonOperators_Cord_Cord) {
1594 CompareOperators<absl::Cord, absl::Cord>();
1595 }
1596
TEST_P(CordTest,ComparisonOperators_Cord_StringPiece)1597 TEST_P(CordTest, ComparisonOperators_Cord_StringPiece) {
1598 CompareOperators<absl::Cord, absl::string_view>();
1599 }
1600
TEST_P(CordTest,ComparisonOperators_StringPiece_Cord)1601 TEST_P(CordTest, ComparisonOperators_StringPiece_Cord) {
1602 CompareOperators<absl::string_view, absl::Cord>();
1603 }
1604
TEST_P(CordTest,ComparisonOperators_Cord_string)1605 TEST_P(CordTest, ComparisonOperators_Cord_string) {
1606 CompareOperators<absl::Cord, std::string>();
1607 }
1608
TEST_P(CordTest,ComparisonOperators_string_Cord)1609 TEST_P(CordTest, ComparisonOperators_string_Cord) {
1610 CompareOperators<std::string, absl::Cord>();
1611 }
1612
TEST_P(CordTest,ComparisonOperators_stdstring_Cord)1613 TEST_P(CordTest, ComparisonOperators_stdstring_Cord) {
1614 CompareOperators<std::string, absl::Cord>();
1615 }
1616
TEST_P(CordTest,ComparisonOperators_Cord_stdstring)1617 TEST_P(CordTest, ComparisonOperators_Cord_stdstring) {
1618 CompareOperators<absl::Cord, std::string>();
1619 }
1620
TEST_P(CordTest,ComparisonOperators_charstar_Cord)1621 TEST_P(CordTest, ComparisonOperators_charstar_Cord) {
1622 CompareOperators<const char*, absl::Cord>();
1623 }
1624
TEST_P(CordTest,ComparisonOperators_Cord_charstar)1625 TEST_P(CordTest, ComparisonOperators_Cord_charstar) {
1626 CompareOperators<absl::Cord, const char*>();
1627 }
1628
TEST_P(CordTest,ConstructFromExternalReleaserInvoked)1629 TEST_P(CordTest, ConstructFromExternalReleaserInvoked) {
1630 // Empty external memory means the releaser should be called immediately.
1631 {
1632 bool invoked = false;
1633 auto releaser = [&invoked](absl::string_view) { invoked = true; };
1634 {
1635 auto c = absl::MakeCordFromExternal("", releaser);
1636 EXPECT_TRUE(invoked);
1637 }
1638 }
1639
1640 // If the size of the data is small enough, a future constructor
1641 // implementation may copy the bytes and immediately invoke the releaser
1642 // instead of creating an external node. We make a large dummy std::string to
1643 // make this test independent of such an optimization.
1644 std::string large_dummy(2048, 'c');
1645 {
1646 bool invoked = false;
1647 auto releaser = [&invoked](absl::string_view) { invoked = true; };
1648 {
1649 auto c = absl::MakeCordFromExternal(large_dummy, releaser);
1650 EXPECT_FALSE(invoked);
1651 }
1652 EXPECT_TRUE(invoked);
1653 }
1654
1655 {
1656 bool invoked = false;
1657 auto releaser = [&invoked](absl::string_view) { invoked = true; };
1658 {
1659 absl::Cord copy;
1660 {
1661 auto c = absl::MakeCordFromExternal(large_dummy, releaser);
1662 copy = c;
1663 EXPECT_FALSE(invoked);
1664 }
1665 EXPECT_FALSE(invoked);
1666 }
1667 EXPECT_TRUE(invoked);
1668 }
1669 }
1670
TEST_P(CordTest,ConstructFromExternalCompareContents)1671 TEST_P(CordTest, ConstructFromExternalCompareContents) {
1672 RandomEngine rng(GTEST_FLAG_GET(random_seed));
1673
1674 for (int length = 1; length <= 2048; length *= 2) {
1675 std::string data = RandomLowercaseString(&rng, length);
1676 auto* external = new std::string(data);
1677 auto cord =
1678 absl::MakeCordFromExternal(*external, [external](absl::string_view sv) {
1679 EXPECT_EQ(external->data(), sv.data());
1680 EXPECT_EQ(external->size(), sv.size());
1681 delete external;
1682 });
1683 MaybeHarden(cord);
1684 EXPECT_EQ(data, cord);
1685 }
1686 }
1687
TEST_P(CordTest,ConstructFromExternalLargeReleaser)1688 TEST_P(CordTest, ConstructFromExternalLargeReleaser) {
1689 RandomEngine rng(GTEST_FLAG_GET(random_seed));
1690 constexpr size_t kLength = 256;
1691 std::string data = RandomLowercaseString(&rng, kLength);
1692 std::array<char, kLength> data_array;
1693 for (size_t i = 0; i < kLength; ++i) data_array[i] = data[i];
1694 bool invoked = false;
1695 auto releaser = [data_array, &invoked](absl::string_view data) {
1696 EXPECT_EQ(data, absl::string_view(data_array.data(), data_array.size()));
1697 invoked = true;
1698 };
1699 (void)MaybeHardened(absl::MakeCordFromExternal(data, releaser));
1700 EXPECT_TRUE(invoked);
1701 }
1702
TEST_P(CordTest,ConstructFromExternalFunctionPointerReleaser)1703 TEST_P(CordTest, ConstructFromExternalFunctionPointerReleaser) {
1704 static absl::string_view data("hello world");
1705 static bool invoked;
1706 auto* releaser =
1707 static_cast<void (*)(absl::string_view)>([](absl::string_view sv) {
1708 EXPECT_EQ(data, sv);
1709 invoked = true;
1710 });
1711 invoked = false;
1712 (void)MaybeHardened(absl::MakeCordFromExternal(data, releaser));
1713 EXPECT_TRUE(invoked);
1714
1715 invoked = false;
1716 (void)MaybeHardened(absl::MakeCordFromExternal(data, *releaser));
1717 EXPECT_TRUE(invoked);
1718 }
1719
TEST_P(CordTest,ConstructFromExternalMoveOnlyReleaser)1720 TEST_P(CordTest, ConstructFromExternalMoveOnlyReleaser) {
1721 struct Releaser {
1722 explicit Releaser(bool* invoked) : invoked(invoked) {}
1723 Releaser(Releaser&& other) noexcept : invoked(other.invoked) {}
1724 void operator()(absl::string_view) const { *invoked = true; }
1725
1726 bool* invoked;
1727 };
1728
1729 bool invoked = false;
1730 (void)MaybeHardened(absl::MakeCordFromExternal("dummy", Releaser(&invoked)));
1731 EXPECT_TRUE(invoked);
1732 }
1733
TEST_P(CordTest,ConstructFromExternalNoArgLambda)1734 TEST_P(CordTest, ConstructFromExternalNoArgLambda) {
1735 bool invoked = false;
1736 (void)MaybeHardened(
1737 absl::MakeCordFromExternal("dummy", [&invoked]() { invoked = true; }));
1738 EXPECT_TRUE(invoked);
1739 }
1740
TEST_P(CordTest,ConstructFromExternalStringViewArgLambda)1741 TEST_P(CordTest, ConstructFromExternalStringViewArgLambda) {
1742 bool invoked = false;
1743 (void)MaybeHardened(absl::MakeCordFromExternal(
1744 "dummy", [&invoked](absl::string_view) { invoked = true; }));
1745 EXPECT_TRUE(invoked);
1746 }
1747
TEST_P(CordTest,ConstructFromExternalNonTrivialReleaserDestructor)1748 TEST_P(CordTest, ConstructFromExternalNonTrivialReleaserDestructor) {
1749 struct Releaser {
1750 explicit Releaser(bool* destroyed) : destroyed(destroyed) {}
1751 ~Releaser() { *destroyed = true; }
1752 void operator()(absl::string_view) const {}
1753
1754 bool* destroyed;
1755 };
1756
1757 bool destroyed = false;
1758 Releaser releaser(&destroyed);
1759 (void)MaybeHardened(absl::MakeCordFromExternal("dummy", releaser));
1760 EXPECT_TRUE(destroyed);
1761 }
1762
TEST_P(CordTest,ConstructFromExternalReferenceQualifierOverloads)1763 TEST_P(CordTest, ConstructFromExternalReferenceQualifierOverloads) {
1764 enum InvokedAs { kMissing, kLValue, kRValue };
1765 enum CopiedAs { kNone, kMove, kCopy };
1766 struct Tracker {
1767 CopiedAs copied_as = kNone;
1768 InvokedAs invoked_as = kMissing;
1769
1770 void Record(InvokedAs rhs) {
1771 ASSERT_EQ(invoked_as, kMissing);
1772 invoked_as = rhs;
1773 }
1774
1775 void Record(CopiedAs rhs) {
1776 if (copied_as == kNone || rhs == kCopy) copied_as = rhs;
1777 }
1778 } tracker;
1779
1780 class Releaser {
1781 public:
1782 explicit Releaser(Tracker* tracker) : tr_(tracker) { *tracker = Tracker(); }
1783 Releaser(Releaser&& rhs) : tr_(rhs.tr_) { tr_->Record(kMove); }
1784 Releaser(const Releaser& rhs) : tr_(rhs.tr_) { tr_->Record(kCopy); }
1785
1786 void operator()(absl::string_view) & { tr_->Record(kLValue); }
1787 void operator()(absl::string_view) && { tr_->Record(kRValue); }
1788
1789 private:
1790 Tracker* tr_;
1791 };
1792
1793 const Releaser releaser1(&tracker);
1794 (void)MaybeHardened(absl::MakeCordFromExternal("", releaser1));
1795 EXPECT_EQ(tracker.copied_as, kCopy);
1796 EXPECT_EQ(tracker.invoked_as, kRValue);
1797
1798 const Releaser releaser2(&tracker);
1799 (void)MaybeHardened(absl::MakeCordFromExternal("", releaser2));
1800 EXPECT_EQ(tracker.copied_as, kCopy);
1801 EXPECT_EQ(tracker.invoked_as, kRValue);
1802
1803 Releaser releaser3(&tracker);
1804 (void)MaybeHardened(absl::MakeCordFromExternal("", std::move(releaser3)));
1805 EXPECT_EQ(tracker.copied_as, kMove);
1806 EXPECT_EQ(tracker.invoked_as, kRValue);
1807
1808 Releaser releaser4(&tracker);
1809 (void)MaybeHardened(absl::MakeCordFromExternal("dummy", releaser4));
1810 EXPECT_EQ(tracker.copied_as, kCopy);
1811 EXPECT_EQ(tracker.invoked_as, kRValue);
1812
1813 const Releaser releaser5(&tracker);
1814 (void)MaybeHardened(absl::MakeCordFromExternal("dummy", releaser5));
1815 EXPECT_EQ(tracker.copied_as, kCopy);
1816 EXPECT_EQ(tracker.invoked_as, kRValue);
1817
1818 Releaser releaser6(&tracker);
1819 (void)MaybeHardened(absl::MakeCordFromExternal("foo", std::move(releaser6)));
1820 EXPECT_EQ(tracker.copied_as, kMove);
1821 EXPECT_EQ(tracker.invoked_as, kRValue);
1822 }
1823
TEST_P(CordTest,ExternalMemoryBasicUsage)1824 TEST_P(CordTest, ExternalMemoryBasicUsage) {
1825 static const char* strings[] = {"", "hello", "there"};
1826 for (const char* str : strings) {
1827 absl::Cord dst("(prefix)");
1828 MaybeHarden(dst);
1829 AddExternalMemory(str, &dst);
1830 MaybeHarden(dst);
1831 dst.Append("(suffix)");
1832 EXPECT_EQ((std::string("(prefix)") + str + std::string("(suffix)")),
1833 std::string(dst));
1834 }
1835 }
1836
TEST_P(CordTest,ExternalMemoryRemovePrefixSuffix)1837 TEST_P(CordTest, ExternalMemoryRemovePrefixSuffix) {
1838 // Exhaustively try all sub-strings.
1839 absl::Cord cord = MakeComposite();
1840 std::string s = std::string(cord);
1841 for (int offset = 0; offset <= s.size(); offset++) {
1842 for (int length = 0; length <= s.size() - offset; length++) {
1843 absl::Cord result(cord);
1844 MaybeHarden(result);
1845 result.RemovePrefix(offset);
1846 MaybeHarden(result);
1847 result.RemoveSuffix(result.size() - length);
1848 EXPECT_EQ(s.substr(offset, length), std::string(result))
1849 << offset << " " << length;
1850 }
1851 }
1852 }
1853
TEST_P(CordTest,ExternalMemoryGet)1854 TEST_P(CordTest, ExternalMemoryGet) {
1855 absl::Cord cord("hello");
1856 AddExternalMemory(" world!", &cord);
1857 MaybeHarden(cord);
1858 AddExternalMemory(" how are ", &cord);
1859 cord.Append(" you?");
1860 MaybeHarden(cord);
1861 std::string s = std::string(cord);
1862 for (int i = 0; i < s.size(); i++) {
1863 EXPECT_EQ(s[i], cord[i]);
1864 }
1865 }
1866
1867 // CordMemoryUsage tests verify the correctness of the EstimatedMemoryUsage()
1868 // We use whiteboxed expectations based on our knowledge of the layout and size
1869 // of empty and inlined cords, and flat nodes.
1870
1871 constexpr auto kFairShare = absl::CordMemoryAccounting::kFairShare;
1872 constexpr auto kTotalMorePrecise =
1873 absl::CordMemoryAccounting::kTotalMorePrecise;
1874
1875 // Creates a cord of `n` `c` values, making sure no string stealing occurs.
MakeCord(size_t n,char c)1876 absl::Cord MakeCord(size_t n, char c) {
1877 const std::string s(n, c);
1878 return absl::Cord(s);
1879 }
1880
TEST(CordTest,CordMemoryUsageEmpty)1881 TEST(CordTest, CordMemoryUsageEmpty) {
1882 absl::Cord cord;
1883 EXPECT_EQ(sizeof(absl::Cord), cord.EstimatedMemoryUsage());
1884 EXPECT_EQ(sizeof(absl::Cord), cord.EstimatedMemoryUsage(kFairShare));
1885 EXPECT_EQ(sizeof(absl::Cord), cord.EstimatedMemoryUsage(kTotalMorePrecise));
1886 }
1887
TEST(CordTest,CordMemoryUsageInlined)1888 TEST(CordTest, CordMemoryUsageInlined) {
1889 absl::Cord a("hello");
1890 EXPECT_EQ(a.EstimatedMemoryUsage(), sizeof(absl::Cord));
1891 EXPECT_EQ(a.EstimatedMemoryUsage(kFairShare), sizeof(absl::Cord));
1892 EXPECT_EQ(a.EstimatedMemoryUsage(kTotalMorePrecise), sizeof(absl::Cord));
1893 }
1894
TEST(CordTest,CordMemoryUsageExternalMemory)1895 TEST(CordTest, CordMemoryUsageExternalMemory) {
1896 absl::Cord cord;
1897 AddExternalMemory(std::string(1000, 'x'), &cord);
1898 const size_t expected =
1899 sizeof(absl::Cord) + 1000 + sizeof(CordRepExternal) + sizeof(intptr_t);
1900 EXPECT_EQ(cord.EstimatedMemoryUsage(), expected);
1901 EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare), expected);
1902 EXPECT_EQ(cord.EstimatedMemoryUsage(kTotalMorePrecise), expected);
1903 }
1904
TEST(CordTest,CordMemoryUsageFlat)1905 TEST(CordTest, CordMemoryUsageFlat) {
1906 absl::Cord cord = MakeCord(1000, 'a');
1907 const size_t flat_size =
1908 absl::CordTestPeer::Tree(cord)->flat()->AllocatedSize();
1909 EXPECT_EQ(cord.EstimatedMemoryUsage(), sizeof(absl::Cord) + flat_size);
1910 EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare),
1911 sizeof(absl::Cord) + flat_size);
1912 EXPECT_EQ(cord.EstimatedMemoryUsage(kTotalMorePrecise),
1913 sizeof(absl::Cord) + flat_size);
1914 }
1915
TEST(CordTest,CordMemoryUsageSubStringSharedFlat)1916 TEST(CordTest, CordMemoryUsageSubStringSharedFlat) {
1917 absl::Cord flat = MakeCord(2000, 'a');
1918 const size_t flat_size =
1919 absl::CordTestPeer::Tree(flat)->flat()->AllocatedSize();
1920 absl::Cord cord = flat.Subcord(500, 1000);
1921 EXPECT_EQ(cord.EstimatedMemoryUsage(),
1922 sizeof(absl::Cord) + sizeof(CordRepSubstring) + flat_size);
1923 EXPECT_EQ(cord.EstimatedMemoryUsage(kTotalMorePrecise),
1924 sizeof(absl::Cord) + sizeof(CordRepSubstring) + flat_size);
1925 EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare),
1926 sizeof(absl::Cord) + sizeof(CordRepSubstring) + flat_size / 2);
1927 }
1928
TEST(CordTest,CordMemoryUsageFlatShared)1929 TEST(CordTest, CordMemoryUsageFlatShared) {
1930 absl::Cord shared = MakeCord(1000, 'a');
1931 absl::Cord cord(shared);
1932 const size_t flat_size =
1933 absl::CordTestPeer::Tree(cord)->flat()->AllocatedSize();
1934 EXPECT_EQ(cord.EstimatedMemoryUsage(), sizeof(absl::Cord) + flat_size);
1935 EXPECT_EQ(cord.EstimatedMemoryUsage(kTotalMorePrecise),
1936 sizeof(absl::Cord) + flat_size);
1937 EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare),
1938 sizeof(absl::Cord) + flat_size / 2);
1939 }
1940
TEST(CordTest,CordMemoryUsageFlatHardenedAndShared)1941 TEST(CordTest, CordMemoryUsageFlatHardenedAndShared) {
1942 absl::Cord shared = MakeCord(1000, 'a');
1943 absl::Cord cord(shared);
1944 const size_t flat_size =
1945 absl::CordTestPeer::Tree(cord)->flat()->AllocatedSize();
1946 cord.SetExpectedChecksum(1);
1947 EXPECT_EQ(cord.EstimatedMemoryUsage(),
1948 sizeof(absl::Cord) + sizeof(CordRepCrc) + flat_size);
1949 EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare),
1950 sizeof(absl::Cord) + sizeof(CordRepCrc) + flat_size / 2);
1951
1952 absl::Cord cord2(cord);
1953 EXPECT_EQ(cord2.EstimatedMemoryUsage(),
1954 sizeof(absl::Cord) + sizeof(CordRepCrc) + flat_size);
1955 EXPECT_EQ(cord2.EstimatedMemoryUsage(kTotalMorePrecise),
1956 sizeof(absl::Cord) + sizeof(CordRepCrc) + flat_size);
1957 EXPECT_EQ(cord2.EstimatedMemoryUsage(kFairShare),
1958 sizeof(absl::Cord) + (sizeof(CordRepCrc) + flat_size / 2) / 2);
1959 }
1960
TEST(CordTest,CordMemoryUsageBTree)1961 TEST(CordTest, CordMemoryUsageBTree) {
1962 absl::Cord cord1;
1963 size_t flats1_size = 0;
1964 absl::Cord flats1[4] = {MakeCord(1000, 'a'), MakeCord(1100, 'a'),
1965 MakeCord(1200, 'a'), MakeCord(1300, 'a')};
1966 for (absl::Cord flat : flats1) {
1967 flats1_size += absl::CordTestPeer::Tree(flat)->flat()->AllocatedSize();
1968 cord1.Append(std::move(flat));
1969 }
1970
1971 // Make sure the created cord is a BTREE tree. Under some builds such as
1972 // windows DLL, we may have ODR like effects on the flag, meaning the DLL
1973 // code will run with the picked up default.
1974 if (!absl::CordTestPeer::Tree(cord1)->IsBtree()) {
1975 LOG(WARNING) << "Cord library code not respecting btree flag";
1976 return;
1977 }
1978
1979 size_t rep1_size = sizeof(CordRepBtree) + flats1_size;
1980 size_t rep1_shared_size = sizeof(CordRepBtree) + flats1_size / 2;
1981
1982 EXPECT_EQ(cord1.EstimatedMemoryUsage(), sizeof(absl::Cord) + rep1_size);
1983 EXPECT_EQ(cord1.EstimatedMemoryUsage(kTotalMorePrecise),
1984 sizeof(absl::Cord) + rep1_size);
1985 EXPECT_EQ(cord1.EstimatedMemoryUsage(kFairShare),
1986 sizeof(absl::Cord) + rep1_shared_size);
1987
1988 absl::Cord cord2;
1989 size_t flats2_size = 0;
1990 absl::Cord flats2[4] = {MakeCord(600, 'a'), MakeCord(700, 'a'),
1991 MakeCord(800, 'a'), MakeCord(900, 'a')};
1992 for (absl::Cord& flat : flats2) {
1993 flats2_size += absl::CordTestPeer::Tree(flat)->flat()->AllocatedSize();
1994 cord2.Append(std::move(flat));
1995 }
1996 size_t rep2_size = sizeof(CordRepBtree) + flats2_size;
1997
1998 EXPECT_EQ(cord2.EstimatedMemoryUsage(), sizeof(absl::Cord) + rep2_size);
1999 EXPECT_EQ(cord2.EstimatedMemoryUsage(kTotalMorePrecise),
2000 sizeof(absl::Cord) + rep2_size);
2001 EXPECT_EQ(cord2.EstimatedMemoryUsage(kFairShare),
2002 sizeof(absl::Cord) + rep2_size);
2003
2004 absl::Cord cord(cord1);
2005 cord.Append(std::move(cord2));
2006
2007 EXPECT_EQ(cord.EstimatedMemoryUsage(),
2008 sizeof(absl::Cord) + sizeof(CordRepBtree) + rep1_size + rep2_size);
2009 EXPECT_EQ(cord.EstimatedMemoryUsage(kTotalMorePrecise),
2010 sizeof(absl::Cord) + sizeof(CordRepBtree) + rep1_size + rep2_size);
2011 EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare),
2012 sizeof(absl::Cord) + sizeof(CordRepBtree) + rep1_shared_size / 2 +
2013 rep2_size);
2014 }
2015
2016 // Regtest for a change that had to be rolled back because it expanded out
2017 // of the InlineRep too soon, which was observable through MemoryUsage().
TEST_P(CordTest,CordMemoryUsageInlineRep)2018 TEST_P(CordTest, CordMemoryUsageInlineRep) {
2019 constexpr size_t kMaxInline = 15; // Cord::InlineRep::N
2020 const std::string small_string(kMaxInline, 'x');
2021 absl::Cord c1(small_string);
2022
2023 absl::Cord c2;
2024 c2.Append(small_string);
2025 EXPECT_EQ(c1, c2);
2026 EXPECT_EQ(c1.EstimatedMemoryUsage(), c2.EstimatedMemoryUsage());
2027 }
2028
TEST_P(CordTest,CordMemoryUsageTotalMorePreciseMode)2029 TEST_P(CordTest, CordMemoryUsageTotalMorePreciseMode) {
2030 constexpr size_t kChunkSize = 2000;
2031 std::string tmp_str(kChunkSize, 'x');
2032 const absl::Cord flat(std::move(tmp_str));
2033
2034 // Construct `fragmented` with two references into the same
2035 // underlying buffer shared with `flat`:
2036 absl::Cord fragmented(flat);
2037 fragmented.Append(flat);
2038
2039 // Memory usage of `flat`, minus the top-level Cord object:
2040 const size_t flat_internal_usage =
2041 flat.EstimatedMemoryUsage() - sizeof(absl::Cord);
2042
2043 // `fragmented` holds a Cord and a CordRepBtree. That tree points to two
2044 // copies of flat's internals, which we expect to dedup:
2045 EXPECT_EQ(fragmented.EstimatedMemoryUsage(kTotalMorePrecise),
2046 sizeof(absl::Cord) +
2047 sizeof(CordRepBtree) +
2048 flat_internal_usage);
2049
2050 // This is a case where kTotal produces an overestimate:
2051 EXPECT_EQ(fragmented.EstimatedMemoryUsage(),
2052 sizeof(absl::Cord) +
2053 sizeof(CordRepBtree) +
2054 2 * flat_internal_usage);
2055 }
2056
TEST_P(CordTest,CordMemoryUsageTotalMorePreciseModeWithSubstring)2057 TEST_P(CordTest, CordMemoryUsageTotalMorePreciseModeWithSubstring) {
2058 constexpr size_t kChunkSize = 2000;
2059 std::string tmp_str(kChunkSize, 'x');
2060 const absl::Cord flat(std::move(tmp_str));
2061
2062 // Construct `fragmented` with two references into the same
2063 // underlying buffer shared with `flat`.
2064 //
2065 // This time, each reference is through a Subcord():
2066 absl::Cord fragmented;
2067 fragmented.Append(flat.Subcord(1, kChunkSize - 2));
2068 fragmented.Append(flat.Subcord(1, kChunkSize - 2));
2069
2070 // Memory usage of `flat`, minus the top-level Cord object:
2071 const size_t flat_internal_usage =
2072 flat.EstimatedMemoryUsage() - sizeof(absl::Cord);
2073
2074 // `fragmented` holds a Cord and a CordRepBtree. That tree points to two
2075 // CordRepSubstrings, each pointing at flat's internals.
2076 EXPECT_EQ(fragmented.EstimatedMemoryUsage(kTotalMorePrecise),
2077 sizeof(absl::Cord) +
2078 sizeof(CordRepBtree) +
2079 2 * sizeof(CordRepSubstring) +
2080 flat_internal_usage);
2081
2082 // This is a case where kTotal produces an overestimate:
2083 EXPECT_EQ(fragmented.EstimatedMemoryUsage(),
2084 sizeof(absl::Cord) +
2085 sizeof(CordRepBtree) +
2086 2 * sizeof(CordRepSubstring) +
2087 2 * flat_internal_usage);
2088 }
2089 } // namespace
2090
2091 // Regtest for 7510292 (fix a bug introduced by 7465150)
TEST_P(CordTest,Concat_Append)2092 TEST_P(CordTest, Concat_Append) {
2093 // Create a rep of type CONCAT
2094 absl::Cord s1("foobarbarbarbarbar");
2095 MaybeHarden(s1);
2096 s1.Append("abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg");
2097 size_t size = s1.size();
2098
2099 // Create a copy of s1 and append to it.
2100 absl::Cord s2 = s1;
2101 MaybeHarden(s2);
2102 s2.Append("x");
2103
2104 // 7465150 modifies s1 when it shouldn't.
2105 EXPECT_EQ(s1.size(), size);
2106 EXPECT_EQ(s2.size(), size + 1);
2107 }
2108
TEST_P(CordTest,DiabolicalGrowth)2109 TEST_P(CordTest, DiabolicalGrowth) {
2110 // This test exercises a diabolical Append(<one char>) on a cord, making the
2111 // cord shared before each Append call resulting in a terribly fragmented
2112 // resulting cord.
2113 RandomEngine rng(GTEST_FLAG_GET(random_seed));
2114 const std::string expected = RandomLowercaseString(&rng, 5000);
2115 absl::Cord cord;
2116 for (char c : expected) {
2117 absl::Cord shared(cord);
2118 cord.Append(absl::string_view(&c, 1));
2119 MaybeHarden(cord);
2120 }
2121 std::string value;
2122 absl::CopyCordToString(cord, &value);
2123 EXPECT_EQ(value, expected);
2124 LOG(INFO) << "Diabolical size allocated = " << cord.EstimatedMemoryUsage();
2125 }
2126
2127 // The following tests check support for >4GB cords in 64-bit binaries, and
2128 // 2GB-4GB cords in 32-bit binaries. This function returns the large cord size
2129 // that's appropriate for the binary.
2130
2131 // Construct a huge cord with the specified valid prefix.
MakeHuge(absl::string_view prefix)2132 static absl::Cord MakeHuge(absl::string_view prefix) {
2133 absl::Cord cord;
2134 if (sizeof(size_t) > 4) {
2135 // In 64-bit binaries, test 64-bit Cord support.
2136 const size_t size =
2137 static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 314;
2138 cord.Append(absl::MakeCordFromExternal(
2139 absl::string_view(prefix.data(), size),
2140 [](absl::string_view s) { DoNothing(s, nullptr); }));
2141 } else {
2142 // Cords are limited to 32-bit lengths in 32-bit binaries. The following
2143 // tests check for use of "signed int" to represent Cord length/offset.
2144 // However absl::string_view does not allow lengths >= (1u<<31), so we need
2145 // to append in two parts;
2146 const size_t s1 = (1u << 31) - 1;
2147 // For shorter cord, `Append` copies the data rather than allocating a new
2148 // node. The threshold is currently set to 511, so `s2` needs to be bigger
2149 // to not trigger the copy.
2150 const size_t s2 = 600;
2151 cord.Append(absl::MakeCordFromExternal(
2152 absl::string_view(prefix.data(), s1),
2153 [](absl::string_view s) { DoNothing(s, nullptr); }));
2154 cord.Append(absl::MakeCordFromExternal(
2155 absl::string_view("", s2),
2156 [](absl::string_view s) { DoNothing(s, nullptr); }));
2157 }
2158 return cord;
2159 }
2160
TEST_P(CordTest,HugeCord)2161 TEST_P(CordTest, HugeCord) {
2162 absl::Cord cord = MakeHuge("huge cord");
2163 MaybeHarden(cord);
2164
2165 const size_t acceptable_delta =
2166 100 + (UseCrc() ? sizeof(absl::cord_internal::CordRepCrc) : 0);
2167 EXPECT_LE(cord.size(), cord.EstimatedMemoryUsage());
2168 EXPECT_GE(cord.size() + acceptable_delta, cord.EstimatedMemoryUsage());
2169 }
2170
2171 // Tests that Append() works ok when handed a self reference
TEST_P(CordTest,AppendSelf)2172 TEST_P(CordTest, AppendSelf) {
2173 // Test the empty case.
2174 absl::Cord empty;
2175 MaybeHarden(empty);
2176 empty.Append(empty);
2177 ASSERT_EQ(empty, "");
2178
2179 // We run the test until data is ~16K
2180 // This guarantees it covers small, medium and large data.
2181 std::string control_data = "Abc";
2182 absl::Cord data(control_data);
2183 while (control_data.length() < 0x4000) {
2184 MaybeHarden(data);
2185 data.Append(data);
2186 control_data.append(control_data);
2187 ASSERT_EQ(control_data, data);
2188 }
2189 }
2190
TEST_P(CordTest,MakeFragmentedCordFromInitializerList)2191 TEST_P(CordTest, MakeFragmentedCordFromInitializerList) {
2192 absl::Cord fragmented =
2193 absl::MakeFragmentedCord({"A ", "fragmented ", "Cord"});
2194
2195 MaybeHarden(fragmented);
2196
2197 EXPECT_EQ("A fragmented Cord", fragmented);
2198
2199 auto chunk_it = fragmented.chunk_begin();
2200
2201 ASSERT_TRUE(chunk_it != fragmented.chunk_end());
2202 EXPECT_EQ("A ", *chunk_it);
2203
2204 ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
2205 EXPECT_EQ("fragmented ", *chunk_it);
2206
2207 ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
2208 EXPECT_EQ("Cord", *chunk_it);
2209
2210 ASSERT_TRUE(++chunk_it == fragmented.chunk_end());
2211 }
2212
TEST_P(CordTest,MakeFragmentedCordFromVector)2213 TEST_P(CordTest, MakeFragmentedCordFromVector) {
2214 std::vector<absl::string_view> chunks = {"A ", "fragmented ", "Cord"};
2215 absl::Cord fragmented = absl::MakeFragmentedCord(chunks);
2216
2217 MaybeHarden(fragmented);
2218
2219 EXPECT_EQ("A fragmented Cord", fragmented);
2220
2221 auto chunk_it = fragmented.chunk_begin();
2222
2223 ASSERT_TRUE(chunk_it != fragmented.chunk_end());
2224 EXPECT_EQ("A ", *chunk_it);
2225
2226 ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
2227 EXPECT_EQ("fragmented ", *chunk_it);
2228
2229 ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
2230 EXPECT_EQ("Cord", *chunk_it);
2231
2232 ASSERT_TRUE(++chunk_it == fragmented.chunk_end());
2233 }
2234
TEST_P(CordTest,CordChunkIteratorTraits)2235 TEST_P(CordTest, CordChunkIteratorTraits) {
2236 static_assert(std::is_copy_constructible<absl::Cord::ChunkIterator>::value,
2237 "");
2238 static_assert(std::is_copy_assignable<absl::Cord::ChunkIterator>::value, "");
2239
2240 // Move semantics to satisfy swappable via std::swap
2241 static_assert(std::is_move_constructible<absl::Cord::ChunkIterator>::value,
2242 "");
2243 static_assert(std::is_move_assignable<absl::Cord::ChunkIterator>::value, "");
2244
2245 static_assert(
2246 std::is_same<
2247 std::iterator_traits<absl::Cord::ChunkIterator>::iterator_category,
2248 std::input_iterator_tag>::value,
2249 "");
2250 static_assert(
2251 std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::value_type,
2252 absl::string_view>::value,
2253 "");
2254 static_assert(
2255 std::is_same<
2256 std::iterator_traits<absl::Cord::ChunkIterator>::difference_type,
2257 ptrdiff_t>::value,
2258 "");
2259 static_assert(
2260 std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::pointer,
2261 const absl::string_view*>::value,
2262 "");
2263 static_assert(
2264 std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::reference,
2265 absl::string_view>::value,
2266 "");
2267 }
2268
VerifyChunkIterator(const absl::Cord & cord,size_t expected_chunks)2269 static void VerifyChunkIterator(const absl::Cord& cord,
2270 size_t expected_chunks) {
2271 EXPECT_EQ(cord.chunk_begin() == cord.chunk_end(), cord.empty()) << cord;
2272 EXPECT_EQ(cord.chunk_begin() != cord.chunk_end(), !cord.empty());
2273
2274 absl::Cord::ChunkRange range = cord.Chunks();
2275 EXPECT_EQ(range.begin() == range.end(), cord.empty());
2276 EXPECT_EQ(range.begin() != range.end(), !cord.empty());
2277
2278 std::string content(cord);
2279 size_t pos = 0;
2280 auto pre_iter = cord.chunk_begin(), post_iter = cord.chunk_begin();
2281 size_t n_chunks = 0;
2282 while (pre_iter != cord.chunk_end() && post_iter != cord.chunk_end()) {
2283 EXPECT_FALSE(pre_iter == cord.chunk_end()); // NOLINT: explicitly test ==
2284 EXPECT_FALSE(post_iter == cord.chunk_end()); // NOLINT
2285
2286 EXPECT_EQ(pre_iter, post_iter);
2287 EXPECT_EQ(*pre_iter, *post_iter);
2288
2289 EXPECT_EQ(pre_iter->data(), (*pre_iter).data());
2290 EXPECT_EQ(pre_iter->size(), (*pre_iter).size());
2291
2292 absl::string_view chunk = *pre_iter;
2293 EXPECT_FALSE(chunk.empty());
2294 EXPECT_LE(pos + chunk.size(), content.size());
2295 EXPECT_EQ(absl::string_view(content.c_str() + pos, chunk.size()), chunk);
2296
2297 int n_equal_iterators = 0;
2298 for (absl::Cord::ChunkIterator it = range.begin(); it != range.end();
2299 ++it) {
2300 n_equal_iterators += static_cast<int>(it == pre_iter);
2301 }
2302 EXPECT_EQ(n_equal_iterators, 1);
2303
2304 ++pre_iter;
2305 EXPECT_EQ(*post_iter++, chunk);
2306
2307 pos += chunk.size();
2308 ++n_chunks;
2309 }
2310 EXPECT_EQ(expected_chunks, n_chunks);
2311 EXPECT_EQ(pos, content.size());
2312 EXPECT_TRUE(pre_iter == cord.chunk_end()); // NOLINT: explicitly test ==
2313 EXPECT_TRUE(post_iter == cord.chunk_end()); // NOLINT
2314 }
2315
TEST_P(CordTest,CordChunkIteratorOperations)2316 TEST_P(CordTest, CordChunkIteratorOperations) {
2317 absl::Cord empty_cord;
2318 VerifyChunkIterator(empty_cord, 0);
2319
2320 absl::Cord small_buffer_cord("small cord");
2321 MaybeHarden(small_buffer_cord);
2322 VerifyChunkIterator(small_buffer_cord, 1);
2323
2324 absl::Cord flat_node_cord("larger than small buffer optimization");
2325 MaybeHarden(flat_node_cord);
2326 VerifyChunkIterator(flat_node_cord, 1);
2327
2328 VerifyChunkIterator(MaybeHardened(absl::MakeFragmentedCord(
2329 {"a ", "small ", "fragmented ", "cord ", "for ",
2330 "testing ", "chunk ", "iterations."})),
2331 8);
2332
2333 absl::Cord reused_nodes_cord(std::string(40, 'c'));
2334 reused_nodes_cord.Prepend(absl::Cord(std::string(40, 'b')));
2335 MaybeHarden(reused_nodes_cord);
2336 reused_nodes_cord.Prepend(absl::Cord(std::string(40, 'a')));
2337 size_t expected_chunks = 3;
2338 for (int i = 0; i < 8; ++i) {
2339 reused_nodes_cord.Prepend(reused_nodes_cord);
2340 MaybeHarden(reused_nodes_cord);
2341 expected_chunks *= 2;
2342 VerifyChunkIterator(reused_nodes_cord, expected_chunks);
2343 }
2344
2345 RandomEngine rng(GTEST_FLAG_GET(random_seed));
2346 absl::Cord flat_cord(RandomLowercaseString(&rng, 256));
2347 absl::Cord subcords;
2348 for (int i = 0; i < 128; ++i) subcords.Prepend(flat_cord.Subcord(i, 128));
2349 VerifyChunkIterator(subcords, 128);
2350 }
2351
2352
TEST_P(CordTest,AdvanceAndReadOnDataEdge)2353 TEST_P(CordTest, AdvanceAndReadOnDataEdge) {
2354 RandomEngine rng(GTEST_FLAG_GET(random_seed));
2355 const std::string data = RandomLowercaseString(&rng, 2000);
2356 for (bool as_flat : {true, false}) {
2357 SCOPED_TRACE(as_flat ? "Flat" : "External");
2358
2359 absl::Cord cord =
2360 as_flat ? absl::Cord(data)
2361 : absl::MakeCordFromExternal(data, [](absl::string_view) {});
2362 auto it = cord.Chars().begin();
2363 #if !defined(NDEBUG) || ABSL_OPTION_HARDENED
2364 EXPECT_DEATH_IF_SUPPORTED(cord.AdvanceAndRead(&it, 2001), ".*");
2365 #endif
2366
2367 it = cord.Chars().begin();
2368 absl::Cord frag = cord.AdvanceAndRead(&it, 2000);
2369 EXPECT_EQ(frag, data);
2370 EXPECT_TRUE(it == cord.Chars().end());
2371
2372 it = cord.Chars().begin();
2373 frag = cord.AdvanceAndRead(&it, 200);
2374 EXPECT_EQ(frag, data.substr(0, 200));
2375 EXPECT_FALSE(it == cord.Chars().end());
2376
2377 frag = cord.AdvanceAndRead(&it, 1500);
2378 EXPECT_EQ(frag, data.substr(200, 1500));
2379 EXPECT_FALSE(it == cord.Chars().end());
2380
2381 frag = cord.AdvanceAndRead(&it, 300);
2382 EXPECT_EQ(frag, data.substr(1700, 300));
2383 EXPECT_TRUE(it == cord.Chars().end());
2384 }
2385 }
2386
TEST_P(CordTest,AdvanceAndReadOnSubstringDataEdge)2387 TEST_P(CordTest, AdvanceAndReadOnSubstringDataEdge) {
2388 RandomEngine rng(GTEST_FLAG_GET(random_seed));
2389 const std::string data = RandomLowercaseString(&rng, 2500);
2390 for (bool as_flat : {true, false}) {
2391 SCOPED_TRACE(as_flat ? "Flat" : "External");
2392
2393 absl::Cord cord =
2394 as_flat ? absl::Cord(data)
2395 : absl::MakeCordFromExternal(data, [](absl::string_view) {});
2396 cord = cord.Subcord(200, 2000);
2397 const std::string substr = data.substr(200, 2000);
2398
2399 auto it = cord.Chars().begin();
2400 #if !defined(NDEBUG) || ABSL_OPTION_HARDENED
2401 EXPECT_DEATH_IF_SUPPORTED(cord.AdvanceAndRead(&it, 2001), ".*");
2402 #endif
2403
2404 it = cord.Chars().begin();
2405 absl::Cord frag = cord.AdvanceAndRead(&it, 2000);
2406 EXPECT_EQ(frag, substr);
2407 EXPECT_TRUE(it == cord.Chars().end());
2408
2409 it = cord.Chars().begin();
2410 frag = cord.AdvanceAndRead(&it, 200);
2411 EXPECT_EQ(frag, substr.substr(0, 200));
2412 EXPECT_FALSE(it == cord.Chars().end());
2413
2414 frag = cord.AdvanceAndRead(&it, 1500);
2415 EXPECT_EQ(frag, substr.substr(200, 1500));
2416 EXPECT_FALSE(it == cord.Chars().end());
2417
2418 frag = cord.AdvanceAndRead(&it, 300);
2419 EXPECT_EQ(frag, substr.substr(1700, 300));
2420 EXPECT_TRUE(it == cord.Chars().end());
2421 }
2422 }
2423
TEST_P(CordTest,CharIteratorTraits)2424 TEST_P(CordTest, CharIteratorTraits) {
2425 static_assert(std::is_copy_constructible<absl::Cord::CharIterator>::value,
2426 "");
2427 static_assert(std::is_copy_assignable<absl::Cord::CharIterator>::value, "");
2428
2429 // Move semantics to satisfy swappable via std::swap
2430 static_assert(std::is_move_constructible<absl::Cord::CharIterator>::value,
2431 "");
2432 static_assert(std::is_move_assignable<absl::Cord::CharIterator>::value, "");
2433
2434 static_assert(
2435 std::is_same<
2436 std::iterator_traits<absl::Cord::CharIterator>::iterator_category,
2437 std::input_iterator_tag>::value,
2438 "");
2439 static_assert(
2440 std::is_same<std::iterator_traits<absl::Cord::CharIterator>::value_type,
2441 char>::value,
2442 "");
2443 static_assert(
2444 std::is_same<
2445 std::iterator_traits<absl::Cord::CharIterator>::difference_type,
2446 ptrdiff_t>::value,
2447 "");
2448 static_assert(
2449 std::is_same<std::iterator_traits<absl::Cord::CharIterator>::pointer,
2450 const char*>::value,
2451 "");
2452 static_assert(
2453 std::is_same<std::iterator_traits<absl::Cord::CharIterator>::reference,
2454 const char&>::value,
2455 "");
2456 }
2457
VerifyCharIterator(const absl::Cord & cord)2458 static void VerifyCharIterator(const absl::Cord& cord) {
2459 EXPECT_EQ(cord.char_begin() == cord.char_end(), cord.empty());
2460 EXPECT_EQ(cord.char_begin() != cord.char_end(), !cord.empty());
2461
2462 absl::Cord::CharRange range = cord.Chars();
2463 EXPECT_EQ(range.begin() == range.end(), cord.empty());
2464 EXPECT_EQ(range.begin() != range.end(), !cord.empty());
2465
2466 size_t i = 0;
2467 absl::Cord::CharIterator pre_iter = cord.char_begin();
2468 absl::Cord::CharIterator post_iter = cord.char_begin();
2469 std::string content(cord);
2470 while (pre_iter != cord.char_end() && post_iter != cord.char_end()) {
2471 EXPECT_FALSE(pre_iter == cord.char_end()); // NOLINT: explicitly test ==
2472 EXPECT_FALSE(post_iter == cord.char_end()); // NOLINT
2473
2474 EXPECT_LT(i, cord.size());
2475 EXPECT_EQ(content[i], *pre_iter);
2476
2477 EXPECT_EQ(pre_iter, post_iter);
2478 EXPECT_EQ(*pre_iter, *post_iter);
2479 EXPECT_EQ(&*pre_iter, &*post_iter);
2480
2481 EXPECT_EQ(&*pre_iter, pre_iter.operator->());
2482
2483 const char* character_address = &*pre_iter;
2484 absl::Cord::CharIterator copy = pre_iter;
2485 ++copy;
2486 EXPECT_EQ(character_address, &*pre_iter);
2487
2488 int n_equal_iterators = 0;
2489 for (absl::Cord::CharIterator it = range.begin(); it != range.end(); ++it) {
2490 n_equal_iterators += static_cast<int>(it == pre_iter);
2491 }
2492 EXPECT_EQ(n_equal_iterators, 1);
2493
2494 absl::Cord::CharIterator advance_iter = range.begin();
2495 absl::Cord::Advance(&advance_iter, i);
2496 EXPECT_EQ(pre_iter, advance_iter);
2497
2498 advance_iter = range.begin();
2499 EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, i), cord.Subcord(0, i));
2500 EXPECT_EQ(pre_iter, advance_iter);
2501
2502 advance_iter = pre_iter;
2503 absl::Cord::Advance(&advance_iter, cord.size() - i);
2504 EXPECT_EQ(range.end(), advance_iter);
2505
2506 advance_iter = pre_iter;
2507 EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, cord.size() - i),
2508 cord.Subcord(i, cord.size() - i));
2509 EXPECT_EQ(range.end(), advance_iter);
2510
2511 ++i;
2512 ++pre_iter;
2513 post_iter++;
2514 }
2515 EXPECT_EQ(i, cord.size());
2516 EXPECT_TRUE(pre_iter == cord.char_end()); // NOLINT: explicitly test ==
2517 EXPECT_TRUE(post_iter == cord.char_end()); // NOLINT
2518
2519 absl::Cord::CharIterator zero_advanced_end = cord.char_end();
2520 absl::Cord::Advance(&zero_advanced_end, 0);
2521 EXPECT_EQ(zero_advanced_end, cord.char_end());
2522
2523 absl::Cord::CharIterator it = cord.char_begin();
2524 for (absl::string_view chunk : cord.Chunks()) {
2525 while (!chunk.empty()) {
2526 EXPECT_EQ(absl::Cord::ChunkRemaining(it), chunk);
2527 chunk.remove_prefix(1);
2528 ++it;
2529 }
2530 }
2531 }
2532
TEST_P(CordTest,CharIteratorOperations)2533 TEST_P(CordTest, CharIteratorOperations) {
2534 absl::Cord empty_cord;
2535 VerifyCharIterator(empty_cord);
2536
2537 absl::Cord small_buffer_cord("small cord");
2538 MaybeHarden(small_buffer_cord);
2539 VerifyCharIterator(small_buffer_cord);
2540
2541 absl::Cord flat_node_cord("larger than small buffer optimization");
2542 MaybeHarden(flat_node_cord);
2543 VerifyCharIterator(flat_node_cord);
2544
2545 VerifyCharIterator(MaybeHardened(
2546 absl::MakeFragmentedCord({"a ", "small ", "fragmented ", "cord ", "for ",
2547 "testing ", "character ", "iteration."})));
2548
2549 absl::Cord reused_nodes_cord("ghi");
2550 reused_nodes_cord.Prepend(absl::Cord("def"));
2551 reused_nodes_cord.Prepend(absl::Cord("abc"));
2552 for (int i = 0; i < 4; ++i) {
2553 reused_nodes_cord.Prepend(reused_nodes_cord);
2554 MaybeHarden(reused_nodes_cord);
2555 VerifyCharIterator(reused_nodes_cord);
2556 }
2557
2558 RandomEngine rng(GTEST_FLAG_GET(random_seed));
2559 absl::Cord flat_cord(RandomLowercaseString(&rng, 256));
2560 absl::Cord subcords;
2561 for (int i = 0; i < 4; ++i) {
2562 subcords.Prepend(flat_cord.Subcord(16 * i, 128));
2563 MaybeHarden(subcords);
2564 }
2565 VerifyCharIterator(subcords);
2566 }
2567
TEST_P(CordTest,CharIteratorAdvanceAndRead)2568 TEST_P(CordTest, CharIteratorAdvanceAndRead) {
2569 // Create a Cord holding 6 flats of 2500 bytes each, and then iterate over it
2570 // reading 150, 1500, 2500 and 3000 bytes. This will result in all possible
2571 // partial, full and straddled read combinations including reads below
2572 // kMaxBytesToCopy. b/197776822 surfaced a bug for a specific partial, small
2573 // read 'at end' on Cord which caused a failure on attempting to read past the
2574 // end in CordRepBtreeReader which was not covered by any existing test.
2575 constexpr int kBlocks = 6;
2576 constexpr size_t kBlockSize = 2500;
2577 constexpr size_t kChunkSize1 = 1500;
2578 constexpr size_t kChunkSize2 = 2500;
2579 constexpr size_t kChunkSize3 = 3000;
2580 constexpr size_t kChunkSize4 = 150;
2581 RandomEngine rng;
2582 std::string data = RandomLowercaseString(&rng, kBlocks * kBlockSize);
2583 absl::Cord cord;
2584 for (int i = 0; i < kBlocks; ++i) {
2585 const std::string block = data.substr(i * kBlockSize, kBlockSize);
2586 cord.Append(absl::Cord(block));
2587 }
2588
2589 MaybeHarden(cord);
2590
2591 for (size_t chunk_size :
2592 {kChunkSize1, kChunkSize2, kChunkSize3, kChunkSize4}) {
2593 absl::Cord::CharIterator it = cord.char_begin();
2594 size_t offset = 0;
2595 while (offset < data.length()) {
2596 const size_t n = std::min<size_t>(data.length() - offset, chunk_size);
2597 absl::Cord chunk = cord.AdvanceAndRead(&it, n);
2598 ASSERT_EQ(chunk.size(), n);
2599 ASSERT_EQ(chunk.Compare(data.substr(offset, n)), 0);
2600 offset += n;
2601 }
2602 }
2603 }
2604
TEST_P(CordTest,StreamingOutput)2605 TEST_P(CordTest, StreamingOutput) {
2606 absl::Cord c =
2607 absl::MakeFragmentedCord({"A ", "small ", "fragmented ", "Cord", "."});
2608 MaybeHarden(c);
2609 std::stringstream output;
2610 output << c;
2611 EXPECT_EQ("A small fragmented Cord.", output.str());
2612 }
2613
TEST_P(CordTest,ForEachChunk)2614 TEST_P(CordTest, ForEachChunk) {
2615 for (int num_elements : {1, 10, 200}) {
2616 SCOPED_TRACE(num_elements);
2617 std::vector<std::string> cord_chunks;
2618 for (int i = 0; i < num_elements; ++i) {
2619 cord_chunks.push_back(absl::StrCat("[", i, "]"));
2620 }
2621 absl::Cord c = absl::MakeFragmentedCord(cord_chunks);
2622 MaybeHarden(c);
2623
2624 std::vector<std::string> iterated_chunks;
2625 absl::CordTestPeer::ForEachChunk(c,
2626 [&iterated_chunks](absl::string_view sv) {
2627 iterated_chunks.emplace_back(sv);
2628 });
2629 EXPECT_EQ(iterated_chunks, cord_chunks);
2630 }
2631 }
2632
TEST_P(CordTest,SmallBufferAssignFromOwnData)2633 TEST_P(CordTest, SmallBufferAssignFromOwnData) {
2634 constexpr size_t kMaxInline = 15;
2635 std::string contents = "small buff cord";
2636 EXPECT_EQ(contents.size(), kMaxInline);
2637 for (size_t pos = 0; pos < contents.size(); ++pos) {
2638 for (size_t count = contents.size() - pos; count > 0; --count) {
2639 absl::Cord c(contents);
2640 MaybeHarden(c);
2641 absl::string_view flat = c.Flatten();
2642 c = flat.substr(pos, count);
2643 EXPECT_EQ(c, contents.substr(pos, count))
2644 << "pos = " << pos << "; count = " << count;
2645 }
2646 }
2647 }
2648
TEST_P(CordTest,Format)2649 TEST_P(CordTest, Format) {
2650 absl::Cord c;
2651 absl::Format(&c, "There were %04d little %s.", 3, "pigs");
2652 EXPECT_EQ(c, "There were 0003 little pigs.");
2653 MaybeHarden(c);
2654 absl::Format(&c, "And %-3llx bad wolf!", 1);
2655 MaybeHarden(c);
2656 EXPECT_EQ(c, "There were 0003 little pigs.And 1 bad wolf!");
2657 }
2658
TEST_P(CordTest,Stringify)2659 TEST_P(CordTest, Stringify) {
2660 absl::Cord c =
2661 absl::MakeFragmentedCord({"A ", "small ", "fragmented ", "Cord", "."});
2662 MaybeHarden(c);
2663 EXPECT_EQ(absl::StrCat(c), "A small fragmented Cord.");
2664 }
2665
TEST_P(CordTest,Hardening)2666 TEST_P(CordTest, Hardening) {
2667 absl::Cord cord("hello");
2668 MaybeHarden(cord);
2669
2670 // These statement should abort the program in all builds modes.
2671 EXPECT_DEATH_IF_SUPPORTED(cord.RemovePrefix(6), "");
2672 EXPECT_DEATH_IF_SUPPORTED(cord.RemoveSuffix(6), "");
2673
2674 bool test_hardening = false;
2675 ABSL_HARDENING_ASSERT([&]() {
2676 // This only runs when ABSL_HARDENING_ASSERT is active.
2677 test_hardening = true;
2678 return true;
2679 }());
2680 if (!test_hardening) return;
2681
2682 EXPECT_DEATH_IF_SUPPORTED(cord[5], "");
2683 EXPECT_DEATH_IF_SUPPORTED(*cord.chunk_end(), "");
2684 EXPECT_DEATH_IF_SUPPORTED(static_cast<void>(cord.chunk_end()->empty()), "");
2685 EXPECT_DEATH_IF_SUPPORTED(++cord.chunk_end(), "");
2686 }
2687
2688 // This test mimics a specific (and rare) application repeatedly splitting a
2689 // cord, inserting (overwriting) a string value, and composing a new cord from
2690 // the three pieces. This is hostile towards a Btree implementation: A split of
2691 // a node at any level is likely to have the right-most edge of the left split,
2692 // and the left-most edge of the right split shared. For example, splitting a
2693 // leaf node with 6 edges will result likely in a 1-6, 2-5, 3-4, etc. split,
2694 // sharing the 'split node'. When recomposing such nodes, we 'injected' an edge
2695 // in that node. As this happens with some probability on each level of the
2696 // tree, this will quickly grow the tree until it reaches maximum height.
TEST_P(CordTest,BtreeHostileSplitInsertJoin)2697 TEST_P(CordTest, BtreeHostileSplitInsertJoin) {
2698 absl::BitGen bitgen;
2699
2700 // Start with about 1GB of data
2701 std::string data(1 << 10, 'x');
2702 absl::Cord buffer(data);
2703 absl::Cord cord;
2704 for (int i = 0; i < 1000000; ++i) {
2705 cord.Append(buffer);
2706 }
2707
2708 for (int j = 0; j < 1000; ++j) {
2709 MaybeHarden(cord);
2710 size_t offset = absl::Uniform(bitgen, 0u, cord.size());
2711 size_t length = absl::Uniform(bitgen, 100u, data.size());
2712 if (cord.size() == offset) {
2713 cord.Append(absl::string_view(data.data(), length));
2714 } else {
2715 absl::Cord suffix;
2716 if (offset + length < cord.size()) {
2717 suffix = cord;
2718 suffix.RemovePrefix(offset + length);
2719 }
2720 if (cord.size() > offset) {
2721 cord.RemoveSuffix(cord.size() - offset);
2722 }
2723 cord.Append(absl::string_view(data.data(), length));
2724 if (!suffix.empty()) {
2725 cord.Append(suffix);
2726 }
2727 }
2728 }
2729 }
2730
2731 class AfterExitCordTester {
2732 public:
Set(absl::Cord * cord,absl::string_view expected)2733 bool Set(absl::Cord* cord, absl::string_view expected) {
2734 cord_ = cord;
2735 expected_ = expected;
2736 return true;
2737 }
2738
~AfterExitCordTester()2739 ~AfterExitCordTester() {
2740 EXPECT_EQ(*cord_, expected_);
2741 }
2742 private:
2743 absl::Cord* cord_;
2744 absl::string_view expected_;
2745 };
2746
2747 // Deliberately prevents the destructor for an absl::Cord from running. The cord
2748 // is accessible via the cord member during the lifetime of the CordLeaker.
2749 // After the CordLeaker is destroyed, pointers to the cord will remain valid
2750 // until the CordLeaker's memory is deallocated.
2751 struct CordLeaker {
2752 union {
2753 absl::Cord cord;
2754 };
2755
2756 template <typename Str>
CordLeakerCordLeaker2757 constexpr explicit CordLeaker(const Str& str) : cord(str) {}
2758
~CordLeakerCordLeaker2759 ~CordLeaker() {
2760 // Don't do anything, including running cord's destructor. (cord's
2761 // destructor won't run automatically because cord is hidden inside a
2762 // union.)
2763 }
2764 };
2765
2766 template <typename Str>
TestConstinitConstructor(Str)2767 void TestConstinitConstructor(Str) {
2768 const auto expected = Str::value;
2769 // Defined before `cord` to be destroyed after it.
2770 static AfterExitCordTester exit_tester; // NOLINT
2771 ABSL_CONST_INIT static CordLeaker cord_leaker(Str{}); // NOLINT
2772 // cord_leaker is static, so this reference will remain valid through the end
2773 // of program execution.
2774 static absl::Cord& cord = cord_leaker.cord;
2775 static bool init_exit_tester = exit_tester.Set(&cord, expected);
2776 (void)init_exit_tester;
2777
2778 EXPECT_EQ(cord, expected);
2779 // Copy the object and test the copy, and the original.
2780 {
2781 absl::Cord copy = cord;
2782 EXPECT_EQ(copy, expected);
2783 }
2784 // The original still works
2785 EXPECT_EQ(cord, expected);
2786
2787 // Try making adding more structure to the tree.
2788 {
2789 absl::Cord copy = cord;
2790 std::string expected_copy(expected);
2791 for (int i = 0; i < 10; ++i) {
2792 copy.Append(cord);
2793 absl::StrAppend(&expected_copy, expected);
2794 EXPECT_EQ(copy, expected_copy);
2795 }
2796 }
2797
2798 // Make sure we are using the right branch during constant evaluation.
2799 EXPECT_EQ(absl::CordTestPeer::IsTree(cord), cord.size() >= 16);
2800
2801 for (int i = 0; i < 10; ++i) {
2802 // Make a few more Cords from the same global rep.
2803 // This tests what happens when the refcount for it gets below 1.
2804 EXPECT_EQ(expected, absl::Cord(Str{}));
2805 }
2806 }
2807
SimpleStrlen(const char * p)2808 constexpr int SimpleStrlen(const char* p) {
2809 return *p ? 1 + SimpleStrlen(p + 1) : 0;
2810 }
2811
2812 struct ShortView {
operator ()ShortView2813 constexpr absl::string_view operator()() const {
2814 return absl::string_view("SSO string", SimpleStrlen("SSO string"));
2815 }
2816 };
2817
2818 struct LongView {
operator ()LongView2819 constexpr absl::string_view operator()() const {
2820 return absl::string_view("String that does not fit SSO.",
2821 SimpleStrlen("String that does not fit SSO."));
2822 }
2823 };
2824
2825
TEST_P(CordTest,ConstinitConstructor)2826 TEST_P(CordTest, ConstinitConstructor) {
2827 TestConstinitConstructor(
2828 absl::strings_internal::MakeStringConstant(ShortView{}));
2829 TestConstinitConstructor(
2830 absl::strings_internal::MakeStringConstant(LongView{}));
2831 }
2832
2833 namespace {
2834
2835 // Test helper that generates a populated cord for future manipulation.
2836 //
2837 // By test convention, all generated cords begin with the characters "abcde" at
2838 // the start of the first chunk.
2839 class PopulatedCordFactory {
2840 public:
PopulatedCordFactory(absl::string_view name,absl::Cord (* generator)())2841 constexpr PopulatedCordFactory(absl::string_view name,
2842 absl::Cord (*generator)())
2843 : name_(name), generator_(generator) {}
2844
Name() const2845 absl::string_view Name() const { return name_; }
Generate() const2846 absl::Cord Generate() const { return generator_(); }
2847
2848 private:
2849 absl::string_view name_;
2850 absl::Cord (*generator_)();
2851 };
2852
2853 // clang-format off
2854 // This array is constant-initialized in conformant compilers.
2855 PopulatedCordFactory cord_factories[] = {
__anond64eef591f02null2856 {"sso", [] { return absl::Cord("abcde"); }},
__anond64eef592002null2857 {"flat", [] {
2858 // Too large to live in SSO space, but small enough to be a simple FLAT.
2859 absl::Cord flat(absl::StrCat("abcde", std::string(1000, 'x')));
2860 flat.Flatten();
2861 return flat;
2862 }},
__anond64eef592102null2863 {"external", [] {
2864 // A cheat: we are using a string literal as the external storage, so a
2865 // no-op releaser is correct here.
2866 return absl::MakeCordFromExternal("abcde External!", []{});
2867 }},
__anond64eef592302null2868 {"external substring", [] {
2869 // A cheat: we are using a string literal as the external storage, so a
2870 // no-op releaser is correct here.
2871 absl::Cord ext = absl::MakeCordFromExternal("-abcde External!", []{});
2872 return absl::CordTestPeer::MakeSubstring(ext, 1, ext.size() - 1);
2873 }},
__anond64eef592502null2874 {"substring", [] {
2875 absl::Cord flat(absl::StrCat("-abcde", std::string(1000, 'x')));
2876 flat.Flatten();
2877 return flat.Subcord(1, 998);
2878 }},
__anond64eef592602null2879 {"fragmented", [] {
2880 std::string fragment = absl::StrCat("abcde", std::string(195, 'x'));
2881 std::vector<std::string> fragments(200, fragment);
2882 absl::Cord cord = absl::MakeFragmentedCord(fragments);
2883 assert(cord.size() == 40000);
2884 return cord;
2885 }},
2886 };
2887 // clang-format on
2888
2889 // Test helper that can mutate a cord, and possibly undo the mutation, for
2890 // testing.
2891 class CordMutator {
2892 public:
CordMutator(absl::string_view name,void (* mutate)(absl::Cord &),void (* undo)(absl::Cord &)=nullptr)2893 constexpr CordMutator(absl::string_view name, void (*mutate)(absl::Cord&),
2894 void (*undo)(absl::Cord&) = nullptr)
2895 : name_(name), mutate_(mutate), undo_(undo) {}
2896
Name() const2897 absl::string_view Name() const { return name_; }
Mutate(absl::Cord & cord) const2898 void Mutate(absl::Cord& cord) const { mutate_(cord); }
CanUndo() const2899 bool CanUndo() const { return undo_ != nullptr; }
Undo(absl::Cord & cord) const2900 void Undo(absl::Cord& cord) const { undo_(cord); }
2901
2902 private:
2903 absl::string_view name_;
2904 void (*mutate_)(absl::Cord&);
2905 void (*undo_)(absl::Cord&);
2906 };
2907
2908 // clang-format off
2909 // This array is constant-initialized in conformant compilers.
2910 CordMutator cord_mutators[] = {
__anond64eef592702() 2911 {"clear", [](absl::Cord& c) { c.Clear(); }},
__anond64eef592802() 2912 {"overwrite", [](absl::Cord& c) { c = "overwritten"; }},
2913 {
2914 "append string",
__anond64eef592902() 2915 [](absl::Cord& c) { c.Append("0123456789"); },
__anond64eef592a02() 2916 [](absl::Cord& c) { c.RemoveSuffix(10); }
2917 },
2918 {
2919 "append cord",
__anond64eef592b02() 2920 [](absl::Cord& c) {
2921 c.Append(absl::MakeFragmentedCord({"12345", "67890"}));
2922 },
__anond64eef592c02() 2923 [](absl::Cord& c) { c.RemoveSuffix(10); }
2924 },
2925 {
2926 "append checksummed cord",
__anond64eef592d02() 2927 [](absl::Cord& c) {
2928 absl::Cord to_append = absl::MakeFragmentedCord({"12345", "67890"});
2929 to_append.SetExpectedChecksum(999);
2930 c.Append(to_append);
2931 },
__anond64eef592e02() 2932 [](absl::Cord& c) { c.RemoveSuffix(10); }
2933 },
2934 {
2935 "append self",
__anond64eef592f02() 2936 [](absl::Cord& c) { c.Append(c); },
__anond64eef593002() 2937 [](absl::Cord& c) { c.RemoveSuffix(c.size() / 2); }
2938 },
2939 {
2940 "append empty string",
__anond64eef593102() 2941 [](absl::Cord& c) { c.Append(""); },
__anond64eef593202() 2942 [](absl::Cord& c) { }
2943 },
2944 {
2945 "append empty cord",
__anond64eef593302() 2946 [](absl::Cord& c) { c.Append(absl::Cord()); },
__anond64eef593402() 2947 [](absl::Cord& c) { }
2948 },
2949 {
2950 "append empty checksummed cord",
__anond64eef593502() 2951 [](absl::Cord& c) {
2952 absl::Cord to_append;
2953 to_append.SetExpectedChecksum(999);
2954 c.Append(to_append);
2955 },
__anond64eef593602() 2956 [](absl::Cord& c) { }
2957 },
2958 {
2959 "prepend string",
__anond64eef593702() 2960 [](absl::Cord& c) { c.Prepend("9876543210"); },
__anond64eef593802() 2961 [](absl::Cord& c) { c.RemovePrefix(10); }
2962 },
2963 {
2964 "prepend cord",
__anond64eef593902() 2965 [](absl::Cord& c) {
2966 c.Prepend(absl::MakeFragmentedCord({"98765", "43210"}));
2967 },
__anond64eef593a02() 2968 [](absl::Cord& c) { c.RemovePrefix(10); }
2969 },
2970 {
2971 "prepend checksummed cord",
__anond64eef593b02() 2972 [](absl::Cord& c) {
2973 absl::Cord to_prepend = absl::MakeFragmentedCord({"98765", "43210"});
2974 to_prepend.SetExpectedChecksum(999);
2975 c.Prepend(to_prepend);
2976 },
__anond64eef593c02() 2977 [](absl::Cord& c) { c.RemovePrefix(10); }
2978 },
2979 {
2980 "prepend empty string",
__anond64eef593d02() 2981 [](absl::Cord& c) { c.Prepend(""); },
__anond64eef593e02() 2982 [](absl::Cord& c) { }
2983 },
2984 {
2985 "prepend empty cord",
__anond64eef593f02() 2986 [](absl::Cord& c) { c.Prepend(absl::Cord()); },
__anond64eef594002() 2987 [](absl::Cord& c) { }
2988 },
2989 {
2990 "prepend empty checksummed cord",
__anond64eef594102() 2991 [](absl::Cord& c) {
2992 absl::Cord to_prepend;
2993 to_prepend.SetExpectedChecksum(999);
2994 c.Prepend(to_prepend);
2995 },
__anond64eef594202() 2996 [](absl::Cord& c) { }
2997 },
2998 {
2999 "prepend self",
__anond64eef594302() 3000 [](absl::Cord& c) { c.Prepend(c); },
__anond64eef594402() 3001 [](absl::Cord& c) { c.RemovePrefix(c.size() / 2); }
3002 },
__anond64eef594502() 3003 {"remove prefix", [](absl::Cord& c) { c.RemovePrefix(c.size() / 2); }},
__anond64eef594602() 3004 {"remove suffix", [](absl::Cord& c) { c.RemoveSuffix(c.size() / 2); }},
__anond64eef594702() 3005 {"remove 0-prefix", [](absl::Cord& c) { c.RemovePrefix(0); }},
__anond64eef594802() 3006 {"remove 0-suffix", [](absl::Cord& c) { c.RemoveSuffix(0); }},
__anond64eef594902() 3007 {"subcord", [](absl::Cord& c) { c = c.Subcord(1, c.size() - 2); }},
3008 {
3009 "swap inline",
__anond64eef594a02() 3010 [](absl::Cord& c) {
3011 absl::Cord other("swap");
3012 c.swap(other);
3013 }
3014 },
3015 {
3016 "swap tree",
__anond64eef594b02() 3017 [](absl::Cord& c) {
3018 absl::Cord other(std::string(10000, 'x'));
3019 c.swap(other);
3020 }
3021 },
3022 };
3023 // clang-format on
3024 } // namespace
3025
TEST_P(CordTest,ExpectedChecksum)3026 TEST_P(CordTest, ExpectedChecksum) {
3027 for (const PopulatedCordFactory& factory : cord_factories) {
3028 SCOPED_TRACE(factory.Name());
3029 for (bool shared : {false, true}) {
3030 SCOPED_TRACE(shared);
3031
3032 absl::Cord shared_cord_source = factory.Generate();
3033 auto make_instance = [=] {
3034 return shared ? shared_cord_source : factory.Generate();
3035 };
3036
3037 const absl::Cord base_value = factory.Generate();
3038 const std::string base_value_as_string(factory.Generate().Flatten());
3039
3040 absl::Cord c1 = make_instance();
3041 EXPECT_FALSE(c1.ExpectedChecksum().has_value());
3042
3043 // Setting an expected checksum works, and retains the cord's bytes
3044 c1.SetExpectedChecksum(12345);
3045 EXPECT_EQ(c1.ExpectedChecksum().value_or(0), 12345);
3046 EXPECT_EQ(c1, base_value);
3047
3048 // Test that setting an expected checksum again doesn't crash or leak
3049 // memory.
3050 c1.SetExpectedChecksum(12345);
3051 EXPECT_EQ(c1.ExpectedChecksum().value_or(0), 12345);
3052 EXPECT_EQ(c1, base_value);
3053
3054 // CRC persists through copies, assignments, and moves:
3055 absl::Cord c1_copy_construct = c1;
3056 EXPECT_EQ(c1_copy_construct.ExpectedChecksum().value_or(0), 12345);
3057
3058 absl::Cord c1_copy_assign;
3059 c1_copy_assign = c1;
3060 EXPECT_EQ(c1_copy_assign.ExpectedChecksum().value_or(0), 12345);
3061
3062 absl::Cord c1_move(std::move(c1_copy_assign));
3063 EXPECT_EQ(c1_move.ExpectedChecksum().value_or(0), 12345);
3064
3065 EXPECT_EQ(c1.ExpectedChecksum().value_or(0), 12345);
3066
3067 // A CRC Cord compares equal to its non-CRC value.
3068 EXPECT_EQ(c1, make_instance());
3069
3070 for (const CordMutator& mutator : cord_mutators) {
3071 SCOPED_TRACE(mutator.Name());
3072
3073 // Test that mutating a cord removes its stored checksum
3074 absl::Cord c2 = make_instance();
3075 c2.SetExpectedChecksum(24680);
3076
3077 mutator.Mutate(c2);
3078
3079 if (c1 == c2) {
3080 // Not a mutation (for example, appending the empty string).
3081 // Whether the checksum is removed is not defined.
3082 continue;
3083 }
3084
3085 EXPECT_EQ(c2.ExpectedChecksum(), absl::nullopt);
3086
3087 if (mutator.CanUndo()) {
3088 // Undoing an operation should not restore the checksum
3089 mutator.Undo(c2);
3090 EXPECT_EQ(c2, base_value);
3091 EXPECT_EQ(c2.ExpectedChecksum(), absl::nullopt);
3092 }
3093 }
3094
3095 absl::Cord c3 = make_instance();
3096 c3.SetExpectedChecksum(999);
3097 const absl::Cord& cc3 = c3;
3098
3099 // Test that all cord reading operations function in the face of an
3100 // expected checksum.
3101
3102 // Test data precondition
3103 ASSERT_TRUE(cc3.StartsWith("abcde"));
3104
3105 EXPECT_EQ(cc3.size(), base_value_as_string.size());
3106 EXPECT_FALSE(cc3.empty());
3107 EXPECT_EQ(cc3.Compare(base_value), 0);
3108 EXPECT_EQ(cc3.Compare(base_value_as_string), 0);
3109 EXPECT_EQ(cc3.Compare("wxyz"), -1);
3110 EXPECT_EQ(cc3.Compare(absl::Cord("wxyz")), -1);
3111 EXPECT_EQ(cc3.Compare("aaaa"), 1);
3112 EXPECT_EQ(cc3.Compare(absl::Cord("aaaa")), 1);
3113 EXPECT_EQ(absl::Cord("wxyz").Compare(cc3), 1);
3114 EXPECT_EQ(absl::Cord("aaaa").Compare(cc3), -1);
3115 EXPECT_TRUE(cc3.StartsWith("abcd"));
3116 EXPECT_EQ(std::string(cc3), base_value_as_string);
3117
3118 std::string dest;
3119 absl::CopyCordToString(cc3, &dest);
3120 EXPECT_EQ(dest, base_value_as_string);
3121
3122 bool first_pass = true;
3123 for (absl::string_view chunk : cc3.Chunks()) {
3124 if (first_pass) {
3125 EXPECT_TRUE(absl::StartsWith(chunk, "abcde"));
3126 }
3127 first_pass = false;
3128 }
3129 first_pass = true;
3130 for (char ch : cc3.Chars()) {
3131 if (first_pass) {
3132 EXPECT_EQ(ch, 'a');
3133 }
3134 first_pass = false;
3135 }
3136 EXPECT_TRUE(absl::StartsWith(*cc3.chunk_begin(), "abcde"));
3137 EXPECT_EQ(*cc3.char_begin(), 'a');
3138
3139 auto char_it = cc3.char_begin();
3140 absl::Cord::Advance(&char_it, 2);
3141 EXPECT_EQ(absl::Cord::AdvanceAndRead(&char_it, 2), "cd");
3142 EXPECT_EQ(*char_it, 'e');
3143 char_it = cc3.char_begin();
3144 absl::Cord::Advance(&char_it, 2);
3145 EXPECT_TRUE(absl::StartsWith(absl::Cord::ChunkRemaining(char_it), "cde"));
3146
3147 EXPECT_EQ(cc3[0], 'a');
3148 EXPECT_EQ(cc3[4], 'e');
3149 EXPECT_EQ(absl::HashOf(cc3), absl::HashOf(base_value));
3150 EXPECT_EQ(absl::HashOf(cc3), absl::HashOf(base_value_as_string));
3151 }
3152 }
3153 }
3154
3155 // Test the special cases encountered with an empty checksummed cord.
TEST_P(CordTest,ChecksummedEmptyCord)3156 TEST_P(CordTest, ChecksummedEmptyCord) {
3157 absl::Cord c1;
3158 EXPECT_FALSE(c1.ExpectedChecksum().has_value());
3159
3160 // Setting an expected checksum works.
3161 c1.SetExpectedChecksum(12345);
3162 EXPECT_EQ(c1.ExpectedChecksum().value_or(0), 12345);
3163 EXPECT_EQ(c1, "");
3164 EXPECT_TRUE(c1.empty());
3165
3166 // Test that setting an expected checksum again doesn't crash or leak memory.
3167 c1.SetExpectedChecksum(12345);
3168 EXPECT_EQ(c1.ExpectedChecksum().value_or(0), 12345);
3169 EXPECT_EQ(c1, "");
3170 EXPECT_TRUE(c1.empty());
3171
3172 // CRC persists through copies, assignments, and moves:
3173 absl::Cord c1_copy_construct = c1;
3174 EXPECT_EQ(c1_copy_construct.ExpectedChecksum().value_or(0), 12345);
3175
3176 absl::Cord c1_copy_assign;
3177 c1_copy_assign = c1;
3178 EXPECT_EQ(c1_copy_assign.ExpectedChecksum().value_or(0), 12345);
3179
3180 absl::Cord c1_move(std::move(c1_copy_assign));
3181 EXPECT_EQ(c1_move.ExpectedChecksum().value_or(0), 12345);
3182
3183 EXPECT_EQ(c1.ExpectedChecksum().value_or(0), 12345);
3184
3185 // A CRC Cord compares equal to its non-CRC value.
3186 EXPECT_EQ(c1, absl::Cord());
3187
3188 for (const CordMutator& mutator : cord_mutators) {
3189 SCOPED_TRACE(mutator.Name());
3190
3191 // Exercise mutating an empty checksummed cord to catch crashes and exercise
3192 // memory sanitizers.
3193 absl::Cord c2;
3194 c2.SetExpectedChecksum(24680);
3195 mutator.Mutate(c2);
3196
3197 if (c2.empty()) {
3198 // Not a mutation
3199 continue;
3200 }
3201 EXPECT_EQ(c2.ExpectedChecksum(), absl::nullopt);
3202
3203 if (mutator.CanUndo()) {
3204 mutator.Undo(c2);
3205 }
3206 }
3207
3208 absl::Cord c3;
3209 c3.SetExpectedChecksum(999);
3210 const absl::Cord& cc3 = c3;
3211
3212 // Test that all cord reading operations function in the face of an
3213 // expected checksum.
3214 EXPECT_TRUE(cc3.StartsWith(""));
3215 EXPECT_TRUE(cc3.EndsWith(""));
3216 EXPECT_TRUE(cc3.empty());
3217 EXPECT_EQ(cc3, "");
3218 EXPECT_EQ(cc3, absl::Cord());
3219 EXPECT_EQ(cc3.size(), 0);
3220 EXPECT_EQ(cc3.Compare(absl::Cord()), 0);
3221 EXPECT_EQ(cc3.Compare(c1), 0);
3222 EXPECT_EQ(cc3.Compare(cc3), 0);
3223 EXPECT_EQ(cc3.Compare(""), 0);
3224 EXPECT_EQ(cc3.Compare("wxyz"), -1);
3225 EXPECT_EQ(cc3.Compare(absl::Cord("wxyz")), -1);
3226 EXPECT_EQ(absl::Cord("wxyz").Compare(cc3), 1);
3227 EXPECT_EQ(std::string(cc3), "");
3228
3229 std::string dest;
3230 absl::CopyCordToString(cc3, &dest);
3231 EXPECT_EQ(dest, "");
3232
3233 for (absl::string_view chunk : cc3.Chunks()) { // NOLINT(unreachable loop)
3234 static_cast<void>(chunk);
3235 GTEST_FAIL() << "no chunks expected";
3236 }
3237 EXPECT_TRUE(cc3.chunk_begin() == cc3.chunk_end());
3238
3239 for (char ch : cc3.Chars()) { // NOLINT(unreachable loop)
3240 static_cast<void>(ch);
3241 GTEST_FAIL() << "no chars expected";
3242 }
3243 EXPECT_TRUE(cc3.char_begin() == cc3.char_end());
3244
3245 EXPECT_EQ(cc3.TryFlat(), "");
3246 EXPECT_EQ(absl::HashOf(c3), absl::HashOf(absl::Cord()));
3247 EXPECT_EQ(absl::HashOf(c3), absl::HashOf(absl::string_view()));
3248 }
3249
TEST(CrcCordTest,ChecksummedEmptyCordEstimateMemoryUsage)3250 TEST(CrcCordTest, ChecksummedEmptyCordEstimateMemoryUsage) {
3251 absl::Cord cord;
3252 cord.SetExpectedChecksum(0);
3253 EXPECT_NE(cord.EstimatedMemoryUsage(), 0);
3254 }
3255
3256 #if defined(GTEST_HAS_DEATH_TEST) && defined(ABSL_INTERNAL_CORD_HAVE_SANITIZER)
3257
3258 // Returns an expected poison / uninitialized death message expression.
MASanDeathExpr()3259 const char* MASanDeathExpr() {
3260 return "(use-after-poison|use-of-uninitialized-value)";
3261 }
3262
TEST(CordSanitizerTest,SanitizesEmptyCord)3263 TEST(CordSanitizerTest, SanitizesEmptyCord) {
3264 absl::Cord cord;
3265 const char* data = cord.Flatten().data();
3266 EXPECT_DEATH(EXPECT_EQ(data[0], 0), MASanDeathExpr());
3267 }
3268
TEST(CordSanitizerTest,SanitizesSmallCord)3269 TEST(CordSanitizerTest, SanitizesSmallCord) {
3270 absl::Cord cord("Hello");
3271 const char* data = cord.Flatten().data();
3272 EXPECT_DEATH(EXPECT_EQ(data[5], 0), MASanDeathExpr());
3273 }
3274
TEST(CordSanitizerTest,SanitizesCordOnSetSSOValue)3275 TEST(CordSanitizerTest, SanitizesCordOnSetSSOValue) {
3276 absl::Cord cord("String that is too big to be an SSO value");
3277 cord = "Hello";
3278 const char* data = cord.Flatten().data();
3279 EXPECT_DEATH(EXPECT_EQ(data[5], 0), MASanDeathExpr());
3280 }
3281
TEST(CordSanitizerTest,SanitizesCordOnCopyCtor)3282 TEST(CordSanitizerTest, SanitizesCordOnCopyCtor) {
3283 absl::Cord src("hello");
3284 absl::Cord dst(src);
3285 const char* data = dst.Flatten().data();
3286 EXPECT_DEATH(EXPECT_EQ(data[5], 0), MASanDeathExpr());
3287 }
3288
TEST(CordSanitizerTest,SanitizesCordOnMoveCtor)3289 TEST(CordSanitizerTest, SanitizesCordOnMoveCtor) {
3290 absl::Cord src("hello");
3291 absl::Cord dst(std::move(src));
3292 const char* data = dst.Flatten().data();
3293 EXPECT_DEATH(EXPECT_EQ(data[5], 0), MASanDeathExpr());
3294 }
3295
TEST(CordSanitizerTest,SanitizesCordOnAssign)3296 TEST(CordSanitizerTest, SanitizesCordOnAssign) {
3297 absl::Cord src("hello");
3298 absl::Cord dst;
3299 dst = src;
3300 const char* data = dst.Flatten().data();
3301 EXPECT_DEATH(EXPECT_EQ(data[5], 0), MASanDeathExpr());
3302 }
3303
TEST(CordSanitizerTest,SanitizesCordOnMoveAssign)3304 TEST(CordSanitizerTest, SanitizesCordOnMoveAssign) {
3305 absl::Cord src("hello");
3306 absl::Cord dst;
3307 dst = std::move(src);
3308 const char* data = dst.Flatten().data();
3309 EXPECT_DEATH(EXPECT_EQ(data[5], 0), MASanDeathExpr());
3310 }
3311
TEST(CordSanitizerTest,SanitizesCordOnSsoAssign)3312 TEST(CordSanitizerTest, SanitizesCordOnSsoAssign) {
3313 absl::Cord src("hello");
3314 absl::Cord dst("String that is too big to be an SSO value");
3315 dst = src;
3316 const char* data = dst.Flatten().data();
3317 EXPECT_DEATH(EXPECT_EQ(data[5], 0), MASanDeathExpr());
3318 }
3319
3320 #endif // GTEST_HAS_DEATH_TEST && ABSL_INTERNAL_CORD_HAVE_SANITIZER
3321