2020-10-21 17:56:05 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
2022-04-20 14:24:59 -04:00
|
|
|
#if WITH_LOW_LEVEL_TESTS
|
|
|
|
|
|
2023-01-05 12:27:16 -05:00
|
|
|
#include "ObjectPtrTestClass.h"
|
2020-10-21 17:56:05 -04:00
|
|
|
#include "UObject/ObjectHandle.h"
|
2022-09-13 12:24:17 -04:00
|
|
|
#include "UObject/ObjectPtr.h"
|
2023-01-05 12:27:16 -05:00
|
|
|
#include "UObject/Package.h"
|
|
|
|
|
#include "UObject/ObjectResource.h"
|
2022-10-06 19:49:55 -04:00
|
|
|
#include "UObject/MetaData.h"
|
2020-10-21 17:56:05 -04:00
|
|
|
#include "HAL/PlatformProperties.h"
|
|
|
|
|
#include "ObjectRefTrackingTestBase.h"
|
2021-01-11 11:17:58 -04:00
|
|
|
#include "IO/IoDispatcher.h"
|
2022-04-07 10:34:55 -04:00
|
|
|
#include "TestHarness.h"
|
2023-01-16 19:20:47 -05:00
|
|
|
#include "UObject/ObjectRef.h"
|
|
|
|
|
#include "UObject/ObjectPathId.h"
|
2022-04-07 10:34:55 -04:00
|
|
|
|
2020-10-21 17:56:05 -04:00
|
|
|
static_assert(sizeof(FObjectHandle) == sizeof(void*), "FObjectHandle type must always compile to something equivalent to a pointer size.");
|
|
|
|
|
|
|
|
|
|
class FObjectHandleTestBase : public FObjectRefTrackingTestBase
|
|
|
|
|
{
|
|
|
|
|
public:
|
2022-03-31 07:45:37 -04:00
|
|
|
|
2020-10-21 17:56:05 -04:00
|
|
|
protected:
|
2023-01-16 19:20:47 -05:00
|
|
|
#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
|
|
|
|
|
void TestResolveFailure(UE::CoreUObject::Private::FPackedObjectRef PackedRef)
|
2020-10-21 17:56:05 -04:00
|
|
|
{
|
|
|
|
|
FSnapshotObjectRefMetrics ObjectRefMetrics(*this);
|
2023-01-16 19:20:47 -05:00
|
|
|
FObjectHandle TargetHandle = { PackedRef.EncodedRef };
|
|
|
|
|
UObject* ResolvedObject = FObjectPtr(TargetHandle).Get();
|
|
|
|
|
ObjectRefMetrics.TestNumResolves(TEXT("NumResolves should be incremented by one after a resolve attempt"), 1);
|
|
|
|
|
ObjectRefMetrics.TestNumReads(TEXT("NumReads should be incremented by one after a resolve attempt"), 1);
|
|
|
|
|
|
|
|
|
|
CHECK(ResolvedObject == nullptr);
|
|
|
|
|
ObjectRefMetrics.TestNumFailedResolves(TEXT("NumFailedResolves should be incremented by one after a failed resolve attempt"), 1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE || UE_WITH_OBJECT_HANDLE_TRACKING
|
|
|
|
|
void TestResolvableNonNull(const ANSICHAR* PackageName, const ANSICHAR* ObjectName, bool bExpectSubRefReads)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
FSnapshotObjectRefMetrics ObjectRefMetrics(*this);
|
|
|
|
|
FObjectRef TargetRef(FName(PackageName), NAME_None, NAME_None, UE::CoreUObject::Private::FObjectPathId(ObjectName));
|
|
|
|
|
UObject* ResolvedObject = TargetRef.Resolve();
|
|
|
|
|
FObjectPtr Ptr(ResolvedObject);
|
|
|
|
|
Ptr.Get();
|
|
|
|
|
TEST_TRUE(TEXT("expected not null"), ResolvedObject != nullptr);
|
2020-10-21 17:56:05 -04:00
|
|
|
ObjectRefMetrics.TestNumResolves(TEXT("NumResolves should be incremented by one after a resolve attempt"), 1);
|
2021-02-03 18:50:08 -04:00
|
|
|
ObjectRefMetrics.TestNumReads(TEXT("NumReads should be incremented by one after a resolve attempt"), 1, bExpectSubRefReads /*bAllowAdditionalReads*/);
|
2020-10-21 17:56:05 -04:00
|
|
|
ObjectRefMetrics.TestNumFailedResolves(TEXT("NumFailedResolves should not change after a successful resolve attempt"), 0);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 19:20:47 -05:00
|
|
|
void TestResolveFailure(const ANSICHAR* PackageName, const ANSICHAR* ObjectName)
|
2020-10-21 17:56:05 -04:00
|
|
|
{
|
|
|
|
|
FSnapshotObjectRefMetrics ObjectRefMetrics(*this);
|
2023-01-16 19:20:47 -05:00
|
|
|
FObjectRef TargetRef(FName(PackageName), NAME_None, NAME_None, UE::CoreUObject::Private::FObjectPathId(ObjectName));
|
|
|
|
|
const UObject* ResolvedObject = TargetRef.Resolve();
|
2020-10-21 17:56:05 -04:00
|
|
|
ObjectRefMetrics.TestNumResolves(TEXT("NumResolves should be incremented by one after a resolve attempt"), 1);
|
|
|
|
|
ObjectRefMetrics.TestNumReads(TEXT("NumReads should be incremented by one after a resolve attempt"), 1);
|
2023-01-16 19:20:47 -05:00
|
|
|
CHECK(ResolvedObject == nullptr);
|
2020-10-21 17:56:05 -04:00
|
|
|
ObjectRefMetrics.TestNumFailedResolves(TEXT("NumFailedResolves should be incremented by one after a failed resolve attempt"), 1);
|
2021-03-02 14:39:53 -04:00
|
|
|
}
|
2023-01-16 19:20:47 -05:00
|
|
|
#endif
|
2020-10-21 17:56:05 -04:00
|
|
|
};
|
|
|
|
|
|
2022-04-07 10:34:55 -04:00
|
|
|
TEST_CASE_METHOD(FObjectHandleTestBase, "CoreUObject::FObjectHandle::Null Behavior", "[CoreUObject][ObjectHandle]")
|
2020-10-21 17:56:05 -04:00
|
|
|
{
|
2023-01-16 19:20:47 -05:00
|
|
|
FObjectHandle TargetHandle = UE::CoreUObject::Private::MakeObjectHandle(nullptr);
|
2020-10-21 17:56:05 -04:00
|
|
|
|
2022-03-31 07:45:37 -04:00
|
|
|
TEST_TRUE(TEXT("Handle to target is null"), IsObjectHandleNull(TargetHandle));
|
|
|
|
|
TEST_TRUE(TEXT("Handle to target is resolved"), IsObjectHandleResolved(TargetHandle));
|
2020-10-21 17:56:05 -04:00
|
|
|
|
|
|
|
|
FSnapshotObjectRefMetrics ObjectRefMetrics(*this);
|
2023-01-16 19:20:47 -05:00
|
|
|
UObject* ResolvedObject = UE::CoreUObject::Private::ResolveObjectHandle(TargetHandle);
|
2020-10-21 17:56:05 -04:00
|
|
|
|
2022-03-31 07:45:37 -04:00
|
|
|
TEST_EQUAL(TEXT("Resolved object is equal to original object"), (UObject*)nullptr, ResolvedObject);
|
2020-10-21 17:56:05 -04:00
|
|
|
|
|
|
|
|
ObjectRefMetrics.TestNumFailedResolves(TEXT("NumFailedResolves should not change after a resolve attempt on a null handle"), 0);
|
|
|
|
|
ObjectRefMetrics.TestNumResolves(TEXT("NumResolves should not change after a resolve attempt on a null handle"), 0);
|
|
|
|
|
ObjectRefMetrics.TestNumReads(TEXT("NumReads should be incremented by one after a resolve attempt on a null handle"), 1);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-07 10:34:55 -04:00
|
|
|
TEST_CASE_METHOD(FObjectHandleTestBase, "CoreUObject::FObjectHandle::Pointer Behavior", "[CoreUObject][ObjectHandle]")
|
2020-10-21 17:56:05 -04:00
|
|
|
{
|
2023-01-16 19:20:47 -05:00
|
|
|
FObjectHandle TargetHandle = UE::CoreUObject::Private::MakeObjectHandle((UObject*)0x0042);
|
2020-10-21 17:56:05 -04:00
|
|
|
|
2022-03-31 07:45:37 -04:00
|
|
|
TEST_FALSE(TEXT("Handle to target is null"), IsObjectHandleNull(TargetHandle));
|
|
|
|
|
TEST_TRUE(TEXT("Handle to target is resolved"), IsObjectHandleResolved(TargetHandle));
|
2020-10-21 17:56:05 -04:00
|
|
|
|
|
|
|
|
FSnapshotObjectRefMetrics ObjectRefMetrics(*this);
|
2023-01-16 19:20:47 -05:00
|
|
|
UObject* ResolvedObject = UE::CoreUObject::Private::ResolveObjectHandle(TargetHandle);
|
2020-10-21 17:56:05 -04:00
|
|
|
|
2022-03-31 07:45:37 -04:00
|
|
|
TEST_EQUAL(TEXT("Resolved object is equal to original object"), (UObject*)0x0042, ResolvedObject);
|
2020-10-21 17:56:05 -04:00
|
|
|
|
|
|
|
|
ObjectRefMetrics.TestNumResolves(TEXT("NumResolves should not change after a resolve attempt on a pointer handle"), 0);
|
|
|
|
|
ObjectRefMetrics.TestNumFailedResolves(TEXT("NumFailedResolves should not change after a resolve attempt on a pointer handle"), 0);
|
|
|
|
|
ObjectRefMetrics.TestNumReads(TEXT("NumReads should be incremented by one after a resolve attempt on a pointer handle"),1);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 19:20:47 -05:00
|
|
|
#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
|
2022-08-16 15:53:22 -04:00
|
|
|
TEST_CASE_METHOD(FObjectHandleTestBase, "CoreUObject::FObjectHandle::Resolve Engine Content Target", "[CoreUObject][ObjectHandle]")
|
2020-10-21 17:56:05 -04:00
|
|
|
{
|
2022-08-16 15:53:22 -04:00
|
|
|
const FName TestPackageName(TEXT("/Engine/Test/ObjectPtrDefaultSerialize/Transient"));
|
|
|
|
|
UPackage* TestPackage = NewObject<UPackage>(nullptr, TestPackageName, RF_Transient);
|
|
|
|
|
TestPackage->AddToRoot();
|
2023-01-05 12:27:16 -05:00
|
|
|
UObject* TestSoftObject = NewObject<UObjectPtrTestClass>(TestPackage, TEXT("DefaultSerializeObject"));
|
|
|
|
|
UObject* TestSubObject = NewObject<UObjectPtrTestClass>(TestSoftObject, TEXT("SubObject"));
|
2022-08-16 15:53:22 -04:00
|
|
|
ON_SCOPE_EXIT{
|
|
|
|
|
TestPackage->RemoveFromRoot();
|
|
|
|
|
};
|
2020-10-21 17:56:05 -04:00
|
|
|
|
2023-01-16 19:20:47 -05:00
|
|
|
TestResolvableNonNull("/Engine/Test/ObjectPtrDefaultSerialize/Transient", "DefaultSerializeObject.SubObject", true);
|
|
|
|
|
TestResolvableNonNull("/Engine/Test/ObjectPtrDefaultSerialize/Transient", "DefaultSerializeObject", false);
|
2020-10-21 17:56:05 -04:00
|
|
|
}
|
|
|
|
|
|
2023-01-16 19:20:47 -05:00
|
|
|
|
2022-08-19 16:12:42 -04:00
|
|
|
// TODO: Disabled until warnings and errors related to loading a non-existent package have been fixed.
|
|
|
|
|
DISABLED_TEST_CASE_METHOD(FObjectHandleTestBase, "CoreUObject::FObjectHandle::Resolve Non Existent Target", "[CoreUObject][ObjectHandle]")
|
2020-10-21 17:56:05 -04:00
|
|
|
{
|
|
|
|
|
// Confirm we don't successfully resolve an incorrect reference to engine content
|
|
|
|
|
TestResolveFailure("/Engine/EngineResources/NonExistentPackageName_0", "DefaultTexture");
|
2022-08-16 15:53:22 -04:00
|
|
|
|
|
|
|
|
const FName TestPackageName(TEXT("/Engine/Test/ObjectPtrDefaultSerialize/Transient"));
|
|
|
|
|
UPackage* TestPackage = NewObject<UPackage>(nullptr, TestPackageName, RF_Transient);
|
|
|
|
|
TestPackage->AddToRoot();
|
2023-01-05 12:27:16 -05:00
|
|
|
UObject* TestSoftObject = NewObject<UObjectPtrTestClass>(TestPackage, TEXT("DefaultSerializeObject"));
|
2022-08-16 15:53:22 -04:00
|
|
|
ON_SCOPE_EXIT{
|
|
|
|
|
TestPackage->RemoveFromRoot();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TestResolveFailure("/Engine/Test/ObjectPtrDefaultSerialize/Transient", "DefaultSerializeObject_DoesNotExist");
|
2020-10-21 17:56:05 -04:00
|
|
|
}
|
|
|
|
|
|
2022-08-16 15:53:22 -04:00
|
|
|
TEST_CASE_METHOD(FObjectHandleTestBase, "CoreUObject::FObjectHandle::Resolve Script Target", "[CoreUObject][ObjectHandle]")
|
2020-10-21 17:56:05 -04:00
|
|
|
{
|
|
|
|
|
// Confirm we successfully resolve a correct reference to engine content
|
2023-01-16 19:20:47 -05:00
|
|
|
TestResolvableNonNull("/Script/CoreUObject", "MetaData", true);
|
2020-10-21 17:56:05 -04:00
|
|
|
}
|
|
|
|
|
|
2023-01-16 19:20:47 -05:00
|
|
|
#endif
|
|
|
|
|
|
2023-01-05 12:27:16 -05:00
|
|
|
TEST_CASE_METHOD(FObjectHandleTestBase, "CoreUObject::TObjectPtr::HandleNullGetClass", "[CoreUObject][ObjectHandle]")
|
2022-09-13 12:24:17 -04:00
|
|
|
{
|
|
|
|
|
TObjectPtr<UObject> Ptr = nullptr;
|
|
|
|
|
TEST_TRUE(TEXT("TObjectPtr.GetClass should return null on a null object"), Ptr.GetClass() == nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-05 12:27:16 -05:00
|
|
|
#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
|
|
|
|
|
TEST_CASE("CoreUObject::FObjectHandle::Names")
|
|
|
|
|
{
|
|
|
|
|
const FName TestPackageName(TEXT("/Engine/Test/PackageResolve/Transient"));
|
|
|
|
|
UPackage* TestPackage = NewObject<UPackage>(nullptr, TestPackageName, RF_Transient);
|
|
|
|
|
TestPackage->AddToRoot();
|
|
|
|
|
UObject* Obj1 = NewObject<UObjectPtrTestClass>(TestPackage, TEXT("DefaultSerializeObject"));
|
|
|
|
|
ON_SCOPE_EXIT{
|
|
|
|
|
TestPackage->RemoveFromRoot();
|
|
|
|
|
};
|
|
|
|
|
|
2023-06-01 18:45:09 -04:00
|
|
|
FObjectPtr Test;
|
2023-01-16 19:20:47 -05:00
|
|
|
FObjectPtr PackagePtr(MakeUnresolvedHandle(TestPackage));
|
|
|
|
|
FObjectPtr Obj1Ptr(MakeUnresolvedHandle(Obj1));
|
2023-01-05 12:27:16 -05:00
|
|
|
|
|
|
|
|
CHECK(!PackagePtr.IsResolved());
|
|
|
|
|
CHECK(TestPackage->GetPathName() == PackagePtr.GetPathName());
|
|
|
|
|
CHECK(TestPackage->GetFName() == PackagePtr.GetFName());
|
|
|
|
|
CHECK(TestPackage->GetName() == PackagePtr.GetName());
|
2023-06-01 18:45:09 -04:00
|
|
|
CHECK(TestPackage->GetFullName() == PackagePtr.GetFullName());
|
2023-01-05 12:27:16 -05:00
|
|
|
CHECK(!PackagePtr.IsResolved());
|
|
|
|
|
|
|
|
|
|
CHECK(!Obj1Ptr.IsResolved());
|
|
|
|
|
CHECK(Obj1->GetPathName() == Obj1Ptr.GetPathName());
|
|
|
|
|
CHECK(Obj1->GetFName() == Obj1Ptr.GetFName());
|
|
|
|
|
CHECK(Obj1->GetName() == Obj1Ptr.GetName());
|
2023-06-01 18:45:09 -04:00
|
|
|
CHECK(Obj1->GetFullName() == Obj1Ptr.GetFullName());
|
2023-01-05 12:27:16 -05:00
|
|
|
CHECK(!Obj1Ptr.IsResolved());
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-01-16 19:20:47 -05:00
|
|
|
#if UE_WITH_OBJECT_HANDLE_TRACKING || UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
|
|
|
|
|
|
2023-01-05 12:27:16 -05:00
|
|
|
TEST_CASE("CoreUObject::ObjectRef")
|
|
|
|
|
{
|
|
|
|
|
const FName TestPackageName(TEXT("/Engine/Test/ObjectRef/Transient"));
|
|
|
|
|
UPackage* TestPackage = NewObject<UPackage>(nullptr, TestPackageName, RF_Transient);
|
|
|
|
|
TestPackage->AddToRoot();
|
|
|
|
|
UObject* Obj1 = NewObject<UObjectPtrTestClass>(TestPackage, TEXT("DefaultSerializeObject"));
|
|
|
|
|
UObject* Inner1 = NewObject<UObjectPtrTestClass>(Obj1, TEXT("Inner"));
|
|
|
|
|
ON_SCOPE_EXIT{
|
|
|
|
|
TestPackage->RemoveFromRoot();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
FObjectImport ObjectImport(Obj1);
|
2023-01-16 19:20:47 -05:00
|
|
|
FObjectRef ObjectRef(Obj1);
|
2023-01-05 12:27:16 -05:00
|
|
|
|
|
|
|
|
CHECK(ObjectImport.ClassPackage == ObjectRef.ClassPackageName);
|
|
|
|
|
CHECK(ObjectImport.ClassName == ObjectRef.ClassName);
|
|
|
|
|
CHECK(TestPackage->GetFName() == ObjectRef.PackageName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
FObjectImport ObjectImport(Inner1);
|
2023-01-16 19:20:47 -05:00
|
|
|
FObjectRef ObjectRef(Inner1);
|
2023-01-05 12:27:16 -05:00
|
|
|
|
|
|
|
|
CHECK(ObjectImport.ClassPackage == ObjectRef.ClassPackageName);
|
|
|
|
|
CHECK(ObjectImport.ClassName == ObjectRef.ClassName);
|
|
|
|
|
CHECK(TestPackage->GetFName() == ObjectRef.PackageName);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-16 19:20:47 -05:00
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
|
2022-10-07 13:42:37 -04:00
|
|
|
|
2022-10-06 19:49:55 -04:00
|
|
|
TEST_CASE_METHOD(FObjectHandleTestBase, "CoreUObject::TObjectPtr::Null Behavior", "[CoreUObject][ObjectHandle]")
|
|
|
|
|
{
|
|
|
|
|
TObjectPtr<UObject> Ptr = nullptr;
|
2023-01-05 12:27:16 -05:00
|
|
|
UObjectPtrTestClass* TestObject = nullptr;
|
2022-10-06 19:49:55 -04:00
|
|
|
|
|
|
|
|
uint32 ResolveCount = 0;
|
2023-01-19 16:34:29 -05:00
|
|
|
auto ResolveDelegate = [&ResolveCount](const FObjectRef& SourceRef, UPackage* ObjectPackage, UObject* Object)
|
2022-10-06 19:49:55 -04:00
|
|
|
{
|
|
|
|
|
++ResolveCount;
|
2023-01-19 16:34:29 -05:00
|
|
|
};
|
|
|
|
|
auto Handle = UE::CoreUObject::AddObjectHandleReferenceResolvedCallback(ResolveDelegate);
|
|
|
|
|
ON_SCOPE_EXIT
|
|
|
|
|
{
|
|
|
|
|
UE::CoreUObject::RemoveObjectHandleReferenceResolvedCallback(Handle);
|
|
|
|
|
};
|
2022-10-06 19:49:55 -04:00
|
|
|
//compare against all flavours of nullptr, should not try and resolve this pointer
|
|
|
|
|
CHECK(Ptr == nullptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(nullptr == Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(Ptr != nullptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(nullptr != Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(!Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
|
|
|
|
|
//using an if otherwise the macros try to convert to a pointer and not use the bool operator
|
|
|
|
|
if (Ptr)
|
|
|
|
|
{
|
|
|
|
|
CHECK(false);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CHECK(true);
|
|
|
|
|
}
|
|
|
|
|
CHECK(ResolveCount == 0u);
|
|
|
|
|
|
|
|
|
|
CHECK(Ptr == TestObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(TestObject == Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(Ptr != TestObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(TestObject != Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
|
2023-01-16 19:20:47 -05:00
|
|
|
FObjectRef TargetRef(FName("SomePackage"), FName("ClassPackageName"), FName("ClassName"), UE::CoreUObject::Private::FObjectPathId("ObjectName"));
|
|
|
|
|
UE::CoreUObject::Private::FPackedObjectRef PackedObjectRef = UE::CoreUObject::Private::MakePackedObjectRef(TargetRef);
|
|
|
|
|
FObjectPtr ObjectPtr({ PackedObjectRef.EncodedRef });
|
2022-10-06 19:49:55 -04:00
|
|
|
REQUIRE(!ObjectPtr.IsResolved()); //make sure not resolved
|
|
|
|
|
|
|
|
|
|
//an unresolved pointers compared against nullptr should still not resolve
|
|
|
|
|
Ptr = *reinterpret_cast<TObjectPtr<UObject>*>(&ObjectPtr);
|
|
|
|
|
CHECK_FALSE(Ptr == nullptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(nullptr == Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(Ptr != nullptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(nullptr != Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(!Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
|
|
|
|
|
//using an if otherwise the macros try to convert to a pointer and not use the bool operator
|
|
|
|
|
if (Ptr)
|
|
|
|
|
{
|
|
|
|
|
CHECK(true);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CHECK(false);
|
|
|
|
|
}
|
|
|
|
|
CHECK(ResolveCount == 0u);
|
|
|
|
|
|
|
|
|
|
//test an unresolve pointer against a null raw pointer
|
|
|
|
|
CHECK_FALSE(Ptr == TestObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(TestObject == Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(Ptr != TestObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(TestObject != Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
|
|
|
|
|
//creating a real object for something that can resolve
|
|
|
|
|
const FName TestPackageName(TEXT("/Engine/Test/ObjectPtrDefaultSerialize/Transient"));
|
|
|
|
|
UPackage* TestPackage = NewObject<UPackage>(nullptr, TestPackageName, RF_Transient);
|
|
|
|
|
TestPackage->AddToRoot();
|
|
|
|
|
|
|
|
|
|
const FName TestObjectName(TEXT("MyObject"));
|
2023-01-05 12:27:16 -05:00
|
|
|
TestObject = NewObject<UObjectPtrTestClass>(TestPackage, TestObjectName, RF_Transient);
|
|
|
|
|
TObjectPtr<UObject> TestNotLazyObject = NewObject<UObjectPtrNotLazyTestClass>(TestPackage, TEXT("NotLazy"), RF_Transient);
|
2022-10-06 19:49:55 -04:00
|
|
|
|
2023-01-05 12:27:16 -05:00
|
|
|
//compare resolved ptr against nullptr
|
|
|
|
|
TObjectPtr<UObject> ResolvedPtr = TestObject;
|
|
|
|
|
CHECK(ResolvedPtr.IsResolved());
|
|
|
|
|
CHECK(Ptr != ResolvedPtr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(ResolvedPtr != Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(Ptr == ResolvedPtr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(ResolvedPtr == Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
|
|
|
|
|
//compare unresolved against nullptr
|
2023-01-16 19:20:47 -05:00
|
|
|
FObjectPtr FPtr(MakeUnresolvedHandle(TestObject));
|
2023-01-05 12:27:16 -05:00
|
|
|
TObjectPtr<UObject> UnResolvedPtr = *reinterpret_cast<TObjectPtr<UObject>*>(&FPtr);
|
|
|
|
|
CHECK(!UnResolvedPtr.IsResolved());
|
|
|
|
|
CHECK_FALSE(Ptr == UnResolvedPtr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(UnResolvedPtr == Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(Ptr != UnResolvedPtr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(UnResolvedPtr != Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
|
|
|
|
|
//compare unresolved against resolved not equal
|
|
|
|
|
CHECK_FALSE(TestNotLazyObject == UnResolvedPtr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(UnResolvedPtr == TestNotLazyObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(TestNotLazyObject != UnResolvedPtr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(UnResolvedPtr != TestNotLazyObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
|
|
|
|
|
//compare resolved against naked pointer
|
2022-10-06 19:49:55 -04:00
|
|
|
Ptr = TestObject;
|
|
|
|
|
REQUIRE(Ptr.IsResolved());
|
|
|
|
|
CHECK(Ptr == TestObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(TestObject == Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(Ptr != TestObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(TestObject != Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
|
2023-01-05 12:27:16 -05:00
|
|
|
//compare resolved pointer and unresolved of the same object
|
|
|
|
|
CHECK(Ptr == UnResolvedPtr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(UnResolvedPtr == Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(Ptr != UnResolvedPtr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(UnResolvedPtr != Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
|
2022-10-06 19:49:55 -04:00
|
|
|
TestObject = nullptr;
|
|
|
|
|
CHECK_FALSE(Ptr == TestObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(TestObject == Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(Ptr != TestObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(TestObject != Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
|
2023-01-05 12:27:16 -05:00
|
|
|
TestObject = static_cast<UObjectPtrTestClass*>(Ptr.Get());
|
2022-10-06 19:49:55 -04:00
|
|
|
Ptr = nullptr;
|
|
|
|
|
CHECK_FALSE(Ptr == TestObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK_FALSE(TestObject == Ptr); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(Ptr != TestObject); CHECK(ResolveCount == 0u);
|
|
|
|
|
CHECK(TestObject != Ptr); CHECK(ResolveCount == 0u);
|
2023-03-02 20:28:39 -05:00
|
|
|
|
2022-10-06 19:49:55 -04:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 13:42:37 -04:00
|
|
|
#endif
|
|
|
|
|
|
2021-03-02 14:39:53 -04:00
|
|
|
#if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
|
2022-03-31 07:45:37 -04:00
|
|
|
|
2022-04-07 10:34:55 -04:00
|
|
|
TEST_CASE_METHOD(FObjectHandleTestBase, "CoreUObject::FObjectHandle::Resolve Malformed Handle", "[CoreUObject][ObjectHandle]")
|
2021-03-02 14:39:53 -04:00
|
|
|
{
|
2023-06-01 18:45:09 -04:00
|
|
|
// make one packed ref guarantee something is in the object handle index
|
|
|
|
|
FObjectRef TargetRef(FName("/Test/DummyPackage"), FName("ClassPackageName"), FName("ClassName"), UE::CoreUObject::Private::FObjectPathId("DummyObjectName"));
|
|
|
|
|
UE::CoreUObject::Private::MakePackedObjectRef(TargetRef);
|
|
|
|
|
|
|
|
|
|
uint32 ObjectId = ~0u;
|
|
|
|
|
UPTRINT PackedId = ObjectId << 1 | 1;
|
|
|
|
|
UE::CoreUObject::Private::FPackedObjectRef PackedObjectRef = { PackedId };
|
|
|
|
|
TestResolveFailure(PackedObjectRef); // packed ref has a valid package id but invalid object id
|
|
|
|
|
|
2023-01-16 19:20:47 -05:00
|
|
|
TestResolveFailure(UE::CoreUObject::Private::FPackedObjectRef { 0xFFFF'FFFF'FFFF'FFFFull });
|
|
|
|
|
TestResolveFailure(UE::CoreUObject::Private::FPackedObjectRef { 0xEFEF'EFEF'EFEF'EFEFull });
|
2021-03-02 14:39:53 -04:00
|
|
|
}
|
|
|
|
|
#endif // UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
|
2022-04-20 14:24:59 -04:00
|
|
|
|
2023-04-26 19:52:36 -04:00
|
|
|
TEST_CASE_METHOD(FObjectHandleTestBase, "CoreUObject::FObjectHandle::Hash Object Without Index", "[CoreUObject][ObjectHandle]")
|
|
|
|
|
{
|
|
|
|
|
UObject DummyObjectWithInvalidIndex(EC_StaticConstructor, RF_NoFlags);
|
|
|
|
|
CHECK(DummyObjectWithInvalidIndex.GetUniqueID() == -1);
|
|
|
|
|
|
|
|
|
|
FObjectHandle DummyObjectHandle = UE::CoreUObject::Private::MakeObjectHandle(&DummyObjectWithInvalidIndex);
|
2023-04-26 19:53:27 -04:00
|
|
|
CHECK(GetTypeHash(DummyObjectHandle) == GetTypeHash(&DummyObjectWithInvalidIndex));
|
2023-04-26 19:52:36 -04:00
|
|
|
}
|
|
|
|
|
|
2023-01-05 12:27:16 -05:00
|
|
|
#endif
|