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
42 changes: 42 additions & 0 deletions Assets/Tests/Editor/CompileResponseFactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,48 @@ public void CreateResponse_WhenForceCompileHasOutcome_ExplainsNullDetails()
Assert.That(response.Message, Is.EqualTo(ForceCompileUnknownResult.MessageText));
}

[Test]
public void CreateResponse_WhenIndeterminateNonForceCompileHasCounts_PreservesCountsWithoutIssues()
{
// Verifies indeterminate non-force results keep observed counts while withholding unreliable issue lists.
CompilerMessage error = new CompilerMessage
{
type = CompilerMessageType.Error,
message = "error",
file = "Assets/Test.cs",
line = 12
};
CompilerMessage warning = new CompilerMessage
{
type = CompilerMessageType.Warning,
message = "warning",
file = "Assets/Test.cs",
line = 15
};
CompileResult result = new CompileResult(
success: null,
errorCount: 1,
warningCount: 1,
completedAt: DateTime.Now,
messages: new[] { error, warning },
errors: new[] { error },
warnings: new[] { warning },
isIndeterminate: true,
message: null);

CompileResponse response =
CompileResponseFactory.CreateResponse(result, forceRecompile: false);

Assert.That(response.Success, Is.Null);
Assert.That(response.ErrorCount, Is.EqualTo(1));
Assert.That(response.WarningCount, Is.EqualTo(1));
Assert.That(response.Errors, Is.Null);
Assert.That(response.Warnings, Is.Null);
Assert.That(
response.Message,
Is.EqualTo("Compilation status is unknown. Use get-logs to inspect the compiler output."));
}

[Test]
public void CreateResponse_WhenForceCompileHasPreservedFailure_MapsDetailedIssues()
{
Expand Down
79 changes: 79 additions & 0 deletions Assets/Tests/Editor/CompileResultSessionRecorderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System;
using NUnit.Framework;
using UnityEditor.Compilation;

using io.github.hatayama.UnityCliLoop.Domain;
using io.github.hatayama.UnityCliLoop.FirstPartyTools;
using io.github.hatayama.UnityCliLoop.Infrastructure;

namespace io.github.hatayama.UnityCliLoop.Tests.Editor
{
/// <summary>
/// Tests the single compile result recording seam used by delayed CLI polling.
/// </summary>
[TestFixture]
public sealed class CompileResultSessionRecorderTests
{
[Test]
public void RecordCompileResult_WhenPendingRequestExists_StoresResponseAndClearsPendingRequest()
{
// Verifies raw compile results are shaped and persisted through the recorder seam once.
UnityCliLoopCompileResultSessionRepository compileResultSessionRepository =
UnityCliLoopEditorSessionStateTestFactory.CreateCompileResultSessionRepository();
UnityCliLoopPendingCompileSessionRepository pendingCompileSessionRepository =
UnityCliLoopEditorSessionStateTestFactory.CreatePendingCompileSessionRepository();
UnityCliLoopCompileSessionLifecycleService compileSessionLifecycleService =
UnityCliLoopEditorSessionStateTestFactory.CreateCompileSessionLifecycleService();
UnityCliLoopEditorSessionStateSnapshot originalSnapshot =
UnityCliLoopEditorSessionStateTestFactory.CaptureSnapshot();
UnityCliLoopEditorSessionStateTestFactory.ClearAll();

try
{
compileSessionLifecycleService.MarkPendingCompileRequest(
"compile_test_request",
forceRecompile: false,
markedAtUtc: DateTime.UtcNow);
CompilerMessage warning = new CompilerMessage
{
type = CompilerMessageType.Warning,
message = "warning",
file = "Assets/Test.cs",
line = 15
};
CompileResult result = new CompileResult(
success: true,
errorCount: 0,
warningCount: 1,
completedAt: DateTime.Now,
messages: new[] { warning },
errors: Array.Empty<CompilerMessage>(),
warnings: new[] { warning });

CompileResponse response = CompileResultSessionRecorder.RecordCompileResult(
compileResultSessionRepository,
pendingCompileSessionRepository,
"compile_test_request",
forceRecompile: false,
result,
"compile_test_request");

UnityCliLoopStoredCompileResult storedResult =
compileResultSessionRepository.GetCompileResult("compile_test_request");
UnityCliLoopPendingCompileRequest pendingRequest =
UnityCliLoopEditorSessionStateTestFactory.GetSinglePendingCompileRequest(
pendingCompileSessionRepository);

Assert.That(response.Success, Is.True);
Assert.That(response.WarningCount, Is.EqualTo(1));
Assert.That(storedResult.ResultJson, Does.Contain("\"Success\":true"));
Assert.That(storedResult.ResultJson, Does.Contain("\"Warnings\":["));
Assert.That(pendingRequest.HasRequest, Is.False);
}
finally
{
originalSnapshot.Restore();
}
}
}
}
11 changes: 11 additions & 0 deletions Assets/Tests/Editor/CompileResultSessionRecorderTests.cs.meta

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

64 changes: 64 additions & 0 deletions Assets/Tests/Editor/CompileSessionResultStoreTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using NUnit.Framework;
using UnityEditor.Compilation;

using io.github.hatayama.UnityCliLoop.Domain;
using io.github.hatayama.UnityCliLoop.FirstPartyTools;
Expand Down Expand Up @@ -65,5 +66,68 @@ public void StoreCompileResult_WhenResultIsPersisted_UsesPascalCaseJson()
originalSnapshot.Restore();
}
}

