1- using System . ClientModel ;
2- using System . ClientModel . Primitives ;
31using System . CommandLine ;
42using System . CommandLine . Parsing ;
5- using Microsoft . Extensions . DependencyInjection ;
6- using Microsoft . Extensions . Logging ;
7- using Moq ;
83using Azure . AI . OpenAI ;
9- using OpenAI . Chat ;
104using Azure . Sdk . Tools . Cli . Helpers ;
5+ using Azure . Sdk . Tools . Cli . Microagents ;
116using Azure . Sdk . Tools . Cli . Services ;
127using Azure . Sdk . Tools . Cli . Tests . Mocks . Helpers ;
138using Azure . Sdk . Tools . Cli . Tests . TestHelpers ;
149using Azure . Sdk . Tools . Cli . Tools . Package ;
10+ using Microsoft . Extensions . DependencyInjection ;
11+ using Microsoft . Extensions . Logging ;
12+ using Moq ;
13+ using OpenAI . Chat ;
1514
1615namespace Azure . Sdk . Tools . Cli . Tests . Tools . Generators
1716{
@@ -20,7 +19,7 @@ internal class ReadMeGeneratorToolTests
2019 [ Test ]
2120 public async Task TestReadmeGeneratorTool ( )
2221 {
23- var testClients = SetupOpenAIMocks ( ) ;
22+ var testClients = SetupMocks ( ) ;
2423 ( DirectoryInfo root , string packagePath ) = await CreateFakeLanguageRepo ( ) ;
2524
2625 var readmeOutputPath = Path . GetTempFileName ( ) ;
@@ -84,6 +83,51 @@ public void TestReadmeGeneratorToolLive()
8483 } ) ;
8584 }
8685
86+ /// <summary>
87+ /// These tests all correspond to "LLM needs to do more work" type of returns from the tool, like removing
88+ /// hardcoded locales, like 'en-us', or having it regenerate if some of the templates tokens make it through
89+ /// and weren't replaced.
90+ /// </summary>
91+ /// <returns></returns>
92+ [ TestCase (
93+ "Bad link, still has locale in it: https://learn.microsoft.com/fr-fr/blahblah" ,
94+ "The readme contains links with locales. Keep the link, but remove these locales from links: (fr-fr)." , TestName = "Links with locales in them" ) ]
95+ [ TestCase (
96+ "Still referencing aztemplate and (package path)" ,
97+ "The readme contains placeholders (aztemplate,(package path)) that should be removed and replaced with a proper package name" ) ]
98+ [ TestCase (
99+ "Still referencing placeholder (package path)" ,
100+ "The readme contains placeholders ((package path)) that should be removed and replaced with a proper package name" ) ]
101+ public async Task TestBadReadmeContent ( string readmeContent , string expectedFeedback )
102+ {
103+ var testClients = SetupMocks ( readmeContent ) ;
104+ ( DirectoryInfo root , string packagePath ) = await CreateFakeLanguageRepo ( ) ;
105+
106+ var readmeOutputPath = Path . GetTempFileName ( ) ;
107+ var readmeTemplatePath = Path . Combine ( AppContext . BaseDirectory , "TestAssets" , "README-template.go.md" ) ;
108+
109+ try
110+ {
111+ var tool = ActivatorUtilities . CreateInstance < ReadMeGeneratorTool > ( testClients . ServiceProvider ) ;
112+ var command = tool . GetCommand ( ) ;
113+
114+ int exitCode = command . Invoke ( $ "--output-path \" { readmeOutputPath } \" --service-url \" https://learn.microsoft.com/azure/service-bus-messaging\" --template-path { readmeTemplatePath } --package-path { packagePath } ") ;
115+
116+ Assert . Multiple ( ( ) =>
117+ {
118+ Assert . That ( exitCode , Is . EqualTo ( 1 ) , "Command should fail, as the final readme doesn't pass validation" ) ;
119+ Assert . That ( testClients . OutputHelper . Outputs . First ( ) . Method , Is . EqualTo ( "OutputError" ) ) ;
120+ Assert . That ( testClients . OutputHelper . Outputs . First ( ) . OutputValue , Is . EqualTo ( $ "ReadmeGenerator failed with validation errors: { expectedFeedback } ") ) ;
121+ } ) ;
122+
123+ Assert . That ( File . Exists ( readmeOutputPath ) , Is . True , "Readme output file should be created" ) ;
124+ }
125+ finally
126+ {
127+ Directory . Delete ( root . FullName , true ) ;
128+ }
129+ }
130+
87131 /// <summary>
88132 /// Creates a service provider in the same way as the normal program. Can be used to instantiate real clients.
89133 /// </summary>
@@ -107,34 +151,19 @@ private static (ServiceProvider, MockOutputHelper) CreateServiceProvider(Action<
107151 return ( sp , OutputHelper ) ;
108152 }
109153
110- private static TestClients SetupOpenAIMocks ( )
154+ private static TestClients SetupMocks ( string readmeContents = "This is a test response for the readme generation." )
111155 {
112156 var ( openAIClientMock , chatClientMock ) = OpenAIMockHelper . Create ( "gpt-4.1" ) ;
113157
114- // basically - create a model using the appropriate OpenAI*ModelFactory
115- // then return it, wrapped in a ClientResult. This is really similar to the online samples
116- // except it's ClientResult (instead of Response).
117- var chatCompletion = OpenAIChatModelFactory . ChatCompletion (
118- content : new ChatMessageContent ( "This is a test response for the readme generation." )
119- ) ;
120-
121- chatClientMock
122- . Setup ( ccm => ccm . CompleteChatAsync ( It . IsAny < ChatMessage [ ] > ( ) ) ) // NOTE: I'm not checking the chat message input - I already know what I'm sending.
123- . Returns ( ( ) =>
124- {
125- return Task . FromResult (
126- ClientResult . FromValue ( chatCompletion , Mock . Of < PipelineResponse > ( ) )
127- ) ;
128- } ) ;
158+ var serviceMock = new Mock < IMicroagentHostService > ( ) ;
159+ serviceMock . Setup ( svc => svc . RunAgentToCompletion (
160+ It . IsAny < Microagent < ReadmeGenerator . ReadmeContents > > ( ) , It . IsAny < CancellationToken > ( ) )
161+ ) . Returns ( ( ) => Task . FromResult ( new ReadmeGenerator . ReadmeContents ( readmeContents ) ) ) ;
129162
130163 var ( serviceProvider , OutputHelper ) = CreateServiceProvider ( ( sc ) =>
131164 {
132165 sc . AddLogging ( ( lb ) => lb . AddConsole ( ) ) ;
133- sc . AddSingleton ( openAIClientMock . Object ) ;
134-
135- // register the mocks too, if you want to grab them later.
136- sc . AddSingleton ( chatClientMock ) ;
137- sc . AddSingleton ( openAIClientMock ) ;
166+ sc . AddSingleton ( serviceMock . Object ) ;
138167 } ) ;
139168
140169 return new TestClients ( openAIClientMock , chatClientMock , serviceProvider , OutputHelper ) ;
0 commit comments