diff --git a/CHANGELOG.md b/CHANGELOG.md index ca91153c..3f520958 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), #### Changed +- **Spinner themes are hidden Easter eggs** — The existing themed and random spinner flags remain parseable for backward compatibility, but normal `--help` output and current user-facing documentation no longer advertise them. Regression tests protect both hidden help output and documentation consistency. Affected: `Runner/ProgramRunner.HelpText.cs`, `USER_GUIDE.md`, `doc/config.sample.jsonc`, `doc/DEVELOPER_GUIDE.md`, `doc/TESTING_GUIDE.md`, `FolderDiffIL4DotNet.Tests/ProgramRunnerTests.HelpVersion.cs`, `FolderDiffIL4DotNet.Tests/Architecture/CiAutomationConfigurationTests.cs`. + - **CLI parsing now returns one structured result and rejects surplus positional arguments** — `CliParser` now separates `oldFolder`, `newFolder`, and optional `reportLabel` while consuming options in one pass. Existing two- and three-positional forms, option placement, automatic labels, and `--creator` behavior are preserved; a fourth positional argument now prints usage and exits with code `2`. `CliOptions` uses named properties with defaults instead of a 35-field positional constructor. Affected: `Runner/CliParser.cs`, `Runner/CliOptions.cs`, `ProgramRunner.cs`, `Runner/ProgramRunner.Wizard.cs`, `Runner/RunPreflightValidator.cs`, `USER_GUIDE.md`. Tests: `CliOptionsTests`, `ProgramRunnerTests`, `CliOverrideApplierTests`, `SpinnerThemesTests`. #### Fixed @@ -1692,6 +1694,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), #### 変更 +- **スピナーテーマを非表示のイースターエッグとして整理** — 既存のテーマ指定およびランダム選択フラグは後方互換のため引き続き解析できますが、通常の `--help` 出力と現行のユーザー向け文書では案内しないようにしました。ヘルプでの非表示と文書整合性を回帰テストで保護します。対象: `Runner/ProgramRunner.HelpText.cs`, `USER_GUIDE.md`, `doc/config.sample.jsonc`, `doc/DEVELOPER_GUIDE.md`, `doc/TESTING_GUIDE.md`, `FolderDiffIL4DotNet.Tests/ProgramRunnerTests.HelpVersion.cs`, `FolderDiffIL4DotNet.Tests/Architecture/CiAutomationConfigurationTests.cs`。 + - **CLI 解析を単一の構造化結果へ集約し、余分な位置引数を拒否** — `CliParser` はオプションを 1 回の走査で消費しながら、`oldFolder`、`newFolder`、任意の `reportLabel` を分離するようになりました。既存の 2/3 位置引数形式、オプション位置、自動ラベル、`--creator` の動作は維持し、4 個目の位置引数は使い方を表示して終了コード `2` で拒否します。`CliOptions` は 35 フィールドの位置指定コンストラクタではなく、既定値付きの名前付きプロパティを使用します。対象: `Runner/CliParser.cs`, `Runner/CliOptions.cs`, `ProgramRunner.cs`, `Runner/ProgramRunner.Wizard.cs`, `Runner/RunPreflightValidator.cs`, `USER_GUIDE.md`。テスト: `CliOptionsTests`, `ProgramRunnerTests`, `CliOverrideApplierTests`, `SpinnerThemesTests`。 #### 修正 diff --git a/FolderDiffIL4DotNet.Tests/Architecture/CiAutomationConfigurationTests.cs b/FolderDiffIL4DotNet.Tests/Architecture/CiAutomationConfigurationTests.cs index dffbe30c..96c7bd55 100644 --- a/FolderDiffIL4DotNet.Tests/Architecture/CiAutomationConfigurationTests.cs +++ b/FolderDiffIL4DotNet.Tests/Architecture/CiAutomationConfigurationTests.cs @@ -49,6 +49,56 @@ public void DotNetWorkflow_DoesNotSkipDocumentationOnlyChanges() Assert.DoesNotContain("'**.md'", workflow, StringComparison.Ordinal); } + /// + /// Verifies that hidden spinner Easter eggs are not advertised by current user-facing documentation. + /// 非表示のスピナーイースターエッグが現行のユーザー向け文書で案内されていないことを検証します。 + /// + [Fact] + [Trait("Category", "Unit")] + public void UserFacingDocumentation_DoesNotAdvertiseHiddenSpinnerOptions() + { + string[] hiddenOptions = + { + "--coffee", + "--beer", + "--matcha", + "--whisky", + "--wine", + "--ramen", + "--sushi", + "--random-spinner", + }; + string[] topLevelDocuments = + { + GetRepositoryFilePath("README.md"), + GetRepositoryFilePath("USER_GUIDE.md"), + GetRepositoryFilePath("PACKAGE_README.md"), + GetRepositoryFilePath("CONTRIBUTING.md"), + GetRepositoryFilePath("SUPPORT.md"), + GetRepositoryFilePath("SECURITY.md"), + GetRepositoryFilePath("index.md"), + GetRepositoryFilePath("api", "index.md"), + GetRepositoryFilePath("FolderDiffIL4DotNet.Core", "PACKAGE_README.md"), + GetRepositoryFilePath("FolderDiffIL4DotNet.Plugin.Abstractions", "PACKAGE_README.md"), + GetRepositoryFilePath("docfx.json"), + GetRepositoryFilePath("toc.yml"), + }; + + foreach (var documentPath in topLevelDocuments) + { + AssertDocumentDoesNotAdvertiseHiddenOptions(documentPath, hiddenOptions); + } + + foreach (var documentPath in Directory.GetFiles(GetRepositoryFilePath("doc"), "*", SearchOption.AllDirectories)) + { + string extension = Path.GetExtension(documentPath); + if (extension is ".md" or ".html" or ".json" or ".jsonc" or ".yml" or ".yaml" or ".xml" or ".txt") + { + AssertDocumentDoesNotAdvertiseHiddenOptions(documentPath, hiddenOptions); + } + } + } + /// /// Verifies that developers and CI share an exact SDK, formatting rules, and a blocking format gate. /// 開発環境と CI が同一の SDK・フォーマット規則・ブロッキング形式検証を共有することを検証します。 @@ -601,6 +651,20 @@ private static string GetRepositoryFilePath(params string[] segments) return path; } + private static void AssertDocumentDoesNotAdvertiseHiddenOptions( + string documentPath, + string[] hiddenOptions) + { + var contents = File.ReadAllText(documentPath); + var relativePath = Path.GetRelativePath(RepositoryRootPath, documentPath); + foreach (var hiddenOption in hiddenOptions) + { + Assert.False( + contents.Contains(hiddenOption, StringComparison.Ordinal), + $"{relativePath} advertises hidden spinner option {hiddenOption}."); + } + } + private static bool CanRunCommand(string fileName, params string[] arguments) { try diff --git a/FolderDiffIL4DotNet.Tests/ProgramRunnerTests.HelpVersion.cs b/FolderDiffIL4DotNet.Tests/ProgramRunnerTests.HelpVersion.cs index a047b688..d7ed1920 100644 --- a/FolderDiffIL4DotNet.Tests/ProgramRunnerTests.HelpVersion.cs +++ b/FolderDiffIL4DotNet.Tests/ProgramRunnerTests.HelpVersion.cs @@ -61,6 +61,48 @@ public async Task RunAsync_HelpFlag_ExitsZeroWithoutInitializingLogger() } } + [Fact] + public async Task RunAsync_HelpFlag_HidesSpinnerEasterEggOptions() + { + var logger = new TestLogger(logFileAbsolutePath: "test.log"); + var runner = new ProgramRunner(logger, new ConfigService()); + var origOut = Console.Out; + using var sw = new System.IO.StringWriter(); + Console.SetOut(sw); + + try + { + var exitCode = await runner.RunAsync(new[] { "--help" }); + + Assert.Equal(0, exitCode); + var output = sw.ToString(); + string[] hiddenOptions = + { + "--coffee", + "--beer", + "--matcha", + "--whisky", + "--wine", + "--ramen", + "--sushi", + "--random-spinner", + }; + + foreach (var hiddenOption in hiddenOptions) + { + Assert.DoesNotContain(hiddenOption, output, StringComparison.Ordinal); + } + + Assert.Contains("--bell", output, StringComparison.Ordinal); + Assert.Contains("--creator", output, StringComparison.Ordinal); + Assert.Contains("--open-reports", output, StringComparison.Ordinal); + } + finally + { + Console.SetOut(origOut); + } + } + [Fact] public async Task RunAsync_HelpFlag_OutputContainsDryRunOption() { diff --git a/Runner/ProgramRunner.HelpText.cs b/Runner/ProgramRunner.HelpText.cs index 4af767e2..c1141741 100644 --- a/Runner/ProgramRunner.HelpText.cs +++ b/Runner/ProgramRunner.HelpText.cs @@ -39,14 +39,6 @@ public sealed partial class ProgramRunner " --dry-run Enumerate files and show statistics without running comparison.\n" + " --fail-on-diff Exit with code 5 when final reportable differences remain.\n" + " Reports and other artifacts are still generated before exit.\n" + - " --coffee Use coffee-themed spinner animation during execution.\n" + - " --beer Use beer-themed spinner animation during execution.\n" + - " --matcha Use matcha tea ceremony spinner animation during execution.\n" + - " --whisky Use whisky distilling spinner animation during execution.\n" + - " --wine Use wine making spinner animation during execution.\n" + - " --ramen Use ramen steaming spinner animation during execution.\n" + - " --sushi Use conveyor-belt sushi spinner animation during execution.\n" + - " --random-spinner Randomly select a spinner theme for each run.\n" + " --credits Show credits and acknowledgements.\n" + " --bell Ring terminal bell when execution completes.\n" + " --output Output directory for reports (default: user-local app-data Reports/).\n" + diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 4a260dd1..bed03e72 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -207,14 +207,6 @@ Normal diff runs accept exactly two or three positional arguments. A fourth posi | `--wizard` | Interactive mode: prompts for old folder, new folder, and an optional report label. Before the report-label prompt, it prints the existing report folder names under the active Reports root so you can avoid collisions or reuse part of an existing label. Press Enter on the report-label prompt to auto-generate a high-resolution timestamp label. Drag-and-drop friendly — auto-strips surrounding quotes, `file://` URI prefixes, backslash-escaped spaces, and percent-encoded characters. | | `--dry-run` | Enumerate files and show statistics without running comparison. | | `--fail-on-diff` | Opt in to CI gating: after all reports, audit logs, and other enabled artifacts are generated, return exit code `5` when final reportable Added/Removed/Modified entries remain. Differences removed by `IgnoredExtensions`, IL-noise suppression, or other comparison filters do not trigger code `5`. Without this flag, a completed comparison still returns `0` even when it reports differences. | -| `--coffee` | Use coffee-themed spinner animation during execution (easter egg). | -| `--beer` | Use beer-themed spinner animation during execution (easter egg). | -| `--matcha` | Use matcha tea ceremony spinner animation during execution (easter egg). | -| `--whisky` | Use whisky distilling spinner animation during execution (easter egg). | -| `--wine` | Use wine making spinner animation during execution (easter egg). | -| `--ramen` | Use ramen steaming spinner animation during execution (easter egg). | -| `--sushi` | Use conveyor-belt sushi spinner animation during execution (easter egg). | -| `--random-spinner` | Randomly select a spinner theme for each run. | | `--bell` | Ring terminal bell (`BEL` / `\a`) when execution completes. | | `--output ` | Output directory for reports (default: `/Reports/`). The report label subfolder is created under this directory. Useful for CI/CD pipelines that need reports written to a custom path. | | `--log-format ` | Log file output format (default: `text`). `json` emits NDJSON (one JSON object per line) with W3C Trace Context fields (`traceId`, `spanId`) for SIEM, OpenTelemetry, and log aggregation tool integration. Console output remains plain text regardless. | @@ -222,7 +214,7 @@ Normal diff runs accept exactly two or three positional arguments. A fourth posi | `--open-config` | Open the configuration folder in the default file manager and exit. When `--config` is also specified, opens the parent directory of the specified config file. Missing directories are created automatically; launcher/path failures exit with code `4` and include the resolved target path plus exception type on stderr. | | `--open-logs` | Open the Logs folder (`/Logs/`) in the default file manager and exit. Missing directories are created automatically; launcher/path failures exit with code `4` and include the resolved target path plus exception type on stderr. | -> **Note:** The spinner options (`--coffee`, `--beer`, `--matcha`, `--whisky`, `--wine`, `--ramen`, `--sushi`) all override [`SpinnerFrames`](#config-en-spinnerframes). If multiple are specified, the tool gently suggests matcha instead (easter egg). Use `--random-spinner` for a surprise theme each run. They also override any custom `SpinnerFrames` set in [`config.json`](config.json). The inline progress bar also shows a fixed-width ETA segment such as `ETA 14:32 (+00 h 12 m)`. +> **Note:** The inline progress bar shows a fixed-width ETA segment such as `ETA 14:32 (+00 h 12 m)`. ```bash dotnet build @@ -760,7 +752,7 @@ Override only the settings you want to change. For example: SpinnerFrames ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] - Array of strings used for the console spinner animation (default: Braille pattern characters). Each element is one frame in the rotation, so multi-character strings (e.g. block characters, emoji) are supported. Must contain at least one element. Setting null restores the default. The CLI options --coffee, --beer, --matcha, --whisky, --wine, --ramen, and --sushi override this value. + Array of strings used for the console spinner animation (default: Braille pattern characters). Each element is one frame in the rotation, so multi-character strings (e.g. block characters, emoji) are supported. Must contain at least one element. Setting null restores the default. ShouldGenerateHtmlReport @@ -1082,14 +1074,6 @@ nildiff [reportLabel] [options] | `--wizard` | 対話モード: 旧フォルダ、新フォルダ、任意のレポートラベルを対話入力で指定します。レポートラベル入力前に、現在の Reports ルート配下にある既存レポートフォルダ名を一覧表示するため、重複回避や既存ラベルの一部再利用がしやすくなります。レポートラベル入力は Enter だけで空欄確定でき、その場合は高粒度のタイムスタンプラベルを自動生成します。ドラッグ&ドロップ対応 — 囲みクォート、`file://` URI プレフィックス、バックスラッシュエスケープされたスペース、パーセントエンコード文字を自動除去します。 | | `--dry-run` | 比較を実行せずファイルを列挙し統計情報を表示します。 | | `--fail-on-diff` | CI ゲートを opt-in します。レポート、監査ログ、その他の有効な成果物をすべて生成した後、最終的な Added/Removed/Modified が残る場合に終了コード `5` を返します。`IgnoredExtensions`、IL ノイズ抑制、その他の比較フィルタで除外された差分はコード `5` の対象外です。このフラグがなければ、差分をレポートした正常な比較も従来どおり `0` を返します。 | -| `--coffee` | 実行中にコーヒーテーマのスピナーアニメーションを使用します(イースターエッグ)。 | -| `--beer` | 実行中にビールテーマのスピナーアニメーションを使用します(イースターエッグ)。 | -| `--matcha` | 実行中に抹茶点前テーマのスピナーアニメーションを使用します(イースターエッグ)。 | -| `--whisky` | 実行中にウイスキー蒸留テーマのスピナーアニメーションを使用します(イースターエッグ)。 | -| `--wine` | 実行中にワイン醸造テーマのスピナーアニメーションを使用します(イースターエッグ)。 | -| `--ramen` | 実行中にラーメン湯気テーマのスピナーアニメーションを使用します(イースターエッグ)。 | -| `--sushi` | 実行中に回転寿司テーマのスピナーアニメーションを使用します(イースターエッグ)。 | -| `--random-spinner` | 実行ごとにスピナーテーマをランダムに選択します。 | | `--bell` | 実行完了時にターミナルベル(`BEL` / `\a`)を鳴らします。 | | `--output ` | レポートの出力ディレクトリ(既定: `/Reports/`)。このディレクトリの下にレポートラベルのサブフォルダが作成されます。CI/CD パイプラインでレポートを任意のパスに出力したい場合に便利です。 | | `--log-format ` | ログファイルの出力形式(既定: `text`)。`json` を指定すると W3C Trace Context フィールド(`traceId`、`spanId`)付きの NDJSON(1行1 JSON オブジェクト)で出力し、SIEM、OpenTelemetry、ログ集約ツールとの連携が容易になります。コンソール出力は形式に関わらずプレーンテキストのままです。 | @@ -1097,7 +1081,7 @@ nildiff [reportLabel] [options] | `--open-config` | 設定ファイルのフォルダをデフォルトのファイルマネージャで開いて終了します。`--config` が同時に指定された場合、指定された設定ファイルの親ディレクトリを開きます。存在しないディレクトリは自動作成されます。パス解決・ディレクトリ作成・ランチャー起動に失敗した場合はコード `4` で終了し、stderr に解決済みターゲットパスと例外種別を出力します。 | | `--open-logs` | Logs フォルダ(`/Logs/`)をデフォルトのファイルマネージャで開いて終了します。存在しないディレクトリは自動作成されます。パス解決・ディレクトリ作成・ランチャー起動に失敗した場合はコード `4` で終了し、stderr に解決済みターゲットパスと例外種別を出力します。 | -> **補足:** スピナーオプション(`--coffee`、`--beer`、`--matcha`、`--whisky`、`--wine`、`--ramen`、`--sushi`)はいずれも [`SpinnerFrames`](#config-ja-spinnerframes) を上書きします。複数同時に指定した場合は抹茶が提案されます(イースターエッグ)。`--random-spinner` で毎回サプライズテーマを楽しめます。[`config.json`](config.json) で設定したカスタム `SpinnerFrames` も上書きされます。インライン進捗バーの右端には `ETA 14:32 (+00 h 12 m)` のような固定長 ETA も表示されます。 +> **補足:** インライン進捗バーの右端には `ETA 14:32 (+00 h 12 m)` のような固定長 ETA が表示されます。 ```bash dotnet build @@ -1635,7 +1619,7 @@ JSON Schema ファイル([`doc/config.schema.json`](doc/config.schema.json)) SpinnerFrames ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] - コンソールスピナーアニメーションに使用する文字列の配列(既定: ブライユパターン文字)。各要素が 1 フレームになるため、複数文字のフレーム(ブロック文字・絵文字など)も指定できます。1 件以上必須です。null を指定すると既定値に戻ります。CLI オプション --coffee--beer--matcha--whisky--wine--ramen--sushi を指定するとこの値は上書きされます。 + コンソールスピナーアニメーションに使用する文字列の配列(既定: ブライユパターン文字)。各要素が 1 フレームになるため、複数文字のフレーム(ブロック文字・絵文字など)も指定できます。1 件以上必須です。null を指定すると既定値に戻ります。 ShouldGenerateHtmlReport diff --git a/doc/DEVELOPER_GUIDE.md b/doc/DEVELOPER_GUIDE.md index c312cac0..b666e0c1 100644 --- a/doc/DEVELOPER_GUIDE.md +++ b/doc/DEVELOPER_GUIDE.md @@ -441,7 +441,7 @@ Why this matters: | [`Program.cs`](../Program.cs) | Application entry point | Must remain thin | | [`ProgramRunner.cs`](../ProgramRunner.cs) | CLI dispatch, argument validation, config loading, exit-code mapping | Help text in [`ProgramRunner.HelpText.cs`](../Runner/ProgramRunner.HelpText.cs), config loading/validation in [`ProgramRunner.Config.cs`](../Runner/ProgramRunner.Config.cs), interactive wizard with drag-and-drop path normalization (`NormalizeDragDropPath`) in [`ProgramRunner.Wizard.cs`](../Runner/ProgramRunner.Wizard.cs), folder-open commands in [`ProgramRunner.OpenFolder.cs`](../Runner/ProgramRunner.OpenFolder.cs) | | [`Runner/CliOverrideApplier.cs`](../Runner/CliOverrideApplier.cs) | CLI option → config builder override application | Delegates spinner theme logic to `SpinnerThemes` | -| [`Runner/SpinnerThemes.cs`](../Runner/SpinnerThemes.cs) | Spinner animation theme definitions and application | 7 themes (coffee, beer, matcha, whisky, wine, ramen, sushi) + random selection | +| [`Runner/SpinnerThemes.cs`](../Runner/SpinnerThemes.cs) | Spinner animation theme definitions and application | Hidden Easter-egg compatibility behavior | | [`Runner/DiffPipelineExecutor.cs`](../Runner/DiffPipelineExecutor.cs) | Diff execution pipeline and report generation | Builds scoped DI container, runs diff, resolves the opt-in review-checklist snapshot once per run, then generates Markdown/HTML/audit-log reports | | [`Runner/DryRunExecutor.cs`](../Runner/DryRunExecutor.cs) | `--dry-run` pre-execution preview | Enumerates files, counts union/assembly candidates, shows extension breakdown without running comparison | | [`FolderDiffIL4DotNet.Core/`](../FolderDiffIL4DotNet.Core/) | Reusable console/diagnostics/IO/text helpers | No folder-diff domain logic | @@ -1417,7 +1417,7 @@ sequenceDiagram | [`Program.cs`](../Program.cs) | アプリ起動点 | 薄いまま維持する | | [`ProgramRunner.cs`](../ProgramRunner.cs) | CLI 分岐、引数検証、設定読込、終了コード写像 | ヘルプテキストは [`ProgramRunner.HelpText.cs`](../Runner/ProgramRunner.HelpText.cs)、設定読込/バリデーションは [`ProgramRunner.Config.cs`](../Runner/ProgramRunner.Config.cs)、ドラッグ&ドロップパス正規化(`NormalizeDragDropPath`)付き対話ウィザードは [`ProgramRunner.Wizard.cs`](../Runner/ProgramRunner.Wizard.cs)、フォルダ開放コマンドは [`ProgramRunner.OpenFolder.cs`](../Runner/ProgramRunner.OpenFolder.cs) | | [`Runner/CliOverrideApplier.cs`](../Runner/CliOverrideApplier.cs) | CLI オプション → 設定ビルダーへのオーバーライド適用 | スピナーテーマロジックを `SpinnerThemes` に委譲 | -| [`Runner/SpinnerThemes.cs`](../Runner/SpinnerThemes.cs) | スピナーアニメーションテーマの定義と適用 | 7テーマ(coffee, beer, matcha, whisky, wine, ramen, sushi)+ ランダム選択 | +| [`Runner/SpinnerThemes.cs`](../Runner/SpinnerThemes.cs) | スピナーアニメーションテーマの定義と適用 | 非表示のイースターエッグ互換動作 | | [`Runner/DiffPipelineExecutor.cs`](../Runner/DiffPipelineExecutor.cs) | 差分実行パイプラインとレポート生成 | スコープ付き DI コンテナ構築・差分実行・opt-in の review checklist snapshot の run ごと 1 回解決・Markdown/HTML/監査ログの全レポート生成 | | [`Runner/DryRunExecutor.cs`](../Runner/DryRunExecutor.cs) | `--dry-run` 事前プレビュー | ファイル列挙・ユニオン数/アセンブリ候補数算出・拡張子内訳表示を比較実行なしで行う | | [`FolderDiffIL4DotNet.Core/`](../FolderDiffIL4DotNet.Core/) | 再利用可能な console / diagnostics / I/O / text helper | フォルダ差分ドメインのポリシーを持たない | diff --git a/doc/TESTING_GUIDE.md b/doc/TESTING_GUIDE.md index 0353b15c..86a2d9d6 100644 --- a/doc/TESTING_GUIDE.md +++ b/doc/TESTING_GUIDE.md @@ -31,7 +31,7 @@ Use the commands in [Run Tests Locally](#testing-en-run-tests) to inspect the cu | Area | Main test classes | What is validated | | --- | --- | --- | -| Entry and configuration | [`ProgramTests`](../FolderDiffIL4DotNet.Tests/ProgramTests.cs), [`ProgramRunnerTests`](../FolderDiffIL4DotNet.Tests/ProgramRunnerTests.cs), [`CliOptionsTests`](../FolderDiffIL4DotNet.Tests/CliOptionsTests.cs), [`ConfigServiceTests`](../FolderDiffIL4DotNet.Tests/Services/ConfigServiceTests.cs), [`ConfigSettingsTests`](../FolderDiffIL4DotNet.Tests/Models/ConfigSettingsTests.cs) | `Main` exit codes, typed [`ProgramRunner`](../ProgramRunner.cs) exit-code mapping for invalid arguments vs. config failures, phase ordering around validation vs. config loading, minimal end-to-end execution, CLI argument parsing via [`CliParser`](../Runner/CliParser.cs) (null/empty/positional-only args, every flag including `--help`/`--version`/`--config`/`--threads`/`--no-il-cache`/`--clear-cache`/`--skip-il`/`--no-timestamp-warnings`/`--print-config`/`--coffee`/`--beer`/`--matcha`/`--whisky`/`--wine`/`--ramen`/`--sushi`/`--bell`/`--random-spinner`/`--log-format`/`--output`/`--open-reports`/`--open-config`/`--open-logs`, unknown flag detection, combined flags, `--config`/`--threads` missing-value errors, spinner last-wins behavior, multiple-spinner detection (`MultipleSpinnersDetected`)), code-defined config defaults (verified via `ConfigSettings.Default*` named constants) and override behavior, SHA256/timestamp warning console and report output, reflection-backed verification of internal IL cache defaults wired by [`ProgramRunner`](../ProgramRunner.cs), completion summary chart output (bar rendering for each file category, zero-total skip, label alignment); JSON syntax error reporting: trailing comma in object (`{"Key":"v",}`), trailing comma in array (`["a","b",]`), and multiline JSON with line-number verification in the [`InvalidDataException`](https://learn.microsoft.com/en-us/dotnet/api/system.io.invaliddataexception?view=net-8.0) message, `line N, position N` pattern verification, trailing-comma hint appended to all JSON parse errors, custom config path `FileNotFoundException` with path in message; preflight write-permission check with fail-fast on [`IOException`](https://learn.microsoft.com/en-us/dotnet/api/system.io.ioexception?view=net-8.0) (no silent swallowing) and cause-specific logging via `ILoggerService`; `--help` text "Tip:" section promoting `--print-config`; stderr `--print-config` hint on configuration error (exit code `3`), `--wizard` interactive mode redirected-stdin rejection (exit code `2` with error message), `--clear-cache` interactive wizard redirected-stdin rejection (exit code `2` with error message), `--clear-cache` option in `--help` output, `--open-reports`/`--open-config`/`--open-logs` early-exit with folder path output, `--output`/`--config` override integration, default-target order (`Reports` → application data root/config directory → `Logs`) when multiple open flags are combined, short-circuit on first/second-launch failure, and launcher-failure error reporting with the resolved target path, `CheckDiskSpaceOrThrow` empty-path skip, `CheckReportsParentWritableOrThrow` empty-parent skip and probe-file cleanup verification, `--help` output contains open-folder options, IL cache helper methods (`FilterCacheFilesByTool` tool-name matching with short-filename skip, `FilterCacheFilesByToolLabel` exact version matching via sanitize round-trip, `ExtractDistinctToolLabels` distinct sorted label extraction from cache filenames with deduplication and short-filename skip, `UnsanitizeToolLabel` version-pattern reversal and no-version fallback, `SanitizeForCacheMatch` colon/parenthesis replacement, sanitize→unsanitize round-trip identity), custom output directory via `--output` (path override, missing value error, default null), `GetReportsFolderAbsolutePath` with custom/null/empty output directory; `NormalizeDragDropPath` drag-and-drop path normalization (double/single quotes, `file://`/`file:///` URI prefixes, backslash-escaped spaces, percent-encoded characters including Japanese, combined formats, empty input, malformed percent-encoding), unresolved `LocalApplicationData` classification for normal runs and `--open-reports`, help-text wording for the active reports root, and resolved-path stderr diagnostics for invalid user-local vs. bundled fallback config JSON | +| Entry and configuration | [`ProgramTests`](../FolderDiffIL4DotNet.Tests/ProgramTests.cs), [`ProgramRunnerTests`](../FolderDiffIL4DotNet.Tests/ProgramRunnerTests.cs), [`CliOptionsTests`](../FolderDiffIL4DotNet.Tests/CliOptionsTests.cs), [`ConfigServiceTests`](../FolderDiffIL4DotNet.Tests/Services/ConfigServiceTests.cs), [`ConfigSettingsTests`](../FolderDiffIL4DotNet.Tests/Models/ConfigSettingsTests.cs) | `Main` exit codes, typed [`ProgramRunner`](../ProgramRunner.cs) exit-code mapping for invalid arguments vs. config failures, phase ordering around validation vs. config loading, minimal end-to-end execution, CLI argument parsing via [`CliParser`](../Runner/CliParser.cs) (null/empty/positional-only args, every documented flag plus hidden spinner Easter-egg compatibility flags, unknown flag detection, combined flags, `--config`/`--threads` missing-value errors, spinner last-wins behavior, multiple-spinner detection (`MultipleSpinnersDetected`)), code-defined config defaults (verified via `ConfigSettings.Default*` named constants) and override behavior, SHA256/timestamp warning console and report output, reflection-backed verification of internal IL cache defaults wired by [`ProgramRunner`](../ProgramRunner.cs), completion summary chart output (bar rendering for each file category, zero-total skip, label alignment); JSON syntax error reporting: trailing comma in object (`{"Key":"v",}`), trailing comma in array (`["a","b",]`), and multiline JSON with line-number verification in the [`InvalidDataException`](https://learn.microsoft.com/en-us/dotnet/api/system.io.invaliddataexception?view=net-8.0) message, `line N, position N` pattern verification, trailing-comma hint appended to all JSON parse errors, custom config path `FileNotFoundException` with path in message; preflight write-permission check with fail-fast on [`IOException`](https://learn.microsoft.com/en-us/dotnet/api/system.io.ioexception?view=net-8.0) (no silent swallowing) and cause-specific logging via `ILoggerService`; `--help` text "Tip:" section promoting `--print-config`; hidden spinner Easter-egg flags remain parseable but are absent from `--help` output and current user-facing documentation; stderr `--print-config` hint on configuration error (exit code `3`), `--wizard` interactive mode redirected-stdin rejection (exit code `2` with error message), `--clear-cache` interactive wizard redirected-stdin rejection (exit code `2` with error message), `--clear-cache` option in `--help` output, `--open-reports`/`--open-config`/`--open-logs` early-exit with folder path output, `--output`/`--config` override integration, default-target order (`Reports` → application data root/config directory → `Logs`) when multiple open flags are combined, short-circuit on first/second-launch failure, and launcher-failure error reporting with the resolved target path, `CheckDiskSpaceOrThrow` empty-path skip, `CheckReportsParentWritableOrThrow` empty-parent skip and probe-file cleanup verification, `--help` output contains open-folder options, IL cache helper methods (`FilterCacheFilesByTool` tool-name matching with short-filename skip, `FilterCacheFilesByToolLabel` exact version matching via sanitize round-trip, `ExtractDistinctToolLabels` distinct sorted label extraction from cache filenames with deduplication and short-filename skip, `UnsanitizeToolLabel` version-pattern reversal and no-version fallback, `SanitizeForCacheMatch` colon/parenthesis replacement, sanitize→unsanitize round-trip identity), custom output directory via `--output` (path override, missing value error, default null), `GetReportsFolderAbsolutePath` with custom/null/empty output directory; `NormalizeDragDropPath` drag-and-drop path normalization (double/single quotes, `file://`/`file:///` URI prefixes, backslash-escaped spaces, percent-encoded characters including Japanese, combined formats, empty input, malformed percent-encoding), unresolved `LocalApplicationData` classification for normal runs and `--open-reports`, help-text wording for the active reports root, and resolved-path stderr diagnostics for invalid user-local vs. bundled fallback config JSON | | Core diff flow | [`FolderDiffExecutionStrategyTests`](../FolderDiffIL4DotNet.Tests/Services/FolderDiffExecutionStrategyTests.cs), [`FolderDiffServiceTests`](../FolderDiffIL4DotNet.Tests/Services/FolderDiffServiceTests.cs), [`FolderDiffServiceUnitTests`](../FolderDiffIL4DotNet.Tests/Services/FolderDiffServiceUnitTests.cs), [`FileDiffServiceTests`](../FolderDiffIL4DotNet.Tests/Services/FileDiffServiceTests.cs), [`FileDiffServiceUnitTests`](../FolderDiffIL4DotNet.Tests/Services/FileDiffServiceUnitTests.cs), [`FileDiffResultListsTests`](../FolderDiffIL4DotNet.Tests/Models/FileDiffResultListsTests.cs), [`DiffExecutionContextTests`](../FolderDiffIL4DotNet.Tests/Services/DiffExecutionContextTests.cs) | Discovery filtering, auto-parallelism policy (I/O-bound `ProcessorCount × 2` for local paths, network-capped for network shares), classification (`Unchanged/Added/Removed/Modified`), diff detail labels, timestamp-regression detection only for **modified** files (unchanged files with reversed timestamps produce no warning), reset behavior, case-insensitive extension handling, propagated text-diff fallback behavior, permission/I/O failure handling, expected-vs-unexpected exception logging/rethrow behavior including stage-aware `FileDiffService` diagnostics (`RelativePath`, `Stage`, `SkipIL`, `MaxParallel`), large-batch classification without real disk I/O, IL-precompute batching for large trees, memory-budget-based throttling of large-text chunk comparison, multi-megabyte real-file text comparison, symlink-backed file classification, per-file hash/IL/text error handling without real disk, symlink-loop [`IOException`](https://learn.microsoft.com/en-us/dotnet/api/system.io.ioexception?view=net-8.0) during enumeration (logged and rethrown), [`FileNotFoundException`](https://learn.microsoft.com/en-us/dotnet/api/system.io.filenotfoundexception?view=net-8.0) during per-file comparison classified as `Removed` with a warning (both sequential and parallel modes), `DiffSummaryStatistics`/`SummaryStatistics` snapshot correctness, completion message routed through `ILoggerService` instead of direct `Console.WriteLine`, `CancellationToken` propagation through diff pipeline (pre-cancelled token throws `OperationCanceledException`), best-effort semantic analysis CA1031 fallback (warning logged but diff result unaffected when `AssemblyMethodAnalyzer.Analyze` fails on non-existent paths), `FolderDiffExecutionStrategy.CountDotNetAssemblyCandidates` empty-input behavior, duplicate-path suppression, managed-assembly-only counting, per-file progress reporting to 100%, `DiffExecutionContext` constructor null-parameter validation (`ArgumentNullException` for each of `oldFolderAbsolutePath`/`newFolderAbsolutePath`/`reportsFolderAbsolutePath`), IL output sub-path derivation from reports folder, and network-share flag preservation | | Dependency analysis | [`DepsJsonAnalyzerTests`](../FolderDiffIL4DotNet.Tests/Services/DepsJsonAnalyzerTests.cs), [`NuGetVersionRangeTests`](../FolderDiffIL4DotNet.Tests/Services/NuGetVersionRangeTests.cs), [`NuGetVulnerabilityServiceTests`](../FolderDiffIL4DotNet.Tests/Services/NuGetVulnerabilityServiceTests.cs) | Structured dependency change analysis for `.deps.json` files: added/removed/updated package detection, importance classification by semver (major=High, minor=Medium, patch=Low), case-insensitive package names, invalid JSON / missing file graceful fallback (returns null), `DependencyChangeSummary` max importance and sort-by-importance ordering, realistic `.deps.json` structure parsing with runtime/compile targets; NuGet version range parsing and containment checks (exact `[x.y.z]`, open/closed intervals `[min, max)`, pre-release suffix stripping, four-part versions, edge cases); NuGet V3 vulnerability API integration (index page URL parsing, vulnerability page parsing, `DepsJsonAnalyzer.Analyze` missing-file `onError` callback invocation, successful-analysis `onError` non-invocation, invalid targets section graceful handling, per-package vulnerability checking with old/new version detection, resolved vs. newly-introduced vulnerabilities, severity label mapping, `DependencyChangeSummary` vulnerability count properties, retry after transient load failure, `OperationCanceledException` propagation, per-page warning logs that retain exception-type context, vulnerability index fetch failure logging with index URL context, outer best-effort failure logging with entry/package counts, index fetch `OperationCanceledException` propagation) | | IL/disassembler behavior | [`ILOutputServiceTests`](../FolderDiffIL4DotNet.Tests/Services/ILOutputServiceTests.cs), [`ILBlockParserTests`](../FolderDiffIL4DotNet.Tests/Services/ILBlockParserTests.cs), [`DotNetDisassembleServiceTests`](../FolderDiffIL4DotNet.Tests/Services/DotNetDisassembleServiceTests.cs), [`DisassemblerBlacklistTests`](../FolderDiffIL4DotNet.Tests/Services/DisassemblerBlacklistTests.cs), [`DisassemblerHelperTests`](../FolderDiffIL4DotNet.Tests/Services/DisassemblerHelperTests.cs), [`DotNetDisassemblerCacheTests`](../FolderDiffIL4DotNet.Tests/Services/Caching/DotNetDisassemblerCacheTests.cs), [`DotNetDetectorTests`](../FolderDiffIL4DotNet.Tests/Core/Diagnostics/DotNetDetectorTests.cs), [`AssemblyMethodAnalyzerTests`](../FolderDiffIL4DotNet.Tests/Services/AssemblyMethodAnalyzerTests.cs), [`AssemblySemanticChangesSummaryTests`](../FolderDiffIL4DotNet.Tests/Models/AssemblySemanticChangesSummaryTests.cs), [`ChangeImportanceClassifierTests`](../FolderDiffIL4DotNet.Tests/Services/ChangeImportanceClassifierTests.cs), [`ChangeTagClassifierTests`](../FolderDiffIL4DotNet.Tests/Services/ChangeTagClassifierTests.cs), [`CompilerGeneratedResolverTests`](../FolderDiffIL4DotNet.Tests/Services/CompilerGeneratedResolverTests.cs) | Same-disassembler pairing, fallback behavior, block-aware order-independent IL comparison (`BlockAwareSequenceEqual`) with method reordering tolerance, IL block parsing (`ILBlockParser.ParseBlocks`) for preamble/method/class/nested-brace handling, blacklist logic (including TTL-boundary expiry: entry removed and tool retried after the 10-minute blacklist window), independent per-tool blacklist state, null/whitespace safety for `RegisterFailure`/`ResetFailure` (explicit branch coverage for the null guard true-branch), reset of non-existent command, concurrent `RegisterFailure` with 32 threads, concurrent TTL-expiry race with no exceptions, detection and command handling, failure-vs-non-.NET detection semantics; `ResolveExecutablePath` branch coverage for relative paths containing directory separators (found and not found), whitespace-only `PATH` environment variable, `PATH` entries that are empty strings, and commands found via `PATH` search; Windows-only `EnumerateExecutableNames` tests verifying no duplicate `.exe`/`.cmd`/`.bat` extension variants when the command already carries those suffixes; `ProbeAllCandidates` availability probing returns non-empty list with unique tool names including both `dotnet-ildasm` and `ilspycmd`; shared path-shape diagnostics now keep warning formatting alive even when invalid path characters appear in disassembler command strings; `BuildInstallSuggestion` OS-specific install command presence, bilingual text with `--skip-il` tip, Windows/macOS/Linux PATH guidance; assembly semantic analysis detects `Modified` entries for method access/modifier changes and property/field type/access/modifier changes; `ChangeImportanceClassifier` correctly classifies all importance levels (High for public/protected removal and access narrowing, Medium for public addition and internal removal, Low for body-only and private additions), `WithClassifiedImportance` preserves all fields; `AssemblySemanticChangesSummary` importance counts, max importance, and entries sorted by importance; CA1031 catch-all fallback paths for corrupt/truncated/empty PE files (returns null instead of throwing), asymmetric valid-vs-corrupt assembly pair; streaming IL comparison (`StreamingFilteredSequenceEqual`) with MVID exclusion, configured ignore strings, empty inputs, length mismatch, all-excluded equality, and behavioral equivalence with legacy `SplitAndFilterIlLines` + `SequenceEqual`; `FilterIlLines` line filtering with and without exclusions; `SplitToLines` line splitting for LF, CRLF, empty, null, and trailing-newline inputs; `ChangeTagClassifier` heuristic pattern detection (Extract same-type modified+private added, Inline reverse, Move cross-type, Rename same-type different name, Signature/Access/BodyEdit arrow detection, DepUpdate dependency-only changes), `FormatTags` comma-separated formatting, `GetLabel` label mapping, edge cases (public method not consumed by Extract, same-type not triggering Move); `ValidateILFilterStrings` safety validation (null input, empty input, all-safe strings, short string warning, mixed lengths, exact minimum length boundary); compiler-generated name resolution (`CompilerGeneratedResolver`): async state machine, display class, lambda method, backing field, local function, record clone/synthesized member annotation and detection; `SimpleSignatureTypeProvider.GetGenericInstantiation` arity suffix stripping for deeply nested generics, `GetTypeFromReference` nested type resolution via `ResolutionScope`, runtime assembly generic signature verification (no backtick-arity in generic instantiations); `Analyze` optional `onError` callback invocation on failure and non-invocation on success | @@ -46,7 +46,7 @@ Use the commands in [Run Tests Locally](#testing-en-run-tests) to inspect the cu | Architecture boundary | [`CoreSeparationTests`](../FolderDiffIL4DotNet.Tests/Architecture/CoreSeparationTests.cs), [`CiAutomationConfigurationTests`](../FolderDiffIL4DotNet.Tests/Architecture/CiAutomationConfigurationTests.cs), [`MutationSummaryScriptTests`](../FolderDiffIL4DotNet.Tests/Architecture/MutationSummaryScriptTests.cs), [`MutationPrCommentScriptTests`](../FolderDiffIL4DotNet.Tests/Architecture/MutationPrCommentScriptTests.cs) | utility types stay in the `FolderDiffIL4DotNet.Core` assembly, the main assembly no longer defines the legacy `FolderDiffIL4DotNet.Utils` namespace, repository automation keeps coverage gates, release workflow, CodeQL, Dependabot, and benchmark regression workflow configured, mutation-summary automation keeps the extracted `scripts/generate-mutation-summary.py` entry point plus best-effort PR-comment guardrails wired, the summary script reads thresholds from `stryker-config.json`, documentation coverage thresholds match the CI workflow, benchmark regression workflow contains expected structure (PR trigger, benchmark-action, alert threshold, fail-on-alert), the mutation-summary script is exercised against valid, zero-mutant, malformed, and missing-report fixtures, and the PR-comment helper covers bot-only selection plus update/create upsert paths for the sticky summary comment | | Git test isolation | [`TestGitRepositoryTests`](../FolderDiffIL4DotNet.Tests/Helpers/TestGitRepositoryTests.cs) | temporary Git repositories use one shared initialization path, ignore user/system Git configuration, disable commit/tag signing and hooks locally, run non-interactively, preserve the simulated global configuration file, and still create commits and annotated tags when the isolated global configuration enables signing | | Plugin system | [`PluginLoaderTests`](../FolderDiffIL4DotNet.Tests/Runner/PluginLoaderTests.cs), [`FileDiffServiceUnitTests.Hooks`](../FolderDiffIL4DotNet.Tests/Services/FileDiffServiceUnitTests.Hooks.cs), [`DotNetDisassemblerProviderTests`](../FolderDiffIL4DotNet.Tests/Services/DotNetDisassemblerProviderTests.cs), [`PluginConfigSettingsTests`](../FolderDiffIL4DotNet.Tests/Models/PluginConfigSettingsTests.cs), [`ReportFormatterTests`](../FolderDiffIL4DotNet.Tests/Services/ReportFormatterTests.cs), [`ReportSectionWriterOrderTests`](../FolderDiffIL4DotNet.Tests/Services/ReportSectionWriterOrderTests.cs) | Plugin loading from search paths (non-existent path, empty directory, invalid DLL, duplicate search-path deduplication for the same plugin DLL, constructor null-guard, strict-mode pre-load hash rejection when trusted hashes are missing/empty/mismatched), `IFileComparisonHook` before/after integration (hook override, null passthrough, exception handling, phase-aware failure logs with hook order, multi-hook ordering), `DotNetDisassemblerProvider` CanHandle for .NET vs non-.NET files, DisplayName/extension-aware warning logs on recoverable detection failures, DisassembleAsync delegation and error handling, plugin config settings round-trip (PluginSearchPaths, PluginEnabledIds, PluginConfig JSON serialization, readonly guarantees), `IReportFormatter` Order values and IsEnabled conditions, `IReportSectionWriter` built-in writer count and unique/increasing order invariants | -| Runner layer | [`CliOverrideApplierTests`](../FolderDiffIL4DotNet.Tests/Runner/CliOverrideApplierTests.cs), [`DiffPipelineExecutorTests`](../FolderDiffIL4DotNet.Tests/Runner/DiffPipelineExecutorTests.cs), [`DryRunExecutorTests`](../FolderDiffIL4DotNet.Tests/Runner/DryRunExecutorTests.cs), [`RunScopeBuilderTests`](../FolderDiffIL4DotNet.Tests/Runner/RunScopeBuilderTests.cs), [`PluginAssemblyLoadContextTests`](../FolderDiffIL4DotNet.Tests/Runner/PluginAssemblyLoadContextTests.cs), [`SpinnerThemesTests`](../FolderDiffIL4DotNet.Tests/Runner/SpinnerThemesTests.cs) | CLI override application (`--threads`, `--no-il-cache`, `--skip-il`, `--no-timestamp-warnings` applied to builder, default options leave builder unchanged), `FormatElapsedTime` formatting (zero, sub-second, multi-hour), `DiffPipelineResult` record equality (including `HasILFilterWarnings` field), constructor null-guards, `RunScopeBuilder.BuildExecutionContext` network detection and path storage, `CreateIlCache` conditional creation, DI container service resolution, `PluginAssemblyLoadContext` collectible context creation and shared assembly fallback, post-process action failures staying best-effort while warning logs retain the action type, execution position, `Order`, and exception type, spinner theme application for all 7 themes plus multiple-spinners-detected matcha fallback and random selection | +| Runner layer | [`CliOverrideApplierTests`](../FolderDiffIL4DotNet.Tests/Runner/CliOverrideApplierTests.cs), [`DiffPipelineExecutorTests`](../FolderDiffIL4DotNet.Tests/Runner/DiffPipelineExecutorTests.cs), [`DryRunExecutorTests`](../FolderDiffIL4DotNet.Tests/Runner/DryRunExecutorTests.cs), [`RunScopeBuilderTests`](../FolderDiffIL4DotNet.Tests/Runner/RunScopeBuilderTests.cs), [`PluginAssemblyLoadContextTests`](../FolderDiffIL4DotNet.Tests/Runner/PluginAssemblyLoadContextTests.cs), [`SpinnerThemesTests`](../FolderDiffIL4DotNet.Tests/Runner/SpinnerThemesTests.cs) | CLI override application (`--threads`, `--no-il-cache`, `--skip-il`, `--no-timestamp-warnings` applied to builder, default options leave builder unchanged), `FormatElapsedTime` formatting (zero, sub-second, multi-hour), `DiffPipelineResult` record equality (including `HasILFilterWarnings` field), constructor null-guards, `RunScopeBuilder.BuildExecutionContext` network detection and path storage, `CreateIlCache` conditional creation, DI container service resolution, `PluginAssemblyLoadContext` collectible context creation and shared assembly fallback, post-process action failures staying best-effort while warning logs retain the action type, execution position, `Order`, and exception type, and hidden spinner Easter-egg compatibility behavior | | Section writer individual | [`HeaderSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/HeaderSectionWriterTests.cs), [`LegendSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/LegendSectionWriterTests.cs), [`ConditionalSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/ConditionalSectionWriterTests.cs), [`FileListSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/FileListSectionWriterTests.cs), [`SummarySectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/SummarySectionWriterTests.cs), [`IgnoredFilesSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/IgnoredFilesSectionWriterTests.cs), [`ILCacheStatsSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/ILCacheStatsSectionWriterTests.cs), [`WarningsSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/WarningsSectionWriterTests.cs) | Per-writer Order values, IsEnabled conditions (IgnoredFiles config flag, UnchangedFiles config flag, ILCacheStats config+cache null, Warnings SHA256 mismatch/timestamp regression/IL filter string validation), Write output content assertions (report title, app version, paths, computer name, legend SHA256, section headers for Added/Removed/Modified/Unchanged, summary elapsed time, warning keyword, IL filter warning text), empty/zero-count result list handling, Ignored early return on empty list, ILCacheStats disabled when cache is null | | Plugin unload/cleanup | [`PluginUnloadCleanupTests`](../FolderDiffIL4DotNet.Tests/Runner/PluginUnloadCleanupTests.cs) | Collectible `AssemblyLoadContext` unload (clean unload, unload after assembly load, multiple independent contexts), `WeakReference` GC reclamation after unload, double-unload `InvalidOperationException`, `Unloading` event firing, shared `Plugin.Abstractions` assembly survives plugin unload | | Security (XSS/path traversal) | [`HtmlReportSecurityTests`](../FolderDiffIL4DotNet.Tests/Security/HtmlReportSecurityTests.cs), [`PathTraversalSecurityTests`](../FolderDiffIL4DotNet.Tests/Security/PathTraversalSecurityTests.cs) | `HtmlEncode` XSS prevention (script tags, attribute injection, template literal backticks, double-encoding, control characters, CJK text pass-through, malicious file paths, all five HTML special chars, null/empty), `PathValidator` traversal prevention (relative escapes, dot/dotdot, null byte/control chars, Windows reserved names, trailing space/dot, absolute paths, Unicode acceptance, extreme path length) | @@ -279,7 +279,7 @@ Workflow/config files: [`.github/workflows/dotnet.yml`](../.github/workflows/dot | 領域 | 主なテストクラス | 主な検証内容 | | --- | --- | --- | -| エントリーポイント/設定 | [`ProgramTests`](../FolderDiffIL4DotNet.Tests/ProgramTests.cs), [`ProgramRunnerTests`](../FolderDiffIL4DotNet.Tests/ProgramRunnerTests.cs), [`CliOptionsTests`](../FolderDiffIL4DotNet.Tests/CliOptionsTests.cs), [`ConfigServiceTests`](../FolderDiffIL4DotNet.Tests/Services/ConfigServiceTests.cs), [`ConfigSettingsTests`](../FolderDiffIL4DotNet.Tests/Models/ConfigSettingsTests.cs) | `Main` の終了コード、引数不正と設定失敗を分ける [`ProgramRunner`](../ProgramRunner.cs) の型付き終了コード分類、引数検証と設定読込の順序、最小構成の実行、[`CliParser`](../Runner/CliParser.cs) による CLI 引数解析(null/空/位置引数のみ、`--help`/`--version`/`--config`/`--threads`/`--no-il-cache`/`--clear-cache`/`--skip-il`/`--no-timestamp-warnings`/`--print-config`/`--coffee`/`--beer`/`--matcha`/`--whisky`/`--wine`/`--ramen`/`--sushi`/`--bell`/`--random-spinner`/`--log-format`/`--output`/`--open-reports`/`--open-config`/`--open-logs` 全フラグ、未知フラグ検出、全フラグ組み合わせ、`--config`/`--threads` の値欠落エラー、スピナー最後勝ち動作、複数スピナー検出(`MultipleSpinnersDetected`))、コード既定値(`ConfigSettings.Default*` 名前付き定数で検証)と override の設定挙動、更新日時警告のコンソール/レポート出力、[`ProgramRunner`](../ProgramRunner.cs) が内部 IL キャッシュ既定値をどう配線するかの検証、完了サマリーチャート出力(各ファイルカテゴリのバー描画、合計ゼロ時のスキップ、ラベル揃え)、JSON 書式エラーの報告(オブジェクト末尾カンマ `{"Key":"v",}`、配列末尾カンマ `["a","b",]`、複数行 JSON での [`InvalidDataException`](https://learn.microsoft.com/ja-jp/dotnet/api/system.io.invaliddataexception?view=net-8.0) メッセージへの行番号付与、`line N, position N` パターン検証、全 JSON パースエラーへのトレイリングカンマヒント付与、カスタム設定パスの `FileNotFoundException` でパスがメッセージに含まれること)、プリフライト書込権限チェックにおける [`IOException`](https://learn.microsoft.com/ja-jp/dotnet/api/system.io.ioexception?view=net-8.0) の fail-fast 処理(サイレントスワロー排除)と `ILoggerService` 経由の原因別ログ出力、`--help` テキストの「Tip:」セクションで `--print-config` を紹介、設定エラー(終了コード `3`)時の stderr への `--print-config` ヒント出力、`--wizard` 対話モードのリダイレクト stdin 拒否(終了コード `2` とエラーメッセージ)、`--clear-cache` 対話ウィザードのリダイレクト stdin 拒否(終了コード `2` とエラーメッセージ)、`--help` 出力に `--clear-cache` オプション表示、`--open-reports`/`--open-config`/`--open-logs` 早期終了、フォルダパス出力、`--output`/`--config` 指定時の連携、複数フラグ同時指定時の既定ターゲット順(`Reports` → アプリケーションデータルート / 設定ディレクトリ → `Logs`)、1 件目/2 件目の起動失敗時の short-circuit、および起動処理失敗時に解決済みターゲットパス付きでエラーを返すこと、`CheckDiskSpaceOrThrow` 空パススキップ、`CheckReportsParentWritableOrThrow` 空親パススキップとプローブファイルクリーンアップ検証、`--help` 出力にフォルダ開放オプション表示、IL キャッシュヘルパーメソッド(`FilterCacheFilesByTool` ツール名マッチングと短ファイル名スキップ、`FilterCacheFilesByToolLabel` サニタイズ往復による正確なバージョンマッチング、`ExtractDistinctToolLabels` キャッシュファイル名からの一意ソート済みラベル抽出と重複排除・短ファイル名スキップ、`UnsanitizeToolLabel` バージョンパターン逆変換とバージョンなしフォールバック、`SanitizeForCacheMatch` コロン/括弧置換、サニタイズ→逆サニタイズ往復一致性)、`--output` によるカスタム出力ディレクトリ(パス指定・値欠落エラー・デフォルト null)、`GetReportsFolderAbsolutePath` のカスタム/null/空出力ディレクトリ、`NormalizeDragDropPath` ドラッグ&ドロップパス正規化(二重/単一引用符、`file://`/`file:///` URI プレフィックス、バックスラッシュエスケープ空白、日本語を含むパーセントエンコード文字、複合形式、空入力、不正パーセントエンコーディング)、未解決 `LocalApplicationData` を通常実行と `--open-reports` でどう分類するか、active reports root に合わせた `--help` 文言、および user-local / bundled fallback の不正 JSON に対する解決済みパス付き stderr 診断 | +| エントリーポイント/設定 | [`ProgramTests`](../FolderDiffIL4DotNet.Tests/ProgramTests.cs), [`ProgramRunnerTests`](../FolderDiffIL4DotNet.Tests/ProgramRunnerTests.cs), [`CliOptionsTests`](../FolderDiffIL4DotNet.Tests/CliOptionsTests.cs), [`ConfigServiceTests`](../FolderDiffIL4DotNet.Tests/Services/ConfigServiceTests.cs), [`ConfigSettingsTests`](../FolderDiffIL4DotNet.Tests/Models/ConfigSettingsTests.cs) | `Main` の終了コード、引数不正と設定失敗を分ける [`ProgramRunner`](../ProgramRunner.cs) の型付き終了コード分類、引数検証と設定読込の順序、最小構成の実行、[`CliParser`](../Runner/CliParser.cs) による CLI 引数解析(null/空/位置引数のみ、文書化済みの全フラグと非表示のスピナーイースターエッグ互換フラグ、未知フラグ検出、全フラグ組み合わせ、`--config`/`--threads` の値欠落エラー、スピナー最後勝ち動作、複数スピナー検出(`MultipleSpinnersDetected`))、コード既定値(`ConfigSettings.Default*` 名前付き定数で検証)と override の設定挙動、更新日時警告のコンソール/レポート出力、[`ProgramRunner`](../ProgramRunner.cs) が内部 IL キャッシュ既定値をどう配線するかの検証、完了サマリーチャート出力(各ファイルカテゴリのバー描画、合計ゼロ時のスキップ、ラベル揃え)、JSON 書式エラーの報告(オブジェクト末尾カンマ `{"Key":"v",}`、配列末尾カンマ `["a","b",]`、複数行 JSON での [`InvalidDataException`](https://learn.microsoft.com/ja-jp/dotnet/api/system.io.invaliddataexception?view=net-8.0) メッセージへの行番号付与、`line N, position N` パターン検証、全 JSON パースエラーへのトレイリングカンマヒント付与、カスタム設定パスの `FileNotFoundException` でパスがメッセージに含まれること)、プリフライト書込権限チェックにおける [`IOException`](https://learn.microsoft.com/ja-jp/dotnet/api/system.io.ioexception?view=net-8.0) の fail-fast 処理(サイレントスワロー排除)と `ILoggerService` 経由の原因別ログ出力、`--help` テキストの「Tip:」セクションで `--print-config` を紹介、非表示のスピナーイースターエッグフラグを解析できる一方で `--help` 出力と現行ユーザー向け文書には掲載しないこと、設定エラー(終了コード `3`)時の stderr への `--print-config` ヒント出力、`--wizard` 対話モードのリダイレクト stdin 拒否(終了コード `2` とエラーメッセージ)、`--clear-cache` 対話ウィザードのリダイレクト stdin 拒否(終了コード `2` とエラーメッセージ)、`--help` 出力に `--clear-cache` オプション表示、`--open-reports`/`--open-config`/`--open-logs` 早期終了、フォルダパス出力、`--output`/`--config` 指定時の連携、複数フラグ同時指定時の既定ターゲット順(`Reports` → アプリケーションデータルート / 設定ディレクトリ → `Logs`)、1 件目/2 件目の起動失敗時の short-circuit、および起動処理失敗時に解決済みターゲットパス付きでエラーを返すこと、`CheckDiskSpaceOrThrow` 空パススキップ、`CheckReportsParentWritableOrThrow` 空親パススキップとプローブファイルクリーンアップ検証、`--help` 出力にフォルダ開放オプション表示、IL キャッシュヘルパーメソッド(`FilterCacheFilesByTool` ツール名マッチングと短ファイル名スキップ、`FilterCacheFilesByToolLabel` サニタイズ往復による正確なバージョンマッチング、`ExtractDistinctToolLabels` キャッシュファイル名からの一意ソート済みラベル抽出と重複排除・短ファイル名スキップ、`UnsanitizeToolLabel` バージョンパターン逆変換とバージョンなしフォールバック、`SanitizeForCacheMatch` コロン/括弧置換、サニタイズ→逆サニタイズ往復一致性)、`--output` によるカスタム出力ディレクトリ(パス指定・値欠落エラー・デフォルト null)、`GetReportsFolderAbsolutePath` のカスタム/null/空出力ディレクトリ、`NormalizeDragDropPath` ドラッグ&ドロップパス正規化(二重/単一引用符、`file://`/`file:///` URI プレフィックス、バックスラッシュエスケープ空白、日本語を含むパーセントエンコード文字、複合形式、空入力、不正パーセントエンコーディング)、未解決 `LocalApplicationData` を通常実行と `--open-reports` でどう分類するか、active reports root に合わせた `--help` 文言、および user-local / bundled fallback の不正 JSON に対する解決済みパス付き stderr 診断 | | 差分処理本体 | [`FolderDiffExecutionStrategyTests`](../FolderDiffIL4DotNet.Tests/Services/FolderDiffExecutionStrategyTests.cs), [`FolderDiffServiceTests`](../FolderDiffIL4DotNet.Tests/Services/FolderDiffServiceTests.cs), [`FolderDiffServiceUnitTests`](../FolderDiffIL4DotNet.Tests/Services/FolderDiffServiceUnitTests.cs), [`FileDiffServiceTests`](../FolderDiffIL4DotNet.Tests/Services/FileDiffServiceTests.cs), [`FileDiffServiceUnitTests`](../FolderDiffIL4DotNet.Tests/Services/FileDiffServiceUnitTests.cs), [`FileDiffResultListsTests`](../FolderDiffIL4DotNet.Tests/Models/FileDiffResultListsTests.cs), [`DiffExecutionContextTests`](../FolderDiffIL4DotNet.Tests/Services/DiffExecutionContextTests.cs) | 列挙フィルタ、自動並列度ポリシー(I/O バウンドのローカルパスでは `ProcessorCount × 2`、ネットワーク共有では上限キャップ)、`Unchanged/Added/Removed/Modified` の分類、判定理由、**Modified と判定されたファイルのみ**を対象とした更新日時逆転検出(Unchanged ファイルは更新日時が逆転しても警告対象外)、状態リセット、拡張子大小無視、伝播したテキスト比較例外からのフォールバック、権限エラー/出力先 I/O 失敗、想定例外と想定外例外のログ/再スロー境界、大量ファイルの扱い、大規模ツリー向け IL 事前計算バッチ化、大きいテキスト比較のメモリ予算ベース抑制、複数 MiB の実ファイル比較、シンボリックリンク経由の分類、ファイル単位のハッシュ/IL/テキスト分岐の異常系、列挙時のシンボリックリンクループ [`IOException`](https://learn.microsoft.com/ja-jp/dotnet/api/system.io.ioexception?view=net-8.0)(ログ出力のうえ再スロー)、比較前ファイル削除時の [`FileNotFoundException`](https://learn.microsoft.com/ja-jp/dotnet/api/system.io.filenotfoundexception?view=net-8.0) を `Removed` 分類+警告(逐次・並列両対応)、`DiffSummaryStatistics`/`SummaryStatistics` のスナップショット正確性、完了メッセージが直接 `Console.WriteLine` ではなく `ILoggerService` 経由で出力されることの検証、差分パイプラインへの `CancellationToken` 伝播(キャンセル済みトークンで `OperationCanceledException` がスローされること)、ベストエフォートセマンティック解析の CA1031 フォールバック(`AssemblyMethodAnalyzer.Analyze` が存在しないパスで失敗した場合に警告ログのみで差分結果に影響しないこと)、`FolderDiffExecutionStrategy.CountDotNetAssemblyCandidates` の空入力時挙動、重複パス抑止、マネージドアセンブリのみのカウント、ファイル単位の進捗 100% 到達、`DiffExecutionContext` コンストラクタの null パラメータ検証(`oldFolderAbsolutePath`/`newFolderAbsolutePath`/`reportsFolderAbsolutePath` 各 `ArgumentNullException`)、レポートフォルダからの IL 出力サブパス導出、ネットワーク共有フラグの保持 | | 依存関係分析 | [`DepsJsonAnalyzerTests`](../FolderDiffIL4DotNet.Tests/Services/DepsJsonAnalyzerTests.cs)、[`NuGetVersionRangeTests`](../FolderDiffIL4DotNet.Tests/Services/NuGetVersionRangeTests.cs)、[`NuGetVulnerabilityServiceTests`](../FolderDiffIL4DotNet.Tests/Services/NuGetVulnerabilityServiceTests.cs) | `.deps.json` ファイルの構造化された依存関係変更分析: パッケージの追加/削除/更新検出、semver による重要度分類(メジャー=High、マイナー=Medium、パッチ=Low)、大小区別なしのパッケージ名、不正 JSON/ファイル不在での安全なフォールバック(null 返却)、`DependencyChangeSummary` の最大重要度と重要度順ソート、runtime/compile ターゲット付きの実際の `.deps.json` 構造パース;NuGet バージョン範囲の解析と包含判定(完全一致 `[x.y.z]`、開区間/閉区間 `[min, max)`、プレリリースサフィックス除去、4 パートバージョン、エッジケース);NuGet V3 脆弱性 API 連携(インデックスページ URL パース、脆弱性ページパース、`DepsJsonAnalyzer.Analyze` ファイル不在時の `onError` コールバック呼び出し、正常解析時の `onError` 非呼び出し、不正 targets セクションのグレースフルハンドリング、旧/新バージョン検出によるパッケージ別脆弱性チェック、解消済み vs 新規導入の脆弱性判定、深刻度ラベルマッピング、`DependencyChangeSummary` 脆弱性カウントプロパティ、一時障害後の再試行、`OperationCanceledException` の伝播、例外型を保持したページ単位の警告ログ、脆弱性インデックス取得失敗時の index URL 付き警告、外側 best-effort failure ログの entry/package 件数、インデックス取得時の `OperationCanceledException` 伝播) | | IL/逆アセンブラ | [`ILOutputServiceTests`](../FolderDiffIL4DotNet.Tests/Services/ILOutputServiceTests.cs), [`ILBlockParserTests`](../FolderDiffIL4DotNet.Tests/Services/ILBlockParserTests.cs), [`DotNetDisassembleServiceTests`](../FolderDiffIL4DotNet.Tests/Services/DotNetDisassembleServiceTests.cs), [`DisassemblerBlacklistTests`](../FolderDiffIL4DotNet.Tests/Services/DisassemblerBlacklistTests.cs), [`DisassemblerHelperTests`](../FolderDiffIL4DotNet.Tests/Services/DisassemblerHelperTests.cs), [`DotNetDisassemblerCacheTests`](../FolderDiffIL4DotNet.Tests/Services/Caching/DotNetDisassemblerCacheTests.cs), [`DotNetDetectorTests`](../FolderDiffIL4DotNet.Tests/Core/Diagnostics/DotNetDetectorTests.cs), [`AssemblyMethodAnalyzerTests`](../FolderDiffIL4DotNet.Tests/Services/AssemblyMethodAnalyzerTests.cs), [`AssemblySemanticChangesSummaryTests`](../FolderDiffIL4DotNet.Tests/Models/AssemblySemanticChangesSummaryTests.cs), [`ChangeImportanceClassifierTests`](../FolderDiffIL4DotNet.Tests/Services/ChangeImportanceClassifierTests.cs), [`ChangeTagClassifierTests`](../FolderDiffIL4DotNet.Tests/Services/ChangeTagClassifierTests.cs), [`CompilerGeneratedResolverTests`](../FolderDiffIL4DotNet.Tests/Services/CompilerGeneratedResolverTests.cs) | 同一逆アセンブラ比較、フォールバック、ブロック単位順序非依存 IL 比較(`BlockAwareSequenceEqual`)によるメソッド並び替え耐性、IL ブロック解析(`ILBlockParser.ParseBlocks`)のプリアンブル/メソッド/クラス/ネスト波括弧対応、ブラックリスト(TTL 境界: 10 分のブラックリスト期間経過後にエントリが削除され、ツールが再試行されることを含む)、ツール独立状態、`RegisterFailure`/`ResetFailure` の null/空白文字ガード(null ガードの true 分岐を明示的にカバー)、存在しないコマンドの reset、32 スレッドの並行 `RegisterFailure`、TTL 切れ境界での並行呼び出し(例外なし)、検出・コマンド処理、判定失敗と非 .NET の区別;`ResolveExecutablePath` のブランチ網羅(ディレクトリ区切り文字を含む相対パス(存在あり/なし)、空白のみの `PATH` 環境変数、空文字列の PATH エントリ、PATH 検索によるコマンド発見);Windows 専用 `EnumerateExecutableNames` テスト(`.exe`/`.cmd`/`.bat` 拡張子を持つコマンドに重複拡張子が追加されないことを検証);`ProbeAllCandidates` 利用可否プローブが `dotnet-ildasm` と `ilspycmd` の両方を含む一意ツール名の非空リストを返すこと;`BuildInstallSuggestion` OS 別インストールコマンドの存在、英日バイリンガルテキストと `--skip-il` ヒント、Windows/macOS/Linux の PATH 案内;アセンブリセマンティック解析がメソッドのアクセス/修飾子変更およびプロパティ/フィールドの型/アクセス/修飾子変更を `Modified` エントリとして検出;`ChangeImportanceClassifier` が全重要度レベルを正しく分類(public/protected 削除やアクセス縮小は High、public 追加や internal 削除は Medium、ボディのみ変更や private 追加は Low)、`WithClassifiedImportance` が全フィールドを保持;`AssemblySemanticChangesSummary` の重要度カウント・最大重要度・重要度順ソート、CA1031 catch-all フォールバック:破損/切り詰め/空の PE ファイルで例外ではなく null を返すこと、正常と破損の非対称アセンブリペア;ストリーミング IL 比較(`StreamingFilteredSequenceEqual`)の MVID 除外・設定文字列除外・空入力・長さ不一致・全行除外時の一致・従来の `SplitAndFilterIlLines` + `SequenceEqual` との動作等価性検証;`FilterIlLines` の除外あり/なし行フィルタリング;`SplitToLines` の LF・CRLF・空文字列・null・末尾改行入力の行分割;`ChangeTagClassifier` のヒューリスティックパターン検出(Extract 同一型内 Modified+private 追加、Inline 逆パターン、Move 型間移動、Rename 同一型で名前変更、Signature/Access/BodyEdit のアロー検出、DepUpdate 依存関係のみの変更)、`FormatTags` カンマ区切りフォーマット、`GetLabel` ラベルマッピング、エッジケース(public メソッドが Extract に消費されないこと、同一型で Move がトリガーされないこと);`ValidateILFilterStrings` 安全性検証(null 入力、空入力、全て安全な文字列、短い文字列の警告、混合長、最小長ちょうどの境界値);コンパイラ生成名解決(`CompilerGeneratedResolver`):async ステートマシン、ディスプレイクラス、ラムダメソッド、バッキングフィールド、ローカル関数、record クローン/合成メンバーの注釈と検出;`SimpleSignatureTypeProvider.GetGenericInstantiation` 深いネストを含むジェネリクスのアリティサフィックス除去、`GetTypeFromReference` `ResolutionScope` 経由のネスト型解決、ランタイムアセンブリのジェネリックシグネチャにバッククォートアリティが含まれないことの検証;`Analyze` オプショナル `onError` コールバックの失敗時呼び出しと成功時非呼び出し | @@ -294,7 +294,7 @@ Workflow/config files: [`.github/workflows/dotnet.yml`](../.github/workflows/dot | アーキテクチャ境界 | [`CoreSeparationTests`](../FolderDiffIL4DotNet.Tests/Architecture/CoreSeparationTests.cs), [`CiAutomationConfigurationTests`](../FolderDiffIL4DotNet.Tests/Architecture/CiAutomationConfigurationTests.cs), [`MutationSummaryScriptTests`](../FolderDiffIL4DotNet.Tests/Architecture/MutationSummaryScriptTests.cs), [`MutationPrCommentScriptTests`](../FolderDiffIL4DotNet.Tests/Architecture/MutationPrCommentScriptTests.cs) | utility 型が `FolderDiffIL4DotNet.Core` アセンブリに残り、実行ファイル側へ旧 `FolderDiffIL4DotNet.Utils` 名前空間が戻らないこと、カバレッジゲート、リリースワークフロー、CodeQL、Dependabot、ベンチマークリグレッションワークフローの設定が維持されること、切り出した `scripts/generate-mutation-summary.py` の entry point と best-effort PR コメント防御が workflow に配線され続けること、summary script が `stryker-config.json` から閾値を読むこと、ドキュメントのカバレッジ閾値が CI ワークフローと一致すること、ベンチマークリグレッションワークフローが期待構造(PR トリガー、benchmark-action、閾値、fail-on-alert)を含むこと、さらに mutation-summary script 自体が正常系・0 mutant・破損レポート・レポート欠落系の fixture で実行検証され、PR コメント helper は bot 所有コメントだけを対象にした update/create の upsert 経路まで検証すること | | Git テスト分離 | [`TestGitRepositoryTests`](../FolderDiffIL4DotNet.Tests/Helpers/TestGitRepositoryTests.cs) | 一時 Git リポジトリが単一の共通初期化経路を使い、ユーザー/システム Git 設定を読み込まず、commit/tag 署名と hook をローカルで無効化して非対話実行すること、擬似グローバル設定ファイルを変更しないこと、分離済みグローバル設定で署名を有効化しても commit と annotated tag を作成できること | | プラグインシステム | [`PluginLoaderTests`](../FolderDiffIL4DotNet.Tests/Runner/PluginLoaderTests.cs), [`FileDiffServiceUnitTests.Hooks`](../FolderDiffIL4DotNet.Tests/Services/FileDiffServiceUnitTests.Hooks.cs), [`DotNetDisassemblerProviderTests`](../FolderDiffIL4DotNet.Tests/Services/DotNetDisassemblerProviderTests.cs), [`PluginConfigSettingsTests`](../FolderDiffIL4DotNet.Tests/Models/PluginConfigSettingsTests.cs), [`ReportFormatterTests`](../FolderDiffIL4DotNet.Tests/Services/ReportFormatterTests.cs), [`ReportSectionWriterOrderTests`](../FolderDiffIL4DotNet.Tests/Services/ReportSectionWriterOrderTests.cs) | サーチパスからのプラグイン読み込み(存在しないパス、空ディレクトリ、無効な DLL、同一プラグイン DLL の重複サーチパス抑止、コンストラクタ null ガード、trusted hash 未設定/空/不一致時の strict mode 事前ハッシュ拒否)、`IFileComparisonHook` の before/after 統合(フックオーバーライド、null パススルー、例外処理、フェーズ付き失敗ログと hook order、マルチフック順序付け)、`DotNetDisassemblerProvider` の .NET/非 .NET ファイル向け CanHandle、recoverable な判定失敗時の DisplayName/拡張子付き warning、DisassembleAsync 委譲とエラー処理、プラグイン設定のラウンドトリップ(PluginSearchPaths、PluginEnabledIds、PluginConfig JSON シリアライズ、読取専用保証)、`IReportFormatter` の Order 値と IsEnabled 条件、`IReportSectionWriter` 組み込みライター数と一意/昇順 Order 不変条件 | -| Runner 層 | [`CliOverrideApplierTests`](../FolderDiffIL4DotNet.Tests/Runner/CliOverrideApplierTests.cs)、[`DiffPipelineExecutorTests`](../FolderDiffIL4DotNet.Tests/Runner/DiffPipelineExecutorTests.cs)、[`DryRunExecutorTests`](../FolderDiffIL4DotNet.Tests/Runner/DryRunExecutorTests.cs)、[`RunScopeBuilderTests`](../FolderDiffIL4DotNet.Tests/Runner/RunScopeBuilderTests.cs)、[`PluginAssemblyLoadContextTests`](../FolderDiffIL4DotNet.Tests/Runner/PluginAssemblyLoadContextTests.cs)、[`SpinnerThemesTests`](../FolderDiffIL4DotNet.Tests/Runner/SpinnerThemesTests.cs) | CLI オーバーライド適用(`--threads`、`--no-il-cache`、`--skip-il`、`--no-timestamp-warnings` のビルダーへの反映、デフォルトオプションはビルダーを変更しないこと)、`FormatElapsedTime` フォーマット(ゼロ、秒未満、複数時間)、`DiffPipelineResult` レコード等価性(`HasILFilterWarnings` フィールドを含む)、コンストラクタ null ガード、`RunScopeBuilder.BuildExecutionContext` ネットワーク検出とパス保存、`CreateIlCache` 条件付き生成、DI コンテナサービス解決、`PluginAssemblyLoadContext` コレクティブルコンテキスト生成と共有アセンブリフォールバック、ポストプロセスアクション失敗が best-effort のまま継続されつつ Warning ログにアクション型と例外型が残ること、全 7 テーマのスピナーテーマ適用と複数スピナー検出時の抹茶フォールバックおよびランダム選択 | +| Runner 層 | [`CliOverrideApplierTests`](../FolderDiffIL4DotNet.Tests/Runner/CliOverrideApplierTests.cs)、[`DiffPipelineExecutorTests`](../FolderDiffIL4DotNet.Tests/Runner/DiffPipelineExecutorTests.cs)、[`DryRunExecutorTests`](../FolderDiffIL4DotNet.Tests/Runner/DryRunExecutorTests.cs)、[`RunScopeBuilderTests`](../FolderDiffIL4DotNet.Tests/Runner/RunScopeBuilderTests.cs)、[`PluginAssemblyLoadContextTests`](../FolderDiffIL4DotNet.Tests/Runner/PluginAssemblyLoadContextTests.cs)、[`SpinnerThemesTests`](../FolderDiffIL4DotNet.Tests/Runner/SpinnerThemesTests.cs) | CLI オーバーライド適用(`--threads`、`--no-il-cache`、`--skip-il`、`--no-timestamp-warnings` のビルダーへの反映、デフォルトオプションはビルダーを変更しないこと)、`FormatElapsedTime` フォーマット(ゼロ、秒未満、複数時間)、`DiffPipelineResult` レコード等価性(`HasILFilterWarnings` フィールドを含む)、コンストラクタ null ガード、`RunScopeBuilder.BuildExecutionContext` ネットワーク検出とパス保存、`CreateIlCache` 条件付き生成、DI コンテナサービス解決、`PluginAssemblyLoadContext` コレクティブルコンテキスト生成と共有アセンブリフォールバック、ポストプロセスアクション失敗が best-effort のまま継続されつつ Warning ログにアクション型と例外型が残ること、非表示のスピナーイースターエッグ互換動作 | | セクションライター個別 | [`HeaderSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/HeaderSectionWriterTests.cs)、[`LegendSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/LegendSectionWriterTests.cs)、[`ConditionalSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/ConditionalSectionWriterTests.cs)、[`FileListSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/FileListSectionWriterTests.cs)、[`SummarySectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/SummarySectionWriterTests.cs)、[`IgnoredFilesSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/IgnoredFilesSectionWriterTests.cs)、[`ILCacheStatsSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/ILCacheStatsSectionWriterTests.cs)、[`WarningsSectionWriterTests`](../FolderDiffIL4DotNet.Tests/Services/SectionWriters/WarningsSectionWriterTests.cs) | ライターごとの Order 値、IsEnabled 条件(IgnoredFiles 設定フラグ、UnchangedFiles 設定フラグ、ILCacheStats 設定+キャッシュ null、Warnings SHA256 不一致/タイムスタンプ後退/IL フィルタ文字列検証)、Write 出力内容アサーション(レポートタイトル、アプリバージョン、パス、コンピュータ名、凡例 SHA256、Added/Removed/Modified/Unchanged セクションヘッダ、サマリー経過時間、警告キーワード、IL フィルタ警告テキスト)、空/ゼロカウント結果リスト処理、Ignored 空リスト時の早期リターン、ILCacheStats キャッシュ null 時の無効化 | | プラグインアンロード/クリーンアップ | [`PluginUnloadCleanupTests`](../FolderDiffIL4DotNet.Tests/Runner/PluginUnloadCleanupTests.cs) | コレクティブル `AssemblyLoadContext` のアンロード(クリーンアンロード、アセンブリ読み込み後のアンロード、複数コンテキストの独立アンロード)、`WeakReference` によるアンロード後 GC 回収検証、二重アンロード `InvalidOperationException`、`Unloading` イベント発火、共有 `Plugin.Abstractions` アセンブリのプラグインアンロード後存続 | | セキュリティ(XSS/パストラバーサル) | [`HtmlReportSecurityTests`](../FolderDiffIL4DotNet.Tests/Security/HtmlReportSecurityTests.cs)、[`PathTraversalSecurityTests`](../FolderDiffIL4DotNet.Tests/Security/PathTraversalSecurityTests.cs) | `HtmlEncode` XSS 防止(script タグ、属性インジェクション、テンプレートリテラルのバックティック、二重エンコード、制御文字、CJK テキスト透過、悪意あるファイルパス、HTML 特殊文字 5 種、null/空文字列)、`PathValidator` トラバーサル防止(相対パスエスケープ、dot/dotdot、NULL バイト/制御文字、Windows 予約名、末尾スペース/ドット、絶対パス、Unicode 受入、極端なパス長) | diff --git a/doc/config.sample.jsonc b/doc/config.sample.jsonc index c3d721ac..41b933ce 100644 --- a/doc/config.sample.jsonc +++ b/doc/config.sample.jsonc @@ -229,7 +229,6 @@ // Custom spinner animation frames (default: null = built-in 10-frame braille animation) // カスタムスピナーアニメーションフレーム(デフォルト: null = 組み込み 10 コマのブライユアニメーション) - // CLI overrides: --coffee, --beer, --matcha, --whisky, --wine, --ramen, --sushi, --random-spinner "SpinnerFrames": null, // --- Logging / ログ ---