Files
UnrealEngine/Engine/Source/Programs/Online/OSSTestsCore/OnlineSubsystemCatchHelper.h
2025-05-18 13:04:45 +08:00

213 lines
7.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "TestHarness.h"
#include "TestDriver.h"
#include "CoreMinimal.h"
#include "Interfaces/OnlineIdentityInterface.h"
#include "Misc/ConfigCacheIni.h"
#include "Modules/ModuleManager.h"
#include "Containers/Ticker.h"
#include <catch2/catch_test_case_info.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
class FOnlineSubsystemFixtureInvoker : public Catch::ITestInvoker
{
public:
struct FReportingSkippableTags
{
TArray<FString> MayFailTags;
TArray<FString> ShouldFailTags;
TArray<FString> DisableTestTags;
};
struct FApplicableServicesConfig
{
FString Tag;
UE::Online::EOnlineServices ServicesType;
TArray<FString> ModulesToLoad;
};
struct FApplicableSubsystemConfig
{
FString Name;
};
enum class EDisableReason { Success, AgainstService, ExclusiveService, DisableTagPresence };
virtual void invoke() const = 0;
virtual Catch::Detail::unique_ptr<FOnlineSubsystemFixtureInvoker> clone() = 0;
void SetSubsystem(const FString& InStoredSubsystem);
// TODO: This should poll some info from the tags and generate the list based on that
static TArray<FApplicableServicesConfig> GetApplicableServices();
static TArray<FApplicableSubsystemConfig> GetApplicableSubsystems();
/*
* Helper function that calls CheckAllTagsIsIn(const TArray<FString>&, const TArray<FString>&);
*
* @param TestTags The array of test tags we wish to test against.
* @param RawTagString Comma seperated string of elemnets we wish to convert to an array.
*
* @return true if all elements of RawTagString prased as an comma sperated array is in TestTags.
*/
static bool CheckAllTagsIsIn(const TArray<FString>& TestTags, const FString& RawTagString);
/**
* Checks if every element of InputTags is in TestTags.
*
* @param TestTags The array of test tags we wish to test against.
* @param InputTags The array of tags we wish to see if all elements of are present in TestTags.
*
* @return true if all elements of InputTags is in TestTags.
*/
static bool CheckAllTagsIsIn(const TArray<FString>& TestTags, const TArray<FString>& InputTags);
static FString GenerateTags(const FString& ServiceName, const FReportingSkippableTags& SkippableTags, const TCHAR* InTag);
static EDisableReason ShouldDisableTest(const FString& ServiceName, const FReportingSkippableTags& SkippableTags, FString& InTag);
static EDisableReason ShouldSkipTest(const FString& ServiceName, const FReportingSkippableTags& SkippableTags, FString& InTag);
static bool IsRunningTestSkipOnTags(const FString& ServiceName, const FReportingSkippableTags& SkippableTags, FString& InTag);
protected:
FString StoredSubsystem;
};
template <typename C>
class TestInvokerFixture : public FOnlineSubsystemFixtureInvoker
{
public:
constexpr TestInvokerFixture(void (C::* InTestAsMethod)()) noexcept
: TestAsMethod(InTestAsMethod)
{
}
void PrepareTestCase() const
{
Fixture = Catch::Detail::make_unique<C>();
Fixture->ConstructInternal(StoredSubsystem);
}
void TearDownTestCase() const
{
Fixture.reset();
}
void invoke() const override
{
PrepareTestCase();
auto* f = Fixture.get();
(f->*TestAsMethod)();
TearDownTestCase();
}
Catch::Detail::unique_ptr<FOnlineSubsystemFixtureInvoker> clone() override
{
return Catch::Detail::unique_ptr<FOnlineSubsystemFixtureInvoker>(Catch::Detail::make_unique<TestInvokerFixture<C>>(TestAsMethod));
}
private:
void (C::* TestAsMethod)();
mutable Catch::Detail::unique_ptr<C> Fixture = nullptr;
};
template<typename C>
Catch::Detail::unique_ptr<FOnlineSubsystemFixtureInvoker> MakeTestInvokerFixture(void (C::* TestAsMethod)()) {
return Catch::Detail::make_unique<TestInvokerFixture<C>>(TestAsMethod);
}
class FOnlineSubsystemTestBaseFixture : public Catch::ITestInvoker
{
public:
void ConstructInternal(FString ServiceName);
virtual ~FOnlineSubsystemTestBaseFixture();
/* Loads all necessary services for the current test run */
static void LoadServiceModules();
/* Unloads all necessary services for the current test run */
static void UnloadServiceModules();
protected:
FOnlineSubsystemTestBaseFixture();
FString GetSubsystem() const;
IOnlineSubsystem* GetSubsystemPtr() const;
virtual void DestroyCurrentOnlineSubsystemModule() const;
#if OSSTESTS_USEEXTERNAUTH
TArray<FOnlineAccountCredentials> CustomCredentials(int32 TestAccountIndex, int32 NumUsers) const;
#endif // OSSTESTS_USEEXTERNAUTH
TArray<FOnlineAccountCredentials> GetIniCredentials(int32 TestAccountIndex) const;
TArray<FOnlineAccountCredentials> GetCredentials(int32 TestAccountIndex, int32 NumUsers) const;
/* Attempts to assign OutAccountId to what LocalUserId is logged in as. */
void AssignLoginUsers(int32 LocalUserNum, FUniqueNetIdPtr& OutAccountId) const;
FTestPipeline& GetLoginPipeline(uint32 NumUsersToLogin = 1, bool MultiLogin = false) const;
FTestPipeline& GetLoginPipeline(uint32 TestAccountIndex, std::initializer_list<std::reference_wrapper<FUniqueNetIdPtr>> AccountIds) const;
FTestPipeline& GetLoginPipeline(std::initializer_list<std::reference_wrapper<FUniqueNetIdPtr>> AccountIds) const;
FTestPipeline& GetPipeline() const;
/* Returns the ini login category name for the configured service */
FString GetLoginCredentialCategory() const;
void RunToCompletion(bool bLogout = true, bool bWaitBeforeLogout = false, const FTimespan TimeToWaitMilliseconds = FTimespan::FromMilliseconds(1000), const FString SubsystemInstanceName = TEXT("")) const;
/* ITestInvoker */
virtual void invoke() const override = 0;
private:
FString Tags;
FString Subsystem;
// Catch's ITestInvoker is a const interface but we'll be changing stuff (emplacing steps into the driver, setting flags, etc.) so we make these mutable
mutable FTestDriver Driver;
mutable FTestPipeline Pipeline;
mutable uint32 NumLocalUsers = -1;
mutable uint32 NumUsersToLogout = -1;
};
class FOnlineSubsystemAutoReg
{
public:
// This code is kept identical to Catch internals so that there is as little deviation from OSS_TESTS and Online_OSS_TESTS as possible
FOnlineSubsystemAutoReg(Catch::Detail::unique_ptr<FOnlineSubsystemFixtureInvoker> TestInvoker, Catch::SourceLineInfo LineInfo, const char* Name, const char* Tags, const char* AddlOnlineInfo);
};
TArray<TFunction<void()>>* GetGlobalInitalizers();
#define INTERNAL_ONLINESUBSYSTEM_TEST_CASE_NAMED_FIXTURE(RegName, ClassName, Name, Tags, ...)\
namespace {\
class PREPROCESSOR_JOIN(OnlineSubsystemTest_,RegName) : public ClassName {\
public:\
virtual void invoke() const override;\
void test();\
};\
FOnlineSubsystemAutoReg RegName( ::MakeTestInvokerFixture( PREPROCESSOR_JOIN(&OnlineSubsystemTest_,RegName)::test ), CATCH_INTERNAL_LINEINFO, Name, Tags, "");\
}\
void PREPROCESSOR_JOIN(OnlineSubsystemTest_,RegName)::test()\
{\
invoke();\
}\
void PREPROCESSOR_JOIN(OnlineSubsystemTest_,RegName)::invoke() const\
#define ONLINESUBSYSTEM_TEST_CASE_FIXTURE(ClassName, Name, Tags, ...) \
INTERNAL_ONLINESUBSYSTEM_TEST_CASE_NAMED_FIXTURE(INTERNAL_CATCH_UNIQUE_NAME(OnlineSubsystemRegistrar), ClassName, Name, Tags, __VA_ARGS__)
#define ONLINESUBSYSTEM_TEST_CASE(Name, Tags, ...) \
INTERNAL_ONLINESUBSYSTEM_TEST_CASE_NAMED_FIXTURE(INTERNAL_CATCH_UNIQUE_NAME(OnlineSubsystemRegistrar), FOnlineSubsystemTestBaseFixture, Name, Tags, __VA_ARGS__)
#define REQUIRE_OP(Op)\
CAPTURE(Op);\
REQUIRE(Op.WasSuccessful());