From 5e5e7f123834444c2f02e7267111619e5c61ef47 Mon Sep 17 00:00:00 2001 From: Pasukhin Dmitry Date: Sun, 6 Apr 2025 12:40:14 +0100 Subject: [PATCH] Testing - Units Tests for NCollection package #481 - 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. --- .github/actions/run-gtest/action.yml | 2 +- .../TKernel/GTests/FILES.cmake | 12 + .../GTests/NCollection_Array1_Test.cxx | 354 +++++++++ .../GTests/NCollection_BaseAllocator_Test.cxx | 220 ++++++ .../GTests/NCollection_DataMap_Test.cxx | 234 ++++++ .../GTests/NCollection_DoubleMap_Test.cxx | 460 ++++++++++++ .../NCollection_IndexedDataMap_Test.cxx | 705 ++++++++++++++++++ .../GTests/NCollection_IndexedMap_Test.cxx | 514 +++++++++++++ .../TKernel/GTests/NCollection_List_Test.cxx | 402 ++++++++++ .../GTests/NCollection_LocalArray_Test.cxx | 191 +++++ .../TKernel/GTests/NCollection_Map_Test.cxx | 218 ++++++ .../GTests/NCollection_Sequence_Test.cxx | 375 ++++++++++ .../GTests/NCollection_SparseArray_Test.cxx | 301 ++++++++ .../GTests/NCollection_Vector_Test.cxx | 382 ++++++++++ 14 files changed, 4369 insertions(+), 1 deletion(-) create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_Array1_Test.cxx create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_BaseAllocator_Test.cxx create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_DataMap_Test.cxx create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_DoubleMap_Test.cxx create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_IndexedDataMap_Test.cxx create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_IndexedMap_Test.cxx create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_List_Test.cxx create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_LocalArray_Test.cxx create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_Map_Test.cxx create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_Sequence_Test.cxx create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_SparseArray_Test.cxx create mode 100644 src/FoundationClasses/TKernel/GTests/NCollection_Vector_Test.cxx diff --git a/.github/actions/run-gtest/action.yml b/.github/actions/run-gtest/action.yml index 16bf9259af..9eae4b5365 100644 --- a/.github/actions/run-gtest/action.yml +++ b/.github/actions/run-gtest/action.yml @@ -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 diff --git a/src/FoundationClasses/TKernel/GTests/FILES.cmake b/src/FoundationClasses/TKernel/GTests/FILES.cmake index c8e80d1d99..04eec73755 100644 --- a/src/FoundationClasses/TKernel/GTests/FILES.cmake +++ b/src/FoundationClasses/TKernel/GTests/FILES.cmake @@ -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 index 0000000000..01e9a74b35 --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_Array1_Test.cxx @@ -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 +#include + +#include + +// 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 anArray; + // Instead we need to use the parameterized constructor + NCollection_Array1 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 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 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 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 anArray1(1, 5); + + // Initialize array + for (Standard_Integer i = anArray1.Lower(); i <= anArray1.Upper(); i++) + { + anArray1(i) = i * 10; + } + + // Copy construct + NCollection_Array1 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 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 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 anArray1(1, 5); + + // Initialize array + for (Standard_Integer i = anArray1.Lower(); i <= anArray1.Upper(); i++) + { + anArray1(i) = i * 10; + } + + // Test assignment + NCollection_Array1 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 anArray1(1, 5); + + // Initialize array + for (Standard_Integer i = anArray1.Lower(); i <= anArray1.Upper(); i++) + { + anArray1(i) = i * 10; + } + + // Test Move method + NCollection_Array1 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 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 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 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 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 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 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 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 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 index 0000000000..f7492d14e5 --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_BaseAllocator_Test.cxx @@ -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 +#include + +#include + +// 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(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(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('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('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 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 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 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 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 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 index 0000000000..7b344a1035 --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_DataMap_Test.cxx @@ -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 +#include +#include + +#include + +// 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 aMap; + + EXPECT_TRUE(aMap.IsEmpty()); + EXPECT_EQ(0, aMap.Size()); + EXPECT_EQ(0, aMap.Extent()); +} + +TEST_F(NCollection_DataMapTest, BindingAndAccess) +{ + NCollection_DataMap 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 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 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 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 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 aMap1; + aMap1.Bind(1, "One"); + aMap1.Bind(2, "Two"); + + // Test assignment operator + NCollection_DataMap 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 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 aMap; + aMap.Bind(1, "One"); + aMap.Bind(2, "Two"); + aMap.Bind(3, "Three"); + + // Test iteration using OCCT iterator + NCollection_DataMap::Iterator it(aMap); + + // Create sets to check all keys and values are visited + std::set foundKeys; + std::set 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 aMap; + aMap.Bind(1, "One"); + + // Test Value change through iterator + NCollection_DataMap::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 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::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 index 0000000000..b12ab430b5 --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_DoubleMap_Test.cxx @@ -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 +#include + +#include + +// 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 +{ + size_t operator()(const TestKey1& key) const + { + return static_cast(key.GetId() + std::hash()(key.GetName())); + } +}; + +template <> +struct hash +{ + size_t operator()(const TestKey2& key) const + { + return static_cast(key.GetValue() * 100 + std::hash()(key.GetCode())); + } +}; +} // namespace std + +TEST(NCollection_DoubleMapTest, DefaultConstructor) +{ + // Test default constructor + NCollection_DoubleMap 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 aMap(100); + EXPECT_TRUE(aMap.IsEmpty()); + EXPECT_EQ(aMap.Extent(), 0); + EXPECT_EQ(aMap.Size(), 0); +} + +TEST(NCollection_DoubleMapTest, BasicBindFind) +{ + NCollection_DoubleMap 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 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 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 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 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 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 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 aMap1; + NCollection_DoubleMap 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 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(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(i) / 10.0)); + EXPECT_DOUBLE_EQ(aMap.Find1(i), static_cast(i) / 10.0); + EXPECT_EQ(aMap.Find2(static_cast(i) / 10.0), i); + } +} + +TEST(NCollection_DoubleMapTest, Exchange) +{ + NCollection_DoubleMap aMap1; + NCollection_DoubleMap 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 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::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 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 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 index 0000000000..a7d108feef --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_IndexedDataMap_Test.cxx @@ -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 +#include + +#include + +// 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 +{ + size_t operator()(const TestKey& key) const + { + // Combine the hash + size_t aCombintation[2] = {std::hash()(key.GetId()), + std::hash()(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 aMap; + EXPECT_TRUE(aMap.IsEmpty()); + EXPECT_EQ(aMap.Extent(), 0); + EXPECT_EQ(aMap.Size(), 0); +} + +TEST(NCollection_IndexedDataMapTest, BasicAddFind) +{ + NCollection_IndexedDataMap 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 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 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 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 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 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 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 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 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 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 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 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 aMap1; + NCollection_IndexedDataMap 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 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::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::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 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 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 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 aMap1; + NCollection_IndexedDataMap 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 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(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(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(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 index 0000000000..cc51e0f1c1 --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_IndexedMap_Test.cxx @@ -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 +#include + +#include + +// 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()(theKey.GetId()), + std::hash()(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 aMap; + EXPECT_TRUE(aMap.IsEmpty()); + EXPECT_EQ(aMap.Extent(), 0); + EXPECT_EQ(aMap.Size(), 0); +} + +TEST(NCollection_IndexedMapTest, BasicAddFind) +{ + NCollection_IndexedMap 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 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 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 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 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 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 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 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 aMap1; + + // Add elements to first map + aMap1.Add(10); + aMap1.Add(20); + aMap1.Add(30); + + // Create a copy + NCollection_IndexedMap 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 aMap1; + NCollection_IndexedMap 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 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::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 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 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 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 aMap1; + NCollection_IndexedMap 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 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 index 0000000000..0cd2ee6dac --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_List_Test.cxx @@ -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 +#include + +#include + +// 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 aList; + EXPECT_TRUE(aList.IsEmpty()); + EXPECT_EQ(0, aList.Size()); + EXPECT_EQ(0, aList.Extent()); +} + +TEST_F(NCollection_ListTest, Append) +{ + NCollection_List 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 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 aList; + aList.Append(10); + aList.Append(20); + aList.Append(30); + + // Test iteration using OCCT iterator + NCollection_List::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 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 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 aList; + aList.Append(10); + aList.Append(20); + aList.Append(30); + + // Test Remove with iterator + NCollection_List::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 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::Iterator it(aList); + EXPECT_EQ(20, it.Value()); + it.Next(); + EXPECT_EQ(30, it.Value()); +} + +TEST_F(NCollection_ListTest, Clear) +{ + NCollection_List 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 aList1; + aList1.Append(10); + aList1.Append(20); + aList1.Append(30); + + // Test assignment operator + NCollection_List aList2; + aList2 = aList1; + + // Check both lists have the same content + EXPECT_EQ(aList1.Size(), aList2.Size()); + + NCollection_List::Iterator it1(aList1); + NCollection_List::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 aList1; + aList1.Append(10); + aList1.Append(20); + aList1.Append(30); + + // Test Assign method + NCollection_List 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::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 aList1; + aList1.Append(10); + aList1.Append(20); + + NCollection_List 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::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 aList1; + aList1.Append(30); + aList1.Append(40); + + NCollection_List 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::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 aList; + aList.Append(10); + aList.Append(30); + + // Get iterator to second element + NCollection_List::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::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 aList; + aList.Append(10); + aList.Append(30); + + // Get iterator to first element + NCollection_List::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::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 aList1; + aList1.Append(10); + aList1.Append(40); + + NCollection_List aList2; + aList2.Append(20); + aList2.Append(30); + + // Get iterator to the second element in aList1 + NCollection_List::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::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 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::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 index 0000000000..c5de4b0197 --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_LocalArray_Test.cxx @@ -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 + +#include + +// Test default constructor and initial state +TEST(NCollection_LocalArrayTest, DefaultConstructor) +{ + NCollection_LocalArray array; + EXPECT_EQ(0, array.Size()); +} + +// Test constructor with size +TEST(NCollection_LocalArrayTest, ConstructorWithSize) +{ + const size_t size = 100; + NCollection_LocalArray 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 array(size); + EXPECT_EQ(size, array.Size()); + + // Populate array + for (size_t i = 0; i < size; ++i) + { + array[i] = static_cast(i * 10); + } + + // Verify array contents + for (size_t i = 0; i < size; ++i) + { + EXPECT_EQ(static_cast(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 array(size); + EXPECT_EQ(size, array.Size()); + + // Populate array + for (size_t i = 0; i < size; ++i) + { + array[i] = static_cast(i * 10); + } + + // Verify array contents + for (size_t i = 0; i < size; ++i) + { + EXPECT_EQ(static_cast(i * 10), array[i]); + } +} + +// Test reallocation +TEST(NCollection_LocalArrayTest, Reallocation) +{ + NCollection_LocalArray array(10); + EXPECT_EQ(10, array.Size()); + + // Populate array + for (size_t i = 0; i < 10; ++i) + { + array[i] = static_cast(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(i * 2); + } + + // Verify array contents + for (size_t i = 0; i < 50; ++i) + { + EXPECT_EQ(static_cast(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(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 smallArray(20); + EXPECT_EQ(20, smallArray.Size()); + + // Test with size greater than custom max + NCollection_LocalArray 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 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 array; + + // Initially allocate in stack buffer + array.Allocate(5); + for (size_t i = 0; i < 5; ++i) + { + array[i] = static_cast(i); + } + + // Verify array contents + for (size_t i = 0; i < 5; ++i) + { + EXPECT_EQ(static_cast(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(i * 3); + } + + // Verify heap allocation + for (size_t i = 0; i < maxSize + 10; ++i) + { + EXPECT_EQ(static_cast(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(i * 5); + } + + // Verify stack allocation again + for (size_t i = 0; i < maxSize - 5; ++i) + { + EXPECT_EQ(static_cast(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 index 0000000000..9b3529eb86 --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_Map_Test.cxx @@ -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 +#include +#include + +#include + +TEST(NCollection_MapTest, DefaultConstructor) +{ + // Default constructor should create an empty map + NCollection_Map 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 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 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 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 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 aMap1; + aMap1.Add(10); + aMap1.Add(20); + aMap1.Add(30); + + // Test assignment operator + NCollection_Map 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 aMap; + aMap.Add(10); + aMap.Add(20); + aMap.Add(30); + + // Test iteration using OCCT iterator + NCollection_Map::Iterator it(aMap); + + // Create set to check all keys are visited + std::set 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 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 elements; + for (NCollection_Map::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 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::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 index 0000000000..ae1383cb67 --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_Sequence_Test.cxx @@ -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 +#include +#include + +#include + +// 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 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 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 aSeq; + aSeq.Append(10); + aSeq.Append(20); + aSeq.Append(30); + + // Test Iterator + NCollection_Sequence::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::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 aSeq1; + aSeq1.Append(10); + aSeq1.Append(20); + aSeq1.Append(30); + + // Test copy constructor + NCollection_Sequence 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 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 aSeq1; + aSeq1.Append(10); + aSeq1.Append(20); + + NCollection_Sequence aSeq2; + aSeq2.Append(30); + aSeq2.Append(40); + + // Test Append(Sequence) + NCollection_Sequence 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 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 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 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 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 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 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 aSeq1; + aSeq1.Append(10); + aSeq1.Append(20); + aSeq1.Append(30); + + NCollection_Sequence 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 aSeq3; + aSeq3.Append(40); + + NCollection_Sequence 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 index 0000000000..df39da1723 --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_SparseArray_Test.cxx @@ -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 + +#include + +// 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 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 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 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 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::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::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 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 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 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 anArray1(10); + anArray1.SetValue(5, 50); + anArray1.SetValue(15, 150); + + // Test Assign method + NCollection_SparseArray 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 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 index 0000000000..65b3796f8e --- /dev/null +++ b/src/FoundationClasses/TKernel/GTests/NCollection_Vector_Test.cxx @@ -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 +#include +#include + +#include + +TEST(NCollection_VectorTest, DefaultConstructor) +{ + // Default constructor should create an empty vector + NCollection_Vector 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 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 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 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 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 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 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 aVector1; + aVector1.Append(10); + aVector1.Append(20); + aVector1.Append(30); + + // Test copy constructor + NCollection_Vector 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 aVector1; + aVector1.Append(10); + aVector1.Append(20); + aVector1.Append(30); + + // Test assignment operator + NCollection_Vector 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 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 aVector; + aVector.Append(10); + aVector.Append(20); + aVector.Append(30); + + // Test iterator + Standard_Integer sum = 0; + for (NCollection_Vector::Iterator it(aVector); it.More(); it.Next()) + { + sum += it.Value(); + } + + EXPECT_EQ(60, sum); + + // Test modifying values through iterator + for (NCollection_Vector::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 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 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 aVector1; + aVector1.Append(10); + aVector1.Append(20); + + // Test Move constructor + NCollection_Vector 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 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 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 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 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 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 -- 2.39.5