@@ -9,22 +9,22 @@ namespace JulianVerdurmen.SlnxValidator.Tests;
99
1010public class ValidatorRunnerTests
1111{
12- private static ValidatorRunner CreateRunner ( IFileSystem fileSystem , IRequiredFilesChecker ? checker = null , IConsole ? console = null )
12+ private static ValidatorRunner CreateRunner ( IFileSystem fileSystem , IConsole console , IRequiredFilesChecker ? checker = null )
1313 {
1414 checker ??= Substitute . For < IRequiredFilesChecker > ( ) ;
1515 var resolver = Substitute . For < ISlnxFileResolver > ( ) ;
1616 var collector = new SlnxCollector ( fileSystem , resolver , Substitute . For < ISlnxValidator > ( ) , checker ) ;
1717 var sonarReporter = new SonarReporter ( fileSystem ) ;
1818 var sarifReporter = new SarifReporter ( fileSystem ) ;
19- return new ValidatorRunner ( collector , sonarReporter , sarifReporter , checker , fileSystem , console ?? new TestConsole ( ) ) ;
19+ return new ValidatorRunner ( collector , sonarReporter , sarifReporter , checker , fileSystem , console ) ;
2020 }
2121
2222 private static ValidatorRunnerOptions Options ( string input = "test.slnx" ,
2323 bool continueOnError = false , string ? requiredFilesPattern = null ) =>
2424 new ( input , SonarqubeReportPath : null , continueOnError , requiredFilesPattern , WorkingDirectory : "." ) ;
2525
2626 private static ValidatorRunner CreateRunnerWithSlnx (
27- string slnxPath , string slnxContent , IRequiredFilesChecker ? checker = null , IConsole ? console = null )
27+ string slnxPath , string slnxContent , IConsole console , IRequiredFilesChecker ? checker = null )
2828 {
2929 checker ??= Substitute . For < IRequiredFilesChecker > ( ) ;
3030 var fileSystem = new MockFileSystem ( new Dictionary < string , string >
@@ -39,7 +39,7 @@ private static ValidatorRunner CreateRunnerWithSlnx(
3939 var collector = new SlnxCollector ( fileSystem , resolver , validator , checker ) ;
4040 var sonarReporter = new SonarReporter ( fileSystem ) ;
4141 var sarifReporter = new SarifReporter ( fileSystem ) ;
42- return new ValidatorRunner ( collector , sonarReporter , sarifReporter , checker , fileSystem , console ?? new TestConsole ( ) ) ;
42+ return new ValidatorRunner ( collector , sonarReporter , sarifReporter , checker , fileSystem , console ) ;
4343 }
4444
4545 #region RunAsync – file resolution
@@ -48,7 +48,7 @@ private static ValidatorRunner CreateRunnerWithSlnx(
4848 public async Task RunAsync_FileNotFound_ContinueOnErrorFalse_ReturnsOne ( )
4949 {
5050 // Arrange
51- var runner = CreateRunner ( new MockFileSystem ( ) ) ;
51+ var runner = CreateRunner ( new MockFileSystem ( ) , new FakeConsole ( ) ) ;
5252
5353 // Act
5454 var exitCode = await runner . RunAsync ( Options ( "nonexistent.slnx" ) , CancellationToken . None ) ;
@@ -61,7 +61,7 @@ public async Task RunAsync_FileNotFound_ContinueOnErrorFalse_ReturnsOne()
6161 public async Task RunAsync_FileNotFound_ContinueOnErrorTrue_ReturnsZero ( )
6262 {
6363 // Arrange
64- var runner = CreateRunner ( new MockFileSystem ( ) ) ;
64+ var runner = CreateRunner ( new MockFileSystem ( ) , new FakeConsole ( ) ) ;
6565
6666 // Act
6767 var exitCode = await runner . RunAsync ( Options ( "nonexistent.slnx" , continueOnError : true ) , CancellationToken . None ) ;
@@ -74,7 +74,7 @@ public async Task RunAsync_FileNotFound_ContinueOnErrorTrue_ReturnsZero()
7474 public async Task RunAsync_NoFilesFound_ContinueOnErrorFalse_ReturnsOne ( )
7575 {
7676 // Arrange
77- var runner = CreateRunner ( new MockFileSystem ( ) ) ;
77+ var runner = CreateRunner ( new MockFileSystem ( ) , new FakeConsole ( ) ) ;
7878
7979 // Act
8080 var exitCode = await runner . RunAsync ( Options ( "src/*.slnx" ) , CancellationToken . None ) ;
@@ -87,7 +87,7 @@ public async Task RunAsync_NoFilesFound_ContinueOnErrorFalse_ReturnsOne()
8787 public async Task RunAsync_NoFilesFound_ContinueOnErrorTrue_ReturnsZero ( )
8888 {
8989 // Arrange
90- var runner = CreateRunner ( new MockFileSystem ( ) ) ;
90+ var runner = CreateRunner ( new MockFileSystem ( ) , new FakeConsole ( ) ) ;
9191
9292 // Act
9393 var exitCode = await runner . RunAsync ( Options ( "src/*.slnx" , continueOnError : true ) , CancellationToken . None ) ;
@@ -114,7 +114,7 @@ public async Task RunAsync_RequiredFiles_AllMatchedAndReferenced_ReturnsZero()
114114 checker . CheckInSlnx ( Arg . Any < IReadOnlyList < string > > ( ) , Arg . Any < SlnxFile > ( ) )
115115 . Returns ( [ ] ) ;
116116
117- var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , checker ) ;
117+ var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , new FakeConsole ( ) , checker ) ;
118118
119119 // Act
120120 var exitCode = await runner . RunAsync (
@@ -134,7 +134,7 @@ public async Task RunAsync_RequiredFiles_NoMatchOnDisk_ReturnsOne()
134134 checker . ResolveMatchedPaths ( Arg . Any < string > ( ) , Arg . Any < string > ( ) )
135135 . Returns ( [ ] ) ; // nothing matched on disk
136136
137- var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , checker ) ;
137+ var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , new FakeConsole ( ) , checker ) ;
138138
139139 // Act
140140 var exitCode = await runner . RunAsync (
@@ -155,7 +155,7 @@ public async Task RunAsync_RequiredFiles_NoMatchOnDisk_ReturnsOne()
155155 public async Task RunAsync_IgnoreAllCodes_WithErrors_ReturnsZero ( )
156156 {
157157 // Arrange: file with wrong extension generates SLNX002; --ignore * suppresses all codes
158- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
158+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
159159 var overrides = SeverityOverridesParser . Parse ( null , null , null , null , null , ignore : "*" ) ;
160160
161161 // Act
@@ -171,7 +171,7 @@ public async Task RunAsync_IgnoreAllCodes_WithErrors_ReturnsZero()
171171 public async Task RunAsync_IgnoreSpecificCode_ThatCodeDoesNotCauseExitOne ( )
172172 {
173173 // Arrange: --ignore SLNX002 suppresses the InvalidExtension error
174- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
174+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
175175 var overrides = SeverityOverridesParser . Parse ( null , null , null , null , null , ignore : "SLNX002" ) ;
176176
177177 // Act
@@ -187,7 +187,7 @@ public async Task RunAsync_IgnoreSpecificCode_ThatCodeDoesNotCauseExitOne()
187187 public async Task RunAsync_MinorOverrideForErrorCode_ReturnsZero ( )
188188 {
189189 // Arrange: --minor SLNX002 downgrades InvalidExtension to non-failing severity
190- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
190+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
191191 var overrides = SeverityOverridesParser . Parse ( null , null , null , minor : "SLNX002" , null , null ) ;
192192
193193 // Act
@@ -203,7 +203,7 @@ public async Task RunAsync_MinorOverrideForErrorCode_ReturnsZero()
203203 public async Task RunAsync_InfoAllCodes_ReturnsZero ( )
204204 {
205205 // Arrange: --info * downgrades all codes to INFO (non-failing)
206- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
206+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
207207 var overrides = SeverityOverridesParser . Parse ( null , null , null , null , info : "*" , null ) ;
208208
209209 // Act
@@ -219,7 +219,7 @@ public async Task RunAsync_InfoAllCodes_ReturnsZero()
219219 public async Task RunAsync_InfoAllCodesMajorSpecificCode_SpecificCodeCausesExitOne ( )
220220 {
221221 // Arrange: --info * --major SLNX002 → SLNX002 stays MAJOR (specific overrides wildcard)
222- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
222+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
223223 var overrides = SeverityOverridesParser . Parse ( null , null , major : "SLNX002" , null , info : "*" , null ) ;
224224
225225 // Act
@@ -235,7 +235,7 @@ public async Task RunAsync_InfoAllCodesMajorSpecificCode_SpecificCodeCausesExitO
235235 public async Task RunAsync_IgnoreAllCodesMajorSpecificCode_SpecificCodeCausesExitOne ( )
236236 {
237237 // Arrange: --ignore * --major SLNX002 → SLNX002 is MAJOR (specific wins over wildcard ignore)
238- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
238+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
239239 var overrides = SeverityOverridesParser . Parse ( null , null , major : "SLNX002" , null , null , ignore : "*" ) ;
240240
241241 // Act
@@ -255,40 +255,40 @@ public async Task RunAsync_IgnoreAllCodesMajorSpecificCode_SpecificCodeCausesExi
255255 public async Task RunAsync_NoFilesFound_WritesErrorToConsole ( )
256256 {
257257 // Arrange
258- var console = new TestConsole ( ) ;
259- var runner = CreateRunner ( new MockFileSystem ( ) , console : console ) ;
258+ var console = new FakeConsole ( ) ;
259+ var runner = CreateRunner ( new MockFileSystem ( ) , console ) ;
260260
261261 // Act
262262 await runner . RunAsync ( Options ( "nonexistent.slnx" ) , CancellationToken . None ) ;
263263
264264 // Assert
265- console . Error . ToString ( ) . Should ( ) . Contain ( " No .slnx files found for input: nonexistent.slnx") ;
265+ console . ErrorOutput . Should ( ) . ContainMatch ( "* No .slnx files found for input: nonexistent.slnx* ") ;
266266 }
267267
268268 [ Test ]
269269 public async Task RunAsync_SonarqubeReportPath_WritesConfirmationToConsole ( )
270270 {
271271 // Arrange
272272 var slnxPath = Path . GetFullPath ( "test.slnx" ) ;
273- var console = new TestConsole ( ) ;
274- var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , console : console ) ;
273+ var console = new FakeConsole ( ) ;
274+ var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , console ) ;
275275 var options = new ValidatorRunnerOptions ( slnxPath , SonarqubeReportPath : "report.xml" ,
276276 ContinueOnError : false , RequiredFilesPattern : null , WorkingDirectory : "." ) ;
277277
278278 // Act
279279 await runner . RunAsync ( options , CancellationToken . None ) ;
280280
281281 // Assert
282- console . Out . ToString ( ) . Should ( ) . Contain ( " SonarQube report written to: report.xml") ;
282+ console . Output . Should ( ) . ContainMatch ( "* SonarQube report written to: report.xml* ") ;
283283 }
284284
285285 [ Test ]
286286 public async Task RunAsync_SarifReportPath_WritesConfirmationToConsole ( )
287287 {
288288 // Arrange
289289 var slnxPath = Path . GetFullPath ( "test.slnx" ) ;
290- var console = new TestConsole ( ) ;
291- var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , console : console ) ;
290+ var console = new FakeConsole ( ) ;
291+ var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , console ) ;
292292 var options = new ValidatorRunnerOptions ( slnxPath , SonarqubeReportPath : null ,
293293 ContinueOnError : false , RequiredFilesPattern : null , WorkingDirectory : "." ,
294294 SarifReportPath : "report.sarif" ) ;
@@ -297,7 +297,7 @@ public async Task RunAsync_SarifReportPath_WritesConfirmationToConsole()
297297 await runner . RunAsync ( options , CancellationToken . None ) ;
298298
299299 // Assert
300- console . Out . ToString ( ) . Should ( ) . Contain ( " SARIF report written to: report.sarif") ;
300+ console . Output . Should ( ) . ContainMatch ( "* SARIF report written to: report.sarif* ") ;
301301 }
302302
303303 #endregion
0 commit comments