Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,44 @@ Options:
--enforce Fail if requirements are not fully tested
```

## Self Validation

Running self-validation produces a report containing the following information:

```text
# DEMA Consulting ReqStream

| Information | Value |
| :------------------ | :------------------------------------------------- |
| ReqStream Version | <version> |
| Machine Name | <machine-name> |
| OS Version | <os-version> |
| DotNet Runtime | <dotnet-runtime-version> |
| Time Stamp | <timestamp> UTC |

✓ ReqStream_RequirementsProcessing - Passed
✓ ReqStream_TraceMatrix - Passed
✓ ReqStream_ReportExport - Passed
✓ ReqStream_TagsFiltering - Passed
✓ ReqStream_EnforcementMode - Passed

Total Tests: 5
Passed: 5
Failed: 0
```

Each test in the report proves:

- **`ReqStream_RequirementsProcessing`** - requirements YAML files are correctly loaded and processed.
- **`ReqStream_TraceMatrix`** - trace matrix is correctly generated from requirements and test results.
- **`ReqStream_ReportExport`** - requirements report is correctly exported to a markdown file.
- **`ReqStream_TagsFiltering`** - requirements are correctly filtered by tags.
- **`ReqStream_EnforcementMode`** - enforcement mode correctly validates requirement test coverage.

See the [User Guide][link-guide] for more details on the self-validation tests.

On validation failure the tool will exit with a non-zero exit code.

## YAML Format

ReqStream uses YAML files to define and manage requirements. The YAML format supports a hierarchical structure
Expand Down Expand Up @@ -528,3 +566,4 @@ For information about reporting security vulnerabilities, please see our [Securi
[mstest]: https://github.com/microsoft/testfx
[github-actions]: https://github.com/features/actions
[sonarcloud]: https://sonarcloud.io
[link-guide]: https://github.com/demaconsulting/ReqStream/blob/main/docs/guide/guide.md
41 changes: 40 additions & 1 deletion docs/guide/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ ReqStream supports the following command-line options:

## Examples

### Running Self-Validation
### Running Validation

Run self-validation to verify core functionality:

Expand All @@ -543,6 +543,45 @@ Run self-validation and save results to a JUnit XML file:
reqstream --validate --results validation-results.xml
```

### Validation Report

The validation report contains the tool version, machine name, operating system version, .NET runtime version,
timestamp, and test results.

Example validation report:

```text
# DEMA Consulting ReqStream

| Information | Value |
| :------------------ | :------------------------------------------------- |
| ReqStream Version | 1.0.0 |
| Machine Name | BUILD-SERVER |
| OS Version | Ubuntu 22.04.3 LTS |
| DotNet Runtime | .NET 10.0.0 |
| Time Stamp | 2024-01-15 10:30:00 UTC |

✓ ReqStream_RequirementsProcessing - Passed
✓ ReqStream_TraceMatrix - Passed
✓ ReqStream_ReportExport - Passed
✓ ReqStream_TagsFiltering - Passed
✓ ReqStream_EnforcementMode - Passed

Total Tests: 5
Passed: 5
Failed: 0
```

### Validation Tests

Each test proves specific functionality works correctly:

- **`ReqStream_RequirementsProcessing`** - requirements YAML files are correctly loaded and processed.
- **`ReqStream_TraceMatrix`** - trace matrix is correctly generated from requirements and test results.
- **`ReqStream_ReportExport`** - requirements report is correctly exported to a markdown file.
- **`ReqStream_TagsFiltering`** - requirements are correctly filtered by tags.
- **`ReqStream_EnforcementMode`** - enforcement mode correctly validates requirement test coverage.

### Requirements Processing

