Add new plugins, refactor exp, introduce stat forge to replace GAS
This commit is contained in:
21
Plugins/SUDS/Source/SUDSTest/Private/SudsTestModule.cpp
Normal file
21
Plugins/SUDS/Source/SUDSTest/Private/SudsTestModule.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "SudsTestModule.h"
|
||||
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogSudsTestModule)
|
||||
|
||||
void FSudsTestModule::StartupModule()
|
||||
{
|
||||
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
|
||||
UE_LOG(LogSudsTestModule, Log, TEXT("SUDSTest Module Started"))
|
||||
}
|
||||
|
||||
void FSudsTestModule::ShutdownModule()
|
||||
{
|
||||
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
|
||||
// we call this function before unloading the module.
|
||||
UE_LOG(LogSudsTestModule, Log, TEXT("SUDSTest Module Stopped"))
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_MODULE(FSudsTestModule, SUDSTest)
|
||||
14
Plugins/SUDS/Source/SUDSTest/Private/SudsTestModule.h
Normal file
14
Plugins/SUDS/Source/SUDSTest/Private/SudsTestModule.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "Modules/ModuleInterface.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogSudsTestModule, All, All)
|
||||
|
||||
class FSudsTestModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
||||
274
Plugins/SUDS/Source/SUDSTest/Private/TestChoiceSpeakerLines.cpp
Normal file
274
Plugins/SUDS/Source/SUDSTest/Private/TestChoiceSpeakerLines.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
#include "SUDSDialogue.h"
|
||||
#include "SUDSLibrary.h"
|
||||
#include "SUDSMessageLogger.h"
|
||||
#include "SUDSScript.h"
|
||||
#include "SUDSScriptImporter.h"
|
||||
#include "TestParticipant.h"
|
||||
#include "TestUtils.h"
|
||||
#include "Misc/AutomationTest.h"
|
||||
|
||||
UE_DISABLE_OPTIMIZATION
|
||||
|
||||
const FString ChoicesAsSpeakerLineEnableInScriptInput = R"RAWSUD(
|
||||
===
|
||||
[importsetting GenerateSpeakerLinesFromChoices true]
|
||||
===
|
||||
Player: Hello
|
||||
* Choice 1
|
||||
NPC: I see
|
||||
* Choice 1a
|
||||
NPC: Sure
|
||||
*- Not a speaker line!
|
||||
Player: I had to say this separately
|
||||
* Choice 2
|
||||
NPC: Totally
|
||||
|
||||
Player: The end
|
||||
)RAWSUD";
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestChoiceSpeakerLineInScript,
|
||||
"SUDSTest.TestChoiceSpeakerLineInScript",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestChoiceSpeakerLineInScript::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(ChoicesAsSpeakerLineEnableInScriptInput), ChoicesAsSpeakerLineEnableInScriptInput.Len(), "ChoicesAsSpeakerLineEnableInScriptInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
auto Participant = NewObject<UTestParticipant>();
|
||||
Participant->TestNumber = 0;
|
||||
Dlg->AddParticipant(Participant);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Line 1", Dlg, "Player", "Hello");
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), TEXT("Choice 1"));
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), TEXT("Choice 2"));
|
||||
const FText ChoiceText0 = Dlg->GetChoiceText(0);
|
||||
Dlg->Choose(0);
|
||||
// Confirm that we got the choice as a speaker line
|
||||
TestDialogueText(this, "Choice as speaker line 1", Dlg, "Player", "Choice 1");
|
||||
// Confirm that text ID is the same
|
||||
TestTrue("Text should be identical", ChoiceText0.IdenticalTo(Dlg->GetText(), ETextIdenticalModeFlags::DeepCompare));
|
||||
TestEqual("TextIDs should match", SUDS_GET_TEXT_KEY(ChoiceText0), SUDS_GET_TEXT_KEY(Dlg->GetText()));
|
||||
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Regular speaker line", Dlg, "NPC", "I see");
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), TEXT("Choice 1a"));
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), TEXT("Not a speaker line!"));
|
||||
|
||||
// Test choice which disables speaker line
|
||||
Dlg->Choose(1);
|
||||
TestDialogueText(this, "Regular speaker line", Dlg, "Player", "I had to say this separately");
|
||||
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const FString ChoicesAsSpeakerLineSetSpeakerIdInScriptInput = R"RAWSUD(
|
||||
===
|
||||
[importsetting GenerateSpeakerLinesFromChoices true]
|
||||
[importsetting SpeakerIDForGeneratedLinesFromChoices `TheDude`]
|
||||
===
|
||||
Player: Hello
|
||||
* Choice 1
|
||||
NPC: You said that choice
|
||||
* Choice 2
|
||||
NPC: Also that one
|
||||
Player: The end
|
||||
)RAWSUD";
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestChoiceSpeakerSetSpeakerIdInScriptInput,
|
||||
"SUDSTest.TestChoiceSpeakerSetSpeakerIdInScriptInput",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestChoiceSpeakerSetSpeakerIdInScriptInput::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(ChoicesAsSpeakerLineSetSpeakerIdInScriptInput), ChoicesAsSpeakerLineSetSpeakerIdInScriptInput.Len(), "ChoicesAsSpeakerLineSetSpeakerIdInScriptInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
auto Participant = NewObject<UTestParticipant>();
|
||||
Participant->TestNumber = 0;
|
||||
Dlg->AddParticipant(Participant);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Line 1", Dlg, "Player", "Hello");
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), TEXT("Choice 1"));
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), TEXT("Choice 2"));
|
||||
const FText ChoiceText0 = Dlg->GetChoiceText(0);
|
||||
Dlg->Choose(0);
|
||||
// Confirm that text ID is the same
|
||||
TestTrue("Text should be identical", ChoiceText0.IdenticalTo(Dlg->GetText(), ETextIdenticalModeFlags::DeepCompare));
|
||||
TestEqual("TextIDs should match", SUDS_GET_TEXT_KEY(ChoiceText0), SUDS_GET_TEXT_KEY(Dlg->GetText()));
|
||||
|
||||
// Confirm that we got the choice as a speaker line, with custom speaker ID
|
||||
TestDialogueText(this, "Choice as speaker line 1", Dlg, "TheDude", "Choice 1");
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Regular speaker line", Dlg, "NPC", "You said that choice");
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
const FString ChoicesAsSpeakerLineChainChoiceInput = R"RAWSUD(
|
||||
===
|
||||
[importsetting GenerateSpeakerLinesFromChoices true]
|
||||
===
|
||||
Player: Hello
|
||||
* Choice 1
|
||||
* Choice 1a
|
||||
NPC: Hey this worked
|
||||
* Choice 1b
|
||||
* Choice 2
|
||||
NPC: Also that one
|
||||
Player: The end
|
||||
)RAWSUD";
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestChoiceSpeakerChainedChoiceInput,
|
||||
"SUDSTest.TestChoiceSpeakerChainedChoiceInput",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestChoiceSpeakerChainedChoiceInput::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(ChoicesAsSpeakerLineChainChoiceInput), ChoicesAsSpeakerLineChainChoiceInput.Len(), "ChoicesAsSpeakerLineChainChoiceInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
auto Participant = NewObject<UTestParticipant>();
|
||||
Participant->TestNumber = 0;
|
||||
Dlg->AddParticipant(Participant);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Line 1", Dlg, "Player", "Hello");
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), TEXT("Choice 1"));
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), TEXT("Choice 2"));
|
||||
Dlg->Choose(0);
|
||||
// Confirm that we got the choice as a speaker line, with custom speaker ID
|
||||
TestDialogueText(this, "Choice as speaker line 1", Dlg, "Player", "Choice 1");
|
||||
TestEqual("Choice 2nd level text", Dlg->GetChoiceText(0).ToString(), TEXT("Choice 1a"));
|
||||
TestEqual("Choice 2nd leveltext", Dlg->GetChoiceText(1).ToString(), TEXT("Choice 1b"));
|
||||
Dlg->Choose(0);
|
||||
TestDialogueText(this, "Choice as speaker line 1", Dlg, "Player", "Choice 1a");
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Regular speaker line", Dlg, "NPC", "Hey this worked");
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
const FString ChoicesAsSpeakerLineWithStringKeysInput = R"RAWSUD(
|
||||
===
|
||||
[importsetting GenerateSpeakerLinesFromChoices true]
|
||||
===
|
||||
Player: Hello @0012@
|
||||
* Choice 1 @0016@
|
||||
NPC: I see @0017@
|
||||
* Choice 1a @0018@
|
||||
NPC: Sure
|
||||
*- Not a speaker line!
|
||||
Player: I had to say this separately
|
||||
* Choice 2
|
||||
NPC: Totally
|
||||
|
||||
Player: The end
|
||||
)RAWSUD";
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestChoicesAsSpeakerLineWithStringKeys,
|
||||
"SUDSTest.TestChoicesAsSpeakerLineWithStringKeys",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestChoicesAsSpeakerLineWithStringKeys::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(ChoicesAsSpeakerLineWithStringKeysInput), ChoicesAsSpeakerLineWithStringKeysInput.Len(), "ChoicesAsSpeakerLineWithStringKeysInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
auto Participant = NewObject<UTestParticipant>();
|
||||
Participant->TestNumber = 0;
|
||||
Dlg->AddParticipant(Participant);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Line 1", Dlg, "Player", "Hello");
|
||||
TestEqual("String key", SUDS_GET_TEXT_KEY(Dlg->GetText()), "@0012@");
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), TEXT("Choice 1"));
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), TEXT("Choice 2"));
|
||||
TestEqual("String key", SUDS_GET_TEXT_KEY(Dlg->GetChoiceText(0)), "@0016@");
|
||||
FText ChoiceText0 = Dlg->GetChoiceText(0);
|
||||
Dlg->Choose(0);
|
||||
// Confirm that we got the choice as a speaker line
|
||||
TestDialogueText(this, "Choice as speaker line 1", Dlg, "Player", "Choice 1");
|
||||
// Confirm that text ID is the same
|
||||
TestTrue("Text should be identical", ChoiceText0.IdenticalTo(Dlg->GetText(), ETextIdenticalModeFlags::DeepCompare));
|
||||
TestEqual("TextIDs should match", SUDS_GET_TEXT_KEY(ChoiceText0), SUDS_GET_TEXT_KEY(Dlg->GetText()));
|
||||
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Regular speaker line", Dlg, "NPC", "I see");
|
||||
TestEqual("String key", SUDS_GET_TEXT_KEY(Dlg->GetText()), "@0017@");
|
||||
TestEqual("String key", SUDS_GET_TEXT_KEY(Dlg->GetChoiceText(0)), "@0018@");
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), TEXT("Choice 1a"));
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), TEXT("Not a speaker line!"));
|
||||
|
||||
ChoiceText0 = Dlg->GetChoiceText(0);
|
||||
Dlg->Choose(0);
|
||||
TestDialogueText(this, "Duplicated speaker line", Dlg, "Player", "Choice 1a");
|
||||
|
||||
// Confirm that text ID is the same
|
||||
TestTrue("Text should be identical", ChoiceText0.IdenticalTo(Dlg->GetText(), ETextIdenticalModeFlags::DeepCompare));
|
||||
TestEqual("TextIDs should match", SUDS_GET_TEXT_KEY(ChoiceText0), SUDS_GET_TEXT_KEY(Dlg->GetText()));
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
UE_ENABLE_OPTIMIZATION
|
||||
1045
Plugins/SUDS/Source/SUDSTest/Private/TestConditionals.cpp
Normal file
1045
Plugins/SUDS/Source/SUDSTest/Private/TestConditionals.cpp
Normal file
File diff suppressed because it is too large
Load Diff
20
Plugins/SUDS/Source/SUDSTest/Private/TestEventSub.cpp
Normal file
20
Plugins/SUDS/Source/SUDSTest/Private/TestEventSub.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "TestEventSub.h"
|
||||
|
||||
#include "SUDSDialogue.h"
|
||||
|
||||
void UTestEventSub::Init(USUDSDialogue* Dlg)
|
||||
{
|
||||
Dlg->OnEvent.AddDynamic(this, &UTestEventSub::OnEvent);
|
||||
Dlg->OnVariableChanged.AddDynamic(this, &UTestEventSub::OnVariableChanged);
|
||||
|
||||
}
|
||||
|
||||
void UTestEventSub::OnEvent(USUDSDialogue* Dlg, FName EventName, const TArray<FSUDSValue>& Args)
|
||||
{
|
||||
EventRecords.Add(FEventRecord { EventName, Args });
|
||||
}
|
||||
|
||||
void UTestEventSub::OnVariableChanged(USUDSDialogue* Dlg, FName VarName, const FSUDSValue& Value, bool bFromScript)
|
||||
{
|
||||
SetVarRecords.Add(FSetVarRecord { VarName, Value, bFromScript });
|
||||
}
|
||||
39
Plugins/SUDS/Source/SUDSTest/Private/TestEventSub.h
Normal file
39
Plugins/SUDS/Source/SUDSTest/Private/TestEventSub.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "SUDSValue.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "TestEventSub.generated.h"
|
||||
|
||||
class USUDSDialogue;
|
||||
UCLASS()
|
||||
class SUDSTEST_API UTestEventSub : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
void Init(USUDSDialogue* Dlg);
|
||||
|
||||
struct FEventRecord
|
||||
{
|
||||
FName Name;
|
||||
TArray<FSUDSValue> Args;
|
||||
};
|
||||
struct FSetVarRecord
|
||||
{
|
||||
FName Name;
|
||||
FSUDSValue Value;
|
||||
bool bFromScript;
|
||||
};
|
||||
|
||||
TArray<FEventRecord> EventRecords;
|
||||
TArray<FSetVarRecord> SetVarRecords;
|
||||
|
||||
UFUNCTION()
|
||||
void OnEvent(USUDSDialogue* Dlg, FName EventName, const TArray<FSUDSValue>& Args);
|
||||
|
||||
UFUNCTION()
|
||||
void OnVariableChanged(USUDSDialogue* Dlg, FName VarName, const FSUDSValue& Value, bool bFromScript);
|
||||
|
||||
|
||||
};
|
||||
278
Plugins/SUDS/Source/SUDSTest/Private/TestEvents.cpp
Normal file
278
Plugins/SUDS/Source/SUDSTest/Private/TestEvents.cpp
Normal file
@@ -0,0 +1,278 @@
|
||||
#include "SUDSDialogue.h"
|
||||
#include "SUDSLibrary.h"
|
||||
#include "SUDSMessageLogger.h"
|
||||
#include "SUDSScript.h"
|
||||
#include "SUDSScriptImporter.h"
|
||||
#include "TestEventSub.h"
|
||||
#include "TestParticipant.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
UE_DISABLE_OPTIMIZATION
|
||||
|
||||
const FString EventParsingInput = R"RAWSUD(
|
||||
Player: Ow do?
|
||||
[set IntVar 2]
|
||||
[set FloatVar 66.67]
|
||||
[set StringVar "Ey up"]
|
||||
[event SummatHappened "2 penneth", 99.99, masculine, {IntVar}, 42, false]
|
||||
NPC: Alreet chook
|
||||
[event Well.Blow.Me.Down {FloatVar}, true, {StringVar}]
|
||||
[event Calculated {FloatVar} + 10, true or false, {StringVar}]
|
||||
[event Actor.Emote `Player`, `Question`]
|
||||
Player: Tara
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestEvents,
|
||||
"SUDSTest.TestEvents",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
bool FTestEvents::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(EventParsingInput), EventParsingInput.Len(), "EventParsingInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
|
||||
// Subscriber
|
||||
auto EvtSub = NewObject<UTestEventSub>();
|
||||
EvtSub->Init(Dlg);
|
||||
|
||||
// Participant
|
||||
auto Participant = NewObject<UTestParticipant>();
|
||||
Participant->TestNumber = 0;
|
||||
Dlg->AddParticipant(Participant);
|
||||
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Line 1", Dlg, "Player", "Ow do?");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
// Should have had an event
|
||||
if (TestEqual("Event sub should have received", EvtSub->EventRecords.Num(), 1))
|
||||
{
|
||||
TestEqual("Event name", EvtSub->EventRecords[0].Name.ToString(), "SummatHappened");
|
||||
if (TestEqual("Event sub arg count", EvtSub->EventRecords[0].Args.Num(), 6))
|
||||
{
|
||||
TestEqual("Event sub arg 0 type", EvtSub->EventRecords[0].Args[0].GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Event sub arg 0 value", EvtSub->EventRecords[0].Args[0].GetTextValue().ToString(), "2 penneth");
|
||||
TestEqual("Event sub arg 1 type", EvtSub->EventRecords[0].Args[1].GetType(), ESUDSValueType::Float);
|
||||
TestEqual("Event sub arg 1 value", EvtSub->EventRecords[0].Args[1].GetFloatValue(), 99.99f);
|
||||
TestEqual("Event sub arg 2 type", EvtSub->EventRecords[0].Args[2].GetType(), ESUDSValueType::Gender);
|
||||
TestEqual("Event sub arg 2 value", EvtSub->EventRecords[0].Args[2].GetGenderValue(), ETextGender::Masculine);
|
||||
TestEqual("Event sub arg 3 type", EvtSub->EventRecords[0].Args[3].GetType(), ESUDSValueType::Int);
|
||||
TestEqual("Event sub arg 3 value", EvtSub->EventRecords[0].Args[3].GetIntValue(), 2);
|
||||
TestEqual("Event sub arg 4 type", EvtSub->EventRecords[0].Args[4].GetType(), ESUDSValueType::Int);
|
||||
TestEqual("Event sub arg 4 value", EvtSub->EventRecords[0].Args[4].GetIntValue(), 42);
|
||||
TestEqual("Event sub arg 5 type", EvtSub->EventRecords[0].Args[5].GetType(), ESUDSValueType::Boolean);
|
||||
TestEqual("Event sub arg 5 value", EvtSub->EventRecords[0].Args[5].GetBooleanValue(), false);
|
||||
}
|
||||
}
|
||||
if (TestEqual("Participant should have received", Participant->EventRecords.Num(), 1))
|
||||
{
|
||||
TestEqual("Event name", Participant->EventRecords[0].Name.ToString(), "SummatHappened");
|
||||
if (TestEqual("Participant arg count", Participant->EventRecords[0].Args.Num(), 6))
|
||||
{
|
||||
TestEqual("Participant arg 0 type", Participant->EventRecords[0].Args[0].GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Participant arg 0 value", Participant->EventRecords[0].Args[0].GetTextValue().ToString(), "2 penneth");
|
||||
TestEqual("Participant arg 1 type", Participant->EventRecords[0].Args[1].GetType(), ESUDSValueType::Float);
|
||||
TestEqual("Participant arg 1 value", Participant->EventRecords[0].Args[1].GetFloatValue(), 99.99f);
|
||||
TestEqual("Participant arg 2 type", Participant->EventRecords[0].Args[2].GetType(), ESUDSValueType::Gender);
|
||||
TestEqual("Participant arg 2 value", Participant->EventRecords[0].Args[2].GetGenderValue(), ETextGender::Masculine);
|
||||
TestEqual("Participant arg 3 type", Participant->EventRecords[0].Args[3].GetType(), ESUDSValueType::Int);
|
||||
TestEqual("Participant arg 3 value", Participant->EventRecords[0].Args[3].GetIntValue(), 2);
|
||||
TestEqual("Participant arg 4 type", Participant->EventRecords[0].Args[4].GetType(), ESUDSValueType::Int);
|
||||
TestEqual("Participant arg 4 value", Participant->EventRecords[0].Args[4].GetIntValue(), 42);
|
||||
TestEqual("Participant arg 5 type", Participant->EventRecords[0].Args[5].GetType(), ESUDSValueType::Boolean);
|
||||
TestEqual("Participant arg 5 value", Participant->EventRecords[0].Args[5].GetBooleanValue(), false);
|
||||
|
||||
}
|
||||
}
|
||||
if (TestEqual("Event var sub should have received", EvtSub->SetVarRecords.Num(), 10))
|
||||
{
|
||||
// First 7 are from the participant setting variables at startup
|
||||
TestEqual("Event var sub arg 0 name", EvtSub->SetVarRecords[0].Name.ToString(), "SpeakerName.Player");
|
||||
TestEqual("Event var sub arg 0 type", EvtSub->SetVarRecords[0].Value.GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Event var sub arg 0 value", EvtSub->SetVarRecords[0].Value.GetTextValue().ToString(), "Protagonist");
|
||||
TestFalse("Event var sub arg 0 fromscript", EvtSub->SetVarRecords[0].bFromScript);
|
||||
|
||||
TestEqual("Event var sub arg 1 name", EvtSub->SetVarRecords[1].Name.ToString(), "SpeakerName.NPC");
|
||||
TestEqual("Event var sub arg 1 type", EvtSub->SetVarRecords[1].Value.GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Event var sub arg 1 value", EvtSub->SetVarRecords[1].Value.GetTextValue().ToString(), "An NPC");
|
||||
TestFalse("Event var sub arg 1 fromscript", EvtSub->SetVarRecords[1].bFromScript);
|
||||
|
||||
TestEqual("Event var sub arg 2 name", EvtSub->SetVarRecords[2].Name.ToString(), "NumCats");
|
||||
TestEqual("Event var sub arg 2 type", EvtSub->SetVarRecords[2].Value.GetType(), ESUDSValueType::Int);
|
||||
TestEqual("Event var sub arg 2 value", EvtSub->SetVarRecords[2].Value.GetIntValue(), 3);
|
||||
TestFalse("Event var sub arg 2 fromscript", EvtSub->SetVarRecords[2].bFromScript);
|
||||
|
||||
TestEqual("Event var sub arg 3 name", EvtSub->SetVarRecords[3].Name.ToString(), "FriendName");
|
||||
TestEqual("Event var sub arg 3 type", EvtSub->SetVarRecords[3].Value.GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Event var sub arg 3 value", EvtSub->SetVarRecords[3].Value.GetTextValue().ToString(), "Susan");
|
||||
TestFalse("Event var sub arg 3 fromscript", EvtSub->SetVarRecords[3].bFromScript);
|
||||
|
||||
TestEqual("Event var sub arg 4 name", EvtSub->SetVarRecords[4].Name.ToString(), "Gender");
|
||||
TestEqual("Event var sub arg 4 type", EvtSub->SetVarRecords[4].Value.GetType(), ESUDSValueType::Gender);
|
||||
TestEqual("Event var sub arg 4 value", EvtSub->SetVarRecords[4].Value.GetGenderValue(), ETextGender::Feminine);
|
||||
TestFalse("Event var sub arg 4 fromscript", EvtSub->SetVarRecords[4].bFromScript);
|
||||
|
||||
TestEqual("Event var sub arg 5 name", EvtSub->SetVarRecords[5].Name.ToString(), "FloatVal");
|
||||
TestEqual("Event var sub arg 5 type", EvtSub->SetVarRecords[5].Value.GetType(), ESUDSValueType::Float);
|
||||
TestEqual("Event var sub arg 5 value", EvtSub->SetVarRecords[5].Value.GetFloatValue(), 12.567f);
|
||||
TestFalse("Event var sub arg 5 fromscript", EvtSub->SetVarRecords[5].bFromScript);
|
||||
|
||||
TestEqual("Event var sub arg 6 name", EvtSub->SetVarRecords[6].Name.ToString(), "BoolVal");
|
||||
TestEqual("Event var sub arg 6 type", EvtSub->SetVarRecords[6].Value.GetType(), ESUDSValueType::Boolean);
|
||||
TestEqual("Event var sub arg 6 value", EvtSub->SetVarRecords[6].Value.GetBooleanValue(), true);
|
||||
TestFalse("Event var sub arg 6 fromscript", EvtSub->SetVarRecords[6].bFromScript);
|
||||
|
||||
// Next 3 are from script
|
||||
TestEqual("Event var sub arg 7 name", EvtSub->SetVarRecords[7].Name.ToString(), "IntVar");
|
||||
TestEqual("Event var sub arg 7 type", EvtSub->SetVarRecords[7].Value.GetType(), ESUDSValueType::Int);
|
||||
TestEqual("Event var sub arg 7 value", EvtSub->SetVarRecords[7].Value.GetIntValue(), 2);
|
||||
TestTrue("Event var sub arg 7 fromscript", EvtSub->SetVarRecords[7].bFromScript);
|
||||
|
||||
TestEqual("Event var sub arg 8 name", EvtSub->SetVarRecords[8].Name.ToString(), "FloatVar");
|
||||
TestEqual("Event var sub arg 8 type", EvtSub->SetVarRecords[8].Value.GetType(), ESUDSValueType::Float);
|
||||
TestEqual("Event var sub arg 8 value", EvtSub->SetVarRecords[8].Value.GetFloatValue(), 66.67f);
|
||||
TestTrue("Event var sub arg 8 fromscript", EvtSub->SetVarRecords[8].bFromScript);
|
||||
|
||||
TestEqual("Event var sub arg 9 name", EvtSub->SetVarRecords[9].Name.ToString(), "StringVar");
|
||||
TestEqual("Event var sub arg 9 type", EvtSub->SetVarRecords[9].Value.GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Event var sub arg 9 value", EvtSub->SetVarRecords[9].Value.GetTextValue().ToString(), "Ey up");
|
||||
TestTrue("Event var sub arg 9 fromscript", EvtSub->SetVarRecords[9].bFromScript);
|
||||
}
|
||||
if (TestEqual("Participant var should have received", Participant->SetVarRecords.Num(), 10))
|
||||
{
|
||||
// First 7 are from the participant setting variables at startup
|
||||
TestEqual("Participant var arg 0 name", Participant->SetVarRecords[0].Name.ToString(), "SpeakerName.Player");
|
||||
TestEqual("Participant var arg 0 type", Participant->SetVarRecords[0].Value.GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Participant var arg 0 value", Participant->SetVarRecords[0].Value.GetTextValue().ToString(), "Protagonist");
|
||||
TestFalse("Participant var arg 0 fromscript", Participant->SetVarRecords[0].bFromScript);
|
||||
|
||||
TestEqual("Participant var arg 1 name", Participant->SetVarRecords[1].Name.ToString(), "SpeakerName.NPC");
|
||||
TestEqual("Participant var arg 1 type", Participant->SetVarRecords[1].Value.GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Participant var arg 1 value", Participant->SetVarRecords[1].Value.GetTextValue().ToString(), "An NPC");
|
||||
TestFalse("Participant var arg 1 fromscript", Participant->SetVarRecords[1].bFromScript);
|
||||
|
||||
TestEqual("Participant var arg 2 name", Participant->SetVarRecords[2].Name.ToString(), "NumCats");
|
||||
TestEqual("Participant var arg 2 type", Participant->SetVarRecords[2].Value.GetType(), ESUDSValueType::Int);
|
||||
TestEqual("Participant var arg 2 value", Participant->SetVarRecords[2].Value.GetIntValue(), 3);
|
||||
TestFalse("Participant var arg 2 fromscript", Participant->SetVarRecords[2].bFromScript);
|
||||
|
||||
TestEqual("Participant var arg 3 name", Participant->SetVarRecords[3].Name.ToString(), "FriendName");
|
||||
TestEqual("Participant var arg 3 type", Participant->SetVarRecords[3].Value.GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Participant var arg 3 value", Participant->SetVarRecords[3].Value.GetTextValue().ToString(), "Susan");
|
||||
TestFalse("Participant var arg 3 fromscript", Participant->SetVarRecords[3].bFromScript);
|
||||
|
||||
TestEqual("Participant var arg 4 name", Participant->SetVarRecords[4].Name.ToString(), "Gender");
|
||||
TestEqual("Participant var arg 4 type", Participant->SetVarRecords[4].Value.GetType(), ESUDSValueType::Gender);
|
||||
TestEqual("Participant var arg 4 value", Participant->SetVarRecords[4].Value.GetGenderValue(), ETextGender::Feminine);
|
||||
TestFalse("Participant var arg 4 fromscript", Participant->SetVarRecords[4].bFromScript);
|
||||
|
||||
TestEqual("Participant var arg 5 name", Participant->SetVarRecords[5].Name.ToString(), "FloatVal");
|
||||
TestEqual("Participant var arg 5 type", Participant->SetVarRecords[5].Value.GetType(), ESUDSValueType::Float);
|
||||
TestEqual("Participant var arg 5 value", Participant->SetVarRecords[5].Value.GetFloatValue(), 12.567f);
|
||||
TestFalse("Participant var arg 5 fromscript", Participant->SetVarRecords[5].bFromScript);
|
||||
|
||||
TestEqual("Participant var arg 6 name", Participant->SetVarRecords[6].Name.ToString(), "BoolVal");
|
||||
TestEqual("Participant var arg 6 type", Participant->SetVarRecords[6].Value.GetType(), ESUDSValueType::Boolean);
|
||||
TestEqual("Participant var arg 6 value", Participant->SetVarRecords[6].Value.GetBooleanValue(), true);
|
||||
TestFalse("Participant var arg 6 fromscript", Participant->SetVarRecords[6].bFromScript);
|
||||
|
||||
// Next 3 are from script
|
||||
TestEqual("Participant var arg 7 name", Participant->SetVarRecords[7].Name.ToString(), "IntVar");
|
||||
TestEqual("Participant var arg 7 type", Participant->SetVarRecords[7].Value.GetType(), ESUDSValueType::Int);
|
||||
TestEqual("Participant var arg 7 value", Participant->SetVarRecords[7].Value.GetIntValue(), 2);
|
||||
TestTrue("Participant var arg 7 fromscript", Participant->SetVarRecords[7].bFromScript);
|
||||
|
||||
TestEqual("Participant var arg 8 name", Participant->SetVarRecords[8].Name.ToString(), "FloatVar");
|
||||
TestEqual("Participant var arg 8 type", Participant->SetVarRecords[8].Value.GetType(), ESUDSValueType::Float);
|
||||
TestEqual("Participant var arg 8 value", Participant->SetVarRecords[8].Value.GetFloatValue(), 66.67f);
|
||||
TestTrue("Participant var arg 8 fromscript", Participant->SetVarRecords[8].bFromScript);
|
||||
|
||||
TestEqual("Participant var arg 9 name", Participant->SetVarRecords[9].Name.ToString(), "StringVar");
|
||||
TestEqual("Participant var arg 9 type", Participant->SetVarRecords[9].Value.GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Participant var arg 9 value", Participant->SetVarRecords[9].Value.GetTextValue().ToString(), "Ey up");
|
||||
TestTrue("Participant var arg 9 fromscript", Participant->SetVarRecords[9].bFromScript);
|
||||
}
|
||||
|
||||
TestDialogueText(this, "Line 2", Dlg, "NPC", "Alreet chook");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
if (TestEqual("Event sub should have received", EvtSub->EventRecords.Num(), 4))
|
||||
{
|
||||
TestEqual("Event name", EvtSub->EventRecords[1].Name.ToString(), "Well.Blow.Me.Down");
|
||||
if (TestEqual("Event sub arg count", EvtSub->EventRecords[1].Args.Num(), 3))
|
||||
{
|
||||
TestEqual("Event sub arg 0 type", EvtSub->EventRecords[1].Args[0].GetType(), ESUDSValueType::Float);
|
||||
TestEqual("Event sub arg 0 value", EvtSub->EventRecords[1].Args[0].GetFloatValue(), 66.67f);
|
||||
TestEqual("Event sub arg 1 type", EvtSub->EventRecords[1].Args[1].GetType(), ESUDSValueType::Boolean);
|
||||
TestEqual("Event sub arg 1 value", EvtSub->EventRecords[1].Args[1].GetBooleanValue(), true);
|
||||
TestEqual("Event sub arg 2 type", EvtSub->EventRecords[1].Args[2].GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Event sub arg 2 value", EvtSub->EventRecords[1].Args[2].GetTextValue().ToString(), "Ey up");
|
||||
}
|
||||
TestEqual("Event name", EvtSub->EventRecords[2].Name.ToString(), "Calculated");
|
||||
if (TestEqual("Event sub arg count", EvtSub->EventRecords[2].Args.Num(), 3))
|
||||
{
|
||||
TestEqual("Event sub arg 0 type", EvtSub->EventRecords[2].Args[0].GetType(), ESUDSValueType::Float);
|
||||
TestEqual("Event sub arg 0 value", EvtSub->EventRecords[2].Args[0].GetFloatValue(), 76.67f);
|
||||
TestEqual("Event sub arg 2 type", EvtSub->EventRecords[2].Args[1].GetType(), ESUDSValueType::Boolean);
|
||||
TestEqual("Event sub arg 2 value", EvtSub->EventRecords[2].Args[1].GetBooleanValue(), true);
|
||||
TestEqual("Event sub arg 2 type", EvtSub->EventRecords[2].Args[2].GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Event sub arg 2 value", EvtSub->EventRecords[2].Args[2].GetTextValue().ToString(), "Ey up");
|
||||
}
|
||||
TestEqual("Event name", EvtSub->EventRecords[3].Name.ToString(), "Actor.Emote");
|
||||
if (TestEqual("Event sub arg count", EvtSub->EventRecords[3].Args.Num(), 2))
|
||||
{
|
||||
TestEqual("Event sub arg 0 type", EvtSub->EventRecords[3].Args[0].GetType(), ESUDSValueType::Name);
|
||||
TestEqual("Event sub arg 0 value", EvtSub->EventRecords[3].Args[0].GetNameValue(), FName("Player"));
|
||||
TestEqual("Event sub arg 2 type", EvtSub->EventRecords[3].Args[1].GetType(), ESUDSValueType::Name);
|
||||
TestEqual("Event sub arg 2 value", EvtSub->EventRecords[3].Args[1].GetNameValue(), FName("Question"));
|
||||
}
|
||||
}
|
||||
if (TestEqual("Participant should have received", Participant->EventRecords.Num(), 4))
|
||||
{
|
||||
TestEqual("Event name", Participant->EventRecords[1].Name.ToString(), "Well.Blow.Me.Down");
|
||||
if (TestEqual("Participant arg count", Participant->EventRecords[1].Args.Num(), 3))
|
||||
{
|
||||
TestEqual("Participant arg 0 type", Participant->EventRecords[1].Args[0].GetType(), ESUDSValueType::Float);
|
||||
TestEqual("Participant arg 0 value", Participant->EventRecords[1].Args[0].GetFloatValue(), 66.67f);
|
||||
TestEqual("Participant arg 1 type", Participant->EventRecords[1].Args[1].GetType(), ESUDSValueType::Boolean);
|
||||
TestEqual("Participant arg 1 value", Participant->EventRecords[1].Args[1].GetBooleanValue(), true);
|
||||
TestEqual("Participant arg 2 type", Participant->EventRecords[1].Args[2].GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Participant arg 2 value", Participant->EventRecords[1].Args[2].GetTextValue().ToString(), "Ey up");
|
||||
}
|
||||
TestEqual("Event name", Participant->EventRecords[2].Name.ToString(), "Calculated");
|
||||
if (TestEqual("Event sub arg count", Participant->EventRecords[2].Args.Num(), 3))
|
||||
{
|
||||
TestEqual("Event sub arg 0 type", Participant->EventRecords[2].Args[0].GetType(), ESUDSValueType::Float);
|
||||
TestEqual("Event sub arg 0 value", Participant->EventRecords[2].Args[0].GetFloatValue(), 76.67f);
|
||||
TestEqual("Event sub arg 2 type", Participant->EventRecords[2].Args[1].GetType(), ESUDSValueType::Boolean);
|
||||
TestEqual("Event sub arg 2 value", Participant->EventRecords[2].Args[1].GetBooleanValue(), true);
|
||||
TestEqual("Event sub arg 2 type", Participant->EventRecords[2].Args[2].GetType(), ESUDSValueType::Text);
|
||||
TestEqual("Event sub arg 2 value", Participant->EventRecords[2].Args[2].GetTextValue().ToString(), "Ey up");
|
||||
}
|
||||
TestEqual("Event name", EvtSub->EventRecords[3].Name.ToString(), "Actor.Emote");
|
||||
if (TestEqual("Event sub arg count", EvtSub->EventRecords[3].Args.Num(), 2))
|
||||
{
|
||||
TestEqual("Event sub arg 0 type", EvtSub->EventRecords[3].Args[0].GetType(), ESUDSValueType::Name);
|
||||
TestEqual("Event sub arg 0 value", EvtSub->EventRecords[3].Args[0].GetNameValue(), FName("Player"));
|
||||
TestEqual("Event sub arg 2 type", EvtSub->EventRecords[3].Args[1].GetType(), ESUDSValueType::Name);
|
||||
TestEqual("Event sub arg 2 value", EvtSub->EventRecords[3].Args[1].GetNameValue(), FName("Question"));
|
||||
}
|
||||
}
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
UE_ENABLE_OPTIMIZATION
|
||||
209
Plugins/SUDS/Source/SUDSTest/Private/TestExpressions.cpp
Normal file
209
Plugins/SUDS/Source/SUDSTest/Private/TestExpressions.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
#include "SUDSExpression.h"
|
||||
#include "Misc/AutomationTest.h"
|
||||
|
||||
UE_DISABLE_OPTIMIZATION
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestExpressions,
|
||||
"SUDSTest.TestExpressions",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestExpressions::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSExpression Expr;
|
||||
TMap<FName, FSUDSValue> Variables;
|
||||
TMap<FName, FSUDSValue> GlobalVariables;
|
||||
|
||||
Variables.Add("Six", 6);
|
||||
TestTrue("SimpleVarParse", Expr.ParseFromString("3 + 4 * {Six} + 1", nullptr));
|
||||
TestEqual("Eval", Expr.Evaluate(Variables, GlobalVariables).GetIntValue(), 28);
|
||||
|
||||
auto& RPN = Expr.GetQueue();
|
||||
if (TestEqual("Queue len", RPN.Num(), 7))
|
||||
{
|
||||
// RPN should be 3 4 6 * + 1 +
|
||||
TestEqual("Queue 0", RPN[0].GetOperandValue().GetIntValue(), 3);
|
||||
TestEqual("Queue 1", RPN[1].GetOperandValue().GetIntValue(), 4);
|
||||
TestEqual("Queue 2", RPN[2].GetOperandValue().GetVariableNameValue().ToString(), "Six");
|
||||
TestEqual("Queue 3", RPN[3].GetType(), ESUDSExpressionItemType::Multiply);
|
||||
TestEqual("Queue 4", RPN[4].GetType(), ESUDSExpressionItemType::Add);
|
||||
TestEqual("Queue 5", RPN[5].GetOperandValue().GetIntValue(), 1);
|
||||
TestEqual("Queue 6", RPN[6].GetType(), ESUDSExpressionItemType::Add);
|
||||
}
|
||||
if (TestEqual("Variable count", Expr.GetVariableNames().Num(), 1))
|
||||
{
|
||||
TestEqual("Variable name", Expr.GetVariableNames()[0].ToString(), "Six");
|
||||
}
|
||||
|
||||
TestTrue("Arithmetic", Expr.ParseFromString("-6.7 * 2 + (21.3 - 8) * 5", nullptr));
|
||||
TestEqual("Eval", Expr.Evaluate(Variables, GlobalVariables).GetFloatValue(), 53.1f);
|
||||
|
||||
// Modulo operator
|
||||
TestTrue("ModuloIntOperator", Expr.ParseFromString("11 % 5", nullptr));
|
||||
TestEqual("Eval", Expr.Evaluate(Variables, GlobalVariables).GetIntValue(), 1);
|
||||
TestTrue("ModuloFloatOperator", Expr.ParseFromString("7.25 % 3.0", nullptr));
|
||||
TestEqual("Eval", Expr.Evaluate(Variables, GlobalVariables).GetFloatValue(), 1.25f);
|
||||
|
||||
// Explicit FSUDSValue(true) needed to avoid it using the int conversion by default
|
||||
Variables.Add("IsATest", FSUDSValue(true));
|
||||
TestTrue("BoolSingleValueParse", Expr.ParseFromString("{IsATest}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
if (TestEqual("Variable count", Expr.GetVariableNames().Num(), 1))
|
||||
{
|
||||
TestEqual("Variable name", Expr.GetVariableNames()[0].ToString(), "IsATest");
|
||||
}
|
||||
|
||||
Variables.Add("SomethingFalse", FSUDSValue(false));
|
||||
Variables.Add("SomethingTrue", FSUDSValue(true));
|
||||
Variables.Add("SomethingElseFalse", FSUDSValue(false));
|
||||
TestTrue("BoolCompound1", Expr.ParseFromString("!{SomethingFalse} && {SomethingTrue}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
if (TestEqual("Variable count", Expr.GetVariableNames().Num(), 2))
|
||||
{
|
||||
TestEqual("Variable name", Expr.GetVariableNames()[0].ToString(), "SomethingFalse");
|
||||
TestEqual("Variable name", Expr.GetVariableNames()[1].ToString(), "SomethingTrue");
|
||||
}
|
||||
TestTrue("BoolCompound2", Expr.ParseFromString("{SomethingFalse} || {SomethingTrue}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("BoolCompound3", Expr.ParseFromString("{SomethingFalse} or {SomethingTrue}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
// Test parentheses changing precedence & result
|
||||
// True result for successful parsing, but false for Eval unless we parenthesise
|
||||
TestTrue("BoolCompound4", Expr.ParseFromString("!{SomethingFalse} && {SomethingElseFalse} && {SomethingTrue}", nullptr));
|
||||
TestFalse("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
if (TestEqual("Variable count", Expr.GetVariableNames().Num(), 3))
|
||||
{
|
||||
TestEqual("Variable name", Expr.GetVariableNames()[0].ToString(), "SomethingFalse");
|
||||
TestEqual("Variable name", Expr.GetVariableNames()[1].ToString(), "SomethingElseFalse");
|
||||
TestEqual("Variable name", Expr.GetVariableNames()[2].ToString(), "SomethingTrue");
|
||||
}
|
||||
TestTrue("BoolCompound5", Expr.ParseFromString("!({SomethingFalse} && {SomethingElseFalse}) && {SomethingTrue}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("BoolCompound6", Expr.ParseFromString("not {SomethingFalse} and {SomethingElseFalse} and {SomethingTrue}", nullptr));
|
||||
TestFalse("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("BoolCompound7", Expr.ParseFromString("not ({SomethingFalse} and {SomethingElseFalse}) and {SomethingTrue}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
|
||||
Variables.Add("Seven", 7);
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Six} == 6", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Six} = 6", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Six} >= 6", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Six} > 6", nullptr));
|
||||
TestFalse("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Six} < 6", nullptr));
|
||||
TestFalse("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Six} <= 6", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Six} < {Seven}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Seven} > {Six}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Seven} != {Six}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Seven} != {Seven}", nullptr));
|
||||
TestFalse("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
|
||||
// Mixed float/int comparisons
|
||||
Variables.Add("EightFloat", 8.1f);
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{EightFloat} > 8", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{EightFloat} > {Seven}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Six} < {EightFloat}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
// Fuzzy float comparisons
|
||||
Variables.Add("EightFloatPlusMargin", 8.1000002f);
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{EightFloat} == 8.1", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{EightFloat} == 8.15", nullptr));
|
||||
TestFalse("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{EightFloatPlusMargin} == 8.1", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{EightFloat} == 8.1000005", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{EightFloatPlusMargin} == 8.1000005", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
|
||||
// Other type comparisons
|
||||
Variables.Add("SomeText", FText::FromString("Hello"));
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{SomeText} == \"Hello\"", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{SomeText} == \"Hi\"", nullptr));
|
||||
TestFalse("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
|
||||
Variables.Add("Male", ETextGender::Masculine);
|
||||
Variables.Add("Female", ETextGender::Feminine);
|
||||
Variables.Add("AlsoFemale", ETextGender::Feminine);
|
||||
Variables.Add("Neuter", ETextGender::Neuter);
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Male} == masculine", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Male} == Masculine", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Male} == feminine", nullptr));
|
||||
TestFalse("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Male} == Feminine", nullptr));
|
||||
TestFalse("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Female} == Feminine", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Female} != feminine", nullptr));
|
||||
TestFalse("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Female} == {AlsoFemale}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Female} != {Neuter}", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Neuter} == neuter", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("Comparisons", Expr.ParseFromString("{Neuter} == Neuter", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
|
||||
// Test local / global by defining the same variable
|
||||
GlobalVariables.Add("GlobalLocalTestInt", 3);
|
||||
Variables.Add("GlobalLocalTestInt", 20);
|
||||
TestTrue("LocalTest", Expr.ParseFromString("{GlobalLocalTestInt} == 20", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
TestTrue("GlobalTest", Expr.ParseFromString("{global.GlobalLocalTestInt} == 3", nullptr));
|
||||
TestTrue("Eval", Expr.Evaluate(Variables, GlobalVariables).GetBooleanValue());
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestBadExpressions,
|
||||
"SUDSTest.TestBadExpressions",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestBadExpressions::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSExpression Expr;
|
||||
TMap<FName, FSUDSValue> Variables;
|
||||
|
||||
FString ParseError;
|
||||
|
||||
TestFalse("Missing operand", Expr.ParseFromString(" + 1", &ParseError));
|
||||
TestTrue("Correct error", ParseError.Contains("Bad expression"));
|
||||
TestFalse("Missing operand", Expr.ParseFromString("1 * ", &ParseError));
|
||||
TestTrue("Correct error", ParseError.Contains("Bad expression"));
|
||||
TestFalse("Missing parenthesis", Expr.ParseFromString("(3 + 1", &ParseError));
|
||||
TestTrue("Correct error", ParseError.Contains("Mismatched parentheses"));
|
||||
TestFalse("Missing parenthesis", Expr.ParseFromString("3 + 1)", &ParseError));
|
||||
TestTrue("Correct error", ParseError.Contains("Mismatched parentheses"));
|
||||
TestFalse("Invalid symbol", Expr.ParseFromString("something + 1", &ParseError));
|
||||
TestTrue("Correct error", ParseError.Contains("Bad expression"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UE_ENABLE_OPTIMIZATION
|
||||
417
Plugins/SUDS/Source/SUDSTest/Private/TestGotoGosub.cpp
Normal file
417
Plugins/SUDS/Source/SUDSTest/Private/TestGotoGosub.cpp
Normal file
@@ -0,0 +1,417 @@
|
||||
#include "SUDSDialogue.h"
|
||||
#include "SUDSLibrary.h"
|
||||
#include "SUDSMessageLogger.h"
|
||||
#include "SUDSScript.h"
|
||||
#include "SUDSScriptImporter.h"
|
||||
#include "TestUtils.h"
|
||||
#include "Misc/AutomationTest.h"
|
||||
|
||||
UE_DISABLE_OPTIMIZATION
|
||||
|
||||
const FString GotoGosubInput = R"RAWSUD(
|
||||
Player: Hello there
|
||||
NPC: Hello
|
||||
:choice
|
||||
* Actually bye
|
||||
NPC: How rude
|
||||
[goto end]
|
||||
* Reused
|
||||
NPC: This is going to re-used dialogue
|
||||
[gosub subroutine]
|
||||
NPC: And now we're back
|
||||
[goto goodbye]
|
||||
* Gosub choice
|
||||
NPC: This is going to return to the choice
|
||||
[gosub subroutine]
|
||||
* Choice After
|
||||
NPC: It's a choice after a gosub!
|
||||
[goto goodbye]
|
||||
* Choice After 2
|
||||
NPC: Not really much difference eh
|
||||
[goto goodbye]
|
||||
* Gosub choice via goto
|
||||
NPC: This is going to return to the choice via goto
|
||||
[gosub subroutine]
|
||||
[goto choice]
|
||||
|
||||
:subroutine
|
||||
Player: Some reused discussion
|
||||
NPC: Yep, sure is
|
||||
[return]
|
||||
:goodbye
|
||||
NPC: Bye!
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestGotoGosub,
|
||||
"SUDSTest.TestGotoGosub",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestGotoGosub::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(GotoGosubInput), GotoGosubInput.Len(), "GotoGosubInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg->Start();
|
||||
|
||||
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello there");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Hello");
|
||||
TestEqual("Choices", Dlg->GetNumberOfChoices(), 4);
|
||||
TestEqual("Choice 0 text", Dlg->GetChoiceText(0).ToString(), "Actually bye");
|
||||
TestTrue("Choose 0", Dlg->Choose(0));
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "How rude");
|
||||
TestFalse("End", Dlg->Continue());
|
||||
|
||||
Dlg->Restart();
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello there");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Hello");
|
||||
TestTrue("Choose 1", Dlg->Choose(1));
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "This is going to re-used dialogue");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "Player", "Some reused discussion");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Yep, sure is");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "And now we're back");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Bye!");
|
||||
TestFalse("Continue", Dlg->Continue());
|
||||
|
||||
Dlg->Restart();
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello there");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Hello");
|
||||
TestTrue("Choose 2", Dlg->Choose(2));
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "This is going to return to the choice");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "Player", "Some reused discussion");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Yep, sure is");
|
||||
// Should have a choice at the end of it this time
|
||||
TestEqual("Choices", Dlg->GetNumberOfChoices(), 2);
|
||||
TestEqual("Choice 0 text", Dlg->GetChoiceText(0).ToString(), "Choice After");
|
||||
TestEqual("Choice 1 text", Dlg->GetChoiceText(1).ToString(), "Choice After 2");
|
||||
TestTrue("Choose 1", Dlg->Choose(1));
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Not really much difference eh");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Bye!");
|
||||
TestFalse("Continue", Dlg->Continue());
|
||||
|
||||
Dlg->Restart();
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello there");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Hello");
|
||||
TestTrue("Choose 2", Dlg->Choose(3));
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "This is going to return to the choice via goto");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "Player", "Some reused discussion");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Yep, sure is");
|
||||
// Should have a choice at the end of it this time
|
||||
TestEqual("Choices", Dlg->GetNumberOfChoices(), 4);
|
||||
TestEqual("Choice 0 text", Dlg->GetChoiceText(0).ToString(), "Actually bye");
|
||||
TestTrue("Choose 0", Dlg->Choose(0));
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "How rude");
|
||||
TestFalse("End", Dlg->Continue());
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const FString NestedGosubInput = R"RAWSUD(
|
||||
Player: Hello there
|
||||
[gosub sub1]
|
||||
NPC: Back at level 0
|
||||
[goto goodbye]
|
||||
|
||||
:sub1
|
||||
Player: This is level 1
|
||||
[gosub sub2_1]
|
||||
[gosub sub2_2]
|
||||
Player: End of level 1
|
||||
[return]
|
||||
|
||||
:sub2_1
|
||||
Player: This is level 2, sub 1
|
||||
[return]
|
||||
|
||||
|
||||
:sub2_2
|
||||
Player: This is level 2, sub 2
|
||||
NPC: We have to go deeper
|
||||
[gosub sub3]
|
||||
Player: End of level 2, sub 2
|
||||
[return]
|
||||
|
||||
:sub3
|
||||
Player: This is level 3
|
||||
[return]
|
||||
|
||||
:goodbye
|
||||
NPC: Bye!
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestNestedGosub,
|
||||
"SUDSTest.TestNestedGosub",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestNestedGosub::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(NestedGosubInput), NestedGosubInput.Len(), "NestedGosubInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg->Start();
|
||||
|
||||
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello there");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Sub", Dlg, "Player", "This is level 1");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Sub", Dlg, "Player", "This is level 2, sub 1");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Sub", Dlg, "Player", "This is level 2, sub 2");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Sub", Dlg, "NPC", "We have to go deeper");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Sub", Dlg, "Player", "This is level 3");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Sub", Dlg, "Player", "End of level 2, sub 2");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Sub", Dlg, "Player", "End of level 1");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Sub", Dlg, "NPC", "Back at level 0");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Bye", Dlg, "NPC", "Bye!");
|
||||
TestFalse("Continue", Dlg->Continue());
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const FString GotoBetweenSpeakerAndChoiceInput = R"RAWSUD(
|
||||
Player: Hello there
|
||||
[if {SkipChoices}]
|
||||
[goto end]
|
||||
[endif]
|
||||
* Option A
|
||||
* Option B
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestGotoBetweenSpeakerAndChoice1,
|
||||
"SUDSTest.TestGotoBetweenSpeakerAndChoice1",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestGotoBetweenSpeakerAndChoice1::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(GotoBetweenSpeakerAndChoiceInput), GotoBetweenSpeakerAndChoiceInput.Len(), "GotoBetweenSpeakerAndChoiceInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg->Start();
|
||||
|
||||
|
||||
if (TestEqual("Choice Count", Dlg->GetNumberOfChoices(), 2))
|
||||
{
|
||||
TestEqual("Choice 1", Dlg->GetChoiceText(0).ToString(), "Option A");
|
||||
TestEqual("Choice 2", Dlg->GetChoiceText(1).ToString(), "Option B");
|
||||
}
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestGotoBetweenSpeakerAndChoice2,
|
||||
"SUDSTest.TestGotoBetweenSpeakerAndChoice2",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestGotoBetweenSpeakerAndChoice2::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(GotoBetweenSpeakerAndChoiceInput), GotoBetweenSpeakerAndChoiceInput.Len(), "GotoBetweenSpeakerAndChoiceInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg->SetVariableBoolean("SkipChoices", true);
|
||||
Dlg->Start();
|
||||
|
||||
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello there");
|
||||
TestTrue("Plain continue", Dlg->IsSimpleContinue());
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const FString GosubBetweenSpeakerAndChoiceInput1 = R"RAWSUD(
|
||||
Player: Hello there
|
||||
[gosub MaybeSkipChoices]
|
||||
* Option A
|
||||
* Option B
|
||||
[goto end]
|
||||
|
||||
:MaybeSkipChoices
|
||||
[if {SkipChoices}]
|
||||
[goto end]
|
||||
[endif]
|
||||
[return]
|
||||
)RAWSUD";
|
||||
|
||||
const FString GosubBetweenSpeakerAndChoiceInput2 = R"RAWSUD(
|
||||
Player: Hello there
|
||||
[gosub PrintDebug]
|
||||
[gosub MaybeSkipChoices]
|
||||
* Option A
|
||||
* Option B
|
||||
[goto end]
|
||||
|
||||
:PrintDebug
|
||||
Debug: SkipChoices is {SkipChoices}
|
||||
[return]
|
||||
|
||||
:MaybeSkipChoices
|
||||
[if {SkipChoices}]
|
||||
[goto end]
|
||||
[endif]
|
||||
Speaker: Another sentence.
|
||||
[return]
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestGosubBetweenSpeakerAndChoice1,
|
||||
"SUDSTest.TestGosubBetweenSpeakerAndChoice1",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestGosubBetweenSpeakerAndChoice1::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(GosubBetweenSpeakerAndChoiceInput1), GosubBetweenSpeakerAndChoiceInput1.Len(), "GosubBetweenSpeakerAndChoiceInput1", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg->Start();
|
||||
|
||||
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello there");
|
||||
if (TestEqual("Choice Count", Dlg->GetNumberOfChoices(), 2))
|
||||
{
|
||||
TestEqual("Choice 1", Dlg->GetChoiceText(0).ToString(), "Option A");
|
||||
TestEqual("Choice 2", Dlg->GetChoiceText(1).ToString(), "Option B");
|
||||
}
|
||||
|
||||
// Now test the true case
|
||||
Dlg->SetVariableBoolean("SkipChoices", true);
|
||||
Dlg->Restart(false);
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello there");
|
||||
TestTrue("Plain continue", Dlg->IsSimpleContinue());
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestGosubBetweenSpeakerAndChoice2,
|
||||
"SUDSTest.TestGosubBetweenSpeakerAndChoice2",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestGosubBetweenSpeakerAndChoice2::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(GosubBetweenSpeakerAndChoiceInput2), GosubBetweenSpeakerAndChoiceInput2.Len(), "GosubBetweenSpeakerAndChoiceInput2", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg->Start();
|
||||
|
||||
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello there");
|
||||
// in this case, there's another speaker line in both nested gosubs so the choices are actually associated with the
|
||||
// last of those.
|
||||
TestTrue("Plain continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Gosub 1 speaker node", Dlg, "Debug", "SkipChoices is {SkipChoices}");
|
||||
TestTrue("Plain continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Gosub 2 speaker node", Dlg, "Speaker", "Another sentence.");
|
||||
|
||||
if (TestEqual("Choice Count", Dlg->GetNumberOfChoices(), 2))
|
||||
{
|
||||
TestEqual("Choice 1", Dlg->GetChoiceText(0).ToString(), "Option A");
|
||||
TestEqual("Choice 2", Dlg->GetChoiceText(1).ToString(), "Option B");
|
||||
}
|
||||
|
||||
// Now test the true case
|
||||
Dlg->SetVariableBoolean("SkipChoices", true);
|
||||
Dlg->Restart(false);
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello there");
|
||||
TestTrue("Plain continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Gosub 1 speaker node", Dlg, "Debug", "SkipChoices is 1");
|
||||
TestTrue("Plain continue", Dlg->IsSimpleContinue());
|
||||
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
UE_ENABLE_OPTIMIZATION
|
||||
133
Plugins/SUDS/Source/SUDSTest/Private/TestMetadata.cpp
Normal file
133
Plugins/SUDS/Source/SUDSTest/Private/TestMetadata.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
#include "SUDSDialogue.h"
|
||||
#include "SUDSLibrary.h"
|
||||
#include "SUDSMessageLogger.h"
|
||||
#include "SUDSScript.h"
|
||||
#include "SUDSScriptImporter.h"
|
||||
#include "TestUtils.h"
|
||||
#include "Internationalization/StringTableCore.h"
|
||||
#include "Misc/AutomationTest.h"
|
||||
|
||||
UE_DISABLE_OPTIMIZATION
|
||||
|
||||
// Assign known keys to the strings so we can detect
|
||||
const FString MetadataInput = R"RAWSUD(
|
||||
# No metadata
|
||||
Player: Hello there @001@
|
||||
#= Transient metadata for next line
|
||||
#= TransientData: Something here
|
||||
NPC: Hello @002@
|
||||
# Should have no metadata anymore
|
||||
Player: Well this is nice @003@
|
||||
#+ Persistent metadata
|
||||
#+ PersistentData: Something longer lived
|
||||
NPC: Isn't it though @004@
|
||||
# Should still apply here
|
||||
Player: Indeed @005@
|
||||
#= Test overriding temporarily
|
||||
#= PersistentData: This should override
|
||||
#= ExtraTransient: This should be new only for next line
|
||||
NPC: Well well @006@
|
||||
Player: Metadata should have gone back now @007@
|
||||
#+ Persistent metadata changed now
|
||||
Player: Persistent change @008@
|
||||
* Some choice @009@
|
||||
NPC: How rude @010@
|
||||
[goto end]
|
||||
#= Temporary comment
|
||||
* Another choice @011@
|
||||
NPC: This should be back now @012@
|
||||
#+ Persistent indented change 1
|
||||
* One more choice @013@
|
||||
#+ Even more indented
|
||||
#+ NestedKey: This will disappear fast even though persistent
|
||||
NPC: Ooops @014@
|
||||
* Final choice @015@
|
||||
NPC: This is going to return to the choice via goto @016@
|
||||
# Nested meta should have been lost but outer meta should be back
|
||||
Player: Something something @017@
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestMetadata,
|
||||
"SUDSTest.TestMetadata",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestMetadata::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(MetadataInput), MetadataInput.Len(), "MetadataInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// In this test we're only interested in the string table metadata
|
||||
// Have to get the mutable string table to get at metadata
|
||||
auto StrTable = StringTableHolder.StringTable->GetMutableStringTable();
|
||||
|
||||
TestEqual("Line 1 Comment", StrTable->GetMetaData(FTextKey("@001@"), FName("Comment")), "");
|
||||
TestEqual("Line 1 Speaker", StrTable->GetMetaData(FTextKey("@001@"), FName("Speaker")), "Player");
|
||||
TestEqual("Line 2 Comment", StrTable->GetMetaData(FTextKey("@002@"), FName("Comment")), "Transient metadata for next line");
|
||||
TestEqual("Line 2 Speaker", StrTable->GetMetaData(FTextKey("@002@"), FName("Speaker")), "NPC");
|
||||
TestEqual("Line 2 Custom", StrTable->GetMetaData(FTextKey("@002@"), FName("TransientData")), "Something here");
|
||||
TestEqual("Line 3 Comment (should have reset)", StrTable->GetMetaData(FTextKey("@003@"), FName("Comment")), "");
|
||||
TestEqual("Line 3 Speaker", StrTable->GetMetaData(FTextKey("@003@"), FName("Speaker")), "Player");
|
||||
TestEqual("Line 3 Custom (should have reset)", StrTable->GetMetaData(FTextKey("@003@"), FName("TransientData")), "");
|
||||
TestEqual("Line 4 Comment", StrTable->GetMetaData(FTextKey("@004@"), FName("Comment")), "Persistent metadata");
|
||||
TestEqual("Line 4 Speaker", StrTable->GetMetaData(FTextKey("@004@"), FName("Speaker")), "NPC");
|
||||
TestEqual("Line 4 Custom", StrTable->GetMetaData(FTextKey("@004@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 5 Comment", StrTable->GetMetaData(FTextKey("@005@"), FName("Comment")), "Persistent metadata");
|
||||
TestEqual("Line 5 Speaker", StrTable->GetMetaData(FTextKey("@005@"), FName("Speaker")), "Player");
|
||||
TestEqual("Line 5 Custom", StrTable->GetMetaData(FTextKey("@005@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 6 Comment", StrTable->GetMetaData(FTextKey("@006@"), FName("Comment")), "Test overriding temporarily");
|
||||
TestEqual("Line 6 Speaker", StrTable->GetMetaData(FTextKey("@006@"), FName("Speaker")), "NPC");
|
||||
TestEqual("Line 6 Custom", StrTable->GetMetaData(FTextKey("@006@"), FName("PersistentData")), "This should override");
|
||||
TestEqual("Line 6 Custom 2", StrTable->GetMetaData(FTextKey("@006@"), FName("ExtraTransient")), "This should be new only for next line");
|
||||
TestEqual("Line 7 Comment", StrTable->GetMetaData(FTextKey("@007@"), FName("Comment")), "Persistent metadata");
|
||||
TestEqual("Line 7 Speaker", StrTable->GetMetaData(FTextKey("@007@"), FName("Speaker")), "Player");
|
||||
TestEqual("Line 7 Custom", StrTable->GetMetaData(FTextKey("@007@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 8 Comment", StrTable->GetMetaData(FTextKey("@008@"), FName("Comment")), "Persistent metadata changed now");
|
||||
TestEqual("Line 8 Speaker", StrTable->GetMetaData(FTextKey("@008@"), FName("Speaker")), "Player");
|
||||
TestEqual("Line 8 Custom", StrTable->GetMetaData(FTextKey("@008@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 9 Comment", StrTable->GetMetaData(FTextKey("@009@"), FName("Comment")), "Persistent metadata changed now");
|
||||
TestEqual("Line 9 Speaker", StrTable->GetMetaData(FTextKey("@009@"), FName("Speaker")), "Player (Choice)");
|
||||
TestEqual("Line 9 Custom", StrTable->GetMetaData(FTextKey("@009@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 10 Comment", StrTable->GetMetaData(FTextKey("@010@"), FName("Comment")), "Persistent metadata changed now");
|
||||
TestEqual("Line 10 Speaker", StrTable->GetMetaData(FTextKey("@010@"), FName("Speaker")), "NPC");
|
||||
TestEqual("Line 10 Custom", StrTable->GetMetaData(FTextKey("@010@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 11 Comment", StrTable->GetMetaData(FTextKey("@011@"), FName("Comment")), "Temporary comment");
|
||||
TestEqual("Line 11 Speaker", StrTable->GetMetaData(FTextKey("@011@"), FName("Speaker")), "Player (Choice)");
|
||||
TestEqual("Line 11 Custom", StrTable->GetMetaData(FTextKey("@011@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 12 Comment", StrTable->GetMetaData(FTextKey("@012@"), FName("Comment")), "Persistent metadata changed now");
|
||||
TestEqual("Line 12 Speaker", StrTable->GetMetaData(FTextKey("@012@"), FName("Speaker")), "NPC");
|
||||
TestEqual("Line 12 Custom", StrTable->GetMetaData(FTextKey("@012@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 13 Comment", StrTable->GetMetaData(FTextKey("@013@"), FName("Comment")), "Persistent indented change 1");
|
||||
TestEqual("Line 13 Speaker", StrTable->GetMetaData(FTextKey("@013@"), FName("Speaker")), "Player (Choice)");
|
||||
TestEqual("Line 13 Custom", StrTable->GetMetaData(FTextKey("@013@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 14 Comment", StrTable->GetMetaData(FTextKey("@014@"), FName("Comment")), "Even more indented");
|
||||
TestEqual("Line 14 Speaker", StrTable->GetMetaData(FTextKey("@014@"), FName("Speaker")), "NPC");
|
||||
TestEqual("Line 14 Custom", StrTable->GetMetaData(FTextKey("@014@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 14 Custom 2", StrTable->GetMetaData(FTextKey("@014@"), FName("NestedKey")), "This will disappear fast even though persistent");
|
||||
TestEqual("Line 15 Comment", StrTable->GetMetaData(FTextKey("@015@"), FName("Comment")), "Persistent indented change 1"); // should have gone back
|
||||
TestEqual("Line 15 Speaker", StrTable->GetMetaData(FTextKey("@015@"), FName("Speaker")), "Player (Choice)");
|
||||
TestEqual("Line 15 Custom", StrTable->GetMetaData(FTextKey("@015@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 15 Custom 2", StrTable->GetMetaData(FTextKey("@015@"), FName("NestedKey")), "");
|
||||
TestEqual("Line 16 Comment", StrTable->GetMetaData(FTextKey("@016@"), FName("Comment")), "Persistent indented change 1"); // should have gone back
|
||||
TestEqual("Line 16 Speaker", StrTable->GetMetaData(FTextKey("@016@"), FName("Speaker")), "NPC");
|
||||
TestEqual("Line 16 Custom", StrTable->GetMetaData(FTextKey("@016@"), FName("PersistentData")), "Something longer lived");
|
||||
TestEqual("Line 16 Custom 2", StrTable->GetMetaData(FTextKey("@016@"), FName("NestedKey")), "");
|
||||
TestEqual("Line 17 Comment", StrTable->GetMetaData(FTextKey("@017@"), FName("Comment")), "Persistent metadata changed now"); // should have gone back to top level
|
||||
TestEqual("Line 17 Speaker", StrTable->GetMetaData(FTextKey("@017@"), FName("Speaker")), "Player");
|
||||
TestEqual("Line 17 Custom", StrTable->GetMetaData(FTextKey("@017@"), FName("PersistentData")), "Something longer lived");
|
||||
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
UE_ENABLE_OPTIMIZATION
|
||||
147
Plugins/SUDS/Source/SUDSTest/Private/TestParameters.cpp
Normal file
147
Plugins/SUDS/Source/SUDSTest/Private/TestParameters.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
#include "SUDSDialogue.h"
|
||||
#include "SUDSLibrary.h"
|
||||
#include "SUDSMessageLogger.h"
|
||||
#include "SUDSScript.h"
|
||||
#include "SUDSScriptImporter.h"
|
||||
#include "TestParticipant.h"
|
||||
#include "TestUtils.h"
|
||||
#include "Internationalization/Internationalization.h"
|
||||
#include "Misc/AutomationTest.h"
|
||||
|
||||
UE_DISABLE_OPTIMIZATION
|
||||
|
||||
const FString ParamsInput = R"RAWSUD(
|
||||
Player: Hello, I'm {SpeakerName.Player}
|
||||
NPC: Greetings, {SpeakerName.Player}, my name is {SpeakerName.NPC}
|
||||
Player: My friend's name is {FriendName}, {Gender}|gender(he,she,they) {Gender}|gender(has,has,have) {NumCats} {NumCats}|plural(one=cat,other=cats)
|
||||
NPC: Floating point {FloatVal} format test
|
||||
Player: Boolean test {BoolVal}?
|
||||
* Choose, {SpeakerName.Player}!
|
||||
* Is {NumCats} {NumCats}|plural(one=cat,other=cats) too many?
|
||||
NPC: No, {numcats} is fine
|
||||
)RAWSUD";
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestParameters,
|
||||
"SUDSTest.TestParameters",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestParameters::RunTest(const FString& Parameters)
|
||||
{
|
||||
// Number and plural formatting are locale-specific, so we must set it to a predefined value to produce the expected output
|
||||
FInternationalization::FCultureStateSnapshot CultureStateSnapshot;
|
||||
FInternationalization::Get().BackupCultureState(CultureStateSnapshot);
|
||||
FInternationalization::Get().SetCurrentCulture(TEXT("en-US"));
|
||||
ON_SCOPE_EXIT
|
||||
{
|
||||
FInternationalization::Get().RestoreCultureState(CultureStateSnapshot);
|
||||
};
|
||||
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(ParamsInput), ParamsInput.Len(), "ParamsInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
auto Participant = NewObject<UTestParticipant>();
|
||||
Participant->TestNumber = 0;
|
||||
Dlg->AddParticipant(Participant);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Line 1", Dlg, "Player", "Hello, I'm Protagonist");
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Line 2", Dlg, "NPC", "Greetings, Protagonist, my name is An NPC");
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Line 3", Dlg, "Player", "My friend's name is Susan, she has 3 cats");
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Line 4", Dlg, "NPC", "Floating point 12.567 format test");
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Line 5", Dlg, "Player", "Boolean test 1?");
|
||||
if (TestEqual("Number of choices", Dlg->GetNumberOfChoices(), 2))
|
||||
{
|
||||
TestEqual("Choice text 1", Dlg->GetChoiceText(0).ToString(), "Choose, Protagonist!");
|
||||
TestEqual("Choice text 2", Dlg->GetChoiceText(1).ToString(), "Is 3 cats too many?");
|
||||
|
||||
}
|
||||
|
||||
// test case insensitivity, this next line uses {numcats} instead of {NumCats}
|
||||
Dlg->Choose(1);
|
||||
TestDialogueText(this, "Line 6", Dlg, "NPC", "No, 3 is fine");
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestParametersPriority,
|
||||
"SUDSTest.TestParametersPriority",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestParametersPriority::RunTest(const FString& Parameters)
|
||||
{
|
||||
// Number and plural formatting are locale-specific, so we must set it to a predefined value to produce the expected output
|
||||
FInternationalization::FCultureStateSnapshot CultureStateSnapshot;
|
||||
FInternationalization::Get().BackupCultureState(CultureStateSnapshot);
|
||||
FInternationalization::Get().SetCurrentCulture(TEXT("en-US"));
|
||||
ON_SCOPE_EXIT
|
||||
{
|
||||
FInternationalization::Get().RestoreCultureState(CultureStateSnapshot);
|
||||
};
|
||||
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(ParamsInput), ParamsInput.Len(), "ParamsInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
auto Participant1 = NewObject<UTestParticipant>();
|
||||
Participant1->TestNumber = 0; // priority 0
|
||||
auto Participant2 = NewObject<UTestParticipant>();
|
||||
Participant2->TestNumber = 1; // priority 100
|
||||
auto Participant3 = NewObject<UTestParticipant>();
|
||||
Participant1->TestNumber = 2; // priority -200
|
||||
Dlg->AddParticipant(Participant1);
|
||||
Dlg->AddParticipant(Participant2);
|
||||
Dlg->AddParticipant(Participant3);
|
||||
Dlg->Start();
|
||||
|
||||
// Ordering of the participants should be from low to high, so variables from higher priority value participant should
|
||||
// have overridden lower priority ones
|
||||
|
||||
// All of these are set by Participant 2 who is higher priority
|
||||
TestDialogueText(this, "Line 1", Dlg, "Player", "Hello, I'm Hero");
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Line 2", Dlg, "NPC", "Greetings, Hero, my name is Bob The NPC");
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Line 3", Dlg, "Player", "My friend's name is Derek, he has 5 cats");
|
||||
Dlg->Continue();
|
||||
|
||||
// These are set by Participant1 and unchanged by 2. 3 has tried to set float but should have been overridden
|
||||
TestDialogueText(this, "Line 4", Dlg, "NPC", "Floating point 12.567 format test");
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Line 5", Dlg, "Player", "Boolean test 1?");
|
||||
|
||||
// Check that there's a variable from Participant2 which no-one else set
|
||||
TestEqual("Participant3 should have set something", Dlg->GetVariableInt("SomethingUniqueTo3"), 120);
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
UE_ENABLE_OPTIMIZATION
|
||||
1189
Plugins/SUDS/Source/SUDSTest/Private/TestParsing.cpp
Normal file
1189
Plugins/SUDS/Source/SUDSTest/Private/TestParsing.cpp
Normal file
File diff suppressed because it is too large
Load Diff
68
Plugins/SUDS/Source/SUDSTest/Private/TestParticipant.cpp
Normal file
68
Plugins/SUDS/Source/SUDSTest/Private/TestParticipant.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
#include "TestParticipant.h"
|
||||
|
||||
#include "SUDSDialogue.h"
|
||||
|
||||
void UTestParticipant::OnDialogueStarting_Implementation(USUDSDialogue* Dialogue, FName AtLabel)
|
||||
{
|
||||
switch(TestNumber)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
Dialogue->SetVariable("SpeakerName.Player", FText::FromString("Protagonist"));
|
||||
Dialogue->SetVariable("SpeakerName.NPC", FText::FromString("An NPC"));
|
||||
Dialogue->SetVariable("NumCats", 3);
|
||||
Dialogue->SetVariableText("FriendName", FText::FromString("Susan"));
|
||||
Dialogue->SetVariable("Gender", ETextGender::Feminine);
|
||||
Dialogue->SetVariableFloat("FloatVal", 12.567);
|
||||
Dialogue->SetVariableBoolean("BoolVal", true);
|
||||
break;
|
||||
case 1:
|
||||
Dialogue->SetVariable("SpeakerName.Player", FText::FromString("Hero"));
|
||||
Dialogue->SetVariable("SpeakerName.NPC", FText::FromString("Bob The NPC"));
|
||||
Dialogue->SetVariableText("FriendName", FText::FromString("Derek"));
|
||||
Dialogue->SetVariable("Gender", ETextGender::Masculine);
|
||||
Dialogue->SetVariable("NumCats", 5);
|
||||
break;
|
||||
case 2:
|
||||
// these will all be overridden by higher priorities
|
||||
Dialogue->SetVariable("SpeakerName.Player", FText::FromString("Dweeb"));
|
||||
Dialogue->SetVariable("SpeakerName.NPC", FText::FromString("Imaginary Friend"));
|
||||
Dialogue->SetVariable("NumCats", 10);
|
||||
Dialogue->SetVariableFloat("FloatVal", 0.002);
|
||||
// This one will be unique and so will still get through
|
||||
Dialogue->SetVariableInt("SomethingUniqueTo3", 120);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int UTestParticipant::GetDialogueParticipantPriority_Implementation() const
|
||||
{
|
||||
switch(TestNumber)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return 100;
|
||||
case 2:
|
||||
return -200;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void UTestParticipant::OnDialogueEvent_Implementation(USUDSDialogue* Dialogue,
|
||||
FName EventName,
|
||||
const TArray<FSUDSValue>& Arguments)
|
||||
{
|
||||
EventRecords.Add(FEventRecord { EventName, Arguments });
|
||||
}
|
||||
|
||||
void UTestParticipant::OnDialogueVariableChanged_Implementation(USUDSDialogue* Dialogue,
|
||||
FName VariableName,
|
||||
const FSUDSValue& Value,
|
||||
bool bFromScript)
|
||||
{
|
||||
SetVarRecords.Add(FSetVarRecord { VariableName, Value, bFromScript });
|
||||
}
|
||||
|
||||
45
Plugins/SUDS/Source/SUDSTest/Private/TestParticipant.h
Normal file
45
Plugins/SUDS/Source/SUDSTest/Private/TestParticipant.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "SUDSParticipant.h"
|
||||
#include "SUDSValue.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "TestParticipant.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class SUDSTEST_API UTestParticipant : public UObject, public ISUDSParticipant
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
int TestNumber = 0;
|
||||
|
||||
struct FEventRecord
|
||||
{
|
||||
FName Name;
|
||||
TArray<FSUDSValue> Args;
|
||||
};
|
||||
struct FSetVarRecord
|
||||
{
|
||||
FName Name;
|
||||
FSUDSValue Value;
|
||||
bool bFromScript;
|
||||
};
|
||||
|
||||
TArray<FEventRecord> EventRecords;
|
||||
TArray<FSetVarRecord> SetVarRecords;
|
||||
|
||||
|
||||
virtual void OnDialogueStarting_Implementation(USUDSDialogue* Dialogue, FName AtLabel) override;
|
||||
virtual int GetDialogueParticipantPriority_Implementation() const override;
|
||||
virtual void OnDialogueEvent_Implementation(USUDSDialogue* Dialogue,
|
||||
FName EventName,
|
||||
const TArray<FSUDSValue>& Arguments) override;
|
||||
virtual void OnDialogueVariableChanged_Implementation(USUDSDialogue* Dialogue,
|
||||
FName VariableName,
|
||||
const FSUDSValue& Value,
|
||||
bool bFromScript) override;
|
||||
};
|
||||
342
Plugins/SUDS/Source/SUDSTest/Private/TestRandom.cpp
Normal file
342
Plugins/SUDS/Source/SUDSTest/Private/TestRandom.cpp
Normal file
@@ -0,0 +1,342 @@
|
||||
#include "SUDSLibrary.h"
|
||||
#include "SUDSMessageLogger.h"
|
||||
#include "SUDSScript.h"
|
||||
#include "SUDSScriptImporter.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
UE_DISABLE_OPTIMIZATION
|
||||
|
||||
const FString BasicRandomInput = R"RAWSUD(
|
||||
Player: Hello
|
||||
:start
|
||||
[random]
|
||||
NPC: Reply when random == 0
|
||||
[or]
|
||||
NPC: Reply when random == 1
|
||||
[or]
|
||||
NPC: Reply when random == 2
|
||||
[endrandom]
|
||||
Player: OK
|
||||
[goto start]
|
||||
)RAWSUD";
|
||||
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestRandomBasics,
|
||||
"SUDSTest.TestRandomBasics",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
bool FTestRandomBasics::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(BasicRandomInput), BasicRandomInput.Len(), "BasicRandomInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
|
||||
// Seed random so we have consistent results
|
||||
FMath::SRandInit(34);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "Hello");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Random node", Dlg, "NPC", "Reply when random == 2");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Final node", Dlg, "Player", "OK");
|
||||
|
||||
// Should loop, run random again
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Random node", Dlg, "NPC", "Reply when random == 1");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Final node", Dlg, "Player", "OK");
|
||||
|
||||
// Should loop, run random again
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Random node", Dlg, "NPC", "Reply when random == 0");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Final node", Dlg, "Player", "OK");
|
||||
|
||||
// Should loop, run random again
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Random node", Dlg, "NPC", "Reply when random == 1");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Final node", Dlg, "Player", "OK");
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
const FString NestedRandomInput = R"RAWSUD(
|
||||
Player: Hello
|
||||
:start
|
||||
[random]
|
||||
NPC: Reply when random == 0
|
||||
[or]
|
||||
[random]
|
||||
NPC: Reply when random == 1 && subrandom == 0
|
||||
[or]
|
||||
NPC: Reply when random == 1 && subrandom == 1
|
||||
[endrandom]
|
||||
[or]
|
||||
NPC: Reply when random == 2
|
||||
[endrandom]
|
||||
Player: OK
|
||||
[goto start]
|
||||
)RAWSUD";
|
||||
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestRandomNested,
|
||||
"SUDSTest.TestRandomNested",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
bool FTestRandomNested::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(NestedRandomInput), NestedRandomInput.Len(), "NestedRandomInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
|
||||
// Seed random so we have consistent results
|
||||
FMath::SRandInit(785);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "Hello");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
TestDialogueText(this, "Random node", Dlg, "NPC", "Reply when random == 0");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Final node", Dlg, "Player", "OK");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
// Restart
|
||||
TestDialogueText(this, "Random node", Dlg, "NPC", "Reply when random == 1 && subrandom == 1");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Final node", Dlg, "Player", "OK");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
// Restart
|
||||
TestDialogueText(this, "Random node", Dlg, "NPC", "Reply when random == 1 && subrandom == 0");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Final node", Dlg, "Player", "OK");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
// Restart
|
||||
TestDialogueText(this, "Random node", Dlg, "NPC", "Reply when random == 2");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Final node", Dlg, "Player", "OK");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
// Restart
|
||||
TestDialogueText(this, "Random node", Dlg, "NPC", "Reply when random == 0");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Final node", Dlg, "Player", "OK");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
const FString SiblingRandomInput = R"RAWSUD(
|
||||
Player: Hello
|
||||
:start
|
||||
[random]
|
||||
NPC: Reply when random == 0
|
||||
[or]
|
||||
NPC: Reply when random == 1
|
||||
[or]
|
||||
NPC: Reply when random == 2
|
||||
[endrandom]
|
||||
[random]
|
||||
NPC: Second random == 0
|
||||
[or]
|
||||
NPC: Second random == 1
|
||||
[or]
|
||||
NPC: Second random == 2
|
||||
[endrandom]
|
||||
Player: OK
|
||||
[goto start]
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestRandomSibling,
|
||||
"SUDSTest.TestRandomSibling",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
bool FTestRandomSibling::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(SiblingRandomInput), SiblingRandomInput.Len(), "SiblingRandomInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
|
||||
// Seed random so we have consistent results
|
||||
FMath::SRandInit(2376);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "Hello");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
|
||||
TestDialogueText(this, "Text node", Dlg, "NPC", "Reply when random == 1");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text node", Dlg, "NPC", "Second random == 0");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "OK");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
// Restart
|
||||
TestDialogueText(this, "Text node", Dlg, "NPC", "Reply when random == 0");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text node", Dlg, "NPC", "Second random == 2");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "OK");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
// Restart
|
||||
TestDialogueText(this, "Text node", Dlg, "NPC", "Reply when random == 1");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text node", Dlg, "NPC", "Second random == 2");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "OK");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
// Restart
|
||||
TestDialogueText(this, "Text node", Dlg, "NPC", "Reply when random == 0");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text node", Dlg, "NPC", "Second random == 0");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "OK");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
// Restart
|
||||
TestDialogueText(this, "Text node", Dlg, "NPC", "Reply when random == 2");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text node", Dlg, "NPC", "Second random == 2");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "OK");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
const FString MixedConditionalChoiceAndRandomInput = R"RAWSUD(
|
||||
Player: Hello
|
||||
* First choice
|
||||
Player: I took the 1.1 choice
|
||||
[if {x} > 0]
|
||||
* Second choice (conditional)
|
||||
[random]
|
||||
Player: I took the 1.2 choice, random == 0
|
||||
[or]
|
||||
Player: I took the 1.2 choice, random == 1
|
||||
[endif]
|
||||
* Third choice (conditional)
|
||||
Player: I took the 1.3 choice
|
||||
[else]
|
||||
* Second Alt Choice
|
||||
[random]
|
||||
Player: I took the alt 1.2 choice, random == 0
|
||||
[or]
|
||||
Player: I took the alt 1.2 choice, random == 1
|
||||
[endif]
|
||||
[endif]
|
||||
* Common last choice
|
||||
Player: I took the 1.4 choice
|
||||
|
||||
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestRandomMixed,
|
||||
"SUDSTest.TestRandomMixed",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
bool FTestRandomMixed::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(MixedConditionalChoiceAndRandomInput), MixedConditionalChoiceAndRandomInput.Len(), "MixedRandomInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
|
||||
// Seed random so we have consistent results
|
||||
FMath::SRandInit(999);
|
||||
Dlg->SetVariableInt("x", 5);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello");
|
||||
// 2 choices from conditional, 2 common
|
||||
if (TestEqual("Choice count when x=5", Dlg->GetNumberOfChoices(), 4))
|
||||
{
|
||||
TestTrue("Choose 1", Dlg->Choose(1));
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "I took the 1.2 choice, random == 0");
|
||||
}
|
||||
|
||||
// Restart, same again but different result if random
|
||||
Dlg->Restart(false);
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello");
|
||||
// 2 choices from conditional, 2 common
|
||||
if (TestEqual("Choice count when x=5", Dlg->GetNumberOfChoices(), 4))
|
||||
{
|
||||
TestTrue("Choose 1", Dlg->Choose(1));
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "I took the 1.2 choice, random == 1");
|
||||
}
|
||||
|
||||
// Now change to other conditional path
|
||||
Dlg->SetVariableInt("x", 0);
|
||||
|
||||
Dlg->Restart(false);
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello");
|
||||
if (TestEqual("Choice count when x=0", Dlg->GetNumberOfChoices(), 3))
|
||||
{
|
||||
TestTrue("Choose 1", Dlg->Choose(1));
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "I took the alt 1.2 choice, random == 1");
|
||||
}
|
||||
Dlg->Restart(false);
|
||||
TestDialogueText(this, "Start node", Dlg, "Player", "Hello");
|
||||
if (TestEqual("Choice count when x=0", Dlg->GetNumberOfChoices(), 3))
|
||||
{
|
||||
TestTrue("Choose 1", Dlg->Choose(1));
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "I took the alt 1.2 choice, random == 0");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
UE_ENABLE_OPTIMIZATION
|
||||
492
Plugins/SUDS/Source/SUDSTest/Private/TestRunning.cpp
Normal file
492
Plugins/SUDS/Source/SUDSTest/Private/TestRunning.cpp
Normal file
@@ -0,0 +1,492 @@
|
||||
#include "SUDSDialogue.h"
|
||||
#include "SUDSLibrary.h"
|
||||
#include "SUDSMessageLogger.h"
|
||||
#include "SUDSScript.h"
|
||||
#include "SUDSScriptImporter.h"
|
||||
#include "SUDSSubsystem.h"
|
||||
#include "TestUtils.h"
|
||||
#include "Internationalization/Internationalization.h"
|
||||
#include "Misc/AutomationTest.h"
|
||||
|
||||
UE_DISABLE_OPTIMIZATION
|
||||
|
||||
const FString SimpleRunnerInput = R"RAWSUD(
|
||||
:start
|
||||
Player: Hello there
|
||||
NPC: Salutations fellow human
|
||||
:choice
|
||||
* Actually no
|
||||
NPC: How rude, bye then
|
||||
[goto end]
|
||||
* Nested option
|
||||
:nestedstart
|
||||
NPC: Some nesting
|
||||
* Actually bye
|
||||
Player: Gotta go!
|
||||
[go to goodbye]
|
||||
* A fallthrough choice
|
||||
NPC: This should fall through to latterhalf
|
||||
* A goto choice
|
||||
[goto latterhalf]
|
||||
* Another option
|
||||
Player: What now?
|
||||
NPC: This is another fallthrough
|
||||
:latterhalf
|
||||
Player: This is the latter half of the discussion
|
||||
NPC: Yep, sure is
|
||||
* Go back to choice
|
||||
NPC: Okay!
|
||||
[goto choice]
|
||||
* Return to the start
|
||||
NPC: Gotcha
|
||||
[goto start]
|
||||
* Continue
|
||||
Player: OK I'd like to carry on now
|
||||
NPC: Right you are guv, falling through
|
||||
:goodbye
|
||||
NPC: Bye!
|
||||
)RAWSUD";
|
||||
|
||||
const FString SetVariableRunnerInput = R"RAWSUD(
|
||||
===
|
||||
# Set some vars in header
|
||||
# Text var with an existing localised ID
|
||||
[set SpeakerName.Player "Protagonist"] @12345@
|
||||
# Text var no localised ID
|
||||
[set ValetName "Bob"]
|
||||
// Also test with equals signs
|
||||
[set SomeFloat = 12.5]
|
||||
[set SomeCalculatedInt = (3 + 4) * 2]
|
||||
[set SomeCalculatedBoolean = true or false]
|
||||
// Test global vars
|
||||
[set global.SomeGlobalInt 3]
|
||||
[set global.SomeGlobalFloat = 12.5 * 3]
|
||||
===
|
||||
|
||||
Player: Hello
|
||||
[set SomeInt 99]
|
||||
# Test that we can use variables in set and that ordering works
|
||||
[set SomeOtherFloat {SomeFloat} + 10]
|
||||
[set SomeFloat 43.754]
|
||||
# Test global values
|
||||
NPC: Wotcha
|
||||
Player: Values are: {global.SomeGlobalInt}, {global.SomeGlobalFloat}, {global.GlobalIntSetOutside}
|
||||
# Test that inserting a set node in between text and choice doesn't break link
|
||||
[set SomeGender masculine]
|
||||
* Choice 1
|
||||
[set SomeBoolean True]
|
||||
NPC: Truth
|
||||
* Choice 2
|
||||
NPC: Surprise
|
||||
[set ValetName "Kate"]
|
||||
[set SomeGender feminine]
|
||||
[set someint 101]
|
||||
Player: Well
|
||||
|
||||
)RAWSUD";
|
||||
|
||||
const FString FallthroughEdgeCaseInput = R"RAWSUD(
|
||||
NPC: First line
|
||||
* Option 1
|
||||
NPC: Fallthrough via goto
|
||||
[goto secondchoice]
|
||||
* Option 2
|
||||
NPC: Fallthrough implicitly
|
||||
* Option 3
|
||||
NPC: Fallthrough implicitly again
|
||||
|
||||
:secondchoice
|
||||
* Fallthrough 1
|
||||
NPC: text 1
|
||||
* Fallthrough 2
|
||||
NPC: text 2
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestSimpleRunning,
|
||||
"SUDSTest.TestSimpleRunning",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestSimpleRunning::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(SimpleRunnerInput), SimpleRunnerInput.Len(), "SimpleRunnerInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "First node", Dlg, "Player", "Hello there");
|
||||
TestEqual("First node choices", Dlg->GetNumberOfChoices(), 1);
|
||||
TestTrue("First node choice text", Dlg->GetChoiceText(0).IsEmpty());
|
||||
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
|
||||
TestDialogueText(this, "Node 2", Dlg, "NPC", "Salutations fellow human");
|
||||
TestEqual("Node 2 choices", Dlg->GetNumberOfChoices(), 3);
|
||||
TestEqual("Node 2 choice text 0", Dlg->GetChoiceText(0).ToString(), "Actually no");
|
||||
TestEqual("Node 2 choice text 1", Dlg->GetChoiceText(1).ToString(), "Nested option");
|
||||
TestEqual("Node 2 choice text 2", Dlg->GetChoiceText(2).ToString(), "Another option");
|
||||
|
||||
TestTrue("Choice 1", Dlg->Choose(0));
|
||||
TestDialogueText(this, "Choice 1 Text", Dlg, "NPC", "How rude, bye then");
|
||||
// Goes straight to end
|
||||
TestFalse("Choice 1 Follow On", Dlg->Continue());
|
||||
TestTrue("Should be at end", Dlg->IsEnded());
|
||||
|
||||
// Start again
|
||||
Dlg->Restart();
|
||||
TestDialogueText(this, "First node", Dlg, "Player", "Hello there");
|
||||
TestEqual("First node choices", Dlg->GetNumberOfChoices(), 1);
|
||||
TestTrue("First node choice text", Dlg->GetChoiceText(0).IsEmpty());
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Node 2", Dlg, "NPC", "Salutations fellow human");
|
||||
|
||||
// Confirm we previously chose 0
|
||||
TestTrue("Choice 0 taken previously", Dlg->HasChoiceIndexBeenTakenPreviously(0));
|
||||
|
||||
TestTrue("Choice 2", Dlg->Choose(1));
|
||||
TestDialogueText(this, "Choice 2 Text", Dlg, "NPC", "Some nesting");
|
||||
TestEqual("Choice 2 nested choices", Dlg->GetNumberOfChoices(), 3);
|
||||
TestEqual("Choice 2 nested choice text 0", Dlg->GetChoiceText(0).ToString(), "Actually bye");
|
||||
TestEqual("Choice 2 nested choice text 1", Dlg->GetChoiceText(1).ToString(), "A fallthrough choice");
|
||||
TestEqual("Choice 2 nested choice text 2", Dlg->GetChoiceText(2).ToString(), "A goto choice");
|
||||
|
||||
TestTrue("Nested choice made", Dlg->Choose(0));
|
||||
TestDialogueText(this, "Nested choice made text", Dlg, "Player", "Gotta go!");
|
||||
TestTrue("Nested choice follow On", Dlg->Continue());
|
||||
TestDialogueText(this, "Nested choice follow on text", Dlg, "NPC", "Bye!");
|
||||
TestFalse("Nested choice follow On 2", Dlg->Continue());
|
||||
TestTrue("Should be at end", Dlg->IsEnded());
|
||||
|
||||
// Start again, this time from nested choice, and reset all state
|
||||
Dlg->Restart(true, "nestedstart");
|
||||
TestDialogueText(this, "nestedchoice restart Text", Dlg, "NPC", "Some nesting");
|
||||
TestTrue("Nested choice made", Dlg->Choose(1));
|
||||
TestDialogueText(this, "Nested choice 2 Text", Dlg, "NPC", "This should fall through to latterhalf");
|
||||
TestTrue("Nested choice 2 follow On", Dlg->Continue());
|
||||
// Should have fallen through
|
||||
TestDialogueText(this, "Fallthrough Text", Dlg, "Player", "This is the latter half of the discussion");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Fallthrough Text 2", Dlg, "NPC", "Yep, sure is");
|
||||
TestEqual("Fallthrough choices", Dlg->GetNumberOfChoices(), 3);
|
||||
TestEqual("Fallthrough choice text 0", Dlg->GetChoiceText(0).ToString(), "Go back to choice");
|
||||
TestEqual("Fallthrough choice text 1", Dlg->GetChoiceText(1).ToString(), "Return to the start");
|
||||
TestEqual("Fallthrough choice text 2", Dlg->GetChoiceText(2).ToString(), "Continue");
|
||||
|
||||
// Go back to choice
|
||||
TestTrue("Fallthrough choice made", Dlg->Choose(0));
|
||||
TestDialogueText(this, "Fallthrough Choice Text", Dlg, "NPC", "Okay!");
|
||||
// The Goto choice should have collapsed the choices such that we can get them immediately
|
||||
TestEqual("Fallthrough then goto choices", Dlg->GetNumberOfChoices(), 3);
|
||||
TestEqual("Fallthrough then goto choice text 0", Dlg->GetChoiceText(0).ToString(), "Actually no");
|
||||
TestEqual("Fallthrough then goto choice text 1", Dlg->GetChoiceText(1).ToString(), "Nested option");
|
||||
TestEqual("Fallthrough then goto choice text 2", Dlg->GetChoiceText(2).ToString(), "Another option");
|
||||
|
||||
// Restart to test another path
|
||||
Dlg->Restart(true, "nestedstart");
|
||||
TestDialogueText(this, "nestedchoice restart Text", Dlg, "NPC", "Some nesting");
|
||||
TestTrue("Nested choice made", Dlg->Choose(2));
|
||||
// This should be a direct goto to latterhalf
|
||||
TestDialogueText(this, "Direct goto", Dlg, "Player", "This is the latter half of the discussion");
|
||||
|
||||
|
||||
Dlg->Restart(true);
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestTrue("Choice 3", Dlg->Choose(2));
|
||||
TestDialogueText(this, "Choice 3 Text", Dlg, "Player", "What now?");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Choice 3 Text 2", Dlg, "NPC", "This is another fallthrough");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
// Should have fallen through
|
||||
TestDialogueText(this, "Direct goto", Dlg, "Player", "This is the latter half of the discussion");
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestSetVariableRunning,
|
||||
"SUDSTest.TestSetVariableRunning",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestSetVariableRunning::RunTest(const FString& Parameters)
|
||||
{
|
||||
// Number and plural formatting are locale-specific, so we must set it to a predefined value to produce the expected output
|
||||
FInternationalization::FCultureStateSnapshot CultureStateSnapshot;
|
||||
FInternationalization::Get().BackupCultureState(CultureStateSnapshot);
|
||||
FInternationalization::Get().SetCurrentCulture(TEXT("en-US"));
|
||||
ON_SCOPE_EXIT
|
||||
{
|
||||
FInternationalization::Get().RestoreCultureState(CultureStateSnapshot);
|
||||
};
|
||||
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(SetVariableRunnerInput), SetVariableRunnerInput.Len(), "SetVariableRunnerInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// We need to use dummy global vars since subsystem doesn't exist
|
||||
USUDSSubsystem::Test_DummyGlobalVariables.Empty();
|
||||
USUDSSubsystem::Test_DummyGlobalVariables.Add("GlobalIntSetOutside", 245);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg->Start();
|
||||
|
||||
// Check headers have run & initial variables are set
|
||||
TestEqual("Header: Player name", Dlg->GetVariableText("SpeakerName.Player").ToString(), "Protagonist");
|
||||
TestEqual("Header: Valet name", Dlg->GetVariableText("ValetName").ToString(), "Bob");
|
||||
TestEqual("Header: Some float", Dlg->GetVariableFloat("SomeFloat"), 12.5f);
|
||||
|
||||
// Check initial values
|
||||
TestEqual("Initial: Some int", Dlg->GetVariableInt("SomeInt"), 0);
|
||||
TestEqual("Initial: Some boolean", Dlg->GetVariableBoolean("SomeBoolean"), false);
|
||||
TestEqual("Initial: Some gender", Dlg->GetVariableGender("SomeGender"), ETextGender::Neuter);
|
||||
TestEqual("Initial: calculated int", Dlg->GetVariableInt("SomeCalculatedInt"), 14);
|
||||
TestTrue("Initial: calculated bool", Dlg->GetVariableBoolean("SomeCalculatedBoolean"));
|
||||
|
||||
|
||||
// Test globals
|
||||
TestFalse("Test not setting local var", Dlg->IsVariableSet("global.SomeGlobalInt"));
|
||||
TestFalse("Test not setting local var", Dlg->IsVariableSet("global.SomeGlobalFloat"));
|
||||
TestTrue("Test setting global var", USUDSSubsystem::Test_DummyGlobalVariables.Contains("SomeGlobalInt"));
|
||||
TestTrue("Test setting global var", USUDSSubsystem::Test_DummyGlobalVariables.Contains("SomeGlobalFloat"));
|
||||
|
||||
TestDialogueText(this, "Node 1", Dlg, "Player", "Hello");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
// Set node should have run
|
||||
TestEqual("Initial: Some int", Dlg->GetVariableInt("SomeInt"), 99);
|
||||
TestDialogueText(this, "Node 2", Dlg, "NPC", "Wotcha");
|
||||
|
||||
// Test that setting a new variable from another variable + 10 worked
|
||||
TestEqual("Some copied float", Dlg->GetVariableFloat("SomeOtherFloat"), 22.5f);
|
||||
TestEqual("Original float", Dlg->GetVariableFloat("SomeFloat"), 43.754f);
|
||||
|
||||
// Test globals
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Global text", Dlg, "Player", "Values are: 3, 37.5, 245");
|
||||
|
||||
TestEqual("Choices count", Dlg->GetNumberOfChoices(), 2);
|
||||
TestEqual("Choice 1 text", Dlg->GetChoiceText(0).ToString(), "Choice 1");
|
||||
TestEqual("Choice 2 text", Dlg->GetChoiceText(1).ToString(), "Choice 2");
|
||||
TestTrue("Choose 1", Dlg->Choose(0));
|
||||
TestEqual("Gender should be set", Dlg->GetVariableGender("SomeGender"), ETextGender::Masculine);
|
||||
TestEqual("Some boolean should be set", Dlg->GetVariableBoolean("SomeBoolean"), true);
|
||||
TestEqual("Valet name should not have changed", Dlg->GetVariableText("ValetName").ToString(), "Bob");
|
||||
TestEqual("Gender should not have changed", Dlg->GetVariableGender("SomeGender"), ETextGender::Masculine);
|
||||
TestDialogueText(this, "Choice end text", Dlg, "NPC", "Truth");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Final node", Dlg, "Player", "Well");
|
||||
TestFalse("Continue", Dlg->Continue());
|
||||
TestTrue("At end", Dlg->IsEnded());
|
||||
|
||||
// Restart and DON'T reset state
|
||||
Dlg->Restart(false);
|
||||
|
||||
// Variables should be the same
|
||||
// Except for the headers, which will have run again
|
||||
TestEqual("Player name should have been set again", Dlg->GetVariableText("SpeakerName.Player").ToString(), "Protagonist");
|
||||
TestEqual("Valet name should have been set again", Dlg->GetVariableText("ValetName").ToString(), "Bob");
|
||||
TestEqual("Some float should have been set again", Dlg->GetVariableFloat("SomeFloat"), 12.5f);
|
||||
TestEqual("Int should still be set", Dlg->GetVariableInt("SomeInt"), 99);
|
||||
TestEqual("Gender should still be set", Dlg->GetVariableGender("SomeGender"), ETextGender::Masculine);
|
||||
TestEqual("Some boolean should still be set", Dlg->GetVariableBoolean("SomeBoolean"), true);
|
||||
|
||||
// Restart and DO reset state
|
||||
Dlg->Restart(true);
|
||||
TestEqual("Player name should have been set again", Dlg->GetVariableText("SpeakerName.Player").ToString(), "Protagonist");
|
||||
TestEqual("Valet name should have been set again", Dlg->GetVariableText("ValetName").ToString(), "Bob");
|
||||
TestEqual("Some float should have been set again", Dlg->GetVariableFloat("SomeFloat"), 12.5f);
|
||||
TestEqual("Int should have been reset", Dlg->GetVariableInt("SomeInt"), 0);
|
||||
TestEqual("Gender should have been reset", Dlg->GetVariableGender("SomeGender"), ETextGender::Neuter);
|
||||
TestEqual("Some boolean should have been reset", Dlg->GetVariableBoolean("SomeBoolean"), false);
|
||||
|
||||
// Try the other path
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestTrue("Choose 2", Dlg->Choose(1));
|
||||
TestDialogueText(this, "Choice 2 text", Dlg, "NPC", "Surprise");
|
||||
TestEqual("Gender should not be changed yet", Dlg->GetVariableGender("SomeGender"), ETextGender::Masculine);
|
||||
TestEqual("Valet name should not be changed yet", Dlg->GetVariableText("ValetName").ToString(), "Bob");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Final node", Dlg, "Player", "Well");
|
||||
TestEqual("Gender should have changed", Dlg->GetVariableGender("SomeGender"), ETextGender::Feminine);
|
||||
TestEqual("Valet name should have changed", Dlg->GetVariableText("ValetName").ToString(), "Kate");
|
||||
TestEqual("Case insensitive set test", Dlg->GetVariableInt("SomeInt"), 101);
|
||||
|
||||
TestFalse("Continue", Dlg->Continue());
|
||||
TestTrue("At end", Dlg->IsEnded());
|
||||
|
||||
USUDSSubsystem::Test_DummyGlobalVariables.Empty();
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
const FString SpeakerNamesInput = R"RAWSUD(
|
||||
===
|
||||
[set SpeakerName.Player "Protagonist"]
|
||||
[set SpeakerName.NPC "Just Some Guy"]
|
||||
===
|
||||
:start
|
||||
Player: Hello there
|
||||
NPC: Salutations fellow human
|
||||
ThirdGuy: Sup
|
||||
[set SpeakerName.NPC "Actually A Villain"]
|
||||
NPC: Aha!
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestSpeakerNames,
|
||||
"SUDSTest.TestSpeakerNames",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
bool FTestSpeakerNames::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(SpeakerNamesInput), SpeakerNamesInput.Len(), "SpeakerNamesInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg->Start();
|
||||
|
||||
// Speaker ID test
|
||||
TestDialogueText(this, "Initial text", Dlg, "Player", "Hello there");
|
||||
TestEqual("Initial player speaker name", Dlg->GetSpeakerDisplayName().ToString(), "Protagonist");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text 2", Dlg, "NPC", "Salutations fellow human");
|
||||
TestEqual("Initial NPC speaker name", Dlg->GetSpeakerDisplayName().ToString(), "Just Some Guy");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text 3", Dlg, "ThirdGuy", "Sup");
|
||||
TestEqual("Initial ThirdGuy speaker name", Dlg->GetSpeakerDisplayName().ToString(), "ThirdGuy");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Text 4", Dlg, "NPC", "Aha!");
|
||||
TestEqual("NPC speaker name should have changed", Dlg->GetSpeakerDisplayName().ToString(), "Actually A Villain");
|
||||
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestFallthroughEdgeCase,
|
||||
"SUDSTest.TestFallthroughEdgeCase",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestFallthroughEdgeCase::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(FallthroughEdgeCaseInput), FallthroughEdgeCaseInput.Len(), "FallthroughEdgeCaseInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Initial text", Dlg, "NPC", "First line");
|
||||
TestEqual("Initial num choices", Dlg->GetNumberOfChoices(), 3);
|
||||
TestTrue("Choice 1", Dlg->Choose(0));
|
||||
TestDialogueText(this, "Second text", Dlg, "NPC", "Fallthrough via goto");
|
||||
if (TestEqual("Second num choices", Dlg->GetNumberOfChoices(), 2))
|
||||
{
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), "Fallthrough 1");
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), "Fallthrough 2");
|
||||
}
|
||||
|
||||
// Now prove that implicit fallthrough works in middle option
|
||||
Dlg->Restart();
|
||||
TestTrue("Choice 2", Dlg->Choose(1));
|
||||
TestDialogueText(this, "Second text", Dlg, "NPC", "Fallthrough implicitly");
|
||||
if (TestEqual("Second num choices", Dlg->GetNumberOfChoices(), 2))
|
||||
{
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), "Fallthrough 1");
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), "Fallthrough 2");
|
||||
}
|
||||
|
||||
// Now prove that implicit fallthrough works in last option
|
||||
Dlg->Restart();
|
||||
TestTrue("Choice 2", Dlg->Choose(2));
|
||||
TestDialogueText(this, "Second text", Dlg, "NPC", "Fallthrough implicitly again");
|
||||
if (TestEqual("Second num choices", Dlg->GetNumberOfChoices(), 2))
|
||||
{
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), "Fallthrough 1");
|
||||
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), "Fallthrough 2");
|
||||
}
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const FString LinesBetweenTextAndChoiceInput = R"RAWSUD(
|
||||
NPC: Hello
|
||||
NPC: Here's some choices
|
||||
[event SomeEvent]
|
||||
* Option 1
|
||||
NPC: This is option 1
|
||||
* Option 2
|
||||
NPC: This is option 2
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestLinesBetweenTextAndChoice,
|
||||
"SUDSTest.TestLinesBetweenTextAndChoiceInput",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestLinesBetweenTextAndChoice::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(LinesBetweenTextAndChoiceInput), LinesBetweenTextAndChoiceInput.Len(), "LinesBetweenTextAndChoiceInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Initial text", Dlg, "NPC", "Hello");
|
||||
TestTrue("Continue", Dlg->Continue());
|
||||
TestDialogueText(this, "Initial text", Dlg, "NPC", "Here's some choices");
|
||||
TestEqual("Initial num choices", Dlg->GetNumberOfChoices(), 2);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
UE_ENABLE_OPTIMIZATION
|
||||
146
Plugins/SUDS/Source/SUDSTest/Private/TestSaveState.cpp
Normal file
146
Plugins/SUDS/Source/SUDSTest/Private/TestSaveState.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
#include "SUDSDialogue.h"
|
||||
#include "SUDSLibrary.h"
|
||||
#include "SUDSMessageLogger.h"
|
||||
#include "SUDSScript.h"
|
||||
#include "SUDSScriptImporter.h"
|
||||
#include "TestUtils.h"
|
||||
#include "Misc/AutomationTest.h"
|
||||
|
||||
UE_DISABLE_OPTIMIZATION
|
||||
|
||||
const FString SaveStateInput = R"RAWSUD(
|
||||
===
|
||||
# To confirm that when resuming we don't run headers again
|
||||
[set y = -2.4]
|
||||
===
|
||||
[if {alreadyvisited}]
|
||||
[goto secondvisit]
|
||||
[endif]
|
||||
|
||||
NPC: Hello
|
||||
* First choice
|
||||
Player: I took the 1.1 choice
|
||||
[if {x} > 0]
|
||||
* Second choice (conditional)
|
||||
Player: I took the 1.2 choice
|
||||
* Third choice (conditional)
|
||||
Player: I took the 1.3 choice
|
||||
[else]
|
||||
* Second Alt Choice
|
||||
Player: I took the alt 1.2 choice
|
||||
[endif]
|
||||
* Common last choice
|
||||
Player: I took the 1.4 choice
|
||||
|
||||
[goto goodbye]
|
||||
|
||||
:secondvisit
|
||||
|
||||
NPC: Hello again you!
|
||||
|
||||
[if {y} < 0]
|
||||
Player: Y is less than 0
|
||||
NPC: How interesting
|
||||
* You don't sound that interested
|
||||
NPC: Well I was trying to be nice
|
||||
[if {x} == 0]
|
||||
* Also x is zero
|
||||
NPC: Fascinating
|
||||
[endif]
|
||||
* Well, better be off
|
||||
[goto goodbye]
|
||||
[elseif {y} == 0]
|
||||
Player: Y is zero
|
||||
NPC: So is my interest level
|
||||
Player: Rude
|
||||
|
||||
[else]
|
||||
Player: Who knows what Y is anyway
|
||||
[if {ponderous}]
|
||||
* Who knows what anything is?
|
||||
NPC: Get out
|
||||
[endif]
|
||||
[if {y} > 4.99]
|
||||
* It's more than I can count on one hand
|
||||
NPC: Well, that helps
|
||||
[else]
|
||||
* It's kind of small though
|
||||
NPC: Much like your brain
|
||||
[endif]
|
||||
* I'm done with this
|
||||
[endif]
|
||||
|
||||
Player: This is some fallthrough text
|
||||
|
||||
:goodbye
|
||||
NPC: Bye
|
||||
)RAWSUD";
|
||||
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestSaveState,
|
||||
"SUDSTest.TestSaveState",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestSaveState::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(SaveStateInput), SaveStateInput.Len(), "SaveStateInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
// Set x before start
|
||||
// No point settings y because that gets changed by headers
|
||||
Dlg->SetVariableInt("x", 5);
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "Text Node", Dlg, "NPC", "Hello");
|
||||
if (!TestEqual("Num choices", Dlg->GetNumberOfChoices(), 4))
|
||||
return true;
|
||||
|
||||
TestEqual("ChoiceText", Dlg->GetChoiceText(0).ToString(), "First choice");
|
||||
TestEqual("ChoiceText", Dlg->GetChoiceText(1).ToString(), "Second choice (conditional)");
|
||||
TestEqual("ChoiceText", Dlg->GetChoiceText(2).ToString(), "Third choice (conditional)");
|
||||
TestEqual("ChoiceText", Dlg->GetChoiceText(3).ToString(), "Common last choice");
|
||||
TestTrue("Choose", Dlg->Choose(2));
|
||||
TestDialogueText(this, "Text node", Dlg, "Player", "I took the 1.3 choice");
|
||||
|
||||
// Set value of y to test it's retained, and not reset by running headers
|
||||
Dlg->SetVariableFloat("y", 23.5f);
|
||||
|
||||
// Save it here
|
||||
auto SaveState = Dlg->GetSavedState();
|
||||
|
||||
// Re-construct the dialogue & restore
|
||||
auto Dlg2 = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
Dlg2->RestoreSavedState(SaveState);
|
||||
|
||||
// We should be back at the same point
|
||||
TestDialogueText(this, "Text node", Dlg2, "Player", "I took the 1.3 choice");
|
||||
// Check vars
|
||||
TestEqual("x value", Dlg2->GetVariableInt("x"), 5);
|
||||
TestEqual("y value", Dlg2->GetVariableFloat("y"), 23.5f);
|
||||
TestTrue("Continue", Dlg2->Continue());
|
||||
TestDialogueText(this, "Text node", Dlg2, "NPC", "Bye");
|
||||
|
||||
// Restart to check choices were remembered
|
||||
Dlg2->Restart();
|
||||
TestDialogueText(this, "Text Node", Dlg2, "NPC", "Hello");
|
||||
TestFalse("Choice not taken", Dlg2->HasChoiceIndexBeenTakenPreviously(0));
|
||||
TestFalse("Choice not taken", Dlg2->HasChoiceIndexBeenTakenPreviously(1));
|
||||
TestTrue("Choice not taken", Dlg2->HasChoiceIndexBeenTakenPreviously(2));
|
||||
TestFalse("Choice not taken", Dlg2->HasChoiceIndexBeenTakenPreviously(3));
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
}
|
||||
|
||||
UE_ENABLE_OPTIMIZATION
|
||||
124
Plugins/SUDS/Source/SUDSTest/Private/TestUserMetadata.cpp
Normal file
124
Plugins/SUDS/Source/SUDSTest/Private/TestUserMetadata.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include "SUDSDialogue.h"
|
||||
#include "SUDSLibrary.h"
|
||||
#include "SUDSMessageLogger.h"
|
||||
#include "SUDSScript.h"
|
||||
#include "SUDSScriptImporter.h"
|
||||
#include "TestUtils.h"
|
||||
#include "Misc/AutomationTest.h"
|
||||
|
||||
UE_DISABLE_OPTIMIZATION
|
||||
|
||||
// Assign known keys to the strings so we can detect
|
||||
const FString UserMetadataInput = R"RAWSUD(
|
||||
# No metadata
|
||||
Player: Good day sir
|
||||
#% IsGreeting = true
|
||||
NPC: Salutations to you too
|
||||
#% IntValue = 1
|
||||
#% Politeness 3.142
|
||||
Player: What are we doing today?
|
||||
# Test a variable-derived, expression metadata
|
||||
[set IntVariable 2]
|
||||
#% IntValue = {IntVariable} + 3
|
||||
#% LookMumNoEquals `OK_Dear`
|
||||
NPC: Looks like we're doing some testing. How about a choice?
|
||||
#% RequirePoshness = 10
|
||||
* Choice 1
|
||||
Player: Capital, old chap
|
||||
#% RequirePoshness = 15
|
||||
#% RequireTopHat = true
|
||||
* Choice 2
|
||||
Player: Top hole, dear boy
|
||||
* Choice 3
|
||||
Player: OK then
|
||||
)RAWSUD";
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestUserMetadata,
|
||||
"SUDSTest.TestUserMetadata",
|
||||
EAutomationTestFlags::EditorContext |
|
||||
EAutomationTestFlags::ClientContext |
|
||||
EAutomationTestFlags::ProductFilter)
|
||||
|
||||
|
||||
|
||||
bool FTestUserMetadata::RunTest(const FString& Parameters)
|
||||
{
|
||||
FSUDSMessageLogger Logger(false);
|
||||
FSUDSScriptImporter Importer;
|
||||
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(UserMetadataInput), UserMetadataInput.Len(), "UserMetadataInput", &Logger, true));
|
||||
|
||||
auto Script = NewObject<USUDSScript>(GetTransientPackage(), "Test");
|
||||
const ScopedStringTableHolder StringTableHolder;
|
||||
Importer.PopulateAsset(Script, StringTableHolder.StringTable);
|
||||
|
||||
// Script shouldn't be the owner of the dialogue but it's the only UObject we've got right now so why not
|
||||
auto Dlg = USUDSLibrary::CreateDialogue(Script, Script);
|
||||
|
||||
Dlg->Start();
|
||||
|
||||
TestDialogueText(this, "First node", Dlg, "Player", "Good day sir");
|
||||
TestEqual("Check metadata empty", Dlg->GetAllSpeakerLineUserMetadata().Num(), 0);
|
||||
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Salutations to you too");
|
||||
FSUDSValue Actual = Dlg->GetSpeakerLineUserMetadata(FName("IsGreeting"));
|
||||
if (TestTrue("Boolean test", Actual.GetType() == ESUDSValueType::Boolean))
|
||||
{
|
||||
TestEqual("Boolean test", Actual.GetBooleanValue(), true);
|
||||
}
|
||||
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Next", Dlg, "Player", "What are we doing today?");
|
||||
Actual = Dlg->GetSpeakerLineUserMetadata(FName("IntValue"));
|
||||
if (TestTrue("Int test", Actual.GetType() == ESUDSValueType::Int))
|
||||
{
|
||||
TestEqual("Int test", Actual.GetIntValue(), 1);
|
||||
}
|
||||
Actual = Dlg->GetSpeakerLineUserMetadata(FName("Politeness"));
|
||||
if (TestTrue("Float test", Actual.GetType() == ESUDSValueType::Float))
|
||||
{
|
||||
TestEqual("Float test", Actual.GetFloatValue(), 3.142f);
|
||||
}
|
||||
Dlg->Continue();
|
||||
TestDialogueText(this, "Next", Dlg, "NPC", "Looks like we're doing some testing. How about a choice?");
|
||||
Actual = Dlg->GetSpeakerLineUserMetadata(FName("IntValue"));
|
||||
if (TestTrue("Expression test", Actual.GetType() == ESUDSValueType::Int))
|
||||
{
|
||||
TestEqual("Expression test", Actual.GetIntValue(), 5);
|
||||
}
|
||||
Actual = Dlg->GetSpeakerLineUserMetadata(FName("LookMumNoEquals"));
|
||||
if (TestTrue("Name & no equals test", Actual.GetType() == ESUDSValueType::Name))
|
||||
{
|
||||
TestEqual("Name & no equals test", Actual.GetNameValue(), FName("OK_Dear"));
|
||||
}
|
||||
|
||||
if (TestEqual("Choice count", Dlg->GetNumberOfChoices(), 3))
|
||||
{
|
||||
Actual = Dlg->GetChoiceUserMetadata(0, FName("RequirePoshness"));
|
||||
if (TestTrue("Choice 0 test", Actual.GetType() == ESUDSValueType::Int))
|
||||
{
|
||||
TestEqual("Choice 0 test", Actual.GetIntValue(), 10);
|
||||
}
|
||||
Actual = Dlg->GetChoiceUserMetadata(1, FName("RequirePoshness"));
|
||||
if (TestTrue("Choice 1 test A", Actual.GetType() == ESUDSValueType::Int))
|
||||
{
|
||||
TestEqual("Choice 1 test A", Actual.GetIntValue(), 15);
|
||||
}
|
||||
Actual = Dlg->GetChoiceUserMetadata(1, FName("RequireTopHat"));
|
||||
if (TestTrue("Choice 1 test B", Actual.GetType() == ESUDSValueType::Boolean))
|
||||
{
|
||||
TestEqual("Choice 1 test B", Actual.GetBooleanValue(), true);
|
||||
}
|
||||
auto Choice1All = Dlg->GetAllChoiceUserMetadata(1);
|
||||
TestEqual("Choice 1 test count", Choice1All.Num(), 2);
|
||||
TestEqual("Choice 2 test", Dlg->GetAllChoiceUserMetadata(2).Num(), 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Script->MarkAsGarbage();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
UE_ENABLE_OPTIMIZATION
|
||||
297
Plugins/SUDS/Source/SUDSTest/Private/TestUtils.h
Normal file
297
Plugins/SUDS/Source/SUDSTest/Private/TestUtils.h
Normal file
@@ -0,0 +1,297 @@
|
||||
#pragma once
|
||||
#include "SUDSDialogue.h"
|
||||
#include "SUDSScriptNode.h"
|
||||
#include "SUDSScriptNodeText.h"
|
||||
#include "Internationalization/StringTable.h"
|
||||
#include "Internationalization/StringTableRegistry.h"
|
||||
#include "Misc/AutomationTest.h"
|
||||
#include "UObject/Package.h"
|
||||
|
||||
FORCEINLINE void TestDialogueText(FAutomationTestBase* T, const FString& NameForTest, USUDSDialogue* D, const FString& SpeakerID, const FString& Text)
|
||||
{
|
||||
T->TestEqual(NameForTest, D->GetSpeakerID(), SpeakerID);
|
||||
T->TestEqual(NameForTest, D->GetText().ToString(), Text);
|
||||
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestParsedText(FAutomationTestBase* T, const FString& NameForTest, const FSUDSParsedNode* Node, const FString& Speaker, const FString& Text)
|
||||
{
|
||||
if (T->TestNotNull(NameForTest, Node))
|
||||
{
|
||||
T->TestEqual(NameForTest, Node->NodeType, ESUDSParsedNodeType::Text);
|
||||
T->TestEqual(NameForTest, Node->Identifier, Speaker);
|
||||
T->TestEqual(NameForTest, Node->Text, Text);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestArgValue(FAutomationTestBase* T, const FString& NameForTest, const FSUDSValue& Actual, int Expected)
|
||||
{
|
||||
if (T->TestEqual(NameForTest, Actual.GetType(), ESUDSValueType::Int))
|
||||
{
|
||||
return T->TestEqual(NameForTest, Actual.GetIntValue(), Expected);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
FORCEINLINE bool TestArgValue(FAutomationTestBase* T, const FString& NameForTest, const FSUDSValue& Actual, float Expected)
|
||||
{
|
||||
if (T->TestEqual(NameForTest, Actual.GetType(), ESUDSValueType::Float))
|
||||
{
|
||||
return T->TestEqual(NameForTest, Actual.GetFloatValue(), Expected);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
FORCEINLINE bool TestArgValue(FAutomationTestBase* T, const FString& NameForTest, const FSUDSValue& Actual, ETextGender Expected)
|
||||
{
|
||||
if (T->TestEqual(NameForTest, Actual.GetType(), ESUDSValueType::Gender))
|
||||
{
|
||||
return T->TestEqual(NameForTest, Actual.GetGenderValue(), Expected);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
FORCEINLINE bool TestArgValue(FAutomationTestBase* T, const FString& NameForTest, const FSUDSValue& Actual, const FString& Expected)
|
||||
{
|
||||
if (T->TestEqual(NameForTest, Actual.GetType(), ESUDSValueType::Text))
|
||||
{
|
||||
return T->TestEqual(NameForTest, Actual.GetTextValue().ToString(), Expected);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
FORCEINLINE bool TestParsedSetLiteral(FAutomationTestBase* T, const FString& NameForTest, const FSUDSParsedNode* Node, const FString& VarName, V Literal)
|
||||
{
|
||||
if (T->TestNotNull(NameForTest, Node))
|
||||
{
|
||||
T->TestEqual(NameForTest, Node->NodeType, ESUDSParsedNodeType::SetVariable);
|
||||
T->TestEqual(NameForTest, Node->Identifier, VarName);
|
||||
if (T->TestTrue(NameForTest, Node->Expression.IsLiteral()))
|
||||
{
|
||||
TestArgValue(T, NameForTest,Node->Expression.GetLiteralValue(), Literal);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Explicit bool version of the above since otherwise it gets converted to int & fails
|
||||
FORCEINLINE bool TestParsedSetLiteral(FAutomationTestBase* T, const FString& NameForTest, const FSUDSParsedNode* Node, const FString& VarName, bool Literal)
|
||||
{
|
||||
if (T->TestNotNull(NameForTest, Node))
|
||||
{
|
||||
T->TestEqual(NameForTest, Node->NodeType, ESUDSParsedNodeType::SetVariable);
|
||||
T->TestEqual(NameForTest, Node->Identifier, VarName);
|
||||
if (T->TestTrue(NameForTest, Node->Expression.IsLiteral()))
|
||||
{
|
||||
T->TestEqual(NameForTest,Node->Expression.GetBooleanLiteralValue(), Literal);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestParsedSetLiteral(FAutomationTestBase* T, const FString& NameForTest, const FSUDSParsedNode* Node, const FString& VarName, const FName& Name)
|
||||
{
|
||||
if (T->TestNotNull(NameForTest, Node))
|
||||
{
|
||||
T->TestEqual(NameForTest, Node->NodeType, ESUDSParsedNodeType::SetVariable);
|
||||
T->TestEqual(NameForTest, Node->Identifier, VarName);
|
||||
if (T->TestTrue(NameForTest, Node->Expression.IsLiteral()))
|
||||
{
|
||||
T->TestEqual(NameForTest,Node->Expression.GetNameLiteralValue(), Name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestGetParsedNextNode(FAutomationTestBase* T, const FString& NameForTest, const FSUDSParsedNode* Node, FSUDSScriptImporter& Importer, bool bIsHeader, const FSUDSParsedNode** OutNextNode)
|
||||
{
|
||||
if (T->TestNotNull(NameForTest, Node))
|
||||
{
|
||||
if (T->TestEqual(NameForTest, Node->Edges.Num(), 1))
|
||||
{
|
||||
const int NextNodeIdx = Node->Edges[0].TargetNodeIdx;
|
||||
*OutNextNode = bIsHeader ? Importer.GetHeaderNode(NextNodeIdx) : Importer.GetNode(NextNodeIdx);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
*OutNextNode = nullptr;
|
||||
return false;
|
||||
}
|
||||
FORCEINLINE bool TestParsedChoice(FAutomationTestBase* T, const FString& NameForTest, const FSUDSParsedNode* Node, int ExpectedNumChoices)
|
||||
{
|
||||
if (T->TestNotNull(NameForTest, Node))
|
||||
{
|
||||
T->TestEqual(NameForTest, Node->NodeType, ESUDSParsedNodeType::Choice);
|
||||
T->TestEqual(NameForTest, Node->Edges.Num(), ExpectedNumChoices);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
FORCEINLINE bool TestParsedSelect(FAutomationTestBase* T, const FString& NameForTest, const FSUDSParsedNode* Node, int ExpectedNumEdges)
|
||||
{
|
||||
if (T->TestNotNull(NameForTest, Node))
|
||||
{
|
||||
T->TestEqual(NameForTest, Node->NodeType, ESUDSParsedNodeType::Select);
|
||||
T->TestEqual(NameForTest, Node->Edges.Num(), ExpectedNumEdges);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestParsedChoiceEdge(FAutomationTestBase* T, const FString& NameForTest, const FSUDSParsedNode* Node, int EdgeIndex, const FString& Text, FSUDSScriptImporter& Importer, const FSUDSParsedNode** OutNode)
|
||||
{
|
||||
*OutNode = nullptr;
|
||||
if (Node && Node->Edges.Num() > EdgeIndex)
|
||||
{
|
||||
auto& Edge = Node->Edges[EdgeIndex];
|
||||
T->TestEqual(NameForTest, Edge.Text, Text);
|
||||
const int Idx = Edge.TargetNodeIdx;
|
||||
*OutNode = Importer.GetNode(Idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestParsedSelectEdge(FAutomationTestBase* T, const FString& NameForTest, const FSUDSParsedNode* Node, int EdgeIndex, const FString& ConditionStr, FSUDSScriptImporter& Importer, const FSUDSParsedNode** OutNode)
|
||||
{
|
||||
*OutNode = nullptr;
|
||||
if (Node && Node->Edges.Num() > EdgeIndex)
|
||||
{
|
||||
auto& Edge = Node->Edges[EdgeIndex];
|
||||
T->TestEqual(NameForTest, Edge.ConditionExpression.GetSourceString(), ConditionStr);
|
||||
const int Idx = Edge.TargetNodeIdx;
|
||||
*OutNode = Importer.GetNode(Idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestParsedGoto(FAutomationTestBase* T, const FString& NameForTest, const FSUDSParsedNode* Node, FSUDSScriptImporter& Importer, const FSUDSParsedNode** OutNode)
|
||||
{
|
||||
if (T->TestNotNull(NameForTest, Node))
|
||||
{
|
||||
T->TestEqual(NameForTest, Node->NodeType, ESUDSParsedNodeType::Goto);
|
||||
const int Target = Importer.GetGotoTargetNodeIndex(Node->Identifier);
|
||||
*OutNode = Importer.GetNode(Target);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestTextNode(FAutomationTestBase* T, const FString& NameForTest, const USUDSScriptNode* Node, const FString& Speaker, const FString& Text)
|
||||
{
|
||||
if (T->TestNotNull(NameForTest, Node))
|
||||
{
|
||||
T->TestEqual(NameForTest, Node->GetNodeType(), ESUDSScriptNodeType::Text);
|
||||
if (auto TextNode = Cast<USUDSScriptNodeText>(Node))
|
||||
{
|
||||
T->TestEqual(NameForTest, TextNode->GetSpeakerID(), Speaker);
|
||||
T->TestEqual(NameForTest, TextNode->GetText().ToString(), Text);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestEdge(FAutomationTestBase* T, const FString& NameForTest, USUDSScriptNode* Node, int EdgeIndex, USUDSScriptNode** OutNode)
|
||||
{
|
||||
*OutNode = nullptr;
|
||||
if (Node && Node->GetEdgeCount() > EdgeIndex)
|
||||
{
|
||||
if (auto Edge = Node->GetEdge(EdgeIndex))
|
||||
{
|
||||
*OutNode = Edge->GetTargetNode().Get();
|
||||
return T->TestNotNull(NameForTest, *OutNode);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestChoiceNode(FAutomationTestBase* T, const FString& NameForTest, const USUDSScriptNode* Node, int NumChoices)
|
||||
{
|
||||
if (T->TestNotNull(NameForTest, Node))
|
||||
{
|
||||
T->TestEqual(NameForTest, Node->GetNodeType(), ESUDSScriptNodeType::Choice);
|
||||
return T->TestEqual(NameForTest, Node->GetEdgeCount(), NumChoices);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestSelectNode(FAutomationTestBase* T, const FString& NameForTest, const USUDSScriptNode* Node, int NumEdges)
|
||||
{
|
||||
if (T->TestNotNull(NameForTest, Node))
|
||||
{
|
||||
T->TestEqual(NameForTest, Node->GetNodeType(), ESUDSScriptNodeType::Select);
|
||||
return T->TestEqual(NameForTest, Node->GetEdgeCount(), NumEdges);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestChoiceEdge(FAutomationTestBase* T, const FString& NameForTest, USUDSScriptNode* Node, int EdgeIndex, const FString& Text, USUDSScriptNode** OutNode)
|
||||
{
|
||||
*OutNode = nullptr;
|
||||
if (Node && Node->GetEdgeCount() > EdgeIndex)
|
||||
{
|
||||
if (auto Edge = Node->GetEdge(EdgeIndex))
|
||||
{
|
||||
T->TestEqual(NameForTest, Edge->GetText().ToString(), Text);
|
||||
*OutNode = Edge->GetTargetNode().Get();
|
||||
return T->TestNotNull(NameForTest, *OutNode);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
FORCEINLINE bool TestSelectEdge(FAutomationTestBase* T, const FString& NameForTest, USUDSScriptNode* Node, int EdgeIndex, const FString& ConditionStr, USUDSScriptNode** OutNode)
|
||||
{
|
||||
*OutNode = nullptr;
|
||||
if (Node && Node->GetEdgeCount() > EdgeIndex)
|
||||
{
|
||||
if (auto Edge = Node->GetEdge(EdgeIndex))
|
||||
{
|
||||
T->TestEqual(NameForTest, Edge->GetCondition().GetSourceString(), ConditionStr);
|
||||
*OutNode = Edge->GetTargetNode().Get();
|
||||
return T->TestNotNull(NameForTest, *OutNode);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Helper to provide a string table just in scope
|
||||
struct ScopedStringTableHolder
|
||||
{
|
||||
public:
|
||||
|
||||
UStringTable* StringTable;
|
||||
|
||||
ScopedStringTableHolder()
|
||||
{
|
||||
StringTable = NewObject<UStringTable>(GetTransientPackage(), "TestStrings");
|
||||
}
|
||||
|
||||
~ScopedStringTableHolder()
|
||||
{
|
||||
// Tidy up string table
|
||||
// UStringTable constructor registered this table
|
||||
FStringTableRegistry::Get().UnregisterStringTable(StringTable->GetStringTableId());
|
||||
}
|
||||
|
||||
};
|
||||
30
Plugins/SUDS/Source/SUDSTest/SUDSTest.Build.cs
Normal file
30
Plugins/SUDS/Source/SUDSTest/SUDSTest.Build.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class SUDSTest : ModuleRules
|
||||
{
|
||||
public SUDSTest(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"SUDS",
|
||||
"SUDSEditor"
|
||||
}
|
||||
);
|
||||
|
||||
// Uncomment if you are using Slate UI
|
||||
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
|
||||
|
||||
// Uncomment if you are using online features
|
||||
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||
|
||||
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user