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