From 09eafd64eaa64948f554d0f44e19976c07bd1b2f Mon Sep 17 00:00:00 2001 From: Widthdom Date: Sun, 6 Sep 2026 07:12:42 +0900 Subject: [PATCH] Isolate search-alternative fixtures from the repository index (#5266) --- TESTING_GUIDE.md | 4 ++ changelog.d/unreleased/5266.internal.md | 16 +++++++ .../QueryCommandRunnerSearchIssue4906Tests.cs | 47 +++++++++++++++---- 3 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 changelog.d/unreleased/5266.internal.md diff --git a/TESTING_GUIDE.md b/TESTING_GUIDE.md index 89e2224df..7460066a8 100644 --- a/TESTING_GUIDE.md +++ b/TESTING_GUIDE.md @@ -8,6 +8,8 @@ If you change test code, test helpers, test execution flow, or testing conventio ## Quick Start +Search-alternative coverage in `QueryCommandRunnerSearchIssue4906Tests` uses an initialized temporary database and project for every invocation (#5266). Keep the suite in the SQLite pool sensitive collection, pin `CDIDX_DATA_DIR` without adding explicit CLI flags, disable ambient config, and restore the environment and current directory in `finally`. Preserve the absent `--db` / `--data-dir` replay assertions and validate both net8.0 and net9.0 while the repository index is updating; language-alias resolution and compact output must not read that live index. + Baseline review regressions also exercise indexing exclusion changes, a different indexed root at the same DB path, contradictory/missing omission metadata, and the partial exit code for empty incomparable snapshots. `AuditBaselineIssue5261Tests` covers compatible deltas, moved lines, changed reviewed evidence, incomplete/legacy metadata, ambiguous duplicates/renames, bounded counts, private atomic writes, invalid paths and malformed/oversized input, plus actual index/recipe CLI export and compare. Keep human/JSON error identity and contextual help/completion checks on both net8.0 and net9.0. Use the console-sensitive collection for CLI capture and isolated temporary projects for baseline files. @@ -1186,6 +1188,8 @@ Check the following: # テストガイド +`QueryCommandRunnerSearchIssue4906Tests` の検索代替案テストは、呼び出しごとに初期化済みの一時DBとプロジェクトを使用します (#5266)。SQLite pool sensitive コレクションで実行し、CLIフラグを追加せずに `CDIDX_DATA_DIR` を固定し、外部の設定読み込みを無効にして、環境変数とカレントディレクトリを `finally` で復元してください。再実行案に `--db` / `--data-dir` が含まれない検証を維持し、リポジトリの索引更新中にも net8.0 と net9.0 の両方で検証します。言語エイリアス解決とcompact出力が作業用索引を参照してはいけません。 + baseline レビューの回帰テストでは、索引除外設定の変更、同一 DB パスでの索引ルートの変更、矛盾・欠落した省略メタデータ、空の比較不能スナップショットの部分終了コードも検証します。 `AuditBaselineIssue5261Tests` は互換性のある差分、行移動、レビュー済み証拠の変化、不完全・旧形式のメタデータ、曖昧な重複・リネーム、上限付き件数、機密ファイルのアトミック保存、不正パス・壊れた入力・過大入力、および実際の索引・レシピによる CLI 保存と比較を検証します。human/JSON のエラー識別と文脈別ヘルプ・補完を net8.0 と net9.0 の両方で維持してください。CLI 出力の捕捉は console-sensitive コレクションに置き、baseline は分離した一時プロジェクトに保存してください。 diff --git a/changelog.d/unreleased/5266.internal.md b/changelog.d/unreleased/5266.internal.md new file mode 100644 index 000000000..2e9cb1350 --- /dev/null +++ b/changelog.d/unreleased/5266.internal.md @@ -0,0 +1,16 @@ +--- +category: internal +issues: + - 5266 +affected: + - tests/CodeIndex.Tests/QueryCommandRunnerSearchIssue4906Tests.cs + - TESTING_GUIDE.md +--- + +## English + +- Isolated search-alternative tests from the live repository index with temporary database/project contexts, preserving implicit database replay behavior during concurrent index updates (#5266). + +## 日本語 + +- 検索代替案のテストに一時DBとプロジェクトを使用し、作業用索引への依存を解消しました。索引更新中も、DB指定を明示しない再実行案の契約を維持します (#5266)。 diff --git a/tests/CodeIndex.Tests/QueryCommandRunnerSearchIssue4906Tests.cs b/tests/CodeIndex.Tests/QueryCommandRunnerSearchIssue4906Tests.cs index e6dade07d..b268616a9 100644 --- a/tests/CodeIndex.Tests/QueryCommandRunnerSearchIssue4906Tests.cs +++ b/tests/CodeIndex.Tests/QueryCommandRunnerSearchIssue4906Tests.cs @@ -4,6 +4,7 @@ namespace CodeIndex.Tests; +[Collection("SQLite pool sensitive")] public class QueryCommandRunnerSearchIssue4906Tests { [Theory] @@ -13,7 +14,7 @@ public void RunSearch_ScanOnlyFlagsPointHumanUsersToFindWithoutExecuting_Issue49 string query, string scanFlag) { - var (exitCode, stdout, stderr) = CaptureConsole(() => + var (exitCode, stdout, stderr) = CaptureIsolatedConsole(() => ProgramRunner.Run( ["search", query, scanFlag], JsonOptions, @@ -36,7 +37,7 @@ public void RunSearch_RegexJsonReturnsTypedShellSafeFindAlternative_Issue4906() { const string query = "a'b $value; .*"; const string path = "src/space dir/**"; - var (exitCode, stdout, stderr) = CaptureConsole(() => + var (exitCode, stdout, stderr) = CaptureIsolatedConsole(() => ProgramRunner.Run( [ "search", @@ -89,6 +90,7 @@ public void RunSearch_RegexJsonReturnsTypedShellSafeFindAlternative_Issue4906() Assert.Contains("--include-generated", argv); Assert.Contains("--json", argv); Assert.DoesNotContain("--all", argv); + Assert.DoesNotContain("--db", argv); Assert.DoesNotContain("--data-dir", argv); var posix = alternative.GetProperty("posix_sh").GetString()!; @@ -102,7 +104,7 @@ public void RunSearch_RegexJsonReturnsTypedShellSafeFindAlternative_Issue4906() [Fact] public void RunSearch_StructuredFormatDoesNotInventJsonFlag_Issue4906() { - var (exitCode, stdout, stderr) = CaptureConsole(() => + var (exitCode, stdout, stderr) = CaptureIsolatedConsole(() => ProgramRunner.Run( ["search", "TODO", "--regex", "--path", "src/**", "--format", "csv"], JsonOptions, @@ -117,7 +119,7 @@ public void RunSearch_StructuredFormatDoesNotInventJsonFlag_Issue4906() [Fact] public void RunSearch_FormatCountPreservesStructuredFindOutput_Issue4906() { - var (exitCode, stdout, stderr) = CaptureConsole(() => + var (exitCode, stdout, stderr) = CaptureIsolatedConsole(() => ProgramRunner.Run( ["search", "TODO", "--regex", "--format", "count"], JsonOptions, @@ -155,7 +157,7 @@ public void RunSearch_OptionShapedQueryIsNotReinterpretedInFindAlternative_Issue foreach (var testCase in cases) { - var (exitCode, stdout, stderr) = CaptureConsole(() => + var (exitCode, stdout, stderr) = CaptureIsolatedConsole(() => ProgramRunner.Run(testCase.Args, JsonOptions, "1.0.0-test")); Assert.Equal(CommandExitCodes.UsageError, exitCode); @@ -179,7 +181,7 @@ public void RunSearch_OptionShapedQueryIsNotReinterpretedInFindAlternative_Issue }; foreach (var args in consumedOptionCases) { - var (exitCode, stdout, stderr) = CaptureConsole(() => + var (exitCode, stdout, stderr) = CaptureIsolatedConsole(() => ProgramRunner.Run(args, JsonOptions, "1.0.0-test")); Assert.Equal(CommandExitCodes.UsageError, exitCode); @@ -227,7 +229,7 @@ public void RunSearch_UnmappableOrUnsafeScanRequestsExplainWhyWithoutCommand_Iss foreach (var testCase in cases) { - var (exitCode, stdout, stderr) = CaptureConsole(() => + var (exitCode, stdout, stderr) = CaptureIsolatedConsole(() => ProgramRunner.Run(testCase.Args, JsonOptions, "1.0.0-test")); Assert.Equal(CommandExitCodes.UsageError, exitCode); @@ -254,7 +256,7 @@ public void RunSearch_UnmappableOrUnsafeScanRequestsExplainWhyWithoutCommand_Iss [Fact] public void RunSearch_FindAlternativeRejectsIncompatibleCompactSnippetOutput_Issue4906() { - var (exitCode, stdout, stderr) = CaptureConsole(() => + var (exitCode, stdout, stderr) = CaptureIsolatedConsole(() => ProgramRunner.Run( [ "search", "TODO", "--regex", "--path", "src/**", @@ -279,7 +281,7 @@ public void RunSearch_FindAlternativeRejectsIncompatibleCompactSnippetOutput_Iss public void RunSearch_FindAlternativeHonorsJsonByteBudget_Issue4906() { const int maxJsonBytes = 200; - var (exitCode, stdout, stderr) = CaptureConsole(() => + var (exitCode, stdout, stderr) = CaptureIsolatedConsole(() => ProgramRunner.Run( [ "search", "TODO", "--regex", "--path", "src/**", @@ -322,7 +324,7 @@ public void RunSearch_FindAlternativeRejectsFindValidationFailures_Issue4906() foreach (var testCase in cases) { - var (exitCode, stdout, stderr) = CaptureConsole(() => + var (exitCode, stdout, stderr) = CaptureIsolatedConsole(() => ProgramRunner.Run(testCase.Args, JsonOptions, "1.0.0-test")); Assert.Equal(CommandExitCodes.UsageError, exitCode); @@ -336,6 +338,31 @@ public void RunSearch_FindAlternativeRejectsFindValidationFailures_Issue4906() } } + private static (int Result, string Stdout, string Stderr) CaptureIsolatedConsole(Func action) + => CaptureConsole(() => + { + using var project = TestProjectHelper.CreateTempProjectScope("cdidx_search_alternative"); + var dbPath = TestProjectHelper.CreateProjectDb(project.Root); + var previousDirectory = Environment.CurrentDirectory; + var previousDataDir = Environment.GetEnvironmentVariable(DbPathResolver.DataDirEnvironmentVariable); + var previousConfigDisable = Environment.GetEnvironmentVariable(CdidxConfigFile.DisableEnvVar); + try + { + // Language resolution and compact output can open the DB before rejecting + // scan-only flags. Isolate those reads without adding explicit replay flags. + Environment.CurrentDirectory = project.Root; + Environment.SetEnvironmentVariable(DbPathResolver.DataDirEnvironmentVariable, Path.GetDirectoryName(dbPath)); + Environment.SetEnvironmentVariable(CdidxConfigFile.DisableEnvVar, "1"); + return action(); + } + finally + { + Environment.SetEnvironmentVariable(CdidxConfigFile.DisableEnvVar, previousConfigDisable); + Environment.SetEnvironmentVariable(DbPathResolver.DataDirEnvironmentVariable, previousDataDir); + Environment.CurrentDirectory = previousDirectory; + } + }); + private static string ValueAfterIssue4906(IReadOnlyList argv, string option) { var index = -1;