From fbb7458ea780c424ab827b70ce9bea888eba11d2 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Sat, 11 Jul 2026 07:32:18 +0000
Subject: [PATCH] =?UTF-8?q?test:=20Phase2/3=20=E3=82=AB=E3=83=90=E3=83=AC?=
=?UTF-8?q?=E3=83=83=E3=82=B8=E8=A3=9C=E5=BC=B7=20-=20CommandProcess,=20In?=
=?UTF-8?q?termissionForm,=20thin=20file=20expansion?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
CommandProcessTests: ProceedInput/ProceedCommand の状態遷移テスト
IntermissionFormTests: ExchangeFormCommand のテスト
既存薄テストファイルの拡充
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../Commands/CommandLaunchTests.cs | 57 ++++++
.../Commands/CommandMapCommandTests.cs | 58 ++++++
.../Commands/CommandProcessTests.cs | 167 ++++++++++++++++++
.../Commands/CommandUnitSpTests.cs | 74 ++++++++
.../Commands/CommandUnitSupplyTests.cs | 57 ++++++
.../Intermissions/IntermissionFormTests.cs | 163 +++++++++++++++++
6 files changed, 576 insertions(+)
create mode 100644 SRC.Sharp/SRCCoreTests/Commands/CommandProcessTests.cs
create mode 100644 SRC.Sharp/SRCCoreTests/Intermissions/IntermissionFormTests.cs
diff --git a/SRC.Sharp/SRCCoreTests/Commands/CommandLaunchTests.cs b/SRC.Sharp/SRCCoreTests/Commands/CommandLaunchTests.cs
index 1b44011b..a672eded 100644
--- a/SRC.Sharp/SRCCoreTests/Commands/CommandLaunchTests.cs
+++ b/SRC.Sharp/SRCCoreTests/Commands/CommandLaunchTests.cs
@@ -142,5 +142,62 @@ public void LaunchCmdID_CancelFromListBox_SelectedCommandCleared()
Assert.AreEqual("", src.Commands.SelectedCommand);
}
+
+ // ──────────────────────────────────────────────
+ // 追加テスト
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void LaunchCmdID_CancelFromListBox_CommandStateIsUnitSelect()
+ {
+ // CancelCommand() 後は CommandState = "ユニット選択"
+ var src = CreateSrc();
+ src.Commands.CommandState = "コマンド選択";
+ ((MockGUI)src.GUI).ListBoxHandler = _ => 0;
+ ((MockGUI)src.GUI).RedrawScreenHandler = _ => { };
+
+ try { src.Commands.UnitCommand(new UiCommand(Command.LaunchCmdID, "発進")); }
+ catch (GUINotImplementedException) { }
+
+ Assert.AreEqual("ユニット選択", src.Commands.CommandState);
+ }
+
+ [TestMethod]
+ public void LaunchCmdID_ListBoxCaption_IsUnitSelect()
+ {
+ var src = CreateSrc();
+ src.Commands.CommandState = "コマンド選択";
+ string captionUsed = null;
+ ((MockGUI)src.GUI).ListBoxHandler = args => { captionUsed = args.lb_caption; return 0; };
+ ((MockGUI)src.GUI).RedrawScreenHandler = _ => { };
+
+ try { src.Commands.UnitCommand(new UiCommand(Command.LaunchCmdID, "発進")); }
+ catch (GUINotImplementedException) { }
+
+ Assert.AreEqual("ユニット選択", captionUsed);
+ }
+
+ [TestMethod]
+ public void LaunchCmdID_ListBoxHasFlag_IsTrue()
+ {
+ // StartLaunchCommand は HasFlag=true でリストを表示する
+ var src = CreateSrc();
+ src.Commands.CommandState = "コマンド選択";
+ bool? hasFlagValue = null;
+ ((MockGUI)src.GUI).ListBoxHandler = args => { hasFlagValue = args.HasFlag; return 0; };
+ ((MockGUI)src.GUI).RedrawScreenHandler = _ => { };
+
+ try { src.Commands.UnitCommand(new UiCommand(Command.LaunchCmdID, "発進")); }
+ catch (GUINotImplementedException) { }
+
+ Assert.AreEqual(true, hasFlagValue, "StartLaunchCommand は HasFlag=true を渡す");
+ }
+
+ [TestMethod]
+ public void LaunchCmdID_InitialSelectedCommand_IsEmpty()
+ {
+ var src = CreateSrc();
+ Assert.IsTrue(string.IsNullOrEmpty(src.Commands.SelectedCommand));
+ }
}
}
diff --git a/SRC.Sharp/SRCCoreTests/Commands/CommandMapCommandTests.cs b/SRC.Sharp/SRCCoreTests/Commands/CommandMapCommandTests.cs
index 0605bacc..7f5c6fc2 100644
--- a/SRC.Sharp/SRCCoreTests/Commands/CommandMapCommandTests.cs
+++ b/SRC.Sharp/SRCCoreTests/Commands/CommandMapCommandTests.cs
@@ -120,5 +120,63 @@ public void MapCommand_AutoDefenseCmdID_SetCommandStateToUnitSelect()
}
Assert.AreEqual("ユニット選択", src.Commands.CommandState);
}
+
+ // ──────────────────────────────────────────────
+ // 追加テスト
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void MapCommand_AlwaysSetsCommandStateToUnitSelect_FromMapCommand()
+ {
+ var src = CreateSrc();
+ src.Commands.CommandState = "マップコマンド";
+ src.Commands.ViewMode = true;
+ src.Commands.MapCommand(new UiCommand(Command.EndTurnCmdID, "ターン終了"));
+ Assert.AreEqual("ユニット選択", src.Commands.CommandState);
+ }
+
+ [TestMethod]
+ public void MapCommand_EndTurnWithViewModeTrue_DoesNotCallEndTurnCommand()
+ {
+ // ViewMode=true の早期 return では EndTurnCommand (GUI依存) は呼ばれない
+ // → GUINotImplementedException は発生しない
+ var src = CreateSrc();
+ src.Commands.ViewMode = true;
+ bool threw = false;
+ try
+ {
+ src.Commands.MapCommand(new UiCommand(Command.EndTurnCmdID, "ターン終了"));
+ }
+ catch (SRCCore.Exceptions.GUINotImplementedException)
+ {
+ threw = true;
+ }
+ Assert.IsFalse(threw, "ViewMode=true の場合 EndTurnCommand は呼ばれない");
+ }
+
+ [TestMethod]
+ public void MapCommand_AutoDefenseCmdID_TogglesFromFalseToTrue()
+ {
+ var src = CreateSrc();
+ src.SystemConfig.AutoDefense = false;
+ try { src.Commands.MapCommand(new UiCommand(Command.AutoDefenseCmdID, "自動反撃")); } catch { }
+ Assert.IsTrue(src.SystemConfig.AutoDefense);
+ }
+
+ [TestMethod]
+ public void MapCommand_AutoDefenseCmdID_TogglesFromTrueToFalse()
+ {
+ var src = CreateSrc();
+ src.SystemConfig.AutoDefense = true;
+ try { src.Commands.MapCommand(new UiCommand(Command.AutoDefenseCmdID, "自動反撃")); } catch { }
+ Assert.IsFalse(src.SystemConfig.AutoDefense);
+ }
+
+ [TestMethod]
+ public void MapCommand_ViewMode_InitiallyFalse()
+ {
+ var src = CreateSrc();
+ Assert.IsFalse(src.Commands.ViewMode);
+ }
}
}
diff --git a/SRC.Sharp/SRCCoreTests/Commands/CommandProcessTests.cs b/SRC.Sharp/SRCCoreTests/Commands/CommandProcessTests.cs
new file mode 100644
index 00000000..d1a971c5
--- /dev/null
+++ b/SRC.Sharp/SRCCoreTests/Commands/CommandProcessTests.cs
@@ -0,0 +1,167 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using SRCCore.Commands;
+using SRCCore.Maps;
+using SRCCore.TestLib;
+using SRCCore.Units;
+
+namespace SRCCore.Commands.Tests
+{
+ ///
+ /// Command.process.cs の ProceedInput / ProceedCommand のユニットテスト。
+ ///
+ [TestClass]
+ public class CommandProcessTests
+ {
+ private SRC CreateSrc() => new SRC { GUI = new MockGUI() };
+
+ // ──────────────────────────────────────────────
+ // ProceedInput - 左クリック
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void ProceedInput_LeftClick_MapCommand_SetsStateToUnitSelect()
+ {
+ var src = CreateSrc();
+ src.Commands.CommandState = "マップコマンド";
+ src.Commands.ProceedInput(GuiButton.Left, null, null);
+ Assert.AreEqual("ユニット選択", src.Commands.CommandState);
+ }
+
+ [TestMethod]
+ public void ProceedInput_LeftClick_CommandSelect_NoUnit_CancelsToUnitSelect()
+ {
+ // unit == null → CancelCommand() → CommandState = "ユニット選択"
+ var src = CreateSrc();
+ src.Commands.CommandState = "コマンド選択";
+ src.Commands.ProceedInput(GuiButton.Left, null, null);
+ Assert.AreEqual("ユニット選択", src.Commands.CommandState);
+ }
+
+ [TestMethod]
+ public void ProceedInput_LeftClick_CommandSelect_NoUnit_ClearsSelectedCommand()
+ {
+ var src = CreateSrc();
+ src.Commands.CommandState = "コマンド選択";
+ src.Commands.SelectedCommand = "攻撃";
+ src.Commands.ProceedInput(GuiButton.Left, null, null);
+ Assert.AreEqual("", src.Commands.SelectedCommand);
+ }
+
+ [TestMethod]
+ public void ProceedInput_LeftClick_AfterMoveCommandSelect_CancelsToUnitSelect()
+ {
+ // "移動後コマンド選択" + 左クリック → CancelCommand() が呼ばれる
+ // CancelCommand() は "移動後コマンド選択" → "ターゲット選択" に変更し、
+ // 以降は GUI 依存処理で例外が出る可能性があるが、
+ // CancelCommand の直前まで "移動後コマンド選択" だった事実を確認
+ var src = CreateSrc();
+ src.Commands.CommandState = "移動後コマンド選択";
+ // CancelCommand() が "移動後コマンド選択" ケースを処理するので例外が出うる
+ try { src.Commands.ProceedInput(GuiButton.Left, null, null); } catch { }
+ // CommandState は "移動後コマンド選択" ではなくなる (CancelCommand が呼ばれた)
+ Assert.AreNotEqual("移動後コマンド選択", src.Commands.CommandState);
+ }
+
+ // ──────────────────────────────────────────────
+ // ProceedInput - 右クリック
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void ProceedInput_RightClick_MapCommand_SetsStateToUnitSelect()
+ {
+ var src = CreateSrc();
+ src.Commands.CommandState = "マップコマンド";
+ src.Commands.ProceedInput(GuiButton.Right, null, null);
+ Assert.AreEqual("ユニット選択", src.Commands.CommandState);
+ }
+
+ [TestMethod]
+ public void ProceedInput_RightClick_CommandSelect_CancelsToUnitSelect()
+ {
+ // "コマンド選択" は右クリックの default ケース → CancelCommand()
+ var src = CreateSrc();
+ src.Commands.CommandState = "コマンド選択";
+ src.Commands.ProceedInput(GuiButton.Right, null, null);
+ Assert.AreEqual("ユニット選択", src.Commands.CommandState);
+ }
+
+ [TestMethod]
+ public void ProceedInput_RightClick_TargetSelect_CancelsCommand()
+ {
+ // "ターゲット選択" + 右クリック → default ケース → CancelCommand()
+ // CancelCommand("ターゲット選択") → "コマンド選択" → GUI 依存で例外が出うる
+ var src = CreateSrc();
+ src.Commands.CommandState = "ターゲット選択";
+ try { src.Commands.ProceedInput(GuiButton.Right, null, null); } catch { }
+ // "ターゲット選択" のまま残らないことを確認
+ Assert.AreNotEqual("ターゲット選択", src.Commands.CommandState);
+ }
+
+ // ──────────────────────────────────────────────
+ // ProceedCommand - ViewMode ガード
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void ProceedCommand_ViewModeTrue_ByCancel_DisablesViewMode()
+ {
+ var src = CreateSrc();
+ src.Commands.ViewMode = true;
+ src.Commands.CommandState = "ユニット選択";
+ src.Commands.ProceedCommand(by_cancel: true);
+ Assert.IsFalse(src.Commands.ViewMode);
+ }
+
+ [TestMethod]
+ public void ProceedCommand_ViewModeTrue_ByCancel_ReturnsAfterDisablingViewMode()
+ {
+ // by_cancel=true で ViewMode=false になり、それ以降の処理には進まない
+ // CommandState は変化しないことで確認
+ var src = CreateSrc();
+ src.Commands.ViewMode = true;
+ src.Commands.CommandState = "ユニット選択";
+ src.Commands.ProceedCommand(by_cancel: true);
+ // GUI.IsGUILocked は ViewMode 分岐より後でセットされるので false のまま
+ Assert.IsFalse(src.GUI.IsGUILocked);
+ }
+
+ [TestMethod]
+ public void ProceedCommand_ViewModeTrue_NotByCancel_StateUnchanged()
+ {
+ // by_cancel=false かつ ViewMode=true → 何もせず即 return
+ var src = CreateSrc();
+ src.Commands.ViewMode = true;
+ src.Commands.CommandState = "コマンド選択";
+ src.Commands.ProceedCommand(by_cancel: false);
+ // ViewMode は変化しない
+ Assert.IsTrue(src.Commands.ViewMode);
+ // CommandState も変化しない
+ Assert.AreEqual("コマンド選択", src.Commands.CommandState);
+ }
+
+ [TestMethod]
+ public void ProceedCommand_ViewModeTrue_NotByCancel_GUIRemainsUnlocked()
+ {
+ var src = CreateSrc();
+ src.Commands.ViewMode = true;
+ src.Commands.CommandState = "コマンド選択";
+ src.Commands.ProceedCommand(by_cancel: false);
+ Assert.IsFalse(src.GUI.IsGUILocked);
+ }
+
+ // ──────────────────────────────────────────────
+ // ProceedInput - 左クリック + ViewMode=true の CommandSelect ガード
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void ProceedInput_LeftClick_CommandSelect_ViewModeTrue_CancelsThenViewModeRemains()
+ {
+ // "コマンド選択" + unit=null → CancelCommand() → "ユニット選択"
+ // (ViewMode ガードは ProceedCommand 内なので CancelCommand は通る)
+ var src = CreateSrc();
+ src.Commands.CommandState = "コマンド選択";
+ src.Commands.ViewMode = true;
+ src.Commands.ProceedInput(GuiButton.Left, null, null);
+ Assert.AreEqual("ユニット選択", src.Commands.CommandState);
+ }
+ }
+}
diff --git a/SRC.Sharp/SRCCoreTests/Commands/CommandUnitSpTests.cs b/SRC.Sharp/SRCCoreTests/Commands/CommandUnitSpTests.cs
index ea1dc9ac..54b1813b 100644
--- a/SRC.Sharp/SRCCoreTests/Commands/CommandUnitSpTests.cs
+++ b/SRC.Sharp/SRCCoreTests/Commands/CommandUnitSpTests.cs
@@ -107,5 +107,79 @@ public void SpecialPowerCmdID_PrevCommandSavedBeforeCall()
// その後 SelectedCommand = "スペシャルパワー" になる
Assert.AreEqual("スペシャルパワー", src.Commands.SelectedCommand);
}
+
+ // ──────────────────────────────────────────────
+ // 追加テスト
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void SpecialPowerCmdID_InitialSelectedCommandIsEmpty()
+ {
+ var src = CreateSrc();
+ Assert.IsTrue(string.IsNullOrEmpty(src.Commands.SelectedCommand));
+ }
+
+ [TestMethod]
+ public void SpecialPowerCmdID_LockCalledBeforeSelectedCommandSet()
+ {
+ // LockGUI が呼ばれてから SelectedCommand が設定されること
+ var src = CreateSrc();
+ var mock = (MockGUI)src.GUI;
+ bool lockCalledBeforeSet = false;
+ mock.LockGUIHandler = () =>
+ {
+ // この時点ではまだ SelectedCommand は変わっていない
+ lockCalledBeforeSet = (src.Commands.SelectedCommand != "スペシャルパワー");
+ };
+
+ try { src.Commands.UnitCommand(new UiCommand(Command.SpecialPowerCmdID, "スペシャルパワー")); }
+ catch { }
+
+ Assert.IsTrue(lockCalledBeforeSet, "LockGUI は SelectedCommand 設定前に呼ばれる");
+ }
+
+ [TestMethod]
+ public void SpecialPowerCmdID_CommandStateIsCommandSelect_BeforeCall()
+ {
+ // SelectedUnit が存在するとき、UnitCommand は CommandState="コマンド選択" を前提とする
+ var src = CreateSrc();
+ src.Commands.CommandState = "コマンド選択";
+ var mock = (MockGUI)src.GUI;
+ mock.LockGUIHandler = () => { };
+
+ try { src.Commands.UnitCommand(new UiCommand(Command.SpecialPowerCmdID, "スペシャルパワー")); }
+ catch { }
+
+ Assert.AreEqual("スペシャルパワー", src.Commands.SelectedCommand);
+ }
+
+ [TestMethod]
+ public void SpecialPowerCmdID_DifferentSrcInstances_IndependentState()
+ {
+ // 複数の SRC インスタンスが独立していることを確認
+ var src1 = CreateSrc();
+ var src2 = CreateSrc();
+ ((MockGUI)src1.GUI).LockGUIHandler = () => { };
+ ((MockGUI)src2.GUI).LockGUIHandler = () => { };
+
+ try { src1.Commands.UnitCommand(new UiCommand(Command.SpecialPowerCmdID, "スペシャルパワー")); } catch { }
+ // src2 は呼ばない
+
+ Assert.AreEqual("スペシャルパワー", src1.Commands.SelectedCommand);
+ Assert.IsTrue(string.IsNullOrEmpty(src2.Commands.SelectedCommand));
+ }
+
+ [TestMethod]
+ public void SpecialPowerCmdID_CalledTwice_SelectedCommandRemainsSpecialPower()
+ {
+ var src = CreateSrc();
+ var mock = (MockGUI)src.GUI;
+ mock.LockGUIHandler = () => { };
+
+ try { src.Commands.UnitCommand(new UiCommand(Command.SpecialPowerCmdID, "スペシャルパワー")); } catch { }
+ try { src.Commands.UnitCommand(new UiCommand(Command.SpecialPowerCmdID, "スペシャルパワー")); } catch { }
+
+ Assert.AreEqual("スペシャルパワー", src.Commands.SelectedCommand);
+ }
}
}
diff --git a/SRC.Sharp/SRCCoreTests/Commands/CommandUnitSupplyTests.cs b/SRC.Sharp/SRCCoreTests/Commands/CommandUnitSupplyTests.cs
index 0b973454..36c335f4 100644
--- a/SRC.Sharp/SRCCoreTests/Commands/CommandUnitSupplyTests.cs
+++ b/SRC.Sharp/SRCCoreTests/Commands/CommandUnitSupplyTests.cs
@@ -172,5 +172,62 @@ public void FixCmdID_And_SupplyCmdID_SetDifferentSelectedCommands()
Assert.AreEqual("補給", src2.Commands.SelectedCommand);
Assert.AreNotEqual(src1.Commands.SelectedCommand, src2.Commands.SelectedCommand);
}
+
+ // ──────────────────────────────────────────────
+ // 追加テスト
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void FixCmdID_InitialSelectedCommand_IsEmpty()
+ {
+ var src = CreateSrc();
+ Assert.IsTrue(string.IsNullOrEmpty(src.Commands.SelectedCommand));
+ }
+
+ [TestMethod]
+ public void SupplyCmdID_InitialSelectedCommand_IsEmpty()
+ {
+ var src = CreateSrc();
+ Assert.IsTrue(string.IsNullOrEmpty(src.Commands.SelectedCommand));
+ }
+
+ [TestMethod]
+ public void FixCmdID_CommandState_MovedAfterSelect_SetsMovedTargetSelect()
+ {
+ // CommandState が "移動後コマンド選択" のとき StartFixCommand() は
+ // CommandState = "移動後ターゲット選択" に変更する (Map 初期化後)
+ // Map が未初期化なので例外が出るが SelectedCommand は設定される
+ var src = CreateSrc();
+ src.Commands.CommandState = "移動後コマンド選択";
+ try { src.Commands.UnitCommand(new UiCommand(Command.FixCmdID, "修理")); } catch { }
+ Assert.AreEqual("修理", src.Commands.SelectedCommand);
+ }
+
+ [TestMethod]
+ public void SupplyCmdID_CommandState_MovedAfterSelect_SetsSelectedCommand()
+ {
+ var src = CreateSrc();
+ src.Commands.CommandState = "移動後コマンド選択";
+ try { src.Commands.UnitCommand(new UiCommand(Command.SupplyCmdID, "補給")); } catch { }
+ Assert.AreEqual("補給", src.Commands.SelectedCommand);
+ }
+
+ [TestMethod]
+ public void FixCmdID_CalledTwice_SelectedCommandRemainsfix()
+ {
+ var src = CreateSrc();
+ try { src.Commands.UnitCommand(new UiCommand(Command.FixCmdID, "修理")); } catch { }
+ try { src.Commands.UnitCommand(new UiCommand(Command.FixCmdID, "修理")); } catch { }
+ Assert.AreEqual("修理", src.Commands.SelectedCommand);
+ }
+
+ [TestMethod]
+ public void SupplyCmdID_CalledTwice_SelectedCommandRemainsSupply()
+ {
+ var src = CreateSrc();
+ try { src.Commands.UnitCommand(new UiCommand(Command.SupplyCmdID, "補給")); } catch { }
+ try { src.Commands.UnitCommand(new UiCommand(Command.SupplyCmdID, "補給")); } catch { }
+ Assert.AreEqual("補給", src.Commands.SelectedCommand);
+ }
}
}
diff --git a/SRC.Sharp/SRCCoreTests/Intermissions/IntermissionFormTests.cs b/SRC.Sharp/SRCCoreTests/Intermissions/IntermissionFormTests.cs
new file mode 100644
index 00000000..5e33781e
--- /dev/null
+++ b/SRC.Sharp/SRCCoreTests/Intermissions/IntermissionFormTests.cs
@@ -0,0 +1,163 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using SRCCore.TestLib;
+
+namespace SRCCore.Intermissions.Tests
+{
+ ///
+ /// InterMission.ExchangeFormCommand() のユニットテスト。
+ ///
+ /// ExchangeFormCommand の動作:
+ /// 1. UList から「待機中の味方」かつ「換装」特殊能力を持つユニットのリストを構築
+ /// 2. GUI.ListBox でユニット選択 (ret=0 でキャンセル → return)
+ /// 3. 選択されたユニットの換装先リストを構築して GUI.ListBox で形態選択
+ /// 4. 形態選択をキャンセルすると先頭ループに戻る (goto Beginning)
+ /// 5. 換装を実施して再びループ (goto Beginning)
+ ///
+ /// GUI 依存が深いため、ユニットリストが空の場合と
+ /// ユニット選択をキャンセルするパスを中心にテストする。
+ ///
+ [TestClass]
+ public class IntermissionFormTests
+ {
+ private (SRC src, MockGUI gui) CreateSrc()
+ {
+ var gui = new MockGUI();
+ var src = new SRC { GUI = gui };
+ return (src, gui);
+ }
+
+ // ──────────────────────────────────────────────
+ // ユニットリストが空の場合 (換装可能ユニットなし)
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void ExchangeFormCommand_EmptyUnitList_ShowsListBoxOnce()
+ {
+ var (src, gui) = CreateSrc();
+ int callCount = 0;
+ gui.ListBoxHandler = _ => { callCount++; return 0; };
+
+ var im = new InterMission(src);
+ im.ExchangeFormCommand();
+
+ Assert.AreEqual(1, callCount, "換装可能ユニットがなくても ListBox は一度呼ばれるべき");
+ }
+
+ [TestMethod]
+ public void ExchangeFormCommand_EmptyUnitList_Cancel_CompletesWithoutError()
+ {
+ var (src, gui) = CreateSrc();
+ gui.ListBoxHandler = _ => 0;
+
+ var im = new InterMission(src);
+ // 例外が発生しないことを確認
+ im.ExchangeFormCommand();
+ }
+
+ // ──────────────────────────────────────────────
+ // ユニット選択でキャンセル (ret=0)
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void ExchangeFormCommand_UnitSelectCancel_ReturnImmediately()
+ {
+ var (src, gui) = CreateSrc();
+ // ret=0 → 即 return
+ gui.ListBoxHandler = _ => 0;
+
+ var im = new InterMission(src);
+ im.ExchangeFormCommand();
+ // ここまで到達すれば正常終了
+ }
+
+ [TestMethod]
+ public void ExchangeFormCommand_UnitSelectCancel_ListBoxCalledExactlyOnce()
+ {
+ var (src, gui) = CreateSrc();
+ int count = 0;
+ gui.ListBoxHandler = _ => { count++; return 0; };
+
+ var im = new InterMission(src);
+ im.ExchangeFormCommand();
+
+ Assert.AreEqual(1, count);
+ }
+
+ // ──────────────────────────────────────────────
+ // GUI.TopItem が設定されることの確認
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void ExchangeFormCommand_SetsTopItemBeforeListBox()
+ {
+ var (src, gui) = CreateSrc();
+ gui.TopItem = 99;
+ int topItemAtCall = -1;
+ gui.ListBoxHandler = args =>
+ {
+ topItemAtCall = gui.TopItem;
+ return 0;
+ };
+
+ var im = new InterMission(src);
+ im.ExchangeFormCommand();
+
+ Assert.AreEqual(1, topItemAtCall, "GUI.TopItem は ListBox 呼び出し前に 1 に設定されるはず");
+ }
+
+ // ──────────────────────────────────────────────
+ // ListBox に渡されるキャプションの確認
+ // ──────────────────────────────────────────────
+
+ [TestMethod]
+ public void ExchangeFormCommand_ListBoxCaption_IsUnitSelect()
+ {
+ var (src, gui) = CreateSrc();
+ string captionUsed = null;
+ gui.ListBoxHandler = args =>
+ {
+ captionUsed = args.lb_caption;
+ return 0;
+ };
+
+ var im = new InterMission(src);
+ im.ExchangeFormCommand();
+
+ Assert.AreEqual("ユニット選択", captionUsed);
+ }
+
+ [TestMethod]
+ public void ExchangeFormCommand_ListBoxMode_ContainsRenzoHyoji()
+ {
+ var (src, gui) = CreateSrc();
+ string modeUsed = null;
+ gui.ListBoxHandler = args =>
+ {
+ modeUsed = args.lb_mode;
+ return 0;
+ };
+
+ var im = new InterMission(src);
+ im.ExchangeFormCommand();
+
+ StringAssert.Contains(modeUsed, "連続表示");
+ }
+
+ [TestMethod]
+ public void ExchangeFormCommand_ListBoxMode_ContainsComment()
+ {
+ var (src, gui) = CreateSrc();
+ string modeUsed = null;
+ gui.ListBoxHandler = args =>
+ {
+ modeUsed = args.lb_mode;
+ return 0;
+ };
+
+ var im = new InterMission(src);
+ im.ExchangeFormCommand();
+
+ StringAssert.Contains(modeUsed, "コメント");
+ }
+ }
+}