**Process requirements and create a report:**
Expand Down
42 changes: 21 additions & 21 deletions src/DemaConsulting.ReqStream/Validation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
{
// Run the program with requirements file (using relative pattern)
int exitCode;
using (var testContext = Context.Create(["--silent", "--log", "requirements-test.log", "--requirements", "*.yaml"]))

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--requirements' 6 times.

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--silent' 6 times.

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--requirements' 6 times.

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--silent' 6 times.

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--requirements' 6 times.

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--silent' 6 times.

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--requirements' 6 times.

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 131 in src/DemaConsulting.ReqStream/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--silent' 6 times.
{
Program.Run(testContext);
exitCode = testContext.ExitCode;
Expand All @@ -144,26 +144,26 @@
logContent.Contains("Requirements loaded successfully"))
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Passed;
context.WriteLine("✓ Requirements Processing Test - PASSED");
context.WriteLine("✓ ReqStream_RequirementsProcessing - Passed");
}
else
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed;
test.ErrorMessage = "Expected output not found in log";
context.WriteError("✗ Requirements Processing Test - FAILED: Expected output not found");
context.WriteError("✗ ReqStream_RequirementsProcessing - Failed: Expected output not found");
}
}
else
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed;
test.ErrorMessage = $"Program exited with code {exitCode}";
context.WriteError($"✗ Requirements Processing Test - FAILED: Exit code {exitCode}");
context.WriteError($"✗ ReqStream_RequirementsProcessing - Failed: Exit code {exitCode}");
}
}
}
catch (Exception ex)
{
HandleTestException(test, context, "Requirements Processing Test", ex);
HandleTestException(test, context, "ReqStream_RequirementsProcessing", ex);
}

FinalizeTestResult(test, startTime, testResults);
Expand Down Expand Up @@ -227,13 +227,13 @@
if (matrixContent.Contains("MTX-001") && matrixContent.Contains("Test_Matrix_Validation"))
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Passed;
context.WriteLine("✓ Trace Matrix Test - PASSED");
context.WriteLine("✓ ReqStream_TraceMatrix - Passed");
}
else
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed;
test.ErrorMessage = "Matrix file missing expected content";
context.WriteError("✗ Trace Matrix Test - FAILED: Matrix file missing expected content");
context.WriteError("✗ ReqStream_TraceMatrix - Failed: Matrix file missing expected content");
}
}
else
Expand All @@ -242,13 +242,13 @@
test.ErrorMessage = exitCode != 0
? $"Program exited with code {exitCode}"
: "Matrix file not created";
context.WriteError($"✗ Trace Matrix Test - FAILED: {test.ErrorMessage}");
context.WriteError($"✗ ReqStream_TraceMatrix - Failed: {test.ErrorMessage}");
}
}
}
catch (Exception ex)
{
HandleTestException(test, context, "Trace Matrix Test", ex);
HandleTestException(test, context, "ReqStream_TraceMatrix", ex);
}

FinalizeTestResult(test, startTime, testResults);
Expand Down Expand Up @@ -297,13 +297,13 @@
if (reportContent.Contains("EXP-001") && reportContent.Contains("Export requirement"))
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Passed;
context.WriteLine("✓ Report Export Test - PASSED");
context.WriteLine("✓ ReqStream_ReportExport - Passed");
}
else
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed;
test.ErrorMessage = "Report file missing expected content";
context.WriteError("✗ Report Export Test - FAILED: Report file missing expected content");
context.WriteError("✗ ReqStream_ReportExport - Failed: Report file missing expected content");
}
}
else
Expand All @@ -312,13 +312,13 @@
test.ErrorMessage = exitCode != 0
? $"Program exited with code {exitCode}"
: "Report file not created";
context.WriteError($"✗ Report Export Test - FAILED: {test.ErrorMessage}");
context.WriteError($"✗ ReqStream_ReportExport - Failed: {test.ErrorMessage}");
}
}
}
catch (Exception ex)
{
HandleTestException(test, context, "Report Export Test", ex);
HandleTestException(test, context, "ReqStream_ReportExport", ex);
}

