1045 lines
47 KiB
C++
1045 lines
47 KiB
C++
#include "SUDSLibrary.h"
|
|
#include "SUDSMessageLogger.h"
|
|
#include "SUDSScript.h"
|
|
#include "SUDSScriptImporter.h"
|
|
#include "TestUtils.h"
|
|
|
|
UE_DISABLE_OPTIMIZATION
|
|
|
|
const FString BasicConditionalInput = R"RAWSUD(
|
|
Player: Hello
|
|
[if {x} == 1]
|
|
NPC: Reply when x == 1
|
|
[if {y} > 0]
|
|
Player: Player text when x ==1 and y > 0
|
|
[endif]
|
|
[elseif {x} > 1]
|
|
NPC: Reply when x > 1
|
|
[else]
|
|
NPC: Reply when x is something else
|
|
[endif]
|
|
[if {z}]
|
|
Player: the end is true
|
|
[else]
|
|
Player: the end is false
|
|
[endif]
|
|
NPC: OK
|
|
)RAWSUD";
|
|
|
|
const FString ConditionalChoiceInput = R"RAWSUD(
|
|
# First test has a regular choice first before conditional
|
|
NPC: Hello
|
|
* First choice
|
|
Player: I took the 1.1 choice
|
|
[if {y} == 2]
|
|
* 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
|
|
# Second test has conditional choice as the first one
|
|
NPC: OK next question
|
|
[if {y} == 0]
|
|
* First conditional choice
|
|
Player: I took the 2.1 choice
|
|
[elseif {y} == 1]
|
|
* Second conditional choice
|
|
Player: I took the 2.2 choice
|
|
[if {q} == 10]
|
|
* Nested conditional choice
|
|
Player: I took the 2.2.1 choice
|
|
[endif]
|
|
[else]
|
|
* Third conditional choice
|
|
Player: I took the 2.3 choice
|
|
[endif]
|
|
* Final common choice
|
|
Player: I took the 2.4 choice
|
|
NPC: Bye
|
|
)RAWSUD";
|
|
|
|
const FString SiblingConditionalChoiceInput = R"RAWSUD(
|
|
NPC: Hello
|
|
[if {x} == 0]
|
|
* First choice
|
|
Player: I took the 1.1 choice
|
|
[endif]
|
|
[if {y} == 1]
|
|
* Second choice (conditional)
|
|
Player: I took the 1.2 choice
|
|
[endif]
|
|
[if {z} == 1]
|
|
* Third choice (conditional)
|
|
Player: I took the 1.3 choice
|
|
[endif]
|
|
* Second Alt Choice
|
|
|
|
NPC: End
|
|
)RAWSUD";
|
|
|
|
const FString SiblingConditionalChoiceWithElseInput = R"RAWSUD(
|
|
NPC: Hello
|
|
[if {x} == 0]
|
|
* First choice
|
|
Player: I took the 1.1 choice
|
|
[elseif {SomeBool}]
|
|
* First alt choice elseif
|
|
Player: I took the 1.1 elseif choice
|
|
[else]
|
|
* First alt choice
|
|
Player: I took the 1.1b choice
|
|
[endif]
|
|
[if {y} == 1]
|
|
* Second choice (conditional)
|
|
Player: I took the 1.2 choice
|
|
[elseif {SomeBool}]
|
|
* Second alt choice elseif
|
|
Player: I took the 1.2 elseif choice
|
|
[else]
|
|
* Second alt choice
|
|
Player: I took the 1.2b choice
|
|
[endif]
|
|
[if {z} == 1]
|
|
* Third choice (conditional)
|
|
Player: I took the 1.3 choice
|
|
[elseif {SomeBool}]
|
|
* Third alt choice elseif
|
|
Player: I took the 1.3 elseif choice
|
|
[else]
|
|
* Third alt choice
|
|
Player: I took the 1.3b choice
|
|
[endif]
|
|
NPC: End
|
|
)RAWSUD";
|
|
|
|
|
|
const FString MixedChoiceAndBranchInput = R"RAWSUD(
|
|
[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
|
|
|
|
[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} > 5]
|
|
* 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(FTestBasicConditionals,
|
|
"SUDSTest.TestBasicConditionals",
|
|
EAutomationTestFlags::EditorContext |
|
|
EAutomationTestFlags::ClientContext |
|
|
EAutomationTestFlags::ProductFilter)
|
|
|
|
|
|
bool FTestBasicConditionals::RunTest(const FString& Parameters)
|
|
{
|
|
FSUDSMessageLogger Logger(false);
|
|
FSUDSScriptImporter Importer;
|
|
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(BasicConditionalInput), BasicConditionalInput.Len(), "BasicConditionalInput", &Logger, true));
|
|
|
|
// Test the content of the parsing
|
|
auto NextNode = Importer.GetNode(0);
|
|
if (!TestNotNull("Root node should exist", NextNode))
|
|
return false;
|
|
|
|
TestParsedText(this, "First node", NextNode, "Player", "Hello");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
|
|
if (TestParsedSelect(this, "First Select node", NextNode, 3))
|
|
{
|
|
auto SelectNode = NextNode;
|
|
TestParsedSelectEdge(this, "First select edge 1 (if)", SelectNode, 0, "{x} == 1", Importer, &NextNode);
|
|
TestParsedText(this, "Nested node 1", NextNode, "NPC", "Reply when x == 1");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
// Note: even though this is a single "if", there is an implicit "else" edge created
|
|
if (TestParsedSelect(this, "Nested Select node", NextNode, 2))
|
|
{
|
|
// Nested select
|
|
auto SelectNode2 = NextNode;
|
|
TestParsedSelectEdge(this, "Nested select edge 1", SelectNode2, 0, "{y} > 0", Importer, &NextNode);
|
|
TestParsedText(this, "Nested node edge 1", NextNode, "Player", "Player text when x ==1 and y > 0");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
if (TestParsedSelect(this, "Fallthrough select", NextNode, 2))
|
|
{
|
|
auto SelectNode3 = NextNode;
|
|
TestParsedSelectEdge(this, "Final select edge 1", SelectNode3, 0, "{z}", Importer, &NextNode);
|
|
TestParsedText(this, "Final select edge 1 text", NextNode, "Player", "the end is true");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Final fallthrough", NextNode, "NPC", "OK");
|
|
|
|
TestParsedSelectEdge(this, "Final select edge 2", SelectNode3, 1, "", Importer, &NextNode);
|
|
TestParsedText(this, "Final select edge 2 text", NextNode, "Player", "the end is false");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Final fallthrough", NextNode, "NPC", "OK");
|
|
|
|
}
|
|
|
|
// Go back to the nested select
|
|
// This "else" edge should have been created automatically to fall through
|
|
TestParsedSelectEdge(this, "Nested select edge 2", SelectNode2, 1, "", Importer, &NextNode);
|
|
// Just test it gets to the fallthrough, we've already tested the continuation from there
|
|
TestParsedSelect(this, "Fallthrough select", NextNode, 2);
|
|
|
|
}
|
|
TestParsedSelectEdge(this, "First select edge 2 (elseif)", SelectNode, 1, "{x} > 1", Importer, &NextNode);
|
|
TestParsedText(this, "Select node 2", NextNode, "NPC", "Reply when x > 1");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
// Just test it gets to the fallthrough, we've already tested the continuation from there
|
|
TestParsedSelect(this, "Fallthrough select", NextNode, 2);
|
|
|
|
TestParsedSelectEdge(this, "First select edge 2 (else)", SelectNode, 2, "", Importer, &NextNode);
|
|
TestParsedText(this, "Select node 3", NextNode, "NPC", "Reply when x is something else");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
// Just test it gets to the fallthrough, we've already tested the continuation from there
|
|
TestParsedSelect(this, "Fallthrough select", NextNode, 2);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestSiblingConditionals,
|
|
"SUDSTest.TestSiblingConditionals",
|
|
EAutomationTestFlags::EditorContext |
|
|
EAutomationTestFlags::ClientContext |
|
|
EAutomationTestFlags::ProductFilter)
|
|
|
|
bool FTestSiblingConditionals::RunTest(const FString& Parameters)
|
|
{
|
|
FSUDSScriptImporter Importer;
|
|
FSUDSMessageLogger Logger(false);
|
|
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(SiblingConditionalChoiceInput), SiblingConditionalChoiceInput.Len(), "SiblingConditionalChoiceInput", &Logger, true));
|
|
|
|
// Test the content of the parsing
|
|
auto NextNode = Importer.GetNode(0);
|
|
if (!TestNotNull("Root node should exist", NextNode))
|
|
return false;
|
|
TestParsedText(this, "Text node", NextNode, "NPC", "Hello");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
if (TestParsedChoice(this, "Root Choice", NextNode, 4))
|
|
{
|
|
auto RootChoice = NextNode;
|
|
// Sibling choices all get their own nodes
|
|
// Bit wasteful to have C -> S -> C -> Text instead of just C -> T but you never know how many choices would
|
|
// be in each select level
|
|
TestParsedChoiceEdge(this, "Choice 0", RootChoice, 0, "", Importer, &NextNode);
|
|
if (TestParsedSelect(this, "Select 0", NextNode, 1))
|
|
{
|
|
TestParsedSelectEdge(this, "Select 0", NextNode, 0, "{x} == 0", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 0 sub", NextNode, 0, "First choice", Importer, &NextNode);
|
|
TestParsedText(this, "Text 0", NextNode, "Player", "I took the 1.1 choice");
|
|
}
|
|
TestParsedChoiceEdge(this, "Choice 1", RootChoice, 1, "", Importer, &NextNode);
|
|
if (TestParsedSelect(this, "Select 1", NextNode, 1))
|
|
{
|
|
TestParsedSelectEdge(this, "Select 1", NextNode, 0, "{y} == 1", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 1 sub", NextNode, 0, "Second choice (conditional)", Importer, &NextNode);
|
|
TestParsedText(this, "Text 1", NextNode, "Player", "I took the 1.2 choice");
|
|
}
|
|
TestParsedChoiceEdge(this, "Choice 2", RootChoice, 2, "", Importer, &NextNode);
|
|
if (TestParsedSelect(this, "Select 2", NextNode, 1))
|
|
{
|
|
TestParsedSelectEdge(this, "Select 2", NextNode, 0, "{z} == 1", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 2 sub", NextNode, 0, "Third choice (conditional)", Importer, &NextNode);
|
|
TestParsedText(this, "Text 1", NextNode, "Player", "I took the 1.3 choice");
|
|
}
|
|
// Dangling choice with no condition
|
|
TestParsedChoiceEdge(this, "Choice 3", RootChoice, 3, "Second Alt Choice", Importer, &NextNode);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestSiblingConditionalsWithElse,
|
|
"SUDSTest.TestSiblingConditionalsWithElse",
|
|
EAutomationTestFlags::EditorContext |
|
|
EAutomationTestFlags::ClientContext |
|
|
EAutomationTestFlags::ProductFilter)
|
|
|
|
bool FTestSiblingConditionalsWithElse::RunTest(const FString& Parameters)
|
|
{
|
|
FSUDSScriptImporter Importer;
|
|
FSUDSMessageLogger Logger(false);
|
|
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(SiblingConditionalChoiceWithElseInput), SiblingConditionalChoiceWithElseInput.Len(), "SiblingConditionalChoiceWithElseInput", &Logger, true));
|
|
|
|
// Test the content of the parsing
|
|
auto NextNode = Importer.GetNode(0);
|
|
if (!TestNotNull("Root node should exist", NextNode))
|
|
return false;
|
|
TestParsedText(this, "Text node", NextNode, "NPC", "Hello");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
if (TestParsedChoice(this, "Root Choice", NextNode, 3))
|
|
{
|
|
auto RootChoice = NextNode;
|
|
// Sibling choices all get their own nodes
|
|
// Bit wasteful to have C -> S -> C -> Text instead of just C -> T but you never know how many choices would
|
|
// be in each select level
|
|
TestParsedChoiceEdge(this, "Choice 0", RootChoice, 0, "", Importer, &NextNode);
|
|
if (TestParsedSelect(this, "Select 0", NextNode, 3))
|
|
{
|
|
const FSUDSParsedNode* SelectNode = NextNode;
|
|
TestParsedSelectEdge(this, "Select 0", SelectNode, 0, "{x} == 0", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 0 sub", NextNode, 0, "First choice", Importer, &NextNode);
|
|
TestParsedText(this, "Text 0", NextNode, "Player", "I took the 1.1 choice");
|
|
|
|
// It's key to have the same "elseif {SomeBool}" for every sibling "if" to prove that the elseifs don't get merged
|
|
// just because their own conditions are the same. They're different because they're dependent on their own ifs not
|
|
// being true.
|
|
TestParsedSelectEdge(this, "Select 0 ELSEIF", SelectNode, 1, "{SomeBool}", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 0 sub ELSEIF", NextNode, 0, "First alt choice elseif", Importer, &NextNode);
|
|
TestParsedText(this, "Text 0 ELSEIF", NextNode, "Player", "I took the 1.1 elseif choice");
|
|
|
|
TestParsedSelectEdge(this, "Select 0 ELSE", SelectNode, 2, "", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 0 sub ELSE", NextNode, 0, "First alt choice", Importer, &NextNode);
|
|
TestParsedText(this, "Text 0 ELSE", NextNode, "Player", "I took the 1.1b choice");
|
|
}
|
|
TestParsedChoiceEdge(this, "Choice 1", RootChoice, 1, "", Importer, &NextNode);
|
|
if (TestParsedSelect(this, "Select 1", NextNode, 3))
|
|
{
|
|
const FSUDSParsedNode* SelectNode = NextNode;
|
|
TestParsedSelectEdge(this, "Select 1", SelectNode, 0, "{y} == 1", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 1 sub", NextNode, 0, "Second choice (conditional)", Importer, &NextNode);
|
|
TestParsedText(this, "Text 1", NextNode, "Player", "I took the 1.2 choice");
|
|
|
|
TestParsedSelectEdge(this, "Select 1 ELSEIF", SelectNode, 1, "{SomeBool}", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 1 sub ELSEIF", NextNode, 0, "Second alt choice elseif", Importer, &NextNode);
|
|
TestParsedText(this, "Text 1 ELSEIF", NextNode, "Player", "I took the 1.2 elseif choice");
|
|
|
|
TestParsedSelectEdge(this, "Select 1 ELSE", SelectNode, 2, "", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 1 sub ELSE", NextNode, 0, "Second alt choice", Importer, &NextNode);
|
|
TestParsedText(this, "Text 1 ELSE", NextNode, "Player", "I took the 1.2b choice");
|
|
}
|
|
TestParsedChoiceEdge(this, "Choice 2", RootChoice, 2, "", Importer, &NextNode);
|
|
if (TestParsedSelect(this, "Select 2", NextNode, 3))
|
|
{
|
|
const FSUDSParsedNode* SelectNode = NextNode;
|
|
TestParsedSelectEdge(this, "Select 2", SelectNode, 0, "{z} == 1", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 2 sub", NextNode, 0, "Third choice (conditional)", Importer, &NextNode);
|
|
TestParsedText(this, "Text 2", NextNode, "Player", "I took the 1.3 choice");
|
|
|
|
TestParsedSelectEdge(this, "Select 2 ELSEIF", SelectNode, 1, "{SomeBool}", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 2 sub ELSEIF", NextNode, 0, "Third alt choice elseif", Importer, &NextNode);
|
|
TestParsedText(this, "Text 2 ELSE", NextNode, "Player", "I took the 1.3 elseif choice");
|
|
|
|
TestParsedSelectEdge(this, "Select 2 ELSE", SelectNode, 2, "", Importer, &NextNode);
|
|
TestParsedChoiceEdge(this, "Choice 2 sub ELSE", NextNode, 0, "Third alt choice", Importer, &NextNode);
|
|
TestParsedText(this, "Text 2 ELSE", NextNode, "Player", "I took the 1.3b choice");
|
|
}
|
|
// Dangling choice with no condition
|
|
TestParsedChoiceEdge(this, "Choice 3", RootChoice, 3, "Second Alt Choice", Importer, &NextNode);
|
|
}
|
|
|
|
|
|
// Test running
|
|
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);
|
|
|
|
// For the first run, do not set any state
|
|
Dlg->Start();
|
|
|
|
TestDialogueText(this, "First node", Dlg, "NPC", "Hello");
|
|
if (TestEqual("Choice count", Dlg->GetNumberOfChoices(), 3))
|
|
{
|
|
TestEqual("Choice 0", Dlg->GetChoiceText(0).ToString(), TEXT("First choice"));
|
|
TestEqual("Choice 1", Dlg->GetChoiceText(1).ToString(), TEXT("Second alt choice"));
|
|
TestEqual("Choice 2", Dlg->GetChoiceText(2).ToString(), TEXT("Third alt choice"));
|
|
}
|
|
|
|
// restart, set some variables to alter the path
|
|
Dlg->SetVariableInt("x", 1);
|
|
Dlg->SetVariableInt("y", 1);
|
|
Dlg->SetVariableInt("z", 0);
|
|
Dlg->Restart(false);
|
|
|
|
TestDialogueText(this, "First node", Dlg, "NPC", "Hello");
|
|
if (TestEqual("Choice count", Dlg->GetNumberOfChoices(), 3))
|
|
{
|
|
TestEqual("Choice 0", Dlg->GetChoiceText(0).ToString(), TEXT("First alt choice"));
|
|
TestEqual("Choice 1", Dlg->GetChoiceText(1).ToString(), TEXT("Second choice (conditional)"));
|
|
TestEqual("Choice 2", Dlg->GetChoiceText(2).ToString(), TEXT("Third alt choice"));
|
|
}
|
|
|
|
// restart, set some variables to alter the path
|
|
Dlg->SetVariableBoolean("SomeBool", true);
|
|
Dlg->SetVariableInt("x", 1);
|
|
Dlg->SetVariableInt("y", 0);
|
|
Dlg->SetVariableInt("z", 1);
|
|
Dlg->Restart(false);
|
|
|
|
TestDialogueText(this, "First node", Dlg, "NPC", "Hello");
|
|
if (TestEqual("Choice count", Dlg->GetNumberOfChoices(), 3))
|
|
{
|
|
TestEqual("Choice 0", Dlg->GetChoiceText(0).ToString(), TEXT("First alt choice elseif"));
|
|
TestEqual("Choice 1", Dlg->GetChoiceText(1).ToString(), TEXT("Second alt choice elseif"));
|
|
TestEqual("Choice 2", Dlg->GetChoiceText(2).ToString(), TEXT("Third choice (conditional)"));
|
|
}
|
|
|
|
Script->MarkAsGarbage();
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestRunningBasicConditionals,
|
|
"SUDSTest.TestRunningBasicConditionals",
|
|
EAutomationTestFlags::EditorContext |
|
|
EAutomationTestFlags::ClientContext |
|
|
EAutomationTestFlags::ProductFilter)
|
|
|
|
|
|
bool FTestRunningBasicConditionals::RunTest(const FString& Parameters)
|
|
{
|
|
FSUDSScriptImporter Importer;
|
|
FSUDSMessageLogger Logger(false);
|
|
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(BasicConditionalInput), BasicConditionalInput.Len(), "BasicConditionalInput", &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);
|
|
|
|
// For the first run, do not set any state
|
|
Dlg->Start();
|
|
|
|
TestDialogueText(this, "First node", Dlg, "Player", "Hello");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text", Dlg, "NPC", "Reply when x is something else");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text", Dlg, "Player", "the end is false");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text", Dlg, "NPC", "OK");
|
|
TestFalse("Continue", Dlg->Continue());
|
|
TestTrue("End", Dlg->IsEnded());
|
|
|
|
|
|
// restart, set some variables to alter the path
|
|
Dlg->Restart(true);
|
|
Dlg->SetVariableInt("x", 1);
|
|
Dlg->SetVariableInt("y", -1);
|
|
Dlg->SetVariableBoolean("z", true);
|
|
|
|
TestDialogueText(this, "First node", Dlg, "Player", "Hello");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text", Dlg, "NPC", "Reply when x == 1");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text", Dlg, "Player", "the end is true");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text", Dlg, "NPC", "OK");
|
|
TestFalse("Continue", Dlg->Continue());
|
|
TestTrue("End", Dlg->IsEnded());
|
|
|
|
|
|
// restart, set some variables to alter the path
|
|
Dlg->Restart(true);
|
|
Dlg->SetVariableInt("x", 1);
|
|
Dlg->SetVariableInt("y", 10);
|
|
Dlg->SetVariableBoolean("z", false);
|
|
|
|
TestDialogueText(this, "First node", Dlg, "Player", "Hello");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text", Dlg, "NPC", "Reply when x == 1");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text", Dlg, "Player", "Player text when x ==1 and y > 0");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text", Dlg, "Player", "the end is false");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text", Dlg, "NPC", "OK");
|
|
TestFalse("Continue", Dlg->Continue());
|
|
TestTrue("End", Dlg->IsEnded());
|
|
|
|
Script->MarkAsGarbage();
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestConditionalChoices,
|
|
"SUDSTest.TestConditionalChoices",
|
|
EAutomationTestFlags::EditorContext |
|
|
EAutomationTestFlags::ClientContext |
|
|
EAutomationTestFlags::ProductFilter)
|
|
|
|
|
|
bool FTestConditionalChoices::RunTest(const FString& Parameters)
|
|
{
|
|
FSUDSMessageLogger Logger(false);
|
|
FSUDSScriptImporter Importer;
|
|
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(ConditionalChoiceInput), ConditionalChoiceInput.Len(), "ConditionalChoiceInput", &Logger, true));
|
|
|
|
// Test the content of the parsing
|
|
auto NextNode = Importer.GetNode(0);
|
|
if (!TestNotNull("Root node should exist", NextNode))
|
|
return false;
|
|
|
|
TestParsedText(this, "First node", NextNode, "NPC", "Hello");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
// This will have one choice edge for the unconditional choice, then an edge to the select node
|
|
if (TestParsedChoice(this, "First choice node", NextNode, 3))
|
|
{
|
|
auto ChoiceNode = NextNode;
|
|
TestParsedChoiceEdge(this, "First choice edge 1", ChoiceNode, 0, "First choice", Importer, &NextNode);
|
|
TestParsedText(this, "First choice edge 1 text", NextNode, "Player", "I took the 1.1 choice");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Fallthrough to next question", NextNode, "NPC", "OK next question");
|
|
|
|
// Second edge has no text because it's going to a select for other choices
|
|
TestParsedChoiceEdge(this, "First choice edge 2", ChoiceNode, 1, "", Importer, &NextNode);
|
|
// 2 edges because only if/else
|
|
if (TestParsedSelect(this, "First choice edge 2 should link to select", NextNode, 2))
|
|
{
|
|
auto SelectNode = NextNode;
|
|
TestParsedSelectEdge(this, "Select edge 0", SelectNode, 0, "{y} == 2", Importer, &NextNode);
|
|
// 2 choices in this if clause
|
|
if (TestParsedChoice(this, "Choice node under first if", NextNode, 2))
|
|
{
|
|
auto Choice2 = NextNode;
|
|
TestParsedChoiceEdge(this, "y == 2 choice edge 1", Choice2, 0, "Second choice (conditional)", Importer, &NextNode);
|
|
TestParsedText(this, "y == 2 choice edge 1 text", NextNode, "Player", "I took the 1.2 choice");
|
|
// This should fall through to text node after the choices
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Fallthrough to next text", NextNode, "NPC", "OK next question");
|
|
|
|
TestParsedChoiceEdge(this, "y == 2 choice edge 2", Choice2, 1, "Third choice (conditional)", Importer, &NextNode);
|
|
TestParsedText(this, "y == 2 choice edge 2 text", NextNode, "Player", "I took the 1.3 choice");
|
|
// This should fall through to text node after the choices
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Fallthrough to next text", NextNode, "NPC", "OK next question");
|
|
|
|
}
|
|
TestParsedSelectEdge(this, "Select edge 1 (else)", SelectNode, 1, "", Importer, &NextNode);
|
|
// 1 choice under this else section
|
|
if (TestParsedChoice(this, "Choice node under first else", NextNode, 1))
|
|
{
|
|
auto Choice3 = NextNode;
|
|
TestParsedChoiceEdge(this, "y == 2 choice edge 1", Choice3, 0, "Second Alt Choice", Importer, &NextNode);
|
|
TestParsedText(this, "Else edge text", NextNode, "Player", "I took the alt 1.2 choice");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Fallthrough to next question", NextNode, "NPC", "OK next question");
|
|
}
|
|
|
|
// Final fallthrough choice, unconditional
|
|
TestParsedChoiceEdge(this, "First choice edge 3", ChoiceNode, 2, "Common last choice", Importer, &NextNode);
|
|
TestParsedText(this, "Fallthrough to next text", NextNode, "Player", "I took the 1.4 choice");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Fallthrough to next question", NextNode, "NPC", "OK next question");
|
|
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
// This time the first choice is already in the select, BUT we should have inserted an extra choice anyway
|
|
// Should be 2 edges because the last common choice should have attached itself
|
|
if (TestParsedChoice(this, "Inserted choice before select", NextNode, 2))
|
|
{
|
|
auto InsertedChoice = NextNode;
|
|
TestParsedChoiceEdge(this, "Inserted choice edge 1", InsertedChoice, 0, "", Importer, &NextNode);
|
|
|
|
// There's an if, elseif, and else edge
|
|
if (TestParsedSelect(this, "Select node under next question", NextNode, 3))
|
|
{
|
|
auto SelectNode2 = NextNode;
|
|
TestParsedSelectEdge(this, "Select edge 0", SelectNode2, 0, "{y} == 0", Importer, &NextNode);
|
|
// Choice node under if, only 1 in this section
|
|
if (TestParsedChoice(this, "Choice node under select", NextNode, 1))
|
|
{
|
|
TestParsedChoiceEdge(this, "First choice edge", NextNode, 0, "First conditional choice", Importer, &NextNode);
|
|
TestParsedText(this, "First choice text", NextNode, "Player", "I took the 2.1 choice");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Final fallthrough", NextNode, "NPC", "Bye");
|
|
|
|
}
|
|
TestParsedSelectEdge(this, "Select edge 1", SelectNode2, 1, "{y} == 1", Importer, &NextNode);
|
|
// Choice node under elseif, only 1 in this section
|
|
if (TestParsedChoice(this, "Choice node under select 2", NextNode, 2))
|
|
{
|
|
auto Choice4 = NextNode;
|
|
TestParsedChoiceEdge(this, "Second choice edge 1", Choice4, 0, "Second conditional choice", Importer, &NextNode);
|
|
TestParsedText(this, "First choice text", NextNode, "Player", "I took the 2.2 choice");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Final fallthrough", NextNode, "NPC", "Bye");
|
|
|
|
// Next edge goes to a select
|
|
TestParsedChoiceEdge(this, "Second choice edge 2", Choice4, 1, "", Importer, &NextNode);
|
|
// There is only an "if" in this nested select. No implicit "else" edge should exist because it's a choice node
|
|
if (TestParsedSelect(this, "Select node under next question", NextNode, 1))
|
|
{
|
|
TestParsedSelectEdge(this, "Nested select edge 1", NextNode, 0, "{q} == 10", Importer, &NextNode);
|
|
if (TestParsedChoice(this, "Choice node under nested select", NextNode, 1))
|
|
{
|
|
TestParsedChoiceEdge(this, "Nested choice edge 1", NextNode, 0, "Nested conditional choice", Importer, &NextNode);
|
|
TestParsedText(this, "First choice text", NextNode, "Player", "I took the 2.2.1 choice");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Final fallthrough", NextNode, "NPC", "Bye");
|
|
}
|
|
}
|
|
|
|
}
|
|
TestParsedSelectEdge(this, "Select edge 2", SelectNode2, 2, "", Importer, &NextNode);
|
|
// Choice node under elseif, only 1 in this section
|
|
if (TestParsedChoice(this, "Choice node under select 3", NextNode, 1))
|
|
{
|
|
TestParsedChoiceEdge(this, "Choice under select 3 edge", NextNode, 0, "Third conditional choice", Importer, &NextNode);
|
|
TestParsedText(this, "First choice text", NextNode, "Player", "I took the 2.3 choice");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Final fallthrough", NextNode, "NPC", "Bye");
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// Finally the last catch-all choice which attached itself to the choice node we created above the select
|
|
TestParsedChoiceEdge(this, "Inserted choice edge 2", InsertedChoice, 1, "Final common choice", Importer, &NextNode);
|
|
TestParsedText(this, "First choice text", NextNode, "Player", "I took the 2.4 choice");
|
|
TestGetParsedNextNode(this, "Get next", NextNode, Importer, false, &NextNode);
|
|
TestParsedText(this, "Final fallthrough", NextNode, "NPC", "Bye");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestMixedChoiceAndBranch,
|
|
"SUDSTest.TestMixedChoiceAndBranch",
|
|
EAutomationTestFlags::EditorContext |
|
|
EAutomationTestFlags::ClientContext |
|
|
EAutomationTestFlags::ProductFilter)
|
|
|
|
|
|
bool FTestMixedChoiceAndBranch::RunTest(const FString& Parameters)
|
|
{
|
|
FSUDSMessageLogger Logger(false);
|
|
FSUDSScriptImporter Importer;
|
|
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(MixedChoiceAndBranchInput), MixedChoiceAndBranchInput.Len(), "MixedChoiceAndBranchInput", &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);
|
|
|
|
// For the first run, do not set any state
|
|
Dlg->Start();
|
|
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Hello");
|
|
TestEqual("Num choices", Dlg->GetNumberOfChoices(), 3);
|
|
TestEqual("Num choices", Dlg->GetChoiceText(0).ToString(), "First choice");
|
|
TestEqual("Num choices", Dlg->GetChoiceText(1).ToString(), "Second Alt Choice");
|
|
TestEqual("Num choices", Dlg->GetChoiceText(2).ToString(), "Common last choice");
|
|
TestTrue("Choose", Dlg->Choose(0));
|
|
TestDialogueText(this, "Text node", Dlg, "Player", "I took the 1.1 choice");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Bye");
|
|
|
|
// Choices are on first node so need to set before restart
|
|
Dlg->SetVariableInt("x", 10);
|
|
Dlg->Restart(false);
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Hello");
|
|
if (TestEqual("Num choices", Dlg->GetNumberOfChoices(), 4))
|
|
{
|
|
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");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Bye");
|
|
}
|
|
|
|
Dlg->SetVariableBoolean("alreadyvisited", true);
|
|
Dlg->SetVariableInt("y", -1);
|
|
Dlg->Restart(false);
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Hello again");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "Player", "Y is less than 0");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "How interesting");
|
|
if (TestEqual("Num choices", Dlg->GetNumberOfChoices(), 2))
|
|
{
|
|
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), "You don't sound that interested");
|
|
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), "Well, better be off");
|
|
TestTrue("Choose", Dlg->Choose(1));
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Bye");
|
|
}
|
|
|
|
Dlg->SetVariableBoolean("alreadyvisited", true);
|
|
Dlg->SetVariableInt("y", -1);
|
|
Dlg->SetVariableInt("x", 0);
|
|
Dlg->Restart(false);
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Hello again");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "Player", "Y is less than 0");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "How interesting");
|
|
if (TestEqual("Num choices", Dlg->GetNumberOfChoices(), 3))
|
|
{
|
|
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), "You don't sound that interested");
|
|
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), "Also x is zero");
|
|
TestEqual("Choice text", Dlg->GetChoiceText(2).ToString(), "Well, better be off");
|
|
TestTrue("Choose", Dlg->Choose(1));
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Fascinating");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "Player", "This is some fallthrough text");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Bye");
|
|
}
|
|
|
|
|
|
Dlg->SetVariableBoolean("alreadyvisited", true);
|
|
Dlg->SetVariableInt("y", 123);
|
|
Dlg->SetVariableBoolean("ponderous", true);
|
|
Dlg->Restart(false);
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Hello again");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "Player", "Who knows what Y is anyway");
|
|
if (TestEqual("Num choices", Dlg->GetNumberOfChoices(), 3))
|
|
{
|
|
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), "Who knows what anything is?");
|
|
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), "It's more than I can count on one hand");
|
|
TestEqual("Choice text", Dlg->GetChoiceText(2).ToString(), "I'm done with this");
|
|
TestTrue("Choose", Dlg->Choose(0));
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Get out");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "Player", "This is some fallthrough text");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Bye");
|
|
|
|
}
|
|
|
|
Dlg->SetVariableBoolean("alreadyvisited", true);
|
|
Dlg->SetVariableInt("y", 4);
|
|
Dlg->SetVariableBoolean("ponderous", true);
|
|
Dlg->Restart(false);
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Hello again");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "Player", "Who knows what Y is anyway");
|
|
if (TestEqual("Num choices", Dlg->GetNumberOfChoices(), 3))
|
|
{
|
|
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), "Who knows what anything is?");
|
|
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), "It's kind of small though");
|
|
TestEqual("Choice text", Dlg->GetChoiceText(2).ToString(), "I'm done with this");
|
|
TestTrue("Choose", Dlg->Choose(2));
|
|
TestDialogueText(this, "Text node", Dlg, "Player", "This is some fallthrough text");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Bye");
|
|
|
|
}
|
|
|
|
Script->MarkAsGarbage();
|
|
return true;
|
|
}
|
|
|
|
const FString ChoiceAfterConditionals = R"RAWSUD(
|
|
NPC: Hello
|
|
[if {AltPath}]
|
|
Player: This is the alternate path before choice
|
|
[else]
|
|
Player: This is the main path
|
|
[endif]
|
|
* Choice 1
|
|
NPC: Choice 1 after conditional
|
|
* Choice 2
|
|
NPC: Choice 2 after conditional
|
|
|
|
NPC: Bye
|
|
)RAWSUD";
|
|
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestChoiceAfterConditionals,
|
|
"SUDSTest.TestChoiceAfterConditionals",
|
|
EAutomationTestFlags::EditorContext |
|
|
EAutomationTestFlags::ClientContext |
|
|
EAutomationTestFlags::ProductFilter)
|
|
|
|
|
|
bool FTestChoiceAfterConditionals::RunTest(const FString& Parameters)
|
|
{
|
|
FSUDSMessageLogger Logger(false);
|
|
FSUDSScriptImporter Importer;
|
|
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(ChoiceAfterConditionals), ChoiceAfterConditionals.Len(), "ChoiceAfterConditionals", &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);
|
|
|
|
// For the first run, do not set any state
|
|
Dlg->Start();
|
|
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Hello");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "Player", "This is the main path");
|
|
TestEqual("Number of choices", Dlg->GetNumberOfChoices(), 2);
|
|
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), "Choice 1");
|
|
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), "Choice 2");
|
|
TestTrue("Choose", Dlg->Choose(0));
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Choice 1 after conditional");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Bye");
|
|
|
|
Script->MarkAsGarbage();
|
|
return true;
|
|
}
|
|
|
|
const FString ChoiceAfterNestedConditionals = R"RAWSUD(
|
|
NPC: Hello
|
|
[if {AltPath}]
|
|
Player: This is the alternate path before choice
|
|
[else]
|
|
Player: This is the main path
|
|
[if {AltPath2}]
|
|
Player: An alt-alt path
|
|
[endif]
|
|
[endif]
|
|
:choices
|
|
* Choice 1
|
|
NPC: Choice 1 after conditional
|
|
* Choice 2
|
|
NPC: Choice 2 after conditional
|
|
|
|
NPC: Bye
|
|
)RAWSUD";
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestChoiceAfterNestedConditionals,
|
|
"SUDSTest.TestChoiceAfterNestedConditionals",
|
|
EAutomationTestFlags::EditorContext |
|
|
EAutomationTestFlags::ClientContext |
|
|
EAutomationTestFlags::ProductFilter)
|
|
|
|
|
|
bool FTestChoiceAfterNestedConditionals::RunTest(const FString& Parameters)
|
|
{
|
|
FSUDSMessageLogger Logger(false);
|
|
FSUDSScriptImporter Importer;
|
|
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(ChoiceAfterNestedConditionals), ChoiceAfterNestedConditionals.Len(), "ChoiceAfterNestedConditionals", &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);
|
|
|
|
// For the first run, do not set any state
|
|
Dlg->Start();
|
|
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Hello");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "Player", "This is the main path");
|
|
TestEqual("Number of choices", Dlg->GetNumberOfChoices(), 2);
|
|
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), "Choice 1");
|
|
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), "Choice 2");
|
|
TestTrue("Choose", Dlg->Choose(0));
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Choice 1 after conditional");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Bye");
|
|
|
|
Script->MarkAsGarbage();
|
|
return true;
|
|
}
|
|
|
|
const FString VarsSetBetweenTextAndChoiceChoice = R"RAWSUD(
|
|
# prove that the set node is run before the choices are evaluated even though it's after the text node
|
|
NPC: Hello
|
|
[set AltPath true]
|
|
[if {AltPath}]
|
|
* Alt Choice
|
|
Player: This is the alternate path choice
|
|
[else]
|
|
* Main Choice
|
|
Player: Main path choice
|
|
[endif]
|
|
* Common Choice
|
|
Player: Common choice here
|
|
NPC: Bye
|
|
)RAWSUD";
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FVarsSetBetweenTextAndChoiceChoice,
|
|
"SUDSTest.VarsSetBetweenTextAndChoiceChoice",
|
|
EAutomationTestFlags::EditorContext |
|
|
EAutomationTestFlags::ClientContext |
|
|
EAutomationTestFlags::ProductFilter)
|
|
|
|
|
|
bool FVarsSetBetweenTextAndChoiceChoice::RunTest(const FString& Parameters)
|
|
{
|
|
FSUDSMessageLogger Logger(false);
|
|
FSUDSScriptImporter Importer;
|
|
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(VarsSetBetweenTextAndChoiceChoice), VarsSetBetweenTextAndChoiceChoice.Len(), "VarsSetBetweenTextAndChoiceChoice", &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);
|
|
|
|
// For the first run, do not set any state
|
|
Dlg->Start();
|
|
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Hello");
|
|
TestEqual("Number of choices", Dlg->GetNumberOfChoices(), 2);
|
|
TestEqual("Choice text", Dlg->GetChoiceText(0).ToString(), "Alt Choice");
|
|
TestEqual("Choice text", Dlg->GetChoiceText(1).ToString(), "Common Choice");
|
|
|
|
Script->MarkAsGarbage();
|
|
return true;
|
|
}
|
|
|
|
|
|
const FString MultipleOptionalChoicesWithLinesBetweenTextAndChoice = R"RAWSUD(
|
|
NPC: Hello
|
|
NPC: Testing
|
|
# This event being here could mess up multiple sibling optional choices
|
|
[event SomeEvent]
|
|
* Choice 1?
|
|
Player: Choice 1
|
|
[if {Opt2}]
|
|
* Optional Choice 2?
|
|
Player: Choice 2
|
|
[endif]
|
|
[if {Opt3}]
|
|
* Optional Choice 3?
|
|
Player: Choice 3
|
|
[endif]
|
|
* Back
|
|
Player: going back
|
|
NPC: Fallthrough
|
|
)RAWSUD";
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FTestMultipleOptionalChoicesWithLinesBetweenTextAndChoice,
|
|
"SUDSTest.TestMultipleOptionalChoicesWithLinesBetweenTextAndChoice",
|
|
EAutomationTestFlags::EditorContext |
|
|
EAutomationTestFlags::ClientContext |
|
|
EAutomationTestFlags::ProductFilter)
|
|
|
|
|
|
bool FTestMultipleOptionalChoicesWithLinesBetweenTextAndChoice::RunTest(const FString& Parameters)
|
|
{
|
|
FSUDSMessageLogger Logger(false);
|
|
FSUDSScriptImporter Importer;
|
|
TestTrue("Import should succeed", Importer.ImportFromBuffer(GetData(MultipleOptionalChoicesWithLinesBetweenTextAndChoice), MultipleOptionalChoicesWithLinesBetweenTextAndChoice.Len(), "MultipleOptionalChoicesWithLinesBetweenTextAndChoice", &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);
|
|
|
|
// For the first run, do not set any state
|
|
Dlg->Start();
|
|
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Hello");
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Testing");
|
|
TestEqual("Number of choices", Dlg->GetNumberOfChoices(), 2);
|
|
TestEqual("Choice text 0", Dlg->GetChoiceText(0).ToString(), "Choice 1?");
|
|
TestEqual("Choice text 1", Dlg->GetChoiceText(1).ToString(), "Back");
|
|
|
|
Dlg->Restart(true);
|
|
Dlg->SetVariableBoolean("Opt2", true);
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Testing");
|
|
TestEqual("Number of choices", Dlg->GetNumberOfChoices(), 3);
|
|
TestEqual("Choice text 0", Dlg->GetChoiceText(0).ToString(), "Choice 1?");
|
|
TestEqual("Choice text 1", Dlg->GetChoiceText(1).ToString(), "Optional Choice 2?");
|
|
TestEqual("Choice text 2", Dlg->GetChoiceText(2).ToString(), "Back");
|
|
|
|
Dlg->Restart(true);
|
|
Dlg->SetVariableBoolean("Opt3", true);
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Testing");
|
|
TestEqual("Number of choices", Dlg->GetNumberOfChoices(), 3);
|
|
TestEqual("Choice text 0", Dlg->GetChoiceText(0).ToString(), "Choice 1?");
|
|
TestEqual("Choice text 1", Dlg->GetChoiceText(1).ToString(), "Optional Choice 3?");
|
|
TestEqual("Choice text 2", Dlg->GetChoiceText(2).ToString(), "Back");
|
|
|
|
Dlg->Restart(true);
|
|
Dlg->SetVariableBoolean("Opt2", true);
|
|
Dlg->SetVariableBoolean("Opt3", true);
|
|
TestTrue("Continue", Dlg->Continue());
|
|
TestDialogueText(this, "Text node", Dlg, "NPC", "Testing");
|
|
TestEqual("Number of choices", Dlg->GetNumberOfChoices(), 4);
|
|
TestEqual("Choice text 0", Dlg->GetChoiceText(0).ToString(), "Choice 1?");
|
|
TestEqual("Choice text 1", Dlg->GetChoiceText(1).ToString(), "Optional Choice 2?");
|
|
TestEqual("Choice text 2", Dlg->GetChoiceText(2).ToString(), "Optional Choice 3?");
|
|
TestEqual("Choice text 3", Dlg->GetChoiceText(3).ToString(), "Back");
|
|
|
|
Script->MarkAsGarbage();
|
|
return true;
|
|
}
|
|
|
|
|
|
UE_ENABLE_OPTIMIZATION |