[Test]
public void StoreCompileResult_WhenEquivalentNormalResponsesAreStoredTwice_WritesByteIdenticalJson()
{
// Verifies equivalent normal responses serialize to stable bytes across repeated storage calls.
UnityCliLoopCompileResultSessionRepository compileResultSessionRepository =
UnityCliLoopEditorSessionStateTestFactory.CreateCompileResultSessionRepository();
UnityCliLoopPendingCompileSessionRepository pendingCompileSessionRepository =
UnityCliLoopEditorSessionStateTestFactory.CreatePendingCompileSessionRepository();
UnityCliLoopEditorSessionStateSnapshot originalSnapshot =
UnityCliLoopEditorSessionStateTestFactory.CaptureSnapshot();
UnityCliLoopEditorSessionStateTestFactory.ClearAll();

try
{
CompilerMessage warning = new CompilerMessage
{
type = CompilerMessageType.Warning,
message = "warning",
file = "Assets/Test.cs",
line = 15
};
CompileResult result = new CompileResult(
success: true,
errorCount: 0,
warningCount: 1,
completedAt: DateTime.Now,
messages: new[] { warning },
errors: Array.Empty<CompilerMessage>(),
warnings: new[] { warning });
CompileResponse firstResponse =
CompileResponseFactory.CreateResponse(result, forceRecompile: false);
CompileResponse secondResponse =
CompileResponseFactory.CreateResponse(result, forceRecompile: false);

CompileSessionResultStore.StoreCompileResult(
compileResultSessionRepository,
pendingCompileSessionRepository,
"compile_test_request",
forceRecompile: false,
firstResponse,
"compile_test_request");
string firstJson =
compileResultSessionRepository.GetCompileResult("compile_test_request").ResultJson;

CompileSessionResultStore.StoreCompileResult(
compileResultSessionRepository,
pendingCompileSessionRepository,
"compile_test_request",
forceRecompile: false,
secondResponse,
"compile_test_request");
string secondJson =
compileResultSessionRepository.GetCompileResult("compile_test_request").ResultJson;

Assert.That(firstJson, Is.EqualTo(secondJson));
Assert.That(firstJson, Does.Contain("\"ProjectRoot\":"));
}
finally
{
originalSnapshot.Restore();
}
}
}
}
147 changes: 147 additions & 0 deletions Assets/Tests/Editor/CompileUseCaseTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using UnityEditor.Compilation;

using io.github.hatayama.UnityCliLoop.Domain;
using io.github.hatayama.UnityCliLoop.FirstPartyTools;
using io.github.hatayama.UnityCliLoop.Infrastructure;

