diff --git a/.gitignore b/.gitignore index a7d34775..7f2e43bd 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,6 @@ artifacts/* .vs/* *.xproj.user *.nuget.targets -*.lock.json \ No newline at end of file +*.lock.json +*.nuget.props + diff --git a/src/CommandLine/Error.cs b/src/CommandLine/Error.cs index 9739a18a..475ac8e3 100644 --- a/src/CommandLine/Error.cs +++ b/src/CommandLine/Error.cs @@ -157,6 +157,11 @@ public abstract class TokenError : Error, IEquatable { private readonly string token; + /// + /// Initializes a new instance of the class. + /// + /// Error type. + /// Problematic token. protected internal TokenError(ErrorType tag, string token) : base(tag) { @@ -232,6 +237,12 @@ public abstract class NamedError : Error, IEquatable { private readonly NameInfo nameInfo; + /// + /// Initializes a new instance of the class. + /// + /// Error type. + /// Problematic name. + protected internal NamedError(ErrorType tag, NameInfo nameInfo) : base(tag) { diff --git a/src/CommandLine/Infrastructure/ReflectionHelper.cs b/src/CommandLine/Infrastructure/ReflectionHelper.cs index 97aac26f..bec7d470 100644 --- a/src/CommandLine/Infrastructure/ReflectionHelper.cs +++ b/src/CommandLine/Infrastructure/ReflectionHelper.cs @@ -1,8 +1,10 @@ // Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information. using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.Remoting.Messaging; using CommandLine.Core; using CSharpx; @@ -10,9 +12,46 @@ namespace CommandLine.Infrastructure { static class ReflectionHelper { + /// + /// Per thread assembly attribute overrides for testing. + /// + [ThreadStatic] private static IDictionary _overrides; + + /// + /// Assembly attribute overrides for testing. + /// + /// + /// The implementation will fail if two or more attributes of the same type + /// are included in . + /// + /// + /// Attributes that replace the existing assembly attributes or null, + /// to clear any testing attributes. + /// + public static void SetAttributeOverride(IEnumerable overrides) + { + if (overrides != null) + { + _overrides = overrides.ToDictionary(attr => attr.GetType(), attr => attr); + } + else + { + _overrides = null; + } + } + public static Maybe GetAttribute() where TAttribute : Attribute { + // Test support + if (_overrides != null) + { + return + _overrides.ContainsKey(typeof(TAttribute)) ? + Maybe.Just((TAttribute)_overrides[typeof(TAttribute)]) : + Maybe.Nothing< TAttribute>(); + } + var assembly = GetExecutingOrEntryAssembly(); #if NET40 diff --git a/src/CommandLine/Text/CopyrightInfo.cs b/src/CommandLine/Text/CopyrightInfo.cs index 8db2a532..3df9e630 100644 --- a/src/CommandLine/Text/CopyrightInfo.cs +++ b/src/CommandLine/Text/CopyrightInfo.cs @@ -1,6 +1,7 @@ // Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information. using System; +using System.Dynamic; using System.Globalization; using System.Reflection; using System.Text; @@ -24,6 +25,17 @@ public class CopyrightInfo private readonly string author; private readonly int builderSize; + /// + /// An empty object used for initialization. + /// + public static CopyrightInfo Empty + { + get + { + return new CopyrightInfo("author", 1); + } + } + /// /// Initializes a new instance of the class /// specifying author and year. diff --git a/src/CommandLine/Text/HeadingInfo.cs b/src/CommandLine/Text/HeadingInfo.cs index dfe95edd..286a1872 100644 --- a/src/CommandLine/Text/HeadingInfo.cs +++ b/src/CommandLine/Text/HeadingInfo.cs @@ -33,6 +33,17 @@ public HeadingInfo(string programName, string version = null) this.version = version; } + /// + /// An empty object used for initialization. + /// + public static HeadingInfo Empty + { + get + { + return new HeadingInfo(""); + } + } + /// /// Gets the default heading instance. /// The title is retrieved from , diff --git a/src/CommandLine/Text/HelpText.cs b/src/CommandLine/Text/HelpText.cs index 9209e25c..68f7af3b 100644 --- a/src/CommandLine/Text/HelpText.cs +++ b/src/CommandLine/Text/HelpText.cs @@ -212,13 +212,23 @@ public static HelpText AutoBuild( { var auto = new HelpText { - Heading = HeadingInfo.Default, - Copyright = CopyrightInfo.Default, + Heading = HeadingInfo.Empty, + Copyright = CopyrightInfo.Empty, AdditionalNewLineAfterOption = true, AddDashesToOption = !verbsIndex, MaximumDisplayWidth = maxDisplayWidth }; + try + { + auto.Heading = HeadingInfo.Default; + auto.Copyright = CopyrightInfo.Default; + } + catch (Exception) + { + auto = onError(auto); + } + var errors = Enumerable.Empty(); if (onError != null && parserResult.Tag == ParserResultType.NotParsed) diff --git a/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs b/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs index f33fff36..6d7e8099 100644 --- a/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs +++ b/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs @@ -4,8 +4,11 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Reflection; using CommandLine.Core; +using CommandLine.Infrastructure; using CommandLine.Tests.Fakes; +using CommandLine.Tests.Unit.Infrastructure; using CommandLine.Text; using FluentAssertions; using Xunit; @@ -564,5 +567,95 @@ public void Default_set_to_sequence_should_be_properly_printed() // Teardown } #endif + + [Fact] + public void AutoBuild_when_no_assembly_attributes() + { + try + { + string expectedCopyright = "Copyright (C) 1 author"; + + ReflectionHelper.SetAttributeOverride(new Attribute[0]); + + ParserResult fakeResult = new NotParsed( + TypeInfo.Create(typeof (Simple_Options)), new Error[0]); + bool onErrorCalled = false; + HelpText actualResult = HelpText.AutoBuild(fakeResult, ht => + { + onErrorCalled = true; + return ht; + }, ex => ex); + + onErrorCalled.Should().BeTrue(); + actualResult.Copyright.Should().Be(expectedCopyright); + } + finally + { + ReflectionHelper.SetAttributeOverride(null); + } + } + + [Fact] + public void AutoBuild_with_assembly_title_and_version_attributes_only() + { + try + { + string expectedTitle = "Title"; + string expectedVersion = "1.2.3.4"; + + ReflectionHelper.SetAttributeOverride(new Attribute[] + { + new AssemblyTitleAttribute(expectedTitle), + new AssemblyInformationalVersionAttribute(expectedVersion) + }); + + ParserResult fakeResult = new NotParsed( + TypeInfo.Create(typeof (Simple_Options)), new Error[0]); + bool onErrorCalled = false; + HelpText actualResult = HelpText.AutoBuild(fakeResult, ht => + { + onErrorCalled = true; + return ht; + }, ex => ex); + + onErrorCalled.Should().BeTrue(); + actualResult.Heading.Should().Be(string.Format("{0} {1}", expectedTitle, expectedVersion)); + } + finally + { + ReflectionHelper.SetAttributeOverride(null); + } + } + + + [Fact] + public void AutoBuild_with_assembly_company_attribute_only() + { + try + { + string expectedCompany = "Company"; + + ReflectionHelper.SetAttributeOverride(new Attribute[] + { + new AssemblyCompanyAttribute(expectedCompany) + }); + + ParserResult fakeResult = new NotParsed( + TypeInfo.Create(typeof (Simple_Options)), new Error[0]); + bool onErrorCalled = false; + HelpText actualResult = HelpText.AutoBuild(fakeResult, ht => + { + onErrorCalled = true; + return ht; + }, ex => ex); + + onErrorCalled.Should().BeFalse(); // Other attributes have fallback logic + actualResult.Copyright.Should().Be(string.Format("Copyright (C) {0} {1}", DateTime.Now.Year, expectedCompany)); + } + finally + { + ReflectionHelper.SetAttributeOverride(null); + } + } } }