From a8e00f91e7837458cad2221b82b8d7ed9df2f7ee Mon Sep 17 00:00:00 2001
From: goat <16760685+goaaats@users.noreply.github.com>
Date: Tue, 10 Aug 2021 23:33:37 +0200
Subject: [PATCH] feat: add self test
---
.../Interface/Internal/DalamudInterface.cs | 21 ++
.../AgingSteps/ActorTableAgingStep.cs | 45 +++
.../SelfTest/AgingSteps/ChatAgingStep.cs | 68 +++++
.../SelfTest/AgingSteps/ConditionAgingStep.cs | 35 +++
.../AgingSteps/EnterTerritoryAgingStep.cs | 65 +++++
.../SelfTest/AgingSteps/FateTableAgingStep.cs | 45 +++
.../AgingSteps/GamepadStateAgingStep.cs | 35 +++
.../SelfTest/AgingSteps/HoverAgingStep.cs | 58 ++++
.../Windows/SelfTest/AgingSteps/IAgingStep.cs | 26 ++
.../SelfTest/AgingSteps/KeyStateAgingStep.cs | 37 +++
.../AgingSteps/LoginEventAgingStep.cs | 54 ++++
.../SelfTest/AgingSteps/LuminaAgingStep.cs | 39 +++
.../AgingSteps/PartyFinderAgingStep.cs | 53 ++++
.../SelfTest/AgingSteps/TargetAgingStep.cs | 73 +++++
.../SelfTest/AgingSteps/ToastAgingStep.cs | 26 ++
.../AgingSteps/WaitFramesAgingStep.cs | 38 +++
.../Windows/SelfTest/SelfTestStepResult.cs | 28 ++
.../Windows/SelfTest/SelfTestWindow.cs | 258 ++++++++++++++++++
18 files changed, 1004 insertions(+)
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ActorTableAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ChatAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ConditionAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/EnterTerritoryAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/FateTableAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/GamepadStateAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/HoverAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/IAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/KeyStateAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LoginEventAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LuminaAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/PartyFinderAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/TargetAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ToastAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/WaitFramesAgingStep.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/SelfTestStepResult.cs
create mode 100644 Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs
diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs
index 3afcbe331..82d328623 100644
--- a/Dalamud/Interface/Internal/DalamudInterface.cs
+++ b/Dalamud/Interface/Internal/DalamudInterface.cs
@@ -5,6 +5,7 @@ using System.Numerics;
using System.Runtime.InteropServices;
using Dalamud.Interface.Internal.Windows;
+using Dalamud.Interface.Internal.Windows.SelfTest;
using Dalamud.Interface.Windowing;
using Dalamud.Logging;
using Dalamud.Logging.Internal;
@@ -36,6 +37,7 @@ namespace Dalamud.Interface.Internal
private readonly PluginInstallerWindow pluginWindow;
private readonly ScratchpadWindow scratchpadWindow;
private readonly SettingsWindow settingsWindow;
+ private readonly SelfTestWindow selfTestWindow;
private ulong frameCount = 0;
@@ -67,6 +69,7 @@ namespace Dalamud.Interface.Internal
this.pluginWindow = new PluginInstallerWindow(dalamud) { IsOpen = false };
this.scratchpadWindow = new ScratchpadWindow(dalamud) { IsOpen = false };
this.settingsWindow = new SettingsWindow(dalamud) { IsOpen = false };
+ this.selfTestWindow = new SelfTestWindow(dalamud) { IsOpen = false };
this.windowSystem.AddWindow(this.changelogWindow);
this.windowSystem.AddWindow(this.colorDemoWindow);
@@ -79,6 +82,7 @@ namespace Dalamud.Interface.Internal
this.windowSystem.AddWindow(this.pluginWindow);
this.windowSystem.AddWindow(this.scratchpadWindow);
this.windowSystem.AddWindow(this.settingsWindow);
+ this.windowSystem.AddWindow(this.selfTestWindow);
this.dalamud.InterfaceManager.OnDraw += this.OnDraw;
@@ -181,6 +185,11 @@ namespace Dalamud.Interface.Internal
///
public void OpenSettings() => this.settingsWindow.IsOpen = true;
+ ///
+ /// Opens the .
+ ///
+ public void OpenSelfTest() => this.selfTestWindow.IsOpen = true;
+
#endregion
#region Toggle
@@ -253,6 +262,11 @@ namespace Dalamud.Interface.Internal
///
public void ToggleSettingsWindow() => this.settingsWindow.Toggle();
+ ///
+ /// Toggles the .
+ ///
+ public void ToggleSelfTestWindow() => this.selfTestWindow.Toggle();
+
#endregion
private void OnDraw()
@@ -383,6 +397,13 @@ namespace Dalamud.Interface.Internal
this.OpenColorsDemoWindow();
}
+ if (ImGui.MenuItem("Open Self-Test"))
+ {
+ this.OpenSelfTest();
+ }
+
+ ImGui.Separator();
+
ImGui.MenuItem("Draw ImGui demo", string.Empty, ref this.isImGuiDrawDemoWindow);
ImGui.Separator();
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ActorTableAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ActorTableAgingStep.cs
new file mode 100644
index 000000000..4d927b010
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ActorTableAgingStep.cs
@@ -0,0 +1,45 @@
+using Dalamud.Utility;
+using ImGuiNET;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for the Actor Table.
+ ///
+ internal class ActorTableAgingStep : IAgingStep
+ {
+ private int index = 0;
+
+ ///
+ public string Name => "Test ActorTable";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ ImGui.Text("Checking actor table...");
+
+ if (this.index == dalamud.ClientState.Actors.Length - 1)
+ {
+ return SelfTestStepResult.Pass;
+ }
+
+ var actor = dalamud.ClientState.Actors[this.index];
+ this.index++;
+
+ if (actor == null)
+ {
+ return SelfTestStepResult.Waiting;
+ }
+
+ Util.ShowObject(actor);
+
+ return SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ // ignored
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ChatAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ChatAgingStep.cs
new file mode 100644
index 000000000..6c58da6b4
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ChatAgingStep.cs
@@ -0,0 +1,68 @@
+using Dalamud.Game.Text;
+using Dalamud.Game.Text.SeStringHandling;
+using ImGuiNET;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for Chat.
+ ///
+ internal class ChatAgingStep : IAgingStep
+ {
+ private int step = 0;
+ private bool subscribed = false;
+ private bool hasPassed = false;
+
+ ///
+ public string Name => "Test Chat";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ switch (this.step)
+ {
+ case 0:
+ dalamud.Framework.Gui.Chat.Print("Testing!");
+ this.step++;
+
+ break;
+
+ case 1:
+ ImGui.Text("Type \"/e DALAMUD\" in chat...");
+
+ if (!this.subscribed)
+ {
+ this.subscribed = true;
+ dalamud.Framework.Gui.Chat.OnChatMessage += this.ChatOnOnChatMessage;
+ }
+
+ if (this.hasPassed)
+ {
+ dalamud.Framework.Gui.Chat.OnChatMessage -= this.ChatOnOnChatMessage;
+ this.subscribed = false;
+ return SelfTestStepResult.Pass;
+ }
+
+ break;
+ }
+
+ return SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ dalamud.Framework.Gui.Chat.OnChatMessage -= this.ChatOnOnChatMessage;
+ this.subscribed = false;
+ }
+
+ private void ChatOnOnChatMessage(
+ XivChatType type, uint senderid, ref SeString sender, ref SeString message, ref bool ishandled)
+ {
+ if (type == XivChatType.Echo && message.TextValue == "DALAMUD")
+ {
+ this.hasPassed = true;
+ }
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ConditionAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ConditionAgingStep.cs
new file mode 100644
index 000000000..2907d39a3
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ConditionAgingStep.cs
@@ -0,0 +1,35 @@
+using Dalamud.Game.ClientState.Conditions;
+using ImGuiNET;
+using Serilog;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for Condition.
+ ///
+ internal class ConditionAgingStep : IAgingStep
+ {
+ ///
+ public string Name => "Test Condition";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ if (!dalamud.ClientState.Condition.Any())
+ {
+ Log.Error("No condition flags present.");
+ return SelfTestStepResult.Fail;
+ }
+
+ ImGui.Text("Please jump...");
+
+ return dalamud.ClientState.Condition[ConditionFlag.Jumping] ? SelfTestStepResult.Pass : SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ // ignored
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/EnterTerritoryAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/EnterTerritoryAgingStep.cs
new file mode 100644
index 000000000..9db72c197
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/EnterTerritoryAgingStep.cs
@@ -0,0 +1,65 @@
+using ImGuiNET;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for Territory Change.
+ ///
+ internal class EnterTerritoryAgingStep : IAgingStep
+ {
+ private readonly ushort territory;
+ private readonly string terriName;
+ private bool subscribed = false;
+ private bool hasPassed = false;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The territory to check for.
+ /// Name to show.
+ public EnterTerritoryAgingStep(ushort terri, string name)
+ {
+ this.terriName = name;
+ this.territory = terri;
+ }
+
+ ///
+ public string Name => $"Enter Terri: {this.terriName}";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ ImGui.TextUnformatted(this.Name);
+
+ if (!this.subscribed)
+ {
+ dalamud.ClientState.TerritoryChanged += this.ClientStateOnTerritoryChanged;
+ this.subscribed = true;
+ }
+
+ if (this.hasPassed)
+ {
+ dalamud.ClientState.TerritoryChanged -= this.ClientStateOnTerritoryChanged;
+ this.subscribed = false;
+ return SelfTestStepResult.Pass;
+ }
+
+ return SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ dalamud.ClientState.TerritoryChanged -= this.ClientStateOnTerritoryChanged;
+ this.subscribed = false;
+ }
+
+ private void ClientStateOnTerritoryChanged(object sender, ushort e)
+ {
+ if (e == this.territory)
+ {
+ this.hasPassed = true;
+ }
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/FateTableAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/FateTableAgingStep.cs
new file mode 100644
index 000000000..1a34b5a58
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/FateTableAgingStep.cs
@@ -0,0 +1,45 @@
+using Dalamud.Utility;
+using ImGuiNET;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for the Fate Table.
+ ///
+ internal class FateTableAgingStep : IAgingStep
+ {
+ private int index = 0;
+
+ ///
+ public string Name => "Test FateTable";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ ImGui.Text("Checking fate table...");
+
+ if (this.index == dalamud.ClientState.Fates.Length - 1)
+ {
+ return SelfTestStepResult.Pass;
+ }
+
+ var actor = dalamud.ClientState.Fates[this.index];
+ this.index++;
+
+ if (actor == null)
+ {
+ return SelfTestStepResult.Waiting;
+ }
+
+ Util.ShowObject(actor);
+
+ return SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ // ignored
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/GamepadStateAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/GamepadStateAgingStep.cs
new file mode 100644
index 000000000..443d65843
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/GamepadStateAgingStep.cs
@@ -0,0 +1,35 @@
+using Dalamud.Game.ClientState.GamePad;
+using ImGuiNET;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for the Gamepad State.
+ ///
+ internal class GamepadStateAgingStep : IAgingStep
+ {
+ ///
+ public string Name => "Test GamePadState";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ ImGui.Text("Hold down North, East, L1");
+
+ if (dalamud.ClientState.GamepadState.Pressed(GamepadButtons.North) == 1
+ && dalamud.ClientState.GamepadState.Pressed(GamepadButtons.East) == 1
+ && dalamud.ClientState.GamepadState.Pressed(GamepadButtons.L1) == 1)
+ {
+ return SelfTestStepResult.Pass;
+ }
+
+ return SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ // ignored
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/HoverAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/HoverAgingStep.cs
new file mode 100644
index 000000000..845a5d40d
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/HoverAgingStep.cs
@@ -0,0 +1,58 @@
+using Dalamud.Game.Gui;
+using ImGuiNET;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for the Hover events.
+ ///
+ internal class HoverAgingStep : IAgingStep
+ {
+ private bool clearedItem = false;
+ private bool clearedAction = false;
+
+ ///
+ public string Name => "Test Hover";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ var hoverItem = dalamud.Framework.Gui.HoveredItem;
+ var hoverAction = dalamud.Framework.Gui.HoveredAction;
+
+ if (!this.clearedItem)
+ {
+ ImGui.Text("Hover WHM soul crystal...");
+
+ if (hoverItem == 4547)
+ {
+ this.clearedItem = true;
+ }
+ }
+
+ if (!this.clearedAction)
+ {
+ ImGui.Text("Hover \"Open Linkshells\" action...");
+
+ if (hoverAction != null && hoverAction.ActionKind == HoverActionKind.MainCommand &&
+ hoverAction.ActionID == 28)
+ {
+ this.clearedAction = true;
+ }
+ }
+
+ if (this.clearedItem && this.clearedAction)
+ {
+ return SelfTestStepResult.Pass;
+ }
+
+ return SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ // ignored
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/IAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/IAgingStep.cs
new file mode 100644
index 000000000..fb1683b40
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/IAgingStep.cs
@@ -0,0 +1,26 @@
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Interface for test implementations.
+ ///
+ internal interface IAgingStep
+ {
+ ///
+ /// Gets the name of the test.
+ ///
+ public string Name { get; }
+
+ ///
+ /// Run the test step, once per frame it is active.
+ ///
+ /// Dalamud instance to act on.
+ /// The result of this frame, test is discarded once a result other than is returned.
+ public SelfTestStepResult RunStep(Dalamud dalamud);
+
+ ///
+ /// Clean up this test.
+ ///
+ /// Dalamud instance to act on.
+ public void CleanUp(Dalamud dalamud);
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/KeyStateAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/KeyStateAgingStep.cs
new file mode 100644
index 000000000..b93ae3165
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/KeyStateAgingStep.cs
@@ -0,0 +1,37 @@
+using Dalamud.Game.ClientState.Keys;
+using ImGuiNET;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for the Key State.
+ ///
+ internal class KeyStateAgingStep : IAgingStep
+ {
+ ///
+ public string Name => "Test KeyState";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ ImGui.Text("Hold down D,A,L,M,U");
+
+ if (dalamud.ClientState.KeyState[VirtualKey.D]
+ && dalamud.ClientState.KeyState[VirtualKey.A]
+ && dalamud.ClientState.KeyState[VirtualKey.L]
+ && dalamud.ClientState.KeyState[VirtualKey.M]
+ && dalamud.ClientState.KeyState[VirtualKey.U])
+ {
+ return SelfTestStepResult.Pass;
+ }
+
+ return SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ // ignored
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LoginEventAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LoginEventAgingStep.cs
new file mode 100644
index 000000000..8a04febf9
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LoginEventAgingStep.cs
@@ -0,0 +1,54 @@
+using System;
+
+using ImGuiNET;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for the login events.
+ ///
+ internal class LoginEventAgingStep : IAgingStep
+ {
+ private bool isSubscribed = false;
+ private bool hasPassed = false;
+
+ ///
+ public string Name => "Test Log-In";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ ImGui.Text("Log in now...");
+
+ if (!this.isSubscribed)
+ {
+ dalamud.ClientState.OnLogin += this.ClientStateOnOnLogin;
+ this.isSubscribed = true;
+ }
+
+ if (this.hasPassed)
+ {
+ dalamud.ClientState.OnLogin -= this.ClientStateOnOnLogin;
+ this.isSubscribed = false;
+ return SelfTestStepResult.Pass;
+ }
+
+ return SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ if (this.isSubscribed)
+ {
+ dalamud.ClientState.OnLogin -= this.ClientStateOnOnLogin;
+ this.isSubscribed = false;
+ }
+ }
+
+ private void ClientStateOnOnLogin(object sender, EventArgs e)
+ {
+ this.hasPassed = true;
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LuminaAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LuminaAgingStep.cs
new file mode 100644
index 000000000..7a8ae0fd6
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LuminaAgingStep.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using System.Linq;
+
+using Dalamud.Utility;
+using Lumina.Excel;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for Lumina.
+ ///
+ /// ExcelRow to run test on.
+ internal class LuminaAgingStep : IAgingStep
+ where T : ExcelRow
+ {
+ private int step = 0;
+ private List rows;
+
+ ///
+ public string Name => "Test Lumina";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ this.rows ??= dalamud.Data.GetExcelSheet().ToList();
+
+ Util.ShowObject(this.rows[this.step]);
+
+ this.step++;
+ return this.step >= this.rows.Count ? SelfTestStepResult.Pass : SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ // ignored
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/PartyFinderAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/PartyFinderAgingStep.cs
new file mode 100644
index 000000000..c2172b9dc
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/PartyFinderAgingStep.cs
@@ -0,0 +1,53 @@
+using Dalamud.Game.Gui.PartyFinder.Types;
+using ImGuiNET;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for Party Finder events.
+ ///
+ internal class PartyFinderAgingStep : IAgingStep
+ {
+ private bool subscribed = false;
+ private bool hasPassed = false;
+
+ ///
+ public string Name => "Test Party Finder";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ if (!this.subscribed)
+ {
+ dalamud.Framework.Gui.PartyFinder.ReceiveListing += this.PartyFinderOnReceiveListing;
+ this.subscribed = true;
+ }
+
+ if (this.hasPassed)
+ {
+ dalamud.Framework.Gui.PartyFinder.ReceiveListing -= this.PartyFinderOnReceiveListing;
+ this.subscribed = false;
+ return SelfTestStepResult.Pass;
+ }
+
+ ImGui.Text("Open Party Finder");
+
+ return SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ if (this.subscribed)
+ {
+ dalamud.Framework.Gui.PartyFinder.ReceiveListing -= this.PartyFinderOnReceiveListing;
+ this.subscribed = false;
+ }
+ }
+
+ private void PartyFinderOnReceiveListing(PartyFinderListing listing, PartyFinderListingEventArgs args)
+ {
+ this.hasPassed = true;
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/TargetAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/TargetAgingStep.cs
new file mode 100644
index 000000000..c2dde87a2
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/TargetAgingStep.cs
@@ -0,0 +1,73 @@
+using Dalamud.Game.ClientState.Actors.Types;
+using Dalamud.Game.ClientState.Actors.Types.NonPlayer;
+using ImGuiNET;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for targets.
+ ///
+ internal class TargetAgingStep : IAgingStep
+ {
+ private int step = 0;
+
+ ///
+ public string Name => "Test Target";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ switch (this.step)
+ {
+ case 0:
+ dalamud.ClientState.Targets.ClearCurrentTarget();
+ dalamud.ClientState.Targets.ClearFocusTarget();
+
+ this.step++;
+
+ break;
+
+ case 1:
+ ImGui.Text("Target a player...");
+
+ var cTarget = dalamud.ClientState.Targets.CurrentTarget;
+ if (cTarget is PlayerCharacter)
+ {
+ this.step++;
+ }
+
+ break;
+
+ case 2:
+ ImGui.Text("Focus-Target a Battle NPC...");
+
+ var fTarget = dalamud.ClientState.Targets.FocusTarget;
+ if (fTarget is BattleNpc)
+ {
+ this.step++;
+ }
+
+ break;
+
+ case 3:
+ ImGui.Text("Soft-Target an EventObj...");
+
+ var sTarget = dalamud.ClientState.Targets.FocusTarget;
+ if (sTarget is EventObj)
+ {
+ return SelfTestStepResult.Pass;
+ }
+
+ break;
+ }
+
+ return SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ // ignored
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ToastAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ToastAgingStep.cs
new file mode 100644
index 000000000..548fe698a
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ToastAgingStep.cs
@@ -0,0 +1,26 @@
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test setup for toasts.
+ ///
+ internal class ToastAgingStep : IAgingStep
+ {
+ ///
+ public string Name => "Test Toasts";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ dalamud.Framework.Gui.Toast.ShowNormal("Normal Toast");
+ dalamud.Framework.Gui.Toast.ShowError("Error Toast");
+
+ return SelfTestStepResult.Pass;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ // ignored
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/WaitFramesAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/WaitFramesAgingStep.cs
new file mode 100644
index 000000000..bac881324
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/WaitFramesAgingStep.cs
@@ -0,0 +1,38 @@
+namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
+{
+ ///
+ /// Test that waits N frames.
+ ///
+ internal class WaitFramesAgingStep : IAgingStep
+ {
+ private readonly int frames;
+ private int cFrames;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Amount of frames to wait.
+ public WaitFramesAgingStep(int frames)
+ {
+ this.frames = frames;
+ this.cFrames = frames;
+ }
+
+ ///
+ public string Name => $"Wait {this.cFrames} frames";
+
+ ///
+ public SelfTestStepResult RunStep(Dalamud dalamud)
+ {
+ this.cFrames--;
+
+ return this.cFrames <= 0 ? SelfTestStepResult.Pass : SelfTestStepResult.Waiting;
+ }
+
+ ///
+ public void CleanUp(Dalamud dalamud)
+ {
+ this.cFrames = this.frames;
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestStepResult.cs b/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestStepResult.cs
new file mode 100644
index 000000000..70dddcab9
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestStepResult.cs
@@ -0,0 +1,28 @@
+namespace Dalamud.Interface.Internal.Windows.SelfTest
+{
+ ///
+ /// Enum declaring result states of tests.
+ ///
+ internal enum SelfTestStepResult
+ {
+ ///
+ /// Test was not ran.
+ ///
+ NotRan,
+
+ ///
+ /// Test is waiting for completion.
+ ///
+ Waiting,
+
+ ///
+ /// Test has failed.
+ ///
+ Fail,
+
+ ///
+ /// Test has passed.
+ ///
+ Pass,
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs b/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs
new file mode 100644
index 000000000..cd22e6344
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs
@@ -0,0 +1,258 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+
+using Dalamud.Interface.Colors;
+using Dalamud.Interface.Components;
+using Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
+using Dalamud.Interface.Windowing;
+using Dalamud.Logging.Internal;
+using ImGuiNET;
+using Lumina.Excel.GeneratedSheets;
+
+namespace Dalamud.Interface.Internal.Windows.SelfTest
+{
+ ///
+ /// Window for the Self-Test logic.
+ ///
+ internal class SelfTestWindow : Window
+ {
+ private static readonly ModuleLog Log = new("AGING");
+
+ private readonly Dalamud dalamud;
+
+ private readonly List steps =
+ new()
+ {
+ new LoginEventAgingStep(),
+ new WaitFramesAgingStep(1000),
+ new EnterTerritoryAgingStep(148, "Central Shroud"),
+ new ActorTableAgingStep(),
+ new FateTableAgingStep(),
+ new ConditionAgingStep(),
+ new ToastAgingStep(),
+ new TargetAgingStep(),
+ new KeyStateAgingStep(),
+ new GamepadStateAgingStep(),
+ new ChatAgingStep(),
+ new HoverAgingStep(),
+ new LuminaAgingStep(),
+ new PartyFinderAgingStep(),
+ };
+
+ private readonly List<(SelfTestStepResult Result, TimeSpan? Duration)> stepResults = new();
+
+ private bool selfTestRunning = false;
+ private int currentStep = 0;
+
+ private DateTimeOffset lastTestStart;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The dalamud instance to act on.
+ public SelfTestWindow(Dalamud dalamud)
+ : base("Dalamud Self-Test", ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)
+ {
+ this.dalamud = dalamud;
+
+ this.Size = new Vector2(800, 800);
+ this.SizeCondition = ImGuiCond.FirstUseEver;
+ }
+
+ ///
+ public override void Draw()
+ {
+ if (this.selfTestRunning)
+ {
+ if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop))
+ {
+ this.StopTests();
+ }
+
+ ImGui.SameLine();
+
+ if (ImGuiComponents.IconButton(FontAwesomeIcon.StepForward))
+ {
+ this.stepResults.Add((SelfTestStepResult.NotRan, null));
+ this.currentStep++;
+ this.lastTestStart = DateTimeOffset.Now;
+
+ if (this.currentStep >= this.steps.Count)
+ {
+ this.StopTests();
+ }
+ }
+ }
+ else
+ {
+ if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
+ {
+ this.selfTestRunning = true;
+ this.currentStep = 0;
+ this.stepResults.Clear();
+ this.lastTestStart = DateTimeOffset.Now;
+ }
+ }
+
+ ImGui.SameLine();
+
+ ImGui.TextUnformatted($"Step: {this.currentStep} / {this.steps.Count}");
+
+ ImGuiHelpers.ScaledDummy(10);
+
+ this.DrawResultTable();
+
+ ImGuiHelpers.ScaledDummy(10);
+
+ if (this.currentStep >= this.steps.Count)
+ {
+ if (this.selfTestRunning)
+ {
+ this.StopTests();
+ }
+
+ if (this.stepResults.Any(x => x.Result == SelfTestStepResult.Fail))
+ {
+ ImGui.TextColored(ImGuiColors.DalamudRed, "One or more checks failed!");
+ }
+ else
+ {
+ ImGui.TextColored(ImGuiColors.HealerGreen, "All checks passed!");
+ }
+
+ return;
+ }
+
+ if (!this.selfTestRunning)
+ {
+ return;
+ }
+
+ ImGui.Separator();
+
+ var step = this.steps[this.currentStep];
+ ImGui.TextUnformatted($"Current: {step.Name}");
+
+ ImGuiHelpers.ScaledDummy(10);
+
+ SelfTestStepResult result;
+ try
+ {
+ result = step.RunStep(this.dalamud);
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, $"Step failed: {step.Name}");
+ result = SelfTestStepResult.Fail;
+ }
+
+ ImGui.Separator();
+
+ if (result != SelfTestStepResult.Waiting)
+ {
+ var duration = DateTimeOffset.Now - this.lastTestStart;
+ this.currentStep++;
+ this.stepResults.Add((result, duration));
+
+ this.lastTestStart = DateTimeOffset.Now;
+ }
+ }
+
+ private void DrawResultTable()
+ {
+ if (ImGui.BeginTable("agingResultTable", 4, ImGuiTableFlags.Borders))
+ {
+ ImGui.TableSetupColumn("###index", ImGuiTableColumnFlags.WidthFixed, 12f);
+ ImGui.TableSetupColumn("Name");
+ ImGui.TableSetupColumn("Result", ImGuiTableColumnFlags.WidthFixed, 40f);
+ ImGui.TableSetupColumn("Duration", ImGuiTableColumnFlags.WidthFixed, 90f);
+
+ ImGui.TableHeadersRow();
+
+ for (var i = 0; i < this.steps.Count; i++)
+ {
+ var step = this.steps[i];
+ ImGui.TableNextRow();
+
+ ImGui.TableSetColumnIndex(0);
+ ImGui.Text(i.ToString());
+
+ ImGui.TableSetColumnIndex(1);
+ ImGui.Text(step.Name);
+
+ ImGui.TableSetColumnIndex(2);
+ ImGui.PushFont(Interface.Internal.InterfaceManager.MonoFont);
+ if (this.stepResults.Count > i)
+ {
+ var result = this.stepResults[i];
+
+ switch (result.Result)
+ {
+ case SelfTestStepResult.Pass:
+ ImGui.TextColored(ImGuiColors.HealerGreen, "PASS");
+ break;
+ case SelfTestStepResult.Fail:
+ ImGui.TextColored(ImGuiColors.DalamudRed, "FAIL");
+ break;
+ default:
+ ImGui.TextColored(ImGuiColors.DalamudGrey, "NR");
+ break;
+ }
+ }
+ else
+ {
+ if (this.selfTestRunning && this.currentStep == i)
+ {
+ ImGui.TextColored(ImGuiColors.DalamudGrey, "WAIT");
+ }
+ else
+ {
+ ImGui.TextColored(ImGuiColors.DalamudGrey, "NR");
+ }
+ }
+
+ ImGui.PopFont();
+
+ ImGui.TableSetColumnIndex(3);
+ if (this.stepResults.Count > i)
+ {
+ var (_, duration) = this.stepResults[i];
+
+ if (duration.HasValue)
+ {
+ ImGui.TextUnformatted(duration.Value.ToString("g"));
+ }
+ }
+ else
+ {
+ if (this.selfTestRunning && this.currentStep == i)
+ {
+ ImGui.TextUnformatted((DateTimeOffset.Now - this.lastTestStart).ToString("g"));
+ }
+ }
+ }
+
+ ImGui.EndTable();
+ }
+ }
+
+ private void StopTests()
+ {
+ this.selfTestRunning = false;
+
+ foreach (var agingStep in this.steps)
+ {
+ try
+ {
+ agingStep.CleanUp(this.dalamud);
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, $"Could not clean up AgingStep: {agingStep.Name}");
+ }
+ }
+ }
+ }
+}