2023-05-30 17:07:23 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "Algo/AllOf.h"
# include "Containers/Array.h"
# include "Containers/UnrealString.h"
# include "EngineTestMetaSoundAutomatedNodeTest.h"
# include "Misc/AutomationTest.h"
# include "MetasoundBuilderInterface.h"
# include "MetasoundFrontendDataTypeRegistry.h"
# include "MetasoundOperatorInterface.h"
# include "MetasoundLog.h"
# include "MetasoundVertexData.h"
# include "Templates/UniquePtr.h"
# include "Tests/AutomationCommon.h"
# if WITH_DEV_AUTOMATION_TESTS
# if WITH_EDITORONLY_DATA
2024-02-13 22:59:01 -05:00
IMPLEMENT_COMPLEX_AUTOMATION_TEST ( FMetasoundAutomatedNodeTest_Reset , " Audio.Metasound.AutomatedNodeTest.Reset " , EAutomationTestFlags : : EditorContext | EAutomationTestFlags : : EngineFilter )
2023-05-30 17:07:23 -04:00
void FMetasoundAutomatedNodeTest_Reset : : GetTests ( TArray < FString > & OutBeautifiedNames , TArray < FString > & OutTestCommands ) const
{
using namespace Metasound : : EngineTest ;
2024-01-25 12:08:15 -05:00
GetAllRegisteredNativeNodes ( OutBeautifiedNames , OutTestCommands ) ;
2023-05-30 17:07:23 -04:00
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Found %d metasound nodes to test " ) , OutTestCommands . Num ( ) ) ;
}
2023-10-12 16:37:45 -04:00
bool FMetasoundAutomatedNodeTest_Reset : : RunTest ( const FString & InRegistryKeyString )
2023-05-30 17:07:23 -04:00
{
using namespace Metasound ;
using namespace Metasound : : EngineTest ;
2023-10-12 16:37:45 -04:00
using namespace Metasound : : Frontend ;
2023-05-30 17:07:23 -04:00
static const FOperatorSettings OperatorSettings { 48000 /* samplerate */ , 100.f /* block rate */ } ;
static const FMetasoundEnvironment SourceEnvironment = GetSourceEnvironmentForTest ( ) ;
2023-10-12 16:37:45 -04:00
FNodeRegistryKey RegistryKey ;
if ( ! FNodeRegistryKey : : Parse ( InRegistryKeyString , RegistryKey ) )
{
AddError ( FString : : Printf ( TEXT ( " Failed to parse registry key string %s " ) , * InRegistryKeyString ) ) ;
return false ;
}
TUniquePtr < INode > Node = CreateNodeFromRegistry ( RegistryKey ) ;
2023-05-30 17:07:23 -04:00
if ( ! Node . IsValid ( ) )
{
2023-10-12 16:37:45 -04:00
AddError ( FString : : Printf ( TEXT ( " Failed to create node %s from registry " ) , * InRegistryKeyString ) ) ;
2023-05-30 17:07:23 -04:00
return false ;
}
// Populate inputs to node.
FInputVertexInterface InputInterface = Node - > GetVertexInterface ( ) . GetInputInterface ( ) ;
FInputVertexInterfaceData InputVertexData ( InputInterface ) ;
CreateDefaultsAndVariables ( OperatorSettings , InputVertexData ) ;
FInputVertexDataTestController InputTester ( OperatorSettings , InputInterface , InputVertexData ) ;
// Create operator
FBuildOperatorParams BuildParams
{
* Node ,
OperatorSettings ,
InputVertexData ,
SourceEnvironment
} ;
IOperator : : FResetParams ResetParams
{
OperatorSettings ,
SourceEnvironment
} ;
// Convenience function for testing entire lifecycle of an individual operator
// with a variety of inputs.
auto RunTestIteration = [ & ] ( )
{
// Create the operator from the node factory
FBuildResults BuildResults ;
TUniquePtr < IOperator > Operator = Node - > GetDefaultOperatorFactory ( ) - > CreateOperator ( BuildParams , BuildResults ) ;
if ( ! Operator . IsValid ( ) )
{
2023-10-12 16:37:45 -04:00
AddError ( FString : : Printf ( TEXT ( " Failed to create operator from node %s - %s. " ) , * InRegistryKeyString , * GetPrettyName ( RegistryKey ) ) ) ;
2023-05-30 17:07:23 -04:00
}
// Store a copy of the input values data values so the inputs
// can be reset to this value later during the test.
FInterfaceState InitialInputState = InputTester . GetInterfaceState ( ) ;
// Bind to inputs and output data of operator.
FVertexInterface VertexInterface = Node - > GetVertexInterface ( ) ;
FVertexInterfaceData VertexInterfaceData { VertexInterface } ;
Operator - > BindInputs ( VertexInterfaceData . GetInputs ( ) ) ;
Operator - > BindOutputs ( VertexInterfaceData . GetOutputs ( ) ) ;
// Create output tester which will analyzer outputs of operator.
FOutputVertexDataTestController OutputTester { VertexInterface . GetOutputInterface ( ) , VertexInterfaceData . GetOutputs ( ) } ;
// Capture current state of outputs so they can be referenced at a later time.
// The captured values are held within the OutputTester.
OutputTester . CaptureCurrentOutputValues ( ) ;
IOperator : : FExecuteFunction OpExecFunc = Operator - > GetExecuteFunction ( ) ;
2024-01-25 17:41:37 -05:00
auto ConditionallyCallExecFunc = [ & OpExecFunc ] ( IOperator * Operator )
2023-05-30 17:07:23 -04:00
{
2024-01-25 17:41:37 -05:00
if ( OpExecFunc )
{
OpExecFunc ( Operator ) ;
}
} ;
IOperator : : FPostExecuteFunction OpPostExecFunc = Operator - > GetPostExecuteFunction ( ) ;
auto ConditionallyCallPostExecFunc = [ & OpPostExecFunc ] ( IOperator * Operator )
{
if ( OpPostExecFunc )
{
OpPostExecFunc ( Operator ) ;
}
} ;
IOperator : : FResetFunction OpResetFunc = Operator - > GetResetFunction ( ) ;
// Test execute function with input variations
if ( OpExecFunc | | OpPostExecFunc )
{
ConditionallyCallExecFunc ( Operator . Get ( ) ) ;
ConditionallyCallPostExecFunc ( Operator . Get ( ) ) ;
2023-05-30 17:07:23 -04:00
if ( InputTester . GetNumMutableInputs ( ) > 0 )
{
InputTester . SetMutableInputsToDefault ( ) ;
2024-01-25 17:41:37 -05:00
ConditionallyCallExecFunc ( Operator . Get ( ) ) ;
ConditionallyCallPostExecFunc ( Operator . Get ( ) ) ;
2023-05-30 17:07:23 -04:00
InputTester . SetMutableInputsToMin ( ) ;
2024-01-25 17:41:37 -05:00
ConditionallyCallExecFunc ( Operator . Get ( ) ) ;
ConditionallyCallPostExecFunc ( Operator . Get ( ) ) ;
2023-05-30 17:07:23 -04:00
InputTester . SetMutableInputsToMax ( ) ;
2024-01-25 17:41:37 -05:00
ConditionallyCallExecFunc ( Operator . Get ( ) ) ;
ConditionallyCallPostExecFunc ( Operator . Get ( ) ) ;
2023-05-30 17:07:23 -04:00
InputTester . SetMutableInputsToRandom ( ) ;
2024-01-25 17:41:37 -05:00
ConditionallyCallExecFunc ( Operator . Get ( ) ) ;
ConditionallyCallPostExecFunc ( Operator . Get ( ) ) ;
2023-05-30 17:07:23 -04:00
}
}
// Return inputs to initial state.
InputTester . SetMutableInputsToState ( InitialInputState ) ;
if ( OpResetFunc )
{
OpResetFunc ( Operator . Get ( ) , ResetParams ) ;
}
2024-01-25 17:41:37 -05:00
else if ( OpExecFunc | | OpPostExecFunc )
2023-05-30 17:07:23 -04:00
{
2024-02-08 17:55:13 -05:00
AddError ( FString : : Printf ( TEXT ( " Missing Reset(...) function when execute function exists for node %s - %s " ) , * InRegistryKeyString , * GetPrettyName ( RegistryKey ) ) ) ;
2023-05-30 17:07:23 -04:00
}
// Check that after returning all inputs to their original state and calling
// reset on the operator, that all output values have returned to their initail state.
if ( ! OutputTester . AreAllOutputValuesEqualToCapturedValues ( ) )
{
2024-02-08 17:55:13 -05:00
AddError ( FString : : Printf ( TEXT ( " Reset(...) function resulted in different starting conditions for node %s - %s " ) , * InRegistryKeyString , * GetPrettyName ( RegistryKey ) ) ) ;
2023-05-30 17:07:23 -04:00
}
} ;
// Test entire operator lifecycle with different starting conditions if
// any of the inputs are mutable
InputTester . SetMutableInputsToDefault ( ) ;
RunTestIteration ( ) ;
if ( InputTester . GetNumMutableInputs ( ) > 0 )
{
InputTester . SetMutableInputsToMin ( ) ;
RunTestIteration ( ) ;
InputTester . SetMutableInputsToMax ( ) ;
RunTestIteration ( ) ;
InputTester . SetMutableInputsToRandom ( ) ;
RunTestIteration ( ) ;
}
return true ;
}
# endif // WITH_EDITORONLY_DATA
# endif //WITH_DEV_AUTOMATION_TESTS