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
119 changes: 119 additions & 0 deletions Assets/Tests/Editor/ControlPlayModeUseCaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,125 @@ public async Task ExecuteAsync_WhenPlayResumesFromPause_OnlyClearsPauseAndReport
Assert.That(quietSaver.SaveCallCount, Is.EqualTo(0));
}

/// <summary>
/// What: Play while already running and not paused is a no-op with the already-running message.
/// </summary>
[Test]
public async Task ExecuteAsync_WhenPlayWhileAlreadyRunning_ReportsNoOpWithoutSideEffects()
{
FakeControlPlayModeEditorStateService editorState = new(isPlaying: true, isPaused: false);
StubEditorUnsavedChangesQuietSaver quietSaver = new(
saveFailures: System.Array.Empty<string>(),
remainingAfterSave: System.Array.Empty<string>());
ControlPlayModeUseCase useCase = new ControlPlayModeUseCase(
new StubCompilationFailureProvider(System.Array.Empty<ControlPlayModeCompileError>()),
new StubCompilationFailureGate(false),
quietSaver,
editorState,
new StubDomainReloadDropStateProvider());
ControlPlayModeSchema schema = new ControlPlayModeSchema
{
Action = PlayModeAction.Play,
};

ControlPlayModeResponse response = await useCase.ExecuteAsync(schema, CancellationToken.None);

Assert.That(
response.Message,
Is.EqualTo("Play mode was already running; nothing to start or resume."));
Assert.That(response.Changed, Is.False);
Assert.That(response.ResumedFromPause, Is.False);
Assert.That(response.Warning, Is.Empty);
Assert.That(response.IsPlaying, Is.True);
Assert.That(response.IsPaused, Is.False);
Assert.That(editorState.IsPlayingSetCount, Is.EqualTo(0));
Assert.That(editorState.IsPausedSetCount, Is.EqualTo(0));
Assert.That(quietSaver.SaveCallCount, Is.EqualTo(0));
}

/// <summary>
/// What: Resume while already running and not paused uses the same no-op contract as Play.
/// </summary>
[Test]
public async Task ExecuteAsync_WhenResumeWhileAlreadyRunning_ReportsNoOpWithoutSideEffects()
{
FakeControlPlayModeEditorStateService editorState = new(isPlaying: true, isPaused: false);
StubEditorUnsavedChangesQuietSaver quietSaver = new(
saveFailures: System.Array.Empty<string>(),
remainingAfterSave: System.Array.Empty<string>());
ControlPlayModeUseCase useCase = new ControlPlayModeUseCase(
new StubCompilationFailureProvider(System.Array.Empty<ControlPlayModeCompileError>()),
new StubCompilationFailureGate(false),
quietSaver,
editorState,
new StubDomainReloadDropStateProvider());
ControlPlayModeSchema schema = new ControlPlayModeSchema
{
Action = PlayModeAction.Resume,
};

ControlPlayModeResponse response = await useCase.ExecuteAsync(schema, CancellationToken.None);

Assert.That(
response.Message,
Is.EqualTo("Play mode was already running; nothing to start or resume."));
Assert.That(response.Changed, Is.False);
Assert.That(response.ResumedFromPause, Is.False);
Assert.That(response.Warning, Is.Empty);
Assert.That(response.IsPlaying, Is.True);
Assert.That(response.IsPaused, Is.False);
Assert.That(editorState.IsPlayingSetCount, Is.EqualTo(0));
Assert.That(editorState.IsPausedSetCount, Is.EqualTo(0));
Assert.That(quietSaver.SaveCallCount, Is.EqualTo(0));
}

/// <summary>
/// What: a failed compile gate does not replace the already-running no-op while Play is live.
/// </summary>
[Test]
public async Task ExecuteAsync_WhenPlayWhileAlreadyRunningAndCompileFailed_ReportsNoOpNotCompileBlock()
{
FakeControlPlayModeEditorStateService editorState = new(isPlaying: true, isPaused: false);
StubEditorUnsavedChangesQuietSaver quietSaver = new(
saveFailures: System.Array.Empty<string>(),
remainingAfterSave: System.Array.Empty<string>());
ControlPlayModeCompileError[] compileErrors =
{
new ControlPlayModeCompileError
{
Message = "CS1525: invalid expression",
File = "Assets/Scripts/Sample.cs",
Line = 3
}
};
ControlPlayModeUseCase useCase = new ControlPlayModeUseCase(
new StubCompilationFailureProvider(compileErrors),
new StubCompilationFailureGate(true),
quietSaver,
editorState,
new StubDomainReloadDropStateProvider());
ControlPlayModeSchema schema = new ControlPlayModeSchema
{
Action = PlayModeAction.Play,
};

ControlPlayModeResponse response = await useCase.ExecuteAsync(schema, CancellationToken.None);

Assert.That(
response.Message,
Is.EqualTo("Play mode was already running; nothing to start or resume."));
Assert.That(response.Changed, Is.False);
Assert.That(response.ResumedFromPause, Is.False);
Assert.That(response.Warning, Is.Empty);
Assert.That(response.IsPlaying, Is.True);
Assert.That(response.IsPaused, Is.False);
Assert.That(response.BlockedByCompileErrors, Is.False);
Assert.That(response.CompileErrorCount, Is.EqualTo(0));
Assert.That(editorState.IsPlayingSetCount, Is.EqualTo(0));
Assert.That(editorState.IsPausedSetCount, Is.EqualTo(0));
Assert.That(quietSaver.SaveCallCount, Is.EqualTo(0));
}

[Test]
public async Task ExecuteAsync_WhenPlayStartsFreshSession_SetsPlayingAndReportsWarning()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ internal static class ControlPlayModeConstants
internal const string StoppedByCliRunTestsCancel = "cli-run-tests-cancel";
internal const string StoppedByScriptCompilation = "script-compilation";
internal const string StoppedByUnknown = "unknown";

internal const string AlreadyRunningPlayMessage =
"Play mode was already running; nothing to start or resume.";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,16 @@ private ControlPlayModeActionResult ExecutePlayModeStart(bool wasPaused, bool wa
true);
}

// Why: already-running Play used to report "Play mode started" even when Changed
// was false, which made a no-op look like a new session.
if (wasPlaying && !wasPaused)
{
return ControlPlayModeActionResult.FromState(
ControlPlayModeConstants.AlreadyRunningPlayMessage,
false,
false);
}

// Why only when entering Play from Edit: SaveScene does not work while already playing,
// and resume-from-pause must not rewrite Scene assets.
if (!wasPlaying)
Expand Down
Loading