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