66using Azure . Sdk . Tools . Cli . Models ;
77using Azure . Sdk . Tools . Cli . Services ;
88using Azure . Sdk . Tools . Cli . Services . Languages ;
9+ using Azure . Sdk . Tools . Cli . Services . SetupRequirements ;
910using Azure . Sdk . Tools . Cli . Tests . TestHelpers ;
1011using Azure . Sdk . Tools . Cli . Tools . Verify ;
1112using Microsoft . VisualStudio . Services . CircuitBreaker ;
@@ -58,7 +59,9 @@ public void Setup()
5859 return "unknown-repo" ; // default fallback
5960 } ) ;
6061
61- // Create temp directory for tests
62+ // Mock DiscoverRepoRootAsync for PackagePathParser.ParseAsync
63+ _mockGitHelper . Setup ( x => x . DiscoverRepoRootAsync ( It . IsAny < string > ( ) , It . IsAny < CancellationToken > ( ) ) )
64+ . ReturnsAsync ( ( string path , CancellationToken _ ) => path ?? "/test/repo" ) ;
6265
6366 languageServices = [
6467 new PythonLanguageService ( mockProcessHelper . Object , mockPythonHelper . Object , _mockNpxHelper . Object , _mockGitHelper . Object , _languageLogger , _commonValidationHelpers . Object , Mock . Of < IFileHelper > ( ) , Mock . Of < ISpecGenSdkConfigHelper > ( ) ) ,
@@ -75,7 +78,7 @@ private void SetupSuccessfulProcessMocks()
7578 {
7679 mockProcessHelper
7780 . Setup ( x => x . Run (
78- It . IsAny < ProcessOptions > ( ) , // Handle cases where command might be wrapped
81+ It . IsAny < ProcessOptions > ( ) ,
7982 It . IsAny < CancellationToken > ( ) ) )
8083
8184 . ReturnsAsync ( ( ProcessOptions processOptions , CancellationToken ct ) =>
@@ -89,13 +92,26 @@ private void SetupSuccessfulProcessMocks()
8992 { "pwsh" , "PowerShell 7.2.0" } ,
9093 { "gh" , "gh version 2.30.0" } ,
9194 { "python" , "Python 3.9.0" } ,
92- { "java" , "java 17.0.1" }
95+ { "pip" , "pip 24.0" } ,
96+ { "java" , "java 17.0.1" } ,
97+ { "mvn" , "Apache Maven 3.9.0" } ,
98+ { "dotnet" , "8.0.100" } ,
99+ { "go" , "go version go1.21.0" } ,
100+ { "pnpm" , "9.0.0" } ,
101+ { "azpysdk" , "azpysdk help" } ,
102+ { "sdk_generator" , "sdk_generator help" } ,
103+ { "GitPython" , "GitPython 3.1.0" } ,
104+ { "pytest" , "pytest 8.3.5" } ,
105+ { "golangci-lint" , "golangci-lint 1.55.0" } ,
106+ { "goimports" , "goimports" } ,
107+ { "generator" , "generator 0.4.3" }
93108 } ;
94109 foreach ( var kvp in successfulCommands )
95110 {
96111 var command = kvp . Key ;
97112 var output = kvp . Value ;
98- if ( processOptions . Command . Contains ( command ) || processOptions . Args . Contains ( command ) )
113+ if ( processOptions . Command . Contains ( command ) ||
114+ processOptions . Args . Any ( a => a . Contains ( command ) ) )
99115 {
100116 return new ProcessResult
101117 {
@@ -116,7 +132,7 @@ private void SetupFailedProcessMock(string command, int exitCode = 1, string err
116132 {
117133 mockProcessHelper
118134 . Setup ( x => x . Run (
119- It . Is < ProcessOptions > ( opt => opt . Command . Contains ( command ) || opt . Args . Contains ( command ) ) ,
135+ It . Is < ProcessOptions > ( opt => opt . Command . Contains ( command ) || opt . Args . Any ( a => a . Contains ( command ) ) ) ,
120136 It . IsAny < CancellationToken > ( ) ) )
121137 . ReturnsAsync ( new ProcessResult
122138 {
@@ -125,174 +141,144 @@ private void SetupFailedProcessMock(string command, int exitCode = 1, string err
125141 } ) ;
126142 }
127143
128- private List < LanguageService > SetupLanguageRequirementsMocks ( Dictionary < SdkLanguage , ( string requirement , string [ ] checkCommand , List < string > instructions ) > languageSpecs )
144+ private void SetupVersionMismatchMock ( string command , string version )
129145 {
130- List < LanguageService > langs = [ ] ;
131- foreach ( var kvp in languageSpecs )
132- {
133- var mockChecker = new Mock < LanguageService > ( ) ;
134- var spec = kvp . Value ;
135- mockChecker
136- . Setup ( x => x . GetRequirements ( It . IsAny < string > ( ) , It . IsAny < Dictionary < string , List < SetupRequirements . Requirement > > > ( ) , It . IsAny < CancellationToken > ( ) ) )
137- . Returns ( new List < SetupRequirements . Requirement >
138- {
139- new SetupRequirements . Requirement
140- {
141- requirement = spec . requirement ,
142- check = spec . checkCommand ,
143- instructions = spec . instructions
144- }
145- } ) ;
146- mockChecker . Setup ( x => x . Language ) . Returns ( kvp . Key ) ;
147- langs . Add ( mockChecker . Object ) ;
148- }
149- return langs ;
146+ mockProcessHelper
147+ . Setup ( x => x . Run (
148+ It . Is < ProcessOptions > ( opt => opt . Command . Contains ( command ) || opt . Args . Any ( a => a . Contains ( command ) ) ) ,
149+ It . IsAny < CancellationToken > ( ) ) )
150+ . ReturnsAsync ( new ProcessResult
151+ {
152+ ExitCode = 0 ,
153+ OutputDetails = new List < ( StdioLevel , string ) > { ( StdioLevel . StandardOutput , version ) }
154+ } ) ;
150155 }
151156
152157 [ Test ]
153158 public async Task VerifySetup_Succeeds_WhenAllRequirementsMet ( )
154159 {
155160 // Arrange
156- var languageSpecs = new Dictionary < SdkLanguage , ( string requirement , string [ ] checkCommand , List < string > instructions ) >
157- {
158- { SdkLanguage . Python , ( "Python >= 3.8" , new [ ] { "python" , "--version" } , new List < string > { "Install Python 3.8 or higher" } ) }
159- } ;
160- var langTestServices = SetupLanguageRequirementsMocks ( languageSpecs ) ;
161-
162- // Act
163161 var tool = new VerifySetupTool (
164162 mockProcessHelper . Object ,
165163 logger ,
166164 _mockGitHelper . Object ,
167- langTestServices
165+ languageServices
168166 ) ;
167+
168+ // Act - Check Python requirements
169169 var result = await tool . VerifySetup ( new HashSet < SdkLanguage > { SdkLanguage . Python } , "/test/path/python" ) ;
170170
171- // Assert
172- Assert . That ( result . Results , Is . Empty ) ;
171+ // Assert - Should have no failures when all mocks return success
173172 Assert . That ( result . ResponseError , Is . Null ) ;
174173 }
175174
176175 [ Test ]
177- public async Task VerifySetup_Fails_WhenSomeRequirementsNotMet ( )
176+ public async Task VerifySetup_Fails_WhenCoreRequirementNotMet ( )
178177 {
179- var languageSpecs = new Dictionary < SdkLanguage , ( string , string [ ] , List < string > ) >
180- {
181- { SdkLanguage . Python , ( "Python >= 3.8" , new [ ] { "python" , "--version" } , new List < string > { "Install Python 3.8 or higher" } ) }
182- } ;
183- var langTestServices = SetupLanguageRequirementsMocks ( languageSpecs ) ;
184-
178+ // Arrange - Node.js command fails
185179 SetupFailedProcessMock ( "node" , 1 , "node: command not found" ) ;
186180
187- // Act
188181 var tool = new VerifySetupTool (
189182 mockProcessHelper . Object ,
190183 logger ,
191184 _mockGitHelper . Object ,
192- langTestServices
185+ languageServices
193186 ) ;
187+
188+ // Act
194189 var result = await tool . VerifySetup ( new HashSet < SdkLanguage > { SdkLanguage . Python } , "/test/path/python" ) ;
195190
196191 // Assert
197- Assert . That ( result . Results , Is . Not . Empty ) ;
198- Assert . That ( result . Results . Any ( r => r . Requirement . Contains ( "Node.js " ) ) , Is . True ) ;
192+ Assert . That ( result . Results , Is . Not . Null . And . Not . Empty ) ;
193+ Assert . That ( result . Results ! . Any ( r => r . Requirement . Contains ( "Node" ) ) , Is . True ) ;
199194 Assert . That ( result . ResponseError , Is . Null ) ;
200195 }
201196
202197 [ Test ]
203- public async Task VerifySetup_Fails_WhenSomeRequirementsVersionNotMet ( )
198+ public async Task VerifySetup_Fails_WhenVersionRequirementNotMet ( )
204199 {
205- var languageSpecs = new Dictionary < SdkLanguage , ( string requirement , string [ ] checkCommand , List < string > instructions ) >
206- {
207- { SdkLanguage . Python , ( "Python >= 3.14" , new [ ] { "python" , "--version" } , new List < string > { "Install Python 3.14 or higher" } ) }
208- } ;
209- var languageTestServices = SetupLanguageRequirementsMocks ( languageSpecs ) ;
200+ // Arrange - Node.js returns old version
201+ SetupVersionMismatchMock ( "node" , "v18.0.0" ) ;
210202
211- // Act
212203 var tool = new VerifySetupTool (
213204 mockProcessHelper . Object ,
214205 logger ,
215206 _mockGitHelper . Object ,
216- languageTestServices
207+ languageServices
217208 ) ;
209+
210+ // Act
218211 var result = await tool . VerifySetup ( new HashSet < SdkLanguage > { SdkLanguage . Python } , "/test/path/python" ) ;
219212
220- // Assert
221- Assert . That ( result . Results , Is . Not . Empty ) ;
222- Assert . That ( result . Results . Any ( r => r . Requirement . Contains ( "Python " ) ) , Is . True ) ;
213+ // Assert - Should have a failure for Node.js version
214+ Assert . That ( result . Results , Is . Not . Null . And . Not . Empty ) ;
215+ Assert . That ( result . Results ! . Any ( r => r . Requirement . Contains ( "Node " ) ) , Is . True ) ;
223216 Assert . That ( result . ResponseError , Is . Null ) ;
224217 }
225218
226219 [ Test ]
227- public async Task VerifySetup_OnlyChecksSpecifiedLanguages ( )
220+ public async Task VerifySetup_OnlyChecksLanguageSpecificRequirements_ForSpecifiedLanguage ( )
228221 {
229- // Arrange - Set up multiple language specs, but only request python
230- var languageSpecs = new Dictionary < SdkLanguage , ( string , string [ ] , List < string > ) >
231- {
232- { SdkLanguage . Python , ( "Python >= 3.14" , new [ ] { "python" , "--version" } , new List < string > { "Install Python 3.14" } ) } ,
233- { SdkLanguage . Java , ( "Java >= 17" , new [ ] { "java" , "-version" } , new List < string > { "Install Java 17" } ) } ,
234- { SdkLanguage . DotNet , ( ".NET >= 8.0" , new [ ] { "dotnet" , "--version" } , new List < string > { "Install .NET 8.0" } ) }
235- } ;
236-
237- var languageTestServices = SetupLanguageRequirementsMocks ( languageSpecs ) ;
222+ // Arrange - Java command fails, but we only request Python
238223 SetupFailedProcessMock ( "java" , 1 , "java: command not found" ) ;
239224
240- // Act
241225 var tool = new VerifySetupTool (
242226 mockProcessHelper . Object ,
243227 logger ,
244228 _mockGitHelper . Object ,
245- languageTestServices
229+ languageServices
246230 ) ;
231+
232+ // Act - Only request Python
247233 var result = await tool . VerifySetup ( new HashSet < SdkLanguage > { SdkLanguage . Python } , "/test/path/python" ) ;
248234
249- // Assert
250- Assert . That ( result . Results , Is . Not . Empty ) ;
251- Assert . That ( result . Results . Count , Is . EqualTo ( 1 ) ) ;
252- Assert . That ( result . Results [ 0 ] . Requirement , Does . Contain ( "Python" ) ) ;
235+ // Assert - Should not fail for Java requirements since we only requested Python
236+ Assert . That ( result . Results ? . Any ( r => r . Requirement . Contains ( "Java" ) ) ?? false , Is . False ) ;
253237 Assert . That ( result . ResponseError , Is . Null ) ;
254238 }
255239
256240 [ Test ]
257- public async Task VerifySetup_ChecksMultipleSpecifiedLanguages ( )
241+ public async Task VerifySetup_ChecksCoreRequirements_ForAnyLanguage ( )
258242 {
259- // Arrange
260- var languageSpecs = new Dictionary < SdkLanguage , ( string , string [ ] , List < string > ) >
261- {
262- { SdkLanguage . Python , ( "Python >= 3.8" , new [ ] { "python" , "--version" } , new List < string > { "Install Python 3.8" } ) } ,
263- { SdkLanguage . Java , ( "Java >= 17.0" , new [ ] { "java" , "-version" } , new List < string > { "Install Java 17" } ) }
264- } ;
243+ // Arrange - PowerShell command fails
244+ SetupFailedProcessMock ( "pwsh" , 1 , "pwsh: command not found" ) ;
265245
266- var languageTestServices = SetupLanguageRequirementsMocks ( languageSpecs ) ;
267-
268- // Act - Request both Python and Java
269246 var tool = new VerifySetupTool (
270247 mockProcessHelper . Object ,
271248 logger ,
272249 _mockGitHelper . Object ,
273- languageTestServices
250+ languageServices
274251 ) ;
275- var result = await tool . VerifySetup ( new HashSet < SdkLanguage > { SdkLanguage . Python , SdkLanguage . Java } , "/test/path/java" ) ;
276252
277- // Assert
278- Assert . That ( result . ResponseError , Is . Null ) ;
253+ // Act - Request any language
254+ var result = await tool . VerifySetup ( new HashSet < SdkLanguage > { SdkLanguage . Go } , "/test/path/go" ) ;
255+
256+ // Assert - Should fail for PowerShell since it's a core requirement
257+ Assert . That ( result . Results , Is . Not . Null . And . Not . Empty ) ;
258+ Assert . That ( result . Results ! . Any ( r => r . Requirement . Contains ( "PowerShell" ) ) , Is . True ) ;
279259 }
280260
281261 [ Test ]
282- public async Task VerifySetup_HandlesInvalidLanguageInput ( )
262+ public async Task VerifySetup_ReturnsInstructions_WhenRequirementFails ( )
283263 {
284- // Act - Pass invalid language
264+ // Arrange - Node.js command fails
265+ SetupFailedProcessMock ( "node" , 1 , "node: command not found" ) ;
266+
285267 var tool = new VerifySetupTool (
286268 mockProcessHelper . Object ,
287269 logger ,
288270 _mockGitHelper . Object ,
289271 languageServices
290272 ) ;
291- var result = await tool . VerifySetup ( new HashSet < SdkLanguage > { ( SdkLanguage ) ( - 1 ) } , "/test/path" ) ;
292273
293- // Assert - Should succeed with just core requirements
294- Assert . That ( result . ResponseError , Is . Null ) ;
295- Assert . That ( result . Results , Is . Empty ) ;
274+ // Act
275+ var result = await tool . VerifySetup ( new HashSet < SdkLanguage > { SdkLanguage . Python } , "/test/path/python" ) ;
276+
277+ // Assert - Should include installation instructions
278+ Assert . That ( result . Results , Is . Not . Null . And . Not . Empty ) ;
279+ var nodeResult = result . Results ! . FirstOrDefault ( r => r . Requirement . Contains ( "Node" ) ) ;
280+ Assert . That ( nodeResult , Is . Not . Null ) ;
281+ Assert . That ( nodeResult ! . Instructions , Is . Not . Empty ) ;
296282 }
297283
298284 [ Test ]
0 commit comments