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