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 <cstdlib>
16 #include <ctime>
17 #include <memory>
18 #include <random>
19 #include <sstream>
20
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "absl/base/config.h"
24 #include "absl/base/internal/raw_logging.h"
25 #include "absl/base/macros.h"
26 #include "absl/debugging/leak_check.h"
27 #include "absl/strings/internal/cord_internal.h"
28 #include "absl/strings/internal/cord_rep_ring.h"
29 #include "absl/strings/str_cat.h"
30 #include "absl/strings/string_view.h"
31
32 extern thread_local bool cord_ring;
33
34 namespace absl {
35 ABSL_NAMESPACE_BEGIN
36 namespace {
37
38 using RandomEngine = std::mt19937_64;
39
40 using ::absl::cord_internal::CordRep;
41 using ::absl::cord_internal::CordRepConcat;
42 using ::absl::cord_internal::CordRepExternal;
43 using ::absl::cord_internal::CordRepFlat;
44 using ::absl::cord_internal::CordRepRing;
45 using ::absl::cord_internal::CordRepSubstring;
46
47 using ::absl::cord_internal::CONCAT;
48 using ::absl::cord_internal::EXTERNAL;
49 using ::absl::cord_internal::SUBSTRING;
50
51 using testing::ElementsAre;
52 using testing::ElementsAreArray;
53 using testing::Eq;
54 using testing::Ge;
55 using testing::Le;
56 using testing::Lt;
57 using testing::Ne;
58 using testing::SizeIs;
59
60 using index_type = CordRepRing::index_type;
61
62 enum InputShareMode { kPrivate, kShared, kSharedIndirect };
63
64 // TestParam class used by all test fixtures.
65 // Not all fixtures use all possible input combinations
66 struct TestParam {
67 TestParam() = default;
TestParamabsl::__anon914e579a0111::TestParam68 explicit TestParam(InputShareMode input_share_mode)
69 : input_share_mode(input_share_mode) {}
70
71 // Run the test with the 'rep under test' to be privately owned.
72 // Otherwise, the rep has a shared ref count of 2 or higher.
73 bool refcount_is_one = true;
74
75 // Run the test with the 'rep under test' being allocated with enough capacity
76 // to accommodate any modifications made to it. Otherwise, the rep has zero
77 // extra (reserve) capacity.
78 bool with_capacity = true;
79
80 // For test providing possibly shared input such as Append(.., CordpRep*),
81 // this field defines if that input is adopted with a refcount of one
82 // (privately owned / donated), or shared. For composite inputs such as
83 // 'substring of flat', we also have the 'shared indirect' value which means
84 // the top level node is not shared, but the contained child node is shared.
85 InputShareMode input_share_mode = kPrivate;
86
ToStringabsl::__anon914e579a0111::TestParam87 std::string ToString() const {
88 return absl::StrCat(refcount_is_one ? "Private" : "Shared",
89 with_capacity ? "" : "_NoCapacity",
90 (input_share_mode == kPrivate) ? ""
91 : (input_share_mode == kShared)
92 ? "_SharedInput"
93 : "_IndirectSharedInput");
94 }
95 };
96 using TestParams = std::vector<TestParam>;
97
98 // Matcher validating when mutable copies are required / performed.
99 MATCHER_P2(EqIfPrivate, param, rep,
100 absl::StrCat("Equal 0x", absl::Hex(rep), " if private")) {
101 return param.refcount_is_one ? arg == rep : true;
102 }
103
104 // Matcher validating when mutable copies are required / performed.
105 MATCHER_P2(EqIfPrivateAndCapacity, param, rep,
106 absl::StrCat("Equal 0x", absl::Hex(rep),
107 " if private and capacity")) {
108 return (param.refcount_is_one && param.with_capacity) ? arg == rep : true;
109 }
110
111 // Matcher validating a shared ring was re-allocated. Should only be used for
112 // tests doing exactly one update as subsequent updates could return the
113 // original (freed and re-used) pointer.
114 MATCHER_P2(NeIfShared, param, rep,
115 absl::StrCat("Not equal 0x", absl::Hex(rep), " if shared")) {
116 return param.refcount_is_one ? true : arg != rep;
117 }
118
119 MATCHER_P2(EqIfInputPrivate, param, rep, "Equal if input is private") {
120 return param.input_share_mode == kPrivate ? arg == rep : arg != rep;
121 }
122
123 // Matcher validating the core in-variants of the CordRepRing instance.
124 MATCHER(IsValidRingBuffer, "RingBuffer is valid") {
125 std::stringstream ss;
126 if (!arg->IsValid(ss)) {
127 *result_listener << "\nERROR: " << ss.str() << "\nRING = " << *arg;
128 return false;
129 }
130 return true;
131 }
132
133 // Returns the flats contained in the provided CordRepRing
ToFlats(const CordRepRing * r)134 std::vector<string_view> ToFlats(const CordRepRing* r) {
135 std::vector<string_view> flats;
136 flats.reserve(r->entries());
137 index_type pos = r->head();
138 do {
139 flats.push_back(r->entry_data(pos));
140 } while ((pos = r->advance(pos)) != r->tail());
141 return flats;
142 }
143
144 class not_a_string_view {
145 public:
not_a_string_view(absl::string_view s)146 explicit not_a_string_view(absl::string_view s)
147 : data_(s.data()), size_(s.size()) {}
not_a_string_view(const void * data,size_t size)148 explicit not_a_string_view(const void* data, size_t size)
149 : data_(data), size_(size) {}
150
remove_prefix(size_t n) const151 not_a_string_view remove_prefix(size_t n) const {
152 return not_a_string_view(static_cast<const char*>(data_) + n, size_ - n);
153 }
154
remove_suffix(size_t n) const155 not_a_string_view remove_suffix(size_t n) const {
156 return not_a_string_view(data_, size_ - n);
157 }
158
data() const159 const void* data() const { return data_; }
size() const160 size_t size() const { return size_; }
161
162 private:
163 const void* data_;
164 size_t size_;
165 };
166
operator ==(not_a_string_view lhs,not_a_string_view rhs)167 bool operator==(not_a_string_view lhs, not_a_string_view rhs) {
168 return lhs.data() == rhs.data() && lhs.size() == rhs.size();
169 }
170
operator <<(std::ostream & s,not_a_string_view rhs)171 std::ostream& operator<<(std::ostream& s, not_a_string_view rhs) {
172 return s << "{ data: " << rhs.data() << " size: " << rhs.size() << "}";
173 }
174
ToRawFlats(const CordRepRing * r)175 std::vector<not_a_string_view> ToRawFlats(const CordRepRing* r) {
176 std::vector<not_a_string_view> flats;
177 flats.reserve(r->entries());
178 index_type pos = r->head();
179 do {
180 flats.emplace_back(r->entry_data(pos));
181 } while ((pos = r->advance(pos)) != r->tail());
182 return flats;
183 }
184
185 // Returns the value contained in the provided CordRepRing
ToString(const CordRepRing * r)186 std::string ToString(const CordRepRing* r) {
187 std::string value;
188 value.reserve(r->length);
189 index_type pos = r->head();
190 do {
191 absl::string_view sv = r->entry_data(pos);
192 value.append(sv.data(), sv.size());
193 } while ((pos = r->advance(pos)) != r->tail());
194 return value;
195 }
196
197 // Creates a flat for testing
MakeFlat(absl::string_view s,size_t extra=0)198 CordRep* MakeFlat(absl::string_view s, size_t extra = 0) {
199 CordRepFlat* flat = CordRepFlat::New(s.length() + extra);
200 memcpy(flat->Data(), s.data(), s.length());
201 flat->length = s.length();
202 return flat;
203 }
204
205 // Creates an external node for testing
MakeExternal(absl::string_view s)206 CordRepExternal* MakeExternal(absl::string_view s) {
207 struct Rep : public CordRepExternal {
208 std::string s;
209 explicit Rep(absl::string_view s) : s(s) {
210 this->tag = EXTERNAL;
211 this->base = s.data();
212 this->length = s.length();
213 this->releaser_invoker = [](CordRepExternal* self) {
214 delete static_cast<Rep*>(self);
215 };
216 }
217 };
218 return new Rep(s);
219 }
220
MakeFakeExternal(size_t length)221 CordRepExternal* MakeFakeExternal(size_t length) {
222 struct Rep : public CordRepExternal {
223 std::string s;
224 explicit Rep(size_t len) {
225 this->tag = EXTERNAL;
226 this->base = reinterpret_cast<const char*>(this->storage);
227 this->length = len;
228 this->releaser_invoker = [](CordRepExternal* self) {
229 delete static_cast<Rep*>(self);
230 };
231 }
232 };
233 return new Rep(length);
234 }
235
236 // Creates a flat or an external node for testing depending on the size.
MakeLeaf(absl::string_view s,size_t extra=0)237 CordRep* MakeLeaf(absl::string_view s, size_t extra = 0) {
238 if (s.size() <= absl::cord_internal::kMaxFlatLength) {
239 return MakeFlat(s, extra);
240 } else {
241 return MakeExternal(s);
242 }
243 }
244
245 // Creates a substring node
MakeSubstring(size_t start,size_t len,CordRep * rep)246 CordRepSubstring* MakeSubstring(size_t start, size_t len, CordRep* rep) {
247 auto* sub = new CordRepSubstring;
248 sub->tag = SUBSTRING;
249 sub->start = start;
250 sub->length = (len <= 0) ? rep->length - start + len : len;
251 sub->child = rep;
252 return sub;
253 }
254
255 // Creates a substring node removing the specified prefix
RemovePrefix(size_t start,CordRep * rep)256 CordRepSubstring* RemovePrefix(size_t start, CordRep* rep) {
257 return MakeSubstring(start, rep->length - start, rep);
258 }
259
260 // Creates a substring node removing the specified suffix
RemoveSuffix(size_t length,CordRep * rep)261 CordRepSubstring* RemoveSuffix(size_t length, CordRep* rep) {
262 return MakeSubstring(0, rep->length - length, rep);
263 }
264
MakeConcat(CordRep * left,CordRep * right,int depth=0)265 CordRepConcat* MakeConcat(CordRep* left, CordRep* right, int depth = 0) {
266 auto* concat = new CordRepConcat;
267 concat->tag = CONCAT;
268 concat->length = left->length + right->length;
269 concat->left = left;
270 concat->right = right;
271 concat->set_depth(depth);
272 return concat;
273 }
274
275 enum Composition { kMix, kAppend, kPrepend };
276
RandomComposition()277 Composition RandomComposition() {
278 RandomEngine rng(GTEST_FLAG_GET(random_seed));
279 return (rng() & 1) ? kMix : ((rng() & 1) ? kAppend : kPrepend);
280 }
281
ToString(Composition composition)282 absl::string_view ToString(Composition composition) {
283 switch (composition) {
284 case kAppend:
285 return "Append";
286 case kPrepend:
287 return "Prepend";
288 case kMix:
289 return "Mix";
290 }
291 assert(false);
292 return "???";
293 }
294
295 constexpr const char* kFox = "The quick brown fox jumps over the lazy dog";
296 constexpr const char* kFoxFlats[] = {"The ", "quick ", "brown ",
297 "fox ", "jumps ", "over ",
298 "the ", "lazy ", "dog"};
299 constexpr const char* kAlphabet = "abcdefghijklmnopqrstuvwxyz";
300
FromFlats(Span<const char * const> flats,Composition composition=kAppend)301 CordRepRing* FromFlats(Span<const char* const> flats,
302 Composition composition = kAppend) {
303 if (flats.empty()) return nullptr;
304 CordRepRing* ring = nullptr;
305 switch (composition) {
306 case kAppend:
307 ring = CordRepRing::Create(MakeLeaf(flats.front()), flats.size() - 1);
308 for (int i = 1; i < flats.size(); ++i) {
309 ring = CordRepRing::Append(ring, MakeLeaf(flats[i]));
310 }
311 break;
312 case kPrepend:
313 ring = CordRepRing::Create(MakeLeaf(flats.back()), flats.size() - 1);
314 for (int i = static_cast<int>(flats.size() - 2); i >= 0; --i) {
315 ring = CordRepRing::Prepend(ring, MakeLeaf(flats[i]));
316 }
317 break;
318 case kMix:
319 size_t middle1 = flats.size() / 2, middle2 = middle1;
320 ring = CordRepRing::Create(MakeLeaf(flats[middle1]), flats.size() - 1);
321 if (!flats.empty()) {
322 if ((flats.size() & 1) == 0) {
323 ring = CordRepRing::Prepend(ring, MakeLeaf(flats[--middle1]));
324 }
325 for (int i = 1; i <= middle1; ++i) {
326 ring = CordRepRing::Prepend(ring, MakeLeaf(flats[middle1 - i]));
327 ring = CordRepRing::Append(ring, MakeLeaf(flats[middle2 + i]));
328 }
329 }
330 break;
331 }
332 EXPECT_THAT(ToFlats(ring), ElementsAreArray(flats));
333 return ring;
334 }
335
operator <<(std::ostream & s,const TestParam & param)336 std::ostream& operator<<(std::ostream& s, const TestParam& param) {
337 return s << param.ToString();
338 }
339
TestParamToString(const testing::TestParamInfo<TestParam> & info)340 std::string TestParamToString(const testing::TestParamInfo<TestParam>& info) {
341 return info.param.ToString();
342 }
343
344 class CordRingTest : public testing::Test {
345 public:
~CordRingTest()346 ~CordRingTest() override {
347 for (CordRep* rep : unrefs_) {
348 CordRep::Unref(rep);
349 }
350 }
351
352 template <typename CordRepType>
NeedsUnref(CordRepType * rep)353 CordRepType* NeedsUnref(CordRepType* rep) {
354 assert(rep);
355 unrefs_.push_back(rep);
356 return rep;
357 }
358
359 template <typename CordRepType>
Ref(CordRepType * rep)360 CordRepType* Ref(CordRepType* rep) {
361 CordRep::Ref(rep);
362 return NeedsUnref(rep);
363 }
364
365 private:
366 std::vector<CordRep*> unrefs_;
367 };
368
369 class CordRingTestWithParam : public testing::TestWithParam<TestParam> {
370 public:
~CordRingTestWithParam()371 ~CordRingTestWithParam() override {
372 for (CordRep* rep : unrefs_) {
373 CordRep::Unref(rep);
374 }
375 }
376
CreateWithCapacity(CordRep * child,size_t extra_capacity)377 CordRepRing* CreateWithCapacity(CordRep* child, size_t extra_capacity) {
378 if (!GetParam().with_capacity) extra_capacity = 0;
379 CordRepRing* ring = CordRepRing::Create(child, extra_capacity);
380 ring->SetCapacityForTesting(1 + extra_capacity);
381 return RefIfShared(ring);
382 }
383
Shared() const384 bool Shared() const { return !GetParam().refcount_is_one; }
InputShared() const385 bool InputShared() const { return GetParam().input_share_mode == kShared; }
InputSharedIndirect() const386 bool InputSharedIndirect() const {
387 return GetParam().input_share_mode == kSharedIndirect;
388 }
389
390 template <typename CordRepType>
NeedsUnref(CordRepType * rep)391 CordRepType* NeedsUnref(CordRepType* rep) {
392 assert(rep);
393 unrefs_.push_back(rep);
394 return rep;
395 }
396
397 template <typename CordRepType>
Ref(CordRepType * rep)398 CordRepType* Ref(CordRepType* rep) {
399 CordRep::Ref(rep);
400 return NeedsUnref(rep);
401 }
402
403 template <typename CordRepType>
RefIfShared(CordRepType * rep)404 CordRepType* RefIfShared(CordRepType* rep) {
405 return Shared() ? Ref(rep) : rep;
406 }
407
408 template <typename CordRepType>
RefIfInputShared(CordRepType * rep)409 CordRepType* RefIfInputShared(CordRepType* rep) {
410 return InputShared() ? Ref(rep) : rep;
411 }
412
413 template <typename CordRepType>
RefIfInputSharedIndirect(CordRepType * rep)414 CordRepType* RefIfInputSharedIndirect(CordRepType* rep) {
415 return InputSharedIndirect() ? Ref(rep) : rep;
416 }
417
418 private:
419 std::vector<CordRep*> unrefs_;
420 };
421
422 class CordRingCreateTest : public CordRingTestWithParam {
423 public:
CreateTestParams()424 static TestParams CreateTestParams() {
425 TestParams params;
426 params.emplace_back(InputShareMode::kPrivate);
427 params.emplace_back(InputShareMode::kShared);
428 return params;
429 }
430 };
431
432 class CordRingSubTest : public CordRingTestWithParam {
433 public:
CreateTestParams()434 static TestParams CreateTestParams() {
435 TestParams params;
436 for (bool refcount_is_one : {true, false}) {
437 TestParam param;
438 param.refcount_is_one = refcount_is_one;
439 params.push_back(param);
440 }
441 return params;
442 }
443 };
444
445 class CordRingBuildTest : public CordRingTestWithParam {
446 public:
CreateTestParams()447 static TestParams CreateTestParams() {
448 TestParams params;
449 for (bool refcount_is_one : {true, false}) {
450 for (bool with_capacity : {true, false}) {
451 TestParam param;
452 param.refcount_is_one = refcount_is_one;
453 param.with_capacity = with_capacity;
454 params.push_back(param);
455 }
456 }
457 return params;
458 }
459 };
460
461 class CordRingCreateFromTreeTest : public CordRingTestWithParam {
462 public:
CreateTestParams()463 static TestParams CreateTestParams() {
464 TestParams params;
465 params.emplace_back(InputShareMode::kPrivate);
466 params.emplace_back(InputShareMode::kShared);
467 params.emplace_back(InputShareMode::kSharedIndirect);
468 return params;
469 }
470 };
471
472 class CordRingBuildInputTest : public CordRingTestWithParam {
473 public:
CreateTestParams()474 static TestParams CreateTestParams() {
475 TestParams params;
476 for (bool refcount_is_one : {true, false}) {
477 for (bool with_capacity : {true, false}) {
478 for (InputShareMode share_mode : {kPrivate, kShared, kSharedIndirect}) {
479 TestParam param;
480 param.refcount_is_one = refcount_is_one;
481 param.with_capacity = with_capacity;
482 param.input_share_mode = share_mode;
483 params.push_back(param);
484 }
485 }
486 }
487 return params;
488 }
489 };
490
491 INSTANTIATE_TEST_SUITE_P(WithParam, CordRingSubTest,
492 testing::ValuesIn(CordRingSubTest::CreateTestParams()),
493 TestParamToString);
494
495 INSTANTIATE_TEST_SUITE_P(
496 WithParam, CordRingCreateTest,
497 testing::ValuesIn(CordRingCreateTest::CreateTestParams()),
498 TestParamToString);
499
500 INSTANTIATE_TEST_SUITE_P(
501 WithParam, CordRingCreateFromTreeTest,
502 testing::ValuesIn(CordRingCreateFromTreeTest::CreateTestParams()),
503 TestParamToString);
504
505 INSTANTIATE_TEST_SUITE_P(
506 WithParam, CordRingBuildTest,
507 testing::ValuesIn(CordRingBuildTest::CreateTestParams()),
508 TestParamToString);
509
510 INSTANTIATE_TEST_SUITE_P(
511 WithParam, CordRingBuildInputTest,
512 testing::ValuesIn(CordRingBuildInputTest::CreateTestParams()),
513 TestParamToString);
514
TEST_P(CordRingCreateTest,CreateFromFlat)515 TEST_P(CordRingCreateTest, CreateFromFlat) {
516 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
517 CordRepRing* result = NeedsUnref(CordRepRing::Create(MakeFlat(str1)));
518 ASSERT_THAT(result, IsValidRingBuffer());
519 EXPECT_THAT(result->length, Eq(str1.size()));
520 EXPECT_THAT(ToFlats(result), ElementsAre(str1));
521 }
522
TEST_P(CordRingCreateTest,CreateFromRing)523 TEST_P(CordRingCreateTest, CreateFromRing) {
524 CordRepRing* ring = RefIfShared(FromFlats(kFoxFlats));
525 CordRepRing* result = NeedsUnref(CordRepRing::Create(ring));
526 ASSERT_THAT(result, IsValidRingBuffer());
527 EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
528 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
529 EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
530 }
531
TEST_P(CordRingCreateFromTreeTest,CreateFromSubstringRing)532 TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringRing) {
533 CordRepRing* ring = RefIfInputSharedIndirect(FromFlats(kFoxFlats));
534 CordRep* sub = RefIfInputShared(MakeSubstring(2, 11, ring));
535 CordRepRing* result = NeedsUnref(CordRepRing::Create(sub));
536 ASSERT_THAT(result, IsValidRingBuffer());
537 EXPECT_THAT(result, EqIfInputPrivate(GetParam(), ring));
538 EXPECT_THAT(ToString(result), string_view(kFox).substr(2, 11));
539 }
540
TEST_F(CordRingTest,CreateWithIllegalExtraCapacity)541 TEST_F(CordRingTest, CreateWithIllegalExtraCapacity) {
542 #if defined(ABSL_HAVE_EXCEPTIONS)
543 CordRep* flat = NeedsUnref(MakeFlat("Hello world"));
544 try {
545 CordRepRing::Create(flat, CordRepRing::kMaxCapacity);
546 GTEST_FAIL() << "expected std::length_error exception";
547 } catch (const std::length_error&) {
548 }
549 #elif defined(GTEST_HAS_DEATH_TEST)
550 CordRep* flat = NeedsUnref(MakeFlat("Hello world"));
551 EXPECT_DEATH(CordRepRing::Create(flat, CordRepRing::kMaxCapacity), ".*");
552 #endif
553 }
554
TEST_P(CordRingCreateFromTreeTest,CreateFromSubstringOfFlat)555 TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfFlat) {
556 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
557 auto* flat = RefIfInputShared(MakeFlat(str1));
558 auto* child = RefIfInputSharedIndirect(MakeSubstring(4, 20, flat));
559 CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
560 ASSERT_THAT(result, IsValidRingBuffer());
561 EXPECT_THAT(result->length, Eq(20));
562 EXPECT_THAT(ToFlats(result), ElementsAre(str1.substr(4, 20)));
563 }
564
TEST_P(CordRingCreateTest,CreateFromExternal)565 TEST_P(CordRingCreateTest, CreateFromExternal) {
566 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
567 auto* child = RefIfInputShared(MakeExternal(str1));
568 CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
569 ASSERT_THAT(result, IsValidRingBuffer());
570 EXPECT_THAT(result->length, Eq(str1.size()));
571 EXPECT_THAT(ToFlats(result), ElementsAre(str1));
572 }
573
TEST_P(CordRingCreateFromTreeTest,CreateFromSubstringOfExternal)574 TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfExternal) {
575 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
576 auto* external = RefIfInputShared(MakeExternal(str1));
577 auto* child = RefIfInputSharedIndirect(MakeSubstring(1, 24, external));
578 CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
579 ASSERT_THAT(result, IsValidRingBuffer());
580 EXPECT_THAT(result->length, Eq(24));
581 EXPECT_THAT(ToFlats(result), ElementsAre(str1.substr(1, 24)));
582 }
583
TEST_P(CordRingCreateFromTreeTest,CreateFromSubstringOfLargeExternal)584 TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfLargeExternal) {
585 auto* external = RefIfInputShared(MakeFakeExternal(1 << 20));
586 auto str = not_a_string_view(external->base, 1 << 20)
587 .remove_prefix(1 << 19)
588 .remove_suffix(6);
589 auto* child =
590 RefIfInputSharedIndirect(MakeSubstring(1 << 19, (1 << 19) - 6, external));
591 CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
592 ASSERT_THAT(result, IsValidRingBuffer());
593 EXPECT_THAT(result->length, Eq(str.size()));
594 EXPECT_THAT(ToRawFlats(result), ElementsAre(str));
595 }
596
TEST_P(CordRingBuildInputTest,CreateFromConcat)597 TEST_P(CordRingBuildInputTest, CreateFromConcat) {
598 CordRep* flats[] = {MakeFlat("abcdefgh"), MakeFlat("ijklm"),
599 MakeFlat("nopqrstuv"), MakeFlat("wxyz")};
600 auto* left = MakeConcat(RefIfInputSharedIndirect(flats[0]), flats[1]);
601 auto* right = MakeConcat(flats[2], RefIfInputSharedIndirect(flats[3]));
602 auto* concat = RefIfInputShared(MakeConcat(left, right));
603 CordRepRing* result = NeedsUnref(CordRepRing::Create(concat));
604 ASSERT_THAT(result, IsValidRingBuffer());
605 EXPECT_THAT(result->length, Eq(26));
606 EXPECT_THAT(ToString(result), Eq(kAlphabet));
607 }
608
TEST_P(CordRingBuildInputTest,CreateFromSubstringConcat)609 TEST_P(CordRingBuildInputTest, CreateFromSubstringConcat) {
610 for (size_t off = 0; off < 26; ++off) {
611 for (size_t len = 1; len < 26 - off; ++len) {
612 CordRep* flats[] = {MakeFlat("abcdefgh"), MakeFlat("ijklm"),
613 MakeFlat("nopqrstuv"), MakeFlat("wxyz")};
614 auto* left = MakeConcat(RefIfInputSharedIndirect(flats[0]), flats[1]);
615 auto* right = MakeConcat(flats[2], RefIfInputSharedIndirect(flats[3]));
616 auto* concat = MakeConcat(left, right);
617 auto* child = RefIfInputShared(MakeSubstring(off, len, concat));
618 CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
619 ASSERT_THAT(result, IsValidRingBuffer());
620 ASSERT_THAT(result->length, Eq(len));
621 ASSERT_THAT(ToString(result), string_view(kAlphabet).substr(off, len));
622 }
623 }
624 }
625
TEST_P(CordRingCreateTest,Properties)626 TEST_P(CordRingCreateTest, Properties) {
627 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
628 CordRepRing* result = NeedsUnref(CordRepRing::Create(MakeFlat(str1), 120));
629 ASSERT_THAT(result, IsValidRingBuffer());
630 EXPECT_THAT(result->head(), Eq(0));
631 EXPECT_THAT(result->tail(), Eq(1));
632 EXPECT_THAT(result->capacity(), Ge(120 + 1));
633 EXPECT_THAT(result->capacity(), Le(2 * 120 + 1));
634 EXPECT_THAT(result->entries(), Eq(1));
635 EXPECT_THAT(result->begin_pos(), Eq(0));
636 }
637
TEST_P(CordRingCreateTest,EntryForNewFlat)638 TEST_P(CordRingCreateTest, EntryForNewFlat) {
639 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
640 CordRep* child = MakeFlat(str1);
641 CordRepRing* result = NeedsUnref(CordRepRing::Create(child, 120));
642 ASSERT_THAT(result, IsValidRingBuffer());
643 EXPECT_THAT(result->entry_child(0), Eq(child));
644 EXPECT_THAT(result->entry_end_pos(0), Eq(str1.length()));
645 EXPECT_THAT(result->entry_data_offset(0), Eq(0));
646 }
647
TEST_P(CordRingCreateTest,EntryForNewFlatSubstring)648 TEST_P(CordRingCreateTest, EntryForNewFlatSubstring) {
649 absl::string_view str1 = "1234567890abcdefghijklmnopqrstuvwxyz";
650 CordRep* child = MakeFlat(str1);
651 CordRep* substring = MakeSubstring(10, 26, child);
652 CordRepRing* result = NeedsUnref(CordRepRing::Create(substring, 1));
653 ASSERT_THAT(result, IsValidRingBuffer());
654 EXPECT_THAT(result->entry_child(0), Eq(child));
655 EXPECT_THAT(result->entry_end_pos(0), Eq(26));
656 EXPECT_THAT(result->entry_data_offset(0), Eq(10));
657 }
658
TEST_P(CordRingBuildTest,AppendFlat)659 TEST_P(CordRingBuildTest, AppendFlat) {
660 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
661 absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
662 CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
663 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, MakeFlat(str2)));
664 ASSERT_THAT(result, IsValidRingBuffer());
665 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
666 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
667 EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
668 EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
669 }
670
TEST_P(CordRingBuildTest,PrependFlat)671 TEST_P(CordRingBuildTest, PrependFlat) {
672 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
673 absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
674 CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
675 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, MakeFlat(str2)));
676 ASSERT_THAT(result, IsValidRingBuffer());
677 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
678 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
679 EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
680 EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1));
681 }
682
TEST_P(CordRingBuildTest,AppendString)683 TEST_P(CordRingBuildTest, AppendString) {
684 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
685 absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
686 CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
687 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
688 ASSERT_THAT(result, IsValidRingBuffer());
689 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
690 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
691 EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
692 EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
693 }
694
TEST_P(CordRingBuildTest,AppendStringHavingExtra)695 TEST_P(CordRingBuildTest, AppendStringHavingExtra) {
696 absl::string_view str1 = "1234";
697 absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
698 CordRepRing* ring = CreateWithCapacity(MakeFlat(str1, 26), 0);
699 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
700 ASSERT_THAT(result, IsValidRingBuffer());
701 EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
702 EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
703 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
704 }
705
TEST_P(CordRingBuildTest,AppendStringHavingPartialExtra)706 TEST_P(CordRingBuildTest, AppendStringHavingPartialExtra) {
707 absl::string_view str1 = "1234";
708 absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
709
710 // Create flat with at least one extra byte. We don't expect to have sized
711 // alloc and capacity rounding to grant us enough to not make it partial.
712 auto* flat = MakeFlat(str1, 1);
713 size_t avail = flat->flat()->Capacity() - flat->length;
714 ASSERT_THAT(avail, Lt(str2.size())) << " adjust test for larger flats!";
715
716 // Construct the flats we do expect using all of `avail`.
717 absl::string_view str1a = str2.substr(0, avail);
718 absl::string_view str2a = str2.substr(avail);
719
720 CordRepRing* ring = CreateWithCapacity(flat, 1);
721 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
722 ASSERT_THAT(result, IsValidRingBuffer());
723 EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
724 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
725 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
726 if (GetParam().refcount_is_one) {
727 EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str1, str1a), str2a));
728 } else {
729 EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
730 }
731 }
732
TEST_P(CordRingBuildTest,AppendStringHavingExtraInSubstring)733 TEST_P(CordRingBuildTest, AppendStringHavingExtraInSubstring) {
734 absl::string_view str1 = "123456789_1234";
735 absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
736 CordRep* flat = RemovePrefix(10, MakeFlat(str1, 26));
737 CordRepRing* ring = CreateWithCapacity(flat, 0);
738 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
739 ASSERT_THAT(result, IsValidRingBuffer());
740 EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
741 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
742 EXPECT_THAT(result->length, Eq(4 + str2.size()));
743 if (GetParam().refcount_is_one) {
744 EXPECT_THAT(ToFlats(result), ElementsAre(StrCat("1234", str2)));
745 } else {
746 EXPECT_THAT(ToFlats(result), ElementsAre("1234", str2));
747 }
748 }
749
TEST_P(CordRingBuildTest,AppendStringHavingSharedExtra)750 TEST_P(CordRingBuildTest, AppendStringHavingSharedExtra) {
751 absl::string_view str1 = "123456789_1234";
752 absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
753 for (int shared_type = 0; shared_type < 2; ++shared_type) {
754 SCOPED_TRACE(absl::StrCat("Shared extra type ", shared_type));
755
756 // Create a flat that is shared in some way.
757 CordRep* flat = nullptr;
758 CordRep* flat1 = nullptr;
759 if (shared_type == 0) {
760 // Shared flat
761 flat = CordRep::Ref(MakeFlat(str1.substr(10), 100));
762 } else if (shared_type == 1) {
763 // Shared flat inside private substring
764 flat1 = CordRep::Ref(MakeFlat(str1));
765 flat = RemovePrefix(10, flat1);
766 } else {
767 // Private flat inside shared substring
768 flat = CordRep::Ref(RemovePrefix(10, MakeFlat(str1, 100)));
769 }
770
771 CordRepRing* ring = CreateWithCapacity(flat, 1);
772 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
773 ASSERT_THAT(result, IsValidRingBuffer());
774 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
775 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
776 EXPECT_THAT(result->length, Eq(4 + str2.size()));
777 EXPECT_THAT(ToFlats(result), ElementsAre("1234", str2));
778
779 CordRep::Unref(shared_type == 1 ? flat1 : flat);
780 }
781 }
782
TEST_P(CordRingBuildTest,AppendStringWithExtra)783 TEST_P(CordRingBuildTest, AppendStringWithExtra) {
784 absl::string_view str1 = "1234";
785 absl::string_view str2 = "1234567890";
786 absl::string_view str3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
787 CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
788 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2, 26));
789 result = CordRepRing::Append(result, str3);
790 ASSERT_THAT(result, IsValidRingBuffer());
791 EXPECT_THAT(result->length, Eq(str1.size() + str2.size() + str3.size()));
792 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
793 EXPECT_THAT(ToFlats(result), ElementsAre(str1, StrCat(str2, str3)));
794 }
795
TEST_P(CordRingBuildTest,PrependString)796 TEST_P(CordRingBuildTest, PrependString) {
797 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
798 absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
799 // Use external rep to avoid appending to first flat
800 CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
801 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
802 ASSERT_THAT(result, IsValidRingBuffer());
803 if (GetParam().with_capacity && GetParam().refcount_is_one) {
804 EXPECT_THAT(result, Eq(ring));
805 } else {
806 EXPECT_THAT(result, Ne(ring));
807 }
808 EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
809 EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1));
810 }
811
TEST_P(CordRingBuildTest,PrependStringHavingExtra)812 TEST_P(CordRingBuildTest, PrependStringHavingExtra) {
813 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz1234";
814 absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
815 CordRep* flat = RemovePrefix(26, MakeFlat(str1));
816 CordRepRing* ring = CreateWithCapacity(flat, 0);
817 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
818 ASSERT_THAT(result, IsValidRingBuffer());
819 EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
820 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
821 EXPECT_THAT(result->length, Eq(4 + str2.size()));
822 if (GetParam().refcount_is_one) {
823 EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str2, "1234")));
824 } else {
825 EXPECT_THAT(ToFlats(result), ElementsAre(str2, "1234"));
826 }
827 }
828
TEST_P(CordRingBuildTest,PrependStringHavingSharedExtra)829 TEST_P(CordRingBuildTest, PrependStringHavingSharedExtra) {
830 absl::string_view str1 = "123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
831 absl::string_view str2 = "abcdefghij";
832 absl::string_view str1a = str1.substr(10);
833 for (int shared_type = 1; shared_type < 2; ++shared_type) {
834 SCOPED_TRACE(absl::StrCat("Shared extra type ", shared_type));
835
836 // Create a flat that is shared in some way.
837 CordRep* flat = nullptr;
838 CordRep* flat1 = nullptr;
839 if (shared_type == 1) {
840 // Shared flat inside private substring
841 flat = RemovePrefix(10, flat1 = CordRep::Ref(MakeFlat(str1)));
842 } else {
843 // Private flat inside shared substring
844 flat = CordRep::Ref(RemovePrefix(10, MakeFlat(str1, 100)));
845 }
846
847 CordRepRing* ring = CreateWithCapacity(flat, 1);
848 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
849 ASSERT_THAT(result, IsValidRingBuffer());
850 EXPECT_THAT(result->length, Eq(str1a.size() + str2.size()));
851 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
852 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
853 EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1a));
854 CordRep::Unref(shared_type == 1 ? flat1 : flat);
855 }
856 }
857
TEST_P(CordRingBuildTest,PrependStringWithExtra)858 TEST_P(CordRingBuildTest, PrependStringWithExtra) {
859 absl::string_view str1 = "1234";
860 absl::string_view str2 = "1234567890";
861 absl::string_view str3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
862 CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
863 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2, 26));
864 ASSERT_THAT(result, IsValidRingBuffer());
865 result = CordRepRing::Prepend(result, str3);
866 EXPECT_THAT(result->length, Eq(str1.size() + str2.size() + str3.size()));
867 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
868 EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str3, str2), str1));
869 }
870
TEST_P(CordRingBuildTest,AppendPrependStringMix)871 TEST_P(CordRingBuildTest, AppendPrependStringMix) {
872 const auto& flats = kFoxFlats;
873 CordRepRing* ring = CreateWithCapacity(MakeFlat(flats[4]), 8);
874 CordRepRing* result = ring;
875 for (int i = 1; i <= 4; ++i) {
876 result = CordRepRing::Prepend(result, flats[4 - i]);
877 result = CordRepRing::Append(result, flats[4 + i]);
878 }
879 NeedsUnref(result);
880 ASSERT_THAT(result, IsValidRingBuffer());
881 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
882 EXPECT_THAT(ToString(result), kFox);
883 }
884
TEST_P(CordRingBuildTest,AppendPrependStringMixWithExtra)885 TEST_P(CordRingBuildTest, AppendPrependStringMixWithExtra) {
886 const auto& flats = kFoxFlats;
887 CordRepRing* ring = CreateWithCapacity(MakeFlat(flats[4], 100), 8);
888 CordRepRing* result = ring;
889 for (int i = 1; i <= 4; ++i) {
890 result = CordRepRing::Prepend(result, flats[4 - i], 100);
891 result = CordRepRing::Append(result, flats[4 + i], 100);
892 }
893 NeedsUnref(result);
894 ASSERT_THAT(result, IsValidRingBuffer());
895 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
896 if (GetParam().refcount_is_one) {
897 EXPECT_THAT(ToFlats(result),
898 ElementsAre("The quick brown fox ", "jumps over the lazy dog"));
899 } else {
900 EXPECT_THAT(ToFlats(result), ElementsAre("The quick brown fox ", "jumps ",
901 "over the lazy dog"));
902 }
903 }
904
TEST_P(CordRingBuildTest,AppendPrependStringMixWithPrependedExtra)905 TEST_P(CordRingBuildTest, AppendPrependStringMixWithPrependedExtra) {
906 const auto& flats = kFoxFlats;
907 CordRep* flat = MakeFlat(StrCat(std::string(50, '.'), flats[4]), 50);
908 CordRepRing* ring = CreateWithCapacity(RemovePrefix(50, flat), 0);
909 CordRepRing* result = ring;
910 for (int i = 1; i <= 4; ++i) {
911 result = CordRepRing::Prepend(result, flats[4 - i], 100);
912 result = CordRepRing::Append(result, flats[4 + i], 100);
913 }
914 result = NeedsUnref(result);
915 ASSERT_THAT(result, IsValidRingBuffer());
916 EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
917 if (GetParam().refcount_is_one) {
918 EXPECT_THAT(ToFlats(result), ElementsAre(kFox));
919 } else {
920 EXPECT_THAT(ToFlats(result), ElementsAre("The quick brown fox ", "jumps ",
921 "over the lazy dog"));
922 }
923 }
924
TEST_P(CordRingSubTest,SubRing)925 TEST_P(CordRingSubTest, SubRing) {
926 auto composition = RandomComposition();
927 SCOPED_TRACE(ToString(composition));
928 auto flats = MakeSpan(kFoxFlats);
929 string_view all = kFox;
930 for (size_t offset = 0; offset < all.size() - 1; ++offset) {
931 CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
932 CordRepRing* result = CordRepRing::SubRing(ring, offset, 0);
933 EXPECT_THAT(result, nullptr);
934
935 for (size_t len = 1; len < all.size() - offset; ++len) {
936 ring = RefIfShared(FromFlats(flats, composition));
937 result = NeedsUnref(CordRepRing::SubRing(ring, offset, len));
938 ASSERT_THAT(result, IsValidRingBuffer());
939 ASSERT_THAT(result, EqIfPrivate(GetParam(), ring));
940 ASSERT_THAT(result, NeIfShared(GetParam(), ring));
941 ASSERT_THAT(ToString(result), Eq(all.substr(offset, len)));
942 }
943 }
944 }
945
TEST_P(CordRingSubTest,SubRingFromLargeExternal)946 TEST_P(CordRingSubTest, SubRingFromLargeExternal) {
947 auto composition = RandomComposition();
948 std::string large_string(1 << 20, '.');
949 const char* flats[] = {
950 "abcdefghijklmnopqrstuvwxyz",
951 large_string.c_str(),
952 "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
953 };
954 std::string buffer = absl::StrCat(flats[0], flats[1], flats[2]);
955 absl::string_view all = buffer;
956 for (size_t offset = 0; offset < 30; ++offset) {
957 CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
958 CordRepRing* result = CordRepRing::SubRing(ring, offset, 0);
959 EXPECT_THAT(result, nullptr);
960
961 for (size_t len = all.size() - 30; len < all.size() - offset; ++len) {
962 ring = RefIfShared(FromFlats(flats, composition));
963 result = NeedsUnref(CordRepRing::SubRing(ring, offset, len));
964 ASSERT_THAT(result, IsValidRingBuffer());
965 ASSERT_THAT(result, EqIfPrivate(GetParam(), ring));
966 ASSERT_THAT(result, NeIfShared(GetParam(), ring));
967 auto str = ToString(result);
968 ASSERT_THAT(str, SizeIs(len));
969 ASSERT_THAT(str, Eq(all.substr(offset, len)));
970 }
971 }
972 }
973
TEST_P(CordRingSubTest,RemovePrefix)974 TEST_P(CordRingSubTest, RemovePrefix) {
975 auto composition = RandomComposition();
976 SCOPED_TRACE(ToString(composition));
977 auto flats = MakeSpan(kFoxFlats);
978 string_view all = kFox;
979 CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
980 CordRepRing* result = CordRepRing::RemovePrefix(ring, all.size());
981 EXPECT_THAT(result, nullptr);
982
983 for (size_t len = 1; len < all.size(); ++len) {
984 ring = RefIfShared(FromFlats(flats, composition));
985 result = NeedsUnref(CordRepRing::RemovePrefix(ring, len));
986 ASSERT_THAT(result, IsValidRingBuffer());
987 EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
988 ASSERT_THAT(result, NeIfShared(GetParam(), ring));
989 EXPECT_THAT(ToString(result), Eq(all.substr(len)));
990 }
991 }
992
TEST_P(CordRingSubTest,RemovePrefixFromLargeExternal)993 TEST_P(CordRingSubTest, RemovePrefixFromLargeExternal) {
994 CordRepExternal* external1 = MakeFakeExternal(1 << 20);
995 CordRepExternal* external2 = MakeFakeExternal(1 << 20);
996 CordRepRing* ring = CordRepRing::Create(external1, 1);
997 ring = CordRepRing::Append(ring, external2);
998 CordRepRing* result = NeedsUnref(CordRepRing::RemovePrefix(ring, 1 << 16));
999 EXPECT_THAT(
1000 ToRawFlats(result),
1001 ElementsAre(
1002 not_a_string_view(external1->base, 1 << 20).remove_prefix(1 << 16),
1003 not_a_string_view(external2->base, 1 << 20)));
1004 }
1005
TEST_P(CordRingSubTest,RemoveSuffix)1006 TEST_P(CordRingSubTest, RemoveSuffix) {
1007 auto composition = RandomComposition();
1008 SCOPED_TRACE(ToString(composition));
1009 auto flats = MakeSpan(kFoxFlats);
1010 string_view all = kFox;
1011 CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
1012 CordRepRing* result = CordRepRing::RemoveSuffix(ring, all.size());
1013 EXPECT_THAT(result, nullptr);
1014
1015 for (size_t len = 1; len < all.size(); ++len) {
1016 ring = RefIfShared(FromFlats(flats, composition));
1017 result = NeedsUnref(CordRepRing::RemoveSuffix(ring, len));
1018 ASSERT_THAT(result, IsValidRingBuffer());
1019 ASSERT_THAT(result, EqIfPrivate(GetParam(), ring));
1020 ASSERT_THAT(result, NeIfShared(GetParam(), ring));
1021 ASSERT_THAT(ToString(result), Eq(all.substr(0, all.size() - len)));
1022 }
1023 }
1024
TEST_P(CordRingSubTest,AppendRing)1025 TEST_P(CordRingSubTest, AppendRing) {
1026 auto composition = RandomComposition();
1027 SCOPED_TRACE(ToString(composition));
1028 auto flats = MakeSpan(kFoxFlats).subspan(1);
1029 CordRepRing* ring = CreateWithCapacity(MakeFlat(kFoxFlats[0]), flats.size());
1030 CordRepRing* child = FromFlats(flats, composition);
1031 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, child));
1032 ASSERT_THAT(result, IsValidRingBuffer());
1033 EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
1034 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1035 EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
1036 }
1037
TEST_P(CordRingBuildInputTest,AppendRingWithFlatOffset)1038 TEST_P(CordRingBuildInputTest, AppendRingWithFlatOffset) {
1039 auto composition = RandomComposition();
1040 SCOPED_TRACE(ToString(composition));
1041 auto flats = MakeSpan(kFoxFlats);
1042 CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
1043 CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
1044 CordRep* stripped = RemovePrefix(10, child);
1045 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
1046 ASSERT_THAT(result, IsValidRingBuffer());
1047 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1048 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1049 EXPECT_THAT(ToFlats(result), ElementsAre("Head", "brown ", "fox ", "jumps ",
1050 "over ", "the ", "lazy ", "dog"));
1051 }
1052
TEST_P(CordRingBuildInputTest,AppendRingWithBrokenOffset)1053 TEST_P(CordRingBuildInputTest, AppendRingWithBrokenOffset) {
1054 auto composition = RandomComposition();
1055 SCOPED_TRACE(ToString(composition));
1056 auto flats = MakeSpan(kFoxFlats);
1057 CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
1058 CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
1059 CordRep* stripped = RemovePrefix(21, child);
1060 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
1061 ASSERT_THAT(result, IsValidRingBuffer());
1062 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1063 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1064 EXPECT_THAT(ToFlats(result),
1065 ElementsAre("Head", "umps ", "over ", "the ", "lazy ", "dog"));
1066 }
1067
TEST_P(CordRingBuildInputTest,AppendRingWithFlatLength)1068 TEST_P(CordRingBuildInputTest, AppendRingWithFlatLength) {
1069 auto composition = RandomComposition();
1070 SCOPED_TRACE(ToString(composition));
1071 auto flats = MakeSpan(kFoxFlats);
1072 CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
1073 CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
1074 CordRep* stripped = RemoveSuffix(8, child);
1075 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
1076 ASSERT_THAT(result, IsValidRingBuffer());
1077 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1078 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1079 EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ",
1080 "fox ", "jumps ", "over ", "the "));
1081 }
1082
TEST_P(CordRingBuildTest,AppendRingWithBrokenFlatLength)1083 TEST_P(CordRingBuildTest, AppendRingWithBrokenFlatLength) {
1084 auto composition = RandomComposition();
1085 SCOPED_TRACE(ToString(composition));
1086 auto flats = MakeSpan(kFoxFlats);
1087 CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
1088 CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
1089 CordRep* stripped = RemoveSuffix(15, child);
1090 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
1091 ASSERT_THAT(result, IsValidRingBuffer());
1092 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1093 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1094 EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ",
1095 "fox ", "jumps ", "ov"));
1096 }
1097
TEST_P(CordRingBuildTest,AppendRingMiddlePiece)1098 TEST_P(CordRingBuildTest, AppendRingMiddlePiece) {
1099 auto composition = RandomComposition();
1100 SCOPED_TRACE(ToString(composition));
1101 auto flats = MakeSpan(kFoxFlats);
1102 CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
1103 CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
1104 CordRep* stripped = MakeSubstring(7, child->length - 27, child);
1105 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
1106 ASSERT_THAT(result, IsValidRingBuffer());
1107 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1108 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1109 EXPECT_THAT(ToFlats(result),
1110 ElementsAre("Head", "ck ", "brown ", "fox ", "jum"));
1111 }
1112
TEST_P(CordRingBuildTest,AppendRingSinglePiece)1113 TEST_P(CordRingBuildTest, AppendRingSinglePiece) {
1114 auto composition = RandomComposition();
1115 SCOPED_TRACE(ToString(composition));
1116 auto flats = MakeSpan(kFoxFlats);
1117 CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
1118 CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
1119 CordRep* stripped = RefIfInputShared(MakeSubstring(11, 3, child));
1120 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
1121 ASSERT_THAT(result, IsValidRingBuffer());
1122 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1123 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1124 EXPECT_THAT(ToFlats(result), ElementsAre("Head", "row"));
1125 }
1126
TEST_P(CordRingBuildInputTest,AppendRingSinglePieceWithPrefix)1127 TEST_P(CordRingBuildInputTest, AppendRingSinglePieceWithPrefix) {
1128 auto composition = RandomComposition();
1129 SCOPED_TRACE(ToString(composition));
1130 auto flats = MakeSpan(kFoxFlats);
1131 size_t extra_capacity = 1 + (GetParam().with_capacity ? flats.size() : 0);
1132 CordRepRing* ring = CordRepRing::Create(MakeFlat("Head"), extra_capacity);
1133 ring->SetCapacityForTesting(1 + extra_capacity);
1134 ring = RefIfShared(CordRepRing::Prepend(ring, MakeFlat("Prepend")));
1135 assert(ring->IsValid(std::cout));
1136 CordRepRing* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
1137 CordRep* stripped = RefIfInputShared(MakeSubstring(11, 3, child));
1138 CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
1139 ASSERT_THAT(result, IsValidRingBuffer());
1140 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1141 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1142 EXPECT_THAT(ToFlats(result), ElementsAre("Prepend", "Head", "row"));
1143 }
1144
TEST_P(CordRingBuildInputTest,PrependRing)1145 TEST_P(CordRingBuildInputTest, PrependRing) {
1146 auto composition = RandomComposition();
1147 SCOPED_TRACE(ToString(composition));
1148 auto fox = MakeSpan(kFoxFlats);
1149 auto flats = MakeSpan(fox).subspan(0, fox.size() - 1);
1150 CordRepRing* ring = CreateWithCapacity(MakeFlat(fox.back()), flats.size());
1151 CordRepRing* child = RefIfInputShared(FromFlats(flats, composition));
1152 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, child));
1153 ASSERT_THAT(result, IsValidRingBuffer());
1154 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1155 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1156 EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
1157 }
1158
TEST_P(CordRingBuildInputTest,PrependRingWithFlatOffset)1159 TEST_P(CordRingBuildInputTest, PrependRingWithFlatOffset) {
1160 auto composition = RandomComposition();
1161 SCOPED_TRACE(ToString(composition));
1162 auto flats = MakeSpan(kFoxFlats);
1163 CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
1164 CordRep* child = RefIfInputShared(FromFlats(flats, composition));
1165 CordRep* stripped = RefIfInputSharedIndirect(RemovePrefix(10, child));
1166 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
1167 ASSERT_THAT(result, IsValidRingBuffer());
1168 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1169 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1170 EXPECT_THAT(ToFlats(result), ElementsAre("brown ", "fox ", "jumps ", "over ",
1171 "the ", "lazy ", "dog", "Tail"));
1172 }
1173
TEST_P(CordRingBuildInputTest,PrependRingWithBrokenOffset)1174 TEST_P(CordRingBuildInputTest, PrependRingWithBrokenOffset) {
1175 auto composition = RandomComposition();
1176 SCOPED_TRACE(ToString(composition));
1177 auto flats = MakeSpan(kFoxFlats);
1178 CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
1179 CordRep* child = RefIfInputShared(FromFlats(flats, composition));
1180 CordRep* stripped = RefIfInputSharedIndirect(RemovePrefix(21, child));
1181 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
1182 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1183 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1184 EXPECT_THAT(ToFlats(result),
1185 ElementsAre("umps ", "over ", "the ", "lazy ", "dog", "Tail"));
1186 }
1187
TEST_P(CordRingBuildInputTest,PrependRingWithFlatLength)1188 TEST_P(CordRingBuildInputTest, PrependRingWithFlatLength) {
1189 auto composition = RandomComposition();
1190 SCOPED_TRACE(ToString(composition));
1191 auto flats = MakeSpan(kFoxFlats);
1192 CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
1193 CordRep* child = RefIfInputShared(FromFlats(flats, composition));
1194 CordRep* stripped = RefIfInputSharedIndirect(RemoveSuffix(8, child));
1195 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
1196 ASSERT_THAT(result, IsValidRingBuffer());
1197 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1198 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1199 EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ",
1200 "jumps ", "over ", "the ", "Tail"));
1201 }
1202
TEST_P(CordRingBuildInputTest,PrependRingWithBrokenFlatLength)1203 TEST_P(CordRingBuildInputTest, PrependRingWithBrokenFlatLength) {
1204 auto composition = RandomComposition();
1205 SCOPED_TRACE(ToString(composition));
1206 auto flats = MakeSpan(kFoxFlats);
1207 CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
1208 CordRep* child = RefIfInputShared(FromFlats(flats, composition));
1209 CordRep* stripped = RefIfInputSharedIndirect(RemoveSuffix(15, child));
1210 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
1211 ASSERT_THAT(result, IsValidRingBuffer());
1212 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1213 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1214 EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ",
1215 "jumps ", "ov", "Tail"));
1216 }
1217
TEST_P(CordRingBuildInputTest,PrependRingMiddlePiece)1218 TEST_P(CordRingBuildInputTest, PrependRingMiddlePiece) {
1219 auto composition = RandomComposition();
1220 SCOPED_TRACE(ToString(composition));
1221 auto flats = MakeSpan(kFoxFlats);
1222 CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
1223 CordRep* child = RefIfInputShared(FromFlats(flats, composition));
1224 CordRep* stripped =
1225 RefIfInputSharedIndirect(MakeSubstring(7, child->length - 27, child));
1226 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
1227 ASSERT_THAT(result, IsValidRingBuffer());
1228 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1229 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1230 EXPECT_THAT(ToFlats(result),
1231 ElementsAre("ck ", "brown ", "fox ", "jum", "Tail"));
1232 }
1233
TEST_P(CordRingBuildInputTest,PrependRingSinglePiece)1234 TEST_P(CordRingBuildInputTest, PrependRingSinglePiece) {
1235 auto composition = RandomComposition();
1236 SCOPED_TRACE(ToString(composition));
1237 auto flats = MakeSpan(kFoxFlats);
1238 CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
1239 CordRep* child = RefIfInputShared(FromFlats(flats, composition));
1240 CordRep* stripped = RefIfInputSharedIndirect(MakeSubstring(11, 3, child));
1241 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
1242 ASSERT_THAT(result, IsValidRingBuffer());
1243 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1244 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1245 EXPECT_THAT(ToFlats(result), ElementsAre("row", "Tail"));
1246 }
1247
TEST_P(CordRingBuildInputTest,PrependRingSinglePieceWithPrefix)1248 TEST_P(CordRingBuildInputTest, PrependRingSinglePieceWithPrefix) {
1249 auto composition = RandomComposition();
1250 SCOPED_TRACE(ToString(composition));
1251 auto flats = MakeSpan(kFoxFlats);
1252 size_t extra_capacity = 1 + (GetParam().with_capacity ? flats.size() : 0);
1253 CordRepRing* ring = CordRepRing::Create(MakeFlat("Tail"), extra_capacity);
1254 ring->SetCapacityForTesting(1 + extra_capacity);
1255 ring = RefIfShared(CordRepRing::Prepend(ring, MakeFlat("Prepend")));
1256 CordRep* child = RefIfInputShared(FromFlats(flats, composition));
1257 CordRep* stripped = RefIfInputSharedIndirect(MakeSubstring(11, 3, child));
1258 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
1259 ASSERT_THAT(result, IsValidRingBuffer());
1260 EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
1261 EXPECT_THAT(result, NeIfShared(GetParam(), ring));
1262 EXPECT_THAT(ToFlats(result), ElementsAre("row", "Prepend", "Tail"));
1263 }
1264
TEST_F(CordRingTest,Find)1265 TEST_F(CordRingTest, Find) {
1266 constexpr const char* flats[] = {
1267 "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
1268 "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
1269 "+-=", "[]\\{}|;':", ",/<>?", "."};
1270 auto composition = RandomComposition();
1271 SCOPED_TRACE(ToString(composition));
1272 CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
1273 std::string value = ToString(ring);
1274 for (int i = 0; i < value.length(); ++i) {
1275 CordRepRing::Position found = ring->Find(i);
1276 auto data = ring->entry_data(found.index);
1277 ASSERT_THAT(found.offset, Lt(data.length()));
1278 ASSERT_THAT(data[found.offset], Eq(value[i]));
1279 }
1280 }
1281
TEST_F(CordRingTest,FindWithHint)1282 TEST_F(CordRingTest, FindWithHint) {
1283 constexpr const char* flats[] = {
1284 "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
1285 "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
1286 "+-=", "[]\\{}|;':", ",/<>?", "."};
1287 auto composition = RandomComposition();
1288 SCOPED_TRACE(ToString(composition));
1289 CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
1290 std::string value = ToString(ring);
1291
1292 #if defined(GTEST_HAS_DEATH_TEST)
1293 // Test hint beyond valid position
1294 index_type head = ring->head();
1295 EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head), 0), ".*");
1296 EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head), 9), ".*");
1297 EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head, 3), 24), ".*");
1298 #endif
1299
1300 int flat_pos = 0;
1301 size_t flat_offset = 0;
1302 for (auto sflat : flats) {
1303 string_view flat(sflat);
1304 for (int offset = 0; offset < flat.length(); ++offset) {
1305 for (int start = 0; start <= flat_pos; ++start) {
1306 index_type hint = ring->advance(ring->head(), start);
1307 CordRepRing::Position found = ring->Find(hint, flat_offset + offset);
1308 ASSERT_THAT(found.index, Eq(ring->advance(ring->head(), flat_pos)));
1309 ASSERT_THAT(found.offset, Eq(offset));
1310 }
1311 }
1312 ++flat_pos;
1313 flat_offset += flat.length();
1314 }
1315 }
1316
TEST_F(CordRingTest,FindInLargeRing)1317 TEST_F(CordRingTest, FindInLargeRing) {
1318 constexpr const char* flats[] = {
1319 "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
1320 "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
1321 "+-=", "[]\\{}|;':", ",/<>?", "."};
1322 auto composition = RandomComposition();
1323 SCOPED_TRACE(ToString(composition));
1324 CordRepRing* ring = FromFlats(flats, composition);
1325 for (int i = 0; i < 13; ++i) {
1326 ring = CordRepRing::Append(ring, FromFlats(flats, composition));
1327 }
1328 NeedsUnref(ring);
1329 std::string value = ToString(ring);
1330 for (int i = 0; i < value.length(); ++i) {
1331 CordRepRing::Position pos = ring->Find(i);
1332 auto data = ring->entry_data(pos.index);
1333 ASSERT_THAT(pos.offset, Lt(data.length()));
1334 ASSERT_THAT(data[pos.offset], Eq(value[i]));
1335 }
1336 }
1337
TEST_F(CordRingTest,FindTail)1338 TEST_F(CordRingTest, FindTail) {
1339 constexpr const char* flats[] = {
1340 "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
1341 "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
1342 "+-=", "[]\\{}|;':", ",/<>?", "."};
1343 auto composition = RandomComposition();
1344 SCOPED_TRACE(ToString(composition));
1345 CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
1346 std::string value = ToString(ring);
1347
1348 for (int i = 0; i < value.length(); ++i) {
1349 CordRepRing::Position pos = ring->FindTail(i + 1);
1350 auto data = ring->entry_data(ring->retreat(pos.index));
1351 ASSERT_THAT(pos.offset, Lt(data.length()));
1352 ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
1353 }
1354 }
1355
TEST_F(CordRingTest,FindTailWithHint)1356 TEST_F(CordRingTest, FindTailWithHint) {
1357 constexpr const char* flats[] = {
1358 "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
1359 "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
1360 "+-=", "[]\\{}|;':", ",/<>?", "."};
1361 auto composition = RandomComposition();
1362 SCOPED_TRACE(ToString(composition));
1363 CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
1364 std::string value = ToString(ring);
1365
1366 // Test hint beyond valid position
1367 #if defined(GTEST_HAS_DEATH_TEST)
1368 index_type head = ring->head();
1369 EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head), 1), ".*");
1370 EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head), 10), ".*");
1371 EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head, 3), 26), ".*");
1372 #endif
1373
1374 for (int i = 0; i < value.length(); ++i) {
1375 CordRepRing::Position pos = ring->FindTail(i + 1);
1376 auto data = ring->entry_data(ring->retreat(pos.index));
1377 ASSERT_THAT(pos.offset, Lt(data.length()));
1378 ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
1379 }
1380 }
1381
TEST_F(CordRingTest,FindTailInLargeRing)1382 TEST_F(CordRingTest, FindTailInLargeRing) {
1383 constexpr const char* flats[] = {
1384 "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
1385 "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
1386 "+-=", "[]\\{}|;':", ",/<>?", "."};
1387 auto composition = RandomComposition();
1388 SCOPED_TRACE(ToString(composition));
1389 CordRepRing* ring = FromFlats(flats, composition);
1390 for (int i = 0; i < 13; ++i) {
1391 ring = CordRepRing::Append(ring, FromFlats(flats, composition));
1392 }
1393 NeedsUnref(ring);
1394 std::string value = ToString(ring);
1395 for (int i = 0; i < value.length(); ++i) {
1396 CordRepRing::Position pos = ring->FindTail(i + 1);
1397 auto data = ring->entry_data(ring->retreat(pos.index));
1398 ASSERT_THAT(pos.offset, Lt(data.length()));
1399 ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
1400 }
1401 }
1402
TEST_F(CordRingTest,GetCharacter)1403 TEST_F(CordRingTest, GetCharacter) {
1404 auto flats = MakeSpan(kFoxFlats);
1405 CordRepRing* ring = CordRepRing::Create(MakeFlat("Tail"), flats.size());
1406 CordRep* child = FromFlats(flats, kAppend);
1407 CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, child));
1408 std::string value = ToString(result);
1409 for (int i = 0; i < value.length(); ++i) {
1410 ASSERT_THAT(result->GetCharacter(i), Eq(value[i]));
1411 }
1412 }
1413
TEST_F(CordRingTest,GetCharacterWithSubstring)1414 TEST_F(CordRingTest, GetCharacterWithSubstring) {
1415 absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
1416 auto* child = MakeSubstring(4, 20, MakeFlat(str1));
1417 CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
1418 ASSERT_THAT(result, IsValidRingBuffer());
1419 std::string value = ToString(result);
1420 for (int i = 0; i < value.length(); ++i) {
1421 ASSERT_THAT(result->GetCharacter(i), Eq(value[i]));
1422 }
1423 }
1424
TEST_F(CordRingTest,IsFlatSingleFlat)1425 TEST_F(CordRingTest, IsFlatSingleFlat) {
1426 for (bool external : {false, true}) {
1427 SCOPED_TRACE(external ? "With External" : "With Flat");
1428 absl::string_view str = "Hello world";
1429 CordRep* rep = external ? MakeExternal(str) : MakeFlat(str);
1430 CordRepRing* ring = NeedsUnref(CordRepRing::Create(rep));
1431
1432 // The ring is a single non-fragmented flat:
1433 absl::string_view fragment;
1434 EXPECT_TRUE(ring->IsFlat(nullptr));
1435 EXPECT_TRUE(ring->IsFlat(&fragment));
1436 EXPECT_THAT(fragment, Eq("Hello world"));
1437 fragment = "";
1438 EXPECT_TRUE(ring->IsFlat(0, 11, nullptr));
1439 EXPECT_TRUE(ring->IsFlat(0, 11, &fragment));
1440 EXPECT_THAT(fragment, Eq("Hello world"));
1441
1442 // Arbitrary ranges must check true as well.
1443 EXPECT_TRUE(ring->IsFlat(1, 4, &fragment));
1444 EXPECT_THAT(fragment, Eq("ello"));
1445 EXPECT_TRUE(ring->IsFlat(6, 5, &fragment));
1446 EXPECT_THAT(fragment, Eq("world"));
1447 }
1448 }
1449
TEST_F(CordRingTest,IsFlatMultiFlat)1450 TEST_F(CordRingTest, IsFlatMultiFlat) {
1451 for (bool external : {false, true}) {
1452 SCOPED_TRACE(external ? "With External" : "With Flat");
1453 absl::string_view str1 = "Hello world";
1454 absl::string_view str2 = "Halt and catch fire";
1455 CordRep* rep1 = external ? MakeExternal(str1) : MakeFlat(str1);
1456 CordRep* rep2 = external ? MakeExternal(str2) : MakeFlat(str2);
1457 CordRepRing* ring = CordRepRing::Append(CordRepRing::Create(rep1), rep2);
1458 NeedsUnref(ring);
1459
1460 // The ring is fragmented, IsFlat() on the entire cord must be false.
1461 EXPECT_FALSE(ring->IsFlat(nullptr));
1462 absl::string_view fragment = "Don't touch this";
1463 EXPECT_FALSE(ring->IsFlat(&fragment));
1464 EXPECT_THAT(fragment, Eq("Don't touch this"));
1465
1466 // Check for ranges exactly within both flats.
1467 EXPECT_TRUE(ring->IsFlat(0, 11, &fragment));
1468 EXPECT_THAT(fragment, Eq("Hello world"));
1469 EXPECT_TRUE(ring->IsFlat(11, 19, &fragment));
1470 EXPECT_THAT(fragment, Eq("Halt and catch fire"));
1471
1472 // Check for arbitrary partial range inside each flat.
1473 EXPECT_TRUE(ring->IsFlat(1, 4, &fragment));
1474 EXPECT_THAT(fragment, "ello");
1475 EXPECT_TRUE(ring->IsFlat(26, 4, &fragment));
1476 EXPECT_THAT(fragment, "fire");
1477
1478 // Check ranges spanning across both flats
1479 fragment = "Don't touch this";
1480 EXPECT_FALSE(ring->IsFlat(1, 18, &fragment));
1481 EXPECT_FALSE(ring->IsFlat(10, 2, &fragment));
1482 EXPECT_THAT(fragment, Eq("Don't touch this"));
1483 }
1484 }
1485
TEST_F(CordRingTest,Dump)1486 TEST_F(CordRingTest, Dump) {
1487 std::stringstream ss;
1488 auto flats = MakeSpan(kFoxFlats);
1489 CordRepRing* ring = NeedsUnref(FromFlats(flats, kPrepend));
1490 ss << *ring;
1491 }
1492
1493 } // namespace
1494 ABSL_NAMESPACE_END
1495 } // namespace absl
1496