namespace io.github.hatayama.UnityCliLoop.Tests.Editor
{
/// <summary>
/// Tests compile use case orchestration around delayed result persistence.
/// </summary>
[TestFixture]
public sealed class CompileUseCaseTests
{
[Test]
public async Task CompileAsync_WhenExecutionLayerStoresDelayedSuccess_DoesNotStoreResultAgain()
{
// Verifies the UseCase success path preserves the execution layer's single delayed-result write.
UnityCliLoopCompileResultSessionRepository innerCompileResultSessionRepository =
UnityCliLoopEditorSessionStateTestFactory.CreateCompileResultSessionRepository();
CountingCompileResultSessionRepository compileResultSessionRepository =
new(innerCompileResultSessionRepository);
UnityCliLoopPendingCompileSessionRepository pendingCompileSessionRepository =
UnityCliLoopEditorSessionStateTestFactory.CreatePendingCompileSessionRepository();
UnityCliLoopCompileSessionLifecycleService compileSessionLifecycleService =
new(
UnityCliLoopEditorSessionStateTestFactory.CreateSessionFlagsRepository(),
compileResultSessionRepository,
pendingCompileSessionRepository);
UnityCliLoopEditorSessionStateSnapshot originalSnapshot =
UnityCliLoopEditorSessionStateTestFactory.CaptureSnapshot();
UnityCliLoopEditorSessionStateTestFactory.ClearAll();

try
{
CompileSchema request = new()
{
WaitForDomainReload = true,
RequestId = "compile_test_request",
ForceRecompile = false,
ReloadExternalSceneChanges = true
};
CompileResult executionResult = CreateSuccessfulCompileResult();
CompileUseCase useCase = new(
compileSessionLifecycleService,
compileResultSessionRepository,
pendingCompileSessionRepository);
useCase.SetCompilationExecutionForTesting((compileRequest, ct) =>
{
ct.ThrowIfCancellationRequested();
CompileResultSessionRecorder.RecordCompileResult(
compileResultSessionRepository,
pendingCompileSessionRepository,
compileRequest.RequestId,
compileRequest.ForceRecompile,
executionResult,
compileRequest.RequestId);
return Task.FromResult(executionResult);
});

CompileResponse response = await useCase.CompileAsync(request, CancellationToken.None);

Assert.That(compileResultSessionRepository.StoreCount, Is.EqualTo(1));
Assert.That(response.Success, Is.True);
Assert.That(response.ProjectRoot, Is.Not.Empty);
UnityCliLoopStoredCompileResult storedResult =
compileResultSessionRepository.GetCompileResult("compile_test_request");
Assert.That(storedResult.ResultJson, Does.Contain("\"ProjectRoot\":"));
}
finally
{
originalSnapshot.Restore();
}
}

private static CompileResult CreateSuccessfulCompileResult()
{
CompilerMessage warning = new()
{
type = CompilerMessageType.Warning,
message = "warning",
file = "Assets/Test.cs",
line = 15
};
return new CompileResult(
success: true,
errorCount: 0,
warningCount: 1,
completedAt: DateTime.Now,
messages: new[] { warning },
errors: Array.Empty<CompilerMessage>(),
warnings: new[] { warning });
}

private sealed class CountingCompileResultSessionRepository : ICompileResultSessionRepository
{
private readonly ICompileResultSessionRepository _inner;

internal CountingCompileResultSessionRepository(ICompileResultSessionRepository inner)
{
Assert.That(inner, Is.Not.Null);
_inner = inner;
}

internal int StoreCount { get; private set; }

public void StoreCompileResult(
string requestId,
bool forceRecompile,
string resultJson,
DateTime completedAtUtc)
{
StoreCount++;
_inner.StoreCompileResult(requestId, forceRecompile, resultJson, completedAtUtc);
}

public UnityCliLoopStoredCompileResult GetCompileResult(string requestId)
{
return _inner.GetCompileResult(requestId);
}

public UnityCliLoopStoredCompileResult GetStoredCompileResult()
{
return _inner.GetStoredCompileResult();
}

public UnityCliLoopStoredCompileResult[] GetStoredCompileResults()
{
return _inner.GetStoredCompileResults();
}

public void ClearCompileResult()
{
_inner.ClearCompileResult();
}

public bool ClearExpiredCompileResult(DateTime utcNow, TimeSpan lifetime)
{
return _inner.ClearExpiredCompileResult(utcNow, lifetime);
}
}
}
}
11 changes: 11 additions & 0 deletions Assets/Tests/Editor/CompileUseCaseTests.cs.meta

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

Loading
Loading