From 51ce96ac6b2feda35bbc611044d2b67fc7918ca2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 10 Jan 2026 18:30:37 +0000
Subject: [PATCH 1/6] Initial plan
From f2643b2b0dfb0ec81c0bd1dfa40579ebf9ef844d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 10 Jan 2026 18:38:04 +0000
Subject: [PATCH 2/6] Add --enforce command-line option for requirements
enforcement
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
---
src/DemaConsulting.ReqStream/Context.cs | 11 +
src/DemaConsulting.ReqStream/Program.cs | 21 +-
src/DemaConsulting.ReqStream/TraceMatrix.cs | 10 +
.../ContextTests.cs | 12 ++
.../ProgramTests.cs | 197 ++++++++++++++++++
5 files changed, 250 insertions(+), 1 deletion(-)
diff --git a/src/DemaConsulting.ReqStream/Context.cs b/src/DemaConsulting.ReqStream/Context.cs
index 77e2569..97a4ee3 100644
--- a/src/DemaConsulting.ReqStream/Context.cs
+++ b/src/DemaConsulting.ReqStream/Context.cs
@@ -58,6 +58,11 @@ public sealed class Context : IDisposable
///
public bool Validate { get; private init; }
+ ///
+ /// Gets a value indicating whether the enforce flag was specified.
+ ///
+ public bool Enforce { get; private init; }
+
///
/// Gets the list of requirements files found from the --requirements glob pattern.
///
@@ -113,6 +118,7 @@ public static Context Create(string[] args)
var help = false;
var silent = false;
var validate = false;
+ var enforce = false;
// Initialize collection variables
var requirementsFiles = new List();
@@ -153,6 +159,10 @@ public static Context Create(string[] args)
validate = true;
break;
+ case "--enforce":
+ enforce = true;
+ break;
+
case "--log":
// Ensure argument has a value
if (i >= args.Length)
@@ -245,6 +255,7 @@ public static Context Create(string[] args)
Help = help,
Silent = silent,
Validate = validate,
+ Enforce = enforce,
RequirementsFiles = requirementsFiles,
TestFiles = testFiles,
RequirementsReport = requirementsReport,
diff --git a/src/DemaConsulting.ReqStream/Program.cs b/src/DemaConsulting.ReqStream/Program.cs
index d5d64a4..d4e7b05 100644
--- a/src/DemaConsulting.ReqStream/Program.cs
+++ b/src/DemaConsulting.ReqStream/Program.cs
@@ -142,6 +142,7 @@ private static void PrintHelp()
Console.WriteLine(" --tests Test result files glob pattern (TRX or JUnit)");
Console.WriteLine(" --matrix Export trace matrix to markdown file");
Console.WriteLine(" --matrix-depth Markdown header depth for trace matrix (default: 1)");
+ Console.WriteLine(" --enforce Fail if requirements are not fully tested");
}
///
@@ -171,10 +172,11 @@ private static void ProcessRequirements(Context context)
}
// Create trace matrix if test files are specified
+ TraceMatrix? traceMatrix = null;
if (context.TestFiles.Count > 0)
{
context.WriteLine($"Processing {context.TestFiles.Count} test result file(s)...");
- var traceMatrix = new TraceMatrix(requirements, context.TestFiles.ToArray());
+ traceMatrix = new TraceMatrix(requirements, context.TestFiles.ToArray());
context.WriteLine("Trace matrix created successfully.");
// Export trace matrix if requested
@@ -185,5 +187,22 @@ private static void ProcessRequirements(Context context)
context.WriteLine("Trace matrix report generated successfully.");
}
}
+
+ // Enforce requirements coverage if requested
+ if (context.Enforce)
+ {
+ if (traceMatrix != null)
+ {
+ var (satisfied, total) = traceMatrix.CalculateSatisfiedRequirements();
+ if (satisfied < total)
+ {
+ context.WriteError($"Error: Only {satisfied} of {total} requirements are satisfied with tests.");
+ }
+ }
+ else
+ {
+ context.WriteError("Error: Cannot enforce requirements without test results. Use --tests to specify test result files.");
+ }
+ }
}
}
diff --git a/src/DemaConsulting.ReqStream/TraceMatrix.cs b/src/DemaConsulting.ReqStream/TraceMatrix.cs
index 4c02ea5..511a0ef 100644
--- a/src/DemaConsulting.ReqStream/TraceMatrix.cs
+++ b/src/DemaConsulting.ReqStream/TraceMatrix.cs
@@ -128,6 +128,16 @@ private void ExportSummary(TextWriter writer, int depth)
writer.WriteLine();
}
+ ///
+ /// Calculates how many requirements are satisfied.
+ /// A requirement is satisfied if it has at least one test and all tests have passed.
+ ///
+ /// A tuple of (satisfied count, total count).
+ public (int satisfied, int total) CalculateSatisfiedRequirements()
+ {
+ return CalculateSatisfiedRequirements(_requirements);
+ }
+
///
/// Calculates how many requirements are satisfied.
/// A requirement is satisfied if it has at least one test and all tests have passed.
diff --git a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs
index 674b37d..1ed5c5b 100644
--- a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs
+++ b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs
@@ -129,6 +129,18 @@ public void Create_ValidateFlag_SetsValidateProperty()
Assert.AreEqual(0, context.ExitCode);
}
+ ///
+ /// Test creating a context with enforce flag.
+ ///
+ [TestMethod]
+ public void Create_EnforceFlag_SetsEnforceProperty()
+ {
+ using var context = Context.Create(["--enforce"]);
+
+ Assert.IsTrue(context.Enforce);
+ Assert.AreEqual(0, context.ExitCode);
+ }
+
///
/// Test creating a context with report depth.
///
diff --git a/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs b/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs
index 70671a8..ba8e157 100644
--- a/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs
+++ b/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs
@@ -309,4 +309,201 @@ public void Run_WithHelpAndValidate_ProcessesHelpFirst()
Console.SetOut(originalOut);
}
}
+
+ ///
+ /// Test enforcement with fully satisfied requirements succeeds.
+ ///
+ [TestMethod]
+ public void Run_WithEnforcementAndFullySatisfiedRequirements_Succeeds()
+ {
+ // Create a test requirements file
+ var reqFile = Path.Combine(_testDirectory, "requirements.yaml");
+ File.WriteAllText(reqFile, @"
+sections:
+ - title: Test Section
+ requirements:
+ - id: REQ-001
+ title: Test Requirement
+ tests:
+ - TestMethod1
+");
+
+ // Create a test TRX file with passing test using TestResults library
+ var testResults = new DemaConsulting.TestResults.TestResults { Name = "TestRun" };
+ testResults.Results.Add(new DemaConsulting.TestResults.TestResult
+ {
+ Name = "TestMethod1",
+ ClassName = "TestClass",
+ CodeBase = "Tests.dll",
+ Outcome = DemaConsulting.TestResults.TestOutcome.Passed,
+ Duration = TimeSpan.FromSeconds(1)
+ });
+
+ var trxFile = Path.Combine(_testDirectory, "tests.trx");
+ File.WriteAllText(trxFile, DemaConsulting.TestResults.IO.TrxSerializer.Serialize(testResults));
+
+ // Save current directory and change to test directory
+ var originalDir = Directory.GetCurrentDirectory();
+ try
+ {
+ Directory.SetCurrentDirectory(_testDirectory);
+
+ using var context = Context.Create([
+ "--requirements", "*.yaml",
+ "--tests", "*.trx",
+ "--enforce"
+ ]);
+ Program.Run(context);
+
+ Assert.AreEqual(0, context.ExitCode);
+ }
+ finally
+ {
+ Directory.SetCurrentDirectory(originalDir);
+ }
+ }
+
+ ///
+ /// Test enforcement with unsatisfied requirements fails.
+ ///
+ [TestMethod]
+ public void Run_WithEnforcementAndUnsatisfiedRequirements_Fails()
+ {
+ // Create a test requirements file with one tested and one untested requirement
+ var reqFile = Path.Combine(_testDirectory, "requirements.yaml");
+ File.WriteAllText(reqFile, @"
+sections:
+ - title: Test Section
+ requirements:
+ - id: REQ-001
+ title: Tested Requirement
+ tests:
+ - TestMethod1
+ - id: REQ-002
+ title: Untested Requirement
+");
+
+ // Create a test TRX file with passing test using TestResults library
+ var testResults = new DemaConsulting.TestResults.TestResults { Name = "TestRun" };
+ testResults.Results.Add(new DemaConsulting.TestResults.TestResult
+ {
+ Name = "TestMethod1",
+ ClassName = "TestClass",
+ CodeBase = "Tests.dll",
+ Outcome = DemaConsulting.TestResults.TestOutcome.Passed,
+ Duration = TimeSpan.FromSeconds(1)
+ });
+
+ var trxFile = Path.Combine(_testDirectory, "tests.trx");
+ File.WriteAllText(trxFile, DemaConsulting.TestResults.IO.TrxSerializer.Serialize(testResults));
+
+ // Save current directory and change to test directory
+ var originalDir = Directory.GetCurrentDirectory();
+ try
+ {
+ Directory.SetCurrentDirectory(_testDirectory);
+
+ using var context = Context.Create([
+ "--requirements", "*.yaml",
+ "--tests", "*.trx",
+ "--enforce"
+ ]);
+ Program.Run(context);
+
+ Assert.AreEqual(1, context.ExitCode);
+ }
+ finally
+ {
+ Directory.SetCurrentDirectory(originalDir);
+ }
+ }
+
+ ///
+ /// Test enforcement without test files fails.
+ ///
+ [TestMethod]
+ public void Run_WithEnforcementAndNoTests_Fails()
+ {
+ // Create a test requirements file
+ var reqFile = Path.Combine(_testDirectory, "requirements.yaml");
+ File.WriteAllText(reqFile, @"
+sections:
+ - title: Test Section
+ requirements:
+ - id: REQ-001
+ title: Test Requirement
+");
+
+ // Save current directory and change to test directory
+ var originalDir = Directory.GetCurrentDirectory();
+ try
+ {
+ Directory.SetCurrentDirectory(_testDirectory);
+
+ using var context = Context.Create([
+ "--requirements", "*.yaml",
+ "--enforce"
+ ]);
+ Program.Run(context);
+
+ Assert.AreEqual(1, context.ExitCode);
+ }
+ finally
+ {
+ Directory.SetCurrentDirectory(originalDir);
+ }
+ }
+
+ ///
+ /// Test enforcement with failed tests fails.
+ ///
+ [TestMethod]
+ public void Run_WithEnforcementAndFailedTests_Fails()
+ {
+ // Create a test requirements file
+ var reqFile = Path.Combine(_testDirectory, "requirements.yaml");
+ File.WriteAllText(reqFile, @"
+sections:
+ - title: Test Section
+ requirements:
+ - id: REQ-001
+ title: Test Requirement
+ tests:
+ - TestMethod1
+");
+
+ // Create a test TRX file with failing test using TestResults library
+ var testResults = new DemaConsulting.TestResults.TestResults { Name = "TestRun" };
+ testResults.Results.Add(new DemaConsulting.TestResults.TestResult
+ {
+ Name = "TestMethod1",
+ ClassName = "TestClass",
+ CodeBase = "Tests.dll",
+ Outcome = DemaConsulting.TestResults.TestOutcome.Failed,
+ Duration = TimeSpan.FromSeconds(1)
+ });
+
+ var trxFile = Path.Combine(_testDirectory, "tests.trx");
+ File.WriteAllText(trxFile, DemaConsulting.TestResults.IO.TrxSerializer.Serialize(testResults));
+
+ // Save current directory and change to test directory
+ var originalDir = Directory.GetCurrentDirectory();
+ try
+ {
+ Directory.SetCurrentDirectory(_testDirectory);
+
+ using var context = Context.Create([
+ "--requirements", "*.yaml",
+ "--tests", "*.trx",
+ "--enforce"
+ ]);
+ Program.Run(context);
+
+ Assert.AreEqual(1, context.ExitCode);
+ }
+ finally
+ {
+ Directory.SetCurrentDirectory(originalDir);
+ }
+ }
}
From b30db614525b4f9269e9a6cef3c2fa0e8cb539d6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 10 Jan 2026 19:08:30 +0000
Subject: [PATCH 3/6] Update README and guide documentation for --enforce
option
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
---
README.md | 52 ++++++
docs/guide/guide.md | 373 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 425 insertions(+)
diff --git a/README.md b/README.md
index 4c286f0..b06cf40 100644
--- a/README.md
+++ b/README.md
@@ -98,6 +98,7 @@ Options:
--tests Test result files glob pattern (TRX or JUnit)
--matrix Export trace matrix to markdown file
--matrix-depth Markdown header depth for trace matrix (default: 1)
+ --enforce Fail if requirements are not fully tested
```
## YAML Format
@@ -201,6 +202,57 @@ requirements:
- File part matching is case-insensitive and supports partial filename matching
- Both plain and source-specific test names can be mixed in the same requirement
+## Requirements Enforcement
+
+ReqStream can enforce that all requirements have adequate test coverage, making it ideal for use in CI/CD pipelines
+to ensure quality gates are met.
+
+### Enforcement Mode
+
+Use the `--enforce` flag to fail the build if any requirements are not fully satisfied with tests:
+
+```bash
+reqstream --requirements "**/*.yaml" --tests "**/*.trx" --enforce
+```
+
+When enforcement mode is enabled:
+
+- All requirements must have at least one test mapped (either directly or through child requirements)
+- All mapped tests must be present in the test results
+- All mapped tests must pass
+- If any requirement is not satisfied, an error is reported and the exit code is non-zero
+
+### CI/CD Integration
+
+Enforcement mode is designed for CI/CD pipelines. The error message is printed after all reports are generated,
+allowing you to review the reports for failure analysis:
+
+```bash
+# GitHub Actions example
+- name: Validate Requirements Coverage
+ run: |
+ dotnet reqstream \
+ --requirements "docs/**/*.yaml" \
+ --tests "test-results/**/*.trx" \
+ --matrix trace-matrix.md \
+ --enforce
+```
+
+If requirements are not fully satisfied, the tool will print:
+
+```text
+Error: Only X of Y requirements are satisfied with tests.
+```
+
+And exit with code 1, failing the build.
+
+### Best Practices
+
+- Use `--enforce` in CI/CD to prevent merging code that reduces requirements coverage
+- Generate the trace matrix (`--matrix`) alongside enforcement to review coverage details
+- Start without enforcement initially, then enable it once baseline coverage is established
+- Use transitive coverage through child requirements for high-level requirements that don't have direct tests
+
## Development
### Requirements
diff --git a/docs/guide/guide.md b/docs/guide/guide.md
index 326c67d..8d842f3 100644
--- a/docs/guide/guide.md
+++ b/docs/guide/guide.md
@@ -444,6 +444,7 @@ ReqStream supports the following command-line options:
| `--tests ` | Glob pattern for test result files (TRX or JUnit format) |
| `--matrix ` | Export trace matrix to markdown file |
| `--matrix-depth ` | Starting header depth for trace matrix (default: 1) |
+| `--enforce` | Fail if requirements are not fully tested |
### Examples
@@ -498,6 +499,22 @@ reqstream --requirements "**/*.yaml" \
--tests "test-results/**/*.xml"
```
+**Requirements enforcement in CI/CD:**
+
+```bash
+# Enforce that all requirements have passing tests
+reqstream --requirements "**/*.yaml" \
+ --tests "test-results/**/*.trx" \
+ --enforce
+
+# Generate reports and enforce coverage
+reqstream --requirements "**/*.yaml" \
+ --tests "test-results/**/*.trx" \
+ --report requirements.md \
+ --matrix trace-matrix.md \
+ --enforce
+```
+
## Exporting
ReqStream can export requirements and test trace matrices to markdown format for documentation and review.
@@ -621,6 +638,328 @@ reqstream --silent \
--report requirements.md
```
+## Requirements Enforcement
+
+ReqStream can enforce that all requirements have adequate test coverage, making it ideal for use in CI/CD pipelines
+as a quality gate to ensure requirements are properly verified.
+
+### Overview
+
+Requirements enforcement validates that:
+
+- Every requirement has at least one test mapped (either directly or through child requirements)
+- All mapped tests are present in the test result files
+- All mapped tests pass
+
+If any requirement doesn't meet these criteria, the tool reports an error and exits with a non-zero status code,
+causing CI/CD builds to fail.
+
+### Basic Usage
+
+Enable enforcement with the `--enforce` flag:
+
+```bash
+reqstream --requirements "**/*.yaml" \
+ --tests "test-results/**/*.trx" \
+ --enforce
+```
+
+### How It Works
+
+Requirements can be satisfied in two ways:
+
+1. **Direct tests**: Tests mapped directly to the requirement via the `tests` field
+2. **Transitive tests**: Tests mapped to child requirements
+
+For a requirement to be satisfied:
+
+- It must have at least one test (direct or via children)
+- All tests must have been executed in the test results
+- All tests must have passed
+
+**Example:**
+
+```yaml
+sections:
+ - title: "System Security"
+ requirements:
+ - id: "SYS-SEC-001"
+ title: "The system shall support authentication."
+ children:
+ - "AUTH-001"
+ - "AUTH-002"
+
+ - id: "AUTH-001"
+ title: "Users shall authenticate with username and password."
+ tests:
+ - "Test_UsernamePassword_Valid"
+ - "Test_UsernamePassword_Invalid"
+
+ - id: "AUTH-002"
+ title: "Failed authentication attempts shall be logged."
+ tests:
+ - "Test_FailedAuth_Logged"
+```
+
+In this example:
+
+- `AUTH-001` is satisfied if both its tests pass
+- `AUTH-002` is satisfied if its test passes
+- `SYS-SEC-001` is satisfied transitively through its children (if both `AUTH-001` and `AUTH-002` are satisfied)
+
+### Enforcement Output
+
+When enforcement mode is enabled, ReqStream processes normally and generates any requested reports. After all
+processing is complete, it checks requirement satisfaction.
+
+**If all requirements are satisfied:**
+
+```text
+ReqStream version 1.0.0
+Copyright (c) 2026 DEMA Consulting
+
+Reading 1 requirements file(s)...
+Requirements loaded successfully.
+Processing 1 test result file(s)...
+Trace matrix created successfully.
+Exporting trace matrix to trace-matrix.md...
+Trace matrix report generated successfully.
+```
+
+Exit code: **0** (success)
+
+**If requirements are not satisfied:**
+
+```text
+ReqStream version 1.0.0
+Copyright (c) 2026 DEMA Consulting
+
+Reading 1 requirements file(s)...
+Requirements loaded successfully.
+Processing 1 test result file(s)...
+Trace matrix created successfully.
+Exporting trace matrix to trace-matrix.md...
+Trace matrix report generated successfully.
+Error: Only 15 of 20 requirements are satisfied with tests.
+```
+
+Exit code: **1** (failure)
+
+The error message clearly indicates how many requirements are satisfied, making it easy to track progress toward
+full coverage.
+
+### CI/CD Integration
+
+Requirements enforcement is designed for CI/CD pipelines. Here are examples for common platforms:
+
+**GitHub Actions:**
+
+```yaml
+name: Validate Requirements
+
+on: [push, pull_request]
+
+jobs:
+ requirements:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '10.0.x'
+
+ - name: Install ReqStream
+ run: dotnet tool install -g DemaConsulting.ReqStream
+
+ - name: Run Tests
+ run: dotnet test --logger trx
+
+ - name: Validate Requirements Coverage
+ run: |
+ reqstream \
+ --requirements "docs/**/*.yaml" \
+ --tests "**/*.trx" \
+ --matrix trace-matrix.md \
+ --enforce
+
+ - name: Upload Trace Matrix
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: trace-matrix
+ path: trace-matrix.md
+```
+
+**Azure Pipelines:**
+
+```yaml
+steps:
+ - task: DotNetCoreCLI@2
+ displayName: 'Install ReqStream'
+ inputs:
+ command: 'custom'
+ custom: 'tool'
+ arguments: 'install -g DemaConsulting.ReqStream'
+
+ - task: DotNetCoreCLI@2
+ displayName: 'Run Tests'
+ inputs:
+ command: 'test'
+ arguments: '--logger trx'
+
+ - script: |
+ reqstream \
+ --requirements "docs/**/*.yaml" \
+ --tests "**/*.trx" \
+ --matrix trace-matrix.md \
+ --enforce
+ displayName: 'Validate Requirements Coverage'
+```
+
+**GitLab CI:**
+
+```yaml
+validate-requirements:
+ stage: test
+ script:
+ - dotnet tool install -g DemaConsulting.ReqStream
+ - export PATH="$PATH:$HOME/.dotnet/tools"
+ - dotnet test --logger trx
+ - reqstream --requirements "docs/**/*.yaml" --tests "**/*.trx" --matrix trace-matrix.md --enforce
+ artifacts:
+ when: always
+ paths:
+ - trace-matrix.md
+```
+
+### Best Practices
+
+**Start without enforcement:**
+
+When first adopting ReqStream, start by generating trace matrices without enforcement to understand your current
+coverage:
+
+```bash
+reqstream --requirements "**/*.yaml" \
+ --tests "**/*.trx" \
+ --matrix trace-matrix.md
+```
+
+Review the trace matrix to identify gaps, then work toward full coverage before enabling enforcement.
+
+**Enable enforcement incrementally:**
+
+If you have a large requirements set with incomplete coverage, consider:
+
+1. Start with enforcement on critical requirements only
+2. Gradually expand coverage
+3. Enable enforcement for all requirements once baseline is achieved
+
+**Use in pull requests:**
+
+Enable enforcement in PR validation to prevent coverage from decreasing:
+
+```yaml
+# GitHub Actions PR validation
+on: [pull_request]
+
+jobs:
+ requirements-coverage:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - run: dotnet test --logger trx
+ - run: dotnet reqstream --requirements "**/*.yaml" --tests "**/*.trx" --enforce
+```
+
+**Generate reports for failure analysis:**
+
+Always generate the trace matrix when using enforcement so you can review which requirements are not satisfied:
+
+```bash
+reqstream --requirements "**/*.yaml" \
+ --tests "**/*.trx" \
+ --matrix trace-matrix.md \
+ --enforce
+```
+
+The trace matrix will show which requirements lack tests or have failing tests.
+
+**Leverage transitive coverage:**
+
+Use parent-child relationships to organize requirements hierarchically. High-level requirements don't need direct
+tests if they're satisfied through child requirements:
+
+```yaml
+requirements:
+ - id: "HIGH-LEVEL-001"
+ title: "System shall be secure"
+ children:
+ - "SEC-001"
+ - "SEC-002"
+ - "SEC-003"
+
+ # Children have direct tests
+ - id: "SEC-001"
+ title: "Authentication required"
+ tests:
+ - "Test_Auth_Required"
+```
+
+### Troubleshooting Enforcement
+
+**Error: Cannot enforce requirements without test results**
+
+This error occurs when `--enforce` is used without the `--tests` option. You must provide test result files to
+validate coverage:
+
+```bash
+# Wrong - no test results
+reqstream --requirements "**/*.yaml" --enforce
+
+# Correct - with test results
+reqstream --requirements "**/*.yaml" --tests "**/*.trx" --enforce
+```
+
+**All requirements show as unsatisfied**
+
+If all or most requirements are showing as unsatisfied, check:
+
+1. Test names in requirements YAML match test names in test result files exactly (case-sensitive)
+2. Test result files are in TRX or JUnit format
+3. Tests are actually being executed (check test result file contents)
+4. Tests are passing (failing tests count as unsatisfied)
+
+**Some tests don't match**
+
+If specific tests aren't being recognized:
+
+1. Verify exact test name match (including namespaces if present)
+2. Check for typos in requirements YAML
+3. If using source-specific tests (`filepart@testname`), verify the file part matches the test result filename
+4. Run without `--enforce` first and review the trace matrix to see which tests are found
+
+**Requirements with no direct tests show as unsatisfied**
+
+Ensure parent requirements reference their children via the `children` field:
+
+```yaml
+requirements:
+ - id: "PARENT-001"
+ title: "Parent requirement"
+ children:
+ - "CHILD-001" # Add child references
+
+ - id: "CHILD-001"
+ title: "Child requirement"
+ tests:
+ - "Test_Child"
+```
+
+
+
## FAQ
### General Questions
@@ -736,6 +1075,40 @@ results from all test result files.
A: Yes, you can mix both styles in the same requirement. Plain test names will aggregate results from all test result
files, while source-specific test names will only match their specified sources.
+### Enforcement Questions
+
+**Q: What does the --enforce flag do?**
+
+A: The `--enforce` flag validates that all requirements have adequate test coverage. If any requirement lacks tests or
+has failing tests, the tool will exit with a non-zero status code, failing the build. This is useful for CI/CD
+pipelines to ensure requirements are properly verified.
+
+**Q: When should I use --enforce?**
+
+A: Use `--enforce` in CI/CD pipelines to prevent merging code that reduces requirements coverage. Start by reviewing
+your coverage with trace matrices first, then enable enforcement once you have acceptable baseline coverage.
+
+**Q: How does transitive coverage work with --enforce?**
+
+A: A parent requirement can be satisfied through its child requirements. If a requirement references children via the
+`children` field, it's considered satisfied if all its children are satisfied with tests. This allows high-level
+requirements to be validated through their detailed child requirements.
+
+**Q: What happens if tests fail when --enforce is enabled?**
+
+A: Requirements with failing tests are considered not satisfied. The tool will report an error and exit with code 1.
+Review the trace matrix (use `--matrix`) to see which tests failed.
+
+**Q: Can I use --enforce without generating reports?**
+
+A: Yes, but it's recommended to generate the trace matrix (`--matrix`) alongside enforcement. The matrix provides
+detailed information about which requirements are not satisfied, making it easier to identify and fix coverage gaps.
+
+**Q: Why does --enforce require test results?**
+
+A: Enforcement validates that requirements have passing tests, which requires test result files. If you use `--enforce`
+without `--tests`, the tool will report an error asking you to specify test result files.
+
### Export Questions
**Q: Can I customize the markdown format of reports?**
From 3f61089ff6f1988bc5ef7e3a6e690ff4da5cac44 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 10 Jan 2026 19:15:18 +0000
Subject: [PATCH 4/6] Comprehensively rename all test methods to include class
name prefix for clarity
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
---
.github/agents/software-quality-enforcer.md | 8 +-
AGENTS.md | 7 +-
requirements.yaml | 104 +++++++++---------
.../ContextTests.cs | 62 +++++------
.../ProgramTests.cs | 26 ++---
.../RequirementsExportTests.cs | 16 +--
.../RequirementsParsingTests.cs | 50 ++++-----
.../RequirementsReadTests.cs | 50 ++++-----
8 files changed, 164 insertions(+), 159 deletions(-)
diff --git a/.github/agents/software-quality-enforcer.md b/.github/agents/software-quality-enforcer.md
index 478b83f..5813547 100644
--- a/.github/agents/software-quality-enforcer.md
+++ b/.github/agents/software-quality-enforcer.md
@@ -90,10 +90,12 @@ Based on `.editorconfig` and project preferences:
### Test Requirements
- **Test Framework**: MSTest (Microsoft.VisualStudio.TestTools.UnitTesting)
-- **Test File Naming**: `[Component]Tests.cs` (e.g., `BasicTests.cs`)
+- **Test File Naming**: `[Component]Tests.cs` (e.g., `ContextTests.cs`, `ProgramTests.cs`)
- **Test Class Naming**: Descriptive names ending with `Tests`
-- **Test Method Naming**: `TestMethod_Scenario_ExpectedBehavior`
- - Examples: `Parse_ValidYaml_ReturnsDocument()`, `Validate_MissingRequiredField_ThrowsException()`
+- **Test Method Naming**: `ClassName_MethodUnderTest_Scenario_ExpectedBehavior`
+ - Example: `Context_Create_NoArguments_ReturnsDefaultContext` clearly indicates testing the `Context.Create` method
+ - Example: `Program_Run_WithVersionFlag_PrintsVersion` clearly indicates testing the `Program.Run` method
+ - This pattern makes test intent clear for requirements traceability and linking
- **All tests must pass** before merging
- **No warnings allowed** in test builds
diff --git a/AGENTS.md b/AGENTS.md
index 6b18354..cb58c17 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -55,8 +55,11 @@ ReqStream/
## Testing Guidelines
- **Test Framework**: MSTest v4 (Microsoft.VisualStudio.TestTools.UnitTesting)
-- **Test File Naming**: `[Component]Tests.cs` (e.g., `BasicTests.cs`)
-- **Test Method Naming**: `TestMethod_Scenario_ExpectedBehavior` format
+- **Test File Naming**: `[Component]Tests.cs` (e.g., `ContextTests.cs`, `ProgramTests.cs`)
+- **Test Method Naming**: `ClassName_MethodUnderTest_Scenario_ExpectedBehavior` format
+ - Example: `Context_Create_NoArguments_ReturnsDefaultContext` clearly indicates testing the `Context.Create` method
+ - Example: `Context_WriteLine_NormalMode_WritesToConsole` clearly indicates testing the `Context.WriteLine` method
+ - This pattern makes test intent clear for requirements traceability
- **MSTest v4 APIs**: Use modern assertions:
- `Assert.HasCount(collection, expectedCount)` instead of `Assert.AreEqual(count, collection.Count)`
- `Assert.IsEmpty(collection)` instead of `Assert.AreEqual(0, collection.Count)`
diff --git a/requirements.yaml b/requirements.yaml
index 27a585f..5f10bc7 100644
--- a/requirements.yaml
+++ b/requirements.yaml
@@ -7,91 +7,91 @@ sections:
- id: "CLI-001"
title: "The tool shall provide a command-line interface."
tests:
- - "Create_NoArguments_ReturnsDefaultContext"
- - "Create_MultipleArguments_ParsesAllCorrectly"
+ - "Context_Create_NoArguments_ReturnsDefaultContext"
+ - "Context_Create_MultipleArguments_ParsesAllCorrectly"
- id: "CLI-002"
title: "The tool shall display version information when requested."
tests:
- - "Run_WithVersionFlag_PrintsVersion"
- - "Create_VersionFlag_SetsVersionProperty"
+ - "Program_Run_WithVersionFlag_PrintsVersion"
+ - "Context_Create_VersionFlag_SetsVersionProperty"
- id: "CLI-003"
title: "The tool shall display help information when requested."
tests:
- - "Run_WithHelpFlag_PrintsHelp"
- - "Create_HelpFlags_SetsHelpProperty"
+ - "Program_Run_WithHelpFlag_PrintsHelp"
+ - "Context_Create_HelpFlags_SetsHelpProperty"
- title: "Requirements File Processing"
requirements:
- id: "REQ-001"
title: "The tool shall process YAML requirements files."
tests:
- - "Read_SimpleRequirement_ParsesCorrectly"
- - "Run_WithRequirementsFiles_ProcessesSuccessfully"
- - "Read_ComplexStructure_ParsesCorrectly"
+ - "Requirements_Read_SimpleRequirement_ParsesCorrectly"
+ - "Program_Run_WithRequirementsFiles_ProcessesSuccessfully"
+ - "Requirements_Read_ComplexStructure_ParsesCorrectly"
- id: "REQ-002"
title: "The tool shall support glob patterns for requirements files."
tests:
- - "Create_WithRequirementsPattern_ExpandsGlobPattern"
+ - "Context_Create_WithRequirementsPattern_ExpandsGlobPattern"
- id: "REQ-003"
title: "The tool shall validate requirements file structure."
tests:
- - "Read_BlankSectionTitle_ThrowsExceptionWithFileLocation"
- - "Read_BlankRequirementId_ThrowsExceptionWithFileLocation"
- - "Read_BlankRequirementTitle_ThrowsExceptionWithFileLocation"
- - "Read_DuplicateRequirementId_ThrowsException"
- - "Read_DuplicateRequirementId_ExceptionIncludesFileLocation"
+ - "Requirements_Read_BlankSectionTitle_ThrowsExceptionWithFileLocation"
+ - "Requirements_Read_BlankRequirementId_ThrowsExceptionWithFileLocation"
+ - "Requirements_Read_BlankRequirementTitle_ThrowsExceptionWithFileLocation"
+ - "Requirements_Read_DuplicateRequirementId_ThrowsException"
+ - "Requirements_Read_DuplicateRequirementId_ExceptionIncludesFileLocation"
- id: "REQ-004"
title: "The tool shall support hierarchical sections and subsections."
tests:
- - "Read_NestedSections_ParsesHierarchyCorrectly"
- - "Export_NestedSections_CreatesHierarchy"
+ - "Requirements_Read_NestedSections_ParsesHierarchyCorrectly"
+ - "Requirements_Export_NestedSections_CreatesHierarchy"
- id: "REQ-005"
title: "The tool shall support file includes in requirements files."
tests:
- - "Read_WithIncludes_MergesFilesCorrectly"
- - "Read_MultipleFiles_MergesAllFiles"
- - "Read_IncludeLoop_DoesNotCauseInfiniteLoop"
+ - "Requirements_Read_WithIncludes_MergesFilesCorrectly"
+ - "Requirements_Read_MultipleFiles_MergesAllFiles"
+ - "Requirements_Read_IncludeLoop_DoesNotCauseInfiniteLoop"
- id: "REQ-006"
title: "The tool shall merge sections with the same hierarchy path."
tests:
- - "Read_IdenticalSections_MergesCorrectly"
- - "Read_MultipleFilesWithSameSections_MergesSections"
+ - "Requirements_Read_IdenticalSections_MergesCorrectly"
+ - "Requirements_Read_MultipleFilesWithSameSections_MergesSections"
- title: "Requirements Definition"
requirements:
- id: "REQ-007"
title: "The tool shall require each requirement to have a unique identifier."
tests:
- - "Read_DuplicateRequirementId_ThrowsException"
- - "Read_BlankRequirementId_ThrowsExceptionWithFileLocation"
- - "Read_MultipleFilesWithDuplicateIds_ThrowsException"
+ - "Requirements_Read_DuplicateRequirementId_ThrowsException"
+ - "Requirements_Read_BlankRequirementId_ThrowsExceptionWithFileLocation"
+ - "Requirements_Read_MultipleFilesWithDuplicateIds_ThrowsException"
- id: "REQ-008"
title: "The tool shall require each requirement to have a title."
tests:
- - "Read_BlankRequirementTitle_ThrowsExceptionWithFileLocation"
+ - "Requirements_Read_BlankRequirementTitle_ThrowsExceptionWithFileLocation"
- id: "REQ-009"
title: "The tool shall support parent-child relationships between requirements."
tests:
- - "Read_RequirementWithChildren_ParsesChildrenCorrectly"
- - "Export_WithChildRequirements_ConsidersChildTests"
+ - "Requirements_Read_RequirementWithChildren_ParsesChildrenCorrectly"
+ - "TraceMatrix_Export_WithChildRequirements_ConsidersChildTests"
- id: "REQ-010"
title: "The tool shall support test mappings for requirements."
tests:
- - "Read_RequirementWithTests_ParsesTestsCorrectly"
- - "Read_BlankTestNameInRequirement_ThrowsExceptionWithFileLocation"
- - "Read_TestMappings_AppliesMappingsCorrectly"
- - "Read_BlankTestNameInMapping_ThrowsExceptionWithFileLocation"
- - "Read_BlankMappingId_ThrowsExceptionWithFileLocation"
+ - "Requirements_Read_RequirementWithTests_ParsesTestsCorrectly"
+ - "Requirements_Read_BlankTestNameInRequirement_ThrowsExceptionWithFileLocation"
+ - "Requirements_Read_TestMappings_AppliesMappingsCorrectly"
+ - "Requirements_Read_BlankTestNameInMapping_ThrowsExceptionWithFileLocation"
+ - "Requirements_Read_BlankMappingId_ThrowsExceptionWithFileLocation"
- title: "Test Integration"
requirements:
@@ -117,7 +117,7 @@ sections:
- id: "TEST-004"
title: "The tool shall support glob patterns for test result files."
tests:
- - "Create_WithTestsPattern_ExpandsGlobPattern"
+ - "Context_Create_WithTestsPattern_ExpandsGlobPattern"
- "TraceMatrix_WithMixedFormats_ProcessesBoth"
- id: "TEST-005"
@@ -151,48 +151,48 @@ sections:
- id: "RPT-001"
title: "The tool shall export requirements to markdown format."
tests:
- - "Run_WithRequirementsExport_GeneratesReport"
- - "Export_SimpleRequirements_CreatesMarkdownFile"
- - "Export_MultipleSections_ExportsAll"
- - "Export_EmptyRequirements_CreatesEmptyFile"
+ - "Program_Run_WithRequirementsExport_GeneratesReport"
+ - "Requirements_Export_SimpleRequirements_CreatesMarkdownFile"
+ - "Requirements_Export_MultipleSections_ExportsAll"
+ - "Requirements_Export_EmptyRequirements_CreatesEmptyFile"
- id: "RPT-002"
title: "The tool shall support configurable markdown header depth for requirements reports."
tests:
- - "Create_ReportDepth_SetsReportDepthProperty"
- - "Export_WithCustomDepth_UsesCorrectHeaderLevel"
+ - "Context_Create_ReportDepth_SetsReportDepthProperty"
+ - "Requirements_Export_WithCustomDepth_UsesCorrectHeaderLevel"
- id: "RPT-003"
title: "The tool shall export trace matrices to markdown format."
tests:
- - "Run_WithTraceMatrixExport_GeneratesMatrix"
- - "Export_SimpleTraceMatrix_CreatesMarkdownFile"
- - "Export_WithFailedTests_ShowsFailures"
- - "Export_WithNoTests_ShowsNotSatisfied"
- - "Export_WithNotExecutedTests_ShowsNotExecuted"
+ - "Program_Run_WithTraceMatrixExport_GeneratesMatrix"
+ - "TraceMatrix_Export_SimpleTraceMatrix_CreatesMarkdownFile"
+ - "TraceMatrix_Export_WithFailedTests_ShowsFailures"
+ - "TraceMatrix_Export_WithNoTests_ShowsNotSatisfied"
+ - "TraceMatrix_Export_WithNotExecutedTests_ShowsNotExecuted"
- id: "RPT-004"
title: "The tool shall support configurable markdown header depth for trace matrices."
tests:
- - "Create_MatrixDepth_SetsMatrixDepthProperty"
- - "Export_WithCustomDepth_UsesCorrectHeaderLevel"
+ - "Context_Create_MatrixDepth_SetsMatrixDepthProperty"
+ - "Requirements_Export_WithCustomDepth_UsesCorrectHeaderLevel"
- title: "Logging"
requirements:
- id: "LOG-001"
title: "The tool shall support writing output to a log file."
tests:
- - "Create_WithLogFile_WritesToLogFile"
- - "Create_WithLogFileAndSilent_WritesToLogOnly"
- - "Dispose_WithLogFile_ClosesLogFile"
+ - "Context_Create_WithLogFile_WritesToLogFile"
+ - "Context_Create_WithLogFileAndSilent_WritesToLogOnly"
+ - "Context_Dispose_WithLogFile_ClosesLogFile"
- title: "Validation"
requirements:
- id: "VAL-001"
title: "The tool shall support self-validation mode."
tests:
- - "Run_WithValidateFlag_ShowsPlaceholder"
- - "Create_ValidateFlag_SetsValidateProperty"
+ - "Program_Run_WithValidateFlag_ShowsPlaceholder"
+ - "Context_Create_ValidateFlag_SetsValidateProperty"
- title: "Platform Support"
requirements:
diff --git a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs
index 1ed5c5b..139b99c 100644
--- a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs
+++ b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs
@@ -54,7 +54,7 @@ public void TestCleanup()
/// Test creating a context with no arguments.
///
[TestMethod]
- public void Create_NoArguments_ReturnsDefaultContext()
+ public void Context_Create_NoArguments_ReturnsDefaultContext()
{
using var context = Context.Create([]);
@@ -75,7 +75,7 @@ public void Create_NoArguments_ReturnsDefaultContext()
/// Test creating a context with version flag.
///
[TestMethod]
- public void Create_VersionFlag_SetsVersionProperty()
+ public void Context_Create_VersionFlag_SetsVersionProperty()
{
using var context1 = Context.Create(["-v"]);
Assert.IsTrue(context1.Version);
@@ -90,7 +90,7 @@ public void Create_VersionFlag_SetsVersionProperty()
/// Test creating a context with help flags.
///
[TestMethod]
- public void Create_HelpFlags_SetsHelpProperty()
+ public void Context_Create_HelpFlags_SetsHelpProperty()
{
using var context1 = Context.Create(["-?"]);
Assert.IsTrue(context1.Help);
@@ -109,7 +109,7 @@ public void Create_HelpFlags_SetsHelpProperty()
/// Test creating a context with silent flag.
///
[TestMethod]
- public void Create_SilentFlag_SetsSilentProperty()
+ public void Context_Create_SilentFlag_SetsSilentProperty()
{
using var context = Context.Create(["--silent"]);
@@ -121,7 +121,7 @@ public void Create_SilentFlag_SetsSilentProperty()
/// Test creating a context with validate flag.
///
[TestMethod]
- public void Create_ValidateFlag_SetsValidateProperty()
+ public void Context_Create_ValidateFlag_SetsValidateProperty()
{
using var context = Context.Create(["--validate"]);
@@ -133,7 +133,7 @@ public void Create_ValidateFlag_SetsValidateProperty()
/// Test creating a context with enforce flag.
///
[TestMethod]
- public void Create_EnforceFlag_SetsEnforceProperty()
+ public void Context_Create_EnforceFlag_SetsEnforceProperty()
{
using var context = Context.Create(["--enforce"]);
@@ -145,7 +145,7 @@ public void Create_EnforceFlag_SetsEnforceProperty()
/// Test creating a context with report depth.
///
[TestMethod]
- public void Create_ReportDepth_SetsReportDepthProperty()
+ public void Context_Create_ReportDepth_SetsReportDepthProperty()
{
using var context = Context.Create(["--report-depth", "3"]);
@@ -157,7 +157,7 @@ public void Create_ReportDepth_SetsReportDepthProperty()
/// Test creating a context with matrix depth.
///
[TestMethod]
- public void Create_MatrixDepth_SetsMatrixDepthProperty()
+ public void Context_Create_MatrixDepth_SetsMatrixDepthProperty()
{
using var context = Context.Create(["--matrix-depth", "2"]);
@@ -169,7 +169,7 @@ public void Create_MatrixDepth_SetsMatrixDepthProperty()
/// Test creating a context with report file.
///
[TestMethod]
- public void Create_ReportFile_SetsReportProperty()
+ public void Context_Create_ReportFile_SetsReportProperty()
{
using var context = Context.Create(["--report", "report.md"]);
@@ -181,7 +181,7 @@ public void Create_ReportFile_SetsReportProperty()
/// Test creating a context with matrix file.
///
[TestMethod]
- public void Create_MatrixFile_SetsMatrixProperty()
+ public void Context_Create_MatrixFile_SetsMatrixProperty()
{
using var context = Context.Create(["--matrix", "matrix.md"]);
@@ -193,7 +193,7 @@ public void Create_MatrixFile_SetsMatrixProperty()
/// Test creating a context with unsupported argument.
///
[TestMethod]
- public void Create_UnsupportedArgument_ThrowsException()
+ public void Context_Create_UnsupportedArgument_ThrowsException()
{
try
{
@@ -210,7 +210,7 @@ public void Create_UnsupportedArgument_ThrowsException()
/// Test creating a context with missing log filename.
///
[TestMethod]
- public void Create_MissingLogFilename_ThrowsException()
+ public void Context_Create_MissingLogFilename_ThrowsException()
{
try
{
@@ -227,7 +227,7 @@ public void Create_MissingLogFilename_ThrowsException()
/// Test creating a context with missing report filename.
///
[TestMethod]
- public void Create_MissingReportFilename_ThrowsException()
+ public void Context_Create_MissingReportFilename_ThrowsException()
{
try
{
@@ -244,7 +244,7 @@ public void Create_MissingReportFilename_ThrowsException()
/// Test creating a context with missing matrix filename.
///
[TestMethod]
- public void Create_MissingMatrixFilename_ThrowsException()
+ public void Context_Create_MissingMatrixFilename_ThrowsException()
{
try
{
@@ -261,7 +261,7 @@ public void Create_MissingMatrixFilename_ThrowsException()
/// Test creating a context with missing report depth.
///
[TestMethod]
- public void Create_MissingReportDepth_ThrowsException()
+ public void Context_Create_MissingReportDepth_ThrowsException()
{
try
{
@@ -278,7 +278,7 @@ public void Create_MissingReportDepth_ThrowsException()
/// Test creating a context with missing matrix depth.
///
[TestMethod]
- public void Create_MissingMatrixDepth_ThrowsException()
+ public void Context_Create_MissingMatrixDepth_ThrowsException()
{
try
{
@@ -295,7 +295,7 @@ public void Create_MissingMatrixDepth_ThrowsException()
/// Test creating a context with invalid report depth.
///
[TestMethod]
- public void Create_InvalidReportDepth_ThrowsException()
+ public void Context_Create_InvalidReportDepth_ThrowsException()
{
try
{
@@ -332,7 +332,7 @@ public void Create_InvalidReportDepth_ThrowsException()
/// Test creating a context with invalid matrix depth.
///
[TestMethod]
- public void Create_InvalidMatrixDepth_ThrowsException()
+ public void Context_Create_InvalidMatrixDepth_ThrowsException()
{
try
{
@@ -359,7 +359,7 @@ public void Create_InvalidMatrixDepth_ThrowsException()
/// Test WriteLine writes to console.
///
[TestMethod]
- public void WriteLine_NormalMode_WritesToConsole()
+ public void Context_WriteLine_NormalMode_WritesToConsole()
{
var originalOut = Console.Out;
var output = new StringWriter();
@@ -382,7 +382,7 @@ public void WriteLine_NormalMode_WritesToConsole()
/// Test WriteLine in silent mode doesn't write to console.
///
[TestMethod]
- public void WriteLine_SilentMode_DoesNotWriteToConsole()
+ public void Context_WriteLine_SilentMode_DoesNotWriteToConsole()
{
var originalOut = Console.Out;
var output = new StringWriter();
@@ -405,7 +405,7 @@ public void WriteLine_SilentMode_DoesNotWriteToConsole()
/// Test WriteError writes to console.
///
[TestMethod]
- public void WriteError_NormalMode_WritesToConsole()
+ public void Context_WriteError_NormalMode_WritesToConsole()
{
var originalOut = Console.Out;
var output = new StringWriter();
@@ -429,7 +429,7 @@ public void WriteError_NormalMode_WritesToConsole()
/// Test WriteError in silent mode doesn't write to console.
///
[TestMethod]
- public void WriteError_SilentMode_DoesNotWriteToConsole()
+ public void Context_WriteError_SilentMode_DoesNotWriteToConsole()
{
var originalOut = Console.Out;
var output = new StringWriter();
@@ -453,7 +453,7 @@ public void WriteError_SilentMode_DoesNotWriteToConsole()
/// Test log file creation and writing.
///
[TestMethod]
- public void Create_WithLogFile_WritesToLogFile()
+ public void Context_Create_WithLogFile_WritesToLogFile()
{
var logPath = Path.Combine(_testDirectory, "test.log");
@@ -473,7 +473,7 @@ public void Create_WithLogFile_WritesToLogFile()
/// Test log file with silent mode still writes to log.
///
[TestMethod]
- public void Create_WithLogFileAndSilent_WritesToLogOnly()
+ public void Context_Create_WithLogFileAndSilent_WritesToLogOnly()
{
var originalOut = Console.Out;
var output = new StringWriter();
@@ -506,7 +506,7 @@ public void Create_WithLogFileAndSilent_WritesToLogOnly()
/// Test requirements glob pattern expansion.
///
[TestMethod]
- public void Create_WithRequirementsPattern_ExpandsGlobPattern()
+ public void Context_Create_WithRequirementsPattern_ExpandsGlobPattern()
{
// Create test files
var file1 = Path.Combine(_testDirectory, "req1.yaml");
@@ -537,7 +537,7 @@ public void Create_WithRequirementsPattern_ExpandsGlobPattern()
/// Test tests glob pattern expansion.
///
[TestMethod]
- public void Create_WithTestsPattern_ExpandsGlobPattern()
+ public void Context_Create_WithTestsPattern_ExpandsGlobPattern()
{
// Create test files
var file1 = Path.Combine(_testDirectory, "test1.trx");
@@ -568,7 +568,7 @@ public void Create_WithTestsPattern_ExpandsGlobPattern()
/// Test missing requirements pattern argument.
///
[TestMethod]
- public void Create_MissingRequirementsPattern_ThrowsException()
+ public void Context_Create_MissingRequirementsPattern_ThrowsException()
{
try
{
@@ -585,7 +585,7 @@ public void Create_MissingRequirementsPattern_ThrowsException()
/// Test missing tests pattern argument.
///
[TestMethod]
- public void Create_MissingTestsPattern_ThrowsException()
+ public void Context_Create_MissingTestsPattern_ThrowsException()
{
try
{
@@ -602,7 +602,7 @@ public void Create_MissingTestsPattern_ThrowsException()
/// Test combining multiple arguments.
///
[TestMethod]
- public void Create_MultipleArguments_ParsesAllCorrectly()
+ public void Context_Create_MultipleArguments_ParsesAllCorrectly()
{
using var context = Context.Create(
["--version", "--help", "--silent", "--validate", "--report", "out.md", "--report-depth", "2"]);
@@ -620,7 +620,7 @@ public void Create_MultipleArguments_ParsesAllCorrectly()
/// Test dispose closes log file.
///
[TestMethod]
- public void Dispose_WithLogFile_ClosesLogFile()
+ public void Context_Dispose_WithLogFile_ClosesLogFile()
{
var logPath = Path.Combine(_testDirectory, "test.log");
@@ -637,7 +637,7 @@ public void Dispose_WithLogFile_ClosesLogFile()
/// Test invalid log file path.
///
[TestMethod]
- public void Create_InvalidLogPath_ThrowsException()
+ public void Context_Create_InvalidLogPath_ThrowsException()
{
var invalidPath = Path.Combine(_testDirectory, "nonexistent", "test.log");
diff --git a/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs b/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs
index ba8e157..f521867 100644
--- a/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs
+++ b/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs
@@ -54,7 +54,7 @@ public void TestCleanup()
/// Test Run with version flag prints version information.
///
[TestMethod]
- public void Run_WithVersionFlag_PrintsVersion()
+ public void Program_Run_WithVersionFlag_PrintsVersion()
{
var originalOut = Console.Out;
var output = new StringWriter();
@@ -81,7 +81,7 @@ public void Run_WithVersionFlag_PrintsVersion()
/// Test Run with help flag prints help information.
///
[TestMethod]
- public void Run_WithHelpFlag_PrintsHelp()
+ public void Program_Run_WithHelpFlag_PrintsHelp()
{
var originalOut = Console.Out;
var output = new StringWriter();
@@ -108,7 +108,7 @@ public void Run_WithHelpFlag_PrintsHelp()
/// Test Run with validate flag shows placeholder message.
///
[TestMethod]
- public void Run_WithValidateFlag_ShowsPlaceholder()
+ public void Program_Run_WithValidateFlag_ShowsPlaceholder()
{
using var context = Context.Create(["--validate"]);
Program.Run(context);
@@ -121,7 +121,7 @@ public void Run_WithValidateFlag_ShowsPlaceholder()
/// Test Run with no requirements files shows message.
///
[TestMethod]
- public void Run_WithNoRequirementsFiles_ShowsMessage()
+ public void Program_Run_WithNoRequirementsFiles_ShowsMessage()
{
using var context = Context.Create([]);
Program.Run(context);
@@ -134,7 +134,7 @@ public void Run_WithNoRequirementsFiles_ShowsMessage()
/// Test Run with requirements files processes them successfully.
///
[TestMethod]
- public void Run_WithRequirementsFiles_ProcessesSuccessfully()
+ public void Program_Run_WithRequirementsFiles_ProcessesSuccessfully()
{
// Create a test requirements file
var reqFile = Path.Combine(_testDirectory, "requirements.yaml");
@@ -167,7 +167,7 @@ public void Run_WithRequirementsFiles_ProcessesSuccessfully()
/// Test Run with requirements export generates report file.
///
[TestMethod]
- public void Run_WithRequirementsExport_GeneratesReport()
+ public void Program_Run_WithRequirementsExport_GeneratesReport()
{
// Create a test requirements file
var reqFile = Path.Combine(_testDirectory, "requirements.yaml");
@@ -207,7 +207,7 @@ public void Run_WithRequirementsExport_GeneratesReport()
/// Test Run with trace matrix export generates matrix file.
///
[TestMethod]
- public void Run_WithTraceMatrixExport_GeneratesMatrix()
+ public void Program_Run_WithTraceMatrixExport_GeneratesMatrix()
{
// Create a test requirements file
var reqFile = Path.Combine(_testDirectory, "requirements.yaml");
@@ -262,7 +262,7 @@ public void Run_WithTraceMatrixExport_GeneratesMatrix()
/// Test priority order: version takes precedence over help.
///
[TestMethod]
- public void Run_WithVersionAndHelp_ProcessesVersionFirst()
+ public void Program_Run_WithVersionAndHelp_ProcessesVersionFirst()
{
var originalOut = Console.Out;
var output = new StringWriter();
@@ -289,7 +289,7 @@ public void Run_WithVersionAndHelp_ProcessesVersionFirst()
/// Test priority order: help takes precedence over validate.
///
[TestMethod]
- public void Run_WithHelpAndValidate_ProcessesHelpFirst()
+ public void Program_Run_WithHelpAndValidate_ProcessesHelpFirst()
{
var originalOut = Console.Out;
var output = new StringWriter();
@@ -314,7 +314,7 @@ public void Run_WithHelpAndValidate_ProcessesHelpFirst()
/// Test enforcement with fully satisfied requirements succeeds.
///
[TestMethod]
- public void Run_WithEnforcementAndFullySatisfiedRequirements_Succeeds()
+ public void Program_Run_WithEnforcementAndFullySatisfiedRequirements_Succeeds()
{
// Create a test requirements file
var reqFile = Path.Combine(_testDirectory, "requirements.yaml");
@@ -367,7 +367,7 @@ public void Run_WithEnforcementAndFullySatisfiedRequirements_Succeeds()
/// Test enforcement with unsatisfied requirements fails.
///
[TestMethod]
- public void Run_WithEnforcementAndUnsatisfiedRequirements_Fails()
+ public void Program_Run_WithEnforcementAndUnsatisfiedRequirements_Fails()
{
// Create a test requirements file with one tested and one untested requirement
var reqFile = Path.Combine(_testDirectory, "requirements.yaml");
@@ -422,7 +422,7 @@ public void Run_WithEnforcementAndUnsatisfiedRequirements_Fails()
/// Test enforcement without test files fails.
///
[TestMethod]
- public void Run_WithEnforcementAndNoTests_Fails()
+ public void Program_Run_WithEnforcementAndNoTests_Fails()
{
// Create a test requirements file
var reqFile = Path.Combine(_testDirectory, "requirements.yaml");
@@ -458,7 +458,7 @@ public void Run_WithEnforcementAndNoTests_Fails()
/// Test enforcement with failed tests fails.
///
[TestMethod]
- public void Run_WithEnforcementAndFailedTests_Fails()
+ public void Program_Run_WithEnforcementAndFailedTests_Fails()
{
// Create a test requirements file
var reqFile = Path.Combine(_testDirectory, "requirements.yaml");
diff --git a/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs b/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs
index afdbca2..32795a3 100644
--- a/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs
+++ b/test/DemaConsulting.ReqStream.Tests/RequirementsExportTests.cs
@@ -54,7 +54,7 @@ public void TestCleanup()
/// Test exporting a simple requirements document to Markdown.
///
[TestMethod]
- public void Export_SimpleRequirements_CreatesMarkdownFile()
+ public void Requirements_Export_SimpleRequirements_CreatesMarkdownFile()
{
var yamlContent = @"---
sections:
@@ -84,7 +84,7 @@ public void Export_SimpleRequirements_CreatesMarkdownFile()
/// Test exporting requirements with custom depth.
///
[TestMethod]
- public void Export_WithCustomDepth_UsesCorrectHeaderLevel()
+ public void Requirements_Export_WithCustomDepth_UsesCorrectHeaderLevel()
{
var yamlContent = @"---
sections:
@@ -108,7 +108,7 @@ public void Export_WithCustomDepth_UsesCorrectHeaderLevel()
/// Test exporting nested sections with proper hierarchy.
///
[TestMethod]
- public void Export_NestedSections_CreatesHierarchy()
+ public void Requirements_Export_NestedSections_CreatesHierarchy()
{
var yamlContent = @"---
sections:
@@ -142,7 +142,7 @@ public void Export_NestedSections_CreatesHierarchy()
/// Test exporting a section with no requirements (only subsections).
///
[TestMethod]
- public void Export_SectionWithNoRequirements_CreatesHeaderOnly()
+ public void Requirements_Export_SectionWithNoRequirements_CreatesHeaderOnly()
{
var yamlContent = @"---
sections:
@@ -170,7 +170,7 @@ public void Export_SectionWithNoRequirements_CreatesHeaderOnly()
/// Test that export throws exception when file path is null.
///
[TestMethod]
- public void Export_NullFilePath_ThrowsArgumentException()
+ public void Requirements_Export_NullFilePath_ThrowsArgumentException()
{
var yamlContent = @"---
sections:
@@ -198,7 +198,7 @@ public void Export_NullFilePath_ThrowsArgumentException()
/// Test that export throws exception when file path is empty.
///
[TestMethod]
- public void Export_EmptyFilePath_ThrowsArgumentException()
+ public void Requirements_Export_EmptyFilePath_ThrowsArgumentException()
{
var yamlContent = @"---
sections:
@@ -226,7 +226,7 @@ public void Export_EmptyFilePath_ThrowsArgumentException()
/// Test exporting multiple sections at the root level.
///
[TestMethod]
- public void Export_MultipleSections_ExportsAll()
+ public void Requirements_Export_MultipleSections_ExportsAll()
{
var yamlContent = @"---
sections:
@@ -257,7 +257,7 @@ public void Export_MultipleSections_ExportsAll()
/// Test exporting empty requirements document.
///
[TestMethod]
- public void Export_EmptyRequirements_CreatesEmptyFile()
+ public void Requirements_Export_EmptyRequirements_CreatesEmptyFile()
{
var yamlContent = @"---
";
diff --git a/test/DemaConsulting.ReqStream.Tests/RequirementsParsingTests.cs b/test/DemaConsulting.ReqStream.Tests/RequirementsParsingTests.cs
index acf1d6e..935e40d 100644
--- a/test/DemaConsulting.ReqStream.Tests/RequirementsParsingTests.cs
+++ b/test/DemaConsulting.ReqStream.Tests/RequirementsParsingTests.cs
@@ -54,7 +54,7 @@ public void TestCleanup()
/// Test reading a simple YAML file with a single requirement.
///
[TestMethod]
- public void Read_SimpleRequirement_ParsesCorrectly()
+ public void Requirements_Read_SimpleRequirement_ParsesCorrectly()
{
var yamlContent = @"---
sections:
@@ -80,7 +80,7 @@ public void Read_SimpleRequirement_ParsesCorrectly()
/// Test reading a requirement with tests.
///
[TestMethod]
- public void Read_RequirementWithTests_ParsesTestsCorrectly()
+ public void Requirements_Read_RequirementWithTests_ParsesTestsCorrectly()
{
var yamlContent = @"---
sections:
@@ -111,7 +111,7 @@ public void Read_RequirementWithTests_ParsesTestsCorrectly()
/// Test reading a requirement with child requirements.
///
[TestMethod]
- public void Read_RequirementWithChildren_ParsesChildrenCorrectly()
+ public void Requirements_Read_RequirementWithChildren_ParsesChildrenCorrectly()
{
var yamlContent = @"---
sections:
@@ -140,7 +140,7 @@ public void Read_RequirementWithChildren_ParsesChildrenCorrectly()
/// Test reading nested sections.
///
[TestMethod]
- public void Read_NestedSections_ParsesHierarchyCorrectly()
+ public void Requirements_Read_NestedSections_ParsesHierarchyCorrectly()
{
var yamlContent = @"---
sections:
@@ -174,7 +174,7 @@ public void Read_NestedSections_ParsesHierarchyCorrectly()
/// Test reading test mappings that are separate from requirements.
///
[TestMethod]
- public void Read_TestMappings_AppliesMappingsCorrectly()
+ public void Requirements_Read_TestMappings_AppliesMappingsCorrectly()
{
var yamlContent = @"---
sections:
@@ -206,7 +206,7 @@ public void Read_TestMappings_AppliesMappingsCorrectly()
/// Test reading a file with includes.
///
[TestMethod]
- public void Read_WithIncludes_MergesFilesCorrectly()
+ public void Requirements_Read_WithIncludes_MergesFilesCorrectly()
{
var mainYaml = @"---
sections:
@@ -244,7 +244,7 @@ public void Read_WithIncludes_MergesFilesCorrectly()
/// Test that identical sections are merged.
///
[TestMethod]
- public void Read_IdenticalSections_MergesCorrectly()
+ public void Requirements_Read_IdenticalSections_MergesCorrectly()
{
var mainYaml = @"---
sections:
@@ -282,7 +282,7 @@ public void Read_IdenticalSections_MergesCorrectly()
/// Test that duplicate requirement IDs throw an exception.
///
[TestMethod]
- public void Read_DuplicateRequirementId_ThrowsException()
+ public void Requirements_Read_DuplicateRequirementId_ThrowsException()
{
var yamlContent = @"---
sections:
@@ -312,7 +312,7 @@ public void Read_DuplicateRequirementId_ThrowsException()
/// Test that include loops are prevented.
///
[TestMethod]
- public void Read_IncludeLoop_DoesNotCauseInfiniteLoop()
+ public void Requirements_Read_IncludeLoop_DoesNotCauseInfiniteLoop()
{
var fileA = @"---
sections:
@@ -349,7 +349,7 @@ public void Read_IncludeLoop_DoesNotCauseInfiniteLoop()
/// Test that file not found throws an exception.
///
[TestMethod]
- public void Read_FileNotFound_ThrowsException()
+ public void Requirements_Read_FileNotFound_ThrowsException()
{
var nonExistentPath = Path.Combine(_testDirectory, "nonexistent.yaml");
@@ -368,7 +368,7 @@ public void Read_FileNotFound_ThrowsException()
/// Test reading an empty YAML file.
///
[TestMethod]
- public void Read_EmptyFile_ReturnsEmptyRequirements()
+ public void Requirements_Read_EmptyFile_ReturnsEmptyRequirements()
{
var yamlContent = @"---
";
@@ -386,7 +386,7 @@ public void Read_EmptyFile_ReturnsEmptyRequirements()
/// Test reading a complex nested structure.
///
[TestMethod]
- public void Read_ComplexStructure_ParsesCorrectly()
+ public void Requirements_Read_ComplexStructure_ParsesCorrectly()
{
var yamlContent = @"---
sections:
@@ -454,7 +454,7 @@ public void Read_ComplexStructure_ParsesCorrectly()
/// Test that blank requirement ID throws an exception with file location.
///
[TestMethod]
- public void Read_BlankRequirementId_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankRequirementId_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -483,7 +483,7 @@ public void Read_BlankRequirementId_ThrowsExceptionWithFileLocation()
/// Test that blank requirement title throws an exception with file location.
///
[TestMethod]
- public void Read_BlankRequirementTitle_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankRequirementTitle_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -512,7 +512,7 @@ public void Read_BlankRequirementTitle_ThrowsExceptionWithFileLocation()
/// Test that blank section title throws an exception with file location.
///
[TestMethod]
- public void Read_BlankSectionTitle_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankSectionTitle_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -540,7 +540,7 @@ public void Read_BlankSectionTitle_ThrowsExceptionWithFileLocation()
/// Test that blank test name in requirement throws an exception with file location.
///
[TestMethod]
- public void Read_BlankTestNameInRequirement_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankTestNameInRequirement_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -573,7 +573,7 @@ public void Read_BlankTestNameInRequirement_ThrowsExceptionWithFileLocation()
/// Test that blank test name in mapping throws an exception with file location.
///
[TestMethod]
- public void Read_BlankTestNameInMapping_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankTestNameInMapping_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -608,7 +608,7 @@ public void Read_BlankTestNameInMapping_ThrowsExceptionWithFileLocation()
/// Test that blank mapping ID throws an exception with file location.
///
[TestMethod]
- public void Read_BlankMappingId_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankMappingId_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -641,7 +641,7 @@ public void Read_BlankMappingId_ThrowsExceptionWithFileLocation()
/// Test that duplicate requirement ID message includes file location.
///
[TestMethod]
- public void Read_DuplicateRequirementId_ExceptionIncludesFileLocation()
+ public void Requirements_Read_DuplicateRequirementId_ExceptionIncludesFileLocation()
{
var yamlContent = @"---
sections:
@@ -672,7 +672,7 @@ public void Read_DuplicateRequirementId_ExceptionIncludesFileLocation()
/// Test reading multiple files with params array.
///
[TestMethod]
- public void Read_MultipleFiles_MergesAllFiles()
+ public void Requirements_Read_MultipleFiles_MergesAllFiles()
{
var file1Yaml = @"---
sections:
@@ -718,7 +718,7 @@ public void Read_MultipleFiles_MergesAllFiles()
/// Test reading multiple files that merge sections.
///
[TestMethod]
- public void Read_MultipleFilesWithSameSections_MergesSections()
+ public void Requirements_Read_MultipleFilesWithSameSections_MergesSections()
{
var file1Yaml = @"---
sections:
@@ -753,7 +753,7 @@ public void Read_MultipleFilesWithSameSections_MergesSections()
/// Test reading single file with params array (backwards compatibility).
///
[TestMethod]
- public void Read_SingleFileWithParamsArray_WorksCorrectly()
+ public void Requirements_Read_SingleFileWithParamsArray_WorksCorrectly()
{
var yamlContent = @"---
sections:
@@ -778,7 +778,7 @@ public void Read_SingleFileWithParamsArray_WorksCorrectly()
/// Test that calling Read with no arguments throws ArgumentException.
///
[TestMethod]
- public void Read_NoArguments_ThrowsArgumentException()
+ public void Requirements_Read_NoArguments_ThrowsArgumentException()
{
try
{
@@ -795,7 +795,7 @@ public void Read_NoArguments_ThrowsArgumentException()
/// Test that calling Read with null throws ArgumentException.
///
[TestMethod]
- public void Read_NullArgument_ThrowsArgumentException()
+ public void Requirements_Read_NullArgument_ThrowsArgumentException()
{
try
{
@@ -812,7 +812,7 @@ public void Read_NullArgument_ThrowsArgumentException()
/// Test that duplicate IDs across multiple files are detected.
///
[TestMethod]
- public void Read_MultipleFilesWithDuplicateIds_ThrowsException()
+ public void Requirements_Read_MultipleFilesWithDuplicateIds_ThrowsException()
{
var file1Yaml = @"---
sections:
diff --git a/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs b/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs
index 7735240..a2b2737 100644
--- a/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs
+++ b/test/DemaConsulting.ReqStream.Tests/RequirementsReadTests.cs
@@ -54,7 +54,7 @@ public void TestCleanup()
/// Test reading a simple YAML file with a single requirement.
///
[TestMethod]
- public void Read_SimpleRequirement_ParsesCorrectly()
+ public void Requirements_Read_SimpleRequirement_ParsesCorrectly()
{
var yamlContent = @"---
sections:
@@ -80,7 +80,7 @@ public void Read_SimpleRequirement_ParsesCorrectly()
/// Test reading a requirement with tests.
///
[TestMethod]
- public void Read_RequirementWithTests_ParsesTestsCorrectly()
+ public void Requirements_Read_RequirementWithTests_ParsesTestsCorrectly()
{
var yamlContent = @"---
sections:
@@ -111,7 +111,7 @@ public void Read_RequirementWithTests_ParsesTestsCorrectly()
/// Test reading a requirement with child requirements.
///
[TestMethod]
- public void Read_RequirementWithChildren_ParsesChildrenCorrectly()
+ public void Requirements_Read_RequirementWithChildren_ParsesChildrenCorrectly()
{
var yamlContent = @"---
sections:
@@ -140,7 +140,7 @@ public void Read_RequirementWithChildren_ParsesChildrenCorrectly()
/// Test reading nested sections.
///
[TestMethod]
- public void Read_NestedSections_ParsesHierarchyCorrectly()
+ public void Requirements_Read_NestedSections_ParsesHierarchyCorrectly()
{
var yamlContent = @"---
sections:
@@ -174,7 +174,7 @@ public void Read_NestedSections_ParsesHierarchyCorrectly()
/// Test reading test mappings that are separate from requirements.
///
[TestMethod]
- public void Read_TestMappings_AppliesMappingsCorrectly()
+ public void Requirements_Read_TestMappings_AppliesMappingsCorrectly()
{
var yamlContent = @"---
sections:
@@ -206,7 +206,7 @@ public void Read_TestMappings_AppliesMappingsCorrectly()
/// Test reading a file with includes.
///
[TestMethod]
- public void Read_WithIncludes_MergesFilesCorrectly()
+ public void Requirements_Read_WithIncludes_MergesFilesCorrectly()
{
var mainYaml = @"---
sections:
@@ -244,7 +244,7 @@ public void Read_WithIncludes_MergesFilesCorrectly()
/// Test that identical sections are merged.
///
[TestMethod]
- public void Read_IdenticalSections_MergesCorrectly()
+ public void Requirements_Read_IdenticalSections_MergesCorrectly()
{
var mainYaml = @"---
sections:
@@ -282,7 +282,7 @@ public void Read_IdenticalSections_MergesCorrectly()
/// Test that duplicate requirement IDs throw an exception.
///
[TestMethod]
- public void Read_DuplicateRequirementId_ThrowsException()
+ public void Requirements_Read_DuplicateRequirementId_ThrowsException()
{
var yamlContent = @"---
sections:
@@ -312,7 +312,7 @@ public void Read_DuplicateRequirementId_ThrowsException()
/// Test that include loops are prevented.
///
[TestMethod]
- public void Read_IncludeLoop_DoesNotCauseInfiniteLoop()
+ public void Requirements_Read_IncludeLoop_DoesNotCauseInfiniteLoop()
{
var fileA = @"---
sections:
@@ -349,7 +349,7 @@ public void Read_IncludeLoop_DoesNotCauseInfiniteLoop()
/// Test that file not found throws an exception.
///
[TestMethod]
- public void Read_FileNotFound_ThrowsException()
+ public void Requirements_Read_FileNotFound_ThrowsException()
{
var nonExistentPath = Path.Combine(_testDirectory, "nonexistent.yaml");
@@ -368,7 +368,7 @@ public void Read_FileNotFound_ThrowsException()
/// Test reading an empty YAML file.
///
[TestMethod]
- public void Read_EmptyFile_ReturnsEmptyRequirements()
+ public void Requirements_Read_EmptyFile_ReturnsEmptyRequirements()
{
var yamlContent = @"---
";
@@ -386,7 +386,7 @@ public void Read_EmptyFile_ReturnsEmptyRequirements()
/// Test reading a complex nested structure.
///
[TestMethod]
- public void Read_ComplexStructure_ParsesCorrectly()
+ public void Requirements_Read_ComplexStructure_ParsesCorrectly()
{
var yamlContent = @"---
sections:
@@ -454,7 +454,7 @@ public void Read_ComplexStructure_ParsesCorrectly()
/// Test that blank requirement ID throws an exception with file location.
///
[TestMethod]
- public void Read_BlankRequirementId_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankRequirementId_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -483,7 +483,7 @@ public void Read_BlankRequirementId_ThrowsExceptionWithFileLocation()
/// Test that blank requirement title throws an exception with file location.
///
[TestMethod]
- public void Read_BlankRequirementTitle_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankRequirementTitle_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -512,7 +512,7 @@ public void Read_BlankRequirementTitle_ThrowsExceptionWithFileLocation()
/// Test that blank section title throws an exception with file location.
///
[TestMethod]
- public void Read_BlankSectionTitle_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankSectionTitle_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -540,7 +540,7 @@ public void Read_BlankSectionTitle_ThrowsExceptionWithFileLocation()
/// Test that blank test name in requirement throws an exception with file location.
///
[TestMethod]
- public void Read_BlankTestNameInRequirement_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankTestNameInRequirement_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -573,7 +573,7 @@ public void Read_BlankTestNameInRequirement_ThrowsExceptionWithFileLocation()
/// Test that blank test name in mapping throws an exception with file location.
///
[TestMethod]
- public void Read_BlankTestNameInMapping_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankTestNameInMapping_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -608,7 +608,7 @@ public void Read_BlankTestNameInMapping_ThrowsExceptionWithFileLocation()
/// Test that blank mapping ID throws an exception with file location.
///
[TestMethod]
- public void Read_BlankMappingId_ThrowsExceptionWithFileLocation()
+ public void Requirements_Read_BlankMappingId_ThrowsExceptionWithFileLocation()
{
var yamlContent = @"---
sections:
@@ -641,7 +641,7 @@ public void Read_BlankMappingId_ThrowsExceptionWithFileLocation()
/// Test that duplicate requirement ID message includes file location.
///
[TestMethod]
- public void Read_DuplicateRequirementId_ExceptionIncludesFileLocation()
+ public void Requirements_Read_DuplicateRequirementId_ExceptionIncludesFileLocation()
{
var yamlContent = @"---
sections:
@@ -672,7 +672,7 @@ public void Read_DuplicateRequirementId_ExceptionIncludesFileLocation()
/// Test reading multiple files with params array.
///
[TestMethod]
- public void Read_MultipleFiles_MergesAllFiles()
+ public void Requirements_Read_MultipleFiles_MergesAllFiles()
{
var file1Yaml = @"---
sections:
@@ -718,7 +718,7 @@ public void Read_MultipleFiles_MergesAllFiles()
/// Test reading multiple files that merge sections.
///
[TestMethod]
- public void Read_MultipleFilesWithSameSections_MergesSections()
+ public void Requirements_Read_MultipleFilesWithSameSections_MergesSections()
{
var file1Yaml = @"---
sections:
@@ -753,7 +753,7 @@ public void Read_MultipleFilesWithSameSections_MergesSections()
/// Test reading single file with params array (backwards compatibility).
///
[TestMethod]
- public void Read_SingleFileWithParamsArray_WorksCorrectly()
+ public void Requirements_Read_SingleFileWithParamsArray_WorksCorrectly()
{
var yamlContent = @"---
sections:
@@ -778,7 +778,7 @@ public void Read_SingleFileWithParamsArray_WorksCorrectly()
/// Test that calling Read with no arguments throws ArgumentException.
///
[TestMethod]
- public void Read_NoArguments_ThrowsArgumentException()
+ public void Requirements_Read_NoArguments_ThrowsArgumentException()
{
try
{
@@ -795,7 +795,7 @@ public void Read_NoArguments_ThrowsArgumentException()
/// Test that calling Read with null throws ArgumentException.
///
[TestMethod]
- public void Read_NullArgument_ThrowsArgumentException()
+ public void Requirements_Read_NullArgument_ThrowsArgumentException()
{
try
{
@@ -812,7 +812,7 @@ public void Read_NullArgument_ThrowsArgumentException()
/// Test that duplicate IDs across multiple files are detected.
///
[TestMethod]
- public void Read_MultipleFilesWithDuplicateIds_ThrowsException()
+ public void Requirements_Read_MultipleFilesWithDuplicateIds_ThrowsException()
{
var file1Yaml = @"---
sections:
From 5cc823c88963ac2724458295764d090cd616db74 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 10 Jan 2026 19:20:31 +0000
Subject: [PATCH 5/6] Simplify enforcement output examples in guide to show
only relevant lines
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
---
docs/guide/guide.md | 18 ++----------------
1 file changed, 2 insertions(+), 16 deletions(-)
diff --git a/docs/guide/guide.md b/docs/guide/guide.md
index 8d842f3..4f1ea16 100644
--- a/docs/guide/guide.md
+++ b/docs/guide/guide.md
@@ -715,14 +715,7 @@ processing is complete, it checks requirement satisfaction.
**If all requirements are satisfied:**
```text
-ReqStream version 1.0.0
-Copyright (c) 2026 DEMA Consulting
-
-Reading 1 requirements file(s)...
-Requirements loaded successfully.
-Processing 1 test result file(s)...
-Trace matrix created successfully.
-Exporting trace matrix to trace-matrix.md...
+...
Trace matrix report generated successfully.
```
@@ -731,14 +724,7 @@ Exit code: **0** (success)
**If requirements are not satisfied:**
```text
-ReqStream version 1.0.0
-Copyright (c) 2026 DEMA Consulting
-
-Reading 1 requirements file(s)...
-Requirements loaded successfully.
-Processing 1 test result file(s)...
-Trace matrix created successfully.
-Exporting trace matrix to trace-matrix.md...
+...
Trace matrix report generated successfully.
Error: Only 15 of 20 requirements are satisfied with tests.
```
From 797b39f60ada500327102f06bd1aada248f758c7 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 10 Jan 2026 19:28:10 +0000
Subject: [PATCH 6/6] Fix linting issues and remove non-existent .globalconfig
reference
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
---
.github/agents/software-quality-enforcer.md | 2 --
docs/guide/guide.md | 12 +++++-------
2 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/.github/agents/software-quality-enforcer.md b/.github/agents/software-quality-enforcer.md
index 5813547..e532b64 100644
--- a/.github/agents/software-quality-enforcer.md
+++ b/.github/agents/software-quality-enforcer.md
@@ -84,8 +84,6 @@ Based on `.editorconfig` and project preferences:
- SonarAnalyzer.CSharp enabled
- EnforceCodeStyleInBuild enabled
- AnalysisLevel set to latest
-- **Analyzer Suppressions**: Use `.globalconfig` file to disable rules globally when needed (e.g., for serializer
- DTOs), rather than SuppressMessage attributes
### Test Requirements
diff --git a/docs/guide/guide.md b/docs/guide/guide.md
index 4f1ea16..8cb4bc4 100644
--- a/docs/guide/guide.md
+++ b/docs/guide/guide.md
@@ -654,7 +654,7 @@ Requirements enforcement validates that:
If any requirement doesn't meet these criteria, the tool reports an error and exits with a non-zero status code,
causing CI/CD builds to fail.
-### Basic Usage
+### Usage
Enable enforcement with the `--enforce` flag:
@@ -896,7 +896,7 @@ requirements:
### Troubleshooting Enforcement
-**Error: Cannot enforce requirements without test results**
+#### Error: Cannot enforce requirements without test results
This error occurs when `--enforce` is used without the `--tests` option. You must provide test result files to
validate coverage:
@@ -909,7 +909,7 @@ reqstream --requirements "**/*.yaml" --enforce
reqstream --requirements "**/*.yaml" --tests "**/*.trx" --enforce
```
-**All requirements show as unsatisfied**
+#### All requirements show as unsatisfied
If all or most requirements are showing as unsatisfied, check:
@@ -918,7 +918,7 @@ If all or most requirements are showing as unsatisfied, check:
3. Tests are actually being executed (check test result file contents)
4. Tests are passing (failing tests count as unsatisfied)
-**Some tests don't match**
+#### Some tests don't match
If specific tests aren't being recognized:
@@ -927,7 +927,7 @@ If specific tests aren't being recognized:
3. If using source-specific tests (`filepart@testname`), verify the file part matches the test result filename
4. Run without `--enforce` first and review the trace matrix to see which tests are found
-**Requirements with no direct tests show as unsatisfied**
+#### Requirements with no direct tests show as unsatisfied
Ensure parent requirements reference their children via the `children` field:
@@ -944,8 +944,6 @@ requirements:
- "Test_Child"
```
-
-
## FAQ
### General Questions