FinalizeTestResult(test, startTime, testResults);
Expand Down Expand Up @@ -372,26 +372,26 @@
if (reportContent.Contains("REQ-001") && !reportContent.Contains("REQ-002"))
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Passed;
context.WriteLine("✓ Tags Filtering Test - PASSED");
context.WriteLine("✓ ReqStream_TagsFiltering - Passed");
}
else
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed;
test.ErrorMessage = "Filtered report did not contain expected requirements";
context.WriteError("✗ Tags Filtering Test - FAILED: Filtering not working correctly");
context.WriteError("✗ ReqStream_TagsFiltering - Failed: Filtering not working correctly");
}
}
else
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed;
test.ErrorMessage = $"Program exited with code {exitCode} or report file not created";
context.WriteError($"✗ Tags Filtering Test - FAILED: {test.ErrorMessage}");
context.WriteError($"✗ ReqStream_TagsFiltering - Failed: {test.ErrorMessage}");
}
}
}
catch (Exception ex)
{
HandleTestException(test, context, "Tags Filtering Test", ex);
HandleTestException(test, context, "ReqStream_TagsFiltering", ex);
}

FinalizeTestResult(test, startTime, testResults);
Expand Down Expand Up @@ -451,7 +451,7 @@
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed;
test.ErrorMessage = $"Enforcement with satisfied requirements should succeed, but exited with code {exitCode}";
context.WriteError($"✗ Enforcement Mode Test - FAILED: {test.ErrorMessage}");
context.WriteError($"✗ ReqStream_EnforcementMode - Failed: {test.ErrorMessage}");
}
else
{
Expand Down Expand Up @@ -479,19 +479,19 @@
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed;
test.ErrorMessage = "Enforcement with unsatisfied requirements should fail, but succeeded";
context.WriteError($"✗ Enforcement Mode Test - FAILED: {test.ErrorMessage}");
context.WriteError($"✗ ReqStream_EnforcementMode - Failed: {test.ErrorMessage}");
}
else
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Passed;
context.WriteLine("✓ Enforcement Mode Test - PASSED");
context.WriteLine("✓ ReqStream_EnforcementMode - Passed");
}
}
}
}
catch (Exception ex)
{
HandleTestException(test, context, "Enforcement Mode Test", ex);
HandleTestException(test, context, "ReqStream_EnforcementMode", ex);
}

FinalizeTestResult(test, startTime, testResults);
Expand Down Expand Up @@ -583,7 +583,7 @@
{
test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed;
test.ErrorMessage = $"Exception: {ex.Message}";
context.WriteError($"✗ {testName} - FAILED: {ex.Message}");
context.WriteError($"✗ {testName} - Failed: {ex.Message}");
}

/// <summary>
Expand Down
10 changes: 5 additions & 5 deletions test/DemaConsulting.ReqStream.Tests/ProgramTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,11 @@ public void Program_Run_WithValidateFlag_RunsValidation()
var logContent = File.ReadAllText(logFile);
Assert.Contains("DEMA Consulting ReqStream", logContent);
Assert.Contains("ReqStream Version", logContent);
Assert.Contains("Requirements Processing Test - PASSED", logContent);
Assert.Contains("Trace Matrix Test - PASSED", logContent);
Assert.Contains("Report Export Test - PASSED", logContent);
Assert.Contains("Tags Filtering Test - PASSED", logContent);
Assert.Contains("Enforcement Mode Test - PASSED", logContent);
Assert.Contains("ReqStream_RequirementsProcessing - Passed", logContent);
Assert.Contains("ReqStream_TraceMatrix - Passed", logContent);
Assert.Contains("ReqStream_ReportExport - Passed", logContent);
Assert.Contains("ReqStream_TagsFiltering - Passed", logContent);
Assert.Contains("ReqStream_EnforcementMode - Passed", logContent);
Assert.Contains("Total Tests: 5", logContent);
Assert.Contains("Passed: 5", logContent);
Assert.Contains("Failed: 0", logContent);
Expand Down
Loading