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 @@ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=demaconsulting_TestResults&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=demaconsulting_TestResults) [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=demaconsulting_TestResults&metric=security_rating)](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 +}