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/casts.h"
32 #include "absl/base/config.h"
33 #include "absl/base/internal/endian.h"
34 #include "absl/base/internal/raw_logging.h"
35 #include "absl/base/macros.h"
36 #include "absl/container/fixed_array.h"
37 #include "absl/strings/cord_test_helpers.h"
38 #include "absl/strings/cordz_test_helpers.h"
39 #include "absl/strings/str_cat.h"
40 #include "absl/strings/str_format.h"
41 #include "absl/strings/string_view.h"
42
43 typedef std::mt19937_64 RandomEngine;
44
45 static std::string RandomLowercaseString(RandomEngine* rng);
46 static std::string RandomLowercaseString(RandomEngine* rng, size_t length);
47
GetUniformRandomUpTo(RandomEngine * rng,int upper_bound)48 static int GetUniformRandomUpTo(RandomEngine* rng, int upper_bound) {
49 if (upper_bound > 0) {
50 std::uniform_int_distribution<int> uniform(0, upper_bound - 1);
51 return uniform(*rng);
52 } else {
53 return 0;
54 }
55 }
56
GetUniformRandomUpTo(RandomEngine * rng,size_t upper_bound)57 static size_t GetUniformRandomUpTo(RandomEngine* rng, size_t upper_bound) {
58 if (upper_bound > 0) {
59 std::uniform_int_distribution<size_t> uniform(0, upper_bound - 1);
60 return uniform(*rng);
61 } else {
62 return 0;
63 }
64 }
65
GenerateSkewedRandom(RandomEngine * rng,int max_log)66 static int32_t GenerateSkewedRandom(RandomEngine* rng, int max_log) {
67 const uint32_t base = (*rng)() % (max_log + 1);
68 const uint32_t mask = ((base < 32) ? (1u << base) : 0u) - 1u;
69 return (*rng)() & mask;
70 }
71
RandomLowercaseString(RandomEngine * rng)72 static std::string RandomLowercaseString(RandomEngine* rng) {
73 int length;
74 std::bernoulli_distribution one_in_1k(0.001);
75 std::bernoulli_distribution one_in_10k(0.0001);
76 // With low probability, make a large fragment
77 if (one_in_10k(*rng)) {
78 length = GetUniformRandomUpTo(rng, 1048576);
79 } else if (one_in_1k(*rng)) {
80 length = GetUniformRandomUpTo(rng, 10000);
81 } else {
82 length = GenerateSkewedRandom(rng, 10);
83 }
84 return RandomLowercaseString(rng, length);
85 }
86
RandomLowercaseString(RandomEngine * rng,size_t length)87 static std::string RandomLowercaseString(RandomEngine* rng, size_t length) {
88 std::string result(length, '\0');
89 std::uniform_int_distribution<int> chars('a', 'z');
90 std::generate(result.begin(), result.end(),
91 [&]() { return static_cast<char>(chars(*rng)); });
92 return result;
93 }
94
DoNothing(absl::string_view,void *)95 static void DoNothing(absl::string_view /* data */, void* /* arg */) {}
96
DeleteExternalString(absl::string_view data,void * arg)97 static void DeleteExternalString(absl::string_view data, void* arg) {
98 std::string* s = reinterpret_cast<std::string*>(arg);
99 EXPECT_EQ(data, *s);
100 delete s;
101 }
102
103 // Add "s" to *dst via `MakeCordFromExternal`
AddExternalMemory(absl::string_view s,absl::Cord * dst)104 static void AddExternalMemory(absl::string_view s, absl::Cord* dst) {
105 std::string* str = new std::string(s.data(), s.size());
106 dst->Append(absl::MakeCordFromExternal(*str, [str](absl::string_view data) {
107 DeleteExternalString(data, str);
108 }));
109 }
110
DumpGrowth()111 static void DumpGrowth() {
112 absl::Cord str;
113 for (int i = 0; i < 1000; i++) {
114 char c = 'a' + i % 26;
115 str.Append(absl::string_view(&c, 1));
116 }
117 }
118
119 // Make a Cord with some number of fragments. Return the size (in bytes)
120 // of the smallest fragment.
AppendWithFragments(const std::string & s,RandomEngine * rng,absl::Cord * cord)121 static size_t AppendWithFragments(const std::string& s, RandomEngine* rng,
122 absl::Cord* cord) {
123 size_t j = 0;
124 const size_t max_size = s.size() / 5; // Make approx. 10 fragments
125 size_t min_size = max_size; // size of smallest fragment
126 while (j < s.size()) {
127 size_t N = 1 + GetUniformRandomUpTo(rng, max_size);
128 if (N > (s.size() - j)) {
129 N = s.size() - j;
130 }
131 if (N < min_size) {
132 min_size = N;
133 }
134
135 std::bernoulli_distribution coin_flip(0.5);
136 if (coin_flip(*rng)) {
137 // Grow by adding an external-memory.
138 AddExternalMemory(absl::string_view(s.data() + j, N), cord);
139 } else {
140 cord->Append(absl::string_view(s.data() + j, N));
141 }
142 j += N;
143 }
144 return min_size;
145 }
146
147 // Add an external memory that contains the specified std::string to cord
AddNewStringBlock(const std::string & str,absl::Cord * dst)148 static void AddNewStringBlock(const std::string& str, absl::Cord* dst) {
149 char* data = new char[str.size()];
150 memcpy(data, str.data(), str.size());
151 dst->Append(absl::MakeCordFromExternal(
152 absl::string_view(data, str.size()),
153 [](absl::string_view s) { delete[] s.data(); }));
154 }
155
156 // Make a Cord out of many different types of nodes.
MakeComposite()157 static absl::Cord MakeComposite() {
158 absl::Cord cord;
159 cord.Append("the");
160 AddExternalMemory(" quick brown", &cord);
161 AddExternalMemory(" fox jumped", &cord);
162
163 absl::Cord full(" over");
164 AddExternalMemory(" the lazy", &full);
165 AddNewStringBlock(" dog slept the whole day away", &full);
166 absl::Cord substring = full.Subcord(0, 18);
167
168 // Make substring long enough to defeat the copying fast path in Append.
169 substring.Append(std::string(1000, '.'));
170 cord.Append(substring);
171 cord = cord.Subcord(0, cord.size() - 998); // Remove most of extra junk
172
173 return cord;
174 }
175
176 namespace absl {
177 ABSL_NAMESPACE_BEGIN
178
179 class CordTestPeer {
180 public:
ForEachChunk(const Cord & c,absl::FunctionRef<void (absl::string_view)> callback)181 static void ForEachChunk(
182 const Cord& c, absl::FunctionRef<void(absl::string_view)> callback) {
183 c.ForEachChunk(callback);
184 }
185
IsTree(const Cord & c)186 static bool IsTree(const Cord& c) { return c.contents_.is_tree(); }
187
GetCordzInfo(const Cord & c)188 static cord_internal::CordzInfo* GetCordzInfo(const Cord& c) {
189 return c.contents_.cordz_info();
190 }
191
MakeSubstring(Cord src,size_t offset,size_t length)192 static Cord MakeSubstring(Cord src, size_t offset, size_t length) {
193 ABSL_RAW_CHECK(src.contents_.is_tree(), "Can not be inlined");
194 Cord cord;
195 auto* rep = new cord_internal::CordRepSubstring;
196 rep->tag = cord_internal::SUBSTRING;
197 rep->child = cord_internal::CordRep::Ref(src.contents_.tree());
198 rep->start = offset;
199 rep->length = length;
200 cord.contents_.EmplaceTree(rep,
201 cord_internal::CordzUpdateTracker::kSubCord);
202 return cord;
203 }
204 };
205
206 ABSL_NAMESPACE_END
207 } // namespace absl
208
209 // The CordTest fixture runs all tests with and without Cord Btree enabled.
210 class CordTest : public testing::TestWithParam<bool> {
211 public:
CordTest()212 CordTest() : was_btree_(absl::cord_internal::cord_btree_enabled.load()) {
213 absl::cord_internal::cord_btree_enabled.store(UseBtree());
214 }
~CordTest()215 ~CordTest() override {
216 absl::cord_internal::cord_btree_enabled.store(was_btree_);
217 }
218
219 // Returns true if test is running with btree enabled.
UseBtree() const220 bool UseBtree() const { return GetParam(); }
221
222 // Returns human readable string representation of the test parameter.
ToString(testing::TestParamInfo<bool> param)223 static std::string ToString(testing::TestParamInfo<bool> param) {
224 return param.param ? "Btree" : "Concat";
225 }
226
227 private:
228 const bool was_btree_;
229 };
230
231 INSTANTIATE_TEST_SUITE_P(WithParam, CordTest, testing::Bool(),
232 CordTest::ToString);
233
TEST_P(CordTest,AllFlatSizes)234 TEST_P(CordTest, AllFlatSizes) {
235 using absl::strings_internal::CordTestAccess;
236
237 for (size_t s = 0; s < CordTestAccess::MaxFlatLength(); s++) {
238 // Make a string of length s.
239 std::string src;
240 while (src.size() < s) {
241 src.push_back('a' + (src.size() % 26));
242 }
243
244 absl::Cord dst(src);
245 EXPECT_EQ(std::string(dst), src) << s;
246 }
247 }
248
249 // We create a Cord at least 128GB in size using the fact that Cords can
250 // internally reference-count; thus the Cord is enormous without actually
251 // consuming very much memory.
TEST_P(CordTest,GigabyteCordFromExternal)252 TEST_P(CordTest, GigabyteCordFromExternal) {
253 const size_t one_gig = 1024U * 1024U * 1024U;
254 size_t max_size = 2 * one_gig;
255 if (sizeof(max_size) > 4) max_size = 128 * one_gig;
256
257 size_t length = 128 * 1024;
258 char* data = new char[length];
259 absl::Cord from = absl::MakeCordFromExternal(
260 absl::string_view(data, length),
261 [](absl::string_view sv) { delete[] sv.data(); });
262
263 // This loop may seem odd due to its combination of exponential doubling of
264 // size and incremental size increases. We do it incrementally to be sure the
265 // Cord will need rebalancing and will exercise code that, in the past, has
266 // caused crashes in production. We grow exponentially so that the code will
267 // execute in a reasonable amount of time.
268 absl::Cord c;
269 c.Append(from);
270 while (c.size() < max_size) {
271 c.Append(c);
272 c.Append(from);
273 c.Append(from);
274 c.Append(from);
275 c.Append(from);
276 }
277
278 for (int i = 0; i < 1024; ++i) {
279 c.Append(from);
280 }
281 ABSL_RAW_LOG(INFO, "Made a Cord with %zu bytes!", c.size());
282 // Note: on a 32-bit build, this comes out to 2,818,048,000 bytes.
283 // Note: on a 64-bit build, this comes out to 171,932,385,280 bytes.
284 }
285
MakeExternalCord(int size)286 static absl::Cord MakeExternalCord(int size) {
287 char* buffer = new char[size];
288 memset(buffer, 'x', size);
289 absl::Cord cord;
290 cord.Append(absl::MakeCordFromExternal(
291 absl::string_view(buffer, size),
292 [](absl::string_view s) { delete[] s.data(); }));
293 return cord;
294 }
295
296 // Extern to fool clang that this is not constant. Needed to suppress
297 // a warning of unsafe code we want to test.
298 extern bool my_unique_true_boolean;
299 bool my_unique_true_boolean = true;
300
TEST_P(CordTest,Assignment)301 TEST_P(CordTest, Assignment) {
302 absl::Cord x(absl::string_view("hi there"));
303 absl::Cord y(x);
304 ASSERT_EQ(std::string(x), "hi there");
305 ASSERT_EQ(std::string(y), "hi there");
306 ASSERT_TRUE(x == y);
307 ASSERT_TRUE(x <= y);
308 ASSERT_TRUE(y <= x);
309
310 x = absl::string_view("foo");
311 ASSERT_EQ(std::string(x), "foo");
312 ASSERT_EQ(std::string(y), "hi there");
313 ASSERT_TRUE(x < y);
314 ASSERT_TRUE(y > x);
315 ASSERT_TRUE(x != y);
316 ASSERT_TRUE(x <= y);
317 ASSERT_TRUE(y >= x);
318
319 x = "foo";
320 ASSERT_EQ(x, "foo");
321
322 // Test that going from inline rep to tree we don't leak memory.
323 std::vector<std::pair<absl::string_view, absl::string_view>>
324 test_string_pairs = {{"hi there", "foo"},
325 {"loooooong coooooord", "short cord"},
326 {"short cord", "loooooong coooooord"},
327 {"loooooong coooooord1", "loooooong coooooord2"}};
328 for (std::pair<absl::string_view, absl::string_view> test_strings :
329 test_string_pairs) {
330 absl::Cord tmp(test_strings.first);
331 absl::Cord z(std::move(tmp));
332 ASSERT_EQ(std::string(z), test_strings.first);
333 tmp = test_strings.second;
334 z = std::move(tmp);
335 ASSERT_EQ(std::string(z), test_strings.second);
336 }
337 {
338 // Test that self-move assignment doesn't crash/leak.
339 // Do not write such code!
340 absl::Cord my_small_cord("foo");
341 absl::Cord my_big_cord("loooooong coooooord");
342 // Bypass clang's warning on self move-assignment.
343 absl::Cord* my_small_alias =
344 my_unique_true_boolean ? &my_small_cord : &my_big_cord;
345 absl::Cord* my_big_alias =
346 !my_unique_true_boolean ? &my_small_cord : &my_big_cord;
347
348 *my_small_alias = std::move(my_small_cord);
349 *my_big_alias = std::move(my_big_cord);
350 // my_small_cord and my_big_cord are in an unspecified but valid
351 // state, and will be correctly destroyed here.
352 }
353 }
354
TEST_P(CordTest,StartsEndsWith)355 TEST_P(CordTest, StartsEndsWith) {
356 absl::Cord x(absl::string_view("abcde"));
357 absl::Cord empty("");
358
359 ASSERT_TRUE(x.StartsWith(absl::Cord("abcde")));
360 ASSERT_TRUE(x.StartsWith(absl::Cord("abc")));
361 ASSERT_TRUE(x.StartsWith(absl::Cord("")));
362 ASSERT_TRUE(empty.StartsWith(absl::Cord("")));
363 ASSERT_TRUE(x.EndsWith(absl::Cord("abcde")));
364 ASSERT_TRUE(x.EndsWith(absl::Cord("cde")));
365 ASSERT_TRUE(x.EndsWith(absl::Cord("")));
366 ASSERT_TRUE(empty.EndsWith(absl::Cord("")));
367
368 ASSERT_TRUE(!x.StartsWith(absl::Cord("xyz")));
369 ASSERT_TRUE(!empty.StartsWith(absl::Cord("xyz")));
370 ASSERT_TRUE(!x.EndsWith(absl::Cord("xyz")));
371 ASSERT_TRUE(!empty.EndsWith(absl::Cord("xyz")));
372
373 ASSERT_TRUE(x.StartsWith("abcde"));
374 ASSERT_TRUE(x.StartsWith("abc"));
375 ASSERT_TRUE(x.StartsWith(""));
376 ASSERT_TRUE(empty.StartsWith(""));
377 ASSERT_TRUE(x.EndsWith("abcde"));
378 ASSERT_TRUE(x.EndsWith("cde"));
379 ASSERT_TRUE(x.EndsWith(""));
380 ASSERT_TRUE(empty.EndsWith(""));
381
382 ASSERT_TRUE(!x.StartsWith("xyz"));
383 ASSERT_TRUE(!empty.StartsWith("xyz"));
384 ASSERT_TRUE(!x.EndsWith("xyz"));
385 ASSERT_TRUE(!empty.EndsWith("xyz"));
386 }
387
TEST_P(CordTest,Subcord)388 TEST_P(CordTest, Subcord) {
389 RandomEngine rng(GTEST_FLAG_GET(random_seed));
390 const std::string s = RandomLowercaseString(&rng, 1024);
391
392 absl::Cord a;
393 AppendWithFragments(s, &rng, &a);
394 ASSERT_EQ(s, std::string(a));
395
396 // Check subcords of a, from a variety of interesting points.
397 std::set<size_t> positions;
398 for (int i = 0; i <= 32; ++i) {
399 positions.insert(i);
400 positions.insert(i * 32 - 1);
401 positions.insert(i * 32);
402 positions.insert(i * 32 + 1);
403 positions.insert(a.size() - i);
404 }
405 positions.insert(237);
406 positions.insert(732);
407 for (size_t pos : positions) {
408 if (pos > a.size()) continue;
409 for (size_t end_pos : positions) {
410 if (end_pos < pos || end_pos > a.size()) continue;
411 absl::Cord sa = a.Subcord(pos, end_pos - pos);
412 ASSERT_EQ(absl::string_view(s).substr(pos, end_pos - pos),
413 std::string(sa))
414 << a;
415 }
416 }
417
418 // Do the same thing for an inline cord.
419 const std::string sh = "short";
420 absl::Cord c(sh);
421 for (size_t pos = 0; pos <= sh.size(); ++pos) {
422 for (size_t n = 0; n <= sh.size() - pos; ++n) {
423 absl::Cord sc = c.Subcord(pos, n);
424 ASSERT_EQ(sh.substr(pos, n), std::string(sc)) << c;
425 }
426 }
427
428 // Check subcords of subcords.
429 absl::Cord sa = a.Subcord(0, a.size());
430 std::string ss = s.substr(0, s.size());
431 while (sa.size() > 1) {
432 sa = sa.Subcord(1, sa.size() - 2);
433 ss = ss.substr(1, ss.size() - 2);
434 ASSERT_EQ(ss, std::string(sa)) << a;
435 if (HasFailure()) break; // halt cascade
436 }
437
438 // It is OK to ask for too much.
439 sa = a.Subcord(0, a.size() + 1);
440 EXPECT_EQ(s, std::string(sa));
441
442 // It is OK to ask for something beyond the end.
443 sa = a.Subcord(a.size() + 1, 0);
444 EXPECT_TRUE(sa.empty());
445 sa = a.Subcord(a.size() + 1, 1);
446 EXPECT_TRUE(sa.empty());
447 }
448
TEST_P(CordTest,Swap)449 TEST_P(CordTest, Swap) {
450 absl::string_view a("Dexter");
451 absl::string_view b("Mandark");
452 absl::Cord x(a);
453 absl::Cord y(b);
454 swap(x, y);
455 ASSERT_EQ(x, absl::Cord(b));
456 ASSERT_EQ(y, absl::Cord(a));
457 x.swap(y);
458 ASSERT_EQ(x, absl::Cord(a));
459 ASSERT_EQ(y, absl::Cord(b));
460 }
461
VerifyCopyToString(const absl::Cord & cord)462 static void VerifyCopyToString(const absl::Cord& cord) {
463 std::string initially_empty;
464 absl::CopyCordToString(cord, &initially_empty);
465 EXPECT_EQ(initially_empty, cord);
466
467 constexpr size_t kInitialLength = 1024;
468 std::string has_initial_contents(kInitialLength, 'x');
469 const char* address_before_copy = has_initial_contents.data();
470 absl::CopyCordToString(cord, &has_initial_contents);
471 EXPECT_EQ(has_initial_contents, cord);
472
473 if (cord.size() <= kInitialLength) {
474 EXPECT_EQ(has_initial_contents.data(), address_before_copy)
475 << "CopyCordToString allocated new string storage; "
476 "has_initial_contents = \""
477 << has_initial_contents << "\"";
478 }
479 }
480
TEST_P(CordTest,CopyToString)481 TEST_P(CordTest, CopyToString) {
482 VerifyCopyToString(absl::Cord());
483 VerifyCopyToString(absl::Cord("small cord"));
484 VerifyCopyToString(
485 absl::MakeFragmentedCord({"fragmented ", "cord ", "to ", "test ",
486 "copying ", "to ", "a ", "string."}));
487 }
488
TEST_P(CordTest,TryFlatEmpty)489 TEST_P(CordTest, TryFlatEmpty) {
490 absl::Cord c;
491 EXPECT_EQ(c.TryFlat(), "");
492 }
493
TEST_P(CordTest,TryFlatFlat)494 TEST_P(CordTest, TryFlatFlat) {
495 absl::Cord c("hello");
496 EXPECT_EQ(c.TryFlat(), "hello");
497 }
498
TEST_P(CordTest,TryFlatSubstrInlined)499 TEST_P(CordTest, TryFlatSubstrInlined) {
500 absl::Cord c("hello");
501 c.RemovePrefix(1);
502 EXPECT_EQ(c.TryFlat(), "ello");
503 }
504
TEST_P(CordTest,TryFlatSubstrFlat)505 TEST_P(CordTest, TryFlatSubstrFlat) {
506 absl::Cord c("longer than 15 bytes");
507 absl::Cord sub = absl::CordTestPeer::MakeSubstring(c, 1, c.size() - 1);
508 EXPECT_EQ(sub.TryFlat(), "onger than 15 bytes");
509 }
510
TEST_P(CordTest,TryFlatConcat)511 TEST_P(CordTest, TryFlatConcat) {
512 absl::Cord c = absl::MakeFragmentedCord({"hel", "lo"});
513 EXPECT_EQ(c.TryFlat(), absl::nullopt);
514 }
515
TEST_P(CordTest,TryFlatExternal)516 TEST_P(CordTest, TryFlatExternal) {
517 absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});
518 EXPECT_EQ(c.TryFlat(), "hell");
519 }
520
TEST_P(CordTest,TryFlatSubstrExternal)521 TEST_P(CordTest, TryFlatSubstrExternal) {
522 absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});
523 absl::Cord sub = absl::CordTestPeer::MakeSubstring(c, 1, c.size() - 1);
524 EXPECT_EQ(sub.TryFlat(), "ell");
525 }
526
TEST_P(CordTest,TryFlatSubstrConcat)527 TEST_P(CordTest, TryFlatSubstrConcat) {
528 absl::Cord c = absl::MakeFragmentedCord({"hello", " world"});
529 absl::Cord sub = absl::CordTestPeer::MakeSubstring(c, 1, c.size() - 1);
530 EXPECT_EQ(sub.TryFlat(), absl::nullopt);
531 c.RemovePrefix(1);
532 EXPECT_EQ(c.TryFlat(), absl::nullopt);
533 }
534
TEST_P(CordTest,TryFlatCommonlyAssumedInvariants)535 TEST_P(CordTest, TryFlatCommonlyAssumedInvariants) {
536 // The behavior tested below is not part of the API contract of Cord, but it's
537 // something we intend to be true in our current implementation. This test
538 // exists to detect and prevent accidental breakage of the implementation.
539 absl::string_view fragments[] = {"A fragmented test",
540 " cord",
541 " to test subcords",
542 " of ",
543 "a",
544 " cord for",
545 " each chunk "
546 "returned by the ",
547 "iterator"};
548 absl::Cord c = absl::MakeFragmentedCord(fragments);
549 int fragment = 0;
550 int offset = 0;
551 absl::Cord::CharIterator itc = c.char_begin();
552 for (absl::string_view sv : c.Chunks()) {
553 absl::string_view expected = fragments[fragment];
554 absl::Cord subcord1 = c.Subcord(offset, sv.length());
555 absl::Cord subcord2 = absl::Cord::AdvanceAndRead(&itc, sv.size());
556 EXPECT_EQ(subcord1.TryFlat(), expected);
557 EXPECT_EQ(subcord2.TryFlat(), expected);
558 ++fragment;
559 offset += sv.length();
560 }
561 }
562
IsFlat(const absl::Cord & c)563 static bool IsFlat(const absl::Cord& c) {
564 return c.chunk_begin() == c.chunk_end() || ++c.chunk_begin() == c.chunk_end();
565 }
566
VerifyFlatten(absl::Cord c)567 static void VerifyFlatten(absl::Cord c) {
568 std::string old_contents(c);
569 absl::string_view old_flat;
570 bool already_flat_and_non_empty = IsFlat(c) && !c.empty();
571 if (already_flat_and_non_empty) {
572 old_flat = *c.chunk_begin();
573 }
574 absl::string_view new_flat = c.Flatten();
575
576 // Verify that the contents of the flattened Cord are correct.
577 EXPECT_EQ(new_flat, old_contents);
578 EXPECT_EQ(std::string(c), old_contents);
579
580 // If the Cord contained data and was already flat, verify that the data
581 // wasn't copied.
582 if (already_flat_and_non_empty) {
583 EXPECT_EQ(old_flat.data(), new_flat.data())
584 << "Allocated new memory even though the Cord was already flat.";
585 }
586
587 // Verify that the flattened Cord is in fact flat.
588 EXPECT_TRUE(IsFlat(c));
589 }
590
TEST_P(CordTest,Flatten)591 TEST_P(CordTest, Flatten) {
592 VerifyFlatten(absl::Cord());
593 VerifyFlatten(absl::Cord("small cord"));
594 VerifyFlatten(absl::Cord("larger than small buffer optimization"));
595 VerifyFlatten(absl::MakeFragmentedCord({"small ", "fragmented ", "cord"}));
596
597 // Test with a cord that is longer than the largest flat buffer
598 RandomEngine rng(GTEST_FLAG_GET(random_seed));
599 VerifyFlatten(absl::Cord(RandomLowercaseString(&rng, 8192)));
600 }
601
602 // Test data
603 namespace {
604 class TestData {
605 private:
606 std::vector<std::string> data_;
607
608 // Return a std::string of the specified length.
MakeString(int length)609 static std::string MakeString(int length) {
610 std::string result;
611 char buf[30];
612 snprintf(buf, sizeof(buf), "(%d)", length);
613 while (result.size() < length) {
614 result += buf;
615 }
616 result.resize(length);
617 return result;
618 }
619
620 public:
TestData()621 TestData() {
622 // short strings increasing in length by one
623 for (int i = 0; i < 30; i++) {
624 data_.push_back(MakeString(i));
625 }
626
627 // strings around half kMaxFlatLength
628 static const int kMaxFlatLength = 4096 - 9;
629 static const int kHalf = kMaxFlatLength / 2;
630
631 for (int i = -10; i <= +10; i++) {
632 data_.push_back(MakeString(kHalf + i));
633 }
634
635 for (int i = -10; i <= +10; i++) {
636 data_.push_back(MakeString(kMaxFlatLength + i));
637 }
638 }
639
size() const640 size_t size() const { return data_.size(); }
data(size_t i) const641 const std::string& data(size_t i) const { return data_[i]; }
642 };
643 } // namespace
644
TEST_P(CordTest,MultipleLengths)645 TEST_P(CordTest, MultipleLengths) {
646 TestData d;
647 for (size_t i = 0; i < d.size(); i++) {
648 std::string a = d.data(i);
649
650 { // Construct from Cord
651 absl::Cord tmp(a);
652 absl::Cord x(tmp);
653 EXPECT_EQ(a, std::string(x)) << "'" << a << "'";
654 }
655
656 { // Construct from absl::string_view
657 absl::Cord x(a);
658 EXPECT_EQ(a, std::string(x)) << "'" << a << "'";
659 }
660
661 { // Append cord to self
662 absl::Cord self(a);
663 self.Append(self);
664 EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";
665 }
666
667 { // Prepend cord to self
668 absl::Cord self(a);
669 self.Prepend(self);
670 EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";
671 }
672
673 // Try to append/prepend others
674 for (size_t j = 0; j < d.size(); j++) {
675 std::string b = d.data(j);
676
677 { // CopyFrom Cord
678 absl::Cord x(a);
679 absl::Cord y(b);
680 x = y;
681 EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";
682 }
683
684 { // CopyFrom absl::string_view
685 absl::Cord x(a);
686 x = b;
687 EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";
688 }
689
690 { // Cord::Append(Cord)
691 absl::Cord x(a);
692 absl::Cord y(b);
693 x.Append(y);
694 EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";
695 }
696
697 { // Cord::Append(absl::string_view)
698 absl::Cord x(a);
699 x.Append(b);
700 EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";
701 }
702
703 { // Cord::Prepend(Cord)
704 absl::Cord x(a);
705 absl::Cord y(b);
706 x.Prepend(y);
707 EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";
708 }
709
710 { // Cord::Prepend(absl::string_view)
711 absl::Cord x(a);
712 x.Prepend(b);
713 EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";
714 }
715 }
716 }
717 }
718
719 namespace {
720
TEST_P(CordTest,RemoveSuffixWithExternalOrSubstring)721 TEST_P(CordTest, RemoveSuffixWithExternalOrSubstring) {
722 absl::Cord cord = absl::MakeCordFromExternal(
723 "foo bar baz", [](absl::string_view s) { DoNothing(s, nullptr); });
724
725 EXPECT_EQ("foo bar baz", std::string(cord));
726
727 // This RemoveSuffix() will wrap the EXTERNAL node in a SUBSTRING node.
728 cord.RemoveSuffix(4);
729 EXPECT_EQ("foo bar", std::string(cord));
730
731 // This RemoveSuffix() will adjust the SUBSTRING node in-place.
732 cord.RemoveSuffix(4);
733 EXPECT_EQ("foo", std::string(cord));
734 }
735
TEST_P(CordTest,RemoveSuffixMakesZeroLengthNode)736 TEST_P(CordTest, RemoveSuffixMakesZeroLengthNode) {
737 absl::Cord c;
738 c.Append(absl::Cord(std::string(100, 'x')));
739 absl::Cord other_ref = c; // Prevent inplace appends
740 c.Append(absl::Cord(std::string(200, 'y')));
741 c.RemoveSuffix(200);
742 EXPECT_EQ(std::string(100, 'x'), std::string(c));
743 }
744
745 } // namespace
746
747 // CordSpliceTest contributed by hendrie.
748 namespace {
749
750 // Create a cord with an external memory block filled with 'z'
CordWithZedBlock(size_t size)751 absl::Cord CordWithZedBlock(size_t size) {
752 char* data = new char[size];
753 if (size > 0) {
754 memset(data, 'z', size);
755 }
756 absl::Cord cord = absl::MakeCordFromExternal(
757 absl::string_view(data, size),
758 [](absl::string_view s) { delete[] s.data(); });
759 return cord;
760 }
761
762 // Establish that ZedBlock does what we think it does.
TEST_P(CordTest,CordSpliceTestZedBlock)763 TEST_P(CordTest, CordSpliceTestZedBlock) {
764 absl::Cord blob = CordWithZedBlock(10);
765 EXPECT_EQ(10, blob.size());
766 std::string s;
767 absl::CopyCordToString(blob, &s);
768 EXPECT_EQ("zzzzzzzzzz", s);
769 }
770
TEST_P(CordTest,CordSpliceTestZedBlock0)771 TEST_P(CordTest, CordSpliceTestZedBlock0) {
772 absl::Cord blob = CordWithZedBlock(0);
773 EXPECT_EQ(0, blob.size());
774 std::string s;
775 absl::CopyCordToString(blob, &s);
776 EXPECT_EQ("", s);
777 }
778
TEST_P(CordTest,CordSpliceTestZedBlockSuffix1)779 TEST_P(CordTest, CordSpliceTestZedBlockSuffix1) {
780 absl::Cord blob = CordWithZedBlock(10);
781 EXPECT_EQ(10, blob.size());
782 absl::Cord suffix(blob);
783 suffix.RemovePrefix(9);
784 EXPECT_EQ(1, suffix.size());
785 std::string s;
786 absl::CopyCordToString(suffix, &s);
787 EXPECT_EQ("z", s);
788 }
789
790 // Remove all of a prefix block
TEST_P(CordTest,CordSpliceTestZedBlockSuffix0)791 TEST_P(CordTest, CordSpliceTestZedBlockSuffix0) {
792 absl::Cord blob = CordWithZedBlock(10);
793 EXPECT_EQ(10, blob.size());
794 absl::Cord suffix(blob);
795 suffix.RemovePrefix(10);
796 EXPECT_EQ(0, suffix.size());
797 std::string s;
798 absl::CopyCordToString(suffix, &s);
799 EXPECT_EQ("", s);
800 }
801
BigCord(size_t len,char v)802 absl::Cord BigCord(size_t len, char v) {
803 std::string s(len, v);
804 return absl::Cord(s);
805 }
806
807 // Splice block into cord.
SpliceCord(const absl::Cord & blob,int64_t offset,const absl::Cord & block)808 absl::Cord SpliceCord(const absl::Cord& blob, int64_t offset,
809 const absl::Cord& block) {
810 ABSL_RAW_CHECK(offset >= 0, "");
811 ABSL_RAW_CHECK(offset + block.size() <= blob.size(), "");
812 absl::Cord result(blob);
813 result.RemoveSuffix(blob.size() - offset);
814 result.Append(block);
815 absl::Cord suffix(blob);
816 suffix.RemovePrefix(offset + block.size());
817 result.Append(suffix);
818 ABSL_RAW_CHECK(blob.size() == result.size(), "");
819 return result;
820 }
821
822 // Taking an empty suffix of a block breaks appending.
TEST_P(CordTest,CordSpliceTestRemoveEntireBlock1)823 TEST_P(CordTest, CordSpliceTestRemoveEntireBlock1) {
824 absl::Cord zero = CordWithZedBlock(10);
825 absl::Cord suffix(zero);
826 suffix.RemovePrefix(10);
827 absl::Cord result;
828 result.Append(suffix);
829 }
830
TEST_P(CordTest,CordSpliceTestRemoveEntireBlock2)831 TEST_P(CordTest, CordSpliceTestRemoveEntireBlock2) {
832 absl::Cord zero = CordWithZedBlock(10);
833 absl::Cord prefix(zero);
834 prefix.RemoveSuffix(10);
835 absl::Cord suffix(zero);
836 suffix.RemovePrefix(10);
837 absl::Cord result(prefix);
838 result.Append(suffix);
839 }
840
TEST_P(CordTest,CordSpliceTestRemoveEntireBlock3)841 TEST_P(CordTest, CordSpliceTestRemoveEntireBlock3) {
842 absl::Cord blob = CordWithZedBlock(10);
843 absl::Cord block = BigCord(10, 'b');
844 blob = SpliceCord(blob, 0, block);
845 }
846
847 struct CordCompareTestCase {
848 template <typename LHS, typename RHS>
CordCompareTestCase__anon58f243cc0b11::CordCompareTestCase849 CordCompareTestCase(const LHS& lhs, const RHS& rhs)
850 : lhs_cord(lhs), rhs_cord(rhs) {}
851
852 absl::Cord lhs_cord;
853 absl::Cord rhs_cord;
854 };
855
__anon58f243cc0d02(int x) 856 const auto sign = [](int x) { return x == 0 ? 0 : (x > 0 ? 1 : -1); };
857
VerifyComparison(const CordCompareTestCase & test_case)858 void VerifyComparison(const CordCompareTestCase& test_case) {
859 std::string lhs_string(test_case.lhs_cord);
860 std::string rhs_string(test_case.rhs_cord);
861 int expected = sign(lhs_string.compare(rhs_string));
862 EXPECT_EQ(expected, test_case.lhs_cord.Compare(test_case.rhs_cord))
863 << "LHS=" << lhs_string << "; RHS=" << rhs_string;
864 EXPECT_EQ(expected, test_case.lhs_cord.Compare(rhs_string))
865 << "LHS=" << lhs_string << "; RHS=" << rhs_string;
866 EXPECT_EQ(-expected, test_case.rhs_cord.Compare(test_case.lhs_cord))
867 << "LHS=" << rhs_string << "; RHS=" << lhs_string;
868 EXPECT_EQ(-expected, test_case.rhs_cord.Compare(lhs_string))
869 << "LHS=" << rhs_string << "; RHS=" << lhs_string;
870 }
871
TEST_P(CordTest,Compare)872 TEST_P(CordTest, Compare) {
873 absl::Cord subcord("aaaaaBBBBBcccccDDDDD");
874 subcord = subcord.Subcord(3, 10);
875
876 absl::Cord tmp("aaaaaaaaaaaaaaaa");
877 tmp.Append("BBBBBBBBBBBBBBBB");
878 absl::Cord concat = absl::Cord("cccccccccccccccc");
879 concat.Append("DDDDDDDDDDDDDDDD");
880 concat.Prepend(tmp);
881
882 absl::Cord concat2("aaaaaaaaaaaaa");
883 concat2.Append("aaaBBBBBBBBBBBBBBBBccccc");
884 concat2.Append("cccccccccccDDDDDDDDDDDDDD");
885 concat2.Append("DD");
886
887 std::vector<CordCompareTestCase> test_cases = {{
888 // Inline cords
889 {"abcdef", "abcdef"},
890 {"abcdef", "abcdee"},
891 {"abcdef", "abcdeg"},
892 {"bbcdef", "abcdef"},
893 {"bbcdef", "abcdeg"},
894 {"abcdefa", "abcdef"},
895 {"abcdef", "abcdefa"},
896
897 // Small flat cords
898 {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBcccccDDDDD"},
899 {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBxccccDDDDD"},
900 {"aaaaaBBBBBcxcccDDDDD", "aaaaaBBBBBcccccDDDDD"},
901 {"aaaaaBBBBBxccccDDDDD", "aaaaaBBBBBcccccDDDDX"},
902 {"aaaaaBBBBBcccccDDDDDa", "aaaaaBBBBBcccccDDDDD"},
903 {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBcccccDDDDDa"},
904
905 // Subcords
906 {subcord, subcord},
907 {subcord, "aaBBBBBccc"},
908 {subcord, "aaBBBBBccd"},
909 {subcord, "aaBBBBBccb"},
910 {subcord, "aaBBBBBxcb"},
911 {subcord, "aaBBBBBccca"},
912 {subcord, "aaBBBBBcc"},
913
914 // Concats
915 {concat, concat},
916 {concat,
917 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDD"},
918 {concat,
919 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBcccccccccccccccxDDDDDDDDDDDDDDDD"},
920 {concat,
921 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBacccccccccccccccDDDDDDDDDDDDDDDD"},
922 {concat,
923 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDD"},
924 {concat,
925 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDDe"},
926
927 {concat, concat2},
928 }};
929
930 for (const auto& tc : test_cases) {
931 VerifyComparison(tc);
932 }
933 }
934
TEST_P(CordTest,CompareAfterAssign)935 TEST_P(CordTest, CompareAfterAssign) {
936 absl::Cord a("aaaaaa1111111");
937 absl::Cord b("aaaaaa2222222");
938 a = "cccccc";
939 b = "cccccc";
940 EXPECT_EQ(a, b);
941 EXPECT_FALSE(a < b);
942
943 a = "aaaa";
944 b = "bbbbb";
945 a = "";
946 b = "";
947 EXPECT_EQ(a, b);
948 EXPECT_FALSE(a < b);
949 }
950
951 // Test CompareTo() and ComparePrefix() against string and substring
952 // comparison methods from basic_string.
TestCompare(const absl::Cord & c,const absl::Cord & d,RandomEngine * rng)953 static void TestCompare(const absl::Cord& c, const absl::Cord& d,
954 RandomEngine* rng) {
955 typedef std::basic_string<uint8_t> ustring;
956 ustring cs(reinterpret_cast<const uint8_t*>(std::string(c).data()), c.size());
957 ustring ds(reinterpret_cast<const uint8_t*>(std::string(d).data()), d.size());
958 // ustring comparison is ideal because we expect Cord comparisons to be
959 // based on unsigned byte comparisons regardless of whether char is signed.
960 int expected = sign(cs.compare(ds));
961 EXPECT_EQ(expected, sign(c.Compare(d))) << c << ", " << d;
962 }
963
TEST_P(CordTest,CompareComparisonIsUnsigned)964 TEST_P(CordTest, CompareComparisonIsUnsigned) {
965 RandomEngine rng(GTEST_FLAG_GET(random_seed));
966 std::uniform_int_distribution<uint32_t> uniform_uint8(0, 255);
967 char x = static_cast<char>(uniform_uint8(rng));
968 TestCompare(
969 absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100), x)),
970 absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100), x ^ 0x80)), &rng);
971 }
972
TEST_P(CordTest,CompareRandomComparisons)973 TEST_P(CordTest, CompareRandomComparisons) {
974 const int kIters = 5000;
975 RandomEngine rng(GTEST_FLAG_GET(random_seed));
976
977 int n = GetUniformRandomUpTo(&rng, 5000);
978 absl::Cord a[] = {MakeExternalCord(n),
979 absl::Cord("ant"),
980 absl::Cord("elephant"),
981 absl::Cord("giraffe"),
982 absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100),
983 GetUniformRandomUpTo(&rng, 100))),
984 absl::Cord(""),
985 absl::Cord("x"),
986 absl::Cord("A"),
987 absl::Cord("B"),
988 absl::Cord("C")};
989 for (int i = 0; i < kIters; i++) {
990 absl::Cord c, d;
991 for (int j = 0; j < (i % 7) + 1; j++) {
992 c.Append(a[GetUniformRandomUpTo(&rng, ABSL_ARRAYSIZE(a))]);
993 d.Append(a[GetUniformRandomUpTo(&rng, ABSL_ARRAYSIZE(a))]);
994 }
995 std::bernoulli_distribution coin_flip(0.5);
996 TestCompare(coin_flip(rng) ? c : absl::Cord(std::string(c)),
997 coin_flip(rng) ? d : absl::Cord(std::string(d)), &rng);
998 }
999 }
1000
1001 template <typename T1, typename T2>
CompareOperators()1002 void CompareOperators() {
1003 const T1 a("a");
1004 const T2 b("b");
1005
1006 EXPECT_TRUE(a == a);
1007 // For pointer type (i.e. `const char*`), operator== compares the address
1008 // instead of the string, so `a == const char*("a")` isn't necessarily true.
1009 EXPECT_TRUE(std::is_pointer<T1>::value || a == T1("a"));
1010 EXPECT_TRUE(std::is_pointer<T2>::value || a == T2("a"));
1011 EXPECT_FALSE(a == b);
1012
1013 EXPECT_TRUE(a != b);
1014 EXPECT_FALSE(a != a);
1015
1016 EXPECT_TRUE(a < b);
1017 EXPECT_FALSE(b < a);
1018
1019 EXPECT_TRUE(b > a);
1020 EXPECT_FALSE(a > b);
1021
1022 EXPECT_TRUE(a >= a);
1023 EXPECT_TRUE(b >= a);
1024 EXPECT_FALSE(a >= b);
1025
1026 EXPECT_TRUE(a <= a);
1027 EXPECT_TRUE(a <= b);
1028 EXPECT_FALSE(b <= a);
1029 }
1030
TEST_P(CordTest,ComparisonOperators_Cord_Cord)1031 TEST_P(CordTest, ComparisonOperators_Cord_Cord) {
1032 CompareOperators<absl::Cord, absl::Cord>();
1033 }
1034
TEST_P(CordTest,ComparisonOperators_Cord_StringPiece)1035 TEST_P(CordTest, ComparisonOperators_Cord_StringPiece) {
1036 CompareOperators<absl::Cord, absl::string_view>();
1037 }
1038
TEST_P(CordTest,ComparisonOperators_StringPiece_Cord)1039 TEST_P(CordTest, ComparisonOperators_StringPiece_Cord) {
1040 CompareOperators<absl::string_view, absl::Cord>();
1041 }
1042
TEST_P(CordTest,ComparisonOperators_Cord_string)1043 TEST_P(CordTest, ComparisonOperators_Cord_string) {
1044 CompareOperators<absl::Cord, std::string>();
1045 }
1046
TEST_P(CordTest,ComparisonOperators_string_Cord)1047 TEST_P(CordTest, ComparisonOperators_string_Cord) {
1048 CompareOperators<std::string, absl::Cord>();
1049 }
1050
TEST_P(CordTest,ComparisonOperators_stdstring_Cord)1051 TEST_P(CordTest, ComparisonOperators_stdstring_Cord) {
1052 CompareOperators<std::string, absl::Cord>();
1053 }
1054
TEST_P(CordTest,ComparisonOperators_Cord_stdstring)1055 TEST_P(CordTest, ComparisonOperators_Cord_stdstring) {
1056 CompareOperators<absl::Cord, std::string>();
1057 }
1058
TEST_P(CordTest,ComparisonOperators_charstar_Cord)1059 TEST_P(CordTest, ComparisonOperators_charstar_Cord) {
1060 CompareOperators<const char*, absl::Cord>();
1061 }
1062
TEST_P(CordTest,ComparisonOperators_Cord_charstar)1063 TEST_P(CordTest, ComparisonOperators_Cord_charstar) {
1064 CompareOperators<absl::Cord, const char*>();
1065 }
1066
TEST_P(CordTest,ConstructFromExternalReleaserInvoked)1067 TEST_P(CordTest, ConstructFromExternalReleaserInvoked) {
1068 // Empty external memory means the releaser should be called immediately.
1069 {
1070 bool invoked = false;
1071 auto releaser = [&invoked](absl::string_view) { invoked = true; };
1072 {
1073 auto c = absl::MakeCordFromExternal("", releaser);
1074 EXPECT_TRUE(invoked);
1075 }
1076 }
1077
1078 // If the size of the data is small enough, a future constructor
1079 // implementation may copy the bytes and immediately invoke the releaser
1080 // instead of creating an external node. We make a large dummy std::string to
1081 // make this test independent of such an optimization.
1082 std::string large_dummy(2048, 'c');
1083 {
1084 bool invoked = false;
1085 auto releaser = [&invoked](absl::string_view) { invoked = true; };
1086 {
1087 auto c = absl::MakeCordFromExternal(large_dummy, releaser);
1088 EXPECT_FALSE(invoked);
1089 }
1090 EXPECT_TRUE(invoked);
1091 }
1092
1093 {
1094 bool invoked = false;
1095 auto releaser = [&invoked](absl::string_view) { invoked = true; };
1096 {
1097 absl::Cord copy;
1098 {
1099 auto c = absl::MakeCordFromExternal(large_dummy, releaser);
1100 copy = c;
1101 EXPECT_FALSE(invoked);
1102 }
1103 EXPECT_FALSE(invoked);
1104 }
1105 EXPECT_TRUE(invoked);
1106 }
1107 }
1108
TEST_P(CordTest,ConstructFromExternalCompareContents)1109 TEST_P(CordTest, ConstructFromExternalCompareContents) {
1110 RandomEngine rng(GTEST_FLAG_GET(random_seed));
1111
1112 for (int length = 1; length <= 2048; length *= 2) {
1113 std::string data = RandomLowercaseString(&rng, length);
1114 auto* external = new std::string(data);
1115 auto cord =
1116 absl::MakeCordFromExternal(*external, [external](absl::string_view sv) {
1117 EXPECT_EQ(external->data(), sv.data());
1118 EXPECT_EQ(external->size(), sv.size());
1119 delete external;
1120 });
1121 EXPECT_EQ(data, cord);
1122 }
1123 }
1124
TEST_P(CordTest,ConstructFromExternalLargeReleaser)1125 TEST_P(CordTest, ConstructFromExternalLargeReleaser) {
1126 RandomEngine rng(GTEST_FLAG_GET(random_seed));
1127 constexpr size_t kLength = 256;
1128 std::string data = RandomLowercaseString(&rng, kLength);
1129 std::array<char, kLength> data_array;
1130 for (size_t i = 0; i < kLength; ++i) data_array[i] = data[i];
1131 bool invoked = false;
1132 auto releaser = [data_array, &invoked](absl::string_view data) {
1133 EXPECT_EQ(data, absl::string_view(data_array.data(), data_array.size()));
1134 invoked = true;
1135 };
1136 (void)absl::MakeCordFromExternal(data, releaser);
1137 EXPECT_TRUE(invoked);
1138 }
1139
TEST_P(CordTest,ConstructFromExternalFunctionPointerReleaser)1140 TEST_P(CordTest, ConstructFromExternalFunctionPointerReleaser) {
1141 static absl::string_view data("hello world");
1142 static bool invoked;
1143 auto* releaser =
1144 static_cast<void (*)(absl::string_view)>([](absl::string_view sv) {
1145 EXPECT_EQ(data, sv);
1146 invoked = true;
1147 });
1148 invoked = false;
1149 (void)absl::MakeCordFromExternal(data, releaser);
1150 EXPECT_TRUE(invoked);
1151
1152 invoked = false;
1153 (void)absl::MakeCordFromExternal(data, *releaser);
1154 EXPECT_TRUE(invoked);
1155 }
1156
TEST_P(CordTest,ConstructFromExternalMoveOnlyReleaser)1157 TEST_P(CordTest, ConstructFromExternalMoveOnlyReleaser) {
1158 struct Releaser {
1159 explicit Releaser(bool* invoked) : invoked(invoked) {}
1160 Releaser(Releaser&& other) noexcept : invoked(other.invoked) {}
1161 void operator()(absl::string_view) const { *invoked = true; }
1162
1163 bool* invoked;
1164 };
1165
1166 bool invoked = false;
1167 (void)absl::MakeCordFromExternal("dummy", Releaser(&invoked));
1168 EXPECT_TRUE(invoked);
1169 }
1170
TEST_P(CordTest,ConstructFromExternalNoArgLambda)1171 TEST_P(CordTest, ConstructFromExternalNoArgLambda) {
1172 bool invoked = false;
1173 (void)absl::MakeCordFromExternal("dummy", [&invoked]() { invoked = true; });
1174 EXPECT_TRUE(invoked);
1175 }
1176
TEST_P(CordTest,ConstructFromExternalStringViewArgLambda)1177 TEST_P(CordTest, ConstructFromExternalStringViewArgLambda) {
1178 bool invoked = false;
1179 (void)absl::MakeCordFromExternal(
1180 "dummy", [&invoked](absl::string_view) { invoked = true; });
1181 EXPECT_TRUE(invoked);
1182 }
1183
TEST_P(CordTest,ConstructFromExternalNonTrivialReleaserDestructor)1184 TEST_P(CordTest, ConstructFromExternalNonTrivialReleaserDestructor) {
1185 struct Releaser {
1186 explicit Releaser(bool* destroyed) : destroyed(destroyed) {}
1187 ~Releaser() { *destroyed = true; }
1188 void operator()(absl::string_view) const {}
1189
1190 bool* destroyed;
1191 };
1192
1193 bool destroyed = false;
1194 Releaser releaser(&destroyed);
1195 (void)absl::MakeCordFromExternal("dummy", releaser);
1196 EXPECT_TRUE(destroyed);
1197 }
1198
TEST_P(CordTest,ConstructFromExternalReferenceQualifierOverloads)1199 TEST_P(CordTest, ConstructFromExternalReferenceQualifierOverloads) {
1200 struct Releaser {
1201 void operator()(absl::string_view) & { *lvalue_invoked = true; }
1202 void operator()(absl::string_view) && { *rvalue_invoked = true; }
1203
1204 bool* lvalue_invoked;
1205 bool* rvalue_invoked;
1206 };
1207
1208 bool lvalue_invoked = false;
1209 bool rvalue_invoked = false;
1210 Releaser releaser = {&lvalue_invoked, &rvalue_invoked};
1211 (void)absl::MakeCordFromExternal("", releaser);
1212 EXPECT_FALSE(lvalue_invoked);
1213 EXPECT_TRUE(rvalue_invoked);
1214 rvalue_invoked = false;
1215
1216 (void)absl::MakeCordFromExternal("dummy", releaser);
1217 EXPECT_FALSE(lvalue_invoked);
1218 EXPECT_TRUE(rvalue_invoked);
1219 rvalue_invoked = false;
1220
1221 // NOLINTNEXTLINE: suppress clang-tidy std::move on trivially copyable type.
1222 (void)absl::MakeCordFromExternal("dummy", std::move(releaser));
1223 EXPECT_FALSE(lvalue_invoked);
1224 EXPECT_TRUE(rvalue_invoked);
1225 }
1226
TEST_P(CordTest,ExternalMemoryBasicUsage)1227 TEST_P(CordTest, ExternalMemoryBasicUsage) {
1228 static const char* strings[] = {"", "hello", "there"};
1229 for (const char* str : strings) {
1230 absl::Cord dst("(prefix)");
1231 AddExternalMemory(str, &dst);
1232 dst.Append("(suffix)");
1233 EXPECT_EQ((std::string("(prefix)") + str + std::string("(suffix)")),
1234 std::string(dst));
1235 }
1236 }
1237
TEST_P(CordTest,ExternalMemoryRemovePrefixSuffix)1238 TEST_P(CordTest, ExternalMemoryRemovePrefixSuffix) {
1239 // Exhaustively try all sub-strings.
1240 absl::Cord cord = MakeComposite();
1241 std::string s = std::string(cord);
1242 for (int offset = 0; offset <= s.size(); offset++) {
1243 for (int length = 0; length <= s.size() - offset; length++) {
1244 absl::Cord result(cord);
1245 result.RemovePrefix(offset);
1246 result.RemoveSuffix(result.size() - length);
1247 EXPECT_EQ(s.substr(offset, length), std::string(result))
1248 << offset << " " << length;
1249 }
1250 }
1251 }
1252
TEST_P(CordTest,ExternalMemoryGet)1253 TEST_P(CordTest, ExternalMemoryGet) {
1254 absl::Cord cord("hello");
1255 AddExternalMemory(" world!", &cord);
1256 AddExternalMemory(" how are ", &cord);
1257 cord.Append(" you?");
1258 std::string s = std::string(cord);
1259 for (int i = 0; i < s.size(); i++) {
1260 EXPECT_EQ(s[i], cord[i]);
1261 }
1262 }
1263
1264 // CordMemoryUsage tests verify the correctness of the EstimatedMemoryUsage()
1265 // These tests take into account that the reported memory usage is approximate
1266 // and non-deterministic. For all tests, We verify that the reported memory
1267 // usage is larger than `size()`, and less than `size() * 1.5` as a cord should
1268 // never reserve more 'extra' capacity than half of its size as it grows.
1269 // Additionally we have some whiteboxed expectations based on our knowledge of
1270 // the layout and size of empty and inlined cords, and flat nodes.
1271
TEST_P(CordTest,CordMemoryUsageEmpty)1272 TEST_P(CordTest, CordMemoryUsageEmpty) {
1273 EXPECT_EQ(sizeof(absl::Cord), absl::Cord().EstimatedMemoryUsage());
1274 }
1275
TEST_P(CordTest,CordMemoryUsageEmbedded)1276 TEST_P(CordTest, CordMemoryUsageEmbedded) {
1277 absl::Cord a("hello");
1278 EXPECT_EQ(a.EstimatedMemoryUsage(), sizeof(absl::Cord));
1279 }
1280
TEST_P(CordTest,CordMemoryUsageEmbeddedAppend)1281 TEST_P(CordTest, CordMemoryUsageEmbeddedAppend) {
1282 absl::Cord a("a");
1283 absl::Cord b("bcd");
1284 EXPECT_EQ(b.EstimatedMemoryUsage(), sizeof(absl::Cord));
1285 a.Append(b);
1286 EXPECT_EQ(a.EstimatedMemoryUsage(), sizeof(absl::Cord));
1287 }
1288
TEST_P(CordTest,CordMemoryUsageExternalMemory)1289 TEST_P(CordTest, CordMemoryUsageExternalMemory) {
1290 static const int kLength = 1000;
1291 absl::Cord cord;
1292 AddExternalMemory(std::string(kLength, 'x'), &cord);
1293 EXPECT_GT(cord.EstimatedMemoryUsage(), kLength);
1294 EXPECT_LE(cord.EstimatedMemoryUsage(), kLength * 1.5);
1295 }
1296
TEST_P(CordTest,CordMemoryUsageFlat)1297 TEST_P(CordTest, CordMemoryUsageFlat) {
1298 static const int kLength = 125;
1299 absl::Cord a(std::string(kLength, 'a'));
1300 EXPECT_GT(a.EstimatedMemoryUsage(), kLength);
1301 EXPECT_LE(a.EstimatedMemoryUsage(), kLength * 1.5);
1302 }
1303
TEST_P(CordTest,CordMemoryUsageAppendFlat)1304 TEST_P(CordTest, CordMemoryUsageAppendFlat) {
1305 using absl::strings_internal::CordTestAccess;
1306 absl::Cord a(std::string(CordTestAccess::MaxFlatLength(), 'a'));
1307 size_t length = a.EstimatedMemoryUsage();
1308 a.Append(std::string(CordTestAccess::MaxFlatLength(), 'b'));
1309 size_t delta = a.EstimatedMemoryUsage() - length;
1310 EXPECT_GT(delta, CordTestAccess::MaxFlatLength());
1311 EXPECT_LE(delta, CordTestAccess::MaxFlatLength() * 1.5);
1312 }
1313
TEST_P(CordTest,CordMemoryUsageAppendExternal)1314 TEST_P(CordTest, CordMemoryUsageAppendExternal) {
1315 static const int kLength = 1000;
1316 using absl::strings_internal::CordTestAccess;
1317 absl::Cord a(std::string(CordTestAccess::MaxFlatLength(), 'a'));
1318 size_t length = a.EstimatedMemoryUsage();
1319 AddExternalMemory(std::string(kLength, 'b'), &a);
1320 size_t delta = a.EstimatedMemoryUsage() - length;
1321 EXPECT_GT(delta, kLength);
1322 EXPECT_LE(delta, kLength * 1.5);
1323 }
1324
TEST_P(CordTest,CordMemoryUsageSubString)1325 TEST_P(CordTest, CordMemoryUsageSubString) {
1326 static const int kLength = 2000;
1327 using absl::strings_internal::CordTestAccess;
1328 absl::Cord a(std::string(kLength, 'a'));
1329 size_t length = a.EstimatedMemoryUsage();
1330 AddExternalMemory(std::string(kLength, 'b'), &a);
1331 absl::Cord b = a.Subcord(0, kLength + kLength / 2);
1332 size_t delta = b.EstimatedMemoryUsage() - length;
1333 EXPECT_GT(delta, kLength);
1334 EXPECT_LE(delta, kLength * 1.5);
1335 }
1336
1337 // Regtest for a change that had to be rolled back because it expanded out
1338 // of the InlineRep too soon, which was observable through MemoryUsage().
TEST_P(CordTest,CordMemoryUsageInlineRep)1339 TEST_P(CordTest, CordMemoryUsageInlineRep) {
1340 constexpr size_t kMaxInline = 15; // Cord::InlineRep::N
1341 const std::string small_string(kMaxInline, 'x');
1342 absl::Cord c1(small_string);
1343
1344 absl::Cord c2;
1345 c2.Append(small_string);
1346 EXPECT_EQ(c1, c2);
1347 EXPECT_EQ(c1.EstimatedMemoryUsage(), c2.EstimatedMemoryUsage());
1348 }
1349
1350 } // namespace
1351
1352 // Regtest for 7510292 (fix a bug introduced by 7465150)
TEST_P(CordTest,Concat_Append)1353 TEST_P(CordTest, Concat_Append) {
1354 // Create a rep of type CONCAT
1355 absl::Cord s1("foobarbarbarbarbar");
1356 s1.Append("abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg");
1357 size_t size = s1.size();
1358
1359 // Create a copy of s1 and append to it.
1360 absl::Cord s2 = s1;
1361 s2.Append("x");
1362
1363 // 7465150 modifies s1 when it shouldn't.
1364 EXPECT_EQ(s1.size(), size);
1365 EXPECT_EQ(s2.size(), size + 1);
1366 }
1367
TEST_P(CordTest,DiabolicalGrowth)1368 TEST_P(CordTest, DiabolicalGrowth) {
1369 // This test exercises a diabolical Append(<one char>) on a cord, making the
1370 // cord shared before each Append call resulting in a terribly fragmented
1371 // resulting cord.
1372 // TODO(b/183983616): Apply some minimum compaction when copying a shared
1373 // source cord into a mutable copy for updates in CordRepRing.
1374 RandomEngine rng(GTEST_FLAG_GET(random_seed));
1375 const std::string expected = RandomLowercaseString(&rng, 5000);
1376 absl::Cord cord;
1377 for (char c : expected) {
1378 absl::Cord shared(cord);
1379 cord.Append(absl::string_view(&c, 1));
1380 }
1381 std::string value;
1382 absl::CopyCordToString(cord, &value);
1383 EXPECT_EQ(value, expected);
1384 ABSL_RAW_LOG(INFO, "Diabolical size allocated = %zu",
1385 cord.EstimatedMemoryUsage());
1386 }
1387
TEST_P(CordTest,MakeFragmentedCordFromInitializerList)1388 TEST_P(CordTest, MakeFragmentedCordFromInitializerList) {
1389 absl::Cord fragmented =
1390 absl::MakeFragmentedCord({"A ", "fragmented ", "Cord"});
1391
1392 EXPECT_EQ("A fragmented Cord", fragmented);
1393
1394 auto chunk_it = fragmented.chunk_begin();
1395
1396 ASSERT_TRUE(chunk_it != fragmented.chunk_end());
1397 EXPECT_EQ("A ", *chunk_it);
1398
1399 ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
1400 EXPECT_EQ("fragmented ", *chunk_it);
1401
1402 ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
1403 EXPECT_EQ("Cord", *chunk_it);
1404
1405 ASSERT_TRUE(++chunk_it == fragmented.chunk_end());
1406 }
1407
TEST_P(CordTest,MakeFragmentedCordFromVector)1408 TEST_P(CordTest, MakeFragmentedCordFromVector) {
1409 std::vector<absl::string_view> chunks = {"A ", "fragmented ", "Cord"};
1410 absl::Cord fragmented = absl::MakeFragmentedCord(chunks);
1411
1412 EXPECT_EQ("A fragmented Cord", fragmented);
1413
1414 auto chunk_it = fragmented.chunk_begin();
1415
1416 ASSERT_TRUE(chunk_it != fragmented.chunk_end());
1417 EXPECT_EQ("A ", *chunk_it);
1418
1419 ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
1420 EXPECT_EQ("fragmented ", *chunk_it);
1421
1422 ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
1423 EXPECT_EQ("Cord", *chunk_it);
1424
1425 ASSERT_TRUE(++chunk_it == fragmented.chunk_end());
1426 }
1427
TEST_P(CordTest,CordChunkIteratorTraits)1428 TEST_P(CordTest, CordChunkIteratorTraits) {
1429 static_assert(std::is_copy_constructible<absl::Cord::ChunkIterator>::value,
1430 "");
1431 static_assert(std::is_copy_assignable<absl::Cord::ChunkIterator>::value, "");
1432
1433 // Move semantics to satisfy swappable via std::swap
1434 static_assert(std::is_move_constructible<absl::Cord::ChunkIterator>::value,
1435 "");
1436 static_assert(std::is_move_assignable<absl::Cord::ChunkIterator>::value, "");
1437
1438 static_assert(
1439 std::is_same<
1440 std::iterator_traits<absl::Cord::ChunkIterator>::iterator_category,
1441 std::input_iterator_tag>::value,
1442 "");
1443 static_assert(
1444 std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::value_type,
1445 absl::string_view>::value,
1446 "");
1447 static_assert(
1448 std::is_same<
1449 std::iterator_traits<absl::Cord::ChunkIterator>::difference_type,
1450 ptrdiff_t>::value,
1451 "");
1452 static_assert(
1453 std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::pointer,
1454 const absl::string_view*>::value,
1455 "");
1456 static_assert(
1457 std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::reference,
1458 absl::string_view>::value,
1459 "");
1460 }
1461
VerifyChunkIterator(const absl::Cord & cord,size_t expected_chunks)1462 static void VerifyChunkIterator(const absl::Cord& cord,
1463 size_t expected_chunks) {
1464 EXPECT_EQ(cord.chunk_begin() == cord.chunk_end(), cord.empty()) << cord;
1465 EXPECT_EQ(cord.chunk_begin() != cord.chunk_end(), !cord.empty());
1466
1467 absl::Cord::ChunkRange range = cord.Chunks();
1468 EXPECT_EQ(range.begin() == range.end(), cord.empty());
1469 EXPECT_EQ(range.begin() != range.end(), !cord.empty());
1470
1471 std::string content(cord);
1472 size_t pos = 0;
1473 auto pre_iter = cord.chunk_begin(), post_iter = cord.chunk_begin();
1474 size_t n_chunks = 0;
1475 while (pre_iter != cord.chunk_end() && post_iter != cord.chunk_end()) {
1476 EXPECT_FALSE(pre_iter == cord.chunk_end()); // NOLINT: explicitly test ==
1477 EXPECT_FALSE(post_iter == cord.chunk_end()); // NOLINT
1478
1479 EXPECT_EQ(pre_iter, post_iter);
1480 EXPECT_EQ(*pre_iter, *post_iter);
1481
1482 EXPECT_EQ(pre_iter->data(), (*pre_iter).data());
1483 EXPECT_EQ(pre_iter->size(), (*pre_iter).size());
1484
1485 absl::string_view chunk = *pre_iter;
1486 EXPECT_FALSE(chunk.empty());
1487 EXPECT_LE(pos + chunk.size(), content.size());
1488 EXPECT_EQ(absl::string_view(content.c_str() + pos, chunk.size()), chunk);
1489
1490 int n_equal_iterators = 0;
1491 for (absl::Cord::ChunkIterator it = range.begin(); it != range.end();
1492 ++it) {
1493 n_equal_iterators += static_cast<int>(it == pre_iter);
1494 }
1495 EXPECT_EQ(n_equal_iterators, 1);
1496
1497 ++pre_iter;
1498 EXPECT_EQ(*post_iter++, chunk);
1499
1500 pos += chunk.size();
1501 ++n_chunks;
1502 }
1503 EXPECT_EQ(expected_chunks, n_chunks);
1504 EXPECT_EQ(pos, content.size());
1505 EXPECT_TRUE(pre_iter == cord.chunk_end()); // NOLINT: explicitly test ==
1506 EXPECT_TRUE(post_iter == cord.chunk_end()); // NOLINT
1507 }
1508
TEST_P(CordTest,CordChunkIteratorOperations)1509 TEST_P(CordTest, CordChunkIteratorOperations) {
1510 absl::Cord empty_cord;
1511 VerifyChunkIterator(empty_cord, 0);
1512
1513 absl::Cord small_buffer_cord("small cord");
1514 VerifyChunkIterator(small_buffer_cord, 1);
1515
1516 absl::Cord flat_node_cord("larger than small buffer optimization");
1517 VerifyChunkIterator(flat_node_cord, 1);
1518
1519 VerifyChunkIterator(
1520 absl::MakeFragmentedCord({"a ", "small ", "fragmented ", "cord ", "for ",
1521 "testing ", "chunk ", "iterations."}),
1522 8);
1523
1524 absl::Cord reused_nodes_cord(std::string(40, 'c'));
1525 reused_nodes_cord.Prepend(absl::Cord(std::string(40, 'b')));
1526 reused_nodes_cord.Prepend(absl::Cord(std::string(40, 'a')));
1527 size_t expected_chunks = 3;
1528 for (int i = 0; i < 8; ++i) {
1529 reused_nodes_cord.Prepend(reused_nodes_cord);
1530 expected_chunks *= 2;
1531 VerifyChunkIterator(reused_nodes_cord, expected_chunks);
1532 }
1533
1534 RandomEngine rng(GTEST_FLAG_GET(random_seed));
1535 absl::Cord flat_cord(RandomLowercaseString(&rng, 256));
1536 absl::Cord subcords;
1537 for (int i = 0; i < 128; ++i) subcords.Prepend(flat_cord.Subcord(i, 128));
1538 VerifyChunkIterator(subcords, 128);
1539 }
1540
TEST(CordCharIterator,Traits)1541 TEST(CordCharIterator, Traits) {
1542 static_assert(std::is_copy_constructible<absl::Cord::CharIterator>::value,
1543 "");
1544 static_assert(std::is_copy_assignable<absl::Cord::CharIterator>::value, "");
1545
1546 // Move semantics to satisfy swappable via std::swap
1547 static_assert(std::is_move_constructible<absl::Cord::CharIterator>::value,
1548 "");
1549 static_assert(std::is_move_assignable<absl::Cord::CharIterator>::value, "");
1550
1551 static_assert(
1552 std::is_same<
1553 std::iterator_traits<absl::Cord::CharIterator>::iterator_category,
1554 std::input_iterator_tag>::value,
1555 "");
1556 static_assert(
1557 std::is_same<std::iterator_traits<absl::Cord::CharIterator>::value_type,
1558 char>::value,
1559 "");
1560 static_assert(
1561 std::is_same<
1562 std::iterator_traits<absl::Cord::CharIterator>::difference_type,
1563 ptrdiff_t>::value,
1564 "");
1565 static_assert(
1566 std::is_same<std::iterator_traits<absl::Cord::CharIterator>::pointer,
1567 const char*>::value,
1568 "");
1569 static_assert(
1570 std::is_same<std::iterator_traits<absl::Cord::CharIterator>::reference,
1571 const char&>::value,
1572 "");
1573 }
1574
VerifyCharIterator(const absl::Cord & cord)1575 static void VerifyCharIterator(const absl::Cord& cord) {
1576 EXPECT_EQ(cord.char_begin() == cord.char_end(), cord.empty());
1577 EXPECT_EQ(cord.char_begin() != cord.char_end(), !cord.empty());
1578
1579 absl::Cord::CharRange range = cord.Chars();
1580 EXPECT_EQ(range.begin() == range.end(), cord.empty());
1581 EXPECT_EQ(range.begin() != range.end(), !cord.empty());
1582
1583 size_t i = 0;
1584 absl::Cord::CharIterator pre_iter = cord.char_begin();
1585 absl::Cord::CharIterator post_iter = cord.char_begin();
1586 std::string content(cord);
1587 while (pre_iter != cord.char_end() && post_iter != cord.char_end()) {
1588 EXPECT_FALSE(pre_iter == cord.char_end()); // NOLINT: explicitly test ==
1589 EXPECT_FALSE(post_iter == cord.char_end()); // NOLINT
1590
1591 EXPECT_LT(i, cord.size());
1592 EXPECT_EQ(content[i], *pre_iter);
1593
1594 EXPECT_EQ(pre_iter, post_iter);
1595 EXPECT_EQ(*pre_iter, *post_iter);
1596 EXPECT_EQ(&*pre_iter, &*post_iter);
1597
1598 EXPECT_EQ(&*pre_iter, pre_iter.operator->());
1599
1600 const char* character_address = &*pre_iter;
1601 absl::Cord::CharIterator copy = pre_iter;
1602 ++copy;
1603 EXPECT_EQ(character_address, &*pre_iter);
1604
1605 int n_equal_iterators = 0;
1606 for (absl::Cord::CharIterator it = range.begin(); it != range.end(); ++it) {
1607 n_equal_iterators += static_cast<int>(it == pre_iter);
1608 }
1609 EXPECT_EQ(n_equal_iterators, 1);
1610
1611 absl::Cord::CharIterator advance_iter = range.begin();
1612 absl::Cord::Advance(&advance_iter, i);
1613 EXPECT_EQ(pre_iter, advance_iter);
1614
1615 advance_iter = range.begin();
1616 EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, i), cord.Subcord(0, i));
1617 EXPECT_EQ(pre_iter, advance_iter);
1618
1619 advance_iter = pre_iter;
1620 absl::Cord::Advance(&advance_iter, cord.size() - i);
1621 EXPECT_EQ(range.end(), advance_iter);
1622
1623 advance_iter = pre_iter;
1624 EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, cord.size() - i),
1625 cord.Subcord(i, cord.size() - i));
1626 EXPECT_EQ(range.end(), advance_iter);
1627
1628 ++i;
1629 ++pre_iter;
1630 post_iter++;
1631 }
1632 EXPECT_EQ(i, cord.size());
1633 EXPECT_TRUE(pre_iter == cord.char_end()); // NOLINT: explicitly test ==
1634 EXPECT_TRUE(post_iter == cord.char_end()); // NOLINT
1635
1636 absl::Cord::CharIterator zero_advanced_end = cord.char_end();
1637 absl::Cord::Advance(&zero_advanced_end, 0);
1638 EXPECT_EQ(zero_advanced_end, cord.char_end());
1639
1640 absl::Cord::CharIterator it = cord.char_begin();
1641 for (absl::string_view chunk : cord.Chunks()) {
1642 while (!chunk.empty()) {
1643 EXPECT_EQ(absl::Cord::ChunkRemaining(it), chunk);
1644 chunk.remove_prefix(1);
1645 ++it;
1646 }
1647 }
1648 }
1649
TEST(CordCharIterator,Operations)1650 TEST(CordCharIterator, Operations) {
1651 absl::Cord empty_cord;
1652 VerifyCharIterator(empty_cord);
1653
1654 absl::Cord small_buffer_cord("small cord");
1655 VerifyCharIterator(small_buffer_cord);
1656
1657 absl::Cord flat_node_cord("larger than small buffer optimization");
1658 VerifyCharIterator(flat_node_cord);
1659
1660 VerifyCharIterator(
1661 absl::MakeFragmentedCord({"a ", "small ", "fragmented ", "cord ", "for ",
1662 "testing ", "character ", "iteration."}));
1663
1664 absl::Cord reused_nodes_cord("ghi");
1665 reused_nodes_cord.Prepend(absl::Cord("def"));
1666 reused_nodes_cord.Prepend(absl::Cord("abc"));
1667 for (int i = 0; i < 4; ++i) {
1668 reused_nodes_cord.Prepend(reused_nodes_cord);
1669 VerifyCharIterator(reused_nodes_cord);
1670 }
1671
1672 RandomEngine rng(GTEST_FLAG_GET(random_seed));
1673 absl::Cord flat_cord(RandomLowercaseString(&rng, 256));
1674 absl::Cord subcords;
1675 for (int i = 0; i < 4; ++i) subcords.Prepend(flat_cord.Subcord(16 * i, 128));
1676 VerifyCharIterator(subcords);
1677 }
1678
TEST_P(CordTest,StreamingOutput)1679 TEST_P(CordTest, StreamingOutput) {
1680 absl::Cord c =
1681 absl::MakeFragmentedCord({"A ", "small ", "fragmented ", "Cord", "."});
1682 std::stringstream output;
1683 output << c;
1684 EXPECT_EQ("A small fragmented Cord.", output.str());
1685 }
1686
TEST_P(CordTest,ForEachChunk)1687 TEST_P(CordTest, ForEachChunk) {
1688 for (int num_elements : {1, 10, 200}) {
1689 SCOPED_TRACE(num_elements);
1690 std::vector<std::string> cord_chunks;
1691 for (int i = 0; i < num_elements; ++i) {
1692 cord_chunks.push_back(absl::StrCat("[", i, "]"));
1693 }
1694 absl::Cord c = absl::MakeFragmentedCord(cord_chunks);
1695
1696 std::vector<std::string> iterated_chunks;
1697 absl::CordTestPeer::ForEachChunk(c,
1698 [&iterated_chunks](absl::string_view sv) {
1699 iterated_chunks.emplace_back(sv);
1700 });
1701 EXPECT_EQ(iterated_chunks, cord_chunks);
1702 }
1703 }
1704
TEST_P(CordTest,SmallBufferAssignFromOwnData)1705 TEST_P(CordTest, SmallBufferAssignFromOwnData) {
1706 constexpr size_t kMaxInline = 15;
1707 std::string contents = "small buff cord";
1708 EXPECT_EQ(contents.size(), kMaxInline);
1709 for (size_t pos = 0; pos < contents.size(); ++pos) {
1710 for (size_t count = contents.size() - pos; count > 0; --count) {
1711 absl::Cord c(contents);
1712 absl::string_view flat = c.Flatten();
1713 c = flat.substr(pos, count);
1714 EXPECT_EQ(c, contents.substr(pos, count))
1715 << "pos = " << pos << "; count = " << count;
1716 }
1717 }
1718 }
1719
TEST_P(CordTest,Format)1720 TEST_P(CordTest, Format) {
1721 absl::Cord c;
1722 absl::Format(&c, "There were %04d little %s.", 3, "pigs");
1723 EXPECT_EQ(c, "There were 0003 little pigs.");
1724 absl::Format(&c, "And %-3llx bad wolf!", 1);
1725 EXPECT_EQ(c, "There were 0003 little pigs.And 1 bad wolf!");
1726 }
1727
TEST(CordDeathTest,Hardening)1728 TEST(CordDeathTest, Hardening) {
1729 absl::Cord cord("hello");
1730 // These statement should abort the program in all builds modes.
1731 EXPECT_DEATH_IF_SUPPORTED(cord.RemovePrefix(6), "");
1732 EXPECT_DEATH_IF_SUPPORTED(cord.RemoveSuffix(6), "");
1733
1734 bool test_hardening = false;
1735 ABSL_HARDENING_ASSERT([&]() {
1736 // This only runs when ABSL_HARDENING_ASSERT is active.
1737 test_hardening = true;
1738 return true;
1739 }());
1740 if (!test_hardening) return;
1741
1742 EXPECT_DEATH_IF_SUPPORTED(cord[5], "");
1743 EXPECT_DEATH_IF_SUPPORTED(*cord.chunk_end(), "");
1744 EXPECT_DEATH_IF_SUPPORTED(static_cast<void>(cord.chunk_end()->empty()), "");
1745 EXPECT_DEATH_IF_SUPPORTED(++cord.chunk_end(), "");
1746 }
1747
1748 class AfterExitCordTester {
1749 public:
Set(absl::Cord * cord,absl::string_view expected)1750 bool Set(absl::Cord* cord, absl::string_view expected) {
1751 cord_ = cord;
1752 expected_ = expected;
1753 return true;
1754 }
1755
~AfterExitCordTester()1756 ~AfterExitCordTester() {
1757 EXPECT_EQ(*cord_, expected_);
1758 }
1759 private:
1760 absl::Cord* cord_;
1761 absl::string_view expected_;
1762 };
1763
1764 template <typename Str>
TestConstinitConstructor(Str)1765 void TestConstinitConstructor(Str) {
1766 const auto expected = Str::value;
1767 // Defined before `cord` to be destroyed after it.
1768 static AfterExitCordTester exit_tester; // NOLINT
1769 ABSL_CONST_INIT static absl::Cord cord(Str{}); // NOLINT
1770 static bool init_exit_tester = exit_tester.Set(&cord, expected);
1771 (void)init_exit_tester;
1772
1773 EXPECT_EQ(cord, expected);
1774 // Copy the object and test the copy, and the original.
1775 {
1776 absl::Cord copy = cord;
1777 EXPECT_EQ(copy, expected);
1778 }
1779 // The original still works
1780 EXPECT_EQ(cord, expected);
1781
1782 // Try making adding more structure to the tree.
1783 {
1784 absl::Cord copy = cord;
1785 std::string expected_copy(expected);
1786 for (int i = 0; i < 10; ++i) {
1787 copy.Append(cord);
1788 absl::StrAppend(&expected_copy, expected);
1789 EXPECT_EQ(copy, expected_copy);
1790 }
1791 }
1792
1793 // Make sure we are using the right branch during constant evaluation.
1794 EXPECT_EQ(absl::CordTestPeer::IsTree(cord), cord.size() >= 16);
1795
1796 for (int i = 0; i < 10; ++i) {
1797 // Make a few more Cords from the same global rep.
1798 // This tests what happens when the refcount for it gets below 1.
1799 EXPECT_EQ(expected, absl::Cord(Str{}));
1800 }
1801 }
1802
SimpleStrlen(const char * p)1803 constexpr int SimpleStrlen(const char* p) {
1804 return *p ? 1 + SimpleStrlen(p + 1) : 0;
1805 }
1806
1807 struct ShortView {
operator ()ShortView1808 constexpr absl::string_view operator()() const {
1809 return absl::string_view("SSO string", SimpleStrlen("SSO string"));
1810 }
1811 };
1812
1813 struct LongView {
operator ()LongView1814 constexpr absl::string_view operator()() const {
1815 return absl::string_view("String that does not fit SSO.",
1816 SimpleStrlen("String that does not fit SSO."));
1817 }
1818 };
1819
1820
TEST_P(CordTest,ConstinitConstructor)1821 TEST_P(CordTest, ConstinitConstructor) {
1822 TestConstinitConstructor(
1823 absl::strings_internal::MakeStringConstant(ShortView{}));
1824 TestConstinitConstructor(
1825 absl::strings_internal::MakeStringConstant(LongView{}));
1826 }
1827