Skip to content

Commit 1607aed

Browse files
authored
Add default values to HelpBuilder output (#898)
* add default values to HelpBuilder output * add ApprovalTests initial setup * Update naming for HelpBuilderTests * Add approval test to HelpBuilderTests
1 parent 425cf56 commit 1607aed

File tree

7 files changed

+364
-20
lines changed

7 files changed

+364
-20
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,7 @@ nCrunchTemp*
151151
TestResults/
152152

153153
.fake
154-
.ionide
154+
.ionide
155+
156+
# ApprovalTests
157+
*.received.txt
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using ApprovalTests.Reporters;
2+
using ApprovalTests.Reporters.TestFrameworks;
3+
4+
// Use globally defined Reporter for ApprovalTests. Please see
5+
// https://github.com/approvals/ApprovalTests.Net/blob/master/docs/ApprovalTests/Reporters.md
6+
7+
[assembly: UseReporter(typeof(FrameworkAssertReporter))]
8+
9+
[assembly: ApprovalTests.Namers.UseApprovalSubdirectory("Approvals")]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
the-root-command:
2+
Test description
3+
4+
Usage:
5+
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>]]]
6+
7+
Arguments:
8+
<the-root-arg-no-description-no-default>
9+
<the-root-arg-no-description-default> [default: the-root-arg-no-description-default-value]
10+
<the-root-arg-no-default> the-root-arg-no-default-description
11+
<the-root-arg> the-root-arg-description [default: the-root-arg-one-value]
12+
<Read|ReadWrite|Write> the-root-arg-enum-default-description [default: Read]
13+
14+
Options:
15+
-trna, --the-root-option-no-arg (REQUIRED) the-root-option-no-arg-description
16+
-trondda, --the-root-option-no-description-default-arg <the-root-option-no-description-default-arg> [default: the-root-option--no-description-default-arg-value]
17+
-tronda, --the-root-option-no-default-arg <the-root-option-arg-no-default-arg> (REQUIRED) the-root-option-no-default-description
18+
-troda, --the-root-option-default-arg <the-root-option-arg> the-root-option-default-arg-description [default: the-root-option-arg-value]
19+
-troea, --the-root-option-enum-arg <Read|ReadWrite|Write> the-root-option-description [default: Read]
20+
-trorea, --the-root-option-required-enum-arg <Read|ReadWrite|Write> (REQUIRED) the-root-option-description [default: Read]
21+
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Xunit;
5+
using System.CommandLine.Help;
6+
using System.IO;
7+
using ApprovalTests;
8+
9+
namespace System.CommandLine.Tests.Help
10+
{
11+
public partial class HelpBuilderTests
12+
{
13+
[Fact]
14+
public void Help_describes_default_values_for_complex_root_command_scenario()
15+
{
16+
var command = new RootCommand(description: "Test description")
17+
{
18+
new Argument<string>("the-root-arg-no-description-no-default"),
19+
new Argument<string>("the-root-arg-no-description-default",
20+
argResult => "the-root-arg-no-description-default-value",
21+
isDefault: true),
22+
new Argument<string>("the-root-arg-no-default")
23+
{
24+
Description = "the-root-arg-no-default-description",
25+
},
26+
new Argument<string>("the-root-arg", () => "the-root-arg-one-value")
27+
{
28+
Description = "the-root-arg-description"
29+
},
30+
new Argument<FileAccess>("the-root-arg-enum-default", () => FileAccess.Read)
31+
{
32+
Description = "the-root-arg-enum-default-description",
33+
ArgumentType = typeof(FileAccess)
34+
},
35+
new Option(aliases: new string[] {"--the-root-option-no-arg", "-trna"}) {
36+
Description = "the-root-option-no-arg-description",
37+
Required = true
38+
},
39+
new Option<string>(
40+
aliases: new string[] {"--the-root-option-no-description-default-arg", "-trondda"},
41+
parseArgument: _ => "the-root-option--no-description-default-arg-value",
42+
isDefault: true
43+
),
44+
new Option(aliases: new string[] {"--the-root-option-no-default-arg", "-tronda"}) {
45+
Description = "the-root-option-no-default-description",
46+
Argument = new Argument<string>("the-root-option-arg-no-default-arg")
47+
{
48+
Description = "the-root-option-arg-no-default-description"
49+
},
50+
Required = true
51+
},
52+
new Option(aliases: new string[] {"--the-root-option-default-arg", "-troda"}) {
53+
Description = "the-root-option-default-arg-description",
54+
Argument = new Argument<string>("the-root-option-arg", () => "the-root-option-arg-value")
55+
{
56+
Description = "the-root-option-arg-description"
57+
},
58+
},
59+
new Option(aliases: new string[] {"--the-root-option-enum-arg", "-troea"}) {
60+
Description = "the-root-option-description",
61+
Argument = new Argument<FileAccess>("the-root-option-arg", () => FileAccess.Read)
62+
{
63+
Description = "the-root-option-arg-description",
64+
},
65+
},
66+
new Option(aliases: new string[] {"--the-root-option-required-enum-arg", "-trorea"}) {
67+
Description = "the-root-option-description",
68+
Argument = new Argument<FileAccess>("the-root-option-arg", () => FileAccess.Read)
69+
{
70+
Description = "the-root-option-arg-description",
71+
},
72+
Required = true
73+
}
74+
};
75+
command.Name = "the-root-command";
76+
77+
HelpBuilder helpBuilder = GetHelpBuilder(LargeMaxWidth);
78+
helpBuilder.Write(command);
79+
var output = _console.Out.ToString();
80+
Approvals.Verify(output);
81+
}
82+
83+
}
84+
}

