summaryrefslogtreecommitdiff
path: root/absl/strings/cord_ring_reader_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/cord_ring_reader_test.cc')
-rw-r--r--absl/strings/cord_ring_reader_test.cc173
1 files changed, 173 insertions, 0 deletions
diff --git a/absl/strings/cord_ring_reader_test.cc b/absl/strings/cord_ring_reader_test.cc
new file mode 100644
index 00000000..585616f3
--- /dev/null
+++ b/absl/strings/cord_ring_reader_test.cc
@@ -0,0 +1,173 @@
+// 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 <cstdlib>
+#include <ctime>
+#include <memory>
+#include <random>
+#include <sstream>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/debugging/leak_check.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/internal/cord_rep_ring_reader.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+namespace {
+
+using testing::Eq;
+
+// Creates a flat for testing
+CordRep* MakeFlat(absl::string_view s) {
+ CordRepFlat* flat = CordRepFlat::New(s.length());
+ memcpy(flat->Data(), s.data(), s.length());
+ flat->length = s.length();
+ return flat;
+}
+
+CordRepRing* FromFlats(Span<absl::string_view const> flats) {
+ CordRepRing* ring = CordRepRing::Create(MakeFlat(flats[0]), flats.size() - 1);
+ for (int i = 1; i < flats.size(); ++i) {
+ ring = CordRepRing::Append(ring, MakeFlat(flats[i]));
+ }
+ return ring;
+}
+
+std::array<absl::string_view, 12> TestFlats() {
+ return {"abcdefghij", "klmnopqrst", "uvwxyz", "ABCDEFGHIJ",
+ "KLMNOPQRST", "UVWXYZ", "1234567890", "~!@#$%^&*()_",
+ "+-=", "[]\\{}|;':", ",/<>?", "."};
+}
+
+TEST(CordRingReaderTest, DefaultInstance) {
+ CordRepRingReader reader;
+ EXPECT_FALSE(static_cast<bool>(reader));
+ EXPECT_THAT(reader.ring(), Eq(nullptr));
+#ifndef NDEBUG
+ EXPECT_DEATH_IF_SUPPORTED(reader.length(), ".*");
+ EXPECT_DEATH_IF_SUPPORTED(reader.consumed(), ".*");
+ EXPECT_DEATH_IF_SUPPORTED(reader.remaining(), ".*");
+ EXPECT_DEATH_IF_SUPPORTED(reader.Next(), ".*");
+ EXPECT_DEATH_IF_SUPPORTED(reader.Seek(0), ".*");
+#endif
+}
+
+TEST(CordRingReaderTest, Reset) {
+ CordRepRingReader reader;
+ auto flats = TestFlats();
+ CordRepRing* ring = FromFlats(flats);
+
+ absl::string_view first = reader.Reset(ring);
+ EXPECT_THAT(first, Eq(flats[0]));
+ EXPECT_TRUE(static_cast<bool>(reader));
+ EXPECT_THAT(reader.ring(), Eq(ring));
+ EXPECT_THAT(reader.index(), Eq(ring->head()));
+ EXPECT_THAT(reader.length(), Eq(ring->length));
+ EXPECT_THAT(reader.consumed(), Eq(flats[0].length()));
+ EXPECT_THAT(reader.remaining(), Eq(ring->length - reader.consumed()));
+
+ reader.Reset();
+ EXPECT_FALSE(static_cast<bool>(reader));
+ EXPECT_THAT(reader.ring(), Eq(nullptr));
+
+ CordRep::Unref(ring);
+}
+
+TEST(CordRingReaderTest, Next) {
+ CordRepRingReader reader;
+ auto flats = TestFlats();
+ CordRepRing* ring = FromFlats(flats);
+ CordRepRing::index_type head = ring->head();
+
+ reader.Reset(ring);
+ size_t consumed = reader.consumed();
+ size_t remaining = reader.remaining();
+ for (int i = 1; i < flats.size(); ++i) {
+ consumed += flats[i].length();
+ remaining -= flats[i].length();
+ absl::string_view next = reader.Next();
+ ASSERT_THAT(next, Eq(flats[i]));
+ ASSERT_THAT(reader.index(), Eq(ring->advance(head, i)));
+ ASSERT_THAT(reader.consumed(), Eq(consumed));
+ ASSERT_THAT(reader.remaining(), Eq(remaining));
+ }
+
+#ifndef NDEBUG
+ EXPECT_DEATH_IF_SUPPORTED(reader.Next(), ".*");
+#endif
+
+ CordRep::Unref(ring);
+}
+
+TEST(CordRingReaderTest, SeekForward) {
+ CordRepRingReader reader;
+ auto flats = TestFlats();
+ CordRepRing* ring = FromFlats(flats);
+ CordRepRing::index_type head = ring->head();
+
+ reader.Reset(ring);
+ size_t consumed = 0;
+ size_t remaining = ring->length;;
+ for (int i = 0; i < flats.size(); ++i) {
+ size_t offset = consumed;
+ consumed += flats[i].length();
+ remaining -= flats[i].length();
+ for (int off = 0; off < flats[i].length(); ++off) {
+ absl::string_view chunk = reader.Seek(offset + off);
+ ASSERT_THAT(chunk, Eq(flats[i].substr(off)));
+ ASSERT_THAT(reader.index(), Eq(ring->advance(head, i)));
+ ASSERT_THAT(reader.consumed(), Eq(consumed));
+ ASSERT_THAT(reader.remaining(), Eq(remaining));
+ }
+ }
+
+ CordRep::Unref(ring);
+}
+
+TEST(CordRingReaderTest, SeekBackward) {
+ CordRepRingReader reader;
+ auto flats = TestFlats();
+ CordRepRing* ring = FromFlats(flats);
+ CordRepRing::index_type head = ring->head();
+
+ reader.Reset(ring);
+ size_t consumed = ring->length;
+ size_t remaining = 0;
+ for (int i = flats.size() - 1; i >= 0; --i) {
+ size_t offset = consumed - flats[i].length();
+ for (int off = 0; off < flats[i].length(); ++off) {
+ absl::string_view chunk = reader.Seek(offset + off);
+ ASSERT_THAT(chunk, Eq(flats[i].substr(off)));
+ ASSERT_THAT(reader.index(), Eq(ring->advance(head, i)));
+ ASSERT_THAT(reader.consumed(), Eq(consumed));
+ ASSERT_THAT(reader.remaining(), Eq(remaining));
+ }
+ consumed -= flats[i].length();
+ remaining += flats[i].length();
+ }
+#ifndef NDEBUG
+ EXPECT_DEATH_IF_SUPPORTED(reader.Seek(ring->length), ".*");
+#endif
+ CordRep::Unref(ring);
+}
+
+} // namespace
+} // namespace cord_internal
+ABSL_NAMESPACE_END
+} // namespace absl