-
Notifications
You must be signed in to change notification settings - Fork 779
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
Command line utils: allow 'inherited' options #131
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Threading.Tasks; | ||
using System.Linq; | ||
using Microsoft.Extensions.CommandLineUtils; | ||
using Xunit; | ||
|
||
|
@@ -363,7 +363,7 @@ public void ThrowsExceptionOnUnexpectedOptionBeforeValidSubcommandByDefault() | |
|
||
app.Command("k", c => | ||
{ | ||
subCmd = c.Command("run", _=> { }); | ||
subCmd = c.Command("run", _ => { }); | ||
c.OnExecute(() => 0); | ||
}); | ||
|
||
|
@@ -390,5 +390,116 @@ public void AllowNoThrowBehaviorOnUnexpectedOptionAfterSubcommand() | |
Assert.Equal(1, subCmd.RemainingArguments.Count); | ||
Assert.Equal(unexpectedOption, subCmd.RemainingArguments[0]); | ||
} | ||
|
||
[Fact] | ||
public void OptionsCanBeInherited() | ||
{ | ||
var app = new CommandLineApplication(); | ||
var optionA = app.Option("-a|--option-a", "", CommandOptionType.SingleValue, inherited: true); | ||
string optionAValue = null; | ||
|
||
var optionB = app.Option("-b", "", CommandOptionType.SingleValue, inherited: false); | ||
|
||
var subcmd = app.Command("subcmd", c => | ||
{ | ||
c.OnExecute(() => | ||
{ | ||
optionAValue = optionA.Value(); | ||
return 0; | ||
}); | ||
}); | ||
|
||
Assert.Equal(2, app.GetOptions().Count()); | ||
Assert.Equal(1, subcmd.GetOptions().Count()); | ||
|
||
app.Execute("-a", "A1", "subcmd"); | ||
Assert.Equal("A1", optionAValue); | ||
|
||
Assert.Throws<CommandParsingException>(() => app.Execute("subcmd", "-b", "B")); | ||
|
||
Assert.Contains("-a|--option-a", subcmd.GetHelpText()); | ||
} | ||
|
||
[Fact] | ||
public void NestedOptionConflictThrows() | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you have nested options with the same name if they are not inherited (i.e. --ask would overwrite --always)? Can you add a test for this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, when options are not inherited (default), only the subcommand-local options are searched. I'll add a sanity test for it. |
||
var app = new CommandLineApplication(); | ||
app.Option("-a|--always", "Top-level", CommandOptionType.SingleValue, inherited: true); | ||
app.Command("subcmd", c => | ||
{ | ||
c.Option("-a|--ask", "Nested", CommandOptionType.SingleValue); | ||
}); | ||
|
||
Assert.Throws<InvalidOperationException>(() => app.Execute("subcmd", "-a", "b")); | ||
} | ||
|
||
[Fact] | ||
public void OptionsWithSameName() | ||
{ | ||
var app = new CommandLineApplication(); | ||
var top = app.Option("-a|--always", "Top-level", CommandOptionType.SingleValue, inherited: false); | ||
CommandOption nested = null; | ||
app.Command("subcmd", c => | ||
{ | ||
nested = c.Option("-a|--ask", "Nested", CommandOptionType.SingleValue); | ||
}); | ||
|
||
app.Execute("-a", "top"); | ||
Assert.Equal("top", top.Value()); | ||
Assert.Null(nested.Value()); | ||
|
||
top.Values.Clear(); | ||
|
||
app.Execute("subcmd", "-a", "nested"); | ||
Assert.Null(top.Value()); | ||
Assert.Equal("nested", nested.Value()); | ||
} | ||
|
||
|
||
[Fact] | ||
public void NestedInheritedOptions() | ||
{ | ||
string globalOptionValue = null, nest1OptionValue = null, nest2OptionValue = null; | ||
|
||
var app = new CommandLineApplication(); | ||
CommandLineApplication subcmd2 = null; | ||
var g = app.Option("-g|--global", "Global option", CommandOptionType.SingleValue, inherited: true); | ||
var subcmd1 = app.Command("lvl1", s1 => | ||
{ | ||
var n1 = s1.Option("--nest1", "Nested one level down", CommandOptionType.SingleValue, inherited: true); | ||
subcmd2 = s1.Command("lvl2", s2 => | ||
{ | ||
var n2 = s2.Option("--nest2", "Nested one level down", CommandOptionType.SingleValue, inherited: true); | ||
s2.HelpOption("-h|--help"); | ||
s2.OnExecute(() => | ||
{ | ||
globalOptionValue = g.Value(); | ||
nest1OptionValue = n1.Value(); | ||
nest2OptionValue = n2.Value(); | ||
return 0; | ||
}); | ||
}); | ||
}); | ||
|
||
Assert.False(app.GetOptions().Any(o => o.LongName == "nest2")); | ||
Assert.False(app.GetOptions().Any(o => o.LongName == "nest1")); | ||
Assert.Contains(app.GetOptions(), o => o.LongName == "global"); | ||
|
||
Assert.False(subcmd1.GetOptions().Any(o => o.LongName == "nest2")); | ||
Assert.Contains(subcmd1.GetOptions(), o => o.LongName == "nest1"); | ||
Assert.Contains(subcmd1.GetOptions(), o => o.LongName == "global"); | ||
|
||
Assert.Contains(subcmd2.GetOptions(), o => o.LongName == "nest2"); | ||
Assert.Contains(subcmd2.GetOptions(), o => o.LongName == "nest1"); | ||
Assert.Contains(subcmd2.GetOptions(), o => o.LongName == "global"); | ||
|
||
Assert.Throws<CommandParsingException>(() => app.Execute("--nest2", "N2", "--nest1", "N1", "-g", "G")); | ||
Assert.Throws<CommandParsingException>(() => app.Execute("lvl1", "--nest2", "N2", "--nest1", "N1", "-g", "G")); | ||
|
||
app.Execute("lvl1", "lvl2", "--nest2", "N2", "-g", "G", "--nest1", "N1"); | ||
Assert.Equal("G", globalOptionValue); | ||
Assert.Equal("N1", nest1OptionValue); | ||
Assert.Equal("N2", nest2OptionValue); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style: add a newline above this method.