2022-01-19 15:00:37 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2023-05-30 18:38:07 -04:00
using System ;
2022-04-27 12:36:35 -04:00
using System.Collections.Generic ;
2022-01-19 15:00:37 -05:00
using System.IO ;
2022-04-27 12:36:35 -04:00
using System.Linq ;
using System.Xml.Linq ;
using EpicGames.Core ;
2024-05-01 11:35:44 -04:00
using Microsoft.Extensions.Logging ;
2023-05-30 18:38:07 -04:00
using UnrealBuildBase ;
2022-01-19 15:00:37 -05:00
namespace UnrealBuildTool
{
/// <summary>
/// ModuleRules extension for low level tests.
/// </summary>
public class TestModuleRules : ModuleRules
{
2024-05-01 11:35:44 -04:00
private static readonly XNamespace BuildGraphNamespace = XNamespace . Get ( "http://www.epicgames.com/BuildGraph" ) ;
private static readonly XNamespace SchemaInstance = XNamespace . Get ( "http://www.w3.org/2001/XMLSchema-instance" ) ;
private static readonly XNamespace SchemaLocation = XNamespace . Get ( "http://www.epicgames.com/BuildGraph ../../Build/Graph/Schema.xsd" ) ;
private static readonly List < string > RestrictedFoldersNonPlatform = new List < string > ( ) {
2024-07-25 16:15:56 -04:00
RestrictedFolder . LimitedAccess . ToString ( ) ,
2024-05-01 11:35:44 -04:00
RestrictedFolder . NotForLicensees . ToString ( ) ,
RestrictedFolder . NoRedist . ToString ( ) ,
RestrictedFolder . EpicInternal . ToString ( ) ,
RestrictedFolder . CarefullyRedist . ToString ( )
} ;
2022-04-27 12:36:35 -04:00
private bool bUsesCatch2 = true ;
2024-05-06 13:09:50 -04:00
/// <summary>
/// Check if running in test mode.
/// </summary>
protected static bool InTestMode = Environment . GetCommandLineArgs ( ) . Contains ( "-Mode=Test" ) ;
2022-01-19 15:00:37 -05:00
/// <summary>
/// Associated tested module of this test module.
/// </summary>
2022-04-27 12:36:35 -04:00
public ModuleRules ? TestedModule { get ; private set ; }
2024-05-01 11:35:44 -04:00
/// <summary>
/// Test metadata, used with BuildGraph only.
/// </summary>
protected static Metadata TestMetadata = new Metadata ( ) ;
2022-04-27 12:36:35 -04:00
/// <summary>
/// Constructs a TestModuleRules object as its own test module.
/// </summary>
/// <param name="Target"></param>
public TestModuleRules ( ReadOnlyTargetRules Target ) : base ( Target )
{
SetupCommonProperties ( Target ) ;
}
/// <summary>
/// Constructs a TestModuleRules object as its own test module.
/// Sets value of bUsesCatch2.
/// </summary>
public TestModuleRules ( ReadOnlyTargetRules Target , bool InUsesCatch2 ) : base ( Target )
{
bUsesCatch2 = InUsesCatch2 ;
if ( bUsesCatch2 )
{
SetupCommonProperties ( Target ) ;
}
}
2022-01-19 15:00:37 -05:00
/// <summary>
/// Constructs a TestModuleRules object with an associated tested module.
/// </summary>
2022-04-20 14:24:59 -04:00
public TestModuleRules ( ModuleRules TestedModule ) : base ( TestedModule . Target )
2022-01-19 15:00:37 -05:00
{
this . TestedModule = TestedModule ;
Name = TestedModule . Name + "Tests" ;
2023-05-30 18:59:32 -04:00
if ( ! String . IsNullOrEmpty ( TestedModule . ShortName ) )
2022-01-19 15:00:37 -05:00
{
ShortName = TestedModule . ShortName + "Tests" ;
}
2022-04-20 14:24:59 -04:00
File = TestedModule . File ;
2022-01-19 15:00:37 -05:00
Directory = DirectoryReference . Combine ( TestedModule . Directory , "Tests" ) ;
Context = TestedModule . Context ;
2022-04-27 12:36:35 -04:00
PrivateDependencyModuleNames . AddRange ( TestedModule . PrivateDependencyModuleNames ) ;
2023-02-06 14:27:24 -05:00
PublicDependencyModuleNames . AddRange ( TestedModule . PublicDependencyModuleNames ) ;
2022-04-27 12:36:35 -04:00
2023-11-29 16:58:22 -05:00
DirectoriesForModuleSubClasses = new Dictionary < Type , DirectoryReference > ( ) ;
2022-04-27 12:36:35 -04:00
// Tests can refer to tested module's Public and Private paths
string ModulePublicDir = Path . Combine ( TestedModule . ModuleDirectory , "Public" ) ;
if ( System . IO . Directory . Exists ( ModulePublicDir ) )
{
PublicIncludePaths . Add ( ModulePublicDir ) ;
}
string ModulePrivateDir = Path . Combine ( TestedModule . ModuleDirectory , "Private" ) ;
if ( System . IO . Directory . Exists ( ModulePrivateDir ) )
{
PrivateIncludePaths . Add ( ModulePrivateDir ) ;
}
SetupCommonProperties ( Target ) ;
}
private void SetupCommonProperties ( ReadOnlyTargetRules Target )
{
bIsTestModuleOverride = true ;
2022-01-19 15:00:37 -05:00
PCHUsage = PCHUsageMode . NoPCHs ;
PrecompileForTargets = PrecompileTargetsType . None ;
if ( Target . Configuration = = UnrealTargetConfiguration . Debug & & Target . Platform = = UnrealTargetPlatform . Linux )
{
OptimizeCode = CodeOptimization . Never ;
}
bAllowConfidentialPlatformDefines = true ;
bLegalToDistributeObjectCode = true ;
// Required false for catch.hpp
bUseUnity = false ;
// Disable exception handling so that tests can assert for exceptions
bEnableObjCExceptions = false ;
bEnableExceptions = false ;
2022-10-18 11:48:58 -04:00
SetResourcesFolder ( "Resources" ) ;
2022-02-22 13:52:35 -05:00
2022-05-17 15:06:28 -04:00
if ( ! PublicDependencyModuleNames . Contains ( "Catch2" ) )
{
PublicDependencyModuleNames . Add ( "Catch2" ) ;
}
2022-02-22 13:52:35 -05:00
if ( ! PrivateDependencyModuleNames . Contains ( "LowLevelTestsRunner" ) )
{
PrivateDependencyModuleNames . Add ( "LowLevelTestsRunner" ) ;
}
2022-01-19 15:00:37 -05:00
2023-06-15 04:50:22 -04:00
if ( Target . Platform = = UnrealTargetPlatform . IOS | | Target . Platform = = UnrealTargetPlatform . TVOS )
{
// Fix missing frameworks from ApplicationCore
2024-04-03 12:22:43 -04:00
2023-06-15 04:50:22 -04:00
// Needed for CADisplayLink
PublicFrameworks . Add ( "QuartzCore" ) ;
// Needed for MTLCreateSystemDefaultDevice
PublicWeakFrameworks . Add ( "Metal" ) ;
}
2022-01-19 15:00:37 -05:00
}
2022-04-27 12:36:35 -04:00
/// <summary>
/// Set test-specific resources folder relative to module directory.
/// This will be copied to the binaries path during deployment.
/// </summary>
protected void SetResourcesFolder ( string ResourcesRelativeFolder )
{
2023-12-20 17:54:40 -05:00
AdditionalPropertiesForReceipt . RemoveAll ( Prop = > Prop . Name = = "ResourcesFolder" ) ;
2022-10-18 11:48:58 -04:00
foreach ( DirectoryReference Directory in GetAllModuleDirectories ( ) )
2022-04-27 12:36:35 -04:00
{
2022-10-18 11:48:58 -04:00
string TestResourcesDir = Path . Combine ( Directory . FullName , ResourcesRelativeFolder ) ;
if ( System . IO . Directory . Exists ( TestResourcesDir ) )
2022-04-27 12:36:35 -04:00
{
AdditionalPropertiesForReceipt . Add ( "ResourcesFolder" , TestResourcesDir ) ;
}
}
}
2023-05-04 11:05:46 -04:00
#pragma warning disable 8602
#pragma warning disable 8604
2024-05-01 11:35:44 -04:00
2022-04-27 12:36:35 -04:00
/// <summary>
2024-05-01 11:35:44 -04:00
/// Deprecated, test metadata now generated explicitly using -Mode-Test with -GenerateMetadata.
2022-04-27 12:36:35 -04:00
/// </summary>
2024-05-01 11:35:44 -04:00
/// <param name="TestMetadata"></param>
[Obsolete("Use RunUBT -Mode=Test -GenerateMetadata instead")]
2023-05-04 11:05:46 -04:00
protected void UpdateBuildGraphPropertiesFile ( Metadata TestMetadata )
2022-04-27 12:36:35 -04:00
{
2024-05-01 11:35:44 -04:00
}
2023-06-29 15:18:42 -04:00
2024-05-01 11:35:44 -04:00
/// <summary>
/// Generates or updates metadata file for LowLevelTests.xml containing test flags: name, short name, target name, relative binaries path, supported platforms etc.
/// Called by RunUBT.bat -Mode=Test -GenerateMetadata
/// </summary>
private static void UpdateBuildGraphMetadata ( Metadata TestMetadata , string ModuleDirectory , string ModuleName , ILogger Log )
{
string BaseFolder = GetBaseFolder ( ModuleDirectory ) ;
2022-04-27 12:36:35 -04:00
2023-05-04 11:05:46 -04:00
bool ModuleInRestrictedPath = IsRestrictedPath ( ModuleDirectory ) ;
2022-04-27 12:36:35 -04:00
// All relevant properties
2024-05-01 11:35:44 -04:00
string TestTargetName = ModuleName ? ? "Launch" ;
string TestBinariesPath = TryGetBinariesPath ( ModuleDirectory ) ;
2022-04-27 12:36:35 -04:00
// Do not save full paths
if ( Path . IsPathRooted ( TestBinariesPath ) )
{
TestBinariesPath = Path . GetRelativePath ( Unreal . RootDirectory . FullName , TestBinariesPath ) ;
}
2023-05-04 11:05:46 -04:00
// Platform-specific configurations
string GeneratedPropertiesPlatformFile ;
string NonPublicPathPlatform ;
2024-05-01 11:35:44 -04:00
Dictionary < string , XDocument > SaveAtEnd = new Dictionary < string , XDocument > ( ) ;
// Generate peroperty file for each supported platform
foreach ( UnrealTargetPlatform ValidPlatform in TestMetadata . SupportedPlatforms )
2023-05-04 11:05:46 -04:00
{
bool IsRestrictedPlatformName = IsPlatformRestricted ( ValidPlatform ) ;
if ( IsRestrictedPlatformName )
{
2023-08-17 16:15:06 -04:00
NonPublicPathPlatform = Path . Combine ( BaseFolder , "Restricted" , "NotForLicensees" , "Platforms" , ValidPlatform . ToString ( ) , "Build" , "LowLevelTests" , $"{TestMetadata.TestName}.xml" ) ;
2023-05-04 11:05:46 -04:00
}
else
{
2023-08-17 16:15:06 -04:00
NonPublicPathPlatform = Path . Combine ( BaseFolder , "Restricted" , "NotForLicensees" , "Build" , "LowLevelTests" , $"{TestMetadata.TestName}.xml" ) ;
2023-05-04 11:05:46 -04:00
}
if ( ModuleInRestrictedPath )
{
GeneratedPropertiesPlatformFile = NonPublicPathPlatform ;
}
else
{
if ( IsRestrictedPlatformName )
{
2023-08-17 16:15:06 -04:00
GeneratedPropertiesPlatformFile = Path . Combine ( BaseFolder , "Platforms" , ValidPlatform . ToString ( ) , "Build" , "LowLevelTests" , $"{TestMetadata.TestName}.xml" ) ;
2023-05-04 11:05:46 -04:00
}
else
{
2023-08-17 16:15:06 -04:00
GeneratedPropertiesPlatformFile = Path . Combine ( BaseFolder , "Build" , "LowLevelTests" , $"{TestMetadata.TestName}.xml" ) ;
2023-05-04 11:05:46 -04:00
}
}
if ( ! System . IO . File . Exists ( GeneratedPropertiesPlatformFile ) )
{
string? DirGenPropsPlatforms = Path . GetDirectoryName ( GeneratedPropertiesPlatformFile ) ;
if ( DirGenPropsPlatforms ! = null & & ! System . IO . Directory . Exists ( DirGenPropsPlatforms ) )
{
System . IO . Directory . CreateDirectory ( DirGenPropsPlatforms ) ;
}
using ( FileStream FileStream = System . IO . File . Create ( GeneratedPropertiesPlatformFile ) )
{
2023-05-30 18:38:07 -04:00
new XDocument ( new XElement ( BuildGraphNamespace + "BuildGraph" , new XAttribute ( XNamespace . Xmlns + "xsi" , SchemaInstance ) , new XAttribute ( SchemaInstance + "schemaLocation" , SchemaLocation ) ) ) . Save ( FileStream ) ;
2023-05-04 11:05:46 -04:00
}
}
2023-08-17 16:15:06 -04:00
MakeFileWriteable ( GeneratedPropertiesPlatformFile ) ;
2024-05-01 11:35:44 -04:00
XElement Root ;
if ( ! SaveAtEnd . ContainsKey ( GeneratedPropertiesPlatformFile ) )
{
XDocument XInitPlatformFile = XDocument . Load ( GeneratedPropertiesPlatformFile ) ;
// Any manually edited elements to keep
List < XElement > KeepElements = XInitPlatformFile . Root ! . Elements ( ) . Where ( e = > e . Attribute ( "Name" ) . Value = = $"{TestMetadata.TestName}AfterSteps" ) . ToList ( ) ;
XInitPlatformFile . Root ! . Elements ( ) . Remove ( ) ;
2024-05-06 19:08:51 -04:00
foreach ( XElement Element in KeepElements )
2024-05-01 11:35:44 -04:00
{
XInitPlatformFile . Root ! . Add ( Element ) ;
}
SaveAtEnd . Add ( GeneratedPropertiesPlatformFile , XInitPlatformFile ) ;
}
2023-05-04 11:05:46 -04:00
2024-05-01 11:35:44 -04:00
Root = SaveAtEnd [ GeneratedPropertiesPlatformFile ] . Root ! ;
// Optional metadata, use Expand and set any non-default metadata
Dictionary < string , string > ExpandArguments = new Dictionary < string , string > ( ) ;
if ( ! IsRestrictedPlatformName )
{
2024-05-26 15:59:52 -04:00
InsertOrUpdateTestOption ( Root , $"Run{TestMetadata.TestName}Tests" , $"Run {TestMetadata.TestShortName} Tests" , "" ) ;
2024-05-24 12:58:43 -04:00
InsertOrUpdateTestProperty ( Root , $"TestNames" , TestMetadata . TestName , true ) ;
2024-05-01 11:35:44 -04:00
}
if ( TestMetadata . Deactivated )
{
ExpandArguments . Add ( "Deactivated" , Convert . ToString ( TestMetadata . Deactivated ) ) ;
}
ExpandArguments . Add ( "TestName" , Convert . ToString ( TestMetadata . TestName ) ) ;
ExpandArguments . Add ( "ShortName" , Convert . ToString ( TestMetadata . TestShortName ) ) ;
if ( TestMetadata . StagesWithProjectFile )
{
ExpandArguments . Add ( "StagesWithProjectFile" , Convert . ToString ( TestMetadata . StagesWithProjectFile ) ) ;
}
ExpandArguments . Add ( "TargetName" , Convert . ToString ( TestTargetName ) ) ;
ExpandArguments . Add ( "BinaryRelativePath" , Convert . ToString ( TestBinariesPath ) ) ;
ExpandArguments . Add ( "ReportType" , Convert . ToString ( TestMetadata . ReportType ) ) ;
2024-05-06 19:08:51 -04:00
if ( ! String . IsNullOrEmpty ( TestMetadata . GauntletArgs ) )
2024-05-01 11:35:44 -04:00
{
ExpandArguments . Add ( "GauntletArgs" , Convert . ToString ( TestMetadata . InitialExtraArgs ) + Convert . ToString ( TestMetadata . GauntletArgs ) ) ;
}
if ( TestMetadata . PlatformGauntletArgs . ContainsKey ( ValidPlatform ) )
{
ExpandArguments . Add ( "PlatformGauntletArgs" , TestMetadata . PlatformGauntletArgs [ ValidPlatform ] ) ;
}
2024-05-06 19:08:51 -04:00
if ( ! String . IsNullOrEmpty ( TestMetadata . ExtraArgs ) )
2024-05-01 11:35:44 -04:00
{
ExpandArguments . Add ( "ExtraArgs" , Convert . ToString ( TestMetadata . ExtraArgs ) ) ;
}
if ( TestMetadata . HasAfterSteps )
{
ExpandArguments . Add ( "HasAfterSteps" , Convert . ToString ( TestMetadata . HasAfterSteps ) ) ;
}
if ( ! TestMetadata . UsesCatch2 )
{
ExpandArguments . Add ( "UsesCatch2" , Convert . ToString ( TestMetadata . UsesCatch2 ) ) ;
}
2023-05-30 18:59:32 -04:00
string TagsValue = TestMetadata . PlatformTags . ContainsKey ( ValidPlatform ) ? TestMetadata . PlatformTags [ ValidPlatform ] : String . Empty ;
2024-05-06 19:08:51 -04:00
if ( ! String . IsNullOrEmpty ( TagsValue ) )
2024-05-01 11:35:44 -04:00
{
ExpandArguments . Add ( "Tags" , TagsValue ) ;
}
2023-05-04 11:05:46 -04:00
2023-05-30 18:59:32 -04:00
string ExtraCompilationArgsValue = TestMetadata . PlatformCompilationExtraArgs . ContainsKey ( ValidPlatform ) ? TestMetadata . PlatformCompilationExtraArgs [ ValidPlatform ] : String . Empty ;
2024-05-06 19:08:51 -04:00
if ( ! String . IsNullOrEmpty ( ExtraCompilationArgsValue ) )
2024-05-01 11:35:44 -04:00
{
ExpandArguments . Add ( "ExtraCompilationArgs" , ExtraCompilationArgsValue ) ;
}
2023-05-04 11:05:46 -04:00
2024-05-01 11:35:44 -04:00
// By default all test supported platforms have run supported, generally only a few don't (e.g. iOS)
bool RunUnsupportedPlatform = TestMetadata . PlatformsRunUnsupported . Contains ( ValidPlatform ) ;
if ( RunUnsupportedPlatform )
{
ExpandArguments . Add ( "RunUnsupported" , "True" ) ;
}
2023-05-04 11:05:46 -04:00
2023-09-11 12:55:31 -04:00
string RunContainerizedValue = TestMetadata . PlatformRunContainerized . ContainsKey ( ValidPlatform ) ? "True" : "False" ;
2024-05-01 11:35:44 -04:00
if ( RunContainerizedValue = = "True" )
{
ExpandArguments . Add ( "RunContainerized" , RunContainerizedValue ) ;
}
2023-09-11 12:55:31 -04:00
2024-05-01 11:35:44 -04:00
AppendOrUpdateRunAllTestsNode ( Root , "DeployAndTest" , ValidPlatform . ToString ( ) , ExpandArguments ) ;
2024-05-22 12:18:21 -04:00
if ( IsRestrictedPlatformName )
{
// Create a General.xml file and add a TestPlatform* option
string RestrictedPlatformFolderPath = Path . GetDirectoryName ( GeneratedPropertiesPlatformFile ) ! ;
string RestrictedPlatformGeneral = Path . Combine ( RestrictedPlatformFolderPath , "General.xml" ) ;
if ( ! System . IO . File . Exists ( RestrictedPlatformGeneral ) )
{
using ( FileStream FileStream = System . IO . File . Create ( RestrictedPlatformGeneral ) )
{
Log . LogInformation ( "Saving general metadata to {File}" , RestrictedPlatformGeneral ) ;
XDocument GeneralProps = new XDocument ( new XElement ( BuildGraphNamespace + "BuildGraph" , new XAttribute ( XNamespace . Xmlns + "xsi" , SchemaInstance ) , new XAttribute ( SchemaInstance + "schemaLocation" , SchemaLocation ) ) ) ;
InsertOrUpdateTestOption ( GeneralProps . Root , $"TestPlatform{ValidPlatform}" , $"Run tests on {ValidPlatform}" , false . ToString ( ) ) ;
GeneralProps . Save ( FileStream ) ;
}
}
}
2024-05-01 11:35:44 -04:00
}
foreach ( KeyValuePair < string , XDocument > KVP in SaveAtEnd )
{
Log . LogInformation ( "Saving metadata to {File}" , KVP . Key ) ;
KVP . Value . Save ( KVP . Key ) ;
2023-05-04 11:05:46 -04:00
}
}
2024-05-01 11:35:44 -04:00
private static string GetBaseFolder ( string ModuleDirectory )
2023-08-17 16:15:06 -04:00
{
string RelativeModulePath = Path . GetRelativePath ( Unreal . RootDirectory . FullName , ModuleDirectory ) ;
string [ ] BreadCrumbs = RelativeModulePath . Split ( new char [ ] { '\\' , '/' } , StringSplitOptions . RemoveEmptyEntries ) ;
if ( BreadCrumbs . Length > 0 )
{
return Path . Combine ( Unreal . RootDirectory . FullName , BreadCrumbs [ 0 ] ) ;
}
return Unreal . EngineDirectory . FullName ;
}
2024-05-01 11:35:44 -04:00
private static bool IsPlatformRestricted ( UnrealTargetPlatform Platform )
2023-05-04 11:05:46 -04:00
{
return RestrictedFolder . GetNames ( ) . Contains ( Platform . ToString ( ) ) ;
2022-04-27 12:36:35 -04:00
}
2024-05-01 11:35:44 -04:00
private static bool IsRestrictedPath ( string ModuleDirectory )
2022-04-27 12:36:35 -04:00
{
2024-05-01 11:35:44 -04:00
return ModuleDirectory . Split ( new char [ ] { '/' , '\\' } ) . Intersect ( RestrictedFoldersNonPlatform ) . Count ( ) > 0 ;
2022-04-27 12:36:35 -04:00
}
2024-05-01 11:35:44 -04:00
private static string TryGetBinariesPath ( string ModuleDirectory )
2022-04-27 12:36:35 -04:00
{
int SourceFolderIndex = ModuleDirectory . IndexOf ( "Source" ) ;
if ( SourceFolderIndex < 0 )
{
2023-08-17 16:15:06 -04:00
int PluginFolderIndex = ModuleDirectory . IndexOf ( "Plugins" ) ;
if ( PluginFolderIndex > = 0 )
{
return ModuleDirectory . Substring ( 0 , PluginFolderIndex ) + "Binaries" ;
}
2024-05-01 11:35:44 -04:00
throw new Exception ( "Could not detect source folder path for module from directory " + ModuleDirectory ) ;
2022-04-27 12:36:35 -04:00
}
return ModuleDirectory . Substring ( 0 , SourceFolderIndex ) + "Binaries" ;
}
2024-05-01 11:35:44 -04:00
private static void AppendOrUpdateRunAllTestsNode ( XElement Root , string MacroName , string Platform , Dictionary < string , string > ExpandArguments )
2023-05-04 11:05:46 -04:00
{
2024-05-01 11:35:44 -04:00
XElement ? ExtendNode = Root . Elements ( ) . Where ( element = > element . Name . LocalName = = "Extend" ) . FirstOrDefault ( ) ;
if ( ExtendNode = = null )
2023-05-04 11:05:46 -04:00
{
2024-05-01 11:35:44 -04:00
ExtendNode = new XElement ( BuildGraphNamespace + "Extend" ) ;
ExtendNode . SetAttributeValue ( "Name" , "RunAllTests" ) ;
Root . Add ( ExtendNode ) ;
2023-05-04 11:05:46 -04:00
}
2024-05-01 11:35:44 -04:00
XElement ? ExpandNode = ExtendNode . Elements ( ) . Where ( element = > element . Attribute ( "Name" ) . Value = = MacroName & & element . Attribute ( "Platform" ) . Value = = Platform ) . FirstOrDefault ( ) ;
if ( ExpandNode = = null )
2023-05-04 11:05:46 -04:00
{
2024-05-01 11:35:44 -04:00
ExpandNode = new XElement ( BuildGraphNamespace + "Expand" ) ;
ExpandNode . SetAttributeValue ( "Name" , MacroName ) ;
ExpandNode . SetAttributeValue ( "Platform" , Platform ) ;
ExtendNode . Add ( ExpandNode ) ;
2023-05-04 11:05:46 -04:00
}
2024-05-01 11:35:44 -04:00
foreach ( KeyValuePair < string , string > ArgumentAndValue in ExpandArguments )
2022-04-27 12:36:35 -04:00
{
2024-05-01 11:35:44 -04:00
ExpandNode ! . SetAttributeValue ( ArgumentAndValue . Key , ArgumentAndValue . Value ) ;
2022-04-27 12:36:35 -04:00
}
}
2024-05-01 11:35:44 -04:00
private static void InsertOrUpdateTestOption ( XElement Root , string OptionName , string Description , string DefaultValue )
2022-04-27 12:36:35 -04:00
{
2024-05-01 11:35:44 -04:00
XElement ? OptionElementWithName = Root . Elements ( BuildGraphNamespace + "Option" )
. Where ( prop = > prop . Attribute ( "Name" ) . Value = = OptionName ) . FirstOrDefault ( ) ;
if ( OptionElementWithName = = null )
2022-04-27 12:36:35 -04:00
{
XElement ElementInsert = new XElement ( BuildGraphNamespace + "Option" ) ;
2024-05-01 11:35:44 -04:00
ElementInsert . SetAttributeValue ( "Name" , OptionName ) ;
2022-04-27 12:36:35 -04:00
ElementInsert . SetAttributeValue ( "DefaultValue" , DefaultValue ) ;
2023-05-04 11:05:46 -04:00
ElementInsert . SetAttributeValue ( "Description" , Description ) ;
2024-05-01 11:35:44 -04:00
Root . Add ( ElementInsert ) ;
2022-04-27 12:36:35 -04:00
}
else
{
2024-05-01 11:35:44 -04:00
OptionElementWithName . SetAttributeValue ( "Description" , Description ) ;
OptionElementWithName . SetAttributeValue ( "DefaultValue" , DefaultValue ) ;
2022-04-27 12:36:35 -04:00
}
}
2023-05-04 11:05:46 -04:00
2024-05-24 12:58:43 -04:00
private static void InsertOrUpdateTestProperty ( XElement Root , string PropertyName , string PropertyValue , bool Append )
{
XElement ? PropertyElementWithName = Root . Elements ( BuildGraphNamespace + "Property" )
. Where ( prop = > prop . Attribute ( "Name" ) . Value = = PropertyName ) . FirstOrDefault ( ) ;
if ( PropertyElementWithName = = null )
{
XElement ElementInsert = new XElement ( BuildGraphNamespace + "Property" ) ;
ElementInsert . SetAttributeValue ( "Name" , PropertyName ) ;
ElementInsert . SetAttributeValue ( "Value" , ! Append ? PropertyValue : $"$({PropertyName});{PropertyValue}" ) ;
Root . Add ( ElementInsert ) ;
}
else
{
PropertyElementWithName . SetAttributeValue ( "Value" , ! Append ? PropertyValue : $"$({PropertyName});{PropertyValue}" ) ;
}
}
2023-05-04 11:05:46 -04:00
#pragma warning restore 8604
2022-04-27 12:36:35 -04:00
#pragma warning restore 8602
2024-05-01 11:35:44 -04:00
private static void MakeFileWriteable ( string InFilePath )
2023-08-17 16:15:06 -04:00
{
System . IO . File . SetAttributes ( InFilePath , System . IO . File . GetAttributes ( InFilePath ) & ~ FileAttributes . ReadOnly ) ;
}
2023-05-04 11:05:46 -04:00
#pragma warning disable 8618
2022-04-27 12:36:35 -04:00
/// <summary>
/// Test metadata class.
/// </summary>
public class Metadata
{
/// <summary>
/// Test long name.
/// </summary>
2023-05-04 11:05:46 -04:00
public string TestName { get ; set ; }
2022-04-27 12:36:35 -04:00
/// <summary>
/// Test short name used for display in build system.
/// </summary>
2023-05-04 11:05:46 -04:00
public string TestShortName { get ; set ; }
2022-04-27 12:36:35 -04:00
2023-06-01 16:57:35 -04:00
private string ReportTypePrivate = "console" ;
2022-04-27 12:36:35 -04:00
/// <summary>
/// Type of Catch2 report, defaults to console.
/// </summary>
2024-04-03 12:22:43 -04:00
public string ReportType
{
2023-06-01 16:57:35 -04:00
get = > ReportTypePrivate ;
set = > ReportTypePrivate = value ;
}
2022-04-27 12:36:35 -04:00
2023-06-22 17:41:56 -04:00
/// <summary>
2023-08-10 11:53:46 -04:00
/// Does this test use project files for staging additional files
2023-06-22 17:41:56 -04:00
/// and cause the build to use BuildCookRun instead of a Compile step
/// </summary>
public bool StagesWithProjectFile { get ; set ; }
2022-04-27 12:36:35 -04:00
/// <summary>
2024-05-01 11:35:44 -04:00
/// Is this test deactivated?
2022-04-27 12:36:35 -04:00
/// </summary>
2024-05-01 11:35:44 -04:00
public bool Deactivated { get ; set ; }
2022-04-27 12:36:35 -04:00
2023-08-10 11:53:46 -04:00
/// <summary>
/// Depercated, use GauntletArgs or ExtraArgs instead to help indicate arguments to launch the test under.
/// </summary>
public string InitialExtraArgs
2024-04-03 12:22:43 -04:00
{
2023-08-10 11:53:46 -04:00
get ;
[Obsolete]
2024-04-03 12:22:43 -04:00
set ;
2023-08-10 11:53:46 -04:00
}
2022-04-27 12:36:35 -04:00
/// <summary>
2023-08-17 16:15:06 -04:00
/// Any initial Gauntlet args to be passed to the test executable
2022-04-27 12:36:35 -04:00
/// </summary>
2023-08-10 11:53:46 -04:00
public string GauntletArgs { get ; set ; }
/// <summary>
/// Any extra args to be passed to the test executable as --extra-args
/// </summary>
public string ExtraArgs { get ; set ; }
2023-05-04 11:05:46 -04:00
/// <summary>
/// Whether there's a step that gets executed after the tests have finished.
/// Typically used for cleanup of resources.
/// </summary>
public bool HasAfterSteps { get ; set ; }
private bool UsesCatch2Private = true ;
/// <summary>
/// Test built with a frakework other than Catch2
/// </summary>
public bool UsesCatch2
2022-04-27 12:36:35 -04:00
{
2023-05-30 18:01:50 -04:00
get = > UsesCatch2Private ;
set = > UsesCatch2Private = value ;
2022-04-27 12:36:35 -04:00
}
2023-08-17 16:15:06 -04:00
/// <summary>
/// Set of supported platforms.
/// </summary>
public HashSet < UnrealTargetPlatform > SupportedPlatforms { get ; set ; } = new HashSet < UnrealTargetPlatform > ( ) { UnrealTargetPlatform . Win64 } ;
2023-05-04 11:05:46 -04:00
private Dictionary < UnrealTargetPlatform , string > PlatformTagsPrivate = new Dictionary < UnrealTargetPlatform , string > ( ) ;
2022-04-27 12:36:35 -04:00
/// <summary>
2023-05-04 11:05:46 -04:00
/// Per-platform tags.
2022-04-27 12:36:35 -04:00
/// </summary>
2023-05-04 11:05:46 -04:00
public Dictionary < UnrealTargetPlatform , string > PlatformTags
2022-04-27 12:36:35 -04:00
{
2023-05-30 18:01:50 -04:00
get = > PlatformTagsPrivate ;
set = > PlatformTagsPrivate = value ;
2022-04-27 12:36:35 -04:00
}
2024-05-01 11:35:44 -04:00
private Dictionary < UnrealTargetPlatform , string > PlatformGauntletArgsPrivate = new Dictionary < UnrealTargetPlatform , string > ( ) ;
/// <summary>
/// Per-platform gauntlet args.
/// </summary>
public Dictionary < UnrealTargetPlatform , string > PlatformGauntletArgs
{
get = > PlatformGauntletArgsPrivate ;
set = > PlatformGauntletArgsPrivate = value ;
}
2023-05-04 11:05:46 -04:00
private Dictionary < UnrealTargetPlatform , string > PlatformCompilationExtraArgsPrivate = new Dictionary < UnrealTargetPlatform , string > ( ) ;
2022-04-27 12:36:35 -04:00
/// <summary>
2023-05-04 11:05:46 -04:00
/// Per-platform extra compilation arguments.
2022-04-27 12:36:35 -04:00
/// </summary>
2023-05-04 11:05:46 -04:00
public Dictionary < UnrealTargetPlatform , string > PlatformCompilationExtraArgs
2022-04-27 12:36:35 -04:00
{
2023-05-30 18:01:50 -04:00
get = > PlatformCompilationExtraArgsPrivate ;
set = > PlatformCompilationExtraArgsPrivate = value ;
2023-05-04 11:05:46 -04:00
}
2023-08-17 16:15:06 -04:00
private List < UnrealTargetPlatform > PlatformsRunUnsupportedPrivate = new List < UnrealTargetPlatform > ( ) {
UnrealTargetPlatform . Android ,
UnrealTargetPlatform . IOS ,
UnrealTargetPlatform . TVOS ,
UnrealTargetPlatform . VisionOS } ;
2023-05-04 11:05:46 -04:00
/// <summary>
/// List of platforms that cannot run tests.
/// </summary>
public List < UnrealTargetPlatform > PlatformsRunUnsupported
{
2023-05-30 18:01:50 -04:00
get = > PlatformsRunUnsupportedPrivate ;
set = > PlatformsRunUnsupportedPrivate = value ;
2022-04-27 12:36:35 -04:00
}
2023-09-11 12:55:31 -04:00
private Dictionary < UnrealTargetPlatform , bool > PlatformRunContainerizedPrivate = new Dictionary < UnrealTargetPlatform , bool > ( ) ;
/// <summary>
/// Whether or not the test is run inside a Docker container for a given platform.
/// </summary>
public Dictionary < UnrealTargetPlatform , bool > PlatformRunContainerized
{
2023-12-21 18:50:32 -05:00
get = > PlatformRunContainerizedPrivate ;
set = > PlatformRunContainerizedPrivate = value ;
2023-09-11 12:55:31 -04:00
}
2022-04-27 12:36:35 -04:00
}
2023-05-04 11:05:46 -04:00
#pragma warning restore 8618
2022-01-19 15:00:37 -05:00
}
2022-04-27 12:36:35 -04:00
}