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
32 changes: 32 additions & 0 deletions src/System.CommandLine.Tests/HelpOptionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,38 @@ public void The_users_can_set_max_width()
output.ToString().Should().Contain($" {secondPart}{Environment.NewLine}");
}

[Fact] // https://github.com/dotnet/command-line-api/issues/2640
public void DefaultValueFactory_does_not_throw_when_help_is_invoked()
{
var invocationConfiguration = new InvocationConfiguration
{
Output = new StringWriter(),
Error = new StringWriter()
};

Command subcommand = new("do")
{
new Option<DirectoryInfo>("-x")
{
DefaultValueFactory = result =>
{
result.AddError("Oops!");
return null;
}
}
};
subcommand.SetAction(_ => { });
RootCommand rootCommand = new()
{
subcommand
};

rootCommand.Parse("do --help").Invoke(invocationConfiguration);

invocationConfiguration.Error.ToString().Should().Be("");
}


private sealed class CustomizedHelpAction : SynchronousCommandLineAction
{
internal const string CustomUsageText = "This is custom command usage example.";
Expand Down
6 changes: 5 additions & 1 deletion src/System.CommandLine/Argument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ public List<Func<CompletionContext, IEnumerable<CompletionItem>>> CompletionSour
/// <returns>Returns the default value for the argument, if defined. Null otherwise.</returns>
public object? GetDefaultValue()
{
return GetDefaultValue(new ArgumentResult(this, null!, null));
var command = Parents.FlattenBreadthFirst(x => x.Parents)
.OfType<Command>()
.FirstOrDefault();

return GetDefaultValue(new ArgumentResult(this, new SymbolResultTree(command), null));
}

internal abstract object? GetDefaultValue(ArgumentResult argumentResult);
Expand Down
2 changes: 1 addition & 1 deletion src/System.CommandLine/Parsing/SymbolResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public abstract class SymbolResult

private protected SymbolResult(SymbolResultTree symbolResultTree, SymbolResult? parent)
{
SymbolResultTree = symbolResultTree;
SymbolResultTree = symbolResultTree ?? throw new ArgumentNullException(nameof(symbolResultTree));
Parent = parent;
}

Expand Down
10 changes: 5 additions & 5 deletions src/System.CommandLine/Parsing/SymbolResultTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ namespace System.CommandLine.Parsing
{
internal sealed class SymbolResultTree : Dictionary<Symbol, SymbolResult>
{
private readonly Command _rootCommand;
private readonly Command? _rootCommand;
internal List<ParseError>? Errors;
internal List<Token>? UnmatchedTokens;
private Dictionary<string, SymbolNode>? _symbolsByName;

internal SymbolResultTree(
Command rootCommand,
List<string>? tokenizeErrors)
Command? rootCommand = null,
List<string>? tokenizeErrors = null)
{
_rootCommand = rootCommand;

Expand Down Expand Up @@ -78,13 +78,13 @@ internal void AddUnmatchedToken(Token token, CommandResult commandResult, Comman

public SymbolResult? GetResult(string name)
{
if (_symbolsByName is null)
if (_symbolsByName is null && _rootCommand is not null)
{
_symbolsByName = new();
PopulateSymbolsByName(_rootCommand);
}

if (!_symbolsByName.TryGetValue(name, out SymbolNode? node))
if (!_symbolsByName!.TryGetValue(name, out SymbolNode? node))
{
throw new ArgumentException($"No symbol result found with name \"{name}\".");
}
Expand Down