src/System.CommandLine.Tests/Help/HelpBuilderTests.cs

Lines changed: 178 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

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

845+
[Fact]
846+
public void Help_describes_default_value_for_defaultable_argument()
847+
{
848+
var argument = new Argument
849+
{
850+
Name = "the-arg",
851+
Description = "Help text from HelpDetail",
852+
};
853+
argument.SetDefaultValue("the-arg-value");
854+
855+
var command = new Command("the-command",
856+
"Help text from description") { argument };
857+
858+
HelpBuilder helpBuilder = GetHelpBuilder(SmallMaxWidth);
859+
860+
helpBuilder.Write(command);
861+
862+
var help = _console.Out.ToString();
863+
864+
help.Should().Contain($"[default: the-arg-value]");
865+
}
866+
867+
[Fact]
868+
public void Command_arguments_default_value_provided()
869+
{
870+
var argument = new Argument
871+
{
872+
Name = "the-arg",
873+
};
874+
875+
var otherArgument = new Argument
876+
{
877+
Name = "the-other-arg",
878+
};
879+
argument.SetDefaultValue("the-arg-value");
880+
otherArgument.SetDefaultValue("the-other-arg-value");
881+
var command = new Command("the-command",
882+
"Help text from description") { argument, otherArgument };
883+
884+
HelpBuilder helpBuilder = GetHelpBuilder(SmallMaxWidth);
885+
886+
helpBuilder.Write(command);
887+
888+
var help = _console.Out.ToString();
889+
890+
help.Should().Contain($"[default: the-arg-value]")
891+
.And.Contain($"[default: the-other-arg-value]");
892+
}
893+
845894
#endregion Arguments
846895

847896
#region Options
@@ -1188,6 +1237,58 @@ public void Option_aliases_are_shown_before_long_names_regardless_of_alphabetica
11881237
.ToString().Should().Contain("-a, -z, --aaa, --zzz");
11891238
}
11901239

