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
2020-10-21 17:56:05 -04:00
# include "UObject/ObjectHandle.h"
# include "HAL/PlatformProperties.h"
# include "ObjectRefTrackingTestBase.h"
2021-01-11 11:17:58 -04:00
# include "IO/IoDispatcher.h"
2020-10-21 17:56:05 -04:00
2022-04-07 10:34:55 -04:00
# include "TestHarness.h"
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 :
2021-03-02 14:39:53 -04:00
UObject * ResolveHandle ( FObjectHandle & TargetHandle )
2020-10-21 17:56:05 -04:00
{
# if UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
// Late resolved handles cannot be null or resolved at this point
2022-04-07 10:34:55 -04:00
bool bValue = IsObjectHandleNull ( TargetHandle ) ;
TEST_FALSE ( TEXT ( " Handle to target is null " ) , bValue ) ;
if ( bValue )
2020-10-21 17:56:05 -04:00
{
return nullptr ;
}
2022-04-07 10:34:55 -04:00
bValue = IsObjectHandleResolved ( TargetHandle ) ;
TEST_FALSE ( TEXT ( " Handle to target is resolved " ) , bValue ) ;
if ( bValue )
2020-10-21 17:56:05 -04:00
{
return nullptr ;
}
# else
2022-04-07 10:34:55 -04:00
bool bValue = IsObjectHandleResolved ( TargetHandle ) ;
2020-10-21 17:56:05 -04:00
// Immediately resolved handles may be null (if the target is invalid) and must be resolved at this point
2022-04-07 10:34:55 -04:00
TEST_TRUE ( TEXT ( " Handle to target is not resolved " ) , bValue ) ;
if ( ! bValue )
2020-10-21 17:56:05 -04:00
{
return nullptr ;
}
# endif
return ResolveObjectHandle ( TargetHandle ) ;
}
2021-03-02 14:39:53 -04:00
UObject * ConstructAndResolveHandle ( const ANSICHAR * PackageName , const ANSICHAR * ObjectName , const ANSICHAR * ClassPackageName = nullptr , const ANSICHAR * ClassName = nullptr )
{
FObjectRef TargetRef { FName ( PackageName ) , FName ( ClassPackageName ) , FName ( ClassName ) , FObjectPathId ( ObjectName ) } ;
2022-04-07 10:34:55 -04:00
bool bValue = IsObjectRefNull ( TargetRef ) ;
TEST_FALSE ( TEXT ( " Reference to target is null " ) , bValue ) ;
if ( bValue )
2021-03-02 14:39:53 -04:00
{
return nullptr ;
}
FObjectHandle TargetHandle = MakeObjectHandle ( TargetRef ) ;
return ResolveHandle ( TargetHandle ) ;
}
UObject * ConstructAndResolveHandle ( const FPackedObjectRef & PackedTargetRef )
{
2022-04-07 10:34:55 -04:00
bool bValue = IsPackedObjectRefNull ( PackedTargetRef ) ;
TEST_FALSE ( TEXT ( " Reference to target is null " ) , bValue ) ;
if ( bValue )
2021-03-02 14:39:53 -04:00
{
return nullptr ;
}
FObjectHandle TargetHandle = MakeObjectHandle ( PackedTargetRef ) ;
return ResolveHandle ( TargetHandle ) ;
}
2021-02-03 18:50:08 -04:00
bool TestResolvableNonNull ( const ANSICHAR * PackageName , const ANSICHAR * ObjectName , const ANSICHAR * ClassPackageName = nullptr , const ANSICHAR * ClassName = nullptr , bool bExpectSubRefReads = false )
2020-10-21 17:56:05 -04:00
{
FSnapshotObjectRefMetrics ObjectRefMetrics ( * this ) ;
UObject * ResolvedObject = ConstructAndResolveHandle ( PackageName , ObjectName , ClassPackageName , ClassName ) ;
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
if ( ! ResolvedObject )
{
2022-03-31 07:45:37 -04:00
FAIL_CHECK ( FString : : Printf ( TEXT ( " Expected '%s.%s' to resolve to non null. " ) , ANSI_TO_TCHAR ( PackageName ) , ANSI_TO_TCHAR ( ObjectName ) ) ) ;
2020-10-21 17:56:05 -04:00
return false ;
}
ObjectRefMetrics . TestNumFailedResolves ( TEXT ( " NumFailedResolves should not change after a successful resolve attempt " ) , 0 ) ;
return true ;
}
bool TestResolveFailure ( const ANSICHAR * PackageName , const ANSICHAR * ObjectName , const ANSICHAR * ClassPackageName = nullptr , const ANSICHAR * ClassName = nullptr )
{
FSnapshotObjectRefMetrics ObjectRefMetrics ( * this ) ;
UObject * ResolvedObject = ConstructAndResolveHandle ( PackageName , ObjectName , ClassPackageName , ClassName ) ;
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 ) ;
if ( ResolvedObject )
{
2022-03-31 07:45:37 -04:00
FAIL_CHECK ( FString : : Printf ( TEXT ( " Expected '%s.%s' to resolve to null. " ) , ANSI_TO_TCHAR ( PackageName ) , ANSI_TO_TCHAR ( ObjectName ) ) ) ;
2020-10-21 17:56:05 -04:00
return false ;
}
ObjectRefMetrics . TestNumFailedResolves ( TEXT ( " NumFailedResolves should be incremented by one after a failed resolve attempt " ) , 1 ) ;
return true ;
}
2021-03-02 14:39:53 -04:00
bool TestResolveFailure ( FPackedObjectRef PackedRef )
{
FSnapshotObjectRefMetrics ObjectRefMetrics ( * this ) ;
UObject * ResolvedObject = ConstructAndResolveHandle ( PackedRef ) ;
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 ) ;
if ( ResolvedObject )
{
2022-03-31 07:45:37 -04:00
FAIL_CHECK ( FString : : Printf ( TEXT ( " Expected PACKEDREF(% " UPTRINT_X_FMT " ) to resolve to null. " ) , PackedRef . EncodedRef ) ) ;
2021-03-02 14:39:53 -04:00
return false ;
}
ObjectRefMetrics . TestNumFailedResolves ( TEXT ( " NumFailedResolves should be incremented by one after a failed resolve attempt " ) , 1 ) ;
return true ;
}
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
{
FObjectHandle TargetHandle = MakeObjectHandle ( nullptr ) ;
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 ) ;
UObject * ResolvedObject = ResolveObjectHandle ( TargetHandle ) ;
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
{
FObjectHandle TargetHandle = MakeObjectHandle ( ( UObject * ) 0x0042 ) ;
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 ) ;
UObject * ResolvedObject = ResolveObjectHandle ( TargetHandle ) ;
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 ) ;
}
2022-03-31 07:45:37 -04:00
TEST_CASE_METHOD ( FObjectHandleTestBase , " CoreUObject::FObjectHandle::Resolve Engine Content Target " , " [CoreUObject][ObjectHandle][.Engine] " )
2020-10-21 17:56:05 -04:00
{
// Confirm we successfully resolve a correct reference to engine content
TestResolvableNonNull ( " /Engine/EngineResources/DefaultTexture " , " DefaultTexture " ) ;
// @TODO: OBJPTR: These assets aren't in a standard cook of EngineTest, so avoid testing them when using cooked content. Should look for other assets to use instead.
if ( ! FPlatformProperties : : RequiresCookedData ( ) )
{
// Confirm we successfully resolve a correct reference to a subobject in engine content
2021-02-03 18:50:08 -04:00
TestResolvableNonNull ( " /Engine/FunctionalTesting/Blueprints/AITesting_MoveGoal " , " AITesting_MoveGoal.EventGraph.K2Node_VariableGet_142 " , nullptr , nullptr , true ) ;
2020-10-21 17:56:05 -04:00
// Attempt to load something that uses a User Defined Enum
2021-02-03 18:50:08 -04:00
TestResolvableNonNull ( " /Engine/ArtTools/RenderToTexture/Macros/RenderToTextureMacros " , " RenderToTextureMacros:Array to HLSL Float Array.K2Node_Select_1 " , nullptr , nullptr , true ) ;
2020-10-21 17:56:05 -04:00
}
}
2022-04-07 10:34:55 -04:00
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 " ) ;
TestResolveFailure ( " /Engine/EngineResources/DefaultTexture " , " NonExistentObject_0 " ) ;
}
2022-03-31 07:45:37 -04:00
TEST_CASE_METHOD ( FObjectHandleTestBase , " CoreUObject::FObjectHandle::Resolve Script Target " , " [CoreUObject][ObjectHandle][.Engine] " )
2020-10-21 17:56:05 -04:00
{
// Confirm we successfully resolve a correct reference to engine content
TestResolvableNonNull ( " /Script/Engine " , " Default__Actor " ) ;
TestResolvableNonNull ( " /Script/Engine " , " DefaultPawn " ) ;
}
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
{
TestResolveFailure ( FPackedObjectRef { 0xFFFF'FFFF'FFFF'FFFFull } ) ;
TestResolveFailure ( FPackedObjectRef { 0xEFEF'EFEF'EFEF'EFEFull } ) ;
}
# endif // UE_WITH_OBJECT_HANDLE_LATE_RESOLVE
2022-04-20 14:24:59 -04:00
# endif