Loading files
3d097a032This file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <NCollection_IndexedDataMap.hxx>
#include <TCollection_AsciiString.hxx>
#include <gtest/gtest.h>
#include <algorithm>
#include <type_traits>
#include <vector>
// Basic test types for the IndexedDataMap
typedef int KeyType;
typedef double ItemType;
// Custom class for testing complex keys
class TestKey
{
public:
TestKey(int id = 0, const char* name = "")
: myId(id),
myName(name)
{
}
bool operator==(const TestKey& other) const
{
return myId == other.myId && myName == other.myName;
}
int GetId() const { return myId; }
const std::string& GetName() const { return myName; }
private:
int myId;
std::string myName;
};
namespace std
{
template <>
struct hash<TestKey>
{
size_t operator()(const TestKey& key) const
{
// Combine the hash
size_t aCombintation[2] = {std::hash<int>()(key.GetId()),
std::hash<std::string>()(key.GetName())};
return opencascade::hashBytes(aCombintation, sizeof(aCombintation));
}
};
} // namespace std
// Custom class for testing complex items
class TestItem
{
public:
TestItem(double value = 0.0, const char* description = "")
: myValue(value),
myDescription(description)
{
}
bool operator==(const TestItem& other) const
{
return fabs(myValue - other.myValue) < 1e-10 && myDescription == other.myDescription;
}
double GetValue() const { return myValue; }
const std::string& GetDescription() const { return myDescription; }
void SetValue(double value) { myValue = value; }
private:
double myValue;
std::string myDescription;
};
TEST(NCollection_IndexedDataMapTest, DefaultConstructor)
{
// Test default constructor
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
EXPECT_TRUE(aMap.IsEmpty());
EXPECT_EQ(aMap.Extent(), 0);
EXPECT_EQ(aMap.Size(), 0);
}
TEST(NCollection_IndexedDataMapTest, BasicAddFind)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Test adding elements
int index1 = aMap.Add(10, 1.0);
int index2 = aMap.Add(20, 2.0);
int index3 = aMap.Add(30, 3.0);
EXPECT_EQ(index1, 1);
EXPECT_EQ(index2, 2);
EXPECT_EQ(index3, 3);
EXPECT_EQ(aMap.Extent(), 3);
// Test finding elements by key
EXPECT_EQ(aMap.FindIndex(10), 1);
EXPECT_EQ(aMap.FindIndex(20), 2);
EXPECT_EQ(aMap.FindIndex(30), 3);
// Test finding keys by index
EXPECT_EQ(aMap.FindKey(1), 10);
EXPECT_EQ(aMap.FindKey(2), 20);
EXPECT_EQ(aMap.FindKey(3), 30);
// Test finding items by index
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(1), 1.0);
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(2), 2.0);
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(3), 3.0);
// Test operator()
EXPECT_DOUBLE_EQ(aMap(1), 1.0);
EXPECT_DOUBLE_EQ(aMap(2), 2.0);
EXPECT_DOUBLE_EQ(aMap(3), 3.0);
// Test finding items by key
EXPECT_DOUBLE_EQ(aMap.FindFromKey(10), 1.0);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(20), 2.0);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(30), 3.0);
// Test Contains
EXPECT_TRUE(aMap.Contains(10));
EXPECT_TRUE(aMap.Contains(20));
EXPECT_TRUE(aMap.Contains(30));
EXPECT_FALSE(aMap.Contains(40));
}
TEST(NCollection_IndexedDataMapTest, DuplicateKey)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Add initial elements
int index1 = aMap.Add(10, 1.0);
int index2 = aMap.Add(20, 2.0);
EXPECT_EQ(index1, 1);
EXPECT_EQ(index2, 2);
// Try to add a duplicate - should return the existing index and not change the item
int indexDup = aMap.Add(10, 3.0);
EXPECT_EQ(indexDup, 1);
EXPECT_EQ(aMap.Extent(), 2); // Size should not change
EXPECT_DOUBLE_EQ(aMap.FindFromKey(10), 1.0); // Original value should be preserved
}
TEST(NCollection_IndexedDataMapTest, ChangeValues)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Add elements
aMap.Add(10, 1.0);
aMap.Add(20, 2.0);
// Change values through ChangeFromIndex
aMap.ChangeFromIndex(1) = 1.5;
aMap.ChangeFromIndex(2) = 2.5;
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(1), 1.5);
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(2), 2.5);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(10), 1.5);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(20), 2.5);
// Change values through ChangeFromKey
aMap.ChangeFromKey(10) = 1.75;
aMap.ChangeFromKey(20) = 2.75;
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(1), 1.75);
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(2), 2.75);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(10), 1.75);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(20), 2.75);
// Change values through operator()
aMap(1) = 1.9;
aMap(2) = 2.9;
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(1), 1.9);
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(2), 2.9);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(10), 1.9);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(20), 2.9);
}
TEST(NCollection_IndexedDataMapTest, SeekTests)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Add elements
aMap.Add(10, 1.0);
aMap.Add(20, 2.0);
// Test Seek
const ItemType* item1 = aMap.Seek(10);
const ItemType* item2 = aMap.Seek(20);
const ItemType* item3 = aMap.Seek(30); // Not present
EXPECT_TRUE(item1 != nullptr);
EXPECT_TRUE(item2 != nullptr);
EXPECT_TRUE(item3 == nullptr);
EXPECT_DOUBLE_EQ(*item1, 1.0);
EXPECT_DOUBLE_EQ(*item2, 2.0);
// Test ChangeSeek
ItemType* changeItem1 = aMap.ChangeSeek(10);
ItemType* changeItem2 = aMap.ChangeSeek(20);
ItemType* changeItem3 = aMap.ChangeSeek(30); // Not present
EXPECT_TRUE(changeItem1 != nullptr);
EXPECT_TRUE(changeItem2 != nullptr);
EXPECT_TRUE(changeItem3 == nullptr);
*changeItem1 = 1.5;
*changeItem2 = 2.5;
EXPECT_DOUBLE_EQ(aMap.FindFromKey(10), 1.5);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(20), 2.5);
// Test FindFromKey with copy
ItemType value;
bool found = aMap.FindFromKey(10, value);
EXPECT_TRUE(found);
EXPECT_DOUBLE_EQ(value, 1.5);
found = aMap.FindFromKey(30, value);
EXPECT_FALSE(found);
}
TEST(NCollection_IndexedDataMapTest, RemoveLast)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Add elements
aMap.Add(10, 1.0);
aMap.Add(20, 2.0);
aMap.Add(30, 3.0);
// Remove the last element
aMap.RemoveLast();
EXPECT_EQ(aMap.Extent(), 2);
EXPECT_TRUE(aMap.Contains(10));
EXPECT_TRUE(aMap.Contains(20));
EXPECT_FALSE(aMap.Contains(30));
// Check indices - they should still be sequential
EXPECT_EQ(aMap.FindIndex(10), 1);
EXPECT_EQ(aMap.FindIndex(20), 2);
}
TEST(NCollection_IndexedDataMapTest, RemoveFromIndex)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Add elements
aMap.Add(10, 1.0);
aMap.Add(20, 2.0);
aMap.Add(30, 3.0);
aMap.Add(40, 4.0);
// Remove element at index 2
aMap.RemoveFromIndex(2);
EXPECT_EQ(aMap.Extent(), 3);
EXPECT_TRUE(aMap.Contains(10));
EXPECT_FALSE(aMap.Contains(20)); // Removed
EXPECT_TRUE(aMap.Contains(30));
EXPECT_TRUE(aMap.Contains(40));
// Test how the indices were rearranged
// Index 2 should now contain what was previously at the last position
EXPECT_EQ(aMap.FindKey(2), 40); // Last element moved to position 2
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(2), 4.0);
EXPECT_EQ(aMap.FindKey(1), 10); // First element unchanged
EXPECT_EQ(aMap.FindKey(3), 30); // Third element unchanged
}
TEST(NCollection_IndexedDataMapTest, RemoveKey)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Add elements
aMap.Add(10, 1.0);
aMap.Add(20, 2.0);
aMap.Add(30, 3.0);
// Remove by key
aMap.RemoveKey(20);
EXPECT_EQ(aMap.Extent(), 2);
EXPECT_TRUE(aMap.Contains(10));
EXPECT_FALSE(aMap.Contains(20));
EXPECT_TRUE(aMap.Contains(30));
// Try to remove non-existent key
aMap.RemoveKey(50); // Should have no effect
EXPECT_EQ(aMap.Extent(), 2);
}
TEST(NCollection_IndexedDataMapTest, Substitute)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Add elements
aMap.Add(10, 1.0);
aMap.Add(20, 2.0);
aMap.Add(30, 3.0);
// Substitute key and value at index 2
aMap.Substitute(2, 25, 2.5);
EXPECT_EQ(aMap.Extent(), 3);
EXPECT_TRUE(aMap.Contains(10));
EXPECT_FALSE(aMap.Contains(20));
EXPECT_TRUE(aMap.Contains(25));
EXPECT_TRUE(aMap.Contains(30));
// Check indices after substitution
EXPECT_EQ(aMap.FindIndex(10), 1);
EXPECT_EQ(aMap.FindIndex(25), 2);
EXPECT_EQ(aMap.FindIndex(30), 3);
// Check values after substitution
EXPECT_DOUBLE_EQ(aMap.FindFromKey(10), 1.0);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(25), 2.5);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(30), 3.0);
}
TEST(NCollection_IndexedDataMapTest, Swap)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Add elements
aMap.Add(10, 1.0);
aMap.Add(20, 2.0);
aMap.Add(30, 3.0);
// Swap elements at indices 1 and 3
aMap.Swap(1, 3);
EXPECT_EQ(aMap.Extent(), 3);
// Check that keys maintained their values
EXPECT_TRUE(aMap.Contains(10));
EXPECT_TRUE(aMap.Contains(20));
EXPECT_TRUE(aMap.Contains(30));
// But indices are swapped
EXPECT_EQ(aMap.FindKey(1), 30);
EXPECT_EQ(aMap.FindKey(2), 20);
EXPECT_EQ(aMap.FindKey(3), 10);
EXPECT_EQ(aMap.FindIndex(10), 3);
EXPECT_EQ(aMap.FindIndex(20), 2);
EXPECT_EQ(aMap.FindIndex(30), 1);
// And values follow their keys
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(1), 3.0);
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(2), 2.0);
EXPECT_DOUBLE_EQ(aMap.FindFromIndex(3), 1.0);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(10), 1.0);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(20), 2.0);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(30), 3.0);
}
TEST(NCollection_IndexedDataMapTest, Clear)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Add elements
aMap.Add(10, 1.0);
aMap.Add(20, 2.0);
aMap.Add(30, 3.0);
EXPECT_EQ(aMap.Extent(), 3);
// Clear the map
aMap.Clear(true);
EXPECT_TRUE(aMap.IsEmpty());
EXPECT_EQ(aMap.Extent(), 0);
// Ensure we can add elements again
int index1 = aMap.Add(40, 4.0);
EXPECT_EQ(index1, 1);
EXPECT_EQ(aMap.Extent(), 1);
}
TEST(NCollection_IndexedDataMapTest, CopyConstructor)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap1;
// Add elements to first map
aMap1.Add(10, 1.0);
aMap1.Add(20, 2.0);
aMap1.Add(30, 3.0);
// Create a copy
NCollection_IndexedDataMap<KeyType, ItemType> aMap2(aMap1);
// Check that copy has the same elements
EXPECT_EQ(aMap2.Extent(), 3);
EXPECT_TRUE(aMap2.Contains(10));
EXPECT_TRUE(aMap2.Contains(20));
EXPECT_TRUE(aMap2.Contains(30));
// Check indices
EXPECT_EQ(aMap2.FindIndex(10), 1);
EXPECT_EQ(aMap2.FindIndex(20), 2);
EXPECT_EQ(aMap2.FindIndex(30), 3);
// Check values
EXPECT_DOUBLE_EQ(aMap2.FindFromKey(10), 1.0);
EXPECT_DOUBLE_EQ(aMap2.FindFromKey(20), 2.0);
EXPECT_DOUBLE_EQ(aMap2.FindFromKey(30), 3.0);
// Modify original to ensure deep copy
aMap1.Add(40, 4.0);
EXPECT_EQ(aMap1.Extent(), 4);
EXPECT_EQ(aMap2.Extent(), 3);
EXPECT_FALSE(aMap2.Contains(40));
}
TEST(NCollection_IndexedDataMapTest, AssignmentOperator)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap1;
NCollection_IndexedDataMap<KeyType, ItemType> aMap2;
// Add elements to first map
aMap1.Add(10, 1.0);
aMap1.Add(20, 2.0);
// Add different elements to second map
aMap2.Add(30, 3.0);
aMap2.Add(40, 4.0);
aMap2.Add(50, 5.0);
// Assign first to second
aMap2 = aMap1;
// Check that second map now matches first
EXPECT_EQ(aMap2.Extent(), 2);
EXPECT_TRUE(aMap2.Contains(10));
EXPECT_TRUE(aMap2.Contains(20));
EXPECT_FALSE(aMap2.Contains(30));
EXPECT_FALSE(aMap2.Contains(40));
EXPECT_FALSE(aMap2.Contains(50));
// Check values
EXPECT_DOUBLE_EQ(aMap2.FindFromKey(10), 1.0);
EXPECT_DOUBLE_EQ(aMap2.FindFromKey(20), 2.0);
}
TEST(NCollection_IndexedDataMapTest, Iterator)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Add elements
aMap.Add(10, 1.0);
aMap.Add(20, 2.0);
aMap.Add(30, 3.0);
// Use iterator to check all elements
bool found10 = false;
bool found20 = false;
bool found30 = false;
size_t count = 0;
for (NCollection_IndexedDataMap<KeyType, ItemType>::Iterator it(aMap); it.More();
it.Next(), ++count)
{
const KeyType& key = it.Key();
const ItemType& value = it.Value();
if (key == 10 && value == 1.0)
{
found10 = true;
}
else if (key == 20 && value == 2.0)
{
found20 = true;
}
else if (key == 30 && value == 3.0)
{
found30 = true;
}
}
EXPECT_EQ(count, 3);
EXPECT_TRUE(found10);
EXPECT_TRUE(found20);
EXPECT_TRUE(found30);
// Test modification through iterator
for (NCollection_IndexedDataMap<KeyType, ItemType>::Iterator it(aMap); it.More(); it.Next())
{
it.ChangeValue() *= 2;
}
EXPECT_DOUBLE_EQ(aMap.FindFromKey(10), 2.0);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(20), 4.0);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(30), 6.0);
}
TEST(NCollection_IndexedDataMapTest, StlIterator)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap;
// Add elements
aMap.Add(10, 1.0);
aMap.Add(20, 2.0);
aMap.Add(30, 3.0);
// Use STL-style iterator
bool found1 = false;
bool found2 = false;
bool found3 = false;
size_t count = 0;
for (auto it = aMap.begin(); it != aMap.end(); ++it, ++count)
{
if (*it == 1.0)
{
found1 = true;
}
else if (*it == 2.0)
{
found2 = true;
}
else if (*it == 3.0)
{
found3 = true;
}
}
EXPECT_EQ(count, 3);
EXPECT_TRUE(found1);
EXPECT_TRUE(found2);
EXPECT_TRUE(found3);
// Test const iterator
count = 0;
found1 = false;
found2 = false;
found3 = false;
for (auto it = aMap.cbegin(); it != aMap.cend(); ++it, ++count)
{
if (*it == 1.0)
{
found1 = true;
}
else if (*it == 2.0)
{
found2 = true;
}
else if (*it == 3.0)
{
found3 = true;
}
}
EXPECT_EQ(count, 3);
EXPECT_TRUE(found1);
EXPECT_TRUE(found2);
EXPECT_TRUE(found3);
}
TEST(NCollection_IndexedDataMapTest, StringKeys)
{
// Test with string keys
NCollection_IndexedDataMap<TCollection_AsciiString, ItemType> aStringMap;
// Add string keys
int index1 = aStringMap.Add(TCollection_AsciiString("First"), 1.0);
int index2 = aStringMap.Add(TCollection_AsciiString("Second"), 2.0);
int index3 = aStringMap.Add(TCollection_AsciiString("Third"), 3.0);
EXPECT_EQ(index1, 1);
EXPECT_EQ(index2, 2);
EXPECT_EQ(index3, 3);
// Find by key
EXPECT_EQ(aStringMap.FindIndex(TCollection_AsciiString("First")), 1);
EXPECT_EQ(aStringMap.FindIndex(TCollection_AsciiString("Second")), 2);
EXPECT_EQ(aStringMap.FindIndex(TCollection_AsciiString("Third")), 3);
// Find by index
EXPECT_TRUE(aStringMap.FindKey(1).IsEqual("First"));
EXPECT_TRUE(aStringMap.FindKey(2).IsEqual("Second"));
EXPECT_TRUE(aStringMap.FindKey(3).IsEqual("Third"));
// Find values
EXPECT_DOUBLE_EQ(aStringMap.FindFromKey(TCollection_AsciiString("First")), 1.0);
EXPECT_DOUBLE_EQ(aStringMap.FindFromKey(TCollection_AsciiString("Second")), 2.0);
EXPECT_DOUBLE_EQ(aStringMap.FindFromKey(TCollection_AsciiString("Third")), 3.0);
}
TEST(NCollection_IndexedDataMapTest, ComplexKeyAndValue)
{
// Create map with custom key and hasher
NCollection_IndexedDataMap<TestKey, TestItem> aComplexMap;
// Add complex keys and values
TestKey key1(1, "One");
TestKey key2(2, "Two");
TestKey key3(3, "Three");
TestItem item1(1.1, "Item One");
TestItem item2(2.2, "Item Two");
TestItem item3(3.3, "Item Three");
int index1 = aComplexMap.Add(key1, item1);
int index2 = aComplexMap.Add(key2, item2);
int index3 = aComplexMap.Add(key3, item3);
EXPECT_EQ(index1, 1);
EXPECT_EQ(index2, 2);
EXPECT_EQ(index3, 3);
// Find by key
EXPECT_EQ(aComplexMap.FindIndex(key1), 1);
EXPECT_EQ(aComplexMap.FindIndex(key2), 2);
EXPECT_EQ(aComplexMap.FindIndex(key3), 3);
// Find by index
EXPECT_EQ(aComplexMap.FindKey(1).GetId(), 1);
EXPECT_EQ(aComplexMap.FindKey(2).GetId(), 2);
EXPECT_EQ(aComplexMap.FindKey(3).GetId(), 3);
// Find values
EXPECT_DOUBLE_EQ(aComplexMap.FindFromKey(key1).GetValue(), 1.1);
EXPECT_DOUBLE_EQ(aComplexMap.FindFromKey(key2).GetValue(), 2.2);
EXPECT_DOUBLE_EQ(aComplexMap.FindFromKey(key3).GetValue(), 3.3);
// Test contains
EXPECT_TRUE(aComplexMap.Contains(TestKey(1, "One")));
EXPECT_FALSE(aComplexMap.Contains(TestKey(4, "Four")));
// Test value modification
aComplexMap.ChangeFromKey(key1).SetValue(1.5);
EXPECT_DOUBLE_EQ(aComplexMap.FindFromKey(key1).GetValue(), 1.5);
}
TEST(NCollection_IndexedDataMapTest, Exchange)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap1;
NCollection_IndexedDataMap<KeyType, ItemType> aMap2;
// Add elements to first map
aMap1.Add(10, 1.0);
aMap1.Add(20, 2.0);
// Add different elements to second map
aMap2.Add(30, 3.0);
aMap2.Add(40, 4.0);
aMap2.Add(50, 5.0);
// Exchange maps
aMap1.Exchange(aMap2);
// Check that maps are exchanged
EXPECT_EQ(aMap1.Extent(), 3);
EXPECT_TRUE(aMap1.Contains(30));
EXPECT_TRUE(aMap1.Contains(40));
EXPECT_TRUE(aMap1.Contains(50));
EXPECT_DOUBLE_EQ(aMap1.FindFromKey(30), 3.0);
EXPECT_DOUBLE_EQ(aMap1.FindFromKey(40), 4.0);
EXPECT_DOUBLE_EQ(aMap1.FindFromKey(50), 5.0);
EXPECT_EQ(aMap2.Extent(), 2);
EXPECT_TRUE(aMap2.Contains(10));
EXPECT_TRUE(aMap2.Contains(20));
EXPECT_DOUBLE_EQ(aMap2.FindFromKey(10), 1.0);
EXPECT_DOUBLE_EQ(aMap2.FindFromKey(20), 2.0);
}
TEST(NCollection_IndexedDataMapTest, ReSize)
{
NCollection_IndexedDataMap<KeyType, ItemType> aMap(3); // Start with small bucket count
// Add many elements to trigger resize
for (int i = 1; i <= 100; ++i)
{
aMap.Add(i, static_cast<double>(i) / 10.0);
}
// Verify all elements are present
EXPECT_EQ(aMap.Extent(), 100);
for (int i = 1; i <= 100; ++i)
{
EXPECT_TRUE(aMap.Contains(i));
EXPECT_EQ(aMap.FindIndex(i), i);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(i), static_cast<double>(i) / 10.0);
}
// Explicitly resize
aMap.ReSize(200);
// Check that elements are still accessible
EXPECT_EQ(aMap.Extent(), 100);
for (int i = 1; i <= 100; ++i)
{
EXPECT_TRUE(aMap.Contains(i));
EXPECT_EQ(aMap.FindIndex(i), i);
EXPECT_DOUBLE_EQ(aMap.FindFromKey(i), static_cast<double>(i) / 10.0);
}
}
TEST(NCollection_IndexedDataMapTest, STLAlgorithmCompatibility_MinMax)
{
NCollection_IndexedDataMap<int, int> aMap;
// Add some sequential values to make results predictable
for (int anIdx = 10; anIdx <= 50; anIdx += 5)
{
aMap.Add(anIdx, anIdx * 2);
}
EXPECT_FALSE(aMap.IsEmpty());
// Test that STL algorithms work with OCCT iterators
auto aMinElement = std::min_element(aMap.cbegin(), aMap.cend());
auto aMaxElement = std::max_element(aMap.cbegin(), aMap.cend());
EXPECT_TRUE(aMinElement != aMap.cend());
EXPECT_TRUE(aMaxElement != aMap.cend());
EXPECT_LE(*aMinElement, *aMaxElement);
}
TEST(NCollection_IndexedDataMapTest, STLAlgorithmCompatibility_Find)
{
NCollection_IndexedDataMap<int, int> aMap;
// Add known values
aMap.Add(100, 200);
aMap.Add(200, 400);
aMap.Add(300, 600);
// Test std::find compatibility
auto aFound = std::find(aMap.cbegin(), aMap.cend(), 200);
EXPECT_TRUE(aFound != aMap.cend());
EXPECT_EQ(*aFound, 200);
// Test finding non-existent value
auto aNotFound = std::find(aMap.cbegin(), aMap.cend(), 999);
EXPECT_TRUE(aNotFound == aMap.cend());
}
TEST(NCollection_IndexedDataMapTest, TryBound_NewKey)
{
NCollection_IndexedDataMap<int, double> aMap;
// TryBound on new key should add and return reference to new item
double& aRef1 = aMap.TryBound(10, 1.0);
EXPECT_DOUBLE_EQ(1.0, aRef1);
EXPECT_DOUBLE_EQ(1.0, aMap.FindFromKey(10));
EXPECT_EQ(1, aMap.Extent());
EXPECT_EQ(1, aMap.FindIndex(10));
// Add another key
double& aRef2 = aMap.TryBound(20, 2.0);
EXPECT_DOUBLE_EQ(2.0, aRef2);
EXPECT_DOUBLE_EQ(2.0, aMap.FindFromKey(20));
EXPECT_EQ(2, aMap.Extent());
EXPECT_EQ(2, aMap.FindIndex(20));
// Modify through reference
aRef1 = 1.5;
EXPECT_DOUBLE_EQ(1.5, aMap.FindFromKey(10));
}
TEST(NCollection_IndexedDataMapTest, TryBound_ExistingKey)
{
NCollection_IndexedDataMap<int, double> aMap;
// First add a key
aMap.Add(10, 1.0);
EXPECT_DOUBLE_EQ(1.0, aMap.FindFromKey(10));
// TryBound on existing key should return reference to existing item (not replace)
double& aRef = aMap.TryBound(10, 999.0);
EXPECT_DOUBLE_EQ(1.0, aRef); // Should be the original value
EXPECT_DOUBLE_EQ(1.0, aMap.FindFromKey(10)); // Map should have original value
EXPECT_EQ(1, aMap.Extent()); // Size should not change
EXPECT_EQ(1, aMap.FindIndex(10)); // Index should be the same
// Modify through reference
aRef = 1.5;
EXPECT_DOUBLE_EQ(1.5, aMap.FindFromKey(10));
}
TEST(NCollection_IndexedDataMapTest, TryBound_MoveSemantics)
{
NCollection_IndexedDataMap<TCollection_AsciiString, double> aMap;
// Test with rvalue key
double& aRef1 = aMap.TryBound(TCollection_AsciiString("Key1"), 1.0);
EXPECT_DOUBLE_EQ(1.0, aRef1);
EXPECT_EQ(1, aMap.Extent());
// Test with existing key - should not replace
double& aRef2 = aMap.TryBound(TCollection_AsciiString("Key1"), 999.0);
EXPECT_DOUBLE_EQ(1.0, aRef2); // Should return original value
EXPECT_EQ(1, aMap.Extent()); // Size should not change
}
TEST(NCollection_IndexedDataMapTest, TryBound_ReferenceValidity)
{
NCollection_IndexedDataMap<int, double> aMap;
// Add multiple keys and verify references point to map contents
double& aRef1 = aMap.TryBound(10, 1.0);
double& aRef2 = aMap.TryBound(20, 2.0);
double& aRef3 = aMap.TryBound(30, 3.0);
// Verify values
EXPECT_DOUBLE_EQ(1.0, aRef1);
EXPECT_DOUBLE_EQ(2.0, aRef2);
EXPECT_DOUBLE_EQ(3.0, aRef3);
// Verify references point to actual map values
EXPECT_EQ(&aRef1, &aMap.ChangeFromIndex(1));
EXPECT_EQ(&aRef2, &aMap.ChangeFromIndex(2));
EXPECT_EQ(&aRef3, &aMap.ChangeFromIndex(3));
}
TEST(NCollection_IndexedDataMapTest, Bind_NewKey)
{
NCollection_IndexedDataMap<int, double> aMap;
// Bind new key should return true
bool isNew1 = aMap.Bind(10, 1.0);
EXPECT_TRUE(isNew1);
EXPECT_DOUBLE_EQ(1.0, aMap.FindFromKey(10));
EXPECT_EQ(1, aMap.Extent());
EXPECT_EQ(1, aMap.FindIndex(10));
// Bind another new key
bool isNew2 = aMap.Bind(20, 2.0);
EXPECT_TRUE(isNew2);
EXPECT_DOUBLE_EQ(2.0, aMap.FindFromKey(20));
EXPECT_EQ(2, aMap.Extent());
EXPECT_EQ(2, aMap.FindIndex(20));
}
TEST(NCollection_IndexedDataMapTest, Bind_ExistingKey)
{
NCollection_IndexedDataMap<int, double> aMap;
// First bind a key
aMap.Bind(10, 1.0);
EXPECT_DOUBLE_EQ(1.0, aMap.FindFromKey(10));
// Bind same key with different value - should overwrite and return false
bool isNew = aMap.Bind(10, 999.0);
EXPECT_FALSE(isNew); // Key already existed
EXPECT_DOUBLE_EQ(999.0, aMap.FindFromKey(10)); // Value should be replaced
EXPECT_EQ(1, aMap.Extent()); // Size should not change
EXPECT_EQ(1, aMap.FindIndex(10)); // Index should be the same
}
TEST(NCollection_IndexedDataMapTest, Bind_MoveSemantics)
{
NCollection_IndexedDataMap<TCollection_AsciiString, double> aMap;
// Test with rvalue key
bool isNew1 = aMap.Bind(TCollection_AsciiString("Key1"), 1.0);
EXPECT_TRUE(isNew1);
EXPECT_EQ(1, aMap.Extent());
EXPECT_DOUBLE_EQ(1.0, aMap.FindFromKey(TCollection_AsciiString("Key1")));
// Test with existing key - should replace
bool isNew2 = aMap.Bind(TCollection_AsciiString("Key1"), 999.0);
EXPECT_FALSE(isNew2); // Key existed
EXPECT_EQ(1, aMap.Extent()); // Size should not change
EXPECT_DOUBLE_EQ(999.0, aMap.FindFromKey(TCollection_AsciiString("Key1"))); // Value replaced
}
TEST(NCollection_IndexedDataMapTest, Bound_NewKey)
{
NCollection_IndexedDataMap<int, double> aMap;
// Bound on new key should add and return pointer to new item
double* pVal1 = aMap.Bound(10, 1.0);
EXPECT_NE(nullptr, pVal1);
EXPECT_DOUBLE_EQ(1.0, *pVal1);
EXPECT_DOUBLE_EQ(1.0, aMap.FindFromKey(10));
EXPECT_EQ(1, aMap.Extent());
EXPECT_EQ(1, aMap.FindIndex(10));
// Add another key
double* pVal2 = aMap.Bound(20, 2.0);
EXPECT_NE(nullptr, pVal2);
EXPECT_DOUBLE_EQ(2.0, *pVal2);
EXPECT_DOUBLE_EQ(2.0, aMap.FindFromKey(20));
EXPECT_EQ(2, aMap.Extent());
EXPECT_EQ(2, aMap.FindIndex(20));
// Modify through pointer
*pVal1 = 1.5;
EXPECT_DOUBLE_EQ(1.5, aMap.FindFromKey(10));
}
TEST(NCollection_IndexedDataMapTest, Bound_ExistingKey)
{
NCollection_IndexedDataMap<int, double> aMap;
// First add a key
aMap.Add(10, 1.0);
EXPECT_DOUBLE_EQ(1.0, aMap.FindFromKey(10));
// Bound on existing key should replace value and return pointer
double* pVal = aMap.Bound(10, 999.0);
EXPECT_NE(nullptr, pVal);
EXPECT_DOUBLE_EQ(999.0, *pVal); // Should be the new value
EXPECT_DOUBLE_EQ(999.0, aMap.FindFromKey(10)); // Map should have new value
EXPECT_EQ(1, aMap.Extent()); // Size should not change
EXPECT_EQ(1, aMap.FindIndex(10)); // Index should be the same
// Modify through pointer
*pVal = 1.5;
EXPECT_DOUBLE_EQ(1.5, aMap.FindFromKey(10));
}
TEST(NCollection_IndexedDataMapTest, Bound_MoveSemantics)
{
NCollection_IndexedDataMap<TCollection_AsciiString, double> aMap;
// Test with rvalue key
double* pVal1 = aMap.Bound(TCollection_AsciiString("Key1"), 1.0);
EXPECT_NE(nullptr, pVal1);
EXPECT_DOUBLE_EQ(1.0, *pVal1);
EXPECT_EQ(1, aMap.Extent());
// Test with existing key - should replace
double* pVal2 = aMap.Bound(TCollection_AsciiString("Key1"), 999.0);
EXPECT_NE(nullptr, pVal2);
EXPECT_DOUBLE_EQ(999.0, *pVal2); // Should return new value
EXPECT_EQ(1, aMap.Extent()); // Size should not change
}
TEST(NCollection_IndexedDataMapTest, Bind_Bound_VsAdd_Behavior)
{
// Test the difference between Add (no overwrite) vs Bind (overwrites)
NCollection_IndexedDataMap<int, double> aMap;
// Add initial value
aMap.Add(10, 1.0);
EXPECT_DOUBLE_EQ(1.0, aMap.FindFromKey(10));
// Add same key - should NOT overwrite
aMap.Add(10, 999.0);
EXPECT_DOUBLE_EQ(1.0, aMap.FindFromKey(10)); // Still 1.0
// Bind same key - SHOULD overwrite
aMap.Bind(10, 2.0);
EXPECT_DOUBLE_EQ(2.0, aMap.FindFromKey(10)); // Now 2.0
// Bound same key - SHOULD overwrite
aMap.Bound(10, 3.0);
EXPECT_DOUBLE_EQ(3.0, aMap.FindFromKey(10)); // Now 3.0
// TryBound same key - should NOT overwrite
aMap.TryBound(10, 999.0);
EXPECT_DOUBLE_EQ(3.0, aMap.FindFromKey(10)); // Still 3.0
}
// Tests for Emplace methods
TEST(NCollection_IndexedDataMapTest, Emplace_NewKey)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
// Emplace with new key should return index
int aIdx = aMap.Emplace(1, "One");
EXPECT_EQ(1, aIdx);
EXPECT_EQ(1, aMap.Extent());
EXPECT_STREQ("One", aMap.FindFromKey(1).ToCString());
}
TEST(NCollection_IndexedDataMapTest, Emplace_ExistingKey)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
aMap.Add(1, "One");
// Emplace on existing key should destroy+reconstruct (return existing index)
int aIdx = aMap.Emplace(1, "New One");
EXPECT_EQ(1, aIdx);
EXPECT_EQ(1, aMap.Extent());
EXPECT_STREQ("New One", aMap.FindFromKey(1).ToCString());
}
TEST(NCollection_IndexedDataMapTest, Emplaced_NewKey)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
// Emplaced with new key should return reference
TCollection_AsciiString& aRef = aMap.Emplaced(1, "One");
EXPECT_STREQ("One", aRef.ToCString());
EXPECT_EQ(1, aMap.Extent());
}
TEST(NCollection_IndexedDataMapTest, Emplaced_ExistingKey)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
aMap.Add(1, "One");
// Emplaced on existing should destroy+reconstruct and return reference
TCollection_AsciiString& aRef = aMap.Emplaced(1, "New One");
EXPECT_STREQ("New One", aRef.ToCString());
}
TEST(NCollection_IndexedDataMapTest, TryEmplace_NewKey)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
// TryEmplace with new key should return index
int aIdx = aMap.TryEmplace(1, "One");
EXPECT_EQ(1, aIdx);
EXPECT_EQ(1, aMap.Extent());
EXPECT_STREQ("One", aMap.FindFromKey(1).ToCString());
}
TEST(NCollection_IndexedDataMapTest, TryEmplace_ExistingKey)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
aMap.Add(1, "One");
// TryEmplace on existing key should NOT modify (return existing index)
int aIdx = aMap.TryEmplace(1, "New One");
EXPECT_EQ(1, aIdx);
EXPECT_EQ(1, aMap.Extent());
EXPECT_STREQ("One", aMap.FindFromKey(1).ToCString()); // Still original
}
TEST(NCollection_IndexedDataMapTest, TryEmplaced_NewKey)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
// TryEmplaced with new key should return reference
TCollection_AsciiString& aRef = aMap.TryEmplaced(1, "One");
EXPECT_STREQ("One", aRef.ToCString());
EXPECT_EQ(1, aMap.Extent());
}
TEST(NCollection_IndexedDataMapTest, TryEmplaced_ExistingKey)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
aMap.Add(1, "One");
// TryEmplaced on existing should return existing without modification
TCollection_AsciiString& aRef = aMap.TryEmplaced(1, "New One");
EXPECT_STREQ("One", aRef.ToCString()); // Original value
}
// Tests for hasher constructor
TEST(NCollection_IndexedDataMapTest, HasherConstructorCopy)
{
// Custom hasher with state
struct StatefulHasher
{
int mySalt;
StatefulHasher(int theSalt = 0)
: mySalt(theSalt)
{
}
size_t operator()(int theKey) const { return std::hash<int>{}(theKey + mySalt); }
bool operator()(int theKey1, int theKey2) const { return theKey1 == theKey2; }
};
StatefulHasher aHasher(42);
NCollection_IndexedDataMap<int, TCollection_AsciiString, StatefulHasher> aMap(aHasher, 10);
aMap.Add(1, "One");
aMap.Add(2, "Two");
EXPECT_EQ(2, aMap.Extent());
EXPECT_STREQ("One", aMap.FindFromIndex(1).ToCString());
EXPECT_STREQ("Two", aMap.FindFromIndex(2).ToCString());
// Verify hasher was copied
const StatefulHasher& aMapHasher = aMap.GetHasher();
EXPECT_EQ(42, aMapHasher.mySalt);
}
TEST(NCollection_IndexedDataMapTest, HasherConstructorMove)
{
struct StatefulHasher
{
int mySalt;
StatefulHasher(int theSalt = 0)
: mySalt(theSalt)
{
}
size_t operator()(int theKey) const { return std::hash<int>{}(theKey + mySalt); }
bool operator()(int theKey1, int theKey2) const { return theKey1 == theKey2; }
};
NCollection_IndexedDataMap<int, TCollection_AsciiString, StatefulHasher> aMap(StatefulHasher(99),
10);
aMap.Add(10, "Ten");
EXPECT_EQ(1, aMap.Extent());
EXPECT_EQ(99, aMap.GetHasher().mySalt);
}
TEST(NCollection_IndexedDataMapTest, CopyConstructorPreservesHasher)
{
struct StatefulHasher
{
int mySalt;
StatefulHasher(int theSalt = 0)
: mySalt(theSalt)
{
}
size_t operator()(int theKey) const { return std::hash<int>{}(theKey + mySalt); }
bool operator()(int theKey1, int theKey2) const { return theKey1 == theKey2; }
};
NCollection_IndexedDataMap<int, TCollection_AsciiString, StatefulHasher> aMap1(
StatefulHasher(123),
10);
aMap1.Add(1, "One");
// Copy construct
NCollection_IndexedDataMap<int, TCollection_AsciiString, StatefulHasher> aMap2(aMap1);
EXPECT_EQ(123, aMap2.GetHasher().mySalt);
EXPECT_EQ(1, aMap2.Extent());
EXPECT_STREQ("One", aMap2.FindFromIndex(1).ToCString());
}
// Tests for Items() key-value pair iteration
TEST(NCollection_IndexedDataMapTest, ItemsIteration)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
aMap.Add(1, "One");
aMap.Add(2, "Two");
aMap.Add(3, "Three");
// Test Items() iteration
std::set<int> aFoundKeys;
std::set<std::string> aFoundValues;
for (auto aKeyValue : aMap.Items())
{
aFoundKeys.insert(aKeyValue.Key);
aFoundValues.insert(aKeyValue.Value.ToCString());
}
EXPECT_EQ(3u, aFoundKeys.size());
EXPECT_TRUE(aFoundKeys.count(1) > 0);
EXPECT_TRUE(aFoundKeys.count(2) > 0);
EXPECT_TRUE(aFoundKeys.count(3) > 0);
EXPECT_EQ(3u, aFoundValues.size());
EXPECT_TRUE(aFoundValues.count("One") > 0);
EXPECT_TRUE(aFoundValues.count("Two") > 0);
EXPECT_TRUE(aFoundValues.count("Three") > 0);
}
TEST(NCollection_IndexedDataMapTest, ItemsStructuredBindings)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
aMap.Add(10, "Ten");
aMap.Add(20, "Twenty");
// Test structured bindings with Items() - key and value only
int aSum = 0;
for (auto [aKey, aValue] : aMap.Items())
{
aSum += aKey;
(void)aValue;
}
EXPECT_EQ(30, aSum);
}
TEST(NCollection_IndexedDataMapTest, ItemsModifyValue)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
aMap.Add(1, "Original");
// Test modifying values through Items()
for (auto [aKey, aValue] : aMap.Items())
{
(void)aKey;
aValue = "Modified";
}
EXPECT_STREQ("Modified", aMap.FindFromIndex(1).ToCString());
}
TEST(NCollection_IndexedDataMapTest, ConstItemsIteration)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
aMap.Add(1, "One");
aMap.Add(2, "Two");
const NCollection_IndexedDataMap<int, TCollection_AsciiString>& aConstMap = aMap;
// Test const Items() iteration
int aCount = 0;
for (const auto& [aKey, aValue] : aConstMap.Items())
{
(void)aKey;
(void)aValue;
++aCount;
}
EXPECT_EQ(2, aCount);
}
TEST(NCollection_IndexedDataMapTest, IndexedItemsIteration)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
aMap.Add(10, "Ten");
aMap.Add(20, "Twenty");
aMap.Add(30, "Thirty");
// Test IndexedItems() with key, value, and index
int aKeySum = 0;
int aIndexSum = 0;
for (auto [aKey, aValue, anIndex] : aMap.IndexedItems())
{
aKeySum += aKey;
aIndexSum += anIndex;
(void)aValue;
}
EXPECT_EQ(60, aKeySum); // 10 + 20 + 30
EXPECT_EQ(6, aIndexSum); // 1 + 2 + 3 (1-based indices)
}
TEST(NCollection_IndexedDataMapTest, ConstIndexedItemsIteration)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
aMap.Add(1, "One");
aMap.Add(2, "Two");
const NCollection_IndexedDataMap<int, TCollection_AsciiString>& aConstMap = aMap;
// Test const IndexedItems() iteration with index
int aIndexSum = 0;
for (const auto& [aKey, aValue, anIndex] : aConstMap.IndexedItems())
{
(void)aKey;
(void)aValue;
aIndexSum += anIndex;
}
EXPECT_EQ(3, aIndexSum); // 1 + 2 = 3
}
TEST(NCollection_IndexedDataMapTest, StandardIteratorContract)
{
using MapType = NCollection_IndexedDataMap<int, TCollection_AsciiString>;
static_assert(std::is_same_v<decltype(std::declval<MapType&>().begin()), MapType::iterator>);
static_assert(
std::is_same_v<decltype(std::declval<const MapType&>().begin()), MapType::const_iterator>);
static_assert(
std::is_same_v<decltype(std::declval<const MapType&>().end()), MapType::const_iterator>);
MapType aMap;
aMap.Add(1, "one");
aMap.Add(2, "two");
const MapType& aConstMap = aMap;
EXPECT_EQ(aMap.begin(), aConstMap.begin());
EXPECT_EQ(aMap.end(), aConstMap.end());
for (auto& aValue : aMap)
{
aValue += "!";
}
EXPECT_STREQ("one!", aMap.FindFromIndex(1).ToCString());
EXPECT_STREQ("two!", aMap.FindFromIndex(2).ToCString());
}
// Test iterator equality for Items() view
TEST(NCollection_IndexedDataMapTest, ItemsIteratorEquality)
{
NCollection_IndexedDataMap<int, TCollection_AsciiString> aMap;
aMap.Add(1, "One");
aMap.Add(2, "Two");
aMap.Add(3, "Three");
auto aView = aMap.Items();
// begin() should equal begin()
EXPECT_EQ(aView.begin(), aView.begin());
// end() should equal end()
EXPECT_EQ(aView.end(), aView.end());
// begin() should not equal end() when map is not empty
EXPECT_NE(aView.begin(), aView.end());
// Two iterators at different positions must NOT be equal
auto anIt1 = aView.begin();
auto anIt2 = aView.begin();
++anIt2;
EXPECT_NE(anIt1, anIt2);
// Iterators at same position should be equal
auto anIt3 = aView.begin();
++anIt3;
EXPECT_EQ(anIt2, anIt3);
}