Skip to content

Commit

Permalink
Merge branch 'master' into merge/release/3.1-to-master
Browse files Browse the repository at this point in the history
Commit migrated from dotnet/extensions@6b37bb0
  • Loading branch information
dougbu committed Feb 21, 2020
2 parents d33c948 + 36e8dcc commit 33d4b28
Show file tree
Hide file tree
Showing 134 changed files with 2,444 additions and 897 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public DefaultCoreConfig()
.With(CsProjCoreToolchain.From(new NetCoreAppSettings("netcoreapp3.0", null, ".NET Core 3.0")))
#elif NETCOREAPP3_1
.With(CsProjCoreToolchain.From(new NetCoreAppSettings("netcoreapp3.1", null, ".NET Core 3.1")))
#elif NETCOREAPP5_0
.With(CsProjCoreToolchain.From(new NetCoreAppSettings("netcoreapp5.0", null, ".NET Core 5.0")))
#else
#error Target frameworks need to be updated.
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ internal class CommandLineApplication
// options.
private readonly bool _continueAfterUnexpectedArg;

public CommandLineApplication(bool throwOnUnexpectedArg = true, bool continueAfterUnexpectedArg = false)
private readonly bool _treatUnmatchedOptionsAsArguments;

public CommandLineApplication(bool throwOnUnexpectedArg = true, bool continueAfterUnexpectedArg = false, bool treatUnmatchedOptionsAsArguments = false)
{
_throwOnUnexpectedArg = throwOnUnexpectedArg;
_continueAfterUnexpectedArg = continueAfterUnexpectedArg;
_treatUnmatchedOptionsAsArguments = treatUnmatchedOptionsAsArguments;
Options = new List<CommandOption>();
Arguments = new List<CommandArgument>();
Commands = new List<CommandLineApplication>();
Expand Down Expand Up @@ -136,6 +139,7 @@ public int Execute(params string[] args)
CommandLineApplication command = this;
CommandOption option = null;
IEnumerator<CommandArgument> arguments = null;
var argumentsAssigned = false;

for (var index = 0; index < args.Length; index++)
{
Expand All @@ -161,6 +165,25 @@ public int Execute(params string[] args)
var longOptionName = longOption[0];
option = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.LongName, longOptionName, StringComparison.Ordinal));

if (option == null && _treatUnmatchedOptionsAsArguments)
{
if (arguments == null)
{
arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator());
}
if (arguments.MoveNext())
{
processed = true;
arguments.Current.Values.Add(arg);
argumentsAssigned = true;
continue;
}
//else
//{
// argumentsAssigned = false;
//}
}

if (option == null)
{
var ignoreContinueAfterUnexpectedArg = false;
Expand Down Expand Up @@ -221,6 +244,25 @@ public int Execute(params string[] args)
processed = true;
option = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.ShortName, shortOption[0], StringComparison.Ordinal));

if (option == null && _treatUnmatchedOptionsAsArguments)
{
if (arguments == null)
{
arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator());
}
if (arguments.MoveNext())
{
processed = true;
arguments.Current.Values.Add(arg);
argumentsAssigned = true;
continue;
}
//else
//{
// argumentsAssigned = false;
//}
}

// If not a short option, try symbol option
if (option == null)
{
Expand Down Expand Up @@ -278,7 +320,7 @@ public int Execute(params string[] args)
option = null;
}

