@@ -9,22 +9,24 @@ namespace JulianVerdurmen.SlnxValidator.Tests;
99
1010public class ValidatorRunnerTests
1111{
12- private static ValidatorRunner CreateRunner ( IFileSystem fileSystem , IConsole console , IRequiredFilesChecker ? checker = null )
12+ private readonly FakeConsole _console = new ( ) ;
13+
14+ private ValidatorRunner CreateRunner ( IFileSystem fileSystem , IRequiredFilesChecker ? checker = null )
1315 {
1416 checker ??= Substitute . For < IRequiredFilesChecker > ( ) ;
1517 var resolver = Substitute . For < ISlnxFileResolver > ( ) ;
1618 var collector = new SlnxCollector ( fileSystem , resolver , Substitute . For < ISlnxValidator > ( ) , checker ) ;
1719 var sonarReporter = new SonarReporter ( fileSystem ) ;
1820 var sarifReporter = new SarifReporter ( fileSystem ) ;
19- return new ValidatorRunner ( collector , sonarReporter , sarifReporter , checker , fileSystem , console ) ;
21+ return new ValidatorRunner ( collector , sonarReporter , sarifReporter , checker , fileSystem , _console ) ;
2022 }
2123
2224 private static ValidatorRunnerOptions Options ( string input = "test.slnx" ,
2325 bool continueOnError = false , string ? requiredFilesPattern = null ) =>
2426 new ( input , SonarqubeReportPath : null , continueOnError , requiredFilesPattern , WorkingDirectory : "." ) ;
2527
26- private static ValidatorRunner CreateRunnerWithSlnx (
27- string slnxPath , string slnxContent , IConsole console , IRequiredFilesChecker ? checker = null )
28+ private ValidatorRunner CreateRunnerWithSlnx (
29+ string slnxPath , string slnxContent , IRequiredFilesChecker ? checker = null )
2830 {
2931 checker ??= Substitute . For < IRequiredFilesChecker > ( ) ;
3032 var fileSystem = new MockFileSystem ( new Dictionary < string , string >
@@ -39,7 +41,7 @@ private static ValidatorRunner CreateRunnerWithSlnx(
3941 var collector = new SlnxCollector ( fileSystem , resolver , validator , checker ) ;
4042 var sonarReporter = new SonarReporter ( fileSystem ) ;
4143 var sarifReporter = new SarifReporter ( fileSystem ) ;
42- return new ValidatorRunner ( collector , sonarReporter , sarifReporter , checker , fileSystem , console ) ;
44+ return new ValidatorRunner ( collector , sonarReporter , sarifReporter , checker , fileSystem , _console ) ;
4345 }
4446
4547 #region RunAsync – file resolution
@@ -48,7 +50,7 @@ private static ValidatorRunner CreateRunnerWithSlnx(
4850 public async Task RunAsync_FileNotFound_ContinueOnErrorFalse_ReturnsOne ( )
4951 {
5052 // Arrange
51- var runner = CreateRunner ( new MockFileSystem ( ) , new FakeConsole ( ) ) ;
53+ var runner = CreateRunner ( new MockFileSystem ( ) ) ;
5254
5355 // Act
5456 var exitCode = await runner . RunAsync ( Options ( "nonexistent.slnx" ) , CancellationToken . None ) ;
@@ -61,7 +63,7 @@ public async Task RunAsync_FileNotFound_ContinueOnErrorFalse_ReturnsOne()
6163 public async Task RunAsync_FileNotFound_ContinueOnErrorTrue_ReturnsZero ( )
6264 {
6365 // Arrange
64- var runner = CreateRunner ( new MockFileSystem ( ) , new FakeConsole ( ) ) ;
66+ var runner = CreateRunner ( new MockFileSystem ( ) ) ;
6567
6668 // Act
6769 var exitCode = await runner . RunAsync ( Options ( "nonexistent.slnx" , continueOnError : true ) , CancellationToken . None ) ;
@@ -74,7 +76,7 @@ public async Task RunAsync_FileNotFound_ContinueOnErrorTrue_ReturnsZero()
7476 public async Task RunAsync_NoFilesFound_ContinueOnErrorFalse_ReturnsOne ( )
7577 {
7678 // Arrange
77- var runner = CreateRunner ( new MockFileSystem ( ) , new FakeConsole ( ) ) ;
79+ var runner = CreateRunner ( new MockFileSystem ( ) ) ;
7880
7981 // Act
8082 var exitCode = await runner . RunAsync ( Options ( "src/*.slnx" ) , CancellationToken . None ) ;
@@ -87,7 +89,7 @@ public async Task RunAsync_NoFilesFound_ContinueOnErrorFalse_ReturnsOne()
8789 public async Task RunAsync_NoFilesFound_ContinueOnErrorTrue_ReturnsZero ( )
8890 {
8991 // Arrange
90- var runner = CreateRunner ( new MockFileSystem ( ) , new FakeConsole ( ) ) ;
92+ var runner = CreateRunner ( new MockFileSystem ( ) ) ;
9193
9294 // Act
9395 var exitCode = await runner . RunAsync ( Options ( "src/*.slnx" , continueOnError : true ) , CancellationToken . None ) ;
@@ -114,7 +116,7 @@ public async Task RunAsync_RequiredFiles_AllMatchedAndReferenced_ReturnsZero()
114116 checker . CheckInSlnx ( Arg . Any < IReadOnlyList < string > > ( ) , Arg . Any < SlnxFile > ( ) )
115117 . Returns ( [ ] ) ;
116118
117- var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , new FakeConsole ( ) , checker ) ;
119+ var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , checker ) ;
118120
119121 // Act
120122 var exitCode = await runner . RunAsync (
@@ -134,7 +136,7 @@ public async Task RunAsync_RequiredFiles_NoMatchOnDisk_ReturnsOne()
134136 checker . ResolveMatchedPaths ( Arg . Any < string > ( ) , Arg . Any < string > ( ) )
135137 . Returns ( [ ] ) ; // nothing matched on disk
136138
137- var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , new FakeConsole ( ) , checker ) ;
139+ var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , checker ) ;
138140
139141 // Act
140142 var exitCode = await runner . RunAsync (
@@ -155,7 +157,7 @@ public async Task RunAsync_RequiredFiles_NoMatchOnDisk_ReturnsOne()
155157 public async Task RunAsync_IgnoreAllCodes_WithErrors_ReturnsZero ( )
156158 {
157159 // Arrange: file with wrong extension generates SLNX002; --ignore * suppresses all codes
158- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
160+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
159161 var overrides = SeverityOverridesParser . Parse ( null , null , null , null , null , ignore : "*" ) ;
160162
161163 // Act
@@ -171,7 +173,7 @@ public async Task RunAsync_IgnoreAllCodes_WithErrors_ReturnsZero()
171173 public async Task RunAsync_IgnoreSpecificCode_ThatCodeDoesNotCauseExitOne ( )
172174 {
173175 // Arrange: --ignore SLNX002 suppresses the InvalidExtension error
174- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
176+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
175177 var overrides = SeverityOverridesParser . Parse ( null , null , null , null , null , ignore : "SLNX002" ) ;
176178
177179 // Act
@@ -187,7 +189,7 @@ public async Task RunAsync_IgnoreSpecificCode_ThatCodeDoesNotCauseExitOne()
187189 public async Task RunAsync_MinorOverrideForErrorCode_ReturnsZero ( )
188190 {
189191 // Arrange: --minor SLNX002 downgrades InvalidExtension to non-failing severity
190- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
192+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
191193 var overrides = SeverityOverridesParser . Parse ( null , null , null , minor : "SLNX002" , null , null ) ;
192194
193195 // Act
@@ -203,7 +205,7 @@ public async Task RunAsync_MinorOverrideForErrorCode_ReturnsZero()
203205 public async Task RunAsync_InfoAllCodes_ReturnsZero ( )
204206 {
205207 // Arrange: --info * downgrades all codes to INFO (non-failing)
206- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
208+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
207209 var overrides = SeverityOverridesParser . Parse ( null , null , null , null , info : "*" , null ) ;
208210
209211 // Act
@@ -219,7 +221,7 @@ public async Task RunAsync_InfoAllCodes_ReturnsZero()
219221 public async Task RunAsync_InfoAllCodesMajorSpecificCode_SpecificCodeCausesExitOne ( )
220222 {
221223 // Arrange: --info * --major SLNX002 → SLNX002 stays MAJOR (specific overrides wildcard)
222- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
224+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
223225 var overrides = SeverityOverridesParser . Parse ( null , null , major : "SLNX002" , null , info : "*" , null ) ;
224226
225227 // Act
@@ -235,7 +237,7 @@ public async Task RunAsync_InfoAllCodesMajorSpecificCode_SpecificCodeCausesExitO
235237 public async Task RunAsync_IgnoreAllCodesMajorSpecificCode_SpecificCodeCausesExitOne ( )
236238 {
237239 // Arrange: --ignore * --major SLNX002 → SLNX002 is MAJOR (specific wins over wildcard ignore)
238- var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" , new FakeConsole ( ) ) ;
240+ var runner = CreateRunnerWithSlnx ( "test.xml" , "<Solution />" ) ;
239241 var overrides = SeverityOverridesParser . Parse ( null , null , major : "SLNX002" , null , null , ignore : "*" ) ;
240242
241243 // Act
@@ -255,40 +257,37 @@ public async Task RunAsync_IgnoreAllCodesMajorSpecificCode_SpecificCodeCausesExi
255257 public async Task RunAsync_NoFilesFound_WritesErrorToConsole ( )
256258 {
257259 // Arrange
258- var console = new FakeConsole ( ) ;
259- var runner = CreateRunner ( new MockFileSystem ( ) , console ) ;
260+ var runner = CreateRunner ( new MockFileSystem ( ) ) ;
260261
261262 // Act
262263 await runner . RunAsync ( Options ( "nonexistent.slnx" ) , CancellationToken . None ) ;
263264
264265 // Assert
265- console . ErrorOutput . Should ( ) . ContainMatch ( "*No .slnx files found for input: nonexistent.slnx*" ) ;
266+ _console . ErrorLines . Should ( ) . ContainMatch ( "*No .slnx files found for input: nonexistent.slnx*" ) ;
266267 }
267268
268269 [ Test ]
269270 public async Task RunAsync_SonarqubeReportPath_WritesConfirmationToConsole ( )
270271 {
271272 // Arrange
272273 var slnxPath = Path . GetFullPath ( "test.slnx" ) ;
273- var console = new FakeConsole ( ) ;
274- var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , console ) ;
274+ var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" ) ;
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 . Output . Should ( ) . ContainMatch ( "*SonarQube report written to: report.xml*" ) ;
282+ _console . OutputLines . 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 FakeConsole ( ) ;
291- var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" , console ) ;
290+ var runner = CreateRunnerWithSlnx ( slnxPath , "<Solution />" ) ;
292291 var options = new ValidatorRunnerOptions ( slnxPath , SonarqubeReportPath : null ,
293292 ContinueOnError : false , RequiredFilesPattern : null , WorkingDirectory : "." ,
294293 SarifReportPath : "report.sarif" ) ;
@@ -297,9 +296,8 @@ public async Task RunAsync_SarifReportPath_WritesConfirmationToConsole()
297296 await runner . RunAsync ( options , CancellationToken . None ) ;
298297
299298 // Assert
300- console . Output . Should ( ) . ContainMatch ( "*SARIF report written to: report.sarif*" ) ;
299+ _console . OutputLines . Should ( ) . ContainMatch ( "*SARIF report written to: report.sarif*" ) ;
301300 }
302301
303302 #endregion
304303}
305-
0 commit comments