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