diff --git a/README.md b/README.md index 91727097..a1eda0ed 100644 --- a/README.md +++ b/README.md @@ -249,6 +249,48 @@ let main args = | :? CommandLine.NotParsed -> 1 ``` +# Configuring Help output + +One of the most valuable aspects of the library is its ability to automatically generate help text for the user when parsing fails. The **HelpText** property of each **Option** is displayed when a command is not recognised or there is a mistake in the parameters. Multi-line 'Verbatim' strings are allowed and are correctly wrapped with sub-indentation honoured. For example: + +```csharp +[Option(HelpText = +@"Length can take several types of values + -- a string such as 'ten days' + -- a number like 1000 - this is interpreted as a number of milliseconds" + )] +public string Length {get;set;} +``` + +In previous versions of the library, configuration of the help output was achieved through calling the AutoBuild method directly. This is now deprecated and a number of helper methods are supplied to simplify the process. + + +```csharp + var textwriter = ... my custom stream .... + + Action configurer = h => { + h.AddEnumValuesToHelpText = true; + h.AdditionalNewLineAfterOption==true; + h.Copyright ="(C) Acme Solutions"; + }; + + var parser = Parser.Default + .SetDisplayWidth(40,WidthPolicy.FitToScreen) + .SetTextWriter(textwriter) + .SetHelpTextConfiguration(configurer) +``` + + +By default, the parser optionally automatically generates help and version commands. To disable these use: + + +```csharp + + var parser = Parser.Default + .SetAutoHelp(false) + .SetAutoVersion(false) +``` + # Contributors First off, _Thank you!_ All contributions are welcome. diff --git a/src/CommandLine/Parser.cs b/src/CommandLine/Parser.cs index 8f4bd049..0d570cf0 100644 --- a/src/CommandLine/Parser.cs +++ b/src/CommandLine/Parser.cs @@ -19,11 +19,12 @@ public class Parser : IDisposable private bool disposed; private readonly ParserSettings settings; private static readonly Lazy DefaultParser = new Lazy( - () => new Parser(new ParserSettings { HelpWriter = Console.Error })); + () => new Parser(new ParserSettings() )); /// /// Initializes a new instance of the class. /// + [Obsolete("Calling the constructor directly is deprecated - prefer Parser.Default")] public Parser() { settings = new ParserSettings { Consumed = true }; @@ -35,6 +36,7 @@ public Parser() /// /// The delegate used to configure /// aspects and behaviors of the parser. + [Obsolete("Calling the constructor directly is deprecated - prefer Parser.Default.Set....")] public Parser(Action configuration) { if (configuration == null) throw new ArgumentNullException("configuration"); @@ -194,16 +196,15 @@ private static ParserResult MakeParserResult(ParserResult parserResult, { return DisplayHelp( parserResult, - settings.HelpWriter, - settings.MaximumDisplayWidth); + settings.HelpTextConfiguration); } - private static ParserResult DisplayHelp(ParserResult parserResult, TextWriter helpWriter, int maxDisplayWidth) + private static ParserResult DisplayHelp(ParserResult parserResult, HelpTextConfiguration helpTextConfig) { parserResult.WithNotParsed( errors => - Maybe.Merge(errors.ToMaybe(), helpWriter.ToMaybe()) - .Do((_, writer) => writer.Write(HelpText.AutoBuild(parserResult, maxDisplayWidth))) + Maybe.Merge(errors.ToMaybe(), helpTextConfig.HelpWriter.ToMaybe()) + .Do((_, writer) => writer.Write(HelpText.AutoBuild(parserResult,helpTextConfig))) ); return parserResult; @@ -228,5 +229,75 @@ private void Dispose(bool disposing) disposed = true; } } + /// + /// Allows the client to use a stream other than Console.Error for ouput. NOTE - client should dispose the stream + /// + /// The output stream to use + /// The parser + public Parser SetTextWriter(TextWriter writer) + { + settings.Consumed = false; + settings.HelpTextConfiguration = settings.HelpTextConfiguration.WithHelpWriter(writer); + settings.Consumed = true; + return this; + } + + /// + /// Allows the client to select the display width + /// + /// The desired width + /// The policy to use when setting the width + /// The parser + public Parser SetDisplayWidth(int width,WidthPolicy policy) + { + settings.Consumed = false; + //Note that the parser constructor has probably already worked out the console width + if (policy == WidthPolicy.FitToScreen) + width = Math.Min(settings.HelpTextConfiguration.DisplayWidth, width); + settings.HelpTextConfiguration = settings.HelpTextConfiguration.WithDisplayWidth(width); + settings.Consumed = true; + return this; + } + + /// + /// Allows the client to configure flags in the helpText class + /// + /// An action which can set flags in the HelpText class + /// The parser + public Parser SetHelpTextConfiguration(Action configurer) + { + settings.Consumed = false; + settings.HelpTextConfiguration = settings.HelpTextConfiguration.WithConfigurer(configurer); + settings.Consumed = true; + return this; + } + + + /// + /// Allows the client to turn the automatic help verb on and off + /// + /// turn on/off + /// The parser + public Parser SetAutoHelp(bool enable) + { + settings.Consumed = false; + settings.HelpTextConfiguration = settings.HelpTextConfiguration.WithAutoHelp(enable); + settings.Consumed = true; + return this; + } + + /// + /// Allows the client to turn the automatic version reporting on and off + /// + /// turn on/off + /// The parser + public Parser SetAutoVersion(bool enable) + { + settings.Consumed = false; + settings.HelpTextConfiguration = settings.HelpTextConfiguration.WithAutoVersion(enable); + settings.Consumed = true; + return this; + } + } -} \ No newline at end of file +} diff --git a/src/CommandLine/ParserSettings.cs b/src/CommandLine/ParserSettings.cs index 7b182a22..34db8668 100644 --- a/src/CommandLine/ParserSettings.cs +++ b/src/CommandLine/ParserSettings.cs @@ -5,6 +5,8 @@ using System.IO; using CommandLine.Infrastructure; +using CommandLine.Text; + namespace CommandLine { @@ -13,19 +15,14 @@ namespace CommandLine /// public class ParserSettings : IDisposable { - private const int DefaultMaximumLength = 80; // default console width - private bool disposed; private bool caseSensitive; private bool caseInsensitiveEnumValues; - private TextWriter helpWriter; + private HelpTextConfiguration helpTextConfiguration = HelpTextConfiguration.Default; private bool ignoreUnknownArguments; - private bool autoHelp; - private bool autoVersion; private CultureInfo parsingCulture; private bool enableDashDash; - private int maximumDisplayWidth; - + /// /// Initializes a new instance of the class. /// @@ -33,20 +30,16 @@ public ParserSettings() { caseSensitive = true; caseInsensitiveEnumValues = false; - autoHelp = true; - autoVersion = true; parsingCulture = CultureInfo.InvariantCulture; try { - maximumDisplayWidth = Console.WindowWidth; - if (maximumDisplayWidth < 1) + if (Console.WindowWidth >= 1) { - maximumDisplayWidth = DefaultMaximumLength; + HelpTextConfiguration=HelpTextConfiguration.WithDisplayWidth(Console.WindowWidth); } } catch (IOException) { - maximumDisplayWidth = DefaultMaximumLength; } } @@ -69,6 +62,7 @@ public bool CaseSensitive set { PopsicleSetter.Set(Consumed, ref caseSensitive, value); } } + /// /// Gets or sets a value indicating whether perform case sensitive comparisons of values. /// Note that case insensitivity only applies to values, not the parameters. @@ -103,12 +97,27 @@ public CultureInfo ParsingCulture /// /// It is the caller's responsibility to dispose or close the . /// + [Obsolete("Internal use only - prefer Parser.Default.SetHelpWriter")] public TextWriter HelpWriter { - get { return helpWriter; } - set { PopsicleSetter.Set(Consumed, ref helpWriter, value); } + get { return HelpTextConfiguration.HelpWriter; } + set { HelpTextConfiguration = HelpTextConfiguration.WithHelpWriter(value); } } + /// + /// Allows the HelpText to be configured + /// + /// + /// It is intended that any future HelpText configuration should be encapsulated in this object. + /// + [Obsolete("Internal use only - prefer Parser.Default.SetHelpTextConfiguration")] + public HelpTextConfiguration HelpTextConfiguration + { + get { return helpTextConfiguration; } + set { PopsicleSetter.Set(Consumed, ref helpTextConfiguration, value); } + } + + /// /// Gets or sets a value indicating whether the parser shall move on to the next argument and ignore the given argument if it /// encounter an unknown arguments @@ -125,43 +134,55 @@ public bool IgnoreUnknownArguments get { return ignoreUnknownArguments; } set { PopsicleSetter.Set(Consumed, ref ignoreUnknownArguments, value); } } + /// - /// Gets or sets a value indicating whether implicit option or verb 'help' should be supported. + /// Gets or sets a value indicating whether enable double dash '--' syntax, + /// that forces parsing of all subsequent tokens as values. /// - public bool AutoHelp + public bool EnableDashDash { - get { return autoHelp; } - set { PopsicleSetter.Set(Consumed, ref autoHelp, value); } + get { return enableDashDash; } + set { PopsicleSetter.Set(Consumed, ref enableDashDash, value); } } /// - /// Gets or sets a value indicating whether implicit option or verb 'version' should be supported. + /// Gets or sets the maximum width of the display. This determines word wrap when displaying the text. /// - public bool AutoVersion + /// + /// + [Obsolete("Prefer Parser.Default.SetDisplayWidth")] + public int MaximumDisplayWidth { - get { return autoVersion; } - set { PopsicleSetter.Set(Consumed, ref autoVersion, value); } + get { return HelpTextConfiguration.DisplayWidth; } + set { HelpTextConfiguration = HelpTextConfiguration.WithDisplayWidth(value); } } /// - /// Gets or sets a value indicating whether enable double dash '--' syntax, - /// that forces parsing of all subsequent tokens as values. + /// Gets or sets a value indicating whether implicit option or verb 'version' should be supported. /// - public bool EnableDashDash + /// + /// Note that AutoVersion and AutoHelp straddle the line between being PARSER and HELP settings; + /// the are used buy the Help-text system to generate output but but the parser itself to decide + /// which verbs to accept. For simplicity, they are stored in HelpTextConfiguration and proxied here + /// + [Obsolete("Internal use only - prefer Parser.Default.SetAutoVersion")] + public bool AutoVersion { - get { return enableDashDash; } - set { PopsicleSetter.Set(Consumed, ref enableDashDash, value); } + get { return HelpTextConfiguration.AutoVersion; } + set { HelpTextConfiguration = HelpTextConfiguration.WithAutoVersion(value); } } /// - /// Gets or sets the maximum width of the display. This determines word wrap when displaying the text. + /// Gets or sets a value indicating whether implicit option or verb 'help' should be supported. /// - public int MaximumDisplayWidth + [Obsolete("Internal use only - prefer Parser.Default.SetAutoHelp")] + public bool AutoHelp { - get { return maximumDisplayWidth; } - set { maximumDisplayWidth = value; } + get { return HelpTextConfiguration.AutoHelp; } + set { HelpTextConfiguration = HelpTextConfiguration.WithAutoHelp(value); } } + internal StringComparer NameComparer { diff --git a/src/CommandLine/Text/HelpText.cs b/src/CommandLine/Text/HelpText.cs index cd11a475..38561f09 100644 --- a/src/CommandLine/Text/HelpText.cs +++ b/src/CommandLine/Text/HelpText.cs @@ -20,7 +20,6 @@ namespace CommandLine.Text public class HelpText { private const int BuilderCapacity = 128; - private const int DefaultMaximumLength = 80; // default console width private readonly StringBuilder preOptionsHelp; private readonly StringBuilder postOptionsHelp; private readonly SentenceBuilder sentenceBuilder; @@ -109,12 +108,12 @@ public HelpText(SentenceBuilder sentenceBuilder, string heading, string copyrigh maximumDisplayWidth = Console.WindowWidth; if (maximumDisplayWidth < 1) { - maximumDisplayWidth = DefaultMaximumLength; + maximumDisplayWidth = HelpTextConfiguration.DefaultMaximumLength; } } catch (IOException) { - maximumDisplayWidth = DefaultMaximumLength; + maximumDisplayWidth = HelpTextConfiguration.DefaultMaximumLength; } this.sentenceBuilder = sentenceBuilder; this.heading = heading; @@ -217,6 +216,27 @@ public SentenceBuilder SentenceBuilder get { return sentenceBuilder; } } + /// + /// Provided only for backwards compatibility + /// + /// + /// + /// + /// + /// + /// + [Obsolete("This method is deprecated - you should supply HelpTextConfiguration.Default or configure the Parser directly")] + public static HelpText AutoBuild( + ParserResult parserResult, + Func onError, + Func onExample, + bool verbsIndex = false + ) + { + return AutoBuild(parserResult, onError, onExample, HelpTextConfiguration.Default, verbsIndex); + } + + /// /// Creates a new instance of the class using common defaults. /// @@ -227,14 +247,15 @@ public SentenceBuilder SentenceBuilder /// A delegate used to customize the text block of reporting parsing errors text block. /// A delegate used to customize model used to render text block of usage examples. /// If true the output style is consistent with verb commands (no dashes), otherwise it outputs options. - /// The maximum width of the display. - /// The parameter is not ontly a metter of formatting, it controls whether to handle verbs or options. + /// The configuration for the help-text + /// The parameter is not only a metter of formatting, it controls whether to handle verbs or options. public static HelpText AutoBuild( ParserResult parserResult, Func onError, Func onExample, - bool verbsIndex = false, - int maxDisplayWidth = DefaultMaximumLength) + HelpTextConfiguration config, + bool verbsIndex = false + ) { var auto = new HelpText { @@ -242,7 +263,9 @@ public static HelpText AutoBuild( Copyright = CopyrightInfo.Empty, AdditionalNewLineAfterOption = true, AddDashesToOption = !verbsIndex, - MaximumDisplayWidth = maxDisplayWidth + MaximumDisplayWidth = config.DisplayWidth, + AutoHelp = config.AutoHelp, + AutoVersion = config.AutoVersion }; try @@ -264,7 +287,8 @@ public static HelpText AutoBuild( if (errors.OnlyMeaningfulOnes().Any()) auto = onError(auto); } - + //this seems to be the earliest meaningful point at which we can let the client configure the helptext options + config.Configurer(auto); ReflectionHelper.GetAttribute() .Do(license => license.AddToHelpText(auto, true)); @@ -307,7 +331,30 @@ public static HelpText AutoBuild( /// /// This feature is meant to be invoked automatically by the parser, setting the HelpWriter property /// of . - public static HelpText AutoBuild(ParserResult parserResult, int maxDisplayWidth = DefaultMaximumLength) + [Obsolete("Calling this method directly is now deprecated in favour of Parser.Default.SetDisplayWidth")] + public static HelpText AutoBuild(ParserResult parserResult, int maxDisplayWidth = HelpTextConfiguration.DefaultMaximumLength) + { + return AutoBuild(parserResult, HelpTextConfiguration.Default.WithDisplayWidth(maxDisplayWidth)); + } + [Obsolete("Internal use only - avoid calling this method directly and prefer configuring via Parser.Default.Set...")] + public static HelpText AutoBuild(ParserResult parserResult, ParserSettings settings) + { + return AutoBuild(parserResult, settings.HelpTextConfiguration); + } + + + /// + /// Creates a new instance of the class, + /// automatically handling verbs or options scenario. + /// + /// The containing the instance that collected command line arguments parsed with class. + /// The configuration for the help text. + /// + /// An instance of class. + /// + /// This feature is meant to be invoked automatically by the parser, setting the HelpWriter property + /// of . + public static HelpText AutoBuild(ParserResult parserResult, HelpTextConfiguration config) { if (parserResult.Tag != ParserResultType.NotParsed) throw new ArgumentException("Excepting NotParsed type.", "parserResult"); @@ -315,16 +362,18 @@ public static HelpText AutoBuild(ParserResult parserResult, int maxDisplay var errors = ((NotParsed)parserResult).Errors; if (errors.Any(e => e.Tag == ErrorType.VersionRequestedError)) - return new HelpText(HeadingInfo.Default){MaximumDisplayWidth = maxDisplayWidth }.AddPreOptionsLine(Environment.NewLine); + return new HelpText(HeadingInfo.Default){MaximumDisplayWidth = config.DisplayWidth,AutoHelp = config.AutoHelp, AutoVersion = config.AutoVersion }.AddPreOptionsLine(Environment.NewLine); if (!errors.Any(e => e.Tag == ErrorType.HelpVerbRequestedError)) - return AutoBuild(parserResult, current => DefaultParsingErrorsHandler(parserResult, current), e => e, maxDisplayWidth: maxDisplayWidth); + return AutoBuild(parserResult, current => DefaultParsingErrorsHandler(parserResult, current), e => e,config); + var err = errors.OfType().Single(); var pr = new NotParsed(TypeInfo.Create(err.Type), Enumerable.Empty()); return err.Matched - ? AutoBuild(pr, current => DefaultParsingErrorsHandler(pr, current), e => e, maxDisplayWidth: maxDisplayWidth) - : AutoBuild(parserResult, current => DefaultParsingErrorsHandler(parserResult, current), e => e, true, maxDisplayWidth); + ? AutoBuild(pr, current => DefaultParsingErrorsHandler(pr, current), e => e,config) + : AutoBuild(parserResult, current => DefaultParsingErrorsHandler(parserResult, current), e => e,config,true); + } /// @@ -998,4 +1047,4 @@ private static string FormatDefaultValue(T value) : string.Empty; } } -} \ No newline at end of file +} diff --git a/src/CommandLine/Text/HelpTextConfiguration.cs b/src/CommandLine/Text/HelpTextConfiguration.cs new file mode 100644 index 00000000..462dcac2 --- /dev/null +++ b/src/CommandLine/Text/HelpTextConfiguration.cs @@ -0,0 +1,121 @@ +using System; +using System.IO; + +namespace CommandLine.Text +{ + /// + /// Contains the configuration used when building HelpText + /// + /// + /// It is intended that this class should contain all settings/logic associated with configuring the + /// display of helptext. + /// + public class HelpTextConfiguration + { + /// + /// The default console width + /// + public const int DefaultMaximumLength = 80; + + /// + /// Constructor - private to avoid too much reliance on the particular argument list + /// + private HelpTextConfiguration(Action configurer, int displayWidth, TextWriter writer, + bool autoVersion, bool autoHelp) + { + Configurer = configurer; + DisplayWidth = displayWidth; + HelpWriter = writer; + AutoVersion = autoVersion; + AutoHelp = autoHelp; + } + + /// + /// The width of the display. Text will wrap if this is exceeded. + /// + public int DisplayWidth { get; private set; } + + /// + /// Method used to set display options within the HelpText + /// + /// + /// In the current implementation, there is only one HelpText and it grows as verbs and options + /// are scanned. Hence any flags this method sets will apply to all text. E.g. setting the + /// 'display enums' flag will set it for all options. + /// + public Action Configurer { get; private set; } + + /// + /// The output for the HelpText + /// + /// + /// This was moved from ParserSettings because logically is part of the help-text generation phase. + /// + public TextWriter HelpWriter { get; private set; } + + /// + /// Default Configuration which will give acceptable results + /// + public static HelpTextConfiguration Default { get; } = + new HelpTextConfiguration(_ => { }, DefaultMaximumLength, Console.Error, true, true); + + public bool AutoHelp { get; private set; } + public bool AutoVersion { get; private set; } + + private HelpTextConfiguration Copy() + { + return new HelpTextConfiguration(Configurer, DisplayWidth, HelpWriter, AutoVersion, AutoHelp); + } + + /// + /// Sets the TextWriter + /// + /// + /// The client is expected to dispose of the writer + /// + public HelpTextConfiguration WithHelpWriter(TextWriter writer) + { + var c = Copy(); + c.HelpWriter = writer; + return c; + } + + /// + /// Sets a different width of the help-text output + /// + public HelpTextConfiguration WithDisplayWidth(int maxDisplayWidth) + { + var c = Copy(); + c.DisplayWidth = maxDisplayWidth; + return c; + } + + /// + /// Allows the client to pass in an action which will be called to configure the HelpText class + /// + /// + /// The Parser constructs the HelpText object then calls this method at the earliest opportunity + /// which allows various display flags and options to be set. + /// + public HelpTextConfiguration WithConfigurer(Action func) + { + var c = Copy(); + c.Configurer = func; + return c; + } + + public HelpTextConfiguration WithAutoVersion(bool enable) + { + var c = Copy(); + c.AutoVersion = enable; + return c; + } + + public HelpTextConfiguration WithAutoHelp(bool enable) + { + var c = Copy(); + c.AutoHelp = enable; + return c; + } + } +} diff --git a/src/CommandLine/WidthPolicy.cs b/src/CommandLine/WidthPolicy.cs new file mode 100644 index 00000000..a7fd3bb0 --- /dev/null +++ b/src/CommandLine/WidthPolicy.cs @@ -0,0 +1,17 @@ +namespace CommandLine +{ + /// + /// Policy that controls how to configure the width of help text + /// + public enum WidthPolicy + { + /// + /// Use the supplied width regardless of whether it will fit on screen (recommended if you are writing to custom stream) + /// + ForceUse, + /// + /// Use the screen width if smaller than the supplied width + /// + FitToScreen + } +} \ No newline at end of file diff --git a/tests/CommandLine.Tests/Unit/HelpTextConfigurationTests.cs b/tests/CommandLine.Tests/Unit/HelpTextConfigurationTests.cs new file mode 100644 index 00000000..7104b91d --- /dev/null +++ b/tests/CommandLine.Tests/Unit/HelpTextConfigurationTests.cs @@ -0,0 +1,81 @@ +using System; +using System.IO; +using System.Linq; +using CommandLine.Tests.Fakes; +using CommandLine.Text; +using FluentAssertions; +using Xunit; + +namespace CommandLine.Tests.Unit +{ + public class HelpTextConfigurationTests + { + public enum AnEnum + { + Option1, + Option2 + } + // Options + [Verb("run", HelpText = "a verb")] + internal class Options + { + [Option] + public AnEnum AnOption { get; set; } + } + + + // Test method (xUnit) which fails + [Fact] + public void ConfigurationIsAccepted() + { + var help = new StringWriter(); + var sut = new Parser(config => + { + config.HelpWriter = help; + config.MaximumDisplayWidth = 80; + + config.HelpTextConfiguration = HelpTextConfiguration.Default + .WithHelpWriter(help) + .WithDisplayWidth(50) + .WithConfigurer(h => h.AddEnumValuesToHelpText = true); + }); + + + //There seems to a bug that prevents "help VERB" outputting anything if + //the parser is only supplied one verb so this test provides + //Add_verb as a workaround + sut.ParseArguments( + new[] {"help", "run",}); + var result = help.ToString(); + + // Verify outcome + var lines = result.ToNotEmptyLines().TrimStringArray(); + lines.Any(line=>line.Contains("Option1")).Should().BeTrue(); + lines.Any(line=>line.Contains("Option2")).Should().BeTrue(); + + } + + [Fact] + public void ConfigurationIsAcceptedUsingFluentAPI() + { + var help = new StringWriter(); + var sut =Parser.Default + .SetDisplayWidth(80,WidthPolicy.FitToScreen) + .SetTextWriter(help) + .SetHelpTextConfiguration(h => h.AddEnumValuesToHelpText = true); + + //There seems to a bug that prevents "help VERB" outputting anything if + //the parser is only supplied one verb so this test provides + //Add_verb as a workaround + sut.ParseArguments( + new[] {"help", "run",}); + var result = help.ToString(); + + // Verify outcome + var lines = result.ToNotEmptyLines().TrimStringArray(); + lines.Any(line=>line.Contains("Option1")).Should().BeTrue(); + lines.Any(line=>line.Contains("Option2")).Should().BeTrue(); + + } + } +} diff --git a/tests/CommandLine.Tests/Unit/ParserTests.cs b/tests/CommandLine.Tests/Unit/ParserTests.cs index c183c47d..3e9e8fa1 100644 --- a/tests/CommandLine.Tests/Unit/ParserTests.cs +++ b/tests/CommandLine.Tests/Unit/ParserTests.cs @@ -860,5 +860,117 @@ public void Parse_options_with_shuffled_index_values() Assert.Equal("two", args.Arg2); }); } + + [Fact] + // Tests a fix for issue #455 + public void Help_screen_does_not_show_help_verb_if_AutoHelp_is_disabled() + { + var output = new StringWriter(); + var sut = new Parser(config => { config.AutoHelp = false; config.HelpWriter = output; }); + + sut.ParseArguments(new string[] { }); + + var helpText = output.ToString(); + Assert.DoesNotContain("help", helpText, StringComparison.InvariantCulture); + Assert.DoesNotContain("Display more information on a specific command", helpText, StringComparison.InvariantCulture); + } + + [Fact] + // Tests a fix for issue #455 + public void Help_screen_does_not_show_help_option_if_AutoHelp_is_disabled() + { + var output = new StringWriter(); + var sut = new Parser(config => { config.AutoHelp = false; config.HelpWriter = output; }); + + sut.ParseArguments(new string[] { }); + + var helpText = output.ToString(); + Assert.DoesNotContain("--help", helpText, StringComparison.InvariantCulture); + Assert.DoesNotContain("Display this help screen.", helpText, StringComparison.InvariantCulture); + } + + [Fact] + // Tests a fix for issue #455 + public void Help_screen_shows_help_verb_if_AutoHelp_is_enabled() + { + var output = new StringWriter(); + var sut = new Parser(config => { config.AutoHelp = true; config.HelpWriter = output; }); + + sut.ParseArguments(new string[] { }); + + var helpText = output.ToString(); + Assert.Contains("help", helpText, StringComparison.InvariantCulture); + Assert.Contains("Display more information on a specific command", helpText, StringComparison.InvariantCulture); + } + + [Fact] + // Tests a fix for issue #455 + public void Help_screen_shows_help_option_if_AutoHelp_is_enabled() + { + var output = new StringWriter(); + var sut = new Parser(config => { config.AutoHelp = true; config.HelpWriter = output; }); + + sut.ParseArguments(new string[] { }); + + var helpText = output.ToString(); + Assert.Contains("help", helpText, StringComparison.InvariantCulture); + Assert.Contains("Display this help screen.", helpText, StringComparison.InvariantCulture); + } + + [Fact] + // Tests a fix for issue #414 + public void Help_screen_does_not_show_version_verb_if_AutoVersion_is_disabled() + { + var output = new StringWriter(); + var sut = new Parser(config => { config.AutoVersion = false; config.HelpWriter = output; }); + + sut.ParseArguments(new string[] { }); + + var helpText = output.ToString(); + Assert.DoesNotContain("version", helpText, StringComparison.InvariantCulture); + Assert.DoesNotContain("Display version information.", helpText, StringComparison.InvariantCulture); + } + + [Fact] + // Tests a fix for issue #414 + public void Help_screen_does_not_show_version_option_if_AutoVersion_is_disabled() + { + var output = new StringWriter(); + var sut = new Parser(config => { config.AutoVersion = false; config.HelpWriter = output; }); + + sut.ParseArguments(new string[] { }); + + var helpText = output.ToString(); + Assert.DoesNotContain("--version", helpText, StringComparison.InvariantCulture); + Assert.DoesNotContain("Display version information.", helpText, StringComparison.InvariantCulture); + } + + [Fact] + // Tests a fix for issue #414 + public void Help_screen_shows_version_verb_if_AutoVersion_is_enabled() + { + var output = new StringWriter(); + var sut = new Parser(config => { config.AutoVersion = true; config.HelpWriter = output; }); + + sut.ParseArguments(new string[] { }); + + var helpText = output.ToString(); + Assert.Contains("version", helpText, StringComparison.InvariantCulture); + Assert.Contains("Display version information.", helpText, StringComparison.InvariantCulture); + } + + [Fact] + // Tests a fix for issue #414 + public void Help_screen_shows_version_option_if_AutoVersion_is_ensabled() + { + var output = new StringWriter(); + var sut = new Parser(config => { config.AutoVersion = true; config.HelpWriter = output; }); + + sut.ParseArguments(new string[] { }); + + var helpText = output.ToString(); + Assert.Contains("--version", helpText, StringComparison.InvariantCulture); + Assert.Contains("Display version information.", helpText, StringComparison.InvariantCulture); + } } } diff --git a/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs b/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs index 7c4d7590..109e7141 100644 --- a/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs +++ b/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using CommandLine.Core; using System.Linq; using System.Reflection; @@ -588,7 +589,10 @@ public void AutoBuild_when_no_assembly_attributes() { onErrorCalled = true; return ht; - }, ex => ex); + }, + ex => ex, + HelpTextConfiguration.Default + ); onErrorCalled.Should().BeTrue(); actualResult.Copyright.Should().Be(expectedCopyright); @@ -613,7 +617,8 @@ public void AutoBuild_with_assembly_title_and_version_attributes_only() { onErrorCalled = true; return ht; - }, ex => ex); + }, ex => ex, + HelpTextConfiguration.Default); onErrorCalled.Should().BeTrue(); actualResult.Heading.Should().Be(string.Format("{0} {1}", expectedTitle, expectedVersion)); @@ -637,7 +642,8 @@ public void AutoBuild_with_assembly_company_attribute_only() { onErrorCalled = true; return ht; - }, ex => ex); + }, ex => ex, + HelpTextConfiguration.Default); onErrorCalled.Should().BeFalse(); // Other attributes have fallback logic actualResult.Copyright.Should().Be(string.Format("Copyright (C) {0} {1}", DateTime.Now.Year, expectedCompany)); @@ -653,5 +659,73 @@ public void Add_line_with_two_empty_spaces_at_the_end() Assert.Equal("T" + Environment.NewLine + "e" + Environment.NewLine + "s" + Environment.NewLine + "t", b.ToString()); } + + [Fact] + public void AutoBuild_without_settings_contains_help_and_version() + { + var parserResult = new NotParsed(TypeInfo.Create(typeof(NullInstance)), new[] { new BadFormatConversionError(new NameInfo("f", "foo")) }); + + var helpText = HelpText.AutoBuild(parserResult); + + var text = helpText.ToString(); + Assert.Contains("--help", helpText, StringComparison.InvariantCulture); + Assert.Contains("Display version information.", helpText, StringComparison.InvariantCulture); + Assert.Contains("--version", helpText, StringComparison.InvariantCulture); + Assert.Contains("Display this help screen.", helpText, StringComparison.InvariantCulture); + } + + [Fact] + public void AutoBuild_can_disable_autohelp() + { + var parserResult = new NotParsed(TypeInfo.Create(typeof(NullInstance)), new[] { new BadFormatConversionError(new NameInfo("f", "foo")) }); + var settings = HelpTextConfiguration.Default.WithAutoHelp(false); + var helpText = HelpText.AutoBuild(parserResult, settings); + + var text = helpText.ToString(); + Assert.DoesNotContain("--help", helpText, StringComparison.InvariantCulture); + Assert.DoesNotContain("Display this help screen.", helpText, StringComparison.InvariantCulture); + Assert.Contains("Display version information.", helpText, StringComparison.InvariantCulture); + Assert.Contains("--version", helpText, StringComparison.InvariantCulture); + + } + + [Fact] + public void AutoBuild_can_disable_autoversion() + { + var parserResult = new NotParsed(TypeInfo.Create(typeof(NullInstance)), new[] { new BadFormatConversionError(new NameInfo("f", "foo")) }); + var settings = HelpTextConfiguration.Default.WithAutoVersion(false); + var helpText = HelpText.AutoBuild(parserResult, settings); + + var text = helpText.ToString(); + Assert.Contains("--help", helpText, StringComparison.InvariantCulture); + Assert.Contains("Display this help screen.", helpText, StringComparison.InvariantCulture); + Assert.DoesNotContain("Display version information.", helpText, StringComparison.InvariantCulture); + Assert.DoesNotContain("--version", helpText, StringComparison.InvariantCulture); + } + + [Fact] + public void Only_contains_one_error() + { + var helpWriter = new StringWriter(); + var sut = new Parser(config => { config.AutoHelp = false; config.HelpWriter = helpWriter; }); + + sut.ParseArguments(new string[] {"--help"}); + var helpText = helpWriter.ToString(); + helpText.Contains("--help").Should().BeFalse(); + helpText.Replace("ERROR(S)", "").Length.Should().Be(helpText.Length - 8); + } + + [Fact] + public void Only_contains_one_error_using_new_configuration_mechanism() + { + var helpWriter = new StringWriter(); + var sut = Parser.Default.SetAutoHelp(false) + .SetTextWriter(helpWriter); + + sut.ParseArguments(new string[] {"--help"}); + var helpText = helpWriter.ToString(); + helpText.Contains("--help").Should().BeFalse(); + helpText.Replace("ERROR(S)", "").Length.Should().Be(helpText.Length - 8); + } } }