Files
UnrealEngine/Engine/Source/Runtime/AssetRegistry/Private/SetKeyFuncsTest.cpp
2025-05-18 13:04:45 +08:00

239 lines
5.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#if WITH_TESTS
#include "SetKeyFuncs.h"
#include "Containers/Array.h"
#include "Tests/TestHarnessAdapter.h"
TEST_CASE_NAMED(FSetKeyFuncsTest, "System::AssetRegistry::SetKeyFuncs", "[ApplicationContextMask][EngingeFilter]")
{
struct FData
{
TArray<uint32> TypeHashes;
TArray<uint32> ValuesA;
TArray<uint32> ValuesB;
TArray<bool> ValueInSet;
TArray<bool> ValueInSetCopiedFromSet;
TArray<uint32> RemainingValues;
uint32 NumInSet = 0;
uint32 EndValue = 500;
};
struct FKeyFuncs1
{
uint32 GetInvalidElement()
{
return (uint32)-1;
}
bool IsInvalid(uint32 Value)
{
return Value == (uint32)-1;
}
uint32 GetTypeHash(uint32 Value)
{
if (Value < Data->EndValue)
{
uint32 TypeHash = Data->TypeHashes[Value];
if (TypeHash != (uint32)-1)
{
return TypeHash;
}
}
FAIL_CHECK(FString::Printf(TEXT("GetTypeHash was unexpectedly called on unknown value %u."), Value));
return (uint32)-1;
}
bool Matches(uint32 A, uint32 B)
{
return A == B;
}
FData* Data;
};
FData Data;
TSetKeyFuncs<uint32, FKeyFuncs1> Set(FKeyFuncs1{ &Data });
auto ValidateExpectedSetContents = [&Data, &Set]()
{
for (uint32 VFind = 0; VFind < Data.EndValue; ++VFind)
{
if (Data.TypeHashes[VFind] == (uint32)-1)
{
continue;
}
const uint32* ExistingValue = Set.Find(VFind);
if (ExistingValue != nullptr != Data.ValueInSet[VFind])
{
if (Data.ValueInSet[VFind])
{
FAIL_CHECK(FString::Printf(TEXT("Expected in-set value %u was unexpectedly not found."), VFind));
}
else
{
FAIL_CHECK(FString::Printf(TEXT("Expected not-in-set value %u was unexpectedly found."), VFind));
}
}
else if (ExistingValue && *ExistingValue != VFind)
{
FAIL_CHECK(FString::Printf(TEXT("Expected value %u returned invalid result %u."),
VFind, *ExistingValue));
}
}
for (uint32 VIter = 0; VIter < Data.EndValue; ++VIter)
{
Data.ValueInSetCopiedFromSet[VIter] = false;
}
for (uint32 VIter : Set)
{
if (Data.ValueInSetCopiedFromSet[VIter])
{
FAIL_CHECK(FString::Printf(TEXT("Value %u unexpectedly encountered twice in Set iterator."), VIter));
}
Data.ValueInSetCopiedFromSet[VIter] = true;
}
for (uint32 VIter = 0; VIter < Data.EndValue; ++VIter)
{
if (Data.ValueInSet[VIter] != Data.ValueInSetCopiedFromSet[VIter])
{
if (Data.ValueInSet[VIter])
{
FAIL_CHECK(FString::Printf(TEXT("Expected in-set value %u was unexpectedly not found in the Set iterator."), VIter));
}
else
{
FAIL_CHECK(FString::Printf(TEXT("Expected not-in-set value %u was unexpectedly found in the Set iterator."), VIter));
}
}
}
if (Set.Num() != Data.NumInSet)
{
FAIL_CHECK(FString::Printf(TEXT("Set Num(%d) != expected num(%d)."), Set.Num(), Data.NumInSet));
}
};
Data.ValueInSet.Reserve(Data.EndValue);
Data.TypeHashes.Reserve(Data.EndValue);
for (uint32 n = 0; n < Data.EndValue; ++n)
{
Data.TypeHashes.Add((uint32)-1);
Data.ValueInSet.Add(false);
}
Data.ValueInSetCopiedFromSet.SetNum(Data.EndValue);
for (uint32 V = 50; V < 150; ++V)
{
check(V < Data.EndValue && V + 200 < Data.EndValue);
Data.ValuesA.Add(V);
Data.TypeHashes[V] = V + 1000;
}
for (uint32 V = 250; V < 350; ++V)
{
check(V < Data.EndValue);
Data.ValuesB.Add(V);
Data.TypeHashes[V] = (V - 200) + 1000;
}
for (uint32 V = 450; V< 500; ++V)
{
check(V< Data.EndValue);
Data.TypeHashes[V] = V + 2000;
}
for (int32 Trial = 0; Trial < 6; ++Trial)
{
Data.RemainingValues.Reset();
for (uint32 V = 0; V < Data.EndValue; ++V)
{
Data.ValueInSet[V] = false;
}
Data.NumInSet = 0;
switch (Trial)
{
default:
Set.Reset();
break;
case 2:
Set.Empty(1000);
break;
case 3:
Set.Empty(10);
break;
case 4:
Set.Empty();
Set.Reserve(50);
break;
}
for (uint32 V : Data.ValuesA)
{
Set.Add(V);
Data.ValueInSet[V] = true;
++Data.NumInSet;
ValidateExpectedSetContents();
}
switch (Trial)
{
default:
break;
case 3:
Set.ResizeToTargetSize();
break;
case 4:
{
TSetKeyFuncs<uint32, FKeyFuncs1> MovedSet(MoveTemp(Set));
Set = MoveTemp(MovedSet);
break;
}
case 5:
{
TSetKeyFuncs<uint32, FKeyFuncs1> CopySet(Set);
CopySet.SetKeyFuncs(FKeyFuncs1{ &Data });
Set.Empty();
Set = CopySet;
break;
}
}
for (uint32 V : Data.ValuesB)
{
Set.Add(V);
Data.ValueInSet[V] = true;
++Data.NumInSet;
ValidateExpectedSetContents();
}
Data.RemainingValues.Append(Data.ValuesA);
uint32 RemoveIndex = 7;
while (!Data.RemainingValues.IsEmpty())
{
RemoveIndex = (RemoveIndex + 13) % Data.RemainingValues.Num();
uint32 RemoveValue = Data.RemainingValues[RemoveIndex];
Data.RemainingValues.RemoveAtSwap(RemoveIndex);
Data.ValueInSet[RemoveValue] = false;
--Data.NumInSet;
Set.Remove(RemoveValue);
ValidateExpectedSetContents();
}
for (uint32 V : Data.ValuesA)
{
Set.Add(V);
Data.ValueInSet[V] = true;
++Data.NumInSet;
ValidateExpectedSetContents();
}
FSetKeyFuncsStats Stats = Set.GetStats();
CHECK_MESSAGE(TEXT("AverageSearch >= 1"), Stats.AverageSearch >= 1.f);
CHECK_MESSAGE(TEXT("LongestSearch >= 1"), Stats.LongestSearch >= 1);
CHECK_MESSAGE(TEXT("LongestSearch >= 1"), Set.GetAllocatedSize() >= Set.Num() * 1);
}
TSetKeyFuncs<uint32, FKeyFuncs1> EmptySet(FKeyFuncs1{ &Data });
FSetKeyFuncsStats Stats = EmptySet.GetStats();
CHECK_MESSAGE(TEXT("Empty AverageSearch == 0.0"), Stats.AverageSearch == 0.0f);
CHECK_MESSAGE(TEXT("Empty LongestSearch == 0"), Stats.AverageSearch == 0);
}
#endif // WITH_TESTS