diff options
author | Derek Mauro <dmauro@google.com> | 2022-10-28 11:21:06 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2022-10-28 11:22:03 -0700 |
commit | 1db72eb03e3685742c62abea9d13ddab2adcdf01 (patch) | |
tree | b2e9c4182d1ba593b924152d24a8e9e1e8569c9e /absl/strings/cord_test.cc | |
parent | fd9fbe74511fb2a060a3b15a1572b52fe16a6a43 (diff) |
Support empty Cords with an expected checksum
PiperOrigin-RevId: 484578104
Change-Id: Ie4be3e4de27dc28d88395e16fd075fb10ab7a302
Diffstat (limited to 'absl/strings/cord_test.cc')
-rw-r--r-- | absl/strings/cord_test.cc | 148 |
1 files changed, 145 insertions, 3 deletions
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index 1fc4be6e..9a72f7be 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc @@ -1988,6 +1988,12 @@ TEST_P(CordTest, HugeCord) { // Tests that Append() works ok when handed a self reference TEST_P(CordTest, AppendSelf) { + // Test the empty case. + absl::Cord empty; + MaybeHarden(empty); + empty.Append(empty); + ASSERT_EQ(empty, ""); + // We run the test until data is ~16K // This guarantees it covers small, medium and large data. std::string control_data = "Abc"; @@ -2712,7 +2718,7 @@ class CordMutator { // clang-format off // This array is constant-initialized in conformant compilers. -CordMutator cord_mutators[] ={ +CordMutator cord_mutators[] = { {"clear", [](absl::Cord& c) { c.Clear(); }}, {"overwrite", [](absl::Cord& c) { c = "overwritten"; }}, { @@ -2742,6 +2748,25 @@ CordMutator cord_mutators[] ={ [](absl::Cord& c) { c.RemoveSuffix(c.size() / 2); } }, { + "append empty string", + [](absl::Cord& c) { c.Append(""); }, + [](absl::Cord& c) { } + }, + { + "append empty cord", + [](absl::Cord& c) { c.Append(absl::Cord()); }, + [](absl::Cord& c) { } + }, + { + "append empty checksummed cord", + [](absl::Cord& c) { + absl::Cord to_append; + to_append.SetExpectedChecksum(999); + c.Append(to_append); + }, + [](absl::Cord& c) { } + }, + { "prepend string", [](absl::Cord& c) { c.Prepend("9876543210"); }, [](absl::Cord& c) { c.RemovePrefix(10); } @@ -2763,12 +2788,33 @@ CordMutator cord_mutators[] ={ [](absl::Cord& c) { c.RemovePrefix(10); } }, { + "prepend empty string", + [](absl::Cord& c) { c.Prepend(""); }, + [](absl::Cord& c) { } + }, + { + "prepend empty cord", + [](absl::Cord& c) { c.Prepend(absl::Cord()); }, + [](absl::Cord& c) { } + }, + { + "prepend empty checksummed cord", + [](absl::Cord& c) { + absl::Cord to_prepend; + to_prepend.SetExpectedChecksum(999); + c.Prepend(to_prepend); + }, + [](absl::Cord& c) { } + }, + { "prepend self", [](absl::Cord& c) { c.Prepend(c); }, [](absl::Cord& c) { c.RemovePrefix(c.size() / 2); } }, - {"remove prefix", [](absl::Cord& c) { c.RemovePrefix(2); }}, - {"remove suffix", [](absl::Cord& c) { c.RemoveSuffix(2); }}, + {"remove prefix", [](absl::Cord& c) { c.RemovePrefix(c.size() / 2); }}, + {"remove suffix", [](absl::Cord& c) { c.RemoveSuffix(c.size() / 2); }}, + {"remove 0-prefix", [](absl::Cord& c) { c.RemovePrefix(0); }}, + {"remove 0-suffix", [](absl::Cord& c) { c.RemoveSuffix(0); }}, {"subcord", [](absl::Cord& c) { c = c.Subcord(1, c.size() - 2); }}, { "swap inline", @@ -2834,6 +2880,13 @@ TEST_P(CordTest, ExpectedChecksum) { c2.SetExpectedChecksum(24680); mutator.Mutate(c2); + + if (c1 == c2) { + // Not a mutation (for example, appending the empty string). + // Whether the checksum is removed is not defined. + continue; + } + EXPECT_EQ(c2.ExpectedChecksum(), absl::nullopt); if (mutator.CanUndo()) { @@ -2903,3 +2956,92 @@ TEST_P(CordTest, ExpectedChecksum) { } } } + +// Test the special cases encountered with an empty checksummed cord. +TEST_P(CordTest, ChecksummedEmptyCord) { + absl::Cord c1; + EXPECT_FALSE(c1.ExpectedChecksum().has_value()); + + // Setting an expected checksum works. + c1.SetExpectedChecksum(12345); + EXPECT_EQ(c1.ExpectedChecksum().value_or(0), 12345); + EXPECT_EQ(c1, ""); + EXPECT_TRUE(c1.empty()); + + // CRC persists through copies, assignments, and moves: + absl::Cord c1_copy_construct = c1; + EXPECT_EQ(c1_copy_construct.ExpectedChecksum().value_or(0), 12345); + + absl::Cord c1_copy_assign; + c1_copy_assign = c1; + EXPECT_EQ(c1_copy_assign.ExpectedChecksum().value_or(0), 12345); + + absl::Cord c1_move(std::move(c1_copy_assign)); + EXPECT_EQ(c1_move.ExpectedChecksum().value_or(0), 12345); + + EXPECT_EQ(c1.ExpectedChecksum().value_or(0), 12345); + + // A CRC Cord compares equal to its non-CRC value. + EXPECT_EQ(c1, absl::Cord()); + + for (const CordMutator& mutator : cord_mutators) { + SCOPED_TRACE(mutator.Name()); + + // Exercise mutating an empty checksummed cord to catch crashes and exercise + // memory sanitizers. + absl::Cord c2; + c2.SetExpectedChecksum(24680); + mutator.Mutate(c2); + + if (c2.empty()) { + // Not a mutation + continue; + } + EXPECT_EQ(c2.ExpectedChecksum(), absl::nullopt); + + if (mutator.CanUndo()) { + mutator.Undo(c2); + } + } + + absl::Cord c3; + c3.SetExpectedChecksum(999); + const absl::Cord& cc3 = c3; + + // Test that all cord reading operations function in the face of an + // expected checksum. + EXPECT_TRUE(cc3.StartsWith("")); + EXPECT_TRUE(cc3.EndsWith("")); + EXPECT_TRUE(cc3.empty()); + EXPECT_EQ(cc3, ""); + EXPECT_EQ(cc3, absl::Cord()); + EXPECT_EQ(cc3.size(), 0); + EXPECT_EQ(cc3.Compare(absl::Cord()), 0); + EXPECT_EQ(cc3.Compare(c1), 0); + EXPECT_EQ(cc3.Compare(cc3), 0); + EXPECT_EQ(cc3.Compare(""), 0); + EXPECT_EQ(cc3.Compare("wxyz"), -1); + EXPECT_EQ(cc3.Compare(absl::Cord("wxyz")), -1); + EXPECT_EQ(absl::Cord("wxyz").Compare(cc3), 1); + EXPECT_EQ(std::string(cc3), ""); + + std::string dest; + absl::CopyCordToString(cc3, &dest); + EXPECT_EQ(dest, ""); + + for (absl::string_view chunk : cc3.Chunks()) { // NOLINT(unreachable loop) + static_cast<void>(chunk); + GTEST_FAIL() << "no chunks expected"; + } + EXPECT_TRUE(cc3.chunk_begin() == cc3.chunk_end()); + + for (char ch : cc3.Chars()) { // NOLINT(unreachable loop) + static_cast<void>(ch); + GTEST_FAIL() << "no chars expected"; + } + EXPECT_TRUE(cc3.char_begin() == cc3.char_end()); + + EXPECT_EQ(cc3.TryFlat(), ""); + EXPECT_EQ(absl::HashOf(c3), absl::HashOf(absl::Cord())); + EXPECT_EQ(absl::HashOf(c3), absl::HashOf(absl::string_view())); +} |