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
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;

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

namespace io.github.hatayama.UnityCliLoop.Tests.Editor.DynamicCodeToolTests
{
Expand Down Expand Up @@ -77,193 +73,4 @@ public void Resolve_WhenAlreadyHasUsing_ShouldNotReportIt()
}
}

/// <summary>
/// Test fixture that verifies Auto Injected Namespaces Integration behavior.
/// </summary>
[TestFixture]
public class AutoInjectedNamespacesIntegrationTests
{
private IPreloadAssemblySecurityValidator _previousValidator;

[SetUp]
public void SetUp()
{
_previousValidator = PreloadAssemblySecurityValidatorRegistry.SwapValidatorForTests(
new SystemReflectionMetadataPreloadValidator());
}

[TearDown]
public void TearDown()
{
PreloadAssemblySecurityValidatorRegistry.SwapValidatorForTests(_previousValidator);
}

[Test]
public async Task CompileAsync_ScriptMode_MissingUsing_ShouldReportAutoInjectedNamespaces()
{
DynamicCodeCompiler compiler = new(DynamicCodeSecurityLevel.Restricted);
CompilationRequest request = new() {
Code = @"
StringBuilder builder = new();
builder.Append(""hello"");
return builder.ToString();
",
ClassName = "AutoInjectedNsTestCommand",
Namespace = "TestNamespace"
};

CompilationResult result = await compiler.CompileAsync(request, CancellationToken.None);

Assert.IsTrue(result.Success,
result.Errors != null && result.Errors.Count > 0 ? result.Errors[0].Message : "Should compile");
Assert.That(result.AutoInjectedNamespaces, Does.Contain("System.Text"));
}

[Test]
public async Task CompileAsync_ScriptMode_NoMissingUsing_ShouldReportEmptyAutoInjectedNamespaces()
{
DynamicCodeCompiler compiler = new(DynamicCodeSecurityLevel.Restricted);
CompilationRequest request = new() {
Code = "return 1 + 2;",
ClassName = "NoAutoInjectionCommand",
Namespace = "TestNamespace"
};

CompilationResult result = await compiler.CompileAsync(request, CancellationToken.None);

Assert.IsTrue(result.Success,
result.Errors != null && result.Errors.Count > 0 ? result.Errors[0].Message : "Should compile");
Assert.That(result.AutoInjectedNamespaces, Is.Empty);
}

[Test]
public async Task CompileAsync_ScriptMode_WithExistingUsing_ShouldNotReportIt()
{
DynamicCodeCompiler compiler = new(DynamicCodeSecurityLevel.Restricted);
CompilationRequest request = new() {
Code = @"
using System.Text;
StringBuilder builder = new();
builder.Append(""already imported"");
return builder.ToString();
",
ClassName = "ExistingUsingCommand",
Namespace = "TestNamespace"
};

CompilationResult result = await compiler.CompileAsync(request, CancellationToken.None);

Assert.IsTrue(result.Success,
result.Errors != null && result.Errors.Count > 0 ? result.Errors[0].Message : "Should compile");
Assert.That(result.AutoInjectedNamespaces, Is.Empty);
}

[Test]
public async Task CompileAsync_ScriptMode_MultipleMissing_ShouldReportAll()
{
DynamicCodeCompiler compiler = new(DynamicCodeSecurityLevel.Restricted);
CompilationRequest request = new() {
Code = @"
StringBuilder sb = new();
Regex regex = new(@""\d+"");
return sb.ToString() + regex.ToString();
",
ClassName = "MultipleAutoInjectedCommand",
Namespace = "TestNamespace"
};

CompilationResult result = await compiler.CompileAsync(request, CancellationToken.None);

Assert.IsTrue(result.Success,
result.Errors != null && result.Errors.Count > 0 ? result.Errors[0].Message : "Should compile");
Assert.That(result.AutoInjectedNamespaces, Does.Contain("System.Text"));
Assert.That(result.AutoInjectedNamespaces, Does.Contain("System.Text.RegularExpressions"));
}

[Test]
public async Task CompileAsync_RawMode_MissingUsing_ShouldReportAutoInjectedNamespaces()
{
DynamicCodeCompiler compiler = new(DynamicCodeSecurityLevel.Restricted);
CompilationRequest request = new() {
Code = @"
/// <summary>
/// Test fixture that verifies Raw Mode Missing Using behavior.
/// </summary>
public class RawModeMissingUsingTest
{
public async System.Threading.Tasks.Task<object> ExecuteAsync(
System.Collections.Generic.Dictionary<string, object> parameters = null,
System.Threading.CancellationToken ct = default)
{
StringBuilder sb = new();
sb.Append(""raw"");
return sb.ToString();
}
}
",
ClassName = "RawModeMissingUsingCommand",
Namespace = "TestNamespace"
};

CompilationResult result = await compiler.CompileAsync(request, CancellationToken.None);

Assert.IsTrue(result.Success,
result.Errors != null && result.Errors.Count > 0 ? result.Errors[0].Message : "Raw mode should compile with auto-using");
Assert.That(result.AutoInjectedNamespaces, Does.Contain("System.Text"));
}

[Test]
public async Task CompileAsync_RawMode_FullyQualifiedNames_ShouldReportEmptyAutoInjectedNamespaces()
{
DynamicCodeCompiler compiler = new(DynamicCodeSecurityLevel.Restricted);
CompilationRequest request = new() {
Code = @"
/// <summary>
/// Test fixture that verifies Raw Mode Auto Injected behavior.
/// </summary>
public class RawModeAutoInjectedTest
{
public async System.Threading.Tasks.Task<object> ExecuteAsync(
System.Collections.Generic.Dictionary<string, object> parameters = null,
System.Threading.CancellationToken ct = default)
{
System.Text.StringBuilder sb = new();
sb.Append(""raw"");
return sb.ToString();
}
}
",
ClassName = "RawModeAutoInjectedCommand",
Namespace = "TestNamespace"
};

CompilationResult result = await compiler.CompileAsync(request, CancellationToken.None);

Assert.IsTrue(result.Success,
result.Errors != null && result.Errors.Count > 0 ? result.Errors[0].Message : "Raw mode should compile");
// Raw mode uses fully-qualified names, so no auto-injection needed
Assert.That(result.AutoInjectedNamespaces, Is.Empty);
}

[Test]
public async Task CompileAsync_ScriptMode_ShouldPopulateCoreTimings()
{
DynamicCodeCompiler compiler = new(DynamicCodeSecurityLevel.Restricted);
CompilationRequest request = new() {
Code = "return 1 + 2;",
ClassName = "TimingVisibilityCommand",
Namespace = "TestNamespace"
};

CompilationResult result = await compiler.CompileAsync(request, CancellationToken.None);

Assert.IsTrue(result.Success, "Timing test should compile");
Assert.That(result.Timings, Has.Some.StartsWith("[Perf] ReferenceResolution:"));
Assert.That(result.Timings, Has.Some.StartsWith("[Perf] Build:"));
Assert.That(result.Timings, Has.Some.StartsWith("[Perf] AssemblyLoad:"));
Assert.That(result.Timings, Has.Some.StartsWith("[Perf] CompilePlan:"));
Assert.That(result.Timings, Has.Some.StartsWith("[Perf] CompileCacheCheck:"));
Assert.That(result.Timings, Has.Some.StartsWith("[Perf] CompilerTotal:"));
}
}
}
55 changes: 0 additions & 55 deletions Assets/Tests/Editor/DynamicCodeToolTests/CommandRunnerTests.cs

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using UnityEditor.Compilation;
using io.github.hatayama.UnityCliLoop.FirstPartyTools;

