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