diff --git a/.agents/skills/uloop-execute-dynamic-code/SKILL.md b/.agents/skills/uloop-execute-dynamic-code/SKILL.md index 77060d33fb..f5343ce15a 100644 --- a/.agents/skills/uloop-execute-dynamic-code/SKILL.md +++ b/.agents/skills/uloop-execute-dynamic-code/SKILL.md @@ -39,7 +39,7 @@ float x = Mathf.PI; return x; ``` -**Forbidden** — these will be rejected at compile time: `System.IO.*`, `AssetDatabase.CreateFolder`, creating/editing `.cs`/`.asmdef` files. Use terminal commands for file operations instead. +Prefer terminal commands for file operations and keep snippets focused on Unity Editor state that existing uloop tools cannot inspect or change. ## Output @@ -50,12 +50,11 @@ Returns JSON: - `compilationErrors`: object[] — Roslyn diagnostics with `message`, `line`, `column`, `errorCode`, optional `hint` and `suggestions` - `errorMessage`: string — top-level failure summary (empty on success) - `error`: string — alias of `errorMessage` -- `securityLevel`: string — dynamic-code security level active for the request - `updatedCode`: string|null — the wrapped form actually compiled (handy when debugging using-statement reordering) - `diagnosticsSummary`: string|null — compact summary when diagnostics are available - `diagnostics`: object[] — structured diagnostics; same shape as `compilationErrors`, usually populated together with it -On `success: false`, inspect `compilationErrors` first. If empty, read `errorMessage` (and `logs` for extra context) — the failure may be a runtime exception, security violation, cancellation, or an "execution in progress" rejection, all of which return empty `compilationErrors`. Both EditMode and PlayMode are supported targets — the snippet runs in whichever mode the Editor is currently in. +On `success: false`, inspect `compilationErrors` first. If empty, read `errorMessage` (and `logs` for extra context) — the failure may be a runtime exception, cancellation, or an "execution in progress" rejection, all of which return empty `compilationErrors`. Both EditMode and PlayMode are supported targets — the snippet runs in whichever mode the Editor is currently in. ## Code Examples by Category diff --git a/.agents/skills/uloop-execute-dynamic-code/references/undo-operations.md b/.agents/skills/uloop-execute-dynamic-code/references/undo-operations.md index 34e31895d4..95a95b85a2 100644 --- a/.agents/skills/uloop-execute-dynamic-code/references/undo-operations.md +++ b/.agents/skills/uloop-execute-dynamic-code/references/undo-operations.md @@ -208,4 +208,3 @@ Undo.RecordObject(mat, "Change Material Color"); mat.color = Color.red; return "Changed material color (Undo available)"; ``` - diff --git a/.claude/skills/uloop-execute-dynamic-code/SKILL.md b/.claude/skills/uloop-execute-dynamic-code/SKILL.md index 77060d33fb..f5343ce15a 100644 --- a/.claude/skills/uloop-execute-dynamic-code/SKILL.md +++ b/.claude/skills/uloop-execute-dynamic-code/SKILL.md @@ -39,7 +39,7 @@ float x = Mathf.PI; return x; ``` -**Forbidden** — these will be rejected at compile time: `System.IO.*`, `AssetDatabase.CreateFolder`, creating/editing `.cs`/`.asmdef` files. Use terminal commands for file operations instead. +Prefer terminal commands for file operations and keep snippets focused on Unity Editor state that existing uloop tools cannot inspect or change. ## Output @@ -50,12 +50,11 @@ Returns JSON: - `compilationErrors`: object[] — Roslyn diagnostics with `message`, `line`, `column`, `errorCode`, optional `hint` and `suggestions` - `errorMessage`: string — top-level failure summary (empty on success) - `error`: string — alias of `errorMessage` -- `securityLevel`: string — dynamic-code security level active for the request - `updatedCode`: string|null — the wrapped form actually compiled (handy when debugging using-statement reordering) - `diagnosticsSummary`: string|null — compact summary when diagnostics are available - `diagnostics`: object[] — structured diagnostics; same shape as `compilationErrors`, usually populated together with it -On `success: false`, inspect `compilationErrors` first. If empty, read `errorMessage` (and `logs` for extra context) — the failure may be a runtime exception, security violation, cancellation, or an "execution in progress" rejection, all of which return empty `compilationErrors`. Both EditMode and PlayMode are supported targets — the snippet runs in whichever mode the Editor is currently in. +On `success: false`, inspect `compilationErrors` first. If empty, read `errorMessage` (and `logs` for extra context) — the failure may be a runtime exception, cancellation, or an "execution in progress" rejection, all of which return empty `compilationErrors`. Both EditMode and PlayMode are supported targets — the snippet runs in whichever mode the Editor is currently in. ## Code Examples by Category diff --git a/.claude/skills/uloop-execute-dynamic-code/references/undo-operations.md b/.claude/skills/uloop-execute-dynamic-code/references/undo-operations.md index 34e31895d4..95a95b85a2 100644 --- a/.claude/skills/uloop-execute-dynamic-code/references/undo-operations.md +++ b/.claude/skills/uloop-execute-dynamic-code/references/undo-operations.md @@ -208,4 +208,3 @@ Undo.RecordObject(mat, "Change Material Color"); mat.color = Color.red; return "Changed material color (Undo available)"; ``` - diff --git a/.codex/skills/uloop-execute-dynamic-code/SKILL.md b/.codex/skills/uloop-execute-dynamic-code/SKILL.md index 77060d33fb..f5343ce15a 100644 --- a/.codex/skills/uloop-execute-dynamic-code/SKILL.md +++ b/.codex/skills/uloop-execute-dynamic-code/SKILL.md @@ -39,7 +39,7 @@ float x = Mathf.PI; return x; ``` -**Forbidden** — these will be rejected at compile time: `System.IO.*`, `AssetDatabase.CreateFolder`, creating/editing `.cs`/`.asmdef` files. Use terminal commands for file operations instead. +Prefer terminal commands for file operations and keep snippets focused on Unity Editor state that existing uloop tools cannot inspect or change. ## Output @@ -50,12 +50,11 @@ Returns JSON: - `compilationErrors`: object[] — Roslyn diagnostics with `message`, `line`, `column`, `errorCode`, optional `hint` and `suggestions` - `errorMessage`: string — top-level failure summary (empty on success) - `error`: string — alias of `errorMessage` -- `securityLevel`: string — dynamic-code security level active for the request - `updatedCode`: string|null — the wrapped form actually compiled (handy when debugging using-statement reordering) - `diagnosticsSummary`: string|null — compact summary when diagnostics are available - `diagnostics`: object[] — structured diagnostics; same shape as `compilationErrors`, usually populated together with it -On `success: false`, inspect `compilationErrors` first. If empty, read `errorMessage` (and `logs` for extra context) — the failure may be a runtime exception, security violation, cancellation, or an "execution in progress" rejection, all of which return empty `compilationErrors`. Both EditMode and PlayMode are supported targets — the snippet runs in whichever mode the Editor is currently in. +On `success: false`, inspect `compilationErrors` first. If empty, read `errorMessage` (and `logs` for extra context) — the failure may be a runtime exception, cancellation, or an "execution in progress" rejection, all of which return empty `compilationErrors`. Both EditMode and PlayMode are supported targets — the snippet runs in whichever mode the Editor is currently in. ## Code Examples by Category diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/AssemblyReferencePolicyTests.cs b/Assets/Tests/Editor/DynamicCodeToolTests/AssemblyReferencePolicyTests.cs deleted file mode 100644 index 8b2fe726b0..0000000000 --- a/Assets/Tests/Editor/DynamicCodeToolTests/AssemblyReferencePolicyTests.cs +++ /dev/null @@ -1,173 +0,0 @@ -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -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 -{ - /// - /// Test for AssemblyReferencePolicy - /// Verify assembly reference policy for different security levels - /// - [TestFixture] - public class AssemblyReferencePolicyTests - { - [Test] - public void Level1_GetAssemblies_Includes_UnityEngine() - { - // Act - IReadOnlyList assemblies = AssemblyReferencePolicy.GetAssemblies(DynamicCodeSecurityLevel.Restricted); - - // Assert - Assert.IsNotNull(assemblies); - Assert.Greater(assemblies.Count, 0); - Assert.IsTrue(assemblies.Any(a => a.StartsWith("UnityEngine"))); - } - - [Test] - public void Level1_GetAssemblies_Includes_UnityEditor() - { - // Act - IReadOnlyList assemblies = AssemblyReferencePolicy.GetAssemblies(DynamicCodeSecurityLevel.Restricted); - - // Assert - Assert.IsNotNull(assemblies); - Assert.IsTrue(assemblies.Any(a => a.StartsWith("UnityEditor"))); - } - - [Test] - public void Level1_GetAssemblies_Includes_SystemIO() - { - // New specification: Include all assemblies even in Restricted mode - // Act - IReadOnlyList assemblies = AssemblyReferencePolicy.GetAssemblies(DynamicCodeSecurityLevel.Restricted); - - // Assert - Assert.IsNotNull(assemblies); - // Confirm system assemblies are included - Assert.IsTrue(assemblies.Any(a => a.StartsWith("System")), "System assemblies should be included in Restricted mode"); - } - - [Test] - public void Level1_GetAssemblies_Includes_AssemblyCSharp() - { - // Arrange & Act - IReadOnlyList assemblies = AssemblyReferencePolicy.GetAssemblies(DynamicCodeSecurityLevel.Restricted); - - // Assert - Assert.IsNotNull(assemblies); - // New specification: Allow Assembly-CSharp in Restricted mode (user-defined class execution feature) - // Should include Assembly-CSharp if it exists - Assembly assemblyCSharp = AppDomain.CurrentDomain.GetAssemblies() - .FirstOrDefault(a => a.GetName().Name == "Assembly-CSharp"); - - if (assemblyCSharp != null) - { - Assert.IsTrue(assemblies.Any(a => a == "Assembly-CSharp"), - "Level 1 (Restricted) should include Assembly-CSharp when it exists"); - } - } - - [Test] - public void Level2_GetAssemblies_Includes_Multiple_Assemblies() - { - // Act - IReadOnlyList assemblies = AssemblyReferencePolicy.GetAssemblies(DynamicCodeSecurityLevel.FullAccess); - - // Assert - Assert.IsNotNull(assemblies); - Assert.Greater(assemblies.Count, 10); // At least 10 or more assemblies - Assert.IsTrue(assemblies.Any(a => a.StartsWith("System"))); - Assert.IsTrue(assemblies.Any(a => a.StartsWith("UnityEngine"))); - } - - [Test] - public void Level2_AssemblyCSharp_Is_Included() - { - // Arrange & Act - IReadOnlyList assemblies = AssemblyReferencePolicy.GetAssemblies(DynamicCodeSecurityLevel.FullAccess); - - // Assert - Assert.IsNotNull(assemblies); - // Assembly-CSharp is available in Level 2 (FullAccess) - Assert.IsTrue(assemblies.Any(a => a == "Assembly-CSharp"), "Level 2 (FullAccess) should include Assembly-CSharp"); - } - - [Test] - public void IsAssemblyAllowed_Level1_Allows_UnityEngine() - { - // Act & Assert - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("UnityEngine", DynamicCodeSecurityLevel.Restricted)); - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("UnityEngine.CoreModule", DynamicCodeSecurityLevel.Restricted)); - } - - [Test] - public void IsAssemblyAllowed_Level1_Allows_SystemIO() - { - // New specification: Allow all assemblies in Restricted mode (block dangerous APIs after compilation) - // Act & Assert - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("System.IO", DynamicCodeSecurityLevel.Restricted)); - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("System.IO.FileSystem", DynamicCodeSecurityLevel.Restricted)); - } - - [Test] - public void IsAssemblyAllowed_Level1_Allows_SystemNet() - { - // New specification: Allow all assemblies in Restricted mode (block dangerous APIs after compilation) - // Act & Assert - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("System.Net", DynamicCodeSecurityLevel.Restricted)); - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("System.Net.Http", DynamicCodeSecurityLevel.Restricted)); - } - - [Test] - public void IsAssemblyAllowed_Level1_Allows_AssemblyCSharp() - { - // New specification: Allow Assembly-CSharp in Restricted mode (user-defined class execution feature) - // Act & Assert - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("Assembly-CSharp", DynamicCodeSecurityLevel.Restricted), - "Level 1 (Restricted) should allow Assembly-CSharp (new feature)"); - } - - [Test] - public void IsAssemblyAllowed_Level2_Allows_Basic_Assemblies() - { - // Act & Assert - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("UnityEngine", DynamicCodeSecurityLevel.FullAccess)); - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("System", DynamicCodeSecurityLevel.FullAccess)); - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("mscorlib", DynamicCodeSecurityLevel.FullAccess)); - } - - [Test] - public void IsAssemblyAllowed_Level2_Allows_AssemblyCSharp() - { - // Act & Assert - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("Assembly-CSharp", DynamicCodeSecurityLevel.FullAccess), - "Level 2 (FullAccess) should allow Assembly-CSharp"); - } - - [Test] - public void IsAssemblyAllowed_Level2_Allows_SystemReflectionEmit() - { - // New specification: Allow all assemblies in FullAccess mode - // Act & Assert - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("System.Reflection.Emit", DynamicCodeSecurityLevel.FullAccess), - "System.Reflection.Emit should be allowed in Level 2"); - Assert.IsTrue(AssemblyReferencePolicy.IsAssemblyAllowed("System.CodeDom", DynamicCodeSecurityLevel.FullAccess), - "System.CodeDom should be allowed in Level 2"); - } - - [Test] - public void IsAssemblyAllowed_Returns_False_For_Empty_Or_Null() - { - // Act & Assert - Assert.IsFalse(AssemblyReferencePolicy.IsAssemblyAllowed("", DynamicCodeSecurityLevel.FullAccess)); - Assert.IsFalse(AssemblyReferencePolicy.IsAssemblyAllowed(null, DynamicCodeSecurityLevel.FullAccess)); - Assert.IsFalse(AssemblyReferencePolicy.IsAssemblyAllowed(" ", DynamicCodeSecurityLevel.FullAccess)); - } - } -} \ No newline at end of file diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/AssemblyReferencePolicyTests.cs.meta b/Assets/Tests/Editor/DynamicCodeToolTests/AssemblyReferencePolicyTests.cs.meta deleted file mode 100644 index a86a51a77a..0000000000 --- a/Assets/Tests/Editor/DynamicCodeToolTests/AssemblyReferencePolicyTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: baf8074460eb14e58b92a740c1fa9f80 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/CompiledAssemblyLoaderTests.cs b/Assets/Tests/Editor/DynamicCodeToolTests/CompiledAssemblyLoaderTests.cs deleted file mode 100644 index dc8ce1ca6c..0000000000 --- a/Assets/Tests/Editor/DynamicCodeToolTests/CompiledAssemblyLoaderTests.cs +++ /dev/null @@ -1,184 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -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 -{ - /// - /// Test fixture that verifies Compiled Assembly Loader behavior. - /// - [TestFixture] - public class CompiledAssemblyLoaderTests - { - private const int CompilerProcessTimeoutMilliseconds = 30000; - - private IPreloadAssemblySecurityValidator _previousValidator; - private string _tempDirectoryPath; - - [SetUp] - public void SetUp() - { - _previousValidator = PreloadAssemblySecurityValidatorRegistry.SwapValidatorForTests(null); - _tempDirectoryPath = Path.Combine( - Path.GetTempPath(), - $"CompiledAssemblyLoaderTests_{Guid.NewGuid():N}"); - Directory.CreateDirectory(_tempDirectoryPath); - } - - [TearDown] - public void TearDown() - { - PreloadAssemblySecurityValidatorRegistry.SwapValidatorForTests(_previousValidator); - if (Directory.Exists(_tempDirectoryPath)) - { - Directory.Delete(_tempDirectoryPath, true); - } - } - - [Test] - public void Load_WhenCustomValidatorIsRegistered_ShouldStillRunMetadataFallbackValidation() - { - byte[] assemblyBytes = BuildAssemblyBytes( - "using System.IO; public class DangerousMetadataType { public FileInfo DangerousField; public int Execute() { return 1; } }"); - PreloadAssemblySecurityValidatorRegistry.SwapValidatorForTests(new AllowAllPreloadAssemblySecurityValidator()); - - CompiledAssemblyLoadResult result = CompiledAssemblyLoader.Load( - DynamicCodeSecurityLevel.Restricted, - assemblyBytes); - - Assert.That(result.Success, Is.False); - Assert.That( - result.SecurityViolations.Any(violation => violation.ApiName == "System.IO.FileInfo"), - Is.True, - "Metadata fallback validation should keep rejecting dangerous field signatures even when a custom validator is registered."); - } - - [Test] - public void Load_WhenOverrideValidatorIsRegistered_ShouldStillApplyMandatoryPostLoadValidation() - { - byte[] assemblyBytes = BuildAssemblyBytes( - "using System.IO; public class DangerousMetadataType { public FileInfo DangerousField; public int Execute() { return 1; } }"); - PreloadAssemblySecurityValidatorRegistry.SwapValidatorForTests(new AllowAllOverridePreloadAssemblySecurityValidator()); - - CompiledAssemblyLoadResult result = CompiledAssemblyLoader.Load( - DynamicCodeSecurityLevel.Restricted, - assemblyBytes); - - Assert.That(result.Success, Is.False); - Assert.That( - result.SecurityViolations.Any(violation => violation.ApiName == "System.IO.FileInfo"), - Is.True); - } - - private byte[] BuildAssemblyBytes(string source) - { - ExternalCompilerPaths externalCompilerPaths = ExternalCompilerPathResolver.Resolve(); - Assert.That(externalCompilerPaths, Is.Not.Null, "Unity external compiler layout should be available for this test"); - - DynamicReferenceSetBuilderService referenceSetBuilder = new(); - List references = referenceSetBuilder.BuildReferenceSet( - new List(), - null, - externalCompilerPaths); - - string sourcePath = Path.Combine(_tempDirectoryPath, "DangerousMetadataType.cs"); - string dllPath = Path.Combine(_tempDirectoryPath, "DangerousMetadataType.dll"); - string responsePath = Path.Combine(_tempDirectoryPath, "DangerousMetadataType.rsp"); - - File.WriteAllText(sourcePath, source); - WriteCompilerResponseFile(responsePath, sourcePath, dllPath, references); - - ProcessStartInfo startInfo = new() { - FileName = externalCompilerPaths.DotnetHostPath, - Arguments = $"\"{externalCompilerPaths.CompilerDllPath}\" @\"{responsePath}\"", - WorkingDirectory = _tempDirectoryPath, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - using Process process = ProcessStartHelper.TryStart(startInfo); - Assert.That(process, Is.Not.Null, "The external C# compiler should start for loader tests"); - - Task stdoutTask = process.StandardOutput.ReadToEndAsync(); - Task stderrTask = process.StandardError.ReadToEndAsync(); - bool exited = process.WaitForExit(CompilerProcessTimeoutMilliseconds); - if (!exited) - { - process.Kill(); - Assert.Fail("The external C# compiler did not exit before the timeout."); - } - - process.WaitForExit(); - string stdout = stdoutTask.Result; - string stderr = stderrTask.Result; - - Assert.That(process.ExitCode, Is.EqualTo(0), $"{stdout}\n{stderr}"); - return File.ReadAllBytes(dllPath); - } - - private static void WriteCompilerResponseFile( - string responsePath, - string sourcePath, - string dllPath, - IReadOnlyCollection references) - { - List lines = new() { - "-nologo", - "-target:library", - $"-out:\"{dllPath}\"" - }; - - foreach (string reference in references) - { - lines.Add($"-r:\"{reference}\""); - } - - lines.Add($"\"{sourcePath}\""); - File.WriteAllLines(responsePath, lines); - } - - /// - /// Test support type used by editor and play mode fixtures. - /// - private sealed class AllowAllPreloadAssemblySecurityValidator : IPreloadAssemblySecurityValidator - { - public SecurityValidationResult Validate(byte[] assemblyBytes) - { - return new SecurityValidationResult - { - IsValid = true, - Violations = new List(), - CompilationErrors = new List() - }; - } - } - - /// - /// Test support type used by editor and play mode fixtures. - /// - private sealed class AllowAllOverridePreloadAssemblySecurityValidator : - IPreloadAssemblySecurityValidator, - IOverrideDefaultPreloadAssemblySecurityValidation - { - public SecurityValidationResult Validate(byte[] assemblyBytes) - { - return new SecurityValidationResult - { - IsValid = true, - Violations = new List(), - CompilationErrors = new List() - }; - } - } - } -} diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/CompiledAssemblyLoaderTests.cs.meta b/Assets/Tests/Editor/DynamicCodeToolTests/CompiledAssemblyLoaderTests.cs.meta deleted file mode 100644 index cc547bc175..0000000000 --- a/Assets/Tests/Editor/DynamicCodeToolTests/CompiledAssemblyLoaderTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 71b5adb3cc84e4fd2aa3a039ecb50315 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/DangerousApiCatalogTests.cs b/Assets/Tests/Editor/DynamicCodeToolTests/DangerousApiCatalogTests.cs deleted file mode 100644 index b10b12e7dd..0000000000 --- a/Assets/Tests/Editor/DynamicCodeToolTests/DangerousApiCatalogTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using NUnit.Framework; - -using io.github.hatayama.UnityCliLoop.ToolContracts; - -namespace io.github.hatayama.UnityCliLoop.Tests.Editor.DynamicCodeToolTests -{ - /// - /// Test fixture that verifies Dangerous API Catalog behavior. - /// - [TestFixture] - public class DangerousApiCatalogTests - { - [Test] - public void EnumerateDangerousMembers_ShouldReturnDefensiveCopies() - { - List>> snapshot = - new List>>(DangerousApiCatalog.EnumerateDangerousMembers()); - - int processEntryIndex = snapshot.FindIndex(entry => entry.Key == "System.Diagnostics.Process"); - Assert.AreNotEqual(-1, processEntryIndex, "Process entry should exist in the catalog"); - - KeyValuePair> processEntry = snapshot[processEntryIndex]; - List mutableCopy = processEntry.Value as List; - Assert.IsNotNull(mutableCopy, "Returned collection should be a mutable defensive copy"); - Assert.Contains("Start", mutableCopy, "The defensive copy should contain the dangerous API entry"); - - mutableCopy.Remove("Start"); - - Assert.IsTrue( - DangerousApiCatalog.IsDangerousApi("System.Diagnostics.Process", "Start"), - "Mutating an enumerated copy must not weaken the catalog"); - } - } -} diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/DangerousApiCatalogTests.cs.meta b/Assets/Tests/Editor/DynamicCodeToolTests/DangerousApiCatalogTests.cs.meta deleted file mode 100644 index c943d6ea83..0000000000 --- a/Assets/Tests/Editor/DynamicCodeToolTests/DangerousApiCatalogTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ccf9688d2e22c47e78b26898dbf5c538 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeExecutionFacadeTests.cs b/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeExecutionFacadeTests.cs index bf7a3e3618..dfe42b9d06 100644 --- a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeExecutionFacadeTests.cs +++ b/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeExecutionFacadeTests.cs @@ -6,8 +6,6 @@ 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 { @@ -20,38 +18,21 @@ public class DynamicCodeExecutionFacadeTests private static readonly TimeSpan CancellationPropagationTimeout = TimeSpan.FromSeconds(1); [Test] - public async Task ExecuteAsync_WhenSameSecurityLevelUsedTwice_ShouldReuseExecutor() + public async Task ExecuteAsync_WhenCalledTwice_ShouldReuseExecutor() { + // Verifies dynamic code execution reuses the same cached executor. FakeDynamicCodeExecutorProvider provider = new(); using DynamicCodeExecutorPool pool = new DynamicCodeExecutorPool(provider); using DynamicCodeExecutionFacade facade = new DynamicCodeExecutionFacade(pool); await facade.ExecuteAsync( - CreateRequest(DynamicCodeSecurityLevel.Restricted, "return 1;"), + CreateRequest("return 1;"), CancellationToken.None); await facade.ExecuteAsync( - CreateRequest(DynamicCodeSecurityLevel.Restricted, "return 2;"), + CreateRequest("return 2;"), CancellationToken.None); - Assert.That(provider.CreateCallsBySecurityLevel[DynamicCodeSecurityLevel.Restricted], Is.EqualTo(1)); - } - - [Test] - public async Task ExecuteAsync_WhenSecurityLevelChanges_ShouldCreateSeparateExecutors() - { - FakeDynamicCodeExecutorProvider provider = new(); - using DynamicCodeExecutorPool pool = new DynamicCodeExecutorPool(provider); - using DynamicCodeExecutionFacade facade = new DynamicCodeExecutionFacade(pool); - - await facade.ExecuteAsync( - CreateRequest(DynamicCodeSecurityLevel.Restricted, "return 1;"), - CancellationToken.None); - await facade.ExecuteAsync( - CreateRequest(DynamicCodeSecurityLevel.FullAccess, "return 2;"), - CancellationToken.None); - - Assert.That(provider.CreateCallsBySecurityLevel[DynamicCodeSecurityLevel.Restricted], Is.EqualTo(1)); - Assert.That(provider.CreateCallsBySecurityLevel[DynamicCodeSecurityLevel.FullAccess], Is.EqualTo(1)); + Assert.That(provider.CreateCallCount, Is.EqualTo(1)); } [Test] @@ -64,7 +45,7 @@ public void Dispose_WhenExecutorsWereCreated_ShouldDisposeCachedExecutors() Assert.DoesNotThrowAsync(async () => { await facade.ExecuteAsync( - CreateRequest(DynamicCodeSecurityLevel.Restricted, "return 1;"), + CreateRequest("return 1;"), CancellationToken.None); }); @@ -100,7 +81,7 @@ public async Task ExecuteAsync_WhenForegroundExecutionIsCancelled_ShouldAllowNex using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); Task firstExecution = facade.ExecuteAsync( - CreateRequest(DynamicCodeSecurityLevel.Restricted, FakeDynamicCodeExecutor.BlockingCode), + CreateRequest(FakeDynamicCodeExecutor.BlockingCode), cancellationTokenSource.Token); FakeDynamicCodeExecutor executor = await provider.CreatedExecutorTask; await executor.BlockingExecutionStartedTask; @@ -110,7 +91,7 @@ public async Task ExecuteAsync_WhenForegroundExecutionIsCancelled_ShouldAllowNex await AssertCanceledWithinTimeoutAsync(firstExecution); ExecutionResult secondExecution = await facade.ExecuteAsync( - CreateRequest(DynamicCodeSecurityLevel.Restricted, "return 2;"), + CreateRequest("return 2;"), CancellationToken.None); Assert.That(secondExecution.Success, Is.True); @@ -134,13 +115,10 @@ private static async Task AssertCanceledWithinTimeoutAsync(Task task) Assert.That(task.IsCanceled, Is.True); } - private static DynamicCodeExecutionRequest CreateRequest( - DynamicCodeSecurityLevel securityLevel, - string code) + private static DynamicCodeExecutionRequest CreateRequest(string code) { return new DynamicCodeExecutionRequest { - SecurityLevel = securityLevel, Code = code, ClassName = "FacadeTestCommand" }; @@ -151,7 +129,7 @@ private static DynamicCodeExecutionRequest CreateRequest( /// private sealed class FakeDynamicCodeExecutorProvider : IDynamicCodeExecutorProvider { - public Dictionary CreateCallsBySecurityLevel { get; } = new(); + public int CreateCallCount { get; private set; } public List CreatedExecutors { get; } = new(); @@ -160,14 +138,9 @@ private sealed class FakeDynamicCodeExecutorProvider : IDynamicCodeExecutorProvi public Task CreatedExecutorTask => _createdExecutorCompletionSource.Task; - public IDynamicCodeExecutor Create(DynamicCodeSecurityLevel securityLevel) + public IDynamicCodeExecutor Create() { - if (!CreateCallsBySecurityLevel.ContainsKey(securityLevel)) - { - CreateCallsBySecurityLevel[securityLevel] = 0; - } - - CreateCallsBySecurityLevel[securityLevel]++; + CreateCallCount++; FakeDynamicCodeExecutor executor = new(); CreatedExecutors.Add(executor); diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeExecutorPoolTests.cs b/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeExecutorPoolTests.cs index 166661db32..2fb5107e64 100644 --- a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeExecutorPoolTests.cs +++ b/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeExecutorPoolTests.cs @@ -5,8 +5,6 @@ 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 { @@ -17,55 +15,57 @@ namespace io.github.hatayama.UnityCliLoop.Tests.Editor.DynamicCodeToolTests public class DynamicCodeExecutorPoolTests { [Test] - public void GetOrCreate_WhenSameSecurityLevelRequestedTwice_ShouldReuseExecutor() + public void GetOrCreate_WhenRequestedTwice_ShouldReuseExecutor() { + // Verifies the pool keeps a single executor for dynamic code execution. FakeDynamicCodeExecutorProvider provider = new(); using DynamicCodeExecutorPool pool = new DynamicCodeExecutorPool(provider); - IDynamicCodeExecutor first = pool.GetOrCreate(DynamicCodeSecurityLevel.Restricted); - IDynamicCodeExecutor second = pool.GetOrCreate(DynamicCodeSecurityLevel.Restricted); + IDynamicCodeExecutor first = pool.GetOrCreate(); + IDynamicCodeExecutor second = pool.GetOrCreate(); Assert.That(first, Is.SameAs(second)); - Assert.That(provider.CreateCallsBySecurityLevel[DynamicCodeSecurityLevel.Restricted], Is.EqualTo(1)); + Assert.That(provider.CreateCallCount, Is.EqualTo(1)); } [Test] public void Dispose_WhenExecutorsWereCreated_ShouldDisposeAllExecutors() { + // Verifies disposing the pool disposes its cached executor once. FakeDynamicCodeExecutorProvider provider = new(); DynamicCodeExecutorPool pool = new(provider); - pool.GetOrCreate(DynamicCodeSecurityLevel.Restricted); - pool.GetOrCreate(DynamicCodeSecurityLevel.FullAccess); + pool.GetOrCreate(); pool.Dispose(); Assert.That(provider.CreatedExecutors[0].DisposeCallCount, Is.EqualTo(1)); - Assert.That(provider.CreatedExecutors[1].DisposeCallCount, Is.EqualTo(1)); } [Test] public void GetOrCreate_AfterDispose_ShouldThrowObjectDisposedException() { + // Verifies the pool fails fast when used after disposal. FakeDynamicCodeExecutorProvider provider = new(); DynamicCodeExecutorPool pool = new(provider); pool.Dispose(); Assert.That( - () => pool.GetOrCreate(DynamicCodeSecurityLevel.Restricted), + () => pool.GetOrCreate(), Throws.TypeOf()); } [Test] public void GetOrCreate_WhenProviderReturnsStubFirst_ShouldReplaceItWhenRealExecutorBecomesAvailable() { + // Verifies unavailable compiler stubs are not cached permanently. SequenceDynamicCodeExecutorProvider provider = new( new DynamicCodeExecutorStub(), new FakeDynamicCodeExecutor()); using DynamicCodeExecutorPool pool = new DynamicCodeExecutorPool(provider); - IDynamicCodeExecutor first = pool.GetOrCreate(DynamicCodeSecurityLevel.Restricted); - IDynamicCodeExecutor second = pool.GetOrCreate(DynamicCodeSecurityLevel.Restricted); + IDynamicCodeExecutor first = pool.GetOrCreate(); + IDynamicCodeExecutor second = pool.GetOrCreate(); Assert.That(first, Is.TypeOf()); Assert.That(second, Is.TypeOf()); @@ -77,18 +77,13 @@ public void GetOrCreate_WhenProviderReturnsStubFirst_ShouldReplaceItWhenRealExec /// private sealed class FakeDynamicCodeExecutorProvider : IDynamicCodeExecutorProvider { - public Dictionary CreateCallsBySecurityLevel { get; } = new(); + public int CreateCallCount { get; private set; } public List CreatedExecutors { get; } = new(); - public IDynamicCodeExecutor Create(DynamicCodeSecurityLevel securityLevel) + public IDynamicCodeExecutor Create() { - if (!CreateCallsBySecurityLevel.ContainsKey(securityLevel)) - { - CreateCallsBySecurityLevel[securityLevel] = 0; - } - - CreateCallsBySecurityLevel[securityLevel]++; + CreateCallCount++; FakeDynamicCodeExecutor executor = new(); CreatedExecutors.Add(executor); @@ -108,7 +103,7 @@ public SequenceDynamicCodeExecutorProvider(params IDynamicCodeExecutor[] executo _executors = new Queue(executors); } - public IDynamicCodeExecutor Create(DynamicCodeSecurityLevel securityLevel) + public IDynamicCodeExecutor Create() { return _executors.Dequeue(); } diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityLevelTests.cs b/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityLevelTests.cs deleted file mode 100644 index d31e5382d9..0000000000 --- a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityLevelTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -using NUnit.Framework; - -using io.github.hatayama.UnityCliLoop.ToolContracts; -using io.github.hatayama.UnityCliLoop.Domain; - -namespace io.github.hatayama.UnityCliLoop.Tests.Editor.DynamicCodeToolTests -{ - /// - /// Test fixture that verifies Dynamic Code Security Level behavior. - /// - [TestFixture] - public class DynamicCodeSecurityLevelTests - { - [Test] - public void Verify_Correct_Level_Values() - { - Assert.AreEqual(1, (int)DynamicCodeSecurityLevel.Restricted); - Assert.AreEqual(2, (int)DynamicCodeSecurityLevel.FullAccess); - } - - [Test] - public void Verify_All_Levels_Are_Defined() - { - string[] expectedNames = { "Restricted", "FullAccess" }; - string[] actualNames = System.Enum.GetNames(typeof(DynamicCodeSecurityLevel)); - - Assert.AreEqual(expectedNames.Length, actualNames.Length); - foreach (string name in expectedNames) - { - Assert.Contains(name, actualNames); - } - } - } -} diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityLevelTests.cs.meta b/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityLevelTests.cs.meta deleted file mode 100644 index f3dec13b3e..0000000000 --- a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityLevelTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7d8c7789ea8994e6ca99edfd2c0bd6e5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityManagerTests.cs b/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityManagerTests.cs deleted file mode 100644 index 525bd4f1f0..0000000000 --- a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityManagerTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -using NUnit.Framework; -using System; - -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 -{ - /// - /// Tests for DynamicCodeSecurityManager - /// Verify security level management and dangerous API detection functionality - /// - [TestFixture] - public class DynamicCodeSecurityManagerTests - { - [SetUp] - public void SetUp() - { - // No setup required for v4.0 stateless design - } - - [Test] - public void GetAllowedAssemblies_ReturnsAppropriateListForEachLevel() - { - // Act - var level1Assemblies = DynamicCodeSecurityManager.GetAllowedAssemblies(DynamicCodeSecurityLevel.Restricted); - var level2Assemblies = DynamicCodeSecurityManager.GetAllowedAssemblies(DynamicCodeSecurityLevel.FullAccess); - - Assert.Greater(level1Assemblies.Count, 0); - Assert.AreEqual(level2Assemblies.Count, level1Assemblies.Count); - } - } -} \ No newline at end of file diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityManagerTests.cs.meta b/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityManagerTests.cs.meta deleted file mode 100644 index a7c0c19843..0000000000 --- a/Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeSecurityManagerTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 00403deddb5a14e11a82f19fa8385a8c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Tests/Editor/DynamicCodeToolTests/ExecuteDynamicCodeUseCaseTests.cs b/Assets/Tests/Editor/DynamicCodeToolTests/ExecuteDynamicCodeUseCaseTests.cs index b8aad8a445..9ecc3b4384 100644 --- a/Assets/Tests/Editor/DynamicCodeToolTests/ExecuteDynamicCodeUseCaseTests.cs +++ b/Assets/Tests/Editor/DynamicCodeToolTests/ExecuteDynamicCodeUseCaseTests.cs @@ -8,7 +8,6 @@ using NUnit.Framework; using io.github.hatayama.UnityCliLoop.Application; -using io.github.hatayama.UnityCliLoop.Domain; using io.github.hatayama.UnityCliLoop.FirstPartyTools; using io.github.hatayama.UnityCliLoop.Infrastructure; using io.github.hatayama.UnityCliLoop.ToolContracts; @@ -176,28 +175,17 @@ public async Task ExecuteAsync_WhenInitialCompilationLooksLikeMissingReturn_Shou Result = "ok" }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "int x = 1", + CompileOnly = false + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "int x = 1", - CompileOnly = false - }, - CancellationToken.None); - - Assert.That(response.Success, Is.True); - Assert.That(runtime.Requests, Has.Count.EqualTo(2)); - Assert.That(runtime.Requests[1].Code, Does.Contain("return null;")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.True); + Assert.That(runtime.Requests, Has.Count.EqualTo(2)); + Assert.That(runtime.Requests[1].Code, Does.Contain("return null;")); } [Test] @@ -225,28 +213,17 @@ public async Task ExecuteAsync_WhenMissingReturnFailureHasUpdatedCode_ShouldRetr Result = "ok" }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "if (condition) return \"x\";", + CompileOnly = false + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "if (condition) return \"x\";", - CompileOnly = false - }, - CancellationToken.None); - - Assert.That(response.Success, Is.True); - Assert.That(runtime.Requests, Has.Count.EqualTo(2)); - Assert.That(runtime.Requests[1].Code, Does.Contain("return null;")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.True); + Assert.That(runtime.Requests, Has.Count.EqualTo(2)); + Assert.That(runtime.Requests[1].Code, Does.Contain("return null;")); } [Test] @@ -269,27 +246,16 @@ public async Task ExecuteAsync_WhenRawTypeDeclarationHasMissingReturnFailure_Sho } }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "public class Sample { public string Run(bool condition) { if (condition) return \"x\"; } }", + CompileOnly = false + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "public class Sample { public string Run(bool condition) { if (condition) return \"x\"; } }", - CompileOnly = false - }, - CancellationToken.None); - - Assert.That(response.Success, Is.False); - Assert.That(runtime.Requests, Has.Count.EqualTo(1)); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.False); + Assert.That(runtime.Requests, Has.Count.EqualTo(1)); } [Test] @@ -315,29 +281,18 @@ public async Task ExecuteAsync_WhenYieldingRequestNeedsMissingReturnRetry_Should Result = "ok" }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "int x = 1", + YieldToForegroundRequests = true + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "int x = 1", - YieldToForegroundRequests = true - }, - CancellationToken.None); - - Assert.That(response.Success, Is.True); - Assert.That(runtime.TryExecuteRequests, Has.Count.EqualTo(2)); - Assert.That(runtime.TryExecuteRequests[0].YieldToForegroundRequests, Is.True); - Assert.That(runtime.TryExecuteRequests[1].YieldToForegroundRequests, Is.True); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.True); + Assert.That(runtime.TryExecuteRequests, Has.Count.EqualTo(2)); + Assert.That(runtime.TryExecuteRequests[0].YieldToForegroundRequests, Is.True); + Assert.That(runtime.TryExecuteRequests[1].YieldToForegroundRequests, Is.True); } [Test] @@ -356,36 +311,25 @@ public async Task ExecuteAsync_WhenYieldingStartupProbeSucceeds_ShouldSkipNextFo Result = "user" }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse probeResponse = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return \"probe\";", + YieldToForegroundRequests = true + }, + CancellationToken.None); + ExecuteDynamicCodeResponse userResponse = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return \"user\";" + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse probeResponse = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return \"probe\";", - YieldToForegroundRequests = true - }, - CancellationToken.None); - ExecuteDynamicCodeResponse userResponse = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return \"user\";" - }, - CancellationToken.None); - - Assert.That(probeResponse.Success, Is.True); - Assert.That(userResponse.Success, Is.True); - Assert.That(runtime.TryExecuteRequests, Has.Count.EqualTo(1)); - Assert.That(runtime.Requests, Has.Count.EqualTo(1)); - Assert.That(runtime.Requests[0].Code, Is.EqualTo("return \"user\";")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(probeResponse.Success, Is.True); + Assert.That(userResponse.Success, Is.True); + Assert.That(runtime.TryExecuteRequests, Has.Count.EqualTo(1)); + Assert.That(runtime.Requests, Has.Count.EqualTo(1)); + Assert.That(runtime.Requests[0].Code, Is.EqualTo("return \"user\";")); } [Test] @@ -399,27 +343,16 @@ public async Task ExecuteAsync_WhenInitialExecutionSucceeds_ShouldNotRetry() Result = "ok" }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return 1;", + CompileOnly = false + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return 1;", - CompileOnly = false - }, - CancellationToken.None); - - Assert.That(response.Success, Is.True); - Assert.That(runtime.Requests, Has.Count.EqualTo(1)); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.True); + Assert.That(runtime.Requests, Has.Count.EqualTo(1)); } [Test] @@ -442,33 +375,22 @@ public async Task ExecuteAsync_WhenFirstForegroundExecutionRuns_ShouldWarmHidden Result = "ok" }); ExecuteDynamicCodeUseCase useCase = new(runtime); - - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return 1;" - }, - CancellationToken.None); - - Assert.That(response.Success, Is.True); - Assert.That(runtime.Requests, Has.Count.EqualTo(3)); - AssertPrewarmCodeMatchesLiteralReturnShape( - runtime.Requests[0].Code, - "return \"user value\";"); - AssertPrewarmCodeMatchesLiteralReturnShape( - runtime.Requests[1].Code, - "return\n \"user value\";"); - Assert.That(runtime.Requests[2].Code, Is.EqualTo("return 1;")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return 1;" + }, + CancellationToken.None); + + Assert.That(response.Success, Is.True); + Assert.That(runtime.Requests, Has.Count.EqualTo(3)); + AssertPrewarmCodeMatchesLiteralReturnShape( + runtime.Requests[0].Code, + "return \"user value\";"); + AssertPrewarmCodeMatchesLiteralReturnShape( + runtime.Requests[1].Code, + "return\n \"user value\";"); + Assert.That(runtime.Requests[2].Code, Is.EqualTo("return 1;")); } [Test] @@ -496,34 +418,23 @@ public async Task ExecuteAsync_WhenForegroundWarmupAlreadyCompleted_ShouldNotRep Result = "second" }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse firstResponse = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return 1;" + }, + CancellationToken.None); + ExecuteDynamicCodeResponse secondResponse = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return 2;" + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse firstResponse = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return 1;" - }, - CancellationToken.None); - ExecuteDynamicCodeResponse secondResponse = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return 2;" - }, - CancellationToken.None); - - Assert.That(firstResponse.Success, Is.True); - Assert.That(secondResponse.Success, Is.True); - Assert.That(runtime.Requests, Has.Count.EqualTo(4)); - Assert.That(runtime.Requests[3].Code, Is.EqualTo("return 2;")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(firstResponse.Success, Is.True); + Assert.That(secondResponse.Success, Is.True); + Assert.That(runtime.Requests, Has.Count.EqualTo(4)); + Assert.That(runtime.Requests[3].Code, Is.EqualTo("return 2;")); } [Test] @@ -546,38 +457,27 @@ public async Task ExecuteAsync_WhenWarmupFailsButForegroundExecutionSucceeds_Sho Result = "second" }); ExecuteDynamicCodeUseCase useCase = new(runtime); - - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse firstResponse = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return 1;" - }, - CancellationToken.None); - ExecuteDynamicCodeResponse secondResponse = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return 2;" - }, - CancellationToken.None); - - Assert.That(firstResponse.Success, Is.True); - Assert.That(secondResponse.Success, Is.True); - Assert.That(runtime.Requests, Has.Count.EqualTo(3)); - AssertPrewarmCodeMatchesLiteralReturnShape( - runtime.Requests[0].Code, - "return \"user value\";"); - Assert.That(runtime.Requests[1].Code, Is.EqualTo("return 1;")); - Assert.That(runtime.Requests[2].Code, Is.EqualTo("return 2;")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + ExecuteDynamicCodeResponse firstResponse = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return 1;" + }, + CancellationToken.None); + ExecuteDynamicCodeResponse secondResponse = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return 2;" + }, + CancellationToken.None); + + Assert.That(firstResponse.Success, Is.True); + Assert.That(secondResponse.Success, Is.True); + Assert.That(runtime.Requests, Has.Count.EqualTo(3)); + AssertPrewarmCodeMatchesLiteralReturnShape( + runtime.Requests[0].Code, + "return \"user value\";"); + Assert.That(runtime.Requests[1].Code, Is.EqualTo("return 1;")); + Assert.That(runtime.Requests[2].Code, Is.EqualTo("return 2;")); } [Test] @@ -590,28 +490,17 @@ public async Task ExecuteAsync_WhenRequestIsCompileOnly_ShouldSkipForegroundWarm Result = "ok" }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return 1;", + CompileOnly = true + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return 1;", - CompileOnly = true - }, - CancellationToken.None); - - Assert.That(response.Success, Is.True); - Assert.That(runtime.Requests, Has.Count.EqualTo(1)); - Assert.That(runtime.Requests[0].Code, Is.EqualTo("return 1;")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.True); + Assert.That(runtime.Requests, Has.Count.EqualTo(1)); + Assert.That(runtime.Requests[0].Code, Is.EqualTo("return 1;")); } [Test] @@ -653,30 +542,19 @@ public async Task ExecuteAsync_WhenRetryAfterMissingReturnStillFails_ShouldRetur Timings = new List { "retry timing" } }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "int x = 1", + CompileOnly = false + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "int x = 1", - CompileOnly = false - }, - CancellationToken.None); - - Assert.That(response.Success, Is.False); - Assert.That(runtime.Requests, Has.Count.EqualTo(2)); - Assert.That(response.Timings, Contains.Item("retry timing")); - Assert.That(response.Diagnostics, Has.Count.EqualTo(1)); - Assert.That(response.Diagnostics[0].ErrorCode, Is.EqualTo("CS0029")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.False); + Assert.That(runtime.Requests, Has.Count.EqualTo(2)); + Assert.That(response.Timings, Contains.Item("retry timing")); + Assert.That(response.Diagnostics, Has.Count.EqualTo(1)); + Assert.That(response.Diagnostics[0].ErrorCode, Is.EqualTo("CS0029")); } [Test] @@ -704,32 +582,21 @@ public async Task ExecuteAsync_WhenDiagnosticLineUsesTwoDigits_ShouldAlignCaretW } }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return x;" + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return x;" - }, - CancellationToken.None); - - Assert.That(response.Diagnostics, Has.Count.EqualTo(1)); + Assert.That(response.Diagnostics, Has.Count.EqualTo(1)); - string[] contextLines = response.Diagnostics[0].Context - .Split(new[] { '\n' }, System.StringSplitOptions.RemoveEmptyEntries); - int targetLineIndex = System.Array.FindIndex(contextLines, line => line.StartsWith("L10:")); + string[] contextLines = response.Diagnostics[0].Context + .Split(new[] { '\n' }, System.StringSplitOptions.RemoveEmptyEntries); + int targetLineIndex = System.Array.FindIndex(contextLines, line => line.StartsWith("L10:")); - Assert.That(targetLineIndex, Is.GreaterThanOrEqualTo(0)); - Assert.That(contextLines[targetLineIndex + 1].IndexOf('^'), Is.EqualTo("L10:".Length + 1)); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(targetLineIndex, Is.GreaterThanOrEqualTo(0)); + Assert.That(contextLines[targetLineIndex + 1].IndexOf('^'), Is.EqualTo("L10:".Length + 1)); } [Test] @@ -740,27 +607,16 @@ public async Task ExecuteAsync_WhenRuntimeThrowsOperationCanceledException_Shoul ExecuteDynamicCodeUseCase useCase = new(runtime); using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource.Cancel(); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return 1;" + }, + cancellationTokenSource.Token); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return 1;" - }, - cancellationTokenSource.Token); - - Assert.That(response.Success, Is.False); - Assert.That(response.ErrorMessage, Is.EqualTo(UnityCliLoopConstants.ERROR_MESSAGE_EXECUTION_CANCELLED)); - Assert.That(response.Logs, Contains.Item("Execution cancelled")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.False); + Assert.That(response.ErrorMessage, Is.EqualTo(UnityCliLoopConstants.ERROR_MESSAGE_EXECUTION_CANCELLED)); + Assert.That(response.Logs, Contains.Item("Execution cancelled")); } [Test] @@ -776,28 +632,17 @@ public async Task ExecuteAsync_WhenRuntimeReturnsCancelledResult_ShouldPreserveN Timings = new List { "compile_ms=1" } }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "return 1;" + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "return 1;" - }, - CancellationToken.None); - - Assert.That(response.Success, Is.False); - Assert.That(response.ErrorMessage, Is.EqualTo(UnityCliLoopConstants.ERROR_MESSAGE_EXECUTION_CANCELLED)); - Assert.That(response.Logs, Contains.Item("Execution cancelled")); - Assert.That(response.Timings, Contains.Item("compile_ms=1")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.False); + Assert.That(response.ErrorMessage, Is.EqualTo(UnityCliLoopConstants.ERROR_MESSAGE_EXECUTION_CANCELLED)); + Assert.That(response.Logs, Contains.Item("Execution cancelled")); + Assert.That(response.Timings, Contains.Item("compile_ms=1")); } [Test] @@ -812,26 +657,15 @@ public async Task ExecuteAsync_WhenRuntimeFailsAfterProducingLogs_ShouldPreserve Logs = new List { "partial log" } }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "Debug.Log(\"partial log\"); throw new NullReferenceException();" + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "Debug.Log(\"partial log\"); throw new NullReferenceException();" - }, - CancellationToken.None); - - Assert.That(response.Success, Is.False); - Assert.That(response.Logs, Contains.Item("partial log")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.False); + Assert.That(response.Logs, Contains.Item("partial log")); } [Test] @@ -847,27 +681,16 @@ public async Task ExecuteAsync_WhenRuntimeReturnsKnownCompilePattern_ShouldRetur Logs = new List { "Top-level statements must precede namespace and type declarations." } }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "namespace Bad { class Wrapped {} }" + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "namespace Bad { class Wrapped {} }" - }, - CancellationToken.None); - - Assert.That(response.Success, Is.False); - Assert.That(response.ErrorMessage, Is.EqualTo("There is an issue with the code structure")); - Assert.That(response.Logs, Contains.Item("Solutions:")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.False); + Assert.That(response.ErrorMessage, Is.EqualTo("There is an issue with the code structure")); + Assert.That(response.Logs, Contains.Item("Solutions:")); } [Test] @@ -890,27 +713,16 @@ public async Task ExecuteAsync_WhenKnownCompilePatternExistsOnlyInCompilationErr } }); ExecuteDynamicCodeUseCase useCase = new(runtime); + ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( + new ExecuteDynamicCodeSchema + { + Code = "namespace Bad { class Wrapped {} }" + }, + CancellationToken.None); - DynamicCodeSecurityLevel previous = ULoopSettings.GetDynamicCodeSecurityLevel(); - ULoopSettings.SetDynamicCodeSecurityLevel(DynamicCodeSecurityLevel.Restricted); - - try - { - ExecuteDynamicCodeResponse response = await useCase.ExecuteAsync( - new ExecuteDynamicCodeSchema - { - Code = "namespace Bad { class Wrapped {} }" - }, - CancellationToken.None); - - Assert.That(response.Success, Is.False); - Assert.That(response.ErrorMessage, Is.EqualTo("There is an issue with the code structure")); - Assert.That(response.Logs, Contains.Item("Solutions:")); - } - finally - { - ULoopSettings.SetDynamicCodeSecurityLevel(previous); - } + Assert.That(response.Success, Is.False); + Assert.That(response.ErrorMessage, Is.EqualTo("There is an issue with the code structure")); + Assert.That(response.Logs, Contains.Item("Solutions:")); } /// @@ -938,7 +750,6 @@ public Task ExecuteAsync( ClassName = request.ClassName, Parameters = request.Parameters, CompileOnly = request.CompileOnly, - SecurityLevel = request.SecurityLevel, YieldToForegroundRequests = request.YieldToForegroundRequests }); return Task.FromResult(_results.Dequeue()); @@ -954,7 +765,6 @@ public Task ExecuteAsync( ClassName = request.ClassName, Parameters = request.Parameters, CompileOnly = request.CompileOnly, - SecurityLevel = request.SecurityLevel, YieldToForegroundRequests = request.YieldToForegroundRequests }); return Task.FromResult<(bool, ExecutionResult)>((true, _results.Dequeue())); diff --git a/Assets/Tests/Editor/OnionAssemblyDependencyTests.cs b/Assets/Tests/Editor/OnionAssemblyDependencyTests.cs index b9c0dff9b3..6851e8f3e5 100644 --- a/Assets/Tests/Editor/OnionAssemblyDependencyTests.cs +++ b/Assets/Tests/Editor/OnionAssemblyDependencyTests.cs @@ -42,8 +42,6 @@ public sealed class OnionAssemblyDependencyTests private const string SimulateMouseUiAssemblyName = "UnityCLILoop.FirstPartyTools.SimulateMouseUi.Editor"; private const string InfrastructureAssemblyName = "UnityCLILoop.Infrastructure"; private const string InternalApiBridgeAssemblyName = "Unity.InternalAPIEditorBridge.024"; - private const string MetadataValidationAssemblyName = - "UnityCLILoop.FirstPartyTools.ExecuteDynamicCode.MetadataValidation.Editor"; private const string PresentationAssemblyName = "UnityCLILoop.Presentation"; private const string ToolContractsAssemblyName = "UnityCLILoop.ToolContracts"; private const string RemovedSharedAssemblyGuidReference = "GUID:290394860909340b7835eb7cc215ee75"; @@ -208,31 +206,14 @@ public void ScriptChangesDuringPlayOptions_WhenLoaded_CompilesUnderDomainAssembl } [Test] - public void DynamicCodeSecurityValues_WhenLoaded_CompileUnderDomainAssembly() - { - // Tests that dynamic-code security levels stay with domain policy while scan results stay public. - string levelAssemblyName = typeof(DynamicCodeSecurityLevel).Assembly.GetName().Name; - string resultAssemblyName = typeof(SecurityValidationResult).Assembly.GetName().Name; - string violationAssemblyName = typeof(SecurityViolation).Assembly.GetName().Name; - - Assert.That(levelAssemblyName, Is.EqualTo(DomainAssemblyName)); - Assert.That(resultAssemblyName, Is.EqualTo(ToolContractsAssemblyName)); - Assert.That(violationAssemblyName, Is.EqualTo(ToolContractsAssemblyName)); - } - - [Test] - public void ULoopSettings_WhenLoaded_CompileUnderDomainAssembly() + public void ToolSettings_WhenLoaded_CompileUnderDomainAssembly() { // Tests that tool-specific settings concepts stay in the domain layer. - string settingsAssemblyName = typeof(ULoopSettings).Assembly.GetName().Name; - string settingsDataAssemblyName = typeof(ULoopSettingsData).Assembly.GetName().Name; string toolSettingsDataAssemblyName = typeof(ToolSettingsData).Assembly.GetName().Name; string editorSettingsDataAssemblyName = typeof(UnityCliLoopEditorSettingsData).Assembly.GetName().Name; string toolSettingsServiceAssemblyName = typeof(ToolSettingsService).Assembly.GetName().Name; string editorSettingsServiceAssemblyName = typeof(UnityCliLoopEditorSettingsService).Assembly.GetName().Name; - Assert.That(settingsAssemblyName, Is.EqualTo(DomainAssemblyName)); - Assert.That(settingsDataAssemblyName, Is.EqualTo(DomainAssemblyName)); Assert.That(toolSettingsDataAssemblyName, Is.EqualTo(DomainAssemblyName)); Assert.That(editorSettingsDataAssemblyName, Is.EqualTo(DomainAssemblyName)); Assert.That(toolSettingsServiceAssemblyName, Is.EqualTo(DomainAssemblyName)); @@ -269,24 +250,6 @@ public void SkillSetupPolicy_WhenLoaded_CompilesUnderDomainAssembly() Assert.That(stateAssemblyName, Is.EqualTo(DomainAssemblyName)); } - [Test] - public void DangerousApiCatalog_WhenLoaded_CompilesUnderDomainAssembly() - { - // Tests that public dynamic-code dangerous API policy stays in the tool contract assembly. - string catalogAssemblyName = typeof(DangerousApiCatalog).Assembly.GetName().Name; - - Assert.That(catalogAssemblyName, Is.EqualTo(ToolContractsAssemblyName)); - } - - [Test] - public void SourceSecurityScanner_WhenLoaded_CompilesUnderDomainAssembly() - { - // Tests that public source-level dynamic-code scanning stays in the tool contract assembly. - string scannerAssemblyName = typeof(SourceSecurityScanner).Assembly.GetName().Name; - - Assert.That(scannerAssemblyName, Is.EqualTo(ToolContractsAssemblyName)); - } - [Test] public void ToolContractsAsmdef_WhenLoaded_HasNoProjectAssemblyReferences() { @@ -516,29 +479,6 @@ public void InputSimulationUseCases_WhenLoaded_CompileUnderApplicationAssembly() Assert.That(mouseUiUseCaseAssemblyName, Does.StartWith(FirstPartyToolsAssemblyNamePrefix)); } - [Test] - public void PreloadMetadataValidationPorts_WhenLoaded_CompileUnderMetadataValidationAssembly() - { - // Tests that preload metadata validation contracts are owned by the metadata validation module. - string validatorAssemblyName = typeof(IPreloadAssemblySecurityValidator).Assembly.GetName().Name; - string overrideAssemblyName = typeof(IOverrideDefaultPreloadAssemblySecurityValidation).Assembly.GetName().Name; - string registryAssemblyName = typeof(PreloadAssemblySecurityValidatorRegistry).Assembly.GetName().Name; - - Assert.That(validatorAssemblyName, Is.EqualTo(MetadataValidationAssemblyName)); - Assert.That(overrideAssemblyName, Is.EqualTo(MetadataValidationAssemblyName)); - Assert.That(registryAssemblyName, Is.EqualTo(MetadataValidationAssemblyName)); - } - - [Test] - public void MetadataValidationAsmdef_WhenLoaded_DependsOnlyOnToolContracts() - { - // Tests that metadata validation depends on public contracts without reaching into implementation layers. - string[] references = ReadResolvedReferences( - "Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/MetadataValidation/UnityCLILoop.FirstPartyTools.ExecuteDynamicCode.MetadataValidation.Editor.asmdef"); - - Assert.That(references, Is.EquivalentTo(new[] { ToolContractsAssemblyName })); - } - [Test] public void SharedSupportTypes_WhenLoaded_CompileUnderOwningAssemblies() { @@ -731,7 +671,6 @@ public void ApplicationSources_WhenLoaded_DoNotReferenceConcreteDynamicCompilati "DynamicReferenceSetBuilder.", "ExternalCompilerMessageParser.", "ExternalCompilerPaths ", - "new IlSecurityValidator(", "SourceShaper.", "TopLevelReturnDetector.", "WrapperTemplate.", @@ -985,7 +924,6 @@ public void EditorUiFiles_WhenLoaded_DoNotReferenceFacadeInternalsDirectly() "NativeCliInstaller", "CliVersionComparer", "ToolSkillSynchronizer", - "ULoopSettings.", "ToolSettings.", "UnityCliLoopToolRegistrar", "UnityCliLoopToolRegistry", diff --git a/Assets/Tests/Editor/StaticFacadeStateGuardTests.cs b/Assets/Tests/Editor/StaticFacadeStateGuardTests.cs index 617def0f21..5c7ace4cbd 100644 --- a/Assets/Tests/Editor/StaticFacadeStateGuardTests.cs +++ b/Assets/Tests/Editor/StaticFacadeStateGuardTests.cs @@ -18,7 +18,6 @@ public sealed class StaticFacadeStateGuardTests { "Packages/src/Editor/Application/CliSetupApplicationService.cs", "Packages/src/Editor/Application/UseCases/SkillSetupUseCaseRegistry.cs", - "Packages/src/Editor/Domain/ULoopSettings.cs", "Packages/src/Editor/Application/UnityCliLoopToolRegistrar.cs", "Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCodeServices.cs", "Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Execution/DynamicCodeForegroundWarmupState.cs", @@ -239,7 +238,7 @@ public void ExecuteDynamicCodeUseCase_WhenAwaitingWorkflow_DoesNotCaptureEditorS string source = ReadSourceFile( "Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/ExecuteDynamicCodeUseCase.cs"); - Assert.That(source, Does.Contain("await WarmForegroundExecutionPathIfNeededAsync(parameters, editorLevel, cancellationToken)\n .ConfigureAwait(false);")); + Assert.That(source, Does.Contain("await WarmForegroundExecutionPathIfNeededAsync(parameters, cancellationToken)\n .ConfigureAwait(false);")); Assert.That(source, Does.Contain("await ExecuteRequestAsync(request, cancellationToken).ConfigureAwait(false);")); Assert.That(source, Does.Contain("await RetryMissingReturnIfNeeded(\n executionResult,")); Assert.That(source, Does.Contain("cancellationToken).ConfigureAwait(false);")); diff --git a/Assets/Tests/Editor/ToolSettingsSectionTests.cs b/Assets/Tests/Editor/ToolSettingsSectionTests.cs index bb86482dcb..e042962564 100644 --- a/Assets/Tests/Editor/ToolSettingsSectionTests.cs +++ b/Assets/Tests/Editor/ToolSettingsSectionTests.cs @@ -3,8 +3,6 @@ using UnityEngine.UIElements; using io.github.hatayama.UnityCliLoop.Presentation; -using io.github.hatayama.UnityCliLoop.ToolContracts; -using io.github.hatayama.UnityCliLoop.Domain; namespace io.github.hatayama.UnityCliLoop.Tests.Editor { @@ -126,47 +124,6 @@ public void Update_ClosedAfterLoad_ReleasesLoadedRows() Assert.AreEqual(DisplayStyle.None, listView.style.display.value); } - [Test] - public void Update_RestrictedLevel_MarksRestrictedButtonAsActive() - { - VisualElement root = CreateRootElement(); - ToolSettingsSection section = new(root); - ToolSettingsSectionData data = CreateData( - compileEnabled: true, - includeGetLogs: false, - dynamicCodeSecurityLevel: DynamicCodeSecurityLevel.Restricted); - - section.Update(data); - - Button restrictedButton = root.Q