aboutsummaryrefslogtreecommitdiff
path: root/absl/strings/cord_ring_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/cord_ring_test.cc')
-rw-r--r--absl/strings/cord_ring_test.cc1458
1 files changed, 0 insertions, 1458 deletions
diff --git a/absl/strings/cord_ring_test.cc b/absl/strings/cord_ring_test.cc
deleted file mode 100644
index 74f57c77..00000000
--- a/absl/strings/cord_ring_test.cc
+++ /dev/null
@@ -1,1458 +0,0 @@
-// Copyright 2020 The Abseil Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <cassert>
-#include <cstdlib>
-#include <cstring>
-#include <ctime>
-#include <iostream>
-#include <ostream>
-#include <random>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "absl/base/config.h"
-#include "absl/strings/internal/cord_internal.h"
-#include "absl/strings/internal/cord_rep_flat.h"
-#include "absl/strings/internal/cord_rep_ring.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/string_view.h"
-#include "absl/types/span.h"
-
-extern thread_local bool cord_ring;
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace {
-
-using RandomEngine = std::mt19937_64;
-
-using ::absl::cord_internal::CordRep;
-using ::absl::cord_internal::CordRepConcat;
-using ::absl::cord_internal::CordRepExternal;
-using ::absl::cord_internal::CordRepFlat;
-using ::absl::cord_internal::CordRepRing;
-using ::absl::cord_internal::CordRepSubstring;
-
-using ::absl::cord_internal::EXTERNAL;
-using ::absl::cord_internal::SUBSTRING;
-
-using testing::ElementsAre;
-using testing::ElementsAreArray;
-using testing::Eq;
-using testing::Ge;
-using testing::Le;
-using testing::Lt;
-using testing::Ne;
-using testing::SizeIs;
-
-using index_type = CordRepRing::index_type;
-
-enum InputShareMode { kPrivate, kShared, kSharedIndirect };
-
-// TestParam class used by all test fixtures.
-// Not all fixtures use all possible input combinations
-struct TestParam {
- TestParam() = default;
- explicit TestParam(InputShareMode input_share_mode)
- : input_share_mode(input_share_mode) {}
-
- // Run the test with the 'rep under test' to be privately owned.
- // Otherwise, the rep has a shared ref count of 2 or higher.
- bool refcount_is_one = true;
-
- // Run the test with the 'rep under test' being allocated with enough capacity
- // to accommodate any modifications made to it. Otherwise, the rep has zero
- // extra (reserve) capacity.
- bool with_capacity = true;
-
- // For test providing possibly shared input such as Append(.., CordpRep*),
- // this field defines if that input is adopted with a refcount of one
- // (privately owned / donated), or shared. For composite inputs such as
- // 'substring of flat', we also have the 'shared indirect' value which means
- // the top level node is not shared, but the contained child node is shared.
- InputShareMode input_share_mode = kPrivate;
-
- std::string ToString() const {
- return absl::StrCat(refcount_is_one ? "Private" : "Shared",
- with_capacity ? "" : "_NoCapacity",
- (input_share_mode == kPrivate) ? ""
- : (input_share_mode == kShared)
- ? "_SharedInput"
- : "_IndirectSharedInput");
- }
-};
-using TestParams = std::vector<TestParam>;
-
-// Matcher validating when mutable copies are required / performed.
-MATCHER_P2(EqIfPrivate, param, rep,
- absl::StrCat("Equal 0x", absl::Hex(rep), " if private")) {
- return param.refcount_is_one ? arg == rep : true;
-}
-
-// Matcher validating when mutable copies are required / performed.
-MATCHER_P2(EqIfPrivateAndCapacity, param, rep,
- absl::StrCat("Equal 0x", absl::Hex(rep),
- " if private and capacity")) {
- return (param.refcount_is_one && param.with_capacity) ? arg == rep : true;
-}
-
-// Matcher validating a shared ring was re-allocated. Should only be used for
-// tests doing exactly one update as subsequent updates could return the
-// original (freed and re-used) pointer.
-MATCHER_P2(NeIfShared, param, rep,
- absl::StrCat("Not equal 0x", absl::Hex(rep), " if shared")) {
- return param.refcount_is_one ? true : arg != rep;
-}
-
-MATCHER_P2(EqIfInputPrivate, param, rep, "Equal if input is private") {
- return param.input_share_mode == kPrivate ? arg == rep : arg != rep;
-}
-
-// Matcher validating the core in-variants of the CordRepRing instance.
-MATCHER(IsValidRingBuffer, "RingBuffer is valid") {
- std::stringstream ss;
- if (!arg->IsValid(ss)) {
- *result_listener << "\nERROR: " << ss.str() << "\nRING = " << *arg;
- return false;
- }
- return true;
-}
-
-// Returns the flats contained in the provided CordRepRing
-std::vector<string_view> ToFlats(const CordRepRing* r) {
- std::vector<string_view> flats;
- flats.reserve(r->entries());
- index_type pos = r->head();
- do {
- flats.push_back(r->entry_data(pos));
- } while ((pos = r->advance(pos)) != r->tail());
- return flats;
-}
-
-class not_a_string_view {
- public:
- explicit not_a_string_view(absl::string_view s)
- : data_(s.data()), size_(s.size()) {}
- explicit not_a_string_view(const void* data, size_t size)
- : data_(data), size_(size) {}
-
- not_a_string_view remove_prefix(size_t n) const {
- return not_a_string_view(static_cast<const char*>(data_) + n, size_ - n);
- }
-
- not_a_string_view remove_suffix(size_t n) const {
- return not_a_string_view(data_, size_ - n);
- }
-
- const void* data() const { return data_; }
- size_t size() const { return size_; }
-
- private:
- const void* data_;
- size_t size_;
-};
-
-bool operator==(not_a_string_view lhs, not_a_string_view rhs) {
- return lhs.data() == rhs.data() && lhs.size() == rhs.size();
-}
-
-std::ostream& operator<<(std::ostream& s, not_a_string_view rhs) {
- return s << "{ data: " << rhs.data() << " size: " << rhs.size() << "}";
-}
-
-std::vector<not_a_string_view> ToRawFlats(const CordRepRing* r) {
- std::vector<not_a_string_view> flats;
- flats.reserve(r->entries());
- index_type pos = r->head();
- do {
- flats.emplace_back(r->entry_data(pos));
- } while ((pos = r->advance(pos)) != r->tail());
- return flats;
-}
-
-// Returns the value contained in the provided CordRepRing
-std::string ToString(const CordRepRing* r) {
- std::string value;
- value.reserve(r->length);
- index_type pos = r->head();
- do {
- absl::string_view sv = r->entry_data(pos);
- value.append(sv.data(), sv.size());
- } while ((pos = r->advance(pos)) != r->tail());
- return value;
-}
-
-// Creates a flat for testing
-CordRep* MakeFlat(absl::string_view s, size_t extra = 0) {
- CordRepFlat* flat = CordRepFlat::New(s.length() + extra);
- memcpy(flat->Data(), s.data(), s.length());
- flat->length = s.length();
- return flat;
-}
-
-// Creates an external node for testing
-CordRepExternal* MakeExternal(absl::string_view s) {
- struct Rep : public CordRepExternal {
- std::string s;
- explicit Rep(absl::string_view s) : s(s) {
- this->tag = EXTERNAL;
- this->base = s.data();
- this->length = s.length();
- this->releaser_invoker = [](CordRepExternal* self) {
- delete static_cast<Rep*>(self);
- };
- }
- };
- return new Rep(s);
-}
-
-CordRepExternal* MakeFakeExternal(size_t length) {
- struct Rep : public CordRepExternal {
- std::string s;
- explicit Rep(size_t len) {
- this->tag = EXTERNAL;
- this->base = reinterpret_cast<const char*>(this->storage);
- this->length = len;
- this->releaser_invoker = [](CordRepExternal* self) {
- delete static_cast<Rep*>(self);
- };
- }
- };
- return new Rep(length);
-}
-
-// Creates a flat or an external node for testing depending on the size.
-CordRep* MakeLeaf(absl::string_view s, size_t extra = 0) {
- if (s.size() <= absl::cord_internal::kMaxFlatLength) {
- return MakeFlat(s, extra);
- } else {
- return MakeExternal(s);
- }
-}
-
-// Creates a substring node
-CordRepSubstring* MakeSubstring(size_t start, size_t len, CordRep* rep) {
- auto* sub = new CordRepSubstring;
- sub->tag = SUBSTRING;
- sub->start = start;
- sub->length = (len <= 0) ? rep->length - start + len : len;
- sub->child = rep;
- return sub;
-}
-
-// Creates a substring node removing the specified prefix
-CordRepSubstring* RemovePrefix(size_t start, CordRep* rep) {
- return MakeSubstring(start, rep->length - start, rep);
-}
-
-// Creates a substring node removing the specified suffix
-CordRepSubstring* RemoveSuffix(size_t length, CordRep* rep) {
- return MakeSubstring(0, rep->length - length, rep);
-}
-
-enum Composition { kMix, kAppend, kPrepend };
-
-Composition RandomComposition() {
- RandomEngine rng(GTEST_FLAG_GET(random_seed));
- return (rng() & 1) ? kMix : ((rng() & 1) ? kAppend : kPrepend);
-}
-
-absl::string_view ToString(Composition composition) {
- switch (composition) {
- case kAppend:
- return "Append";
- case kPrepend:
- return "Prepend";
- case kMix:
- return "Mix";
- }
- assert(false);
- return "???";
-}
-
-constexpr const char* kFox = "The quick brown fox jumps over the lazy dog";
-constexpr const char* kFoxFlats[] = {"The ", "quick ", "brown ",
- "fox ", "jumps ", "over ",
- "the ", "lazy ", "dog"};
-
-CordRepRing* FromFlats(Span<const char* const> flats,
- Composition composition = kAppend) {
- if (flats.empty()) return nullptr;
- CordRepRing* ring = nullptr;
- switch (composition) {
- case kAppend:
- ring = CordRepRing::Create(MakeLeaf(flats.front()), flats.size() - 1);
- for (int i = 1; i < flats.size(); ++i) {
- ring = CordRepRing::Append(ring, MakeLeaf(flats[i]));
- }
- break;
- case kPrepend:
- ring = CordRepRing::Create(MakeLeaf(flats.back()), flats.size() - 1);
- for (int i = static_cast<int>(flats.size() - 2); i >= 0; --i) {
- ring = CordRepRing::Prepend(ring, MakeLeaf(flats[i]));
- }
- break;
- case kMix:
- size_t middle1 = flats.size() / 2, middle2 = middle1;
- ring = CordRepRing::Create(MakeLeaf(flats[middle1]), flats.size() - 1);
- if (!flats.empty()) {
- if ((flats.size() & 1) == 0) {
- ring = CordRepRing::Prepend(ring, MakeLeaf(flats[--middle1]));
- }
- for (int i = 1; i <= middle1; ++i) {
- ring = CordRepRing::Prepend(ring, MakeLeaf(flats[middle1 - i]));
- ring = CordRepRing::Append(ring, MakeLeaf(flats[middle2 + i]));
- }
- }
- break;
- }
- EXPECT_THAT(ToFlats(ring), ElementsAreArray(flats));
- return ring;
-}
-
-std::ostream& operator<<(std::ostream& s, const TestParam& param) {
- return s << param.ToString();
-}
-
-std::string TestParamToString(const testing::TestParamInfo<TestParam>& info) {
- return info.param.ToString();
-}
-
-class CordRingTest : public testing::Test {
- public:
- ~CordRingTest() override {
- for (CordRep* rep : unrefs_) {
- CordRep::Unref(rep);
- }
- }
-
- template <typename CordRepType>
- CordRepType* NeedsUnref(CordRepType* rep) {
- assert(rep);
- unrefs_.push_back(rep);
- return rep;
- }
-
- template <typename CordRepType>
- CordRepType* Ref(CordRepType* rep) {
- CordRep::Ref(rep);
- return NeedsUnref(rep);
- }
-
- private:
- std::vector<CordRep*> unrefs_;
-};
-
-class CordRingTestWithParam : public testing::TestWithParam<TestParam> {
- public:
- ~CordRingTestWithParam() override {
- for (CordRep* rep : unrefs_) {
- CordRep::Unref(rep);
- }
- }
-
- CordRepRing* CreateWithCapacity(CordRep* child, size_t extra_capacity) {
- if (!GetParam().with_capacity) extra_capacity = 0;
- CordRepRing* ring = CordRepRing::Create(child, extra_capacity);
- ring->SetCapacityForTesting(1 + extra_capacity);
- return RefIfShared(ring);
- }
-
- bool Shared() const { return !GetParam().refcount_is_one; }
- bool InputShared() const { return GetParam().input_share_mode == kShared; }
- bool InputSharedIndirect() const {
- return GetParam().input_share_mode == kSharedIndirect;
- }
-
- template <typename CordRepType>
- CordRepType* NeedsUnref(CordRepType* rep) {
- assert(rep);
- unrefs_.push_back(rep);
- return rep;
- }
-
- template <typename CordRepType>
- CordRepType* Ref(CordRepType* rep) {
- CordRep::Ref(rep);
- return NeedsUnref(rep);
- }
-
- template <typename CordRepType>
- CordRepType* RefIfShared(CordRepType* rep) {
- return Shared() ? Ref(rep) : rep;
- }
-
- template <typename CordRepType>
- CordRepType* RefIfInputShared(CordRepType* rep) {
- return InputShared() ? Ref(rep) : rep;
- }
-
- template <typename CordRepType>
- CordRepType* RefIfInputSharedIndirect(CordRepType* rep) {
- return InputSharedIndirect() ? Ref(rep) : rep;
- }
-
- private:
- std::vector<CordRep*> unrefs_;
-};
-
-class CordRingCreateTest : public CordRingTestWithParam {
- public:
- static TestParams CreateTestParams() {
- TestParams params;
- params.emplace_back(InputShareMode::kPrivate);
- params.emplace_back(InputShareMode::kShared);
- return params;
- }
-};
-
-class CordRingSubTest : public CordRingTestWithParam {
- public:
- static TestParams CreateTestParams() {
- TestParams params;
- for (bool refcount_is_one : {true, false}) {
- TestParam param;
- param.refcount_is_one = refcount_is_one;
- params.push_back(param);
- }
- return params;
- }
-};
-
-class CordRingBuildTest : public CordRingTestWithParam {
- public:
- static TestParams CreateTestParams() {
- TestParams params;
- for (bool refcount_is_one : {true, false}) {
- for (bool with_capacity : {true, false}) {
- TestParam param;
- param.refcount_is_one = refcount_is_one;
- param.with_capacity = with_capacity;
- params.push_back(param);
- }
- }
- return params;
- }
-};
-
-class CordRingCreateFromTreeTest : public CordRingTestWithParam {
- public:
- static TestParams CreateTestParams() {
- TestParams params;
- params.emplace_back(InputShareMode::kPrivate);
- params.emplace_back(InputShareMode::kShared);
- params.emplace_back(InputShareMode::kSharedIndirect);
- return params;
- }
-};
-
-class CordRingBuildInputTest : public CordRingTestWithParam {
- public:
- static TestParams CreateTestParams() {
- TestParams params;
- for (bool refcount_is_one : {true, false}) {
- for (bool with_capacity : {true, false}) {
- for (InputShareMode share_mode : {kPrivate, kShared, kSharedIndirect}) {
- TestParam param;
- param.refcount_is_one = refcount_is_one;
- param.with_capacity = with_capacity;
- param.input_share_mode = share_mode;
- params.push_back(param);
- }
- }
- }
- return params;
- }
-};
-
-INSTANTIATE_TEST_SUITE_P(WithParam, CordRingSubTest,
- testing::ValuesIn(CordRingSubTest::CreateTestParams()),
- TestParamToString);
-
-INSTANTIATE_TEST_SUITE_P(
- WithParam, CordRingCreateTest,
- testing::ValuesIn(CordRingCreateTest::CreateTestParams()),
- TestParamToString);
-
-INSTANTIATE_TEST_SUITE_P(
- WithParam, CordRingCreateFromTreeTest,
- testing::ValuesIn(CordRingCreateFromTreeTest::CreateTestParams()),
- TestParamToString);
-
-INSTANTIATE_TEST_SUITE_P(
- WithParam, CordRingBuildTest,
- testing::ValuesIn(CordRingBuildTest::CreateTestParams()),
- TestParamToString);
-
-INSTANTIATE_TEST_SUITE_P(
- WithParam, CordRingBuildInputTest,
- testing::ValuesIn(CordRingBuildInputTest::CreateTestParams()),
- TestParamToString);
-
-TEST_P(CordRingCreateTest, CreateFromFlat) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
- CordRepRing* result = NeedsUnref(CordRepRing::Create(MakeFlat(str1)));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->length, Eq(str1.size()));
- EXPECT_THAT(ToFlats(result), ElementsAre(str1));
-}
-
-TEST_P(CordRingCreateTest, CreateFromRing) {
- CordRepRing* ring = RefIfShared(FromFlats(kFoxFlats));
- CordRepRing* result = NeedsUnref(CordRepRing::Create(ring));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
-}
-
-TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringRing) {
- CordRepRing* ring = RefIfInputSharedIndirect(FromFlats(kFoxFlats));
- CordRep* sub = RefIfInputShared(MakeSubstring(2, 11, ring));
- CordRepRing* result = NeedsUnref(CordRepRing::Create(sub));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfInputPrivate(GetParam(), ring));
- EXPECT_THAT(ToString(result), string_view(kFox).substr(2, 11));
-}
-
-TEST_F(CordRingTest, CreateWithIllegalExtraCapacity) {
-#if defined(ABSL_HAVE_EXCEPTIONS)
- CordRep* flat = NeedsUnref(MakeFlat("Hello world"));
- try {
- CordRepRing::Create(flat, CordRepRing::kMaxCapacity);
- GTEST_FAIL() << "expected std::length_error exception";
- } catch (const std::length_error&) {
- }
-#elif defined(GTEST_HAS_DEATH_TEST)
- CordRep* flat = NeedsUnref(MakeFlat("Hello world"));
- EXPECT_DEATH(CordRepRing::Create(flat, CordRepRing::kMaxCapacity), ".*");
-#endif
-}
-
-TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfFlat) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
- auto* flat = RefIfInputShared(MakeFlat(str1));
- auto* child = RefIfInputSharedIndirect(MakeSubstring(4, 20, flat));
- CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->length, Eq(20));
- EXPECT_THAT(ToFlats(result), ElementsAre(str1.substr(4, 20)));
-}
-
-TEST_P(CordRingCreateTest, CreateFromExternal) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
- auto* child = RefIfInputShared(MakeExternal(str1));
- CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->length, Eq(str1.size()));
- EXPECT_THAT(ToFlats(result), ElementsAre(str1));
-}
-
-TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfExternal) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
- auto* external = RefIfInputShared(MakeExternal(str1));
- auto* child = RefIfInputSharedIndirect(MakeSubstring(1, 24, external));
- CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->length, Eq(24));
- EXPECT_THAT(ToFlats(result), ElementsAre(str1.substr(1, 24)));
-}
-
-TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfLargeExternal) {
- auto* external = RefIfInputShared(MakeFakeExternal(1 << 20));
- auto str = not_a_string_view(external->base, 1 << 20)
- .remove_prefix(1 << 19)
- .remove_suffix(6);
- auto* child =
- RefIfInputSharedIndirect(MakeSubstring(1 << 19, (1 << 19) - 6, external));
- CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->length, Eq(str.size()));
- EXPECT_THAT(ToRawFlats(result), ElementsAre(str));
-}
-
-TEST_P(CordRingCreateTest, Properties) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
- CordRepRing* result = NeedsUnref(CordRepRing::Create(MakeFlat(str1), 120));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->head(), Eq(0));
- EXPECT_THAT(result->tail(), Eq(1));
- EXPECT_THAT(result->capacity(), Ge(120 + 1));
- EXPECT_THAT(result->capacity(), Le(2 * 120 + 1));
- EXPECT_THAT(result->entries(), Eq(1));
- EXPECT_THAT(result->begin_pos(), Eq(0));
-}
-
-TEST_P(CordRingCreateTest, EntryForNewFlat) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
- CordRep* child = MakeFlat(str1);
- CordRepRing* result = NeedsUnref(CordRepRing::Create(child, 120));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->entry_child(0), Eq(child));
- EXPECT_THAT(result->entry_end_pos(0), Eq(str1.length()));
- EXPECT_THAT(result->entry_data_offset(0), Eq(0));
-}
-
-TEST_P(CordRingCreateTest, EntryForNewFlatSubstring) {
- absl::string_view str1 = "1234567890abcdefghijklmnopqrstuvwxyz";
- CordRep* child = MakeFlat(str1);
- CordRep* substring = MakeSubstring(10, 26, child);
- CordRepRing* result = NeedsUnref(CordRepRing::Create(substring, 1));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->entry_child(0), Eq(child));
- EXPECT_THAT(result->entry_end_pos(0), Eq(26));
- EXPECT_THAT(result->entry_data_offset(0), Eq(10));
-}
-
-TEST_P(CordRingBuildTest, AppendFlat) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
- absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, MakeFlat(str2)));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
- EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
-}
-
-TEST_P(CordRingBuildTest, PrependFlat) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
- absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, MakeFlat(str2)));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
- EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1));
-}
-
-TEST_P(CordRingBuildTest, AppendString) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
- absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
- EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
-}
-
-TEST_P(CordRingBuildTest, AppendStringHavingExtra) {
- absl::string_view str1 = "1234";
- absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- CordRepRing* ring = CreateWithCapacity(MakeFlat(str1, 26), 0);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
- EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
-}
-
-TEST_P(CordRingBuildTest, AppendStringHavingPartialExtra) {
- absl::string_view str1 = "1234";
- absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
- // Create flat with at least one extra byte. We don't expect to have sized
- // alloc and capacity rounding to grant us enough to not make it partial.
- auto* flat = MakeFlat(str1, 1);
- size_t avail = flat->flat()->Capacity() - flat->length;
- ASSERT_THAT(avail, Lt(str2.size())) << " adjust test for larger flats!";
-
- // Construct the flats we do expect using all of `avail`.
- absl::string_view str1a = str2.substr(0, avail);
- absl::string_view str2a = str2.substr(avail);
-
- CordRepRing* ring = CreateWithCapacity(flat, 1);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- if (GetParam().refcount_is_one) {
- EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str1, str1a), str2a));
- } else {
- EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
- }
-}
-
-TEST_P(CordRingBuildTest, AppendStringHavingExtraInSubstring) {
- absl::string_view str1 = "123456789_1234";
- absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- CordRep* flat = RemovePrefix(10, MakeFlat(str1, 26));
- CordRepRing* ring = CreateWithCapacity(flat, 0);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(result->length, Eq(4 + str2.size()));
- if (GetParam().refcount_is_one) {
- EXPECT_THAT(ToFlats(result), ElementsAre(StrCat("1234", str2)));
- } else {
- EXPECT_THAT(ToFlats(result), ElementsAre("1234", str2));
- }
-}
-
-TEST_P(CordRingBuildTest, AppendStringHavingSharedExtra) {
- absl::string_view str1 = "123456789_1234";
- absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- for (int shared_type = 0; shared_type < 2; ++shared_type) {
- SCOPED_TRACE(absl::StrCat("Shared extra type ", shared_type));
-
- // Create a flat that is shared in some way.
- CordRep* flat = nullptr;
- CordRep* flat1 = nullptr;
- if (shared_type == 0) {
- // Shared flat
- flat = CordRep::Ref(MakeFlat(str1.substr(10), 100));
- } else if (shared_type == 1) {
- // Shared flat inside private substring
- flat1 = CordRep::Ref(MakeFlat(str1));
- flat = RemovePrefix(10, flat1);
- } else {
- // Private flat inside shared substring
- flat = CordRep::Ref(RemovePrefix(10, MakeFlat(str1, 100)));
- }
-
- CordRepRing* ring = CreateWithCapacity(flat, 1);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(result->length, Eq(4 + str2.size()));
- EXPECT_THAT(ToFlats(result), ElementsAre("1234", str2));
-
- CordRep::Unref(shared_type == 1 ? flat1 : flat);
- }
-}
-
-TEST_P(CordRingBuildTest, AppendStringWithExtra) {
- absl::string_view str1 = "1234";
- absl::string_view str2 = "1234567890";
- absl::string_view str3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2, 26));
- result = CordRepRing::Append(result, str3);
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->length, Eq(str1.size() + str2.size() + str3.size()));
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre(str1, StrCat(str2, str3)));
-}
-
-TEST_P(CordRingBuildTest, PrependString) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
- absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- // Use external rep to avoid appending to first flat
- CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
- ASSERT_THAT(result, IsValidRingBuffer());
- if (GetParam().with_capacity && GetParam().refcount_is_one) {
- EXPECT_THAT(result, Eq(ring));
- } else {
- EXPECT_THAT(result, Ne(ring));
- }
- EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
- EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1));
-}
-
-TEST_P(CordRingBuildTest, PrependStringHavingExtra) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz1234";
- absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- CordRep* flat = RemovePrefix(26, MakeFlat(str1));
- CordRepRing* ring = CreateWithCapacity(flat, 0);
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(result->length, Eq(4 + str2.size()));
- if (GetParam().refcount_is_one) {
- EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str2, "1234")));
- } else {
- EXPECT_THAT(ToFlats(result), ElementsAre(str2, "1234"));
- }
-}
-
-TEST_P(CordRingBuildTest, PrependStringHavingSharedExtra) {
- absl::string_view str1 = "123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- absl::string_view str2 = "abcdefghij";
- absl::string_view str1a = str1.substr(10);
- for (int shared_type = 1; shared_type < 2; ++shared_type) {
- SCOPED_TRACE(absl::StrCat("Shared extra type ", shared_type));
-
- // Create a flat that is shared in some way.
- CordRep* flat = nullptr;
- CordRep* flat1 = nullptr;
- if (shared_type == 1) {
- // Shared flat inside private substring
- flat = RemovePrefix(10, flat1 = CordRep::Ref(MakeFlat(str1)));
- } else {
- // Private flat inside shared substring
- flat = CordRep::Ref(RemovePrefix(10, MakeFlat(str1, 100)));
- }
-
- CordRepRing* ring = CreateWithCapacity(flat, 1);
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result->length, Eq(str1a.size() + str2.size()));
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1a));
- CordRep::Unref(shared_type == 1 ? flat1 : flat);
- }
-}
-
-TEST_P(CordRingBuildTest, PrependStringWithExtra) {
- absl::string_view str1 = "1234";
- absl::string_view str2 = "1234567890";
- absl::string_view str3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2, 26));
- ASSERT_THAT(result, IsValidRingBuffer());
- result = CordRepRing::Prepend(result, str3);
- EXPECT_THAT(result->length, Eq(str1.size() + str2.size() + str3.size()));
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str3, str2), str1));
-}
-
-TEST_P(CordRingBuildTest, AppendPrependStringMix) {
- const auto& flats = kFoxFlats;
- CordRepRing* ring = CreateWithCapacity(MakeFlat(flats[4]), 8);
- CordRepRing* result = ring;
- for (int i = 1; i <= 4; ++i) {
- result = CordRepRing::Prepend(result, flats[4 - i]);
- result = CordRepRing::Append(result, flats[4 + i]);
- }
- NeedsUnref(result);
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(ToString(result), kFox);
-}
-
-TEST_P(CordRingBuildTest, AppendPrependStringMixWithExtra) {
- const auto& flats = kFoxFlats;
- CordRepRing* ring = CreateWithCapacity(MakeFlat(flats[4], 100), 8);
- CordRepRing* result = ring;
- for (int i = 1; i <= 4; ++i) {
- result = CordRepRing::Prepend(result, flats[4 - i], 100);
- result = CordRepRing::Append(result, flats[4 + i], 100);
- }
- NeedsUnref(result);
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- if (GetParam().refcount_is_one) {
- EXPECT_THAT(ToFlats(result),
- ElementsAre("The quick brown fox ", "jumps over the lazy dog"));
- } else {
- EXPECT_THAT(ToFlats(result), ElementsAre("The quick brown fox ", "jumps ",
- "over the lazy dog"));
- }
-}
-
-TEST_P(CordRingBuildTest, AppendPrependStringMixWithPrependedExtra) {
- const auto& flats = kFoxFlats;
- CordRep* flat = MakeFlat(StrCat(std::string(50, '.'), flats[4]), 50);
- CordRepRing* ring = CreateWithCapacity(RemovePrefix(50, flat), 0);
- CordRepRing* result = ring;
- for (int i = 1; i <= 4; ++i) {
- result = CordRepRing::Prepend(result, flats[4 - i], 100);
- result = CordRepRing::Append(result, flats[4 + i], 100);
- }
- result = NeedsUnref(result);
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
- if (GetParam().refcount_is_one) {
- EXPECT_THAT(ToFlats(result), ElementsAre(kFox));
- } else {
- EXPECT_THAT(ToFlats(result), ElementsAre("The quick brown fox ", "jumps ",
- "over the lazy dog"));
- }
-}
-
-TEST_P(CordRingSubTest, SubRing) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- string_view all = kFox;
- for (size_t offset = 0; offset < all.size() - 1; ++offset) {
- CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
- CordRepRing* result = CordRepRing::SubRing(ring, offset, 0);
- EXPECT_THAT(result, nullptr);
-
- for (size_t len = 1; len < all.size() - offset; ++len) {
- ring = RefIfShared(FromFlats(flats, composition));
- result = NeedsUnref(CordRepRing::SubRing(ring, offset, len));
- ASSERT_THAT(result, IsValidRingBuffer());
- ASSERT_THAT(result, EqIfPrivate(GetParam(), ring));
- ASSERT_THAT(result, NeIfShared(GetParam(), ring));
- ASSERT_THAT(ToString(result), Eq(all.substr(offset, len)));
- }
- }
-}
-
-TEST_P(CordRingSubTest, SubRingFromLargeExternal) {
- auto composition = RandomComposition();
- std::string large_string(1 << 20, '.');
- const char* flats[] = {
- "abcdefghijklmnopqrstuvwxyz",
- large_string.c_str(),
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
- };
- std::string buffer = absl::StrCat(flats[0], flats[1], flats[2]);
- absl::string_view all = buffer;
- for (size_t offset = 0; offset < 30; ++offset) {
- CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
- CordRepRing* result = CordRepRing::SubRing(ring, offset, 0);
- EXPECT_THAT(result, nullptr);
-
- for (size_t len = all.size() - 30; len < all.size() - offset; ++len) {
- ring = RefIfShared(FromFlats(flats, composition));
- result = NeedsUnref(CordRepRing::SubRing(ring, offset, len));
- ASSERT_THAT(result, IsValidRingBuffer());
- ASSERT_THAT(result, EqIfPrivate(GetParam(), ring));
- ASSERT_THAT(result, NeIfShared(GetParam(), ring));
- auto str = ToString(result);
- ASSERT_THAT(str, SizeIs(len));
- ASSERT_THAT(str, Eq(all.substr(offset, len)));
- }
- }
-}
-
-TEST_P(CordRingSubTest, RemovePrefix) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- string_view all = kFox;
- CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
- CordRepRing* result = CordRepRing::RemovePrefix(ring, all.size());
- EXPECT_THAT(result, nullptr);
-
- for (size_t len = 1; len < all.size(); ++len) {
- ring = RefIfShared(FromFlats(flats, composition));
- result = NeedsUnref(CordRepRing::RemovePrefix(ring, len));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
- ASSERT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToString(result), Eq(all.substr(len)));
- }
-}
-
-TEST_P(CordRingSubTest, RemovePrefixFromLargeExternal) {
- CordRepExternal* external1 = MakeFakeExternal(1 << 20);
- CordRepExternal* external2 = MakeFakeExternal(1 << 20);
- CordRepRing* ring = CordRepRing::Create(external1, 1);
- ring = CordRepRing::Append(ring, external2);
- CordRepRing* result = NeedsUnref(CordRepRing::RemovePrefix(ring, 1 << 16));
- EXPECT_THAT(
- ToRawFlats(result),
- ElementsAre(
- not_a_string_view(external1->base, 1 << 20).remove_prefix(1 << 16),
- not_a_string_view(external2->base, 1 << 20)));
-}
-
-TEST_P(CordRingSubTest, RemoveSuffix) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- string_view all = kFox;
- CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
- CordRepRing* result = CordRepRing::RemoveSuffix(ring, all.size());
- EXPECT_THAT(result, nullptr);
-
- for (size_t len = 1; len < all.size(); ++len) {
- ring = RefIfShared(FromFlats(flats, composition));
- result = NeedsUnref(CordRepRing::RemoveSuffix(ring, len));
- ASSERT_THAT(result, IsValidRingBuffer());
- ASSERT_THAT(result, EqIfPrivate(GetParam(), ring));
- ASSERT_THAT(result, NeIfShared(GetParam(), ring));
- ASSERT_THAT(ToString(result), Eq(all.substr(0, all.size() - len)));
- }
-}
-
-TEST_P(CordRingSubTest, AppendRing) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats).subspan(1);
- CordRepRing* ring = CreateWithCapacity(MakeFlat(kFoxFlats[0]), flats.size());
- CordRepRing* child = FromFlats(flats, composition);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, child));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
-}
-
-TEST_P(CordRingBuildInputTest, AppendRingWithFlatOffset) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
- CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
- CordRep* stripped = RemovePrefix(10, child);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre("Head", "brown ", "fox ", "jumps ",
- "over ", "the ", "lazy ", "dog"));
-}
-
-TEST_P(CordRingBuildInputTest, AppendRingWithBrokenOffset) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
- CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
- CordRep* stripped = RemovePrefix(21, child);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result),
- ElementsAre("Head", "umps ", "over ", "the ", "lazy ", "dog"));
-}
-
-TEST_P(CordRingBuildInputTest, AppendRingWithFlatLength) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
- CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
- CordRep* stripped = RemoveSuffix(8, child);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ",
- "fox ", "jumps ", "over ", "the "));
-}
-
-TEST_P(CordRingBuildTest, AppendRingWithBrokenFlatLength) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
- CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
- CordRep* stripped = RemoveSuffix(15, child);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ",
- "fox ", "jumps ", "ov"));
-}
-
-TEST_P(CordRingBuildTest, AppendRingMiddlePiece) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
- CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
- CordRep* stripped = MakeSubstring(7, child->length - 27, child);
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result),
- ElementsAre("Head", "ck ", "brown ", "fox ", "jum"));
-}
-
-TEST_P(CordRingBuildTest, AppendRingSinglePiece) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
- CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
- CordRep* stripped = RefIfInputShared(MakeSubstring(11, 3, child));
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre("Head", "row"));
-}
-
-TEST_P(CordRingBuildInputTest, AppendRingSinglePieceWithPrefix) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- size_t extra_capacity = 1 + (GetParam().with_capacity ? flats.size() : 0);
- CordRepRing* ring = CordRepRing::Create(MakeFlat("Head"), extra_capacity);
- ring->SetCapacityForTesting(1 + extra_capacity);
- ring = RefIfShared(CordRepRing::Prepend(ring, MakeFlat("Prepend")));
- assert(ring->IsValid(std::cout));
- CordRepRing* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
- CordRep* stripped = RefIfInputShared(MakeSubstring(11, 3, child));
- CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre("Prepend", "Head", "row"));
-}
-
-TEST_P(CordRingBuildInputTest, PrependRing) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto fox = MakeSpan(kFoxFlats);
- auto flats = MakeSpan(fox).subspan(0, fox.size() - 1);
- CordRepRing* ring = CreateWithCapacity(MakeFlat(fox.back()), flats.size());
- CordRepRing* child = RefIfInputShared(FromFlats(flats, composition));
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, child));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
-}
-
-TEST_P(CordRingBuildInputTest, PrependRingWithFlatOffset) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
- CordRep* child = RefIfInputShared(FromFlats(flats, composition));
- CordRep* stripped = RefIfInputSharedIndirect(RemovePrefix(10, child));
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre("brown ", "fox ", "jumps ", "over ",
- "the ", "lazy ", "dog", "Tail"));
-}
-
-TEST_P(CordRingBuildInputTest, PrependRingWithBrokenOffset) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
- CordRep* child = RefIfInputShared(FromFlats(flats, composition));
- CordRep* stripped = RefIfInputSharedIndirect(RemovePrefix(21, child));
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result),
- ElementsAre("umps ", "over ", "the ", "lazy ", "dog", "Tail"));
-}
-
-TEST_P(CordRingBuildInputTest, PrependRingWithFlatLength) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
- CordRep* child = RefIfInputShared(FromFlats(flats, composition));
- CordRep* stripped = RefIfInputSharedIndirect(RemoveSuffix(8, child));
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ",
- "jumps ", "over ", "the ", "Tail"));
-}
-
-TEST_P(CordRingBuildInputTest, PrependRingWithBrokenFlatLength) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
- CordRep* child = RefIfInputShared(FromFlats(flats, composition));
- CordRep* stripped = RefIfInputSharedIndirect(RemoveSuffix(15, child));
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ",
- "jumps ", "ov", "Tail"));
-}
-
-TEST_P(CordRingBuildInputTest, PrependRingMiddlePiece) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
- CordRep* child = RefIfInputShared(FromFlats(flats, composition));
- CordRep* stripped =
- RefIfInputSharedIndirect(MakeSubstring(7, child->length - 27, child));
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result),
- ElementsAre("ck ", "brown ", "fox ", "jum", "Tail"));
-}
-
-TEST_P(CordRingBuildInputTest, PrependRingSinglePiece) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
- CordRep* child = RefIfInputShared(FromFlats(flats, composition));
- CordRep* stripped = RefIfInputSharedIndirect(MakeSubstring(11, 3, child));
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre("row", "Tail"));
-}
-
-TEST_P(CordRingBuildInputTest, PrependRingSinglePieceWithPrefix) {
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- auto flats = MakeSpan(kFoxFlats);
- size_t extra_capacity = 1 + (GetParam().with_capacity ? flats.size() : 0);
- CordRepRing* ring = CordRepRing::Create(MakeFlat("Tail"), extra_capacity);
- ring->SetCapacityForTesting(1 + extra_capacity);
- ring = RefIfShared(CordRepRing::Prepend(ring, MakeFlat("Prepend")));
- CordRep* child = RefIfInputShared(FromFlats(flats, composition));
- CordRep* stripped = RefIfInputSharedIndirect(MakeSubstring(11, 3, child));
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
- ASSERT_THAT(result, IsValidRingBuffer());
- EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
- EXPECT_THAT(result, NeIfShared(GetParam(), ring));
- EXPECT_THAT(ToFlats(result), ElementsAre("row", "Prepend", "Tail"));
-}
-
-TEST_F(CordRingTest, Find) {
- constexpr const char* flats[] = {
- "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
- "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
- "+-=", "[]\\{}|;':", ",/<>?", "."};
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
- std::string value = ToString(ring);
- for (int i = 0; i < value.length(); ++i) {
- CordRepRing::Position found = ring->Find(i);
- auto data = ring->entry_data(found.index);
- ASSERT_THAT(found.offset, Lt(data.length()));
- ASSERT_THAT(data[found.offset], Eq(value[i]));
- }
-}
-
-TEST_F(CordRingTest, FindWithHint) {
- constexpr const char* flats[] = {
- "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
- "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
- "+-=", "[]\\{}|;':", ",/<>?", "."};
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
- std::string value = ToString(ring);
-
-#if defined(GTEST_HAS_DEATH_TEST)
- // Test hint beyond valid position
- index_type head = ring->head();
- EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head), 0), ".*");
- EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head), 9), ".*");
- EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head, 3), 24), ".*");
-#endif
-
- int flat_pos = 0;
- size_t flat_offset = 0;
- for (auto sflat : flats) {
- string_view flat(sflat);
- for (int offset = 0; offset < flat.length(); ++offset) {
- for (int start = 0; start <= flat_pos; ++start) {
- index_type hint = ring->advance(ring->head(), start);
- CordRepRing::Position found = ring->Find(hint, flat_offset + offset);
- ASSERT_THAT(found.index, Eq(ring->advance(ring->head(), flat_pos)));
- ASSERT_THAT(found.offset, Eq(offset));
- }
- }
- ++flat_pos;
- flat_offset += flat.length();
- }
-}
-
-TEST_F(CordRingTest, FindInLargeRing) {
- constexpr const char* flats[] = {
- "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
- "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
- "+-=", "[]\\{}|;':", ",/<>?", "."};
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- CordRepRing* ring = FromFlats(flats, composition);
- for (int i = 0; i < 13; ++i) {
- ring = CordRepRing::Append(ring, FromFlats(flats, composition));
- }
- NeedsUnref(ring);
- std::string value = ToString(ring);
- for (int i = 0; i < value.length(); ++i) {
- CordRepRing::Position pos = ring->Find(i);
- auto data = ring->entry_data(pos.index);
- ASSERT_THAT(pos.offset, Lt(data.length()));
- ASSERT_THAT(data[pos.offset], Eq(value[i]));
- }
-}
-
-TEST_F(CordRingTest, FindTail) {
- constexpr const char* flats[] = {
- "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
- "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
- "+-=", "[]\\{}|;':", ",/<>?", "."};
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
- std::string value = ToString(ring);
-
- for (int i = 0; i < value.length(); ++i) {
- CordRepRing::Position pos = ring->FindTail(i + 1);
- auto data = ring->entry_data(ring->retreat(pos.index));
- ASSERT_THAT(pos.offset, Lt(data.length()));
- ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
- }
-}
-
-TEST_F(CordRingTest, FindTailWithHint) {
- constexpr const char* flats[] = {
- "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
- "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
- "+-=", "[]\\{}|;':", ",/<>?", "."};
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
- std::string value = ToString(ring);
-
- // Test hint beyond valid position
-#if defined(GTEST_HAS_DEATH_TEST)
- index_type head = ring->head();
- EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head), 1), ".*");
- EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head), 10), ".*");
- EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head, 3), 26), ".*");
-#endif
-
- for (int i = 0; i < value.length(); ++i) {
- CordRepRing::Position pos = ring->FindTail(i + 1);
- auto data = ring->entry_data(ring->retreat(pos.index));
- ASSERT_THAT(pos.offset, Lt(data.length()));
- ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
- }
-}
-
-TEST_F(CordRingTest, FindTailInLargeRing) {
- constexpr const char* flats[] = {
- "abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
- "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
- "+-=", "[]\\{}|;':", ",/<>?", "."};
- auto composition = RandomComposition();
- SCOPED_TRACE(ToString(composition));
- CordRepRing* ring = FromFlats(flats, composition);
- for (int i = 0; i < 13; ++i) {
- ring = CordRepRing::Append(ring, FromFlats(flats, composition));
- }
- NeedsUnref(ring);
- std::string value = ToString(ring);
- for (int i = 0; i < value.length(); ++i) {
- CordRepRing::Position pos = ring->FindTail(i + 1);
- auto data = ring->entry_data(ring->retreat(pos.index));
- ASSERT_THAT(pos.offset, Lt(data.length()));
- ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
- }
-}
-
-TEST_F(CordRingTest, GetCharacter) {
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = CordRepRing::Create(MakeFlat("Tail"), flats.size());
- CordRep* child = FromFlats(flats, kAppend);
- CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, child));
- std::string value = ToString(result);
- for (int i = 0; i < value.length(); ++i) {
- ASSERT_THAT(result->GetCharacter(i), Eq(value[i]));
- }
-}
-
-TEST_F(CordRingTest, GetCharacterWithSubstring) {
- absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
- auto* child = MakeSubstring(4, 20, MakeFlat(str1));
- CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
- ASSERT_THAT(result, IsValidRingBuffer());
- std::string value = ToString(result);
- for (int i = 0; i < value.length(); ++i) {
- ASSERT_THAT(result->GetCharacter(i), Eq(value[i]));
- }
-}
-
-TEST_F(CordRingTest, IsFlatSingleFlat) {
- for (bool external : {false, true}) {
- SCOPED_TRACE(external ? "With External" : "With Flat");
- absl::string_view str = "Hello world";
- CordRep* rep = external ? MakeExternal(str) : MakeFlat(str);
- CordRepRing* ring = NeedsUnref(CordRepRing::Create(rep));
-
- // The ring is a single non-fragmented flat:
- absl::string_view fragment;
- EXPECT_TRUE(ring->IsFlat(nullptr));
- EXPECT_TRUE(ring->IsFlat(&fragment));
- EXPECT_THAT(fragment, Eq("Hello world"));
- fragment = "";
- EXPECT_TRUE(ring->IsFlat(0, 11, nullptr));
- EXPECT_TRUE(ring->IsFlat(0, 11, &fragment));
- EXPECT_THAT(fragment, Eq("Hello world"));
-
- // Arbitrary ranges must check true as well.
- EXPECT_TRUE(ring->IsFlat(1, 4, &fragment));
- EXPECT_THAT(fragment, Eq("ello"));
- EXPECT_TRUE(ring->IsFlat(6, 5, &fragment));
- EXPECT_THAT(fragment, Eq("world"));
- }
-}
-
-TEST_F(CordRingTest, IsFlatMultiFlat) {
- for (bool external : {false, true}) {
- SCOPED_TRACE(external ? "With External" : "With Flat");
- absl::string_view str1 = "Hello world";
- absl::string_view str2 = "Halt and catch fire";
- CordRep* rep1 = external ? MakeExternal(str1) : MakeFlat(str1);
- CordRep* rep2 = external ? MakeExternal(str2) : MakeFlat(str2);
- CordRepRing* ring = CordRepRing::Append(CordRepRing::Create(rep1), rep2);
- NeedsUnref(ring);
-
- // The ring is fragmented, IsFlat() on the entire cord must be false.
- EXPECT_FALSE(ring->IsFlat(nullptr));
- absl::string_view fragment = "Don't touch this";
- EXPECT_FALSE(ring->IsFlat(&fragment));
- EXPECT_THAT(fragment, Eq("Don't touch this"));
-
- // Check for ranges exactly within both flats.
- EXPECT_TRUE(ring->IsFlat(0, 11, &fragment));
- EXPECT_THAT(fragment, Eq("Hello world"));
- EXPECT_TRUE(ring->IsFlat(11, 19, &fragment));
- EXPECT_THAT(fragment, Eq("Halt and catch fire"));
-
- // Check for arbitrary partial range inside each flat.
- EXPECT_TRUE(ring->IsFlat(1, 4, &fragment));
- EXPECT_THAT(fragment, "ello");
- EXPECT_TRUE(ring->IsFlat(26, 4, &fragment));
- EXPECT_THAT(fragment, "fire");
-
- // Check ranges spanning across both flats
- fragment = "Don't touch this";
- EXPECT_FALSE(ring->IsFlat(1, 18, &fragment));
- EXPECT_FALSE(ring->IsFlat(10, 2, &fragment));
- EXPECT_THAT(fragment, Eq("Don't touch this"));
- }
-}
-
-TEST_F(CordRingTest, Dump) {
- std::stringstream ss;
- auto flats = MakeSpan(kFoxFlats);
- CordRepRing* ring = NeedsUnref(FromFlats(flats, kPrepend));
- ss << *ring;
-}
-
-} // namespace
-ABSL_NAMESPACE_END
-} // namespace absl