23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "absl/base/config.h"
26 #include "absl/base/internal/raw_logging.h"
27 #include "absl/cleanup/cleanup.h"
29 #include "absl/strings/internal/cord_internal.h"
31 #include "absl/strings/str_cat.h"
32 #include "absl/strings/string_view.h"
36 namespace cord_internal {
50 using ::absl::cordrep_testing::AutoUnref;
62 using ::testing::Conditional;
75 *result_listener <<
"Expected FLAT, got tag " <<
static_cast<int>(
arg->tag);
80 *result_listener <<
"Expected flat holding \"" <<
data
81 <<
"\", got flat holding \"" << actual <<
"\"";
89 *result_listener <<
"Expected NODE, got nullptr";
93 *result_listener <<
"Expected NODE, got " <<
static_cast<int>(
arg->tag);
98 *result_listener->stream());
102 *result_listener <<
"Expected NODE of height " <<
height <<
", got "
103 <<
arg->btree()->height();
112 if (
arg ==
nullptr) {
113 *result_listener <<
"Expected substring, got nullptr";
117 *result_listener <<
"Expected SUBSTRING, got "
118 <<
static_cast<int>(
arg->tag);
121 const CordRepSubstring*
const substr =
arg->substring();
122 if (substr->start !=
start || substr->length !=
length) {
123 *result_listener <<
"Expected substring(" <<
start <<
", " <<
length
124 <<
"), got substring(" << substr->start <<
", "
125 << substr->length <<
")";
131 MATCHER_P2(EqExtractResult, tree,
rep,
"Equals ExtractResult") {
132 if (
arg.tree != tree ||
arg.extracted !=
rep) {
133 *result_listener <<
"Expected {" <<
static_cast<const void*
>(tree) <<
", "
134 <<
static_cast<const void*
>(
rep) <<
"}, got {" <<
arg.tree
135 <<
", " <<
arg.extracted <<
"}";
171 CordRepBtree* BtreeAdd(CordRepBtree* node,
bool append,
178 void GetLeafEdges(
const CordRepBtree* tree, std::vector<CordRep*>& edges) {
179 if (tree->height() == 0) {
180 for (CordRep* edge : tree->Edges()) {
181 edges.push_back(edge);
184 for (CordRep* edge : tree->Edges()) {
185 GetLeafEdges(edge->btree(), edges);
191 std::vector<CordRep*> GetLeafEdges(
const CordRepBtree* tree) {
192 std::vector<CordRep*> edges;
193 GetLeafEdges(tree, edges);
199 CordRepFlat* MakeHexFlat(
size_t i) {
206 for (
size_t i = 1;
i <
size; ++
i) {
212 CordRepBtree* MakeTree(
size_t size,
bool append =
true) {
214 for (
size_t i = 1;
i <
size; ++
i) {
216 : CordRepBtree::Prepend(tree, MakeHexFlat(
i));
234 auto rit = flats.rbegin();
242 bool shared()
const {
return GetParam(); }
245 return param.
param ?
"Shared" :
"Private";
254 int height()
const {
return GetParam(); }
265 using TwoBools = testing::tuple<bool, bool>;
269 bool first_shared()
const {
return std::get<0>(GetParam()); }
270 bool second_shared()
const {
return std::get<1>(GetParam()); }
273 if (std::get<0>(param.
param)) {
274 return std::get<1>(param.
param) ?
"BothShared" :
"FirstShared";
276 return std::get<1>(param.
param) ?
"SecondShared" :
"Private";
284 TEST(CordRepBtreeTest, SizeIsMultipleOf64) {
286 if (
sizeof(
size_t) == 8 &&
sizeof(
void*) == 8) {
287 EXPECT_THAT(
sizeof(CordRepBtree) % 64,
Eq(0)) <<
"Should be multiple of 64";
291 TEST(CordRepBtreeTest, NewDestroyEmptyTree) {
299 TEST(CordRepBtreeTest, NewDestroyEmptyTreeAtHeight) {
307 TEST(CordRepBtreeTest, Btree) {
312 #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
315 EXPECT_DEATH(
static_cast<const CordRep*
>(
rep)->btree(),
".*");
321 CordRepFlat* flat =
MakeFlat(
"Hello world");
322 CordRepExternal* external =
MakeExternal(
"Hello external");
341 TypedEq<const void*>(external->base + 1));
345 #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
346 EXPECT_DEATH(
EdgeData(bad_substr),
".*");
356 TEST(CordRepBtreeTest, CreateUnrefLeaf) {
365 TEST(CordRepBtreeTest, NewUnrefNode) {
374 TEST_P(CordRepBtreeTest, AppendToLeafToCapacity) {
376 std::vector<CordRep*> flats;
377 flats.push_back(MakeHexFlat(0));
381 refs.RefIf(shared(), leaf);
382 flats.push_back(MakeHexFlat(i));
392 TEST_P(CordRepBtreeTest, PrependToLeafToCapacity) {
394 std::deque<CordRep*> flats;
395 flats.push_front(MakeHexFlat(0));
399 refs.RefIf(shared(), leaf);
400 flats.push_front(MakeHexFlat(i));
413 TEST_P(CordRepBtreeTest, AppendPrependToLeafToCapacity) {
415 std::deque<CordRep*> flats;
416 flats.push_front(MakeHexFlat(0));
420 refs.RefIf(shared(), leaf);
423 flats.push_front(MakeHexFlat(i));
426 flats.push_back(MakeHexFlat(i));
437 TEST_P(CordRepBtreeTest, AppendToLeafBeyondCapacity) {
440 refs.RefIf(shared(), leaf);
451 TEST_P(CordRepBtreeTest, PrependToLeafBeyondCapacity) {
454 refs.RefIf(shared(), leaf);
465 TEST_P(CordRepBtreeTest, AppendToTreeOneDeep) {
468 std::vector<CordRep*> flats;
469 flats.push_back(MakeHexFlat(0));
471 for (
size_t i = 1;
i <= max_cap; ++
i) {
472 flats.push_back(MakeHexFlat(i));
477 for (
size_t i = max_cap + 1;
i < max_cap * max_cap; ++
i) {
481 refs.RefIf(shared(), tree);
482 refs.RefIf(i % 4 == 0, tree->Edges().back());
484 flats.push_back(MakeHexFlat(i));
488 std::vector<CordRep*> edges = GetLeafEdges(
result);
495 TEST_P(CordRepBtreeTest, AppendToTreeTwoDeep) {
498 std::vector<CordRep*> flats;
499 flats.push_back(MakeHexFlat(0));
501 for (
size_t i = 1;
i <= max_cap * max_cap; ++
i) {
502 flats.push_back(MakeHexFlat(i));
506 for (
size_t i = max_cap * max_cap + 1;
i < max_cap * max_cap * max_cap; ++
i) {
511 refs.RefIf(shared(), tree);
512 refs.RefIf(i % 16 == 0, tree->Edges().back());
513 refs.RefIf(i % 4 == 0, tree->Edges().back()->btree()->Edges().back());
515 flats.push_back(MakeHexFlat(i));
519 std::vector<CordRep*> edges = GetLeafEdges(
result);
526 TEST_P(CordRepBtreeTest, PrependToTreeOneDeep) {
529 std::deque<CordRep*> flats;
530 flats.push_back(MakeHexFlat(0));
532 for (
size_t i = 1;
i <= max_cap; ++
i) {
533 flats.push_front(MakeHexFlat(i));
538 for (
size_t i = max_cap + 1;
i < max_cap * max_cap; ++
i) {
542 refs.RefIf(shared(), tree);
543 refs.RefIf(i % 4 == 0, tree->Edges().back());
545 flats.push_front(MakeHexFlat(i));
549 std::vector<CordRep*> edges = GetLeafEdges(
result);
556 TEST_P(CordRepBtreeTest, PrependToTreeTwoDeep) {
559 std::deque<CordRep*> flats;
560 flats.push_back(MakeHexFlat(0));
562 for (
size_t i = 1;
i <= max_cap * max_cap; ++
i) {
563 flats.push_front(MakeHexFlat(i));
567 for (
size_t i = max_cap * max_cap + 1;
i < max_cap * max_cap * max_cap; ++
i) {
572 refs.RefIf(shared(), tree);
573 refs.RefIf(i % 16 == 0, tree->Edges().back());
574 refs.RefIf(i % 4 == 0, tree->Edges().back()->btree()->Edges().back());
576 flats.push_front(MakeHexFlat(i));
580 std::vector<CordRep*> edges = GetLeafEdges(
result);
587 TEST_P(CordRepBtreeDualTest, MergeLeafsNotExceedingCapacity) {
588 for (
bool use_append : {
false,
true}) {
589 SCOPED_TRACE(use_append ?
"Using Append" :
"Using Prepend");
592 std::vector<CordRep*> flats;
596 GetLeafEdges(left, flats);
597 refs.RefIf(first_shared(), left);
601 GetLeafEdges(right, flats);
602 refs.RefIf(second_shared(), right);
605 : CordRepBtree::Prepend(right, left);
614 TEST_P(CordRepBtreeDualTest, MergeLeafsExceedingCapacity) {
615 for (
bool use_append : {
false,
true}) {
616 SCOPED_TRACE(use_append ?
"Using Append" :
"Using Prepend");
622 refs.RefIf(first_shared(), left);
626 refs.RefIf(second_shared(), right);
629 : CordRepBtree::Prepend(right, left);
636 TEST_P(CordRepBtreeDualTest, MergeEqualHeightTrees) {
637 for (
bool use_append : {
false,
true}) {
638 SCOPED_TRACE(use_append ?
"Using Append" :
"Using Prepend");
641 std::vector<CordRep*> flats;
645 GetLeafEdges(left, flats);
646 refs.RefIf(first_shared(), left);
650 GetLeafEdges(right, flats);
651 refs.RefIf(second_shared(), right);
654 : CordRepBtree::Prepend(right, left);
664 TEST_P(CordRepBtreeDualTest, MergeLeafWithTreeNotExceedingLeafCapacity) {
665 for (
bool use_append : {
false,
true}) {
666 SCOPED_TRACE(use_append ?
"Using Append" :
"Using Prepend");
669 std::vector<CordRep*> flats;
673 GetLeafEdges(left, flats);
674 refs.RefIf(first_shared(), left);
677 CordRepBtree* right = MakeTree(3);
678 GetLeafEdges(right, flats);
679 refs.RefIf(second_shared(), right);
682 : CordRepBtree::Prepend(right, left);
692 TEST_P(CordRepBtreeDualTest, MergeLeafWithTreeExceedingLeafCapacity) {
693 for (
bool use_append : {
false,
true}) {
694 SCOPED_TRACE(use_append ?
"Using Append" :
"Using Prepend");
697 std::vector<CordRep*> flats;
701 GetLeafEdges(left, flats);
702 refs.RefIf(first_shared(), left);
705 CordRepBtree* right = MakeTree(3);
706 GetLeafEdges(right, flats);
707 refs.RefIf(second_shared(), right);
710 : CordRepBtree::Prepend(right, left);
720 void RefEdgesAt(
size_t depth, AutoUnref&
refs, CordRepBtree* tree) {
726 assert(tree->height() > 0);
732 TEST(CordRepBtreeTest, MergeFuzzTest) {
734 std::minstd_rand rnd;
735 std::uniform_int_distribution<int> coin_flip(0, 1);
736 std::uniform_int_distribution<int> dice_throw(1, 6);
738 auto random_leaf_count = [&]() {
739 std::uniform_int_distribution<int> dist_height(0, 3);
740 std::uniform_int_distribution<int> dist_leaf(0, max_cap - 1);
741 const size_t height = dist_height(rnd);
742 return (
height ? pow(max_cap,
height) : 0) + dist_leaf(rnd);
745 for (
int i = 0;
i < 10000; ++
i) {
747 std::vector<CordRep*> flats;
749 CordRepBtree* left = MakeTree(random_leaf_count(), coin_flip(rnd));
750 GetLeafEdges(left, flats);
751 if (dice_throw(rnd) == 1) {
752 std::uniform_int_distribution<int> dist(0, left->height());
753 RefEdgesAt(dist(rnd),
refs, left);
756 CordRepBtree* right = MakeTree(random_leaf_count(), coin_flip(rnd));
757 GetLeafEdges(right, flats);
758 if (dice_throw(rnd) == 1) {
759 std::uniform_int_distribution<int> dist(0, right->height());
760 RefEdgesAt(dist(rnd),
refs, right);
772 for (
size_t cap : {max_cap - 1, max_cap * 2, max_cap * max_cap * 2}) {
778 CordRepBtree* node =
refs.RefIf(shared(), CreateTree(
data, 512));
782 node =
refs.RefIf(shared(), CreateTree(
data, 512));
787 for (
int n = 1;
n <
data.length(); ++
n) {
790 CordRepBtree* node =
refs.RefIf(shared(), CreateTree(flats));
795 auto is_flat = [](CordRep*
rep) {
return rep->
tag >=
FLAT; };
800 CordRep* last_edge = edges.back();
802 const size_t last_length =
rep->
length - edges.size() * 512;
806 for (CordRep* edge : edges) {
813 if (last_length >= 500) {
826 TEST(CordRepBtreeTest, SubTree) {
829 const size_t n = max_cap * max_cap * 2;
831 std::vector<CordRep*> flats;
833 flats.push_back(
MakeFlat(
s.substr(0, 3)));
836 for (
size_t i = 1;
i < flats.size(); ++
i) {
848 for (CordRep*
rep : flats) {
853 TEST(CordRepBtreeTest, SubTreeOnExistingSubstring) {
864 CordRep*
result = leaf->SubTree(0, 3 + 990);
872 result = leaf->SubTree(3 + 5, 970);
880 TEST_P(CordRepBtreeTest, AddDataToLeaf) {
884 for (
bool append : {
true,
false}) {
890 for (
size_t i = 1;
i <
n; ++
i) {
891 refs.RefIf(shared(), leaf);
901 TEST_P(CordRepBtreeTest, AppendDataToTree) {
905 CordRepBtree* tree =
refs.RefIf(shared(), CreateTree(
data, 3));
906 CordRepBtree* leaf0 = tree->Edges()[0]->btree();
907 CordRepBtree* leaf1 = tree->Edges()[1]->btree();
916 TEST_P(CordRepBtreeTest, PrependDataToTree) {
920 CordRepBtree* tree =
refs.RefIf(shared(), CreateTreeReverse(
data, 3));
921 CordRepBtree* leaf0 = tree->Edges()[0]->btree();
922 CordRepBtree* leaf1 = tree->Edges()[1]->btree();
931 TEST_P(CordRepBtreeTest, AddDataToTreeThreeLevelsDeep) {
933 const size_t n = max_cap * max_cap * max_cap;
936 for (
bool append : {
true,
false}) {
943 for (
size_t i = 1;
i < max_cap; ++
i) {
944 tree = BtreeAdd(tree, append,
consumer.Next(3));
949 refs.RefIf(shared(), tree);
955 for (
size_t i = max_cap + 1;
i < max_cap * max_cap; ++
i) {
956 refs.RefIf(shared(), tree);
964 refs.RefIf(shared(), tree);
970 for (
size_t i = max_cap * max_cap + 1;
i < max_cap * max_cap * max_cap;
972 refs.RefIf(shared(), tree);
983 TEST_P(CordRepBtreeTest, AddLargeDataToLeaf) {
985 const size_t n = max_cap * max_cap * max_cap * 3 + 2;
988 for (
bool append : {
true,
false}) {
993 refs.RefIf(shared(), leaf);
994 CordRepBtree*
result = BtreeAdd(leaf, append,
data);
1000 TEST_P(CordRepBtreeTest, CreateFromTreeReturnsTree) {
1003 refs.RefIf(shared(), leaf);
1009 TEST(CordRepBtreeTest, GetCharacter) {
1012 CordRepBtree* tree = CreateTree(
data, 3);
1016 for (
size_t i = 0;
i <
data.length(); ++
i) {
1022 TEST_P(CordRepBtreeTest, IsFlatSingleFlat) {
1043 TEST(CordRepBtreeTest, IsFlatMultiFlat) {
1046 CordRepBtree* tree = CreateTree(
data, 3);
1062 fragment =
"Can't touch this";
1078 #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
1080 TEST_P(CordRepBtreeHeightTest, GetAppendBufferNotPrivate) {
1083 EXPECT_DEATH(tree->GetAppendBuffer(1),
".*");
1088 #endif // defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
1090 TEST_P(CordRepBtreeHeightTest, GetAppendBufferNotFlat) {
1092 for (
int i = 1;
i <=
height(); ++
i) {
1099 TEST_P(CordRepBtreeHeightTest, GetAppendBufferFlatNotPrivate) {
1100 CordRepFlat* flat =
MakeFlat(
"abc");
1102 for (
int i = 1;
i <=
height(); ++
i) {
1110 TEST_P(CordRepBtreeHeightTest, GetAppendBufferTreeNotPrivate) {
1111 if (
height() == 0)
return;
1113 CordRepFlat* flat =
MakeFlat(
"abc");
1115 for (
int i = 1;
i <=
height(); ++
i) {
1124 TEST_P(CordRepBtreeHeightTest, GetAppendBufferFlatNoCapacity) {
1125 CordRepFlat* flat =
MakeFlat(
"abc");
1126 flat->length = flat->Capacity();
1128 for (
int i = 1;
i <=
height(); ++
i) {
1135 TEST_P(CordRepBtreeHeightTest, GetAppendBufferFlatWithCapacity) {
1136 CordRepFlat* flat =
MakeFlat(
"abc");
1138 for (
int i = 1;
i <=
height(); ++
i) {
1146 size_t avail = flat->Capacity() - 5;
1147 span = tree->GetAppendBuffer(avail + 100);
1157 std::stringstream ss;
1164 CordRepFlat* flat =
MakeFlat(
"Hello world");
1165 CordRepExternal* external =
MakeExternal(
"Hello external");
1176 while (tree->height() == 0) {
1183 for (
int api = 0; api <= 3; ++api) {
1185 std::stringstream ss;
1192 api_scope =
"Label only";
1196 api_scope =
"Label no content";
1200 api_scope =
"Label and content";
1246 TEST(CordRepBtreeTest, IsValid) {
1253 for (
bool as_tree : {
false,
true}) {
1256 CordRepBtree*
check = as_tree ? tree : leaf;
1272 leaf->storage[0] = 1;
1274 leaf->storage[0] = 0;
1281 leaf->storage[1] = 2;
1283 leaf->storage[1] =
begin;
1290 leaf->storage[2] =
end;
1294 CordRep*
const edge = leaf->Edges()[0];
1311 tree->storage[0] =
static_cast<uint8_t>(2);
1313 tree->storage[0] = 1;
1317 CordRep*
const edge = tree->Edges()[0];
1329 TEST(CordRepBtreeTest, AssertValid) {
1331 const CordRepBtree* ctree = tree;
1335 #if defined(GTEST_HAS_DEATH_TEST)
1336 CordRepBtree* nulltree =
nullptr;
1337 const CordRepBtree* cnulltree =
nullptr;
1353 TEST(CordRepBtreeTest, CheckAssertValidShallowVsDeep) {
1366 const size_t n = max_cap * max_cap * 2;
1367 for (
size_t i = 0;
i <
n; ++
i) {
1378 #if defined(GTEST_HAS_DEATH_TEST)
1386 #if defined(GTEST_HAS_DEATH_TEST)
1395 TEST_P(CordRepBtreeTest, Rebuild) {
1396 for (
size_t size : {3, 8, 100, 10000, 1000000}) {
1399 std::vector<CordRepFlat*> flats;
1400 for (
int i = 0;
i <
size; ++
i) {
1402 flats.back()->Data()[0] =
'x';
1403 flats.back()->length = 1;
1409 size_t split_count = 0;
1410 size_t split_limit = 3;
1411 auto it = flats.begin();
1412 CordRepBtree* left =
nullptr;
1414 while (++
it != flats.end()) {
1415 if (++split_count >= split_limit) {
1416 split_limit += split_limit / 16;
1436 if (edge->tag <
FLAT)
return;
1437 ok =
ok && (
it != flats.end() && *
it++ == edge);
1444 CordRepBtree::ExtractResult ExtractLast(CordRepBtree*
input,
size_t cap = 1) {
1448 TEST(CordRepBtreeTest, ExtractAppendBufferLeafSingleFlat) {
1451 EXPECT_THAT(ExtractLast(leaf), EqExtractResult(
nullptr, flat));
1455 TEST(CordRepBtreeTest, ExtractAppendBufferNodeSingleFlat) {
1459 EXPECT_THAT(ExtractLast(node), EqExtractResult(
nullptr, flat));
1463 TEST(CordRepBtreeTest, ExtractAppendBufferLeafTwoFlats) {
1465 CordRepBtree* leaf = CreateTree(flats);
1466 EXPECT_THAT(ExtractLast(leaf), EqExtractResult(flats[0], flats[1]));
1471 TEST(CordRepBtreeTest, ExtractAppendBufferNodeTwoFlats) {
1473 CordRepBtree* leaf = CreateTree(flats);
1475 EXPECT_THAT(ExtractLast(node), EqExtractResult(flats[0], flats[1]));
1480 TEST(CordRepBtreeTest, ExtractAppendBufferNodeTwoFlatsInTwoLeafs) {
1485 EXPECT_THAT(ExtractLast(node), EqExtractResult(flats[0], flats[1]));
1490 TEST(CordRepBtreeTest, ExtractAppendBufferLeafThreeFlats) {
1492 CordRepBtree* leaf = CreateTree(flats);
1493 EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf, flats[2]));
1498 TEST(CordRepBtreeTest, ExtractAppendBufferNodeThreeFlatsRightNoFolding) {
1502 CordRepBtree* leaf2 = CreateTree(flats);
1504 EXPECT_THAT(ExtractLast(node), EqExtractResult(node, flats[1]));
1512 TEST(CordRepBtreeTest, ExtractAppendBufferNodeThreeFlatsRightLeafFolding) {
1515 CordRepBtree* leaf1 = CreateTree(flats);
1518 EXPECT_THAT(ExtractLast(node), EqExtractResult(leaf1, flat));
1524 TEST(CordRepBtreeTest, ExtractAppendBufferNoCapacity) {
1526 CordRepBtree* leaf = CreateTree(flats);
1527 size_t avail = flats[1]->flat()->Capacity() - flats[1]->length;
1528 EXPECT_THAT(ExtractLast(leaf, avail + 1), EqExtractResult(leaf,
nullptr));
1529 EXPECT_THAT(ExtractLast(leaf, avail), EqExtractResult(flats[0], flats[1]));
1534 TEST(CordRepBtreeTest, ExtractAppendBufferNotFlat) {
1537 CordRepBtree* leaf = CreateTree({flats[0], substr});
1538 EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf,
nullptr));
1542 TEST(CordRepBtreeTest, ExtractAppendBufferShared) {
1544 CordRepBtree* leaf = CreateTree(flats);
1547 EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf,
nullptr));
1551 EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf,
nullptr));
1556 EXPECT_THAT(ExtractLast(node), EqExtractResult(node,
nullptr));