// Copyright 2021 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 #include #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_test_util.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { namespace { using ::absl::cordrep_testing::MakeFlat; using ::absl::cordrep_testing::MakeSubstring; using ::testing::Eq; MATCHER_P2(EqExtractResult, tree, rep, "Equals ExtractResult") { if (arg.tree != tree || arg.extracted != rep) { *result_listener << "Expected {" << static_cast(tree) << ", " << static_cast(rep) << "}, got {" << arg.tree << ", " << arg.extracted << "}"; return false; } return true; } CordRepConcat* MakeConcat(CordRep* left, CordRep* right, int depth) { CordRepConcat* concat = new CordRepConcat; concat->tag = CONCAT; concat->set_depth(depth); concat->length = left->length + right->length; concat->left = left; concat->right = right; return concat; } CordRepConcat::ExtractResult ExtractLast(CordRepConcat* concat, size_t extra_capacity = 1) { return CordRepConcat::ExtractAppendBuffer(concat, extra_capacity); } TEST(CordRepConcatTest, ExtractAppendBufferTwoFlats) { CordRepFlat* flat1 = MakeFlat("abc"); CordRepFlat* flat2 = MakeFlat("defg"); CordRepConcat* concat = MakeConcat(flat1, flat2, 0); EXPECT_THAT(ExtractLast(concat), EqExtractResult(flat1, flat2)); CordRep::Unref(flat1); CordRep::Unref(flat2); } TEST(CordRepConcatTest, ExtractAppendBufferThreeFlatsOne) { CordRepFlat* flat1 = MakeFlat("abc"); CordRepFlat* flat2 = MakeFlat("defg"); CordRepFlat* flat3 = MakeFlat("hijkl"); CordRepConcat* lconcat = MakeConcat(flat1, flat2, 0); CordRepConcat* concat = MakeConcat(lconcat, flat3, 1); EXPECT_THAT(ExtractLast(concat), EqExtractResult(lconcat, flat3)); ASSERT_THAT(lconcat->length, Eq(7)); CordRep::Unref(lconcat); CordRep::Unref(flat3); } TEST(CordRepConcatTest, ExtractAppendBufferThreeFlatsTwo) { CordRepFlat* flat1 = MakeFlat("hijkl"); CordRepFlat* flat2 = MakeFlat("abc"); CordRepFlat* flat3 = MakeFlat("defg"); CordRepConcat* rconcat = MakeConcat(flat2, flat3, 0); CordRepConcat* concat = MakeConcat(flat1, rconcat, 1); EXPECT_THAT(ExtractLast(concat), EqExtractResult(concat, flat3)); ASSERT_THAT(concat->length, Eq(8)); CordRep::Unref(concat); CordRep::Unref(flat3); } TEST(CordRepConcatTest, ExtractAppendBufferShared) { CordRepFlat* flat1 = MakeFlat("hijkl"); CordRepFlat* flat2 = MakeFlat("abc"); CordRepFlat* flat3 = MakeFlat("defg"); CordRepConcat* rconcat = MakeConcat(flat2, flat3, 0); CordRepConcat* concat = MakeConcat(flat1, rconcat, 1); CordRep::Ref(concat); EXPECT_THAT(ExtractLast(concat), EqExtractResult(concat, nullptr)); CordRep::Unref(concat); CordRep::Ref(rconcat); EXPECT_THAT(ExtractLast(concat), EqExtractResult(concat, nullptr)); CordRep::Unref(rconcat); CordRep::Ref(flat3); EXPECT_THAT(ExtractLast(concat), EqExtractResult(concat, nullptr)); CordRep::Unref(flat3); CordRep::Unref(concat); } TEST(CordRepConcatTest, ExtractAppendBufferNotFlat) { CordRepFlat* flat1 = MakeFlat("hijkl"); CordRepFlat* flat2 = MakeFlat("abc"); CordRepFlat* flat3 = MakeFlat("defg"); auto substr = MakeSubstring(1, 2, flat3); CordRepConcat* rconcat = MakeConcat(flat2, substr, 0); CordRepConcat* concat = MakeConcat(flat1, rconcat, 1); EXPECT_THAT(ExtractLast(concat), EqExtractResult(concat, nullptr)); CordRep::Unref(concat); } TEST(CordRepConcatTest, ExtractAppendBufferNoCapacity) { CordRepFlat* flat1 = MakeFlat("hijkl"); CordRepFlat* flat2 = MakeFlat("abc"); CordRepFlat* flat3 = MakeFlat("defg"); size_t avail = flat3->Capacity() - flat3->length; CordRepConcat* rconcat = MakeConcat(flat2, flat3, 0); CordRepConcat* concat = MakeConcat(flat1, rconcat, 1); // Should fail if 1 byte over, success if exactly matching EXPECT_THAT(ExtractLast(concat, avail + 1), EqExtractResult(concat, nullptr)); EXPECT_THAT(ExtractLast(concat, avail), EqExtractResult(concat, flat3)); CordRep::Unref(concat); CordRep::Unref(flat3); } } // namespace } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl