diff --git a/.cspell.yaml b/.cspell.yaml index e90cd54..b2cdfd2 100644 --- a/.cspell.yaml +++ b/.cspell.yaml @@ -18,6 +18,7 @@ words: - Dema - fileassert - mstest + - xunit - netstandard - Newtonsoft - pandoc diff --git a/.fileassert.yaml b/.fileassert.yaml index a989575..a5ae99a 100644 --- a/.fileassert.yaml +++ b/.fileassert.yaml @@ -1,7 +1,7 @@ --- # FileAssert document validation tests for NuGetCaching. # Tests are tagged by document group to allow per-group execution during the build pipeline. -# Tags: build-notes, code-quality, code-review, design, user-guide, requirements. +# Tags: build-notes, code-quality, code-review, design, verification, user-guide, requirements. # # NOTE: build-notes through user-guide tests provide OTS evidence for Pandoc and WeasyPrint # and run before ReqStream. The requirements tests run after ReqStream and validate the @@ -15,7 +15,7 @@ tests: description: "Build Notes HTML was generated by Pandoc" tags: [build-notes] files: - - pattern: "docs/build_notes/build_notes.html" + - pattern: "docs/build_notes/generated/build_notes.html" count: 1 html: - query: "//head/title" @@ -27,7 +27,7 @@ tests: description: "Build Notes PDF was generated by WeasyPrint" tags: [build-notes] files: - - pattern: "docs/NuGetCaching Build Notes.pdf" + - pattern: "docs/generated/NuGetCaching Build Notes.pdf" count: 1 pdf: metadata: @@ -48,7 +48,7 @@ tests: description: "Code Quality HTML was generated by Pandoc" tags: [code-quality] files: - - pattern: "docs/code_quality/quality.html" + - pattern: "docs/code_quality/generated/quality.html" count: 1 html: - query: "//head/title" @@ -60,7 +60,7 @@ tests: description: "Code Quality PDF was generated by WeasyPrint" tags: [code-quality] files: - - pattern: "docs/NuGetCaching Code Quality.pdf" + - pattern: "docs/generated/NuGetCaching Code Quality.pdf" count: 1 pdf: metadata: @@ -81,7 +81,7 @@ tests: description: "Code Review Plan HTML was generated by Pandoc" tags: [code-review] files: - - pattern: "docs/code_review_plan/plan.html" + - pattern: "docs/code_review_plan/generated/plan.html" count: 1 html: - query: "//head/title" @@ -93,7 +93,7 @@ tests: description: "Code Review Plan PDF was generated by WeasyPrint" tags: [code-review] files: - - pattern: "docs/NuGetCaching Review Plan.pdf" + - pattern: "docs/generated/NuGetCaching Review Plan.pdf" count: 1 pdf: metadata: @@ -114,7 +114,7 @@ tests: description: "Code Review Report HTML was generated by Pandoc" tags: [code-review] files: - - pattern: "docs/code_review_report/report.html" + - pattern: "docs/code_review_report/generated/report.html" count: 1 html: - query: "//head/title" @@ -126,7 +126,7 @@ tests: description: "Code Review Report PDF was generated by WeasyPrint" tags: [code-review] files: - - pattern: "docs/NuGetCaching Review Report.pdf" + - pattern: "docs/generated/NuGetCaching Review Report.pdf" count: 1 pdf: metadata: @@ -147,7 +147,7 @@ tests: description: "Design HTML was generated by Pandoc" tags: [design] files: - - pattern: "docs/design/design.html" + - pattern: "docs/design/generated/design.html" count: 1 html: - query: "//head/title" @@ -159,7 +159,7 @@ tests: description: "Design PDF was generated by WeasyPrint" tags: [design] files: - - pattern: "docs/NuGetCaching Software Design.pdf" + - pattern: "docs/generated/NuGetCaching Software Design.pdf" count: 1 pdf: metadata: @@ -174,13 +174,46 @@ tests: text: - contains: "Design" + # --- VERIFICATION DOCUMENT --- + + - name: Pandoc_VerificationHtml + description: "Verification HTML was generated by Pandoc" + tags: [verification] + files: + - pattern: "docs/verification/generated/verification.html" + count: 1 + html: + - query: "//head/title" + count: 1 + text: + - contains: "Verification" + + - name: WeasyPrint_VerificationPdf + description: "Verification PDF was generated by WeasyPrint" + tags: [verification] + files: + - pattern: "docs/generated/NuGetCaching Verification Design.pdf" + count: 1 + pdf: + metadata: + - field: "Title" + contains: "Verification" + - field: "Author" + contains: "DEMA Consulting" + - field: "Subject" + contains: "Verification design document" + pages: + min: 3 + text: + - contains: "Verification" + # --- USER GUIDE --- - name: Pandoc_UserGuideHtml description: "User Guide HTML was generated by Pandoc" tags: [user-guide] files: - - pattern: "docs/user_guide/user_guide.html" + - pattern: "docs/user_guide/generated/user_guide.html" count: 1 html: - query: "//head/title" @@ -192,7 +225,7 @@ tests: description: "User Guide PDF was generated by WeasyPrint" tags: [user-guide] files: - - pattern: "docs/NuGetCaching User Guide.pdf" + - pattern: "docs/generated/NuGetCaching User Guide.pdf" count: 1 pdf: metadata: @@ -214,7 +247,7 @@ tests: description: "Requirements HTML was generated by Pandoc" tags: [requirements] files: - - pattern: "docs/requirements_doc/requirements.html" + - pattern: "docs/requirements_doc/generated/requirements.html" count: 1 html: - query: "//head/title" @@ -226,7 +259,7 @@ tests: description: "Requirements PDF was generated by WeasyPrint" tags: [requirements] files: - - pattern: "docs/NuGetCaching Requirements.pdf" + - pattern: "docs/generated/NuGetCaching Requirements.pdf" count: 1 pdf: metadata: @@ -248,7 +281,7 @@ tests: description: "Trace Matrix HTML was generated by Pandoc" tags: [requirements] files: - - pattern: "docs/requirements_report/trace_matrix.html" + - pattern: "docs/requirements_report/generated/trace_matrix.html" count: 1 html: - query: "//head/title" @@ -260,7 +293,7 @@ tests: description: "Trace Matrix PDF was generated by WeasyPrint" tags: [requirements] files: - - pattern: "docs/NuGetCaching Trace Matrix.pdf" + - pattern: "docs/generated/NuGetCaching Trace Matrix.pdf" count: 1 pdf: metadata: diff --git a/.github/agents/developer.agent.md b/.github/agents/developer.agent.md index 35f5dda..a95c562 100644 --- a/.github/agents/developer.agent.md +++ b/.github/agents/developer.agent.md @@ -21,7 +21,7 @@ Perform software development tasks by determining and applying appropriate stand 5. **Formatting**: Run `pwsh ./fix.ps1` to silently apply all available auto-fixers (dotnet format, markdown, YAML) before committing 6. **Build and test** (code changes only): Run `pwsh ./build.ps1` and confirm it - passes — report FAILED if the build or any tests fail + passes - report FAILED if the build or any tests fail 7. **Generate completion report** per the AGENTS.md reporting requirements - save to `.agent-logs/{agent-name}-{subject}-{unique-id}.md` and return the summary to the caller diff --git a/.github/agents/formal-review.agent.md b/.github/agents/formal-review.agent.md index 88b0691..7dd8e84 100644 --- a/.github/agents/formal-review.agent.md +++ b/.github/agents/formal-review.agent.md @@ -20,6 +20,8 @@ Before reviewing, read these standards to inform review judgments: hierarchy and categorization review judgments - **`design-documentation.md`** - defines mandatory sections, structural conventions, and coverage expected at each level; informs all design documentation review judgments +- **`verification-documentation.md`** - defines mandatory sections, structural conventions, + and coverage expected at each level; informs all verification design review judgments For review sets that include source code or tests, also consult the relevant standards from the selection matrix in AGENTS.md. diff --git a/.github/agents/lint-fix.agent.md b/.github/agents/lint-fix.agent.md index 83ad8cb..549e751 100644 --- a/.github/agents/lint-fix.agent.md +++ b/.github/agents/lint-fix.agent.md @@ -36,7 +36,12 @@ submission, not during normal development. - **markdownlint MD013 (line length)**: Wrap long lines at natural break points, after commas, before conjunctions, or at sentence boundaries. Do not break - in the middle of a code span or URL. + in the middle of a code span or URL. **Pipe-tables that cannot be wrapped + without breaking structure** are a special case - convert them to a bullet + list if the data reads naturally that way, or rewrite as a + [grid table](https://pandoc.org/MANUAL.html#tables) if a tabular layout is + essential. Do not get stuck trying to squeeze a wide pipe-table into 120 + characters. - **markdownlint other rules**: Apply the specific fix indicated in the output (e.g., missing blank lines, heading levels, code fence languages). diff --git a/.github/agents/repo-consistency.agent.md b/.github/agents/repo-consistency.agent.md deleted file mode 100644 index 0b66277..0000000 --- a/.github/agents/repo-consistency.agent.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -name: repo-consistency -description: > - Ensures downstream repositories remain consistent with the TemplateDotNetLibrary - template patterns and best practices. -user-invocable: true ---- - -# Repo Consistency Agent - -Maintain consistency between downstream projects and the TemplateDotNetLibrary template, ensuring repositories -benefit from template evolution while respecting project-specific customizations. - -# Consistency Workflow (MANDATORY) - -**CRITICAL**: This agent MUST follow these steps systematically to ensure proper template consistency analysis: - -1. **Fetch Recent Template Changes**: Use GitHub search to fetch the 20 most recently merged PRs - (`is:pr is:merged sort:updated-desc`) from -2. **Analyze Template Evolution**: For each relevant PR, determine the intent and scope of changes - (what files were modified, what improvements were made) -3. **Assess Downstream Applicability**: Evaluate which template changes would benefit this repository - while respecting project-specific customizations -4. **Apply Appropriate Updates**: Implement applicable template improvements with proper translation for project context -5. **Validate Consistency**: Verify that applied changes maintain functionality and follow project patterns -6. **Generate completion report** per the AGENTS.md reporting requirements - save to - `.agent-logs/{agent-name}-{subject}-{unique-id}.md` and return the summary to the caller - -## Key Principles - -- **Evolutionary Consistency**: Template improvements should enhance downstream projects systematically -- **Intelligent Customization Respect**: Distinguish valid customizations from unintentional drift -- **Incremental Template Adoption**: Support phased adoption of template improvements based on project capacity - -# Don't Do These Things - -- **Never recommend changes without understanding project context** (some differences are intentional) -- **Never flag valid project-specific customizations** as consistency problems -- **Never apply template changes blindly** without assessing downstream project impact -- **Never ignore template evolution benefits** when they clearly improve downstream projects -- **Never recommend breaking changes** without migration guidance and impact assessment -- **Never skip validation** of preserved functionality after template alignment -- **Never assume all template patterns apply universally** (assess project-specific needs) - -# Report Template - -```markdown -# Repo Consistency Report - -**Result**: (SUCCEEDED|FAILED) - -## Consistency Analysis - -- **Template PRs Analyzed**: {Number and timeframe of PRs reviewed} -- **Template Changes Identified**: {Count and types of template improvements} -- **Applicable Updates**: {Changes determined suitable for this repository} -- **Project Customizations Preserved**: {Valid differences maintained} - -## Template Evolution Applied - -- **Files Modified**: {List of files updated for template consistency} -- **Improvements Adopted**: {Specific template enhancements implemented} -- **Configuration Updates**: {Tool configurations, workflows, or standards updated} - -## Consistency Status - -- **Template Alignment**: {Overall consistency rating with template} -- **Customization Respect**: {How project-specific needs were preserved} -- **Functionality Validation**: {Verification that changes don't break existing features} -- **Future Consistency**: {Recommendations for ongoing template alignment} - -## Issues Resolved - -- **Drift Corrections**: {Template drift issues addressed} -- **Enhancement Adoptions**: {Template improvements successfully integrated} -- **Validation Results**: {Testing and validation outcomes} -``` diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 30b81da..82a413e 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -26,13 +26,11 @@ Before submitting this pull request, ensure you have completed the following: ### Build and Test -- [ ] Code builds successfully: `dotnet build --configuration Release` -- [ ] All unit tests pass: `dotnet test --configuration Release` +- [ ] Code builds successfully and all tests pass: `pwsh ./build.ps1` - [ ] Code produces zero warnings ### Code Quality -- [ ] Code formatting is correct: `dotnet format --verify-no-changes` - [ ] New code has appropriate XML documentation comments - [ ] Static analyzer warnings have been addressed @@ -40,7 +38,7 @@ Before submitting this pull request, ensure you have completed the following: Please run the following checks before submitting: -- [ ] **All linters pass**: `./lint.sh` (Unix/macOS) or `cmd /c lint.bat` / `./lint.bat` (Windows) +- [ ] **All linters pass**: `pwsh ./lint.ps1` ### Testing @@ -52,7 +50,7 @@ Please run the following checks before submitting: ### Documentation - [ ] Updated README.md (if applicable) -- [ ] Updated ARCHITECTURE.md (if applicable) +- [ ] Updated docs/ documentation (if applicable) - [ ] Added code examples for new features (if applicable) - [ ] Updated requirements.yaml (if applicable) diff --git a/.github/standards/coding-principles.md b/.github/standards/coding-principles.md index 213c031..9e67fbb 100644 --- a/.github/standards/coding-principles.md +++ b/.github/standards/coding-principles.md @@ -20,11 +20,35 @@ All code MUST follow literate programming principles: matches design intent without reading the full codebase - **Logical Separation**: Complex functions use block comments to separate and describe logical steps within the implementation -- **Public Documentation**: All public interfaces have comprehensive documentation - because consumers and auditors rely on interface contracts for integration - and compliance verification +- **Full Symbol Documentation**: ALL symbols have comprehensive documentation + because reviewers and auditors must verify every implementation detail, not + just the public interface - access-level specifics (public, protected, + private, internal, etc.) vary by language; see the language-specific standard - **Clarity Over Cleverness**: Code should be immediately understandable by team members +## API Documentation + +Good API documentation enables consumers, reviewers, and agents to use an +interface correctly without reading the implementation: + +- **Self-Contained**: Each member's documentation must be fully understandable + in isolation - consumers must not need to read the implementation to call it + correctly +- **Intent-Focused**: Explain WHY the member exists and WHAT problem it solves, + not just restate the name - this lets reviewers verify the implementation + matches design intent +- **Parameter and Return Contracts**: Document valid ranges, null handling, and + boundary cases - agents and consumers rely on these contracts to call the API + correctly +- **Error Conditions**: Document every exception or error code, the condition + that triggers it, and how the caller should respond - undocumented errors + cannot be handled correctly +- **Side Effects**: Document I/O, state mutation, resource allocation, or + network calls - hidden side effects cause integration bugs that are hard to + diagnose +- **Thread Safety**: State whether the API is safe for concurrent use - missing + this forces consumers to read the implementation or risk data races + ## Universal Code Architecture Principles ### Design Patterns diff --git a/.github/standards/csharp-language.md b/.github/standards/csharp-language.md index 707b0f9..6df39cd 100644 --- a/.github/standards/csharp-language.md +++ b/.github/standards/csharp-language.md @@ -4,37 +4,63 @@ description: Follow these standards when developing C# source code. globs: ["**/*.cs"] --- -# C# Language Development Standard - -## Required Standards +# Required Standards Read these standards first before applying this standard: - **`coding-principles.md`** - Universal coding principles and quality gates -# File Patterns - -- **Source Files**: `**/*.cs` +# API Documentation and Literate Coding Example -# Literate Coding Example +The example below demonstrates good XmlDoc API documentation combined with +literate coding comments. ```csharp -// Validate input parameters to prevent downstream errors -if (string.IsNullOrEmpty(input)) +/// +/// Converts a raw sensor reading into a validated measurement ready for downstream consumers. +/// +/// +/// Clamping is preferred over throwing on out-of-range values because sensor drift at +/// range boundaries is expected; clamping produces a usable result where rejection would +/// discard valid near-boundary readings. Stateless and thread-safe; the calibration +/// profile is read but never modified. +/// +/// Raw sensor value. Must be finite (NaN and infinities are rejected). +/// Calibration profile providing offset and range. Must not be null. +/// Corrected value clamped to [calibration.Minimum, calibration.Maximum]. +/// Thrown when is NaN or infinite. +/// Thrown when is null. +public double ProcessReading(double reading, CalibrationProfile calibration) { - throw new ArgumentException("Input cannot be null or empty", nameof(input)); -} - -// Transform input data using the configured processing pipeline -var processedData = ProcessingPipeline.Transform(input); + // Reject invalid inputs before any calculation - non-finite readings cannot be + // corrected, and a null calibration profile provides no offset or range to apply + if (!double.IsFinite(reading)) + throw new ArgumentException("Reading must be a finite number.", nameof(reading)); + ArgumentNullException.ThrowIfNull(calibration); -// Apply business rules and validation logic -var validatedResults = BusinessRuleEngine.ValidateAndProcess(processedData); + // Apply the calibration offset to convert raw counts to physical units + var corrected = reading + calibration.Offset; -// Return formatted results matching the expected output contract -return OutputFormatter.Format(validatedResults); + // Clamp to the operational range so consumers can rely on the documented contract + return Math.Clamp(corrected, calibration.Minimum, calibration.Maximum); +} ``` +Key qualities demonstrated above: + +- **``** is a brief one-liner explaining *what* the method does +- **``** sits directly after summary and carries the extended intent - + *why* it exists, design decisions, thread-safety, and side-effect disclosures +- **`` tags** state constraints (finite, non-null) so callers know what + is valid without reading the body +- **``** documents the boundary guarantee so consumers can rely on the + contract +- **`` tags** name every thrown exception and the condition that + triggers each one +- **Inline block comments** follow the Literate Coding principles from + `coding-principles.md`, separating logical steps so reviewers can verify each + step against design intent + # Code Formatting - **Format entire solution**: `dotnet format` diff --git a/.github/standards/csharp-testing.md b/.github/standards/csharp-testing.md index 1591eeb..181de02 100644 --- a/.github/standards/csharp-testing.md +++ b/.github/standards/csharp-testing.md @@ -4,115 +4,74 @@ description: Follow these standards when developing C# tests. globs: ["**/test/**/*.cs", "**/tests/**/*.cs", "**/*Tests.cs", "**/*Test.cs"] --- -# C# Testing Standards (MSTest) - -This document defines standards for C# test development using -MSTest within Continuous Compliance environments. - -## Required Standards +# Required Standards Read these standards first before applying this standard: - **`testing-principles.md`** - Universal testing principles and dependency boundaries - **`csharp-language.md`** - C# language development standards -# C# AAA Pattern Implementation +# Package Reference -```csharp -[TestMethod] -public void ServiceName_MethodName_Scenario_ExpectedBehavior() -{ - // Arrange: description of setup (omit if nothing to set up) +Every xUnit v3 test project requires the following package references for +`dotnet test` to discover and execute tests: - // Act: description of action (can combine with Assert when action occurs within assertion) +| Package | Purpose | +| ------- | ------- | +| `xunit.v3` | xUnit v3 framework (monolithic - includes assertions and fixtures) | +| `Microsoft.NET.Test.Sdk` | Required by the VSTest/`dotnet test` host for test discovery | +| `xunit.runner.visualstudio` | VSTest adapter that bridges xUnit v3 to `dotnet test` | - // Assert: description of verification -} -``` +Omitting `Microsoft.NET.Test.Sdk` or `xunit.runner.visualstudio` causes tests +to be silently undiscoverable by `dotnet test`. + +If tests require mocking of dependencies, add `NSubstitute` as a package +reference - it is recommended when mocking is needed but is not required for +every test project. -# Test Naming Standards +# Test Style -Use descriptive test names because test names appear in requirements traceability matrices and compliance reports. +Test names appear in requirements traceability matrices - use the hierarchical +naming pattern, and follow AAA with labeled comments: - **System tests**: `{SystemName}_{Functionality}_{Scenario}_{ExpectedBehavior}` - **Subsystem tests**: `{SubsystemName}_{Functionality}_{Scenario}_{ExpectedBehavior}` - **Unit tests**: `{ClassName}_{MethodUnderTest}_{Scenario}_{ExpectedBehavior}` -- **Descriptive Scenarios**: Clearly describe the input condition being tested -- **Expected Behavior**: State the expected outcome or exception - -## Examples - -- `UserValidator_ValidateEmail_ValidFormat_ReturnsTrue` -- `UserValidator_ValidateEmail_InvalidFormat_ThrowsArgumentException` -- `PaymentProcessor_ProcessPayment_InsufficientFunds_ReturnsFailureResult` - -# Mock Dependencies - -Mock external dependencies using NSubstitute (preferred) because tests must run in isolation to generate -reliable evidence. - -- **Isolate System Under Test**: Mock all external dependencies (databases, web services, file systems) -- **Verify Interactions**: Assert that expected method calls occurred with correct parameters -- **Predictable Behavior**: Set up mocks to return known values for consistent test results - -# MSTest V4 Anti-patterns - -Avoid these common MSTest V4 patterns because they produce poor error messages or cause tests to be silently ignored. - -# Avoid Assertions in Catch Blocks (MSTEST0058) - -Instead of wrapping code in try/catch and asserting in the catch block, use `Assert.ThrowsExactly()`: - -```csharp -var ex = Assert.ThrowsExactly(() => SomeWork()); -Assert.Contains("Some message", ex.Message); -``` - -# Avoid Assert.IsTrue/IsFalse for Equality Checks - -Use `Assert.AreEqual`/`Assert.AreNotEqual` instead, as they provide better failure messages: - -```csharp -// ❌ Bad: Assert.IsTrue(result == expected); -// ✅ Good: Assert.AreEqual(expected, result); -``` - -# Avoid Non-Public Test Classes and Methods - -Test classes and `[TestMethod]` methods must be `public` or they will be silently ignored: ```csharp -// ❌ Bad: internal class MyTests -// ✅ Good: public class MyTests -``` - -# Avoid Assert.IsTrue for Collection Count - -Use `Assert.HasCount` for count assertions: +/// +/// Validates that an invalid email format throws an ArgumentException. +/// +[Fact] +public void UserValidator_ValidateEmail_InvalidFormat_ThrowsArgumentException() +{ + // Arrange: create a validator with default configuration + var validator = new UserValidator(); -```csharp -// ❌ Bad: Assert.IsTrue(collection.Count == 3); -// ✅ Good: Assert.HasCount(3, collection); + // Act / Assert: email with no domain throws + Assert.Throws(() => validator.ValidateEmail("not-an-email")); +} ``` -# Avoid Assert.IsTrue for String Prefix Checks +# xUnit v3 Specifics -Use `Assert.StartsWith` instead, as it produces clearer failure messages: +These are non-obvious v3 behaviors that differ from v2 or common assumptions: -```csharp -// ❌ Bad: Assert.IsTrue(value.StartsWith("prefix")); -// ✅ Good: Assert.StartsWith("prefix", value); -``` +- **`IAsyncLifetime`**: Both `InitializeAsync` and `DisposeAsync` return `ValueTask` + in v3, not `Task` - using `Task` compiles but does not satisfy the v3 interface +- **`Assert.Multiple`**: Use to collect all assertion failures in a single test + rather than stopping at the first +- **`[Collection]` without `[CollectionDefinition]`**: Silently disables parallelism + without providing any shared fixture - always pair them or remove `[Collection]` # Quality Checks Before submitting C# tests, verify: - [ ] All tests follow AAA pattern with clear section comments -- [ ] Test names follow hierarchical patterns defined in Test Naming Standards section -- [ ] Each test verifies single, specific behavior (no shared state) +- [ ] Test names follow hierarchical naming pattern above +- [ ] Each test verifies single, specific behavior (no shared state between tests) - [ ] Both success and failure scenarios covered including edge cases -- [ ] External dependencies mocked with NSubstitute or equivalent +- [ ] External dependencies mocked with NSubstitute (when mocking is needed) - [ ] Tests linked to requirements with source filters where needed -- [ ] Test results generate TRX format for ReqStream compatibility -- [ ] MSTest V4 anti-patterns avoided (proper assertions, public visibility, etc.) +- [ ] Test results generated in TRX format for ReqStream compatibility (`dotnet test --logger trx`) diff --git a/.github/standards/design-documentation.md b/.github/standards/design-documentation.md index 30becb5..3b448f3 100644 --- a/.github/standards/design-documentation.md +++ b/.github/standards/design-documentation.md @@ -108,6 +108,13 @@ src/Project2Name/ └── HelperClass.cs - Helper functions ``` +### References Section (RECOMMENDED) + +If the design references external documents (standards, specifications), include +a `## References` section in `introduction.md`. This is the **only** place in the +design document collection where a References section should appear - do not add +one to any other design file. + ### Companion Artifact Structure (RECOMMENDED) Include a brief note explaining that each software item has parallel artifacts @@ -122,6 +129,7 @@ parallel directory trees: - Requirements: `docs/reqstream/{system}/.../{item}.yaml` (kebab-case) - Design docs: `docs/design/{system}/.../{item}.md` (kebab-case) +- Verification design: `docs/verification/{system}/.../{item}.md` (kebab-case) - Source code: `src/{System}/.../{Item}.{ext}` (cased per language - see `software-items.md`) - Tests: `test/{System}.Tests/.../{Item}Tests.{ext}` (cased per language - see `software-items.md`) - Review-sets: defined in `.reviewmark.yaml` @@ -168,6 +176,9 @@ implementation specification for formal code review: - **Implementation Detail**: Provide sufficient detail for code review and implementation - **Architectural Clarity**: Clearly define component boundaries and interfaces - **Traceability**: Link to requirements where applicable using ReqStream patterns +- **Verbal Cross-References**: Reference other parts of the design by name (e.g., + "See *Parser Design* for more details") - do not use markdown hyperlinks, which + break in compiled PDFs # Mermaid Diagram Integration diff --git a/.github/standards/reqstream-usage.md b/.github/standards/reqstream-usage.md index ae5e565..58b08b4 100644 --- a/.github/standards/reqstream-usage.md +++ b/.github/standards/reqstream-usage.md @@ -104,16 +104,16 @@ dotnet reqstream --requirements requirements.yaml --lint # Generate requirements document for compliance record dotnet reqstream --requirements requirements.yaml \ - --report docs/requirements_doc/requirements.md + --report docs/requirements_doc/generated/requirements.md # Generate justifications document for compliance record dotnet reqstream --requirements requirements.yaml \ - --justifications docs/requirements_doc/justifications.md + --justifications docs/requirements_doc/generated/justifications.md # Generate trace matrix proving each requirement is covered by passing tests dotnet reqstream --requirements requirements.yaml \ --tests "artifacts/**/*.trx" \ - --matrix docs/requirements_report/trace_matrix.md + --matrix docs/requirements_report/generated/trace_matrix.md ``` # Quality Checks diff --git a/.github/standards/requirements-principles.md b/.github/standards/requirements-principles.md index 7d2d572..b6cf136 100644 --- a/.github/standards/requirements-principles.md +++ b/.github/standards/requirements-principles.md @@ -29,6 +29,10 @@ implementation code. - **Valid**: "The parser shall report the line number of the first syntax error." - **Not a requirement (design decision)**: "The parser shall use a `TokenStream` class." +A unit may use its own name freely - that is identity, not HOW. What is +forbidden is describing *internal construction*: class names, method signatures, +algorithms, or data structures. + # Requirements at Every Level (MANDATORY) Every identified subsystem and unit MUST have its own requirements file because diff --git a/.github/standards/reviewmark-usage.md b/.github/standards/reviewmark-usage.md index 5d6219e..2f778dc 100644 --- a/.github/standards/reviewmark-usage.md +++ b/.github/standards/reviewmark-usage.md @@ -20,7 +20,7 @@ review, organizes them into review-sets, and generates review plans and reports. - **Lint Configuration**: `dotnet reviewmark --lint` - **Elaborate Review-Set**: `dotnet reviewmark --elaborate {review-set}` -- **Generate Plan**: `dotnet reviewmark --plan docs/code_review_plan/plan.md --enforce` +- **Generate Plan**: `dotnet reviewmark --plan docs/code_review_plan/generated/plan.md --enforce` > **Note**: `--enforce` causes the plan to fail with a non-zero exit code if any repository > files are not covered by a review-set. Uncovered files indicate a gap in review-set @@ -31,7 +31,8 @@ review, organizes them into review-sets, and generates review plans and reports. Required repository items for ReviewMark operation: - `.reviewmark.yaml` - Configuration for review-sets, file-patterns, and review evidence-source. -- `docs/code_review_plan/` - Review planning artifacts +- `docs/code_review_plan/generated/` - Generated review plan (build output, do not edit) +- `docs/code_review_report/generated/` - Generated review report (build output, do not edit) # Review Definition Structure @@ -55,6 +56,7 @@ needs-review: - "README.md" # Root level README - "docs/user_guide/**/*.md" # User guide - "docs/design/**/*.md" # Design documentation + - "docs/verification/**/*.md" # Verification design documentation # Source of review evidence evidence-source: @@ -109,6 +111,8 @@ Reviews system architecture and operational validation: - System requirements: `docs/reqstream/{system-name}/{system-name}.yaml` - Design introduction: `docs/design/introduction.md` - System design: `docs/design/{system-name}/{system-name}.md` + - Verification introduction: `docs/verification/introduction.md` + - System verification design: `docs/verification/{system-name}/{system-name}.md` - System integration tests: `test/{SystemName}.Tests/{SystemName}Tests.{ext}` ## `{System}-Design` Review (one per system) @@ -147,6 +151,7 @@ Reviews subsystem architecture and interfaces: - **File Path Patterns**: - Requirements: `docs/reqstream/{system-name}/.../{subsystem-name}/{subsystem-name}.yaml` - Design: `docs/design/{system-name}/.../{subsystem-name}/{subsystem-name}.md` + - Verification design: `docs/verification/{system-name}/.../{subsystem-name}/{subsystem-name}.md` - Tests: `test/{SystemName}.Tests/.../{SubsystemName}/{SubsystemName}Tests.{ext}` ## `{System}-{Subsystem[-Child...]}-{Unit}` Review (one per unit) @@ -159,6 +164,7 @@ Reviews individual software unit implementation: - **File Path Patterns**: - Requirements: `docs/reqstream/{system-name}/.../{unit-name}.yaml` - Design: `docs/design/{system-name}/.../{unit-name}.md` + - Verification design: `docs/verification/{system-name}/.../{unit-name}.md` - Source: `src/{SystemName}/.../{UnitName}.{ext}` - Tests: `test/{SystemName}.Tests/.../{UnitName}Tests.{ext}` @@ -175,6 +181,9 @@ Before submitting ReviewMark configuration, verify: - [ ] System-level reviews follow hierarchical scope principle (exclude subsystem/unit details) - [ ] Subsystem reviews follow hierarchical scope principle (exclude unit source code) - [ ] Only unit reviews include actual source code files +- [ ] Architecture review-sets include system verification design alongside system design +- [ ] Subsystem review-sets include subsystem verification design +- [ ] Unit review-sets include unit verification design - [ ] Each review-set focuses on a single compliance question (single focus principle) - [ ] File patterns use correct glob syntax and match intended files - [ ] Review-set file counts remain manageable (context management principle) diff --git a/.github/standards/software-items.md b/.github/standards/software-items.md index bb67b1d..4e5c90e 100644 --- a/.github/standards/software-items.md +++ b/.github/standards/software-items.md @@ -84,11 +84,12 @@ Choose the appropriate category based on scope and testability: # Software Item Artifact Model -Each software item has four artifact types that together form a complete review +Each software item has five artifact types that together form a complete review unit - because reviewing any one artifact in isolation cannot determine whether the item is correct, well-designed, and proven to work: - **Requirements** - WHAT the item must do (drives all other artifacts; applies to all item types) - **Design** - HOW the item satisfies its requirements (in-house items only: system, subsystem, unit) +- **Verification Design** - HOW the requirements will be tested (applies to all item types) - **Source code** - The implementation of the design (in-house units only) - **Tests** - PROOF the item does WHAT it is required to do (applies to all item types) diff --git a/.github/standards/technical-documentation.md b/.github/standards/technical-documentation.md index 455b2fd..7ff5b5a 100644 --- a/.github/standards/technical-documentation.md +++ b/.github/standards/technical-documentation.md @@ -1,7 +1,7 @@ --- name: Technical Documentation description: Follow these standards when creating technical documentation. -globs: ["docs/**/*.md", "README.md"] +globs: ["docs/**/*.md", "README.md", "!docs/**/generated/**"] --- # Technical Documentation Standards @@ -23,63 +23,25 @@ for regulatory review: - **Review Integration**: Documentation follows ReviewMark patterns for formal review tracking -# Documentation Organization +# Pandoc Document Structure (MANDATORY) -Structure documentation under `docs/` following standard patterns for -consistency and tool compatibility: +Each document collection under `docs/` follows this layout: ```text -docs/ - build_notes.md # Generated by BuildMark - build_notes/ # Auto-generated build notes - versions.md # Generated by VersionMark - code_review_plan/ # Auto-generated review plans - plan.md # Generated by ReviewMark - code_review_report/ # Auto-generated review reports - report.md # Generated by ReviewMark - design/ # Design documentation - introduction.md # Design overview - {system-name}/ # System architecture folder - {system-name}.md # System architecture - {subsystem-name}/ # Subsystem folder; may nest recursively - {subsystem-name}.md # Subsystem-specific designs - {child-subsystem}/ # Child subsystem (same structure) - {unit-name}.md # Unit-specific designs - {unit-name}.md # Top-level unit design - reqstream/ # Requirements source files - {system-name}/ # System requirements folder - {system-name}.yaml # System requirements - platform-requirements.yaml # Platform requirements - {subsystem-name}/ # Subsystem folder; may nest recursively - {subsystem-name}.yaml # Subsystem requirements - {child-subsystem}/ # Child subsystem (same structure) - {unit-name}.yaml # Unit-specific requirements - {unit-name}.yaml # Top-level unit requirements - ots/ # OTS requirement files - {ots-name}.yaml # OTS requirements - requirements_doc/ # Auto-generated requirements reports - requirements.md # Generated by ReqStream - justifications.md # Generated by ReqStream - requirements_report/ # Auto-generated trace matrices - trace_matrix.md # Generated by ReqStream - user_guide/ # User-facing documentation - introduction.md # User guide overview - {section}.md # User guide sections +docs/{collection}/ + title.txt # MANDATORY - YAML document metadata (title, author, etc.) + definition.yaml # MANDATORY - Pandoc build definition (inputs, template, paths) + introduction.md # MANDATORY - document introduction (Purpose, Scope, References) + {section}.md # optional checked-in content sections (zero or more) + generated/ # BUILD OUTPUT - never read, edit, or lint these files + {report}.md # generated by CI tools (ReqStream, ReviewMark, SarifMark, etc.) + {collection}.html # generated by Pandoc ``` -# Pandoc Document Structure (MANDATORY) - -All document collections processed by Pandoc MUST include all four files below - -without `title.txt` and `definition.yaml` the pipeline cannot generate the document: - -- `title.txt` - YAML metadata (title, subtitle, author, description, lang, keywords) -- `definition.yaml` - Pandoc build definition (resource paths, input file list, template) -- `introduction.md` - document introduction -- `{sections}.md` - additional content sections - -When creating a new document collection, create `title.txt` and `definition.yaml` -alongside `introduction.md`. Use the existing files under `docs/` as templates - -they share a consistent structure across all collections. +Without `title.txt` and `definition.yaml` the pipeline cannot generate the document. +When creating a new document collection, create these three files together and use +the existing collections under `docs/` as templates - they share a consistent +structure across all collections. **`title.txt`** - YAML front matter with document metadata. Use the existing files under `docs/` as a pattern and keep fields consistent with the rest of @@ -106,8 +68,17 @@ Include regulatory or business drivers where applicable. Define what is covered and what is explicitly excluded from this documentation. Specify version, system boundaries, and applicability constraints. + +## References + +- [REF-1] Document Title, Author, Version, Date +- [REF-2] Standard Name (e.g., IEEE 12207, ISO 9001) ``` +The `Purpose`, `Scope`, and `References` sections are **unique to `introduction.md`** and must +**not** be replicated in other markdown files within the same document collection. Including them +elsewhere causes duplicate sections in the compiled PDF. + ## Document Ordering List documents in logical reading order in Pandoc configuration because @@ -135,6 +106,19 @@ References in design/technical documents must point to **external specifications - **INCLUDE**: Requirements documents, system specifications, program documents, standards (IEEE, ISO, etc.) - **NEVER INCLUDE**: Internal development standards (`.github/standards/` files) - these are agent guides +## Cross-References (Within-Document and Cross-Document) + +Do **not** use markdown hyperlinks to reference other sections or documents. Markdown anchor links +(`[text](#heading)`) and relative file links work in a browser but break when compiled to a PDF. + +Instead use **verbal references** - plain prose that identifies the target by name: + +> See *XYZ Design* for more details. +> +> Refer to the *System Requirements* document for the full specification. + +Verbal references are readable by both AI agents and humans in any rendering environment. + # Markdown Format Requirements Markdown documentation in this repository must follow the formatting standards @@ -156,14 +140,13 @@ for consistency and professional presentation: # Auto-Generated Content (CRITICAL) -**NEVER modify auto-generated markdown files** because changes will be -overwritten and break compliance automation: +**NEVER read, lint, or modify files inside any `generated/` folder** - they are +build outputs that are overwritten on every CI run: -- **Read-Only Files**: Generated reports under `docs/requirements_doc/`, - `docs/requirements_report/`, `docs/code_review_plan/`, and - `docs/code_review_report/` are regenerated on every build -- **Source Modification**: Update source files (requirements YAML, code - comments) instead of generated output +- **Location**: All generated files live in `generated/` subfolders within their + respective `docs/` sections, or in `docs/generated/` for final release artifacts +- **Source Modification**: Update source files (requirements YAML, `.reviewmark.yaml`, + tool configuration) instead of generated output - **Tool Integration**: Generated content integrates with CI/CD pipelines and manual changes disrupt automation diff --git a/.github/standards/verification-documentation.md b/.github/standards/verification-documentation.md new file mode 100644 index 0000000..f6f407f --- /dev/null +++ b/.github/standards/verification-documentation.md @@ -0,0 +1,128 @@ +--- +name: Verification Documentation +description: Follow these standards when creating software verification design documentation. +globs: ["docs/verification/**/*.md"] +--- + +# Required Standards + +Read these standards first before applying this standard: + +- **`technical-documentation.md`** - General technical documentation standards +- **`software-items.md`** - Software categorization (System/Subsystem/Unit/OTS) + +# Core Principles + +Verification design is the bridge between requirements and tests - it documents HOW +requirements will be verified, enabling reviewers to confirm test completeness without +reading implementation code. + +# Required Structure and Documents + +Organize under `docs/verification/` mirroring the software item hierarchy: + +```text +docs/verification/ +├── introduction.md # Verification overview +├── {system-name}/ # System-level verification folder (one per system) +│ ├── {system-name}.md # System-level verification design +│ ├── {subsystem-name}/ # Subsystem (kebab-case); may nest recursively +│ │ ├── {subsystem-name}.md # Subsystem verification design +│ │ ├── {child-subsystem}/ # Child subsystem (same structure as parent) +│ │ └── {unit-name}.md # Unit-level verification design documents +│ └── {unit-name}.md # Top-level unit verification documents (if not in subsystem) +└── ots/ # OTS items (one verification file per OTS item) + └── {ots-name}.md # Verification evidence for each OTS item +``` + +## introduction.md (MANDATORY) + +Follow the standard `introduction.md` format from `technical-documentation.md`. Scope +covers all software items including OTS items (via self-validation if appropriate). + +Include a Companion Artifact Structure note so agents and reviewers can navigate from any +artifact to all related files: + +```text +In-house items have parallel artifacts in: +- Requirements: `docs/reqstream/{system}/.../{item}.yaml` (kebab-case) +- Design: `docs/design/{system}/.../{item}.md` (kebab-case) +- Verification: `docs/verification/{system}/.../{item}.md` (kebab-case) +- Source: `src/{System}/.../{Item}.{ext}` (cased per language) +- Tests: `test/{System}.Tests/.../{Item}Tests.{ext}` (cased per language) + +OTS items have parallel artifacts in: +- Requirements: `docs/reqstream/ots/{ots-name}.yaml` (kebab-case) +- Verification: `docs/verification/ots/{ots-name}.md` (kebab-case) +- Tests: `test/{OtsName}.Tests/...` (cased per language, if required) + +Review-sets: defined in `.reviewmark.yaml` +``` + +If the verification design references external documents (standards, specifications), include +a `## References` section in `introduction.md` only - do not add one to any other verification file. + +## System Verification Design (MANDATORY) + +For each system, create a kebab-case folder and `{system-name}.md` covering: + +- System verification strategy and overall test approach +- Test environments and configuration required +- External interface simulation and test-harness design +- End-to-end and integration test scenarios covering system requirements +- Acceptance criteria and pass/fail conditions at the system boundary +- Coverage mapping of system requirements to system-level test scenarios + +## Subsystem Verification Design (MANDATORY) + +For each subsystem, create a kebab-case folder and `{subsystem-name}.md` covering: + +- Subsystem verification strategy and integration test approach +- Dependencies that must be mocked or stubbed at the subsystem boundary +- Integration test scenarios covering subsystem requirements +- Coverage mapping of subsystem requirements to subsystem-level test scenarios + +## Unit Verification Design (MANDATORY) + +For each unit, create `{unit-name}.md` covering: + +- Verification approach for each unit requirement +- Named test scenarios including boundary conditions, error paths, and normal-operation cases +- Which dependencies are mocked and how they are configured +- Coverage mapping of every unit requirement to at least one named test scenario + +## OTS Verification Evidence (when OTS items are used) + +For each OTS item, create `docs/verification/ots/{ots-name}.md` covering: + +- The OTS item's required functionality (reference `docs/reqstream/ots/{ots-name}.yaml`) +- Verification of each requirement (using self-validation evidence if appropriate) +- Coverage mapping of OTS requirements to test scenarios + +# Writing Guidelines + +- **Test Coverage**: Map every requirement to at least one named test scenario so + reviewers can verify completeness without reading test code +- **Scenario Clarity**: Name each scenario clearly - "Valid input returns parsed result" not "Test 1" +- **Boundary Conditions**: Call out boundary values, error inputs, and edge cases explicitly +- **Isolation Strategy**: Describe what is mocked or stubbed and why at each level +- **Traceability**: Link to requirements where applicable using ReqStream patterns +- **Verbal Cross-References**: Reference other documents by name - do not use markdown + hyperlinks, which break in compiled PDFs + +Mermaid diagrams may supplement text descriptions where test flow benefits from visual +representation, but must not replace text content. + +# Quality Checks + +Before submitting verification documentation, verify: + +- [ ] Every requirement at each level is mapped to at least one named test scenario +- [ ] System verification documents cover end-to-end and integration scenarios +- [ ] Subsystem verification documents identify mocked boundaries and integration scenarios +- [ ] Unit verification documents identify individual scenarios including boundary and error paths +- [ ] Subsystem documentation folders use kebab-case names mirroring the source subsystem structure +- [ ] All documents follow technical documentation formatting standards +- [ ] Content is current with requirements and test implementation +- [ ] Every OTS item has `docs/verification/ots/{ots-name}.md` with requirement coverage +- [ ] Documents are integrated into ReviewMark review-sets for formal review diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index f94ee64..86b14aa 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -359,6 +359,15 @@ jobs: buildmark versionmark reviewmark fileassert echo "✓ Tool versions captured" + # === PREPARE DOCUMENT OUTPUT === + # Creates the shared docs/generated/ folder that all document sections write PDFs into. + # This step is intentionally separate from the document sections so any individual + # section can be commented out without breaking the shared output directory. + + - name: Create documents output directory + shell: bash + run: mkdir -p docs/generated + # === COMPILE BUILD NOTES === # This section generates the Build Notes document. BuildMark and VersionMark self-validations # run here to co-locate their evidence with the document that depends on their output. @@ -366,6 +375,10 @@ jobs: # validates the outputs contain expected content. # Downstream projects: Add any additional build notes steps here. + - name: Create build notes output directories + shell: bash + run: mkdir -p docs/build_notes/generated + - name: Run BuildMark self-validation run: > dotnet buildmark @@ -385,20 +398,20 @@ jobs: run: > dotnet buildmark --build-version ${{ inputs.version }} - --report docs/build_notes.md + --report docs/build_notes/generated/build_notes.md --report-depth 1 - name: Display Build Notes Report shell: bash run: | echo "=== Build Notes Report ===" - cat docs/build_notes.md + cat docs/build_notes/generated/build_notes.md - name: Publish Tool Versions shell: bash run: | echo "Publishing tool versions..." - dotnet versionmark --publish --report docs/build_notes/versions.md --report-depth 1 \ + dotnet versionmark --publish --report docs/build_notes/generated/versions.md --report-depth 1 \ -- "artifacts/**/versionmark-*.json" echo "✓ Tool versions published" @@ -406,7 +419,7 @@ jobs: shell: bash run: | echo "=== Tool Versions Report ===" - cat docs/build_notes/versions.md + cat docs/build_notes/generated/versions.md - name: Generate Build Notes HTML with Pandoc shell: bash @@ -416,14 +429,14 @@ jobs: --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/build_notes/build_notes.html + --output docs/build_notes/generated/build_notes.html - name: Generate Build Notes PDF with WeasyPrint run: > dotnet weasyprint --pdf-variant pdf/a-3u - docs/build_notes/build_notes.html - "docs/NuGetCaching Build Notes.pdf" + docs/build_notes/generated/build_notes.html + "docs/generated/NuGetCaching Build Notes.pdf" - name: Assert Build Notes Documents with FileAssert run: > @@ -431,6 +444,10 @@ jobs: --results artifacts/fileassert-build-notes.trx build-notes + - name: Copy Build Notes report to docs/generated + shell: bash + run: cp docs/build_notes/generated/build_notes.md docs/generated/build_notes.md + # === COMPILE CODE QUALITY REPORT === # This section generates the Code Quality document. SarifMark and SonarMark self-validations # run here to co-locate their evidence with the document that depends on their output. @@ -438,6 +455,10 @@ jobs: # validates the outputs contain expected content. # Downstream projects: Add any additional code quality steps here. + - name: Create code quality output directory + shell: bash + run: mkdir -p docs/code_quality/generated + - name: Run SarifMark self-validation run: > dotnet sarifmark @@ -454,7 +475,7 @@ jobs: run: > dotnet sarifmark --sarif artifacts/csharp.sarif - --report docs/code_quality/codeql-quality.md + --report docs/code_quality/generated/codeql-quality.md --heading "NuGetCaching CodeQL Analysis" --report-depth 1 @@ -462,7 +483,7 @@ jobs: shell: bash run: | echo "=== CodeQL Quality Report ===" - cat docs/code_quality/codeql-quality.md + cat docs/code_quality/generated/codeql-quality.md - name: Generate SonarCloud Quality Report shell: bash @@ -474,14 +495,14 @@ jobs: --project-key demaconsulting_NuGetCaching --branch ${{ github.ref_name }} --token "$SONAR_TOKEN" - --report docs/code_quality/sonar-quality.md + --report docs/code_quality/generated/sonar-quality.md --report-depth 1 - name: Display SonarCloud Quality Report shell: bash run: | echo "=== SonarCloud Quality Report ===" - cat docs/code_quality/sonar-quality.md + cat docs/code_quality/generated/sonar-quality.md - name: Generate Code Quality HTML with Pandoc shell: bash @@ -491,14 +512,14 @@ jobs: --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/code_quality/quality.html + --output docs/code_quality/generated/quality.html - name: Generate Code Quality PDF with WeasyPrint run: > dotnet weasyprint --pdf-variant pdf/a-3u - docs/code_quality/quality.html - "docs/NuGetCaching Code Quality.pdf" + docs/code_quality/generated/quality.html + "docs/generated/NuGetCaching Code Quality.pdf" - name: Assert Code Quality Documents with FileAssert run: > @@ -513,6 +534,10 @@ jobs: # PDF, and FileAssert validates the outputs contain expected content. # Downstream projects: Add any additional code review steps here. + - name: Create code review output directories + shell: bash + run: mkdir -p docs/code_review_plan/generated docs/code_review_report/generated + - name: Run ReviewMark self-validation run: > dotnet reviewmark @@ -524,22 +549,22 @@ jobs: # TODO: Add --enforce once reviews branch is populated with review evidence PDFs and index.json run: > dotnet reviewmark - --plan docs/code_review_plan/plan.md + --plan docs/code_review_plan/generated/plan.md --plan-depth 1 - --report docs/code_review_report/report.md + --report docs/code_review_report/generated/report.md --report-depth 1 - name: Display Review Plan shell: bash run: | echo "=== Review Plan ===" - cat docs/code_review_plan/plan.md + cat docs/code_review_plan/generated/plan.md - name: Display Review Report shell: bash run: | echo "=== Review Report ===" - cat docs/code_review_report/report.md + cat docs/code_review_report/generated/report.md - name: Generate Review Plan HTML with Pandoc shell: bash @@ -549,14 +574,14 @@ jobs: --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/code_review_plan/plan.html + --output docs/code_review_plan/generated/plan.html - name: Generate Review Plan PDF with WeasyPrint run: > dotnet weasyprint --pdf-variant pdf/a-3u - docs/code_review_plan/plan.html - "docs/NuGetCaching Review Plan.pdf" + docs/code_review_plan/generated/plan.html + "docs/generated/NuGetCaching Review Plan.pdf" - name: Generate Review Report HTML with Pandoc shell: bash @@ -566,14 +591,14 @@ jobs: --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/code_review_report/report.html + --output docs/code_review_report/generated/report.html - name: Generate Review Report PDF with WeasyPrint run: > dotnet weasyprint --pdf-variant pdf/a-3u - docs/code_review_report/report.html - "docs/NuGetCaching Review Report.pdf" + docs/code_review_report/generated/report.html + "docs/generated/NuGetCaching Review Report.pdf" - name: Assert Code Review Documents with FileAssert run: > @@ -586,6 +611,10 @@ jobs: # FileAssert validates that the HTML and PDF outputs contain expected content. # Downstream projects: Add any additional design document steps here. + - name: Create design output directory + shell: bash + run: mkdir -p docs/design/generated + - name: Generate Design HTML with Pandoc shell: bash run: > @@ -594,14 +623,14 @@ jobs: --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/design/design.html + --output docs/design/generated/design.html - name: Generate Design PDF with WeasyPrint run: > dotnet weasyprint --pdf-variant pdf/a-3u - docs/design/design.html - "docs/NuGetCaching Software Design.pdf" + docs/design/generated/design.html + "docs/generated/NuGetCaching Software Design.pdf" - name: Assert Design Documents with FileAssert run: > @@ -609,11 +638,47 @@ jobs: --results artifacts/fileassert-design.trx design + # === COMPILE VERIFICATION DOCUMENT === + # This section generates the Verification Design document using Pandoc and WeasyPrint. + # FileAssert validates that the HTML and PDF outputs contain expected content. + # Downstream projects: Add any additional verification document steps here. + + - name: Create verification output directory + shell: bash + run: mkdir -p docs/verification/generated + + - name: Generate Verification HTML with Pandoc + shell: bash + run: > + dotnet pandoc + --defaults docs/verification/definition.yaml + --filter node_modules/.bin/mermaid-filter.cmd + --metadata version="${{ inputs.version }}" + --metadata date="$(date +'%Y-%m-%d')" + --output docs/verification/generated/verification.html + + - name: Generate Verification PDF with WeasyPrint + run: > + dotnet weasyprint + --pdf-variant pdf/a-3u + docs/verification/generated/verification.html + "docs/generated/NuGetCaching Verification Design.pdf" + + - name: Assert Verification Documents with FileAssert + run: > + dotnet fileassert + --results artifacts/fileassert-verification.trx + verification + # === COMPILE USER GUIDE === # This section generates the User Guide document using Pandoc and WeasyPrint. # FileAssert validates that the HTML and PDF outputs contain expected content. # Downstream projects: Add any additional user guide steps here. + - name: Create user guide output directory + shell: bash + run: mkdir -p docs/user_guide/generated + - name: Generate User Guide HTML with Pandoc shell: bash run: > @@ -622,14 +687,14 @@ jobs: --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/user_guide/user_guide.html + --output docs/user_guide/generated/user_guide.html - name: Generate User Guide PDF with WeasyPrint run: > dotnet weasyprint --pdf-variant pdf/a-3u - docs/user_guide/user_guide.html - "docs/NuGetCaching User Guide.pdf" + docs/user_guide/generated/user_guide.html + "docs/generated/NuGetCaching User Guide.pdf" - name: Assert User Guide Documents with FileAssert run: > @@ -638,8 +703,8 @@ jobs: user-guide # === FILEASSERT SELF-VALIDATION === - # By this point Pandoc and WeasyPrint have each produced 6 validated documents - # (Build Notes, Code Quality, Review Plan, Review Report, Design, User Guide), + # By this point Pandoc and WeasyPrint have each produced 7 validated documents + # (Build Notes, Code Quality, Review Plan, Review Report, Design, Verification, User Guide), # providing strong OTS evidence for both tools before ReqStream runs. FileAssert # self-validation confirms the assertion tool itself is operational. # Downstream projects: Add any additional FileAssert self-validation steps here. @@ -659,6 +724,10 @@ jobs: # confirm the requirements pipeline produced well-formed documents. # Downstream projects: Add any additional requirements steps here. + - name: Create requirements output directories + shell: bash + run: mkdir -p docs/requirements_doc/generated docs/requirements_report/generated + - name: Run ReqStream self-validation run: > dotnet reqstream @@ -670,9 +739,9 @@ jobs: dotnet reqstream --requirements requirements.yaml --tests "artifacts/**/*.trx" - --report docs/requirements_doc/requirements.md - --justifications docs/requirements_doc/justifications.md - --matrix docs/requirements_report/trace_matrix.md + --report docs/requirements_doc/generated/requirements.md + --justifications docs/requirements_doc/generated/justifications.md + --matrix docs/requirements_report/generated/trace_matrix.md --enforce - name: Generate Requirements HTML with Pandoc @@ -683,14 +752,14 @@ jobs: --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/requirements_doc/requirements.html + --output docs/requirements_doc/generated/requirements.html - name: Generate Requirements PDF with WeasyPrint run: > dotnet weasyprint --pdf-variant pdf/a-3u - docs/requirements_doc/requirements.html - "docs/NuGetCaching Requirements.pdf" + docs/requirements_doc/generated/requirements.html + "docs/generated/NuGetCaching Requirements.pdf" - name: Generate Trace Matrix HTML with Pandoc shell: bash @@ -700,14 +769,14 @@ jobs: --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/requirements_report/trace_matrix.html + --output docs/requirements_report/generated/trace_matrix.html - name: Generate Trace Matrix PDF with WeasyPrint run: > dotnet weasyprint --pdf-variant pdf/a-3u - docs/requirements_report/trace_matrix.html - "docs/NuGetCaching Trace Matrix.pdf" + docs/requirements_report/generated/trace_matrix.html + "docs/generated/NuGetCaching Trace Matrix.pdf" - name: Assert Requirements Documents with FileAssert run: > @@ -723,6 +792,4 @@ jobs: uses: actions/upload-artifact@v7 with: name: documents - path: |- - docs/*.pdf - docs/build_notes.md + path: docs/generated/* diff --git a/.reviewmark.yaml b/.reviewmark.yaml index 22ffcb3..9558402 100644 --- a/.reviewmark.yaml +++ b/.reviewmark.yaml @@ -11,6 +11,7 @@ needs-review: - "**/*.cs" # All C# source and test files - "docs/reqstream/**/*.yaml" # Requirements files - "docs/design/**/*.md" # Design documentation files + - "docs/verification/**/*.md" # Verification documentation files - "docs/user_guide/**/*.md" # User guide documentation - "!**/obj/**" # Exclude build output - "!**/bin/**" # Exclude build output @@ -28,6 +29,7 @@ evidence-source: # Review sets following hierarchical scope principles. # Each review-set focuses on a single compliance question with manageable file counts. reviews: + # Purpose - id: Purpose title: Review that Advertised Features Match System Design paths: @@ -37,12 +39,14 @@ reviews: - "docs/design/introduction.md" - "docs/design/nuget-caching/nuget-caching.md" + # NuGetCaching - Specials - id: NuGetCaching-Architecture title: Review that NuGetCaching Architecture Satisfies Requirements paths: - "docs/reqstream/nuget-caching/nuget-caching.yaml" - "docs/design/introduction.md" - "docs/design/nuget-caching/nuget-caching.md" + - "docs/verification/nuget-caching/nuget-caching.md" - "test/DemaConsulting.NuGet.Caching.Tests/NuGetCachingTests.cs" - id: NuGetCaching-Design @@ -52,6 +56,7 @@ reviews: - "docs/reqstream/nuget-caching/platform-requirements.yaml" - "docs/design/introduction.md" - "docs/design/nuget-caching/**/*.md" + - "docs/verification/introduction.md" - id: NuGetCaching-AllRequirements title: Review that All NuGetCaching Requirements are Complete @@ -60,18 +65,83 @@ reviews: - "docs/reqstream/nuget-caching/**/*.yaml" - "docs/reqstream/ots/**/*.yaml" + # NuGetCaching - NuGetCache - id: NuGetCaching-NuGetCache title: Review that NuGetCaching NuGetCache Implementation is Correct paths: - "docs/reqstream/nuget-caching/nuget-cache.yaml" - "docs/design/nuget-caching/nuget-cache.md" + - "docs/verification/nuget-caching/nuget-cache.md" - "src/DemaConsulting.NuGet.Caching/NuGetCache.cs" - "test/DemaConsulting.NuGet.Caching.Tests/NuGetCacheTests.cs" + # NuGetCaching - PathHelpers - id: NuGetCaching-PathHelpers title: Review that NuGetCaching PathHelpers Implementation is Correct paths: - "docs/reqstream/nuget-caching/path-helpers.yaml" - "docs/design/nuget-caching/path-helpers.md" + - "docs/verification/nuget-caching/path-helpers.md" - "src/DemaConsulting.NuGet.Caching/PathHelpers.cs" - "test/DemaConsulting.NuGet.Caching.Tests/PathHelpersTests.cs" + + # OTS Items + - id: OTS-BuildMark + title: Review of BuildMark OTS verification evidence + paths: + - "docs/reqstream/ots/buildmark.yaml" + - "docs/verification/ots/buildmark.md" + + - id: OTS-FileAssert + title: Review of FileAssert OTS verification evidence + paths: + - "docs/reqstream/ots/fileassert.yaml" + - "docs/verification/ots/fileassert.md" + + - id: OTS-Pandoc + title: Review of Pandoc OTS verification evidence + paths: + - "docs/reqstream/ots/pandoc.yaml" + - "docs/verification/ots/pandoc.md" + + - id: OTS-ReqStream + title: Review of ReqStream OTS verification evidence + paths: + - "docs/reqstream/ots/reqstream.yaml" + - "docs/verification/ots/reqstream.md" + + - id: OTS-ReviewMark + title: Review of ReviewMark OTS verification evidence + paths: + - "docs/reqstream/ots/reviewmark.yaml" + - "docs/verification/ots/reviewmark.md" + + - id: OTS-SarifMark + title: Review of SarifMark OTS verification evidence + paths: + - "docs/reqstream/ots/sarifmark.yaml" + - "docs/verification/ots/sarifmark.md" + + - id: OTS-SonarMark + title: Review of SonarMark OTS verification evidence + paths: + - "docs/reqstream/ots/sonarmark.yaml" + - "docs/verification/ots/sonarmark.md" + + - id: OTS-VersionMark + title: Review of VersionMark OTS verification evidence + paths: + - "docs/reqstream/ots/versionmark.yaml" + - "docs/verification/ots/versionmark.md" + + - id: OTS-WeasyPrint + title: Review of WeasyPrint OTS verification evidence + paths: + - "docs/reqstream/ots/weasyprint.yaml" + - "docs/verification/ots/weasyprint.md" + + - id: OTS-xUnit + title: Review of xUnit OTS verification evidence + paths: + - "docs/reqstream/ots/xunit.yaml" + - "docs/verification/ots/xunit.md" diff --git a/AGENTS.md b/AGENTS.md index 974cc23..2d88e59 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,3 +1,10 @@ +# Project Overview + +- **name**: DemaConsulting NuGet Caching +- **description**: A library for caching NuGet packages on the local PC +- **languages**: C# +- **technologies**: .NET (netstandard2.0, net8.0, net9.0, net10.0), NuGet.Protocol, NuGet.Configuration + # Project Structure ```text @@ -10,7 +17,8 @@ │ ├── requirements_doc/ │ ├── requirements_report/ │ ├── reqstream/ -│ └── user_guide/ +│ ├── user_guide/ +│ └── verification/ ├── src/ │ └── DemaConsulting.NuGet.Caching/ └── test/ @@ -45,16 +53,17 @@ before searching the filesystem. Before performing any work, agents must read and apply the relevant standards from `.github/standards/`. Use this matrix to determine which to load: -| Work involves... | Load these standards | -|----------------------|------------------------------------------------------------------------------| -| Any code | `coding-principles.md` | -| C# code | `coding-principles.md`, `csharp-language.md` | -| Any tests | `testing-principles.md` | -| C# tests | `testing-principles.md`, `csharp-testing.md` | -| Requirements | `requirements-principles.md`, `software-items.md`, `reqstream-usage.md` | -| Design docs | `software-items.md`, `design-documentation.md`, `technical-documentation.md` | -| Review configuration | `software-items.md`, `reviewmark-usage.md` | -| Any documentation | `technical-documentation.md` | +| Work involves... | Load these standards | +|----------------------|------------------------------------------------------------------------------------| +| Any code | `coding-principles.md` | +| C# code | `coding-principles.md`, `csharp-language.md` | +| Any tests | `testing-principles.md` | +| C# tests | `testing-principles.md`, `csharp-testing.md` | +| Requirements | `requirements-principles.md`, `software-items.md`, `reqstream-usage.md` | +| Design docs | `software-items.md`, `design-documentation.md`, `technical-documentation.md` | +| Verification docs | `software-items.md`, `verification-documentation.md`, `technical-documentation.md` | +| Review configuration | `software-items.md`, `reviewmark-usage.md` | +| Any documentation | `technical-documentation.md` | Load only the standards relevant to your specific task scope. @@ -69,26 +78,10 @@ Delegate to specialized agents only for specific scenarios: - **Formal feature implementation** (complex, multi-step) → Call the implementation agent - **Formal bug resolution** (complex debugging, systematic fixes) → Call the implementation agent - **Formal reviews** (compliance verification, detailed analysis) → Call the formal-review agent -- **Template consistency** (downstream repository alignment) → Call the repo-consistency agent - -## Available Specialized Agents - -- **lint-fix** - Pre-PR lint sweep agent that loops running `pwsh ./lint.ps1`, - fixing issues until the repository is lint-clean -- **developer** - General-purpose software development agent that applies appropriate - standards based on the work being performed -- **formal-review** - Agent for performing formal reviews using standardized review processes -- **implementation** - Orchestrator agent that manages quality implementations - through a formal state machine workflow -- **quality** - Quality assurance agent that grades developer work against project - standards and Continuous Compliance practices -- **repo-consistency** - Ensures downstream repositories remain consistent with - the TemplateDotNetLibrary template patterns and best practices # Agent Reporting (Specialized Agents Must Follow) -Specialized agents (lint-fix, developer, quality, implementation, -formal-review, repo-consistency) MUST generate a completion report: +Specialized agents MUST generate a completion report: 1. Save to `.agent-logs/{agent-name}-{subject}-{unique-id}.md` where `{subject}` is a kebab-case task summary (max 5 words) and @@ -124,6 +117,8 @@ reqstream, versionmark, and reviewmark. # Scope Discipline (ALL Agents Must Follow) +- **No generated file access**: Files inside any `generated/` folder are build + outputs — do not read, lint, or modify them - **Minimum necessary changes**: Only modify files directly required by the task - **No speculative refactoring**: Do not refactor code adjacent to the change unless the task explicitly requests it diff --git a/docs/build_notes/definition.yaml b/docs/build_notes/definition.yaml index 207a375..ba1360b 100644 --- a/docs/build_notes/definition.yaml +++ b/docs/build_notes/definition.yaml @@ -5,8 +5,8 @@ resource-path: input-files: - docs/build_notes/title.txt - docs/build_notes/introduction.md - - docs/build_notes.md - - docs/build_notes/versions.md + - docs/build_notes/generated/build_notes.md + - docs/build_notes/generated/versions.md template: template.html table-of-contents: true number-sections: true diff --git a/docs/code_quality/definition.yaml b/docs/code_quality/definition.yaml index 68c58f2..fed5f02 100644 --- a/docs/code_quality/definition.yaml +++ b/docs/code_quality/definition.yaml @@ -5,8 +5,8 @@ resource-path: input-files: - docs/code_quality/title.txt - docs/code_quality/introduction.md - - docs/code_quality/codeql-quality.md - - docs/code_quality/sonar-quality.md + - docs/code_quality/generated/codeql-quality.md + - docs/code_quality/generated/sonar-quality.md template: template.html table-of-contents: true number-sections: true diff --git a/docs/code_review_plan/definition.yaml b/docs/code_review_plan/definition.yaml index 3a24f0b..56989bf 100644 --- a/docs/code_review_plan/definition.yaml +++ b/docs/code_review_plan/definition.yaml @@ -5,7 +5,7 @@ resource-path: input-files: - docs/code_review_plan/title.txt - docs/code_review_plan/introduction.md - - docs/code_review_plan/plan.md + - docs/code_review_plan/generated/plan.md template: template.html table-of-contents: true number-sections: true diff --git a/docs/code_review_report/definition.yaml b/docs/code_review_report/definition.yaml index 6498e6c..b238d43 100644 --- a/docs/code_review_report/definition.yaml +++ b/docs/code_review_report/definition.yaml @@ -5,7 +5,7 @@ resource-path: input-files: - docs/code_review_report/title.txt - docs/code_review_report/introduction.md - - docs/code_review_report/report.md + - docs/code_review_report/generated/report.md template: template.html table-of-contents: true number-sections: true diff --git a/docs/reqstream/ots/mstest.yaml b/docs/reqstream/ots/mstest.yaml deleted file mode 100644 index 2bc8d4b..0000000 --- a/docs/reqstream/ots/mstest.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -# MSTest OTS Software Requirements -# -# Requirements for the MSTest testing framework functionality. - -sections: - - title: OTS Software Requirements - sections: - - title: MSTest Requirements - requirements: - - id: Caching-OTS-MSTest - title: MSTest shall execute unit tests and report results. - justification: | - The project's MSTest-based test stack uses MSTest.TestFramework, - MSTest.TestAdapter, and Microsoft.NET.Test.Sdk. Together they discover and run - all test methods and write TRX result files that feed into coverage reporting and - requirements traceability. Passing tests confirm the framework is functioning - correctly. - tags: [ots] - tests: - - NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFolder - - PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly diff --git a/docs/reqstream/ots/pandoc.yaml b/docs/reqstream/ots/pandoc.yaml index 035e963..07c86e8 100644 --- a/docs/reqstream/ots/pandoc.yaml +++ b/docs/reqstream/ots/pandoc.yaml @@ -23,4 +23,5 @@ sections: - Pandoc_ReviewPlanHtml - Pandoc_ReviewReportHtml - Pandoc_DesignHtml + - Pandoc_VerificationHtml - Pandoc_UserGuideHtml diff --git a/docs/reqstream/ots/weasyprint.yaml b/docs/reqstream/ots/weasyprint.yaml index aeba435..0f9104c 100644 --- a/docs/reqstream/ots/weasyprint.yaml +++ b/docs/reqstream/ots/weasyprint.yaml @@ -23,4 +23,5 @@ sections: - WeasyPrint_ReviewPlanPdf - WeasyPrint_ReviewReportPdf - WeasyPrint_DesignPdf + - WeasyPrint_VerificationPdf - WeasyPrint_UserGuidePdf diff --git a/docs/reqstream/ots/xunit.yaml b/docs/reqstream/ots/xunit.yaml new file mode 100644 index 0000000..f17dd3e --- /dev/null +++ b/docs/reqstream/ots/xunit.yaml @@ -0,0 +1,33 @@ +--- +# xUnit OTS Software Requirements +# +# Requirements for the xUnit v3 testing framework functionality. + +sections: + - title: OTS Software Requirements + sections: + - title: xUnit Requirements + requirements: + - id: Caching-OTS-xUnit-Execute + title: xUnit shall discover and execute unit tests. + justification: | + xUnit v3 (xunit.v3 and xunit.runner.visualstudio) is the unit-testing framework + used by the project. It discovers and runs all test methods, confirming the + framework is functioning correctly. + tags: [ots] + tests: + - NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFolder + - PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly + - NuGetCache_EnsureCachedAsync_NullPackageId_ThrowsArgumentNullException + + - id: Caching-OTS-xUnit-Report + title: xUnit shall write TRX result files. + justification: | + xUnit v3 (xunit.v3 and xunit.runner.visualstudio) writes TRX result files that + feed into coverage reporting and requirements traceability. Passing tests confirm + the TRX output is produced correctly. + tags: [ots] + tests: + - NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFolder + - PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly + - NuGetCache_EnsureCachedAsync_NullPackageId_ThrowsArgumentNullException diff --git a/docs/requirements_doc/definition.yaml b/docs/requirements_doc/definition.yaml index 0f4ccd2..628b789 100644 --- a/docs/requirements_doc/definition.yaml +++ b/docs/requirements_doc/definition.yaml @@ -5,8 +5,8 @@ resource-path: input-files: - docs/requirements_doc/title.txt - docs/requirements_doc/introduction.md - - docs/requirements_doc/requirements.md - - docs/requirements_doc/justifications.md + - docs/requirements_doc/generated/requirements.md + - docs/requirements_doc/generated/justifications.md template: template.html table-of-contents: true number-sections: true diff --git a/docs/requirements_report/definition.yaml b/docs/requirements_report/definition.yaml index 918a645..9ee62a4 100644 --- a/docs/requirements_report/definition.yaml +++ b/docs/requirements_report/definition.yaml @@ -5,7 +5,7 @@ resource-path: input-files: - docs/requirements_report/title.txt - docs/requirements_report/introduction.md - - docs/requirements_report/trace_matrix.md + - docs/requirements_report/generated/trace_matrix.md template: template.html table-of-contents: true number-sections: true diff --git a/docs/verification/definition.yaml b/docs/verification/definition.yaml new file mode 100644 index 0000000..638d3a8 --- /dev/null +++ b/docs/verification/definition.yaml @@ -0,0 +1,26 @@ +--- +resource-path: + - docs/verification + - docs/verification/nuget-caching + - docs/verification/ots + - docs/template + +input-files: + - docs/verification/title.txt + - docs/verification/introduction.md + - docs/verification/nuget-caching/nuget-caching.md + - docs/verification/nuget-caching/nuget-cache.md + - docs/verification/nuget-caching/path-helpers.md + - docs/verification/ots/buildmark.md + - docs/verification/ots/fileassert.md + - docs/verification/ots/pandoc.md + - docs/verification/ots/reqstream.md + - docs/verification/ots/reviewmark.md + - docs/verification/ots/sarifmark.md + - docs/verification/ots/sonarmark.md + - docs/verification/ots/versionmark.md + - docs/verification/ots/weasyprint.md + - docs/verification/ots/xunit.md +template: template.html +table-of-contents: true +number-sections: true diff --git a/docs/verification/introduction.md b/docs/verification/introduction.md new file mode 100644 index 0000000..f1c21ad --- /dev/null +++ b/docs/verification/introduction.md @@ -0,0 +1,78 @@ +# Introduction + +This document provides the verification design for the DemaConsulting NuGet Caching library, a +.NET library for programmatic NuGet package caching. + +## Purpose + +The purpose of this document is to describe how each requirement for the NuGetCaching library is +verified. For every software item — system and unit — this document names the verification +approach, identifies the test scenarios (including boundary conditions and error paths), describes +what is mocked or stubbed, and maps each requirement to at least one named test scenario. The +document does not restate design; it explains how the design is proven correct. + +## Scope + +This document covers the verification design for the same software items described in the +*NuGetCaching Software Design Document*: + +- **NuGetCaching** — the system as a whole +- **NuGetCache** — the public API unit providing `EnsureCachedAsync` +- **PathHelpers** — the internal safe path-combination utility + +The following topics are out of scope: + +- Test infrastructure (xUnit framework, test helpers) +- Build pipeline and CI/CD configuration + +The following OTS items are also covered: + +- **BuildMark** — build-notes documentation tool +- **FileAssert** — document assertion tool +- **Pandoc** — Markdown-to-HTML conversion tool +- **ReqStream** — requirements traceability tool +- **ReviewMark** — file review enforcement tool +- **SarifMark** — SARIF report conversion tool +- **SonarMark** — SonarCloud quality report tool +- **VersionMark** — tool-version documentation tool +- **WeasyPrint** — HTML-to-PDF conversion tool +- **xUnit** — unit-testing framework + +## Software Structure + +The following tree shows the software items covered by this document: + +```text +NuGetCaching (System) +├── NuGetCache (Unit) +└── PathHelpers (Unit) + +OTS Items +├── BuildMark +├── FileAssert +├── Pandoc +├── ReqStream +├── ReviewMark +├── SarifMark +├── SonarMark +├── VersionMark +├── WeasyPrint +└── xUnit +``` + +## Companion Artifact Structure + +In-house items have corresponding artifacts in parallel directory trees: + +- Requirements: `docs/reqstream/{system}/.../{item}.yaml` (kebab-case) +- Design docs: `docs/design/{system}/.../{item}.md` (kebab-case) +- Verification design: `docs/verification/{system}/.../{item}.md` (kebab-case) +- Source code: `src/{System}/.../{Item}.cs` (PascalCase for C#) +- Tests: `test/{System}.Tests/.../{Item}Tests.cs` (PascalCase for C#) + +OTS items have parallel artifacts in: + +- Requirements: `docs/reqstream/ots/{ots-name}.yaml` (kebab-case) +- Verification: `docs/verification/ots/{ots-name}.md` (kebab-case) + +Review-sets: defined in `.reviewmark.yaml` diff --git a/docs/verification/nuget-caching/nuget-cache.md b/docs/verification/nuget-caching/nuget-cache.md new file mode 100644 index 0000000..12154a2 --- /dev/null +++ b/docs/verification/nuget-caching/nuget-cache.md @@ -0,0 +1,73 @@ +# NuGetCache Unit Verification + +This document provides the verification design for the `NuGetCache` unit. Requirements for this +unit are defined in the NuGetCache Unit Requirements document. + +## Required Functionality + +The `NuGetCache` unit shall ensure a specified NuGet package version is available in the local +cache, reject null arguments, and report an error when the requested package cannot be found in +any configured NuGet source. + +## Verification Approach + +Unit requirements are verified by tests that exercise `NuGetCache.EnsureCachedAsync` through its +full execution path, including network access for cache-miss scenarios. Each test scenario names a +specific test method that provides evidence for one or more unit requirements. + +## Test Scenarios + +### NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFolder + +**Scenario**: `EnsureCachedAsync` is called with a valid package ID and version. The package may +already be cached (cache hit) or may require downloading (cache miss). + +**Expected**: Returns a non-null absolute path to the cached package folder on disk. + +**Requirement coverage**: `Caching-NuGetCache-EnsureCached`. + +### NuGetCache_EnsureCachedAsync_CalledTwiceWithSamePackage_ReturnsSamePath + +**Scenario**: `EnsureCachedAsync` is called twice with the same package ID and version. The second +call exercises the early-exit cache-hit path via the `.nupkg.metadata` sentinel check. + +**Expected**: Both calls return the same non-null path, proving the early-exit path returns +consistent results. + +**Requirement coverage**: `Caching-NuGetCache-EnsureCached`. + +### NuGetCache_EnsureCachedAsync_NullPackageId_ThrowsArgumentNullException + +**Scenario**: `EnsureCachedAsync` is called with a null `packageId`. + +**Expected**: Throws `ArgumentNullException` with parameter name `packageId`. + +**Requirement coverage**: `Caching-NuGetCache-NullValidation`. + +### NuGetCache_EnsureCachedAsync_NullVersion_ThrowsArgumentNullException + +**Scenario**: `EnsureCachedAsync` is called with a null `version`. + +**Expected**: Throws `ArgumentNullException` with parameter name `version`. + +**Requirement coverage**: `Caching-NuGetCache-NullValidation`. + +### NuGetCache_EnsureCachedAsync_PackageAbsentFromAllSources_ThrowsInvalidOperationException + +**Scenario**: `EnsureCachedAsync` is called with a package ID and version that is not present in +any configured NuGet source. + +**Expected**: Throws `InvalidOperationException` with a message that identifies the package. + +**Requirement coverage**: `Caching-NuGetCache-NotFound`. + +## Requirements Coverage + +- **`Caching-NuGetCache-EnsureCached`**: + NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFolder, + NuGetCache_EnsureCachedAsync_CalledTwiceWithSamePackage_ReturnsSamePath +- **`Caching-NuGetCache-NullValidation`**: + NuGetCache_EnsureCachedAsync_NullPackageId_ThrowsArgumentNullException, + NuGetCache_EnsureCachedAsync_NullVersion_ThrowsArgumentNullException +- **`Caching-NuGetCache-NotFound`**: + NuGetCache_EnsureCachedAsync_PackageAbsentFromAllSources_ThrowsInvalidOperationException diff --git a/docs/verification/nuget-caching/nuget-caching.md b/docs/verification/nuget-caching/nuget-caching.md new file mode 100644 index 0000000..90090e6 --- /dev/null +++ b/docs/verification/nuget-caching/nuget-caching.md @@ -0,0 +1,63 @@ +# NuGetCaching System Verification + +This document provides the verification design for the NuGetCaching system — the DemaConsulting +NuGet Caching library as a whole. Requirements for this system are defined in the NuGetCaching +System Requirements document. + +## Required Functionality + +The NuGetCaching system shall provide a .NET library for programmatic NuGet package caching and +shall reject null arguments with a clear, actionable error. + +## Verification Approach + +System requirements are verified through integration-level tests that exercise the library through +its public API against real NuGet infrastructure. Each test scenario names a specific test method +that provides evidence for one or more system requirements. + +## Test Scenarios + +### NuGetCaching_EnsureCachedAsync_WhenKnownPackageAndVersionProvided_ReturnsPackageFolder + +**Scenario**: The system is called with a known package ID and version. The expected behavior is +that the package is cached locally and the absolute path to the cached folder is returned. + +**Expected**: `EnsureCachedAsync` returns a non-null path that exists on disk and ends with the +normalized package ID and version. + +**Requirement coverage**: `Caching-Sys-PackageCaching`. + +### NuGetCaching_EnsureCachedAsync_WhenPackageNotFound_ThrowsInvalidOperationException + +**Scenario**: The system is called with a package ID and version that cannot be found in any +configured NuGet source. + +**Expected**: `EnsureCachedAsync` throws `InvalidOperationException` with a message identifying +the package. + +**Requirement coverage**: `Caching-Sys-PackageCaching`. + +### NuGetCaching_EnsureCachedAsync_WhenPackageIdIsNull_ThrowsArgumentNullException + +**Scenario**: The system is called with a null package ID. + +**Expected**: `EnsureCachedAsync` throws `ArgumentNullException` identifying `packageId`. + +**Requirement coverage**: `Caching-Sys-NullValidation`. + +### NuGetCaching_EnsureCachedAsync_WhenVersionIsNull_ThrowsArgumentNullException + +**Scenario**: The system is called with a null version string. + +**Expected**: `EnsureCachedAsync` throws `ArgumentNullException` identifying `version`. + +**Requirement coverage**: `Caching-Sys-NullValidation`. + +## Requirements Coverage + +- **`Caching-Sys-PackageCaching`**: + NuGetCaching_EnsureCachedAsync_WhenKnownPackageAndVersionProvided_ReturnsPackageFolder, + NuGetCaching_EnsureCachedAsync_WhenPackageNotFound_ThrowsInvalidOperationException +- **`Caching-Sys-NullValidation`**: + NuGetCaching_EnsureCachedAsync_WhenPackageIdIsNull_ThrowsArgumentNullException, + NuGetCaching_EnsureCachedAsync_WhenVersionIsNull_ThrowsArgumentNullException diff --git a/docs/verification/nuget-caching/path-helpers.md b/docs/verification/nuget-caching/path-helpers.md new file mode 100644 index 0000000..1be44f9 --- /dev/null +++ b/docs/verification/nuget-caching/path-helpers.md @@ -0,0 +1,135 @@ +# PathHelpers Unit Verification + +This document provides the verification design for the `PathHelpers` unit. Requirements for this +unit are defined in the PathHelpers Unit Requirements document. + +## Required Functionality + +The `PathHelpers` unit shall safely combine a base path and a relative path, rejecting any +combination that would escape the base directory. + +## Verification Approach + +Unit requirements are verified by tests that exercise `PathHelpers.SafePathCombine` across a range +of valid and invalid input combinations. Each test scenario names a specific test method that +provides evidence for the unit requirement. + +## Test Scenarios + +### PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly + +**Scenario**: `SafePathCombine` is called with a valid base path and a valid relative path that +stays within the base. + +**Expected**: Returns the correctly combined path without throwing. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +### PathHelpers_SafePathCombine_PathTraversalWithDoubleDots_ThrowsArgumentException + +**Scenario**: `SafePathCombine` is called with a relative path of `..` that would escape the base +directory. + +**Expected**: Throws `ArgumentException`. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +### PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentException + +**Scenario**: `SafePathCombine` is called with a relative path containing an embedded `../` that +would escape the base directory. + +**Expected**: Throws `ArgumentException`. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +### PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException + +**Scenario**: `SafePathCombine` is called with an absolute path as the relative component. + +**Expected**: Throws `ArgumentException` because an absolute path escapes the base directory. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +### PathHelpers_SafePathCombine_DotDotPrefixedName_CombinesCorrectly + +**Scenario**: `SafePathCombine` is called with a relative path whose name starts with `..` but +does not perform traversal (e.g., `..data`). + +**Expected**: Returns the correctly combined path without throwing, confirming no false positive. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +### PathHelpers_SafePathCombine_NestedPaths_CombinesCorrectly + +**Scenario**: `SafePathCombine` is called with a relative path containing nested subdirectories +that stay within the base. + +**Expected**: Returns the correctly combined path without throwing. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +### PathHelpers_SafePathCombine_SimpleFilename_CombinesCorrectly + +**Scenario**: `SafePathCombine` is called with a simple filename as the relative component. + +**Expected**: Returns the correctly combined path without throwing. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +### PathHelpers_SafePathCombine_GuidBasedFilename_CombinesSuccessfully + +**Scenario**: `SafePathCombine` is called with a GUID-format filename as the relative component. + +**Expected**: Returns the correctly combined path without throwing. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +### PathHelpers_SafePathCombine_EmptyRelativePath_ReturnsBasePath + +**Scenario**: `SafePathCombine` is called with an empty string as the relative component. + +**Expected**: Returns the base path without throwing. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +### PathHelpers_SafePathCombine_CurrentDirectoryReference_CombinesCorrectly + +**Scenario**: `SafePathCombine` is called with `.` or a path starting with `./` as the relative +component. + +**Expected**: Returns the correctly combined path without throwing. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +### PathHelpers_SafePathCombine_NullBasePath_ThrowsArgumentNullException + +**Scenario**: `SafePathCombine` is called with a null base path. + +**Expected**: Throws `ArgumentNullException` with parameter name `basePath`. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +### PathHelpers_SafePathCombine_NullRelativePath_ThrowsArgumentNullException + +**Scenario**: `SafePathCombine` is called with a null relative path. + +**Expected**: Throws `ArgumentNullException` with parameter name `relativePath`. + +**Requirement coverage**: `Caching-PathHelpers-SafeCombine`. + +## Requirements Coverage + +- **`Caching-PathHelpers-SafeCombine`**: + PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly, + PathHelpers_SafePathCombine_PathTraversalWithDoubleDots_ThrowsArgumentException, + PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentException, + PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException, + PathHelpers_SafePathCombine_DotDotPrefixedName_CombinesCorrectly, + PathHelpers_SafePathCombine_NestedPaths_CombinesCorrectly, + PathHelpers_SafePathCombine_SimpleFilename_CombinesCorrectly, + PathHelpers_SafePathCombine_GuidBasedFilename_CombinesSuccessfully, + PathHelpers_SafePathCombine_EmptyRelativePath_ReturnsBasePath, + PathHelpers_SafePathCombine_CurrentDirectoryReference_CombinesCorrectly, + PathHelpers_SafePathCombine_NullBasePath_ThrowsArgumentNullException, + PathHelpers_SafePathCombine_NullRelativePath_ThrowsArgumentNullException diff --git a/docs/verification/ots/buildmark.md b/docs/verification/ots/buildmark.md new file mode 100644 index 0000000..3fc3cc2 --- /dev/null +++ b/docs/verification/ots/buildmark.md @@ -0,0 +1,72 @@ +# BuildMark Verification + +This document provides the verification evidence for the `BuildMark` OTS software item. + +## Required Functionality + +DemaConsulting.BuildMark queries the GitHub API to capture workflow run details and renders them as +a markdown build-notes document included in the release artifacts. It runs as part of the same CI +pipeline that produces the TRX test results, so a successful pipeline run is evidence that BuildMark +executed without error. + +## Verification Approach + +BuildMark is verified by two complementary layers of evidence. First, the CI pipeline runs +`buildmark --validate --results artifacts/buildmark-self-validation.trx`, which exercises +BuildMark's built-in self-validation suite against mock data and records results for ReqStream. + +Second, the pipeline invokes BuildMark with live GitHub Actions metadata to generate +`docs/build_notes/generated/build_notes.md`. Pandoc then converts this file to HTML; if the +file were absent or malformed, Pandoc would fail. WeasyPrint renders the HTML to a PDF/A +artifact, and FileAssert asserts the PDF exists, has content, and contains expected text +(`WeasyPrint_BuildNotesPdf`). A CI build failure at any step in this chain is evidence that +BuildMark did not produce the required output. + +## Test Scenarios + +### BuildMark_MarkdownReportGeneration + +**Scenario**: A CI pipeline run triggers BuildMark with live GitHub Actions metadata. + +**Expected**: BuildMark exits without error and produces a non-empty markdown build-notes document +in the release artifacts. + +**Requirement coverage**: `Caching-OTS-BuildMark`. + +### BuildMark_GitIntegration + +**Scenario**: BuildMark self-validation reads version tags and commits from a mock Git history. + +**Expected**: Exits 0 and correctly reads version tags and commit history. + +**Requirement coverage**: `Caching-OTS-BuildMark`. + +### BuildMark_IssueTracking + +**Scenario**: BuildMark self-validation processes mock GitHub issues and pull requests. + +**Expected**: Exits 0 and correctly fetches and processes mock issues and pull requests. + +**Requirement coverage**: `Caching-OTS-BuildMark`. + +### BuildMark_KnownIssuesReporting + +**Scenario**: BuildMark self-validation includes open bugs in the generated report when requested. + +**Expected**: Exits 0 and correctly includes known issues. + +**Requirement coverage**: `Caching-OTS-BuildMark`. + +### BuildMark_RulesRouting + +**Scenario**: BuildMark self-validation assigns mock items to report sections based on label and +type rules. + +**Expected**: Exits 0 and correctly routes items to the expected sections. + +**Requirement coverage**: `Caching-OTS-BuildMark`. + +## Requirements Coverage + +- **`Caching-OTS-BuildMark`**: BuildMark_MarkdownReportGeneration, BuildMark_GitIntegration, + BuildMark_IssueTracking, BuildMark_KnownIssuesReporting, BuildMark_RulesRouting diff --git a/docs/verification/ots/fileassert.md b/docs/verification/ots/fileassert.md new file mode 100644 index 0000000..9126020 --- /dev/null +++ b/docs/verification/ots/fileassert.md @@ -0,0 +1,59 @@ +# FileAssert Verification + +This document provides the verification evidence for the FileAssert OTS software item. Requirements +for this OTS item are defined in the FileAssert OTS Software Requirements document. + +## Required Functionality + +DemaConsulting.FileAssert validates HTML and PDF documents produced during the build, asserting that +each document exists, has a non-trivial size, is structurally valid, and contains expected content. +It provides OTS evidence for Pandoc and WeasyPrint and independently confirms file assertion is +functioning. Self-validation proves the tool itself is operational before ReqStream consumes the +results. + +## Verification Approach + +FileAssert is verified by two complementary layers of evidence. First, the CI pipeline runs +`fileassert --validate --results artifacts/fileassert-self-validation.trx` after all documents +have been generated, exercising FileAssert's built-in self-validation suite and recording +functional test results for ReqStream. + +Second, FileAssert is used throughout the pipeline to validate every generated document before +ReqStream runs — Build Notes, Code Quality, Review Plan, Review Report, Design, Verification, +and User Guide. If FileAssert were non-functional, these validation steps would fail or produce +incorrect results, causing `reqstream --enforce` to report missing test coverage and fail the +build. A passing CI build therefore constitutes transitive evidence that FileAssert correctly +asserted document content at each stage of the pipeline. + +## Test Scenarios + +### FileAssert_Results + +**Scenario**: FileAssert self-validation exercises the `--results` option, generating TRX test +results containing both passing and failing outcomes. + +**Expected**: Writes a TRX results file with correctly classified pass and fail entries. + +**Requirement coverage**: `Caching-OTS-FileAssert`. + +### FileAssert_Exists + +**Scenario**: FileAssert self-validation exercises a test configuration using a glob pattern to +assert file existence. + +**Expected**: Passes when the specified file is present. + +**Requirement coverage**: `Caching-OTS-FileAssert`. + +### FileAssert_Contains + +**Scenario**: FileAssert self-validation exercises a test configuration using a `contains` assertion +to verify file content. + +**Expected**: Passes when the specified content is present. + +**Requirement coverage**: `Caching-OTS-FileAssert`. + +## Requirements Coverage + +- **`Caching-OTS-FileAssert`**: FileAssert_Results, FileAssert_Exists, FileAssert_Contains diff --git a/docs/verification/ots/pandoc.md b/docs/verification/ots/pandoc.md new file mode 100644 index 0000000..0ce988d --- /dev/null +++ b/docs/verification/ots/pandoc.md @@ -0,0 +1,86 @@ +# Pandoc Verification + +This document provides the verification evidence for the `Pandoc` OTS software item. + +## Required Functionality + +DemaConsulting.PandocTool converts Markdown source documents to HTML as part of the documentation +build pipeline. FileAssert validates that each generated HTML file exists, has a non-trivial size, +contains a valid HTML title element, and includes expected document content. Passing FileAssert +assertions for each document type proves Pandoc executed correctly and produced meaningful output. + +## Verification Approach + +Pandoc is verified by self-validation evidence from the CI pipeline. Each scenario is a FileAssert +assertion that runs after Pandoc converts a specific Markdown document to HTML. A passing pipeline +run for all scenarios constitutes evidence that the requirement is satisfied. + +## Test Scenarios + +### Pandoc_BuildNotesHtml + +**Scenario**: FileAssert asserts the build-notes HTML file exists, is non-trivially sized, contains +a valid HTML title element, and includes expected document content. + +**Expected**: FileAssert exits 0 for the build-notes HTML document. + +**Requirement coverage**: `Caching-OTS-Pandoc`. + +### Pandoc_CodeQualityHtml + +**Scenario**: FileAssert asserts the code-quality HTML file exists, is non-trivially sized, contains +a valid HTML title element, and includes expected document content. + +**Expected**: FileAssert exits 0 for the code-quality HTML document. + +**Requirement coverage**: `Caching-OTS-Pandoc`. + +### Pandoc_ReviewPlanHtml + +**Scenario**: FileAssert asserts the review plan HTML file exists, is non-trivially sized, contains +a valid HTML title element, and includes expected document content. + +**Expected**: FileAssert exits 0 for the review plan HTML document. + +**Requirement coverage**: `Caching-OTS-Pandoc`. + +### Pandoc_ReviewReportHtml + +**Scenario**: FileAssert asserts the review report HTML file exists, is non-trivially sized, +contains a valid HTML title element, and includes expected document content. + +**Expected**: FileAssert exits 0 for the review report HTML document. + +**Requirement coverage**: `Caching-OTS-Pandoc`. + +### Pandoc_DesignHtml + +**Scenario**: FileAssert asserts the design document HTML file exists, is non-trivially sized, +contains a valid HTML title element, and includes expected document content. + +**Expected**: FileAssert exits 0 for the design document HTML. + +**Requirement coverage**: `Caching-OTS-Pandoc`. + +### Pandoc_VerificationHtml + +**Scenario**: FileAssert asserts the verification HTML file exists, is non-trivially sized, contains +a valid HTML title element, and includes expected verification document content. + +**Expected**: FileAssert exits 0 for the verification document. + +**Requirement coverage**: `Caching-OTS-Pandoc`. + +### Pandoc_UserGuideHtml + +**Scenario**: FileAssert asserts the user guide HTML file exists, is non-trivially sized, contains +a valid HTML title element, and includes expected document content. + +**Expected**: FileAssert exits 0 for the user guide HTML document. + +**Requirement coverage**: `Caching-OTS-Pandoc`. + +## Requirements Coverage + +- **`Caching-OTS-Pandoc`**: Pandoc_BuildNotesHtml, Pandoc_CodeQualityHtml, Pandoc_ReviewPlanHtml, + Pandoc_ReviewReportHtml, Pandoc_DesignHtml, Pandoc_VerificationHtml, Pandoc_UserGuideHtml diff --git a/docs/verification/ots/reqstream.md b/docs/verification/ots/reqstream.md new file mode 100644 index 0000000..1dc660d --- /dev/null +++ b/docs/verification/ots/reqstream.md @@ -0,0 +1,84 @@ +# ReqStream Verification + +This document provides the verification evidence for the `ReqStream` OTS software item. + +## Required Functionality + +DemaConsulting.ReqStream processes requirements.yaml and the TRX test-result files to produce a +requirements report, justifications document, and traceability matrix. When run with `--enforce`, it +exits with a non-zero code if any requirement lacks test evidence, making unproven requirements a +build-breaking condition. A successful pipeline run with `--enforce` proves all requirements are +covered and that ReqStream is functioning. + +## Verification Approach + +ReqStream is verified by two complementary layers of evidence. First, the CI pipeline runs +`reqstream --validate --results artifacts/reqstream-self-validation.trx`, which exercises +ReqStream's built-in self-validation suite against internal test requirements and records +results. + +Second, the pipeline invokes `reqstream --enforce` with `requirements.yaml` and all TRX +test-evidence files accumulated during the build. ReqStream generates `requirements.md`, +`justifications.md`, and `trace_matrix.md`. If ReqStream failed or produced no output, the +subsequent Pandoc step would fail, breaking the CI build. Additionally, `--enforce` exits +non-zero if any requirement lacks test evidence, which would also fail the build. A passing +CI build proves ReqStream correctly processed the project's real requirements and found +complete test coverage. + +## Test Scenarios + +### ReqStream_RequirementsProcessing + +**Scenario**: ReqStream self-validation loads and processes a set of requirements YAML files. + +**Expected**: Correctly loads and parses all requirements. + +**Requirement coverage**: `Caching-OTS-ReqStream`. + +### ReqStream_TraceMatrix + +**Scenario**: ReqStream self-validation generates a trace matrix from requirements and TRX test +results. + +**Expected**: Produces a correctly linked trace matrix. + +**Requirement coverage**: `Caching-OTS-ReqStream`. + +### ReqStream_ReportExport + +**Scenario**: ReqStream self-validation exports a requirements report to a markdown file. + +**Expected**: Produces a correctly formatted requirements report. + +**Requirement coverage**: `Caching-OTS-ReqStream`. + +### ReqStream_TagsFiltering + +**Scenario**: ReqStream self-validation filters requirements by tags. + +**Expected**: Returns only requirements matching the specified tags. + +**Requirement coverage**: `Caching-OTS-ReqStream`. + +### ReqStream_EnforcementMode + +**Scenario**: ReqStream self-validation exercises enforcement mode where all requirements have test +coverage. + +**Expected**: Exits 0; would exit non-zero if any requirement lacked coverage. + +**Requirement coverage**: `Caching-OTS-ReqStream`. + +### ReqStream_Lint + +**Scenario**: ReqStream self-validation exercises lint mode against a requirements file with +deliberate issues. + +**Expected**: Correctly identifies and reports the issues. + +**Requirement coverage**: `Caching-OTS-ReqStream`. + +## Requirements Coverage + +- **`Caching-OTS-ReqStream`**: ReqStream_RequirementsProcessing, ReqStream_TraceMatrix, + ReqStream_ReportExport, ReqStream_TagsFiltering, ReqStream_EnforcementMode, ReqStream_Lint diff --git a/docs/verification/ots/reviewmark.md b/docs/verification/ots/reviewmark.md new file mode 100644 index 0000000..9ae63fc --- /dev/null +++ b/docs/verification/ots/reviewmark.md @@ -0,0 +1,96 @@ +# ReviewMark Verification + +This document provides the verification evidence for the ReviewMark OTS software item. Requirements +for this OTS item are defined in the ReviewMark OTS Software Requirements document. + +## Required Functionality + +DemaConsulting.ReviewMark reads the `.reviewmark.yaml` configuration and the review evidence store +to produce a review plan and review report documenting file review coverage and currency. It runs in +the same CI pipeline that produces the TRX test results, so a successful pipeline run is evidence +that ReviewMark executed without error. + +## Verification Approach + +ReviewMark is verified by two complementary layers of evidence. First, the CI pipeline runs +`reviewmark --validate --results artifacts/reviewmark-self-validation.trx`, which exercises +ReviewMark's built-in self-validation suite against test review configurations and records +results for ReqStream. + +Second, the pipeline invokes ReviewMark to generate +`docs/code_review_plan/generated/plan.md` and `docs/code_review_report/generated/report.md`. +Pandoc converts each to HTML; if either file were absent or malformed, Pandoc would fail. +WeasyPrint renders both to PDF and FileAssert asserts their content +(`WeasyPrint_ReviewPlanPdf`, `WeasyPrint_ReviewReportPdf`). A CI build failure at any step is +evidence that ReviewMark did not produce the required review documents. + +## Test Scenarios + +### ReviewMark_ReviewPlanGeneration + +**Scenario**: ReviewMark self-validation uses `--definition` and `--plan` to generate a review plan +from a test configuration. + +**Expected**: Exits 0 and produces a non-empty review plan markdown file. + +**Requirement coverage**: `Caching-OTS-ReviewMark`. + +### ReviewMark_ReviewReportGeneration + +**Scenario**: ReviewMark self-validation uses `--definition` and `--report` to generate a review +report from a test configuration and evidence store. + +**Expected**: Exits 0 and produces a non-empty review report. + +**Requirement coverage**: `Caching-OTS-ReviewMark`. + +### ReviewMark_IndexScan + +**Scenario**: ReviewMark self-validation uses `--index` to scan PDF evidence files and write an +`index.json` catalogue. + +**Expected**: Exits 0 and produces a correctly structured `index.json`. + +**Requirement coverage**: `Caching-OTS-ReviewMark-Operations`. + +### ReviewMark_WorkingDirectoryOverride + +**Scenario**: ReviewMark self-validation uses `--dir` to override the working directory for file +operations. + +**Expected**: Exits 0 and resolves paths relative to the specified directory. + +**Requirement coverage**: `Caching-OTS-ReviewMark-Operations`. + +### ReviewMark_Enforce + +**Scenario**: ReviewMark self-validation uses `--enforce` against a configuration with review +issues. + +**Expected**: Exits with a non-zero exit code when review issues are present. + +**Requirement coverage**: `Caching-OTS-ReviewMark-Operations`. + +### ReviewMark_Elaborate + +**Scenario**: ReviewMark self-validation uses `--elaborate` to print a Markdown elaboration of a +named review set. + +**Expected**: Exits 0 and prints the review-set ID, fingerprint, and file list. + +**Requirement coverage**: `Caching-OTS-ReviewMark-Operations`. + +### ReviewMark_Lint + +**Scenario**: ReviewMark self-validation uses `--lint` to validate a definition file and report +issues. + +**Expected**: Correctly reports structural and semantic issues found in the test definition. + +**Requirement coverage**: `Caching-OTS-ReviewMark-Operations`. + +## Requirements Coverage + +- **`Caching-OTS-ReviewMark`**: ReviewMark_ReviewPlanGeneration, ReviewMark_ReviewReportGeneration +- **`Caching-OTS-ReviewMark-Operations`**: ReviewMark_IndexScan, ReviewMark_WorkingDirectoryOverride, + ReviewMark_Enforce, ReviewMark_Elaborate, ReviewMark_Lint diff --git a/docs/verification/ots/sarifmark.md b/docs/verification/ots/sarifmark.md new file mode 100644 index 0000000..897dbc6 --- /dev/null +++ b/docs/verification/ots/sarifmark.md @@ -0,0 +1,58 @@ +# SarifMark Verification + +This document provides the verification evidence for the SarifMark OTS software item. Requirements +for this OTS item are defined in the SarifMark OTS Software Requirements document. + +## Required Functionality + +DemaConsulting.SarifMark reads the SARIF output produced by CodeQL code scanning and renders it as +a human-readable markdown document included in the release artifacts. It runs in the same CI +pipeline that produces the TRX test results, so a successful pipeline run is evidence that SarifMark +executed without error. + +## Verification Approach + +SarifMark is verified by two complementary layers of evidence. First, the CI pipeline runs +`sarifmark --validate --results artifacts/sarifmark-self-validation.trx`, which exercises +SarifMark's built-in self-validation suite against mock SARIF data and records results for +ReqStream. + +Second, the pipeline invokes SarifMark with the CodeQL SARIF output to generate +`docs/code_quality/generated/codeql-quality.md`. Pandoc converts this file (along with the +SonarMark output) to HTML; if the file were absent or malformed, Pandoc would fail. WeasyPrint +renders the result to PDF and FileAssert asserts the PDF contains expected content +(`WeasyPrint_CodeQualityPdf`). A CI build failure at any step is evidence that SarifMark did +not produce the required output. + +## Test Scenarios + +### SarifMark_SarifReading + +**Scenario**: SarifMark is invoked with a CodeQL SARIF results file as input. + +**Expected**: Exits 0 and successfully reads the SARIF content. + +**Requirement coverage**: `Caching-OTS-SarifMark`. + +### SarifMark_MarkdownReportGeneration + +**Scenario**: SarifMark renders the SARIF input as a markdown report included in the release +artifacts. + +**Expected**: Exits 0 and produces a non-empty markdown report. + +**Requirement coverage**: `Caching-OTS-SarifMark`. + +### SarifMark_Enforcement + +**Scenario**: SarifMark self-validation processes a SARIF file containing known issues in +enforcement mode. + +**Expected**: Returns a non-zero exit code when issues are found. + +**Requirement coverage**: `Caching-OTS-SarifMark-Enforcement`. + +## Requirements Coverage + +- **`Caching-OTS-SarifMark`**: SarifMark_SarifReading, SarifMark_MarkdownReportGeneration +- **`Caching-OTS-SarifMark-Enforcement`**: SarifMark_Enforcement diff --git a/docs/verification/ots/sonarmark.md b/docs/verification/ots/sonarmark.md new file mode 100644 index 0000000..2f55275 --- /dev/null +++ b/docs/verification/ots/sonarmark.md @@ -0,0 +1,64 @@ +# SonarMark Verification + +This document provides the verification evidence for the SonarMark OTS software item. Requirements +for this OTS item are defined in the SonarMark OTS Software Requirements document. + +## Required Functionality + +DemaConsulting.SonarMark retrieves quality-gate and metrics data from SonarCloud and renders it as +a markdown document included in the release artifacts. It runs in the same CI pipeline that produces +the TRX test results, so a successful pipeline run is evidence that SonarMark executed without +error. + +## Verification Approach + +SonarMark is verified by two complementary layers of evidence. First, the CI pipeline runs +`sonarmark --validate --results artifacts/sonarmark-self-validation.trx`, which exercises +SonarMark's built-in self-validation suite against mock SonarCloud data and records results +for ReqStream. + +Second, the pipeline invokes SonarMark against the live SonarCloud API to generate +`docs/code_quality/generated/sonar-quality.md`. Pandoc converts this file (along with the +SarifMark output) to HTML; if the file were absent or malformed, Pandoc would fail. WeasyPrint +renders the result to PDF and FileAssert asserts the PDF contains expected content +(`WeasyPrint_CodeQualityPdf`). A CI build failure at any step is evidence that SonarMark did +not retrieve and render quality data correctly. + +## Test Scenarios + +### SonarMark_QualityGateRetrieval + +**Scenario**: SonarMark queries the SonarCloud API for quality-gate status. + +**Expected**: Exits 0 and retrieves quality-gate data. + +**Requirement coverage**: `Caching-OTS-SonarMark`. + +### SonarMark_IssuesRetrieval + +**Scenario**: SonarMark queries the SonarCloud API for issues. + +**Expected**: Exits 0 and retrieves issues data. + +**Requirement coverage**: `Caching-OTS-SonarMark`. + +### SonarMark_HotSpotsRetrieval + +**Scenario**: SonarMark queries the SonarCloud API for hot spots. + +**Expected**: Exits 0 and retrieves hot-spots data. + +**Requirement coverage**: `Caching-OTS-SonarMark`. + +### SonarMark_MarkdownReportGeneration + +**Scenario**: SonarMark renders quality-gate, issues, and hot-spots data as a markdown report. + +**Expected**: Exits 0 and produces a non-empty markdown quality report. + +**Requirement coverage**: `Caching-OTS-SonarMark`. + +## Requirements Coverage + +- **`Caching-OTS-SonarMark`**: SonarMark_QualityGateRetrieval, SonarMark_IssuesRetrieval, + SonarMark_HotSpotsRetrieval, SonarMark_MarkdownReportGeneration diff --git a/docs/verification/ots/versionmark.md b/docs/verification/ots/versionmark.md new file mode 100644 index 0000000..df24a9a --- /dev/null +++ b/docs/verification/ots/versionmark.md @@ -0,0 +1,65 @@ +# VersionMark Verification + +This document provides the verification evidence for the `VersionMark` OTS software item. + +## Required Functionality + +DemaConsulting.VersionMark reads version metadata for each dotnet tool used in the pipeline and +writes a versions markdown document included in the release artifacts. It runs in the same CI +pipeline that produces the TRX test results, so a successful pipeline run is evidence that +VersionMark executed without error. + +## Verification Approach + +VersionMark is verified by two complementary layers of evidence. First, the CI pipeline runs +`versionmark --validate --results *.trx` in each build job, exercising VersionMark's built-in +self-validation suite and recording results for ReqStream. + +Second, each CI job runs `versionmark --capture` to collect tool-version JSON files, and the +build-docs job runs `versionmark --publish` to produce +`docs/build_notes/generated/versions.md`. This file is included in the Build Notes document +compiled by Pandoc. If VersionMark failed to produce the versions document, the Build Notes +compilation would be incomplete. WeasyPrint renders the result to PDF and FileAssert asserts +its content (`WeasyPrint_BuildNotesPdf`). A CI build failure at any step is evidence that +VersionMark did not execute correctly. + +## Test Scenarios + +### VersionMark_CapturesVersions + +**Scenario**: VersionMark reads version metadata for each dotnet tool defined in the pipeline. + +**Expected**: Exits 0 and captures version data for every tool. + +**Requirement coverage**: `Caching-OTS-VersionMark`. + +### VersionMark_GeneratesMarkdownReport + +**Scenario**: VersionMark writes a versions markdown document to the release artifacts. + +**Expected**: Exits 0 and produces a non-empty versions markdown file. + +**Requirement coverage**: `Caching-OTS-VersionMark`. + +### VersionMark_LintPassesForValidConfig + +**Scenario**: VersionMark self-validation exercises lint mode against a valid `.versionmark.yaml` +config. + +**Expected**: Exits 0 and reports no errors. + +**Requirement coverage**: `Caching-OTS-VersionMark`. + +### VersionMark_LintReportsErrorsForInvalidConfig + +**Scenario**: VersionMark self-validation exercises lint mode against a malformed config with +deliberate errors. + +**Expected**: Correctly identifies and reports the configuration errors. + +**Requirement coverage**: `Caching-OTS-VersionMark`. + +## Requirements Coverage + +- **`Caching-OTS-VersionMark`**: VersionMark_CapturesVersions, VersionMark_GeneratesMarkdownReport, + VersionMark_LintPassesForValidConfig, VersionMark_LintReportsErrorsForInvalidConfig diff --git a/docs/verification/ots/weasyprint.md b/docs/verification/ots/weasyprint.md new file mode 100644 index 0000000..2c11f62 --- /dev/null +++ b/docs/verification/ots/weasyprint.md @@ -0,0 +1,89 @@ +# WeasyPrint Verification + +This document provides the verification evidence for the WeasyPrint OTS software item. Requirements +for this OTS item are defined in the WeasyPrint OTS Software Requirements document. + +## Required Functionality + +DemaConsulting.WeasyPrintTool converts HTML documents to PDF as part of the documentation build +pipeline. FileAssert validates that each generated PDF file exists, has a non-trivial size, contains +at least one page, and includes expected document content in the rendered text. Passing FileAssert +assertions for each document type proves WeasyPrint executed correctly and produced meaningful +output. + +## Verification Approach + +WeasyPrint is verified by self-validation evidence from the CI pipeline. Each scenario is a +FileAssert assertion that runs after WeasyPrint converts a specific HTML document to PDF. A passing +pipeline run for all scenarios constitutes evidence that the requirement is satisfied. + +## Test Scenarios + +### WeasyPrint_BuildNotesPdf + +**Scenario**: FileAssert asserts the build-notes PDF file exists, is non-trivially sized, contains +at least one page, and includes expected document content. + +**Expected**: FileAssert exits 0 for the build-notes PDF document. + +**Requirement coverage**: `Caching-OTS-WeasyPrint`. + +### WeasyPrint_CodeQualityPdf + +**Scenario**: FileAssert asserts the code-quality PDF file exists, is non-trivially sized, contains +at least one page, and includes expected document content. + +**Expected**: FileAssert exits 0 for the code-quality PDF document. + +**Requirement coverage**: `Caching-OTS-WeasyPrint`. + +### WeasyPrint_ReviewPlanPdf + +**Scenario**: FileAssert asserts the review plan PDF file exists, is non-trivially sized, contains +at least one page, and includes expected document content. + +**Expected**: FileAssert exits 0 for the review plan PDF document. + +**Requirement coverage**: `Caching-OTS-WeasyPrint`. + +### WeasyPrint_ReviewReportPdf + +**Scenario**: FileAssert asserts the review report PDF file exists, is non-trivially sized, contains +at least one page, and includes expected document content. + +**Expected**: FileAssert exits 0 for the review report PDF document. + +**Requirement coverage**: `Caching-OTS-WeasyPrint`. + +### WeasyPrint_DesignPdf + +**Scenario**: FileAssert asserts the design document PDF file exists, is non-trivially sized, +contains at least one page, and includes expected document content. + +**Expected**: FileAssert exits 0 for the design document PDF. + +**Requirement coverage**: `Caching-OTS-WeasyPrint`. + +### WeasyPrint_VerificationPdf + +**Scenario**: FileAssert asserts the verification PDF file exists, is non-trivially sized, contains +at least one page, and includes expected verification document content. + +**Expected**: FileAssert exits 0 for the verification PDF. + +**Requirement coverage**: `Caching-OTS-WeasyPrint`. + +### WeasyPrint_UserGuidePdf + +**Scenario**: FileAssert asserts the user guide PDF file exists, is non-trivially sized, contains +at least one page, and includes expected document content. + +**Expected**: FileAssert exits 0 for the user guide PDF document. + +**Requirement coverage**: `Caching-OTS-WeasyPrint`. + +## Requirements Coverage + +- **`Caching-OTS-WeasyPrint`**: WeasyPrint_BuildNotesPdf, WeasyPrint_CodeQualityPdf, + WeasyPrint_ReviewPlanPdf, WeasyPrint_ReviewReportPdf, WeasyPrint_DesignPdf, + WeasyPrint_VerificationPdf, WeasyPrint_UserGuidePdf diff --git a/docs/verification/ots/xunit.md b/docs/verification/ots/xunit.md new file mode 100644 index 0000000..bea4e46 --- /dev/null +++ b/docs/verification/ots/xunit.md @@ -0,0 +1,55 @@ +# xUnit Verification + +This document provides the verification evidence for the xUnit OTS software item. Requirements +for this OTS item are defined in the xUnit OTS Software Requirements document. + +## Required Functionality + +xUnit v3 (xunit.v3 and xunit.runner.visualstudio) is the unit-testing framework used by the +project. It discovers and runs all test methods and writes TRX result files that feed into coverage +reporting and requirements traceability. Passing tests confirm the framework is functioning +correctly. + +## Verification Approach + +xUnit is verified by self-validation evidence from the CI pipeline. Each scenario names a specific +test method that xUnit must discover, execute, and record in a TRX result file. A passing pipeline +run for all scenarios constitutes evidence that both requirements are satisfied. + +## Test Scenarios + +### NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFolder + +**Scenario**: xUnit discovers and runs this test; the test verifies that `EnsureCachedAsync` +returns a valid path when called with a known package ID and version. + +**Expected**: xUnit executes the test, the test passes, and the result appears in the TRX output. + +**Requirement coverage**: `Caching-OTS-xUnit-Execute`, `Caching-OTS-xUnit-Report`. + +### PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly + +**Scenario**: xUnit discovers and runs this test; the test verifies that `SafePathCombine` +correctly joins valid path segments. + +**Expected**: xUnit executes the test, the test passes, and the result appears in the TRX output. + +**Requirement coverage**: `Caching-OTS-xUnit-Execute`, `Caching-OTS-xUnit-Report`. + +### NuGetCache_EnsureCachedAsync_NullPackageId_ThrowsArgumentNullException + +**Scenario**: xUnit discovers and runs this test; the test verifies that a null package ID raises +`ArgumentNullException`. + +**Expected**: xUnit executes the test, the test passes, and the result appears in the TRX output. + +**Requirement coverage**: `Caching-OTS-xUnit-Execute`, `Caching-OTS-xUnit-Report`. + +## Requirements Coverage + +- **`Caching-OTS-xUnit-Execute`**: NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFolder, + PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly, + NuGetCache_EnsureCachedAsync_NullPackageId_ThrowsArgumentNullException +- **`Caching-OTS-xUnit-Report`**: NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFolder, + PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly, + NuGetCache_EnsureCachedAsync_NullPackageId_ThrowsArgumentNullException diff --git a/docs/verification/title.txt b/docs/verification/title.txt new file mode 100644 index 0000000..5fc8601 --- /dev/null +++ b/docs/verification/title.txt @@ -0,0 +1,14 @@ +--- +title: NuGetCaching Verification Design Document +subtitle: A .NET Library for Programmatic NuGet Package Caching +author: DEMA Consulting +description: Verification design document for NuGetCaching +lang: en-US +keywords: + - NuGetCaching + - .NET + - NuGet + - Library + - Verification + - Verification Design Document +--- diff --git a/requirements.yaml b/requirements.yaml index 9736c71..f56d672 100644 --- a/requirements.yaml +++ b/requirements.yaml @@ -25,7 +25,7 @@ includes: - docs/reqstream/nuget-caching/nuget-cache.yaml - docs/reqstream/nuget-caching/path-helpers.yaml - docs/reqstream/ots/nuget.yaml - - docs/reqstream/ots/mstest.yaml + - docs/reqstream/ots/xunit.yaml - docs/reqstream/ots/reqstream.yaml - docs/reqstream/ots/buildmark.yaml - docs/reqstream/ots/versionmark.yaml diff --git a/test/DemaConsulting.NuGet.Caching.Tests/DemaConsulting.NuGet.Caching.Tests.csproj b/test/DemaConsulting.NuGet.Caching.Tests/DemaConsulting.NuGet.Caching.Tests.csproj index db8d2cf..c91052a 100644 --- a/test/DemaConsulting.NuGet.Caching.Tests/DemaConsulting.NuGet.Caching.Tests.csproj +++ b/test/DemaConsulting.NuGet.Caching.Tests/DemaConsulting.NuGet.Caching.Tests.csproj @@ -2,6 +2,7 @@ + Exe net481;net8.0;net9.0;net10.0 net8.0;net9.0;net10.0 latest @@ -19,6 +20,12 @@ latest + + + + + + @@ -56,9 +66,4 @@ - - - - - diff --git a/test/DemaConsulting.NuGet.Caching.Tests/NuGetCacheTests.cs b/test/DemaConsulting.NuGet.Caching.Tests/NuGetCacheTests.cs index f37f8c2..c2440b6 100644 --- a/test/DemaConsulting.NuGet.Caching.Tests/NuGetCacheTests.cs +++ b/test/DemaConsulting.NuGet.Caching.Tests/NuGetCacheTests.cs @@ -23,14 +23,8 @@ namespace DemaConsulting.NuGet.Caching.Tests; /// /// Unit tests for the class. /// -[TestClass] public class NuGetCacheTests { - /// - /// Gets or sets the test context provided by the MSTest framework before each test runs. - /// - public TestContext TestContext { get; set; } = null!; - /// /// Tests that returns the path to an existing /// package folder after downloading a known small package from nuget.org. @@ -38,8 +32,8 @@ public class NuGetCacheTests /// /// This test proves Caching-NuGetCache-EnsureCached: the library can ensure a NuGet package is cached locally. /// - [TestMethod] - [TestCategory("Integration")] + [Fact] + [Trait("Category", "Integration")] public async Task NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFolder() { // Arrange - use a small, known package that is reliably available on nuget.org @@ -47,11 +41,11 @@ public async Task NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFold const string version = "1.5.0"; // Act - ensure the package is present in the local NuGet global packages cache - var packageFolder = await NuGetCache.EnsureCachedAsync(packageId, version, TestContext.CancellationToken); + var packageFolder = await NuGetCache.EnsureCachedAsync(packageId, version, CancellationToken.None); // Assert - the returned path must point to a real directory on disk - Assert.IsNotNull(packageFolder, "EnsureCachedAsync should not return null"); - Assert.IsTrue( + Assert.NotNull(packageFolder); + Assert.True( Directory.Exists(packageFolder), $"Expected package folder to exist at: {packageFolder}"); @@ -61,7 +55,7 @@ public async Task NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFold Directory.EnumerateFiles(packageFolder, "*.nupkg", SearchOption.AllDirectories).Any() || Directory.EnumerateFiles(packageFolder, "*.nuspec", SearchOption.AllDirectories).Any(); - Assert.IsTrue( + Assert.True( hasPackageContent, $"Expected package folder to contain .nupkg or .nuspec files at: {packageFolder}"); } @@ -73,8 +67,8 @@ public async Task NuGetCache_EnsureCachedAsync_ValidPackageId_ReturnsPackageFold /// /// This test proves Caching-NuGetCache-NotFound: the library reports when a package cannot be found. /// - [TestMethod] - [TestCategory("Integration")] + [Fact] + [Trait("Category", "Integration")] public async Task NuGetCache_EnsureCachedAsync_PackageAbsentFromAllSources_ThrowsInvalidOperationException() { // Arrange - use a GUID-based package ID that cannot exist on any NuGet feed @@ -82,8 +76,8 @@ public async Task NuGetCache_EnsureCachedAsync_PackageAbsentFromAllSources_Throw const string version = "1.0.0"; // Act & Assert - calling with a non-existent package must throw InvalidOperationException - _ = await Assert.ThrowsExactlyAsync( - async () => await NuGetCache.EnsureCachedAsync(packageId, version, TestContext.CancellationToken)); + _ = await Assert.ThrowsAsync( + async () => await NuGetCache.EnsureCachedAsync(packageId, version, CancellationToken.None)); } /// @@ -94,15 +88,15 @@ public async Task NuGetCache_EnsureCachedAsync_PackageAbsentFromAllSources_Throw /// This test proves Caching-NuGetCache-NullValidation: the library validates input parameters /// and throws for null arguments. /// - [TestMethod] + [Fact] public async Task NuGetCache_EnsureCachedAsync_NullPackageId_ThrowsArgumentNullException() { // Arrange - null packageId is an invalid argument const string version = "1.5.0"; // Act & Assert - calling with null packageId must throw ArgumentNullException - _ = await Assert.ThrowsExactlyAsync( - async () => await NuGetCache.EnsureCachedAsync(null!, version, TestContext.CancellationToken)); + _ = await Assert.ThrowsAsync( + async () => await NuGetCache.EnsureCachedAsync(null!, version, CancellationToken.None)); } /// @@ -113,22 +107,22 @@ public async Task NuGetCache_EnsureCachedAsync_NullPackageId_ThrowsArgumentNullE /// This test proves Caching-NuGetCache-NullValidation: the library validates input parameters /// and throws for null arguments. /// - [TestMethod] + [Fact] public async Task NuGetCache_EnsureCachedAsync_NullVersion_ThrowsArgumentNullException() { // Arrange - null version is an invalid argument const string packageId = "DemaConsulting.TestResults"; // Act & Assert - calling with null version must throw ArgumentNullException - _ = await Assert.ThrowsExactlyAsync( - async () => await NuGetCache.EnsureCachedAsync(packageId, null!, TestContext.CancellationToken)); + _ = await Assert.ThrowsAsync( + async () => await NuGetCache.EnsureCachedAsync(packageId, null!, CancellationToken.None)); } /// /// Tests that throws /// when version is not a valid NuGet version string. /// - [TestMethod] + [Fact] public async Task NuGetCache_EnsureCachedAsync_InvalidVersion_ThrowsArgumentException() { // Arrange: a string that is not a valid NuGet version @@ -136,8 +130,8 @@ public async Task NuGetCache_EnsureCachedAsync_InvalidVersion_ThrowsArgumentExce const string version = "not-a-version"; // Act & Assert: calling with an invalid version must throw ArgumentException - _ = await Assert.ThrowsExactlyAsync( - async () => await NuGetCache.EnsureCachedAsync(packageId, version, TestContext.CancellationToken)); + _ = await Assert.ThrowsAsync( + async () => await NuGetCache.EnsureCachedAsync(packageId, version, CancellationToken.None)); } /// @@ -148,8 +142,8 @@ public async Task NuGetCache_EnsureCachedAsync_InvalidVersion_ThrowsArgumentExce /// This test proves Caching-NuGetCache-EnsureCached: the library can ensure a NuGet package is cached locally, /// and the operation is idempotent — calling it a second time returns the same path from the cache. /// - [TestMethod] - [TestCategory("Integration")] + [Fact] + [Trait("Category", "Integration")] public async Task NuGetCache_EnsureCachedAsync_CalledTwiceWithSamePackage_ReturnsSamePath() { // Arrange - use a small, known package that is reliably available on nuget.org @@ -157,11 +151,11 @@ public async Task NuGetCache_EnsureCachedAsync_CalledTwiceWithSamePackage_Return const string version = "1.5.0"; // Act - call EnsureCachedAsync twice with the same package identity - var firstPath = await NuGetCache.EnsureCachedAsync(packageId, version, TestContext.CancellationToken); - var secondPath = await NuGetCache.EnsureCachedAsync(packageId, version, TestContext.CancellationToken); + var firstPath = await NuGetCache.EnsureCachedAsync(packageId, version, CancellationToken.None); + var secondPath = await NuGetCache.EnsureCachedAsync(packageId, version, CancellationToken.None); // Assert - both calls must return identical paths, proving the method is idempotent // and does not change the cache location on subsequent calls - Assert.AreEqual(firstPath, secondPath, "EnsureCachedAsync must return the same path on repeated calls"); + Assert.Equal(firstPath, secondPath); } } diff --git a/test/DemaConsulting.NuGet.Caching.Tests/NuGetCachingTests.cs b/test/DemaConsulting.NuGet.Caching.Tests/NuGetCachingTests.cs index b396620..3872d95 100644 --- a/test/DemaConsulting.NuGet.Caching.Tests/NuGetCachingTests.cs +++ b/test/DemaConsulting.NuGet.Caching.Tests/NuGetCachingTests.cs @@ -23,14 +23,8 @@ namespace DemaConsulting.NuGet.Caching.Tests; /// /// System-level integration tests for the DemaConsulting NuGet Caching library. /// -[TestClass] public class NuGetCachingTests { - /// - /// Gets or sets the test context provided by the MSTest framework before each test runs. - /// - public TestContext TestContext { get; set; } = null!; - /// /// Tests that the library provides programmatic NuGet package caching by ensuring a known /// package is available in the local global packages cache after calling the library. @@ -39,8 +33,8 @@ public class NuGetCachingTests /// This test proves Caching-Sys-PackageCaching: the system provides a .NET library for /// programmatic NuGet package caching. /// - [TestMethod] - [TestCategory("Integration")] + [Fact] + [Trait("Category", "Integration")] public async Task NuGetCaching_EnsureCachedAsync_WhenKnownPackageAndVersionProvided_ReturnsPackageFolder() { // Arrange: use a small, known package that is reliably available on nuget.org @@ -48,18 +42,18 @@ public async Task NuGetCaching_EnsureCachedAsync_WhenKnownPackageAndVersionProvi const string version = "1.5.0"; // Act: invoke the library's package caching capability - var packageFolder = await NuGetCache.EnsureCachedAsync(packageId, version, TestContext.CancellationToken); + var packageFolder = await NuGetCache.EnsureCachedAsync(packageId, version, CancellationToken.None); // Assert: the library returned a valid path to the cached package on disk - Assert.IsNotNull(packageFolder, "EnsureCachedAsync should not return null"); - Assert.IsTrue( + Assert.NotNull(packageFolder); + Assert.True( Directory.Exists(packageFolder), $"Expected package folder to exist at: {packageFolder}"); // Assert: a fully installed package should include the NuGet installation sentinel file var metadataFilePath = Path.Combine(packageFolder, ".nupkg.metadata"); - Assert.IsTrue( + Assert.True( File.Exists(metadataFilePath), $"Expected package folder to contain .nupkg.metadata at: {metadataFilePath}"); } @@ -72,8 +66,8 @@ public async Task NuGetCaching_EnsureCachedAsync_WhenKnownPackageAndVersionProvi /// This test proves the error-path behavior of Caching-Sys-PackageCaching: the system /// correctly signals when a package version is unavailable across all configured sources. /// - [TestMethod] - [TestCategory("Integration")] + [Fact] + [Trait("Category", "Integration")] public async Task NuGetCaching_EnsureCachedAsync_WhenPackageNotFound_ThrowsInvalidOperationException() { // Arrange: use a package ID and version combination that does not exist on any source @@ -81,12 +75,12 @@ public async Task NuGetCaching_EnsureCachedAsync_WhenPackageNotFound_ThrowsInval const string version = "99.99.99"; // Act & Assert: the library should throw when the package cannot be found - var ex = await Assert.ThrowsExactlyAsync( - async () => await NuGetCache.EnsureCachedAsync(packageId, version, TestContext.CancellationToken)); + var ex = await Assert.ThrowsAsync( + async () => await NuGetCache.EnsureCachedAsync(packageId, version, CancellationToken.None)); // Assert: the exception message must identify the package ID and version - StringAssert.Contains(ex.Message, packageId, "Exception message must contain the package ID"); - StringAssert.Contains(ex.Message, version, "Exception message must contain the version"); + Assert.Contains(packageId, ex.Message); + Assert.Contains(version, ex.Message); } /// @@ -97,15 +91,15 @@ public async Task NuGetCaching_EnsureCachedAsync_WhenPackageNotFound_ThrowsInval /// This test proves Caching-Sys-NullValidation: the system rejects null arguments /// with a clear, actionable error. /// - [TestMethod] + [Fact] public async Task NuGetCaching_EnsureCachedAsync_WhenPackageIdIsNull_ThrowsArgumentNullException() { // Arrange: null packageId is an invalid argument const string version = "1.5.0"; // Act & Assert: the library should throw ArgumentNullException for a null package ID - _ = await Assert.ThrowsExactlyAsync( - async () => await NuGetCache.EnsureCachedAsync(null!, version, TestContext.CancellationToken)); + _ = await Assert.ThrowsAsync( + async () => await NuGetCache.EnsureCachedAsync(null!, version, CancellationToken.None)); } /// @@ -116,14 +110,14 @@ public async Task NuGetCaching_EnsureCachedAsync_WhenPackageIdIsNull_ThrowsArgum /// This test proves Caching-Sys-NullValidation: the system rejects null arguments /// with a clear, actionable error. /// - [TestMethod] + [Fact] public async Task NuGetCaching_EnsureCachedAsync_WhenVersionIsNull_ThrowsArgumentNullException() { // Arrange: null version is an invalid argument const string packageId = "DemaConsulting.TestResults"; // Act & Assert: the library should throw ArgumentNullException for a null version - _ = await Assert.ThrowsExactlyAsync( - async () => await NuGetCache.EnsureCachedAsync(packageId, null!, TestContext.CancellationToken)); + _ = await Assert.ThrowsAsync( + async () => await NuGetCache.EnsureCachedAsync(packageId, null!, CancellationToken.None)); } } diff --git a/test/DemaConsulting.NuGet.Caching.Tests/PathHelpersTests.cs b/test/DemaConsulting.NuGet.Caching.Tests/PathHelpersTests.cs index 6911afc..93292d5 100644 --- a/test/DemaConsulting.NuGet.Caching.Tests/PathHelpersTests.cs +++ b/test/DemaConsulting.NuGet.Caching.Tests/PathHelpersTests.cs @@ -23,13 +23,12 @@ namespace DemaConsulting.NuGet.Caching.Tests; /// /// Unit tests for the PathHelpers class. /// -[TestClass] public class PathHelpersTests { /// /// Test that SafePathCombine successfully combines valid paths. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly() { // Arrange - set up valid base and relative paths @@ -40,13 +39,13 @@ public void PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly() var result = PathHelpers.SafePathCombine(basePath, relativePath); // Assert - combined path matches standard path combination - Assert.AreEqual(Path.Combine(basePath, relativePath), result); + Assert.Equal(Path.Combine(basePath, relativePath), result); } /// /// Test that SafePathCombine throws ArgumentException for path traversal with double dots. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_PathTraversalWithDoubleDots_ThrowsArgumentException() { // Arrange - set up a path traversal attempt using double dots @@ -54,16 +53,16 @@ public void PathHelpers_SafePathCombine_PathTraversalWithDoubleDots_ThrowsArgume var relativePath = "../etc/passwd"; // Act & Assert - SafePathCombine must reject path traversal with ArgumentException - var exception = Assert.ThrowsExactly(() => + var exception = Assert.Throws(() => PathHelpers.SafePathCombine(basePath, relativePath)); Assert.Contains("Invalid path component", exception.Message); - Assert.AreEqual("relativePath", exception.ParamName); + Assert.Equal("relativePath", exception.ParamName); } /// /// Test that SafePathCombine throws ArgumentException for path with double dots in middle. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentException() { // Arrange - set up a path with embedded double dots in the middle @@ -71,7 +70,7 @@ public void PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentExcepti var relativePath = "documents/../../../etc/passwd"; // Act & Assert - SafePathCombine must reject traversal sequences with ArgumentException - var exception = Assert.ThrowsExactly(() => + var exception = Assert.Throws(() => PathHelpers.SafePathCombine(basePath, relativePath)); Assert.Contains("Invalid path component", exception.Message); } @@ -79,7 +78,7 @@ public void PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentExcepti /// /// Test that SafePathCombine throws ArgumentException for absolute paths. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException() { // Arrange - set up Unix absolute path as relative argument @@ -87,7 +86,7 @@ public void PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException() var unixRelativePath = "/etc/passwd"; // Act & Assert - SafePathCombine must reject an absolute Unix path - var unixException = Assert.ThrowsExactly(() => + var unixException = Assert.Throws(() => PathHelpers.SafePathCombine(unixBasePath, unixRelativePath)); Assert.Contains("Invalid path component", unixException.Message); @@ -99,7 +98,7 @@ public void PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException() var windowsRelativePath = "C:\\Windows\\System32"; // Act & Assert - SafePathCombine must reject an absolute Windows path - var windowsException = Assert.ThrowsExactly(() => + var windowsException = Assert.Throws(() => PathHelpers.SafePathCombine(windowsBasePath, windowsRelativePath)); Assert.Contains("Invalid path component", windowsException.Message); } @@ -108,7 +107,7 @@ public void PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException() /// /// Test that SafePathCombine accepts a filename that starts with ".." but is not a traversal sequence. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_DotDotPrefixedName_CombinesCorrectly() { // Arrange - set up a filename starting with ".." that is not a traversal @@ -119,13 +118,13 @@ public void PathHelpers_SafePathCombine_DotDotPrefixedName_CombinesCorrectly() var result = PathHelpers.SafePathCombine(basePath, relativePath); // Assert - result matches standard path combination for this valid filename - Assert.AreEqual(Path.Combine(basePath, relativePath), result); + Assert.Equal(Path.Combine(basePath, relativePath), result); } /// /// Test that SafePathCombine correctly handles current directory reference. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_CurrentDirectoryReference_CombinesCorrectly() { // Arrange - set up a relative path with a leading current-directory reference @@ -136,13 +135,13 @@ public void PathHelpers_SafePathCombine_CurrentDirectoryReference_CombinesCorrec var result = PathHelpers.SafePathCombine(basePath, relativePath); // Assert - result matches standard path combination - Assert.AreEqual(Path.Combine(basePath, relativePath), result); + Assert.Equal(Path.Combine(basePath, relativePath), result); } /// /// Test that SafePathCombine correctly handles empty relative path. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_EmptyRelativePath_ReturnsBasePath() { // Arrange - use an empty string as the relative path @@ -153,13 +152,13 @@ public void PathHelpers_SafePathCombine_EmptyRelativePath_ReturnsBasePath() var result = PathHelpers.SafePathCombine(basePath, relativePath); // Assert - result equals the base path when relative path is empty - Assert.AreEqual(Path.Combine(basePath, relativePath), result); + Assert.Equal(Path.Combine(basePath, relativePath), result); } /// /// Test that SafePathCombine accepts simple filename. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_SimpleFilename_CombinesCorrectly() { // Arrange - set up a simple single-segment filename @@ -170,13 +169,13 @@ public void PathHelpers_SafePathCombine_SimpleFilename_CombinesCorrectly() var result = PathHelpers.SafePathCombine(basePath, relativePath); // Assert - result matches standard path combination - Assert.AreEqual(Path.Combine(basePath, relativePath), result); + Assert.Equal(Path.Combine(basePath, relativePath), result); } /// /// Test that SafePathCombine accepts path with subdirectories. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_NestedPaths_CombinesCorrectly() { // Arrange - set up a multi-segment relative path with nested subdirectories @@ -187,13 +186,13 @@ public void PathHelpers_SafePathCombine_NestedPaths_CombinesCorrectly() var result = PathHelpers.SafePathCombine(basePath, relativePath); // Assert - result matches standard path combination for nested paths - Assert.AreEqual(Path.Combine(basePath, relativePath), result); + Assert.Equal(Path.Combine(basePath, relativePath), result); } /// /// Test that SafePathCombine accepts GUID-based filename. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_GuidBasedFilename_CombinesSuccessfully() { // Arrange - set up a GUID-based temporary filename @@ -205,13 +204,13 @@ public void PathHelpers_SafePathCombine_GuidBasedFilename_CombinesSuccessfully() var result = PathHelpers.SafePathCombine(basePath, relativePath); // Assert - result matches standard path combination for GUID-based filenames - Assert.AreEqual(Path.Combine(basePath, relativePath), result); + Assert.Equal(Path.Combine(basePath, relativePath), result); } /// /// Test that SafePathCombine throws ArgumentNullException for null basePath. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_NullBasePath_ThrowsArgumentNullException() { // Arrange - use null as the basePath argument @@ -219,14 +218,14 @@ public void PathHelpers_SafePathCombine_NullBasePath_ThrowsArgumentNullException var relativePath = "file.txt"; // Act & Assert - SafePathCombine must throw ArgumentNullException for null basePath - _ = Assert.ThrowsExactly(() => + _ = Assert.Throws(() => PathHelpers.SafePathCombine(basePath!, relativePath)); } /// /// Test that SafePathCombine throws ArgumentNullException for null relativePath. /// - [TestMethod] + [Fact] public void PathHelpers_SafePathCombine_NullRelativePath_ThrowsArgumentNullException() { // Arrange - use null as the relativePath argument @@ -234,7 +233,7 @@ public void PathHelpers_SafePathCombine_NullRelativePath_ThrowsArgumentNullExcep const string? relativePath = null; // Act & Assert - SafePathCombine must throw ArgumentNullException for null relativePath - _ = Assert.ThrowsExactly(() => + _ = Assert.Throws(() => PathHelpers.SafePathCombine(basePath, relativePath!)); } }