466 lines
20 KiB
C#
466 lines
20 KiB
C#
using GeometryTD.Definition;
|
||
using GeometryTD.Procedure;
|
||
using GeometryTD.UI;
|
||
using NUnit.Framework;
|
||
|
||
namespace GeometryTD.Tests.EditMode
|
||
{
|
||
public sealed class ProcedureMainServicesTests
|
||
{
|
||
[Test]
|
||
public void TryAdvanceRun_Returns_AdvancedToNextNode_For_Normal_Completion()
|
||
{
|
||
RunState runState = CreateTwoNodeRun();
|
||
|
||
ProcedureMainRunAdvanceResult result = ProcedureMainRunFlowService.TryAdvanceRun(
|
||
runState,
|
||
RunNodeCompletionStatus.Completed,
|
||
new BackpackInventoryData { Gold = 88 });
|
||
|
||
Assert.That(result, Is.EqualTo(ProcedureMainRunAdvanceResult.AdvancedToNextNode));
|
||
Assert.That(runState.IsCompleted, Is.False);
|
||
Assert.That(runState.Nodes[0].Status, Is.EqualTo(RunNodeStatus.Completed));
|
||
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(1));
|
||
Assert.That(runState.CurrentNode.Status, Is.EqualTo(RunNodeStatus.Available));
|
||
Assert.That(runState.RunInventorySnapshot.Gold, Is.EqualTo(88));
|
||
}
|
||
|
||
[Test]
|
||
public void TryAdvanceRun_Returns_NodeException_For_Exception_Fallback()
|
||
{
|
||
RunState runState = CreateTwoNodeRun();
|
||
|
||
ProcedureMainRunAdvanceResult result = ProcedureMainRunFlowService.TryAdvanceRun(
|
||
runState,
|
||
RunNodeCompletionStatus.Exception,
|
||
new BackpackInventoryData { Gold = 5 });
|
||
|
||
Assert.That(result, Is.EqualTo(ProcedureMainRunAdvanceResult.NodeException));
|
||
Assert.That(runState.IsCompleted, Is.False);
|
||
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(0));
|
||
Assert.That(runState.CurrentNode.Status, Is.EqualTo(RunNodeStatus.Exception));
|
||
Assert.That(runState.Nodes[1].Status, Is.EqualTo(RunNodeStatus.Locked));
|
||
Assert.That(runState.RunInventorySnapshot.Gold, Is.EqualTo(5));
|
||
}
|
||
|
||
[Test]
|
||
public void TryAdvanceRun_Returns_RunCompleted_When_Last_Node_Finishes()
|
||
{
|
||
RunState runState = RunStateFactory.Create(
|
||
LevelThemeType.Plain,
|
||
new BackpackInventoryData { Gold = 30 },
|
||
new[]
|
||
{
|
||
new RunNodeSeed { NodeId = 901, NodeType = RunNodeType.BossCombat, LinkedLevelId = 4 }
|
||
});
|
||
|
||
ProcedureMainRunAdvanceResult result = ProcedureMainRunFlowService.TryAdvanceRun(
|
||
runState,
|
||
RunNodeCompletionStatus.Completed,
|
||
new BackpackInventoryData { Gold = 123 });
|
||
|
||
Assert.That(result, Is.EqualTo(ProcedureMainRunAdvanceResult.RunCompleted));
|
||
Assert.That(runState.IsCompleted, Is.True);
|
||
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(1));
|
||
Assert.That(runState.CompletedNodeCount, Is.EqualTo(1));
|
||
Assert.That(runState.RunInventorySnapshot.Gold, Is.EqualTo(123));
|
||
}
|
||
|
||
[Test]
|
||
public void TryAdvanceRun_Returns_NoChange_When_Run_Cannot_Advance()
|
||
{
|
||
ProcedureMainRunAdvanceResult nullRunResult = ProcedureMainRunFlowService.TryAdvanceRun(
|
||
null,
|
||
RunNodeCompletionStatus.Completed,
|
||
new BackpackInventoryData { Gold = 1 });
|
||
|
||
Assert.That(nullRunResult, Is.EqualTo(ProcedureMainRunAdvanceResult.NoChange));
|
||
|
||
RunState completedRun = RunStateFactory.Create(
|
||
LevelThemeType.Plain,
|
||
new BackpackInventoryData { Gold = 10 },
|
||
new RunNodeSeed[0]);
|
||
|
||
ProcedureMainRunAdvanceResult completedRunResult = ProcedureMainRunFlowService.TryAdvanceRun(
|
||
completedRun,
|
||
RunNodeCompletionStatus.Completed,
|
||
new BackpackInventoryData { Gold = 20 });
|
||
|
||
Assert.That(completedRunResult, Is.EqualTo(ProcedureMainRunAdvanceResult.NoChange));
|
||
Assert.That(completedRun.RunInventorySnapshot.Gold, Is.EqualTo(10));
|
||
}
|
||
|
||
[Test]
|
||
public void TryAdvanceRun_Returns_NoChange_But_Still_Replaces_Snapshot_For_NonTerminal_Status()
|
||
{
|
||
RunState runState = CreateTwoNodeRun();
|
||
|
||
ProcedureMainRunAdvanceResult result = ProcedureMainRunFlowService.TryAdvanceRun(
|
||
runState,
|
||
RunNodeCompletionStatus.None,
|
||
new BackpackInventoryData { Gold = 999 });
|
||
|
||
Assert.That(result, Is.EqualTo(ProcedureMainRunAdvanceResult.NoChange));
|
||
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(0));
|
||
Assert.That(runState.CurrentNode.Status, Is.EqualTo(RunNodeStatus.Available));
|
||
Assert.That(runState.RunInventorySnapshot.Gold, Is.EqualTo(999));
|
||
}
|
||
|
||
[Test]
|
||
public void MatchesCurrentNode_Returns_True_For_Current_Node_And_Default_Wildcards()
|
||
{
|
||
RunState runState = CreateTwoNodeRun();
|
||
|
||
bool exactMatch = ProcedureMainNodeEventGuardService.MatchesCurrentNode(
|
||
runState,
|
||
101,
|
||
RunNodeType.Combat,
|
||
0);
|
||
bool wildcardMatch = ProcedureMainNodeEventGuardService.MatchesCurrentNode(
|
||
runState,
|
||
0,
|
||
RunNodeType.None,
|
||
-1);
|
||
|
||
Assert.That(exactMatch, Is.True);
|
||
Assert.That(wildcardMatch, Is.True);
|
||
}
|
||
|
||
[Test]
|
||
public void MatchesCurrentNode_Returns_False_For_Mismatched_Node_Event()
|
||
{
|
||
RunState runState = CreateTwoNodeRun();
|
||
|
||
bool nodeIdMismatch = ProcedureMainNodeEventGuardService.MatchesCurrentNode(
|
||
runState,
|
||
999,
|
||
RunNodeType.Combat,
|
||
0);
|
||
bool nodeTypeMismatch = ProcedureMainNodeEventGuardService.MatchesCurrentNode(
|
||
runState,
|
||
101,
|
||
RunNodeType.Shop,
|
||
0);
|
||
bool sequenceMismatch = ProcedureMainNodeEventGuardService.MatchesCurrentNode(
|
||
runState,
|
||
101,
|
||
RunNodeType.Combat,
|
||
1);
|
||
|
||
Assert.That(nodeIdMismatch, Is.False);
|
||
Assert.That(nodeTypeMismatch, Is.False);
|
||
Assert.That(sequenceMismatch, Is.False);
|
||
}
|
||
|
||
[Test]
|
||
public void MatchesCurrentNode_Returns_False_When_Run_Has_No_Current_Node()
|
||
{
|
||
RunState completedRun = RunStateFactory.Create(
|
||
LevelThemeType.Plain,
|
||
new BackpackInventoryData { Gold = 10 },
|
||
new RunNodeSeed[0]);
|
||
|
||
bool match = ProcedureMainNodeEventGuardService.MatchesCurrentNode(
|
||
completedRun,
|
||
1,
|
||
RunNodeType.Combat,
|
||
0);
|
||
|
||
Assert.That(match, Is.False);
|
||
}
|
||
|
||
[Test]
|
||
public void TryEnterCompletedPendingFinish_Shows_Dialog_Only_Once()
|
||
{
|
||
ProcedureMainRunCompletionResult firstResult =
|
||
ProcedureMainRunCompletionService.TryEnterCompletedPendingFinish(false);
|
||
ProcedureMainRunCompletionResult secondResult =
|
||
ProcedureMainRunCompletionService.TryEnterCompletedPendingFinish(true);
|
||
|
||
Assert.That(firstResult, Is.EqualTo(ProcedureMainRunCompletionResult.ShowCompletionDialog));
|
||
Assert.That(secondResult, Is.EqualTo(ProcedureMainRunCompletionResult.NoChange));
|
||
}
|
||
|
||
[Test]
|
||
public void TryConfirmReturnToMenu_Returns_Menu_Only_In_Completed_Pending_Finish()
|
||
{
|
||
ProcedureMainRunCompletionResult validResult =
|
||
ProcedureMainRunCompletionService.TryConfirmReturnToMenu(
|
||
ProcedureMainFlowPhase.RunCompletedPendingFinish,
|
||
false);
|
||
|
||
ProcedureMainRunCompletionResult hubResult =
|
||
ProcedureMainRunCompletionService.TryConfirmReturnToMenu(
|
||
ProcedureMainFlowPhase.Hub,
|
||
false);
|
||
|
||
ProcedureMainRunCompletionResult pendingResult =
|
||
ProcedureMainRunCompletionService.TryConfirmReturnToMenu(
|
||
ProcedureMainFlowPhase.RunCompletedPendingFinish,
|
||
true);
|
||
|
||
Assert.That(validResult, Is.EqualTo(ProcedureMainRunCompletionResult.ReturnToMenu));
|
||
Assert.That(hubResult, Is.EqualTo(ProcedureMainRunCompletionResult.NoChange));
|
||
Assert.That(pendingResult, Is.EqualTo(ProcedureMainRunCompletionResult.NoChange));
|
||
}
|
||
|
||
[Test]
|
||
public void ValidateCombatEntry_Returns_InventoryUnavailable_When_Inventory_Is_Null()
|
||
{
|
||
ProcedureMainCombatEntryValidationResult result =
|
||
ProcedureMainCombatEntryValidationService.Validate(null);
|
||
|
||
Assert.That(result.CanEnterCombat, Is.False);
|
||
Assert.That(result.BlockReason, Is.EqualTo(ProcedureMainCombatEntryBlockReason.InventoryUnavailable));
|
||
Assert.That(result.ValidationSummary, Is.Not.Null);
|
||
Assert.That(result.ValidationSummary.HasAnyValidParticipantTower, Is.False);
|
||
}
|
||
|
||
[Test]
|
||
public void ValidateCombatEntry_Returns_NoValidParticipantTower_When_ParticipantArea_Is_Empty()
|
||
{
|
||
BackpackInventoryData inventory = CreateCombatInventory();
|
||
inventory.ParticipantTowerInstanceIds.Clear();
|
||
|
||
ProcedureMainCombatEntryValidationResult result =
|
||
ProcedureMainCombatEntryValidationService.Validate(inventory);
|
||
|
||
Assert.That(result.CanEnterCombat, Is.False);
|
||
Assert.That(result.BlockReason, Is.EqualTo(ProcedureMainCombatEntryBlockReason.NoValidParticipantTower));
|
||
Assert.That(result.ValidationSummary.HasAnyValidParticipantTower, Is.False);
|
||
Assert.That(result.ValidationSummary.ValidTowers.Count, Is.EqualTo(0));
|
||
Assert.That(result.ValidationSummary.InvalidResults.Count, Is.EqualTo(0));
|
||
}
|
||
|
||
[Test]
|
||
public void ValidateCombatEntry_Returns_NoValidParticipantTower_When_AllParticipantTowers_Are_Invalid()
|
||
{
|
||
BackpackInventoryData inventory = CreateCombatInventory();
|
||
inventory.Towers[0].BaseComponentInstanceId = 99903;
|
||
|
||
ProcedureMainCombatEntryValidationResult result =
|
||
ProcedureMainCombatEntryValidationService.Validate(inventory);
|
||
|
||
Assert.That(result.CanEnterCombat, Is.False);
|
||
Assert.That(result.BlockReason, Is.EqualTo(ProcedureMainCombatEntryBlockReason.NoValidParticipantTower));
|
||
Assert.That(result.ValidationSummary.ValidTowers.Count, Is.EqualTo(0));
|
||
Assert.That(result.ValidationSummary.InvalidResults.Count, Is.EqualTo(1));
|
||
Assert.That(
|
||
result.ValidationSummary.InvalidResults[0].FailureReason,
|
||
Is.EqualTo(CombatParticipantTowerValidationFailureReason.MissingBaseComponent));
|
||
}
|
||
|
||
[Test]
|
||
public void ValidateCombatEntry_Returns_NoValidParticipantTower_When_AllParticipantTowers_Are_Broken()
|
||
{
|
||
BackpackInventoryData inventory = CreateCombatInventory();
|
||
inventory.MuzzleComponents[0].Endurance = 0f;
|
||
|
||
ProcedureMainCombatEntryValidationResult result =
|
||
ProcedureMainCombatEntryValidationService.Validate(inventory);
|
||
|
||
Assert.That(result.CanEnterCombat, Is.False);
|
||
Assert.That(result.BlockReason, Is.EqualTo(ProcedureMainCombatEntryBlockReason.NoValidParticipantTower));
|
||
Assert.That(result.ValidationSummary.ValidTowers.Count, Is.EqualTo(0));
|
||
Assert.That(result.ValidationSummary.InvalidResults.Count, Is.EqualTo(1));
|
||
Assert.That(
|
||
result.ValidationSummary.InvalidResults[0].FailureReason,
|
||
Is.EqualTo(CombatParticipantTowerValidationFailureReason.BrokenMuzzleComponent));
|
||
}
|
||
|
||
[Test]
|
||
public void ValidateCombatEntry_Returns_CanEnter_When_At_Least_One_ParticipantTower_Is_Valid()
|
||
{
|
||
BackpackInventoryData inventory = CreateCombatInventory();
|
||
inventory.Towers.Add(new TowerItemData
|
||
{
|
||
InstanceId = 90002,
|
||
Name = "非法塔",
|
||
MuzzleComponentInstanceId = 10001,
|
||
BearingComponentInstanceId = 20001,
|
||
BaseComponentInstanceId = 99903
|
||
});
|
||
inventory.ParticipantTowerInstanceIds.Add(90002);
|
||
|
||
ProcedureMainCombatEntryValidationResult result =
|
||
ProcedureMainCombatEntryValidationService.Validate(inventory);
|
||
|
||
Assert.That(result.CanEnterCombat, Is.True);
|
||
Assert.That(result.BlockReason, Is.EqualTo(ProcedureMainCombatEntryBlockReason.None));
|
||
Assert.That(result.ValidationSummary.ValidTowers.Count, Is.EqualTo(1));
|
||
Assert.That(result.ValidationSummary.ValidTowers[0].InstanceId, Is.EqualTo(90001));
|
||
Assert.That(result.ValidationSummary.InvalidResults.Count, Is.EqualTo(1));
|
||
}
|
||
|
||
[Test]
|
||
public void BuildInvalidParticipantTowerLog_Returns_None_When_InvalidResults_Are_Empty()
|
||
{
|
||
string log = ProcedureMainCombatEntryValidationService.BuildInvalidParticipantTowerLog(
|
||
new CombatParticipantTowerValidationSummary());
|
||
|
||
Assert.That(log, Is.EqualTo("none"));
|
||
}
|
||
|
||
[Test]
|
||
public void BuildInvalidParticipantTowerLog_Formats_TowerIds_And_Reasons()
|
||
{
|
||
CombatParticipantTowerValidationSummary summary = new CombatParticipantTowerValidationSummary
|
||
{
|
||
InvalidResults = new[]
|
||
{
|
||
new CombatParticipantTowerValidationResult
|
||
{
|
||
TowerInstanceId = 90002,
|
||
FailureReason = CombatParticipantTowerValidationFailureReason.MissingBaseComponent
|
||
},
|
||
new CombatParticipantTowerValidationResult
|
||
{
|
||
TowerInstanceId = 90003,
|
||
FailureReason = CombatParticipantTowerValidationFailureReason.MissingBearingComponent
|
||
}
|
||
}
|
||
};
|
||
|
||
string log = ProcedureMainCombatEntryValidationService.BuildInvalidParticipantTowerLog(summary);
|
||
|
||
Assert.That(log, Is.EqualTo("#90002:MissingBaseComponent, #90003:MissingBearingComponent"));
|
||
}
|
||
|
||
[Test]
|
||
public void BuildBlockedCombatDialogRawData_Returns_InventoryUnavailable_Message()
|
||
{
|
||
DialogFormRawData rawData = ProcedureMainCombatEntryValidationService.BuildBlockedCombatDialogRawData(
|
||
new ProcedureMainCombatEntryValidationResult
|
||
{
|
||
BlockReason = ProcedureMainCombatEntryBlockReason.InventoryUnavailable,
|
||
ValidationSummary = new CombatParticipantTowerValidationSummary()
|
||
});
|
||
|
||
Assert.That(rawData.Title, Is.EqualTo("无法进入战斗"));
|
||
Assert.That(rawData.Message, Is.EqualTo("当前无法读取库存快照,暂时不能进入战斗。请重新进入本轮流程后再试。"));
|
||
Assert.That(rawData.ConfirmText, Is.EqualTo("知道了"));
|
||
Assert.That(rawData.Mode, Is.EqualTo(1));
|
||
}
|
||
|
||
[Test]
|
||
public void BuildBlockedCombatDialogRawData_Returns_Generic_Message_When_NoParticipantTower_Is_Assigned()
|
||
{
|
||
DialogFormRawData rawData = ProcedureMainCombatEntryValidationService.BuildBlockedCombatDialogRawData(
|
||
new ProcedureMainCombatEntryValidationResult
|
||
{
|
||
BlockReason = ProcedureMainCombatEntryBlockReason.NoValidParticipantTower,
|
||
ValidationSummary = new CombatParticipantTowerValidationSummary()
|
||
});
|
||
|
||
Assert.That(
|
||
rawData.Message,
|
||
Is.EqualTo("参战区至少需要 1 座完整装配了枪口、轴承、底座的塔,才能进入战斗。"));
|
||
}
|
||
|
||
[Test]
|
||
public void BuildBlockedCombatDialogRawData_Lists_Invalid_Tower_Reasons()
|
||
{
|
||
DialogFormRawData rawData = ProcedureMainCombatEntryValidationService.BuildBlockedCombatDialogRawData(
|
||
new ProcedureMainCombatEntryValidationResult
|
||
{
|
||
BlockReason = ProcedureMainCombatEntryBlockReason.NoValidParticipantTower,
|
||
ValidationSummary = new CombatParticipantTowerValidationSummary
|
||
{
|
||
InvalidResults = new[]
|
||
{
|
||
new CombatParticipantTowerValidationResult
|
||
{
|
||
TowerInstanceId = 90002,
|
||
FailureReason = CombatParticipantTowerValidationFailureReason.MissingBaseComponent
|
||
},
|
||
new CombatParticipantTowerValidationResult
|
||
{
|
||
TowerInstanceId = 90003,
|
||
FailureReason = CombatParticipantTowerValidationFailureReason.MissingMuzzleComponent
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
Assert.That(
|
||
rawData.Message,
|
||
Is.EqualTo("参战区没有可出战的完整塔。\n塔 #90002 缺少底座组件。\n塔 #90003 缺少枪口组件。"));
|
||
}
|
||
|
||
[Test]
|
||
public void BuildBlockedCombatDialogRawData_Lists_Broken_Component_Reasons()
|
||
{
|
||
DialogFormRawData rawData = ProcedureMainCombatEntryValidationService.BuildBlockedCombatDialogRawData(
|
||
new ProcedureMainCombatEntryValidationResult
|
||
{
|
||
BlockReason = ProcedureMainCombatEntryBlockReason.NoValidParticipantTower,
|
||
ValidationSummary = new CombatParticipantTowerValidationSummary
|
||
{
|
||
InvalidResults = new[]
|
||
{
|
||
new CombatParticipantTowerValidationResult
|
||
{
|
||
TowerInstanceId = 90002,
|
||
FailureReason = CombatParticipantTowerValidationFailureReason.BrokenBaseComponent
|
||
},
|
||
new CombatParticipantTowerValidationResult
|
||
{
|
||
TowerInstanceId = 90003,
|
||
FailureReason = CombatParticipantTowerValidationFailureReason.BrokenMuzzleComponent
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
Assert.That(
|
||
rawData.Message,
|
||
Is.EqualTo("参战区没有可出战的完整塔。\n塔 #90002 底座组件耐久为 0,无法参战。\n塔 #90003 枪口组件耐久为 0,无法参战。"));
|
||
}
|
||
|
||
private static RunState CreateTwoNodeRun()
|
||
{
|
||
return RunStateFactory.Create(
|
||
LevelThemeType.Plain,
|
||
new BackpackInventoryData { Gold = 50 },
|
||
new[]
|
||
{
|
||
new RunNodeSeed { NodeId = 101, NodeType = RunNodeType.Combat, LinkedLevelId = 1 },
|
||
new RunNodeSeed { NodeId = 102, NodeType = RunNodeType.Event }
|
||
});
|
||
}
|
||
|
||
private static BackpackInventoryData CreateCombatInventory()
|
||
{
|
||
BackpackInventoryData inventory = new BackpackInventoryData();
|
||
inventory.MuzzleComponents.Add(new MuzzleCompItemData
|
||
{
|
||
InstanceId = 10001,
|
||
Name = "枪口",
|
||
Endurance = 100f
|
||
});
|
||
inventory.BearingComponents.Add(new BearingCompItemData
|
||
{
|
||
InstanceId = 20001,
|
||
Name = "轴承",
|
||
Endurance = 100f
|
||
});
|
||
inventory.BaseComponents.Add(new BaseCompItemData
|
||
{
|
||
InstanceId = 30001,
|
||
Name = "底座",
|
||
Endurance = 100f
|
||
});
|
||
inventory.Towers.Add(new TowerItemData
|
||
{
|
||
InstanceId = 90001,
|
||
Name = "合法塔",
|
||
MuzzleComponentInstanceId = 10001,
|
||
BearingComponentInstanceId = 20001,
|
||
BaseComponentInstanceId = 30001
|
||
});
|
||
inventory.ParticipantTowerInstanceIds.Add(90001);
|
||
return inventory;
|
||
}
|
||
}
|
||
}
|