namespace io.github.hatayama.UnityCliLoop.Tests.Editor.DynamicCodeToolTests
Expand All @@ -24,51 +21,5 @@ public void CreateUniqueCompilationName_WhenClassNameContainsPathCharacters_Shou
Assert.That(compilationName, Does.Not.Contain("\\"));
Assert.That(compilationName, Does.Not.Contain(":"));
}

[Test]
public void AwaitBuildCompletionAsync_WhenCancellationIsRequested_ShouldCancelAfterBuildCompletion()
{
TaskCompletionSource<CompilerMessage[]> buildTaskCompletionSource =
new TaskCompletionSource<CompilerMessage[]>(TaskCreationOptions.RunContinuationsAsynchronously);
using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

Task<CompilerMessage[]> waitTask = AssemblyBuilderFallbackCompilerBackend.AwaitBuildCompletionAsync(
buildTaskCompletionSource.Task,
cancellationTokenSource.Token);

cancellationTokenSource.Cancel();

Assert.That(waitTask.IsCompleted, Is.False);

buildTaskCompletionSource.SetResult(System.Array.Empty<CompilerMessage>());

Assert.ThrowsAsync<TaskCanceledException>(async () => await waitTask);
}

[Test]
public async Task RegisterBuildFinishedContinuation_WhenCancellationWins_ShouldWaitForActualBuildCompletion()
{
TaskCompletionSource<CompilerMessage[]> buildTaskCompletionSource =
new TaskCompletionSource<CompilerMessage[]>(TaskCreationOptions.RunContinuationsAsynchronously);
using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
bool buildFinished = false;

Task continuationTask = AssemblyBuilderFallbackCompilerBackend.RegisterBuildFinishedContinuation(
buildTaskCompletionSource.Task,
() => buildFinished = true);
Task<CompilerMessage[]> waitTask = AssemblyBuilderFallbackCompilerBackend.AwaitBuildCompletionAsync(
buildTaskCompletionSource.Task,
cancellationTokenSource.Token);

cancellationTokenSource.Cancel();

Assert.That(buildFinished, Is.False);

buildTaskCompletionSource.SetResult(System.Array.Empty<CompilerMessage>());
Assert.That(async () => await waitTask, Throws.InstanceOf<TaskCanceledException>());
await continuationTask;

Assert.That(buildFinished, Is.True);
}
}
}
Loading