1240+
[Fact]
1241+
public void Help_describes_default_value_for_option_with_defaultable_argument()
1242+
{
1243+
var argument = new Argument
1244+
{
1245+
Name = "the-arg",
1246+
};
1247+
argument.SetDefaultValue("the-arg-value");
1248+
1249+
var command = new Command("the-command", "command help")
1250+
{
1251+
new Option(new[] { "-arg"})
1252+
{
1253+
Argument = argument
1254+
}
1255+
};
1256+
1257+
HelpBuilder helpBuilder = GetHelpBuilder(SmallMaxWidth);
1258+
1259+
helpBuilder.Write(command);
1260+
1261+
var help = _console.Out.ToString();
1262+
1263+
help.Should().Contain($"[default: the-arg-value]");
1264+
}
1265+
1266+
[Fact]
1267+
public void Help_should_not_contain_default_value_for_hidden_argument_defined_for_option ()
1268+
{
1269+
var argument = new Argument
1270+
{
1271+
Name = "the-arg",
1272+
IsHidden = true
1273+
};
1274+
argument.SetDefaultValue("the-arg-value");
1275+
var command = new Command("the-command", "command help")
1276+
{
1277+
new Option(new[] { "-arg"})
1278+
{
1279+
Argument = argument
1280+
}
1281+
};
1282+
1283+
HelpBuilder helpBuilder = GetHelpBuilder(LargeMaxWidth);
1284+
1285+
helpBuilder.Write(command);
1286+
1287+
var help = _console.Out.ToString();
1288+
1289+
help.Should().NotContain($"[default: the-arg-value]");
1290+
}
1291+
11911292
#endregion Options
11921293

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

1495+
[Fact]
1496+
public void Help_describes_default_value_for_subcommand_with_arguments_and_only_defaultable_is_shown()
1497+
{
1498+
var argument = new Argument
1499+
{
1500+
Name = "the-arg",
1501+
};
1502+
var otherArgumentHidden = new Argument
1503+
{
1504+
Name = "the-other-hidden-arg",
1505+
IsHidden = true
1506+
};
1507+
argument.SetDefaultValue("the-arg-value");
1508+
otherArgumentHidden.SetDefaultValue("the-other-hidden-arg-value");
1509+
1510+
var command = new Command("outer", "outer command help")
1511+
{
1512+
new Argument<string>
1513+
{
1514+
Name = "outer-args"
1515+
},
1516+
new Command("inner", $"inner command help")
1517+
{
1518+
argument,
1519+
otherArgumentHidden,
1520+
new Argument<string>
1521+
{
1522+
Name = "inner-other-arg-no-default"
1523+
}
1524+
}
1525+
};
1526+
1527+
HelpBuilder helpBuilder = GetHelpBuilder(LargeMaxWidth);
1528+
1529+
helpBuilder.Write(command);
1530+
1531+
var help = _console.Out.ToString();
1532+
1533+
help.Should().Contain($"[default: the-arg-value]");
1534+
}
1535+
1536+
[Fact]
1537+
public void Help_describes_default_values_for_subcommand_with_multiple_defaultable_arguments ()
1538+
{
1539+
var argument = new Argument
1540+
{
1541+
Name = "the-arg",
1542+
};
1543+
var otherArgument = new Argument
1544+
{
1545+
Name = "the-other-arg"
1546+
};
1547+
argument.SetDefaultValue("the-arg-value");
1548+
otherArgument.SetDefaultValue("the-other-arg-value");
1549+
1550+
var command = new Command("outer", "outer command help")
1551+
{
1552+
new Argument<string>
1553+
{
1554+
Name = "outer-args"
1555+
},
1556+
new Command("inner", $"inner command help")
1557+
{
1558+
argument, otherArgument
1559+
}
1560+
};
1561+
1562+
HelpBuilder helpBuilder = GetHelpBuilder(LargeMaxWidth);
1563+
1564+
helpBuilder.Write(command);
1565+
1566+
var help = _console.Out.ToString();
1567+
1568+
help.Should().Contain($"[the-arg: the-arg-value, the-other-arg: the-other-arg-value]");
1569+
}
1570+
13941571
private class CustomHelpBuilderThatAddsTextAfterDefaultText : HelpBuilder
13951572
{
13961573
private readonly string _theTextToAdd;

src/System.CommandLine.Tests/System.CommandLine.Tests.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919
</ItemGroup>
2020

2121
<ItemGroup>
22+
<PackageReference Include="ApprovalTests" Version="5.2.2" />
2223
<PackageReference Include="FluentAssertions" Version="5.10.3" />
2324
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
24-
<PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="2.1.0" />
25+
<PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="2.1.0" />
2526
</ItemGroup>
2627

2728
<ItemGroup Condition="'$(DisableArcade)' == '1'">

0 commit comments

Comments
 (0)