Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions changelog.d/unreleased/1700.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
category: fixed
issues:
- 1700
affected:
- tests/CodeIndex.Tests/QueryCommandRunnerTests.cs
---

## English

- **Out-of-range query numeric flags now fail closed (#1700)** — numeric options such as `--depth 999999999` return usage errors instead of being silently coerced or clamped.

## 日本語

- **範囲外の query 数値フラグを fail-closed にしました (#1700)** — `--depth 999999999` のような数値 option は silent な補正や clamp ではなく usage error を返します。
17 changes: 17 additions & 0 deletions changelog.d/unreleased/1705-1801.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
category: fixed
issues:
- 1705
- 1801
affected:
- src/CodeIndex/Cli/QueryCommandRunner.cs
- tests/CodeIndex.Tests/QueryCommandRunnerTests.cs
---

## English

- **Unknown query flags now fail closed (#1705, #1801)** — query commands reject unknown dash-prefixed tokens unless the user explicitly passes them after `--`.

## 日本語

- **未知の query flag を fail-closed にしました (#1705, #1801)** — query command は、ユーザーが明示的に `--` の後ろへ置いた場合を除き、未知の dash 始まり token を拒否します。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/1803.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 1803
affected:
- src/CodeIndex/Cli/IndexCommandRunner.cs
- tests/CodeIndex.Tests/IndexCommandRunnerTests.cs
---

## English

- **Unknown `index` options now stop the run (#1803)** — `cdidx index` treats unknown options as usage errors with did-you-mean hints instead of warning and continuing.

## 日本語

- **未知の `index` option で実行を停止するようにしました (#1803)** — `cdidx index` は未知 option を warning で続行せず、did-you-mean hint 付きの usage error として扱います。
18 changes: 9 additions & 9 deletions src/CodeIndex/Cli/IndexCommandRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ internal static int Run(string[] indexArgs, JsonSerializerOptions jsonOptions, C
jsonOptions,
options.ParseError,
CommandExitCodes.UsageError,
"Rerun `cdidx index <projectPath> --commits <commit-id> [commit-id ...]` with 7-40 hex commit object IDs.",
"Run `cdidx index --help` to see supported options.",
CommandErrorCodes.UsageError);
}

Expand Down Expand Up @@ -804,14 +804,14 @@ internal static int RunBackfillFold(


// Index-mode flag names recognized by `ParseArgs`. Kept in sync with the switch above
// so `Warning: unknown option ...` can suggest the closest accepted flag (#1582). Easter-egg
// so unknown option errors can suggest the closest accepted flag (#1582). Easter-egg
// and random-spinner flags are excluded since they are intentionally undiscoverable.
// `ParseArgs` の switch と同期した index 系の受理フラグ一覧。`unknown option` 警告で
// `ParseArgs` の switch と同期した index 系の受理フラグ一覧。`unknown option` error で
// 最も近い受理フラグを did-you-mean 提案するのに用いる (#1582)。
// easter egg や random-spinner は意図的に未公開なので除外する。
private static readonly string[] AcceptedIndexFlags =
[
"--db", "--rebuild", "--verbose", "--json", "--dry-run", "--force",
"--db", "--data-dir", "--rebuild", "--verbose", "--json", "--dry-run", "--force",
"--yes", "--watch", "--debounce", "--duration-format", "--max-file-bytes",
"--parallelism",
"--commits", "--changed-between", "--files", "--solution", "--project",
Expand Down Expand Up @@ -858,12 +858,13 @@ private static OptimizeFtsCommandOptions ParseOptimizeFtsArgs(string[] args)
};
}

private static void WriteUnknownIndexOptionSuggestion(string token)
private static string BuildUnknownIndexOptionError(string token)
{
var name = TrimInlineValue(token);
var suggestion = ConsoleUi.FindClosestMatch(name, AcceptedIndexFlags);
if (suggestion != null)
Console.Error.WriteLine($"Did you mean: {suggestion}?");
return suggestion == null
? $"unknown option '{token}'"
: $"unknown option '{token}'\nDid you mean: {suggestion}?";
}

private static void WriteUnknownBackfillFoldOptionSuggestion(string token)
Expand Down Expand Up @@ -1106,8 +1107,7 @@ public static IndexCommandOptions ParseArgs(string[] args)
default:
if (args[i].StartsWith('-'))
{
Console.Error.WriteLine($"Warning: unknown option '{args[i]}' (ignored) / 不明なオプション '{args[i]}'(無視されます)");
WriteUnknownIndexOptionSuggestion(args[i]);
parseError ??= BuildUnknownIndexOptionError(args[i]);
}
else
projectPath = args[i];
Expand Down
3 changes: 1 addition & 2 deletions src/CodeIndex/Cli/QueryCommandRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4566,8 +4566,7 @@ void WarnIfDuplicateSingleValueOption(string canonicalName, string newValue)
default:
if (args[i].StartsWith('-'))
{
if (allowNamedQuery && query == null)
query = args[i];
AddParseError($"Error: unsupported option: {args[i]}. Use `--` before a query literal that starts with `-`.");
break;
}
else if (query == null)
Expand Down
60 changes: 28 additions & 32 deletions tests/CodeIndex.Tests/IndexCommandRunnerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ public void ParseArgs_HelpFlagSetsShowHelp()
Assert.Null(options.ProjectPath);
}

[Fact]
public void Run_UnknownIndexOption_ReturnsUsageError()
{
var projectRoot = CreateTempProject();
try
{
var (exitCode, stdout, stderr) = RunAndCaptureStreams([projectRoot, "--verbos"]);

Assert.Equal(CommandExitCodes.UsageError, exitCode);
Assert.Equal(string.Empty, stdout);
Assert.Contains("unknown option '--verbos'", stderr);
Assert.Contains("Did you mean: --verbose?", stderr);
Assert.DoesNotContain("Warning: unknown option", stderr);
}
finally
{
DeleteDirectory(projectRoot);
}
}

[Fact]
public void FormatIndexFileException_RegexTimeout_UsesBoundedExtractionMessage()
{
Expand Down Expand Up @@ -369,43 +389,19 @@ public void Run_ExistingIndexDatabase_RunsPragmaOptimizeAfterSuccessfulIndex()
[Fact]
public void ParseArgs_UnknownIndexOption_SuggestsClosestFlag()
{
lock (TestConsoleLock.Gate)
{
var originalErr = Console.Error;
using var stderr = new StringWriter();
try
{
Console.SetError(stderr);
IndexCommandRunner.ParseArgs([".", "--rebild"]);
Assert.Contains("Warning: unknown option '--rebild'", stderr.ToString());
Assert.Contains("Did you mean: --rebuild?", stderr.ToString());
}
finally
{
Console.SetError(originalErr);
}
}
var options = IndexCommandRunner.ParseArgs([".", "--rebild"]);

Assert.Contains("unknown option '--rebild'", options.ParseError);
Assert.Contains("Did you mean: --rebuild?", options.ParseError);
}

[Fact]
public void ParseArgs_UnknownIndexOption_NoSuggestionWhenFarFromAnyFlag()
{
lock (TestConsoleLock.Gate)
{
var originalErr = Console.Error;
using var stderr = new StringWriter();
try
{
Console.SetError(stderr);
IndexCommandRunner.ParseArgs([".", "--zzzzzzzz"]);
Assert.Contains("Warning: unknown option '--zzzzzzzz'", stderr.ToString());
Assert.DoesNotContain("Did you mean:", stderr.ToString());
}
finally
{
Console.SetError(originalErr);
}
}
var options = IndexCommandRunner.ParseArgs([".", "--zzzzzzzz"]);

Assert.Contains("unknown option '--zzzzzzzz'", options.ParseError);
Assert.DoesNotContain("Did you mean:", options.ParseError);
}

[Fact]
Expand Down
45 changes: 41 additions & 4 deletions tests/CodeIndex.Tests/QueryCommandRunnerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1133,10 +1133,11 @@ public void NormalizeQueryLanguage_MapsJavaSpelling(string input)
}

[Fact]
public void ParseArgs_AllowsDashPrefixedPositionalQueryLiteral()
public void ParseArgs_EndOfOptionsAllowsDashPrefixedPositionalQueryLiteralWithOptions()
{
var options = QueryCommandRunner.ParseArgs(["--open-reports", "--db", "query.db"], jsonDefault: false, allowNamedQuery: true);
var options = QueryCommandRunner.ParseArgs(["--", "--open-reports", "--db", "query.db"], jsonDefault: false, allowNamedQuery: true);

Assert.Null(options.ParseError);
Assert.Equal("--open-reports", options.Query);
Assert.Equal("query.db", options.DbPath);
}
Expand Down Expand Up @@ -3698,6 +3699,28 @@ public void RunSearch_UnsupportedFlagTypoInInlineValueForm_SuggestsClosestFlag_I
Assert.Contains("Did you mean: --path?", stderr);
}

[Fact]
public void RunSearch_UnknownFlagAfterQuery_ReturnsUsageError()
{
var (exitCode, stdout, stderr) = CaptureConsole(() => QueryCommandRunner.RunSearch(
["foo", "--dapth", "3"],
_jsonOptions));

Assert.Equal(CommandExitCodes.UsageError, exitCode);
Assert.Equal(string.Empty, stdout);
Assert.Contains("--dapth is not supported for search", stderr);
Assert.Contains("Did you mean: --path?", stderr);
}

[Fact]
public void ParseArgs_EndOfOptionsAllowsDashPrefixedQueryLiteral()
{
var options = QueryCommandRunner.ParseArgs(["--", "--baar"], jsonDefault: false, allowNamedQuery: true);

Assert.Null(options.ParseError);
Assert.Equal("--baar", options.Query);
}

// `find` previously emitted only the raw `Error: unsupported option for find: --paht`
// line — round-2 fix routes the unknown token through the same suggester so users see
// `Did you mean: --path?`. Covers both the separated and inline `=value` forms.
Expand Down Expand Up @@ -3748,6 +3771,20 @@ public void QueryEntrypoints_InvalidNumericOptionsReturnUsageError(string scenar
Assert.DoesNotContain("database not found", stderr);
}

[Fact]
public void RunImpact_OutOfRangeDepthUpperBound_ReturnsUsageError_Issue1700()
{
var (exitCode, stdout, stderr) = CaptureConsole(() => QueryCommandRunner.RunImpact(
["Target", "--depth", "999999999"],
_jsonOptions));

Assert.Equal(CommandExitCodes.UsageError, exitCode);
Assert.Equal(string.Empty, stdout);
Assert.Contains("--depth must be less than or equal to 64", stderr);
Assert.Contains($"Usage: {ConsoleUi.GetUsageLine("impact")}", stderr);
Assert.DoesNotContain("database not found", stderr);
}

// Regression lock for #161: valid integers that fail the positive / non-negative
// range check used to be swallowed silently, leaving the command to run with the
// default value and write real results to stdout with exit 0. Every case below
Expand Down Expand Up @@ -28856,7 +28893,7 @@ public void RunSearch_DoubleDashEscapesSingleOptionLookingQueryToken_Issue923()
}

[Fact]
public void RunSearch_PositionalQueryAcceptsOptionLookingLiteral_Issue799()
public void RunSearch_EndOfOptionsAcceptsOptionLookingLiteral()
{
var projectRoot = TestProjectHelper.CreateTempProject("cdidx_issue799_search_positional_literal");
try
Expand All @@ -28869,7 +28906,7 @@ public void RunSearch_PositionalQueryAcceptsOptionLookingLiteral_Issue799()
"--open-reports appears here\n");

var (exitCode, stdout, stderr) = CaptureConsole(() => QueryCommandRunner.RunSearch(
["--open-reports", "--path", "README.md", "--db", dbPath, "--count"],
["--", "--open-reports", "--path", "README.md", "--db", dbPath, "--count"],
_jsonOptions));

Assert.Equal(CommandExitCodes.Success, exitCode);
Expand Down
Loading