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