From c69749f25746b979fa09568b39b66a4b1e531d8f Mon Sep 17 00:00:00 2001 From: hatayama Date: Tue, 7 Jul 2026 07:51:24 +0900 Subject: [PATCH] Fail fast for migration DTO null contracts Align migration DTO null handling with the existing Debug.Assert contracts so invalid internal calls fail fast instead of being silently normalized. Pin the contract behavior for rule data results and migration file path snapshots. --- ...ThirdPartyToolMigrationFileServiceTests.cs | 14 ++++++ .../ThirdPartyToolMigrationRulesTests.cs | 43 +++++++++++++++++++ .../Domain/ThirdPartyToolMigrationData.cs | 7 ++- .../Domain/ThirdPartyToolMigrationRuleData.cs | 9 ++-- 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/Assets/Tests/Editor/ThirdPartyToolMigrationFileServiceTests.cs b/Assets/Tests/Editor/ThirdPartyToolMigrationFileServiceTests.cs index 49fd5afb34..b04cecea34 100644 --- a/Assets/Tests/Editor/ThirdPartyToolMigrationFileServiceTests.cs +++ b/Assets/Tests/Editor/ThirdPartyToolMigrationFileServiceTests.cs @@ -37,6 +37,13 @@ public void ThirdPartyToolMigrationPreview_WhenInputFilePathsMutate_KeepsSnapsho Assert.That(preview.FilePaths, Is.EqualTo(new[] { "Assets/VendorTools/HelloTool.cs" })); } + [Test] + public void ThirdPartyToolMigrationPreview_WhenFilePathsIsNull_Throws() + { + // Verifies that preview snapshots fail fast when file paths are missing. + Assert.Throws(() => new ThirdPartyToolMigrationPreview(0, 0, null)); + } + [Test] public void ThirdPartyToolMigrationResult_WhenInputFilePathsMutate_KeepsSnapshot() { @@ -53,6 +60,13 @@ public void ThirdPartyToolMigrationResult_WhenInputFilePathsMutate_KeepsSnapshot Assert.That(result.FilePaths, Is.EqualTo(new[] { "Assets/VendorTools/HelloTool.cs" })); } + [Test] + public void ThirdPartyToolMigrationResult_WhenFilePathsIsNull_Throws() + { + // Verifies that result snapshots fail fast when file paths are missing. + Assert.Throws(() => new ThirdPartyToolMigrationResult(0, 0, null)); + } + [Test] public void ThirdPartyToolMigrationSourceFileCache_WhenFileIsReadTwice_UsesCachedSource() { diff --git a/Assets/Tests/Editor/ThirdPartyToolMigrationRulesTests.cs b/Assets/Tests/Editor/ThirdPartyToolMigrationRulesTests.cs index dece29f92d..b36d2226e6 100644 --- a/Assets/Tests/Editor/ThirdPartyToolMigrationRulesTests.cs +++ b/Assets/Tests/Editor/ThirdPartyToolMigrationRulesTests.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using NUnit.Framework; @@ -12,6 +13,48 @@ namespace io.github.hatayama.UnityCliLoop.Tests.Editor /// public sealed class ThirdPartyToolMigrationRulesTests { + [Test] + public void RemovedLegacyPlayerLoopTimingSignature_WhenOriginalParametersIsNull_Throws() + { + // Verifies that timing signatures fail fast when original parameter snapshots are missing. + Assert.Throws(() => new RemovedLegacyPlayerLoopTimingSignature( + "Run", + "SampleTool", + null, + Array.Empty())); + } + + [Test] + public void RemovedLegacyPlayerLoopTimingSignature_WhenRemovedParametersIsNull_Throws() + { + // Verifies that timing signatures fail fast when removed parameter snapshots are missing. + Assert.Throws(() => new RemovedLegacyPlayerLoopTimingSignature( + "Run", + "SampleTool", + Array.Empty(), + null)); + } + + [Test] + public void ThirdPartyToolMigrationContentResult_WhenContentIsNull_Throws() + { + // Verifies that migration content results fail fast when rewritten content is missing. + Assert.Throws(() => new ThirdPartyToolMigrationContentResult( + null, + 0, + Array.Empty())); + } + + [Test] + public void ThirdPartyToolMigrationContentResult_WhenRemovedSignaturesIsNull_Throws() + { + // Verifies that migration content results fail fast when removed timing signatures are missing. + Assert.Throws(() => new ThirdPartyToolMigrationContentResult( + string.Empty, + 0, + null)); + } + [Test] public void MigrateCSharpSource_WhenLegacyToolApiIsUsed_RewritesToV3Contracts() { diff --git a/Packages/src/Editor/Domain/ThirdPartyToolMigrationData.cs b/Packages/src/Editor/Domain/ThirdPartyToolMigrationData.cs index 6b0ec7f355..032ad6a2c4 100644 --- a/Packages/src/Editor/Domain/ThirdPartyToolMigrationData.cs +++ b/Packages/src/Editor/Domain/ThirdPartyToolMigrationData.cs @@ -96,7 +96,12 @@ internal static class ThirdPartyToolMigrationFilePathSnapshot { internal static string[] Copy(string[] filePaths) { - if (filePaths == null || filePaths.Length == 0) + if (filePaths == null) + { + throw new ArgumentNullException(nameof(filePaths)); + } + + if (filePaths.Length == 0) { return Array.Empty(); } diff --git a/Packages/src/Editor/Domain/ThirdPartyToolMigrationRuleData.cs b/Packages/src/Editor/Domain/ThirdPartyToolMigrationRuleData.cs index b0352877e6..7a409a6910 100644 --- a/Packages/src/Editor/Domain/ThirdPartyToolMigrationRuleData.cs +++ b/Packages/src/Editor/Domain/ThirdPartyToolMigrationRuleData.cs @@ -22,8 +22,9 @@ public RemovedLegacyPlayerLoopTimingSignature( MethodName = methodName; DeclaringTypeName = declaringTypeName; OriginalParameters = - originalParameters ?? Array.Empty(); - RemovedParameters = removedParameters ?? Array.Empty(); + originalParameters ?? throw new ArgumentNullException(nameof(originalParameters)); + RemovedParameters = + removedParameters ?? throw new ArgumentNullException(nameof(removedParameters)); } public string MethodName { get; } @@ -93,11 +94,11 @@ public ThirdPartyToolMigrationContentResult( removedPlayerLoopTimingSignatures != null, "removedPlayerLoopTimingSignatures must not be null"); - Content = content ?? string.Empty; + Content = content ?? throw new ArgumentNullException(nameof(content)); ReplacementCount = replacementCount; RemovedPlayerLoopTimingSignatures = removedPlayerLoopTimingSignatures ?? - Array.Empty(); + throw new ArgumentNullException(nameof(removedPlayerLoopTimingSignatures)); } public string Content { get; }