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