|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.CommandLine;
using FakeItEasy;
using Microsoft.TemplateEngine.Abstractions;
using Microsoft.TemplateEngine.Cli.Commands;
using Microsoft.TemplateEngine.Edge;
using Microsoft.TemplateEngine.Edge.Settings;
using Microsoft.TemplateEngine.Mocks;
namespace Microsoft.TemplateEngine.Cli.UnitTests.ParserTests
{
public partial class InstantiateTests
{
private static readonly string NewLine = Environment.NewLine;
public static IEnumerable<object[]> GetInvalidParametersTestData()
{
yield return new object[]
{
"foo --framework netcoreapp3.0",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group").WithChoiceParameter("framework", "netcoreapp2.1", "netcoreapp3.1"),
new MockTemplateInfo("foo", identity: "foo.2", groupIdentity: "foo.group").WithChoiceParameter("framework", "net5.0"),
},
new string[][]
{
new string[] { "value", "framework", "--framework", "netcoreapp3.0", $"'netcoreapp3.0' is not a valid value for --framework. The possible values are:{NewLine} net5.0 {NewLine} netcoreapp2.1{NewLine} netcoreapp3.1" }
}
};
yield return new object[]
{
"foo --framework net",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group").WithChoiceParameter("framework", "netcoreapp2.1", "netcoreapp3.1"),
new MockTemplateInfo("foo", identity: "foo.2", groupIdentity: "foo.group").WithChoiceParameter("framework", "net5.0"),
},
new string[][]
{
new string[] { "value", "framework", "--framework", "net", $"'net' is not a valid value for --framework. The possible values are:{NewLine} net5.0 {NewLine} netcoreapp2.1{NewLine} netcoreapp3.1" }
}
};
yield return new object[]
{
"foo --framework net",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group").WithChoiceParameter("framework", "netcoreapp2.1"),
new MockTemplateInfo("foo", identity: "foo.2", groupIdentity: "foo.group").WithChoiceParameter("framework", "net5.0"),
new MockTemplateInfo("foo", identity: "foo.3", groupIdentity: "foo.group").WithChoiceParameter("framework", "netcoreapp3.1"),
},
new string[][]
{
new string[] { "value", "framework", "--framework", "net", $"'net' is not a valid value for --framework. The possible values are:{NewLine} net5.0 {NewLine} netcoreapp2.1{NewLine} netcoreapp3.1" }
}
};
yield return new object[]
{
"foo --framework net --fake fake --OtherChoice fake",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group").WithChoiceParameter("framework", "netcoreapp2.1", "netcoreapp3.1").WithChoiceParameter("OtherChoice", "val1", "val2"),
new MockTemplateInfo("foo", identity: "foo.2", groupIdentity: "foo.group").WithChoiceParameter("framework", "net5.0").WithChoiceParameter("OtherChoice", "val1", "val2"),
},
new string?[][]
{
new string?[] { "value", "framework", "--framework", "net", $"'net' is not a valid value for --framework. The possible values are:{NewLine} net5.0 {NewLine} netcoreapp2.1{NewLine} netcoreapp3.1" },
new string?[] { "name", null, "--fake", null },
new string?[] { "name", null, "fake", null },
new string?[] { "value", "OtherChoice", "--OtherChoice", "fake", $"'fake' is not a valid value for --OtherChoice. The possible values are:{NewLine} val1{NewLine} val2" }
}
};
yield return new object[]
{
"foo --int fake",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group")
.WithParameter("int", paramType: "integer")
},
new string[][]
{
new string[] { "value", "int", "--int", "fake", "Cannot parse argument 'fake' for option '--int' as expected type 'Int64'." },
}
};
yield return new object[]
{
"foo --int",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group")
.WithParameter("int", paramType: "integer", defaultIfNoOptionValue: "fake")
},
new string?[][]
{
new string?[] { "value", "int", "--int", null, "Cannot parse default if option without value 'fake' for option '--int' as expected type 'Int64'." },
}
};
//TODO: does not work, see https://github.com/dotnet/command-line-api/issues/1474
//yield return new object[]
//{
// "foo",
// new MockTemplateInfo[]
// {
// new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group")
// .WithParameter("int", paramType: "integer", defaultValue: "fake")
// },
// new string[][]
// {
// new string[] { "value", "int", "--int", "fake", "expected-error" },
// }
//};
yield return new object[]
{
"foo --langVersion",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group").WithParameter("langVersion"),
new MockTemplateInfo("foo", identity: "foo.2", groupIdentity: "foo.group")
},
new string?[][]
{
new string?[] { "value", "langVersion", "--langVersion", null, "Required argument missing for option: '--langVersion'." }
}
};
yield return new object[]
{
"foo --fake",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group").WithParameter("langVersion")
},
new string?[][]
{
new string?[] { "name", null, "--fake", null, null }
}
};
yield return new object[]
{
"foo --fake value",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group").WithParameter("langVersion")
},
new string?[][]
{
new string?[] { "name", null, "--fake", null, null },
new string?[] { "name", null, "value", null, null }
}
};
yield return new object[]
{
"foo --language F# --include",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group").WithTag("language", "C#").WithParameter("include", "bool"),
new MockTemplateInfo("foo", identity: "foo.2", groupIdentity: "foo.group").WithTag("language", "F#")
},
new string?[][]
{
new string?[] { "name", null, "--include", null, null }
}
};
yield return new object[]
{
"foo --language F# --exclude",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group").WithTag("language", "C#").WithParameter("include", "bool"),
new MockTemplateInfo("foo", identity: "foo.2", groupIdentity: "foo.group").WithTag("language", "F#")
},
new string?[][]
{
new string?[] { "name", null, "--exclude", null, null }
}
};
yield return new object[]
{
"foo --int 6 --float 3.14 --hex 0x1A2F --bool --string stringtype --choice c1 --fake",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group")
.WithParameter("int", paramType: "integer")
.WithParameter("float", paramType: "float")
.WithParameter("hex", paramType: "hex")
.WithParameter("bool", paramType: "bool")
.WithParameter("string", paramType: "string")
.WithChoiceParameter("choice", "c1", "c2")
},
new string?[][]
{
new string?[] { "name", null, "--fake", null, null }
}
};
yield return new object[]
{
"foo --int 6 --float 3.14 --hex 0x1A2F --bool --string stringtype --choice c1 --fake value",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group")
.WithParameter("int", paramType: "integer")
.WithParameter("float", paramType: "float")
.WithParameter("hex", paramType: "hex")
.WithParameter("bool", paramType: "bool")
.WithParameter("string", paramType: "string")
.WithChoiceParameter("choice", "c1", "c2")
},
new string?[][]
{
new string?[] { "name", null, "--fake", null, null },
new string?[] { "name", null, "value", null, null }
}
};
yield return new object[]
{
"foo --language F# --int 6 --float 3.14 --hex 0x1A2F --bool --string stringtype --choice c1 --include",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group").WithTag("language", "C#")
.WithParameter("int", paramType: "integer")
.WithParameter("float", paramType: "float")
.WithParameter("hex", paramType: "hex")
.WithParameter("bool", paramType: "bool")
.WithParameter("string", paramType: "string")
.WithChoiceParameter("choice", "c1", "c2")
.WithParameter("include", "bool"),
new MockTemplateInfo("foo", identity: "foo.2", groupIdentity: "foo.group").WithTag("language", "F#")
.WithParameter("int", paramType: "integer")
.WithParameter("float", paramType: "float")
.WithParameter("hex", paramType: "hex")
.WithParameter("bool", paramType: "bool")
.WithParameter("string", paramType: "string")
.WithChoiceParameter("choice", "c1", "c2")
},
new string?[][]
{
new string?[] { "name", null, "--include", null, null }
}
};
yield return new object[]
{
"foo --language F# --int 6 --float 3.14 --hex 0x1A2F --bool --string stringtype --choice c1 --exclude",
new MockTemplateInfo[]
{
new MockTemplateInfo("foo", identity: "foo.1", groupIdentity: "foo.group").WithTag("language", "C#")
.WithParameter("int", paramType: "integer")
.WithParameter("float", paramType: "float")
.WithParameter("hex", paramType: "hex")
.WithParameter("bool", paramType: "bool")
.WithParameter("string", paramType: "string")
.WithChoiceParameter("choice", "c1", "c2")
.WithParameter("include", "bool"),
new MockTemplateInfo("foo", identity: "foo.2", groupIdentity: "foo.group").WithTag("language", "F#")
.WithParameter("int", paramType: "integer")
.WithParameter("float", paramType: "float")
.WithParameter("hex", paramType: "hex")
.WithParameter("bool", paramType: "bool")
.WithParameter("string", paramType: "string")
.WithChoiceParameter("choice", "c1", "c2")
},
new string?[][]
{
new string?[] { "name", null, "--exclude", null, null }
}
};
}
[Theory]
[MemberData(nameof(GetInvalidParametersTestData))]
// invalid params:
// [0] name / value - Kind
// [1] canonical
// [2] input format
// [3] param value
// [4] error message
internal void CanEvaluateInvalidParameters(string command, MockTemplateInfo[] templates, string?[][] expectedInvalidParams)
{
TemplateGroup templateGroup = TemplateGroup.FromTemplateList(
CliTemplateInfo.FromTemplateInfo(templates, A.Fake<IHostSpecificDataLoader>()))
.Single();
ICliTemplateEngineHost host = CliTestHostFactory.GetVirtualHost();
IEngineEnvironmentSettings settings = new EngineEnvironmentSettings(host, virtualizeSettings: true);
TemplatePackageManager templatePackageManager = A.Fake<TemplatePackageManager>();
NewCommand myCommand = (NewCommand)NewCommandFactory.Create("new", _ => host);
ParseResult parseResult = myCommand.Parse($" new {command}");
var args = InstantiateCommandArgs.FromNewCommandArgs(new NewCommandArgs(myCommand, parseResult));
HashSet<TemplateCommand> templateCommands = InstantiateCommand.GetTemplateCommand(args, settings, A.Fake<TemplatePackageManager>(), templateGroup);
Assert.Empty(templateCommands);
List<TemplateResult> templateMatchInfos = InstantiateCommand.CollectTemplateMatchInfo(args, settings, templatePackageManager, templateGroup);
List<InvalidTemplateOptionResult> invalidOptions = InstantiateCommand.GetInvalidOptions(templateMatchInfos);
Assert.Equal(expectedInvalidParams.Length, invalidOptions.Count);
foreach (string?[] invalidParam in expectedInvalidParams)
{
InvalidTemplateOptionResult.Kind expectedErrorKind = invalidParam[0] == "name"
? InvalidTemplateOptionResult.Kind.InvalidName
: InvalidTemplateOptionResult.Kind.InvalidValue;
string? expectedCanonicalName = invalidParam[1];
string expectedInputFormat = invalidParam[2] ?? throw new Exception("Input Format cannot be null");
string? expectedSpecifiedValue = invalidParam[3];
string? expectedErrorMessage = null;
if (invalidParam.Length == 5)
{
expectedErrorMessage = invalidParam[4];
}
InvalidTemplateOptionResult actualParam = invalidOptions.Single(param => param.InputFormat == expectedInputFormat);
Assert.Equal(expectedErrorKind, actualParam.ErrorKind);
Assert.Equal(expectedCanonicalName, actualParam.TemplateOption?.TemplateParameter.Name);
Assert.Equal(expectedInputFormat, actualParam.InputFormat);
Assert.Equal(expectedSpecifiedValue, actualParam.SpecifiedValue);
Assert.Equal(expectedErrorMessage, actualParam.ErrorMessage);
}
}
}
}
|