@@ -1467,6 +1467,76 @@ public async Task AddCommandInteractiveDoesNotPromptForVersionWhenSpecifiedVersi
14671467 Assert . All ( exactMatchQueries , query => Assert . Equal ( "Aspire.Hosting.Redis" , query ) ) ;
14681468 }
14691469
1470+ [ Theory ]
1471+ [ InlineData ( "redis" ) ]
1472+ [ InlineData ( "Aspire.Hosting.Redis" ) ]
1473+ public async Task AddCommandInteractiveDoesNotPromptForIntegrationWhenExactMatchIsFound ( string integrationName )
1474+ {
1475+ var promptedForIntegration = false ;
1476+ var promptedForVersion = false ;
1477+ var selectedPackageName = string . Empty ;
1478+ var selectedPackageVersion = string . Empty ;
1479+
1480+ using var workspace = TemporaryWorkspace . Create ( outputHelper ) ;
1481+ var services = CliTestHelper . CreateServiceCollection ( workspace , outputHelper , options =>
1482+ {
1483+ options . CliHostEnvironmentFactory = _ => TestHelpers . CreateInteractiveHostEnvironment ( ) ;
1484+ options . AddCommandPrompterFactory = ( sp ) =>
1485+ {
1486+ var interactionService = sp . GetRequiredService < IInteractionService > ( ) ;
1487+ var prompter = new TestAddCommandPrompter ( interactionService ) ;
1488+ prompter . PromptForIntegrationCallback = ( packages ) =>
1489+ {
1490+ promptedForIntegration = true ;
1491+ throw new InvalidOperationException ( "Should not have been prompted for integration selection." ) ;
1492+ } ;
1493+ prompter . PromptForIntegrationVersionCallback = ( packages ) =>
1494+ {
1495+ promptedForVersion = true ;
1496+ return packages . Single ( package => package . Package . Version == "13.2.0" ) ;
1497+ } ;
1498+
1499+ return prompter ;
1500+ } ;
1501+
1502+ options . ProjectLocatorFactory = _ => new TestProjectLocator ( ) ;
1503+
1504+ options . DotNetCliRunnerFactory = ( sp ) =>
1505+ {
1506+ var runner = new TestDotNetCliRunner ( ) ;
1507+ runner . SearchPackagesAsyncCallback = ( dir , query , exactMatch , prerelease , take , skip , nugetSource , useCache , invocationOptions , cancellationToken ) =>
1508+ {
1509+ return ( 0 , [
1510+ new NuGetPackage { Id = "Aspire.Hosting.Redis" , Source = "nuget" , Version = "13.3.0" } ,
1511+ new NuGetPackage { Id = "Aspire.Hosting.Redis" , Source = "nuget" , Version = "13.2.0" }
1512+ ] ) ;
1513+ } ;
1514+
1515+ runner . AddPackageAsyncCallback = ( projectFilePath , packageName , packageVersion , nugetSource , noRestore , invocationOptions , cancellationToken ) =>
1516+ {
1517+ selectedPackageName = packageName ;
1518+ selectedPackageVersion = packageVersion ;
1519+ return 0 ;
1520+ } ;
1521+
1522+ return runner ;
1523+ } ;
1524+ } ) ;
1525+
1526+ using var provider = services . BuildServiceProvider ( ) ;
1527+
1528+ var command = provider . GetRequiredService < AddCommand > ( ) ;
1529+ var result = command . Parse ( $ "add { integrationName } ") ;
1530+
1531+ var exitCode = await result . InvokeAsync ( ) . DefaultTimeout ( ) ;
1532+
1533+ Assert . Equal ( 0 , exitCode ) ;
1534+ Assert . False ( promptedForIntegration ) ;
1535+ Assert . True ( promptedForVersion ) ;
1536+ Assert . Equal ( "Aspire.Hosting.Redis" , selectedPackageName ) ;
1537+ Assert . Equal ( "13.2.0" , selectedPackageVersion ) ;
1538+ }
1539+
14701540 [ Fact ]
14711541 public async Task AddCommandSearchesEachPackageIdOnceWhenExactMatchFallsBackAcrossSharedChannel ( )
14721542 {
@@ -2811,6 +2881,131 @@ public async Task AddCommand_NonInteractive_ExactMatchWithoutVersion_StillSuccee
28112881 Assert . Equal ( "Aspire.Hosting.Kubernetes" , addedPackage ) ;
28122882 }
28132883
2884+ [ Fact ]
2885+ public async Task AddCommand_Interactive_SingleFuzzyMatchPromptsBeforeAdding_Regression17724 ( )
2886+ {
2887+ var promptedPackages = new List < ( string FriendlyName , NuGetPackage Package , PackageChannel Channel ) > ( ) ;
2888+ var addedPackage = string . Empty ;
2889+
2890+ using var workspace = TemporaryWorkspace . Create ( outputHelper ) ;
2891+ var services = CliTestHelper . CreateServiceCollection ( workspace , outputHelper , options =>
2892+ {
2893+ options . CliHostEnvironmentFactory = _ => TestHelpers . CreateInteractiveHostEnvironment ( ) ;
2894+ options . AddCommandPrompterFactory = ( sp ) =>
2895+ {
2896+ var interactionService = sp . GetRequiredService < IInteractionService > ( ) ;
2897+ var prompter = new TestAddCommandPrompter ( interactionService ) ;
2898+ prompter . PromptForIntegrationCallback = ( packages ) =>
2899+ {
2900+ promptedPackages . AddRange ( packages ) ;
2901+ return packages . Single ( ) ;
2902+ } ;
2903+
2904+ return prompter ;
2905+ } ;
2906+ options . ProjectLocatorFactory = _ => new TestProjectLocator ( ) ;
2907+
2908+ options . DotNetCliRunnerFactory = ( sp ) =>
2909+ {
2910+ var runner = new TestDotNetCliRunner ( ) ;
2911+ runner . SearchPackagesAsyncCallback = ( dir , query , exactMatch , prerelease , take , skip , nugetSource , useCache , options , cancellationToken ) =>
2912+ {
2913+ return (
2914+ 0 ,
2915+ new NuGetPackage [ ]
2916+ {
2917+ new ( ) { Id = "Aspire.Hosting.Azure" , Source = "nuget" , Version = "9.2.0" }
2918+ } ) ;
2919+ } ;
2920+
2921+ runner . AddPackageAsyncCallback = ( projectFilePath , packageName , packageVersion , nugetSource , noRestore , options , cancellationToken ) =>
2922+ {
2923+ addedPackage = packageName ;
2924+ return 0 ;
2925+ } ;
2926+
2927+ return runner ;
2928+ } ;
2929+ } ) ;
2930+ using var provider = services . BuildServiceProvider ( ) ;
2931+
2932+ var command = provider . GetRequiredService < AddCommand > ( ) ;
2933+ var result = command . Parse ( "add kube" ) ;
2934+
2935+ var exitCode = await result . InvokeAsync ( ) . DefaultTimeout ( ) ;
2936+
2937+ var promptedPackage = Assert . Single ( promptedPackages ) ;
2938+ Assert . Equal ( 0 , exitCode ) ;
2939+ Assert . Equal ( "Aspire.Hosting.Azure" , promptedPackage . Package . Id ) ;
2940+ Assert . Equal ( "Aspire.Hosting.Azure" , addedPackage ) ;
2941+ }
2942+
2943+ [ Fact ]
2944+ public async Task AddCommand_Interactive_NoFuzzyMatchSinglePackagePromptsBeforeAdding ( )
2945+ {
2946+ var promptedPackages = new List < ( string FriendlyName , NuGetPackage Package , PackageChannel Channel ) > ( ) ;
2947+ var displayedSubtleMessage = string . Empty ;
2948+ var addedPackage = string . Empty ;
2949+ var testInteractionService = new TestInteractionService
2950+ {
2951+ DisplaySubtleMessageCallback = message => displayedSubtleMessage = message
2952+ } ;
2953+
2954+ using var workspace = TemporaryWorkspace . Create ( outputHelper ) ;
2955+ var services = CliTestHelper . CreateServiceCollection ( workspace , outputHelper , options =>
2956+ {
2957+ options . CliHostEnvironmentFactory = _ => TestHelpers . CreateInteractiveHostEnvironment ( ) ;
2958+ options . InteractionServiceFactory = _ => testInteractionService ;
2959+ options . AddCommandPrompterFactory = ( sp ) =>
2960+ {
2961+ var interactionService = sp . GetRequiredService < IInteractionService > ( ) ;
2962+ var prompter = new TestAddCommandPrompter ( interactionService ) ;
2963+ prompter . PromptForIntegrationCallback = ( packages ) =>
2964+ {
2965+ promptedPackages . AddRange ( packages ) ;
2966+ return packages . Single ( ) ;
2967+ } ;
2968+
2969+ return prompter ;
2970+ } ;
2971+ options . ProjectLocatorFactory = _ => new TestProjectLocator ( ) ;
2972+
2973+ options . DotNetCliRunnerFactory = ( sp ) =>
2974+ {
2975+ var runner = new TestDotNetCliRunner ( ) ;
2976+ runner . SearchPackagesAsyncCallback = ( dir , query , exactMatch , prerelease , take , skip , nugetSource , useCache , options , cancellationToken ) =>
2977+ {
2978+ return (
2979+ 0 ,
2980+ new NuGetPackage [ ]
2981+ {
2982+ new ( ) { Id = "Aspire.Hosting.Redis" , Source = "nuget" , Version = "9.2.0" }
2983+ } ) ;
2984+ } ;
2985+
2986+ runner . AddPackageAsyncCallback = ( projectFilePath , packageName , packageVersion , nugetSource , noRestore , options , cancellationToken ) =>
2987+ {
2988+ addedPackage = packageName ;
2989+ return 0 ;
2990+ } ;
2991+
2992+ return runner ;
2993+ } ;
2994+ } ) ;
2995+ using var provider = services . BuildServiceProvider ( ) ;
2996+
2997+ var command = provider . GetRequiredService < AddCommand > ( ) ;
2998+ var result = command . Parse ( "add zzzzzzzzzz" ) ;
2999+
3000+ var exitCode = await result . InvokeAsync ( ) . DefaultTimeout ( ) ;
3001+
3002+ var promptedPackage = Assert . Single ( promptedPackages ) ;
3003+ Assert . Equal ( 0 , exitCode ) ;
3004+ Assert . Equal ( string . Format ( AddCommandStrings . NoPackagesMatchedSearchTerm , "zzzzzzzzzz" ) , displayedSubtleMessage ) ;
3005+ Assert . Equal ( "Aspire.Hosting.Redis" , promptedPackage . Package . Id ) ;
3006+ Assert . Equal ( "Aspire.Hosting.Redis" , addedPackage ) ;
3007+ }
3008+
28143009 [ Fact ]
28153010 public async Task AddCommand_WithVersionAndNonExactPackageName_FailsInsteadOfUsingFuzzySearch ( )
28163011 {
0 commit comments