blob: ccd6f267fcf4c3f6d81e4ad6a8bf64c972da445b [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/disk_cache/sql/indexed_pair_set.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::UnorderedElementsAre;
namespace disk_cache {
class IndexedPairSetTest : public testing::Test {
protected:
IndexedPairSet<int64_t, int64_t> set_;
};
TEST_F(IndexedPairSetTest, EmptyInitially) {
EXPECT_TRUE(set_.empty());
EXPECT_EQ(0u, set_.size());
}
TEST_F(IndexedPairSetTest, InsertAndFindSingleValue) {
EXPECT_TRUE(set_.Insert(10, 100));
EXPECT_FALSE(set_.empty());
EXPECT_EQ(1u, set_.size());
EXPECT_TRUE(set_.Contains(10));
std::vector<int64_t> values = set_.Find(10);
ASSERT_EQ(1u, values.size());
EXPECT_EQ(100, values[0]);
}
TEST_F(IndexedPairSetTest, InsertDuplicatePair) {
EXPECT_TRUE(set_.Insert(10, 100));
EXPECT_EQ(1u, set_.size());
// Inserting the exact same pair should do nothing and return false.
EXPECT_FALSE(set_.Insert(10, 100));
EXPECT_EQ(1u, set_.size());
EXPECT_TRUE(set_.Insert(10, 200));
EXPECT_EQ(2u, set_.size());
// Inserting the exact same pair which exists in the secondary map should do
// nothing and return false.
EXPECT_FALSE(set_.Insert(10, 200));
EXPECT_EQ(2u, set_.size());
}
TEST_F(IndexedPairSetTest, InsertDuplicateKey) {
EXPECT_TRUE(set_.Insert(10, 100));
EXPECT_TRUE(set_.Insert(10, 200));
EXPECT_EQ(2u, set_.size());
EXPECT_THAT(set_.Find(10), UnorderedElementsAre(100, 200));
EXPECT_TRUE(set_.Insert(10, 300));
EXPECT_EQ(3u, set_.size());
EXPECT_THAT(set_.Find(10), UnorderedElementsAre(100, 200, 300));
}
TEST_F(IndexedPairSetTest, Contains) {
EXPECT_TRUE(set_.Insert(10, 100));
EXPECT_TRUE(set_.Insert(20, 200));
EXPECT_TRUE(set_.Insert(10, 300));
EXPECT_TRUE(set_.Contains(10));
EXPECT_TRUE(set_.Contains(20));
EXPECT_FALSE(set_.Contains(99)); // Non-existent key
}
TEST_F(IndexedPairSetTest, Clear) {
EXPECT_TRUE(set_.Insert(10, 100));
EXPECT_TRUE(set_.Insert(20, 200));
EXPECT_FALSE(set_.empty());
set_.Clear();
EXPECT_TRUE(set_.empty());
EXPECT_EQ(0u, set_.size());
EXPECT_FALSE(set_.Contains(10));
EXPECT_TRUE(set_.Find(20).empty());
}
TEST_F(IndexedPairSetTest, RemoveNonExistent) {
EXPECT_TRUE(set_.Insert(10, 100));
EXPECT_FALSE(set_.Remove(99, 999)); // Non-existent key
EXPECT_FALSE(set_.Remove(10, 999)); // Non-existent value
EXPECT_EQ(1u, set_.size());
}
TEST_F(IndexedPairSetTest, RemoveSingleValue) {
EXPECT_TRUE(set_.Insert(10, 100));
EXPECT_TRUE(set_.Remove(10, 100));
EXPECT_EQ(0u, set_.size());
EXPECT_TRUE(set_.empty());
EXPECT_FALSE(set_.Contains(10));
EXPECT_TRUE(set_.Find(10).empty());
}
TEST_F(IndexedPairSetTest, RemoveMultipleValuesForKey) {
EXPECT_TRUE(set_.Insert(10, 100));
EXPECT_TRUE(set_.Insert(10, 200));
EXPECT_TRUE(set_.Insert(10, 300));
EXPECT_EQ(3u, set_.size());
// Remove a value from the secondary_map_.
EXPECT_TRUE(set_.Remove(10, 200));
EXPECT_EQ(2u, set_.size());
EXPECT_TRUE(set_.Contains(10));
EXPECT_THAT(set_.Find(10), UnorderedElementsAre(100, 300));
// Remove a value from the primary_map_, triggering a promotion.
EXPECT_TRUE(set_.Remove(10, 100));
EXPECT_EQ(1u, set_.size());
EXPECT_THAT(set_.Find(10), UnorderedElementsAre(300));
// Remove the final value.
EXPECT_TRUE(set_.Remove(10, 300));
EXPECT_EQ(0u, set_.size());
EXPECT_FALSE(set_.Contains(10));
}
TEST_F(IndexedPairSetTest, RemovePromotesFromAdditionalMap) {
set_.Insert(10, 100);
set_.Insert(10, 200);
set_.Insert(10, 300);
// This will remove 100 from the primary_map_ and promote one of the values
// from secondary_map_ (either 200 or 300).
EXPECT_TRUE(set_.Remove(10, 100));
EXPECT_EQ(2u, set_.size());
EXPECT_THAT(set_.Find(10), UnorderedElementsAre(200, 300));
}
TEST_F(IndexedPairSetTest, RemoveLastFromAdditionalMapEmptiesSet) {
set_.Insert(10, 100);
set_.Insert(10, 200);
// Remove the value from the secondary_map_.
EXPECT_TRUE(set_.Remove(10, 200));
EXPECT_EQ(1u, set_.size());
EXPECT_THAT(set_.Find(10), UnorderedElementsAre(100));
// The secondary_map_ should now be empty for key 10.
// Inserting a new value should work as expected.
EXPECT_TRUE(set_.Insert(10, 300));
EXPECT_EQ(2u, set_.size());
EXPECT_THAT(set_.Find(10), UnorderedElementsAre(100, 300));
}
TEST_F(IndexedPairSetTest, RemoveFromAdditionalMapThenInsertNewValue) {
// Setup:
// primary_map_ will contain: {10, 100}, {20, 300}
// secondary_map_ will contain: {10, {200}}
EXPECT_TRUE(set_.Insert(10, 100));
EXPECT_TRUE(set_.Insert(10, 200));
EXPECT_TRUE(set_.Insert(20, 300));
EXPECT_EQ(3u, set_.size());
// Action: Remove the only value for key 10 from the secondary_map_.
EXPECT_TRUE(set_.Remove(10, 200));
EXPECT_EQ(2u, set_.size());
// Verification: The secondary_map_ should no longer have an entry for
// key 10. Inserting a new value for key 10 should add it to the
// secondary_map_.
EXPECT_TRUE(set_.Insert(10, 400));
EXPECT_EQ(3u, set_.size());
EXPECT_THAT(set_.Find(10), UnorderedElementsAre(100, 400));
}
TEST_F(IndexedPairSetTest, MoveConstructor) {
set_.Insert(10, 100);
set_.Insert(20, 200);
EXPECT_EQ(2u, set_.size());
IndexedPairSet<int64_t, int64_t> new_set(std::move(set_));
// The old set should be empty.
EXPECT_EQ(0u, set_.size());
EXPECT_TRUE(set_.empty());
// The new set should have the data.
EXPECT_EQ(2u, new_set.size());
EXPECT_TRUE(new_set.Contains(10));
EXPECT_TRUE(new_set.Contains(20));
EXPECT_THAT(new_set.Find(10), UnorderedElementsAre(100));
EXPECT_THAT(new_set.Find(20), UnorderedElementsAre(200));
}
TEST_F(IndexedPairSetTest, MoveAssignment) {
set_.Insert(10, 100);
set_.Insert(20, 200);
IndexedPairSet<int64_t, int64_t> new_set;
new_set.Insert(30, 300);
new_set = std::move(set_);
// The old set should be empty.
EXPECT_EQ(0u, set_.size());
EXPECT_TRUE(set_.empty());
// The new set should have the moved data.
EXPECT_EQ(2u, new_set.size());
EXPECT_TRUE(new_set.Contains(10));
EXPECT_TRUE(new_set.Contains(20));
EXPECT_THAT(new_set.Find(10), UnorderedElementsAre(100));
EXPECT_THAT(new_set.Find(20), UnorderedElementsAre(200));
EXPECT_FALSE(new_set.Contains(30)); // Original data should be gone.
}
TEST_F(IndexedPairSetTest, MoveAssignmentSelf) {
set_.Insert(10, 100);
set_.Insert(20, 200);
EXPECT_EQ(2u, set_.size());
set_ = std::move(set_);
// The set should be unchanged.
EXPECT_EQ(2u, set_.size());
EXPECT_TRUE(set_.Contains(10));
EXPECT_TRUE(set_.Contains(20));
EXPECT_THAT(set_.Find(10), UnorderedElementsAre(100));
EXPECT_THAT(set_.Find(20), UnorderedElementsAre(200));
}
TEST_F(IndexedPairSetTest, RemoveLastValueFromSecondaryMapRemovesKey) {
set_.Insert(10, 100);
set_.Insert(10, 200);
EXPECT_TRUE(set_.SecondaryMapContainsKeyForTesting(10));
// Remove the value from the secondary_map.
EXPECT_TRUE(set_.Remove(10, 200));
EXPECT_EQ(1u, set_.size());
EXPECT_THAT(set_.Find(10), UnorderedElementsAre(100));
// The key should no longer exist in the secondary_map.
EXPECT_FALSE(set_.SecondaryMapContainsKeyForTesting(10));
}
TEST_F(IndexedPairSetTest, RemoveAndPromoteWithEmptyingSecondaryMapRemovesKey) {
set_.Insert(10, 100);
set_.Insert(10, 200);
EXPECT_TRUE(set_.SecondaryMapContainsKeyForTesting(10));
// This will remove 100 from the primary_map and promote 200 from the
// secondary_map. After promotion, the secondary_map should be empty for key
// 10, so the key should be removed.
EXPECT_TRUE(set_.Remove(10, 100));
EXPECT_EQ(1u, set_.size());
EXPECT_THAT(set_.Find(10), UnorderedElementsAre(200));
// The key should no longer exist in the secondary_map.
EXPECT_FALSE(set_.SecondaryMapContainsKeyForTesting(10));
}
} // namespace disk_cache