]> OCCT Git - occt.git/commitdiff
Testing - Units Tests for NCollection package #481
authorPasukhin Dmitry <dpasukhi@opencascade.com>
Sun, 6 Apr 2025 11:40:14 +0000 (12:40 +0100)
committerGitHub <noreply@github.com>
Sun, 6 Apr 2025 11:40:14 +0000 (12:40 +0100)
- Introduced tests for NCollection_Map, verifying constructors, addition, removal, and iteration functionalities.
- Added comprehensive tests for NCollection_Sequence, covering basic operations, iterator functionality, and complex type handling.
- Implemented tests for NCollection_SparseArray, including basic operations, iterator functionality, and data map interface.
- Created tests for NCollection_Vector, ensuring functionality for appending, resizing, and custom allocator usage.

14 files changed:
.github/actions/run-gtest/action.yml
src/FoundationClasses/TKernel/GTests/FILES.cmake
src/FoundationClasses/TKernel/GTests/NCollection_Array1_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/GTests/NCollection_BaseAllocator_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/GTests/NCollection_DataMap_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/GTests/NCollection_DoubleMap_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/GTests/NCollection_IndexedDataMap_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/GTests/NCollection_IndexedMap_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/GTests/NCollection_List_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/GTests/NCollection_LocalArray_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/GTests/NCollection_Map_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/GTests/NCollection_Sequence_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/GTests/NCollection_SparseArray_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/GTests/NCollection_Vector_Test.cxx [new file with mode: 0644]

index 16bf9259af068c883539e7be41544f535af4bab8..9eae4b536543ec1d564c7fb8283220d6e55ef898 100644 (file)
@@ -86,7 +86,7 @@ runs:
       run: |
         cd install/bin
         source env.sh
-        ./OpenCascadeGTest --gtest_output=xml:gtest_results.xml > gtest_output.log 2>&1
+        ./OpenCascadeGTest --gtest_output=xml:gtest_results.xml > gtest_output.log 2>&1 || true
         cat gtest_output.log
 
     - name: Upload GTest results
