diff --git a/Microsoft.TemplateEngine.sln b/Microsoft.TemplateEngine.sln index 928a42175d..3d6a02719b 100644 --- a/Microsoft.TemplateEngine.sln +++ b/Microsoft.TemplateEngine.sln @@ -66,6 +66,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{B794BF86-4185-4DCE-AC86-C27D5D966B9B}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TemplateEngine.Authoring.TemplateVerifier", "src\Microsoft.TemplateEngine.Authoring.TemplateVerifier\Microsoft.TemplateEngine.Authoring.TemplateVerifier.csproj", "{12764D81-61A7-437A-90B6-9F245E43F457}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests", "test\Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests\Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests.csproj", "{B1DDA327-F55E-466A-AF3E-7F039B9B51A9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests", "test\Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests\Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests.csproj", "{D478568D-CA20-4331-9019-F585B564425E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TemplateEngine.Authoring.CLI.UnitTests", "test\Microsoft.TemplateEngine.Authoring.CLI.UnitTests\Microsoft.TemplateEngine.Authoring.CLI.UnitTests.csproj", "{E8B9226E-879F-495A-BDAD-2607844D048C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -388,6 +396,54 @@ Global {2FFDBB61-8AE8-468B-87D3-0D907D7C2FFE}.Release|x64.Build.0 = Release|Any CPU {2FFDBB61-8AE8-468B-87D3-0D907D7C2FFE}.Release|x86.ActiveCfg = Release|Any CPU {2FFDBB61-8AE8-468B-87D3-0D907D7C2FFE}.Release|x86.Build.0 = Release|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Debug|Any CPU.Build.0 = Debug|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Debug|x64.ActiveCfg = Debug|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Debug|x64.Build.0 = Debug|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Debug|x86.ActiveCfg = Debug|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Debug|x86.Build.0 = Debug|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Release|Any CPU.ActiveCfg = Release|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Release|Any CPU.Build.0 = Release|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Release|x64.ActiveCfg = Release|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Release|x64.Build.0 = Release|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Release|x86.ActiveCfg = Release|Any CPU + {12764D81-61A7-437A-90B6-9F245E43F457}.Release|x86.Build.0 = Release|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Debug|x64.ActiveCfg = Debug|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Debug|x64.Build.0 = Debug|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Debug|x86.ActiveCfg = Debug|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Debug|x86.Build.0 = Debug|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Release|Any CPU.Build.0 = Release|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Release|x64.ActiveCfg = Release|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Release|x64.Build.0 = Release|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Release|x86.ActiveCfg = Release|Any CPU + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9}.Release|x86.Build.0 = Release|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Debug|x64.ActiveCfg = Debug|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Debug|x64.Build.0 = Debug|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Debug|x86.ActiveCfg = Debug|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Debug|x86.Build.0 = Debug|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Release|Any CPU.Build.0 = Release|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Release|x64.ActiveCfg = Release|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Release|x64.Build.0 = Release|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Release|x86.ActiveCfg = Release|Any CPU + {D478568D-CA20-4331-9019-F585B564425E}.Release|x86.Build.0 = Release|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Debug|x64.ActiveCfg = Debug|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Debug|x64.Build.0 = Debug|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Debug|x86.ActiveCfg = Debug|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Debug|x86.Build.0 = Debug|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Release|Any CPU.Build.0 = Release|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Release|x64.ActiveCfg = Release|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Release|x64.Build.0 = Release|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Release|x86.ActiveCfg = Release|Any CPU + {E8B9226E-879F-495A-BDAD-2607844D048C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -419,6 +475,10 @@ Global {B0330A2C-3F10-4C46-97DF-13D187564F70} = {8B498D0C-F488-4B38-8A7D-B20BF9DB6F60} {BD758B10-A47F-4159-B9A1-997723AF7349} = {B794BF86-4185-4DCE-AC86-C27D5D966B9B} {2FFDBB61-8AE8-468B-87D3-0D907D7C2FFE} = {8B498D0C-F488-4B38-8A7D-B20BF9DB6F60} + {12764D81-61A7-437A-90B6-9F245E43F457} = {B794BF86-4185-4DCE-AC86-C27D5D966B9B} + {B1DDA327-F55E-466A-AF3E-7F039B9B51A9} = {8B498D0C-F488-4B38-8A7D-B20BF9DB6F60} + {D478568D-CA20-4331-9019-F585B564425E} = {8B498D0C-F488-4B38-8A7D-B20BF9DB6F60} + {E8B9226E-879F-495A-BDAD-2607844D048C} = {8B498D0C-F488-4B38-8A7D-B20BF9DB6F60} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6EA1A508-6033-4538-BF98-7F71B4E297AD} diff --git a/eng/Signing.props b/eng/Signing.props index 586fe4875a..f233f020f2 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -2,4 +2,20 @@ true + + + + + + + + + + + + + diff --git a/eng/dependabot/Packages.props b/eng/dependabot/Packages.props index a1d7c6cd52..00b8c1f170 100644 --- a/eng/dependabot/Packages.props +++ b/eng/dependabot/Packages.props @@ -31,7 +31,7 @@ - + diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommand.cs b/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommand.cs new file mode 100644 index 0000000000..8a41dce441 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommand.cs @@ -0,0 +1,204 @@ +// 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 System.CommandLine.Binding; +using System.CommandLine.Parsing; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.TemplateEngine.Authoring.TemplateVerifier; + +namespace Microsoft.TemplateEngine.Authoring.CLI.Commands.Verify +{ + internal class VerifyCommand : ExecutableCommand + { + private const string CommandName = "verify"; + + private readonly Argument _templateNameArgument = new("template-short-name") + { + Description = LocalizableStrings.command_verify_help_templateName_description, + // 0 for case where only path is specified + Arity = new ArgumentArity(1, 1) + }; + + private readonly Option _remainingArguments = new Option("--template-args") + { + Description = "Template specific arguments - all joined into single enquoted string. Any needed quotations of actual arguments has to be escaped.", + Arity = new ArgumentArity(0, 1) + }; + + private readonly Option _templatePathOption = new(new[] { "-p", "--template-path" }) + { + Description = LocalizableStrings.command_verify_help_templatePath_description, + }; + + private readonly Option _newCommandPathOption = new("--new-command-assembly") + { + Description = LocalizableStrings.command_verify_help_newCommandPath_description, + //TODO: do we have better way of distinguishing options that might rarely be needed? + // if not - we should probably add a link to more detailed help in the command description (mentioning that online help has additional options) + IsHidden = true + }; + + private readonly Option _templateOutputPathOption = new(new[] { "-o", "--output" }) + { + Description = LocalizableStrings.command_verify_help_outputPath_description, + }; + + private readonly Option _expectationsDirectoryOption = new(new[] { "-d", "--expectations-directory" }) + { + Description = LocalizableStrings.command_verify_help_expectationsDirPath_description, + }; + + private readonly Option _disableDiffToolOption = new("--disable-diff-tool") + { + Description = LocalizableStrings.command_verify_help_disableDiffTool_description, + }; + + private readonly Option _disableDefaultExcludePatternsOption = new("--disable-default-exclude-patterns") + { + Description = LocalizableStrings.command_verify_help_disableDefaultExcludes_description, + }; + + private readonly Option> _excludePatternOption = new("--exclude-pattern") + { + Description = LocalizableStrings.command_verify_help_customExcludes_description, + Arity = new ArgumentArity(0, 999) + }; + + private readonly Option _verifyCommandOutputOption = new("--verify-std") + { + Description = LocalizableStrings.command_verify_help_verifyOutputs_description, + }; + + private readonly Option _isCommandExpectedToFailOption = new("--fail-expected") + { + Description = LocalizableStrings.command_verify_help_expectFailure_description, + }; + + private readonly Option> _uniqueForOption = new("--unique-for") + { + Description = LocalizableStrings.command_verify_help_uniqueFor_description, + Arity = new ArgumentArity(0, 999), + AllowMultipleArgumentsPerToken = true, + }; + + public VerifyCommand(ILoggerFactory loggerFactory) + : base(CommandName, LocalizableStrings.command_verify_help_description, loggerFactory) + { + AddArgument(_templateNameArgument); + AddOption(_remainingArguments); + AddOption(_templatePathOption); + AddOption(_newCommandPathOption); + AddOption(_templateOutputPathOption); + AddOption(_expectationsDirectoryOption); + AddOption(_disableDiffToolOption); + AddOption(_disableDefaultExcludePatternsOption); + AddOption(_excludePatternOption); + AddOption(_verifyCommandOutputOption); + AddOption(_isCommandExpectedToFailOption); + FromAmongCaseInsensitive( + _uniqueForOption, + System.Enum.GetNames(typeof(UniqueForOption)) + .Where(v => !v.Equals(UniqueForOption.None.ToString(), StringComparison.OrdinalIgnoreCase)) + .ToArray()); + AddOption(_uniqueForOption); + } + + internal static VerifyCommandArgs ExtractArguments(VerifyCommand verifyCommand, ParseResult parseResult) + { + return new VerifyCommandArgs( + templateName: parseResult.GetValueForArgument(verifyCommand._templateNameArgument), + templateSpecificArgs: parseResult.GetValueForOption(verifyCommand._remainingArguments), + templatePath: parseResult.GetValueForOption(verifyCommand._templatePathOption), + dotnetNewCommandAssemblyPath: parseResult.GetValueForOption(verifyCommand._newCommandPathOption), + expectationsDirectory: parseResult.GetValueForOption(verifyCommand._expectationsDirectoryOption), + outputDirectory: parseResult.GetValueForOption(verifyCommand._templateOutputPathOption), + disableDiffTool: parseResult.GetValueForOption(verifyCommand._disableDiffToolOption), + disableDefaultVerificationExcludePatterns: parseResult.GetValueForOption(verifyCommand._disableDefaultExcludePatternsOption), + verificationExcludePatterns: parseResult.GetValueForOption(verifyCommand._excludePatternOption), + verifyCommandOutput: parseResult.GetValueForOption(verifyCommand._verifyCommandOutputOption), + isCommandExpectedToFail: parseResult.GetValueForOption(verifyCommand._isCommandExpectedToFailOption), + uniqueForOptions: parseResult.GetValueForOption(verifyCommand._uniqueForOption)); + } + + protected override async Task ExecuteAsync(VerifyCommandArgs args, CancellationToken cancellationToken = default) + { + Logger.LogInformation("Running the verification of {templateName}.", args.TemplateName); + + try + { + VerificationEngine engine = new VerificationEngine(LoggerFactory ?? NullLoggerFactory.Instance); + TemplateVerifierOptions options = new(templateName: args.TemplateName) + { + TemplatePath = args.TemplatePath, + TemplateSpecificArgs = args.TemplateSpecificArgs, + DisableDiffTool = args.DisableDiffTool, + DisableDefaultVerificationExcludePatterns = args.DisableDefaultVerificationExcludePatterns, + VerificationExcludePatterns = args.VerificationExcludePatterns, + DotnetNewCommandAssemblyPath = args.DotnetNewCommandAssemblyPath, + ExpectationsDirectory = args.ExpectationsDirectory, + OutputDirectory = args.OutputDirectory, + VerifyCommandOutput = args.VerifyCommandOutput, + IsCommandExpectedToFail = args.IsCommandExpectedToFail, + UniqueFor = args.UniqueFor, + }; + await engine.Execute( + options, + cancellationToken, + // We explicitly pass a path - so that the engine then process it and gets the current executing dir + // and treats it as a code base of caller of API (as in case of CLI usage we do not want to store + // expectation files in CLI sources dir) + Path.Combine(Environment.CurrentDirectory, "_") + ).ConfigureAwait(false); + return 0; + } + catch (Exception e) + { + Logger.LogError(LocalizableStrings.command_verify_error_failed); + Logger.LogError(e.Message); + TemplateVerificationException? ex = e as TemplateVerificationException; + return (int)(ex?.TemplateVerificationErrorCode ?? TemplateVerificationErrorCode.InternalError); + } + } + + protected override BinderBase GetModelBinder() => new VerifyModelBinder(this); + + /// + /// Case insensitive version for . + /// + private static void FromAmongCaseInsensitive(Option option, string[]? allowedValues = null, string? allowedHiddenValue = null) + { + allowedValues ??= Array.Empty(); + option.AddValidator(optionResult => ValidateAllowedValues(optionResult, allowedValues, allowedHiddenValue)); + option.AddCompletions(allowedValues); + } + + private static void ValidateAllowedValues(OptionResult optionResult, string[] allowedValues, string? allowedHiddenValue = null) + { + var invalidArguments = optionResult.Tokens.Where(token => !allowedValues.Append(allowedHiddenValue).Contains(token.Value, StringComparer.OrdinalIgnoreCase)).ToList(); + if (invalidArguments.Any()) + { + optionResult.ErrorMessage = string.Format( + LocalizableStrings.command_verify_error_unrecognizedArguments, + string.Join(", ", invalidArguments.Select(arg => $"'{arg.Value}'")), + string.Join(", ", allowedValues.Select(allowedValue => $"'{allowedValue}'"))); + } + } + + private class VerifyModelBinder : BinderBase + { + private readonly VerifyCommand _verifyCommand; + + internal VerifyModelBinder(VerifyCommand verifyCommand) + { + _verifyCommand = verifyCommand; + } + + protected override VerifyCommandArgs GetBoundValue(BindingContext bindingContext) + { + return VerifyCommand.ExtractArguments(_verifyCommand, bindingContext.ParseResult); + } + } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommandArgs.cs b/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommandArgs.cs new file mode 100644 index 0000000000..a6fb0b2cdd --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommandArgs.cs @@ -0,0 +1,150 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.RegularExpressions; +using Microsoft.TemplateEngine.Authoring.TemplateVerifier; + +namespace Microsoft.TemplateEngine.Authoring.CLI.Commands.Verify +{ + /// + /// Model class representing the arguments of . + /// + internal sealed class VerifyCommandArgs + { + public VerifyCommandArgs(string templateName, string? templateSpecificArgs) + { + TemplateName = templateName; + TemplateSpecificArgs = TokenizeJoinedArgs(templateSpecificArgs); + } + + public VerifyCommandArgs( + string templateName, + string? templatePath, + string? templateSpecificArgs, + string? dotnetNewCommandAssemblyPath, + string? expectationsDirectory, + string? outputDirectory, + bool? disableDiffTool, + bool? disableDefaultVerificationExcludePatterns, + IEnumerable? verificationExcludePatterns, + bool? verifyCommandOutput, + bool isCommandExpectedToFail, + IEnumerable? uniqueForOptions) + : this(templateName, templateSpecificArgs) + { + TemplatePath = templatePath; + DotnetNewCommandAssemblyPath = dotnetNewCommandAssemblyPath; + ExpectationsDirectory = expectationsDirectory; + OutputDirectory = outputDirectory; + DisableDiffTool = disableDiffTool; + DisableDefaultVerificationExcludePatterns = disableDefaultVerificationExcludePatterns; + VerificationExcludePatterns = verificationExcludePatterns; + VerifyCommandOutput = verifyCommandOutput; + IsCommandExpectedToFail = isCommandExpectedToFail; + UniqueFor = ToUniqueForOptionFlags(uniqueForOptions); + } + + /// + /// Gets the name of locally installed template. + /// + public string TemplateName { get; init; } + + /// + /// Gets the path to template.json file or containing directory. + /// + public string? TemplatePath { get; init; } + + /// + /// Gets the path to custom assembly implementing the new command. + /// + public string? DotnetNewCommandAssemblyPath { get; init; } + + /// + /// Gets the template specific arguments. + /// + public IEnumerable TemplateSpecificArgs { get; init; } + + /// + /// Gets the directory with expectation files. + /// + public string? ExpectationsDirectory { get; init; } + + /// + /// Gets the target directory to output the generated template. + /// + public string? OutputDirectory { get; init; } + + /// + /// If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + /// + public bool? DisableDiffTool { get; init; } + + /// + /// If set to true - all template output files will be verified, unless are specified. + /// Otherwise a default exclusions (to be documented - mostly binaries etc.). + /// + public bool? DisableDefaultVerificationExcludePatterns { get; init; } + + /// + /// Set of patterns defining files to be excluded from verification. + /// + public IEnumerable? VerificationExcludePatterns { get; init; } + + /// + /// If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + /// + public bool? VerifyCommandOutput { get; init; } + + /// + /// If set to true - 'dotnet new' command is expected to return nonzero return code. + /// Otherwise a zero error code and no error output is expected. + /// + public bool IsCommandExpectedToFail { get; init; } + + /// + /// Gets the Verifier expectations directory naming convention - by indicating which scenarios should be differentiated. + /// + public UniqueForOption? UniqueFor { get; init; } + + public static IEnumerable TokenizeJoinedArgs(string? joinedArgs) + { + if (string.IsNullOrEmpty(joinedArgs)) + { + return Enumerable.Empty(); + } + + if (!joinedArgs.Contains('"') && !joinedArgs.Contains('\'')) + { + return joinedArgs.Split().Where(s => !string.IsNullOrWhiteSpace(s)); + } + + return Regex.Matches(joinedArgs, @"[\""'].+?[\""']|[^ ]+") + .Cast() + .Select(m => m.Value) + .Select(RemoveEnclosingQuotation) + .Where(s => !string.IsNullOrWhiteSpace(s)); + } + + public static UniqueForOption? ToUniqueForOptionFlags(IEnumerable? uniqueForOptions) + { + return uniqueForOptions?.Aggregate(UniqueForOption.None, (a, b) => a | b); + } + + private static string RemoveEnclosingQuotation(string input) + { + int indexOfLast = input.Length - 1; + + if ( + indexOfLast >= 1 && + (input[0] == '"' && input[indexOfLast] == '"' || input[0] == '\'' && input[indexOfLast] == '\'') + ) + { + return input.Substring(1, indexOfLast - 1); + } + else + { + return input; + } + } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/Globals.cs b/src/Microsoft.TemplateEngine.Authoring.CLI/Globals.cs index 66de30e624..08fae9e6e6 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/Globals.cs +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/Globals.cs @@ -4,3 +4,4 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.TemplateEngine.Authoring.CLI.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.Designer.cs b/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.Designer.cs index 7aab621e7c..815cb30209 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.Designer.cs +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.Designer.cs @@ -161,6 +161,132 @@ internal static string command_export_log_templateJsonNotFound { } } + /// + /// Looks up a localized string similar to Verification Failed.. + /// + internal static string command_verify_error_failed { + get { + return ResourceManager.GetString("command_verify_error_failed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Argument(s) {0} are not recognized. Must be one of: {1}.. + /// + internal static string command_verify_error_unrecognizedArguments { + get { + return ResourceManager.GetString("command_verify_error_unrecognizedArguments", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Specifies pattern(s) defining files to be excluded from verification.. + /// + internal static string command_verify_help_customExcludes_description { + get { + return ResourceManager.GetString("command_verify_help_customExcludes_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Runs the template with specified arguments and compares the result with expectations files.. + /// + internal static string command_verify_help_description { + get { + return ResourceManager.GetString("command_verify_help_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If set to true - all template output files will be verified, unless --exclude-pattern option is used.. + /// + internal static string command_verify_help_disableDefaultExcludes_description { + get { + return ResourceManager.GetString("command_verify_help_disableDefaultExcludes_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If set to true - the diff tool won't be automatically started by the Verifier on verification failures.. + /// + internal static string command_verify_help_disableDiffTool_description { + get { + return ResourceManager.GetString("command_verify_help_disableDiffTool_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Specifies path to the directory with expectation files.. + /// + internal static string command_verify_help_expectationsDirPath_description { + get { + return ResourceManager.GetString("command_verify_help_expectationsDirPath_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If set to true - 'dotnet new' command is expected to return non-zero return code.. + /// + internal static string command_verify_help_expectFailure_description { + get { + return ResourceManager.GetString("command_verify_help_expectFailure_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Specifies the path to custom assembly implementing 'dotnet new' command.. + /// + internal static string command_verify_help_newCommandPath_description { + get { + return ResourceManager.GetString("command_verify_help_newCommandPath_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Specifies the path to target directory to output the generated template to.. + /// + internal static string command_verify_help_outputPath_description { + get { + return ResourceManager.GetString("command_verify_help_outputPath_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option.. + /// + internal static string command_verify_help_templateName_description { + get { + return ResourceManager.GetString("command_verify_help_templateName_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Specifies the path to the directory with template to be verified.. + /// + internal static string command_verify_help_templatePath_description { + get { + return ResourceManager.GetString("command_verify_help_templatePath_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated.. + /// + internal static string command_verify_help_uniqueFor_description { + get { + return ResourceManager.GetString("command_verify_help_uniqueFor_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files.. + /// + internal static string command_verify_help_verifyOutputs_description { + get { + return ResourceManager.GetString("command_verify_help_verifyOutputs_description", resourceCulture); + } + } + /// /// Looks up a localized string similar to "{0}" command has encountered an error. See the logs for more details.. /// diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.resx b/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.resx index e4212abebc..3f760fd527 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.resx +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.resx @@ -161,6 +161,55 @@ Do not localize: "template.json" Failed to find "template.json" file under the path "{0}". Do not localize: "template.json" + + Verification Failed. + + + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + + + Runs the template with specified arguments and compares the result with expectations files. + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + Specifies path to the directory with expectation files. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. {0} will be replaced by the command name. Such as: "export" command has encountered an error. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/Microsoft.TemplateEngine.Authoring.CLI.csproj b/src/Microsoft.TemplateEngine.Authoring.CLI/Microsoft.TemplateEngine.Authoring.CLI.csproj index e7cb35a7e3..8250fe767c 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/Microsoft.TemplateEngine.Authoring.CLI.csproj +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/Microsoft.TemplateEngine.Authoring.CLI.csproj @@ -16,10 +16,14 @@ + + + + diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/Program.cs b/src/Microsoft.TemplateEngine.Authoring.CLI/Program.cs index a64ee1f98f..f9867cfe16 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/Program.cs +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/Program.cs @@ -4,6 +4,7 @@ using System.CommandLine; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine.Authoring.CLI.Commands; +using Microsoft.TemplateEngine.Authoring.CLI.Commands.Verify; namespace Microsoft.TemplateEngine.Authoring.CLI { @@ -12,10 +13,10 @@ internal sealed class Program internal static async Task Main(string[] args) { using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); - ILogger logger = loggerFactory.CreateLogger(); RootCommand rootCommand = new("dotnet-template-authoring"); rootCommand.AddCommand(new LocalizeCommand(loggerFactory)); + rootCommand.AddCommand(new VerifyCommand(loggerFactory)); return await rootCommand.InvokeAsync(args).ConfigureAwait(false); } diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.cs.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.cs.xlf index d5883f51b8..d451e2ea19 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.cs.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.cs.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" Soubor „template.json“ se v cestě „{0}“ nepodařilo najít. Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. V příkazu {0} došlo k chybě. Další podrobnosti najdete v protokolech. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.de.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.de.xlf index f33dfac5c3..7f733b9dce 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.de.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.de.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" Die Datei "template.json" konnte unter dem Pfad "{0}" nicht gefunden werden. Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. Fehler beim Ausführen des Befehls "{0}". Weitere Informationen finden Sie in den Protokollen. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.es.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.es.xlf index d44b1edd42..a2b0f32928 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.es.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.es.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" No se pudo encontrar el archivo "template.json" bajo la ruta "{0}". Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. El comando "{0}" ha encontrado un error. Vea los registros para obtener más información. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.fr.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.fr.xlf index cd188c2870..0c44da946e 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.fr.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.fr.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" Échec de la recherche du fichier « template.jssur » sous le chemin d’accès «0{0} ». Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. La commande « {0} » a rencontré une erreur. Pour plus d’informations, consultez les journaux. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.it.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.it.xlf index 5ebaf4a8f5..492eac7bb9 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.it.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.it.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" Non è stato possibile trovare il file "template.json" nel percorso "{0}". Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. Si è verificato un errore durante il comando "{0}". Per altri dettagli, vedere i log. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ja.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ja.xlf index bd5aff2f55..512acdd8c4 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ja.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ja.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" パス "{0}" の下に "template.json" ファイルが見つかりません。 Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. "{0}" コマンドでエラーが発生しました。詳細については、ログを参照してください。 diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ko.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ko.xlf index 86c86d09ef..c1dc26907d 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ko.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ko.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" "{0}” 경로에서 "template.json" 파일을 찾지 못했습니다. Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. "{0}" 명령에 오류가 발생했습니다. 자세한 내용은 로그를 참조하세요. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pl.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pl.xlf index e9896887dd..e9d66c68c6 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pl.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pl.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" Nie można odnaleźć pliku „template.json” pod ścieżką „{0}”. Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. Wystąpił błąd przy poleceniu „{0}”. Zobacz dzienniki, aby uzyskać więcej szczegółów. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pt-BR.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pt-BR.xlf index b21e7dd7f7..3663145525 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pt-BR.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" Falhou em localizar o arquivo "template.json" no o caminho "{0}". Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. O comando "{0}" encontrou um erro. Veja os logs para mais detalhes. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ru.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ru.xlf index f8eb22b87e..d5d79055ff 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ru.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ru.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" Не удалось найти файл template.json в пути "{0}". Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. Команда "{0}" обнаружила ошибку. Дополнительные сведения см. в журналах. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.tr.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.tr.xlf index 463d3f5789..796bc4137d 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.tr.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.tr.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" "{0}" yolunda "template.json" dosyası bulunamadı. Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. "{0}" komutu bir hatayla karşılaştı. Daha fazla ayrıntı için günlüklere bakın. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hans.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hans.xlf index b14e82f316..d1890f2be7 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hans.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" 在路径“{0}”下未找到“template.json”文件。 Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. “{0}”命令遇到错误。如需了解详细信息,请参阅日志。 diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hant.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hant.xlf index 4126aed756..1c6beb21fb 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hant.xlf @@ -63,6 +63,76 @@ Do not localize: "template.json" 在路徑 "{0}" 下找不到 "template.json" 檔案。 Do not localize: "template.json" + + Verification Failed. + Verification Failed. + + + + Argument(s) {0} are not recognized. Must be one of: {1}. + Argument(s) {0} are not recognized. Must be one of: {1}. + {0} and {1} is both a list of arguments + + + Specifies pattern(s) defining files to be excluded from verification. + Specifies pattern(s) defining files to be excluded from verification. + + + + Runs the template with specified arguments and compares the result with expectations files. + Runs the template with specified arguments and compares the result with expectations files. + + + + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + If set to true - all template output files will be verified, unless --exclude-pattern option is used. + Do not translate 'true'. Do not translate '--exclude-pattern' + + + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + Do not translate 'true'. + + + If set to true - 'dotnet new' command is expected to return non-zero return code. + If set to true - 'dotnet new' command is expected to return non-zero return code. + Do not translate 'true'. Do not translate 'dotnet new' + + + Specifies path to the directory with expectation files. + Specifies path to the directory with expectation files. + + + + Specifies the path to custom assembly implementing 'dotnet new' command. + Specifies the path to custom assembly implementing 'dotnet new' command. + Do not translate 'dotnet new' + + + Specifies the path to target directory to output the generated template to. + Specifies the path to target directory to output the generated template to. + + + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. + Do not translate the '-p/--template-path' + + + Specifies the path to the directory with template to be verified. + Specifies the path to the directory with template to be verified. + + + + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + Sets the Verifier expectations directory naming convention, by indicating which scenarios should be differentiated. + + + + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + Do not translate 'true'. Do not translate 'dotnet new' + "{0}" command has encountered an error. See the logs for more details. "{0}" 命令發生錯誤。如需詳細資料,請參閱記錄檔。 diff --git a/src/Microsoft.TemplateEngine.Authoring.Tasks/Microsoft.TemplateEngine.Authoring.Tasks.csproj b/src/Microsoft.TemplateEngine.Authoring.Tasks/Microsoft.TemplateEngine.Authoring.Tasks.csproj index 50dfede5cf..907d1c4824 100644 --- a/src/Microsoft.TemplateEngine.Authoring.Tasks/Microsoft.TemplateEngine.Authoring.Tasks.csproj +++ b/src/Microsoft.TemplateEngine.Authoring.Tasks/Microsoft.TemplateEngine.Authoring.Tasks.csproj @@ -1,4 +1,4 @@ - + $(NETStandardTargetFramework) @@ -14,7 +14,6 @@ - diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/BasicCommand.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/BasicCommand.cs new file mode 100644 index 0000000000..7e37d7e992 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/BasicCommand.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.Logging; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier.Commands +{ + internal class BasicCommand : TestCommand + { + private readonly string _processName; + + public BasicCommand(ILogger log, string processName, params string[] args) : base(log) + { + _processName = processName; + Arguments.AddRange(args.Where(a => !string.IsNullOrWhiteSpace(a))); + } + + protected override SdkCommandSpec CreateCommand(IEnumerable args) + { + var sdkCommandSpec = new SdkCommandSpec() + { + FileName = _processName, + Arguments = args.ToList(), + WorkingDirectory = WorkingDirectory + }; + return sdkCommandSpec; + } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/CommandResultData.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/CommandResultData.cs new file mode 100644 index 0000000000..e8edebb75b --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/CommandResultData.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier.Commands +{ + internal class CommandResultData + { + public CommandResultData(int exitCode, string stdOut, string stdErr, string workingDirectory) + { + ExitCode = exitCode; + StdOut = stdOut; + StdErr = stdErr; + WorkingDirectory = workingDirectory; + } + + public CommandResultData(CommandResult commandResult) + : this(commandResult.ExitCode, commandResult.StdOut, commandResult.StdErr, commandResult.StartInfo.WorkingDirectory) + { } + + public int ExitCode { get; } + + public string StdOut { get; } + + public string StdErr { get; } + + public string WorkingDirectory { get; } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/CommandRunner.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/CommandRunner.cs new file mode 100644 index 0000000000..8b3ef8d524 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/CommandRunner.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier.Commands +{ + internal class CommandRunner : ICommandRunner + { + public CommandResultData RunCommand(TestCommand testCommand) + { + return new CommandResultData(testCommand.Execute()); + } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/DotnetCommand.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/DotnetCommand.cs new file mode 100644 index 0000000000..db84430f22 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/DotnetCommand.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.Logging; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier.Commands +{ + internal class DotnetCommand : TestCommand + { + private readonly string commandName; + + public DotnetCommand(ILogger log, string commandName, params string[] args) : base(log) + { + Arguments.Add(commandName); + Arguments.AddRange(args); + this.commandName = commandName; + } + + public DotnetCommand WithCustomHive(string? path = null) + { + path ??= CreateTemporaryFolder(); + Arguments.Add("--debug:custom-hive"); + Arguments.Add(path); + return this; + } + + protected override SdkCommandSpec CreateCommand(IEnumerable args) + { + var sdkCommandSpec = new SdkCommandSpec() + { + FileName = "dotnet", + Arguments = args.ToList(), + WorkingDirectory = WorkingDirectory + }; + return sdkCommandSpec; + } + + private static string CreateTemporaryFolder(string name = "") + { + string workingDir = Path.Combine(Path.GetTempPath(), "TemplateEngine.Tests", Guid.NewGuid().ToString(), name); + Directory.CreateDirectory(workingDir); + return workingDir; + } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/ICommandRunner.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/ICommandRunner.cs new file mode 100644 index 0000000000..a5344249db --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/ICommandRunner.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier.Commands +{ + internal interface ICommandRunner + { + CommandResultData RunCommand(TestCommand testCommand); + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/SdkCommandSpec.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/SdkCommandSpec.cs new file mode 100644 index 0000000000..1d8b34f50f --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/SdkCommandSpec.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier.Commands +{ + internal class SdkCommandSpec + { + public string? FileName { get; set; } + + public List Arguments { get; set; } = new List(); + + public Dictionary Environment { get; set; } = new Dictionary(); + + public List EnvironmentToRemove { get; } = new List(); + + public string? WorkingDirectory { get; set; } + + public Command ToCommand() + { + var process = new Process() + { + StartInfo = ToProcessStartInfo() + }; + var ret = new Command(process, trimtrailingNewlines: true); + return ret; + } + + public ProcessStartInfo ToProcessStartInfo() + { + var ret = new ProcessStartInfo(); + ret.FileName = FileName; + ret.Arguments = EscapeArgs(); + ret.UseShellExecute = false; + foreach (var kvp in Environment) + { + ret.Environment[kvp.Key] = kvp.Value; + } + foreach (var envToRemove in EnvironmentToRemove) + { + ret.Environment.Remove(envToRemove); + } + + if (WorkingDirectory != null) + { + ret.WorkingDirectory = WorkingDirectory; + } + + return ret; + } + + private string EscapeArgs() + { + // Note: this doesn't handle invoking .cmd files via "cmd /c" on Windows, which probably won't be necessary here + // If it is, refer to the code in WindowsExePreferredCommandSpecFactory in Microsoft.DotNet.Cli.Utils + return ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(Arguments); + } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/TestCommand.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/TestCommand.cs new file mode 100644 index 0000000000..c04e586b4d --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Commands/TestCommand.cs @@ -0,0 +1,118 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.Extensions.Logging; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier.Commands +{ + internal abstract class TestCommand + { + protected TestCommand(ILogger log) + { + Log = log; + } + + public ILogger Log { get; } + + public string? WorkingDirectory { get; set; } + + public List Arguments { get; set; } = new List(); + + public List EnvironmentToRemove { get; } = new List(); + + // These only work via Execute(), not when using GetProcessStartInfo() + public Action? CommandOutputHandler { get; set; } + + public Action? ProcessStartedHandler { get; set; } + + protected Dictionary Environment { get; set; } = new Dictionary(); + + public TestCommand WithEnvironmentVariable(string name, string value) + { + Environment[name] = value; + return this; + } + + public TestCommand WithWorkingDirectory(string workingDirectory) + { + WorkingDirectory = workingDirectory; + return this; + } + + public ProcessStartInfo GetProcessStartInfo(params string[] args) + { + var commandSpec = CreateCommandSpec(args); + + var psi = commandSpec.ToProcessStartInfo(); + + return psi; + } + + public CommandResult Execute(params string[] args) + { + IEnumerable enumerableArgs = args; + return Execute(enumerableArgs); + } + + public virtual CommandResult Execute(IEnumerable args) + { + var command = CreateCommandSpec(args) + .ToCommand() + .CaptureStdOut() + .CaptureStdErr(); + + if (CommandOutputHandler != null) + { + command.OnOutputLine(CommandOutputHandler); + } + + var result = ((Command)command).Execute(ProcessStartedHandler); + + Log.LogInformation($"> {result.StartInfo.FileName} {result.StartInfo.Arguments}"); + Log.LogInformation(result.StdOut); + + if (!string.IsNullOrEmpty(result.StdErr)) + { + Log.LogWarning("StdErr:"); + Log.LogWarning(result.StdErr); + } + + if (result.ExitCode != 0) + { + Log.LogInformation($"Exit Code: {result.ExitCode}"); + } + + return result; + } + + protected abstract SdkCommandSpec CreateCommand(IEnumerable args); + + private SdkCommandSpec CreateCommandSpec(IEnumerable args) + { + var commandSpec = CreateCommand(args); + foreach (var kvp in Environment) + { + commandSpec.Environment[kvp.Key] = kvp.Value; + } + + foreach (var envToRemove in EnvironmentToRemove) + { + commandSpec.EnvironmentToRemove.Add(envToRemove); + } + + if (WorkingDirectory != null) + { + commandSpec.WorkingDirectory = WorkingDirectory; + } + + if (Arguments.Any()) + { + commandSpec.Arguments = Arguments.Concat(commandSpec.Arguments).ToList(); + } + + return commandSpec; + } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Globals.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Globals.cs new file mode 100644 index 0000000000..974d69b2b9 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Globals.cs @@ -0,0 +1,8 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/IPhysicalFileSystemEx.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/IPhysicalFileSystemEx.cs new file mode 100644 index 0000000000..abb48993ce --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/IPhysicalFileSystemEx.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.TemplateEngine.Abstractions.PhysicalFileSystem; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier +{ + internal interface IPhysicalFileSystemEx : IPhysicalFileSystem + { + /// + /// Same behavior as . + /// + Task ReadAllTextAsync(string path, CancellationToken cancellationToken = default); + + /// + /// Same behavior as . + /// + Task WriteAllTextAsync(string path, string? contents, CancellationToken cancellationToken = default); + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/LocalizableStrings.Designer.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/LocalizableStrings.Designer.cs new file mode 100644 index 0000000000..06fe6f9322 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/LocalizableStrings.Designer.cs @@ -0,0 +1,144 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class LocalizableStrings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal LocalizableStrings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.TemplateEngine.Authoring.TemplateVerifier.LocalizableStrings", typeof(LocalizableStrings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Template installation expected to pass but it had exit code '{0}'.. + /// + internal static string VerificationEngine_Error_InstallUnexpectedFail { + get { + return ResourceManager.GetString("VerificationEngine_Error_InstallUnexpectedFail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File extension passed to scrubber should not start with dot.. + /// + internal static string VerificationEngine_Error_ScrubberExtension { + get { + return ResourceManager.GetString("VerificationEngine_Error_ScrubberExtension", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case.. + /// + internal static string VerificationEngine_Error_StdOutFolderExists { + get { + return ResourceManager.GetString("VerificationEngine_Error_StdOutFolderExists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Template name is mandatory, but was not supplied.. + /// + internal static string VerificationEngine_Error_TemplateNameMandatory { + get { + return ResourceManager.GetString("VerificationEngine_Error_TemplateNameMandatory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected error encountered.. + /// + internal static string VerificationEngine_Error_Unexpected { + get { + return ResourceManager.GetString("VerificationEngine_Error_Unexpected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Template instantiation expected to pass but it had exit code '{0}'.. + /// + internal static string VerificationEngine_Error_UnexpectedFail { + get { + return ResourceManager.GetString("VerificationEngine_Error_UnexpectedFail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Template instantiation expected to fail but it passed.. + /// + internal static string VerificationEngine_Error_UnexpectedPass { + get { + return ResourceManager.GetString("VerificationEngine_Error_UnexpectedPass", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1}. + /// + internal static string VerificationEngine_Error_UnexpectedStdErr { + get { + return ResourceManager.GetString("VerificationEngine_Error_UnexpectedStdErr", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The working directory already exists and is not empty.. + /// + internal static string VerificationEngine_Error_WorkDirExists { + get { + return ResourceManager.GetString("VerificationEngine_Error_WorkDirExists", resourceCulture); + } + } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/LocalizableStrings.resx b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/LocalizableStrings.resx new file mode 100644 index 0000000000..2f13e36175 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/LocalizableStrings.resx @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Template installation expected to pass but it had exit code '{0}'. + + + File extension passed to scrubber should not start with dot. + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + + + Unexpected error encountered. + + + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + + diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Microsoft.TemplateEngine.Authoring.TemplateVerifier.csproj b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Microsoft.TemplateEngine.Authoring.TemplateVerifier.csproj new file mode 100644 index 0000000000..8a30a6cf50 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/Microsoft.TemplateEngine.Authoring.TemplateVerifier.csproj @@ -0,0 +1,46 @@ + + + + Library + $(NETCoreTargetFramework) + The verification engine for the templates for .NET template engine. + true + enable + enable + true + true + true + + + + + + + + + + + + + + + + + + + + + + True + True + LocalizableStrings.resx + + + + + + ResXFileCodeGenerator + LocalizableStrings.Designer.cs + + + diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PhysicalFileSystemEx.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PhysicalFileSystemEx.cs new file mode 100644 index 0000000000..fb9e245e88 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PhysicalFileSystemEx.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.TemplateEngine.Utils; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier +{ + internal class PhysicalFileSystemEx : PhysicalFileSystem, IPhysicalFileSystemEx + { + public Task ReadAllTextAsync(string path, CancellationToken cancellationToken = default) + => File.ReadAllTextAsync(path, cancellationToken); + + public Task WriteAllTextAsync(string path, string? contents, CancellationToken cancellationToken = default) + => File.WriteAllTextAsync(path, contents, cancellationToken); + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PublicAPI.Shipped.txt b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PublicAPI.Shipped.txt new file mode 100644 index 0000000000..ab058de62d --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PublicAPI.Shipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PublicAPI.Unshipped.txt b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PublicAPI.Unshipped.txt new file mode 100644 index 0000000000..294d43a6a6 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PublicAPI.Unshipped.txt @@ -0,0 +1,66 @@ +Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition +Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition.AddScrubber(System.Action! scrubber, string? extension = null) -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition! +Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition.GeneralScrubber.get -> System.Action? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition.ScrubbersDefinition() -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition.ScrubbersDefinition(System.Action! scrubber, string? extension = null) -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition.ScrubersByExtension.get -> System.Collections.Generic.Dictionary!>! +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode.InstallFailed = 106 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode.InstantiationFailed = 100 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode.InternalError = 70 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode.InvalidOption = 127 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode.TemplateDoesNotExist = 103 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode.VerificationFailed = 65 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode.WorkingDirectoryExists = 73 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationException +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationException.TemplateVerificationErrorCode.get -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationException.TemplateVerificationErrorCode.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationException.TemplateVerificationException(string! message, Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode templateVerificationErrorCode) -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationException.TemplateVerificationException(string! message, Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationErrorCode templateVerificationErrorCode, System.Exception! inner) -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationException.TemplateVerificationException(System.Runtime.Serialization.SerializationInfo! info, System.Runtime.Serialization.StreamingContext context) -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.CustomDirectoryVerifier.get -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.VerifyDirectory? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.CustomScrubbers.get -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DisableDefaultVerificationExcludePatterns.get -> bool? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DisableDefaultVerificationExcludePatterns.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DisableDiffTool.get -> bool? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DisableDiffTool.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DotnetNewCommandAssemblyPath.get -> string? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DotnetNewCommandAssemblyPath.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.ExpectationsDirectory.get -> string? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.ExpectationsDirectory.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.IsCommandExpectedToFail.get -> bool? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.IsCommandExpectedToFail.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.OutputDirectory.get -> string? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.OutputDirectory.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.StandardOutputFileExtension.get -> string? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.StandardOutputFileExtension.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.TemplateName.get -> string! +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.TemplateName.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.TemplatePath.get -> string? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.TemplatePath.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.TemplateSpecificArgs.get -> System.Collections.Generic.IEnumerable? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.TemplateSpecificArgs.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.TemplateVerifierOptions(string! templateName) -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.UniqueFor.get -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.UniqueFor.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.VerificationExcludePatterns.get -> System.Collections.Generic.IEnumerable? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.VerificationExcludePatterns.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.VerifyCommandOutput.get -> bool? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.VerifyCommandOutput.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.WithCustomDirectoryVerifier(Microsoft.TemplateEngine.Authoring.TemplateVerifier.VerifyDirectory! verifier) -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions! +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.WithCustomScrubbers(Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition! scrubbers) -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions! +Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption +Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption.Architecture = 1 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption +Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption.None = 0 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption +Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption.OsPlatform = 2 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption +Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption.Runtime = 4 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption +Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption.RuntimeAndVersion = 8 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption +Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption.TargetFramework = 16 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption +Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption.TargetFrameworkAndVersion = 32 -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption +Microsoft.TemplateEngine.Authoring.TemplateVerifier.VerificationEngine +Microsoft.TemplateEngine.Authoring.TemplateVerifier.VerificationEngine.Execute(Microsoft.Extensions.Options.IOptions! optionsAccessor, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken), string! sourceFile = "") -> System.Threading.Tasks.Task! +Microsoft.TemplateEngine.Authoring.TemplateVerifier.VerificationEngine.VerificationEngine(Microsoft.Extensions.Logging.ILogger! logger) -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.VerificationEngine.VerificationEngine(Microsoft.Extensions.Logging.ILoggerFactory! loggerFactory) -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.VerifyDirectory +static readonly Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition.Empty -> Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition! \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/ScrubbersDefinition.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/ScrubbersDefinition.cs new file mode 100644 index 0000000000..20c38b41f4 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/ScrubbersDefinition.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier; + +public class ScrubbersDefinition +{ + public static readonly ScrubbersDefinition Empty = new(); + + public ScrubbersDefinition() { } + + public ScrubbersDefinition(Action scrubber, string? extension = null) + { + this.AddScrubber(scrubber, extension); + } + + public Dictionary> ScrubersByExtension { get; private set; } = new Dictionary>(); + + public Action? GeneralScrubber { get; private set; } + + public ScrubbersDefinition AddScrubber(Action scrubber, string? extension = null) + { + if (object.ReferenceEquals(this, Empty)) + { + return new ScrubbersDefinition().AddScrubber(scrubber, extension); + } + + if (string.IsNullOrWhiteSpace(extension)) + { + GeneralScrubber += scrubber; + } + // This is to get the same behavior as Verify.NET + else if (extension.Trim().StartsWith('.')) + { + throw new TemplateVerificationException(LocalizableStrings.VerificationEngine_Error_ScrubberExtension, TemplateVerificationErrorCode.InvalidOption); + } + else + { + ScrubersByExtension[extension.Trim()] = scrubber; + } + + return this; + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerificationErrorCode.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerificationErrorCode.cs new file mode 100644 index 0000000000..6a5a675435 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerificationErrorCode.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier +{ + /// + /// VerificationEngine error codes in thrown . Correspond to VerificationCommand exit codes. + /// + /// Exit codes based on + /// * https://tldp.org/LDP/abs/html/exitcodes.html + /// * https://github.com/openbsd/src/blob/master/include/sysexits.h. + /// related reference: dotnet new exit codes: https://aka.ms/templating-exit-codes. + /// Future exit codes should be allocated in a range of 107 - 113. If not sufficient, a range of 79 - 99 may be used as well. + /// + public enum TemplateVerificationErrorCode + { + /// + /// Indicates failed verification - assertions defined for the scenarios were not met. + /// E.g. unexpected exit code, stdout/stderr output or created templates content. + /// + VerificationFailed = 65, + + /// + /// Unexpected internal error in . This might indicate a bug. + /// + InternalError = 70, + + /// + /// Configured working directory already exists and is not empty - so instantiation cannot proceed without destructive changes. + /// + WorkingDirectoryExists = 73, + + /// + /// Selected template (via name or path) was not found. + /// + TemplateDoesNotExist = 103, + + /// + /// The template instantiation failed and results were not created. + /// + InstantiationFailed = 100, + + /// + /// Installation/Uninstallation Failed - Processing issues. + /// + InstallFailed = 106, + + /// + /// Unrecognized option(s) and/or argument(s) for a command. + /// + InvalidOption = 127, + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerificationException.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerificationException.cs new file mode 100644 index 0000000000..77bc6a33f1 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerificationException.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.Serialization; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier +{ + [Serializable] + public class TemplateVerificationException : Exception + { + public TemplateVerificationException(string message, TemplateVerificationErrorCode templateVerificationErrorCode) : base(message) + { + TemplateVerificationErrorCode = templateVerificationErrorCode; + } + + public TemplateVerificationException(string message, TemplateVerificationErrorCode templateVerificationErrorCode, Exception inner) : base(message, inner) + { + TemplateVerificationErrorCode = templateVerificationErrorCode; + } + + protected TemplateVerificationException( + SerializationInfo info, + StreamingContext context) : base(info, context) + { + } + + public TemplateVerificationErrorCode TemplateVerificationErrorCode { get; init; } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerifierOptions.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerifierOptions.cs new file mode 100644 index 0000000000..e425cac20b --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerifierOptions.cs @@ -0,0 +1,122 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.Options; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier +{ + /// + /// Configuration bag for the class. + /// + public class TemplateVerifierOptions : IOptions + { + /// + /// Initializes a new instance of the class. + /// + /// + public TemplateVerifierOptions(string templateName) => TemplateName = templateName; + + /// + /// Gets the name of locally installed template. + /// + public string TemplateName { get; init; } + + /// + /// Gets the path to template.json file or containing directory. + /// + public string? TemplatePath { get; init; } + + /// + /// Gets the path to custom assembly implementing the new command. + /// + public string? DotnetNewCommandAssemblyPath { get; init; } + + /// + /// Gets the template specific arguments. + /// + public IEnumerable? TemplateSpecificArgs { get; init; } + + /// + /// Gets the directory with expectation files. + /// + public string? ExpectationsDirectory { get; init; } + + /// + /// If set to true - 'dotnet new' command standard output and error contents will be verified along with the produced template files. + /// + public bool? VerifyCommandOutput { get; init; } + + /// + /// If set to true - 'dotnet new' command is expected to return nonzero return code. + /// Otherwise a zero error code and no error output is expected. + /// + public bool? IsCommandExpectedToFail { get; init; } + + /// + /// If set to true - the diff tool won't be automatically started by the Verifier on verification failures. + /// + public bool? DisableDiffTool { get; init; } + + /// + /// If set to true - all template output files will be verified, unless are specified. + /// Otherwise a default exclusions (to be documented - mostly binaries etc.). + /// + public bool? DisableDefaultVerificationExcludePatterns { get; init; } + + /// + /// Set of patterns defining files to be excluded from verification. + /// + public IEnumerable? VerificationExcludePatterns { get; init; } + + /// + /// Gets the target directory to output the generated template. + /// + public string? OutputDirectory { get; init; } + + /// + /// Gets the Verifier expectations directory naming convention - by indicating which scenarios should be differentiated. + /// + public UniqueForOption? UniqueFor { get; init; } + + /// + /// Gets the delegates that perform custom scrubbing of template output contents before verifications. + /// + public ScrubbersDefinition? CustomScrubbers { get; private set; } + + /// + /// Gets the delegate that performs custom verification of template output contents. + /// + public VerifyDirectory? CustomDirectoryVerifier { get; private set; } + + /// + /// Gets the extension of autogeneratedfiles with stdout and stderr content. + /// + public string? StandardOutputFileExtension { get; init; } + + TemplateVerifierOptions IOptions.Value => this; + + /// + /// Adds a custom scrubber definition. + /// The scrubber definition can alter the template content (globally or based on the file extension), before the verifications occur. + /// + /// + /// + public TemplateVerifierOptions WithCustomScrubbers(ScrubbersDefinition scrubbers) + { + this.CustomScrubbers = scrubbers; + return this; + } + + /// + /// Adds on optional custom verifier implementation. + /// If custom verifier is provided, no default verifications of content will be performed - the caller is responsible for performing the verifications. + /// + /// + /// + public TemplateVerifierOptions WithCustomDirectoryVerifier(VerifyDirectory verifier) + { + this.CustomDirectoryVerifier = verifier; + return this; + } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/UniqueForOption.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/UniqueForOption.cs new file mode 100644 index 0000000000..d6788bb4ac --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/UniqueForOption.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier +{ + [Flags] + public enum UniqueForOption + { + None = 0, + Architecture = 1, + OsPlatform = 2, + Runtime = 4, + RuntimeAndVersion = 8, + TargetFramework = 16, + TargetFrameworkAndVersion = 32 + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/VerificationEngine.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/VerificationEngine.cs new file mode 100644 index 0000000000..5848ee370b --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/VerificationEngine.cs @@ -0,0 +1,405 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.TemplateEngine.Authoring.TemplateVerifier.Commands; +using Microsoft.TemplateEngine.Utils; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier +{ + public class VerificationEngine + { + private static readonly IReadOnlyList _defaultVerificationExcludePatterns = new List() + { + @"obj/*", + @"obj\*", + @"bin/*", + @"bin\*", + "*.exe", + "*.dll", + "*.", + "*.exe", + }; + + private readonly ILogger _logger; + private readonly ILoggerFactory? _loggerFactory; + private readonly ICommandRunner _commandRunner = new CommandRunner(); + private readonly IPhysicalFileSystemEx _fileSystem = new PhysicalFileSystemEx(); + + static VerificationEngine() + { + // Customize diff output of verifier + VerifyDiffPlex.Initialize(OutputType.Compact); + VerifierSettings.UseSplitModeForUniqueDirectory(); + } + + public VerificationEngine(ILogger logger) + { + _logger = logger; + } + + public VerificationEngine(ILoggerFactory loggerFactory) + : this(loggerFactory.CreateLogger(typeof(VerificationEngine))) + { + _loggerFactory = loggerFactory; + } + + internal VerificationEngine(ICommandRunner commandRunner, ILogger logger) + : this(logger) + { + _commandRunner = commandRunner; + } + + public async Task Execute( + IOptions optionsAccessor, + CancellationToken cancellationToken = default, + [CallerFilePath] string sourceFile = "") + { + if (optionsAccessor == null) + { + throw new ArgumentNullException(nameof(optionsAccessor)); + } + + TemplateVerifierOptions options = optionsAccessor.Value; + + CommandResultData commandResult = RunDotnetNewCommand(options, _commandRunner, _loggerFactory, _logger); + + if (options.IsCommandExpectedToFail ?? false) + { + if (commandResult.ExitCode == 0) + { + throw new TemplateVerificationException( + LocalizableStrings.VerificationEngine_Error_UnexpectedPass, + TemplateVerificationErrorCode.VerificationFailed); + } + } + else + { + if (commandResult.ExitCode != 0) + { + throw new TemplateVerificationException( + string.Format(LocalizableStrings.VerificationEngine_Error_UnexpectedFail, commandResult.ExitCode), + TemplateVerificationErrorCode.InstantiationFailed); + } + + // We do not expect stderr in passing command. + // However if verification of stdout and stderr is opted-in - we will let that verification validate the stderr content + if (!(options.VerifyCommandOutput ?? false) && !string.IsNullOrEmpty(commandResult.StdErr)) + { + throw new TemplateVerificationException( + string.Format( + LocalizableStrings.VerificationEngine_Error_UnexpectedStdErr, + Environment.NewLine, + commandResult.StdErr), + TemplateVerificationErrorCode.InstantiationFailed); + } + } + + await VerifyResult(options, commandResult, string.IsNullOrEmpty(sourceFile) ? string.Empty : Path.GetDirectoryName(sourceFile)!) + .ConfigureAwait(false); + } + + internal static Task CreateVerificationTask( + string contentDir, + string callerDir, + TemplateVerifierOptions options, + IPhysicalFileSystemEx fileSystem) + { + List exclusionsList = (options.DisableDefaultVerificationExcludePatterns ?? false) + ? new() + : new(_defaultVerificationExcludePatterns); + + if (options.VerificationExcludePatterns != null) + { + exclusionsList.AddRange(options.VerificationExcludePatterns); + } + + List globs = exclusionsList.Select(pattern => Glob.Parse(pattern)).ToList(); + + if (options.CustomDirectoryVerifier != null) + { + return options.CustomDirectoryVerifier( + contentDir, + new Lazy>( + GetVerificationContent(contentDir, globs, options.CustomScrubbers, fileSystem))); + } + + VerifySettings verifySettings = new(); + + if (options.CustomScrubbers != null) + { + if (options.CustomScrubbers.GeneralScrubber != null) + { + verifySettings.AddScrubber(options.CustomScrubbers.GeneralScrubber); + } + + foreach (var pair in options.CustomScrubbers.ScrubersByExtension) + { + verifySettings.AddScrubber(pair.Key, pair.Value); + } + } + + verifySettings.UseTypeName(options.TemplateName); + string expectationsDir = options.ExpectationsDirectory ?? "VerifyExpectations"; + if (!string.IsNullOrEmpty(callerDir) && !Path.IsPathRooted(expectationsDir)) + { + expectationsDir = Path.Combine(callerDir, expectationsDir); + } + verifySettings.UseDirectory(expectationsDir); + verifySettings.UseMethodName(EncodeArgsAsPath(options.TemplateSpecificArgs)); + + if ((options.UniqueFor ?? UniqueForOption.None) != UniqueForOption.None) + { + foreach (UniqueForOption value in Enum.GetValues(typeof(UniqueForOption))) + { + if ((options.UniqueFor & value) == value) + { + switch (value) + { + case UniqueForOption.None: + break; + case UniqueForOption.Architecture: + verifySettings.UniqueForArchitecture(); + break; + case UniqueForOption.OsPlatform: + verifySettings.UniqueForOSPlatform(); + break; + case UniqueForOption.Runtime: + verifySettings.UniqueForRuntime(); + break; + case UniqueForOption.RuntimeAndVersion: + verifySettings.UniqueForRuntimeAndVersion(); + break; + case UniqueForOption.TargetFramework: + verifySettings.UniqueForTargetFramework(); + break; + case UniqueForOption.TargetFrameworkAndVersion: + verifySettings.UniqueForTargetFrameworkAndVersion(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + } + } + + if (options.DisableDiffTool ?? false) + { + verifySettings.DisableDiff(); + } + + return Verifier.VerifyDirectory( + contentDir, + (filePath) => !globs.Any(g => g.IsMatch(filePath)), + settings: verifySettings); + } + + private static string EncodeArgsAsPath(IEnumerable? args) + { + if (args == null || !args.Any()) + { + return string.Empty; + } + + Regex r = new Regex(string.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars())))); + return r.Replace(string.Join('#', args), string.Empty); + } + + private static CommandResultData RunDotnetNewCommand(TemplateVerifierOptions options, ICommandRunner commandRunner, ILoggerFactory? loggerFactory, ILogger logger) + { + // Create temp folder and instantiate there + string workingDir = options.OutputDirectory ?? Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + if (Directory.Exists(workingDir) && Directory.EnumerateFileSystemEntries(workingDir).Any()) + { + throw new TemplateVerificationException(LocalizableStrings.VerificationEngine_Error_WorkDirExists, TemplateVerificationErrorCode.WorkingDirectoryExists); + } + + Directory.CreateDirectory(workingDir); + ILogger commandLogger = loggerFactory?.CreateLogger(typeof(DotnetCommand)) ?? logger; + string? customHiveLocation = null; + + if (!string.IsNullOrEmpty(options.TemplatePath)) + { + customHiveLocation = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName(), "home"); + var installCommand = + new DotnetCommand(commandLogger, "new", "install", options.TemplatePath) + .WithCustomHive(customHiveLocation) + .WithWorkingDirectory(workingDir); + + CommandResultData installCommandResult = commandRunner.RunCommand(installCommand); + + if (installCommandResult.ExitCode != 0) + { + throw new TemplateVerificationException( + string.Format(LocalizableStrings.VerificationEngine_Error_InstallUnexpectedFail, installCommandResult.ExitCode), + TemplateVerificationErrorCode.InstantiationFailed); + } + } + + List cmdArgs = new(); + if (!string.IsNullOrEmpty(options.DotnetNewCommandAssemblyPath)) + { + cmdArgs.Add(options.DotnetNewCommandAssemblyPath); + } + cmdArgs.Add(options.TemplateName); + if (options.TemplateSpecificArgs != null) + { + cmdArgs.AddRange(options.TemplateSpecificArgs); + } + + if (!string.IsNullOrEmpty(customHiveLocation)) + { + cmdArgs.Add("--debug:custom-hive"); + cmdArgs.Add(customHiveLocation); + } + else + { + cmdArgs.Add("--debug:ephemeral-hive"); + } + + // let's make sure the template outputs are named and placed deterministically + if (!cmdArgs.Select(arg => arg.Trim()) + .Any(arg => new[] { "-n", "--name" }.Contains(arg, StringComparer.OrdinalIgnoreCase))) + { + cmdArgs.Add("-n"); + cmdArgs.Add(options.TemplateName); + } + if (!cmdArgs.Select(arg => arg.Trim()) + .Any(arg => new[] { "-o", "--output" }.Contains(arg, StringComparer.OrdinalIgnoreCase))) + { + cmdArgs.Add("-o"); + cmdArgs.Add(options.TemplateName); + } + + var command = new DotnetCommand(loggerFactory?.CreateLogger(typeof(DotnetCommand)) ?? logger, "new", cmdArgs.ToArray()) + .WithWorkingDirectory(workingDir); + var result = commandRunner.RunCommand(command); + if (!string.IsNullOrEmpty(customHiveLocation)) + { + Directory.Delete(customHiveLocation, true); + } + return result; + } + + private static void DummyMethod() + { } + + private static async IAsyncEnumerable<(string FilePath, string ScrubbedContent)> GetVerificationContent( + string contentDir, + List globs, + ScrubbersDefinition? scrubbers, + IPhysicalFileSystemEx fileSystem) + { + foreach (string filePath in fileSystem.EnumerateFiles(contentDir, "*", SearchOption.AllDirectories)) + { + if (globs.Any(g => g.IsMatch(filePath))) + { + continue; + } + + string content = await fileSystem.ReadAllTextAsync(filePath).ConfigureAwait(false); + + if (scrubbers != null) + { + string extension = Path.GetExtension(filePath); + // This is to get the same behavior as Verify.NET + if (extension.Length > 0) + { + extension = extension[1..]; + } + StringBuilder? sb = null; + + if (!string.IsNullOrEmpty(extension) && scrubbers.ScrubersByExtension.TryGetValue(extension, out Action? scrubber)) + { + sb = new StringBuilder(content); + scrubber(sb); + } + + if (scrubbers.GeneralScrubber != null) + { + sb = sb ?? new StringBuilder(content); + scrubbers.GeneralScrubber(sb); + } + + if (sb != null) + { + content = sb.ToString(); + } + } + + yield return new(filePath, content); + } + } + + private async Task VerifyResult(TemplateVerifierOptions args, CommandResultData commandResultData, string callerDir) + { + UsesVerifyAttribute a = new UsesVerifyAttribute(); + // https://github.com/VerifyTests/Verify/blob/d8cbe38f527d6788ecadd6205c82803bec3cdfa6/src/Verify.Xunit/Verifier.cs#L10 + // need to simulate execution from tests + var v = DummyMethod; + MethodInfo mi = v.Method; + a.Before(mi); + + if (args.VerifyCommandOutput ?? false) + { + if (_fileSystem.DirectoryExists(Path.Combine(commandResultData.WorkingDirectory, SpecialFiles.StandardStreamsDir))) + { + throw new TemplateVerificationException( + string.Format( + LocalizableStrings.VerificationEngine_Error_StdOutFolderExists, + SpecialFiles.StandardStreamsDir), + TemplateVerificationErrorCode.InternalError); + } + + _fileSystem.CreateDirectory(Path.Combine(commandResultData.WorkingDirectory, SpecialFiles.StandardStreamsDir)); + + await _fileSystem.WriteAllTextAsync( + Path.Combine(commandResultData.WorkingDirectory, SpecialFiles.StandardStreamsDir, SpecialFiles.StdOut + (args.StandardOutputFileExtension ?? SpecialFiles.DefaultExtension)), + commandResultData.StdOut) + .ConfigureAwait(false); + + await _fileSystem.WriteAllTextAsync( + Path.Combine(commandResultData.WorkingDirectory, SpecialFiles.StandardStreamsDir, SpecialFiles.StdErr + (args.StandardOutputFileExtension ?? SpecialFiles.DefaultExtension)), + commandResultData.StdErr) + .ConfigureAwait(false); + } + + Task verifyTask = CreateVerificationTask(commandResultData.WorkingDirectory, callerDir, args, _fileSystem); + + try + { + await verifyTask.ConfigureAwait(false); + } + catch (Exception e) + { + if (e is TemplateVerificationException) + { + throw; + } + if (e.GetType().Name == "VerifyException") + { + throw new TemplateVerificationException(e.Message, TemplateVerificationErrorCode.VerificationFailed); + } + else + { + _logger.LogError(e, LocalizableStrings.VerificationEngine_Error_Unexpected); + throw; + } + } + } + + private static class SpecialFiles + { + public const string StandardStreamsDir = "std-streams"; + public const string StdOut = "stdout"; + public const string StdErr = "stderr"; + public const string DefaultExtension = ".txt"; + public static readonly string[] FileNames = { StdOut, StdErr }; + } + } +} diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/VerifyDirectory.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/VerifyDirectory.cs new file mode 100644 index 0000000000..9612b2054c --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/VerifyDirectory.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier; + +/// +/// Delegate signature for performing custom directory content verifications. +/// Expectable verification failures should be signaled with . +/// API provider can either perform content enumeration, skipping and scrubbing by themselves (then the second argument can be ignored) +/// or the contentFetcher can be awaited to get the content of files - filtered by exclusion patterns and scrubbed by scrubbers. +/// +/// +/// +/// +public delegate Task VerifyDirectory(string contentDirectory, Lazy> contentFetcher); diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.cs.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.cs.xlf new file mode 100644 index 0000000000..bf14b01923 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.cs.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.de.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.de.xlf new file mode 100644 index 0000000000..1313fa12b5 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.de.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.es.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.es.xlf new file mode 100644 index 0000000000..5b705cebdc --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.es.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.fr.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.fr.xlf new file mode 100644 index 0000000000..0094d0c9c7 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.fr.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.it.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.it.xlf new file mode 100644 index 0000000000..6078316e39 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.it.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.ja.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.ja.xlf new file mode 100644 index 0000000000..b2de952bf6 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.ja.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.ko.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.ko.xlf new file mode 100644 index 0000000000..8afaac8f26 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.ko.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.pl.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.pl.xlf new file mode 100644 index 0000000000..ab145ca527 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.pl.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.pt-BR.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.pt-BR.xlf new file mode 100644 index 0000000000..5f67ef0a9a --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.pt-BR.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.ru.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.ru.xlf new file mode 100644 index 0000000000..4914bd0a68 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.ru.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.tr.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.tr.xlf new file mode 100644 index 0000000000..f52ec73632 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.tr.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.zh-Hans.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.zh-Hans.xlf new file mode 100644 index 0000000000..b2445f8d93 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.zh-Hans.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.zh-Hant.xlf b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.zh-Hant.xlf new file mode 100644 index 0000000000..42f012f204 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/xlf/LocalizableStrings.zh-Hant.xlf @@ -0,0 +1,52 @@ + + + + + + Template installation expected to pass but it had exit code '{0}'. + Template installation expected to pass but it had exit code '{0}'. + + + + File extension passed to scrubber should not start with dot. + File extension passed to scrubber should not start with dot. + + + + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + The folder [{0}] should not exist in the template output - cannot verify stdout/stderr in such case. + {0} is a folder path + + + Template name is mandatory, but was not supplied. + Template name is mandatory, but was not supplied. + + + + Unexpected error encountered. + Unexpected error encountered. + + + + Template instantiation expected to pass but it had exit code '{0}'. + Template instantiation expected to pass but it had exit code '{0}'. + {0} is an exit code number + + + Template instantiation expected to fail but it passed. + Template instantiation expected to fail but it passed. + + + + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + Template instantiation expected not to have any stderr output, but stderr output was encountered:{0}{1} + {0} is newline, {1} is the standard error content + + + The working directory already exists and is not empty. + The working directory already exists and is not empty. + + + + + \ No newline at end of file diff --git a/src/Microsoft.TemplateEngine.Utils/AsyncLazy.cs b/src/Microsoft.TemplateEngine.Utils/AsyncLazy.cs new file mode 100644 index 0000000000..e7e5faef33 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Utils/AsyncLazy.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.TemplateEngine.Utils +{ + /// + /// Provides support for asynchronous lazy initialization. + /// + /// The type to be lazily initialized. + public class AsyncLazy : Lazy> + { + // inspired by https://devblogs.microsoft.com/pfxteam/asynclazyt/ + + /// + /// Creates a lazy type that performs the value construction asynchronously on a first access. + /// + /// Synchronous value factory that will be executed asynchronously on first access in separate task. + public AsyncLazy(Func valueFactory) + : base(() => Task.Factory.StartNew(valueFactory, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)) + { } + + /// + /// Creates a lazy type that performs the value construction asynchronously on a first access. + /// + /// Asynchronous value factory that will be executed on a first access. + public AsyncLazy(Func> taskFactory) + : base(() => Task.Factory.StartNew( + () => taskFactory(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default) + .Unwrap()) + { } + + /// + /// The awaiter to be awaited in order to trigger asynchronous value creation. + /// + /// + public TaskAwaiter GetAwaiter() { return Value.GetAwaiter(); } + } +} diff --git a/src/Microsoft.TemplateEngine.Utils/PublicAPI.Unshipped.txt b/src/Microsoft.TemplateEngine.Utils/PublicAPI.Unshipped.txt index 5f282702bb..14d64ba4ce 100644 --- a/src/Microsoft.TemplateEngine.Utils/PublicAPI.Unshipped.txt +++ b/src/Microsoft.TemplateEngine.Utils/PublicAPI.Unshipped.txt @@ -1 +1,4 @@ - \ No newline at end of file +Microsoft.TemplateEngine.Utils.AsyncLazy +Microsoft.TemplateEngine.Utils.AsyncLazy.AsyncLazy(System.Func!>! taskFactory) -> void +Microsoft.TemplateEngine.Utils.AsyncLazy.AsyncLazy(System.Func! valueFactory) -> void +Microsoft.TemplateEngine.Utils.AsyncLazy.GetAwaiter() -> System.Runtime.CompilerServices.TaskAwaiter \ No newline at end of file diff --git a/test/Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests/ExportCommandFailureTests.cs b/test/Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests/ExportCommandFailureTests.cs index 7cbb137100..623229588e 100644 --- a/test/Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests/ExportCommandFailureTests.cs +++ b/test/Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests/ExportCommandFailureTests.cs @@ -3,7 +3,6 @@ using System.Globalization; using Microsoft.TemplateEngine.TestHelper.Commands; -using Xunit; using Xunit.Abstractions; namespace Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests diff --git a/test/Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests/VerifyCommandTests.cs b/test/Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests/VerifyCommandTests.cs new file mode 100644 index 0000000000..cca64ae001 --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests/VerifyCommandTests.cs @@ -0,0 +1,214 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using FluentAssertions; +using Microsoft.TemplateEngine.Authoring.TemplateVerifier; +using Microsoft.TemplateEngine.TestHelper; +using Microsoft.TemplateEngine.TestHelper.Commands; +using Microsoft.TemplateEngine.Tests; +using Xunit.Abstractions; + +namespace Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests +{ + [UsesVerify] + public class VerifyCommandTests : TestBase + { + private readonly ITestOutputHelper _log; + + public VerifyCommandTests(ITestOutputHelper log) + { + _log = log; + } + + [Fact] + public void VerifyCommandFullDevLoop() + { + // dots issue https://github.com/VerifyTests/Verify/issues/658 + string workingDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + string expectationsDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + string templateOutputDir = "path with spaces"; + + var cmd = new BasicCommand( + _log, + "dotnet", + Path.GetFullPath("Microsoft.TemplateEngine.Authoring.CLI.dll"), + "verify", + "console", + "--template-args", + "--use-program-main -o \"" + templateOutputDir + "\" --no-restore", + "--verify-std", + "-o", + workingDir, + "--expectations-directory", + expectationsDir, + "--disable-diff-tool", + "--unique-for", + "architecture", + "--unique-for", + "RuntimeAndVersion"); + + cmd.Execute() + .Should() + .ExitWith((int)TemplateVerificationErrorCode.VerificationFailed) + .And.HaveStdOutContaining("Verification Failed."); + + // Assert template created + Directory.Exists(Path.Combine(workingDir, templateOutputDir)).Should().BeTrue(); + File.Exists(Path.Combine(workingDir, templateOutputDir, "console.csproj")).Should().BeTrue(); + File.Exists(Path.Combine(workingDir, templateOutputDir, "Program.cs")).Should().BeTrue(); + + // Assert verification files created + Directory.Exists(expectationsDir).Should().BeTrue(); + Directory.GetDirectories(expectationsDir).Length.Should().Be(2); + //for simplicity move to the created dir + expectationsDir = Directory.GetDirectories(expectationsDir).Single(d => d.EndsWith(".received", StringComparison.Ordinal)); + File.Exists(Path.Combine(expectationsDir, templateOutputDir, "console.csproj")).Should().BeTrue(); + File.Exists(Path.Combine(expectationsDir, templateOutputDir, "Program.cs")).Should().BeTrue(); + File.Exists(Path.Combine(expectationsDir, "std-streams", "stdout.txt")).Should().BeTrue(); + File.Exists(Path.Combine(expectationsDir, "std-streams", "stderr.txt")).Should().BeTrue(); + Directory.GetFiles(expectationsDir, "*", SearchOption.AllDirectories).Length.Should().Be(4); + // .verified files are only created when diff tool is used - that is however turned off in CI + //File.Exists(Path.Combine(expectationsDir, "console.console.csproj.verified.csproj")).Should().BeTrue(); + //File.Exists(Path.Combine(expectationsDir, "console.Program.cs.verified.cs")).Should().BeTrue(); + //File.Exists(Path.Combine(expectationsDir, "console.StdOut.verified.txt")).Should().BeTrue(); + //File.Exists(Path.Combine(expectationsDir, "console.StdErr.verified.txt")).Should().BeTrue(); + + // .verified files are only created when diff tool is used - that is however turned off in CI + //File.ReadAllText(Path.Combine(expectationsDir, "console.console.csproj.verified.csproj")).Should().BeEmpty(); + //File.ReadAllText(Path.Combine(expectationsDir, "console.Program.cs.verified.cs")).Should().BeEmpty(); + //File.ReadAllText(Path.Combine(expectationsDir, "console.StdOut.verified.txt")).Should().BeEmpty(); + //File.ReadAllText(Path.Combine(expectationsDir, "console.StdErr.verified.txt")).Should().BeEmpty(); + File.ReadAllText(Path.Combine(expectationsDir, templateOutputDir, "console.csproj").UnixifyLineBreaks()).Should() + .BeEquivalentTo(File.ReadAllText(Path.Combine(workingDir, templateOutputDir, "console.csproj")).UnixifyLineBreaks()); + File.ReadAllText(Path.Combine(expectationsDir, templateOutputDir, "Program.cs").UnixifyLineBreaks()).Should() + .BeEquivalentTo(File.ReadAllText(Path.Combine(workingDir, templateOutputDir, "Program.cs")).UnixifyLineBreaks()); + + // Accept changes + string verifiedDir = expectationsDir.Replace(".received", ".verified", StringComparison.Ordinal); + Directory.Delete(verifiedDir, false); + Directory.Move(expectationsDir, verifiedDir); + + //reset the expectations dir to where it was before previous run + expectationsDir = Path.GetDirectoryName(expectationsDir)!; + + // And run again same scenario - verification should succeed now + string workingDir2 = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + var cmd2 = new BasicCommand( + _log, + "dotnet", + Path.GetFullPath("Microsoft.TemplateEngine.Authoring.CLI.dll"), + "verify", + "console", + "--template-args", + "--use-program-main -o \"" + templateOutputDir + "\" --no-restore", + "--verify-std", + "-o", + workingDir2, + "--expectations-directory", + expectationsDir, + "--unique-for", + "architecture", + "--unique-for", + "RuntimeAndVersion"); + + cmd2.Execute() + .Should() + .Pass() + .And.HaveStdOutContaining("Running the verification of console.") + .And.NotHaveStdErr(); + + Directory.Delete(workingDir, true); + Directory.Delete(workingDir2, true); + Directory.Delete(expectationsDir, true); + } + + [Fact] + public void VerifyCommandFullDevLoopWithNotInstalledTemplate() + { + // dots issue https://github.com/VerifyTests/Verify/issues/658 + string workingDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + string expectationsDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + string templateShortName = "TestAssets.SampleTestTemplate"; + string templateOutputDir = templateShortName; + + //get the template location + string executingAssemblyPath = this.GetType().Assembly.Location; + string templateLocation = Path.Combine(TestTemplatesLocation, "TestTemplate"); + + var cmd = new BasicCommand( + _log, + "dotnet", + Path.GetFullPath("Microsoft.TemplateEngine.Authoring.CLI.dll"), + "verify", + templateShortName, + "--template-path", + templateLocation, + "--template-args", + "--paramB true", + "--verify-std", + "-o", + workingDir, + "--expectations-directory", + expectationsDir, + "--disable-diff-tool"); + + cmd.Execute() + .Should() + .ExitWith((int)TemplateVerificationErrorCode.VerificationFailed) + .And.HaveStdOutContaining("Verification Failed."); + + // Assert template created + Directory.Exists(Path.Combine(workingDir, templateOutputDir)).Should().BeTrue(); + File.Exists(Path.Combine(workingDir, templateOutputDir, "Test.cs")).Should().BeTrue(); + + // Assert verification files created + Directory.Exists(expectationsDir).Should().BeTrue(); + Directory.GetDirectories(expectationsDir).Length.Should().Be(2); + //for simplicity move to the created dir + expectationsDir = Directory.GetDirectories(expectationsDir).Single(d => d.EndsWith(".received", StringComparison.Ordinal)); + File.Exists(Path.Combine(expectationsDir, templateOutputDir, "Test.cs")).Should().BeTrue(); + File.Exists(Path.Combine(expectationsDir, "std-streams", "stdout.txt")).Should().BeTrue(); + File.Exists(Path.Combine(expectationsDir, "std-streams", "stderr.txt")).Should().BeTrue(); + Directory.GetFiles(expectationsDir, "*", SearchOption.AllDirectories).Length.Should().Be(3); + + File.ReadAllText(Path.Combine(expectationsDir, templateOutputDir, "Test.cs").UnixifyLineBreaks()).Should() + .BeEquivalentTo(File.ReadAllText(Path.Combine(workingDir, templateOutputDir, "Test.cs")).UnixifyLineBreaks()); + + // Accept changes + string verifiedDir = expectationsDir.Replace(".received", ".verified", StringComparison.Ordinal); + Directory.Delete(verifiedDir, false); + Directory.Move(expectationsDir, verifiedDir); + + //reset the expectations dir to where it was before previous run + expectationsDir = Path.GetDirectoryName(expectationsDir)!; + + // And run again same scenario - verification should succeed now + string workingDir2 = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + var cmd2 = new BasicCommand( + _log, + "dotnet", + Path.GetFullPath("Microsoft.TemplateEngine.Authoring.CLI.dll"), + "verify", + templateShortName, + "--template-path", + templateLocation, + "--template-args", + "--paramB true", + "--verify-std", + "-o", + workingDir2, + "--expectations-directory", + expectationsDir); + + cmd2.Execute() + .Should() + .Pass() + .And.HaveStdOutContaining(string.Format("Running the verification of {0}.", templateShortName)) + .And.NotHaveStdErr(); + + Directory.Delete(workingDir, true); + Directory.Delete(workingDir2, true); + Directory.Delete(expectationsDir, true); + } + } +} diff --git a/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/Microsoft.TemplateEngine.Authoring.CLI.UnitTests.csproj b/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/Microsoft.TemplateEngine.Authoring.CLI.UnitTests.csproj new file mode 100644 index 0000000000..92aab69eda --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/Microsoft.TemplateEngine.Authoring.CLI.UnitTests.csproj @@ -0,0 +1,14 @@ + + + $(NETCoreTargetFramework) + false + enable + enable + + + + + + + + diff --git a/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/VerifyCommandArgsTests.cs b/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/VerifyCommandArgsTests.cs new file mode 100644 index 0000000000..8017674a03 --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/VerifyCommandArgsTests.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using FluentAssertions; +using Microsoft.TemplateEngine.Authoring.CLI.Commands.Verify; + +namespace Microsoft.TemplateEngine.Authoring.CLI.UnitTests +{ + public class VerifyCommandArgsTests + { + [Theory] + [InlineData(null, new string[] { })] + [InlineData(" ", new string[] { })] + [InlineData(" a b c", new string[] { "a", "b", "c" })] + [InlineData(" abc ", new string[] { "abc" })] + [InlineData("a \"b c \" d ", new string[] { "a", "b c ", "d" })] + [InlineData("aa \" bb cc \"dd", new string[] { "aa", " bb cc ", "dd" })] + [InlineData("aa q= 'bb cc'dd", new string[] { "aa", "q=", "bb cc", "dd" })] + public void OnTokenizeJoinedArgsResultIsExpected(string? input, IEnumerable expectedOutput) + { + var result = VerifyCommandArgs.TokenizeJoinedArgs(input); + result.Should().BeEquivalentTo(expectedOutput, options => options.WithStrictOrdering()); + } + } +} diff --git a/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/VerifyCommandTests.cs b/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/VerifyCommandTests.cs new file mode 100644 index 0000000000..cd8577e5b9 --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/VerifyCommandTests.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Concurrent; +using System.CommandLine; +using FluentAssertions; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.TemplateEngine.Authoring.CLI.Commands.Verify; +using Microsoft.TemplateEngine.Authoring.TemplateVerifier; + +namespace Microsoft.TemplateEngine.Authoring.CLI.UnitTests +{ + public class VerifyCommandTests + { + public static IEnumerable CanParseVerifyCommandArgsData => + new object?[][] + { + new object[] + { + "someName -p path --template-args \" a b cc\" --disable-diff-tool", + new VerifyCommandArgs( + "someName", + " a b cc") + { + TemplatePath = "path", + DisableDiffTool = true, + DisableDefaultVerificationExcludePatterns = false, + VerificationExcludePatterns = Enumerable.Empty(), + VerifyCommandOutput = false, + IsCommandExpectedToFail = false, + UniqueFor = UniqueForOption.None, + } + }, + new object[] + { + "someName -p path --template-args \" a \'b cc\'\" --unique-for Runtime", + new VerifyCommandArgs( + "someName", + " a \"b cc\"") + { + TemplatePath = "path", + DisableDiffTool = false, + DisableDefaultVerificationExcludePatterns = false, + VerificationExcludePatterns = Enumerable.Empty(), + VerifyCommandOutput = false, + IsCommandExpectedToFail = false, + UniqueFor = UniqueForOption.Runtime, + } + }, + + new object[] + { + "someName", + new VerifyCommandArgs( + "someName", + null) + { + DisableDiffTool = false, + DisableDefaultVerificationExcludePatterns = false, + VerificationExcludePatterns = Enumerable.Empty(), + VerifyCommandOutput = false, + IsCommandExpectedToFail = false, + UniqueFor = UniqueForOption.None, + } + }, + new object[] + { + "someName --new-command-assembly a\\b\\c.dll", + new VerifyCommandArgs( + "someName", + null) + { + DotnetNewCommandAssemblyPath = "a\\b\\c.dll", + DisableDiffTool = false, + DisableDefaultVerificationExcludePatterns = false, + VerificationExcludePatterns = Enumerable.Empty(), + VerifyCommandOutput = false, + IsCommandExpectedToFail = false, + UniqueFor = UniqueForOption.None, + } + }, + }; + + [Theory] + [MemberData(nameof(CanParseVerifyCommandArgsData))] + internal void CanParseVerifyCommandArgs(string command, VerifyCommandArgs expVerifyCommandArgs) + { + VerifyCommand verifyCommand = new VerifyCommand(NullLoggerFactory.Instance); + + ParseResult parseResult = verifyCommand.Parse(command); + + VerifyCommandArgs args = VerifyCommand.ExtractArguments(verifyCommand, parseResult); + + args.Should().BeEquivalentTo(expVerifyCommandArgs); + } + } +} diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/ExampleTemplateTest.cs b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/ExampleTemplateTest.cs new file mode 100644 index 0000000000..78e5ed28da --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/ExampleTemplateTest.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.Logging; +using Microsoft.TemplateEngine.TestHelper; +using Microsoft.TemplateEngine.Tests; +using Xunit.Abstractions; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests +{ + public class ExampleTemplateTest : TestBase + { + private readonly ILogger _log; + + public ExampleTemplateTest(ITestOutputHelper log) + { + _log = new XunitLoggerProvider(log).CreateLogger("TestRun"); + } + + [Fact] + public async void VerificationEngineSampleDogfoodTest() + { + string workingDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + string templateShortName = "TestAssets.SampleTestTemplate"; + + //get the template location + string executingAssemblyPath = this.GetType().Assembly.Location; + string templateLocation = Path.Combine(TestTemplatesLocation, "TestTemplate"); + + TemplateVerifierOptions options = new TemplateVerifierOptions(templateName: templateShortName) + { + TemplateSpecificArgs = new string[] { "--paramB", "true" }, + TemplatePath = templateLocation, + ExpectationsDirectory = "Expectations", + OutputDirectory = workingDir, + VerifyCommandOutput = true, + UniqueFor = UniqueForOption.RuntimeAndVersion, + } + .WithCustomScrubbers( + ScrubbersDefinition.Empty + .AddScrubber(sb => sb.Replace("B is enabled", "*******")) + ); + + VerificationEngine engine = new VerificationEngine(_log); + await engine.Execute(options); + } + } +} diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.DotNet7_0.verified/TestAssets.SampleTestTemplate/Test.cs b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.DotNet7_0.verified/TestAssets.SampleTestTemplate/Test.cs new file mode 100644 index 0000000000..e68913f9bb --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.DotNet7_0.verified/TestAssets.SampleTestTemplate/Test.cs @@ -0,0 +1,6 @@ + +// value of paramA: false +// value of paramB: true + + + // ******* diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.DotNet7_0.verified/std-streams/stderr.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.DotNet7_0.verified/std-streams/stderr.txt new file mode 100644 index 0000000000..5f282702bb --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.DotNet7_0.verified/std-streams/stderr.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.DotNet7_0.verified/std-streams/stdout.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.DotNet7_0.verified/std-streams/stdout.txt new file mode 100644 index 0000000000..9e2d2f7ea3 --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.DotNet7_0.verified/std-streams/stdout.txt @@ -0,0 +1 @@ +The template "SampleTestTemplate" was created successfully. \ No newline at end of file diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests.csproj b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests.csproj new file mode 100644 index 0000000000..db7748bf8e --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests.csproj @@ -0,0 +1,24 @@ + + + $(NETCoreTargetFramework) + enable + enable + + + + + + + + + + + + + + + + + + + diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/VerificationEngineTests.cs b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/VerificationEngineTests.cs new file mode 100644 index 0000000000..b0000bfe19 --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/VerificationEngineTests.cs @@ -0,0 +1,150 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using FluentAssertions; +using Microsoft.Extensions.Logging; +using Microsoft.TemplateEngine.TestHelper; +using Xunit.Abstractions; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests +{ + public class VerificationEngineTests + { + private readonly ILogger _log; + + public VerificationEngineTests(ITestOutputHelper log) + { + _log = new XunitLoggerProvider(log).CreateLogger("TestRun"); + } + + [Fact] + public async void VerificationEngineFullDevLoop() + { + string workingDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + string expectationsDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + string templateDir = "path with spaces"; + + TemplateVerifierOptions options = new TemplateVerifierOptions(templateName: "console") + { + TemplateSpecificArgs = new string[] { "--use-program-main", "-o", templateDir, "--no-restore" }, + DisableDiffTool = true, + ExpectationsDirectory = expectationsDir, + OutputDirectory = workingDir, + VerifyCommandOutput = true, + UniqueFor = UniqueForOption.OsPlatform | UniqueForOption.OsPlatform, + }; + + VerificationEngine engine = new VerificationEngine(_log); + Func executeTask = () => engine.Execute(options); + await executeTask + .Should() + .ThrowAsync() + .Where(e => e.TemplateVerificationErrorCode == TemplateVerificationErrorCode.VerificationFailed); + + // Assert template created + Directory.Exists(Path.Combine(workingDir, templateDir)).Should().BeTrue(); + File.Exists(Path.Combine(workingDir, templateDir, "console.csproj")).Should().BeTrue(); + File.Exists(Path.Combine(workingDir, templateDir, "Program.cs")).Should().BeTrue(); + + // Assert verification files created + Directory.Exists(expectationsDir).Should().BeTrue(); + Directory.GetDirectories(expectationsDir).Length.Should().Be(2); + //for simplicity move to the received dir + expectationsDir = Directory.GetDirectories(expectationsDir).Single(d => d.EndsWith(".received", StringComparison.Ordinal)); + File.Exists(Path.Combine(expectationsDir, templateDir, "console.csproj")).Should().BeTrue(); + File.Exists(Path.Combine(expectationsDir, templateDir, "Program.cs")).Should().BeTrue(); + File.Exists(Path.Combine(expectationsDir, "std-streams", "stdout.txt")).Should().BeTrue(); + File.Exists(Path.Combine(expectationsDir, "std-streams", "stderr.txt")).Should().BeTrue(); + Directory.GetFiles(expectationsDir, "*", SearchOption.AllDirectories).Length.Should().Be(4); + + File.ReadAllText(Path.Combine(expectationsDir, templateDir, "console.csproj").UnixifyLineBreaks()).Should() + .BeEquivalentTo(File.ReadAllText(Path.Combine(workingDir, templateDir, "console.csproj")).UnixifyLineBreaks()); + File.ReadAllText(Path.Combine(expectationsDir, templateDir, "Program.cs").UnixifyLineBreaks()).Should() + .BeEquivalentTo(File.ReadAllText(Path.Combine(workingDir, templateDir, "Program.cs")).UnixifyLineBreaks()); + + // Accept changes + string verifiedDir = expectationsDir.Replace(".received", ".verified", StringComparison.Ordinal); + Directory.Delete(verifiedDir, false); + Directory.Move(expectationsDir, verifiedDir); + + //reset the expectations dir to where it was before previous run + expectationsDir = Path.GetDirectoryName(expectationsDir)!; + + // And run again same scenario - verification should succeed now + string workingDir2 = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + + TemplateVerifierOptions options2 = new TemplateVerifierOptions(templateName: "console") + { + TemplateSpecificArgs = new string[] { "--use-program-main", "-o", templateDir, "--no-restore" }, + DisableDiffTool = true, + ExpectationsDirectory = expectationsDir, + OutputDirectory = workingDir2, + VerifyCommandOutput = true, + UniqueFor = UniqueForOption.OsPlatform | UniqueForOption.OsPlatform, + }; + + Func executeTask2 = () => engine.Execute(options2); + await executeTask2 + .Should() + .NotThrowAsync(); + + Directory.Delete(workingDir, true); + Directory.Delete(workingDir2, true); + Directory.Delete(expectationsDir, true); + } + + [Fact] + public async void VerificationEngineCustomVerifier() + { + string workingDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + string templateDir = "path with spaces"; + + TemplateVerifierOptions options = new TemplateVerifierOptions(templateName: "console") + { + TemplateSpecificArgs = new string[] { "--use-program-main", "-o", templateDir, "--no-restore" }, + DisableDiffTool = true, + OutputDirectory = workingDir, + VerificationExcludePatterns = new[] { "*.cs" }, + VerifyCommandOutput = true, + UniqueFor = UniqueForOption.OsPlatform | UniqueForOption.OsPlatform, + } + .WithCustomScrubbers( + ScrubbersDefinition.Empty + .AddScrubber(sb => sb.Replace("Donut", "Veggies"), "txt") + .AddScrubber(sb => sb.Replace(DateTime.UtcNow.ToString("yyyy-MM-dd"), "2000-01-01")) + ) + .WithCustomDirectoryVerifier( + async (content, contentFetcher) => + { + await foreach (var file in contentFetcher.Value) + { + if (Path.GetExtension(file.FilePath).Equals(".cs")) + { + throw new Exception(".cs files should be excluded per VerificationExcludePatterns"); + } + + if (Path.GetFileName(file.FilePath).Equals("stdout.txt", StringComparison.OrdinalIgnoreCase) + && !file.ScrubbedContent.Contains("Console")) + { + throw new Exception("stdout should contain 'Console'"); + } + + if (Path.GetExtension(file.FilePath).Equals(".csproj") + && !file.ScrubbedContent.Contains("enable")) + { + throw new Exception("Implicit usings should be used"); + } + } + } + ); + + VerificationEngine engine = new VerificationEngine(_log); + Func executeTask = () => engine.Execute(options); + await executeTask + .Should() + .NotThrowAsync(); + + Directory.Delete(workingDir, true); + } + } +} diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--a#-b#c#--d.verified/std-streams/stderr.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--a#-b#c#--d.verified/std-streams/stderr.txt new file mode 100644 index 0000000000..994af8b0a8 --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--a#-b#c#--d.verified/std-streams/stderr.txt @@ -0,0 +1 @@ +stderr content \ No newline at end of file diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--a#-b#c#--d.verified/std-streams/stdout.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--a#-b#c#--d.verified/std-streams/stdout.txt new file mode 100644 index 0000000000..e9cc259327 --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--a#-b#c#--d.verified/std-streams/stdout.txt @@ -0,0 +1 @@ +stdout content \ No newline at end of file diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--x#y#-z.verified/std-streams/stderr.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--x#y#-z.verified/std-streams/stderr.txt new file mode 100644 index 0000000000..1980902be4 --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--x#y#-z.verified/std-streams/stderr.txt @@ -0,0 +1 @@ +another stderr content \ No newline at end of file diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--x#y#-z.verified/std-streams/stdout.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--x#y#-z.verified/std-streams/stdout.txt new file mode 100644 index 0000000000..db3dcaee12 --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--x#y#-z.verified/std-streams/stdout.txt @@ -0,0 +1 @@ +different stdout content \ No newline at end of file diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests.csproj b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests.csproj new file mode 100644 index 0000000000..864aad8cfb --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests.csproj @@ -0,0 +1,24 @@ + + + $(NETCoreTargetFramework) + enable + enable + + + + + + + + + + + + + + + + + + + diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/VerificationEngineTests.cs b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/VerificationEngineTests.cs new file mode 100644 index 0000000000..3bfbb2d229 --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/VerificationEngineTests.cs @@ -0,0 +1,153 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices.JavaScript; +using FakeItEasy; +using FluentAssertions; +using Microsoft.Extensions.Logging; +using Microsoft.TemplateEngine.Authoring.TemplateVerifier.Commands; +using Microsoft.TemplateEngine.TestHelper; +using Xunit.Abstractions; + +namespace Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests +{ + [UsesVerify] + public class VerificationEngineTests + { + private readonly ILogger _log; + + public VerificationEngineTests(ITestOutputHelper log) + { + _log = new XunitLoggerProvider(log).CreateLogger("TestRun"); + } + + [Fact] + public async void CreateVerificationTaskWithCustomScrubbersAndVerifier() + { + string verifyLocation = "foo\\bar\\baz"; + + Dictionary files = new Dictionary() + { + { "Program.cs", "aa bb cc" }, + { "Subfolder\\Class.cs", "123 456 789 aa" }, + { "out.dll", "a1 b2" } + }; + + IPhysicalFileSystemEx fileSystem = A.Fake(); + A.CallTo(() => fileSystem.EnumerateFiles(verifyLocation, "*", SearchOption.AllDirectories)).Returns(files.Keys); + A.CallTo(() => fileSystem.ReadAllTextAsync(A._, A._)) + .ReturnsLazily((string fileName, CancellationToken _) => Task.FromResult(files[fileName])); + + Dictionary resultContents = new Dictionary(); + + TemplateVerifierOptions options = new TemplateVerifierOptions(templateName: "console") + { + TemplateSpecificArgs = null, + DisableDiffTool = null, + OutputDirectory = verifyLocation, + VerificationExcludePatterns = new[] { "*.dll" }, + VerifyCommandOutput = null, + UniqueFor = null, + } + .WithCustomScrubbers( + ScrubbersDefinition.Empty + .AddScrubber(sb => sb.Replace("bb", "xx"), "cs") + .AddScrubber(sb => sb.Replace("cc", "yy"), "dll") + .AddScrubber(sb => sb.Replace("123", "yy"), "dll") + .AddScrubber(sb => sb.Replace("aa", "zz")) + ) + .WithCustomDirectoryVerifier( + async (content, contentFetcher) => + { + await foreach (var file in contentFetcher.Value) + { + resultContents[file.FilePath] = file.ScrubbedContent; + } + } + ); + + await VerificationEngine.CreateVerificationTask(verifyLocation, "callerLocation", options, fileSystem); + + resultContents.Keys.Count.Should().Be(2); + resultContents["Program.cs"].Should().BeEquivalentTo("zz xx cc"); + resultContents["Subfolder\\Class.cs"].Should().BeEquivalentTo("123 456 789 zz"); + } + + [Fact] + public async void ExecuteFailsOnInstantiationFailure() + { + string workingDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + string expectationsDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + + ICommandRunner commandRunner = A.Fake(); + A.CallTo(() => commandRunner.RunCommand(A._)) + .Returns(new CommandResultData(20, "stdout content", "stderr content", workingDir)); + + TemplateVerifierOptions options = new TemplateVerifierOptions(templateName: "made-up-template") + { + TemplateSpecificArgs = new string[] { "--a", "-b", "c", "--d" }, + DisableDiffTool = true, + ExpectationsDirectory = expectationsDir, + OutputDirectory = workingDir, + VerifyCommandOutput = true, + UniqueFor = UniqueForOption.OsPlatform | UniqueForOption.OsPlatform, + }; + + VerificationEngine engine = new VerificationEngine(_log); + Func executeTask = () => engine.Execute(options); + await executeTask + .Should() + .ThrowAsync() + .Where(e => e.TemplateVerificationErrorCode == TemplateVerificationErrorCode.InstantiationFailed); + + } + + [Fact] + public async void ExecuteSucceedsOnExpectedInstantiationFailure() + { + string workingDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + string expectationsDir = "Expectations"; + + ICommandRunner commandRunner = A.Fake(); + A.CallTo(() => commandRunner.RunCommand(A._)) + .Returns(new CommandResultData(20, "stdout content", "stderr content", workingDir)); + + TemplateVerifierOptions options = new TemplateVerifierOptions(templateName: "made-up-template") + { + TemplateSpecificArgs = new string[] { "--a", "-b", "c", "--d" }, + //DisableDiffTool = true, + ExpectationsDirectory = expectationsDir, + IsCommandExpectedToFail = true, + OutputDirectory = workingDir, + VerifyCommandOutput = true, + }; + + VerificationEngine engine = new VerificationEngine(commandRunner, _log); + await engine.Execute(options); + } + + [Fact] + public async void ExecuteSucceedsOnExpectedInstantiationSuccess() + { + string workingDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); + string expectationsDir = "Expectations"; + + ICommandRunner commandRunner = A.Fake(); + A.CallTo(() => commandRunner.RunCommand(A._)) + .Returns(new CommandResultData(0, "different stdout content", "another stderr content", workingDir)); + + TemplateVerifierOptions options = new TemplateVerifierOptions(templateName: "made-up-template") + { + TemplateSpecificArgs = new string[] { "--x", "y", "-z" }, + //DisableDiffTool = true, + ExpectationsDirectory = expectationsDir, + IsCommandExpectedToFail = false, + OutputDirectory = workingDir, + VerifyCommandOutput = true, + }; + + VerificationEngine engine = new VerificationEngine(commandRunner, _log); + await engine.Execute(options); + } + } +} diff --git a/test/Microsoft.TemplateEngine.IDE.IntegrationTests/VerifySettingsFixture.cs b/test/Microsoft.TemplateEngine.IDE.IntegrationTests/VerifySettingsFixture.cs index ea381535fc..4f9e09652d 100644 --- a/test/Microsoft.TemplateEngine.IDE.IntegrationTests/VerifySettingsFixture.cs +++ b/test/Microsoft.TemplateEngine.IDE.IntegrationTests/VerifySettingsFixture.cs @@ -1,16 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using VerifyTests; - namespace Microsoft.TemplateEngine.IDE.IntegrationTests { public class VerifySettingsFixture : IDisposable { public VerifySettingsFixture() { - VerifierSettings.DerivePathInfo( + Verifier.DerivePathInfo( (_, _, type, method) => new( directory: "Approvals", typeName: type.Name, diff --git a/test/Microsoft.TemplateEngine.TestHelper/StringExtensions.cs b/test/Microsoft.TemplateEngine.TestHelper/StringExtensions.cs new file mode 100644 index 0000000000..3111049d14 --- /dev/null +++ b/test/Microsoft.TemplateEngine.TestHelper/StringExtensions.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.TemplateEngine.TestHelper +{ + public static class StringExtensions + { + public static string UnixifyLineBreaks(this string input) + { + return input.Replace("\r\n", "\n"); + } + } +} diff --git a/test/Microsoft.TemplateEngine.TestTemplates/Microsoft.TemplateEngine.TestTemplates.csproj b/test/Microsoft.TemplateEngine.TestTemplates/Microsoft.TemplateEngine.TestTemplates.csproj index 9d07da7269..331ad190fc 100644 --- a/test/Microsoft.TemplateEngine.TestTemplates/Microsoft.TemplateEngine.TestTemplates.csproj +++ b/test/Microsoft.TemplateEngine.TestTemplates/Microsoft.TemplateEngine.TestTemplates.csproj @@ -16,10 +16,10 @@ - + - + diff --git a/test/Microsoft.TemplateEngine.TestTemplates/test_templates/TestTemplate/.template.config/template.json b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/TestTemplate/.template.config/template.json new file mode 100644 index 0000000000..b60eb7bc74 --- /dev/null +++ b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/TestTemplate/.template.config/template.json @@ -0,0 +1,24 @@ +{ + "author": "Test Asset", + "classifications": [ "Test Asset" ], + "name": "SampleTestTemplate", + "generatorVersions": "[1.0.0.0-*)", + "groupIdentity": "TestAssets.SampleTestTemplate", + "precedence": "100", + "identity": "TestAssets.SampleTestTemplate", + "shortName": "TestAssets.SampleTestTemplate", + "symbols": { + "paramA": { + "type": "parameter", + "datatype": "string", + "replaces": "placeholderA", + "defaultValue": "false" + }, + "paramB": { + "type": "parameter", + "datatype": "string", + "isRequired": true, + "replaces": "placeholderB" + } + } +} diff --git a/test/Microsoft.TemplateEngine.TestTemplates/test_templates/TestTemplate/Test.cs b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/TestTemplate/Test.cs new file mode 100644 index 0000000000..0de65665c3 --- /dev/null +++ b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/TestTemplate/Test.cs @@ -0,0 +1,11 @@ + +// value of paramA: placeholderA +// value of paramB: placeholderB + +//#if( paramA ) + // A is enabled +//#endif + +//#if( paramB ) + // B is enabled +//#endif