| // Copyright 2017-2020 The Verible 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 | |
| // | |
| // http://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 "common/strings/string_memory_map.h" | |
| #include <memory> | |
| #include <string> | |
| #include "absl/memory/memory.h" | |
| #include "common/strings/range.h" | |
| #include "common/util/range.h" | |
| #include "gmock/gmock.h" | |
| #include "gtest/gtest.h" | |
| namespace verible { | |
| namespace { | |
| static void ForAllSubstringRanges( | |
| absl::string_view sv, const std::function<void(absl::string_view)>& func) { | |
| for (auto start_iter = sv.begin(); start_iter != sv.end(); ++start_iter) { | |
| for (auto end_iter = start_iter; end_iter != sv.end(); ++end_iter) { | |
| if (start_iter == end_iter) continue; // skip empty ranges | |
| func(make_string_view_range(start_iter, end_iter)); | |
| } | |
| } | |
| } | |
| TEST(StringViewSuperRangeMapTest, Empty) { | |
| StringViewSuperRangeMap svmap; | |
| EXPECT_TRUE(svmap.empty()); | |
| } | |
| TEST(StringViewSuperRangeMapTest, OneString) { | |
| StringViewSuperRangeMap svmap; | |
| constexpr absl::string_view text("text"); | |
| const auto new_iter = svmap.must_emplace(text); | |
| EXPECT_NE(new_iter, svmap.end()); | |
| EXPECT_FALSE(svmap.empty()); | |
| EXPECT_TRUE(BoundsEqual( | |
| make_string_view_range(new_iter->first, new_iter->second), text)); | |
| EXPECT_TRUE(BoundsEqual(svmap.must_find(text), text)); | |
| ForAllSubstringRanges(text, [&svmap, text](absl::string_view subrange) { | |
| EXPECT_TRUE(BoundsEqual(svmap.must_find(subrange), text)); | |
| }); | |
| } | |
| TEST(StringViewSuperRangeMapTest, Overlap) { | |
| StringViewSuperRangeMap svmap; | |
| constexpr absl::string_view text("text"); | |
| svmap.must_emplace(text); | |
| EXPECT_DEATH(svmap.must_emplace(text), "Failed to emplace"); | |
| } | |
| TEST(StringViewSuperRangeMapTest, OverlapSubstring) { | |
| StringViewSuperRangeMap svmap; | |
| constexpr absl::string_view text("text"); | |
| svmap.must_emplace(text); | |
| EXPECT_DEATH(svmap.must_emplace(text.substr(1)), "Failed to emplace"); | |
| } | |
| TEST(StringViewSuperRangeMapTest, SuperRangeNotInSet) { | |
| StringViewSuperRangeMap svmap; | |
| constexpr absl::string_view text("text"); | |
| svmap.must_emplace(text); | |
| EXPECT_DEATH(svmap.must_find(absl::string_view("never-there")), ""); | |
| } | |
| TEST(StringViewSuperRangeMapTest, TwoStrings) { | |
| StringViewSuperRangeMap svmap; | |
| constexpr absl::string_view text1("hello"), text2("world"); | |
| { | |
| const auto new_iter = svmap.must_emplace(text1); | |
| EXPECT_NE(new_iter, svmap.end()); | |
| EXPECT_FALSE(svmap.empty()); | |
| EXPECT_TRUE(BoundsEqual( | |
| make_string_view_range(new_iter->first, new_iter->second), text1)); | |
| EXPECT_TRUE(BoundsEqual(svmap.must_find(text1), text1)); | |
| } | |
| { | |
| const auto new_iter = svmap.must_emplace(text2); | |
| EXPECT_NE(new_iter, svmap.end()); | |
| EXPECT_FALSE(svmap.empty()); | |
| EXPECT_TRUE(BoundsEqual( | |
| make_string_view_range(new_iter->first, new_iter->second), text2)); | |
| EXPECT_TRUE(BoundsEqual(svmap.must_find(text2), text2)); | |
| } | |
| ForAllSubstringRanges(text1, [&svmap, text1](absl::string_view subrange) { | |
| EXPECT_TRUE(BoundsEqual(svmap.must_find(subrange), text1)); | |
| }); | |
| ForAllSubstringRanges(text2, [&svmap, text2](absl::string_view subrange) { | |
| EXPECT_TRUE(BoundsEqual(svmap.must_find(subrange), text2)); | |
| }); | |
| } | |
| // Function to get the owned address range of the underlying string. | |
| static absl::string_view StringViewKey( | |
| const std::unique_ptr<const std::string>& owned) { | |
| return absl::string_view(*ABSL_DIE_IF_NULL(owned)); | |
| } | |
| typedef StringMemoryMap<std::unique_ptr<const std::string>, StringViewKey> | |
| StringSet; | |
| TEST(StringMemoryMapTest, EmptyOwnsNothing) { | |
| const StringSet sset; | |
| EXPECT_EQ(sset.find("not-owned-anywhere"), nullptr); | |
| } | |
| static absl::string_view InsertStringCopy(StringSet* sset, const char* text) { | |
| const auto new_iter = | |
| sset->insert(std::make_unique<std::string>(text)); // copy | |
| return make_string_view_range(new_iter->first.first, new_iter->first.second); | |
| } | |
| TEST(StringMemoryMapTest, OneElement) { | |
| StringSet sset; | |
| const absl::string_view sv(InsertStringCopy(&sset, "OWNED")); | |
| // Check all valid substring ranges | |
| ForAllSubstringRanges(sv, [&sset, sv](absl::string_view subrange) { | |
| const auto* f = sset.find(subrange); | |
| ASSERT_NE(f, nullptr) << "subrange returned nullptr: " << subrange; | |
| const absl::string_view fv(**f); | |
| EXPECT_TRUE(BoundsEqual(fv, sv)) << "got: " << fv << " vs. " << sv; | |
| EXPECT_EQ(fv, "OWNED"); | |
| }); | |
| } | |
| TEST(StringMemoryMapTest, MultipleElements) { | |
| StringSet sset; | |
| // There's no telling where these allocated strings will reside in memory. | |
| const absl::string_view sv1(InsertStringCopy(&sset, "AAA")); | |
| const absl::string_view sv2(InsertStringCopy(&sset, "BBBB")); | |
| const absl::string_view sv3(InsertStringCopy(&sset, "CCCCC")); | |
| // Check all valid substring ranges | |
| ForAllSubstringRanges(sv1, [&sset, sv1](absl::string_view subrange) { | |
| const auto* f = sset.find(subrange); | |
| ASSERT_NE(f, nullptr) << "subrange returned nullptr: " << subrange; | |
| const absl::string_view fv(*ABSL_DIE_IF_NULL(*f)); | |
| EXPECT_TRUE(BoundsEqual(fv, sv1)) << "got: " << fv << " vs. " << sv1; | |
| EXPECT_EQ(fv, "AAA"); | |
| }); | |
| ForAllSubstringRanges(sv2, [&sset, sv2](absl::string_view subrange) { | |
| const auto* f = sset.find(subrange); | |
| ASSERT_NE(f, nullptr) << "subrange returned nullptr: " << subrange; | |
| const absl::string_view fv(*ABSL_DIE_IF_NULL(*f)); | |
| EXPECT_TRUE(BoundsEqual(fv, sv2)) << "got: " << fv << " vs. " << sv2; | |
| EXPECT_EQ(fv, "BBBB"); | |
| }); | |
| ForAllSubstringRanges(sv3, [&sset, sv3](absl::string_view subrange) { | |
| const auto* f = sset.find(subrange); | |
| ASSERT_NE(f, nullptr) << "subrange returned nullptr: " << subrange; | |
| const absl::string_view fv(*ABSL_DIE_IF_NULL(*f)); | |
| EXPECT_TRUE(BoundsEqual(fv, sv3)) << "got: " << fv << " vs. " << sv3; | |
| EXPECT_EQ(fv, "CCCCC"); | |
| }); | |
| } | |
| } // namespace | |
| } // namespace verible |