• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "absl/strings/cord.h"
2 
3 #include <algorithm>
4 #include <climits>
5 #include <cstdio>
6 #include <iterator>
7 #include <map>
8 #include <numeric>
9 #include <random>
10 #include <sstream>
11 #include <type_traits>
12 #include <utility>
13 #include <vector>
14 
15 #include "gmock/gmock.h"
16 #include "gtest/gtest.h"
17 #include "absl/base/casts.h"
18 #include "absl/base/config.h"
19 #include "absl/base/internal/endian.h"
20 #include "absl/base/internal/raw_logging.h"
21 #include "absl/container/fixed_array.h"
22 #include "absl/strings/cord_test_helpers.h"
23 #include "absl/strings/str_cat.h"
24 #include "absl/strings/string_view.h"
25 
26 typedef std::mt19937_64 RandomEngine;
27 
28 static std::string RandomLowercaseString(RandomEngine* rng);
29 static std::string RandomLowercaseString(RandomEngine* rng, size_t length);
30 
GetUniformRandomUpTo(RandomEngine * rng,int upper_bound)31 static int GetUniformRandomUpTo(RandomEngine* rng, int upper_bound) {
32   if (upper_bound > 0) {
33     std::uniform_int_distribution<int> uniform(0, upper_bound - 1);
34     return uniform(*rng);
35   } else {
36     return 0;
37   }
38 }
39 
GetUniformRandomUpTo(RandomEngine * rng,size_t upper_bound)40 static size_t GetUniformRandomUpTo(RandomEngine* rng, size_t upper_bound) {
41   if (upper_bound > 0) {
42     std::uniform_int_distribution<size_t> uniform(0, upper_bound - 1);
43     return uniform(*rng);
44   } else {
45     return 0;
46   }
47 }
48 
GenerateSkewedRandom(RandomEngine * rng,int max_log)49 static int32_t GenerateSkewedRandom(RandomEngine* rng, int max_log) {
50   const uint32_t base = (*rng)() % (max_log + 1);
51   const uint32_t mask = ((base < 32) ? (1u << base) : 0u) - 1u;
52   return (*rng)() & mask;
53 }
54 
RandomLowercaseString(RandomEngine * rng)55 static std::string RandomLowercaseString(RandomEngine* rng) {
56   int length;
57   std::bernoulli_distribution one_in_1k(0.001);
58   std::bernoulli_distribution one_in_10k(0.0001);
59   // With low probability, make a large fragment
60   if (one_in_10k(*rng)) {
61     length = GetUniformRandomUpTo(rng, 1048576);
62   } else if (one_in_1k(*rng)) {
63     length = GetUniformRandomUpTo(rng, 10000);
64   } else {
65     length = GenerateSkewedRandom(rng, 10);
66   }
67   return RandomLowercaseString(rng, length);
68 }
69 
RandomLowercaseString(RandomEngine * rng,size_t length)70 static std::string RandomLowercaseString(RandomEngine* rng, size_t length) {
71   std::string result(length, '\0');
72   std::uniform_int_distribution<int> chars('a', 'z');
73   std::generate(result.begin(), result.end(), [&]() {
74     return static_cast<char>(chars(*rng));
75   });
76   return result;
77 }
78 
DoNothing(absl::string_view,void *)79 static void DoNothing(absl::string_view /* data */, void* /* arg */) {}
80 
DeleteExternalString(absl::string_view data,void * arg)81 static void DeleteExternalString(absl::string_view data, void* arg) {
82   std::string* s = reinterpret_cast<std::string*>(arg);
83   EXPECT_EQ(data, *s);
84   delete s;
85 }
86 
87 // Add "s" to *dst via `MakeCordFromExternal`
AddExternalMemory(absl::string_view s,absl::Cord * dst)88 static void AddExternalMemory(absl::string_view s, absl::Cord* dst) {
89   std::string* str = new std::string(s.data(), s.size());
90   dst->Append(absl::MakeCordFromExternal(*str, [str](absl::string_view data) {
91     DeleteExternalString(data, str);
92   }));
93 }
94 
DumpGrowth()95 static void DumpGrowth() {
96   absl::Cord str;
97   for (int i = 0; i < 1000; i++) {
98     char c = 'a' + i % 26;
99     str.Append(absl::string_view(&c, 1));
100   }
101 }
102 
103 // Make a Cord with some number of fragments.  Return the size (in bytes)
104 // of the smallest fragment.
AppendWithFragments(const std::string & s,RandomEngine * rng,absl::Cord * cord)105 static size_t AppendWithFragments(const std::string& s, RandomEngine* rng,
106                                   absl::Cord* cord) {
107   size_t j = 0;
108   const size_t max_size = s.size() / 5;  // Make approx. 10 fragments
109   size_t min_size = max_size;            // size of smallest fragment
110   while (j < s.size()) {
111     size_t N = 1 + GetUniformRandomUpTo(rng, max_size);
112     if (N > (s.size() - j)) {
113       N = s.size() - j;
114     }
115     if (N < min_size) {
116       min_size = N;
117     }
118 
119     std::bernoulli_distribution coin_flip(0.5);
120     if (coin_flip(*rng)) {
121       // Grow by adding an external-memory.
122       AddExternalMemory(absl::string_view(s.data() + j, N), cord);
123     } else {
124       cord->Append(absl::string_view(s.data() + j, N));
125     }
126     j += N;
127   }
128   return min_size;
129 }
130 
131 // Add an external memory that contains the specified std::string to cord
AddNewStringBlock(const std::string & str,absl::Cord * dst)132 static void AddNewStringBlock(const std::string& str, absl::Cord* dst) {
133   char* data = new char[str.size()];
134   memcpy(data, str.data(), str.size());
135   dst->Append(absl::MakeCordFromExternal(
136       absl::string_view(data, str.size()),
137       [](absl::string_view s) { delete[] s.data(); }));
138 }
139 
140 // Make a Cord out of many different types of nodes.
MakeComposite()141 static absl::Cord MakeComposite() {
142   absl::Cord cord;
143   cord.Append("the");
144   AddExternalMemory(" quick brown", &cord);
145   AddExternalMemory(" fox jumped", &cord);
146 
147   absl::Cord full(" over");
148   AddExternalMemory(" the lazy", &full);
149   AddNewStringBlock(" dog slept the whole day away", &full);
150   absl::Cord substring = full.Subcord(0, 18);
151 
152   // Make substring long enough to defeat the copying fast path in Append.
153   substring.Append(std::string(1000, '.'));
154   cord.Append(substring);
155   cord = cord.Subcord(0, cord.size() - 998);  // Remove most of extra junk
156 
157   return cord;
158 }
159 
160 namespace absl {
161 ABSL_NAMESPACE_BEGIN
162 
163 class CordTestPeer {
164  public:
ForEachChunk(const Cord & c,absl::FunctionRef<void (absl::string_view)> callback)165   static void ForEachChunk(
166       const Cord& c, absl::FunctionRef<void(absl::string_view)> callback) {
167     c.ForEachChunk(callback);
168   }
169 };
170 
171 ABSL_NAMESPACE_END
172 }  // namespace absl
173 
TEST(Cord,AllFlatSizes)174 TEST(Cord, AllFlatSizes) {
175   using absl::strings_internal::CordTestAccess;
176 
177   for (size_t s = 0; s < CordTestAccess::MaxFlatLength(); s++) {
178     // Make a std::string of length s.
179     std::string src;
180     while (src.size() < s) {
181       src.push_back('a' + (src.size() % 26));
182     }
183 
184     absl::Cord dst(src);
185     EXPECT_EQ(std::string(dst), src) << s;
186   }
187 }
188 
189 // We create a Cord at least 128GB in size using the fact that Cords can
190 // internally reference-count; thus the Cord is enormous without actually
191 // consuming very much memory.
TEST(GigabyteCord,FromExternal)192 TEST(GigabyteCord, FromExternal) {
193   const size_t one_gig = 1024U * 1024U * 1024U;
194   size_t max_size = 2 * one_gig;
195   if (sizeof(max_size) > 4) max_size = 128 * one_gig;
196 
197   size_t length = 128 * 1024;
198   char* data = new char[length];
199   absl::Cord from = absl::MakeCordFromExternal(
200       absl::string_view(data, length),
201       [](absl::string_view sv) { delete[] sv.data(); });
202 
203   // This loop may seem odd due to its combination of exponential doubling of
204   // size and incremental size increases.  We do it incrementally to be sure the
205   // Cord will need rebalancing and will exercise code that, in the past, has
206   // caused crashes in production.  We grow exponentially so that the code will
207   // execute in a reasonable amount of time.
208   absl::Cord c;
209   ABSL_RAW_LOG(INFO, "Made a Cord with %zu bytes!", c.size());
210   c.Append(from);
211   while (c.size() < max_size) {
212     c.Append(c);
213     c.Append(from);
214     c.Append(from);
215     c.Append(from);
216     c.Append(from);
217   }
218 
219   for (int i = 0; i < 1024; ++i) {
220     c.Append(from);
221   }
222   ABSL_RAW_LOG(INFO, "Made a Cord with %zu bytes!", c.size());
223   // Note: on a 32-bit build, this comes out to   2,818,048,000 bytes.
224   // Note: on a 64-bit build, this comes out to 171,932,385,280 bytes.
225 }
226 
MakeExternalCord(int size)227 static absl::Cord MakeExternalCord(int size) {
228   char* buffer = new char[size];
229   memset(buffer, 'x', size);
230   absl::Cord cord;
231   cord.Append(absl::MakeCordFromExternal(
232       absl::string_view(buffer, size),
233       [](absl::string_view s) { delete[] s.data(); }));
234   return cord;
235 }
236 
237 // Extern to fool clang that this is not constant. Needed to suppress
238 // a warning of unsafe code we want to test.
239 extern bool my_unique_true_boolean;
240 bool my_unique_true_boolean = true;
241 
TEST(Cord,Assignment)242 TEST(Cord, Assignment) {
243   absl::Cord x(absl::string_view("hi there"));
244   absl::Cord y(x);
245   ASSERT_EQ(std::string(x), "hi there");
246   ASSERT_EQ(std::string(y), "hi there");
247   ASSERT_TRUE(x == y);
248   ASSERT_TRUE(x <= y);
249   ASSERT_TRUE(y <= x);
250 
251   x = absl::string_view("foo");
252   ASSERT_EQ(std::string(x), "foo");
253   ASSERT_EQ(std::string(y), "hi there");
254   ASSERT_TRUE(x < y);
255   ASSERT_TRUE(y > x);
256   ASSERT_TRUE(x != y);
257   ASSERT_TRUE(x <= y);
258   ASSERT_TRUE(y >= x);
259 
260   x = "foo";
261   ASSERT_EQ(x, "foo");
262 
263   // Test that going from inline rep to tree we don't leak memory.
264   std::vector<std::pair<absl::string_view, absl::string_view>>
265       test_string_pairs = {{"hi there", "foo"},
266                            {"loooooong coooooord", "short cord"},
267                            {"short cord", "loooooong coooooord"},
268                            {"loooooong coooooord1", "loooooong coooooord2"}};
269   for (std::pair<absl::string_view, absl::string_view> test_strings :
270        test_string_pairs) {
271     absl::Cord tmp(test_strings.first);
272     absl::Cord z(std::move(tmp));
273     ASSERT_EQ(std::string(z), test_strings.first);
274     tmp = test_strings.second;
275     z = std::move(tmp);
276     ASSERT_EQ(std::string(z), test_strings.second);
277   }
278   {
279     // Test that self-move assignment doesn't crash/leak.
280     // Do not write such code!
281     absl::Cord my_small_cord("foo");
282     absl::Cord my_big_cord("loooooong coooooord");
283     // Bypass clang's warning on self move-assignment.
284     absl::Cord* my_small_alias =
285         my_unique_true_boolean ? &my_small_cord : &my_big_cord;
286     absl::Cord* my_big_alias =
287         !my_unique_true_boolean ? &my_small_cord : &my_big_cord;
288 
289     *my_small_alias = std::move(my_small_cord);
290     *my_big_alias = std::move(my_big_cord);
291     // my_small_cord and my_big_cord are in an unspecified but valid
292     // state, and will be correctly destroyed here.
293   }
294 }
295 
TEST(Cord,StartsEndsWith)296 TEST(Cord, StartsEndsWith) {
297   absl::Cord x(absl::string_view("abcde"));
298   absl::Cord empty("");
299 
300   ASSERT_TRUE(x.StartsWith(absl::Cord("abcde")));
301   ASSERT_TRUE(x.StartsWith(absl::Cord("abc")));
302   ASSERT_TRUE(x.StartsWith(absl::Cord("")));
303   ASSERT_TRUE(empty.StartsWith(absl::Cord("")));
304   ASSERT_TRUE(x.EndsWith(absl::Cord("abcde")));
305   ASSERT_TRUE(x.EndsWith(absl::Cord("cde")));
306   ASSERT_TRUE(x.EndsWith(absl::Cord("")));
307   ASSERT_TRUE(empty.EndsWith(absl::Cord("")));
308 
309   ASSERT_TRUE(!x.StartsWith(absl::Cord("xyz")));
310   ASSERT_TRUE(!empty.StartsWith(absl::Cord("xyz")));
311   ASSERT_TRUE(!x.EndsWith(absl::Cord("xyz")));
312   ASSERT_TRUE(!empty.EndsWith(absl::Cord("xyz")));
313 
314   ASSERT_TRUE(x.StartsWith("abcde"));
315   ASSERT_TRUE(x.StartsWith("abc"));
316   ASSERT_TRUE(x.StartsWith(""));
317   ASSERT_TRUE(empty.StartsWith(""));
318   ASSERT_TRUE(x.EndsWith("abcde"));
319   ASSERT_TRUE(x.EndsWith("cde"));
320   ASSERT_TRUE(x.EndsWith(""));
321   ASSERT_TRUE(empty.EndsWith(""));
322 
323   ASSERT_TRUE(!x.StartsWith("xyz"));
324   ASSERT_TRUE(!empty.StartsWith("xyz"));
325   ASSERT_TRUE(!x.EndsWith("xyz"));
326   ASSERT_TRUE(!empty.EndsWith("xyz"));
327 }
328 
TEST(Cord,Subcord)329 TEST(Cord, Subcord) {
330   RandomEngine rng(testing::GTEST_FLAG(random_seed));
331   const std::string s = RandomLowercaseString(&rng, 1024);
332 
333   absl::Cord a;
334   AppendWithFragments(s, &rng, &a);
335   ASSERT_EQ(s.size(), a.size());
336 
337   // Check subcords of a, from a variety of interesting points.
338   std::set<size_t> positions;
339   for (int i = 0; i <= 32; ++i) {
340     positions.insert(i);
341     positions.insert(i * 32 - 1);
342     positions.insert(i * 32);
343     positions.insert(i * 32 + 1);
344     positions.insert(a.size() - i);
345   }
346   positions.insert(237);
347   positions.insert(732);
348   for (size_t pos : positions) {
349     if (pos > a.size()) continue;
350     for (size_t end_pos : positions) {
351       if (end_pos < pos || end_pos > a.size()) continue;
352       absl::Cord sa = a.Subcord(pos, end_pos - pos);
353       EXPECT_EQ(absl::string_view(s).substr(pos, end_pos - pos),
354                 std::string(sa))
355           << a;
356     }
357   }
358 
359   // Do the same thing for an inline cord.
360   const std::string sh = "short";
361   absl::Cord c(sh);
362   for (size_t pos = 0; pos <= sh.size(); ++pos) {
363     for (size_t n = 0; n <= sh.size() - pos; ++n) {
364       absl::Cord sc = c.Subcord(pos, n);
365       EXPECT_EQ(sh.substr(pos, n), std::string(sc)) << c;
366     }
367   }
368 
369   // Check subcords of subcords.
370   absl::Cord sa = a.Subcord(0, a.size());
371   std::string ss = s.substr(0, s.size());
372   while (sa.size() > 1) {
373     sa = sa.Subcord(1, sa.size() - 2);
374     ss = ss.substr(1, ss.size() - 2);
375     EXPECT_EQ(ss, std::string(sa)) << a;
376     if (HasFailure()) break;  // halt cascade
377   }
378 
379   // It is OK to ask for too much.
380   sa = a.Subcord(0, a.size() + 1);
381   EXPECT_EQ(s, std::string(sa));
382 
383   // It is OK to ask for something beyond the end.
384   sa = a.Subcord(a.size() + 1, 0);
385   EXPECT_TRUE(sa.empty());
386   sa = a.Subcord(a.size() + 1, 1);
387   EXPECT_TRUE(sa.empty());
388 }
389 
TEST(Cord,Swap)390 TEST(Cord, Swap) {
391   absl::string_view a("Dexter");
392   absl::string_view b("Mandark");
393   absl::Cord x(a);
394   absl::Cord y(b);
395   swap(x, y);
396   ASSERT_EQ(x, absl::Cord(b));
397   ASSERT_EQ(y, absl::Cord(a));
398 }
399 
VerifyCopyToString(const absl::Cord & cord)400 static void VerifyCopyToString(const absl::Cord& cord) {
401   std::string initially_empty;
402   absl::CopyCordToString(cord, &initially_empty);
403   EXPECT_EQ(initially_empty, cord);
404 
405   constexpr size_t kInitialLength = 1024;
406   std::string has_initial_contents(kInitialLength, 'x');
407   const char* address_before_copy = has_initial_contents.data();
408   absl::CopyCordToString(cord, &has_initial_contents);
409   EXPECT_EQ(has_initial_contents, cord);
410 
411   if (cord.size() <= kInitialLength) {
412     EXPECT_EQ(has_initial_contents.data(), address_before_copy)
413         << "CopyCordToString allocated new std::string storage; "
414            "has_initial_contents = \""
415         << has_initial_contents << "\"";
416   }
417 }
418 
TEST(Cord,CopyToString)419 TEST(Cord, CopyToString) {
420   VerifyCopyToString(absl::Cord());
421   VerifyCopyToString(absl::Cord("small cord"));
422   VerifyCopyToString(
423       absl::MakeFragmentedCord({"fragmented ", "cord ", "to ", "test ",
424                                 "copying ", "to ", "a ", "string."}));
425 }
426 
IsFlat(const absl::Cord & c)427 static bool IsFlat(const absl::Cord& c) {
428   return c.chunk_begin() == c.chunk_end() || ++c.chunk_begin() == c.chunk_end();
429 }
430 
VerifyFlatten(absl::Cord c)431 static void VerifyFlatten(absl::Cord c) {
432   std::string old_contents(c);
433   absl::string_view old_flat;
434   bool already_flat_and_non_empty = IsFlat(c) && !c.empty();
435   if (already_flat_and_non_empty) {
436     old_flat = *c.chunk_begin();
437   }
438   absl::string_view new_flat = c.Flatten();
439 
440   // Verify that the contents of the flattened Cord are correct.
441   EXPECT_EQ(new_flat, old_contents);
442   EXPECT_EQ(std::string(c), old_contents);
443 
444   // If the Cord contained data and was already flat, verify that the data
445   // wasn't copied.
446   if (already_flat_and_non_empty) {
447     EXPECT_EQ(old_flat.data(), new_flat.data())
448         << "Allocated new memory even though the Cord was already flat.";
449   }
450 
451   // Verify that the flattened Cord is in fact flat.
452   EXPECT_TRUE(IsFlat(c));
453 }
454 
TEST(Cord,Flatten)455 TEST(Cord, Flatten) {
456   VerifyFlatten(absl::Cord());
457   VerifyFlatten(absl::Cord("small cord"));
458   VerifyFlatten(absl::Cord("larger than small buffer optimization"));
459   VerifyFlatten(absl::MakeFragmentedCord({"small ", "fragmented ", "cord"}));
460 
461   // Test with a cord that is longer than the largest flat buffer
462   RandomEngine rng(testing::GTEST_FLAG(random_seed));
463   VerifyFlatten(absl::Cord(RandomLowercaseString(&rng, 8192)));
464 }
465 
466 // Test data
467 namespace {
468 class TestData {
469  private:
470   std::vector<std::string> data_;
471 
472   // Return a std::string of the specified length.
MakeString(int length)473   static std::string MakeString(int length) {
474     std::string result;
475     char buf[30];
476     snprintf(buf, sizeof(buf), "(%d)", length);
477     while (result.size() < length) {
478       result += buf;
479     }
480     result.resize(length);
481     return result;
482   }
483 
484  public:
TestData()485   TestData() {
486     // short strings increasing in length by one
487     for (int i = 0; i < 30; i++) {
488       data_.push_back(MakeString(i));
489     }
490 
491     // strings around half kMaxFlatLength
492     static const int kMaxFlatLength = 4096 - 9;
493     static const int kHalf = kMaxFlatLength / 2;
494 
495     for (int i = -10; i <= +10; i++) {
496       data_.push_back(MakeString(kHalf + i));
497     }
498 
499     for (int i = -10; i <= +10; i++) {
500       data_.push_back(MakeString(kMaxFlatLength + i));
501     }
502   }
503 
size() const504   size_t size() const { return data_.size(); }
data(size_t i) const505   const std::string& data(size_t i) const { return data_[i]; }
506 };
507 }  // namespace
508 
TEST(Cord,MultipleLengths)509 TEST(Cord, MultipleLengths) {
510   TestData d;
511   for (size_t i = 0; i < d.size(); i++) {
512     std::string a = d.data(i);
513 
514     { // Construct from Cord
515       absl::Cord tmp(a);
516       absl::Cord x(tmp);
517       EXPECT_EQ(a, std::string(x)) << "'" << a << "'";
518     }
519 
520     { // Construct from absl::string_view
521       absl::Cord x(a);
522       EXPECT_EQ(a, std::string(x)) << "'" << a << "'";
523     }
524 
525     { // Append cord to self
526       absl::Cord self(a);
527       self.Append(self);
528       EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";
529     }
530 
531     { // Prepend cord to self
532       absl::Cord self(a);
533       self.Prepend(self);
534       EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";
535     }
536 
537     // Try to append/prepend others
538     for (size_t j = 0; j < d.size(); j++) {
539       std::string b = d.data(j);
540 
541       { // CopyFrom Cord
542         absl::Cord x(a);
543         absl::Cord y(b);
544         x = y;
545         EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";
546       }
547 
548       { // CopyFrom absl::string_view
549         absl::Cord x(a);
550         x = b;
551         EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";
552       }
553 
554       { // Cord::Append(Cord)
555         absl::Cord x(a);
556         absl::Cord y(b);
557         x.Append(y);
558         EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";
559       }
560 
561       { // Cord::Append(absl::string_view)
562         absl::Cord x(a);
563         x.Append(b);
564         EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";
565       }
566 
567       { // Cord::Prepend(Cord)
568         absl::Cord x(a);
569         absl::Cord y(b);
570         x.Prepend(y);
571         EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";
572       }
573 
574       { // Cord::Prepend(absl::string_view)
575         absl::Cord x(a);
576         x.Prepend(b);
577         EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";
578       }
579     }
580   }
581 }
582 
583 namespace {
584 
TEST(Cord,RemoveSuffixWithExternalOrSubstring)585 TEST(Cord, RemoveSuffixWithExternalOrSubstring) {
586   absl::Cord cord = absl::MakeCordFromExternal(
587       "foo bar baz", [](absl::string_view s) { DoNothing(s, nullptr); });
588 
589   EXPECT_EQ("foo bar baz", std::string(cord));
590 
591   // This RemoveSuffix() will wrap the EXTERNAL node in a SUBSTRING node.
592   cord.RemoveSuffix(4);
593   EXPECT_EQ("foo bar", std::string(cord));
594 
595   // This RemoveSuffix() will adjust the SUBSTRING node in-place.
596   cord.RemoveSuffix(4);
597   EXPECT_EQ("foo", std::string(cord));
598 }
599 
TEST(Cord,RemoveSuffixMakesZeroLengthNode)600 TEST(Cord, RemoveSuffixMakesZeroLengthNode) {
601   absl::Cord c;
602   c.Append(absl::Cord(std::string(100, 'x')));
603   absl::Cord other_ref = c;  // Prevent inplace appends
604   c.Append(absl::Cord(std::string(200, 'y')));
605   c.RemoveSuffix(200);
606   EXPECT_EQ(std::string(100, 'x'), std::string(c));
607 }
608 
609 }  // namespace
610 
611 // CordSpliceTest contributed by hendrie.
612 namespace {
613 
614 // Create a cord with an external memory block filled with 'z'
CordWithZedBlock(size_t size)615 absl::Cord CordWithZedBlock(size_t size) {
616   char* data = new char[size];
617   if (size > 0) {
618     memset(data, 'z', size);
619   }
620   absl::Cord cord = absl::MakeCordFromExternal(
621       absl::string_view(data, size),
622       [](absl::string_view s) { delete[] s.data(); });
623   return cord;
624 }
625 
626 // Establish that ZedBlock does what we think it does.
TEST(CordSpliceTest,ZedBlock)627 TEST(CordSpliceTest, ZedBlock) {
628   absl::Cord blob = CordWithZedBlock(10);
629   EXPECT_EQ(10, blob.size());
630   std::string s;
631   absl::CopyCordToString(blob, &s);
632   EXPECT_EQ("zzzzzzzzzz", s);
633 }
634 
TEST(CordSpliceTest,ZedBlock0)635 TEST(CordSpliceTest, ZedBlock0) {
636   absl::Cord blob = CordWithZedBlock(0);
637   EXPECT_EQ(0, blob.size());
638   std::string s;
639   absl::CopyCordToString(blob, &s);
640   EXPECT_EQ("", s);
641 }
642 
TEST(CordSpliceTest,ZedBlockSuffix1)643 TEST(CordSpliceTest, ZedBlockSuffix1) {
644   absl::Cord blob = CordWithZedBlock(10);
645   EXPECT_EQ(10, blob.size());
646   absl::Cord suffix(blob);
647   suffix.RemovePrefix(9);
648   EXPECT_EQ(1, suffix.size());
649   std::string s;
650   absl::CopyCordToString(suffix, &s);
651   EXPECT_EQ("z", s);
652 }
653 
654 // Remove all of a prefix block
TEST(CordSpliceTest,ZedBlockSuffix0)655 TEST(CordSpliceTest, ZedBlockSuffix0) {
656   absl::Cord blob = CordWithZedBlock(10);
657   EXPECT_EQ(10, blob.size());
658   absl::Cord suffix(blob);
659   suffix.RemovePrefix(10);
660   EXPECT_EQ(0, suffix.size());
661   std::string s;
662   absl::CopyCordToString(suffix, &s);
663   EXPECT_EQ("", s);
664 }
665 
BigCord(size_t len,char v)666 absl::Cord BigCord(size_t len, char v) {
667   std::string s(len, v);
668   return absl::Cord(s);
669 }
670 
671 // Splice block into cord.
SpliceCord(const absl::Cord & blob,int64_t offset,const absl::Cord & block)672 absl::Cord SpliceCord(const absl::Cord& blob, int64_t offset,
673                       const absl::Cord& block) {
674   ABSL_RAW_CHECK(offset >= 0, "");
675   ABSL_RAW_CHECK(offset + block.size() <= blob.size(), "");
676   absl::Cord result(blob);
677   result.RemoveSuffix(blob.size() - offset);
678   result.Append(block);
679   absl::Cord suffix(blob);
680   suffix.RemovePrefix(offset + block.size());
681   result.Append(suffix);
682   ABSL_RAW_CHECK(blob.size() == result.size(), "");
683   return result;
684 }
685 
686 // Taking an empty suffix of a block breaks appending.
TEST(CordSpliceTest,RemoveEntireBlock1)687 TEST(CordSpliceTest, RemoveEntireBlock1) {
688   absl::Cord zero = CordWithZedBlock(10);
689   absl::Cord suffix(zero);
690   suffix.RemovePrefix(10);
691   absl::Cord result;
692   result.Append(suffix);
693 }
694 
TEST(CordSpliceTest,RemoveEntireBlock2)695 TEST(CordSpliceTest, RemoveEntireBlock2) {
696   absl::Cord zero = CordWithZedBlock(10);
697   absl::Cord prefix(zero);
698   prefix.RemoveSuffix(10);
699   absl::Cord suffix(zero);
700   suffix.RemovePrefix(10);
701   absl::Cord result(prefix);
702   result.Append(suffix);
703 }
704 
TEST(CordSpliceTest,RemoveEntireBlock3)705 TEST(CordSpliceTest, RemoveEntireBlock3) {
706   absl::Cord blob = CordWithZedBlock(10);
707   absl::Cord block = BigCord(10, 'b');
708   blob = SpliceCord(blob, 0, block);
709 }
710 
711 struct CordCompareTestCase {
712   template <typename LHS, typename RHS>
CordCompareTestCase__anon162060ad0911::CordCompareTestCase713   CordCompareTestCase(const LHS& lhs, const RHS& rhs)
714       : lhs_cord(lhs), rhs_cord(rhs) {}
715 
716   absl::Cord lhs_cord;
717   absl::Cord rhs_cord;
718 };
719 
__anon162060ad0b02(int x) 720 const auto sign = [](int x) { return x == 0 ? 0 : (x > 0 ? 1 : -1); };
721 
VerifyComparison(const CordCompareTestCase & test_case)722 void VerifyComparison(const CordCompareTestCase& test_case) {
723   std::string lhs_string(test_case.lhs_cord);
724   std::string rhs_string(test_case.rhs_cord);
725   int expected = sign(lhs_string.compare(rhs_string));
726   EXPECT_EQ(expected, test_case.lhs_cord.Compare(test_case.rhs_cord))
727       << "LHS=" << lhs_string << "; RHS=" << rhs_string;
728   EXPECT_EQ(expected, test_case.lhs_cord.Compare(rhs_string))
729       << "LHS=" << lhs_string << "; RHS=" << rhs_string;
730   EXPECT_EQ(-expected, test_case.rhs_cord.Compare(test_case.lhs_cord))
731       << "LHS=" << rhs_string << "; RHS=" << lhs_string;
732   EXPECT_EQ(-expected, test_case.rhs_cord.Compare(lhs_string))
733       << "LHS=" << rhs_string << "; RHS=" << lhs_string;
734 }
735 
TEST(Cord,Compare)736 TEST(Cord, Compare) {
737   absl::Cord subcord("aaaaaBBBBBcccccDDDDD");
738   subcord = subcord.Subcord(3, 10);
739 
740   absl::Cord tmp("aaaaaaaaaaaaaaaa");
741   tmp.Append("BBBBBBBBBBBBBBBB");
742   absl::Cord concat = absl::Cord("cccccccccccccccc");
743   concat.Append("DDDDDDDDDDDDDDDD");
744   concat.Prepend(tmp);
745 
746   absl::Cord concat2("aaaaaaaaaaaaa");
747   concat2.Append("aaaBBBBBBBBBBBBBBBBccccc");
748   concat2.Append("cccccccccccDDDDDDDDDDDDDD");
749   concat2.Append("DD");
750 
751   std::vector<CordCompareTestCase> test_cases = {{
752       // Inline cords
753       {"abcdef", "abcdef"},
754       {"abcdef", "abcdee"},
755       {"abcdef", "abcdeg"},
756       {"bbcdef", "abcdef"},
757       {"bbcdef", "abcdeg"},
758       {"abcdefa", "abcdef"},
759       {"abcdef", "abcdefa"},
760 
761       // Small flat cords
762       {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBcccccDDDDD"},
763       {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBxccccDDDDD"},
764       {"aaaaaBBBBBcxcccDDDDD", "aaaaaBBBBBcccccDDDDD"},
765       {"aaaaaBBBBBxccccDDDDD", "aaaaaBBBBBcccccDDDDX"},
766       {"aaaaaBBBBBcccccDDDDDa", "aaaaaBBBBBcccccDDDDD"},
767       {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBcccccDDDDDa"},
768 
769       // Subcords
770       {subcord, subcord},
771       {subcord, "aaBBBBBccc"},
772       {subcord, "aaBBBBBccd"},
773       {subcord, "aaBBBBBccb"},
774       {subcord, "aaBBBBBxcb"},
775       {subcord, "aaBBBBBccca"},
776       {subcord, "aaBBBBBcc"},
777 
778       // Concats
779       {concat, concat},
780       {concat,
781        "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDD"},
782       {concat,
783        "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBcccccccccccccccxDDDDDDDDDDDDDDDD"},
784       {concat,
785        "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBacccccccccccccccDDDDDDDDDDDDDDDD"},
786       {concat,
787        "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDD"},
788       {concat,
789        "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDDe"},
790 
791       {concat, concat2},
792   }};
793 
794   for (const auto& tc : test_cases) {
795     VerifyComparison(tc);
796   }
797 }
798 
TEST(Cord,CompareAfterAssign)799 TEST(Cord, CompareAfterAssign) {
800   absl::Cord a("aaaaaa1111111");
801   absl::Cord b("aaaaaa2222222");
802   a = "cccccc";
803   b = "cccccc";
804   EXPECT_EQ(a, b);
805   EXPECT_FALSE(a < b);
806 
807   a = "aaaa";
808   b = "bbbbb";
809   a = "";
810   b = "";
811   EXPECT_EQ(a, b);
812   EXPECT_FALSE(a < b);
813 }
814 
815 // Test CompareTo() and ComparePrefix() against string and substring
816 // comparison methods from std::basic_string.
TestCompare(const absl::Cord & c,const absl::Cord & d,RandomEngine * rng)817 static void TestCompare(const absl::Cord& c, const absl::Cord& d,
818                         RandomEngine* rng) {
819   typedef std::basic_string<uint8_t> ustring;
820   ustring cs(reinterpret_cast<const uint8_t*>(std::string(c).data()), c.size());
821   ustring ds(reinterpret_cast<const uint8_t*>(std::string(d).data()), d.size());
822   // ustring comparison is ideal because we expect Cord comparisons to be
823   // based on unsigned byte comparisons regardless of whether char is signed.
824   int expected = sign(cs.compare(ds));
825   EXPECT_EQ(expected, sign(c.Compare(d))) << c << ", " << d;
826 }
827 
TEST(Compare,ComparisonIsUnsigned)828 TEST(Compare, ComparisonIsUnsigned) {
829   RandomEngine rng(testing::GTEST_FLAG(random_seed));
830   std::uniform_int_distribution<uint32_t> uniform_uint8(0, 255);
831   char x = static_cast<char>(uniform_uint8(rng));
832   TestCompare(
833       absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100), x)),
834       absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100), x ^ 0x80)), &rng);
835 }
836 
TEST(Compare,RandomComparisons)837 TEST(Compare, RandomComparisons) {
838   const int kIters = 5000;
839   RandomEngine rng(testing::GTEST_FLAG(random_seed));
840 
841   int n = GetUniformRandomUpTo(&rng, 5000);
842   absl::Cord a[] = {MakeExternalCord(n),
843                     absl::Cord("ant"),
844                     absl::Cord("elephant"),
845                     absl::Cord("giraffe"),
846                     absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100),
847                                            GetUniformRandomUpTo(&rng, 100))),
848                     absl::Cord(""),
849                     absl::Cord("x"),
850                     absl::Cord("A"),
851                     absl::Cord("B"),
852                     absl::Cord("C")};
853   for (int i = 0; i < kIters; i++) {
854     absl::Cord c, d;
855     for (int j = 0; j < (i % 7) + 1; j++) {
856       c.Append(a[GetUniformRandomUpTo(&rng, ABSL_ARRAYSIZE(a))]);
857       d.Append(a[GetUniformRandomUpTo(&rng, ABSL_ARRAYSIZE(a))]);
858     }
859     std::bernoulli_distribution coin_flip(0.5);
860     TestCompare(coin_flip(rng) ? c : absl::Cord(std::string(c)),
861                 coin_flip(rng) ? d : absl::Cord(std::string(d)), &rng);
862   }
863 }
864 
865 template <typename T1, typename T2>
CompareOperators()866 void CompareOperators() {
867   const T1 a("a");
868   const T2 b("b");
869 
870   EXPECT_TRUE(a == a);
871   // For pointer type (i.e. `const char*`), operator== compares the address
872   // instead of the std::string, so `a == const char*("a")` isn't necessarily true.
873   EXPECT_TRUE(std::is_pointer<T1>::value || a == T1("a"));
874   EXPECT_TRUE(std::is_pointer<T2>::value || a == T2("a"));
875   EXPECT_FALSE(a == b);
876 
877   EXPECT_TRUE(a != b);
878   EXPECT_FALSE(a != a);
879 
880   EXPECT_TRUE(a < b);
881   EXPECT_FALSE(b < a);
882 
883   EXPECT_TRUE(b > a);
884   EXPECT_FALSE(a > b);
885 
886   EXPECT_TRUE(a >= a);
887   EXPECT_TRUE(b >= a);
888   EXPECT_FALSE(a >= b);
889 
890   EXPECT_TRUE(a <= a);
891   EXPECT_TRUE(a <= b);
892   EXPECT_FALSE(b <= a);
893 }
894 
TEST(ComparisonOperators,Cord_Cord)895 TEST(ComparisonOperators, Cord_Cord) {
896   CompareOperators<absl::Cord, absl::Cord>();
897 }
898 
TEST(ComparisonOperators,Cord_StringPiece)899 TEST(ComparisonOperators, Cord_StringPiece) {
900   CompareOperators<absl::Cord, absl::string_view>();
901 }
902 
TEST(ComparisonOperators,StringPiece_Cord)903 TEST(ComparisonOperators, StringPiece_Cord) {
904   CompareOperators<absl::string_view, absl::Cord>();
905 }
906 
TEST(ComparisonOperators,Cord_string)907 TEST(ComparisonOperators, Cord_string) {
908   CompareOperators<absl::Cord, std::string>();
909 }
910 
TEST(ComparisonOperators,string_Cord)911 TEST(ComparisonOperators, string_Cord) {
912   CompareOperators<std::string, absl::Cord>();
913 }
914 
TEST(ComparisonOperators,stdstring_Cord)915 TEST(ComparisonOperators, stdstring_Cord) {
916   CompareOperators<std::string, absl::Cord>();
917 }
918 
TEST(ComparisonOperators,Cord_stdstring)919 TEST(ComparisonOperators, Cord_stdstring) {
920   CompareOperators<absl::Cord, std::string>();
921 }
922 
TEST(ComparisonOperators,charstar_Cord)923 TEST(ComparisonOperators, charstar_Cord) {
924   CompareOperators<const char*, absl::Cord>();
925 }
926 
TEST(ComparisonOperators,Cord_charstar)927 TEST(ComparisonOperators, Cord_charstar) {
928   CompareOperators<absl::Cord, const char*>();
929 }
930 
TEST(ConstructFromExternal,ReleaserInvoked)931 TEST(ConstructFromExternal, ReleaserInvoked) {
932   // Empty external memory means the releaser should be called immediately.
933   {
934     bool invoked = false;
935     auto releaser = [&invoked](absl::string_view) { invoked = true; };
936     {
937       auto c = absl::MakeCordFromExternal("", releaser);
938       EXPECT_TRUE(invoked);
939     }
940   }
941 
942   // If the size of the data is small enough, a future constructor
943   // implementation may copy the bytes and immediately invoke the releaser
944   // instead of creating an external node. We make a large dummy std::string to
945   // make this test independent of such an optimization.
946   std::string large_dummy(2048, 'c');
947   {
948     bool invoked = false;
949     auto releaser = [&invoked](absl::string_view) { invoked = true; };
950     {
951       auto c = absl::MakeCordFromExternal(large_dummy, releaser);
952       EXPECT_FALSE(invoked);
953     }
954     EXPECT_TRUE(invoked);
955   }
956 
957   {
958     bool invoked = false;
959     auto releaser = [&invoked](absl::string_view) { invoked = true; };
960     {
961       absl::Cord copy;
962       {
963         auto c = absl::MakeCordFromExternal(large_dummy, releaser);
964         copy = c;
965         EXPECT_FALSE(invoked);
966       }
967       EXPECT_FALSE(invoked);
968     }
969     EXPECT_TRUE(invoked);
970   }
971 }
972 
TEST(ConstructFromExternal,CompareContents)973 TEST(ConstructFromExternal, CompareContents) {
974   RandomEngine rng(testing::GTEST_FLAG(random_seed));
975 
976   for (int length = 1; length <= 2048; length *= 2) {
977     std::string data = RandomLowercaseString(&rng, length);
978     auto* external = new std::string(data);
979     auto cord =
980         absl::MakeCordFromExternal(*external, [external](absl::string_view sv) {
981           EXPECT_EQ(external->data(), sv.data());
982           EXPECT_EQ(external->size(), sv.size());
983           delete external;
984         });
985     EXPECT_EQ(data, cord);
986   }
987 }
988 
TEST(ConstructFromExternal,LargeReleaser)989 TEST(ConstructFromExternal, LargeReleaser) {
990   RandomEngine rng(testing::GTEST_FLAG(random_seed));
991   constexpr size_t kLength = 256;
992   std::string data = RandomLowercaseString(&rng, kLength);
993   std::array<char, kLength> data_array;
994   for (size_t i = 0; i < kLength; ++i) data_array[i] = data[i];
995   bool invoked = false;
996   auto releaser = [data_array, &invoked](absl::string_view data) {
997     EXPECT_EQ(data, absl::string_view(data_array.data(), data_array.size()));
998     invoked = true;
999   };
1000   (void)absl::MakeCordFromExternal(data, releaser);
1001   EXPECT_TRUE(invoked);
1002 }
1003 
TEST(ConstructFromExternal,FunctionPointerReleaser)1004 TEST(ConstructFromExternal, FunctionPointerReleaser) {
1005   static absl::string_view data("hello world");
1006   static bool invoked;
1007   auto* releaser =
1008       static_cast<void (*)(absl::string_view)>([](absl::string_view sv) {
1009         EXPECT_EQ(data, sv);
1010         invoked = true;
1011       });
1012   invoked = false;
1013   (void)absl::MakeCordFromExternal(data, releaser);
1014   EXPECT_TRUE(invoked);
1015 
1016   invoked = false;
1017   (void)absl::MakeCordFromExternal(data, *releaser);
1018   EXPECT_TRUE(invoked);
1019 }
1020 
TEST(ConstructFromExternal,MoveOnlyReleaser)1021 TEST(ConstructFromExternal, MoveOnlyReleaser) {
1022   struct Releaser {
1023     explicit Releaser(bool* invoked) : invoked(invoked) {}
1024     Releaser(Releaser&& other) noexcept : invoked(other.invoked) {}
1025     void operator()(absl::string_view) const { *invoked = true; }
1026 
1027     bool* invoked;
1028   };
1029 
1030   bool invoked = false;
1031   (void)absl::MakeCordFromExternal("dummy", Releaser(&invoked));
1032   EXPECT_TRUE(invoked);
1033 }
1034 
TEST(ConstructFromExternal,NonTrivialReleaserDestructor)1035 TEST(ConstructFromExternal, NonTrivialReleaserDestructor) {
1036   struct Releaser {
1037     explicit Releaser(bool* destroyed) : destroyed(destroyed) {}
1038     ~Releaser() { *destroyed = true; }
1039     void operator()(absl::string_view) const {}
1040 
1041     bool* destroyed;
1042   };
1043 
1044   bool destroyed = false;
1045   Releaser releaser(&destroyed);
1046   (void)absl::MakeCordFromExternal("dummy", releaser);
1047   EXPECT_TRUE(destroyed);
1048 }
1049 
TEST(ConstructFromExternal,ReferenceQualifierOverloads)1050 TEST(ConstructFromExternal, ReferenceQualifierOverloads) {
1051   struct Releaser {
1052     void operator()(absl::string_view) & { *lvalue_invoked = true; }
1053     void operator()(absl::string_view) && { *rvalue_invoked = true; }
1054 
1055     bool* lvalue_invoked;
1056     bool* rvalue_invoked;
1057   };
1058 
1059   bool lvalue_invoked = false;
1060   bool rvalue_invoked = false;
1061   Releaser releaser = {&lvalue_invoked, &rvalue_invoked};
1062   (void)absl::MakeCordFromExternal("", releaser);
1063   EXPECT_FALSE(lvalue_invoked);
1064   EXPECT_TRUE(rvalue_invoked);
1065   rvalue_invoked = false;
1066 
1067   (void)absl::MakeCordFromExternal("dummy", releaser);
1068   EXPECT_FALSE(lvalue_invoked);
1069   EXPECT_TRUE(rvalue_invoked);
1070   rvalue_invoked = false;
1071 
1072   // NOLINTNEXTLINE: suppress clang-tidy std::move on trivially copyable type.
1073   (void)absl::MakeCordFromExternal("dummy", std::move(releaser));
1074   EXPECT_FALSE(lvalue_invoked);
1075   EXPECT_TRUE(rvalue_invoked);
1076 }
1077 
TEST(ExternalMemory,BasicUsage)1078 TEST(ExternalMemory, BasicUsage) {
1079   static const char* strings[] = { "", "hello", "there" };
1080   for (const char* str : strings) {
1081     absl::Cord dst("(prefix)");
1082     AddExternalMemory(str, &dst);
1083     dst.Append("(suffix)");
1084     EXPECT_EQ((std::string("(prefix)") + str + std::string("(suffix)")),
1085               std::string(dst));
1086   }
1087 }
1088 
TEST(ExternalMemory,RemovePrefixSuffix)1089 TEST(ExternalMemory, RemovePrefixSuffix) {
1090   // Exhaustively try all sub-strings.
1091   absl::Cord cord = MakeComposite();
1092   std::string s = std::string(cord);
1093   for (int offset = 0; offset <= s.size(); offset++) {
1094     for (int length = 0; length <= s.size() - offset; length++) {
1095       absl::Cord result(cord);
1096       result.RemovePrefix(offset);
1097       result.RemoveSuffix(result.size() - length);
1098       EXPECT_EQ(s.substr(offset, length), std::string(result))
1099           << offset << " " << length;
1100     }
1101   }
1102 }
1103 
TEST(ExternalMemory,Get)1104 TEST(ExternalMemory, Get) {
1105   absl::Cord cord("hello");
1106   AddExternalMemory(" world!", &cord);
1107   AddExternalMemory(" how are ", &cord);
1108   cord.Append(" you?");
1109   std::string s = std::string(cord);
1110   for (int i = 0; i < s.size(); i++) {
1111     EXPECT_EQ(s[i], cord[i]);
1112   }
1113 }
1114 
1115 // CordMemoryUsage tests verify the correctness of the EstimatedMemoryUsage()
1116 // These tests take into account that the reported memory usage is approximate
1117 // and non-deterministic. For all tests, We verify that the reported memory
1118 // usage is larger than `size()`, and less than `size() * 1.5` as a cord should
1119 // never reserve more 'extra' capacity than half of its size as it grows.
1120 // Additionally we have some whiteboxed expectations based on our knowledge of
1121 // the layout and size of empty and inlined cords, and flat nodes.
1122 
TEST(CordMemoryUsage,Empty)1123 TEST(CordMemoryUsage, Empty) {
1124   EXPECT_EQ(sizeof(absl::Cord), absl::Cord().EstimatedMemoryUsage());
1125 }
1126 
TEST(CordMemoryUsage,Embedded)1127 TEST(CordMemoryUsage, Embedded) {
1128   absl::Cord a("hello");
1129   EXPECT_EQ(a.EstimatedMemoryUsage(), sizeof(absl::Cord));
1130 }
1131 
TEST(CordMemoryUsage,EmbeddedAppend)1132 TEST(CordMemoryUsage, EmbeddedAppend) {
1133   absl::Cord a("a");
1134   absl::Cord b("bcd");
1135   EXPECT_EQ(b.EstimatedMemoryUsage(), sizeof(absl::Cord));
1136   a.Append(b);
1137   EXPECT_EQ(a.EstimatedMemoryUsage(), sizeof(absl::Cord));
1138 }
1139 
TEST(CordMemoryUsage,ExternalMemory)1140 TEST(CordMemoryUsage, ExternalMemory) {
1141   static const int kLength = 1000;
1142   absl::Cord cord;
1143   AddExternalMemory(std::string(kLength, 'x'), &cord);
1144   EXPECT_GT(cord.EstimatedMemoryUsage(), kLength);
1145   EXPECT_LE(cord.EstimatedMemoryUsage(), kLength * 1.5);
1146 }
1147 
TEST(CordMemoryUsage,Flat)1148 TEST(CordMemoryUsage, Flat) {
1149   static const int kLength = 125;
1150   absl::Cord a(std::string(kLength, 'a'));
1151   EXPECT_GT(a.EstimatedMemoryUsage(), kLength);
1152   EXPECT_LE(a.EstimatedMemoryUsage(), kLength * 1.5);
1153 }
1154 
TEST(CordMemoryUsage,AppendFlat)1155 TEST(CordMemoryUsage, AppendFlat) {
1156   using absl::strings_internal::CordTestAccess;
1157   absl::Cord a(std::string(CordTestAccess::MaxFlatLength(), 'a'));
1158   size_t length = a.EstimatedMemoryUsage();
1159   a.Append(std::string(CordTestAccess::MaxFlatLength(), 'b'));
1160   size_t delta = a.EstimatedMemoryUsage() - length;
1161   EXPECT_GT(delta, CordTestAccess::MaxFlatLength());
1162   EXPECT_LE(delta, CordTestAccess::MaxFlatLength() * 1.5);
1163 }
1164 
1165 // Regtest for a change that had to be rolled back because it expanded out
1166 // of the InlineRep too soon, which was observable through MemoryUsage().
TEST(CordMemoryUsage,InlineRep)1167 TEST(CordMemoryUsage, InlineRep) {
1168   constexpr size_t kMaxInline = 15;  // Cord::InlineRep::N
1169   const std::string small_string(kMaxInline, 'x');
1170   absl::Cord c1(small_string);
1171 
1172   absl::Cord c2;
1173   c2.Append(small_string);
1174   EXPECT_EQ(c1, c2);
1175   EXPECT_EQ(c1.EstimatedMemoryUsage(), c2.EstimatedMemoryUsage());
1176 }
1177 
1178 }  // namespace
1179 
1180 // Regtest for 7510292 (fix a bug introduced by 7465150)
TEST(Cord,Concat_Append)1181 TEST(Cord, Concat_Append) {
1182   // Create a rep of type CONCAT
1183   absl::Cord s1("foobarbarbarbarbar");
1184   s1.Append("abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg");
1185   size_t size = s1.size();
1186 
1187   // Create a copy of s1 and append to it.
1188   absl::Cord s2 = s1;
1189   s2.Append("x");
1190 
1191   // 7465150 modifies s1 when it shouldn't.
1192   EXPECT_EQ(s1.size(), size);
1193   EXPECT_EQ(s2.size(), size + 1);
1194 }
1195 
TEST(MakeFragmentedCord,MakeFragmentedCordFromInitializerList)1196 TEST(MakeFragmentedCord, MakeFragmentedCordFromInitializerList) {
1197   absl::Cord fragmented =
1198       absl::MakeFragmentedCord({"A ", "fragmented ", "Cord"});
1199 
1200   EXPECT_EQ("A fragmented Cord", fragmented);
1201 
1202   auto chunk_it = fragmented.chunk_begin();
1203 
1204   ASSERT_TRUE(chunk_it != fragmented.chunk_end());
1205   EXPECT_EQ("A ", *chunk_it);
1206 
1207   ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
1208   EXPECT_EQ("fragmented ", *chunk_it);
1209 
1210   ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
1211   EXPECT_EQ("Cord", *chunk_it);
1212 
1213   ASSERT_TRUE(++chunk_it == fragmented.chunk_end());
1214 }
1215 
TEST(MakeFragmentedCord,MakeFragmentedCordFromVector)1216 TEST(MakeFragmentedCord, MakeFragmentedCordFromVector) {
1217   std::vector<absl::string_view> chunks = {"A ", "fragmented ", "Cord"};
1218   absl::Cord fragmented = absl::MakeFragmentedCord(chunks);
1219 
1220   EXPECT_EQ("A fragmented Cord", fragmented);
1221 
1222   auto chunk_it = fragmented.chunk_begin();
1223 
1224   ASSERT_TRUE(chunk_it != fragmented.chunk_end());
1225   EXPECT_EQ("A ", *chunk_it);
1226 
1227   ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
1228   EXPECT_EQ("fragmented ", *chunk_it);
1229 
1230   ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
1231   EXPECT_EQ("Cord", *chunk_it);
1232 
1233   ASSERT_TRUE(++chunk_it == fragmented.chunk_end());
1234 }
1235 
TEST(CordChunkIterator,Traits)1236 TEST(CordChunkIterator, Traits) {
1237   static_assert(std::is_copy_constructible<absl::Cord::ChunkIterator>::value,
1238                 "");
1239   static_assert(std::is_copy_assignable<absl::Cord::ChunkIterator>::value, "");
1240 
1241   // Move semantics to satisfy swappable via std::swap
1242   static_assert(std::is_move_constructible<absl::Cord::ChunkIterator>::value,
1243                 "");
1244   static_assert(std::is_move_assignable<absl::Cord::ChunkIterator>::value, "");
1245 
1246   static_assert(
1247       std::is_same<
1248           std::iterator_traits<absl::Cord::ChunkIterator>::iterator_category,
1249           std::input_iterator_tag>::value,
1250       "");
1251   static_assert(
1252       std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::value_type,
1253                    absl::string_view>::value,
1254       "");
1255   static_assert(
1256       std::is_same<
1257           std::iterator_traits<absl::Cord::ChunkIterator>::difference_type,
1258           ptrdiff_t>::value,
1259       "");
1260   static_assert(
1261       std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::pointer,
1262                    const absl::string_view*>::value,
1263       "");
1264   static_assert(
1265       std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::reference,
1266                    absl::string_view>::value,
1267       "");
1268 }
1269 
VerifyChunkIterator(const absl::Cord & cord,size_t expected_chunks)1270 static void VerifyChunkIterator(const absl::Cord& cord,
1271                                 size_t expected_chunks) {
1272   EXPECT_EQ(cord.chunk_begin() == cord.chunk_end(), cord.empty()) << cord;
1273   EXPECT_EQ(cord.chunk_begin() != cord.chunk_end(), !cord.empty());
1274 
1275   absl::Cord::ChunkRange range = cord.Chunks();
1276   EXPECT_EQ(range.begin() == range.end(), cord.empty());
1277   EXPECT_EQ(range.begin() != range.end(), !cord.empty());
1278 
1279   std::string content(cord);
1280   size_t pos = 0;
1281   auto pre_iter = cord.chunk_begin(), post_iter = cord.chunk_begin();
1282   size_t n_chunks = 0;
1283   while (pre_iter != cord.chunk_end() && post_iter != cord.chunk_end()) {
1284     EXPECT_FALSE(pre_iter == cord.chunk_end());   // NOLINT: explicitly test ==
1285     EXPECT_FALSE(post_iter == cord.chunk_end());  // NOLINT
1286 
1287     EXPECT_EQ(pre_iter, post_iter);
1288     EXPECT_EQ(*pre_iter, *post_iter);
1289 
1290     EXPECT_EQ(pre_iter->data(), (*pre_iter).data());
1291     EXPECT_EQ(pre_iter->size(), (*pre_iter).size());
1292 
1293     absl::string_view chunk = *pre_iter;
1294     EXPECT_FALSE(chunk.empty());
1295     EXPECT_LE(pos + chunk.size(), content.size());
1296     EXPECT_EQ(absl::string_view(content.c_str() + pos, chunk.size()), chunk);
1297 
1298     int n_equal_iterators = 0;
1299     for (absl::Cord::ChunkIterator it = range.begin(); it != range.end();
1300          ++it) {
1301       n_equal_iterators += static_cast<int>(it == pre_iter);
1302     }
1303     EXPECT_EQ(n_equal_iterators, 1);
1304 
1305     ++pre_iter;
1306     EXPECT_EQ(*post_iter++, chunk);
1307 
1308     pos += chunk.size();
1309     ++n_chunks;
1310   }
1311   EXPECT_EQ(expected_chunks, n_chunks);
1312   EXPECT_EQ(pos, content.size());
1313   EXPECT_TRUE(pre_iter == cord.chunk_end());   // NOLINT: explicitly test ==
1314   EXPECT_TRUE(post_iter == cord.chunk_end());  // NOLINT
1315 }
1316 
TEST(CordChunkIterator,Operations)1317 TEST(CordChunkIterator, Operations) {
1318   absl::Cord empty_cord;
1319   VerifyChunkIterator(empty_cord, 0);
1320 
1321   absl::Cord small_buffer_cord("small cord");
1322   VerifyChunkIterator(small_buffer_cord, 1);
1323 
1324   absl::Cord flat_node_cord("larger than small buffer optimization");
1325   VerifyChunkIterator(flat_node_cord, 1);
1326 
1327   VerifyChunkIterator(
1328       absl::MakeFragmentedCord({"a ", "small ", "fragmented ", "cord ", "for ",
1329                                 "testing ", "chunk ", "iterations."}),
1330       8);
1331 
1332   absl::Cord reused_nodes_cord(std::string(40, 'c'));
1333   reused_nodes_cord.Prepend(absl::Cord(std::string(40, 'b')));
1334   reused_nodes_cord.Prepend(absl::Cord(std::string(40, 'a')));
1335   size_t expected_chunks = 3;
1336   for (int i = 0; i < 8; ++i) {
1337     reused_nodes_cord.Prepend(reused_nodes_cord);
1338     expected_chunks *= 2;
1339     VerifyChunkIterator(reused_nodes_cord, expected_chunks);
1340   }
1341 
1342   RandomEngine rng(testing::GTEST_FLAG(random_seed));
1343   absl::Cord flat_cord(RandomLowercaseString(&rng, 256));
1344   absl::Cord subcords;
1345   for (int i = 0; i < 128; ++i) subcords.Prepend(flat_cord.Subcord(i, 128));
1346   VerifyChunkIterator(subcords, 128);
1347 }
1348 
TEST(CordCharIterator,Traits)1349 TEST(CordCharIterator, Traits) {
1350   static_assert(std::is_copy_constructible<absl::Cord::CharIterator>::value,
1351                 "");
1352   static_assert(std::is_copy_assignable<absl::Cord::CharIterator>::value, "");
1353 
1354   // Move semantics to satisfy swappable via std::swap
1355   static_assert(std::is_move_constructible<absl::Cord::CharIterator>::value,
1356                 "");
1357   static_assert(std::is_move_assignable<absl::Cord::CharIterator>::value, "");
1358 
1359   static_assert(
1360       std::is_same<
1361           std::iterator_traits<absl::Cord::CharIterator>::iterator_category,
1362           std::input_iterator_tag>::value,
1363       "");
1364   static_assert(
1365       std::is_same<std::iterator_traits<absl::Cord::CharIterator>::value_type,
1366                    char>::value,
1367       "");
1368   static_assert(
1369       std::is_same<
1370           std::iterator_traits<absl::Cord::CharIterator>::difference_type,
1371           ptrdiff_t>::value,
1372       "");
1373   static_assert(
1374       std::is_same<std::iterator_traits<absl::Cord::CharIterator>::pointer,
1375                    const char*>::value,
1376       "");
1377   static_assert(
1378       std::is_same<std::iterator_traits<absl::Cord::CharIterator>::reference,
1379                    const char&>::value,
1380       "");
1381 }
1382 
VerifyCharIterator(const absl::Cord & cord)1383 static void VerifyCharIterator(const absl::Cord& cord) {
1384   EXPECT_EQ(cord.char_begin() == cord.char_end(), cord.empty());
1385   EXPECT_EQ(cord.char_begin() != cord.char_end(), !cord.empty());
1386 
1387   absl::Cord::CharRange range = cord.Chars();
1388   EXPECT_EQ(range.begin() == range.end(), cord.empty());
1389   EXPECT_EQ(range.begin() != range.end(), !cord.empty());
1390 
1391   size_t i = 0;
1392   absl::Cord::CharIterator pre_iter = cord.char_begin();
1393   absl::Cord::CharIterator post_iter = cord.char_begin();
1394   std::string content(cord);
1395   while (pre_iter != cord.char_end() && post_iter != cord.char_end()) {
1396     EXPECT_FALSE(pre_iter == cord.char_end());   // NOLINT: explicitly test ==
1397     EXPECT_FALSE(post_iter == cord.char_end());  // NOLINT
1398 
1399     EXPECT_LT(i, cord.size());
1400     EXPECT_EQ(content[i], *pre_iter);
1401 
1402     EXPECT_EQ(pre_iter, post_iter);
1403     EXPECT_EQ(*pre_iter, *post_iter);
1404     EXPECT_EQ(&*pre_iter, &*post_iter);
1405 
1406     EXPECT_EQ(&*pre_iter, pre_iter.operator->());
1407 
1408     const char* character_address = &*pre_iter;
1409     absl::Cord::CharIterator copy = pre_iter;
1410     ++copy;
1411     EXPECT_EQ(character_address, &*pre_iter);
1412 
1413     int n_equal_iterators = 0;
1414     for (absl::Cord::CharIterator it = range.begin(); it != range.end(); ++it) {
1415       n_equal_iterators += static_cast<int>(it == pre_iter);
1416     }
1417     EXPECT_EQ(n_equal_iterators, 1);
1418 
1419     absl::Cord::CharIterator advance_iter = range.begin();
1420     absl::Cord::Advance(&advance_iter, i);
1421     EXPECT_EQ(pre_iter, advance_iter);
1422 
1423     advance_iter = range.begin();
1424     EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, i), cord.Subcord(0, i));
1425     EXPECT_EQ(pre_iter, advance_iter);
1426 
1427     advance_iter = pre_iter;
1428     absl::Cord::Advance(&advance_iter, cord.size() - i);
1429     EXPECT_EQ(range.end(), advance_iter);
1430 
1431     advance_iter = pre_iter;
1432     EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, cord.size() - i),
1433               cord.Subcord(i, cord.size() - i));
1434     EXPECT_EQ(range.end(), advance_iter);
1435 
1436     ++i;
1437     ++pre_iter;
1438     post_iter++;
1439   }
1440   EXPECT_EQ(i, cord.size());
1441   EXPECT_TRUE(pre_iter == cord.char_end());   // NOLINT: explicitly test ==
1442   EXPECT_TRUE(post_iter == cord.char_end());  // NOLINT
1443 
1444   absl::Cord::CharIterator zero_advanced_end = cord.char_end();
1445   absl::Cord::Advance(&zero_advanced_end, 0);
1446   EXPECT_EQ(zero_advanced_end, cord.char_end());
1447 
1448   absl::Cord::CharIterator it = cord.char_begin();
1449   for (absl::string_view chunk : cord.Chunks()) {
1450     while (!chunk.empty()) {
1451       EXPECT_EQ(absl::Cord::ChunkRemaining(it), chunk);
1452       chunk.remove_prefix(1);
1453       ++it;
1454     }
1455   }
1456 }
1457 
TEST(CordCharIterator,Operations)1458 TEST(CordCharIterator, Operations) {
1459   absl::Cord empty_cord;
1460   VerifyCharIterator(empty_cord);
1461 
1462   absl::Cord small_buffer_cord("small cord");
1463   VerifyCharIterator(small_buffer_cord);
1464 
1465   absl::Cord flat_node_cord("larger than small buffer optimization");
1466   VerifyCharIterator(flat_node_cord);
1467 
1468   VerifyCharIterator(
1469       absl::MakeFragmentedCord({"a ", "small ", "fragmented ", "cord ", "for ",
1470                                 "testing ", "character ", "iteration."}));
1471 
1472   absl::Cord reused_nodes_cord("ghi");
1473   reused_nodes_cord.Prepend(absl::Cord("def"));
1474   reused_nodes_cord.Prepend(absl::Cord("abc"));
1475   for (int i = 0; i < 4; ++i) {
1476     reused_nodes_cord.Prepend(reused_nodes_cord);
1477     VerifyCharIterator(reused_nodes_cord);
1478   }
1479 
1480   RandomEngine rng(testing::GTEST_FLAG(random_seed));
1481   absl::Cord flat_cord(RandomLowercaseString(&rng, 256));
1482   absl::Cord subcords;
1483   for (int i = 0; i < 4; ++i) subcords.Prepend(flat_cord.Subcord(16 * i, 128));
1484   VerifyCharIterator(subcords);
1485 }
1486 
TEST(Cord,StreamingOutput)1487 TEST(Cord, StreamingOutput) {
1488   absl::Cord c =
1489       absl::MakeFragmentedCord({"A ", "small ", "fragmented ", "Cord", "."});
1490   std::stringstream output;
1491   output << c;
1492   EXPECT_EQ("A small fragmented Cord.", output.str());
1493 }
1494 
TEST(Cord,ForEachChunk)1495 TEST(Cord, ForEachChunk) {
1496   for (int num_elements : {1, 10, 200}) {
1497     SCOPED_TRACE(num_elements);
1498     std::vector<std::string> cord_chunks;
1499     for (int i = 0; i < num_elements; ++i) {
1500       cord_chunks.push_back(absl::StrCat("[", i, "]"));
1501     }
1502     absl::Cord c = absl::MakeFragmentedCord(cord_chunks);
1503 
1504     std::vector<std::string> iterated_chunks;
1505     absl::CordTestPeer::ForEachChunk(c,
1506                                      [&iterated_chunks](absl::string_view sv) {
1507                                        iterated_chunks.emplace_back(sv);
1508                                      });
1509     EXPECT_EQ(iterated_chunks, cord_chunks);
1510   }
1511 }
1512 
TEST(Cord,SmallBufferAssignFromOwnData)1513 TEST(Cord, SmallBufferAssignFromOwnData) {
1514   constexpr size_t kMaxInline = 15;
1515   std::string contents = "small buff cord";
1516   EXPECT_EQ(contents.size(), kMaxInline);
1517   for (size_t pos = 0; pos < contents.size(); ++pos) {
1518     for (size_t count = contents.size() - pos; count > 0; --count) {
1519       absl::Cord c(contents);
1520       absl::string_view flat = c.Flatten();
1521       c = flat.substr(pos, count);
1522       EXPECT_EQ(c, contents.substr(pos, count))
1523           << "pos = " << pos << "; count = " << count;
1524     }
1525   }
1526 }
1527