diff --git a/.cspell.json b/.cspell.json
new file mode 100644
index 0000000..2be99ec
--- /dev/null
+++ b/.cspell.json
@@ -0,0 +1,46 @@
+{
+ "version": "0.2",
+ "language": "en",
+ "words": [
+ "camelcase",
+ "cspell",
+ "csproj",
+ "dbproj",
+ "Dema",
+ "dependabot",
+ "dotnet",
+ "editorconfig",
+ "fsproj",
+ "Gidget",
+ "gitattributes",
+ "LINQ",
+ "markdownlint",
+ "mstest",
+ "nuget",
+ "nupkg",
+ "SBOM",
+ "semver",
+ "snupkg",
+ "Sonar",
+ "sonarcloud",
+ "spdx",
+ "TestResults",
+ "trx",
+ "vbproj",
+ "vcxproj"
+ ],
+ "ignorePaths": [
+ "node_modules",
+ ".git",
+ "bin",
+ "obj",
+ "*.nupkg",
+ "*.snupkg",
+ "*.dll",
+ "*.exe",
+ "*.trx",
+ "*.spdx.json",
+ "package-lock.json",
+ "yarn.lock"
+ ]
+}
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..a78874c
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,173 @@
+# EditorConfig is awesome: https://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# All files
+[*]
+charset = utf-8
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = space
+
+# Code files
+[*.{cs,csx,vb,vbx}]
+indent_size = 4
+
+# XML project files
+[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
+indent_size = 2
+
+# XML config files
+[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
+indent_size = 2
+
+# JSON files
+[*.json]
+indent_size = 2
+
+# YAML files
+[*.{yml,yaml}]
+indent_size = 2
+
+# Markdown files
+[*.md]
+trim_trailing_whitespace = false
+
+# Shell scripts
+[*.sh]
+end_of_line = lf
+
+# Batch files
+[*.{cmd,bat}]
+end_of_line = crlf
+
+# Dotnet code style settings:
+[*.{cs,vb}]
+
+# IDE0055: Fix formatting
+dotnet_diagnostic.IDE0055.severity = warning
+
+# Sort using and Import directives with System.* appearing first
+dotnet_sort_system_directives_first = true
+dotnet_separate_import_directive_groups = false
+
+# Avoid "this." and "Me." if not necessary
+dotnet_style_qualification_for_field = false:warning
+dotnet_style_qualification_for_property = false:warning
+dotnet_style_qualification_for_method = false:warning
+dotnet_style_qualification_for_event = false:warning
+
+# Use language keywords instead of framework type names for type references
+dotnet_style_predefined_type_for_locals_parameters_members = true:warning
+dotnet_style_predefined_type_for_member_access = true:warning
+
+# Suggest more modern language features when available
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+
+# Naming conventions
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = warning
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# Symbol specifications
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# Naming styles
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+# CSharp code style settings:
+[*.cs]
+
+# Newline settings
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_case_contents = true
+csharp_indent_switch_labels = true
+csharp_indent_labels = flush_left
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents_when_block = false
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_between_parentheses = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+
+# Wrapping preferences
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = true
+
+# Prefer "var" everywhere
+csharp_style_var_for_built_in_types = true:suggestion
+csharp_style_var_when_type_is_apparent = true:suggestion
+csharp_style_var_elsewhere = true:suggestion
+
+# Prefer method-like constructs to have a block body
+csharp_style_expression_bodied_methods = false:none
+csharp_style_expression_bodied_constructors = false:none
+csharp_style_expression_bodied_operators = false:none
+
+# Prefer property-like constructs to have an expression-body
+csharp_style_expression_bodied_properties = true:suggestion
+csharp_style_expression_bodied_indexers = true:suggestion
+csharp_style_expression_bodied_accessors = true:suggestion
+
+# Suggest more modern language features when available
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Code quality rules
+dotnet_code_quality_unused_parameters = all:warning
+
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..28f77f7
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,52 @@
+# Auto detect text files and perform LF normalization
+* text=auto
+
+# Source code
+*.cs text diff=csharp
+*.csx text diff=csharp
+*.vb text
+
+# Project files
+*.csproj text
+*.vbproj text
+*.fsproj text
+*.dbproj text
+*.sln text eol=crlf
+
+# Configuration files
+*.config text
+*.json text
+*.xml text
+*.yaml text
+*.yml text
+
+# Documentation
+*.md text
+*.txt text
+
+# Scripts
+*.sh text eol=lf
+*.bash text eol=lf
+*.ps1 text eol=crlf
+*.cmd text eol=crlf
+*.bat text eol=crlf
+
+# Graphics
+*.png binary
+*.jpg binary
+*.jpeg binary
+*.gif binary
+*.ico binary
+*.svg text
+
+# Archives
+*.zip binary
+*.gz binary
+*.tar binary
+*.nupkg binary
+*.snupkg binary
+
+# Other binaries
+*.dll binary
+*.exe binary
+*.pdb binary
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..f134e1b
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,27 @@
+version: 2
+updates:
+ # Maintain dependencies for NuGet
+ - package-ecosystem: "nuget"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ day: "monday"
+ open-pull-requests-limit: 10
+ groups:
+ analyzers:
+ patterns:
+ - "Microsoft.CodeAnalysis.*"
+ - "SonarAnalyzer.*"
+ test-dependencies:
+ patterns:
+ - "Microsoft.NET.Test.Sdk"
+ - "MSTest.*"
+ - "coverlet.*"
+
+ # Maintain dependencies for GitHub Actions
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ day: "monday"
+ open-pull-requests-limit: 10
diff --git a/.github/workflows/build_on_push.yaml b/.github/workflows/build_on_push.yaml
index 2cbc3c2..82708d7 100644
--- a/.github/workflows/build_on_push.yaml
+++ b/.github/workflows/build_on_push.yaml
@@ -8,8 +8,35 @@ on:
- cron: '0 17 * * 1'
jobs:
+ quality-checks:
+ name: Quality Checks
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+
+ - name: Install cspell
+ run: npm install -g cspell
+
+ - name: Install markdownlint-cli
+ run: npm install -g markdownlint-cli
+
+ - name: Run spell checker
+ run: cspell "**/*.{md,cs}" --no-progress
+
+ - name: Run markdown linter
+ run: markdownlint "**/*.md" --ignore node_modules
+
build-windows:
name: Build Windows
+ needs: quality-checks
permissions:
contents: read # To read repository contents
pull-requests: write # To write pull requests analysis results and artifacts
@@ -22,6 +49,7 @@ jobs:
build-linux:
name: Build Linux
+ needs: quality-checks
permissions:
contents: read # To read repository contents
pull-requests: write # To write pull requests analysis results and artifacts
diff --git a/.markdownlint.json b/.markdownlint.json
new file mode 100644
index 0000000..18afdd8
--- /dev/null
+++ b/.markdownlint.json
@@ -0,0 +1,15 @@
+{
+ "default": true,
+ "MD013": {
+ "line_length": 120,
+ "heading_line_length": 120,
+ "code_block_line_length": 120,
+ "code_blocks": true,
+ "tables": false,
+ "headings": true,
+ "strict": false,
+ "stern": false
+ },
+ "MD033": false,
+ "MD041": false
+}
diff --git a/AGENTS.md b/AGENTS.md
index da8971f..193499c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -3,69 +3,317 @@
This file provides specific context and instructions for AI coding agents to
interact effectively with this C# project.
-
## Project Overview
-TestResults is a C# library for creating TRX test result files.
+TestResults is a C# library for creating test result files. The library is designed to be:
+
+- **Lightweight**: Minimal external dependencies
+- **Simple**: Easy-to-use API for creating test result files
+- **Type-Safe**: Strongly-typed C# objects
+- **Cross-Platform**: Supports .NET 8, 9, and 10
+The library currently focuses on TRX format, with potential for additional formats in the future.
## Technologies and Dependencies
-* **Language**: C# 12
-* **.NET Frameworks**: .NET 8, 9, and 10
-* **Primary Dependencies**: None
+### Runtime
+
+- **Language**: C# 12
+- **.NET Frameworks**: .NET 8, 9, and 10
+- **Primary Dependencies**: None currently
+
+### Development Tools
+- **Analyzers**: Microsoft.CodeAnalysis.NetAnalyzers and SonarAnalyzer.CSharp for static code analysis
+- **Source Control**: SourceLink for debugging support
+- **Testing**: MSTest framework with code coverage
+- **CI/CD**: GitHub Actions for build and release automation
+- **Code Quality**: SonarCloud for quality metrics
+- **Dependency Management**: Dependabot for automated dependency updates
## Project Structure
The repository is organized as follows:
-* `/.config/`: Contains the .NET Tool configuration.
-* `/.github/workflows/`: Contains the CI/CD pipeline configurations.
-* `/src/DemaConsulting.TestResults/`: Contains the library source code.
-* `/test/DemaConsulting.TestResults.Tests/`: Contains the library unit tests.
-* `/DemaConsulting.TestResults.sln`: The main Visual Studio solution file.
+```text
+/
+├── .config/ # .NET tool configurations
+├── .github/workflows/ # CI/CD pipeline configurations
+├── src/DemaConsulting.TestResults/ # Main library source code
+├── test/DemaConsulting.TestResults.Tests/ # Unit tests
+├── .editorconfig # Code style enforcement
+├── .cspell.json # Spell checking configuration
+├── .markdownlint.json # Markdown linting rules
+├── AGENTS.md # This file
+├── ARCHITECTURE.md # Architecture documentation
+├── CODE_OF_CONDUCT.md # Code of conduct
+├── CONTRIBUTING.md # Contribution guidelines
+├── DemaConsulting.TestResults.sln # Visual Studio solution
+└── README.md # Main documentation
+```
+Key directories:
+
+- **src/** - Contains the main library implementation
+- **test/** - Contains unit tests and test resources
+- **.github/** - Contains CI/CD workflows and automation
## Development Commands
Use these commands to perform common development tasks:
-* **Restore DotNet Tools**:
- ```bash
- dotnet tool restore
- ```
+### Initial Setup
+
+```bash
+# Restore .NET tools
+dotnet tool restore
+
+# Restore dependencies
+dotnet restore
+```
+
+### Building and Testing
-* **Build the Project**:
- ```bash
- dotnet build
- ```
+```bash
+# Build the project
+dotnet build
-* **Run All Tests**:
- ```bash
- dotnet test
- ```
+# Build in release mode
+dotnet build --configuration Release
+# Run all tests
+dotnet test
+
+# Run tests with code coverage
+dotnet test --collect "XPlat Code Coverage"
+
+# Build NuGet package
+dotnet pack
+```
+
+### Quality Checks
+
+```bash
+# Run spell checker (requires npm install -g cspell)
+cspell "**/*.{md,cs}"
+
+# Run markdown linter (requires npm install -g markdownlint-cli)
+markdownlint "**/*.md"
+
+# Format code (if format tools are installed)
+dotnet format
+```
## Testing Guidelines
-* Tests are located under the `/test/DemaConsulting.TestResults.Tests/` folder and use the MSTest framework.
-* Test files should end with `.cs` and adhere to the naming convention `[Component]Tests.cs`.
-* All new features should be tested with comprehensive unit tests.
-* The build must pass all tests and static analysis warnings before merging.
-* Tests should be written using the AAA (Arrange, Act, Assert) pattern.
+### Test Organization
+
+- Tests are located under the `/test/DemaConsulting.TestResults.Tests/` folder
+- Use the MSTest framework (`[TestClass]`, `[TestMethod]`, etc.)
+- Test files should end with `.cs` and follow the naming convention `[Component]Tests.cs`
+
+### Test Structure
+- Use the AAA (Arrange, Act, Assert) pattern
+- Keep tests focused on a single behavior
+- Use descriptive test method names that explain what is being tested
+- Example: `TestMethod_Scenario_ExpectedBehavior`
+
+### Test Coverage
+
+- All new features must have comprehensive unit tests
+- Aim for high code coverage (>80%)
+- Test both success and failure scenarios
+- Include edge cases and boundary conditions
+
+### Test Requirements
+
+- All tests must pass before merging
+- No warnings are allowed (warnings are treated as errors)
+- Tests should be isolated and not depend on execution order
+- Use appropriate assertions from MSTest (`Assert.AreEqual`, `Assert.ThrowsException`, etc.)
## Code Style and Conventions
-* Follow standard C# naming conventions (PascalCase for classes/methods/properties, camelCase for local variables).
-* Nullable reference types are enabled at the project level (`enable` in .csproj files). Do not use file-level `#nullable enable` directives.
-* Warnings are treated as errors (`true`).
-* Avoid public fields; prefer properties.
+### Naming Conventions
+
+- **PascalCase**: Classes, methods, properties, public fields, namespaces
+- **camelCase**: Local variables, private fields, parameters
+- **Interface names**: Start with 'I' (e.g., `ITestResult`)
+- **Test methods**: Use descriptive names (e.g., `Serialize_EmptyResults_ReturnsValidXml`)
+
+### Code Organization
+
+- One class per file (except for nested/related classes)
+- Organize using statements (System.* first, then others alphabetically)
+- Use file-scoped namespaces when appropriate
+- Group class members by type (fields, properties, constructors, methods)
+
+### Best Practices
+
+- **Nullable Reference Types**: Enabled at project level; use appropriately
+- **Warnings as Errors**: All warnings must be resolved
+- **XML Documentation**: Required for all public APIs
+- **Immutability**: Prefer readonly fields and get-only properties where appropriate
+- **LINQ**: Use LINQ for collection operations when it improves readability
+- **String Interpolation**: Prefer over string concatenation
+- **Object Initializers**: Use for cleaner object construction
+
+### Code Quality
+
+- Follow .editorconfig settings for consistent formatting
+- Use meaningful variable and method names
+- Keep methods focused and concise (Single Responsibility Principle)
+- Avoid code duplication (DRY principle)
+- Comment only when necessary to explain "why", not "what"
+- Use static analysis recommendations from analyzers
+
+## Quality Standards
+
+### Static Analysis
+
+- Microsoft.CodeAnalysis.NetAnalyzers is enabled in all projects for .NET-specific analysis
+- SonarAnalyzer.CSharp is enabled in all projects for additional code quality checks
+- All analyzer warnings must be addressed or explicitly suppressed with justification
+- Code style rules are enforced via .editorconfig
+
+### Documentation
+
+- All public APIs must have XML documentation comments
+- Include ``, ``, ``, and `` tags as appropriate
+- Keep documentation clear, concise, and accurate
+- Update README.md and ARCHITECTURE.md for significant changes
+### Spelling and Markdown
+
+- Use cspell for spell checking code and documentation
+- Follow markdownlint rules for markdown files
+- Add technical terms to .cspell.json dictionary as needed
+
+## CI/CD Pipeline
+
+### Build Process
+
+The build pipeline includes:
+
+1. **Checkout**: Clone the repository
+2. **Setup**: Install .NET SDKs (8, 9, 10)
+3. **Restore**: Restore tools and dependencies
+4. **SonarCloud Start**: Begin SonarCloud analysis
+5. **Build**: Compile in Release mode
+6. **Test**: Run all tests with code coverage
+7. **SonarCloud End**: Complete SonarCloud analysis
+8. **SBOM**: Generate Software Bill of Materials
+9. **Package**: Create NuGet packages
+
+### Quality Gates
+
+All builds must pass:
+
+- Compilation with zero warnings
+- All unit tests passing
+- SonarCloud quality gate
+- Code coverage thresholds
+
+## Common Tasks for AI Agents
+
+### Adding a New Feature
+
+1. Read ARCHITECTURE.md to understand the design
+2. Create or update the domain model classes
+3. Update serialization logic if needed
+4. Add comprehensive unit tests
+5. Update XML documentation
+6. Update README.md with usage examples
+7. Run all tests and ensure they pass
+
+### Fixing a Bug
+
+1. Reproduce the bug with a failing test
+2. Fix the bug with minimal changes
+3. Ensure the test now passes
+4. Verify no other tests are broken
+5. Update documentation if the bug fix changes behavior
+
+### Improving Code Quality
+
+1. Run static analysis and address warnings
+2. Review code coverage reports
+3. Refactor duplicated code
+4. Improve naming and clarity
+5. Add missing documentation
+6. Verify all tests still pass
+
+### Updating Dependencies
+
+1. Check dependency versions in .csproj files
+2. Update to latest stable versions when appropriate
+3. Test thoroughly after updates
+4. Update documentation if APIs changed
## Boundaries and Guardrails
-* **NEVER** modify files within the `/obj/` or `/bin/` directories.
-* **NEVER** commit secrets, API keys, or sensitive configuration data.
-* **ASK FIRST** before making significant architectural changes to the core library logic.
+### What AI Agents Should NEVER Do
+
+- Modify files within `/obj/` or `/bin/` directories
+- Commit secrets, API keys, or sensitive configuration data
+- Make significant architectural changes without discussion
+- Remove or disable existing tests
+- Ignore or suppress analyzer warnings without justification
+- Add external runtime dependencies (the library must remain zero-dependency)
+
+### What AI Agents Should ALWAYS Do
+
+- Run tests before committing changes
+- Follow existing code style and patterns
+- Update documentation for user-facing changes
+- Add tests for new functionality
+- Resolve all warnings and analyzer suggestions
+- Keep changes minimal and focused
+
+### What AI Agents Should ASK About
+
+- Adding new public APIs or changing existing ones
+- Significant refactoring or architectural changes
+- Adding development dependencies
+- Changing build or release processes
+- Questions about requirements or expected behavior
+
+## Performance Considerations
+
+- The library is lightweight and should remain so
+- Avoid unnecessary allocations during serialization
+- Use efficient string handling (StringBuilder for concatenation)
+- Profile performance for large test result sets
+
+## Security Considerations
+
+- No file I/O operations within the library (caller controls file operations)
+- No network operations
+- Validate all inputs to public APIs
+- Be careful with XML serialization to avoid XXE attacks
+- Keep dependencies minimal to reduce security surface area
+
+## Tips for Effective Changes
+
+1. **Understand First**: Read existing code and documentation before making changes
+2. **Test Driven**: Write tests first or alongside code changes
+3. **Small Steps**: Make small, incremental changes that are easy to review
+4. **Run Often**: Build and test frequently during development
+5. **Document**: Update documentation as you change code
+6. **Review**: Self-review your changes before submitting
+
+## Getting Help
+
+- Review [ARCHITECTURE.md](ARCHITECTURE.md) for design details
+- Check [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines
+- Look at existing code for patterns and examples
+- Run `dotnet build` and `dotnet test` to verify changes
+- Use `dotnet --info` to check your environment
+
+## Version Support
+
+- The library targets .NET 8, 9, and 10
+- Use APIs available in all target frameworks
+- Test on multiple framework versions when possible
+- Check for framework-specific issues in CI/CD logs
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
new file mode 100644
index 0000000..692f234
--- /dev/null
+++ b/ARCHITECTURE.md
@@ -0,0 +1,152 @@
+# TestResults Library Architecture
+
+## Overview
+
+The TestResults library is a lightweight C# library designed to programmatically create test result files.
+The library currently focuses on the TRX (Test Results) format, with potential for additional formats in the future.
+TRX files are XML-based test result files commonly used by Visual Studio, Azure DevOps, and other Microsoft testing
+tools to store and visualize test execution results.
+
+## Design Philosophy
+
+The library follows these core principles:
+
+- **Simplicity**: Provide a straightforward API for creating test result files without unnecessary complexity
+- **Type Safety**: Use strongly-typed C# objects to represent test results
+- **Lightweight**: Minimize external dependencies to keep the library easy to integrate
+- **Multi-Target Support**: Support multiple .NET versions (.NET 8, 9, and 10) for broad compatibility
+
+## Architecture Components
+
+### Core Domain Model
+
+The library uses a simple object model to represent test results:
+
+#### `TestResults`
+
+The root container for all test results. Key properties:
+
+- `Name`: The name of the test run
+- `Results`: A collection of individual test results
+
+#### `TestResult`
+
+Represents a single test result. Key properties:
+
+- `Name`: The test name
+- `ClassName`: The fully qualified name of the test class
+- `CodeBase`: The test assembly name
+- `Outcome`: The test outcome (see `TestOutcome` enum)
+- `Duration`: Test execution duration
+- `StartTime`: When the test started
+- `EndTime`: When the test finished
+- `ErrorMessage`: Error message if the test failed
+- `ErrorStackTrace`: Stack trace if the test failed
+- `StdOut`: Standard output captured during test execution
+- `StdErr`: Standard error output captured during test execution
+
+#### `TestOutcome`
+
+An enumeration representing possible test outcomes:
+
+- `Passed`: Test passed successfully
+- `Failed`: Test failed
+- `Inconclusive`: Test result was inconclusive
+- `NotExecuted`: Test was not executed
+- `Timeout`: Test exceeded timeout limit
+- `Aborted`: Test was aborted
+- `Unknown`: Test outcome is unknown
+
+### Serialization Layer
+
+#### `TrxSerializer`
+
+The `TrxSerializer` class is responsible for converting the domain model into TRX XML format:
+
+- Uses .NET's built-in XML serialization capabilities
+- Produces TRX files compatible with Visual Studio and Azure DevOps
+- Handles proper formatting and schema compliance
+
+## Data Flow
+
+```text
+1. User creates TestResults instance
+2. User adds TestResult objects to the Results collection
+3. User calls TrxSerializer.Serialize() to convert to TRX XML format
+4. User saves the XML string to a .trx file
+```
+
+## Design Patterns
+
+- **Data Transfer Object (DTO)**: The `TestResults` and `TestResult` classes serve as DTOs for test data
+- **Serializer Pattern**: The `TrxSerializer` class encapsulates all serialization logic
+- **Builder Pattern**: The API allows for fluent construction of test results
+
+## File Organization
+
+The library source code is organized in the `/src/DemaConsulting.TestResults/` directory:
+
+- **Domain Model**: Core classes representing test results (`TestResults`, `TestResult`, `TestOutcome`)
+- **Serialization**: I/O operations for converting to/from file formats (in the `IO/` subdirectory)
+- **Additional Components**: May be added as the library evolves
+
+## Extension Points
+
+The library is designed to be extended in several ways:
+
+1. **Custom Test Outcomes**: While the standard outcomes cover most scenarios, custom outcomes could be added
+2. **Additional Metadata**: The model could be extended to support additional TRX metadata fields
+3. **Alternative Serializers**: Additional serializers could be added for other test result formats
+
+## Quality Attributes
+
+### Reliability
+
+- Warnings are treated as errors to ensure code quality
+- Nullable reference types are enabled to prevent null reference exceptions
+- Comprehensive unit tests validate core functionality
+
+### Performance
+
+- Minimal memory allocation during serialization
+- No external dependencies to reduce overhead
+- Lightweight object model
+
+### Maintainability
+
+- Clear separation of concerns between domain model and serialization
+- Comprehensive XML documentation for all public APIs
+- Consistent code style enforced through .editorconfig
+
+### Security
+
+- No file I/O operations within the library (caller controls where files are written)
+- No network operations
+- No external dependencies that could introduce vulnerabilities
+
+## Future Considerations
+
+Potential enhancements that could be considered:
+
+1. **Deserialization**: Add support for reading existing TRX files back into the object model
+2. **Additional Formats**: Support for other test result formats (JUnit XML, NUnit XML, etc.)
+3. **Streaming**: Support for streaming large test result sets to avoid memory issues
+4. **Validation**: Add schema validation to ensure generated TRX files are well-formed
+
+## Dependencies
+
+### Runtime Dependencies
+
+- None currently
+
+### Development Dependencies
+
+- Microsoft.SourceLink.GitHub: For source linking in NuGet packages
+- Microsoft.CodeAnalysis.NetAnalyzers: For .NET-specific static code analysis
+- SonarAnalyzer.CSharp: For additional code quality and security analysis
+
+### Test Dependencies
+
+- MSTest: Testing framework
+- Microsoft.NET.Test.Sdk: Test SDK
+- coverlet.collector: Code coverage collection
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..caf2c95
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,133 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual
+identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+- Demonstrating empathy and kindness toward other people
+- Being respectful of differing opinions, viewpoints, and experiences
+- Giving and gracefully accepting constructive feedback
+- Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+- Focusing on what is best not just for us as individuals, but for the overall
+ community
+
+Examples of unacceptable behavior include:
+
+- The use of sexualized language or imagery, and sexual attention or advances of
+ any kind
+- Trolling, insulting or derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or email address,
+ without their explicit permission
+- Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official email address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement through GitHub
+issues or by contacting the project maintainers directly.
+
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series of
+actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
+ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within the
+community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][mozilla coc].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][faq]. Translations are available at
+[https://www.contributor-covenant.org/translations][translations].
+
+[homepage]: https://www.contributor-covenant.org
+[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
+[mozilla coc]: https://github.com/mozilla/diversity
+[faq]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..f6af004
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,193 @@
+# Contributing to TestResults
+
+First off, thank you for considering contributing to TestResults! It's people like you that make TestResults such a
+great tool.
+
+## Code of Conduct
+
+This project and everyone participating in it is governed by our
+[Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report
+unacceptable behavior through GitHub issues.
+
+## How Can I Contribute?
+
+### Reporting Bugs
+
+Before creating bug reports, please check the existing issues as you might find out that you don't need to create one.
+When you are creating a bug report, please include as many details as possible:
+
+- **Use a clear and descriptive title** for the issue to identify the problem
+- **Describe the exact steps which reproduce the problem** in as much detail as possible
+- **Provide specific examples to demonstrate the steps**
+- **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that
+ behavior
+- **Explain which behavior you expected to see instead and why**
+- **Include code samples and test cases** if applicable
+
+### Suggesting Enhancements
+
+Enhancement suggestions are tracked as GitHub issues. When creating an enhancement suggestion, please include:
+
+- **Use a clear and descriptive title** for the issue to identify the suggestion
+- **Provide a step-by-step description of the suggested enhancement** in as much detail as possible
+- **Provide specific examples to demonstrate the steps** or provide examples of how the enhancement would be used
+- **Describe the current behavior** and **explain which behavior you expected to see instead** and why
+- **Explain why this enhancement would be useful** to most TestResults users
+
+### Pull Requests
+
+- Fill in the pull request template
+- Follow the C# coding style used throughout the project
+- Include unit tests for new functionality
+- Update documentation to reflect any changes
+- Ensure all tests pass and there are no linting errors
+
+## Development Setup
+
+### Prerequisites
+
+- [.NET SDK 8.0, 9.0, or 10.0](https://dotnet.microsoft.com/download)
+- A code editor ([Visual Studio](https://visualstudio.microsoft.com/),
+ [Visual Studio Code](https://code.visualstudio.com/), or [JetBrains Rider](https://www.jetbrains.com/rider/))
+
+### Getting Started
+
+1. Fork the repository
+2. Clone your fork:
+
+ ```bash
+ git clone https://github.com/YOUR-USERNAME/TestResults.git
+ cd TestResults
+ ```
+
+3. Restore .NET tools:
+
+ ```bash
+ dotnet tool restore
+ ```
+
+4. Restore dependencies:
+
+ ```bash
+ dotnet restore
+ ```
+
+5. Build the project:
+
+ ```bash
+ dotnet build
+ ```
+
+6. Run tests:
+
+ ```bash
+ dotnet test
+ ```
+
+### Making Changes
+
+1. Create a new branch for your changes:
+
+ ```bash
+ git checkout -b feature/your-feature-name
+ ```
+
+2. Make your changes, following the coding guidelines below
+3. Add or update tests as needed
+4. Run the full test suite to ensure nothing is broken
+5. Commit your changes with a clear and descriptive commit message
+6. Push to your fork and submit a pull request
+
+## Coding Guidelines
+
+### C# Style
+
+- Follow standard C# naming conventions:
+ - PascalCase for classes, methods, properties, and public fields
+ - camelCase for local variables and private fields
+ - Interface names should start with 'I'
+- Use meaningful and descriptive names for variables, methods, and classes
+- Add XML documentation comments for all public APIs
+- Keep methods focused and concise (Single Responsibility Principle)
+- Prefer composition over inheritance
+- Use nullable reference types appropriately
+
+### Code Quality
+
+- Warnings are treated as errors - ensure your code produces no warnings
+- Follow the existing code style in the project
+- Use the .editorconfig settings provided in the repository
+- Run static analysis and address any issues
+- Maintain high code coverage with unit tests
+
+### Testing
+
+- Write unit tests for all new functionality
+- Follow the AAA (Arrange, Act, Assert) pattern
+- Use descriptive test names that explain what is being tested
+- Test both success and failure scenarios
+- Keep tests isolated and independent
+- Mock external dependencies when appropriate
+
+### Documentation
+
+- Update README.md if you change functionality
+- Add XML documentation comments for all public APIs
+- Update ARCHITECTURE.md for significant architectural changes
+- Include code examples for new features
+
+## Commit Message Guidelines
+
+- Use the present tense ("Add feature" not "Added feature")
+- Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
+- Limit the first line to 72 characters or less
+- Reference issues and pull requests liberally after the first line
+- Consider starting the commit message with an applicable emoji:
+ - ✨ `:sparkles:` when adding a new feature
+ - 🐛 `:bug:` when fixing a bug
+ - 📝 `:memo:` when writing docs
+ - 🎨 `:art:` when improving the format/structure of the code
+ - ⚡ `:zap:` when improving performance
+ - ✅ `:white_check_mark:` when adding tests
+ - 🔒 `:lock:` when dealing with security
+
+## Project Structure
+
+```text
+TestResults/
+├── .config/ # .NET tool configuration
+├── .github/workflows/ # CI/CD workflows
+├── src/
+│ └── DemaConsulting.TestResults/ # Main library
+├── test/
+│ └── DemaConsulting.TestResults.Tests/ # Unit tests
+├── .editorconfig # Editor configuration
+├── .gitignore # Git ignore rules
+├── AGENTS.md # AI agent instructions
+├── ARCHITECTURE.md # Architecture documentation
+├── CODE_OF_CONDUCT.md # Code of conduct
+├── CONTRIBUTING.md # This file
+├── DemaConsulting.TestResults.sln # Solution file
+├── LICENSE # MIT license
+└── README.md # Main documentation
+```
+
+## Release Process
+
+Releases are managed by the project maintainers:
+
+1. Version numbers follow [Semantic Versioning](https://semver.org/)
+2. Releases are created through GitHub releases
+3. NuGet packages are automatically published on release
+4. Release notes are generated from commit messages
+
+## Questions?
+
+Feel free to open an issue with your question or reach out to the maintainers directly through GitHub.
+
+## Recognition
+
+Contributors will be recognized in the project README and release notes. We appreciate all contributions, no matter
+how small!
+
+Thank you for contributing to TestResults! 🎉
diff --git a/README.md b/README.md
index 1867f55..fb0cdda 100644
--- a/README.md
+++ b/README.md
@@ -8,24 +8,64 @@
[](https://sonarcloud.io/summary/new_code?id=demaconsulting_TestResults)
[](https://sonarcloud.io/summary/new_code?id=demaconsulting_TestResults)
-The TestResults library supports saving test results to TRX files.
+A lightweight C# library for programmatically creating TRX (Test Results) files.
+## Features
-## Usage
+- ✨ **Simple API** - Intuitive and easy-to-use object model
+- 🎯 **Type-Safe** - Strongly-typed C# classes for test results
+- 🪶 **Lightweight** - Minimal external dependencies
+- 🔄 **Multi-Target** - Supports .NET 8, 9, and 10
+- 📦 **NuGet Ready** - Easy integration via NuGet package
+- ✅ **Compatible** - Generates TRX files compatible with Visual Studio, Azure DevOps, and other Microsoft testing tools
-The following code-snippet shows how to create a TRX test-results file.
+## Installation
+
+Install via NuGet Package Manager:
+
+```bash
+dotnet add package DemaConsulting.TestResults
+```
+
+Or via Package Manager Console:
+
+```powershell
+Install-Package DemaConsulting.TestResults
+```
+
+## Quick Start
+
+The following code-snippet shows how to create a TRX test-results file:
```csharp
+using DemaConsulting.TestResults;
+using DemaConsulting.TestResults.IO;
+
// Create a TestResults instance
-var results = new TestResults{Name = "SomeTests"};
+var results = new TestResults { Name = "SomeTests" };
// Add some results
results.Results.Add(
- new TestResult{
+ new TestResult
+ {
Name = "Test1",
ClassName = "SomeTestClass",
CodeBase = "MyTestAssembly",
- Outcome = TestOutcome.Passed
+ Outcome = TestOutcome.Passed,
+ Duration = TimeSpan.FromSeconds(1.5),
+ StartTime = DateTime.UtcNow,
+ EndTime = DateTime.UtcNow.AddSeconds(1.5)
+ });
+
+results.Results.Add(
+ new TestResult
+ {
+ Name = "Test2",
+ ClassName = "SomeTestClass",
+ CodeBase = "MyTestAssembly",
+ Outcome = TestOutcome.Failed,
+ ErrorMessage = "Expected value to be 42 but was 0",
+ ErrorStackTrace = "at SomeTestClass.Test2() in Test.cs:line 15"
});
// Save the results to file
@@ -33,3 +73,103 @@ File.WriteAllText(
"results.trx",
TrxSerializer.Serialize(results));
```
+
+## Advanced Usage
+
+### Capturing Standard Output
+
+```csharp
+var result = new TestResult
+{
+ Name = "TestWithOutput",
+ ClassName = "MyTests",
+ CodeBase = "MyAssembly",
+ Outcome = TestOutcome.Passed,
+ StdOut = "Debug information\nTest completed successfully"
+};
+```
+
+### Handling Test Failures
+
+```csharp
+var failedResult = new TestResult
+{
+ Name = "FailingTest",
+ ClassName = "MyTests",
+ CodeBase = "MyAssembly",
+ Outcome = TestOutcome.Failed,
+ ErrorMessage = "Assertion failed: Expected 100, got 50",
+ ErrorStackTrace = "at MyTests.FailingTest() in Tests.cs:line 42",
+ StdErr = "Additional error details"
+};
+```
+
+## Test Outcomes
+
+The library supports the following test outcomes:
+
+- `Passed` - Test passed successfully
+- `Failed` - Test failed
+- `Inconclusive` - Test result was inconclusive
+- `NotExecuted` - Test was not executed
+- `Timeout` - Test exceeded timeout limit
+- `Aborted` - Test was aborted
+- `Unknown` - Test outcome is unknown
+
+## Use Cases
+
+This library is useful when you need to:
+
+- Generate TRX files from custom test runners
+- Convert test results from other formats to TRX
+- Create test reports programmatically
+- Aggregate test results from multiple sources
+- Build custom testing tools that integrate with Visual Studio or Azure DevOps
+
+## Documentation
+
+- [Architecture](ARCHITECTURE.md) - Learn about the library's architecture and design
+- [Contributing](CONTRIBUTING.md) - Guidelines for contributing to the project
+- [Code of Conduct](CODE_OF_CONDUCT.md) - Our code of conduct for contributors
+
+## Building from Source
+
+```bash
+# Clone the repository
+git clone https://github.com/demaconsulting/TestResults.git
+cd TestResults
+
+# Restore tools
+dotnet tool restore
+
+# Restore dependencies
+dotnet restore
+
+# Build
+dotnet build
+
+# Run tests
+dotnet test
+```
+
+## Requirements
+
+- .NET 8.0, 9.0, or 10.0
+
+## Contributing
+
+We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
+
+## License
+
+This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
+
+## Support
+
+- 📝 [Report a Bug](https://github.com/demaconsulting/TestResults/issues/new?labels=bug)
+- 💡 [Request a Feature](https://github.com/demaconsulting/TestResults/issues/new?labels=enhancement)
+- 💬 [Ask a Question](https://github.com/demaconsulting/TestResults/discussions)
+
+## Acknowledgments
+
+Developed and maintained by [DEMA Consulting](https://github.com/demaconsulting).
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..7b772e8
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,132 @@
+# Security Policy
+
+## Supported Versions
+
+We release patches for security vulnerabilities for the following versions:
+
+| Version | Supported |
+| ------- | ------------------ |
+| Latest | :white_check_mark: |
+| < Latest| :x: |
+
+We recommend always using the latest version of the TestResults library to ensure you have the most recent security
+updates and bug fixes.
+
+## Reporting a Vulnerability
+
+The TestResults team takes security vulnerabilities seriously. We appreciate your efforts to responsibly disclose your
+findings.
+
+### How to Report a Security Vulnerability
+
+**Please do not report security vulnerabilities through public GitHub issues.**
+
+Instead, please report them using one of the following methods:
+
+1. **GitHub Security Advisories** (Preferred)
+ - Go to the [Security tab](https://github.com/demaconsulting/TestResults/security)
+ - Click on "Report a vulnerability"
+ - Fill out the form with details about the vulnerability
+
+2. **Direct Contact**
+ - Open a private security advisory on GitHub
+ - Contact the project maintainers directly through GitHub
+
+### What to Include in Your Report
+
+Please include the following information in your report:
+
+- **Description**: A clear description of the vulnerability
+- **Impact**: What kind of vulnerability is it and what is the potential impact?
+- **Location**: Where in the codebase the vulnerability exists
+- **Reproduction Steps**: Detailed steps to reproduce the vulnerability
+- **Proof of Concept**: If possible, provide a proof-of-concept or exploit code
+- **Suggested Fix**: If you have a suggestion for how to fix the vulnerability, please include it
+- **Your Details**: Your name and contact information (optional, but helpful for follow-up questions)
+
+### What to Expect
+
+After you submit a vulnerability report:
+
+1. **Acknowledgment**: We will acknowledge receipt of your vulnerability report within 3 business days
+2. **Investigation**: We will investigate and validate the vulnerability
+3. **Updates**: We will keep you informed about the progress of addressing the vulnerability
+4. **Resolution**: We will work on a fix and coordinate the release with you
+5. **Credit**: We will credit you in the security advisory (unless you prefer to remain anonymous)
+
+### Disclosure Policy
+
+- We ask that you give us reasonable time to address the vulnerability before any public disclosure
+- We will work with you to understand the severity and impact of the vulnerability
+- We will coordinate the release of security patches and advisories with you
+- We will publicly acknowledge your responsible disclosure (if you wish to be credited)
+
+## Security Measures
+
+The TestResults library implements several security best practices:
+
+### Code Security
+
+- **No External Dependencies**: The library has zero runtime dependencies, minimizing the attack surface
+- **Input Validation**: All public APIs validate their inputs
+- **No File Operations**: The library does not perform file I/O operations internally (caller controls file operations)
+- **No Network Operations**: The library does not make any network calls
+- **Static Analysis**: Code is analyzed with Microsoft.CodeAnalysis.NetAnalyzers
+- **Warnings as Errors**: All compiler warnings are treated as errors
+
+### Build Security
+
+- **Continuous Integration**: All code changes go through automated CI/CD pipelines
+- **SonarCloud Analysis**: Code quality and security are analyzed by SonarCloud
+- **Code Coverage**: Unit tests provide comprehensive code coverage
+- **SBOM Generation**: Software Bill of Materials is generated for all releases
+- **Dependency Scanning**: Dependencies are regularly scanned for known vulnerabilities
+
+### Development Security
+
+- **Code Review**: All changes require code review before merging
+- **Branch Protection**: The main branch is protected and requires passing CI checks
+- **Signed Commits**: We encourage signed commits for verification
+- **Least Privilege**: Development follows the principle of least privilege
+
+## Known Vulnerabilities
+
+We maintain transparency about known security issues:
+
+- No known vulnerabilities at this time
+
+Historical security advisories can be found in the
+[GitHub Security Advisories](https://github.com/demaconsulting/TestResults/security/advisories) section.
+
+## Security Best Practices for Users
+
+When using the TestResults library:
+
+1. **Keep Updated**: Always use the latest version of the library
+2. **Validate Input**: If accepting TRX file paths from users, validate and sanitize them
+3. **File Permissions**: When writing TRX files, use appropriate file permissions
+4. **Error Handling**: Implement proper error handling when using the library
+5. **Code Review**: Review any code that uses this library as part of your security practices
+
+## Scope
+
+This security policy applies to:
+
+- The TestResults library source code
+- Official NuGet packages published by DEMA Consulting
+- GitHub repository and infrastructure
+
+This policy does not cover:
+
+- Third-party applications that use the TestResults library
+- Forks of the repository not maintained by DEMA Consulting
+- Issues in dependencies (report those to the respective projects)
+
+## Contact
+
+For any questions about this security policy, please open an issue in the GitHub repository or contact the maintainers
+directly.
+
+## Attribution
+
+This security policy is based on security policy best practices and adapted for the TestResults project.
diff --git a/src/DemaConsulting.TestResults/DemaConsulting.TestResults.csproj b/src/DemaConsulting.TestResults/DemaConsulting.TestResults.csproj
index f32036f..dcd43d8 100644
--- a/src/DemaConsulting.TestResults/DemaConsulting.TestResults.csproj
+++ b/src/DemaConsulting.TestResults/DemaConsulting.TestResults.csproj
@@ -7,6 +7,9 @@
enable
true
True
+ true
+ true
+ latest
https://github.com/demaconsulting/TestResults
MIT
README.md
@@ -31,7 +34,15 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/src/DemaConsulting.TestResults/IO/TrxSerializer.cs b/src/DemaConsulting.TestResults/IO/TrxSerializer.cs
index d2c2f95..968af4f 100644
--- a/src/DemaConsulting.TestResults/IO/TrxSerializer.cs
+++ b/src/DemaConsulting.TestResults/IO/TrxSerializer.cs
@@ -1,4 +1,4 @@
-// Copyright(c) 2025 DEMA Consulting
+// Copyright(c) 2025 DEMA Consulting
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -266,4 +266,4 @@ private sealed class Utf8StringWriter : StringWriter
///
public override Encoding Encoding => Encoding.UTF8;
}
-}
\ No newline at end of file
+}
diff --git a/src/DemaConsulting.TestResults/TestOutcome.cs b/src/DemaConsulting.TestResults/TestOutcome.cs
index 6b486bc..7bd8b64 100644
--- a/src/DemaConsulting.TestResults/TestOutcome.cs
+++ b/src/DemaConsulting.TestResults/TestOutcome.cs
@@ -1,4 +1,4 @@
-// Copyright(c) 2025 DEMA Consulting
+// Copyright(c) 2025 DEMA Consulting
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -149,4 +149,4 @@ public static bool IsExecuted(this TestOutcome outcome)
_ => true
};
}
-}
\ No newline at end of file
+}
diff --git a/src/DemaConsulting.TestResults/TestResult.cs b/src/DemaConsulting.TestResults/TestResult.cs
index e4408f5..f0dbbba 100644
--- a/src/DemaConsulting.TestResults/TestResult.cs
+++ b/src/DemaConsulting.TestResults/TestResult.cs
@@ -1,4 +1,4 @@
-// Copyright(c) 2025 DEMA Consulting
+// Copyright(c) 2025 DEMA Consulting
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -89,4 +89,4 @@ public sealed class TestResult
/// Gets or sets the test case error stack trace
///
public string ErrorStackTrace { get; set; } = string.Empty;
-}
\ No newline at end of file
+}
diff --git a/src/DemaConsulting.TestResults/TestResults.cs b/src/DemaConsulting.TestResults/TestResults.cs
index 63364f0..bec33be 100644
--- a/src/DemaConsulting.TestResults/TestResults.cs
+++ b/src/DemaConsulting.TestResults/TestResults.cs
@@ -1,4 +1,4 @@
-// Copyright(c) 2025 DEMA Consulting
+// Copyright(c) 2025 DEMA Consulting
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -44,4 +44,4 @@ public sealed class TestResults
/// Gets or sets the list containing each TestResult
///
public List Results { get; set; } = [];
-}
\ No newline at end of file
+}
diff --git a/test/DemaConsulting.TestResults.Tests/DemaConsulting.TestResults.Tests.csproj b/test/DemaConsulting.TestResults.Tests/DemaConsulting.TestResults.Tests.csproj
index 7d2b1ce..4b06ff6 100644
--- a/test/DemaConsulting.TestResults.Tests/DemaConsulting.TestResults.Tests.csproj
+++ b/test/DemaConsulting.TestResults.Tests/DemaConsulting.TestResults.Tests.csproj
@@ -5,6 +5,9 @@
enable
enable
true
+ true
+ true
+ latest
false
true
@@ -20,9 +23,17 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/test/DemaConsulting.TestResults.Tests/IO/TrxExampleTests.cs b/test/DemaConsulting.TestResults.Tests/IO/TrxExampleTests.cs
index 75018bb..294f412 100644
--- a/test/DemaConsulting.TestResults.Tests/IO/TrxExampleTests.cs
+++ b/test/DemaConsulting.TestResults.Tests/IO/TrxExampleTests.cs
@@ -1,4 +1,4 @@
-// Copyright(c) 2025 DEMA Consulting
+// Copyright(c) 2025 DEMA Consulting
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -125,4 +125,4 @@ public void TestDeserializeExample2()
Assert.AreEqual(TestOutcome.Passed, results.Results[3].Outcome);
Assert.AreEqual(0.0000016, results.Results[3].Duration.TotalSeconds, 0.001);
}
-}
\ No newline at end of file
+}
diff --git a/test/DemaConsulting.TestResults.Tests/IO/TrxSerializerTests.cs b/test/DemaConsulting.TestResults.Tests/IO/TrxSerializerTests.cs
index 1b6ab16..a6db899 100644
--- a/test/DemaConsulting.TestResults.Tests/IO/TrxSerializerTests.cs
+++ b/test/DemaConsulting.TestResults.Tests/IO/TrxSerializerTests.cs
@@ -1,4 +1,4 @@
-// Copyright(c) 2025 DEMA Consulting
+// Copyright(c) 2025 DEMA Consulting
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -32,6 +32,13 @@ namespace DemaConsulting.TestResults.Tests.IO;
[TestClass]
public sealed class TrxSerializerTests
{
+#pragma warning disable S1075 // URIs should not be hardcoded - This is an XML namespace URI, not a file path
+ ///
+ /// TRX namespace URI
+ ///
+ private const string TrxNamespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010";
+#pragma warning restore S1075
+
///
/// Test for basic serialization
///
@@ -65,7 +72,7 @@ public void TestSerializeBasic()
// Parse the document
var doc = XDocument.Parse(result);
var nsMgr = new XmlNamespaceManager(new NameTable());
- nsMgr.AddNamespace("trx", "http://microsoft.com/schemas/VisualStudio/TeamTest/2010");
+ nsMgr.AddNamespace("trx", TrxNamespace);
// Verify the UnitTestResult element is present
Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:Results/trx:UnitTestResult[@testName='Test']", nsMgr));
@@ -124,7 +131,7 @@ public void TestSerializeComplex()
// Parse the document
var doc = XDocument.Parse(result);
var nsMgr = new XmlNamespaceManager(new NameTable());
- nsMgr.AddNamespace("trx", "http://microsoft.com/schemas/VisualStudio/TeamTest/2010");
+ nsMgr.AddNamespace("trx", TrxNamespace);
// Verify the UnitTestResult elements are present
Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:Results/trx:UnitTestResult[@testName='Test1']", nsMgr));
@@ -281,4 +288,4 @@ public void TestDeserializeComplex()
Assert.AreEqual(TestOutcome.Failed, result2.Outcome);
Assert.AreEqual("Error", result2.ErrorMessage);
}
-}
\ No newline at end of file
+}
diff --git a/test/DemaConsulting.TestResults.Tests/TestHelpers.cs b/test/DemaConsulting.TestResults.Tests/TestHelpers.cs
index 9b2e6a0..2211db7 100644
--- a/test/DemaConsulting.TestResults.Tests/TestHelpers.cs
+++ b/test/DemaConsulting.TestResults.Tests/TestHelpers.cs
@@ -1,4 +1,4 @@
-// Copyright(c) 2025 DEMA Consulting
+// Copyright(c) 2025 DEMA Consulting
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -41,4 +41,4 @@ public static string GetEmbeddedResource(string resourceName)
using var reader = new StreamReader(stream);
return reader.ReadToEnd().ReplaceLineEndings();
}
-}
\ No newline at end of file
+}
diff --git a/test/DemaConsulting.TestResults.Tests/TestOutcomeTests.cs b/test/DemaConsulting.TestResults.Tests/TestOutcomeTests.cs
index fbb9d8a..1579ee5 100644
--- a/test/DemaConsulting.TestResults.Tests/TestOutcomeTests.cs
+++ b/test/DemaConsulting.TestResults.Tests/TestOutcomeTests.cs
@@ -1,4 +1,4 @@
-// Copyright(c) 2025 DEMA Consulting
+// Copyright(c) 2025 DEMA Consulting
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -93,4 +93,4 @@ public void Test_Outcome_IsExecuted()
Assert.IsTrue(TestOutcome.InProgress.IsExecuted());
Assert.IsFalse(TestOutcome.Pending.IsExecuted());
}
-}
\ No newline at end of file
+}