Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 176 additions & 0 deletions Assets/Tests/Editor/CliPlayModeRunInBackgroundControllerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
#nullable enable
using NUnit.Framework;

using io.github.hatayama.UnityCliLoop.FirstPartyTools;

namespace io.github.hatayama.UnityCliLoop.Tests.Editor
{
/// <summary>
/// Pure unit tests for CLI PlayMode runInBackground override state transitions.
/// </summary>
public sealed class CliPlayModeRunInBackgroundControllerTests
{
[Test]
public void OnCliPlayStarting_WhenInactive_SavesOriginalAndRequestsTrue()
{
// Verifies CLI Play start records the pre-Play value and forces runInBackground on.
InMemoryCliPlayModeRunInBackgroundStore store = new InMemoryCliPlayModeRunInBackgroundStore();
CliPlayModeRunInBackgroundController controller = new CliPlayModeRunInBackgroundController(store);

bool desired = controller.OnCliPlayStarting(currentRunInBackground: false);

Assert.That(desired, Is.True);
Assert.That(store.IsActive, Is.True);
Assert.That(store.OriginalRunInBackground, Is.False);
}

[Test]
public void OnCliPlayStarting_WhenAlreadyActive_DoesNotOverwriteOriginal()
{
// Verifies a second CLI Play while the override is active keeps the first original value.
InMemoryCliPlayModeRunInBackgroundStore store = new InMemoryCliPlayModeRunInBackgroundStore();
CliPlayModeRunInBackgroundController controller = new CliPlayModeRunInBackgroundController(store);
controller.OnCliPlayStarting(currentRunInBackground: false);

bool desired = controller.OnCliPlayStarting(currentRunInBackground: true);

Assert.That(desired, Is.True);
Assert.That(store.IsActive, Is.True);
Assert.That(store.OriginalRunInBackground, Is.False);
}

[Test]
public void PeekOriginalIfActive_WhenActive_ReturnsOriginalWithoutClearing()
{
// Verifies early exit restore can re-apply the original without dropping ownership yet.
InMemoryCliPlayModeRunInBackgroundStore store = new InMemoryCliPlayModeRunInBackgroundStore();
CliPlayModeRunInBackgroundController controller = new CliPlayModeRunInBackgroundController(store);
controller.OnCliPlayStarting(currentRunInBackground: false);

bool? peeked = controller.PeekOriginalIfActive();

Assert.That(peeked, Is.False);
Assert.That(store.IsActive, Is.True);
Assert.That(store.OriginalRunInBackground, Is.False);
}

[Test]
public void CommitRestoreAfterPlayModeExit_WhenActive_RestoresOriginalAndClears()
{
// Verifies stable EditMode exit (CLI Stop or manual Stop) restores and clears ownership.
InMemoryCliPlayModeRunInBackgroundStore store = new InMemoryCliPlayModeRunInBackgroundStore();
CliPlayModeRunInBackgroundController controller = new CliPlayModeRunInBackgroundController(store);
controller.OnCliPlayStarting(currentRunInBackground: false);

bool? restored = controller.CommitRestoreAfterPlayModeExit();

Assert.That(restored, Is.False);
Assert.That(store.IsActive, Is.False);
}

[Test]
public void CommitRestoreAfterPlayModeExit_WhenInactive_ReturnsNull()
{
// Verifies manual Play sessions that never went through CLI Play leave runInBackground alone.
InMemoryCliPlayModeRunInBackgroundStore store = new InMemoryCliPlayModeRunInBackgroundStore();
CliPlayModeRunInBackgroundController controller = new CliPlayModeRunInBackgroundController(store);

bool? restored = controller.CommitRestoreAfterPlayModeExit();

Assert.That(restored, Is.Null);
Assert.That(store.IsActive, Is.False);
}

[Test]
public void OnEditorStartup_WhenActiveAndStillPlaying_ReappliesTrue()
{
// Verifies domain reload during CLI Play re-applies runInBackground without clearing the original.
InMemoryCliPlayModeRunInBackgroundStore store = new InMemoryCliPlayModeRunInBackgroundStore();
CliPlayModeRunInBackgroundController controller = new CliPlayModeRunInBackgroundController(store);
controller.OnCliPlayStarting(currentRunInBackground: false);

bool? desired = controller.OnEditorStartup(isPlaying: true);

Assert.That(desired, Is.True);
Assert.That(store.IsActive, Is.True);
Assert.That(store.OriginalRunInBackground, Is.False);
}

[Test]
public void OnEditorStartup_WhenActiveButNotPlaying_RestoresOriginalAndClears()
{
// Verifies domain reload after Play exit still restores when ownership was not committed yet.
InMemoryCliPlayModeRunInBackgroundStore store = new InMemoryCliPlayModeRunInBackgroundStore();
store.Activate(originalRunInBackground: false);
CliPlayModeRunInBackgroundController controller = new CliPlayModeRunInBackgroundController(store);

bool? desired = controller.OnEditorStartup(isPlaying: false);

Assert.That(desired, Is.False);
Assert.That(store.IsActive, Is.False);
}

[Test]
public void OnEditorStartup_WhenInactive_ReturnsNull()
{
// Verifies startup is a no-op when CLI never enabled a PlayMode override.
InMemoryCliPlayModeRunInBackgroundStore store = new InMemoryCliPlayModeRunInBackgroundStore();
CliPlayModeRunInBackgroundController controller = new CliPlayModeRunInBackgroundController(store);

bool? desired = controller.OnEditorStartup(isPlaying: true);

Assert.That(desired, Is.Null);
}

[Test]
public void CommitRestoreAfterPlayModeExit_WhenOriginalWasTrue_RestoresTrue()
{
// Verifies projects that already had runInBackground enabled stay enabled after CLI Play ends.
InMemoryCliPlayModeRunInBackgroundStore store = new InMemoryCliPlayModeRunInBackgroundStore();
CliPlayModeRunInBackgroundController controller = new CliPlayModeRunInBackgroundController(store);
controller.OnCliPlayStarting(currentRunInBackground: true);

bool? restored = controller.CommitRestoreAfterPlayModeExit();

Assert.That(restored, Is.True);
Assert.That(store.IsActive, Is.False);
}

[Test]
public void ExitSequence_PeekThenCommit_SurvivesTransitionOverwriteModel()
{
// Verifies early peek restore + later commit matches the ExitingPlayMode → EnteredEditMode path.
InMemoryCliPlayModeRunInBackgroundStore store = new InMemoryCliPlayModeRunInBackgroundStore();
CliPlayModeRunInBackgroundController controller = new CliPlayModeRunInBackgroundController(store);
controller.OnCliPlayStarting(currentRunInBackground: false);

bool? peeked = controller.PeekOriginalIfActive();
bool? committed = controller.CommitRestoreAfterPlayModeExit();

Assert.That(peeked, Is.False);
Assert.That(committed, Is.False);
Assert.That(store.IsActive, Is.False);
Assert.That(controller.PeekOriginalIfActive(), Is.Null);
Assert.That(controller.CommitRestoreAfterPlayModeExit(), Is.Null);
}

private sealed class InMemoryCliPlayModeRunInBackgroundStore : ICliPlayModeRunInBackgroundStore
{
public bool IsActive { get; private set; }

public bool OriginalRunInBackground { get; private set; }

public void Activate(bool originalRunInBackground)
{
OriginalRunInBackground = originalRunInBackground;
IsActive = true;
}

public void Clear()
{
IsActive = false;
OriginalRunInBackground = false;
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

113 changes: 113 additions & 0 deletions Assets/Tests/Editor/PressHoldUntilEdgeLogicTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#nullable enable
using NUnit.Framework;

using io.github.hatayama.UnityCliLoop.FirstPartyTools;

namespace io.github.hatayama.UnityCliLoop.Tests.Editor
{
/// <summary>
/// Pure unit tests for Press hold-until-edge wait decisions.
/// </summary>
public sealed class PressHoldUntilEdgeLogicTests
{
[Test]
public void IsBaseWaitSatisfied_WhenFramesAndDurationMet_ReturnsTrue()
{
// Verifies the normal Press wait can finish once min frames and duration both pass.
bool satisfied = PressHoldUntilEdgeLogic.IsBaseWaitSatisfied(
observedFrames: 2,
minimumObservationFrames: 2,
elapsedSeconds: 0f,
durationSeconds: 0f);

Assert.That(satisfied, Is.True);
}

[Test]
public void IsBaseWaitSatisfied_WhenFramesShort_ReturnsFalse()
{
// Verifies duration alone is not enough before the minimum observation frames elapse.
bool satisfied = PressHoldUntilEdgeLogic.IsBaseWaitSatisfied(
observedFrames: 1,
minimumObservationFrames: 2,
elapsedSeconds: 1f,
durationSeconds: 0f);

Assert.That(satisfied, Is.False);
}

[Test]
public void ShouldExtendHoldForEdge_WhenEdgeAlreadyObserved_ReturnsFalse()
{
// Verifies release proceeds immediately once the gameplay press edge was seen.
bool shouldExtend = PressHoldUntilEdgeLogic.ShouldExtendHoldForEdge(
pressEdgeObserved: true,
baseWaitSatisfied: true,
elapsedMilliseconds: 10,
timeoutMilliseconds: 5000);

Assert.That(shouldExtend, Is.False);
}

[Test]
public void ShouldExtendHoldForEdge_WhenEdgeMissingAndUnderTimeout_ReturnsTrue()
{
// Verifies release is delayed until the edge is observed (within the existing timeout budget).
bool shouldExtend = PressHoldUntilEdgeLogic.ShouldExtendHoldForEdge(
pressEdgeObserved: false,
baseWaitSatisfied: true,
elapsedMilliseconds: 100,
timeoutMilliseconds: 5000);

Assert.That(shouldExtend, Is.True);
}

[Test]
public void ShouldExtendHoldForEdge_WhenTimeoutExceeded_ReturnsFalse()
{
// Verifies the hold does not block forever when the edge never becomes visible.
bool shouldExtend = PressHoldUntilEdgeLogic.ShouldExtendHoldForEdge(
pressEdgeObserved: false,
baseWaitSatisfied: true,
elapsedMilliseconds: 5000,
timeoutMilliseconds: 5000);

Assert.That(shouldExtend, Is.False);
}

[Test]
public void ShouldExtendHoldForEdge_WhenBaseWaitNotSatisfied_ReturnsFalse()
{
// Verifies edge extension only starts after duration + min frames already completed.
bool shouldExtend = PressHoldUntilEdgeLogic.ShouldExtendHoldForEdge(
pressEdgeObserved: false,
baseWaitSatisfied: false,
elapsedMilliseconds: 0,
timeoutMilliseconds: 5000);

Assert.That(shouldExtend, Is.False);
}

[Test]
public void CountExtendedFrames_WhenBeyondBase_ReturnsDelta()
{
// Verifies response can report how many frames release was delayed for edge observation.
int extended = PressHoldUntilEdgeLogic.CountExtendedFrames(
observedFrames: 5,
baseSatisfiedFrameCount: 2);

Assert.That(extended, Is.EqualTo(3));
}

[Test]
public void CountExtendedFrames_WhenNotBeyondBase_ReturnsZero()
{
// Verifies no extension is reported when release happened at the normal wait end.
int extended = PressHoldUntilEdgeLogic.CountExtendedFrames(
observedFrames: 2,
baseSatisfiedFrameCount: 2);

Assert.That(extended, Is.EqualTo(0));
}
}
}
11 changes: 11 additions & 0 deletions Assets/Tests/Editor/PressHoldUntilEdgeLogicTests.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading