Skip to content
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,4 +39,6 @@ artifacts/*
.vs/*
*.xproj.user
*.nuget.targets
*.lock.json
*.lock.json
*.nuget.props

11 changes: 11 additions & 0 deletions src/CommandLine/Error.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -157,6 +157,11 @@ public abstract class TokenError : Error, IEquatable<TokenError>
{
private readonly string token;

/// <summary>
/// Initializes a new instance of the <see cref="CommandLine.TokenError"/> class.
/// </summary>
/// <param name="tag">Error type.</param>
/// <param name="token">Problematic token.</param>
protected internal TokenError(ErrorType tag, string token)
: base(tag)
{
Expand DownExpand Up@@ -232,6 +237,12 @@ public abstract class NamedError : Error, IEquatable<NamedError>
{
private readonly NameInfo nameInfo;

/// <summary>
/// Initializes a new instance of the <see cref="CommandLine.NamedError"/> class.
/// </summary>
/// <param name="tag">Error type.</param>
/// <param name="nameInfo">Problematic name.</param>

protected internal NamedError(ErrorType tag, NameInfo nameInfo)
: base(tag)
{
Expand Down
39 changes: 39 additions & 0 deletions src/CommandLine/Infrastructure/ReflectionHelper.cs
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,57 @@
// 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;

namespace CommandLine.Infrastructure
{
static class ReflectionHelper
{
/// <summary>
/// Per thread assembly attribute overrides for testing.
/// </summary>
[ThreadStatic] private static IDictionary<Type, Attribute> _overrides;

/// <summary>
/// Assembly attribute overrides for testing.
/// </summary>
/// <remarks>
/// The implementation will fail if two or more attributes of the same type
/// are included in <paramref name="overrides"/>.
/// </remarks>
/// <param name="overrides">
/// Attributes that replace the existing assembly attributes or null,
/// to clear any testing attributes.
/// </param>
public static void SetAttributeOverride(IEnumerable<Attribute> overrides)
{
if (overrides != null)
{
_overrides = overrides.ToDictionary(attr => attr.GetType(), attr => attr);
}
else
{
_overrides = null;
}
}

public static Maybe<TAttribute> GetAttribute<TAttribute>()
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
Expand Down
12 changes: 12 additions & 0 deletions src/CommandLine/Text/CopyrightInfo.cs
Original file line numberDiff line numberDiff line change
@@ -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;
Expand All@@ -24,6 +25,17 @@ public class CopyrightInfo
private readonly string author;
private readonly int builderSize;

/// <summary>
/// An empty object used for initialization.
/// </summary>
public static CopyrightInfo Empty
{
get
{
return new CopyrightInfo("author", 1);
}
}

/// <summary>
/// Initializes a new instance of the <see cref="CommandLine.Text.CopyrightInfo"/> class
/// specifying author and year.
Expand Down
11 changes: 11 additions & 0 deletions src/CommandLine/Text/HeadingInfo.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,6 +33,17 @@ public HeadingInfo(string programName, string version = null)
this.version = version;
}

/// <summary>
/// An empty object used for initialization.
/// </summary>
public static HeadingInfo Empty
{
get
{
return new HeadingInfo("");
}
}

/// <summary>
/// Gets the default heading instance.
/// The title is retrieved from <see cref="AssemblyTitleAttribute"/>,
Expand Down
14 changes: 12 additions & 2 deletions src/CommandLine/Text/HelpText.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -212,13 +212,23 @@ public static HelpText AutoBuild<T>(
{
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<Error>();

if (onError != null && parserResult.Tag == ParserResultType.NotParsed)
Expand Down
93 changes: 93 additions & 0 deletions tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -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;
Expand DownExpand Up@@ -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<Simple_Options> fakeResult = new NotParsed<Simple_Options>(
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<Simple_Options> fakeResult = new NotParsed<Simple_Options>(
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<Simple_Options> fakeResult = new NotParsed<Simple_Options>(
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);
}
}
}
}