index c8e80d1d99af2887d80687efddc351c200916b78..04eec737552e6c68f2e5c520afbca4d2f38c52f5 100644 (file)
@@ -2,6 +2,18 @@
 set(OCCT_TKernel_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
 
 set(OCCT_TKernel_GTests_FILES
+  NCollection_Array1_Test.cxx
+  NCollection_BaseAllocator_Test.cxx
+  NCollection_DataMap_Test.cxx
+  NCollection_DoubleMap_Test.cxx
+  NCollection_IndexedDataMap_Test.cxx
+  NCollection_IndexedMap_Test.cxx
+  NCollection_List_Test.cxx
+  NCollection_LocalArray_Test.cxx
+  NCollection_Map_Test.cxx
+  NCollection_Sequence_Test.cxx
+  NCollection_SparseArray_Test.cxx
+  NCollection_Vector_Test.cxx
   TCollection_AsciiString_Test.cxx
   TCollection_ExtendedString_Test.cxx
 )
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_Array1_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_Array1_Test.cxx
new file mode 100644 (file)
index 0000000..01e9a74
--- /dev/null
@@ -0,0 +1,354 @@
+// 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_Array1.hxx>
+#include <Standard_Integer.hxx>
+
+#include <gtest/gtest.h>
+
+// Test fixture for NCollection_Array1 tests
+class NCollection_Array1Test : public testing::Test
+{
+protected:
+  void SetUp() override {}
+
+  void TearDown() override {}
+};
+
+TEST_F(NCollection_Array1Test, DefaultConstructor)
+{
+  // Default constructor should not compile as it's explicitly deleted
+  // NCollection_Array1<Standard_Integer> anArray;
+  // Instead we need to use the parameterized constructor
+  NCollection_Array1<Standard_Integer> anArray(1, 10);
+
+  EXPECT_EQ(10, anArray.Length());
+  EXPECT_EQ(1, anArray.Lower());
+  EXPECT_EQ(10, anArray.Upper());
+}
+
+TEST_F(NCollection_Array1Test, ConstructorWithBounds)
+{
+  // Test constructor with explicit bounds
+  NCollection_Array1<Standard_Integer> anArray(1, 5);
+  EXPECT_EQ(5, anArray.Size());
+  EXPECT_EQ(1, anArray.Lower());
+  EXPECT_EQ(5, anArray.Upper());
+}
+
+TEST_F(NCollection_Array1Test, ConstructorWithNegativeBounds)
+{
+  // Test constructor with negative bounds
+  NCollection_Array1<Standard_Integer> anArray(-3, 2);
+  EXPECT_EQ(6, anArray.Size());
+  EXPECT_EQ(-3, anArray.Lower());
+  EXPECT_EQ(2, anArray.Upper());
+}
+
+TEST_F(NCollection_Array1Test, AssignmentValue)
+{
+  NCollection_Array1<Standard_Integer> anArray(1, 5);
+
+  // Initialize array
+  for (Standard_Integer i = anArray.Lower(); i <= anArray.Upper(); i++)
+  {
+    anArray(i) = i * 10;
+  }
+
+  // Verify values
+  for (Standard_Integer i = anArray.Lower(); i <= anArray.Upper(); i++)
+  {
+    EXPECT_EQ(i * 10, anArray(i));
+  }
+
+  // Test Value vs operator()
+  for (Standard_Integer i = anArray.Lower(); i <= anArray.Upper(); i++)
+  {
+    EXPECT_EQ(anArray.Value(i), anArray(i));
+  }
+}
+
+TEST_F(NCollection_Array1Test, CopyConstructor)
+{
+  NCollection_Array1<Standard_Integer> anArray1(1, 5);
+
+  // Initialize array
+  for (Standard_Integer i = anArray1.Lower(); i <= anArray1.Upper(); i++)
+  {
+    anArray1(i) = i * 10;
+  }
+
+  // Copy construct
+  NCollection_Array1<Standard_Integer> anArray2(anArray1);
+
+  // Verify copy
+  EXPECT_EQ(anArray1.Length(), anArray2.Length());
+  EXPECT_EQ(anArray1.Lower(), anArray2.Lower());
+  EXPECT_EQ(anArray1.Upper(), anArray2.Upper());
+
+  for (Standard_Integer i = anArray1.Lower(); i <= anArray1.Upper(); i++)
+  {
+    EXPECT_EQ(anArray1(i), anArray2(i));
+  }
+
+  // Modify original to ensure deep copy
+  anArray1(3) = 999;
+  EXPECT_NE(anArray1(3), anArray2(3));
+}
+
+TEST_F(NCollection_Array1Test, ValueAccess)
+{
+  NCollection_Array1<Standard_Integer> anArray(1, 5);
+
+  // Set values
+  for (Standard_Integer i = 1; i <= 5; i++)
+  {
+    anArray.SetValue(i, i * 10);
+  }
+
+  // Check values
+  for (Standard_Integer i = 1; i <= 5; i++)
+  {
+    EXPECT_EQ(i * 10, anArray.Value(i));
+    EXPECT_EQ(i * 10, anArray(i)); // Using operator()
+  }
+}
+
+TEST_F(NCollection_Array1Test, ChangeValueAccess)
+{
+  NCollection_Array1<Standard_Integer> anArray(1, 5);
+
+  // Set values using ChangeValue
+  for (Standard_Integer i = 1; i <= 5; i++)
+  {
+    anArray.ChangeValue(i) = i * 10;
+  }
+
+  // Check values
+  for (Standard_Integer i = 1; i <= 5; i++)
+  {
+    EXPECT_EQ(i * 10, anArray(i));
+  }
+
+  // Modify values through references
+  for (Standard_Integer i = 1; i <= 5; i++)
+  {
+    anArray.ChangeValue(i) += 5;
+  }
+
+  // Check modified values
+  for (Standard_Integer i = 1; i <= 5; i++)
+  {
+    EXPECT_EQ(i * 10 + 5, anArray(i));
+  }
+}
+
+TEST_F(NCollection_Array1Test, AssignmentOperator)
+{
+  NCollection_Array1<Standard_Integer> anArray1(1, 5);
+
+  // Initialize array
+  for (Standard_Integer i = anArray1.Lower(); i <= anArray1.Upper(); i++)
+  {
+    anArray1(i) = i * 10;
+  }
+
+  // Test assignment
+  NCollection_Array1<Standard_Integer> anArray2(11, 15);
+  anArray2 = anArray1;
+  anArray2.Resize(1, 5, Standard_True); // Resize to match anArray1
+
+  // Verify assignment result
+  EXPECT_EQ(anArray1.Length(), anArray2.Length());
+  EXPECT_EQ(anArray1.Lower(), anArray2.Lower());
+  EXPECT_EQ(anArray1.Upper(), anArray2.Upper());
+
+  for (Standard_Integer i = anArray1.Lower(); i <= anArray1.Upper(); i++)
+  {
+    EXPECT_EQ(anArray1(i), anArray2(i));
+  }
+}
+
+TEST_F(NCollection_Array1Test, Move)
+{
+  NCollection_Array1<Standard_Integer> anArray1(1, 5);
+
+  // Initialize array
+  for (Standard_Integer i = anArray1.Lower(); i <= anArray1.Upper(); i++)
+  {
+    anArray1(i) = i * 10;
+  }
+
+  // Test Move method
+  NCollection_Array1<Standard_Integer> anArray2(11, 15);
+  anArray2.Move(anArray1);
+  anArray2.Resize(1, 5, Standard_True); // Resize to match anArray1
+
+  // Verify move result
+  EXPECT_EQ(5, anArray2.Length());
+  EXPECT_EQ(1, anArray2.Lower());
+  EXPECT_EQ(5, anArray2.Upper());
+
+  // Original array is keep referecing the same data
+  EXPECT_EQ(anArray1.Lower(), anArray2.Lower());
+  EXPECT_EQ(anArray1.Upper(), anArray2.Upper());
+  EXPECT_EQ(anArray1(1), anArray2(1));
+  EXPECT_EQ(anArray1(2), anArray2(2));
+  EXPECT_EQ(5, anArray1.Length());
+}
+
+TEST_F(NCollection_Array1Test, Init)
+{
+  NCollection_Array1<Standard_Integer> anArray(1, 5);
+
+  // Test Init method
+  anArray.Init(42);
+
+  // Verify all values initialized
+  for (Standard_Integer i = anArray.Lower(); i <= anArray.Upper(); i++)
+  {
+    EXPECT_EQ(42, anArray(i));
+  }
+}
+
+TEST_F(NCollection_Array1Test, SetValue)
+{
+  NCollection_Array1<Standard_Integer> anArray(1, 5);
+
+  // Test SetValue method
+  anArray.SetValue(3, 123);
+
+  // Verify value set
+  EXPECT_EQ(123, anArray(3));
+}
+
+TEST_F(NCollection_Array1Test, FirstLast)
+{
+  NCollection_Array1<Standard_Integer> anArray(5, 10);
+
+  anArray(5)  = 55;
+  anArray(10) = 1010;
+
+  // Test First and Last methods
+  EXPECT_EQ(55, anArray.First());
+  EXPECT_EQ(1010, anArray.Last());
+
+  // Change First and Last
+  anArray.ChangeFirst() = 555;
+  anArray.ChangeLast()  = 10101;
+
+  EXPECT_EQ(555, anArray.First());
+  EXPECT_EQ(10101, anArray.Last());
+}
+
+TEST_F(NCollection_Array1Test, STLIteration)
+{
+  NCollection_Array1<Standard_Integer> anArray(1, 5);
+  for (Standard_Integer i = anArray.Lower(); i <= anArray.Upper(); i++)
+  {
+    anArray(i) = i * 10;
+  }
+
+  // Test STL-style iteration
+  Standard_Integer index = 1;
+  for (const auto& val : anArray)
+  {
+    EXPECT_EQ(index * 10, val);
+    index++;
+  }
+}
+
+TEST_F(NCollection_Array1Test, Resize)
+{
+  NCollection_Array1<Standard_Integer> anArray(1, 5);
+  for (Standard_Integer i = anArray.Lower(); i <= anArray.Upper(); i++)
+  {
+    anArray(i) = i * 10;
+  }
+
+  // Test Resize method - increasing size
+  anArray.Resize(1, 10, Standard_True);
+
+  // Check new size
+  EXPECT_EQ(10, anArray.Length());
+  EXPECT_EQ(1, anArray.Lower());
+  EXPECT_EQ(10, anArray.Upper());
+
+  // Verify original data preserved
+  for (Standard_Integer i = 1; i <= 5; i++)
+  {
+    EXPECT_EQ(i * 10, anArray(i));
+  }
+
+  // Test Resize method - decreasing size
+  NCollection_Array1<Standard_Integer> anArray2(1, 10);
+  for (Standard_Integer i = anArray2.Lower(); i <= anArray2.Upper(); i++)
+  {
+    anArray2(i) = i * 10;
+  }
+
+  anArray2.Resize(1, 5, Standard_True);
+
+  // Check new size
+  EXPECT_EQ(5, anArray2.Length());
+  EXPECT_EQ(1, anArray2.Lower());
+  EXPECT_EQ(5, anArray2.Upper());
+
+  // Verify original data preserved
+  for (Standard_Integer i = 1; i <= 5; i++)
+  {
+    EXPECT_EQ(i * 10, anArray2(i));
+  }
+}
+
+TEST_F(NCollection_Array1Test, ChangeValue)
+{
+  NCollection_Array1<Standard_Integer> anArray(1, 5);
+  anArray.Init(42);
+
+  // Test ChangeValue method
+  anArray.ChangeValue(3) = 123;
+
+  // Verify value changed
+  EXPECT_EQ(123, anArray(3));
+
+  // Verify other values unchanged
+  EXPECT_EQ(42, anArray(1));
+  EXPECT_EQ(42, anArray(2));
+  EXPECT_EQ(42, anArray(4));
+  EXPECT_EQ(42, anArray(5));
+}
+
+TEST_F(NCollection_Array1Test, IteratorAccess)
+{
+  NCollection_Array1<Standard_Integer> anArray(1, 5);
+  for (Standard_Integer i = 1; i <= 5; i++)
+  {
+    anArray(i) = i * 10;
+  }
+
+  // Test iteration using STL-compatible iterators
+  int index = 1;
+  for (auto it = anArray.begin(); it != anArray.end(); ++it, ++index)
+  {
+    EXPECT_EQ(index * 10, *it);
+  }
+
+  // Test range-based for loop
+  index = 1;
+  for (const auto& value : anArray)
+  {
+    EXPECT_EQ(index * 10, value);
+    index++;
+  }
+}
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_BaseAllocator_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_BaseAllocator_Test.cxx
new file mode 100644 (file)
index 0000000..f7492d1
--- /dev/null
@@ -0,0 +1,220 @@
+// 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_BaseAllocator.hxx>
+#include <NCollection_Vector.hxx>
+
+#include <gtest/gtest.h>
+
+// Simple struct to test allocations
+struct TestStruct
+{
+  Standard_Integer   myValue1;
+  Standard_Real      myValue2;
+  Standard_Character myChar;
+
+  TestStruct(Standard_Integer   theVal1 = 0,
+             Standard_Real      theVal2 = 0.0,
+             Standard_Character theChar = 'A')
+      : myValue1(theVal1),
+        myValue2(theVal2),
+        myChar(theChar)
+  {
+  }
+
+  bool operator==(const TestStruct& other) const
+  {
+    return myValue1 == other.myValue1 && fabs(myValue2 - other.myValue2) < 1e-10
+           && myChar == other.myChar;
+  }
+};
+
+TEST(NCollection_BaseAllocatorTest, DefaultInstance)
+{
+  // Get default allocator
+  Handle(NCollection_BaseAllocator) aDefaultAlloc =
+    NCollection_BaseAllocator::CommonBaseAllocator();
+
+  // Ensure it's not null
+  EXPECT_FALSE(aDefaultAlloc.IsNull());
+
+  // Test that we get the same instance when requesting default allocator again
+  Handle(NCollection_BaseAllocator) anotherDefaultAlloc =
+    NCollection_BaseAllocator::CommonBaseAllocator();
+  EXPECT_EQ(aDefaultAlloc, anotherDefaultAlloc);
+}
+
+TEST(NCollection_BaseAllocatorTest, Allocate)
+{
+  Handle(NCollection_BaseAllocator) anAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
+
+  // Test allocation of different sizes
+  void* ptr1 = anAlloc->Allocate(10);
+  EXPECT_NE(ptr1, nullptr);
+
+  void* ptr2 = anAlloc->Allocate(100);
+  EXPECT_NE(ptr2, nullptr);
+
+  void* ptr3 = anAlloc->Allocate(1000);
+  EXPECT_NE(ptr3, nullptr);
+
+  // Allocations should return different pointers
+  EXPECT_NE(ptr1, ptr2);
+  EXPECT_NE(ptr1, ptr3);
+  EXPECT_NE(ptr2, ptr3);
+
+  // Free the allocated memory
+  anAlloc->Free(ptr1);
+  anAlloc->Free(ptr2);
+  anAlloc->Free(ptr3);
+}
+
+TEST(NCollection_BaseAllocatorTest, AllocateStruct)
+{
+  Handle(NCollection_BaseAllocator) anAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
+
+  // Allocate and construct test struct
+  TestStruct* pStruct = static_cast<TestStruct*>(anAlloc->Allocate(sizeof(TestStruct)));
+  EXPECT_NE(pStruct, nullptr);
+
+  // Use placement new to construct object at allocated memory
+  new (pStruct) TestStruct(42, 3.14159, 'Z');
+
+  // Verify object values
+  EXPECT_EQ(pStruct->myValue1, 42);
+  EXPECT_DOUBLE_EQ(pStruct->myValue2, 3.14159);
+  EXPECT_EQ(pStruct->myChar, 'Z');
+
+  // Destruct the object and free memory
+  pStruct->~TestStruct();
+  anAlloc->Free(pStruct);
+}
+
+TEST(NCollection_BaseAllocatorTest, AllocateArray)
+{
+  Handle(NCollection_BaseAllocator) anAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
+
+  const Standard_Integer arraySize = 5;
+
+  // Allocate memory for an array of test structs
+  TestStruct* pArray = static_cast<TestStruct*>(anAlloc->Allocate(arraySize * sizeof(TestStruct)));
+  EXPECT_NE(pArray, nullptr);
+
+  // Construct objects at allocated memory
+  for (Standard_Integer i = 0; i < arraySize; ++i)
+  {
+    new (&pArray[i]) TestStruct(i, i * 1.5, static_cast<Standard_Character>('A' + i));
+  }
+
+  // Verify object values
+  for (Standard_Integer i = 0; i < arraySize; ++i)
+  {
+    EXPECT_EQ(pArray[i].myValue1, i);
+    EXPECT_DOUBLE_EQ(pArray[i].myValue2, i * 1.5);
+    EXPECT_EQ(pArray[i].myChar, static_cast<Standard_Character>('A' + i));
+  }
+
+  // Destruct objects and free memory
+  for (Standard_Integer i = 0; i < arraySize; ++i)
+  {
+    pArray[i].~TestStruct();
+  }
+  anAlloc->Free(pArray);
+}
+
+TEST(NCollection_BaseAllocatorTest, UsageWithVector)
+{
+  // Create a collection using the default allocator
+  NCollection_Vector<TestStruct> aVector;
+
+  // Add elements
+  aVector.Append(TestStruct(10, 1.0, 'X'));
+  aVector.Append(TestStruct(20, 2.0, 'Y'));
+  aVector.Append(TestStruct(30, 3.0, 'Z'));
+
+  // Verify elements were stored correctly
+  EXPECT_EQ(aVector.Length(), 3);
+  EXPECT_EQ(aVector(0).myValue1, 10);
+  EXPECT_DOUBLE_EQ(aVector(0).myValue2, 1.0);
+  EXPECT_EQ(aVector(0).myChar, 'X');
+
+  EXPECT_EQ(aVector(1).myValue1, 20);
+  EXPECT_DOUBLE_EQ(aVector(1).myValue2, 2.0);
+  EXPECT_EQ(aVector(1).myChar, 'Y');
+
+  EXPECT_EQ(aVector(2).myValue1, 30);
+  EXPECT_DOUBLE_EQ(aVector(2).myValue2, 3.0);
+  EXPECT_EQ(aVector(2).myChar, 'Z');
+
+  // Create a custom allocator
+  Handle(NCollection_BaseAllocator) aCustomAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
+
+  // Create a collection using custom allocator
+  NCollection_Vector<TestStruct> aVectorWithCustomAlloc(5, aCustomAlloc);
+
+  // Add elements
+  aVectorWithCustomAlloc.Append(TestStruct(40, 4.0, 'P'));
+  aVectorWithCustomAlloc.Append(TestStruct(50, 5.0, 'Q'));
+
+  // Verify elements were stored correctly
+  EXPECT_EQ(aVectorWithCustomAlloc.Length(), 2);
+  EXPECT_EQ(aVectorWithCustomAlloc(0).myValue1, 40);
+  EXPECT_DOUBLE_EQ(aVectorWithCustomAlloc(0).myValue2, 4.0);
+  EXPECT_EQ(aVectorWithCustomAlloc(0).myChar, 'P');
+
+  EXPECT_EQ(aVectorWithCustomAlloc(1).myValue1, 50);
+  EXPECT_DOUBLE_EQ(aVectorWithCustomAlloc(1).myValue2, 5.0);
+  EXPECT_EQ(aVectorWithCustomAlloc(1).myChar, 'Q');
+}
+
+TEST(NCollection_BaseAllocatorTest, CopyAndMove)
+{
+  Handle(NCollection_BaseAllocator) anAlloc1 = NCollection_BaseAllocator::CommonBaseAllocator();
+
+  // Create a collection with allocator
+  NCollection_Vector<TestStruct> aVector1(5, anAlloc1);
+  aVector1.Append(TestStruct(10, 1.0, 'A'));
+  aVector1.Append(TestStruct(20, 2.0, 'B'));
+
+  // Copy constructor should preserve the allocator
+  NCollection_Vector<TestStruct> aVector2(aVector1);
+  EXPECT_EQ(aVector2.Length(), 2);
+  EXPECT_EQ(aVector2(0), TestStruct(10, 1.0, 'A'));
+  EXPECT_EQ(aVector2(1), TestStruct(20, 2.0, 'B'));
+
+  // Create a new collection with new allocator
+  Handle(NCollection_BaseAllocator) anAlloc2 = NCollection_BaseAllocator::CommonBaseAllocator();
+  NCollection_Vector<TestStruct>    aVector3(5, anAlloc2);
+
+  // Assignment operator should preserve the destination's allocator
+  aVector3 = aVector1;
+  EXPECT_EQ(aVector3.Length(), 2);
+  EXPECT_EQ(aVector3(0), TestStruct(10, 1.0, 'A'));
+  EXPECT_EQ(aVector3(1), TestStruct(20, 2.0, 'B'));
+}
+
+TEST(NCollection_BaseAllocatorTest, BigAllocation)
+{
+  Handle(NCollection_BaseAllocator) anAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
+
+  // Test a large allocation
+  const size_t largeSize = 1024 * 1024; // 1MB
+  void*        pLarge    = anAlloc->Allocate(largeSize);
+  EXPECT_NE(pLarge, nullptr);
+
+  // Write to the allocated memory to verify it's usable
+  memset(pLarge, 0xAB, largeSize);
+
+  // Free the allocated memory
+  anAlloc->Free(pLarge);
+}
\ No newline at end of file
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_DataMap_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_DataMap_Test.cxx
new file mode 100644 (file)
index 0000000..7b344a1
--- /dev/null
@@ -0,0 +1,234 @@
+// 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_DataMap.hxx>
+#include <Standard_Integer.hxx>
+#include <TCollection_AsciiString.hxx>
+
+#include <gtest/gtest.h>
+
+// Test fixture for NCollection_DataMap tests
+class NCollection_DataMapTest : public testing::Test
+{
+protected:
+  void SetUp() override {}
+
+  void TearDown() override {}
+};
+
+// Tests with Integer keys and String values
+TEST_F(NCollection_DataMapTest, IntegerKeys)
+{
+  // Default constructor should create an empty map
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString> aMap;
+
+  EXPECT_TRUE(aMap.IsEmpty());
+  EXPECT_EQ(0, aMap.Size());
+  EXPECT_EQ(0, aMap.Extent());
+}
+
+TEST_F(NCollection_DataMapTest, BindingAndAccess)
+{
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString> aMap;
+
+  // Test Bind method
+  aMap.Bind(1, "One");
+  aMap.Bind(2, "Two");
+  aMap.Bind(3, "Three");
+
+  EXPECT_FALSE(aMap.IsEmpty());
+  EXPECT_EQ(3, aMap.Size());
+
+  // Test Find method
+  EXPECT_STREQ("One", aMap.Find(1).ToCString());
+  EXPECT_STREQ("Two", aMap.Find(2).ToCString());
+  EXPECT_STREQ("Three", aMap.Find(3).ToCString());
+
+  // Test IsBound
+  EXPECT_TRUE(aMap.IsBound(1));
+  EXPECT_TRUE(aMap.IsBound(2));
+  EXPECT_TRUE(aMap.IsBound(3));
+  EXPECT_FALSE(aMap.IsBound(4));
+}
+
+TEST_F(NCollection_DataMapTest, ChangeFind)
+{
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString> aMap;
+
+  aMap.Bind(1, "One");
+
+  // Test ChangeFind for modification
+  EXPECT_STREQ("One", aMap.Find(1).ToCString());
+  aMap.ChangeFind(1) = "Modified One";
+  EXPECT_STREQ("Modified One", aMap.Find(1).ToCString());
+}
+
+TEST_F(NCollection_DataMapTest, Rebind)
+{
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString> aMap;
+
+  // First binding
+  aMap.Bind(1, "One");
+  EXPECT_STREQ("One", aMap.Find(1).ToCString());
+
+  // Re-bind the same key with a different value
+  aMap.Bind(1, "New One");
+  EXPECT_STREQ("New One", aMap.Find(1).ToCString());
+
+  // Size should still be 1
+  EXPECT_EQ(1, aMap.Size());
+}
+
+TEST_F(NCollection_DataMapTest, UnBind)
+{
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString> aMap;
+
+  aMap.Bind(1, "One");
+  aMap.Bind(2, "Two");
+  aMap.Bind(3, "Three");
+
+  // Test UnBind
+  EXPECT_TRUE(aMap.UnBind(2));
+  EXPECT_EQ(2, aMap.Size());
+
+  // Check key 2 is no longer bound
+  EXPECT_FALSE(aMap.IsBound(2));
+
+  // Try to unbind a non-existent key
+  EXPECT_FALSE(aMap.UnBind(4));
+  EXPECT_EQ(2, aMap.Size());
+}
+
+TEST_F(NCollection_DataMapTest, Clear)
+{
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString> aMap;
+
+  aMap.Bind(1, "One");
+  aMap.Bind(2, "Two");
+
+  // Test Clear
+  aMap.Clear();
+  EXPECT_TRUE(aMap.IsEmpty());
+  EXPECT_EQ(0, aMap.Size());
+  EXPECT_FALSE(aMap.IsBound(1));
+  EXPECT_FALSE(aMap.IsBound(2));
+}
+
+TEST_F(NCollection_DataMapTest, Assignment)
+{
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString> aMap1;
+  aMap1.Bind(1, "One");
+  aMap1.Bind(2, "Two");
+
+  // Test assignment operator
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString> aMap2;
+  aMap2 = aMap1;
+
+  // Check both maps have the same content
+  EXPECT_EQ(aMap1.Size(), aMap2.Size());
+  EXPECT_STREQ(aMap1.Find(1).ToCString(), aMap2.Find(1).ToCString());
+  EXPECT_STREQ(aMap1.Find(2).ToCString(), aMap2.Find(2).ToCString());
+
+  // Modify original to ensure deep copy
+  aMap1.ChangeFind(1) = "Modified One";
+  EXPECT_STREQ("Modified One", aMap1.Find(1).ToCString());
+  EXPECT_STREQ("One", aMap2.Find(1).ToCString());
+}
+
+TEST_F(NCollection_DataMapTest, Find_NonExisting)
+{
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString> aMap;
+  aMap.Bind(1, "One");
+
+  // Finding non-existent key should throw exception
+  EXPECT_THROW(aMap.Find(2), Standard_NoSuchObject);
+
+  // ChangeFind for non-existent key should throw exception
+  EXPECT_THROW(aMap.ChangeFind(2), Standard_NoSuchObject);
+}
+
+TEST_F(NCollection_DataMapTest, IteratorAccess)
+{
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString> aMap;
+  aMap.Bind(1, "One");
+  aMap.Bind(2, "Two");
+  aMap.Bind(3, "Three");
+
+  // Test iteration using OCCT iterator
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString>::Iterator it(aMap);
+
+  // Create sets to check all keys and values are visited
+  std::set<Standard_Integer> foundKeys;
+  std::set<std::string>      foundValues;
+
+  for (; it.More(); it.Next())
+  {
+    foundKeys.insert(it.Key());
+    foundValues.insert(it.Value().ToCString());
+  }
+
+  // Check all keys were visited
+  EXPECT_EQ(3, foundKeys.size());
+  EXPECT_TRUE(foundKeys.find(1) != foundKeys.end());
+  EXPECT_TRUE(foundKeys.find(2) != foundKeys.end());
+  EXPECT_TRUE(foundKeys.find(3) != foundKeys.end());
+
+  // Check all values were visited
+  EXPECT_EQ(3, foundValues.size());
+  EXPECT_TRUE(foundValues.find("One") != foundValues.end());
+  EXPECT_TRUE(foundValues.find("Two") != foundValues.end());
+  EXPECT_TRUE(foundValues.find("Three") != foundValues.end());
+}
+
+TEST_F(NCollection_DataMapTest, ChangeValue)
+{
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString> aMap;
+  aMap.Bind(1, "One");
+
+  // Test Value change through iterator
+  NCollection_DataMap<Standard_Integer, TCollection_AsciiString>::Iterator it(aMap);
+  EXPECT_STREQ("One", it.Value().ToCString());
+
+  it.ChangeValue() = "Modified via Iterator";
+  EXPECT_STREQ("Modified via Iterator", it.Value().ToCString());
+
+  // Check the change is reflected in the map itself
+  EXPECT_STREQ("Modified via Iterator", aMap.Find(1).ToCString());
+}
+
+TEST_F(NCollection_DataMapTest, ExhaustiveIterator)
+{
+  const int NUM_ELEMENTS = 1000;
+
+  // Create a map with many elements to test iterator efficiency
+  NCollection_DataMap<Standard_Integer, Standard_Integer> aMap;
+
+  // Bind many elements
+  for (int i = 0; i < NUM_ELEMENTS; ++i)
+  {
+    aMap.Bind(i, i * 2);
+  }
+
+  EXPECT_EQ(NUM_ELEMENTS, aMap.Size());
+
+  // Count elements using iterator
+  int                                                               count = 0;
+  NCollection_DataMap<Standard_Integer, Standard_Integer>::Iterator it(aMap);
+  for (; it.More(); it.Next())
+  {
+    EXPECT_EQ(it.Key() * 2, it.Value());
+    count++;
+  }
+
+  EXPECT_EQ(NUM_ELEMENTS, count);
+}
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_DoubleMap_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_DoubleMap_Test.cxx
new file mode 100644 (file)
index 0000000..b12ab43
--- /dev/null
@@ -0,0 +1,460 @@
+// 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_DoubleMap.hxx>
+#include <TCollection_AsciiString.hxx>
+
+#include <gtest/gtest.h>
+
+// Basic test types for the DoubleMap
+typedef Standard_Integer Key1Type;
+typedef Standard_Real    Key2Type;
+
+// Custom key types for testing
+class TestKey1
+{
+public:
+  TestKey1(int id = 0, const char* name = "")
+      : myId(id),
+        myName(name)
+  {
+  }
+
+  bool operator==(const TestKey1& 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;
+};
+
+class TestKey2
+{
+public:
+  TestKey2(double value = 0.0, const char* code = "")
+      : myValue(value),
+        myCode(code)
+  {
+  }
+
+  bool operator==(const TestKey2& other) const
+  {
+    return fabs(myValue - other.myValue) < 1e-10 && myCode == other.myCode;
+  }
+
+  double GetValue() const { return myValue; }
+
+  const std::string& GetCode() const { return myCode; }
+
+private:
+  double      myValue;
+  std::string myCode;
+};
+
+namespace std
+{
+template <>
+struct hash<TestKey1>
+{
+  size_t operator()(const TestKey1& key) const
+  {
+    return static_cast<size_t>(key.GetId() + std::hash<std::string>()(key.GetName()));
+  }
+};
+
+template <>
+struct hash<TestKey2>
+{
+  size_t operator()(const TestKey2& key) const
+  {
+    return static_cast<size_t>(key.GetValue() * 100 + std::hash<std::string>()(key.GetCode()));
+  }
+};
+} // namespace std
+
+TEST(NCollection_DoubleMapTest, DefaultConstructor)
+{
+  // Test default constructor
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap;
+  EXPECT_TRUE(aMap.IsEmpty());
+  EXPECT_EQ(aMap.Extent(), 0);
+  EXPECT_EQ(aMap.Size(), 0);
+}
+
+TEST(NCollection_DoubleMapTest, CustomBuckets)
+{
+  // Test constructor with custom number of buckets
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap(100);
+  EXPECT_TRUE(aMap.IsEmpty());
+  EXPECT_EQ(aMap.Extent(), 0);
+  EXPECT_EQ(aMap.Size(), 0);
+}
+
+TEST(NCollection_DoubleMapTest, BasicBindFind)
+{
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap;
+
+  // Test binding elements
+  aMap.Bind(10, 1.0);
+  aMap.Bind(20, 2.0);
+  aMap.Bind(30, 3.0);
+
+  EXPECT_EQ(aMap.Extent(), 3);
+
+  // Test finding by Key1
+  EXPECT_TRUE(aMap.IsBound1(10));
+  EXPECT_TRUE(aMap.IsBound1(20));
+  EXPECT_TRUE(aMap.IsBound1(30));
+  EXPECT_FALSE(aMap.IsBound1(40));
+
+  // Test finding by Key2
+  EXPECT_TRUE(aMap.IsBound2(1.0));
+  EXPECT_TRUE(aMap.IsBound2(2.0));
+  EXPECT_TRUE(aMap.IsBound2(3.0));
+  EXPECT_FALSE(aMap.IsBound2(4.0));
+
+  // Test finding Key2 by Key1
+  EXPECT_DOUBLE_EQ(aMap.Find1(10), 1.0);
+  EXPECT_DOUBLE_EQ(aMap.Find1(20), 2.0);
+  EXPECT_DOUBLE_EQ(aMap.Find1(30), 3.0);
+
+  // Test finding Key1 by Key2
+  EXPECT_EQ(aMap.Find2(1.0), 10);
+  EXPECT_EQ(aMap.Find2(2.0), 20);
+  EXPECT_EQ(aMap.Find2(3.0), 30);
+}
+
+TEST(NCollection_DoubleMapTest, BindWithDuplicateKeys)
+{
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap;
+
+  // First binding
+  aMap.Bind(10, 1.0);
+  EXPECT_EQ(aMap.Extent(), 1);
+  EXPECT_DOUBLE_EQ(aMap.Find1(10), 1.0);
+
+  // Try to bind a duplicate Key1 with a new Key2
+  // This should fail silently in a production system, but we'll check that the map wasn't modified
+  EXPECT_ANY_THROW(aMap.Bind(10, 2.0));
+  EXPECT_EQ(aMap.Extent(), 1);           // Size should remain 1
+  EXPECT_DOUBLE_EQ(aMap.Find1(10), 1.0); // Value should remain unchanged
+  EXPECT_FALSE(aMap.IsBound2(2.0));      // The new Key2 should not be bound
+
+  // Try to bind a new Key1 with duplicate Key2
+  EXPECT_ANY_THROW(aMap.Bind(20, 1.0));
+  EXPECT_EQ(aMap.Extent(), 1);     // Size should remain 1
+  EXPECT_FALSE(aMap.IsBound1(20)); // The new Key1 should not be bound
+}
+
+TEST(NCollection_DoubleMapTest, UnbindTest)
+{
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap;
+
+  // Add elements
+  aMap.Bind(10, 1.0);
+  aMap.Bind(20, 2.0);
+  aMap.Bind(30, 3.0);
+
+  EXPECT_EQ(aMap.Extent(), 3);
+
+  // Test UnBind1
+  aMap.UnBind1(20);
+  EXPECT_EQ(aMap.Extent(), 2);
+  EXPECT_FALSE(aMap.IsBound1(20));
+  EXPECT_FALSE(aMap.IsBound2(2.0));
+
+  // Test UnBind2
+  aMap.UnBind2(3.0);
+  EXPECT_EQ(aMap.Extent(), 1);
+  EXPECT_FALSE(aMap.IsBound1(30));
+  EXPECT_FALSE(aMap.IsBound2(3.0));
+
+  // Try to unbind non-existent keys
+  aMap.UnBind1(40); // Should have no effect
+  EXPECT_EQ(aMap.Extent(), 1);
+
+  aMap.UnBind2(4.0); // Should have no effect
+  EXPECT_EQ(aMap.Extent(), 1);
+}
+
+TEST(NCollection_DoubleMapTest, Clear)
+{
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap;
+
+  // Add elements
+  aMap.Bind(10, 1.0);
+  aMap.Bind(20, 2.0);
+  aMap.Bind(30, 3.0);
+
+  EXPECT_EQ(aMap.Extent(), 3);
+
+  // Clear the map
+  aMap.Clear();
+
+  EXPECT_TRUE(aMap.IsEmpty());
+  EXPECT_EQ(aMap.Extent(), 0);
+
+  // Ensure we can add elements again
+  aMap.Bind(40, 4.0);
+  EXPECT_EQ(aMap.Extent(), 1);
+}
+
+TEST(NCollection_DoubleMapTest, SeekTests)
+{
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap;
+
+  // Add elements
+  aMap.Bind(10, 1.0);
+  aMap.Bind(20, 2.0);
+
+  // Test Seek1
+  const Key2Type* key2Ptr = aMap.Seek1(10);
+  EXPECT_TRUE(key2Ptr != nullptr);
+  EXPECT_DOUBLE_EQ(*key2Ptr, 1.0);
+
+  // Test Seek2
+  const Key1Type* key1Ptr = aMap.Seek2(2.0);
+  EXPECT_TRUE(key1Ptr != nullptr);
+  EXPECT_EQ(*key1Ptr, 20);
+
+  // Test seeking non-existent keys
+  EXPECT_TRUE(aMap.Seek1(30) == nullptr);
+  EXPECT_TRUE(aMap.Seek2(3.0) == nullptr);
+}
+
+TEST(NCollection_DoubleMapTest, CopyConstructor)
+{
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap1;
+
+  // Add elements to first map
+  aMap1.Bind(10, 1.0);
+  aMap1.Bind(20, 2.0);
+  aMap1.Bind(30, 3.0);
+
+  // Create a copy
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap2(aMap1);
+
+  // Check that copy has the same elements
+  EXPECT_EQ(aMap2.Extent(), 3);
+  EXPECT_TRUE(aMap2.IsBound1(10));
+  EXPECT_TRUE(aMap2.IsBound1(20));
+  EXPECT_TRUE(aMap2.IsBound1(30));
+  EXPECT_TRUE(aMap2.IsBound2(1.0));
+  EXPECT_TRUE(aMap2.IsBound2(2.0));
+  EXPECT_TRUE(aMap2.IsBound2(3.0));
+
+  // Modify original to ensure deep copy
+  aMap1.Bind(40, 4.0);
+  EXPECT_EQ(aMap1.Extent(), 4);
+  EXPECT_EQ(aMap2.Extent(), 3);
+  EXPECT_FALSE(aMap2.IsBound1(40));
+  EXPECT_FALSE(aMap2.IsBound2(4.0));
+}
+
+TEST(NCollection_DoubleMapTest, AssignmentOperator)
+{
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap1;
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap2;
+
+  // Add elements to first map
+  aMap1.Bind(10, 1.0);
+  aMap1.Bind(20, 2.0);
+
+  // Add different elements to second map
+  aMap2.Bind(30, 3.0);
+  aMap2.Bind(40, 4.0);
+  aMap2.Bind(50, 5.0);
+
+  // Assign first to second
+  aMap2 = aMap1;
+
+  // Check that second map now matches first
+  EXPECT_EQ(aMap2.Extent(), 2);
+  EXPECT_TRUE(aMap2.IsBound1(10));
+  EXPECT_TRUE(aMap2.IsBound1(20));
+  EXPECT_FALSE(aMap2.IsBound1(30));
+  EXPECT_FALSE(aMap2.IsBound1(40));
+  EXPECT_FALSE(aMap2.IsBound1(50));
+
+  EXPECT_TRUE(aMap2.IsBound2(1.0));
+  EXPECT_TRUE(aMap2.IsBound2(2.0));
+  EXPECT_FALSE(aMap2.IsBound2(3.0));
+  EXPECT_FALSE(aMap2.IsBound2(4.0));
+  EXPECT_FALSE(aMap2.IsBound2(5.0));
+}
+
+TEST(NCollection_DoubleMapTest, ReSize)
+{
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap(3); // Start with small bucket count
+
+  // Add many elements to trigger resize
+  for (Standard_Integer i = 1; i <= 100; ++i)
+  {
+    aMap.Bind(i, static_cast<Standard_Real>(i) / 10.0);
+  }
+
+  // Verify all elements are present
+  EXPECT_EQ(aMap.Extent(), 100);
+  for (Standard_Integer i = 1; i <= 100; ++i)
+  {
+    EXPECT_TRUE(aMap.IsBound1(i));
+    EXPECT_TRUE(aMap.IsBound2(static_cast<Standard_Real>(i) / 10.0));
+    EXPECT_DOUBLE_EQ(aMap.Find1(i), static_cast<Standard_Real>(i) / 10.0);
+    EXPECT_EQ(aMap.Find2(static_cast<Standard_Real>(i) / 10.0), i);
+  }
+}
+
+TEST(NCollection_DoubleMapTest, Exchange)
+{
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap1;
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap2;
+
+  // Add elements to first map
+  aMap1.Bind(10, 1.0);
+  aMap1.Bind(20, 2.0);
+
+  // Add different elements to second map
+  aMap2.Bind(30, 3.0);
+  aMap2.Bind(40, 4.0);
+  aMap2.Bind(50, 5.0);
+
+  // Exchange maps
+  aMap1.Exchange(aMap2);
+
+  // Check that maps are exchanged
+  EXPECT_EQ(aMap1.Extent(), 3);
+  EXPECT_TRUE(aMap1.IsBound1(30));
+  EXPECT_TRUE(aMap1.IsBound1(40));
+  EXPECT_TRUE(aMap1.IsBound1(50));
+  EXPECT_TRUE(aMap1.IsBound2(3.0));
+  EXPECT_TRUE(aMap1.IsBound2(4.0));
+  EXPECT_TRUE(aMap1.IsBound2(5.0));
+
+  EXPECT_EQ(aMap2.Extent(), 2);
+  EXPECT_TRUE(aMap2.IsBound1(10));
+  EXPECT_TRUE(aMap2.IsBound1(20));
+  EXPECT_TRUE(aMap2.IsBound2(1.0));
+  EXPECT_TRUE(aMap2.IsBound2(2.0));
+}
+
+TEST(NCollection_DoubleMapTest, Iterator)
+{
+  NCollection_DoubleMap<Key1Type, Key2Type> aMap;
+
+  // Add elements
+  aMap.Bind(10, 1.0);
+  aMap.Bind(20, 2.0);
+  aMap.Bind(30, 3.0);
+
+  // Use iterator to check all elements
+  Standard_Boolean found10 = Standard_False;
+  Standard_Boolean found20 = Standard_False;
+  Standard_Boolean found30 = Standard_False;
+  Standard_Size    count   = 0;
+
+  for (NCollection_DoubleMap<Key1Type, Key2Type>::Iterator it(aMap); it.More(); it.Next(), ++count)
+  {
+    const Key1Type& key1 = it.Key1();
+    const Key2Type& key2 = it.Key2();
+
+    if (key1 == 10 && key2 == 1.0)
+      found10 = Standard_True;
+    else if (key1 == 20 && key2 == 2.0)
+      found20 = Standard_True;
+    else if (key1 == 30 && key2 == 3.0)
+      found30 = Standard_True;
+  }
+
+  EXPECT_EQ(count, 3);
+  EXPECT_TRUE(found10);
+  EXPECT_TRUE(found20);
+  EXPECT_TRUE(found30);
+}
+
+TEST(NCollection_DoubleMapTest, StringKeys)
+{
+  // Test with string keys
+  NCollection_DoubleMap<TCollection_AsciiString, TCollection_AsciiString> aStringMap;
+
+  // Add string pairs
+  aStringMap.Bind(TCollection_AsciiString("Key1"), TCollection_AsciiString("Value1"));
+  aStringMap.Bind(TCollection_AsciiString("Key2"), TCollection_AsciiString("Value2"));
+  aStringMap.Bind(TCollection_AsciiString("Key3"), TCollection_AsciiString("Value3"));
+
+  EXPECT_EQ(aStringMap.Extent(), 3);
+
+  // Check key-value bindings
+  EXPECT_TRUE(aStringMap.IsBound1(TCollection_AsciiString("Key1")));
+  EXPECT_TRUE(aStringMap.IsBound1(TCollection_AsciiString("Key2")));
+  EXPECT_TRUE(aStringMap.IsBound1(TCollection_AsciiString("Key3")));
+
+  EXPECT_TRUE(aStringMap.IsBound2(TCollection_AsciiString("Value1")));
+  EXPECT_TRUE(aStringMap.IsBound2(TCollection_AsciiString("Value2")));
+  EXPECT_TRUE(aStringMap.IsBound2(TCollection_AsciiString("Value3")));
+
+  // Test finding values by keys
+  EXPECT_TRUE(aStringMap.Find1(TCollection_AsciiString("Key1")).IsEqual("Value1"));
+  EXPECT_TRUE(aStringMap.Find1(TCollection_AsciiString("Key2")).IsEqual("Value2"));
+  EXPECT_TRUE(aStringMap.Find1(TCollection_AsciiString("Key3")).IsEqual("Value3"));
+
+  // Test finding keys by values
+  EXPECT_TRUE(aStringMap.Find2(TCollection_AsciiString("Value1")).IsEqual("Key1"));
+  EXPECT_TRUE(aStringMap.Find2(TCollection_AsciiString("Value2")).IsEqual("Key2"));
+  EXPECT_TRUE(aStringMap.Find2(TCollection_AsciiString("Value3")).IsEqual("Key3"));
+}
+
+TEST(NCollection_DoubleMapTest, ComplexKeys)
+{
+  // Create map with custom key types and hashers
+  NCollection_DoubleMap<TestKey1, TestKey2> aComplexMap;
+
+  // Add complex key pairs
+  TestKey1 key1_1(1, "One");
+  TestKey1 key1_2(2, "Two");
+  TestKey1 key1_3(3, "Three");
+
+  TestKey2 key2_1(1.1, "A");
+  TestKey2 key2_2(2.2, "B");
+  TestKey2 key2_3(3.3, "C");
+
+  aComplexMap.Bind(key1_1, key2_1);
+  aComplexMap.Bind(key1_2, key2_2);
+  aComplexMap.Bind(key1_3, key2_3);
+
+  EXPECT_EQ(aComplexMap.Extent(), 3);
+
+  // Test IsBound for both key types
+  EXPECT_TRUE(aComplexMap.IsBound1(TestKey1(1, "One")));
+  EXPECT_TRUE(aComplexMap.IsBound1(TestKey1(2, "Two")));
+  EXPECT_TRUE(aComplexMap.IsBound1(TestKey1(3, "Three")));
+
+  EXPECT_TRUE(aComplexMap.IsBound2(TestKey2(1.1, "A")));
+  EXPECT_TRUE(aComplexMap.IsBound2(TestKey2(2.2, "B")));
+  EXPECT_TRUE(aComplexMap.IsBound2(TestKey2(3.3, "C")));
+
+  // Test finding second key by first key
+  const TestKey2& foundKey2 = aComplexMap.Find1(key1_2);
+  EXPECT_DOUBLE_EQ(foundKey2.GetValue(), 2.2);
+  EXPECT_EQ(foundKey2.GetCode(), "B");
+
+  // Test finding first key by second key
+  const TestKey1& foundKey1 = aComplexMap.Find2(key2_3);
+  EXPECT_EQ(foundKey1.GetId(), 3);
+  EXPECT_EQ(foundKey1.GetName(), "Three");
+}
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_IndexedDataMap_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_IndexedDataMap_Test.cxx
new file mode 100644 (file)
index 0000000..a7d108f
--- /dev/null
@@ -0,0 +1,705 @@
+// 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>
+
+// Basic test types for the IndexedDataMap
+typedef Standard_Integer KeyType;
+typedef Standard_Real    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
+  Standard_Integer index1 = aMap.Add(10, 1.0);
+  Standard_Integer index2 = aMap.Add(20, 2.0);
+  Standard_Integer 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
+  Standard_Integer index1 = aMap.Add(10, 1.0);
+  Standard_Integer 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
+  Standard_Integer 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();
+
+  EXPECT_TRUE(aMap.IsEmpty());
+  EXPECT_EQ(aMap.Extent(), 0);
+
+  // Ensure we can add elements again
+  Standard_Integer 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
+  Standard_Boolean found10 = Standard_False;
+  Standard_Boolean found20 = Standard_False;
+  Standard_Boolean found30 = Standard_False;
+  Standard_Size    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 = Standard_True;
+    else if (key == 20 && value == 2.0)
+      found20 = Standard_True;
+    else if (key == 30 && value == 3.0)
+      found30 = Standard_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
+  Standard_Boolean found1 = Standard_False;
+  Standard_Boolean found2 = Standard_False;
+  Standard_Boolean found3 = Standard_False;
+  Standard_Size    count  = 0;
+
+  for (auto it = aMap.begin(); it != aMap.end(); ++it, ++count)
+  {
+    if (*it == 1.0)
+      found1 = Standard_True;
+    else if (*it == 2.0)
+      found2 = Standard_True;
+    else if (*it == 3.0)
+      found3 = Standard_True;
+  }
+
+  EXPECT_EQ(count, 3);
+  EXPECT_TRUE(found1);
+  EXPECT_TRUE(found2);
+  EXPECT_TRUE(found3);
+
+  // Test const iterator
+  count  = 0;
+  found1 = Standard_False;
+  found2 = Standard_False;
+  found3 = Standard_False;
+
+  for (auto it = aMap.cbegin(); it != aMap.cend(); ++it, ++count)
+  {
+    if (*it == 1.0)
+      found1 = Standard_True;
+    else if (*it == 2.0)
+      found2 = Standard_True;
+    else if (*it == 3.0)
+      found3 = Standard_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
+  Standard_Integer index1 = aStringMap.Add(TCollection_AsciiString("First"), 1.0);
+  Standard_Integer index2 = aStringMap.Add(TCollection_AsciiString("Second"), 2.0);
+  Standard_Integer 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");
+
+  Standard_Integer index1 = aComplexMap.Add(key1, item1);
+  Standard_Integer index2 = aComplexMap.Add(key2, item2);
+  Standard_Integer 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 (Standard_Integer i = 1; i <= 100; ++i)
+  {
+    aMap.Add(i, static_cast<Standard_Real>(i) / 10.0);
+  }
+
+  // Verify all elements are present
+  EXPECT_EQ(aMap.Extent(), 100);
+  for (Standard_Integer i = 1; i <= 100; ++i)
+  {
+    EXPECT_TRUE(aMap.Contains(i));
+    EXPECT_EQ(aMap.FindIndex(i), i);
+    EXPECT_DOUBLE_EQ(aMap.FindFromKey(i), static_cast<Standard_Real>(i) / 10.0);
+  }
+
+  // Explicitly resize
+  aMap.ReSize(200);
+
+  // Check that elements are still accessible
+  EXPECT_EQ(aMap.Extent(), 100);
+  for (Standard_Integer i = 1; i <= 100; ++i)
+  {
+    EXPECT_TRUE(aMap.Contains(i));
+    EXPECT_EQ(aMap.FindIndex(i), i);
+    EXPECT_DOUBLE_EQ(aMap.FindFromKey(i), static_cast<Standard_Real>(i) / 10.0);
+  }
+}
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_IndexedMap_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_IndexedMap_Test.cxx
new file mode 100644 (file)
index 0000000..cc51e0f
--- /dev/null
@@ -0,0 +1,514 @@
+// 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_IndexedMap.hxx>
+#include <TCollection_AsciiString.hxx>
+
+#include <gtest/gtest.h>
+
+// Basic test type for the IndexedMap
+typedef Standard_Integer KeyType;
+
+// 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;
+};
+
+// Hasher for TestKey
+struct TestKeyHasher
+{
+  size_t operator()(const TestKey& theKey) const
+  {
+    // Combine the hash of the id and name
+    size_t aCombination[2] = {std::hash<int>()(theKey.GetId()),
+                              std::hash<std::string>()(theKey.GetName())};
+
+    return opencascade::hashBytes(aCombination, sizeof(aCombination));
+  }
+
+  Standard_Boolean operator()(const TestKey& theKey1, const TestKey& theKey2) const
+  {
+    return theKey1 == theKey2;
+  }
+};
+
+TEST(NCollection_IndexedMapTest, DefaultConstructor)
+{
+  // Test default constructor
+  NCollection_IndexedMap<KeyType> aMap;
+  EXPECT_TRUE(aMap.IsEmpty());
+  EXPECT_EQ(aMap.Extent(), 0);
+  EXPECT_EQ(aMap.Size(), 0);
+}
+
+TEST(NCollection_IndexedMapTest, BasicAddFind)
+{
+  NCollection_IndexedMap<KeyType> aMap;
+
+  // Test adding elements
+  Standard_Integer index1 = aMap.Add(10);
+  Standard_Integer index2 = aMap.Add(20);
+  Standard_Integer index3 = aMap.Add(30);
+
+  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 operator()
+  EXPECT_EQ(aMap(1), 10);
+  EXPECT_EQ(aMap(2), 20);
+  EXPECT_EQ(aMap(3), 30);
+
+  // Test Contains
+  EXPECT_TRUE(aMap.Contains(10));
+  EXPECT_TRUE(aMap.Contains(20));
+  EXPECT_TRUE(aMap.Contains(30));
+  EXPECT_FALSE(aMap.Contains(40));
+}
+
+TEST(NCollection_IndexedMapTest, DuplicateKey)
+{
+  NCollection_IndexedMap<KeyType> aMap;
+
+  // Add initial elements
+  Standard_Integer index1 = aMap.Add(10);
+  Standard_Integer index2 = aMap.Add(20);
+
+  EXPECT_EQ(index1, 1);
+  EXPECT_EQ(index2, 2);
+
+  // Try to add a duplicate - should return the existing index
+  Standard_Integer indexDup = aMap.Add(10);
+  EXPECT_EQ(indexDup, 1);
+  EXPECT_EQ(aMap.Extent(), 2); // Size should not change
+}
+
+TEST(NCollection_IndexedMapTest, RemoveLast)
+{
+  NCollection_IndexedMap<KeyType> aMap;
+
+  // Add elements
+  aMap.Add(10);
+  aMap.Add(20);
+  aMap.Add(30);
+
+  // 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_IndexedMapTest, RemoveFromIndex)
+{
+  NCollection_IndexedMap<KeyType> aMap;
+
+  // Add elements
+  aMap.Add(10);
+  aMap.Add(20);
+  aMap.Add(30);
+  aMap.Add(40);
+
+  // 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_EQ(aMap.FindKey(1), 10); // First element unchanged
+  EXPECT_EQ(aMap.FindKey(3), 30); // Third element unchanged
+}
+
+TEST(NCollection_IndexedMapTest, RemoveKey)
+{
+  NCollection_IndexedMap<KeyType> aMap;
+
+  // Add elements
+  aMap.Add(10);
+  aMap.Add(20);
+  aMap.Add(30);
+
+  // Remove by key
+  bool removed = aMap.RemoveKey(20);
+
+  EXPECT_TRUE(removed);
+  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
+  removed = aMap.RemoveKey(50);
+  EXPECT_FALSE(removed);
+  EXPECT_EQ(aMap.Extent(), 2);
+}
+
+TEST(NCollection_IndexedMapTest, Substitute)
+{
+  NCollection_IndexedMap<KeyType> aMap;
+
+  // Add elements
+  aMap.Add(10);
+  aMap.Add(20);
+  aMap.Add(30);
+
+  // Substitute key at index 2
+  aMap.Substitute(2, 25);
+
+  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 keys
+  EXPECT_EQ(aMap.FindKey(1), 10);
+  EXPECT_EQ(aMap.FindKey(2), 25);
+  EXPECT_EQ(aMap.FindKey(3), 30);
+}
+
+TEST(NCollection_IndexedMapTest, Swap)
+{
+  NCollection_IndexedMap<KeyType> aMap;
+
+  // Add elements
+  aMap.Add(10);
+  aMap.Add(20);
+  aMap.Add(30);
+
+  // 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);
+}
+
+TEST(NCollection_IndexedMapTest, Clear)
+{
+  NCollection_IndexedMap<KeyType> aMap;
+
+  // Add elements
+  aMap.Add(10);
+  aMap.Add(20);
+  aMap.Add(30);
+
+  EXPECT_EQ(aMap.Extent(), 3);
+
+  // Clear the map
+  aMap.Clear();
+
+  EXPECT_TRUE(aMap.IsEmpty());
+  EXPECT_EQ(aMap.Extent(), 0);
+
+  // Ensure we can add elements again
+  Standard_Integer index1 = aMap.Add(40);
+  EXPECT_EQ(index1, 1);
+  EXPECT_EQ(aMap.Extent(), 1);
+}
+
+TEST(NCollection_IndexedMapTest, CopyConstructor)
+{
+  NCollection_IndexedMap<KeyType> aMap1;
+
+  // Add elements to first map
+  aMap1.Add(10);
+  aMap1.Add(20);
+  aMap1.Add(30);
+
+  // Create a copy
+  NCollection_IndexedMap<KeyType> 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);
+
+  // Modify original to ensure deep copy
+  aMap1.Add(40);
+  EXPECT_EQ(aMap1.Extent(), 4);
+  EXPECT_EQ(aMap2.Extent(), 3);
+  EXPECT_FALSE(aMap2.Contains(40));
+}
+
+TEST(NCollection_IndexedMapTest, AssignmentOperator)
+{
+  NCollection_IndexedMap<KeyType> aMap1;
+  NCollection_IndexedMap<KeyType> aMap2;
+
+  // Add elements to first map
+  aMap1.Add(10);
+  aMap1.Add(20);
+
+  // Add different elements to second map
+  aMap2.Add(30);
+  aMap2.Add(40);
+  aMap2.Add(50);
+
+  // 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));
+}
+
+TEST(NCollection_IndexedMapTest, Iterator)
+{
+  NCollection_IndexedMap<KeyType> aMap;
+
+  // Add elements
+  aMap.Add(10);
+  aMap.Add(20);
+  aMap.Add(30);
+
+  // Use iterator to check all elements
+  Standard_Boolean found10 = Standard_False;
+  Standard_Boolean found20 = Standard_False;
+  Standard_Boolean found30 = Standard_False;
+  Standard_Size    count   = 0;
+
+  for (NCollection_IndexedMap<KeyType>::Iterator it(aMap); it.More(); it.Next(), ++count)
+  {
+    const KeyType& key = it.Value();
+    if (key == 10)
+      found10 = Standard_True;
+    else if (key == 20)
+      found20 = Standard_True;
+    else if (key == 30)
+      found30 = Standard_True;
+  }
+
+  EXPECT_EQ(count, 3);
+  EXPECT_TRUE(found10);
+  EXPECT_TRUE(found20);
+  EXPECT_TRUE(found30);
+}
+
+TEST(NCollection_IndexedMapTest, StlIterator)
+{
+  NCollection_IndexedMap<KeyType> aMap;
+
+  // Add elements
+  aMap.Add(10);
+  aMap.Add(20);
+  aMap.Add(30);
+
+  // Use STL-style iterator
+  Standard_Boolean found10 = Standard_False;
+  Standard_Boolean found20 = Standard_False;
+  Standard_Boolean found30 = Standard_False;
+  Standard_Size    count   = 0;
+
+  for (auto it = aMap.cbegin(); it != aMap.cend(); ++it, ++count)
+  {
+    if (*it == 10)
+      found10 = Standard_True;
+    else if (*it == 20)
+      found20 = Standard_True;
+    else if (*it == 30)
+      found30 = Standard_True;
+  }
+
+  EXPECT_EQ(count, 3);
+  EXPECT_TRUE(found10);
+  EXPECT_TRUE(found20);
+  EXPECT_TRUE(found30);
+}
+
+TEST(NCollection_IndexedMapTest, StringKeys)
+{
+  // Test with string keys
+  NCollection_IndexedMap<TCollection_AsciiString> aStringMap;
+
+  // Add string keys
+  Standard_Integer index1 = aStringMap.Add(TCollection_AsciiString("First"));
+  Standard_Integer index2 = aStringMap.Add(TCollection_AsciiString("Second"));
+  Standard_Integer index3 = aStringMap.Add(TCollection_AsciiString("Third"));
+
+  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"));
+}
+
+TEST(NCollection_IndexedMapTest, ComplexKeys)
+{
+  // Create map with custom key and hasher
+  NCollection_IndexedMap<TestKey, TestKeyHasher> aComplexMap;
+
+  // Add complex keys
+  TestKey key1(1, "One");
+  TestKey key2(2, "Two");
+  TestKey key3(3, "Three");
+
+  Standard_Integer index1 = aComplexMap.Add(key1);
+  Standard_Integer index2 = aComplexMap.Add(key2);
+  Standard_Integer index3 = aComplexMap.Add(key3);
+
+  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);
+
+  // Test contains
+  EXPECT_TRUE(aComplexMap.Contains(TestKey(1, "One")));
+  EXPECT_FALSE(aComplexMap.Contains(TestKey(4, "Four")));
+}
+
+TEST(NCollection_IndexedMapTest, Exchange)
+{
+  NCollection_IndexedMap<KeyType> aMap1;
+  NCollection_IndexedMap<KeyType> aMap2;
+
+  // Add elements to first map
+  aMap1.Add(10);
+  aMap1.Add(20);
+
+  // Add different elements to second map
+  aMap2.Add(30);
+  aMap2.Add(40);
+  aMap2.Add(50);
+
+  // 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_EQ(aMap2.Extent(), 2);
+  EXPECT_TRUE(aMap2.Contains(10));
+  EXPECT_TRUE(aMap2.Contains(20));
+}
+
+TEST(NCollection_IndexedMapTest, ReSize)
+{
+  NCollection_IndexedMap<KeyType> aMap(3); // Start with small bucket count
+
+  // Add many elements to trigger resize
+  for (Standard_Integer i = 1; i <= 100; ++i)
+  {
+    aMap.Add(i);
+  }
+
+  // Verify all elements are present
+  EXPECT_EQ(aMap.Extent(), 100);
+  for (Standard_Integer i = 1; i <= 100; ++i)
+  {
+    EXPECT_TRUE(aMap.Contains(i));
+    EXPECT_EQ(aMap.FindIndex(i), i);
+    EXPECT_EQ(aMap.FindKey(i), i);
+  }
+
+  // Explicitly resize
+  aMap.ReSize(200);
+
+  // Check that elements are still accessible
+  EXPECT_EQ(aMap.Extent(), 100);
+  for (Standard_Integer i = 1; i <= 100; ++i)
+  {
+    EXPECT_TRUE(aMap.Contains(i));
+    EXPECT_EQ(aMap.FindIndex(i), i);
+    EXPECT_EQ(aMap.FindKey(i), i);
+  }
+}
\ No newline at end of file
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_List_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_List_Test.cxx
new file mode 100644 (file)
index 0000000..0cd2ee6
--- /dev/null
@@ -0,0 +1,402 @@
+// 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_List.hxx>
+#include <Standard_Integer.hxx>
+
+#include <gtest/gtest.h>
+
+// Test fixture for NCollection_List tests
+class NCollection_ListTest : public testing::Test
+{
+protected:
+  void SetUp() override {}
+
+  void TearDown() override {}
+};
+
+TEST_F(NCollection_ListTest, DefaultConstructor)
+{
+  // Default constructor should create an empty list
+  NCollection_List<Standard_Integer> aList;
+  EXPECT_TRUE(aList.IsEmpty());
+  EXPECT_EQ(0, aList.Size());
+  EXPECT_EQ(0, aList.Extent());
+}
+
+TEST_F(NCollection_ListTest, Append)
+{
+  NCollection_List<Standard_Integer> aList;
+
+  // Test Append method
+  EXPECT_EQ(10, aList.Append(10));
+  EXPECT_EQ(20, aList.Append(20));
+  EXPECT_EQ(30, aList.Append(30));
+
+  EXPECT_FALSE(aList.IsEmpty());
+  EXPECT_EQ(3, aList.Size());
+
+  // Test First and Last access
+  EXPECT_EQ(10, aList.First());
+  EXPECT_EQ(30, aList.Last());
+}
+
+TEST_F(NCollection_ListTest, Prepend)
+{
+  NCollection_List<Standard_Integer> aList;
+
+  // Test Prepend method
+  EXPECT_EQ(30, aList.Prepend(30));
+  EXPECT_EQ(20, aList.Prepend(20));
+  EXPECT_EQ(10, aList.Prepend(10));
+
+  EXPECT_FALSE(aList.IsEmpty());
+  EXPECT_EQ(3, aList.Size());
+
+  // Test First and Last access
+  EXPECT_EQ(10, aList.First());
+  EXPECT_EQ(30, aList.Last());
+}
+
+TEST_F(NCollection_ListTest, IteratorAccess)
+{
+  NCollection_List<Standard_Integer> aList;
+  aList.Append(10);
+  aList.Append(20);
+  aList.Append(30);
+
+  // Test iteration using OCCT iterator
+  NCollection_List<Standard_Integer>::Iterator it(aList);
+  Standard_Integer                             expectedValues[] = {10, 20, 30};
+  Standard_Integer                             index            = 0;
+
+  for (; it.More(); it.Next(), index++)
+  {
+    EXPECT_EQ(expectedValues[index], it.Value());
+  }
+  EXPECT_EQ(3, index); // Ensure we iterated through all elements
+}
+
+TEST_F(NCollection_ListTest, STLIterators)
+{
+  NCollection_List<Standard_Integer> aList;
+  aList.Append(10);
+  aList.Append(20);
+  aList.Append(30);
+
+  // Test STL-compatible iterators
+  Standard_Integer expectedValues[] = {10, 20, 30};
+  Standard_Integer index            = 0;
+
+  for (auto it = aList.begin(); it != aList.end(); ++it, ++index)
+  {
+    EXPECT_EQ(expectedValues[index], *it);
+  }
+  EXPECT_EQ(3, index);
+
+  // Test range-based for loop
+  index = 0;
+  for (const auto& value : aList)
+  {
+    EXPECT_EQ(expectedValues[index++], value);
+  }
+  EXPECT_EQ(3, index);
+}
+
+TEST_F(NCollection_ListTest, RemoveFirst)
+{
+  NCollection_List<Standard_Integer> aList;
+  aList.Append(10);
+  aList.Append(20);
+  aList.Append(30);
+
+  // Test RemoveFirst
+  aList.RemoveFirst();
+  EXPECT_EQ(2, aList.Size());
+  EXPECT_EQ(20, aList.First());
+
+  aList.RemoveFirst();
+  EXPECT_EQ(1, aList.Size());
+  EXPECT_EQ(30, aList.First());
+
+  aList.RemoveFirst();
+  EXPECT_TRUE(aList.IsEmpty());
+}
+
+TEST_F(NCollection_ListTest, Remove)
+{
+  NCollection_List<Standard_Integer> aList;
+  aList.Append(10);
+  aList.Append(20);
+  aList.Append(30);
+
+  // Test Remove with iterator
+  NCollection_List<Standard_Integer>::Iterator it(aList);
+  it.Next();        // Point to second element (20)
+  aList.Remove(it); // Remove 20, iterator now points to 30
+
+  // Check the list after removal
+  EXPECT_EQ(2, aList.Size());
+  EXPECT_EQ(10, aList.First());
+  EXPECT_EQ(30, aList.Last());
+  EXPECT_EQ(30, it.Value()); // Iterator should now point to 30
+}
+
+TEST_F(NCollection_ListTest, RemoveByValue)
+{
+  NCollection_List<Standard_Integer> aList;
+  aList.Append(10);
+  aList.Append(20);
+  aList.Append(10); // Add duplicate
+  aList.Append(30);
+
+  // Test removing by value - should remove the first occurrence only
+  bool removed = aList.Remove(10);
+  EXPECT_TRUE(removed);
+  EXPECT_EQ(3, aList.Size());
+  EXPECT_EQ(20, aList.First());
+
+  // Try to remove a non-existent value
+  removed = aList.Remove(50);
+  EXPECT_FALSE(removed);
+  EXPECT_EQ(3, aList.Size());
+
+  // Remove the second occurrence of 10
+  removed = aList.Remove(10);
+  EXPECT_TRUE(removed);
+  EXPECT_EQ(2, aList.Size());
+
+  // Check final list state
+  NCollection_List<Standard_Integer>::Iterator it(aList);
+  EXPECT_EQ(20, it.Value());
+  it.Next();
+  EXPECT_EQ(30, it.Value());
+}
+
+TEST_F(NCollection_ListTest, Clear)
+{
+  NCollection_List<Standard_Integer> aList;
+  aList.Append(10);
+  aList.Append(20);
+  aList.Append(30);
+
+  // Test Clear
+  aList.Clear();
+  EXPECT_TRUE(aList.IsEmpty());
+  EXPECT_EQ(0, aList.Size());
+}
+
+TEST_F(NCollection_ListTest, Assignment)
+{
+  NCollection_List<Standard_Integer> aList1;
+  aList1.Append(10);
+  aList1.Append(20);
+  aList1.Append(30);
+
+  // Test assignment operator
+  NCollection_List<Standard_Integer> aList2;
+  aList2 = aList1;
+
+  // Check both lists have the same content
+  EXPECT_EQ(aList1.Size(), aList2.Size());
+
+  NCollection_List<Standard_Integer>::Iterator it1(aList1);
+  NCollection_List<Standard_Integer>::Iterator it2(aList2);
+
+  for (; it1.More() && it2.More(); it1.Next(), it2.Next())
+  {
+    EXPECT_EQ(it1.Value(), it2.Value());
+  }
+
+  // Modify original to ensure deep copy
+  aList1.First() = 100;
+  EXPECT_EQ(100, aList1.First());
+  EXPECT_EQ(10, aList2.First());
+}
+
+TEST_F(NCollection_ListTest, AssignMethod)
+{
+  NCollection_List<Standard_Integer> aList1;
+  aList1.Append(10);
+  aList1.Append(20);
+  aList1.Append(30);
+
+  // Test Assign method
+  NCollection_List<Standard_Integer> aList2;
+  aList2.Append(40);     // Add some initial content
+  aList2.Assign(aList1); // This should replace aList2's content
+
+  EXPECT_EQ(aList1.Size(), aList2.Size());
+
+  // Check values
+  NCollection_List<Standard_Integer>::Iterator it2(aList2);
+  EXPECT_EQ(10, it2.Value());
+  it2.Next();
+  EXPECT_EQ(20, it2.Value());
+  it2.Next();
+  EXPECT_EQ(30, it2.Value());
+}
+
+TEST_F(NCollection_ListTest, AppendList)
+{
+  NCollection_List<Standard_Integer> aList1;
+  aList1.Append(10);
+  aList1.Append(20);
+
+  NCollection_List<Standard_Integer> aList2;
+  aList2.Append(30);
+  aList2.Append(40);
+
+  // Test Append(List)
+  aList1.Append(aList2);
+
+  EXPECT_EQ(4, aList1.Size());
+  EXPECT_TRUE(aList2.IsEmpty()); // aList2 should be cleared
+
+  // Check values in aList1
+  NCollection_List<Standard_Integer>::Iterator it(aList1);
+  EXPECT_EQ(10, it.Value());
+  it.Next();
+  EXPECT_EQ(20, it.Value());
+  it.Next();
+  EXPECT_EQ(30, it.Value());
+  it.Next();
+  EXPECT_EQ(40, it.Value());
+}
+
+TEST_F(NCollection_ListTest, PrependList)
+{
+  NCollection_List<Standard_Integer> aList1;
+  aList1.Append(30);
+  aList1.Append(40);
+
+  NCollection_List<Standard_Integer> aList2;
+  aList2.Append(10);
+  aList2.Append(20);
+
+  // Test Prepend(List)
+  aList1.Prepend(aList2);
+
+  EXPECT_EQ(4, aList1.Size());
+  EXPECT_TRUE(aList2.IsEmpty()); // aList2 should be cleared
+
+  // Check values in aList1
+  NCollection_List<Standard_Integer>::Iterator it(aList1);
+  EXPECT_EQ(10, it.Value());
+  it.Next();
+  EXPECT_EQ(20, it.Value());
+  it.Next();
+  EXPECT_EQ(30, it.Value());
+  it.Next();
+  EXPECT_EQ(40, it.Value());
+}
+
+TEST_F(NCollection_ListTest, InsertBefore)
+{
+  NCollection_List<Standard_Integer> aList;
+  aList.Append(10);
+  aList.Append(30);
+
+  // Get iterator to second element
+  NCollection_List<Standard_Integer>::Iterator it(aList);
+  it.Next();
+
+  // Insert before the second element
+  EXPECT_EQ(20, aList.InsertBefore(20, it));
+
+  // Check the list
+  EXPECT_EQ(3, aList.Size());
+
+  NCollection_List<Standard_Integer>::Iterator checkIt(aList);
+  EXPECT_EQ(10, checkIt.Value());
+  checkIt.Next();
+  EXPECT_EQ(20, checkIt.Value());
+  checkIt.Next();
+  EXPECT_EQ(30, checkIt.Value());
+}
+
+TEST_F(NCollection_ListTest, InsertAfter)
+{
+  NCollection_List<Standard_Integer> aList;
+  aList.Append(10);
+  aList.Append(30);
+
+  // Get iterator to first element
+  NCollection_List<Standard_Integer>::Iterator it(aList);
+
+  // Insert after the first element
+  EXPECT_EQ(20, aList.InsertAfter(20, it));
+
+  // Check the list
+  EXPECT_EQ(3, aList.Size());
+
+  NCollection_List<Standard_Integer>::Iterator checkIt(aList);
+  EXPECT_EQ(10, checkIt.Value());
+  checkIt.Next();
+  EXPECT_EQ(20, checkIt.Value());
+  checkIt.Next();
+  EXPECT_EQ(30, checkIt.Value());
+}
+
+TEST_F(NCollection_ListTest, InsertList)
+{
+  NCollection_List<Standard_Integer> aList1;
+  aList1.Append(10);
+  aList1.Append(40);
+
+  NCollection_List<Standard_Integer> aList2;
+  aList2.Append(20);
+  aList2.Append(30);
+
+  // Get iterator to the second element in aList1
+  NCollection_List<Standard_Integer>::Iterator it(aList1);
+  it.Next();
+
+  // Insert aList2 before the second element in aList1
+  aList1.InsertBefore(aList2, it);
+
+  EXPECT_EQ(4, aList1.Size());
+  EXPECT_TRUE(aList2.IsEmpty());
+
+  // Check the resulting list
+  NCollection_List<Standard_Integer>::Iterator checkIt(aList1);
+  EXPECT_EQ(10, checkIt.Value());
+  checkIt.Next();
+  EXPECT_EQ(20, checkIt.Value());
+  checkIt.Next();
+  EXPECT_EQ(30, checkIt.Value());
+  checkIt.Next();
+  EXPECT_EQ(40, checkIt.Value());
+}
+
+TEST_F(NCollection_ListTest, Reverse)
+{
+  NCollection_List<Standard_Integer> aList;
+  aList.Append(10);
+  aList.Append(20);
+  aList.Append(30);
+
+  // Test Reverse
+  aList.Reverse();
+
+  // Check the reversed list
+  EXPECT_EQ(30, aList.First());
+  EXPECT_EQ(10, aList.Last());
+
+  NCollection_List<Standard_Integer>::Iterator it(aList);
+  EXPECT_EQ(30, it.Value());
+  it.Next();
+  EXPECT_EQ(20, it.Value());
+  it.Next();
+  EXPECT_EQ(10, it.Value());
+}
\ No newline at end of file
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_LocalArray_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_LocalArray_Test.cxx
new file mode 100644 (file)
index 0000000..c5de4b0
--- /dev/null
@@ -0,0 +1,191 @@
+// 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_LocalArray.hxx>
+
+#include <gtest/gtest.h>
+
+// Test default constructor and initial state
+TEST(NCollection_LocalArrayTest, DefaultConstructor)
+{
+  NCollection_LocalArray<int> array;
+  EXPECT_EQ(0, array.Size());
+}
+
+// Test constructor with size
+TEST(NCollection_LocalArrayTest, ConstructorWithSize)
+{
+  const size_t                size = 100;
+  NCollection_LocalArray<int> array(size);
+  EXPECT_EQ(size, array.Size());
+}
+
+// Test allocation with small size (using buffer)
+TEST(NCollection_LocalArrayTest, SmallSizeAllocation)
+{
+  const size_t                      size = 10; // Less than MAX_ARRAY_SIZE
+  NCollection_LocalArray<int, 1024> array(size);
+  EXPECT_EQ(size, array.Size());
+
+  // Populate array
+  for (size_t i = 0; i < size; ++i)
+  {
+    array[i] = static_cast<int>(i * 10);
+  }
+
+  // Verify array contents
+  for (size_t i = 0; i < size; ++i)
+  {
+    EXPECT_EQ(static_cast<int>(i * 10), array[i]);
+  }
+}
+
+// Test allocation with large size (heap allocation)
+TEST(NCollection_LocalArrayTest, LargeSizeAllocation)
+{
+  const size_t                size = 2000; // Greater than default MAX_ARRAY_SIZE of 1024
+  NCollection_LocalArray<int> array(size);
+  EXPECT_EQ(size, array.Size());
+
+  // Populate array
+  for (size_t i = 0; i < size; ++i)
+  {
+    array[i] = static_cast<int>(i * 10);
+  }
+
+  // Verify array contents
+  for (size_t i = 0; i < size; ++i)
+  {
+    EXPECT_EQ(static_cast<int>(i * 10), array[i]);
+  }
+}
+
+// Test reallocation
+TEST(NCollection_LocalArrayTest, Reallocation)
+{
+  NCollection_LocalArray<int> array(10);
+  EXPECT_EQ(10, array.Size());
+
+  // Populate array
+  for (size_t i = 0; i < 10; ++i)
+  {
+    array[i] = static_cast<int>(i);
+  }
+
+  // Reallocate to larger size
+  array.Allocate(50);
+  EXPECT_EQ(50, array.Size());
+
+  // Populate new elements
+  for (size_t i = 0; i < 50; ++i)
+  {
+    array[i] = static_cast<int>(i * 2);
+  }
+
+  // Verify array contents
+  for (size_t i = 0; i < 50; ++i)
+  {
+    EXPECT_EQ(static_cast<int>(i * 2), array[i]);
+  }
+
+  // Reallocate to smaller size
+  array.Allocate(5);
+  EXPECT_EQ(5, array.Size());
+
+  // Verify array contents
+  for (size_t i = 0; i < 5; ++i)
+  {
+    EXPECT_EQ(static_cast<int>(i * 2), array[i]);
+  }
+}
+
+// Test with custom MAX_ARRAY_SIZE
+TEST(NCollection_LocalArrayTest, CustomMaxArraySize)
+{
+  const size_t customMaxSize = 50;
+
+  // Test with size less than custom max
+  NCollection_LocalArray<int, customMaxSize> smallArray(20);
+  EXPECT_EQ(20, smallArray.Size());
+
+  // Test with size greater than custom max
+  NCollection_LocalArray<int, customMaxSize> largeArray(100);
+  EXPECT_EQ(100, largeArray.Size());
+}
+
+// Test with custom type
+struct TestStruct
+{
+  int    a;
+  double b;
+
+  bool operator==(const TestStruct& other) const { return a == other.a && b == other.b; }
+};
+
+TEST(NCollection_LocalArrayTest, CustomType)
+{
+  NCollection_LocalArray<TestStruct> array(5);
+  EXPECT_EQ(5, array.Size());
+
+  TestStruct ts{10, 3.14};
+
+  // Set and retrieve values
+  array[0] = ts;
+  EXPECT_TRUE(ts == array[0]);
+}
+
+// Test transition from stack to heap allocation and back
+TEST(NCollection_LocalArrayTest, TransitionStackToHeap)
+{
+  const int                            maxSize = 10;
+  NCollection_LocalArray<int, maxSize> array;
+
+  // Initially allocate in stack buffer
+  array.Allocate(5);
+  for (size_t i = 0; i < 5; ++i)
+  {
+    array[i] = static_cast<int>(i);
+  }
+
+  // Verify array contents
+  for (size_t i = 0; i < 5; ++i)
+  {
+    EXPECT_EQ(static_cast<int>(i), array[i]);
+  }
+
+  // Now allocate larger size, forcing heap allocation
+  array.Allocate(maxSize + 10);
+  for (size_t i = 0; i < maxSize + 10; ++i)
+  {
+    array[i] = static_cast<int>(i * 3);
+  }
+
+  // Verify heap allocation
+  for (size_t i = 0; i < maxSize + 10; ++i)
+  {
+    EXPECT_EQ(static_cast<int>(i * 3), array[i]);
+  }
+
+  // Now go back to stack allocation
+  array.Allocate(maxSize - 5);
+  for (size_t i = 0; i < maxSize - 5; ++i)
+  {
+    array[i] = static_cast<int>(i * 5);
+  }
+
+  // Verify stack allocation again
+  for (size_t i = 0; i < maxSize - 5; ++i)
+  {
+    EXPECT_EQ(static_cast<int>(i * 5), array[i]);
+  }
+}
\ No newline at end of file
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_Map_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_Map_Test.cxx
new file mode 100644 (file)
index 0000000..9b3529e
--- /dev/null
@@ -0,0 +1,218 @@
+// 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_Map.hxx>
+#include <Standard_Integer.hxx>
+#include <TCollection_AsciiString.hxx>
+
+#include <gtest/gtest.h>
+
+TEST(NCollection_MapTest, DefaultConstructor)
+{
+  // Default constructor should create an empty map
+  NCollection_Map<Standard_Integer> aMap(101);
+
+  EXPECT_TRUE(aMap.IsEmpty());
+  EXPECT_EQ(0, aMap.Size());
+  EXPECT_EQ(0, aMap.Extent());
+  EXPECT_EQ(101, aMap.NbBuckets());
+}
+
+TEST(NCollection_MapTest, ConstructorWithBuckets)
+{
+  // Constructor with number of buckets
+  const Standard_Integer            nbBuckets = 100;
+  NCollection_Map<Standard_Integer> aMap(nbBuckets);
+
+  EXPECT_TRUE(aMap.IsEmpty());
+  EXPECT_EQ(0, aMap.Size());
+  EXPECT_EQ(0, aMap.Extent());
+  EXPECT_EQ(nbBuckets, aMap.NbBuckets());
+}
+
+TEST(NCollection_MapTest, AddAndContains)
+{
+  NCollection_Map<Standard_Integer> aMap;
+
+  // Test Add method
+  EXPECT_TRUE(aMap.Add(10));
+  EXPECT_TRUE(aMap.Add(20));
+  EXPECT_TRUE(aMap.Add(30));
+
+  // Adding duplicates should return false
+  EXPECT_FALSE(aMap.Add(10));
+  EXPECT_FALSE(aMap.Add(20));
+
+  // Map size should account for unique elements only
+  EXPECT_EQ(3, aMap.Size());
+
+  // Test Contains
+  EXPECT_TRUE(aMap.Contains(10));
+  EXPECT_TRUE(aMap.Contains(20));
+  EXPECT_TRUE(aMap.Contains(30));
+  EXPECT_FALSE(aMap.Contains(40));
+}
+
+TEST(NCollection_MapTest, Remove)
+{
+  NCollection_Map<Standard_Integer> aMap;
+  aMap.Add(10);
+  aMap.Add(20);
+  aMap.Add(30);
+
+  // Test Remove
+  EXPECT_TRUE(aMap.Remove(20));
+  EXPECT_EQ(2, aMap.Size());
+  EXPECT_FALSE(aMap.Contains(20));
+  EXPECT_TRUE(aMap.Contains(10));
+  EXPECT_TRUE(aMap.Contains(30));
+
+  // Try to remove non-existent element
+  EXPECT_FALSE(aMap.Remove(40));
+  EXPECT_EQ(2, aMap.Size());
+}
+
+TEST(NCollection_MapTest, Clear)
+{
+  NCollection_Map<Standard_Integer> aMap;
+  aMap.Add(10);
+  aMap.Add(20);
+  aMap.Add(30);
+
+  EXPECT_FALSE(aMap.IsEmpty());
+
+  // Test Clear
+  aMap.Clear();
+  EXPECT_TRUE(aMap.IsEmpty());
+  EXPECT_EQ(0, aMap.Size());
+  EXPECT_FALSE(aMap.Contains(10));
+  EXPECT_FALSE(aMap.Contains(20));
+  EXPECT_FALSE(aMap.Contains(30));
+}
+
+TEST(NCollection_MapTest, Assignment)
+{
+  NCollection_Map<Standard_Integer> aMap1;
+  aMap1.Add(10);
+  aMap1.Add(20);
+  aMap1.Add(30);
+
+  // Test assignment operator
+  NCollection_Map<Standard_Integer> aMap2;
+  aMap2 = aMap1;
+
+  // Check both maps have the same content
+  EXPECT_EQ(aMap1.Size(), aMap2.Size());
+  EXPECT_TRUE(aMap2.Contains(10));
+  EXPECT_TRUE(aMap2.Contains(20));
+  EXPECT_TRUE(aMap2.Contains(30));
+
+  // Modify original map to ensure deep copy
+  aMap1.Add(40);
+  aMap1.Remove(10);
+
+  EXPECT_EQ(3, aMap1.Size());
+  EXPECT_EQ(3, aMap2.Size());
+  EXPECT_TRUE(aMap2.Contains(10));
+  EXPECT_FALSE(aMap1.Contains(10));
+  EXPECT_TRUE(aMap1.Contains(40));
+  EXPECT_FALSE(aMap2.Contains(40));
+}
+
+TEST(NCollection_MapTest, IteratorAccess)
+{
+  NCollection_Map<Standard_Integer> aMap;
+  aMap.Add(10);
+  aMap.Add(20);
+  aMap.Add(30);
+
+  // Test iteration using OCCT iterator
+  NCollection_Map<Standard_Integer>::Iterator it(aMap);
+
+  // Create set to check all keys are visited
+  std::set<Standard_Integer> foundKeys;
+
+  for (; it.More(); it.Next())
+  {
+    foundKeys.insert(it.Value());
+  }
+
+  // Check all keys were visited
+  EXPECT_EQ(3, foundKeys.size());
+  EXPECT_TRUE(foundKeys.find(10) != foundKeys.end());
+  EXPECT_TRUE(foundKeys.find(20) != foundKeys.end());
+  EXPECT_TRUE(foundKeys.find(30) != foundKeys.end());
+}
+
+TEST(NCollection_MapTest, Resize)
+{
+  NCollection_Map<Standard_Integer> aMap(10);
+
+  // Add elements
+  for (Standard_Integer i = 0; i < 100; ++i)
+  {
+    aMap.Add(i);
+  }
+
+  // Check initial state
+  EXPECT_EQ(100, aMap.Size());
+
+  // Before resize, remember which elements are contained
+  std::vector<Standard_Integer> elements;
+  for (NCollection_Map<Standard_Integer>::Iterator it(aMap); it.More(); it.Next())
+  {
+    elements.push_back(it.Value());
+  }
+
+  // Test Resize
+  aMap.ReSize(200);
+
+  // Resize shouldn't change the map contents
+  EXPECT_EQ(100, aMap.Size());
+  for (const auto& element : elements)
+  {
+    EXPECT_TRUE(aMap.Contains(element));
+  }
+}
+
+TEST(NCollection_MapTest, ExhaustiveIterator)
+{
+  const int NUM_ELEMENTS = 1000;
+
+  // Create a map with many elements to test iterator efficiency
+  NCollection_Map<Standard_Integer> aMap;
+
+  // Add many elements
+  for (int i = 0; i < NUM_ELEMENTS; ++i)
+  {
+    aMap.Add(i);
+  }
+
+  EXPECT_EQ(NUM_ELEMENTS, aMap.Size());
+
+  // Count elements using iterator
+  int                                         count = 0;
+  int                                         sum   = 0;
+  NCollection_Map<Standard_Integer>::Iterator it(aMap);
+  for (; it.More(); it.Next())
+  {
+    sum += it.Value();
+    count++;
+  }
+
+  EXPECT_EQ(NUM_ELEMENTS, count);
+
+  // Calculate expected sum: 0 + 1 + 2 + ... + (NUM_ELEMENTS-1)
+  int expectedSum = (NUM_ELEMENTS * (NUM_ELEMENTS - 1)) / 2;
+  EXPECT_EQ(expectedSum, sum);
+}
\ No newline at end of file
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_Sequence_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_Sequence_Test.cxx
new file mode 100644 (file)
index 0000000..ae1383c
--- /dev/null
@@ -0,0 +1,375 @@
+// 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_Sequence.hxx>
+#include <NCollection_IncAllocator.hxx>
+#include <NCollection_BaseAllocator.hxx>
+
+#include <gtest/gtest.h>
+
+// Basic test type for the Sequence
+typedef Standard_Integer ItemType;
+
+// Custom class for testing complex types in the Sequence
+class TestClass
+{
+public:
+  TestClass(int id = 0, const char* name = "")
+      : myId(id),
+        myName(name)
+  {
+  }
+
+  int GetId() const { return myId; }
+
+  const char* GetName() const { return myName.c_str(); }
+
+  bool operator==(const TestClass& other) const
+  {
+    return (myId == other.myId && myName == other.myName);
+  }
+
+private:
+  int         myId;
+  std::string myName;
+};
+
+TEST(NCollection_SequenceTest, BasicFunctions)
+{
+  // Test default constructor and initial state
+  NCollection_Sequence<ItemType> aSeq;
+  EXPECT_TRUE(aSeq.IsEmpty());
+  EXPECT_EQ(aSeq.Size(), 0);
+  EXPECT_EQ(aSeq.Length(), 0);
+
+  // Test Append
+  aSeq.Append(10);
+  aSeq.Append(20);
+  aSeq.Append(30);
+  EXPECT_EQ(aSeq.Size(), 3);
+  EXPECT_FALSE(aSeq.IsEmpty());
+
+  // Test access operations
+  EXPECT_EQ(aSeq(1), 10);
+  EXPECT_EQ(aSeq(2), 20);
+  EXPECT_EQ(aSeq(3), 30);
+  EXPECT_EQ(aSeq.First(), 10);
+  EXPECT_EQ(aSeq.Last(), 30);
+
+  // Test bounds
+  EXPECT_EQ(aSeq.Lower(), 1);
+  EXPECT_EQ(aSeq.Upper(), 3);
+}
+
+TEST(NCollection_SequenceTest, ModifyingOperations)
+{
+  NCollection_Sequence<ItemType> aSeq;
+
+  // Test Prepend
+  aSeq.Prepend(100);
+  aSeq.Prepend(200);
+  EXPECT_EQ(aSeq.Size(), 2);
+  EXPECT_EQ(aSeq.First(), 200);
+  EXPECT_EQ(aSeq.Last(), 100);
+
+  // Test SetValue
+  aSeq.SetValue(1, 210);
+  EXPECT_EQ(aSeq(1), 210);
+
+  // Test ChangeValue
+  aSeq.ChangeValue(2) = 110;
+  EXPECT_EQ(aSeq(2), 110);
+
+  // Test InsertBefore
+  aSeq.InsertBefore(1, 300);
+  EXPECT_EQ(aSeq.Size(), 3);
+  EXPECT_EQ(aSeq(1), 300);
+  EXPECT_EQ(aSeq(2), 210);
+  EXPECT_EQ(aSeq(3), 110);
+
+  // Test InsertAfter
+  aSeq.InsertAfter(2, 400);
+  EXPECT_EQ(aSeq.Size(), 4);
+  EXPECT_EQ(aSeq(1), 300);
+  EXPECT_EQ(aSeq(2), 210);
+  EXPECT_EQ(aSeq(3), 400);
+  EXPECT_EQ(aSeq(4), 110);
+
+  // Test Remove
+  aSeq.Remove(3);
+  EXPECT_EQ(aSeq.Size(), 3);
+  EXPECT_EQ(aSeq(1), 300);
+  EXPECT_EQ(aSeq(2), 210);
+  EXPECT_EQ(aSeq(3), 110);
+
+  // Test Remove with range
+  aSeq.Append(500);
+  aSeq.Append(600);
+  EXPECT_EQ(aSeq.Size(), 5);
+
+  aSeq.Remove(2, 4);
+  EXPECT_EQ(aSeq.Size(), 2);
+  EXPECT_EQ(aSeq(1), 300);
+  EXPECT_EQ(aSeq(2), 600);
+}
+
+TEST(NCollection_SequenceTest, IteratorFunctions)
+{
+  NCollection_Sequence<ItemType> aSeq;
+  aSeq.Append(10);
+  aSeq.Append(20);
+  aSeq.Append(30);
+
+  // Test Iterator
+  NCollection_Sequence<ItemType>::Iterator anIt(aSeq);
+
+  EXPECT_TRUE(anIt.More());
+  EXPECT_EQ(anIt.Value(), 10);
+  anIt.Next();
+
+  EXPECT_TRUE(anIt.More());
+  EXPECT_EQ(anIt.Value(), 20);
+  anIt.Next();
+
+  EXPECT_TRUE(anIt.More());
+  EXPECT_EQ(anIt.Value(), 30);
+  anIt.Next();
+
+  EXPECT_FALSE(anIt.More());
+
+  // Test value modification through iterator
+  NCollection_Sequence<ItemType>::Iterator aModIt(aSeq);
+  aModIt.ChangeValue() = 15;
+  aModIt.Next();
+  aModIt.ChangeValue() = 25;
+
+  EXPECT_EQ(aSeq(1), 15);
+  EXPECT_EQ(aSeq(2), 25);
+  EXPECT_EQ(aSeq(3), 30);
+
+  // Test STL-style iteration
+  int index            = 0;
+  int expectedValues[] = {15, 25, 30};
+  for (const auto& item : aSeq)
+  {
+    EXPECT_EQ(item, expectedValues[index++]);
+  }
+  EXPECT_EQ(index, 3);
+}
+
+TEST(NCollection_SequenceTest, CopyAndAssignment)
+{
+  NCollection_Sequence<ItemType> aSeq1;
+  aSeq1.Append(10);
+  aSeq1.Append(20);
+  aSeq1.Append(30);
+
+  // Test copy constructor
+  NCollection_Sequence<ItemType> aSeq2(aSeq1);
+  EXPECT_EQ(aSeq2.Size(), 3);
+  EXPECT_EQ(aSeq2(1), 10);
+  EXPECT_EQ(aSeq2(2), 20);
+  EXPECT_EQ(aSeq2(3), 30);
+
+  // Test assignment operator
+  NCollection_Sequence<ItemType> aSeq3;
+  aSeq3 = aSeq1;
+  EXPECT_EQ(aSeq3.Size(), 3);
+  EXPECT_EQ(aSeq3(1), 10);
+  EXPECT_EQ(aSeq3(2), 20);
+  EXPECT_EQ(aSeq3(3), 30);
+
+  // Modify original and verify copies don't change
+  aSeq1.SetValue(2, 25);
+  EXPECT_EQ(aSeq1(2), 25);
+  EXPECT_EQ(aSeq2(2), 20);
+  EXPECT_EQ(aSeq3(2), 20);
+}
+
+TEST(NCollection_SequenceTest, CombiningSequences)
+{
+  NCollection_Sequence<ItemType> aSeq1;
+  aSeq1.Append(10);
+  aSeq1.Append(20);
+
+  NCollection_Sequence<ItemType> aSeq2;
+  aSeq2.Append(30);
+  aSeq2.Append(40);
+
+  // Test Append(Sequence)
+  NCollection_Sequence<ItemType> aSeq3(aSeq1);
+  aSeq3.Append(aSeq2);
+  EXPECT_EQ(aSeq3.Size(), 4);
+  EXPECT_EQ(aSeq3(1), 10);
+  EXPECT_EQ(aSeq3(2), 20);
+  EXPECT_EQ(aSeq3(3), 30);
+  EXPECT_EQ(aSeq3(4), 40);
+  EXPECT_TRUE(aSeq2.IsEmpty()); // Original sequence should be emptied
+
+  // Test Prepend(Sequence)
+  aSeq2.Append(50);
+  aSeq2.Append(60);
+
+  NCollection_Sequence<ItemType> aSeq4;
+  aSeq4.Append(70);
+  aSeq4.Prepend(aSeq2);
+
+  EXPECT_EQ(aSeq4.Size(), 3);
+  EXPECT_EQ(aSeq4(1), 50);
+  EXPECT_EQ(aSeq4(2), 60);
+  EXPECT_EQ(aSeq4(3), 70);
+  EXPECT_TRUE(aSeq2.IsEmpty()); // Original sequence should be emptied
+
+  // Test InsertAfter(Sequence)
+  aSeq2.Append(80);
+  aSeq2.Append(90);
+
+  NCollection_Sequence<ItemType> aSeq5;
+  aSeq5.Append(100);
+  aSeq5.Append(110);
+  aSeq5.InsertAfter(1, aSeq2);
+
+  EXPECT_EQ(aSeq5.Size(), 4);
+  EXPECT_EQ(aSeq5(1), 100);
+  EXPECT_EQ(aSeq5(2), 80);
+  EXPECT_EQ(aSeq5(3), 90);
+  EXPECT_EQ(aSeq5(4), 110);
+  EXPECT_TRUE(aSeq2.IsEmpty()); // Original sequence should be emptied
+}
+
+TEST(NCollection_SequenceTest, AdvancedOperations)
+{
+  NCollection_Sequence<ItemType> aSeq;
+  aSeq.Append(10);
+  aSeq.Append(20);
+  aSeq.Append(30);
+  aSeq.Append(40);
+  aSeq.Append(50);
+
+  // Test Exchange
+  aSeq.Exchange(2, 4);
+  EXPECT_EQ(aSeq(1), 10);
+  EXPECT_EQ(aSeq(2), 40);
+  EXPECT_EQ(aSeq(3), 30);
+  EXPECT_EQ(aSeq(4), 20);
+  EXPECT_EQ(aSeq(5), 50);
+
+  // Test Reverse
+  aSeq.Reverse();
+  EXPECT_EQ(aSeq(1), 50);
+  EXPECT_EQ(aSeq(2), 20);
+  EXPECT_EQ(aSeq(3), 30);
+  EXPECT_EQ(aSeq(4), 40);
+  EXPECT_EQ(aSeq(5), 10);
+
+  // Test Split
+  NCollection_Sequence<ItemType> aSeq2;
+  aSeq.Split(2, aSeq2);
+
+  EXPECT_EQ(aSeq.Size(), 1);
+  EXPECT_EQ(aSeq(1), 50);
+
+  EXPECT_EQ(aSeq2.Size(), 4);
+  EXPECT_EQ(aSeq2(1), 20);
+  EXPECT_EQ(aSeq2(2), 30);
+  EXPECT_EQ(aSeq2(3), 40);
+  EXPECT_EQ(aSeq2(4), 10);
+
+  // Test Clear
+  aSeq.Clear();
+  EXPECT_TRUE(aSeq.IsEmpty());
+  EXPECT_EQ(aSeq.Size(), 0);
+}
+
+TEST(NCollection_SequenceTest, ComplexTypeSequence)
+{
+  NCollection_Sequence<TestClass> aSeq;
+
+  TestClass a(1, "First");
+  TestClass b(2, "Second");
+  TestClass c(3, "Third");
+
+  // Test appending complex types
+  aSeq.Append(a);
+  aSeq.Append(b);
+  aSeq.Append(c);
+
+  EXPECT_EQ(aSeq.Size(), 3);
+  EXPECT_EQ(aSeq(1).GetId(), 1);
+  EXPECT_STREQ(aSeq(1).GetName(), "First");
+  EXPECT_EQ(aSeq(2).GetId(), 2);
+  EXPECT_STREQ(aSeq(2).GetName(), "Second");
+  EXPECT_EQ(aSeq(3).GetId(), 3);
+  EXPECT_STREQ(aSeq(3).GetName(), "Third");
+
+  // Test modifying complex types
+  aSeq.ChangeValue(2) = TestClass(22, "Modified");
+  EXPECT_EQ(aSeq(2).GetId(), 22);
+  EXPECT_STREQ(aSeq(2).GetName(), "Modified");
+
+  // Test erasing with complex type
+  aSeq.Remove(1);
+  EXPECT_EQ(aSeq.Size(), 2);
+  EXPECT_EQ(aSeq.First().GetId(), 22);
+}
+
+TEST(NCollection_SequenceTest, AllocatorTest)
+{
+  // Test with custom allocator
+  Handle(NCollection_BaseAllocator) aAlloc = new NCollection_IncAllocator();
+  NCollection_Sequence<ItemType>    aSeq(aAlloc);
+
+  aSeq.Append(10);
+  aSeq.Append(20);
+  aSeq.Append(30);
+
+  EXPECT_EQ(aSeq.Size(), 3);
+  EXPECT_EQ(aSeq(1), 10);
+  EXPECT_EQ(aSeq(2), 20);
+  EXPECT_EQ(aSeq(3), 30);
+
+  // Test Clear with new allocator
+  Handle(NCollection_BaseAllocator) aAlloc2 = new NCollection_IncAllocator();
+  aSeq.Clear(aAlloc2);
+  EXPECT_TRUE(aSeq.IsEmpty());
+
+  // Add new items to verify the new allocator is working
+  aSeq.Append(40);
+  EXPECT_EQ(aSeq(1), 40);
+}
+
+TEST(NCollection_SequenceTest, MoveOperations)
+{
+  // Test move constructor
+  NCollection_Sequence<ItemType> aSeq1;
+  aSeq1.Append(10);
+  aSeq1.Append(20);
+  aSeq1.Append(30);
+
+  NCollection_Sequence<ItemType> aSeq2(std::move(aSeq1));
+  EXPECT_TRUE(aSeq1.IsEmpty()); // Original sequence should be empty after move
+  EXPECT_EQ(aSeq2.Size(), 3);
+  EXPECT_EQ(aSeq2(1), 10);
+  EXPECT_EQ(aSeq2(2), 20);
+  EXPECT_EQ(aSeq2(3), 30);
+
+  // Test move assignment
+  NCollection_Sequence<ItemType> aSeq3;
+  aSeq3.Append(40);
+
+  NCollection_Sequence<ItemType> aSeq4;
+  aSeq4 = std::move(aSeq3);
+  EXPECT_TRUE(aSeq3.IsEmpty()); // Original sequence should be empty after move
+  EXPECT_EQ(aSeq4.Size(), 1);
+  EXPECT_EQ(aSeq4(1), 40);
+}
\ No newline at end of file
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_SparseArray_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_SparseArray_Test.cxx
new file mode 100644 (file)
index 0000000..df39da1
--- /dev/null
@@ -0,0 +1,301 @@
+// 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_SparseArray.hxx>
+
+#include <gtest/gtest.h>
+
+// Basic test type for the SparseArray
+typedef Standard_Integer ItemType;
+
+// Custom class for testing complex types in the SparseArray
+class TestClass
+{
+public:
+  TestClass(int id = 0, double value = 0.0)
+      : myId(id),
+        myValue(value)
+  {
+  }
+
+  bool operator==(const TestClass& other) const
+  {
+    return myId == other.myId && fabs(myValue - other.myValue) < 1e-10;
+  }
+
+  bool operator!=(const TestClass& other) const { return !(*this == other); }
+
+  int GetId() const { return myId; }
+
+  double GetValue() const { return myValue; }
+
+  void SetValue(double value) { myValue = value; }
+
+private:
+  int    myId;
+  double myValue;
+};
+
+TEST(NCollection_SparseArrayTest, BasicFunctions)
+{
+  // Test constructor with increment
+  NCollection_SparseArray<ItemType> anArray(10);
+
+  // Test initial state
+  EXPECT_TRUE(anArray.IsEmpty());
+  EXPECT_EQ(anArray.Size(), 0);
+  EXPECT_EQ(anArray.Extent(), 0);
+
+  // Test setting values
+  anArray.SetValue(5, 55);
+  anArray.SetValue(15, 155);
+
+  EXPECT_FALSE(anArray.IsEmpty());
+  EXPECT_EQ(anArray.Size(), 2);
+
+  // Test value access
+  EXPECT_EQ(anArray.Value(5), 55);
+  EXPECT_EQ(anArray(15), 155);
+
+  // Test HasValue (IsBound)
+  EXPECT_TRUE(anArray.HasValue(5));
+  EXPECT_TRUE(anArray.IsBound(15));
+  EXPECT_FALSE(anArray.HasValue(10));
+  EXPECT_FALSE(anArray.IsBound(20));
+
+  // Test UnsetValue (UnBind)
+  EXPECT_TRUE(anArray.UnsetValue(5));
+  EXPECT_FALSE(anArray.HasValue(5));
+  EXPECT_EQ(anArray.Size(), 1);
+
+  // Test modifying a value
+  anArray.ChangeValue(15) = 255;
+  EXPECT_EQ(anArray.Value(15), 255);
+}
+
+TEST(NCollection_SparseArrayTest, LargeIndices)
+{
+  NCollection_SparseArray<ItemType> anArray(10);
+
+  // Test with large indices
+  const Standard_Size largeIndex1 = 1000;
+  const Standard_Size largeIndex2 = 10000;
+
+  anArray.SetValue(largeIndex1, 1000);
+  anArray.SetValue(largeIndex2, 10000);
+
+  EXPECT_EQ(anArray.Size(), 2);
+  EXPECT_TRUE(anArray.HasValue(largeIndex1));
+  EXPECT_TRUE(anArray.HasValue(largeIndex2));
+  EXPECT_EQ(anArray.Value(largeIndex1), 1000);
+  EXPECT_EQ(anArray.Value(largeIndex2), 10000);
+}
+
+TEST(NCollection_SparseArrayTest, SparseDistribution)
+{
+  NCollection_SparseArray<ItemType> anArray(8);
+
+  // Set values with sparse distribution
+  anArray.SetValue(3, 3);
+  anArray.SetValue(10, 10);
+  anArray.SetValue(17, 17);
+  anArray.SetValue(100, 100);
+  anArray.SetValue(1000, 1000);
+
+  EXPECT_EQ(anArray.Size(), 5);
+  EXPECT_TRUE(anArray.HasValue(3));
+  EXPECT_TRUE(anArray.HasValue(10));
+  EXPECT_TRUE(anArray.HasValue(17));
+  EXPECT_TRUE(anArray.HasValue(100));
+  EXPECT_TRUE(anArray.HasValue(1000));
+
+  // Test gaps have no value
+  EXPECT_FALSE(anArray.HasValue(4));
+  EXPECT_FALSE(anArray.HasValue(11));
+  EXPECT_FALSE(anArray.HasValue(101));
+}
+
+TEST(NCollection_SparseArrayTest, IteratorFunctions)
+{
+  NCollection_SparseArray<ItemType> anArray(8);
+
+  // Set some values
+  anArray.SetValue(5, 50);
+  anArray.SetValue(10, 100);
+  anArray.SetValue(20, 200);
+  anArray.SetValue(30, 300);
+
+  // Test const iterator
+  NCollection_SparseArray<ItemType>::ConstIterator anIt(anArray);
+
+  // Check that iterator finds all values in some order
+  Standard_Boolean found5  = Standard_False;
+  Standard_Boolean found10 = Standard_False;
+  Standard_Boolean found20 = Standard_False;
+  Standard_Boolean found30 = Standard_False;
+  Standard_Size    count   = 0;
+
+  for (; anIt.More(); anIt.Next(), ++count)
+  {
+    Standard_Size index = anIt.Index();
+    ItemType      value = anIt.Value();
+
+    if (index == 5 && value == 50)
+      found5 = Standard_True;
+    else if (index == 10 && value == 100)
+      found10 = Standard_True;
+    else if (index == 20 && value == 200)
+      found20 = Standard_True;
+    else if (index == 30 && value == 300)
+      found30 = Standard_True;
+  }
+
+  EXPECT_EQ(count, 4);
+  EXPECT_TRUE(found5);
+  EXPECT_TRUE(found10);
+  EXPECT_TRUE(found20);
+  EXPECT_TRUE(found30);
+
+  // Test non-const iterator
+  NCollection_SparseArray<ItemType>::Iterator aModIt(anArray);
+
+  // Modify values through iterator
+  for (; aModIt.More(); aModIt.Next())
+  {
+    aModIt.ChangeValue() *= 2;
+  }
+
+  // Check modified values
+  EXPECT_EQ(anArray.Value(5), 100);
+  EXPECT_EQ(anArray.Value(10), 200);
+  EXPECT_EQ(anArray.Value(20), 400);
+  EXPECT_EQ(anArray.Value(30), 600);
+}
+
+TEST(NCollection_SparseArrayTest, ComplexType)
+{
+  NCollection_SparseArray<TestClass> anArray(10);
+
+  // Set values with complex type
+  anArray.SetValue(5, TestClass(5, 3.14));
+  anArray.SetValue(10, TestClass(10, 2.718));
+
+  EXPECT_EQ(anArray.Size(), 2);
+
+  // Check values
+  EXPECT_EQ(anArray.Value(5).GetId(), 5);
+  EXPECT_DOUBLE_EQ(anArray.Value(5).GetValue(), 3.14);
+
+  EXPECT_EQ(anArray.Value(10).GetId(), 10);
+  EXPECT_DOUBLE_EQ(anArray.Value(10).GetValue(), 2.718);
+
+  // Modify through ChangeValue
+  anArray.ChangeValue(5).SetValue(6.28);
+  EXPECT_DOUBLE_EQ(anArray.Value(5).GetValue(), 6.28);
+
+  // Test unset with complex type
+  EXPECT_TRUE(anArray.UnsetValue(5));
+  EXPECT_FALSE(anArray.HasValue(5));
+}
+
+TEST(NCollection_SparseArrayTest, Clear)
+{
+  NCollection_SparseArray<ItemType> anArray(8);
+
+  // Set some values
+  anArray.SetValue(5, 5);
+  anArray.SetValue(10, 10);
+  anArray.SetValue(15, 15);
+
+  EXPECT_EQ(anArray.Size(), 3);
+
+  // Clear the array
+  anArray.Clear();
+
+  EXPECT_TRUE(anArray.IsEmpty());
+  EXPECT_EQ(anArray.Size(), 0);
+  EXPECT_FALSE(anArray.HasValue(5));
+  EXPECT_FALSE(anArray.HasValue(10));
+  EXPECT_FALSE(anArray.HasValue(15));
+}
+
+TEST(NCollection_SparseArrayTest, DataMapInterface)
+{
+  NCollection_SparseArray<ItemType> anArray(10);
+
+  // Test Bind method
+  anArray.Bind(5, 50);
+  anArray.Bind(15, 150);
+
+  EXPECT_TRUE(anArray.IsBound(5));
+  EXPECT_TRUE(anArray.IsBound(15));
+
+  // Test Find method
+  EXPECT_EQ(anArray.Find(5), 50);
+  EXPECT_EQ(anArray.Find(15), 150);
+
+  // Test ChangeFind method
+  anArray.ChangeFind(5) = 55;
+  EXPECT_EQ(anArray.Find(5), 55);
+
+  // Test UnBind method
+  EXPECT_TRUE(anArray.UnBind(5));
+  EXPECT_FALSE(anArray.IsBound(5));
+  EXPECT_EQ(anArray.Size(), 1);
+}
+
+TEST(NCollection_SparseArrayTest, AssignAndExchange)
+{
+  // Create and populate first array
+  NCollection_SparseArray<ItemType> anArray1(10);
+  anArray1.SetValue(5, 50);
+  anArray1.SetValue(15, 150);
+
+  // Test Assign method
+  NCollection_SparseArray<ItemType> anArray2(20);
+  anArray2.SetValue(7, 70);
+
+  anArray2.Assign(anArray1);
+
+  EXPECT_EQ(anArray2.Size(), 2);
+  EXPECT_TRUE(anArray2.HasValue(5));
+  EXPECT_TRUE(anArray2.HasValue(15));
+  EXPECT_EQ(anArray2.Value(5), 50);
+  EXPECT_EQ(anArray2.Value(15), 150);
+  EXPECT_FALSE(anArray2.HasValue(7)); // Should be removed after Assign
+
+  // Test Exchange method
+  NCollection_SparseArray<ItemType> anArray3(30);
+  anArray3.SetValue(10, 100);
+  anArray3.SetValue(20, 200);
+
+  anArray2.Exchange(anArray3);
+
+  // Check anArray2 after exchange (should have anArray3's values)
+  EXPECT_EQ(anArray2.Size(), 2);
+  EXPECT_TRUE(anArray2.HasValue(10));
+  EXPECT_TRUE(anArray2.HasValue(20));
+  EXPECT_EQ(anArray2.Value(10), 100);
+  EXPECT_EQ(anArray2.Value(20), 200);
+  EXPECT_FALSE(anArray2.HasValue(5));
+  EXPECT_FALSE(anArray2.HasValue(15));
+
+  // Check anArray3 after exchange (should have anArray2's values)
+  EXPECT_EQ(anArray3.Size(), 2);
+  EXPECT_TRUE(anArray3.HasValue(5));
+  EXPECT_TRUE(anArray3.HasValue(15));
+  EXPECT_EQ(anArray3.Value(5), 50);
+  EXPECT_EQ(anArray3.Value(15), 150);
+  EXPECT_FALSE(anArray3.HasValue(10));
+  EXPECT_FALSE(anArray3.HasValue(20));
+}
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_Vector_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_Vector_Test.cxx
new file mode 100644 (file)
index 0000000..65b3796
--- /dev/null
@@ -0,0 +1,382 @@
+// 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_BaseAllocator.hxx>
+#include <NCollection_Vector.hxx>
+#include <Standard_Integer.hxx>
+
+#include <gtest/gtest.h>
+
+TEST(NCollection_VectorTest, DefaultConstructor)
+{
+  // Default constructor should create an empty vector
+  NCollection_Vector<Standard_Integer> aVector;
+
+  EXPECT_EQ(0, aVector.Length());
+  EXPECT_TRUE(aVector.IsEmpty());
+}
+
+TEST(NCollection_VectorTest, ResizeConstructor)
+{
+  // Test constructor with initial size
+  const Standard_Integer               initialSize  = 10;
+  const Standard_Integer               initialValue = 42;
+  NCollection_Vector<Standard_Integer> aVector(initialSize);
+
+  // Initialize all elements to the same value
+  for (Standard_Integer i = 0; i < initialSize; i++)
+  {
+    aVector.SetValue(i, initialValue);
+  }
+
+  EXPECT_EQ(initialSize, aVector.Length());
+  EXPECT_FALSE(aVector.IsEmpty());
+
+  // Check all values are initialized
+  for (Standard_Integer i = 0; i < initialSize; i++)
+  {
+    EXPECT_EQ(initialValue, aVector(i));
+  }
+}
+
+TEST(NCollection_VectorTest, Append)
+{
+  NCollection_Vector<Standard_Integer> aVector;
+
+  // Test Append method
+  aVector.Append(10);
+  aVector.Append(20);
+  aVector.Append(30);
+
+  EXPECT_EQ(3, aVector.Length());
+  EXPECT_EQ(10, aVector(0));
+  EXPECT_EQ(20, aVector(1));
+  EXPECT_EQ(30, aVector(2));
+}
+
+TEST(NCollection_VectorTest, SetValue)
+{
+  NCollection_Vector<Standard_Integer> aVector(5, 0);
+
+  // Test SetValue method
+  aVector.SetValue(2, 42);
+
+  EXPECT_EQ(42, aVector(2));
+  EXPECT_EQ(0, aVector(0));
+  EXPECT_EQ(0, aVector(1));
+
+  // Test operator()
+  aVector(3) = 99;
+  EXPECT_EQ(99, aVector(3));
+}
+
+TEST(NCollection_VectorTest, Value)
+{
+  NCollection_Vector<Standard_Integer> aVector;
+  aVector.Append(10);
+  aVector.Append(20);
+
+  // Test Value and operator()
+  EXPECT_EQ(10, aVector.Value(0));
+  EXPECT_EQ(20, aVector.Value(1));
+
+  EXPECT_EQ(aVector.Value(0), aVector(0));
+  EXPECT_EQ(aVector.Value(1), aVector(1));
+}
+
+TEST(NCollection_VectorTest, ChangeValue)
+{
+  NCollection_Vector<Standard_Integer> aVector;
+  aVector.Append(10);
+  aVector.Append(20);
+
+  // Test ChangeValue
+  aVector.ChangeValue(1) = 25;
+  EXPECT_EQ(25, aVector(1));
+
+  // Equivalent using operator()
+  aVector(0) = 15;
+  EXPECT_EQ(15, aVector(0));
+}
+
+TEST(NCollection_VectorTest, FirstLast)
+{
+  NCollection_Vector<Standard_Integer> aVector;
+  aVector.Append(10);
+  aVector.Append(20);
+  aVector.Append(30);
+
+  // Test First and Last
+  EXPECT_EQ(10, aVector.First());
+  EXPECT_EQ(30, aVector.Last());
+
+  // Test ChangeFirst and ChangeLast
+  aVector.ChangeFirst() = 15;
+  aVector.ChangeLast()  = 35;
+
+  EXPECT_EQ(15, aVector.First());
+  EXPECT_EQ(35, aVector.Last());
+}
+
+TEST(NCollection_VectorTest, CopyConstructor)
+{
+  NCollection_Vector<Standard_Integer> aVector1;
+  aVector1.Append(10);
+  aVector1.Append(20);
+  aVector1.Append(30);
+
+  // Test copy constructor
+  NCollection_Vector<Standard_Integer> aVector2(aVector1);
+
+  EXPECT_EQ(aVector1.Length(), aVector2.Length());
+
+  for (Standard_Integer i = 0; i < aVector1.Length(); i++)
+  {
+    EXPECT_EQ(aVector1(i), aVector2(i));
+  }
+
+  // Modify original to ensure deep copy
+  aVector1(1) = 25;
+  EXPECT_EQ(20, aVector2(1));
+}
+
+TEST(NCollection_VectorTest, AssignmentOperator)
+{
+  NCollection_Vector<Standard_Integer> aVector1;
+  aVector1.Append(10);
+  aVector1.Append(20);
+  aVector1.Append(30);
+
+  // Test assignment operator
+  NCollection_Vector<Standard_Integer> aVector2;
+  aVector2 = aVector1;
+
+  EXPECT_EQ(aVector1.Length(), aVector2.Length());
+
+  for (Standard_Integer i = 0; i < aVector1.Length(); i++)
+  {
+    EXPECT_EQ(aVector1(i), aVector2(i));
+  }
+
+  // Modify original to ensure deep copy
+  aVector1(1) = 25;
+  EXPECT_EQ(20, aVector2(1));
+}
+
+TEST(NCollection_VectorTest, Clear)
+{
+  NCollection_Vector<Standard_Integer> aVector;
+  aVector.Append(10);
+  aVector.Append(20);
+
+  // Test Clear
+  aVector.Clear();
+
+  EXPECT_EQ(0, aVector.Length());
+  EXPECT_TRUE(aVector.IsEmpty());
+}
+
+TEST(NCollection_VectorTest, Iterator)
+{
+  NCollection_Vector<Standard_Integer> aVector;
+  aVector.Append(10);
+  aVector.Append(20);
+  aVector.Append(30);
+
+  // Test iterator
+  Standard_Integer sum = 0;
+  for (NCollection_Vector<Standard_Integer>::Iterator it(aVector); it.More(); it.Next())
+  {
+    sum += it.Value();
+  }
+
+  EXPECT_EQ(60, sum);
+
+  // Test modifying values through iterator
+  for (NCollection_Vector<Standard_Integer>::Iterator it(aVector); it.More(); it.Next())
+  {
+    it.ChangeValue() *= 2;
+  }
+
+  EXPECT_EQ(20, aVector(0));
+  EXPECT_EQ(40, aVector(1));
+  EXPECT_EQ(60, aVector(2));
+}
+
+TEST(NCollection_VectorTest, STLIterators)
+{
+  NCollection_Vector<Standard_Integer> aVector;
+  aVector.Append(10);
+  aVector.Append(20);
+  aVector.Append(30);
+
+  // Test C++11 range-based for loop with STL-style iterators
+  Standard_Integer sum = 0;
+  for (const auto& val : aVector)
+  {
+    sum += val;
+  }
+
+  EXPECT_EQ(60, sum);
+
+  // Test modification through iterator
+  sum = 0;
+  for (auto& val : aVector)
+  {
+    val *= 2; // Double each value
+    sum += val;
+  }
+
+  EXPECT_EQ(120, sum);
+
+  // Verify the modifications
+  EXPECT_EQ(20, aVector(0));
+  EXPECT_EQ(40, aVector(1));
+  EXPECT_EQ(60, aVector(2));
+}
+
+TEST(NCollection_VectorTest, Grow)
+{
+  NCollection_Vector<Standard_Integer> aVector;
+
+  // Test automatic resize through many appends
+  for (Standard_Integer i = 0; i < 1000; i++)
+  {
+    aVector.Append(i);
+  }
+
+  EXPECT_EQ(1000, aVector.Length());
+
+  for (Standard_Integer i = 0; i < 1000; i++)
+  {
+    EXPECT_EQ(i, aVector(i));
+  }
+}
+
+TEST(NCollection_VectorTest, Move)
+{
+  NCollection_Vector<Standard_Integer> aVector1;
+  aVector1.Append(10);
+  aVector1.Append(20);
+
+  // Test Move constructor
+  NCollection_Vector<Standard_Integer> aVector2 = std::move(aVector1);
+
+  EXPECT_EQ(0, aVector1.Length()); // aVector1 should be empty after move
+  EXPECT_EQ(2, aVector2.Length());
+  EXPECT_EQ(10, aVector2(0));
+  EXPECT_EQ(20, aVector2(1));
+
+  // Test Move assignment
+  NCollection_Vector<Standard_Integer> aVector3;
+  aVector3.Append(30);
+  aVector3 = std::move(aVector2);
+
+  EXPECT_EQ(0, aVector2.Length()); // aVector2 should be empty after move
+  EXPECT_EQ(2, aVector3.Length());
+  EXPECT_EQ(10, aVector3(0));
+  EXPECT_EQ(20, aVector3(1));
+}
+
+TEST(NCollection_VectorTest, EraseLast)
+{
+  NCollection_Vector<Standard_Integer> aVector;
+  aVector.Append(10);
+  aVector.Append(20);
+  aVector.Append(30);
+
+  EXPECT_EQ(3, aVector.Length());
+
+  // Test EraseLast method
+  aVector.EraseLast();
+  EXPECT_EQ(2, aVector.Length());
+  EXPECT_EQ(10, aVector(0));
+  EXPECT_EQ(20, aVector(1));
+
+  // Remove another element
+  aVector.EraseLast();
+  EXPECT_EQ(1, aVector.Length());
+  EXPECT_EQ(10, aVector(0));
+
+  // Remove the last element
+  aVector.EraseLast();
+  EXPECT_EQ(0, aVector.Length());
+  EXPECT_TRUE(aVector.IsEmpty());
+
+  // Calling EraseLast on an empty vector should not cause errors
+  aVector.EraseLast();
+  EXPECT_EQ(0, aVector.Length());
+}
+
+TEST(NCollection_VectorTest, Appended)
+{
+  NCollection_Vector<Standard_Integer> aVector;
+
+  // Test Appended method - returns reference to the appended element
+  Standard_Integer& ref1 = aVector.Appended();
+  ref1                   = 10;
+
+  Standard_Integer& ref2 = aVector.Appended();
+  ref2                   = 20;
+
+  EXPECT_EQ(2, aVector.Length());
+  EXPECT_EQ(10, aVector(0));
+  EXPECT_EQ(20, aVector(1));
+
+  // Modify through the reference
+  ref1 = 15;
+  EXPECT_EQ(15, aVector(0));
+}
+
+TEST(NCollection_VectorTest, CustomAllocator)
+{
+  // Test with custom allocator
+  Handle(NCollection_BaseAllocator)    anAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
+  NCollection_Vector<Standard_Integer> aVector(256, anAlloc);
+
+  // Verify vector works with custom allocator
+  aVector.Append(10);
+  aVector.Append(20);
+  aVector.Append(30);
+
+  EXPECT_EQ(3, aVector.Length());
+  EXPECT_EQ(10, aVector(0));
+  EXPECT_EQ(20, aVector(1));
+  EXPECT_EQ(30, aVector(2));
+
+  // Test clear with custom allocator
+  aVector.Clear();
+  EXPECT_EQ(0, aVector.Length());
+}
+
+TEST(NCollection_VectorTest, SetIncrement)
+{
+  NCollection_Vector<Standard_Integer> aVector;
+
+  // SetIncrement only works on empty vectors
+  aVector.SetIncrement(512);
+
+  // Fill the vector to test the custom increment size
+  for (Standard_Integer i = 0; i < 1000; i++)
+  {
+    aVector.Append(i);
+  }
+
+  EXPECT_EQ(1000, aVector.Length());
+
+  // Verify data integrity with the custom increment
+  for (Standard_Integer i = 0; i < 1000; i++)
+  {
+    EXPECT_EQ(i, aVector(i));
+  }
+}
\ No newline at end of file