if (!processed && arguments == null)
if (!processed && !argumentsAssigned)
{
var currentCommand = command;
foreach (var subcommand in command.Commands)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace Microsoft.Extensions.Internal
{
internal class TypeNameHelper
internal static class TypeNameHelper
{
private const char DefaultNestedTypeDelimiter = '+';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1166,5 +1166,59 @@ public void ThrowsExceptionOnInvalidOption()

Assert.Equal($"Unrecognized option '{inputOption}'", exception.Message);
}

[Fact]
public void TreatUnmatchedOptionsAsArguments()
{
CommandArgument first = null;
CommandArgument second = null;

CommandOption firstOption = null;
CommandOption secondOption = null;

var firstUnmatchedOption = "-firstUnmatchedOption";
var firstActualOption = "-firstActualOption";
var seconUnmatchedOption = "--secondUnmatchedOption";
var secondActualOption = "--secondActualOption";

var app = new CommandLineApplication(treatUnmatchedOptionsAsArguments: true);

app.Command("test", c =>
{
firstOption = c.Option("-firstActualOption", "first option", CommandOptionType.NoValue);
secondOption = c.Option("--secondActualOption", "second option", CommandOptionType.NoValue);

first = c.Argument("first", "First argument");
second = c.Argument("second", "Second argument");
c.OnExecute(() => 0);
});

app.Execute("test", firstUnmatchedOption, firstActualOption, seconUnmatchedOption, secondActualOption);

Assert.Equal(firstUnmatchedOption, first.Value);
Assert.Equal(seconUnmatchedOption, second.Value);

Assert.Equal(firstActualOption, firstOption.Template);
Assert.Equal(secondActualOption, secondOption.Template);
}

[Fact]
public void ThrowExceptionWhenUnmatchedOptionAndTreatUnmatchedOptionsAsArgumentsIsFalse()
{
CommandArgument first = null;

var firstOption = "-firstUnmatchedOption";

var app = new CommandLineApplication(treatUnmatchedOptionsAsArguments: false);
app.Command("test", c =>
{
first = c.Argument("first", "First argument");
c.OnExecute(() => 0);
});

var exception = Assert.Throws<CommandParsingException>(() => app.Execute("test", firstOption));

Assert.Equal($"Unrecognized option '{firstOption}'", exception.Message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ public static string GetAssemblyBaseDirectory(Assembly assembly, string baseDire
return Path.Combine(baseDirectory, assembly.GetName().Name, attribute.TargetFramework);
}

public static bool GetPreserveExistingLogsInOutput(Assembly assembly)
{
var attribute = assembly.GetCustomAttributes().OfType<TestOutputDirectoryAttribute>().FirstOrDefault();
return attribute.PreserveExistingLogsInOutput;
}

public static string GetTestClassName(Type type)
{
var shortNameAttribute =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ namespace Microsoft.AspNetCore.Testing
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = true)]
public class TestOutputDirectoryAttribute : Attribute
{
public TestOutputDirectoryAttribute(string targetFramework, string baseDirectory = null)
public TestOutputDirectoryAttribute(string preserveExistingLogsInOutput, string targetFramework, string baseDirectory = null)
{
TargetFramework = targetFramework;
BaseDirectory = baseDirectory;
PreserveExistingLogsInOutput = bool.Parse(preserveExistingLogsInOutput);
}

public string BaseDirectory { get; }
public string TargetFramework { get; }
public bool PreserveExistingLogsInOutput { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Microsoft.AspNetCore.Testing
{
[Obsolete("This API is obsolete and the pattern its usage encouraged should not be used anymore. See https://github.com/aspnet/Extensions/issues/1697 for details.")]
[Obsolete("This API is obsolete and the pattern its usage encouraged should not be used anymore. See https://github.com/dotnet/extensions/issues/1697 for details.")]
public class TestPathUtilities
{
public static string GetRepoRootDirectory()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Testing
/// properties. Once these traits are applied, build scripts can include/exclude tests based on them.
/// </para>
/// <para>
/// All flakiness-related traits start with <code>Flaky:</code> and are grouped first by the process running the tests: Azure Pipelines (AzP) or Helix.
/// All flakiness-related traits start with <c>Flaky:</c> and are grouped first by the process running the tests: Azure Pipelines (AzP) or Helix.
/// Then there is a segment specifying the "selector" which indicates where the test is flaky. Finally a segment specifying the value of that selector.
/// The value of these traits is always either "true" or the trait is not present. We encode the entire selector in the name of the trait because xUnit.net only
/// provides "==" and "!=" operators for traits, there is no way to check if a trait "contains" or "does not contain" a value. VSTest does support "contains" checks
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Runtime.InteropServices;

namespace Microsoft.AspNetCore.Testing
{
/// <summary>
/// Skips a test if the OS is the given type (Windows) and the OS version is greater than specified.
/// E.g. Specifying Window 8 skips on Win 10, but not on Linux. Combine with OSSkipConditionAttribute as needed.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)]
public class MaximumOSVersionAttribute : Attribute, ITestCondition
{
private readonly OperatingSystems _targetOS;
private readonly Version _maxVersion;
private readonly OperatingSystems _currentOS;
private readonly Version _currentVersion;
private readonly bool _skip;

public MaximumOSVersionAttribute(OperatingSystems operatingSystem, string maxVersion) :
this(operatingSystem, Version.Parse(maxVersion), GetCurrentOS(), GetCurrentOSVersion())
{
}

// to enable unit testing
internal MaximumOSVersionAttribute(OperatingSystems targetOS, Version maxVersion, OperatingSystems currentOS, Version currentVersion)
{
if (targetOS != OperatingSystems.Windows)
{
throw new NotImplementedException("Max version support is only implemented for Windows.");
}
_targetOS = targetOS;
_maxVersion = maxVersion;
_currentOS = currentOS;
// We drop the 4th field because it is not significant and it messes up the comparisons.
_currentVersion = new Version(currentVersion.Major, currentVersion.Minor,
// Major and Minor are required by the parser, but if Build isn't specified then it returns -1
// which the constructor rejects.
currentVersion.Build == -1 ? 0 : currentVersion.Build);

// Do not skip other OS's, Use OSSkipConditionAttribute or a separate MaximumOsVersionAttribute for that.
_skip = _targetOS == _currentOS && _maxVersion < _currentVersion;
SkipReason = $"This test requires {_targetOS} {_maxVersion} or earlier.";
}

// Since a test would be executed only if 'IsMet' is true, return false if we want to skip
public bool IsMet => !_skip;

public string SkipReason { get; set; }

private static OperatingSystems GetCurrentOS()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return OperatingSystems.Windows;
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return OperatingSystems.Linux;
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return OperatingSystems.MacOSX;
}
throw new PlatformNotSupportedException();
}

static private Version GetCurrentOSVersion()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return Environment.OSVersion.Version;
}
else
{
// Not implemented, but this will still be called before the OS check happens so don't throw.
return new Version(0, 0);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;

namespace Microsoft.AspNetCore.Testing
Expand All @@ -12,46 +10,31 @@ namespace Microsoft.AspNetCore.Testing
public class OSSkipConditionAttribute : Attribute, ITestCondition
{
private readonly OperatingSystems _excludedOperatingSystem;
private readonly IEnumerable<string> _excludedVersions;
private readonly OperatingSystems _osPlatform;
private readonly string _osVersion;

public OSSkipConditionAttribute(OperatingSystems operatingSystem, params string[] versions) :
this(
operatingSystem,
GetCurrentOS(),
GetCurrentOSVersion(),
versions)
public OSSkipConditionAttribute(OperatingSystems operatingSystem) :
this(operatingSystem, GetCurrentOS())
{
}

[Obsolete("Use the Minimum/MaximumOSVersionAttribute for version checks.", error: true)]
public OSSkipConditionAttribute(OperatingSystems operatingSystem, params string[] versions) :
this(operatingSystem, GetCurrentOS())
{
}

// to enable unit testing
internal OSSkipConditionAttribute(
OperatingSystems operatingSystem, OperatingSystems osPlatform, string osVersion, params string[] versions)
internal OSSkipConditionAttribute(OperatingSystems operatingSystem, OperatingSystems osPlatform)
{
_excludedOperatingSystem = operatingSystem;
_excludedVersions = versions ?? Enumerable.Empty<string>();
_osPlatform = osPlatform;
_osVersion = osVersion;
}

public bool IsMet
{
get
{
var currentOSInfo = new OSInfo()
{
OperatingSystem = _osPlatform,
Version = _osVersion,
};

var skip = (_excludedOperatingSystem & currentOSInfo.OperatingSystem) == currentOSInfo.OperatingSystem;
if (_excludedVersions.Any())
{
skip = skip
&& _excludedVersions.Any(ex => _osVersion.StartsWith(ex, StringComparison.OrdinalIgnoreCase));
}

var skip = (_excludedOperatingSystem & _osPlatform) == _osPlatform;
// Since a test would be excuted only if 'IsMet' is true, return false if we want to skip
return !skip;
}
Expand All @@ -75,25 +58,5 @@ static private OperatingSystems GetCurrentOS()
}
throw new PlatformNotSupportedException();
}

static private string GetCurrentOSVersion()
{
// currently not used on other OS's
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return Environment.OSVersion.Version.ToString();
}
else
{
return string.Empty;
}
}

private class OSInfo
{
public OperatingSystems OperatingSystem { get; set; }

public string Version { get; set; }
}
}
}
Loading

0 comments on commit 33d4b28

Please sign in to comment.