From 083d70a9035e34a1681a206576bf7f14b01d5de9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 11:55:25 +0000 Subject: [PATCH 1/4] Initial plan From 196130cc5d9d597cb4c09a93ea04fdb4ea4377a9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 12:03:44 +0000 Subject: [PATCH 2/4] Fix Sonar code smell issues - part 1 Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- src/DemaConsulting.ReqStream/TraceMatrix.cs | 2 +- .../ContextTests.cs | 183 ++++-------------- .../RequirementsExportTests.cs | 22 +-- .../RequirementsReadTests.cs | 156 ++++----------- .../TraceMatrixExportTests.cs | 22 +-- .../TraceMatrixReadTests.cs | 22 +-- 6 files changed, 86 insertions(+), 321 deletions(-) diff --git a/src/DemaConsulting.ReqStream/TraceMatrix.cs b/src/DemaConsulting.ReqStream/TraceMatrix.cs index 0d5efb3..362f860 100644 --- a/src/DemaConsulting.ReqStream/TraceMatrix.cs +++ b/src/DemaConsulting.ReqStream/TraceMatrix.cs @@ -475,7 +475,7 @@ private void ExportRequirementSection(TextWriter writer, Section section, int de /// The section to check. /// The set of filter tags. /// True if the section has filtered content, false otherwise. - private bool SectionHasFilteredContent(Section section, HashSet? filterTags) + private static bool SectionHasFilteredContent(Section section, HashSet? filterTags) { // Check if section has any matching requirements if (filterTags == null || filterTags.Count == 0) diff --git a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs index 36dfd24..63ac9db 100644 --- a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs @@ -148,15 +148,8 @@ public void Context_Create_ResultsFlag_SetsResultsFileProperty() [TestMethod] public void Context_Create_MissingResultsFilename_ThrowsException() { - try - { - Context.Create(["--results"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--results requires a filename argument", ex.Message); - } + var ex = Assert.ThrowsException(() => Context.Create(["--results"])); + Assert.Contains("--results requires a filename argument", ex.Message); } /// @@ -225,15 +218,8 @@ public void Context_Create_MatrixFile_SetsMatrixProperty() [TestMethod] public void Context_Create_UnsupportedArgument_ThrowsException() { - try - { - Context.Create(["--unsupported"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("Unsupported argument '--unsupported'", ex.Message); - } + var ex = Assert.ThrowsException(() => Context.Create(["--unsupported"])); + Assert.Contains("Unsupported argument '--unsupported'", ex.Message); } /// @@ -242,15 +228,8 @@ public void Context_Create_UnsupportedArgument_ThrowsException() [TestMethod] public void Context_Create_MissingLogFilename_ThrowsException() { - try - { - Context.Create(["--log"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--log requires a filename argument", ex.Message); - } + var ex = Assert.ThrowsException(() => Context.Create(["--log"])); + Assert.Contains("--log requires a filename argument", ex.Message); } /// @@ -259,14 +238,8 @@ public void Context_Create_MissingLogFilename_ThrowsException() [TestMethod] public void Context_Create_MissingReportFilename_ThrowsException() { - try - { - Context.Create(["--report"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--report requires a filename argument", ex.Message); + var ex = Assert.ThrowsException(() => Context.Create(["--report"])); + Assert.Contains("--report requires a filename argument", ex.Message); } } @@ -276,15 +249,8 @@ public void Context_Create_MissingReportFilename_ThrowsException() [TestMethod] public void Context_Create_MissingMatrixFilename_ThrowsException() { - try - { - Context.Create(["--matrix"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--matrix requires a filename argument", ex.Message); - } + var ex = Assert.ThrowsException(() => Context.Create(["--matrix"])); + Assert.Contains("--matrix requires a filename argument", ex.Message); } /// @@ -293,15 +259,8 @@ public void Context_Create_MissingMatrixFilename_ThrowsException() [TestMethod] public void Context_Create_MissingReportDepth_ThrowsException() { - try - { - Context.Create(["--report-depth"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--report-depth requires a depth argument", ex.Message); - } + var ex = Assert.ThrowsException(() => Context.Create(["--report-depth"])); + Assert.Contains("--report-depth requires a depth argument", ex.Message); } /// @@ -310,15 +269,8 @@ public void Context_Create_MissingReportDepth_ThrowsException() [TestMethod] public void Context_Create_MissingMatrixDepth_ThrowsException() { - try - { - Context.Create(["--matrix-depth"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--matrix-depth requires a depth argument", ex.Message); - } + var ex = Assert.ThrowsException(() => Context.Create(["--matrix-depth"])); + Assert.Contains("--matrix-depth requires a depth argument", ex.Message); } /// @@ -327,35 +279,14 @@ public void Context_Create_MissingMatrixDepth_ThrowsException() [TestMethod] public void Context_Create_InvalidReportDepth_ThrowsException() { - try - { - Context.Create(["--report-depth", "invalid"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--report-depth requires a positive integer", ex.Message); - } + var ex1 = Assert.ThrowsException(() => Context.Create(["--report-depth", "invalid"])); + Assert.Contains("--report-depth requires a positive integer", ex1.Message); - try - { - Context.Create(["--report-depth", "0"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--report-depth requires a positive integer", ex.Message); - } + var ex2 = Assert.ThrowsException(() => Context.Create(["--report-depth", "0"])); + Assert.Contains("--report-depth requires a positive integer", ex2.Message); - try - { - Context.Create(["--report-depth", "-1"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--report-depth requires a positive integer", ex.Message); - } + var ex3 = Assert.ThrowsException(() => Context.Create(["--report-depth", "-1"])); + Assert.Contains("--report-depth requires a positive integer", ex3.Message); } /// @@ -364,25 +295,11 @@ public void Context_Create_InvalidReportDepth_ThrowsException() [TestMethod] public void Context_Create_InvalidMatrixDepth_ThrowsException() { - try - { - Context.Create(["--matrix-depth", "invalid"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--matrix-depth requires a positive integer", ex.Message); - } + var ex1 = Assert.ThrowsException(() => Context.Create(["--matrix-depth", "invalid"])); + Assert.Contains("--matrix-depth requires a positive integer", ex1.Message); - try - { - Context.Create(["--matrix-depth", "0"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--matrix-depth requires a positive integer", ex.Message); - } + var ex2 = Assert.ThrowsException(() => Context.Create(["--matrix-depth", "0"])); + Assert.Contains("--matrix-depth requires a positive integer", ex2.Message); } /// @@ -553,8 +470,8 @@ public void Context_Create_WithRequirementsPattern_ExpandsGlobPattern() using var context = Context.Create(["--requirements", "*.yaml"]); Assert.HasCount(2, context.RequirementsFiles); - Assert.IsTrue(context.RequirementsFiles.Any(f => f.EndsWith("req1.yaml"))); - Assert.IsTrue(context.RequirementsFiles.Any(f => f.EndsWith("req2.yaml"))); + Assert.Contains(context.RequirementsFiles.Single(f => f.EndsWith("req1.yaml")), context.RequirementsFiles); + Assert.Contains(context.RequirementsFiles.Single(f => f.EndsWith("req2.yaml")), context.RequirementsFiles); Assert.AreEqual(0, context.ExitCode); } finally @@ -584,8 +501,8 @@ public void Context_Create_WithTestsPattern_ExpandsGlobPattern() using var context = Context.Create(["--tests", "*.trx"]); Assert.HasCount(2, context.TestFiles); - Assert.IsTrue(context.TestFiles.Any(f => f.EndsWith("test1.trx"))); - Assert.IsTrue(context.TestFiles.Any(f => f.EndsWith("test2.trx"))); + Assert.Contains(context.TestFiles.Single(f => f.EndsWith("test1.trx")), context.TestFiles); + Assert.Contains(context.TestFiles.Single(f => f.EndsWith("test2.trx")), context.TestFiles); Assert.AreEqual(0, context.ExitCode); } finally @@ -600,15 +517,8 @@ public void Context_Create_WithTestsPattern_ExpandsGlobPattern() [TestMethod] public void Context_Create_MissingRequirementsPattern_ThrowsException() { - try - { - Context.Create(["--requirements"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--requirements requires a pattern argument", ex.Message); - } + var ex = Assert.ThrowsException(() => Context.Create(["--requirements"])); + Assert.Contains("--requirements requires a pattern argument", ex.Message); } /// @@ -617,15 +527,8 @@ public void Context_Create_MissingRequirementsPattern_ThrowsException() [TestMethod] public void Context_Create_MissingTestsPattern_ThrowsException() { - try - { - Context.Create(["--tests"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--tests requires a pattern argument", ex.Message); - } + var ex = Assert.ThrowsException(() => Context.Create(["--tests"])); + Assert.Contains("--tests requires a pattern argument", ex.Message); } /// @@ -672,15 +575,8 @@ public void Context_Create_InvalidLogPath_ThrowsException() { var invalidPath = Path.Combine(_testDirectory, "nonexistent", "test.log"); - try - { - Context.Create(["--log", invalidPath]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("Failed to open log file", ex.Message); - } + var ex = Assert.ThrowsException(() => Context.Create(["--log", invalidPath])); + Assert.Contains("Failed to open log file", ex.Message); } /// @@ -720,15 +616,8 @@ public void Context_Create_FilterArgumentWithSpaces_TrimsAndParsesTagsCorrectly( [TestMethod] public void Context_Create_FilterArgumentMissingValue_ThrowsArgumentException() { - try - { - Context.Create(["--filter"]); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("--filter requires a comma-separated list of tags", ex.Message); - } + var ex = Assert.ThrowsException(() => Context.Create(["--filter"])); + Assert.Contains("--filter requires a comma-separated list of tags", ex.Message); } /// diff --git a/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs b/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs index 150af66..14effa7 100644 --- a/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs @@ -183,15 +183,8 @@ public void Requirements_Export_NullFilePath_ThrowsArgumentException() File.WriteAllText(reqPath, yamlContent); var requirements = Requirements.Read(reqPath); - try - { - requirements.Export(null!); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("File path cannot be null or empty", ex.Message); - } + var ex = Assert.ThrowsException(() => requirements.Export(null!)); + Assert.Contains("File path cannot be null or empty", ex.Message); } /// @@ -211,15 +204,8 @@ public void Requirements_Export_EmptyFilePath_ThrowsArgumentException() File.WriteAllText(reqPath, yamlContent); var requirements = Requirements.Read(reqPath); - try - { - requirements.Export(string.Empty); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("File path cannot be null or empty", ex.Message); - } + var ex = Assert.ThrowsException(() => requirements.Export(string.Empty)); + Assert.Contains("File path cannot be null or empty", ex.Message); } /// diff --git a/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs b/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs index 3fb4ae6..e248bd0 100644 --- a/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs @@ -326,16 +326,9 @@ public void Requirements_Read_DuplicateRequirementId_ThrowsException() var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - try - { - Requirements.Read(filePath); - Assert.Fail("Expected InvalidOperationException was not thrown"); - } - catch (InvalidOperationException ex) - { - Assert.Contains("SYS-SEC-001", ex.Message); - Assert.Contains("Duplicate requirement ID", ex.Message); - } + var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + Assert.Contains("SYS-SEC-001", ex.Message); + Assert.Contains("Duplicate requirement ID", ex.Message); } /// @@ -383,15 +376,8 @@ public void Requirements_Read_FileNotFound_ThrowsException() { var nonExistentPath = Path.Combine(_testDirectory, "nonexistent.yaml"); - try - { - Requirements.Read(nonExistentPath); - Assert.Fail("Expected FileNotFoundException was not thrown"); - } - catch (FileNotFoundException ex) - { - Assert.Contains("Requirements file not found", ex.Message); - } + var ex = Assert.ThrowsException(() => Requirements.Read(nonExistentPath)); + Assert.Contains("Requirements file not found", ex.Message); } /// @@ -496,17 +482,10 @@ public void Requirements_Read_BlankRequirementId_ThrowsExceptionWithFileLocation var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - try - { - Requirements.Read(filePath); - Assert.Fail("Expected InvalidOperationException was not thrown"); - } - catch (InvalidOperationException ex) - { - Assert.Contains("Requirement ID cannot be blank", ex.Message); - Assert.Contains("System Security", ex.Message); - Assert.Contains(filePath, ex.Message); - } + var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + Assert.Contains("Requirement ID cannot be blank", ex.Message); + Assert.Contains("System Security", ex.Message); + Assert.Contains(filePath, ex.Message); } /// @@ -525,17 +504,10 @@ public void Requirements_Read_BlankRequirementTitle_ThrowsExceptionWithFileLocat var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - try - { - Requirements.Read(filePath); - Assert.Fail("Expected InvalidOperationException was not thrown"); - } - catch (InvalidOperationException ex) - { - Assert.Contains("Requirement title cannot be blank", ex.Message); - Assert.Contains("SYS-SEC-001", ex.Message); - Assert.Contains(filePath, ex.Message); - } + var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + Assert.Contains("Requirement title cannot be blank", ex.Message); + Assert.Contains("SYS-SEC-001", ex.Message); + Assert.Contains(filePath, ex.Message); } /// @@ -554,16 +526,9 @@ public void Requirements_Read_BlankSectionTitle_ThrowsExceptionWithFileLocation( var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - try - { - Requirements.Read(filePath); - Assert.Fail("Expected InvalidOperationException was not thrown"); - } - catch (InvalidOperationException ex) - { - Assert.Contains("Section title cannot be blank", ex.Message); - Assert.Contains(filePath, ex.Message); - } + var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + Assert.Contains("Section title cannot be blank", ex.Message); + Assert.Contains(filePath, ex.Message); } /// @@ -586,15 +551,9 @@ public void Requirements_Read_BlankTestNameInRequirement_ThrowsExceptionWithFile var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - try - { - Requirements.Read(filePath); - Assert.Fail("Expected InvalidOperationException was not thrown"); - } - catch (InvalidOperationException ex) - { - Assert.Contains("Test name cannot be blank", ex.Message); - Assert.Contains("SYS-SEC-001", ex.Message); + var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + Assert.Contains("Test name cannot be blank", ex.Message); + Assert.Contains("SYS-SEC-001", ex.Message); Assert.Contains(filePath, ex.Message); } } @@ -621,17 +580,10 @@ public void Requirements_Read_BlankTestNameInMapping_ThrowsExceptionWithFileLoca var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - try - { - Requirements.Read(filePath); - Assert.Fail("Expected InvalidOperationException was not thrown"); - } - catch (InvalidOperationException ex) - { - Assert.Contains("Test name cannot be blank", ex.Message); - Assert.Contains("SYS-SEC-001", ex.Message); - Assert.Contains(filePath, ex.Message); - } + var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + Assert.Contains("Test name cannot be blank", ex.Message); + Assert.Contains("SYS-SEC-001", ex.Message); + Assert.Contains(filePath, ex.Message); } /// @@ -655,16 +607,9 @@ public void Requirements_Read_BlankMappingId_ThrowsExceptionWithFileLocation() var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - try - { - Requirements.Read(filePath); - Assert.Fail("Expected InvalidOperationException was not thrown"); - } - catch (InvalidOperationException ex) - { - Assert.Contains("Mapping requirement ID cannot be blank", ex.Message); - Assert.Contains(filePath, ex.Message); - } + var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + Assert.Contains("Mapping requirement ID cannot be blank", ex.Message); + Assert.Contains(filePath, ex.Message); } /// @@ -685,15 +630,9 @@ public void Requirements_Read_DuplicateRequirementId_ExceptionIncludesFileLocati var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - try - { - Requirements.Read(filePath); - Assert.Fail("Expected InvalidOperationException was not thrown"); - } - catch (InvalidOperationException ex) - { - Assert.Contains("SYS-SEC-001", ex.Message); - Assert.Contains("Duplicate requirement ID", ex.Message); + var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + Assert.Contains("SYS-SEC-001", ex.Message); + Assert.Contains("Duplicate requirement ID", ex.Message); Assert.Contains(filePath, ex.Message); } } @@ -810,15 +749,8 @@ public void Requirements_Read_SingleFileWithParamsArray_WorksCorrectly() [TestMethod] public void Requirements_Read_NoArguments_ThrowsArgumentException() { - try - { - Requirements.Read(); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("At least one file path must be provided", ex.Message); - } + var ex = Assert.ThrowsException(() => Requirements.Read()); + Assert.Contains("At least one file path must be provided", ex.Message); } /// @@ -827,15 +759,8 @@ public void Requirements_Read_NoArguments_ThrowsArgumentException() [TestMethod] public void Requirements_Read_NullArgument_ThrowsArgumentException() { - try - { - Requirements.Read(null!); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("At least one file path must be provided", ex.Message); - } + var ex = Assert.ThrowsException(() => Requirements.Read(null!)); + Assert.Contains("At least one file path must be provided", ex.Message); } /// @@ -925,16 +850,9 @@ public void Requirements_Read_BlankTagName_ThrowsExceptionWithFileLocation() var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - try - { - Requirements.Read(filePath); - Assert.Fail("Expected InvalidOperationException was not thrown"); - } - catch (InvalidOperationException ex) - { - Assert.Contains("Tag name cannot be blank", ex.Message); - Assert.Contains("SYS-SEC-001", ex.Message); - Assert.Contains(filePath, ex.Message); - } + var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + Assert.Contains("Tag name cannot be blank", ex.Message); + Assert.Contains("SYS-SEC-001", ex.Message); + Assert.Contains(filePath, ex.Message); } } diff --git a/test/DemaConsulting.ReqStream.Tests/TraceMatrixExportTests.cs b/test/DemaConsulting.ReqStream.Tests/TraceMatrixExportTests.cs index 5770e82..35410c9 100644 --- a/test/DemaConsulting.ReqStream.Tests/TraceMatrixExportTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/TraceMatrixExportTests.cs @@ -358,15 +358,8 @@ public void TraceMatrix_Export_NullFilePath_ThrowsArgumentException() // Create TraceMatrix var matrix = new TraceMatrix(requirements); - try - { - matrix.Export(null!); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("File path cannot be null or empty", ex.Message); - } + var ex = Assert.ThrowsException(() => matrix.Export(null!)); + Assert.Contains("File path cannot be null or empty", ex.Message); } /// @@ -392,15 +385,8 @@ public void TraceMatrix_Export_EmptyFilePath_ThrowsArgumentException() // Create TraceMatrix var matrix = new TraceMatrix(requirements); - try - { - matrix.Export(string.Empty); - Assert.Fail("Expected ArgumentException was not thrown"); - } - catch (ArgumentException ex) - { - Assert.Contains("File path cannot be null or empty", ex.Message); - } + var ex = Assert.ThrowsException(() => matrix.Export(string.Empty)); + Assert.Contains("File path cannot be null or empty", ex.Message); } /// diff --git a/test/DemaConsulting.ReqStream.Tests/TraceMatrixReadTests.cs b/test/DemaConsulting.ReqStream.Tests/TraceMatrixReadTests.cs index 45040da..65ca2aa 100644 --- a/test/DemaConsulting.ReqStream.Tests/TraceMatrixReadTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/TraceMatrixReadTests.cs @@ -266,15 +266,8 @@ public void TraceMatrix_WithExtraTests_IgnoresUnreferencedTests() [TestMethod] public void TraceMatrix_NullRequirements_ThrowsArgumentNullException() { - try - { - _ = new TraceMatrix(null!, Array.Empty()); - Assert.Fail("Expected ArgumentNullException was not thrown"); - } - catch (ArgumentNullException ex) - { - Assert.Contains("requirements", ex.Message); - } + var ex = Assert.ThrowsException(() => _ = new TraceMatrix(null!, Array.Empty())); + Assert.Contains("requirements", ex.Message); } /// @@ -299,15 +292,8 @@ public void TraceMatrix_MissingFile_ThrowsFileNotFoundException() var nonExistentPath = Path.Combine(_testDirectory, "nonexistent.trx"); - try - { - _ = new TraceMatrix(requirements, nonExistentPath); - Assert.Fail("Expected FileNotFoundException was not thrown"); - } - catch (FileNotFoundException ex) - { - Assert.Contains("Test result file not found", ex.Message); - } + var ex = Assert.ThrowsException(() => _ = new TraceMatrix(requirements, nonExistentPath)); + Assert.Contains("Test result file not found", ex.Message); } /// From e8791220d5f3e5494a668af4548c38f39108e9ef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 12:07:26 +0000 Subject: [PATCH 3/4] Fix MSTest method name - use ThrowsExactly instead of ThrowsException Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- .../ContextTests.cs | 33 +++++++++---------- .../RequirementsExportTests.cs | 4 +-- .../RequirementsReadTests.cs | 30 ++++++++--------- .../TraceMatrixExportTests.cs | 4 +-- .../TraceMatrixReadTests.cs | 4 +-- 5 files changed, 36 insertions(+), 39 deletions(-) diff --git a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs index 63ac9db..31a6fb2 100644 --- a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs @@ -148,7 +148,7 @@ public void Context_Create_ResultsFlag_SetsResultsFileProperty() [TestMethod] public void Context_Create_MissingResultsFilename_ThrowsException() { - var ex = Assert.ThrowsException(() => Context.Create(["--results"])); + var ex = Assert.ThrowsExactly(() => Context.Create(["--results"])); Assert.Contains("--results requires a filename argument", ex.Message); } @@ -218,7 +218,7 @@ public void Context_Create_MatrixFile_SetsMatrixProperty() [TestMethod] public void Context_Create_UnsupportedArgument_ThrowsException() { - var ex = Assert.ThrowsException(() => Context.Create(["--unsupported"])); + var ex = Assert.ThrowsExactly(() => Context.Create(["--unsupported"])); Assert.Contains("Unsupported argument '--unsupported'", ex.Message); } @@ -228,7 +228,7 @@ public void Context_Create_UnsupportedArgument_ThrowsException() [TestMethod] public void Context_Create_MissingLogFilename_ThrowsException() { - var ex = Assert.ThrowsException(() => Context.Create(["--log"])); + var ex = Assert.ThrowsExactly(() => Context.Create(["--log"])); Assert.Contains("--log requires a filename argument", ex.Message); } @@ -238,9 +238,8 @@ public void Context_Create_MissingLogFilename_ThrowsException() [TestMethod] public void Context_Create_MissingReportFilename_ThrowsException() { - var ex = Assert.ThrowsException(() => Context.Create(["--report"])); + var ex = Assert.ThrowsExactly(() => Context.Create(["--report"])); Assert.Contains("--report requires a filename argument", ex.Message); - } } /// @@ -249,7 +248,7 @@ public void Context_Create_MissingReportFilename_ThrowsException() [TestMethod] public void Context_Create_MissingMatrixFilename_ThrowsException() { - var ex = Assert.ThrowsException(() => Context.Create(["--matrix"])); + var ex = Assert.ThrowsExactly(() => Context.Create(["--matrix"])); Assert.Contains("--matrix requires a filename argument", ex.Message); } @@ -259,7 +258,7 @@ public void Context_Create_MissingMatrixFilename_ThrowsException() [TestMethod] public void Context_Create_MissingReportDepth_ThrowsException() { - var ex = Assert.ThrowsException(() => Context.Create(["--report-depth"])); + var ex = Assert.ThrowsExactly(() => Context.Create(["--report-depth"])); Assert.Contains("--report-depth requires a depth argument", ex.Message); } @@ -269,7 +268,7 @@ public void Context_Create_MissingReportDepth_ThrowsException() [TestMethod] public void Context_Create_MissingMatrixDepth_ThrowsException() { - var ex = Assert.ThrowsException(() => Context.Create(["--matrix-depth"])); + var ex = Assert.ThrowsExactly(() => Context.Create(["--matrix-depth"])); Assert.Contains("--matrix-depth requires a depth argument", ex.Message); } @@ -279,13 +278,13 @@ public void Context_Create_MissingMatrixDepth_ThrowsException() [TestMethod] public void Context_Create_InvalidReportDepth_ThrowsException() { - var ex1 = Assert.ThrowsException(() => Context.Create(["--report-depth", "invalid"])); + var ex1 = Assert.ThrowsExactly(() => Context.Create(["--report-depth", "invalid"])); Assert.Contains("--report-depth requires a positive integer", ex1.Message); - var ex2 = Assert.ThrowsException(() => Context.Create(["--report-depth", "0"])); + var ex2 = Assert.ThrowsExactly(() => Context.Create(["--report-depth", "0"])); Assert.Contains("--report-depth requires a positive integer", ex2.Message); - var ex3 = Assert.ThrowsException(() => Context.Create(["--report-depth", "-1"])); + var ex3 = Assert.ThrowsExactly(() => Context.Create(["--report-depth", "-1"])); Assert.Contains("--report-depth requires a positive integer", ex3.Message); } @@ -295,10 +294,10 @@ public void Context_Create_InvalidReportDepth_ThrowsException() [TestMethod] public void Context_Create_InvalidMatrixDepth_ThrowsException() { - var ex1 = Assert.ThrowsException(() => Context.Create(["--matrix-depth", "invalid"])); + var ex1 = Assert.ThrowsExactly(() => Context.Create(["--matrix-depth", "invalid"])); Assert.Contains("--matrix-depth requires a positive integer", ex1.Message); - var ex2 = Assert.ThrowsException(() => Context.Create(["--matrix-depth", "0"])); + var ex2 = Assert.ThrowsExactly(() => Context.Create(["--matrix-depth", "0"])); Assert.Contains("--matrix-depth requires a positive integer", ex2.Message); } @@ -517,7 +516,7 @@ public void Context_Create_WithTestsPattern_ExpandsGlobPattern() [TestMethod] public void Context_Create_MissingRequirementsPattern_ThrowsException() { - var ex = Assert.ThrowsException(() => Context.Create(["--requirements"])); + var ex = Assert.ThrowsExactly(() => Context.Create(["--requirements"])); Assert.Contains("--requirements requires a pattern argument", ex.Message); } @@ -527,7 +526,7 @@ public void Context_Create_MissingRequirementsPattern_ThrowsException() [TestMethod] public void Context_Create_MissingTestsPattern_ThrowsException() { - var ex = Assert.ThrowsException(() => Context.Create(["--tests"])); + var ex = Assert.ThrowsExactly(() => Context.Create(["--tests"])); Assert.Contains("--tests requires a pattern argument", ex.Message); } @@ -575,7 +574,7 @@ public void Context_Create_InvalidLogPath_ThrowsException() { var invalidPath = Path.Combine(_testDirectory, "nonexistent", "test.log"); - var ex = Assert.ThrowsException(() => Context.Create(["--log", invalidPath])); + var ex = Assert.ThrowsExactly(() => Context.Create(["--log", invalidPath])); Assert.Contains("Failed to open log file", ex.Message); } @@ -616,7 +615,7 @@ public void Context_Create_FilterArgumentWithSpaces_TrimsAndParsesTagsCorrectly( [TestMethod] public void Context_Create_FilterArgumentMissingValue_ThrowsArgumentException() { - var ex = Assert.ThrowsException(() => Context.Create(["--filter"])); + var ex = Assert.ThrowsExactly(() => Context.Create(["--filter"])); Assert.Contains("--filter requires a comma-separated list of tags", ex.Message); } diff --git a/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs b/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs index 14effa7..6f2eebe 100644 --- a/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs @@ -183,7 +183,7 @@ public void Requirements_Export_NullFilePath_ThrowsArgumentException() File.WriteAllText(reqPath, yamlContent); var requirements = Requirements.Read(reqPath); - var ex = Assert.ThrowsException(() => requirements.Export(null!)); + var ex = Assert.ThrowsExactly(() => requirements.Export(null!)); Assert.Contains("File path cannot be null or empty", ex.Message); } @@ -204,7 +204,7 @@ public void Requirements_Export_EmptyFilePath_ThrowsArgumentException() File.WriteAllText(reqPath, yamlContent); var requirements = Requirements.Read(reqPath); - var ex = Assert.ThrowsException(() => requirements.Export(string.Empty)); + var ex = Assert.ThrowsExactly(() => requirements.Export(string.Empty)); Assert.Contains("File path cannot be null or empty", ex.Message); } diff --git a/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs b/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs index e248bd0..a89b731 100644 --- a/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs @@ -326,7 +326,7 @@ public void Requirements_Read_DuplicateRequirementId_ThrowsException() var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + var ex = Assert.ThrowsExactly(() => Requirements.Read(filePath)); Assert.Contains("SYS-SEC-001", ex.Message); Assert.Contains("Duplicate requirement ID", ex.Message); } @@ -376,7 +376,7 @@ public void Requirements_Read_FileNotFound_ThrowsException() { var nonExistentPath = Path.Combine(_testDirectory, "nonexistent.yaml"); - var ex = Assert.ThrowsException(() => Requirements.Read(nonExistentPath)); + var ex = Assert.ThrowsExactly(() => Requirements.Read(nonExistentPath)); Assert.Contains("Requirements file not found", ex.Message); } @@ -482,7 +482,7 @@ public void Requirements_Read_BlankRequirementId_ThrowsExceptionWithFileLocation var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + var ex = Assert.ThrowsExactly(() => Requirements.Read(filePath)); Assert.Contains("Requirement ID cannot be blank", ex.Message); Assert.Contains("System Security", ex.Message); Assert.Contains(filePath, ex.Message); @@ -504,7 +504,7 @@ public void Requirements_Read_BlankRequirementTitle_ThrowsExceptionWithFileLocat var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + var ex = Assert.ThrowsExactly(() => Requirements.Read(filePath)); Assert.Contains("Requirement title cannot be blank", ex.Message); Assert.Contains("SYS-SEC-001", ex.Message); Assert.Contains(filePath, ex.Message); @@ -526,7 +526,7 @@ public void Requirements_Read_BlankSectionTitle_ThrowsExceptionWithFileLocation( var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + var ex = Assert.ThrowsExactly(() => Requirements.Read(filePath)); Assert.Contains("Section title cannot be blank", ex.Message); Assert.Contains(filePath, ex.Message); } @@ -551,11 +551,10 @@ public void Requirements_Read_BlankTestNameInRequirement_ThrowsExceptionWithFile var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + var ex = Assert.ThrowsExactly(() => Requirements.Read(filePath)); Assert.Contains("Test name cannot be blank", ex.Message); Assert.Contains("SYS-SEC-001", ex.Message); - Assert.Contains(filePath, ex.Message); - } + Assert.Contains(filePath, ex.Message); } /// @@ -580,7 +579,7 @@ public void Requirements_Read_BlankTestNameInMapping_ThrowsExceptionWithFileLoca var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + var ex = Assert.ThrowsExactly(() => Requirements.Read(filePath)); Assert.Contains("Test name cannot be blank", ex.Message); Assert.Contains("SYS-SEC-001", ex.Message); Assert.Contains(filePath, ex.Message); @@ -607,7 +606,7 @@ public void Requirements_Read_BlankMappingId_ThrowsExceptionWithFileLocation() var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + var ex = Assert.ThrowsExactly(() => Requirements.Read(filePath)); Assert.Contains("Mapping requirement ID cannot be blank", ex.Message); Assert.Contains(filePath, ex.Message); } @@ -630,11 +629,10 @@ public void Requirements_Read_DuplicateRequirementId_ExceptionIncludesFileLocati var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + var ex = Assert.ThrowsExactly(() => Requirements.Read(filePath)); Assert.Contains("SYS-SEC-001", ex.Message); Assert.Contains("Duplicate requirement ID", ex.Message); - Assert.Contains(filePath, ex.Message); - } + Assert.Contains(filePath, ex.Message); } /// @@ -749,7 +747,7 @@ public void Requirements_Read_SingleFileWithParamsArray_WorksCorrectly() [TestMethod] public void Requirements_Read_NoArguments_ThrowsArgumentException() { - var ex = Assert.ThrowsException(() => Requirements.Read()); + var ex = Assert.ThrowsExactly(() => Requirements.Read()); Assert.Contains("At least one file path must be provided", ex.Message); } @@ -759,7 +757,7 @@ public void Requirements_Read_NoArguments_ThrowsArgumentException() [TestMethod] public void Requirements_Read_NullArgument_ThrowsArgumentException() { - var ex = Assert.ThrowsException(() => Requirements.Read(null!)); + var ex = Assert.ThrowsExactly(() => Requirements.Read(null!)); Assert.Contains("At least one file path must be provided", ex.Message); } @@ -850,7 +848,7 @@ public void Requirements_Read_BlankTagName_ThrowsExceptionWithFileLocation() var filePath = Path.Combine(_testDirectory, "requirements.yaml"); File.WriteAllText(filePath, yamlContent); - var ex = Assert.ThrowsException(() => Requirements.Read(filePath)); + var ex = Assert.ThrowsExactly(() => Requirements.Read(filePath)); Assert.Contains("Tag name cannot be blank", ex.Message); Assert.Contains("SYS-SEC-001", ex.Message); Assert.Contains(filePath, ex.Message); diff --git a/test/DemaConsulting.ReqStream.Tests/TraceMatrixExportTests.cs b/test/DemaConsulting.ReqStream.Tests/TraceMatrixExportTests.cs index 35410c9..de1faa1 100644 --- a/test/DemaConsulting.ReqStream.Tests/TraceMatrixExportTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/TraceMatrixExportTests.cs @@ -358,7 +358,7 @@ public void TraceMatrix_Export_NullFilePath_ThrowsArgumentException() // Create TraceMatrix var matrix = new TraceMatrix(requirements); - var ex = Assert.ThrowsException(() => matrix.Export(null!)); + var ex = Assert.ThrowsExactly(() => matrix.Export(null!)); Assert.Contains("File path cannot be null or empty", ex.Message); } @@ -385,7 +385,7 @@ public void TraceMatrix_Export_EmptyFilePath_ThrowsArgumentException() // Create TraceMatrix var matrix = new TraceMatrix(requirements); - var ex = Assert.ThrowsException(() => matrix.Export(string.Empty)); + var ex = Assert.ThrowsExactly(() => matrix.Export(string.Empty)); Assert.Contains("File path cannot be null or empty", ex.Message); } diff --git a/test/DemaConsulting.ReqStream.Tests/TraceMatrixReadTests.cs b/test/DemaConsulting.ReqStream.Tests/TraceMatrixReadTests.cs index 65ca2aa..1bdf865 100644 --- a/test/DemaConsulting.ReqStream.Tests/TraceMatrixReadTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/TraceMatrixReadTests.cs @@ -266,7 +266,7 @@ public void TraceMatrix_WithExtraTests_IgnoresUnreferencedTests() [TestMethod] public void TraceMatrix_NullRequirements_ThrowsArgumentNullException() { - var ex = Assert.ThrowsException(() => _ = new TraceMatrix(null!, Array.Empty())); + var ex = Assert.ThrowsExactly(() => _ = new TraceMatrix(null!, Array.Empty())); Assert.Contains("requirements", ex.Message); } @@ -292,7 +292,7 @@ public void TraceMatrix_MissingFile_ThrowsFileNotFoundException() var nonExistentPath = Path.Combine(_testDirectory, "nonexistent.trx"); - var ex = Assert.ThrowsException(() => _ = new TraceMatrix(requirements, nonExistentPath)); + var ex = Assert.ThrowsExactly(() => _ = new TraceMatrix(requirements, nonExistentPath)); Assert.Contains("Test result file not found", ex.Message); } From 209aa4302a68e0d8acb8bc59f74d2f6b6d41b12f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 12:08:31 +0000 Subject: [PATCH 4/4] Address code review feedback - revert redundant Assert.Contains checks Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- test/DemaConsulting.ReqStream.Tests/ContextTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs index 31a6fb2..cdcad5a 100644 --- a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs @@ -469,8 +469,8 @@ public void Context_Create_WithRequirementsPattern_ExpandsGlobPattern() using var context = Context.Create(["--requirements", "*.yaml"]); Assert.HasCount(2, context.RequirementsFiles); - Assert.Contains(context.RequirementsFiles.Single(f => f.EndsWith("req1.yaml")), context.RequirementsFiles); - Assert.Contains(context.RequirementsFiles.Single(f => f.EndsWith("req2.yaml")), context.RequirementsFiles); + Assert.IsTrue(context.RequirementsFiles.Any(f => f.EndsWith("req1.yaml"))); + Assert.IsTrue(context.RequirementsFiles.Any(f => f.EndsWith("req2.yaml"))); Assert.AreEqual(0, context.ExitCode); } finally @@ -500,8 +500,8 @@ public void Context_Create_WithTestsPattern_ExpandsGlobPattern() using var context = Context.Create(["--tests", "*.trx"]); Assert.HasCount(2, context.TestFiles); - Assert.Contains(context.TestFiles.Single(f => f.EndsWith("test1.trx")), context.TestFiles); - Assert.Contains(context.TestFiles.Single(f => f.EndsWith("test2.trx")), context.TestFiles); + Assert.IsTrue(context.TestFiles.Any(f => f.EndsWith("test1.trx"))); + Assert.IsTrue(context.TestFiles.Any(f => f.EndsWith("test2.trx"))); Assert.AreEqual(0, context.ExitCode); } finally