Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
AutomationTest.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "Async/Async.h"
7#include "Async/Future.h"
8#include "Containers/Array.h"
9#include "Containers/Map.h"
10#include "Containers/Queue.h"
11#include "Containers/Set.h"
12#include "Containers/UnrealString.h"
13#include "Delegates/Delegate.h"
14#include "Delegates/DelegateBase.h"
15#include "Delegates/DelegateInstancesImpl.h"
16#include "Delegates/IDelegateInstance.h"
17#include "GenericPlatform/GenericPlatformStackWalk.h"
18#include "HAL/CriticalSection.h"
19#include "HAL/LowLevelMemTracker.h"
20#include "HAL/PlatformProcess.h"
21#include "HAL/PlatformStackWalk.h"
22#include "HAL/PlatformTime.h"
23#include "HAL/ThreadSafeBool.h"
24#include "Internationalization/Regex.h"
25#include "Logging/LogVerbosity.h"
26#include "Math/Color.h"
27#include "Math/Color.h"
28#include "Math/MathFwd.h"
29#include "Math/Rotator.h"
30#include "Math/UnrealMathUtility.h"
31#include "Math/Vector.h"
32#include "Misc/AssertionMacros.h"
33#include "Misc/AutomationEvent.h"
34#include "Misc/Build.h"
35#include "Misc/Char.h"
36#include "Misc/CString.h"
37#include "Misc/DateTime.h"
38#include "Misc/FeedbackContext.h"
39#include "Misc/Guid.h"
40#include "Misc/Optional.h"
41#include "Misc/OutputDevice.h"
42#include "Misc/Timespan.h"
43#include "Templates/Function.h"
44#include "Templates/SharedPointer.h"
45#include "Templates/UnrealTemplate.h"
46#include "UObject/NameTypes.h"
47
48#include <atomic>
49
52
53#ifndef WITH_AUTOMATION_TESTS
54 #define WITH_AUTOMATION_TESTS (WITH_DEV_AUTOMATION_TESTS || WITH_PERF_AUTOMATION_TESTS)
55#endif
56
57/** Call GetStack, with a guarantee of a non-empty return; a placeholder "Unknown",1) is used if necessary */
58#define SAFE_GETSTACK(VariableName, IgnoreCount, MaxDepth)
59 TArray<FProgramCounterSymbolInfo> VariableName = FPlatformStackWalk::GetStack(IgnoreCount, MaxDepth);
60 if (VariableName.Num() == 0)
61 {
62 /* This is a rare failure that can occur in some circumstances */
63 FProgramCounterSymbolInfo& Info = VariableName.Emplace_GetRef();
64 TCString<ANSICHAR>::Strcpy(Info.Filename, FProgramCounterSymbolInfo::MAX_NAME_LENGTH, "Unknown");
65 Info.LineNumber = 1;
66 }
67
68/**
69* Flags for specifying automation test requirements/behavior
70* Update GetTestFlagsMap when updating this enum.
71*/
73{
74 enum Type
75 {
76 None = 0x00000000,
77 //~ Application context required for the test
78 // Test is suitable for running within the editor
79 EditorContext = 0x00000001,
80 // Test is suitable for running within the client
81 ClientContext = 0x00000002,
82 // Test is suitable for running within the server
83 ServerContext = 0x00000004,
84 // Test is suitable for running within a commandlet
85 CommandletContext = 0x00000008,
86 ApplicationContextMask = EditorContext | ClientContext | ServerContext | CommandletContext,
87
88 //~ Features required for the test - not specifying means it is valid for any feature combination
89 // Test requires a non-null RHI to run correctly
90 NonNullRHI = 0x00000100,
91 // Test requires a user instigated session
92 RequiresUser = 0x00000200,
93 FeatureMask = NonNullRHI | RequiresUser,
94
95 //~ One-off flag to allow for fast disabling of tests without commenting code out
96 // Temp disabled and never returns for a filter
97 Disabled = 0x00010000,
98
99 //~ Priority of the test
100 // The highest priority possible. Showstopper/blocker.
101 CriticalPriority = 0x00100000,
102 // High priority. Major feature functionality etc.
103 HighPriority = 0x00200000,
104 // Mask for High on SetMinimumPriority
105 HighPriorityAndAbove = CriticalPriority | HighPriority,
106 // Medium Priority. Minor feature functionality, major generic content issues.
107 MediumPriority = 0x00400000,
108 // Mask for Medium on SetMinimumPriority
109 MediumPriorityAndAbove = CriticalPriority | HighPriority | MediumPriority,
110 // Low Priority. Minor content bugs. String errors. Etc.
111 LowPriority = 0x00800000,
112 PriorityMask = CriticalPriority | HighPriority | MediumPriority | LowPriority,
113
114 //~ Speed of the test
115 //Super Fast Filter
116 SmokeFilter = 0x01000000,
117 //Engine Level Test
118 EngineFilter = 0x02000000,
119 //Product Level Test
120 ProductFilter = 0x04000000,
121 //Performance Test
122 PerfFilter = 0x08000000,
123 //Stress Test
124 StressFilter = 0x10000000,
125 //Negative Test. For tests whose correct expected outcome is failure.
126 NegativeFilter = 0x20000000,
127 FilterMask = SmokeFilter | EngineFilter | ProductFilter | PerfFilter | StressFilter | NegativeFilter
128 };
129
130 static const TMap<FString, Type>& GetTestFlagsMap();
131
132 static const Type FromString(FString Name)
133 {
134 static auto FlagMap = GetTestFlagsMap();
135 if (FlagMap.Contains(Name))
136 {
137 return FlagMap[Name];
138 }
139 return Type::None;
140 }
141};
142
143/** Flags for indicating the matching type to use for an expected message */
145{
147 {
148 // When matching expected messages, do so exactly.
150 // When matching expected messages, just see if the message string is contained in the string to be evaluated.
152 };
153
155 {
156 switch (ThisType)
157 {
158 case Contains:
159 return TEXT("Contains");
160 case Exact:
161 return TEXT("Exact");
162 }
163 return TEXT("Unknown");
164 }
165}
166
167/** Flags for indicating the matching type to use for an expected error message. Aliased for backwards compatibility. */
168namespace EAutomationExpectedErrorFlags = EAutomationExpectedMessageFlags;
169
171{
175
176 FAutomationTelemetryData(const FString& InDataPoint, double InMeasurement, const FString& InContext)
178 , Measurement(InMeasurement)
180 {
181 }
182};
183
184/** Simple class to store the results of the execution of a automation test */
186{
187public:
188 /** Constructor */
190 : bSuccessful( false )
191 , Duration(0.0)
192 , Errors(0)
193 , Warnings(0)
194 {}
195
196 /** Destructor */
198 {
199 Clear();
200 }
201
202 /** Helper method to clear out the results from a previous execution */
203 void Clear();
204
206
207 int32 RemoveAllEvents(TFunctionRef<bool(FAutomationEvent&)> FilterPredicate);
208
209 /** Any errors that occurred during execution */
210 const TArray<FAutomationExecutionEntry>& GetEntries() const { return Entries; }
211
212 void AddEvent(const FAutomationEvent& Event, int StackOffset = 0, bool bCaptureStack = true);
213
214 void AddWarning(const FString& WarningMessage);
215 void AddError(const FString& ErrorMessage);
216
217 int32 GetWarningTotal() const { return Warnings; }
218 int32 GetErrorTotal() const { return Errors; }
219
220 const FString& GetContext() const
221 {
222 static FString EmptyContext;
223 return ContextStack.Num() ? ContextStack.Top() : EmptyContext;
224 }
225
226 void PushContext(const FString& Context)
227 {
228 ContextStack.Push(Context);
229 }
230
232 {
233 if ( ContextStack.Num() > 0 )
234 {
235 ContextStack.Pop();
236 }
237 }
238
239public:
240
241 /** Whether the automation test completed successfully or not */
243
244 /** Any analytics items that occurred during execution */
246
247 /** Telemetry items that occurred during execution */
249
250 /** Telemetry storage name set by the test */
252
253 /** Time to complete the task */
254 double Duration;
255
256private:
257 /** Any errors that occurred during execution */
259
260 int32 Errors;
261 int32 Warnings;
262
264};
265
266/** Simple class to store the automation test info */
268{
269public:
270
271 // Default constructor
273 : TestFlags( 0 )
276 {}
277
278 /**
279 * Constructor
280 *
281 * @param InDisplayName - Name used in the UI
282 * @param InTestName - The test command string
283 * @param InTestFlag - Test flags
284 * @param InParameterName - optional parameter. e.g. asset name
285 */
286 FAutomationTestInfo(const FString& InDisplayName, const FString& InFullTestPath, const FString& InTestName, const uint32 InTestFlags, const int32 InNumParticipantsRequired, const FString& InParameterName = FString(), const FString& InSourceFile = FString(), int32 InSourceFileLine = 0, const FString& InAssetPath = FString(), const FString& InOpenCommand = FString())
292 , SourceFileLine( InSourceFileLine )
295 , TestFlags( InTestFlags )
296 , NumParticipantsRequired( InNumParticipantsRequired )
298 {}
299
300public:
301
302 /**
303 * Add a test flag if a parent node.
304 *
305 * @Param InTestFlags - the child test flag to add.
306 */
307 void AddTestFlags( const uint32 InTestFlags)
308 {
309 TestFlags |= InTestFlags;
310 }
311
312 /**
313 * Get the display name of this test.
314 *
315 * @return the display name.
316 */
317 const FString& GetDisplayName() const
318 {
319 return DisplayName;
320 }
321
322 /**
323 * Gets the full path for this test if you wanted to run it.
324 *
325 * @return the display name.
326 */
328 {
329 return FullTestPath;
330 }
331
332 /**
333 * Get the test name of this test.
334 *
335 * @return The test name.
336 */
338 {
339 return TestName;
340 }
341
342 /**
343 * Get the type of parameter. This will be the asset name for linked assets.
344 *
345 * @return the parameter.
346 */
348 {
349 return TestParameter;
350 }
351
352 /**
353 * Get the source file this test originated in.
354 *
355 * @return the source file.
356 */
357 const FString GetSourceFile() const
358 {
359 return SourceFile;
360 }
361
362 /**
363 * Get the line number in the source file this test originated on.
364 *
365 * @return the source line number.
366 */
367 const int32 GetSourceFileLine() const
368 {
369 return SourceFileLine;
370 }
371
372 /**
373 * Gets the asset potentially associated with the test.
374 *
375 * @return the source line number.
376 */
377 const FString GetAssetPath() const
378 {
379 return AssetPath;
380 }
381
382 /**
383 * Gets the open command potentially associated with the test.
384 *
385 * @return the source line number.
386 */
388 {
389 return OpenCommand;
390 }
391
392 /**
393 * Get the type of test.
394 *
395 * @return the test type.
396 */
397 const uint32 GetTestFlags() const
398 {
399 return TestFlags;
400 }
401
402 /**
403 * Zero the number of devices running this test
404 */
406 {
408 }
409
410 /**
411 * Be notified of a new device running the test so we should update our flag counting these
412 */
414 {
416 }
417
418 /**
419 * Get the number of devices running this test
420 *
421 * @return The number of devices which have been given this test to run
422 */
423 const int GetNumDevicesRunningTest() const
424 {
426 }
427
428 /**
429 * Get the number of participant this test needs in order to be run
430 *
431 * @return The number of participants needed
432 */
433 const int32 GetNumParticipantsRequired() const
434 {
436 }
437
438
439 /**
440 * Set the display name of the child node.
441 *
442 * @Param InDisplayName - the new child test name.
443 */
444 void SetDisplayName( const FString& InDisplayName )
445 {
446 DisplayName = InDisplayName;
447 }
448
449 /**
450 * Set the number of participant this test needs in order to be run
451 *
452 * @Param NumRequired - The new number of participants needed
453 */
454 void SetNumParticipantsRequired( int32 NumRequired )
455 {
456 NumParticipantsRequired = NumRequired;
457 }
458
459private:
460 /** Display name used in the UI */
462
464
465 /** Test name used to run the test */
467
468 /** Parameter - e.g. an asset name or map name */
470
471 /** The source file this test originated in. */
473
474 /** The line number in the source file this test originated on. */
476
477 /** The asset path associated with the test. */
479
480 /** A custom open command for the test. */
482
483 /** The test flags. */
484 uint32 TestFlags;
485
486 /** The number of participants this test requires */
488
489 /** The number of devices which have been given this test to run */
491};
492
493
494/**
495 * Simple abstract base class for creating time deferred of a single test that need to be run sequentially (Loadmap & Wait, Open Editor & Wait, then execute...)
496 */
498{
499public:
500 /* virtual destructor */
502
503 /**
504 * Updates the current command and will only return TRUE when it has fulfilled its role (Load map has completed and wait time has expired)
505 */
506 virtual bool Update() = 0;
507
508private:
509 /**
510 * Private update that allows for use of "StartTime"
511 */
513 {
514 if (StartTime == 0.0)
515 {
517 }
518
519 return Update();
520 }
521
522protected:
523 /** Default constructor*/
525 : StartTime(0.0f)
526 {
527 }
528
529 // Gets current run time for the command for reporting purposes.
530 double GetCurrentRunTime() const
531 {
532 if (StartTime == 0.0)
533 {
534 return 0.0;
535 }
536
538 }
539
540 /** For timers, track the first time this ticks */
541 double StartTime;
542
544};
545
546/**
547 * A simple latent command that runs the provided function on another thread
548 */
550{
551public:
552
554
555 virtual bool Update() override
556 {
557 if (!Future.IsValid())
558 {
559 Future = Async(EAsyncExecution::Thread, MoveTemp(Function));
560 }
561
562 return Future.IsReady();
563 }
564
565 FThreadedAutomationLatentCommand(TUniqueFunction<void()> InFunction)
567 { }
568
569protected:
570
571 TUniqueFunction<void()> Function;
572
574
576};
577
578
579/**
580 * Simple abstract base class for networked, multi-participant tests
581 */
583{
584public:
585 /* virtual destructor */
587
588 /**
589 * Identifier to distinguish which worker on the network should execute this command
590 *
591 * The index of the worker that should execute this command
592 */
593 virtual uint32 GetRoleIndex() const = 0;
594
595 /** Runs the network command */
596 virtual void Run() = 0;
597};
598
600{
601 // Original regular expression pattern string matching expected log message.
602 // NOTE: using the Exact comparison type wraps the pattern string with ^ and $ tokens,
603 // but the base pattern string is preserved to allow checks for duplicate entries.
605 // Regular expression pattern for MessagePatternString
607 // Type of comparison to perform on error log using MessagePattern.
609 /**
610 * Number of occurrences expected for message. If set greater than 0, it will cause the test to fail if the
611 * exact number of occurrences expected is not matched. If set to 0, it will suppress all matching messages.
612 */
615 // Log message Verbosity
617
618 /**
619 * Constructor
620 */
621 FAutomationExpectedMessage(FString& InMessagePattern, ELogVerbosity::Type InVerbosity, EAutomationExpectedMessageFlags::MatchType InCompareType, int32 InExpectedNumberOfOccurrences = 1)
624 , CompareType(InCompareType)
625 , ExpectedNumberOfOccurrences(InExpectedNumberOfOccurrences)
627 , Verbosity(InVerbosity)
628 {}
629
630 FAutomationExpectedMessage(FString& InMessagePattern, ELogVerbosity::Type InVerbosity, int32 InExpectedNumberOfOccurrences)
634 , ExpectedNumberOfOccurrences(InExpectedNumberOfOccurrences)
636 , Verbosity(InVerbosity)
637 {}
638};
639
641{
646
649
650 int32 Width;
651 int32 Height;
652
653 // RHI Details
658
659 // Hardware Details
665
666 // Quality Levels
678
679 // Comparison Requests
691
692 // Name of the screenshot generated from AutomationCommon::GetScreenShotName()
694
696 : Id()
697 , Commit()
698 , Width(0)
699 , Height(0)
700 , bIsStereo(false)
701 , ResolutionQuality(1.0f)
704 , ShadowQuality(0)
708 , TextureQuality(0)
709 , EffectsQuality(0)
710 , FoliageQuality(0)
711 , ShadingQuality(0)
712 , bHasComparisonRules(false)
713 , ToleranceRed(0)
714 , ToleranceGreen(0)
715 , ToleranceBlue(0)
716 , ToleranceAlpha(0)
719 , MaximumLocalError(0.0f)
720 , MaximumGlobalError(0.0f)
721 , bIgnoreAntiAliasing(false)
722 , bIgnoreColors(false)
723 {
724 }
725};
726
728{
731 double MaxLocalDifference = 0.0;
732 double GlobalDifference = 0.0;
733 bool bWasNew = false;
734 bool bWasSimilar = false;
735
736 FAutomationEvent ToAutomationEvent(const FString& ScreenhotName) const;
737};
738
740{
741 Zero,
742 Low,
743 Medium,
744 High
745};
746
748{
749public:
750
752 : Red(0)
753 , Green(0)
754 , Blue(0)
755 , Alpha(0)
756 , MinBrightness(0)
757 , MaxBrightness(255)
758 {
759 }
760
761 FAutomationComparisonToleranceAmount(uint8 R, uint8 G, uint8 B, uint8 A, uint8 InMinBrightness, uint8 InMaxBrightness)
762 : Red(R)
763 , Green(G)
764 , Blue(B)
765 , Alpha(A)
766 , MinBrightness(InMinBrightness)
767 , MaxBrightness(InMaxBrightness)
768 {
769 }
770
772 {
773 switch (InTolerance)
774 {
776 return FAutomationComparisonToleranceAmount(16, 16, 16, 16, 16, 240);
778 return FAutomationComparisonToleranceAmount(24, 24, 24, 24, 24, 220);
780 return FAutomationComparisonToleranceAmount(32, 32, 32, 32, 64, 96);
781 }
782 // Zero
784 }
785
786 uint8 Red;
787 uint8 Green;
788 uint8 Blue;
789 uint8 Alpha;
792};
793
794/**
795 * Delegate type for when a test screenshot has been captured
796 *
797 * The first parameter is the array of the raw color data.
798 * The second parameter is the image metadata.
799 */
800DECLARE_DELEGATE_TwoParams(FOnTestScreenshotCaptured, const TArray<FColor>&, const FAutomationScreenshotData&);
801
802DECLARE_DELEGATE_ThreeParams(FOnTestScreenshotAndTraceCaptured, const TArray<FColor>&, const TArray<uint8>&, const FAutomationScreenshotData&);
803
804DECLARE_MULTICAST_DELEGATE_OneParam(FOnTestScreenshotComparisonComplete, const FAutomationScreenshotCompareResults& /*CompareResults*/);
805
806DECLARE_MULTICAST_DELEGATE_TwoParams(FOnTestDataRetrieved, bool /*bWasNew*/, const FString& /*JsonData*/);
807
808DECLARE_MULTICAST_DELEGATE_TwoParams(FOnPerformanceDataRetrieved, bool /*bSuccess*/, const FString& /*ErrorMessage*/);
809
810DECLARE_MULTICAST_DELEGATE_OneParam(FOnTestEvent, FAutomationTestBase*);
811
812/** Class representing the main framework for running automation tests */
814{
815public:
816 /** Called right before automated test is about to begin */
817 FSimpleMulticastDelegate PreTestingEvent;
818
819 /** Called after all automated tests have completed */
820 FSimpleMulticastDelegate PostTestingEvent;
821
822 /** Called when each automated test is starting */
823 FOnTestEvent OnTestStartEvent;
824
825 /** Called when each automated test is ending */
826 FOnTestEvent OnTestEndEvent;
827
828 /** Called when a screenshot comparison completes. */
829 FOnTestScreenshotComparisonComplete OnScreenshotCompared;
830
831 /** Called when the test data is retrieved. */
832 FOnTestDataRetrieved OnTestDataRetrieved;
833
834 /** Called when the performance data is retrieved. */
835 FOnPerformanceDataRetrieved OnPerformanceDataRetrieved;
836
837 /** The final call related to screenshots, after they've been taken, and after they've been compared (or not if automation isn't running). */
838 FSimpleMulticastDelegate OnScreenshotTakenAndCompared;
839
840 /**
841 * Return the singleton instance of the framework.
842 *
843 * @return The singleton instance of the framework.
844 */
847
848 /**
849 * Gets a scratch space location outside of the project and saved directories. When an automation test needs
850 * to do something like generate project files, or create new projects it should use this directory, rather
851 * than pollute other areas of the machine.
852 */
854
855 /**
856 * Register a automation test into the framework. The automation test may or may not be necessarily valid
857 * for the particular application configuration, but that will be determined when tests are attempted
858 * to be run.
859 *
860 * @param InTestNameToRegister Name of the test being registered
861 * @param InTestToRegister Actual test to register
862 *
863 * @return true if the test was successfully registered; false if a test was already registered under the same
864 * name as before
865 */
866 bool RegisterAutomationTest( const FString& InTestNameToRegister, FAutomationTestBase* InTestToRegister );
867
868 /**
869 * Unregister a automation test with the provided name from the framework.
870 *
871 * @return true if the test was successfully unregistered; false if a test with that name was not found in the framework.
872 */
873 bool UnregisterAutomationTest( const FString& InTestNameToUnregister );
874
875 /**
876 * Enqueues a latent command for execution on a subsequent frame
877 *
878 * @param NewCommand - The new command to enqueue for deferred execution
879 */
880 void EnqueueLatentCommand(TSharedPtr<IAutomationLatentCommand> NewCommand);
881
882 /**
883 * Enqueues a network command for execution in accordance with this workers role
884 *
885 * @param NewCommand - The new command to enqueue for network execution
886 */
887 void EnqueueNetworkCommand(TSharedPtr<IAutomationNetworkCommand> NewCommand);
888
889 /**
890 * Checks if a provided test is contained within the framework.
891 *
892 * @param InTestName Name of the test to check
893 *
894 * @return true if the provided test is within the framework; false otherwise
895 */
896 bool ContainsTest( const FString& InTestName ) const;
897
898 /**
899 * Attempt to run all fast smoke tests that are valid for the current application configuration.
900 *
901 * @return true if all smoke tests run were successful, false if any failed
902 */
904
905 /**
906 * Reset status of worker (delete local files, etc)
907 */
909
910 /**
911 * Attempt to start the specified test.
912 *
913 * @param InTestToRun Name of the test that should be run
914 * @param InRoleIndex Identifier for which worker in this group that should execute a command
915 */
916 void StartTestByName( const FString& InTestToRun, const int32 InRoleIndex );
917
918 /**
919 * Stop the current test and return the results of execution
920 *
921 * @return true if the test ran successfully, false if it did not (or the test could not be found/was invalid)
922 */
923 bool StopTest( FAutomationTestExecutionInfo& OutExecutionInfo );
924
925 /**
926 * Execute all latent functions that complete during update
927 *
928 * @return - true if the latent command queue is now empty and the test is complete
929 */
931
932 /**
933 * Execute the next network command if you match the role, otherwise just dequeue
934 *
935 * @return - true if any network commands were in the queue to give subsequent latent commands a chance to execute next frame
936 */
938
939 /**
940 * Dequeue all latent and network commands
941 */
943
944 /**
945 * Whether there is no latent command in queue
946 */
948 {
949 return LatentCommands.IsEmpty();
950 }
951
952 /**
953 * Load any modules that are not loaded by default and have test classes in them
954 */
956
957 /**
958 * Populates the provided array with the names of all tests in the framework that are valid to run for the current
959 * application settings.
960 *
961 * @param TestInfo Array to populate with the test information
962 */
963 void GetValidTestNames( TArray<FAutomationTestInfo>& TestInfo ) const;
964
965 /**
966 * Whether the testing framework should allow content to be tested or not. Intended to block developer directories.
967 * @param Path - Full path to the content in question
968 * @return - Whether this content should have tests performed on it
969 */
970 bool ShouldTestContent(const FString& Path) const;
971
972 /**
973 * Sets whether we want to include content in developer directories in automation testing
974 */
975 void SetDeveloperDirectoryIncluded(const bool bInDeveloperDirectoryIncluded);
976
977 /**
978 * Sets which set of tests to pull from.
979 */
980 void SetRequestedTestFilter(const uint32 InRequestedTestFlags);
981
982
983 /**
984 * Accessor for delegate called when a png screenshot is captured
985 */
986 FOnTestScreenshotCaptured& OnScreenshotCaptured();
987
988 /**
989 * Accessor for delegate called when a png screenshot is captured and a frame trace
990 */
991 FOnTestScreenshotAndTraceCaptured& OnScreenshotAndTraceCaptured();
992
993 /**
994 * Sets forcing smoke tests.
995 */
996 void SetForceSmokeTests(const bool bInForceSmokeTests)
997 {
998 bForceSmokeTests = bInForceSmokeTests;
999 }
1000
1001 bool GetCaptureStack() const
1002 {
1003 return bCaptureStack;
1004 }
1005
1006 void SetCaptureStack(bool bCapture)
1007 {
1008 bCaptureStack = bCapture;
1009 }
1010
1011 /**
1012 * Adds a analytics string to the current test to be parsed later. Must be called only when an automation test is in progress
1013 *
1014 * @param AnalyticsItem Log item to add to the current test
1015 */
1016 void AddAnalyticsItemToCurrentTest( const FString& AnalyticsItem );
1017
1018 /**
1019 * Returns the actively executing test or null if there isn't one
1020 */
1022 {
1023 return CurrentTest;
1024 }
1025
1027 void NotifyTestDataRetrieved(bool bWasNew, const FString& JsonData);
1028 void NotifyPerformanceDataRetrieved(bool bSuccess, const FString& ErrorMessage);
1029
1031
1032private:
1033
1034 /** Special output device used during automation testing to gather messages that happen during tests */
1036 {
1037 public:
1039 : CurTest( nullptr ) {}
1040
1042 {
1043 CurTest = nullptr;
1044 }
1045
1046 /**
1047 * FOutputDevice interface
1048 *
1049 * @param V String to serialize within the output device
1050 * @param Event Event associated with the string
1051 */
1052 virtual void Serialize( const TCHAR* V, ELogVerbosity::Type Verbosity, const class FName& Category ) override;
1053
1054 /**
1055 * FOutputDevice interface
1056 *
1057 * Make it unbuffered by returning true
1058 */
1059 virtual bool CanBeUsedOnMultipleThreads() const override
1060 {
1061 return true;
1062 }
1063
1064 /**
1065 * Set the automation test associated with the output device. The automation test is where all warnings, errors, etc.
1066 * will be routed to.
1067 *
1068 * @param InAutomationTest Automation test to associate with the output device.
1069 */
1071 {
1072 CurTest = InAutomationTest;
1073 }
1074
1075 private:
1076 /** Associated automation test; all warnings, errors, etc. are routed to the automation test to track */
1078
1079 /** Critical section */
1081
1082 /** Tests that we've logged the failure cause when an error is involved */
1084 };
1085
1086 /** Special feedback context used during automated testing to filter messages that happen during tests */
1088 {
1089 public:
1091 : CurTest(nullptr)
1092 , DestinationContext(nullptr) {}
1093
1095 {
1096 DestinationContext = nullptr;
1097 CurTest = nullptr;
1098 }
1099
1100 /**
1101 * FOutputDevice interface
1102 *
1103 * @param V String to serialize within the context
1104 * @param Event Event associated with the string
1105 */
1106 virtual void Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category) override;
1107 virtual void Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category, double Time) override;
1108
1109 virtual void SerializeRecord(const UE::FLogRecord& Record) override;
1110
1111 /**
1112 * FOutputDevice interface
1113 *
1114 * Make it unbuffered by returning true
1115 */
1116 virtual bool CanBeUsedOnMultipleThreads() const override
1117 {
1118 return true;
1119 }
1120
1121 /**
1122 * Set the automation test associated with the feedback context. The automation test is what will be used
1123 * to determine if a given warning or error is expected and thus should not be treated as a warning or error
1124 * by the destination context.
1125 *
1126 * @param InAutomationTest Automation test to associate with the feedback context.
1127 */
1129 {
1130 CurTest = InAutomationTest;
1131 }
1132
1133 /**
1134 * Set the destination associated with the feedback context. The automation test is where all warnings, errors, etc.
1135 * will be routed to.
1136 *
1137 * @param InAutomationTest Automation test to associate with the feedback context.
1138 */
1139 void SetDestinationContext(FFeedbackContext* InDestinationContext)
1140 {
1141 DestinationContext = InDestinationContext;
1142 }
1143
1144 private:
1148 };
1149
1151 /** Helper method called to prepare settings for automation testing to follow */
1153
1154 /** Helper method called after automation testing is complete to restore settings to how they should be */
1156
1157 /**
1158 * Helper method to dump the contents of the provided test name to execution info map to the provided feedback context
1159 *
1160 * @param InContext Context to dump the execution info to
1161 * @param InInfoToDump Execution info that should be dumped to the provided feedback context
1162 */
1163 void DumpAutomationTestExecutionInfo( const TMap<FString, FAutomationTestExecutionInfo>& InInfoToDump );
1164
1165 /**
1166 * Internal helper method designed to simply start the provided test name.
1167 *
1168 * @param InTestToRun Name of the test that should be run
1169 * @param OutExecutionInfo Results of executing the test
1170 */
1171 void InternalStartTest( const FString& InTestToRun );
1172
1173 /**
1174 * Internal helper method designed to stop current executing test and return the results of execution.
1175 *
1176 * @return true if the test was successfully run; false if it was not, could not be found, or is invalid for
1177 * the current application settings
1178 */
1180
1181 /** Constructor */
1183
1184 /** Destructor */
1186
1187 // Copy constructor and assignment operator intentionally left unimplemented
1190
1191 /** Specialized output device used for automation testing */
1193
1194 /** Specialized feedback context used for message filtering during automated testing */
1196
1198
1199 /** Mapping of automation test names to their respective object instances */
1201
1202 /** Queue of deferred commands */
1204
1205 /** Queue of deferred commands */
1207
1208 /** Whether we are currently executing smoke tests for startup/commandlet to minimize log spam */
1210
1211 /** Time when the test began executing */
1213
1214 /** True if the execution of the test (but possibly not the latent actions) were successful */
1216
1217 /** Pointer to the current test being run */
1219
1220 /** Copy of the parameters for the active test */
1222
1223 /** Whether we want to run automation tests on content within the Developer Directories */
1225
1226 /** Participation role as given by the automation controller */
1228
1229 /** Delegate called at the end of the frame when a screenshot is captured and a .png is requested */
1230 FOnTestScreenshotCaptured TestScreenshotCapturedDelegate;
1231
1232 /** Delegate called at the end of the frame when a screenshot and frame trace is captured and a .png is requested */
1233 FOnTestScreenshotAndTraceCaptured TestScreenshotAndTraceCapturedDelegate;
1234
1235 /** Forces running smoke tests */
1237
1239};
1240
1241
1242/** Simple abstract base class for all automation tests */
1244{
1245public:
1246 /**
1247 * Constructor
1248 *
1249 * @param InName Name of the test
1250 */
1251 FAutomationTestBase( const FString& InName, const bool bInComplexTask )
1252 : bComplexTask( bInComplexTask )
1253 {
1254 LLM_SCOPE_BYNAME(TEXT("AutomationTest/Framework"));
1255 TestName = InName;
1256 // Register the newly created automation test into the automation testing framework
1258 }
1259
1260 /** Destructor */
1262 {
1263 // Unregister the automation test from the automation testing framework
1264 FAutomationTestFramework::Get().UnregisterAutomationTest( TestName );
1265 }
1266
1267 /**
1268 * Pure virtual method; returns the flags associated with the given automation test
1269 *
1270 * @return Automation test flags associated with the test
1271 */
1272 virtual uint32 GetTestFlags() const = 0;
1273
1274 /** Gets the C++ name of the test. */
1275 FString GetTestName() const { return TestName; }
1276
1277 /** Gets the parameter context of the test. */
1278 FString GetTestContext() const { return TestParameterContext; }
1279
1280 /**
1281 * Returns the beautified test name with test context. Should return what is displayed in the Test Automation UI. See GenerateTestNames()
1282 */
1283 virtual FString GetTestFullName() const {
1285 return FString::Printf(TEXT("%s.%s"), *GetBeautifiedTestName(), *GetTestContext());
1286 }
1287
1288 /**
1289 * Pure virtual method; returns the number of participants for this test
1290 *
1291 * @return Number of required participants
1292 */
1293 virtual uint32 GetRequiredDeviceNum() const = 0;
1294
1295 /** Clear any execution info/results from a prior running of this test */
1297
1298 /**
1299 * Adds an error message to this test
1300 *
1301 * @param InError Error message to add to this test
1302 */
1303 virtual void AddError( const FString& InError, int32 StackOffset = 0 );
1304
1305 /**
1306 * Adds an error message to this test if the condition is false
1307 *
1308 * @param bCondition The condition to validate.
1309 * @param InError Error message to add to this test
1310 */
1311 virtual void AddErrorIfFalse( bool bCondition, const FString& InError, int32 StackOffset = 0 );
1312
1313 /**
1314 * Adds an error message to this test
1315 *
1316 * @param InError Error message to add to this test
1317 * @param InFilename The filename the error originated in
1318 * @param InLineNumber The line number in the file this error originated in
1319 */
1320 virtual void AddErrorS(const FString& InError, const FString& InFilename, int32 InLineNumber);
1321
1322 /**
1323 * Adds an warning message to this test
1324 *
1325 * @param InWarning Warning message to add to this test
1326 * @param InFilename The filename the error originated in
1327 * @param InLineNumber The line number in the file this error originated in
1328 */
1329 virtual void AddWarningS(const FString& InWarning, const FString& InFilename, int32 InLineNumber);
1330
1331 /**
1332 * Adds a warning to this test
1333 *
1334 * @param InWarning Warning message to add to this test
1335 */
1336 virtual void AddWarning( const FString& InWarning, int32 StackOffset = 0);
1337
1338 /**
1339 * Adds a log item to this test
1340 *
1341 * @param InLogItem Log item to add to this test
1342 */
1343 virtual void AddInfo( const FString& InLogItem, int32 StackOffset = 0, bool bCaptureStack = false);
1344
1345 /**
1346 * Adds an automation event directly into the execution log.
1347 *
1348 * @param InLogItem Log item to add to this test
1349 */
1350 virtual void AddEvent(const FAutomationEvent& InEvent, int32 StackOffset = 0, bool bCaptureStack = false);
1351
1352 /**
1353 * Adds a analytics string to parse later
1354 *
1355 * @param InLogItem Log item to add to this test
1356 */
1357 virtual void AddAnalyticsItem(const FString& InAnalyticsItem);
1358
1359 /**
1360 * Adds a telemetry data point measurement
1361 *
1362 * @param DataPoint Name of the Data point
1363 * @param Measurement Value to associate to the data point
1364 * @param Context optional context associated with the data point
1365 */
1366 virtual void AddTelemetryData(const FString& DataPoint, double Measurement, const FString& Context = TEXT(""));
1367
1368 /**
1369 * Adds several telemetry data point measurements
1370 *
1371 * @param ValuePairs value pair of Name and Measurement of several Data points
1372 * @param Context optional context associated with the data point
1373 */
1374 virtual void AddTelemetryData(const TMap<FString, double>& ValuePairs, const FString& Context = TEXT(""));
1375
1376 /**
1377 * Set telemetry storage name
1378 *
1379 * @param StorageName Name of the data storage
1380 */
1381 virtual void SetTelemetryStorage(const FString& StorageName);
1382
1383 /**
1384 * Returns whether this test has any errors associated with it or not
1385 *
1386 * @return true if this test has at least one error associated with it; false if not
1387 */
1388 bool HasAnyErrors() const;
1389
1390 /**
1391 * Returns whether this test has encountered all expected log messages defined for it
1392 * @param VerbosityType Optionally specify to check by log level. Defaults to all.
1393 * @return true if this test has encountered all expected messages; false if not
1394 */
1396
1397 /**
1398 * Returns whether this test has encountered all expected errors defined for it
1399 *
1400 * @return true if this test has encountered all expected errors; false if not
1401 */
1403
1404 /**
1405 * Return the last success state for this test
1406 */
1408
1409 /**
1410 * [Deprecated] Use AddError(msg) instead to change the state of the test to a failure
1411 */
1412 UE_DEPRECATED(5.1, "Use AddError(msg) instead to change the state of the test to a failure.")
1413 void SetSuccessState(bool bSuccessful) { }
1414
1415 /**
1416 * [Deprecated] Return the last success state for this test
1417 */
1418 UE_DEPRECATED(5.1, "Use GetLastExecutionSuccessState instead.")
1420
1421 /**
1422 * Populate the provided execution info object with the execution info contained within the test. Not particularly efficient,
1423 * but providing direct access to the test's private execution info could result in errors.
1424 *
1425 * @param OutInfo Execution info to be populated with the same data contained within this test's execution info
1426 */
1428
1429 /**
1430 * Helper function that will generate a list of sub-tests via GetTests
1431 */
1432 void GenerateTestNames( TArray<FAutomationTestInfo>& TestInfo ) const;
1433
1434 /**
1435 * Helper function that determines if the given log category matches the expected category, inclusively (so an Error counts as a Warning)
1436 */
1438
1439 /**
1440 * Adds a regex pattern to an internal list that this test will expect to encounter in logs (of the specified verbosity) during its execution. If an expected pattern
1441 * is not encountered, it will cause this test to fail.
1442 *
1443 * @param ExpectedPatternString - The expected message string. Supports basic regex patterns.
1444 * @param ExpectedVerbosity - The expected message verbosity. This is treated as a minimum requirement, so for example the Warning level will intercept Warnings, Errors and Fatal.
1445 * @param CompareType - How to match this string with an encountered message, should it match exactly or simply just contain the string.
1446 * @param Occurrences - How many times to expect this message string to be seen. If > 0, the message must be seen the exact number of times
1447 * specified or the test will fail. If == 0, the message must be seen one or more times (with no upper limit) or the test will fail.
1448 */
1449 void AddExpectedMessage(FString ExpectedPatternString, ELogVerbosity::Type ExpectedVerbosity, EAutomationExpectedMessageFlags::MatchType CompareType = EAutomationExpectedMessageFlags::Contains, int32 Occurrences = 1);
1450
1451 /**
1452 * Adds a regex pattern to an internal list that this test will expect to encounter in logs (of all severities) during its execution. If an expected pattern
1453 * is not encountered, it will cause this test to fail.
1454 *
1455 * @param ExpectedPatternString - The expected message string. Supports basic regex patterns.
1456 * @param CompareType - How to match this string with an encountered message, should it match exactly or simply just contain the string.
1457 * @param Occurrences - How many times to expect this message string to be seen. If > 0, the message must be seen the exact number of times
1458 * specified or the test will fail. If == 0, the message must be seen one or more times (with no upper limit) or the test will fail.
1459 */
1461
1462 /**
1463 * Populate the provided expected log messages object with the expected messages contained within the test. Not particularly efficient,
1464 * but providing direct access to the test's private execution messages list could result in errors.
1465 * @param Verbosity - Optionally filter the returned messages by verbosity. This is inclusive, so Warning will return Warnings, Errors, etc.
1466 * @param OutInfo - Array of Expected Messages to be populated with the same data contained within this test's expected messages list
1467 */
1468 void GetExpectedMessages(TArray<FAutomationExpectedMessage>& OutInfo, ELogVerbosity::Type Verbosity = ELogVerbosity::All) const;
1469
1470 /**
1471 * Adds a regex pattern to an internal list that this test will expect to encounter in error or warning logs during its execution. If an expected pattern
1472 * is not encountered, it will cause this test to fail.
1473 *
1474 * @param ExpectedPatternString - The expected message string. Supports basic regex patterns.
1475 * @param CompareType - How to match this string with an encountered error, should it match exactly or simply just contain the string.
1476 * @param Occurrences - How many times to expect this error string to be seen. If > 0, the error must be seen the exact number of times
1477 * specified or the test will fail. If == 0, the error must be seen one or more times (with no upper limit) or the test will fail.
1478 */
1479 void AddExpectedError(FString ExpectedPatternString, EAutomationExpectedErrorFlags::MatchType CompareType = EAutomationExpectedErrorFlags::Contains, int32 Occurrences = 1);
1480
1481 /**
1482 * Is this a complex tast - if so it will be a stress test.
1483 *
1484 * @return true if this is a complex task.
1485 */
1486 const bool IsComplexTask() const
1487 {
1488 return bComplexTask;
1489 }
1490
1491 const bool IsRanOnSeparateThread() const
1492 {
1493 return bRunOnSeparateThread;
1494 }
1495
1496 /**
1497 * If true no logging will be included in test events
1498 *
1499 * @return true to suppress logs
1500 */
1501 virtual bool SuppressLogs()
1502 {
1503 return bSuppressLogs;
1504 }
1505
1506 /**
1507 * If returns true then logging with a level of Error will not be recorded in test results
1508 *
1509 * @return false to make errors errors
1510 */
1511 virtual bool SuppressLogErrors() { return false; }
1512
1513 /**
1514 * If returns true then logging with a level of Warning will not be recorded in test results
1515 *
1516 * @return true to make warnings errors
1517 */
1518 virtual bool SuppressLogWarnings() { return false; }
1519
1520 /**
1521 * If returns true then logging with a level of Warning will be treated as an error
1522 *
1523 * @return true to make warnings errors
1524 */
1525 virtual bool ElevateLogWarningsToErrors() { return false; }
1526
1527 /**
1528 * Enqueues a new latent command.
1529 */
1531 {
1532 TSharedRef<IAutomationLatentCommand> CommandPtr = MakeShareable(NewCommand);
1533 FAutomationTestFramework::Get().EnqueueLatentCommand(CommandPtr);
1534 }
1535
1536 /**
1537 * Enqueues a new latent network command.
1538 */
1540 {
1541 TSharedRef<IAutomationNetworkCommand> CommandPtr = MakeShareable(NewCommand);
1542 FAutomationTestFramework::Get().EnqueueNetworkCommand(CommandPtr);
1543 }
1544
1545 /** Gets the filename where this test was defined. */
1546 virtual FString GetTestSourceFileName() const { return TEXT(""); }
1547
1548 /** Gets the line number where this test was defined. */
1549 virtual int32 GetTestSourceFileLine() const { return 0; }
1550
1551 /** Gets the filename where this test was defined. */
1552 virtual FString GetTestSourceFileName(const FString& InTestName) const { return GetTestSourceFileName(); }
1553
1554 /** Gets the line number where this test was defined. */
1555 virtual int32 GetTestSourceFileLine(const FString& InTestName) const { return GetTestSourceFileLine(); }
1556
1557 /** Allows navigation to the asset associated with the test if there is one. */
1558 virtual FString GetTestAssetPath(const FString& Parameter) const { return TEXT(""); }
1559
1560 /** Return an exec command to open the test associated with this parameter. */
1561 virtual FString GetTestOpenCommand(const FString& Parameter) const { return TEXT(""); }
1562
1563 void PushContext(const FString& Context)
1564 {
1565 ExecutionInfo.PushContext(Context);
1566 }
1567
1569 {
1570 ExecutionInfo.PopContext();
1571 }
1572
1573public:
1574
1575 bool TestEqual(const TCHAR* What, const int32 Actual, const int32 Expected);
1576 bool TestEqual(const TCHAR* What, const int64 Actual, const int64 Expected);
1578 bool TestEqual(const TCHAR* What, const SIZE_T Actual, const SIZE_T Expected);
1579#endif
1580 bool TestEqual(const TCHAR* What, const float Actual, const float Expected, float Tolerance = UE_KINDA_SMALL_NUMBER);
1581 bool TestEqual(const TCHAR* What, const double Actual, const double Expected, double Tolerance = UE_KINDA_SMALL_NUMBER);
1582 bool TestEqual(const TCHAR* What, const FVector Actual, const FVector Expected, float Tolerance = UE_KINDA_SMALL_NUMBER);
1583 bool TestEqual(const TCHAR* What, const FTransform Actual, const FTransform Expected, float Tolerance = UE_KINDA_SMALL_NUMBER);
1584 bool TestEqual(const TCHAR* What, const FRotator Actual, const FRotator Expected, float Tolerance = UE_KINDA_SMALL_NUMBER);
1585 bool TestEqual(const TCHAR* What, const FColor Actual, const FColor Expected);
1586 bool TestEqual(const TCHAR* What, const FLinearColor Actual, const FLinearColor Expected);
1587 bool TestEqual(const TCHAR* What, const TCHAR* Actual, const TCHAR* Expected);
1588 bool TestEqualInsensitive(const TCHAR* What, const TCHAR* Actual, const TCHAR* Expected);
1589
1590 bool TestEqual(const FString& What, const int32 Actual, const int32 Expected)
1591 {
1592 return TestEqual(*What, Actual, Expected);
1593 }
1594
1595 bool TestEqual(const FString& What, const float Actual, const float Expected, float Tolerance = UE_KINDA_SMALL_NUMBER)
1596 {
1597 return TestEqual(*What, Actual, Expected, Tolerance);
1598 }
1599
1600 bool TestEqual(const FString& What, const double Actual, const double Expected, double Tolerance = UE_KINDA_SMALL_NUMBER)
1601 {
1602 return TestEqual(*What, Actual, Expected, Tolerance);
1603 }
1604
1605 bool TestEqual(const FString& What, const FVector Actual, const FVector Expected, float Tolerance = UE_KINDA_SMALL_NUMBER)
1606 {
1607 return TestEqual(*What, Actual, Expected, Tolerance);
1608 }
1609
1610 bool TestEqual(const FString& What, const FRotator Actual, const FRotator Expected, float Tolerance = UE_KINDA_SMALL_NUMBER)
1611 {
1612 return TestEqual(*What, Actual, Expected, Tolerance);
1613 }
1614
1615 bool TestEqual(const FString& What, const FColor Actual, const FColor Expected)
1616 {
1617 return TestEqual(*What, Actual, Expected);
1618 }
1619
1620 bool TestEqual(const FString& What, const TCHAR* Actual, const TCHAR* Expected)
1621 {
1622 return TestEqual(*What, Actual, Expected);
1623 }
1624
1625 bool TestEqual(const TCHAR* What, const FString& Actual, const TCHAR* Expected)
1626 {
1627 return TestEqualInsensitive(What, *Actual, Expected);
1628 }
1629
1630 bool TestEqual(const FString& What, const FString& Actual, const TCHAR* Expected)
1631 {
1632 return TestEqualInsensitive(*What, *Actual, Expected);
1633 }
1634
1635 bool TestEqual(const TCHAR* What, const TCHAR* Actual, const FString& Expected)
1636 {
1637 return TestEqualInsensitive(What, Actual, *Expected);
1638 }
1639
1640 bool TestEqual(const FString& What, const TCHAR* Actual, const FString& Expected)
1641 {
1642 return TestEqualInsensitive(*What, Actual, *Expected);
1643 }
1644
1645 bool TestEqual(const TCHAR* What, const FString& Actual, const FString& Expected)
1646 {
1647 return TestEqualInsensitive(What, *Actual, *Expected);
1648 }
1649
1650 bool TestEqual(const FString& What, const FString& Actual, const FString& Expected)
1651 {
1652 return TestEqualInsensitive(*What, *Actual, *Expected);
1653 }
1654
1655 /**
1656 * Logs an error if the two values are not equal.
1657 *
1658 * @param What - Description text for the test.
1659 * @param A - The first value.
1660 * @param B - The second value.
1661 *
1662 * @see TestNotEqual
1663 */
1664 template<typename ValueType>
1665 bool TestEqual(const TCHAR* What, const ValueType& Actual, const ValueType& Expected)
1666 {
1667 if (Actual != Expected)
1668 {
1669 AddError(FString::Printf(TEXT("%s: The two values are not equal."), What), 1);
1670 return false;
1671 }
1672 return true;
1673 }
1674
1675 template<typename ValueType>
1676 bool TestEqual(const FString& What, const ValueType& Actual, const ValueType& Expected)
1677 {
1678 return TestEqual(*What, Actual, Expected);
1679 }
1680
1681
1682 /**
1683 * Logs an error if the specified Boolean value is not false.
1684 *
1685 * @param What - Description text for the test.
1686 * @param Value - The value to test.
1687 *
1688 * @see TestFalse
1689 */
1690 bool TestFalse(const TCHAR* What, bool Value);
1691
1692 bool TestFalse(const FString& What, bool Value)
1693 {
1694 return TestFalse(*What, Value);
1695 }
1696
1697 /**
1698 * Logs an error if the given shared pointer is valid.
1699 *
1700 * @param Description - Description text for the test.
1701 * @param SharedPointer - The shared pointer to test.
1702 *
1703 * @see TestValid
1704 */
1705 template<typename ValueType> bool TestInvalid(const TCHAR* Description, const TSharedPtr<ValueType>& SharedPointer)
1706 {
1707 if (SharedPointer.IsValid())
1708 {
1709 AddError(FString::Printf(TEXT("%s: The shared pointer is valid."), Description), 1);
1710 return false;
1711 }
1712 return true;
1713 }
1714
1715 template<typename ValueType> bool TestInvalid(const FString& Description, const TSharedPtr<ValueType>& SharedPointer)
1716 {
1718 }
1719
1720 /**
1721 * Logs an error if the two values are equal.
1722 *
1723 * @param Description - Description text for the test.
1724 * @param A - The first value.
1725 * @param B - The second value.
1726 *
1727 * @see TestEqual
1728 */
1729 template<typename ValueType> bool TestNotEqual(const TCHAR* Description, const ValueType& Actual, const ValueType& Expected)
1730 {
1731 if (Actual == Expected)
1732 {
1733 AddError(FString::Printf(TEXT("%s: The two values are equal."), Description), 1);
1734 return false;
1735 }
1736 return true;
1737 }
1738
1739 template<typename ValueType> bool TestNotEqual(const FString& Description, const ValueType& Actual, const ValueType& Expected)
1740 {
1742 }
1743
1744 /**
1745 * Logs an error if the specified pointer is NULL.
1746 *
1747 * @param What - Description text for the test.
1748 * @param Pointer - The pointer to test.
1749 *
1750 * @see TestNull
1751 */
1752 template<typename ValueType> bool TestNotNull(const TCHAR* What, const ValueType* Pointer)
1753 {
1754 if (Pointer == nullptr)
1755 {
1756 AddError(FString::Printf(TEXT("Expected '%s' to be not null."), What), 1);
1757 return false;
1758 }
1759 return true;
1760 }
1761
1762 template<typename ValueType> bool TestNotNull(const FString& What, const ValueType* Pointer)
1763 {
1764 return TestNotNull(*What, Pointer);
1765 }
1766
1767 /**
1768 * Logs an error if the two values are the same object in memory.
1769 *
1770 * @param Description - Description text for the test.
1771 * @param A - The first value.
1772 * @param B - The second value.
1773 *
1774 * @see TestSame
1775 */
1776 template<typename ValueType> bool TestNotSame(const TCHAR* Description, const ValueType& Actual, const ValueType& Expected)
1777 {
1778 if (&Actual == &Expected)
1779 {
1780 AddError(FString::Printf(TEXT("%s: The two values are the same."), Description), 1);
1781 return false;
1782 }
1783 return true;
1784 }
1785
1786 template<typename ValueType> bool TestNotSame(const FString& Description, const ValueType& Actual, const ValueType& Expected)
1787 {
1789 }
1790
1791 /**
1792 * Logs an error if the specified pointer is not NULL.
1793 *
1794 * @param Description - Description text for the test.
1795 * @param Pointer - The pointer to test.
1796 *
1797 * @see TestNotNull
1798 */
1799 bool TestNull(const TCHAR* What, const void* Pointer);
1800
1801 bool TestNull(const FString& What, const void* Pointer)
1802 {
1803 return TestNull(*What, Pointer);
1804 }
1805
1806 /**
1807 * Logs an error if the two values are not the same object in memory.
1808 *
1809 * @param Description - Description text for the test.
1810 * @param Actual - The actual value.
1811 * @param Expected - The expected value.
1812 *
1813 * @see TestNotSame
1814 */
1815 template<typename ValueType> bool TestSame(const TCHAR* Description, const ValueType& Actual, const ValueType& Expected)
1816 {
1817 if (&Actual != &Expected)
1818 {
1819 AddError(FString::Printf(TEXT("%s: The two values are not the same."), Description), 1);
1820 return false;
1821 }
1822 return true;
1823 }
1824
1825 template<typename ValueType> bool TestSame(const FString& Description, const ValueType& Actual, const ValueType& Expected)
1826 {
1828 }
1829
1830 /**
1831 * Logs an error if the specified Boolean value is not true.
1832 *
1833 * @param Description - Description text for the test.
1834 * @param Value - The value to test.
1835 *
1836 * @see TestFalse
1837 */
1838 bool TestTrue(const TCHAR* What, bool Value);
1839
1840 bool TestTrue(const FString& What, bool Value)
1841 {
1842 return TestTrue(*What, Value);
1843 }
1844
1845 /** Macro version of above, uses the passed in expression as the description as well */
1846 #define TestTrueExpr(Expression) TestTrue(TEXT(#Expression), Expression)
1847
1848 /**
1849 * Logs an error if the given shared pointer is not valid.
1850 *
1851 * @param Description - Description text for the test.
1852 * @param SharedPointer - The shared pointer to test.
1853 *
1854 * @see TestInvalid
1855 */
1856 template<typename ValueType> bool TestValid(const TCHAR* Description, const TSharedPtr<ValueType>& SharedPointer)
1857 {
1858 if (!SharedPointer.IsValid())
1859 {
1860 AddError(FString::Printf(TEXT("%s: The shared pointer is not valid."), Description), 1);
1861 return false;
1862 }
1863 return true;
1864 }
1865
1866 template<typename ValueType> bool TestValid(const FString& Description, const TSharedPtr<ValueType>& SharedPointer)
1867 {
1869 }
1870
1871protected:
1872 /**
1873 * Asks the test to enumerate variants that will all go through the "RunTest" function with different parameters (for load all maps, this should enumerate all maps to load)\
1874 *
1875 * @param OutBeautifiedNames - Name of the test that can be displayed by the UI (for load all maps, it would be the map name without any directory prefix)
1876 * @param OutTestCommands - The parameters to be specified to each call to RunTests (for load all maps, it would be the map name to load)
1877 */
1878 virtual void GetTests(TArray<FString>& OutBeautifiedNames, TArray <FString>& OutTestCommands) const = 0;
1879
1880 /**
1881 * Virtual call to execute the automation test.
1882 *
1883 * @param Parameters - Parameter list for the test (but it will be empty for simple tests)
1884 * @return TRUE if the test was run successfully; FALSE otherwise
1885 */
1886 virtual bool RunTest(const FString& Parameters)=0;
1887
1888 /**
1889 * Returns the beautified test name
1890 */
1891 virtual FString GetBeautifiedTestName() const = 0;
1892
1893 /** Sets the parameter context of the test. */
1894 virtual void SetTestContext(FString Context) { TestParameterContext = Context; }
1895
1896 /** Extracts a combined EAutomationTestFlags value from a string representation using tag notation "[Filter_1]...[Filter_n][Tag_1]...[Tag_m]" */
1898
1899protected:
1900
1901 //Flag to indicate if this is a complex task
1903
1904 //Flag to indicate if this test should be ran on it's own thread
1906
1907 /** Flag to suppress logs */
1908 bool bSuppressLogs = false;
1909
1910 /** Name of the test */
1912
1913 /** Context of the test */
1915
1916 /** Info related to the last execution of this test */
1918
1919 //allow framework to call protected function
1921
1922private:
1923 /**
1924 * Returns whether this test has defined any expected log messages matching the given message.
1925 * If a match is found, the expected message definition increments it actual occurrence count.
1926 *
1927 * @return true if this message matches any of the expected messages
1928 */
1929 bool IsExpectedMessage(const FString& Message, const ELogVerbosity::Type& Verbosity = ELogVerbosity::All);
1930
1931 /**
1932 * Sets whether the test has succeeded or not
1933 *
1934 * @param bSuccessful true to mark the test successful, false to mark the test as failed
1935 */
1936 void InternalSetSuccessState(bool bSuccessful);
1937
1938 /* Log messages to be expected while processing this test.*/
1940
1941 /** Critical section lock */
1943};
1944
1946{
1947public:
1948 FBDDAutomationTestBase(const FString& InName, const bool bInComplexTask)
1949 : FAutomationTestBase(InName, bInComplexTask)
1950 , bIsDiscoveryMode(false)
1951 , bBaseRunTestRan(false)
1952 {}
1953
1954 virtual bool RunTest(const FString& Parameters) override
1955 {
1956 bBaseRunTestRan = true;
1957 TestIdToExecute = Parameters;
1958
1959 return true;
1960 }
1961
1962 virtual void GetTests(TArray<FString>& OutBeautifiedNames, TArray <FString>& OutTestCommands) const override
1963 {
1964 const_cast<FBDDAutomationTestBase*>(this)->BeautifiedNames.Empty();
1965 const_cast<FBDDAutomationTestBase*>(this)->TestCommands.Empty();
1966
1967 bIsDiscoveryMode = true;
1969 bIsDiscoveryMode = false;
1970
1971 OutBeautifiedNames.Append(BeautifiedNames);
1972 OutTestCommands.Append(TestCommands);
1973 bBaseRunTestRan = false;
1974 }
1975
1976 bool IsDiscoveryMode() const
1977 {
1978 return bIsDiscoveryMode;
1979 }
1980
1981 void xDescribe(const FString& InDescription, TFunction<void()> DoWork)
1982 {
1983 check(bBaseRunTestRan);
1984 //disabled this suite
1985 }
1986
1987 void Describe(const FString& InDescription, TFunction<void()> DoWork)
1988 {
1989 check(bBaseRunTestRan);
1990
1991 PushDescription(InDescription);
1992
1993 int32 OriginalBeforeEachCount = BeforeEachStack.Num();
1994 int32 OriginalAfterEachCount = AfterEachStack.Num();
1995
1996 DoWork();
1997
1998 check(OriginalBeforeEachCount <= BeforeEachStack.Num());
1999 if (OriginalBeforeEachCount != BeforeEachStack.Num())
2000 {
2001 BeforeEachStack.Pop();
2002 }
2003
2004 check(OriginalAfterEachCount <= AfterEachStack.Num());
2005 if (OriginalAfterEachCount != AfterEachStack.Num())
2006 {
2007 AfterEachStack.Pop();
2008 }
2009
2010 PopDescription(InDescription);
2011 }
2012
2013 void xIt(const FString& InDescription, TFunction<void()> DoWork)
2014 {
2015 check(bBaseRunTestRan);
2016 //disabled this spec
2017 }
2018
2019 void It(const FString& InDescription, TFunction<void()> DoWork)
2020 {
2021 check(bBaseRunTestRan);
2022
2023 PushDescription(InDescription);
2024
2025 if (bIsDiscoveryMode)
2026 {
2027 BeautifiedNames.Add(GetDescription());
2028
2029 bIsDiscoveryMode = false;
2030 TestCommands.Add(GetDescription());
2031 bIsDiscoveryMode = true;
2032 }
2033 else if (TestIdToExecute.IsEmpty() || GetDescription() == TestIdToExecute)
2034 {
2035 for (int32 Index = 0; Index < BeforeEachStack.Num(); Index++)
2036 {
2037 BeforeEachStack[Index]();
2038 }
2039
2040 DoWork();
2041
2042 for (int32 Index = AfterEachStack.Num() - 1; Index >= 0; Index--)
2043 {
2044 AfterEachStack[Index]();
2045 }
2046 }
2047
2048 PopDescription(InDescription);
2049 }
2050
2051 void BeforeEach(TFunction<void()> DoWork)
2052 {
2053 BeforeEachStack.Push(DoWork);
2054 }
2055
2056 void AfterEach(TFunction<void()> DoWork)
2057 {
2058 AfterEachStack.Push(DoWork);
2059 }
2060
2061private:
2062
2063 void PushDescription(const FString& InDescription)
2064 {
2065 Description.Add(InDescription);
2066 }
2067
2068 void PopDescription(const FString& InDescription)
2069 {
2070 Description.RemoveAt(Description.Num() - 1);
2071 }
2072
2074 {
2075 FString CompleteDescription;
2076 for (int32 Index = 0; Index < Description.Num(); ++Index)
2077 {
2078 if (Description[Index].IsEmpty())
2079 {
2080 continue;
2081 }
2082
2083 if (CompleteDescription.IsEmpty())
2084 {
2085 CompleteDescription = Description[Index];
2086 }
2087 else if (FChar::IsWhitespace(CompleteDescription[CompleteDescription.Len() - 1]) || FChar::IsWhitespace(Description[Index][0]))
2088 {
2089 if (bIsDiscoveryMode)
2090 {
2091 CompleteDescription = CompleteDescription + TEXT(".") + Description[Index];
2092 }
2093 else
2094 {
2095 CompleteDescription = CompleteDescription + Description[Index];
2096 }
2097 }
2098 else
2099 {
2100 if (bIsDiscoveryMode)
2101 {
2102 CompleteDescription = FString::Printf(TEXT("%s.%s"), *CompleteDescription, *Description[Index]);
2103 }
2104 else
2105 {
2106 CompleteDescription = FString::Printf(TEXT("%s %s"), *CompleteDescription, *Description[Index]);
2107 }
2108 }
2109 }
2110
2111 return CompleteDescription;
2112 }
2113
2114private:
2115
2120
2123 mutable bool bIsDiscoveryMode;
2124 mutable bool bBaseRunTestRan;
2125};
2126
2127DECLARE_DELEGATE(FDoneDelegate);
2128
2130 : public FAutomationTestBase
2132{
2133private:
2134
2136 {
2137 public:
2138 FSingleExecuteLatentCommand(const FAutomationSpecBase* const InSpec, TFunction<void()> InPredicate, bool bInSkipIfErrored = false)
2139 : Spec(InSpec)
2141 , bSkipIfErrored(bInSkipIfErrored)
2142 { }
2143
2145 { }
2146
2147 virtual bool Update() override
2148 {
2150 {
2151 return true;
2152 }
2153
2154 Predicate();
2155 return true;
2156 }
2157
2158 private:
2159
2161 const TFunction<void()> Predicate;
2162 const bool bSkipIfErrored;
2163 };
2164
2166 {
2167 public:
2168
2169 FUntilDoneLatentCommand(FAutomationSpecBase* const InSpec, TFunction<void(const FDoneDelegate&)> InPredicate, const FTimespan& InTimeout, bool bInSkipIfErrored = false)
2170 : Spec(InSpec)
2172 , Timeout(InTimeout)
2173 , bSkipIfErrored(bInSkipIfErrored)
2174 , bIsRunning(false)
2175 , bDone(false)
2176 { }
2177
2179 { }
2180
2181 virtual bool Update() override
2182 {
2183 if (!bIsRunning)
2184 {
2186 {
2187 return true;
2188 }
2189
2190 Predicate(FDoneDelegate::CreateSP(this, &FUntilDoneLatentCommand::Done));
2191 bIsRunning = true;
2193 }
2194
2195 if (bDone)
2196 {
2197 Reset();
2198 return true;
2199 }
2201 {
2202 Reset();
2203 Spec->AddError(TEXT("Latent command timed out."), 0);
2204 return true;
2205 }
2206
2207 return false;
2208 }
2209
2210 private:
2211
2212 void Done()
2213 {
2214 bDone = true;
2215 }
2216
2217 void Reset()
2218 {
2219 // Reset the done for the next potential run of this command
2220 bDone = false;
2221 bIsRunning = false;
2222 }
2223
2224 private:
2225
2227 const TFunction<void(const FDoneDelegate&)> Predicate;
2229 const bool bSkipIfErrored;
2230
2234 };
2235
2237 {
2238 public:
2239
2240 FAsyncUntilDoneLatentCommand(FAutomationSpecBase* const InSpec, EAsyncExecution InExecution, TFunction<void(const FDoneDelegate&)> InPredicate, const FTimespan& InTimeout, bool bInSkipIfErrored = false)
2241 : Spec(InSpec)
2244 , Timeout(InTimeout)
2245 , bSkipIfErrored(bInSkipIfErrored)
2246 , bDone(false)
2247 { }
2248
2250 { }
2251
2252 virtual bool Update() override
2253 {
2254 if (!Future.IsValid())
2255 {
2257 {
2258 return true;
2259 }
2260
2261 Future = Async(Execution, [this]() {
2262 Predicate(FDoneDelegate::CreateRaw(this, &FAsyncUntilDoneLatentCommand::Done));
2263 });
2264
2266 }
2267
2268 if (bDone)
2269 {
2270 Reset();
2271 return true;
2272 }
2274 {
2275 Reset();
2276 Spec->AddError(TEXT("Latent command timed out."), 0);
2277 return true;
2278 }
2279
2280 return false;
2281 }
2282
2283 private:
2284
2285 void Done()
2286 {
2287 bDone = true;
2288 }
2289
2290 void Reset()
2291 {
2292 // Reset the done for the next potential run of this command
2293 bDone = false;
2294 Future = TFuture<void>();
2295 }
2296
2297 private:
2298
2301 const TFunction<void(const FDoneDelegate&)> Predicate;
2303 const bool bSkipIfErrored;
2304
2308 };
2309
2311 {
2312 public:
2313
2314 FAsyncLatentCommand(FAutomationSpecBase* const InSpec, EAsyncExecution InExecution, TFunction<void()> InPredicate, const FTimespan& InTimeout, bool bInSkipIfErrored = false)
2315 : Spec(InSpec)
2318 , Timeout(InTimeout)
2319 , bSkipIfErrored(bInSkipIfErrored)
2320 , bDone(false)
2321 { }
2322
2324 { }
2325
2326 virtual bool Update() override
2327 {
2328 if (!Future.IsValid())
2329 {
2331 {
2332 return true;
2333 }
2334
2335 Future = Async(Execution, [this]() {
2336 Predicate();
2337 bDone = true;
2338 });
2339
2341 }
2342
2343 if (bDone)
2344 {
2345 Reset();
2346 return true;
2347 }
2349 {
2350 Reset();
2351 Spec->AddError(TEXT("Latent command timed out."), 0);
2352 return true;
2353 }
2354
2355 return false;
2356 }
2357
2358 private:
2359
2360 void Done()
2361 {
2362 bDone = true;
2363 }
2364
2365 void Reset()
2366 {
2367 // Reset the done for the next potential run of this command
2368 bDone = false;
2369 Future = TFuture<void>();
2370 }
2371
2372 private:
2373
2376 const TFunction<void()> Predicate;
2378 const bool bSkipIfErrored;
2379
2383 };
2384
2385 struct FSpecIt
2386 {
2387 public:
2388
2394
2395 FSpecIt(FString InDescription, FString InId, FString InFilename, int32 InLineNumber, TSharedRef<IAutomationLatentCommand> InCommand)
2397 , Id(MoveTemp(InId))
2399 , LineNumber(MoveTemp(InLineNumber))
2401 { }
2402 };
2403
2405 {
2406 public:
2407
2409
2413
2415 };
2416
2417 struct FSpec
2418 {
2419 public:
2420
2426 };
2427
2428public:
2429
2430 FAutomationSpecBase(const FString& InName, const bool bInComplexTask)
2431 : FAutomationTestBase(InName, bInComplexTask)
2433 , bEnableSkipIfError(true)
2435 {
2436 DefinitionScopeStack.Push(RootDefinitionScope.ToSharedRef());
2437 }
2438
2439 virtual bool RunTest(const FString& InParameters) override
2440 {
2442
2443 if (!InParameters.IsEmpty())
2444 {
2445 const TSharedRef<FSpec>* SpecToRun = IdToSpecMap.Find(InParameters);
2446 if (SpecToRun != nullptr)
2447 {
2448 for (int32 Index = 0; Index < (*SpecToRun)->Commands.Num(); ++Index)
2449 {
2450 FAutomationTestFramework::GetInstance().EnqueueLatentCommand((*SpecToRun)->Commands[Index]);
2451 }
2452 }
2453 }
2454 else
2455 {
2456 TArray<TSharedRef<FSpec>> Specs;
2457 IdToSpecMap.GenerateValueArray(Specs);
2458
2459 for (int32 SpecIndex = 0; SpecIndex < Specs.Num(); SpecIndex++)
2460 {
2461 for (int32 CommandIndex = 0; CommandIndex < Specs[SpecIndex]->Commands.Num(); ++CommandIndex)
2462 {
2463 FAutomationTestFramework::GetInstance().EnqueueLatentCommand(Specs[SpecIndex]->Commands[CommandIndex]);
2464 }
2465 }
2466 }
2467
2468 return true;
2469 }
2470
2471 virtual bool IsStressTest() const
2472 {
2473 return false;
2474 }
2475
2476 virtual uint32 GetRequiredDeviceNum() const override
2477 {
2478 return 1;
2479 }
2480
2481 virtual FString GetTestSourceFileName(const FString& InTestName) const override
2482 {
2483 FString TestId = InTestName;
2484 if (TestId.StartsWith(TestName + TEXT(" ")))
2485 {
2486 TestId = InTestName.RightChop(TestName.Len() + 1);
2487 }
2488
2489 const TSharedRef<FSpec>* Spec = IdToSpecMap.Find(TestId);
2490 if (Spec != nullptr)
2491 {
2492 return (*Spec)->Filename;
2493 }
2494
2495 return FAutomationTestBase::GetTestSourceFileName();
2496 }
2497
2498 virtual int32 GetTestSourceFileLine(const FString& InTestName) const override
2499 {
2500 FString TestId = InTestName;
2501 if (TestId.StartsWith(TestName + TEXT(" ")))
2502 {
2503 TestId = InTestName.RightChop(TestName.Len() + 1);
2504 }
2505
2506 const TSharedRef<FSpec>* Spec = IdToSpecMap.Find(TestId);
2507 if (Spec != nullptr)
2508 {
2509 return (*Spec)->LineNumber;
2510 }
2511
2512 return FAutomationTestBase::GetTestSourceFileLine();
2513 }
2514
2515 virtual void GetTests(TArray<FString>& OutBeautifiedNames, TArray<FString>& OutTestCommands) const override
2516 {
2518
2519 TArray<TSharedRef<FSpec>> Specs;
2520 IdToSpecMap.GenerateValueArray(Specs);
2521
2522 for (int32 Index = 0; Index < Specs.Num(); Index++)
2523 {
2524 OutTestCommands.Push(Specs[Index]->Id);
2525 OutBeautifiedNames.Push(Specs[Index]->Description);
2526 }
2527 }
2528
2529 void xDescribe(const FString& InDescription, TFunction<void()> DoWork)
2530 {
2531 //disabled
2532 }
2533
2534 void Describe(const FString& InDescription, TFunction<void()> DoWork)
2535 {
2536 LLM_SCOPE_BYNAME(TEXT("AutomationTest/Framework"));
2537 const TSharedRef<FSpecDefinitionScope> ParentScope = DefinitionScopeStack.Last();
2538 const TSharedRef<FSpecDefinitionScope> NewScope = MakeShareable(new FSpecDefinitionScope());
2539 NewScope->Description = InDescription;
2540 ParentScope->Children.Push(NewScope);
2541
2542 DefinitionScopeStack.Push(NewScope);
2543 PushDescription(InDescription);
2544 DoWork();
2545 PopDescription(InDescription);
2546 DefinitionScopeStack.Pop();
2547
2548 if (NewScope->It.Num() == 0 && NewScope->Children.Num() == 0)
2549 {
2550 ParentScope->Children.Remove(NewScope);
2551 }
2552 }
2553
2554 void xIt(const FString& InDescription, TFunction<void()> DoWork)
2555 {
2556 //disabled
2557 }
2558
2559 void xIt(const FString& InDescription, EAsyncExecution Execution, TFunction<void()> DoWork)
2560 {
2561 //disabled
2562 }
2563
2564 void xIt(const FString& InDescription, EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void()> DoWork)
2565 {
2566 //disabled
2567 }
2568
2569 void xLatentIt(const FString& InDescription, TFunction<void(const FDoneDelegate&)> DoWork)
2570 {
2571 //disabled
2572 }
2573
2574 void xLatentIt(const FString& InDescription, const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2575 {
2576 //disabled
2577 }
2578
2579 void xLatentIt(const FString& InDescription, EAsyncExecution Execution, TFunction<void(const FDoneDelegate&)> DoWork)
2580 {
2581 //disabled
2582 }
2583
2584 void xLatentIt(const FString& InDescription, EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2585 {
2586 //disabled
2587 }
2588
2589 void It(const FString& InDescription, TFunction<void()> DoWork)
2590 {
2591 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2592 SAFE_GETSTACK(Stack, 1, 1);
2593
2594 PushDescription(InDescription);
2595 CurrentScope->It.Push(MakeShareable(new FSpecIt(GetDescription(), GetId(), Stack[0].Filename, Stack[0].LineNumber, MakeShareable(new FSingleExecuteLatentCommand(this, DoWork, bEnableSkipIfError)))));
2596 PopDescription(InDescription);
2597 }
2598
2599 void It(const FString& InDescription, EAsyncExecution Execution, TFunction<void()> DoWork)
2600 {
2601 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2602 SAFE_GETSTACK(Stack, 1, 1);
2603
2604 PushDescription(InDescription);
2605 CurrentScope->It.Push(MakeShareable(new FSpecIt(GetDescription(), GetId(), Stack[0].Filename, Stack[0].LineNumber, MakeShareable(new FAsyncLatentCommand(this, Execution, DoWork, DefaultTimeout, bEnableSkipIfError)))));
2606 PopDescription(InDescription);
2607 }
2608
2609 void It(const FString& InDescription, EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void()> DoWork)
2610 {
2611 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2612 SAFE_GETSTACK(Stack, 1, 1);
2613
2614 PushDescription(InDescription);
2615 CurrentScope->It.Push(MakeShareable(new FSpecIt(GetDescription(), GetId(), Stack[0].Filename, Stack[0].LineNumber, MakeShareable(new FAsyncLatentCommand(this, Execution, DoWork, Timeout, bEnableSkipIfError)))));
2616 PopDescription(InDescription);
2617 }
2618
2619 void LatentIt(const FString& InDescription, TFunction<void(const FDoneDelegate&)> DoWork)
2620 {
2621 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2622 SAFE_GETSTACK(Stack, 1, 1);
2623
2624 PushDescription(InDescription);
2625 CurrentScope->It.Push(MakeShareable(new FSpecIt(GetDescription(), GetId(), Stack[0].Filename, Stack[0].LineNumber, MakeShareable(new FUntilDoneLatentCommand(this, DoWork, DefaultTimeout, bEnableSkipIfError)))));
2626 PopDescription(InDescription);
2627 }
2628
2629 void LatentIt(const FString& InDescription, const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2630 {
2631 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2632 SAFE_GETSTACK(Stack, 1, 1);
2633
2634 PushDescription(InDescription);
2635 CurrentScope->It.Push(MakeShareable(new FSpecIt(GetDescription(), GetId(), Stack[0].Filename, Stack[0].LineNumber, MakeShareable(new FUntilDoneLatentCommand(this, DoWork, Timeout, bEnableSkipIfError)))));
2636 PopDescription(InDescription);
2637 }
2638
2639 void LatentIt(const FString& InDescription, EAsyncExecution Execution, TFunction<void(const FDoneDelegate&)> DoWork)
2640 {
2641 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2642 SAFE_GETSTACK(Stack, 1, 1);
2643
2644 PushDescription(InDescription);
2645 CurrentScope->It.Push(MakeShareable(new FSpecIt(GetDescription(), GetId(), Stack[0].Filename, Stack[0].LineNumber, MakeShareable(new FAsyncUntilDoneLatentCommand(this, Execution, DoWork, DefaultTimeout, bEnableSkipIfError)))));
2646 PopDescription(InDescription);
2647 }
2648
2649 void LatentIt(const FString& InDescription, EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2650 {
2651 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2652 SAFE_GETSTACK(Stack, 1, 1);
2653
2654 PushDescription(InDescription);
2655 CurrentScope->It.Push(MakeShareable(new FSpecIt(GetDescription(), GetId(), Stack[0].Filename, Stack[0].LineNumber, MakeShareable(new FAsyncUntilDoneLatentCommand(this, Execution, DoWork, Timeout, bEnableSkipIfError)))));
2656 PopDescription(InDescription);
2657 }
2658
2659 void xBeforeEach(TFunction<void()> DoWork)
2660 {
2661 // disabled
2662 }
2663
2664 void xBeforeEach(EAsyncExecution Execution, TFunction<void()> DoWork)
2665 {
2666 // disabled
2667 }
2668
2669 void xBeforeEach(EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void()> DoWork)
2670 {
2671 // disabled
2672 }
2673
2674 void xLatentBeforeEach(TFunction<void(const FDoneDelegate&)> DoWork)
2675 {
2676 // disabled
2677 }
2678
2679 void xLatentBeforeEach(const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2680 {
2681 // disabled
2682 }
2683
2684 void xLatentBeforeEach(EAsyncExecution Execution, TFunction<void(const FDoneDelegate&)> DoWork)
2685 {
2686 // disabled
2687 }
2688
2689 void xLatentBeforeEach(EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2690 {
2691 // disabled
2692 }
2693
2694 void BeforeEach(TFunction<void()> DoWork)
2695 {
2696 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2697 CurrentScope->BeforeEach.Push(MakeShareable(new FSingleExecuteLatentCommand(this, DoWork, bEnableSkipIfError)));
2698 }
2699
2700 void BeforeEach(EAsyncExecution Execution, TFunction<void()> DoWork)
2701 {
2702 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2703 CurrentScope->BeforeEach.Push(MakeShareable(new FAsyncLatentCommand(this, Execution, DoWork, DefaultTimeout, bEnableSkipIfError)));
2704 }
2705
2706 void BeforeEach(EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void()> DoWork)
2707 {
2708 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2709 CurrentScope->BeforeEach.Push(MakeShareable(new FAsyncLatentCommand(this, Execution, DoWork, Timeout, bEnableSkipIfError)));
2710 }
2711
2712 void LatentBeforeEach(TFunction<void(const FDoneDelegate&)> DoWork)
2713 {
2714 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2715 CurrentScope->BeforeEach.Push(MakeShareable(new FUntilDoneLatentCommand(this, DoWork, DefaultTimeout, bEnableSkipIfError)));
2716 }
2717
2718 void LatentBeforeEach(const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2719 {
2720 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2721 CurrentScope->BeforeEach.Push(MakeShareable(new FUntilDoneLatentCommand(this, DoWork, Timeout, bEnableSkipIfError)));
2722 }
2723
2724 void LatentBeforeEach(EAsyncExecution Execution, TFunction<void(const FDoneDelegate&)> DoWork)
2725 {
2726 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2727 CurrentScope->BeforeEach.Push(MakeShareable(new FAsyncUntilDoneLatentCommand(this, Execution, DoWork, DefaultTimeout, bEnableSkipIfError)));
2728 }
2729
2730 void LatentBeforeEach(EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2731 {
2732 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2733 CurrentScope->BeforeEach.Push(MakeShareable(new FAsyncUntilDoneLatentCommand(this, Execution, DoWork, Timeout, bEnableSkipIfError)));
2734 }
2735
2736 void xAfterEach(TFunction<void()> DoWork)
2737 {
2738 // disabled
2739 }
2740
2741 void xAfterEach(EAsyncExecution Execution, TFunction<void()> DoWork)
2742 {
2743 // disabled
2744 }
2745
2746 void xAfterEach(EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void()> DoWork)
2747 {
2748 // disabled
2749 }
2750
2751 void xLatentAfterEach(TFunction<void(const FDoneDelegate&)> DoWork)
2752 {
2753 // disabled
2754 }
2755
2756 void xLatentAfterEach(const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2757 {
2758 // disabled
2759 }
2760
2761 void xLatentAfterEach(EAsyncExecution Execution, TFunction<void(const FDoneDelegate&)> DoWork)
2762 {
2763 // disabled
2764 }
2765
2766 void xLatentAfterEach(EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2767 {
2768 // disabled
2769 }
2770
2771 void AfterEach(TFunction<void()> DoWork)
2772 {
2773 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2774 CurrentScope->AfterEach.Push(MakeShareable(new FSingleExecuteLatentCommand(this, DoWork)));
2775 }
2776
2777 void AfterEach(EAsyncExecution Execution, TFunction<void()> DoWork)
2778 {
2779 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2780 CurrentScope->AfterEach.Push(MakeShareable(new FAsyncLatentCommand(this, Execution, DoWork, DefaultTimeout)));
2781 }
2782
2783 void AfterEach(EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void()> DoWork)
2784 {
2785 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2786 CurrentScope->AfterEach.Push(MakeShareable(new FAsyncLatentCommand(this, Execution, DoWork, Timeout)));
2787 }
2788
2789 void LatentAfterEach(TFunction<void(const FDoneDelegate&)> DoWork)
2790 {
2791 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2792 CurrentScope->AfterEach.Push(MakeShareable(new FUntilDoneLatentCommand(this, DoWork, DefaultTimeout)));
2793 }
2794
2795 void LatentAfterEach(const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2796 {
2797 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2798 CurrentScope->AfterEach.Push(MakeShareable(new FUntilDoneLatentCommand(this, DoWork, Timeout)));
2799 }
2800
2801 void LatentAfterEach(EAsyncExecution Execution, TFunction<void(const FDoneDelegate&)> DoWork)
2802 {
2803 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2804 CurrentScope->AfterEach.Push(MakeShareable(new FAsyncUntilDoneLatentCommand(this, Execution, DoWork, DefaultTimeout)));
2805 }
2806
2807 void LatentAfterEach(EAsyncExecution Execution, const FTimespan& Timeout, TFunction<void(const FDoneDelegate&)> DoWork)
2808 {
2809 const TSharedRef<FSpecDefinitionScope> CurrentScope = DefinitionScopeStack.Last();
2810 CurrentScope->AfterEach.Push(MakeShareable(new FAsyncUntilDoneLatentCommand(this, Execution, DoWork, Timeout)));
2811 }
2812
2813protected:
2814
2815 /* The timespan for how long a block should be allowed to execute before giving up and failing the test */
2817
2818 /* Whether or not BeforeEach and It blocks should skip execution if the test has already failed */
2820
2822 {
2823 if (!bHasBeenDefined)
2824 {
2825 const_cast<FAutomationSpecBase*>(this)->Define();
2826 const_cast<FAutomationSpecBase*>(this)->PostDefine();
2827 }
2828 }
2829
2830 virtual void Define() = 0;
2831
2833 {
2834 TArray<TSharedRef<FSpecDefinitionScope>> Stack;
2835 Stack.Push(RootDefinitionScope.ToSharedRef());
2836
2837 TArray<TSharedRef<IAutomationLatentCommand>> BeforeEach;
2838 TArray<TSharedRef<IAutomationLatentCommand>> AfterEach;
2839
2840 while (Stack.Num() > 0)
2841 {
2842 const TSharedRef<FSpecDefinitionScope> Scope = Stack.Last();
2843
2844 BeforeEach.Append(Scope->BeforeEach);
2845 AfterEach.Append(Scope->AfterEach); // iterate in reverse
2846
2847 for (int32 ItIndex = 0; ItIndex < Scope->It.Num(); ItIndex++)
2848 {
2849 TSharedRef<FSpecIt> It = Scope->It[ItIndex];
2850
2851 TSharedRef<FSpec> Spec = MakeShareable(new FSpec());
2852 Spec->Id = It->Id;
2853 Spec->Description = It->Description;
2854 Spec->Filename = It->Filename;
2855 Spec->LineNumber = It->LineNumber;
2856 Spec->Commands.Append(BeforeEach);
2857 Spec->Commands.Add(It->Command);
2858
2859 for (int32 AfterEachIndex = AfterEach.Num() - 1; AfterEachIndex >= 0; AfterEachIndex--)
2860 {
2861 Spec->Commands.Add(AfterEach[AfterEachIndex]);
2862 }
2863
2864 check(!IdToSpecMap.Contains(Spec->Id));
2865 IdToSpecMap.Add(Spec->Id, Spec);
2866 }
2867 Scope->It.Empty();
2868
2869 if (Scope->Children.Num() > 0)
2870 {
2871 Stack.Append(Scope->Children);
2872 Scope->Children.Empty();
2873 }
2874 else
2875 {
2876 while (Stack.Num() > 0 && Stack.Last()->Children.Num() == 0 && Stack.Last()->It.Num() == 0)
2877 {
2878 const TSharedRef<FSpecDefinitionScope> PoppedScope = Stack.Pop();
2879
2880 if (PoppedScope->BeforeEach.Num() > 0)
2881 {
2882 BeforeEach.RemoveAt(BeforeEach.Num() - PoppedScope->BeforeEach.Num(), PoppedScope->BeforeEach.Num());
2883 }
2884
2885 if (PoppedScope->AfterEach.Num() > 0)
2886 {
2887 AfterEach.RemoveAt(AfterEach.Num() - PoppedScope->AfterEach.Num(), PoppedScope->AfterEach.Num());
2888 }
2889 }
2890 }
2891 }
2892
2893 RootDefinitionScope.Reset();
2894 DefinitionScopeStack.Reset();
2895 bHasBeenDefined = true;
2896 }
2897
2899 {
2900 Description.Empty();
2901 IdToSpecMap.Empty();
2902 RootDefinitionScope.Reset();
2903 DefinitionScopeStack.Empty();
2904 bHasBeenDefined = false;
2905 }
2906
2907private:
2908
2909 void PushDescription(const FString& InDescription)
2910 {
2911 LLM_SCOPE_BYNAME(TEXT("AutomationTest/Framework"));
2912 Description.Add(InDescription);
2913 }
2914
2915 void PopDescription(const FString& InDescription)
2916 {
2917 Description.RemoveAt(Description.Num() - 1);
2918 }
2919
2921 {
2922 FString CompleteDescription;
2923 for (int32 Index = 0; Index < Description.Num(); ++Index)
2924 {
2925 if (Description[Index].IsEmpty())
2926 {
2927 continue;
2928 }
2929
2930 if (CompleteDescription.IsEmpty())
2931 {
2932 CompleteDescription = Description[Index];
2933 }
2934 else if (FChar::IsWhitespace(CompleteDescription[CompleteDescription.Len() - 1]) || FChar::IsWhitespace(Description[Index][0]))
2935 {
2936 CompleteDescription = CompleteDescription + TEXT(".") + Description[Index];
2937 }
2938 else
2939 {
2940 CompleteDescription = FString::Printf(TEXT("%s.%s"), *CompleteDescription, *Description[Index]);
2941 }
2942 }
2943
2944 return CompleteDescription;
2945 }
2946
2948 {
2949 if (Description.Last().EndsWith(TEXT("]")))
2950 {
2951 FString ItDescription = Description.Last();
2952 ItDescription.RemoveAt(ItDescription.Len() - 1);
2953
2954 int32 StartingBraceIndex = INDEX_NONE;
2955 if (ItDescription.FindLastChar(TEXT('['), StartingBraceIndex) && StartingBraceIndex != ItDescription.Len() - 1)
2956 {
2957 FString CommandId = ItDescription.RightChop(StartingBraceIndex + 1);
2958 return CommandId;
2959 }
2960 }
2961
2962 FString CompleteId;
2963 for (int32 Index = 0; Index < Description.Num(); ++Index)
2964 {
2965 if (Description[Index].IsEmpty())
2966 {
2967 continue;
2968 }
2969
2970 if (CompleteId.IsEmpty())
2971 {
2972 CompleteId = Description[Index];
2973 }
2974 else if (FChar::IsWhitespace(CompleteId[CompleteId.Len() - 1]) || FChar::IsWhitespace(Description[Index][0]))
2975 {
2976 CompleteId = CompleteId + Description[Index];
2977 }
2978 else
2979 {
2980 CompleteId = FString::Printf(TEXT("%s %s"), *CompleteId, *Description[Index]);
2981 }
2982 }
2983
2984 return CompleteId;
2985 }
2986
2987private:
2988
2994};
2995
2996
2997//////////////////////////////////////////////////
2998// Latent command definition macros
2999
3000#define DEFINE_LATENT_AUTOMATION_COMMAND(CommandName) class
3001 CommandName : public IAutomationLatentCommand
3002 {
3003 public:
3004 virtual ~CommandName()
3005 {}
3006 virtual bool Update() override; \
3007}
3008
3009#define DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER(CommandName,ParamType,ParamName) class
3010 CommandName : public IAutomationLatentCommand
3011 {
3012 public:
3013 CommandName(ParamType InputParam)
3014 : ParamName(InputParam)
3015 {}
3016 virtual ~CommandName()
3017 {}
3018 virtual bool Update() override;
3019 private:
3020 ParamType ParamName; \
3021}
3022
3023#define DEFINE_LATENT_AUTOMATION_COMMAND_TWO_PARAMETER(CommandName,ParamType0,ParamName0,ParamType1,ParamName1) class
3024 CommandName : public IAutomationLatentCommand
3025 {
3026 public:
3027 CommandName(ParamType0 InputParam0, ParamType1 InputParam1)
3028 : ParamName0(InputParam0)
3029 , ParamName1(InputParam1)
3030 {}
3031 virtual ~CommandName()
3032 {}
3033 virtual bool Update() override;
3034 private:
3035 ParamType0 ParamName0;
3036 ParamType1 ParamName1; \
3037}
3038
3039#define DEFINE_LATENT_AUTOMATION_COMMAND_THREE_PARAMETER(CommandName,ParamType0,ParamName0,ParamType1,ParamName1,ParamType2,ParamName2) class
3040 CommandName : public IAutomationLatentCommand
3041 {
3042 public:
3043 CommandName(ParamType0 InputParam0, ParamType1 InputParam1, ParamType2 InputParam2)
3044 : ParamName0(InputParam0)
3045 , ParamName1(InputParam1)
3046 , ParamName2(InputParam2)
3047 {}
3048 virtual ~CommandName()
3049 {}
3050 virtual bool Update() override;
3051 private:
3052 ParamType0 ParamName0;
3053 ParamType1 ParamName1;
3054 ParamType2 ParamName2; \
3055}
3056
3057#define DEFINE_LATENT_AUTOMATION_COMMAND_FOUR_PARAMETER(CommandName,ParamType0,ParamName0,ParamType1,ParamName1,ParamType2,ParamName2,ParamType3,ParamName3) class
3058 CommandName : public IAutomationLatentCommand
3059 {
3060 public:
3061 CommandName(ParamType0 InputParam0, ParamType1 InputParam1, ParamType2 InputParam2, ParamType3 InputParam3)
3062 : ParamName0(InputParam0)
3063 , ParamName1(InputParam1)
3064 , ParamName2(InputParam2)
3065 , ParamName3(InputParam3)
3066 {}
3067 virtual ~CommandName()
3068 {}
3069 virtual bool Update() override;
3070 private:
3071 ParamType0 ParamName0;
3072 ParamType1 ParamName1;
3073 ParamType2 ParamName2;
3074 ParamType3 ParamName3; \
3075}
3076
3077#define DEFINE_LATENT_AUTOMATION_COMMAND_FIVE_PARAMETER(CommandName,ParamType0,ParamName0,ParamType1,ParamName1,ParamType2,ParamName2,ParamType3,ParamName3,ParamType4,ParamName4) class
3078 CommandName : public IAutomationLatentCommand
3079 {
3080 public:
3081 CommandName(ParamType0 InputParam0, ParamType1 InputParam1, ParamType2 InputParam2, ParamType3 InputParam3, ParamType4 InputParam4)
3082 : ParamName0(InputParam0)
3083 , ParamName1(InputParam1)
3084 , ParamName2(InputParam2)
3085 , ParamName3(InputParam3)
3086 , ParamName4(InputParam4)
3087 {}
3088 virtual ~CommandName()
3089 {}
3090 virtual bool Update() override;
3091 private:
3092 ParamType0 ParamName0;
3093 ParamType1 ParamName1;
3094 ParamType2 ParamName2;
3095 ParamType3 ParamName3;
3096 ParamType4 ParamName4; \
3097}
3098
3099#define DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND(EXPORT_API, CommandName) class
3100 EXPORT_API CommandName : public IAutomationLatentCommand
3101 {
3102 public:
3103 virtual ~CommandName()
3104 {}
3105 virtual bool Update() override; \
3106}
3107
3108#define DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER(EXPORT_API, CommandName,ParamType,ParamName) class
3109 EXPORT_API CommandName : public IAutomationLatentCommand
3110 {
3111 public:
3112 CommandName(ParamType InputParam)
3113 : ParamName(InputParam)
3114 {}
3115 virtual ~CommandName()
3116 {}
3117 virtual bool Update() override;
3118 private:
3119 ParamType ParamName; \
3120}
3121
3122#define DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND_TWO_PARAMETER(EXPORT_API, CommandName,ParamType0,ParamName0,ParamType1,ParamName1) class
3123 EXPORT_API CommandName : public IAutomationLatentCommand
3124 {
3125 public:
3126 CommandName(ParamType0 InputParam0, ParamType1 InputParam1)
3127 : ParamName0(InputParam0)
3128 , ParamName1(InputParam1)
3129 {}
3130 virtual ~CommandName()
3131 {}
3132 virtual bool Update() override;
3133 private:
3134 ParamType0 ParamName0;
3135 ParamType1 ParamName1; \
3136}
3137
3138#define DEFINE_ENGINE_LATENT_AUTOMATION_COMMAND(CommandName)
3139 DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND(ENGINE_API, CommandName)
3140
3141#define DEFINE_ENGINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER(CommandName,ParamType,ParamName)
3142 DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER(ENGINE_API, CommandName, ParamType, ParamName)
3143
3144#define DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND_WITH_RETRIES(EXPORT_API,CommandName,RetryCount,WaitTimeBetweenRuns) class
3145 EXPORT_API CommandName : public IAutomationLatentCommandWithRetriesAndDelays
3146 {
3147 public:
3148 CommandName(int32 InRetryCount, double InWaitTimeBetweenRuns)
3149 : IAutomationLatentCommandWithRetriesAndDelays(#CommandName, InRetryCount, InWaitTimeBetweenRuns)
3150 {}
3151 virtual ~CommandName()
3152 {}
3153 virtual bool Execute() override;
3154 private: \
3155}
3156
3157#define DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND_WITH_RETRIES_ONE_PARAMETER(EXPORT_API,CommandName,RetryCount,WaitTimeBetweenRuns,ParamType,ParamName) class
3158 EXPORT_API CommandName : public IAutomationLatentCommandWithRetriesAndDelays
3159 {
3160 public:
3161 CommandName(int32 InRetryCount, double InWaitTimeBetweenRuns, ParamType ParamName)
3162 : IAutomationLatentCommandWithRetriesAndDelays(#CommandName, InRetryCount, InWaitTimeBetweenRuns)
3163 , ParamName(ParamName)
3164 {}
3165 virtual ~CommandName()
3166 {}
3167 virtual bool Execute() override;
3168 private:
3169 ParamType ParamName; \
3170}
3171
3172#define DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND_WITH_RETRIES_TWO_PARAMETERS(EXPORT_API,CommandName,RetryCount,WaitTimeBetweenRuns,ParamType0,ParamName0,ParamType1,ParamName1) class
3173 EXPORT_API CommandName : public IAutomationLatentCommandWithRetriesAndDelays
3174 {
3175 public:
3176 CommandName(int32 InRetryCount, double InWaitTimeBetweenRuns, ParamType0 ParamName0, ParamType1 ParamName1)
3177 : IAutomationLatentCommandWithRetriesAndDelays(#CommandName, InRetryCount, InWaitTimeBetweenRuns)
3178 , ParamName0(ParamName0)
3179 , ParamName1(ParamName1)
3180 {}
3181 virtual ~CommandName()
3182 {}
3183 virtual bool Execute() override;
3184 private:
3185 ParamType0 ParamName0;
3186 ParamType1 ParamName1; \
3187}
3188
3189#define DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND_WITH_RETRIES_THREE_PARAMETERS(EXPORT_API,CommandName,RetryCount,WaitTimeBetweenRuns,ParamType0,ParamName0,ParamType1,ParamName1,ParamType2,ParamName2) class
3190 EXPORT_API CommandName : public IAutomationLatentCommandWithRetriesAndDelays
3191 {
3192 public:
3193 CommandName(int32 InRetryCount, double InWaitTimeBetweenRuns, ParamType0 ParamName0, ParamType1 ParamName1, ParamType2 ParamName2)
3194 : IAutomationLatentCommandWithRetriesAndDelays(#CommandName, InRetryCount, InWaitTimeBetweenRuns)
3195 , ParamName0(ParamName0)
3196 , ParamName1(ParamName1)
3197 , ParamName2(ParamName2)
3198 {}
3199 virtual ~CommandName()
3200 {}
3201 virtual bool Execute() override;
3202 private:
3203 ParamType0 ParamName0;
3204 ParamType1 ParamName1;
3205 ParamType2 ParamName2; \
3206}
3207
3208#define DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND_WITH_RETRIES_FOUR_PARAMETERS(EXPORT_API,CommandName,RetryCount,WaitTimeBetweenRuns,ParamType0,ParamName0,ParamType1,ParamName1,ParamType2,ParamName2,ParamType3,ParamName3) class
3209 EXPORT_API CommandName : public IAutomationLatentCommandWithRetriesAndDelays
3210 {
3211 public:
3212 CommandName(int32 InRetryCount, double InWaitTimeBetweenRuns, ParamType0 ParamName0, ParamType1 ParamName1, ParamType2 ParamName2, ParamType3 ParamName3)
3213 : IAutomationLatentCommandWithRetriesAndDelays(#CommandName, InRetryCount, InWaitTimeBetweenRuns)
3214 , ParamName0(ParamName0)
3215 , ParamName1(ParamName1)
3216 , ParamName2(ParamName2)
3217 , ParamName3(ParamName3)
3218 {}
3219 virtual ~CommandName()
3220 {}
3221 virtual bool Execute() override;
3222 private:
3223 ParamType0 ParamName0;
3224 ParamType1 ParamName1;
3225 ParamType2 ParamName2;
3226 ParamType3 ParamName3; \
3227}
3228
3229//macro to simply the syntax for enqueueing a latent command
3230#define ADD_LATENT_AUTOMATION_COMMAND(ClassDeclaration) FAutomationTestFramework::Get().EnqueueLatentCommand(MakeShareable(new ClassDeclaration));
3231
3232
3233//declare the class
3234#define START_NETWORK_AUTOMATION_COMMAND(ClassDeclaration) class
3235 F##ClassDeclaration : public IAutomationNetworkCommand \
3236{private
3237 :
3238 int32 RoleIndex; public
3239 :
3240 F##ClassDeclaration(int32 InRoleIndex) : RoleIndex(InRoleIndex) {}
3241 virtual ~F##ClassDeclaration() {}
3242 virtual uint32 GetRoleIndex() const override { return RoleIndex; }
3243 virtual void Run() override
3244
3245//close the class and add to the framework
3246#define END_NETWORK_AUTOMATION_COMMAND(ClassDeclaration,InRoleIndex) };
3247 FAutomationTestFramework::Get().EnqueueNetworkCommand(MakeShareable(new F##ClassDeclaration(InRoleIndex)));
3248
3249/**
3250 * Macros to simplify the creation of new automation tests. To create a new test one simply must put
3251 * IMPLEMENT_SIMPLE_AUTOMATION_TEST( NewAutomationClassName, AutomationClassFlags )
3252 * IMPLEMENT_COMPLEX_AUTOMATION_TEST( NewAutomationClassName, AutomationClassFlags )
3253 * in their cpp file, and then proceed to write an implementation for:
3254 * bool NewAutomationTestClassName::RunTest() {}
3255 * While the macro could also have allowed the code to be specified, leaving it out of the macro allows
3256 * the code to be debugged more easily.
3257 *
3258 * Builds supporting automation tests will automatically create and register an instance of the automation test within
3259 * the automation test framework as a result of the macro.
3260 */
3261
3262#define IMPLEMENT_SIMPLE_AUTOMATION_TEST_PRIVATE( TClass, TBaseClass, PrettyName, TFlags, FileName, LineNumber )
3263 class TClass : public TBaseClass
3264 {
3265 public:
3266 TClass( const FString& InName )
3267 :TBaseClass( InName, false ) {
3268 static_assert((TFlags)&EAutomationTestFlags::ApplicationContextMask, "AutomationTest has no application flag. It shouldn't run. See AutomationTest.h.");
3269 static_assert( (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::SmokeFilter) ||
3270 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::EngineFilter) ||
3271 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::ProductFilter) ||
3272 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::PerfFilter) ||
3273 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::StressFilter) ||
3274 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::NegativeFilter),
3275 "All AutomationTests must have exactly 1 filter type specified. See AutomationTest.h.");
3276 }
3277 virtual uint32 GetTestFlags() const override { return TFlags; }
3278 virtual bool IsStressTest() const { return false; }
3279 virtual uint32 GetRequiredDeviceNum() const override { return 1; }
3280 virtual FString GetTestSourceFileName() const override { return FileName; }
3281 virtual int32 GetTestSourceFileLine() const override { return LineNumber; }
3282 protected:
3283 virtual void GetTests(TArray<FString>& OutBeautifiedNames, TArray <FString>& OutTestCommands) const override
3284 {
3285 OutBeautifiedNames.Add(PrettyName);
3286 OutTestCommands.Add(FString());
3287 }
3288 virtual bool RunTest(const FString& Parameters) override;
3289 virtual FString GetBeautifiedTestName() const override { return PrettyName; }
3290 };
3291
3292
3293
3294#define IMPLEMENT_COMPLEX_AUTOMATION_TEST_PRIVATE( TClass, TBaseClass, PrettyName, TFlags, FileName, LineNumber )
3295 class TClass : public TBaseClass
3296 {
3297 public:
3298 TClass( const FString& InName )
3299 :TBaseClass( InName, true ) {
3300 static_assert((TFlags)&EAutomationTestFlags::ApplicationContextMask, "AutomationTest has no application flag. It shouldn't run. See AutomationTest.h.");
3301 static_assert( (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::SmokeFilter) ||
3302 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::EngineFilter) ||
3303 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::ProductFilter) ||
3304 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::PerfFilter) ||
3305 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::StressFilter) ||
3306 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::NegativeFilter),
3307 "All AutomationTests must have exactly 1 filter type specified. See AutomationTest.h.");
3308 }
3309 virtual uint32 GetTestFlags() const override { return ((TFlags) & ~(EAutomationTestFlags::SmokeFilter)); }
3310 virtual bool IsStressTest() const { return true; }
3311 virtual uint32 GetRequiredDeviceNum() const override { return 1; }
3312 virtual FString GetTestSourceFileName() const override { return FileName; }
3313 virtual int32 GetTestSourceFileLine() const override { return LineNumber; }
3314 protected:
3315 virtual void GetTests(TArray<FString>& OutBeautifiedNames, TArray <FString>& OutTestCommands) const override;
3316 virtual bool RunTest(const FString& Parameters) override;
3317 virtual FString GetBeautifiedTestName() const override { return PrettyName; }
3318 };
3319
3320#define IMPLEMENT_NETWORKED_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, NumParticipants, FileName, LineNumber)
3321 class TClass : public TBaseClass
3322 {
3323 public:
3324 TClass( const FString& InName )
3325 :TBaseClass( InName, false ) {
3326 static_assert((TFlags)&EAutomationTestFlags::ApplicationContextMask, "AutomationTest has no application flag. It shouldn't run. See AutomationTest.h.");
3327 static_assert( (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::SmokeFilter) ||
3328 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::EngineFilter) ||
3329 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::ProductFilter) ||
3330 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::PerfFilter) ||
3331 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::StressFilter) ||
3332 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::NegativeFilter),
3333 "All AutomationTests must have exactly 1 filter type specified. See AutomationTest.h.");
3334 }
3335 virtual uint32 GetTestFlags() const override { return ((TFlags) & ~(EAutomationTestFlags::EditorContext | EAutomationTestFlags::CommandletContext | EAutomationTestFlags::SmokeFilter)); }
3336 virtual uint32 GetRequiredDeviceNum() const override { return NumParticipants; }
3337 virtual FString GetTestSourceFileName() const override { return FileName; }
3338 virtual int32 GetTestSourceFileLine() const override { return LineNumber; }
3339 protected:
3340 virtual void GetTests(TArray<FString>& OutBeautifiedNames, TArray <FString>& OutTestCommands) const override
3341 {
3342 OutBeautifiedNames.Add(PrettyName);
3343 OutTestCommands.Add(FString());
3344 }
3345 virtual bool RunTest(const FString& Parameters) override;
3346 virtual FString GetBeautifiedTestName() const override { return PrettyName; }
3347 };
3348
3349#define IMPLEMENT_BDD_AUTOMATION_TEST_PRIVATE( TClass, PrettyName, TFlags, FileName, LineNumber )
3350 class TClass : public FBDDAutomationTestBase
3351 {
3352 public:
3353 TClass( const FString& InName )
3354 :FBDDAutomationTestBase( InName, false ) {
3355 static_assert((TFlags)&EAutomationTestFlags::ApplicationContextMask, "AutomationTest has no application flag. It shouldn't run. See AutomationTest.h.");
3356 static_assert( (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::SmokeFilter) ||
3357 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::EngineFilter) ||
3358 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::ProductFilter) ||
3359 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::PerfFilter) ||
3360 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::StressFilter) ||
3361 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::NegativeFilter),
3362 "All AutomationTests must have exactly 1 filter type specified. See AutomationTest.h.");
3363 }
3364 virtual uint32 GetTestFlags() const override { return TFlags; }
3365 virtual bool IsStressTest() const { return false; }
3366 virtual uint32 GetRequiredDeviceNum() const override { return 1; }
3367 virtual FString GetTestSourceFileName() const override { return FileName; }
3368 virtual int32 GetTestSourceFileLine() const override { return LineNumber; }
3369 protected:
3370 virtual bool RunTest(const FString& Parameters) override;
3371 virtual FString GetBeautifiedTestName() const override { return PrettyName; }
3372 private:
3373 void Define();
3374 };
3375
3376#define DEFINE_SPEC_PRIVATE( TClass, PrettyName, TFlags, FileName, LineNumber )
3377 class TClass : public FAutomationSpecBase
3378 {
3379 public:
3380 TClass( const FString& InName )
3381 : FAutomationSpecBase( InName, false ) {
3382 static_assert((TFlags)&EAutomationTestFlags::ApplicationContextMask, "AutomationTest has no application flag. It shouldn't run. See AutomationTest.h.");
3383 static_assert( (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::SmokeFilter) ||
3384 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::EngineFilter) ||
3385 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::ProductFilter) ||
3386 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::PerfFilter) ||
3387 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::StressFilter) ||
3388 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::NegativeFilter),
3389 "All AutomationTests must have exactly 1 filter type specified. See AutomationTest.h.");
3390 }
3391 virtual uint32 GetTestFlags() const override { return TFlags; }
3392 using FAutomationSpecBase::GetTestSourceFileName;
3393 virtual FString GetTestSourceFileName() const override { return FileName; }
3394 using FAutomationSpecBase::GetTestSourceFileLine;
3395 virtual int32 GetTestSourceFileLine() const override { return LineNumber; }
3396 virtual FString GetTestSourceFileName(const FString&) const override { return GetTestSourceFileName(); }
3397 virtual int32 GetTestSourceFileLine(const FString&) const override { return GetTestSourceFileLine(); }
3398 protected:
3399 virtual FString GetBeautifiedTestName() const override { return PrettyName; }
3400 virtual void Define() override;
3401 };
3402
3403#define BEGIN_DEFINE_SPEC_PRIVATE( TClass, PrettyName, TFlags, FileName, LineNumber )
3404 class TClass : public FAutomationSpecBase
3405 {
3406 public:
3407 TClass( const FString& InName )
3408 : FAutomationSpecBase( InName, false ) {
3409 static_assert((TFlags)&EAutomationTestFlags::ApplicationContextMask, "AutomationTest has no application flag. It shouldn't run. See AutomationTest.h.");
3410 static_assert( (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::SmokeFilter) ||
3411 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::EngineFilter) ||
3412 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::ProductFilter) ||
3413 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::PerfFilter) ||
3414 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::StressFilter) ||
3415 (((TFlags)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::NegativeFilter),
3416 "All AutomationTests must have exactly 1 filter type specified. See AutomationTest.h.");
3417 }
3418 virtual uint32 GetTestFlags() const override { return TFlags; }
3419 using FAutomationSpecBase::GetTestSourceFileName;
3420 virtual FString GetTestSourceFileName() const override { return FileName; }
3421 using FAutomationSpecBase::GetTestSourceFileLine;
3422 virtual int32 GetTestSourceFileLine() const override { return LineNumber; }
3423 protected:
3424 virtual FString GetBeautifiedTestName() const override { return PrettyName; }
3425 virtual void Define() override;
3426
3428 #define IMPLEMENT_SIMPLE_AUTOMATION_TEST( TClass, PrettyName, TFlags )
3429 IMPLEMENT_SIMPLE_AUTOMATION_TEST_PRIVATE(TClass, FAutomationTestBase, PrettyName, TFlags, __FILE__, __LINE__)
3430 namespace
3431 {
3432 TClass TClass##AutomationTestInstance( TEXT(#TClass) );
3433 }
3434 #define IMPLEMENT_COMPLEX_AUTOMATION_TEST( TClass, PrettyName, TFlags )
3435 IMPLEMENT_COMPLEX_AUTOMATION_TEST_PRIVATE(TClass, FAutomationTestBase, PrettyName, TFlags, __FILE__, __LINE__)
3436 namespace
3437 {
3438 TClass TClass##AutomationTestInstance( TEXT(#TClass) );
3439 }
3440 #define IMPLEMENT_COMPLEX_AUTOMATION_CLASS( TClass, PrettyName, TFlags )
3441 IMPLEMENT_COMPLEX_AUTOMATION_TEST_PRIVATE(TClass, FAutomationTestBase, PrettyName, TFlags, __FILE__, __LINE__)
3442 #define IMPLEMENT_NETWORKED_AUTOMATION_TEST(TClass, PrettyName, TFlags, NumParticipants)
3443 IMPLEMENT_NETWORKED_AUTOMATION_TEST_PRIVATE(TClass, FAutomationTestBase, PrettyName, TFlags, NumParticipants, __FILE__, __LINE__)
3444 namespace
3445 {
3446 TClass TClass##AutomationTestInstance( TEXT(#TClass) );
3447 }
3448
3449 #define IMPLEMENT_CUSTOM_SIMPLE_AUTOMATION_TEST( TClass, TBaseClass, PrettyName, TFlags )
3450 IMPLEMENT_SIMPLE_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, __FILE__, __LINE__)
3451 namespace
3452 {
3453 TClass TClass##AutomationTestInstance( TEXT(#TClass) );
3454 }
3455
3456 #define IMPLEMENT_CUSTOM_COMPLEX_AUTOMATION_TEST( TClass, TBaseClass, PrettyName, TFlags )
3457 IMPLEMENT_COMPLEX_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, __FILE__, __LINE__)
3458 namespace
3459 {
3460 TClass TClass##AutomationTestInstance( TEXT(#TClass) );
3461 }
3462
3463 #define IMPLEMENT_BDD_AUTOMATION_TEST( TClass, PrettyName, TFlags )
3464 IMPLEMENT_BDD_AUTOMATION_TEST_PRIVATE(TClass, PrettyName, TFlags, __FILE__, __LINE__)
3465 namespace
3466 {
3467 TClass TClass##AutomationTestInstance( TEXT(#TClass) );
3468 }
3469
3470 #define DEFINE_SPEC( TClass, PrettyName, TFlags )
3471 DEFINE_SPEC_PRIVATE(TClass, PrettyName, TFlags, __FILE__, __LINE__)
3472 namespace
3473 {
3474 TClass TClass##AutomationSpecInstance( TEXT(#TClass) );
3475 }
3476
3477 #define BEGIN_DEFINE_SPEC( TClass, PrettyName, TFlags )
3478 BEGIN_DEFINE_SPEC_PRIVATE(TClass, PrettyName, TFlags, __FILE__, __LINE__)
3479
3480 #define END_DEFINE_SPEC( TClass )
3481 };
3482 namespace
3483 {
3484 TClass TClass##AutomationSpecInstance( TEXT(#TClass) );
3485 }
3486
3487 //#define BEGIN_CUSTOM_COMPLEX_AUTOMATION_TEST( TClass, TBaseClass, PrettyName, TFlags ) \
3488 // BEGIN_COMPLEX_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, __FILE__, __LINE__)
3489 //
3490 //#define END_CUSTOM_COMPLEX_AUTOMATION_TEST( TClass ) \
3491 // BEGIN_COMPLEX_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, __FILE__, __LINE__)
3492 // namespace\
3493 // {\
3494 // TClass TClass##AutomationTestInstance( TEXT(#TClass) );\
3495 // }
3496
3497#else
3498 #define IMPLEMENT_SIMPLE_AUTOMATION_TEST( TClass, PrettyName, TFlags )
3499 IMPLEMENT_SIMPLE_AUTOMATION_TEST_PRIVATE(TClass, FAutomationTestBase, PrettyName, TFlags, __FILE__, __LINE__)
3500 #define IMPLEMENT_COMPLEX_AUTOMATION_TEST( TClass, PrettyName, TFlags )
3501 IMPLEMENT_COMPLEX_AUTOMATION_TEST_PRIVATE(TClass, FAutomationTestBase, PrettyName, TFlags, __FILE__, __LINE__)
3502 #define IMPLEMENT_NETWORKED_AUTOMATION_TEST(TClass, PrettyName, TFlags, NumParticipants)
3503 IMPLEMENT_NETWORKED_AUTOMATION_TEST_PRIVATE(TClass, FAutomationTestBase, PrettyName, TFlags, NumParticipants, __FILE__, __LINE__)
3504
3505 #define IMPLEMENT_CUSTOM_SIMPLE_AUTOMATION_TEST( TClass, TBaseClass, PrettyName, TFlags )
3506 IMPLEMENT_SIMPLE_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, __FILE__, __LINE__)
3507 #define IMPLEMENT_CUSTOM_COMPLEX_AUTOMATION_TEST( TClass, TBaseClass, PrettyName, TFlags )
3508 IMPLEMENT_COMPLEX_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, __FILE__, __LINE__)
3509 #define IMPLEMENT_BDD_AUTOMATION_TEST(TClass, PrettyName, TFlags)
3510 IMPLEMENT_BDD_AUTOMATION_TEST_PRIVATE(TClass, PrettyName, TFlags, __FILE__, __LINE__)
3511 #define DEFINE_SPEC(TClass, PrettyName, TFlags)
3512 DEFINE_SPEC_PRIVATE(TClass, PrettyName, TFlags, __FILE__, __LINE__)
3513 #define BEGIN_DEFINE_SPEC(TClass, PrettyName, TFlags)
3514 BEGIN_DEFINE_SPEC_PRIVATE(TClass, PrettyName, TFlags, __FILE__, __LINE__)
3515 #define END_DEFINE_SPEC(TClass)
3516 };
3517
3518 //#define BEGIN_CUSTOM_COMPLEX_AUTOMATION_TEST( TClass, TBaseClass, PrettyName, TFlags ) \
3519 // BEGIN_CUSTOM_COMPLEX_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, __FILE__, __LINE__)
3520
3521 //#define END_CUSTOM_COMPLEX_AUTOMATION_TEST( TClass )
3522 // END_COMPLEX_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, __FILE__, __LINE__)
3523#endif // #if WITH_AUTOMATION_WORKER
3524
3525
3526/**
3527 * Macros to make it easy to test state with one-liners: they will run the appropriate
3528 * test method and, if the test fail, with execute `return false;`, which (if placed in
3529 * the main test case method) will stop the test immediately.
3530 *
3531 * The error logging is already handled by the test method being called.
3532 *
3533 * As a result, you can easily test things that, if wrong, would potentially crash the test:
3534 *
3535 * bool FMyEasyTest::RunTest(const FString& Parameters)
3536 * {
3537 * TArray<float> Data = GetSomeData();
3538 * int32 Index = GetSomeIndex();
3539 * UTEST_TRUE("Check valid index", Index < Data.Num());
3540 * float DataItem = Data[Index]; // Won't crash, the test exited on the previous
3541 * // line if index was invalid.
3542 * UTEST_TRUE("Check valid item", DataItem > 0.f);
3543 * }
3544 *
3545 */
3546
3547#define UTEST_EQUAL(What, Actual, Expected)
3548 if (!TestEqual(What, Actual, Expected))
3549 {
3550 return false;
3551 }
3552
3553#define UTEST_EQUAL_TOLERANCE(What, Actual, Expected, Tolerance)
3554 if (!TestEqual(What, Actual, Expected, Tolerance))
3555 {
3556 return false;
3557 }
3558
3559#define UTEST_EQUAL_INSENSITIVE(What, Actual, Expected)
3560 if (!TestEqualInsensitive(What, Actual, Expected))
3561 {
3562 return false;
3563 }
3564
3565#define UTEST_NOT_EQUAL(What, Actual, Expected)
3566 if (!TestNotEqual(What, Actual, Expected))
3567 {
3568 return false;
3569 }
3570
3571#define UTEST_SAME(What, Actual, Expected)
3572 if (!TestSame(What, Actual, Expected))
3573 {
3574 return false;
3575 }
3576
3577#define UTEST_NOT_SAME(What, Actual, Expected)
3578 if (!TestNotSame(What, Actual, Expected))
3579 {
3580 return false;
3581 }
3582
3583#define UTEST_TRUE(What, Value)
3584 if (!TestTrue(What, Value))
3585 {
3586 return false;
3587 }
3588
3589#define UTEST_FALSE(What, Value)
3590 if (!TestFalse(What, Value))
3591 {
3592 return false;
3593 }
3594
3595#define UTEST_VALID(What, SharedPointer)
3596 if (!TestValid(What, SharedPointer))
3597 {
3598 return false;
3599 }
3600
3601#define UTEST_INVALID(What, SharedPointer)
3602 if (!TestInvalid(What, SharedPointer))
3603 {
3604 return false;
3605 }
3606
3607#define UTEST_NULL(What, Pointer)
3608 if (!TestNull(What, Pointer))
3609 {
3610 return false;
3611 }
3612
3613#define UTEST_NOT_NULL(What, Pointer)
3614 if (!TestNotNull(What, Pointer))
3615 {
3616 return false;
3617 }
3618
3619//////////////////////////////////////////////////
3620// Basic Latent Commands
3621
3622/**
3623 * Run some code latently with a predicate lambda. If the predicate returns false, the latent action will be called
3624 * again next frame. If it returns true, the command will stop running.
3625 */
3627{
3628public:
3629 FFunctionLatentCommand(TFunction<bool()> InLatentPredicate)
3631 {
3632 }
3633
3635 {
3636 }
3637
3638 virtual bool Update() override
3639 {
3640 return LatentPredicate();
3641 }
3642
3643private:
3644 TFunction<bool()> LatentPredicate;
3645};
3646
3647
3649{
3650public:
3651 FDelayedFunctionLatentCommand(TFunction<void()> InCallback, float InDelay = 0.1f)
3653 , Delay(InDelay)
3654 {}
3655
3656 virtual bool Update() override
3657 {
3658 double NewTime = FPlatformTime::Seconds();
3659 if ( NewTime - StartTime >= Delay )
3660 {
3661 Callback();
3662 return true;
3663 }
3664 return false;
3665 }
3666
3667private:
3668 TFunction<void()> Callback;
3669 float Delay;
3670};
3671
3672
3674{
3675public:
3676 FUntilCommand(TFunction<bool()> InCallback, TFunction<bool()> InTimeoutCallback, float InTimeout = 5.0f)
3679 , Timeout(InTimeout)
3680 {}
3681
3682 virtual bool Update() override
3683 {
3684 if ( !Callback() )
3685 {
3686 const double NewTime = FPlatformTime::Seconds();
3687 if ( NewTime - StartTime >= Timeout )
3688 {
3689 TimeoutCallback();
3690 return true;
3691 }
3692
3693 return false;
3694 }
3695
3696 return true;
3697 }
3698
3699private:
3700 TFunction<bool()> Callback;
3701 TFunction<bool()> TimeoutCallback;
3702 float Timeout;
3703};
3704
3705// Extension of IAutomationLatentCommand with delays between attempts
3706// if initial command does not succeed. Has a max retry count that can be
3707// overridden. Default is 10 retries with a 1 second delay in between.
3708// To protect against misuse of unlimited retries, has a Max execution
3709// time of 5 minutes. This can be overridden, but not recommended. Only
3710// do this if you're absolutely certain it will not cause an infinite loop
3712{
3713public:
3715
3716 virtual void CommandFailedDueToError(const FString& ErrorMessage)
3717 {
3718 // Stop further commands and log error so the test fails.
3720 // Must log here so that Gauntlet can also pick up the error for its report. Otherwise, it will only show up in the Automation log.
3721 UE_LOG(LogLatentCommands, Error, TEXT("%s"), *ErrorMessage);
3722 GetCurrentTest()->AddError(ErrorMessage);
3723 }
3724
3725 // Base Update override with delay logic built in. Can be further overridden in child
3726 // classes
3727 virtual bool Update() override
3728 {
3730 {
3731 // command has unlimited retries, so need to check if max run time has been exceeded
3733 {
3734 // Command run time has exceeded max total run time.
3735 FString ErrorMessageText = FString::Printf(TEXT("%s has failed due to exceeding the max allowed run time of %f seconds. \
3736This may be due to an error, or having a single command attempt to do too many things. If this is not due to an error, consider breaking \
3737up this command into multiple, smaller commands."),*GetTestAndCommandName(),MaxTotalRunTimeInSeconds);
3738 CommandFailedDueToError(ErrorMessageText);
3739 return true;
3740 }
3741 }
3742
3744 {
3745 return false;
3746 }
3747
3748 // pre-increment iteration so that its 1 based instead of 0 based for readability
3750
3751 if (!CanRetry())
3752 {
3753 // Must log here so that Gauntlet can also pick up the error for its report. Otherwise, it will only show up in the Automation log.
3754 FString ErrorMessageText = FString::Printf(TEXT("%s Latent command with retries and delays has failed after %d retries"), *GetTestAndCommandName(), MaxRetries);
3755 CommandFailedDueToError(ErrorMessageText);
3756 return true;
3757 }
3758
3760
3761 // auto-logging for limited retries and unlimited retries
3763 {
3764 UE_LOG(LogLatentCommands, Log, TEXT("%s Executing Attempt %d."), *GetTestAndCommandName(), CurrentIteration);
3765 }
3766 else
3767 {
3768 UE_LOG(LogLatentCommands, Log, TEXT("%s Executing Attempt %d of %d."), *GetTestAndCommandName(), CurrentIteration, MaxRetries);
3769 }
3770
3771 if (Execute())
3772 {
3773 // completion log message, logs total time taken.
3774 UE_LOG(LogLatentCommands, Log, TEXT("%s Completed Successfully, total run time: %f seconds."), *GetTestAndCommandName(), GetCurrentRunTime());
3775
3776 return true;
3777 }
3778
3779 return false;
3780 }
3781
3782 // Pure virtual method that must be overridden.
3783 // This is the actual command logic.
3784 virtual bool Execute() = 0;
3785
3786private:
3787 // To keep track of which iteration we are on. 1 based
3788 // To allow for more readable logs. Attempt 1 of N instead
3789 // of 0 of N.
3791
3792protected:
3793 // default constructor
3795
3796 // parameterized constructor
3797 IAutomationLatentCommandWithRetriesAndDelays(const FString InCommandClassName, const int32 InMaxRetries, const double InWaitTimeBetweenRuns)
3799 , MaxRetries(InMaxRetries < 0 ? 0 : InMaxRetries)
3800 , bHasUnlimitedRetries(InMaxRetries == 0)
3801 , DelayTimeInSeconds(InWaitTimeBetweenRuns)
3802 {
3803 // set first run start time so that we don't start off in a delay. Its fine if its negative.
3804 DelayStartTime = FPlatformTime::Seconds() - InWaitTimeBetweenRuns;
3805
3806 // warn if command has unlimited retries MaxTotalRunTime
3808 {
3809 // Must log here so that Gauntlet can also pick up the error for its report. Otherwise, it will only show up in the Automation log.
3810 UE_LOG(LogLatentCommands, Warning, TEXT("%s has been set to Unlimited retries. Will be using MaxTotalRunTime to prevent \
3811running forever. Default time is set at 300 seconds. If this is not enough time, make sure to override this in your Execute() loop."),*GetTestAndCommandName());
3812 }
3813 }
3814
3815 // Resets the Delay Timer by setting start time to now (In game time).
3817 {
3819 }
3820
3821 // Determines if timer is running, pausing execution in a non-blocking way.
3823 {
3824 // time elapsed < Delay time
3826 }
3827
3828 // Returns if we have exceeded max allowed total run time for this latent command
3830 {
3832 }
3833
3834 // Determines if we should execute the command. If MaxRetries is set to 0,
3835 // indicates unlimited retries.
3836 bool CanRetry() const
3837 {
3838 return (CurrentIteration <= MaxRetries) || MaxRetries == 0;
3839 }
3840
3841 // Returns the command name
3843 {
3844 // Otherwise use the provided string
3845 return FString::Printf(TEXT("Test: %s - Command: %s - "), *GetCurrentTest()->GetTestFullName(), *CommandClassName);
3846 }
3847
3849 {
3851 }
3852
3853 void OverrideMaxTotalRunTimeInSeconds(double OverrideValue)
3854 {
3855 MaxTotalRunTimeInSeconds = OverrideValue;
3856 }
3857
3858 // Command Name stored for easy logging
3859 const FString CommandClassName = "UnknownCommand";
3860
3861 // Times to retry command before reporting command failure.
3862 // Defaults to 10, but can be overridden.
3863 const int32 MaxRetries = 10;
3864
3865 // Indicates that this latent command has unlimited retries
3866 // Used to implement the MaxTotalRunTimeInSeconds logic
3867 const bool bHasUnlimitedRetries = false;
3868
3869 // Time in between UpdateDelayed calls.
3870 // Default is 1 second but can be overridden.
3871 const double DelayTimeInSeconds = 1.0;
3872
3873 // Time that the Delay Timer started.
3874 double DelayStartTime = 0.0;
3875
3876private:
3877 // Max total run time for command
3878 // Default is 5 minutes, but can be overridden
3880
3881};
#define check(expr)
#define IMPLEMENT_BDD_AUTOMATION_TEST_PRIVATE(TClass, PrettyName, TFlags, FileName, LineNumber)
#define DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER(EXPORT_API, CommandName, ParamType, ParamName)
#define IMPLEMENT_COMPLEX_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, FileName, LineNumber)
#define DEFINE_SPEC_PRIVATE(TClass, PrettyName, TFlags, FileName, LineNumber)
#define SAFE_GETSTACK(VariableName, IgnoreCount, MaxDepth)
DEFINE_LOG_CATEGORY_STATIC(LogLatentCommands, Log, All)
#define DEFINE_EXPORTED_LATENT_AUTOMATION_COMMAND(EXPORT_API, CommandName)
#define IMPLEMENT_SIMPLE_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, FileName, LineNumber)
#define IMPLEMENT_NETWORKED_AUTOMATION_TEST_PRIVATE(TClass, TBaseClass, PrettyName, TFlags, NumParticipants, FileName, LineNumber)
#define BEGIN_DEFINE_SPEC_PRIVATE(TClass, PrettyName, TFlags, FileName, LineNumber)
#define WITH_AUTOMATION_WORKER
Definition Build.h:127
@ INDEX_NONE
#define UE_DEPRECATED(Version, Message)
#define DECLARE_MULTICAST_DELEGATE_TwoParams(DelegateName, Param1Type, Param2Type)
#define DECLARE_DELEGATE(DelegateName)
#define DECLARE_DELEGATE_TwoParams(DelegateName, Param1Type, Param2Type)
#define DECLARE_DELEGATE_ThreeParams(DelegateName, Param1Type, Param2Type, Param3Type)
#define DECLARE_MULTICAST_DELEGATE_OneParam(DelegateName, Param1Type)
EAutomationComparisonToleranceLevel
Definition Enums.h:9193
EAutomationEventType
Definition Enums.h:11562
#define LLM_SCOPE_BYNAME(...)
#define TEXT(x)
Definition Platform.h:1108
#define FORCEINLINE
Definition Platform.h:644
#define UE_KINDA_SMALL_NUMBER
FWindowsCriticalSection FCriticalSection
#define PLATFORM_64BITS
FWindowsPlatformTime FPlatformTime
FAsyncLatentCommand(FAutomationSpecBase *const InSpec, EAsyncExecution InExecution, TFunction< void()> InPredicate, const FTimespan &InTimeout, bool bInSkipIfErrored=false)
FAsyncUntilDoneLatentCommand(FAutomationSpecBase *const InSpec, EAsyncExecution InExecution, TFunction< void(const FDoneDelegate &)> InPredicate, const FTimespan &InTimeout, bool bInSkipIfErrored=false)
const TFunction< void(const FDoneDelegate &) Predicate)
FSingleExecuteLatentCommand(const FAutomationSpecBase *const InSpec, TFunction< void()> InPredicate, bool bInSkipIfErrored=false)
const TFunction< void(const FDoneDelegate &) Predicate)
FUntilDoneLatentCommand(FAutomationSpecBase *const InSpec, TFunction< void(const FDoneDelegate &)> InPredicate, const FTimespan &InTimeout, bool bInSkipIfErrored=false)
void xLatentIt(const FString &InDescription, const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
void xLatentBeforeEach(EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
void xIt(const FString &InDescription, EAsyncExecution Execution, TFunction< void()> DoWork)
void xLatentIt(const FString &InDescription, EAsyncExecution Execution, TFunction< void(const FDoneDelegate &)> DoWork)
virtual FString GetTestSourceFileName(const FString &InTestName) const override
void LatentIt(const FString &InDescription, EAsyncExecution Execution, TFunction< void(const FDoneDelegate &)> DoWork)
void xLatentIt(const FString &InDescription, TFunction< void(const FDoneDelegate &)> DoWork)
void LatentIt(const FString &InDescription, TFunction< void(const FDoneDelegate &)> DoWork)
void LatentAfterEach(TFunction< void(const FDoneDelegate &)> DoWork)
void xLatentIt(const FString &InDescription, EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
void LatentAfterEach(const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
void PopDescription(const FString &InDescription)
void xBeforeEach(EAsyncExecution Execution, TFunction< void()> DoWork)
void xLatentAfterEach(const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
void xIt(const FString &InDescription, TFunction< void()> DoWork)
void xLatentAfterEach(TFunction< void(const FDoneDelegate &)> DoWork)
void xLatentAfterEach(EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
FString GetDescription() const
void xLatentAfterEach(EAsyncExecution Execution, TFunction< void(const FDoneDelegate &)> DoWork)
TArray< FString > Description
void LatentBeforeEach(const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
void LatentAfterEach(EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
void xBeforeEach(TFunction< void()> DoWork)
FString GetId() const
FAutomationSpecBase(const FString &InName, const bool bInComplexTask)
void AfterEach(TFunction< void()> DoWork)
void BeforeEach(EAsyncExecution Execution, TFunction< void()> DoWork)
virtual int32 GetTestSourceFileLine(const FString &InTestName) const override
void LatentIt(const FString &InDescription, const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
void It(const FString &InDescription, TFunction< void()> DoWork)
TMap< FString, TSharedRef< FSpec > > IdToSpecMap
void EnsureDefinitions() const
void xAfterEach(EAsyncExecution Execution, TFunction< void()> DoWork)
void xAfterEach(EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void()> DoWork)
virtual void Define()=0
void AfterEach(EAsyncExecution Execution, TFunction< void()> DoWork)
void It(const FString &InDescription, EAsyncExecution Execution, TFunction< void()> DoWork)
void xLatentBeforeEach(const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
void xLatentBeforeEach(EAsyncExecution Execution, TFunction< void(const FDoneDelegate &)> DoWork)
void xIt(const FString &InDescription, EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void()> DoWork)
TSharedPtr< FSpecDefinitionScope > RootDefinitionScope
void LatentAfterEach(EAsyncExecution Execution, TFunction< void(const FDoneDelegate &)> DoWork)
void xBeforeEach(EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void()> DoWork)
virtual bool RunTest(const FString &InParameters) override
void xAfterEach(TFunction< void()> DoWork)
void PushDescription(const FString &InDescription)
void LatentIt(const FString &InDescription, EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
virtual uint32 GetRequiredDeviceNum() const override
void It(const FString &InDescription, EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void()> DoWork)
void LatentBeforeEach(TFunction< void(const FDoneDelegate &)> DoWork)
void LatentBeforeEach(EAsyncExecution Execution, TFunction< void(const FDoneDelegate &)> DoWork)
void xLatentBeforeEach(TFunction< void(const FDoneDelegate &)> DoWork)
void BeforeEach(EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void()> DoWork)
void LatentBeforeEach(EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void(const FDoneDelegate &)> DoWork)
virtual void GetTests(TArray< FString > &OutBeautifiedNames, TArray< FString > &OutTestCommands) const override
void AfterEach(EAsyncExecution Execution, const FTimespan &Timeout, TFunction< void()> DoWork)
virtual bool IsStressTest() const
TArray< TSharedRef< FSpecDefinitionScope > > DefinitionScopeStack
void BeforeEach(TFunction< void()> DoWork)
void Describe(const FString &InDescription, TFunction< void()> DoWork)
void xDescribe(const FString &InDescription, TFunction< void()> DoWork)
bool TestEqual(const TCHAR *What, const FString &Actual, const FString &Expected)
bool TestNull(const TCHAR *What, const void *Pointer)
bool TestEqual(const TCHAR *What, const int32 Actual, const int32 Expected)
virtual uint32 GetRequiredDeviceNum() const =0
bool TestEqual(const TCHAR *What, const FString &Actual, const TCHAR *Expected)
bool TestEqual(const TCHAR *What, const TCHAR *Actual, const FString &Expected)
bool TestNotEqual(const TCHAR *Description, const ValueType &Actual, const ValueType &Expected)
FAutomationTestExecutionInfo ExecutionInfo
virtual void AddTelemetryData(const FString &DataPoint, double Measurement, const FString &Context=TEXT(""))
bool TestNotSame(const TCHAR *Description, const ValueType &Actual, const ValueType &Expected)
bool TestSame(const FString &Description, const ValueType &Actual, const ValueType &Expected)
virtual bool SuppressLogWarnings()
TArray< FAutomationExpectedMessage > ExpectedMessages
bool HasMetExpectedMessages(ELogVerbosity::Type VerbosityType=ELogVerbosity::All)
virtual bool SuppressLogErrors()
FString GetTestContext() const
virtual FString GetBeautifiedTestName() const =0
bool TestEqual(const FString &What, const int32 Actual, const int32 Expected)
static bool LogCategoryMatchesSeverityInclusive(ELogVerbosity::Type Actual, ELogVerbosity::Type MaximumVerbosity)
virtual void SetTestContext(FString Context)
virtual void AddTelemetryData(const TMap< FString, double > &ValuePairs, const FString &Context=TEXT(""))
bool IsExpectedMessage(const FString &Message, const ELogVerbosity::Type &Verbosity=ELogVerbosity::All)
virtual FString GetTestSourceFileName() const
bool TestEqual(const TCHAR *What, const float Actual, const float Expected, float Tolerance=UE_KINDA_SMALL_NUMBER)
virtual void SetTelemetryStorage(const FString &StorageName)
FORCEINLINE void AddCommand(IAutomationLatentCommand *NewCommand)
bool TestNotSame(const FString &Description, const ValueType &Actual, const ValueType &Expected)
bool TestEqual(const TCHAR *What, const FColor Actual, const FColor Expected)
bool TestNotNull(const FString &What, const ValueType *Pointer)
const bool IsComplexTask() const
bool TestNull(const FString &What, const void *Pointer)
bool TestSame(const TCHAR *Description, const ValueType &Actual, const ValueType &Expected)
virtual void GetTests(TArray< FString > &OutBeautifiedNames, TArray< FString > &OutTestCommands) const =0
bool TestInvalid(const FString &Description, const TSharedPtr< ValueType > &SharedPointer)
bool GetLastExecutionSuccessState()
bool TestValid(const TCHAR *Description, const TSharedPtr< ValueType > &SharedPointer)
bool TestEqual(const TCHAR *What, const FVector Actual, const FVector Expected, float Tolerance=UE_KINDA_SMALL_NUMBER)
bool TestEqual(const FString &What, const double Actual, const double Expected, double Tolerance=UE_KINDA_SMALL_NUMBER)
virtual void AddEvent(const FAutomationEvent &InEvent, int32 StackOffset=0, bool bCaptureStack=false)
bool TestTrue(const FString &What, bool Value)
virtual bool RunTest(const FString &Parameters)=0
FString GetTestName() const
bool TestEqual(const FString &What, const TCHAR *Actual, const FString &Expected)
bool TestEqual(const TCHAR *What, const int64 Actual, const int64 Expected)
bool TestEqual(const FString &What, const FString &Actual, const FString &Expected)
virtual FString GetTestOpenCommand(const FString &Parameter) const
virtual void AddErrorS(const FString &InError, const FString &InFilename, int32 InLineNumber)
void GenerateTestNames(TArray< FAutomationTestInfo > &TestInfo) const
virtual int32 GetTestSourceFileLine(const FString &InTestName) const
virtual void AddAnalyticsItem(const FString &InAnalyticsItem)
const bool IsRanOnSeparateThread() const
bool TestEqual(const TCHAR *What, const FLinearColor Actual, const FLinearColor Expected)
bool TestEqual(const FString &What, const FColor Actual, const FColor Expected)
virtual FString GetTestSourceFileName(const FString &InTestName) const
bool TestTrue(const TCHAR *What, bool Value)
void GetExecutionInfo(FAutomationTestExecutionInfo &OutInfo) const
virtual bool SuppressLogs()
virtual FString GetTestAssetPath(const FString &Parameter) const
bool TestFalse(const FString &What, bool Value)
bool TestFalse(const TCHAR *What, bool Value)
bool TestEqual(const FString &What, const FVector Actual, const FVector Expected, float Tolerance=UE_KINDA_SMALL_NUMBER)
uint32 ExtractAutomationTestFlags(FString InTagNotation)
virtual int32 GetTestSourceFileLine() const
bool TestEqualInsensitive(const TCHAR *What, const TCHAR *Actual, const TCHAR *Expected)
void AddExpectedMessage(FString ExpectedPatternString, EAutomationExpectedMessageFlags::MatchType CompareType=EAutomationExpectedMessageFlags::Contains, int32 Occurrences=1)
FAutomationTestBase(const FString &InName, const bool bInComplexTask)
virtual void AddWarning(const FString &InWarning, int32 StackOffset=0)
void PushContext(const FString &Context)
bool TestEqual(const TCHAR *What, const FRotator Actual, const FRotator Expected, float Tolerance=UE_KINDA_SMALL_NUMBER)
bool TestEqual(const TCHAR *What, const ValueType &Actual, const ValueType &Expected)
bool TestEqual(const TCHAR *What, const TCHAR *Actual, const TCHAR *Expected)
void AddExpectedError(FString ExpectedPatternString, EAutomationExpectedErrorFlags::MatchType CompareType=EAutomationExpectedErrorFlags::Contains, int32 Occurrences=1)
virtual uint32 GetTestFlags() const =0
bool TestInvalid(const TCHAR *Description, const TSharedPtr< ValueType > &SharedPointer)
bool TestEqual(const FString &What, const FString &Actual, const TCHAR *Expected)
bool TestEqual(const FString &What, const FRotator Actual, const FRotator Expected, float Tolerance=UE_KINDA_SMALL_NUMBER)
bool HasAnyErrors() const
virtual void AddErrorIfFalse(bool bCondition, const FString &InError, int32 StackOffset=0)
virtual FString GetTestFullName() const
void AddExpectedMessage(FString ExpectedPatternString, ELogVerbosity::Type ExpectedVerbosity, EAutomationExpectedMessageFlags::MatchType CompareType=EAutomationExpectedMessageFlags::Contains, int32 Occurrences=1)
virtual void AddWarningS(const FString &InWarning, const FString &InFilename, int32 InLineNumber)
bool TestEqual(const FString &What, const ValueType &Actual, const ValueType &Expected)
void SetSuccessState(bool bSuccessful)
FORCEINLINE void AddCommand(IAutomationNetworkCommand *NewCommand)
bool TestEqual(const TCHAR *What, const double Actual, const double Expected, double Tolerance=UE_KINDA_SMALL_NUMBER)
bool TestNotEqual(const FString &Description, const ValueType &Actual, const ValueType &Expected)
FCriticalSection ActionCS
virtual void AddInfo(const FString &InLogItem, int32 StackOffset=0, bool bCaptureStack=false)
void GetExpectedMessages(TArray< FAutomationExpectedMessage > &OutInfo, ELogVerbosity::Type Verbosity=ELogVerbosity::All) const
virtual bool ElevateLogWarningsToErrors()
bool TestEqual(const TCHAR *What, const FTransform Actual, const FTransform Expected, float Tolerance=UE_KINDA_SMALL_NUMBER)
bool TestValid(const FString &Description, const TSharedPtr< ValueType > &SharedPointer)
virtual void AddError(const FString &InError, int32 StackOffset=0)
void InternalSetSuccessState(bool bSuccessful)
bool TestNotNull(const TCHAR *What, const ValueType *Pointer)
bool TestEqual(const FString &What, const float Actual, const float Expected, float Tolerance=UE_KINDA_SMALL_NUMBER)
bool TestEqual(const FString &What, const TCHAR *Actual, const TCHAR *Expected)
void PushContext(const FString &Context)
const FString & GetContext() const
TArray< FAutomationTelemetryData > TelemetryItems
void AddEvent(const FAutomationEvent &Event, int StackOffset=0, bool bCaptureStack=true)
void AddError(const FString &ErrorMessage)
TArray< FAutomationExecutionEntry > Entries
TArray< FString > AnalyticsItems
int32 RemoveAllEvents(EAutomationEventType EventType)
void AddWarning(const FString &WarningMessage)
const TArray< FAutomationExecutionEntry > & GetEntries() const
int32 RemoveAllEvents(TFunctionRef< bool(FAutomationEvent &)> FilterPredicate)
virtual void SerializeRecord(const UE::FLogRecord &Record) override
virtual void Serialize(const TCHAR *V, ELogVerbosity::Type Verbosity, const FName &Category) override
void SetCurrentAutomationTest(FAutomationTestBase *InAutomationTest)
void SetDestinationContext(FFeedbackContext *InDestinationContext)
virtual void Serialize(const TCHAR *V, ELogVerbosity::Type Verbosity, const FName &Category, double Time) override
virtual void Serialize(const TCHAR *V, ELogVerbosity::Type Verbosity, const class FName &Category) override
void SetCurrentAutomationTest(FAutomationTestBase *InAutomationTest)
FAutomationTestBase * CurrentTest
TQueue< TSharedPtr< IAutomationNetworkCommand > > NetworkCommands
bool IsLatentCommandQueueEmpty() const
void EnqueueNetworkCommand(TSharedPtr< IAutomationNetworkCommand > NewCommand)
static FAutomationTestFramework & GetInstance()
bool RegisterAutomationTest(const FString &InTestNameToRegister, FAutomationTestBase *InTestToRegister)
FOnTestDataRetrieved OnTestDataRetrieved
void GetValidTestNames(TArray< FAutomationTestInfo > &TestInfo) const
FOnTestScreenshotAndTraceCaptured TestScreenshotAndTraceCapturedDelegate
FSimpleMulticastDelegate PostTestingEvent
FString GetUserAutomationDirectory() const
void DumpAutomationTestExecutionInfo(const TMap< FString, FAutomationTestExecutionInfo > &InInfoToDump)
FAutomationTestOutputDevice AutomationTestOutputDevice
FOnTestScreenshotCaptured & OnScreenshotCaptured()
void NotifyPerformanceDataRetrieved(bool bSuccess, const FString &ErrorMessage)
FAutomationTestFramework(const FAutomationTestFramework &)
TMap< FString, FAutomationTestBase * > AutomationTestClassNameToInstanceMap
void SetForceSmokeTests(const bool bInForceSmokeTests)
void NotifyTestDataRetrieved(bool bWasNew, const FString &JsonData)
FSimpleMulticastDelegate PreTestingEvent
bool InternalStopTest(FAutomationTestExecutionInfo &OutExecutionInfo)
void NotifyScreenshotComparisonComplete(const FAutomationScreenshotCompareResults &CompareResults)
FAutomationTestMessageFilter AutomationTestMessageFilter
void EnqueueLatentCommand(TSharedPtr< IAutomationLatentCommand > NewCommand)
bool StopTest(FAutomationTestExecutionInfo &OutExecutionInfo)
FOnTestScreenshotComparisonComplete OnScreenshotCompared
FOnPerformanceDataRetrieved OnPerformanceDataRetrieved
FOnTestScreenshotAndTraceCaptured & OnScreenshotAndTraceCaptured()
void InternalStartTest(const FString &InTestToRun)
bool ContainsTest(const FString &InTestName) const
void SetDeveloperDirectoryIncluded(const bool bInDeveloperDirectoryIncluded)
static FAutomationTestFramework & Get()
void SetRequestedTestFilter(const uint32 InRequestedTestFlags)
void SetCaptureStack(bool bCapture)
void NotifyScreenshotTakenAndCompared()
TQueue< TSharedPtr< IAutomationLatentCommand > > LatentCommands
void StartTestByName(const FString &InTestToRun, const int32 InRoleIndex)
FOnTestScreenshotCaptured TestScreenshotCapturedDelegate
FSimpleMulticastDelegate OnScreenshotTakenAndCompared
FAutomationTestFramework & operator=(const FAutomationTestFramework &)
bool ShouldTestContent(const FString &Path) const
FFeedbackContext * OriginalGWarn
void AddAnalyticsItemToCurrentTest(const FString &AnalyticsItem)
FAutomationTestBase * GetCurrentTest() const
bool UnregisterAutomationTest(const FString &InTestNameToUnregister)
const int32 GetNumParticipantsRequired() const
FAutomationTestInfo(const FString &InDisplayName, const FString &InFullTestPath, const FString &InTestName, const uint32 InTestFlags, const int32 InNumParticipantsRequired, const FString &InParameterName=FString(), const FString &InSourceFile=FString(), int32 InSourceFileLine=0, const FString &InAssetPath=FString(), const FString &InOpenCommand=FString())
uint32 NumDevicesCurrentlyRunningTest
void AddTestFlags(const uint32 InTestFlags)
const FString & GetDisplayName() const
const FString GetOpenCommand() const
void InformOfNewDeviceRunningTest()
const FString GetTestParameter() const
void SetNumParticipantsRequired(int32 NumRequired)
const FString GetAssetPath() const
const FString GetSourceFile() const
const uint32 GetTestFlags() const
void SetDisplayName(const FString &InDisplayName)
const int32 GetSourceFileLine() const
const FString & GetFullTestPath() const
const int GetNumDevicesRunningTest() const
FString GetTestName() const
TArray< TFunction< void()> > BeforeEachStack
TArray< FString > Description
void PushDescription(const FString &InDescription)
void It(const FString &InDescription, TFunction< void()> DoWork)
TArray< TFunction< void()> > AfterEachStack
TArray< FString > TestCommands
void PopDescription(const FString &InDescription)
FBDDAutomationTestBase(const FString &InName, const bool bInComplexTask)
virtual void GetTests(TArray< FString > &OutBeautifiedNames, TArray< FString > &OutTestCommands) const override
void xIt(const FString &InDescription, TFunction< void()> DoWork)
virtual bool RunTest(const FString &Parameters) override
void Describe(const FString &InDescription, TFunction< void()> DoWork)
FString GetDescription() const
void xDescribe(const FString &InDescription, TFunction< void()> DoWork)
TArray< FString > BeautifiedNames
void BeforeEach(TFunction< void()> DoWork)
void AfterEach(TFunction< void()> DoWork)
virtual bool Update() override
FDelayedFunctionLatentCommand(TFunction< void()> InCallback, float InDelay=0.1f)
virtual bool Update() override
TFunction< bool()> LatentPredicate
FFunctionLatentCommand(TFunction< bool()> InLatentPredicate)
UE_NODISCARD FString RightChop(int32 Count) const &
ARK_API void RemoveAt(int32 Index, int32 Count=1, bool bAllowShrinking=true)
Definition String.cpp:484
FString()=default
UE_NODISCARD FORCEINLINE int32 Len() const
UE_NODISCARD FORCEINLINE const TCHAR * operator*() const UE_LIFETIMEBOUND
UE_NODISCARD FORCEINLINE bool IsEmpty() const
FThreadSafeBool(bool bValue=false)
FORCEINLINE bool operator=(bool bNewValue)
FThreadedAutomationLatentCommand(TUniqueFunction< void()> InFunction)
virtual bool Update() override
TUniqueFunction< void()> Function
FUntilCommand(TFunction< bool()> InCallback, TFunction< bool()> InTimeoutCallback, float InTimeout=5.0f)
virtual bool Update() override
TFunction< bool()> Callback
TFunction< bool()> TimeoutCallback
virtual bool Update()=0
double GetCurrentRunTime() const
IAutomationLatentCommandWithRetriesAndDelays(const FString InCommandClassName, const int32 InMaxRetries, const double InWaitTimeBetweenRuns)
void OverrideMaxTotalRunTimeInSeconds(double OverrideValue)
virtual void CommandFailedDueToError(const FString &ErrorMessage)
FAutomationTestBase * GetCurrentTest() const
virtual void Run()=0
virtual uint32 GetRoleIndex() const =0
const TCHAR * ToString(EAutomationExpectedMessageFlags::MatchType ThisType)
Definition Vector.h:40
Definition json.hpp:4518
static const Type FromString(FString Name)
static const TMap< FString, Type > & GetTestFlagsMap()
static FAutomationComparisonToleranceAmount FromToleranceLevel(EAutomationComparisonToleranceLevel InTolerance)
FAutomationComparisonToleranceAmount(uint8 R, uint8 G, uint8 B, uint8 A, uint8 InMinBrightness, uint8 InMaxBrightness)
FAutomationExpectedMessage(FString &InMessagePattern, ELogVerbosity::Type InVerbosity, EAutomationExpectedMessageFlags::MatchType InCompareType, int32 InExpectedNumberOfOccurrences=1)
FAutomationExpectedMessage(FString &InMessagePattern, ELogVerbosity::Type InVerbosity, int32 InExpectedNumberOfOccurrences)
ELogVerbosity::Type Verbosity
EAutomationExpectedMessageFlags::MatchType CompareType
FAutomationEvent ToAutomationEvent(const FString &ScreenhotName) const
TArray< TSharedRef< FSpecDefinitionScope > > Children
TArray< TSharedRef< IAutomationLatentCommand > > AfterEach
TArray< TSharedRef< IAutomationLatentCommand > > BeforeEach
TArray< TSharedRef< FSpecIt > > It
TArray< TSharedRef< IAutomationLatentCommand > > Commands
TSharedRef< IAutomationLatentCommand > Command
FSpecIt(FString InDescription, FString InId, FString InFilename, int32 InLineNumber, TSharedRef< IAutomationLatentCommand > InCommand)
FAutomationTelemetryData(const FString &InDataPoint, double InMeasurement, const FString &InContext)
bool operator>=(const FDateTime &Other) const
Definition DateTime.h:212
static FDateTime UtcNow()
FDateTime operator+(const FTimespan &Other) const
Definition DateTime.h:114
Definition Guid.h:108
FGuid()
Definition Guid.h:112
static FTimespan FromSeconds(double Seconds)
Definition Timespan.h:673
static FORCEINLINE double Seconds()