diff --git a/eng/dependabot/Packages.props b/eng/dependabot/Packages.props index aeef3d67f0..f89b3a6bc4 100644 --- a/eng/dependabot/Packages.props +++ b/eng/dependabot/Packages.props @@ -26,7 +26,7 @@ - + diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommand.cs b/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommand.cs index 48ccef56a5..4e44650122 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommand.cs +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommand.cs @@ -50,6 +50,11 @@ internal class VerifyCommand : ExecutableCommand Description = LocalizableStrings.command_verify_help_expectationsDirPath_description, }; + private readonly Option _scenarioNameOption = new(new[] { "--scenario-name" }) + { + Description = LocalizableStrings.command_verify_help_scenarioName_description, + }; + private readonly Option _disableDiffToolOption = new("--disable-diff-tool") { Description = LocalizableStrings.command_verify_help_disableDiffTool_description, @@ -66,6 +71,12 @@ internal class VerifyCommand : ExecutableCommand Arity = new ArgumentArity(0, 999) }; + private readonly Option> _includePatternOption = new("--include-pattern") + { + Description = LocalizableStrings.command_verify_help_customIncludes_description, + Arity = new ArgumentArity(0, 999) + }; + private readonly Option _verifyCommandOutputOption = new("--verify-std") { Description = LocalizableStrings.command_verify_help_verifyOutputs_description, @@ -92,14 +103,16 @@ public VerifyCommand(ILoggerFactory loggerFactory) AddOption(_newCommandPathOption); AddOption(_templateOutputPathOption); AddOption(_expectationsDirectoryOption); + AddOption(_scenarioNameOption); AddOption(_disableDiffToolOption); AddOption(_disableDefaultExcludePatternsOption); AddOption(_excludePatternOption); + AddOption(_includePatternOption); AddOption(_verifyCommandOutputOption); AddOption(_isCommandExpectedToFailOption); FromAmongCaseInsensitive( _uniqueForOption, - System.Enum.GetNames(typeof(UniqueForOption)) + Enum.GetNames(typeof(UniqueForOption)) .Where(v => !v.Equals(UniqueForOption.None.ToString(), StringComparison.OrdinalIgnoreCase)) .ToArray()); AddOption(_uniqueForOption); @@ -113,10 +126,12 @@ internal static VerifyCommandArgs ExtractArguments(VerifyCommand verifyCommand, templatePath: parseResult.GetValueForOption(verifyCommand._templatePathOption), dotnetNewCommandAssemblyPath: parseResult.GetValueForOption(verifyCommand._newCommandPathOption), expectationsDirectory: parseResult.GetValueForOption(verifyCommand._expectationsDirectoryOption), + scenarioDistinguisher: parseResult.GetValueForOption(verifyCommand._scenarioNameOption), outputDirectory: parseResult.GetValueForOption(verifyCommand._templateOutputPathOption), disableDiffTool: parseResult.GetValueForOption(verifyCommand._disableDiffToolOption), disableDefaultVerificationExcludePatterns: parseResult.GetValueForOption(verifyCommand._disableDefaultExcludePatternsOption), verificationExcludePatterns: parseResult.GetValueForOption(verifyCommand._excludePatternOption), + verificationIncludePatterns: parseResult.GetValueForOption(verifyCommand._includePatternOption), verifyCommandOutput: parseResult.GetValueForOption(verifyCommand._verifyCommandOutputOption), isCommandExpectedToFail: parseResult.GetValueForOption(verifyCommand._isCommandExpectedToFailOption), uniqueForOptions: parseResult.GetValueForOption(verifyCommand._uniqueForOption)); @@ -136,12 +151,15 @@ protected override async Task ExecuteAsync(VerifyCommandArgs args, Cancella DisableDiffTool = args.DisableDiffTool, DisableDefaultVerificationExcludePatterns = args.DisableDefaultVerificationExcludePatterns, VerificationExcludePatterns = args.VerificationExcludePatterns, + VerificationIncludePatterns = args.VerificationIncludePatterns, DotnetNewCommandAssemblyPath = args.DotnetNewCommandAssemblyPath, ExpectationsDirectory = args.ExpectationsDirectory, + ScenarioName = args.ScenarioDistinguisher, OutputDirectory = args.OutputDirectory, VerifyCommandOutput = args.VerifyCommandOutput, IsCommandExpectedToFail = args.IsCommandExpectedToFail, UniqueFor = args.UniqueFor, + DoNotPrependCallerMethodNameToScenarioName = true }; await engine.Execute( options, diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommandArgs.cs b/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommandArgs.cs index b66212dbdc..f7acd475de 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommandArgs.cs +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/Commands/Verify/VerifyCommandArgs.cs @@ -23,11 +23,13 @@ public VerifyCommandArgs( string? templateSpecificArgs, string? dotnetNewCommandAssemblyPath, string? expectationsDirectory, + string? scenarioDistinguisher, string? outputDirectory, - bool? disableDiffTool, - bool? disableDefaultVerificationExcludePatterns, + bool disableDiffTool, + bool disableDefaultVerificationExcludePatterns, IEnumerable? verificationExcludePatterns, - bool? verifyCommandOutput, + IEnumerable? verificationIncludePatterns, + bool verifyCommandOutput, bool isCommandExpectedToFail, IEnumerable? uniqueForOptions) : this(templateName, templateSpecificArgs) @@ -35,10 +37,12 @@ public VerifyCommandArgs( TemplatePath = templatePath; DotnetNewCommandAssemblyPath = dotnetNewCommandAssemblyPath; ExpectationsDirectory = expectationsDirectory; + ScenarioDistinguisher = scenarioDistinguisher; OutputDirectory = outputDirectory; DisableDiffTool = disableDiffTool; DisableDefaultVerificationExcludePatterns = disableDefaultVerificationExcludePatterns; VerificationExcludePatterns = verificationExcludePatterns; + VerificationIncludePatterns = verificationIncludePatterns; VerifyCommandOutput = verifyCommandOutput; IsCommandExpectedToFail = isCommandExpectedToFail; UniqueFor = ToUniqueForOptionFlags(uniqueForOptions); @@ -69,6 +73,11 @@ public VerifyCommandArgs( /// public string? ExpectationsDirectory { get; init; } + /// + /// Gets a custom prefix prepended in front of generated scenario name - result used for naming verification subdirectories. + /// + public string? ScenarioDistinguisher { get; init; } + /// /// Gets the target directory to output the generated template. /// @@ -77,23 +86,29 @@ public VerifyCommandArgs( /// /// If set to true - the diff tool won't be automatically started by the Verifier on verification failures. /// - public bool? DisableDiffTool { get; init; } + 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; } + public bool DisableDefaultVerificationExcludePatterns { get; init; } /// /// Set of patterns defining files to be excluded from verification. /// public IEnumerable? VerificationExcludePatterns { get; init; } + /// + /// Set of patterns defining files to be included into verification (unless excluded by ). + /// By default all files are included (unless excluded). + /// + public IEnumerable? VerificationIncludePatterns { 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; } + public bool VerifyCommandOutput { get; init; } /// /// If set to true - 'dotnet new' command is expected to return nonzero return code. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.Designer.cs b/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.Designer.cs index 815cb30209..28a4ffef84 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.Designer.cs +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.Designer.cs @@ -188,6 +188,15 @@ internal static string command_verify_help_customExcludes_description { } } + /// + /// Looks up a localized string similar to Specifies pattern(s) defining files to be included to verification (all files are included if not specified).. + /// + internal static string command_verify_help_customIncludes_description { + get { + return ResourceManager.GetString("command_verify_help_customIncludes_description", resourceCulture); + } + } + /// /// Looks up a localized string similar to Runs the template with specified arguments and compares the result with expectations files.. /// @@ -251,6 +260,15 @@ internal static string command_verify_help_outputPath_description { } } + /// + /// Looks up a localized string similar to Specifies optional scenario name to be used in the snapshot folder name.. + /// + internal static string command_verify_help_scenarioName_description { + get { + return ResourceManager.GetString("command_verify_help_scenarioName_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.. /// diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.resx b/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.resx index 3f760fd527..b08bfb4070 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.resx +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/LocalizableStrings.resx @@ -171,6 +171,9 @@ Do not localize: "template.json" Specifies pattern(s) defining files to be excluded from verification. + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Runs the template with specified arguments and compares the result with expectations files. @@ -196,6 +199,9 @@ Do not localize: "template.json" Specifies the path to target directory to output the generated template to. + + Specifies optional scenario name to be used in the snapshot folder name. + 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' @@ -217,4 +223,4 @@ Do not localize: "template.json" There was an error while running the "--{0}" command. Error message: "{1}". See the logs for more details. - \ No newline at end of file + diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.cs.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.cs.xlf index 1e93aa8a2a..43be25a50b 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.cs.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.cs.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" Určuje vzory definující soubory, které se mají vyloučit z ověřování. + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. Spustí šablonu se zadanými argumenty a porovná výsledek s očekávanými soubory. @@ -113,6 +118,11 @@ Do not localize: "template.json" Určuje cestu k cílovému adresáři pro výstup vygenerované šablony. + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. Název šablony, která se má ověřit. Může jít o již nainstalovanou šablonu, nebo o šablonu v místní cestě zadané s parametrem -p/--template-path. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.de.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.de.xlf index c63b8e2951..1b50f88a51 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.de.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.de.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" Gibt Muster an, die Dateien definieren, die von der Überprüfung ausgeschlossen werden sollen. + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. Führt die Vorlage mit angegebenen Argumenten aus und vergleicht das Ergebnis mit den Erwartungsdateien. @@ -113,6 +118,11 @@ Do not localize: "template.json" Gibt den Pfad zum Zielverzeichnis an, in das die generierte Vorlage ausgegeben werden soll. + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + 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 der zu überprüfenden Vorlage. Kann eine bereits installierte Vorlage oder eine Vorlage innerhalb des lokalen Pfads sein, der mit der Option „-p/--template-path“ angegeben ist. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.es.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.es.xlf index 4a86d891f5..67a5b5eeaa 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.es.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.es.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" Especifica los patrones que definen los archivos que se excluirán de la comprobación. + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. Ejecuta la plantilla con los argumentos especificados y compara el resultado con los archivos de expectativas. @@ -113,6 +118,11 @@ Do not localize: "template.json" Especifica la ruta de acceso al directorio de destino en el que se generará la plantilla generada. + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. Nombre de la plantilla por verificar. Puede ser una plantilla ya instalada o una plantilla dentro de la ruta local especificada con la opción -p/--template-path. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.fr.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.fr.xlf index 5d8f81551f..5698be899c 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.fr.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.fr.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" Spécifie le ou les modèles définissant les fichiers à exclure de la vérification. + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. Exécute le modèle avec les arguments spécifiés et compare le résultat aux fichiers attendus. @@ -113,6 +118,11 @@ Do not localize: "template.json" Spécifie le chemin d’accès au répertoire cible vers lequel générer la sortie du modèle généré. + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. Nom du modèle à vérifier. Peut déjà un modèle être installé ou un modèle dans le chemin d’accès local spécifié avec l’option -p/--template-path. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.it.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.it.xlf index 0bfd646d2d..e5b7fd7fe4 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.it.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.it.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" Specifica i criteri che definiscono i file da escludere dalla verifica. + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. Esegue il modello con gli argomenti specificati e confronta il risultato con i file delle aspettative. @@ -113,6 +118,11 @@ Do not localize: "template.json" Specifica il percorso della directory di destinazione in cui restituire il modello generato. + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. Nome del modello da verificare. Può essere già installato un modello o un modello all'interno del percorso locale specificato con l'opzione -p/--template-path. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ja.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ja.xlf index 5fd18efd97..b90937305c 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ja.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ja.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" 検証から除外するファイルを定義するパターンを指定します。 + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. 指定された引数を使用してテンプレートを実行し、結果を期待値ファイルと比較します。 @@ -113,6 +118,11 @@ Do not localize: "template.json" 生成されたテンプレートを出力するターゲット ディレクトリへのパスを指定します。 + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. 検証するテンプレートの名前。既にインストールされているテンプレート、または -p/--template-path オプションで指定されたローカル パス内のテンプレート。 diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ko.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ko.xlf index 45af5ed10e..a78101f415 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ko.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ko.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" 확인에서 제외할 파일을 정의하는 패턴을 지정합니다. + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. 지정된 인수로 템플릿을 실행하고 결과를 예상 파일과 비교합니다. @@ -113,6 +118,11 @@ Do not localize: "template.json" 생성된 템플릿을 출력할 대상 디렉터리의 경로를 지정합니다. + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. 확인할 템플릿의 이름입니다. 이미 설치된 템플릿 또는 -p/--template-path 옵션으로 지정된 로컬 경로 내의 템플릿일 수 있습니다. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pl.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pl.xlf index 50600f39a4..e875bc3405 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pl.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pl.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" Określa wzorce definiujące pliki, które mają zostać wykluczone z weryfikacji. + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. Uruchamia szablon z określonymi argumentami i porównuje wynik z plikami oczekiwań. @@ -113,6 +118,11 @@ Do not localize: "template.json" Określa ścieżkę do katalogu docelowego, do którą ma zostać wygenerowany szablon. + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. Nazwa szablonu do zweryfikowania. Można już zainstalować szablon lub szablon w ścieżce lokalnej określonej za pomocą opcji -p/--template-path. 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 957bd68bc2..ea36e405fd 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.pt-BR.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" Especifica padrões que definem arquivos a serem excluídos da verificação. + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. Executa o modelo com argumentos especificados e compara o resultado com arquivos de expectativas. @@ -113,6 +118,11 @@ Do not localize: "template.json" Especifica o caminho para o diretório de destino para a saída do modelo gerado. + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. Nome do modelo a ser verificado. Pode ser um modelo já instalado ou um modelo dentro do caminho local especificado com a opção -p/--template-path. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ru.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ru.xlf index 527a13718a..2f1b3e924f 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ru.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.ru.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" Задает шаблон(ы), определяя файлы, которые следует исключить из проверки. + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. Запускает шаблон с указанными аргументами и сравнивает результат с файлами ожиданий. @@ -113,6 +118,11 @@ Do not localize: "template.json" Указывает путь к целевому каталогу для вывода созданного шаблона. + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. Имя шаблона, который необходимо проверить. Это может быть уже установленный шаблон или шаблон в локальном пути, указанном через параметр -p/--template-path. diff --git a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.tr.xlf b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.tr.xlf index c6ee6497d9..61efa0288a 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.tr.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.tr.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" Doğrulamanın dışında tutulacak dosyaları tanımlayan desenleri belirtir. + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. Şablonu, belirtilen bağımsız değişkenlerle çalıştırıp sonucu beklenti dosyalarıyla karşılaştırır. @@ -113,6 +118,11 @@ Do not localize: "template.json" Oluşturulan şablonun çıkış yapılacağı hedef dizini yolunu belirtir. + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + 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ğrulanacak şablonun adı. Zaten yüklü bir şablon veya -p/--template-path seçeneğiyle belirtilen yerel yolda bir şablon olabilir. 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 36fb9ed44b..27fbeb6e9b 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hans.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" 指定定义要从验证中排除的文件的模式。 + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. 使用指定的参数运行模板,并将结果与期望文件进行比较。 @@ -113,6 +118,11 @@ Do not localize: "template.json" 指定要将生成的模板输出到的目标目录的路径。 + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. 要验证的模板的名称。可以是已安装的模板或在使用 -p/--template-path 选项指定的本地路径内的模板。 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 f57ab7ce63..42e04dc893 100644 --- a/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Microsoft.TemplateEngine.Authoring.CLI/xlf/LocalizableStrings.zh-Hant.xlf @@ -78,6 +78,11 @@ Do not localize: "template.json" 指定要從驗證排除的模式定義檔案。 + + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + Specifies pattern(s) defining files to be included to verification (all files are included if not specified). + + Runs the template with specified arguments and compares the result with expectations files. 使用指定的引數執行範本,並將結果與期望檔案比較。 @@ -113,6 +118,11 @@ Do not localize: "template.json" 指定要輸出所產生範本的目標目錄路徑。 + + Specifies optional scenario name to be used in the snapshot folder name. + Specifies optional scenario name to be used in the snapshot folder name. + + Name of the template to be verified. Can be already installed template or a template within local path specified with -p/--template-path option. 要驗證的範本名稱。可以是已安裝的範本,或以 -p/--template-path 選項指定之本機路徑內的範本。 diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PublicAPI.Unshipped.txt b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PublicAPI.Unshipped.txt index 294d43a6a6..343b8d1445 100644 --- a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PublicAPI.Unshipped.txt +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/PublicAPI.Unshipped.txt @@ -1,9 +1,8 @@ Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition +Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition.AddScrubber(Microsoft.TemplateEngine.Authoring.TemplateVerifier.ScrubbersDefinition.ScrubFileByPath! fileScrubber) -> 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.ScrubbersDefinition.ScrubFileByPath 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 @@ -21,18 +20,28 @@ Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerificationExceptio 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.get -> bool Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DisableDefaultVerificationExcludePatterns.init -> void -Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DisableDiffTool.get -> bool? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DisableDiffTool.get -> bool Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DisableDiffTool.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DoNotAppendTemplateArgsToScenarioName.get -> bool +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DoNotAppendTemplateArgsToScenarioName.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DoNotPrependCallerMethodNameToScenarioName.get -> bool +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DoNotPrependCallerMethodNameToScenarioName.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DoNotPrependTemplateNameToScenarioName.get -> bool +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.DoNotPrependTemplateNameToScenarioName.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.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.ScenarioName.get -> string? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.ScenarioName.init -> void +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.SettingsDirectory.get -> string? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.SettingsDirectory.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! @@ -46,7 +55,9 @@ Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.Uniq 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.VerificationIncludePatterns.get -> System.Collections.Generic.IEnumerable? +Microsoft.TemplateEngine.Authoring.TemplateVerifier.TemplateVerifierOptions.VerificationIncludePatterns.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! @@ -59,7 +70,7 @@ Microsoft.TemplateEngine.Authoring.TemplateVerifier.UniqueForOption.RuntimeAndVe 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.Execute(Microsoft.Extensions.Options.IOptions! optionsAccessor, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken), string! sourceFile = "", string! callerMethod = "") -> 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 diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/ScrubbersDefinition.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/ScrubbersDefinition.cs index cb975f6ca7..2dc19d19c0 100644 --- a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/ScrubbersDefinition.cs +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/ScrubbersDefinition.cs @@ -9,20 +9,24 @@ public class ScrubbersDefinition { public static readonly ScrubbersDefinition Empty = new(); - public ScrubbersDefinition() { } - public ScrubbersDefinition(Action scrubber, string? extension = null) { AddScrubber(scrubber, extension); } - public Dictionary> ScrubersByExtension { get; private set; } = new Dictionary>(); + private ScrubbersDefinition() { } + + public delegate void ScrubFileByPath(string relativeFilePath, StringBuilder content); + + internal Dictionary> ScrubersByExtension { get; private set; } = new Dictionary>(); + + internal Action? GeneralScrubber { get; private set; } - public Action? GeneralScrubber { get; private set; } + internal List ByPathScrubbers { get; private set; } = new List(); public ScrubbersDefinition AddScrubber(Action scrubber, string? extension = null) { - if (object.ReferenceEquals(this, Empty)) + if (ReferenceEquals(this, Empty)) { return new ScrubbersDefinition().AddScrubber(scrubber, extension); } @@ -41,4 +45,10 @@ public ScrubbersDefinition AddScrubber(Action scrubber, string? e return this; } + + public ScrubbersDefinition AddScrubber(ScrubFileByPath fileScrubber) + { + ByPathScrubbers.Add(fileScrubber); + return this; + } } diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerifierOptions.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerifierOptions.cs index a222406edf..44d2cd6bfd 100644 --- a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerifierOptions.cs +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/TemplateVerifierOptions.cs @@ -44,35 +44,46 @@ public class TemplateVerifierOptions : IOptions /// /// 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; } + 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; } + 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; } + 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; } + public bool DisableDefaultVerificationExcludePatterns { get; init; } /// /// Set of patterns defining files to be excluded from verification. /// public IEnumerable? VerificationExcludePatterns { get; init; } + /// + /// Gets a set of patterns defining files to be included into verification (unless excluded by ). + /// By default all files are included (unless excluded). + /// + public IEnumerable? VerificationIncludePatterns { get; init; } + /// /// Gets the target directory to output the generated template. /// public string? OutputDirectory { get; init; } + /// + /// Gets the settings directory for template engine (in memory location used if not specified). + /// + public string? SettingsDirectory { get; init; } + /// /// Gets the Verifier expectations directory naming convention - by indicating which scenarios should be differentiated. /// @@ -88,11 +99,35 @@ public class TemplateVerifierOptions : IOptions /// public VerifyDirectory? CustomDirectoryVerifier { get; private set; } + /// + /// Gets the custom scenario name; if specified it will be used as part of verification snapshot. + /// + public string? ScenarioName { get; init; } + + /// + /// , if the instantiation args should not be appended to verification subdirectories. + /// + public bool DoNotAppendTemplateArgsToScenarioName { get; init; } + + /// + /// , if the template name should not be prepended to verification subdirectories. + /// + public bool DoNotPrependTemplateNameToScenarioName { get; init; } + + /// + /// , if the caller method name should not be prepended to verification subdirectories. + /// + public bool DoNotPrependCallerMethodNameToScenarioName { get; init; } + /// /// Gets the extension of autogeneratedfiles with stdout and stderr content. /// public string? StandardOutputFileExtension { get; init; } + // Enable if too many underlying features are asked. + // On the other hand if possible, we should wrap everyting and dfo not expose underlying technology to allow for change. + // public Action VerifySettingsAdjustor { get; init; } + TemplateVerifierOptions IOptions.Value => this; /// diff --git a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/VerificationEngine.cs b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/VerificationEngine.cs index 3bcbd4b19c..36df3213f2 100644 --- a/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/VerificationEngine.cs +++ b/src/Microsoft.TemplateEngine.Authoring.TemplateVerifier/VerificationEngine.cs @@ -16,14 +16,13 @@ public class VerificationEngine { private static readonly IReadOnlyList DefaultVerificationExcludePatterns = new List() { - @"obj/*", - @"obj\*", - @"bin/*", - @"bin\*", + @"**/obj/*", + @"**\obj\*", + @"**/bin/*", + @"**\bin\*", "*.exe", "*.dll", "*.", - "*.exe", }; private readonly ILogger _logger; @@ -55,10 +54,19 @@ internal VerificationEngine(ICommandRunner commandRunner, ILogger logger) _commandRunner = commandRunner; } + /// + /// Asynchronously performs the scenario and its verification based on given configuration options. + /// + /// Configuration of the scenario and verification. + /// + /// + /// + /// A Task to be awaited. public async Task Execute( IOptions optionsAccessor, CancellationToken cancellationToken = default, - [CallerFilePath] string sourceFile = "") + [CallerFilePath] string sourceFile = "", + [CallerMemberName] string callerMethod = "") { if (optionsAccessor == null) { @@ -69,7 +77,7 @@ public async Task Execute( CommandResultData commandResult = RunDotnetNewCommand(options, _commandRunner, _loggerFactory, _logger); - if (options.IsCommandExpectedToFail ?? false) + if (options.IsCommandExpectedToFail) { if (commandResult.ExitCode == 0) { @@ -89,7 +97,7 @@ public async Task Execute( // 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)) + if (!options.VerifyCommandOutput && !string.IsNullOrEmpty(commandResult.StdErr)) { throw new TemplateVerificationException( string.Format( @@ -100,17 +108,24 @@ public async Task Execute( } } - await VerifyResult(options, commandResult, string.IsNullOrEmpty(sourceFile) ? string.Empty : Path.GetDirectoryName(sourceFile)!) + await VerifyResult(options, commandResult, string.IsNullOrEmpty(sourceFile) ? string.Empty : Path.GetDirectoryName(sourceFile)!, callerMethod) .ConfigureAwait(false); + + // if everything is successful - let's delete the created files (unless placed into explicitly requested dir) + if (string.IsNullOrEmpty(options.OutputDirectory) && _fileSystem.DirectoryExists(commandResult.WorkingDirectory)) + { + _fileSystem.DirectoryDelete(commandResult.WorkingDirectory, true); + } } internal static Task CreateVerificationTask( string contentDir, string callerDir, + string? callerMethodName, TemplateVerifierOptions options, IPhysicalFileSystemEx fileSystem) { - List exclusionsList = (options.DisableDefaultVerificationExcludePatterns ?? false) + List exclusionsList = options.DisableDefaultVerificationExcludePatterns ? new() : new(DefaultVerificationExcludePatterns); @@ -119,18 +134,30 @@ internal static Task CreateVerificationTask( exclusionsList.AddRange(options.VerificationExcludePatterns); } - List globs = exclusionsList.Select(pattern => Glob.Parse(pattern)).ToList(); + List excludeGlobs = exclusionsList.Select(pattern => (IPatternMatcher)Glob.Parse(pattern)).ToList(); + List includeGlobs = new(); + + if (options.VerificationIncludePatterns != null) + { + includeGlobs.AddRange(options.VerificationIncludePatterns.Select(pattern => Glob.Parse(pattern))); + } + + if (!includeGlobs.Any()) + { + includeGlobs.Add(Glob.MatchAll); + } if (options.CustomDirectoryVerifier != null) { return options.CustomDirectoryVerifier( contentDir, new Lazy>( - GetVerificationContent(contentDir, globs, options.CustomScrubbers, fileSystem))); + GetVerificationContent(contentDir, includeGlobs, excludeGlobs, options.CustomScrubbers, fileSystem))); } VerifySettings verifySettings = new(); + // Scrubbers by file: https://github.com/VerifyTests/Verify/issues/673 if (options.CustomScrubbers != null) { if (options.CustomScrubbers.GeneralScrubber != null) @@ -144,14 +171,20 @@ internal static Task CreateVerificationTask( } } - verifySettings.UseTypeName(options.TemplateName); + string scenarioPrefix = options.DoNotPrependTemplateNameToScenarioName ? string.Empty : options.TemplateName; + if (!options.DoNotPrependCallerMethodNameToScenarioName && !string.IsNullOrEmpty(callerMethodName)) + { + scenarioPrefix = callerMethodName + (string.IsNullOrEmpty(scenarioPrefix) ? null : ".") + scenarioPrefix; + } + scenarioPrefix = string.IsNullOrEmpty(scenarioPrefix) ? "_" : scenarioPrefix; + verifySettings.UseTypeName(scenarioPrefix); 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)); + verifySettings.UseMethodName(GetScenarioName(options)); if ((options.UniqueFor ?? UniqueForOption.None) != UniqueForOption.None) { @@ -188,17 +221,48 @@ internal static Task CreateVerificationTask( } } - if (options.DisableDiffTool ?? false) + if (options.DisableDiffTool) { verifySettings.DisableDiff(); } return Verifier.VerifyDirectory( contentDir, - (filePath) => !globs.Any(g => g.IsMatch(filePath)), + include: (filePath) => + { + string relativePath = fileSystem.PathRelativeTo(filePath, contentDir); + return includeGlobs.Any(g => g.IsMatch(relativePath)) && !excludeGlobs.Any(g => g.IsMatch(relativePath)); + }, + fileScrubber: ExtractFileScrubber(options, contentDir, fileSystem), settings: verifySettings); } + private static FileScrubber? ExtractFileScrubber(TemplateVerifierOptions options, string contentDir, IPhysicalFileSystemEx fileSystem) + { + if (!(options.CustomScrubbers?.ByPathScrubbers.Any() ?? false)) + { + return null; + } + + return (fullPath, builder) => + { + string relativePath = fileSystem.PathRelativeTo(fullPath, contentDir); + options.CustomScrubbers.ByPathScrubbers.ForEach(scrubberByPath => scrubberByPath(relativePath, builder)); + }; + } + + private static string GetScenarioName(TemplateVerifierOptions options) + { + // TBD: once the custom SDK switching feature is implemented - here we should append the sdk distinguisher if UniqueForOption.Runtime requested + + var scenarioName = options.ScenarioName + (options.DoNotAppendTemplateArgsToScenarioName ? null : EncodeArgsAsPath(options.TemplateSpecificArgs)); + if (string.IsNullOrEmpty(scenarioName)) + { + scenarioName = "_"; + } + return scenarioName; + } + private static string EncodeArgsAsPath(IEnumerable? args) { if (args == null || !args.Any()) @@ -221,11 +285,11 @@ private static CommandResultData RunDotnetNewCommand(TemplateVerifierOptions opt Directory.CreateDirectory(workingDir); ILogger commandLogger = loggerFactory?.CreateLogger(typeof(DotnetCommand)) ?? logger; - string? customHiveLocation = null; + string? customHiveLocation = options.SettingsDirectory; if (!string.IsNullOrEmpty(options.TemplatePath)) { - customHiveLocation = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName(), "home"); + customHiveLocation ??= Path.Combine(Path.GetTempPath(), Path.GetRandomFileName(), "home"); var installCommand = new DotnetCommand(commandLogger, "new", "install", options.TemplatePath) .WithCustomHive(customHiveLocation) @@ -279,7 +343,8 @@ private static CommandResultData RunDotnetNewCommand(TemplateVerifierOptions opt var command = new DotnetCommand(loggerFactory?.CreateLogger(typeof(DotnetCommand)) ?? logger, "new", cmdArgs.ToArray()) .WithWorkingDirectory(workingDir); var result = commandRunner.RunCommand(command); - if (!string.IsNullOrEmpty(customHiveLocation)) + // Cleanup, unless the settings dir was externally passed + if (!string.IsNullOrEmpty(customHiveLocation) && string.IsNullOrEmpty(options.SettingsDirectory)) { Directory.Delete(customHiveLocation, true); } @@ -291,13 +356,21 @@ private static void DummyMethod() private static async IAsyncEnumerable<(string FilePath, string ScrubbedContent)> GetVerificationContent( string contentDir, - List globs, + List includeMatchers, + List excludeMatchers, ScrubbersDefinition? scrubbers, IPhysicalFileSystemEx fileSystem) { foreach (string filePath in fileSystem.EnumerateFiles(contentDir, "*", SearchOption.AllDirectories)) { - if (globs.Any(g => g.IsMatch(filePath))) + string relativePath = fileSystem.PathRelativeTo(filePath, contentDir); + + if (!includeMatchers.Any(g => g.IsMatch(relativePath))) + { + continue; + } + + if (excludeMatchers.Any(g => g.IsMatch(relativePath))) { continue; } @@ -314,9 +387,15 @@ private static void DummyMethod() } StringBuilder? sb = null; - if (!string.IsNullOrEmpty(extension) && scrubbers.ScrubersByExtension.TryGetValue(extension, out Action? scrubber)) + if (scrubbers.ByPathScrubbers.Any()) { sb = new StringBuilder(content); + scrubbers.ByPathScrubbers.ForEach(scrubberByPath => scrubberByPath(relativePath, sb)); + } + + if (!string.IsNullOrEmpty(extension) && scrubbers.ScrubersByExtension.TryGetValue(extension, out Action? scrubber)) + { + sb ??= new StringBuilder(content); scrubber(sb); } @@ -332,11 +411,11 @@ private static void DummyMethod() } } - yield return new(filePath, content); + yield return new(relativePath, content); } } - private async Task VerifyResult(TemplateVerifierOptions args, CommandResultData commandResultData, string callerDir) + private async Task VerifyResult(TemplateVerifierOptions args, CommandResultData commandResultData, string callerDir, string callerMethodName) { UsesVerifyAttribute a = new UsesVerifyAttribute(); // https://github.com/VerifyTests/Verify/blob/d8cbe38f527d6788ecadd6205c82803bec3cdfa6/src/Verify.Xunit/Verifier.cs#L10 @@ -345,7 +424,7 @@ private async Task VerifyResult(TemplateVerifierOptions args, CommandResultData MethodInfo mi = v.Method; a.Before(mi); - if (args.VerifyCommandOutput ?? false) + if (args.VerifyCommandOutput) { if (_fileSystem.DirectoryExists(Path.Combine(commandResultData.WorkingDirectory, SpecialFiles.StandardStreamsDir))) { @@ -369,7 +448,7 @@ await _fileSystem.WriteAllTextAsync( .ConfigureAwait(false); } - Task verifyTask = CreateVerificationTask(commandResultData.WorkingDirectory, callerDir, args, _fileSystem); + Task verifyTask = CreateVerificationTask(commandResultData.WorkingDirectory, callerDir, callerMethodName, args, _fileSystem); try { diff --git a/src/Microsoft.TemplateEngine.Utils/Glob.cs b/src/Microsoft.TemplateEngine.Utils/Glob.cs index 69fa7533f6..d5e556ae21 100644 --- a/src/Microsoft.TemplateEngine.Utils/Glob.cs +++ b/src/Microsoft.TemplateEngine.Utils/Glob.cs @@ -7,8 +7,13 @@ namespace Microsoft.TemplateEngine.Utils { - public class Glob + public class Glob : IPatternMatcher { + /// + /// Instance of Matcher satisfying all patterns tests. + /// + public static readonly IPatternMatcher MatchAll = new MatchAllGlob(); + private readonly IReadOnlyList _matchers; private readonly bool _negate; private readonly bool _isNameOnlyMatch; @@ -330,5 +335,14 @@ public override string ToString() return "**"; } } + + private class MatchAllGlob : IPatternMatcher + { + public MatchAllGlob() + { } + + /// + public bool IsMatch(string test) => true; + } } } diff --git a/src/Microsoft.TemplateEngine.Utils/IPatternMatcher.cs b/src/Microsoft.TemplateEngine.Utils/IPatternMatcher.cs new file mode 100644 index 0000000000..1f40d29f11 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Utils/IPatternMatcher.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.Utils; + +/// +/// Interface for pattern matchers. +/// +public interface IPatternMatcher +{ + /// + /// Evaluates the test path against the pattern and returns whether the path is a match. + /// + /// + /// + bool IsMatch(string test); +} diff --git a/src/Microsoft.TemplateEngine.Utils/PublicAPI.Unshipped.txt b/src/Microsoft.TemplateEngine.Utils/PublicAPI.Unshipped.txt index 14d64ba4ce..f359d060c2 100644 --- a/src/Microsoft.TemplateEngine.Utils/PublicAPI.Unshipped.txt +++ b/src/Microsoft.TemplateEngine.Utils/PublicAPI.Unshipped.txt @@ -1,4 +1,7 @@ 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 +Microsoft.TemplateEngine.Utils.AsyncLazy.GetAwaiter() -> System.Runtime.CompilerServices.TaskAwaiter +Microsoft.TemplateEngine.Utils.IPatternMatcher +Microsoft.TemplateEngine.Utils.IPatternMatcher.IsMatch(string! test) -> bool +static readonly Microsoft.TemplateEngine.Utils.Glob.MatchAll -> Microsoft.TemplateEngine.Utils.IPatternMatcher! \ No newline at end of file diff --git a/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/VerifyCommandTests.cs b/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/VerifyCommandTests.cs index cd8577e5b9..89518c4931 100644 --- a/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/VerifyCommandTests.cs +++ b/test/Microsoft.TemplateEngine.Authoring.CLI.UnitTests/VerifyCommandTests.cs @@ -26,6 +26,7 @@ public class VerifyCommandTests DisableDiffTool = true, DisableDefaultVerificationExcludePatterns = false, VerificationExcludePatterns = Enumerable.Empty(), + VerificationIncludePatterns = Enumerable.Empty(), VerifyCommandOutput = false, IsCommandExpectedToFail = false, UniqueFor = UniqueForOption.None, @@ -42,6 +43,7 @@ public class VerifyCommandTests DisableDiffTool = false, DisableDefaultVerificationExcludePatterns = false, VerificationExcludePatterns = Enumerable.Empty(), + VerificationIncludePatterns = Enumerable.Empty(), VerifyCommandOutput = false, IsCommandExpectedToFail = false, UniqueFor = UniqueForOption.Runtime, @@ -58,6 +60,7 @@ public class VerifyCommandTests DisableDiffTool = false, DisableDefaultVerificationExcludePatterns = false, VerificationExcludePatterns = Enumerable.Empty(), + VerificationIncludePatterns = Enumerable.Empty(), VerifyCommandOutput = false, IsCommandExpectedToFail = false, UniqueFor = UniqueForOption.None, @@ -74,6 +77,7 @@ public class VerifyCommandTests DisableDiffTool = false, DisableDefaultVerificationExcludePatterns = false, VerificationExcludePatterns = Enumerable.Empty(), + VerificationIncludePatterns = Enumerable.Empty(), VerifyCommandOutput = false, IsCommandExpectedToFail = false, UniqueFor = UniqueForOption.None, diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/ExampleTemplateTest.cs b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/ExampleTemplateTest.cs index 7f40b9ec3c..c61eb66459 100644 --- a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/ExampleTemplateTest.cs +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/ExampleTemplateTest.cs @@ -24,7 +24,6 @@ public async void VerificationEngineSampleDogfoodTest() string templateShortName = "TestAssets.SampleTestTemplate"; //get the template location - string executingAssemblyPath = GetType().Assembly.Location; string templateLocation = Path.Combine(TestTemplatesLocation, "TestTemplate"); TemplateVerifierOptions options = new TemplateVerifierOptions(templateName: templateShortName) @@ -38,7 +37,14 @@ public async void VerificationEngineSampleDogfoodTest() } .WithCustomScrubbers( ScrubbersDefinition.Empty - .AddScrubber(sb => sb.Replace("B is enabled", "*******"))); + .AddScrubber(sb => sb.Replace("B is enabled", "*******")) + .AddScrubber((path, content) => + { + if (path.Replace(Path.DirectorySeparatorChar, '/') == "std-streams/stdout.txt") + { + content.Replace("SampleTestTemplate", "%TEMPLATE%"); + } + })); VerificationEngine engine = new VerificationEngine(_log); await engine.Execute(options); diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.x64.verified/std-streams/stdout.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.x64.verified/std-streams/stdout.txt deleted file mode 100644 index 9e2d2f7ea3..0000000000 --- a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.x64.verified/std-streams/stdout.txt +++ /dev/null @@ -1 +0,0 @@ -The template "SampleTestTemplate" was created successfully. \ No newline at end of file diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.x64.verified/TestAssets.SampleTestTemplate/Test.cs b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/VerificationEngineSampleDogfoodTest.TestAssets.SampleTestTemplate.--paramB#true.x64.verified/TestAssets.SampleTestTemplate/Test.cs similarity index 100% rename from test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.x64.verified/TestAssets.SampleTestTemplate/Test.cs rename to test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/VerificationEngineSampleDogfoodTest.TestAssets.SampleTestTemplate.--paramB#true.x64.verified/TestAssets.SampleTestTemplate/Test.cs diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.x64.verified/std-streams/stderr.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/VerificationEngineSampleDogfoodTest.TestAssets.SampleTestTemplate.--paramB#true.x64.verified/std-streams/stderr.txt similarity index 100% rename from test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/TestAssets.SampleTestTemplate.--paramB#true.x64.verified/std-streams/stderr.txt rename to test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/VerificationEngineSampleDogfoodTest.TestAssets.SampleTestTemplate.--paramB#true.x64.verified/std-streams/stderr.txt diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/VerificationEngineSampleDogfoodTest.TestAssets.SampleTestTemplate.--paramB#true.x64.verified/std-streams/stdout.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/VerificationEngineSampleDogfoodTest.TestAssets.SampleTestTemplate.--paramB#true.x64.verified/std-streams/stdout.txt new file mode 100644 index 0000000000..5a67fb40d4 --- /dev/null +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.IntegrationTests/Expectations/VerificationEngineSampleDogfoodTest.TestAssets.SampleTestTemplate.--paramB#true.x64.verified/std-streams/stdout.txt @@ -0,0 +1 @@ +The template "%TEMPLATE%" was created successfully. \ 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/stderr.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/ExecuteSucceedsOnExpectedInstantiationFailure.made-up-template.--a#-b#c#--d.verified/std-streams/stderr.txt similarity index 100% rename from test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--a#-b#c#--d.verified/std-streams/stderr.txt rename to test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/ExecuteSucceedsOnExpectedInstantiationFailure.made-up-template.--a#-b#c#--d.verified/std-streams/stderr.txt 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/ExecuteSucceedsOnExpectedInstantiationFailure.made-up-template.--a#-b#c#--d.verified/std-streams/stdout.txt similarity index 100% rename from test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--a#-b#c#--d.verified/std-streams/stdout.txt rename to test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/ExecuteSucceedsOnExpectedInstantiationFailure.made-up-template.--a#-b#c#--d.verified/std-streams/stdout.txt 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/ExecuteSucceedsOnExpectedInstantiationFailure.made-up-template.--x#y#-z.verified/std-streams/stderr.txt similarity index 100% rename from test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--x#y#-z.verified/std-streams/stderr.txt rename to test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/ExecuteSucceedsOnExpectedInstantiationFailure.made-up-template.--x#y#-z.verified/std-streams/stderr.txt 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/ExecuteSucceedsOnExpectedInstantiationFailure.made-up-template.--x#y#-z.verified/std-streams/stdout.txt similarity index 100% rename from test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/made-up-template.--x#y#-z.verified/std-streams/stdout.txt rename to test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/ExecuteSucceedsOnExpectedInstantiationFailure.made-up-template.--x#y#-z.verified/std-streams/stdout.txt diff --git a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/ExecuteSucceedsOnExpectedInstantiationSuccess.made-up-template.--x#y#-z.verified/std-streams/stderr.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/ExecuteSucceedsOnExpectedInstantiationSuccess.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/ExecuteSucceedsOnExpectedInstantiationSuccess.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/ExecuteSucceedsOnExpectedInstantiationSuccess.made-up-template.--x#y#-z.verified/std-streams/stdout.txt b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/Expectations/ExecuteSucceedsOnExpectedInstantiationSuccess.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/ExecuteSucceedsOnExpectedInstantiationSuccess.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/VerificationEngineTests.cs b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/VerificationEngineTests.cs index a864213353..9d66048a31 100644 --- a/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/VerificationEngineTests.cs +++ b/test/Microsoft.TemplateEngine.Authoring.TemplateVerifier.UnitTests/VerificationEngineTests.cs @@ -36,16 +36,16 @@ public async void CreateVerificationTaskWithCustomScrubbersAndVerifier() A.CallTo(() => fileSystem.EnumerateFiles(verifyLocation, "*", SearchOption.AllDirectories)).Returns(files.Keys); A.CallTo(() => fileSystem.ReadAllTextAsync(A._, A._)) .ReturnsLazily((string fileName, CancellationToken _) => Task.FromResult(files[fileName])); + A.CallTo(() => fileSystem.PathRelativeTo(A._, A._)) + .ReturnsLazily((string target, string relativeTo) => target); Dictionary resultContents = new Dictionary(); TemplateVerifierOptions options = new TemplateVerifierOptions(templateName: "console") { TemplateSpecificArgs = null, - DisableDiffTool = null, OutputDirectory = verifyLocation, VerificationExcludePatterns = new[] { "*.dll" }, - VerifyCommandOutput = null, UniqueFor = null, } .WithCustomScrubbers( @@ -63,7 +63,7 @@ public async void CreateVerificationTaskWithCustomScrubbersAndVerifier() } }); - await VerificationEngine.CreateVerificationTask(verifyLocation, "callerLocation", options, fileSystem); + await VerificationEngine.CreateVerificationTask(verifyLocation, "callerLocation", null, options, fileSystem); resultContents.Keys.Count.Should().Be(2); resultContents["Program.cs"].Should().BeEquivalentTo("zz xx cc");