From 00a66a407052043e3dca0b6a75e54c173f4f9041 Mon Sep 17 00:00:00 2001 From: Vlada Shubina Date: Fri, 21 May 2021 13:54:25 +0300 Subject: [PATCH] fixes dotnet/templating#3038 show all available short names for template group --- .../HelpAndUsage/HelpForTemplateResolution.cs | 2 +- .../TableOutput/TemplateGroupDisplay.cs | 63 ++++++++------- .../TableOutput/TemplateGroupTableRow.cs | 4 +- .../TemplateResolution/TemplateGroup.cs | 15 ++-- .../TemplateInfoWithGroupShortNames.cs | 77 +++++++++++++++++++ .../TemplateResolution/TemplateResolver.cs | 66 +--------------- .../CliTemplateSearchCoordinator.cs | 2 +- .../MultiShortNameResolutionTests.cs | 41 +++++----- .../DotnetNewInstantiate.cs | 28 ++++++- test/dotnet-new3.UnitTests/DotnetNewList.cs | 48 +++++++++++- 10 files changed, 223 insertions(+), 123 deletions(-) create mode 100644 src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateInfoWithGroupShortNames.cs diff --git a/src/Microsoft.TemplateEngine.Cli/HelpAndUsage/HelpForTemplateResolution.cs b/src/Microsoft.TemplateEngine.Cli/HelpAndUsage/HelpForTemplateResolution.cs index d662cdf1d54..014b77d7da2 100644 --- a/src/Microsoft.TemplateEngine.Cli/HelpAndUsage/HelpForTemplateResolution.cs +++ b/src/Microsoft.TemplateEngine.Cli/HelpAndUsage/HelpForTemplateResolution.cs @@ -475,7 +475,7 @@ private static void DisplayTemplateList( headerSeparator: '-', blankLineBetweenRows: false) .DefineColumn(t => t.Name, out object nameColumn, LocalizableStrings.ColumnNameTemplateName, shrinkIfNeeded: true, minWidth: 15, showAlways: true) - .DefineColumn(t => t.ShortName, LocalizableStrings.ColumnNameShortName, showAlways: true) + .DefineColumn(t => t.ShortNames, LocalizableStrings.ColumnNameShortName, showAlways: true) .DefineColumn(t => t.Languages, out object languageColumn, LocalizableStrings.ColumnNameLanguage, NewCommandInputCli.LanguageColumnFilter, defaultColumn: true) .DefineColumn(t => t.Type, LocalizableStrings.ColumnNameType, NewCommandInputCli.TypeColumnFilter, defaultColumn: false) .DefineColumn(t => t.Author, LocalizableStrings.ColumnNameAuthor, NewCommandInputCli.AuthorColumnFilter, defaultColumn: false, shrinkIfNeeded: true, minWidth: 10) diff --git a/src/Microsoft.TemplateEngine.Cli/TableOutput/TemplateGroupDisplay.cs b/src/Microsoft.TemplateEngine.Cli/TableOutput/TemplateGroupDisplay.cs index 026b88ee7b8..71655643672 100644 --- a/src/Microsoft.TemplateEngine.Cli/TableOutput/TemplateGroupDisplay.cs +++ b/src/Microsoft.TemplateEngine.Cli/TableOutput/TemplateGroupDisplay.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable enable + using System; using System.Collections.Generic; using System.Linq; @@ -26,13 +28,25 @@ internal static class TemplateGroupDisplay /// language from the command input. /// default language. /// - internal static IReadOnlyList GetTemplateGroupsForListDisplay(IEnumerable templateList, string language, string defaultLanguage) + internal static IReadOnlyList GetTemplateGroupsForListDisplay(IEnumerable templateList, string? language, string? defaultLanguage) { List templateGroupsForDisplay = new List(); - IEnumerable> groupedTemplateList = templateList.GroupBy(x => x.GroupIdentity, x => !string.IsNullOrEmpty(x.GroupIdentity), StringComparer.OrdinalIgnoreCase); - foreach (IGrouping grouping in groupedTemplateList) + IEnumerable> groupedTemplateList = templateList.GroupBy(x => x.GroupIdentity, x => !string.IsNullOrEmpty(x.GroupIdentity), StringComparer.OrdinalIgnoreCase); + foreach (IGrouping templateGroup in groupedTemplateList) { - templateGroupsForDisplay.Add(GetTemplateGroupRow(grouping, language, defaultLanguage)); + ITemplateInfo highestPrecedenceTemplate = templateGroup.OrderByDescending(x => x.Precedence).First(); + string shortNames = string.Join(",", templateGroup.SelectMany(t => t.ShortNameList).Distinct(StringComparer.OrdinalIgnoreCase)); + + TemplateGroupTableRow groupDisplayInfo = new TemplateGroupTableRow + { + Name = highestPrecedenceTemplate.Name, + ShortNames = shortNames, + Languages = string.Join(",", GetLanguagesToDisplay(templateGroup, language, defaultLanguage)), + Classifications = highestPrecedenceTemplate.Classifications != null ? string.Join("/", highestPrecedenceTemplate.Classifications) : string.Empty, + Author = highestPrecedenceTemplate.Author ?? string.Empty, + Type = highestPrecedenceTemplate.GetTemplateType() ?? string.Empty + }; + templateGroupsForDisplay.Add(groupDisplayInfo); } return templateGroupsForDisplay; @@ -52,24 +66,34 @@ internal static IReadOnlyList GetTemplateGroupsForListDis /// language from the command input. /// default language. /// - internal static IReadOnlyList GetTemplateGroupsForListDisplay(IReadOnlyCollection templateGroupList, string language, string defaultLanguage) + internal static IReadOnlyList GetTemplateGroupsForListDisplay(IReadOnlyCollection templateGroupList, string? language, string? defaultLanguage) { List templateGroupsForDisplay = new List(); foreach (TemplateGroup templateGroup in templateGroupList) { - templateGroupsForDisplay.Add(GetTemplateGroupRow(templateGroup.Templates.Select(mi => mi.Info), language, defaultLanguage)); + ITemplateInfo highestPrecedenceTemplate = templateGroup.Templates.OrderByDescending(x => x.Info.Precedence).First().Info; + TemplateGroupTableRow groupDisplayInfo = new TemplateGroupTableRow + { + Name = highestPrecedenceTemplate.Name, + ShortNames = string.Join(",", templateGroup.ShortNames), + Languages = string.Join(",", GetLanguagesToDisplay(templateGroup.Templates.Select(t => t.Info), language, defaultLanguage)), + Classifications = highestPrecedenceTemplate.Classifications != null ? string.Join("/", highestPrecedenceTemplate.Classifications) : string.Empty, + Author = highestPrecedenceTemplate.Author ?? string.Empty, + Type = highestPrecedenceTemplate.GetTemplateType() ?? string.Empty + }; + templateGroupsForDisplay.Add(groupDisplayInfo); } return templateGroupsForDisplay; } - private static TemplateGroupTableRow GetTemplateGroupRow(IEnumerable templateGroup, string language, string defaultLanguage) + private static IEnumerable GetLanguagesToDisplay(IEnumerable templateGroup, string? language, string? defaultLanguage) { - List languageForDisplay = new List(); + List languagesForDisplay = new List(); HashSet uniqueLanguages = new HashSet(StringComparer.OrdinalIgnoreCase); string defaultLanguageDisplay = string.Empty; foreach (ITemplateInfo template in templateGroup) { - string lang = template.GetLanguage(); + string? lang = template.GetLanguage(); if (string.IsNullOrWhiteSpace(lang)) { continue; @@ -85,29 +109,16 @@ private static TemplateGroupTableRow GetTemplateGroupRow(IEnumerable x.Precedence).First(); - string shortName = highestPrecedenceTemplate.ShortNameList[0]; - - TemplateGroupTableRow groupDisplayInfo = new TemplateGroupTableRow - { - Name = highestPrecedenceTemplate.Name, - ShortName = shortName, - Languages = string.Join(",", languageForDisplay), - Classifications = highestPrecedenceTemplate.Classifications != null ? string.Join("/", highestPrecedenceTemplate.Classifications) : null, - Author = highestPrecedenceTemplate.Author, - Type = highestPrecedenceTemplate.GetTemplateType() ?? string.Empty - }; - return groupDisplayInfo; + return languagesForDisplay; } } } diff --git a/src/Microsoft.TemplateEngine.Cli/TableOutput/TemplateGroupTableRow.cs b/src/Microsoft.TemplateEngine.Cli/TableOutput/TemplateGroupTableRow.cs index c8dbce9f841..10526577833 100644 --- a/src/Microsoft.TemplateEngine.Cli/TableOutput/TemplateGroupTableRow.cs +++ b/src/Microsoft.TemplateEngine.Cli/TableOutput/TemplateGroupTableRow.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable enable + namespace Microsoft.TemplateEngine.Cli.TableOutput { /// @@ -16,7 +18,7 @@ internal struct TemplateGroupTableRow internal string Name { get; set; } - internal string ShortName { get; set; } + internal string ShortNames { get; set; } internal string Type { get; set; } } diff --git a/src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateGroup.cs b/src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateGroup.cs index 4cd738783ce..74764046dbb 100644 --- a/src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateGroup.cs +++ b/src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateGroup.cs @@ -63,14 +63,17 @@ internal IReadOnlyList ShortNames { get { - if (HasSingleTemplate) - { - return Templates.First().Info.ShortNameList; - } - HashSet shortNames = new HashSet(); + HashSet shortNames = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (ITemplateMatchInfo template in Templates) { - shortNames.UnionWith(template.Info.ShortNameList); + if (template.Info is TemplateInfoWithGroupShortNames groupAwareTemplate) + { + shortNames.UnionWith(groupAwareTemplate.GroupShortNameList); + } + else + { + shortNames.UnionWith(template.Info.ShortNameList); + } } return shortNames.ToList(); } diff --git a/src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateInfoWithGroupShortNames.cs b/src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateInfoWithGroupShortNames.cs new file mode 100644 index 00000000000..e680ccce085 --- /dev/null +++ b/src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateInfoWithGroupShortNames.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.TemplateEngine.Abstractions; + +namespace Microsoft.TemplateEngine.Cli.TemplateResolution +{ + /// + /// In addition to the class contains property which contains the short names of other templates in the template group. + /// The class is used for template filtering using specific TemplateResolver.CliNameFilter which takes into account the short names of template group when matching names. + /// + internal class TemplateInfoWithGroupShortNames : ITemplateInfo + { + private ITemplateInfo _parent; + + internal TemplateInfoWithGroupShortNames(ITemplateInfo source, IEnumerable groupShortNameList) + { + _parent = source; + GroupShortNameList = groupShortNameList.ToList(); + } + + public string? Author => _parent.Author; + + public string? Description => _parent.Description; + + public IReadOnlyList Classifications => _parent.Classifications; + + public string? DefaultName => _parent.DefaultName; + + public string Identity => _parent.Identity; + + public Guid GeneratorId => _parent.GeneratorId; + + public string? GroupIdentity => _parent.GroupIdentity; + + public int Precedence => _parent.Precedence; + + public string Name => _parent.Name; + + [Obsolete] + public string ShortName => _parent.ShortName; + + public IReadOnlyList ShortNameList => _parent.ShortNameList; + + public IReadOnlyList GroupShortNameList { get; } = new List(); + + [Obsolete] + public IReadOnlyDictionary Tags => _parent.Tags; + + [Obsolete] + public IReadOnlyDictionary CacheParameters => _parent.CacheParameters; + + public IReadOnlyList Parameters => _parent.Parameters; + + public string MountPointUri => _parent.MountPointUri; + + public string ConfigPlace => _parent.ConfigPlace; + + public string? LocaleConfigPlace => _parent.LocaleConfigPlace; + + public string? HostConfigPlace => _parent.HostConfigPlace; + + public string? ThirdPartyNotices => _parent.ThirdPartyNotices; + + public IReadOnlyDictionary BaselineInfo => _parent.BaselineInfo; + + public IReadOnlyDictionary TagsCollection => _parent.TagsCollection; + + bool ITemplateInfo.HasScriptRunningPostActions { get; set; } + + } +} diff --git a/src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateResolver.cs b/src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateResolver.cs index 2da441f3cb0..435a71e66b1 100644 --- a/src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateResolver.cs +++ b/src/Microsoft.TemplateEngine.Cli/TemplateResolution/TemplateResolver.cs @@ -391,7 +391,7 @@ private static IReadOnlyList SetupTemplateInfoWithGroupShortNames if (!shortNamesByGroup.TryGetValue(effectiveGroupIdentity, out HashSet? shortNames)) { - shortNames = new HashSet(); + shortNames = new HashSet(StringComparer.OrdinalIgnoreCase); shortNamesByGroup[effectiveGroupIdentity] = shortNames; } shortNames.UnionWith(template.ShortNameList); @@ -471,69 +471,5 @@ private static bool IsTemplateHiddenByHostFile(ITemplateInfo templateInfo, IHost HostSpecificTemplateData hostData = hostDataLoader.ReadHostSpecificTemplateData(templateInfo); return hostData.IsHidden; } - - /// - /// In addition to the class contains property which contains the short names of other templates in the template group. - /// The class is used for template filtering using specific filter which takes into account the short names of template group when matching names. - /// - private class TemplateInfoWithGroupShortNames : ITemplateInfo - { - private ITemplateInfo _parent; - - internal TemplateInfoWithGroupShortNames(ITemplateInfo source, IEnumerable groupShortNameList) - { - _parent = source; - GroupShortNameList = groupShortNameList.ToList(); - } - - public string? Author => _parent.Author; - - public string? Description => _parent.Description; - - public IReadOnlyList Classifications => _parent.Classifications; - - public string? DefaultName => _parent.DefaultName; - - public string Identity => _parent.Identity; - - public Guid GeneratorId => _parent.GeneratorId; - - public string? GroupIdentity => _parent.GroupIdentity; - - public int Precedence => _parent.Precedence; - - public string Name => _parent.Name; - - [Obsolete] - public string ShortName => _parent.ShortName; - - public IReadOnlyList ShortNameList => _parent.ShortNameList; - - public IReadOnlyList GroupShortNameList { get; } = new List(); - - [Obsolete] - public IReadOnlyDictionary Tags => _parent.Tags; - - [Obsolete] - public IReadOnlyDictionary CacheParameters => _parent.CacheParameters; - - public IReadOnlyList Parameters => _parent.Parameters; - - public string MountPointUri => _parent.MountPointUri; - - public string ConfigPlace => _parent.ConfigPlace; - - public string? LocaleConfigPlace => _parent.LocaleConfigPlace; - - public string? HostConfigPlace => _parent.HostConfigPlace; - - public string? ThirdPartyNotices => _parent.ThirdPartyNotices; - - public IReadOnlyDictionary BaselineInfo => _parent.BaselineInfo; - - public IReadOnlyDictionary TagsCollection => _parent.TagsCollection; - - bool ITemplateInfo.HasScriptRunningPostActions { get; set; } - } } } diff --git a/src/Microsoft.TemplateEngine.Cli/TemplateSearch/CliTemplateSearchCoordinator.cs b/src/Microsoft.TemplateEngine.Cli/TemplateSearch/CliTemplateSearchCoordinator.cs index 2acf9571ee7..7a2028571aa 100644 --- a/src/Microsoft.TemplateEngine.Cli/TemplateSearch/CliTemplateSearchCoordinator.cs +++ b/src/Microsoft.TemplateEngine.Cli/TemplateSearch/CliTemplateSearchCoordinator.cs @@ -102,7 +102,7 @@ private static void DisplayResultsForPack(TemplateSourceSearchResult sourceResul headerSeparator: '-', blankLineBetweenRows: false) .DefineColumn(r => r.TemplateGroupInfo.Name, out object nameColumn, LocalizableStrings.ColumnNameTemplateName, showAlways: true, shrinkIfNeeded: true, minWidth: 15) - .DefineColumn(r => r.TemplateGroupInfo.ShortName, LocalizableStrings.ColumnNameShortName, showAlways: true) + .DefineColumn(r => r.TemplateGroupInfo.ShortNames, LocalizableStrings.ColumnNameShortName, showAlways: true) .DefineColumn(r => r.TemplateGroupInfo.Author, LocalizableStrings.ColumnNameAuthor, NewCommandInputCli.AuthorColumnFilter, defaultColumn: true, shrinkIfNeeded: true, minWidth: 10) .DefineColumn(r => r.TemplateGroupInfo.Languages, LocalizableStrings.ColumnNameLanguage, NewCommandInputCli.LanguageColumnFilter, defaultColumn: true) .DefineColumn(r => r.TemplateGroupInfo.Type, LocalizableStrings.ColumnNameType, NewCommandInputCli.TypeColumnFilter, defaultColumn: false) diff --git a/test/Microsoft.TemplateEngine.Cli.UnitTests/TemplateResolutionTests/MultiShortNameResolutionTests.cs b/test/Microsoft.TemplateEngine.Cli.UnitTests/TemplateResolutionTests/MultiShortNameResolutionTests.cs index 9735b42eb90..3bde033e081 100644 --- a/test/Microsoft.TemplateEngine.Cli.UnitTests/TemplateResolutionTests/MultiShortNameResolutionTests.cs +++ b/test/Microsoft.TemplateEngine.Cli.UnitTests/TemplateResolutionTests/MultiShortNameResolutionTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable enable + using System; using System.Collections.Generic; using System.Linq; @@ -17,7 +19,7 @@ namespace Microsoft.TemplateEngine.Cli.UnitTests.TemplateResolutionTests { public class MultiShortNameResolutionTests { - private static IReadOnlyList _multiShortNameGroupTemplateInfo; + private static IReadOnlyList? _multiShortNameGroupTemplateInfo; private static IReadOnlyList MultiShortNameGroupTemplateInfo { @@ -57,20 +59,23 @@ private static IReadOnlyList MultiShortNameGroupTemplateInfo } } + private static readonly IReadOnlyList _shortNamesForGroup = new [] { "aaa", "bbb", "ccc", "ddd", "eee", "fff" }; + [Fact(DisplayName = nameof(AllTemplatesInGroupUseAllShortNamesForResolution))] public void AllTemplatesInGroupUseAllShortNamesForResolution() { - IReadOnlyList shortNamesForGroup = new List() - { - "aaa", "bbb", "ccc", "ddd", "eee", "fff" - }; string defaultLanguage = "C#"; - foreach (string testShortName in shortNamesForGroup) + foreach (string testShortName in _shortNamesForGroup) { INewCommandInput userInputs = new MockNewCommandInput(testShortName); - TemplateResolutionResult matchResult = TemplateResolver.GetTemplateResolutionResult(MultiShortNameGroupTemplateInfo, new MockHostSpecificDataLoader(), userInputs, defaultLanguage); + TemplateResolutionResult matchResult = TemplateResolver.GetTemplateResolutionResult( + MultiShortNameGroupTemplateInfo, + new MockHostSpecificDataLoader(), + userInputs, + defaultLanguage); + Assert.Equal(TemplateResolutionResult.UnambiguousTemplateGroupStatus.SingleMatch, matchResult.GroupResolutionStatus); Assert.Equal(3, matchResult.UnambiguousTemplateGroup.Templates.Count); Assert.True(matchResult.UnambiguousTemplateGroup.Templates.All(t => WellKnownSearchFilters.MatchesAllCriteria(t))); @@ -78,7 +83,7 @@ public void AllTemplatesInGroupUseAllShortNamesForResolution() foreach (ITemplateMatchInfo templateMatchInfo in matchResult.UnambiguousTemplateGroup.Templates) { Assert.Equal("MultiName.Test", templateMatchInfo.Info.GroupIdentity); - if (templateMatchInfo.Info.GetLanguage().Equals(defaultLanguage, StringComparison.OrdinalIgnoreCase)) + if (templateMatchInfo.Info.GetLanguage()?.Equals(defaultLanguage, StringComparison.OrdinalIgnoreCase) ?? false) { //default language match is part of MatchDisposition collection Assert.Equal(2, templateMatchInfo.MatchDisposition.Count); @@ -89,42 +94,34 @@ public void AllTemplatesInGroupUseAllShortNamesForResolution() } Assert.True(templateMatchInfo.MatchDisposition[0].Name == MatchInfo.BuiltIn.ShortName && templateMatchInfo.MatchDisposition[0].Kind == MatchKind.Exact); } + Assert.Equal(_shortNamesForGroup, matchResult.UnambiguousTemplateGroup.ShortNames); } } [Fact(DisplayName = nameof(HighestPrecedenceWinsWithMultipleShortNames))] public void HighestPrecedenceWinsWithMultipleShortNames() { - IReadOnlyList shortNamesForGroup = new List() - { - "aaa", "bbb", "ccc", "ddd", "eee", "fff" - }; - - foreach (string testShortName in shortNamesForGroup) + foreach (string testShortName in _shortNamesForGroup) { INewCommandInput userInputs = new MockNewCommandInput(testShortName); TemplateResolutionResult matchResult = TemplateResolver.GetTemplateResolutionResult(MultiShortNameGroupTemplateInfo, new MockHostSpecificDataLoader(), userInputs, "C#"); Assert.Equal(TemplateResolutionResult.Status.SingleMatch, matchResult.ResolutionStatus); Assert.Equal("MultiName.Test.High.CSharp", matchResult.TemplateToInvoke.Info.Identity); + Assert.Equal(_shortNamesForGroup, matchResult.UnambiguousTemplateGroup.ShortNames); } } [Fact(DisplayName = nameof(ExplicitLanguageChoiceIsHonoredWithMultipleShortNames))] public void ExplicitLanguageChoiceIsHonoredWithMultipleShortNames() { - IReadOnlyList shortNamesForGroup = new List() - { - "aaa", "bbb", "ccc", "ddd", "eee", "fff" - }; - - foreach (string testShortName in shortNamesForGroup) + foreach (string testShortName in _shortNamesForGroup) { INewCommandInput userInputs = new MockNewCommandInput(testShortName, "F#"); - TemplateResolutionResult matchResult = TemplateResolver.GetTemplateResolutionResult(MultiShortNameGroupTemplateInfo, new MockHostSpecificDataLoader(), userInputs, "C#"); Assert.Equal(TemplateResolutionResult.Status.SingleMatch, matchResult.ResolutionStatus); Assert.Equal("Multiname.Test.Only.FSharp", matchResult.TemplateToInvoke.Info.Identity); + Assert.Equal(_shortNamesForGroup, matchResult.UnambiguousTemplateGroup.ShortNames); } } @@ -142,6 +139,7 @@ public void ChoiceValueDisambiguatesMatchesWithMultipleShortNames(string name, s TemplateResolutionResult matchResult = TemplateResolver.GetTemplateResolutionResult(MultiShortNameGroupTemplateInfo, new MockHostSpecificDataLoader(), commandInput, "C#"); Assert.Equal(TemplateResolutionResult.Status.SingleMatch, matchResult.ResolutionStatus); Assert.Equal(expectedIdentity, matchResult.TemplateToInvoke.Info.Identity); + Assert.Equal(_shortNamesForGroup, matchResult.UnambiguousTemplateGroup.ShortNames); } [Theory(DisplayName = nameof(ParameterExistenceDisambiguatesMatchesWithMultipleShortNames))] @@ -158,6 +156,7 @@ public void ParameterExistenceDisambiguatesMatchesWithMultipleShortNames(string TemplateResolutionResult matchResult = TemplateResolver.GetTemplateResolutionResult(MultiShortNameGroupTemplateInfo, new MockHostSpecificDataLoader(), commandInput, "C#"); Assert.Equal(TemplateResolutionResult.Status.SingleMatch, matchResult.ResolutionStatus); Assert.Equal(expectedIdentity, matchResult.TemplateToInvoke.Info.Identity); + Assert.Equal(_shortNamesForGroup, matchResult.UnambiguousTemplateGroup.ShortNames); } } } diff --git a/test/dotnet-new3.UnitTests/DotnetNewInstantiate.cs b/test/dotnet-new3.UnitTests/DotnetNewInstantiate.cs index 65540034812..533073d3c30 100644 --- a/test/dotnet-new3.UnitTests/DotnetNewInstantiate.cs +++ b/test/dotnet-new3.UnitTests/DotnetNewInstantiate.cs @@ -300,6 +300,32 @@ public void CanOverwriteFilesWithForce() .And.HaveStdOutContaining("The template \"Console Application\" was created successfully."); Assert.Equal(commandResult.StdOut, forceCommandResult.StdOut); - } + } + + [Fact] + public void CanInstantiateTemplateWithSecondShortName() + { + string home = TestUtils.CreateTemporaryFolder("Home"); + string workingDirectory = TestUtils.CreateTemporaryFolder(); + Helpers.InstallNuGetTemplate("Microsoft.DotNet.Web.ProjectTemplates.5.0", _log, workingDirectory, home); + + new DotnetNewCommand(_log, "webapp", "-o", "webapp") + .WithCustomHive(home) + .WithWorkingDirectory(workingDirectory) + .Execute() + .Should() + .ExitWith(0) + .And.NotHaveStdErr() + .And.HaveStdOutContaining("The template \"ASP.NET Core Web App\" was created successfully."); + + new DotnetNewCommand(_log, "razor", "-o", "razor") + .WithCustomHive(home) + .WithWorkingDirectory(workingDirectory) + .Execute() + .Should() + .ExitWith(0) + .And.NotHaveStdErr() + .And.HaveStdOutContaining("The template \"ASP.NET Core Web App\" was created successfully."); + } } } diff --git a/test/dotnet-new3.UnitTests/DotnetNewList.cs b/test/dotnet-new3.UnitTests/DotnetNewList.cs index 2db8a0b0917..450e19b90c0 100644 --- a/test/dotnet-new3.UnitTests/DotnetNewList.cs +++ b/test/dotnet-new3.UnitTests/DotnetNewList.cs @@ -73,7 +73,7 @@ public void CanSortByName() ASP.NET Core Empty web [C#],F# Web/Empty ASP.NET Core gRPC Service grpc [C#] Web/gRPC ASP.NET Core Web API webapi [C#],F# Web/WebAPI -ASP.NET Core Web App webapp [C#] Web/MVC/Razor Pages +ASP.NET Core Web App webapp,razor [C#] Web/MVC/Razor Pages ASP.NET Core Web App (Model-View-Controller) mvc [C#],F# Web/MVC Blazor Server App blazorserver [C#] Web/Blazor Blazor WebAssembly App blazorwasm [C#] Web/Blazor/WebAssembly @@ -98,7 +98,53 @@ Web Config webconfig Config .ExitWith(0) .And.HaveStdOut(expectedOutput) .And.NotHaveStdErr(); + } + + [Fact] + public void CanShowMultipleShortNames() + { + string home = TestUtils.CreateTemporaryFolder("Home"); + string workingDirectory = TestUtils.CreateTemporaryFolder(); + + new DotnetNewCommand(_log, "-i", "Microsoft.DotNet.Web.ProjectTemplates.5.0") + .WithCustomHive(home) + .WithWorkingDirectory(workingDirectory) + .Execute() + .Should() + .ExitWith(0) + .And + .NotHaveStdErr() + .And.HaveStdOutMatching("ASP\\.NET Core Web App\\s+webapp,razor\\s+\\[C#\\]\\s+Web/MVC/Razor Pages"); + + new DotnetNewCommand(_log, "--list") + .WithCustomHive(home) + .WithoutBuiltInTemplates() + .WithWorkingDirectory(workingDirectory) + .Execute() + .Should() + .ExitWith(0) + .And.NotHaveStdErr() + .And.HaveStdOutMatching("ASP\\.NET Core Web App\\s+webapp,razor\\s+\\[C#\\]\\s+Web/MVC/Razor Pages"); + new DotnetNewCommand(_log, "webapp", "--list") + .WithCustomHive(home) + .WithoutBuiltInTemplates() + .WithWorkingDirectory(workingDirectory) + .Execute() + .Should() + .ExitWith(0) + .And.NotHaveStdErr() + .And.HaveStdOutMatching("ASP\\.NET Core Web App\\s+webapp,razor\\s+\\[C#\\]\\s+Web/MVC/Razor Pages"); + + new DotnetNewCommand(_log, "razor", "--list") + .WithCustomHive(home) + .WithoutBuiltInTemplates() + .WithWorkingDirectory(workingDirectory) + .Execute() + .Should() + .ExitWith(0) + .And.NotHaveStdErr() + .And.HaveStdOutMatching("ASP\\.NET Core Web App\\s+webapp,razor\\s+\\[C#\\]\\s+Web/MVC/Razor Pages"); } } }