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