Skip to content

Add default values to HelpBuilder output #898

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 22, 2020
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,7 @@ nCrunchTemp*
TestResults/

.fake
.ionide
.ionide

# ApprovalTests
*.received.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using ApprovalTests.Reporters;
using ApprovalTests.Reporters.TestFrameworks;

// Use globally defined Reporter for ApprovalTests. Please see
// https://github.com/approvals/ApprovalTests.Net/blob/master/docs/ApprovalTests/Reporters.md

[assembly: UseReporter(typeof(FrameworkAssertReporter))]

[assembly: ApprovalTests.Namers.UseApprovalSubdirectory("Approvals")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
the-root-command:
Test description

Usage:
the-root-command [options] <the-root-arg-no-description-no-default> [<the-root-arg-no-description-default> <the-root-arg-no-default> [<the-root-arg> [<the-root-arg-enum-default>]]]

Arguments:
<the-root-arg-no-description-no-default>
<the-root-arg-no-description-default> [default: the-root-arg-no-description-default-value]
<the-root-arg-no-default> the-root-arg-no-default-description
<the-root-arg> the-root-arg-description [default: the-root-arg-one-value]
<Read|ReadWrite|Write> the-root-arg-enum-default-description [default: Read]

Options:
-trna, --the-root-option-no-arg (REQUIRED) the-root-option-no-arg-description
-trondda, --the-root-option-no-description-default-arg <the-root-option-no-description-default-arg> [default: the-root-option--no-description-default-arg-value]
-tronda, --the-root-option-no-default-arg <the-root-option-arg-no-default-arg> (REQUIRED) the-root-option-no-default-description
-troda, --the-root-option-default-arg <the-root-option-arg> the-root-option-default-arg-description [default: the-root-option-arg-value]
-troea, --the-root-option-enum-arg <Read|ReadWrite|Write> the-root-option-description [default: Read]
-trorea, --the-root-option-required-enum-arg <Read|ReadWrite|Write> (REQUIRED) the-root-option-description [default: Read]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is super helpful.

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Xunit;
using System.CommandLine.Help;
using System.IO;
using ApprovalTests;

namespace System.CommandLine.Tests.Help
{
public partial class HelpBuilderTests
{
[Fact]
public void Help_describes_default_values_for_complex_root_command_scenario()
{
var command = new RootCommand(description: "Test description")
{
new Argument<string>("the-root-arg-no-description-no-default"),
new Argument<string>("the-root-arg-no-description-default",
argResult => "the-root-arg-no-description-default-value",
isDefault: true),
new Argument<string>("the-root-arg-no-default")
{
Description = "the-root-arg-no-default-description",
},
new Argument<string>("the-root-arg", () => "the-root-arg-one-value")
{
Description = "the-root-arg-description"
},
new Argument<FileAccess>("the-root-arg-enum-default", () => FileAccess.Read)
{
Description = "the-root-arg-enum-default-description",
ArgumentType = typeof(FileAccess)
},
new Option(aliases: new string[] {"--the-root-option-no-arg", "-trna"}) {
Description = "the-root-option-no-arg-description",
Required = true
},
new Option<string>(
aliases: new string[] {"--the-root-option-no-description-default-arg", "-trondda"},
parseArgument: _ => "the-root-option--no-description-default-arg-value",
isDefault: true
),
new Option(aliases: new string[] {"--the-root-option-no-default-arg", "-tronda"}) {
Description = "the-root-option-no-default-description",
Argument = new Argument<string>("the-root-option-arg-no-default-arg")
{
Description = "the-root-option-arg-no-default-description"
},
Required = true
},
new Option(aliases: new string[] {"--the-root-option-default-arg", "-troda"}) {
Description = "the-root-option-default-arg-description",
Argument = new Argument<string>("the-root-option-arg", () => "the-root-option-arg-value")
{
Description = "the-root-option-arg-description"
},
},
new Option(aliases: new string[] {"--the-root-option-enum-arg", "-troea"}) {
Description = "the-root-option-description",
Argument = new Argument<FileAccess>("the-root-option-arg", () => FileAccess.Read)
{
Description = "the-root-option-arg-description",
},
},
new Option(aliases: new string[] {"--the-root-option-required-enum-arg", "-trorea"}) {
Description = "the-root-option-description",
Argument = new Argument<FileAccess>("the-root-option-arg", () => FileAccess.Read)
{
Description = "the-root-option-arg-description",
},
Required = true
}
};
command.Name = "the-root-command";

HelpBuilder helpBuilder = GetHelpBuilder(LargeMaxWidth);
helpBuilder.Write(command);
var output = _console.Out.ToString();
Approvals.Verify(output);
}

}
}
179 changes: 178 additions & 1 deletion src/System.CommandLine.Tests/Help/HelpBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

namespace System.CommandLine.Tests.Help
{
public class HelpBuilderTests
public partial class HelpBuilderTests
{
private const int SmallMaxWidth = 70;
private const int LargeMaxWidth = 200;
Expand Down Expand Up @@ -842,6 +842,55 @@ public void Option_argument_descriptor_indicates_enums_values(Type type)
_console.Out.ToString().Should().Contain($"--opt <Read|ReadWrite|Write>{_columnPadding}{description}");
}

[Fact]
public void Help_describes_default_value_for_defaultable_argument()
{
var argument = new Argument
{
Name = "the-arg",
Description = "Help text from HelpDetail",
};
argument.SetDefaultValue("the-arg-value");

var command = new Command("the-command",
"Help text from description") { argument };

HelpBuilder helpBuilder = GetHelpBuilder(SmallMaxWidth);

helpBuilder.Write(command);

var help = _console.Out.ToString();

help.Should().Contain($"[default: the-arg-value]");
}

[Fact]
public void Command_arguments_default_value_provided()
{
var argument = new Argument
{
Name = "the-arg",
};

var otherArgument = new Argument
{
Name = "the-other-arg",
};
argument.SetDefaultValue("the-arg-value");
otherArgument.SetDefaultValue("the-other-arg-value");
var command = new Command("the-command",
"Help text from description") { argument, otherArgument };

HelpBuilder helpBuilder = GetHelpBuilder(SmallMaxWidth);

helpBuilder.Write(command);

var help = _console.Out.ToString();

help.Should().Contain($"[default: the-arg-value]")
.And.Contain($"[default: the-other-arg-value]");
}

#endregion Arguments

#region Options
Expand Down Expand Up @@ -1188,6 +1237,58 @@ public void Option_aliases_are_shown_before_long_names_regardless_of_alphabetica
.ToString().Should().Contain("-a, -z, --aaa, --zzz");
}

[Fact]
public void Help_describes_default_value_for_option_with_defaultable_argument()
{
var argument = new Argument
{
Name = "the-arg",
};
argument.SetDefaultValue("the-arg-value");

var command = new Command("the-command", "command help")
{
new Option(new[] { "-arg"})
{
Argument = argument
}
};

HelpBuilder helpBuilder = GetHelpBuilder(SmallMaxWidth);

helpBuilder.Write(command);

var help = _console.Out.ToString();

help.Should().Contain($"[default: the-arg-value]");
}

[Fact]
public void Help_should_not_contain_default_value_for_hidden_argument_defined_for_option ()
{
var argument = new Argument
{
Name = "the-arg",
IsHidden = true
};
argument.SetDefaultValue("the-arg-value");
var command = new Command("the-command", "command help")
{
new Option(new[] { "-arg"})
{
Argument = argument
}
};

HelpBuilder helpBuilder = GetHelpBuilder(LargeMaxWidth);

helpBuilder.Write(command);

var help = _console.Out.ToString();

help.Should().NotContain($"[default: the-arg-value]");
}

#endregion Options

#region Subcommands
Expand Down Expand Up @@ -1391,6 +1492,82 @@ public void Help_text_can_be_added_after_default_text_by_inheriting_HelpBuilder(
console.Out.ToString().Should().EndWith("The text to add");
}

[Fact]
public void Help_describes_default_value_for_subcommand_with_arguments_and_only_defaultable_is_shown()
{
var argument = new Argument
{
Name = "the-arg",
};
var otherArgumentHidden = new Argument
{
Name = "the-other-hidden-arg",
IsHidden = true
};
argument.SetDefaultValue("the-arg-value");
otherArgumentHidden.SetDefaultValue("the-other-hidden-arg-value");

var command = new Command("outer", "outer command help")
{
new Argument<string>
{
Name = "outer-args"
},
new Command("inner", $"inner command help")
{
argument,
otherArgumentHidden,
new Argument<string>
{
Name = "inner-other-arg-no-default"
}
}
};

HelpBuilder helpBuilder = GetHelpBuilder(LargeMaxWidth);

helpBuilder.Write(command);

var help = _console.Out.ToString();

help.Should().Contain($"[default: the-arg-value]");
}

[Fact]
public void Help_describes_default_values_for_subcommand_with_multiple_defaultable_arguments ()
{
var argument = new Argument
{
Name = "the-arg",
};
var otherArgument = new Argument
{
Name = "the-other-arg"
};
argument.SetDefaultValue("the-arg-value");
otherArgument.SetDefaultValue("the-other-arg-value");

var command = new Command("outer", "outer command help")
{
new Argument<string>
{
Name = "outer-args"
},
new Command("inner", $"inner command help")
{
argument, otherArgument
}
};

HelpBuilder helpBuilder = GetHelpBuilder(LargeMaxWidth);

helpBuilder.Write(command);

var help = _console.Out.ToString();

help.Should().Contain($"[the-arg: the-arg-value, the-other-arg: the-other-arg-value]");
}

private class CustomHelpBuilderThatAddsTextAfterDefaultText : HelpBuilder
{
private readonly string _theTextToAdd;
Expand Down
3 changes: 2 additions & 1 deletion src/System.CommandLine.Tests/System.CommandLine.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="ApprovalTests" Version="5.2.2" />
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="2.1.0" />
</ItemGroup>

<ItemGroup Condition="'$(DisableArcade)' == '1'">
Expand Down
Loading