Contributing to LogAssertions.TUnit

Thanks for considering a contribution. This document covers the small set of conventions that keep the project consistent.

Reporting bugs

Use the bug report template. The template asks for the LogAssertions.TUnit version, TUnit version, .NET SDK version, expected vs actual behavior, and a minimal reproduction. The smaller and more self-contained the repro, the faster the fix.

Proposing features

Use the feature request template. Describe the test scenario the feature enables, the proposed API shape (in code), and any alternatives you considered. Indicate whether you'd like to submit a PR yourself.

For larger ideas (new entry points, breaking changes, cross-cutting refactors), open a Discussion first to align on direction before investing implementation time.

Submitting a pull request

  1. Fork the repo and create a branch from main. Branch name convention: fix/short-description, feat/short-description, docs/short-description.
  2. Make your change. Keep it focused: a single logical change per PR.
  3. Add or update tests. The project uses TUnit; existing tests in tests/LogAssertions.TUnit.Tests/ show the patterns.
  4. Build clean: dotnet build must produce zero warnings (TreatWarningsAsErrors=true is enforced).
  5. Test green: dotnet test must pass.
  6. Update CHANGELOG.md under the ## [Unreleased] section.
  7. Open the PR. Use the PR template.

Code conventions

  • Language version: latest. Use modern C# (collection expressions, primary constructors where appropriate, etc.).
  • Nullability: enabled. All public APIs annotate nullability correctly.
  • XML documentation: required on every public type, member, and parameter.
  • Argument validation: public methods that take reference-type arguments use ArgumentNullException.ThrowIfNull(...) at the top of the body. Methods taking numeric arguments validate ranges with ArgumentOutOfRangeException.ThrowIfNegative(...) (or similar).
  • Spelling: American English in code, identifiers, and prose. (TUnit upstream uses British; this project does not. Don't take this as a stylistic preference, just a project rule.)
  • Globalisation: explicit CultureInfo.InvariantCulture on all string.Format, numeric ToString, and similar calls. Meziantou.Analyzer enforces this via MA0011.
  • String comparison: explicit StringComparison.Ordinal (or OrdinalIgnoreCase where appropriate). Meziantou.Analyzer enforces this via MA0006.

Tests

  • Tests live in tests/LogAssertions.TUnit.Tests/ (main behavior), tests/LogAssertions.Tests/ (framework-agnostic core, no TUnit reference), and tests/LogAssertions.TUnit.SnapshotTests/ (public API surface pin via MatchesSnapshot()).
  • Each public method on the assertion classes should have at least one test covering its happy path and at least one covering an invalid-input path.
  • Tests use TUnit's [Test] and the project's own assertion style (we eat our own dog food where possible).
  • Add [Category("Smoke")] to tests that should run in the pre-commit / fast feedback loop.

Snapshot files (when contributing tests)

Tests that use MatchesSnapshot() produce two file types:

  • *.expected.txt. The committed baseline. Diffed against actual output on every run.
  • *.actual.txt. The transient diff output, written when actual diverges from expected. Gitignored; never commit.

To accept a snapshot change:

  1. Locally, use your IDE's diff-and-merge view, or cp Snapshots/Foo.actual.txt Snapshots/Foo.expected.txt.
  2. Or run SNAPSHOT_ACCEPT=1 dotnet test to bulk-accept all changes.
  3. CI never sets SNAPSHOT_ACCEPT; mismatches fail the build.

Releases

Versioning follows Semantic Versioning:

  • 0.x.y while the API is evolving: minor bumps may include breaking changes.
  • 1.0.0 and beyond: breaking changes only on major-version bumps.

Releases are published to NuGet via a tagged commit on main. The <Version> in LogAssertions.TUnit.csproj is the source of truth for the package version.

Code of conduct

This project follows the Contributor Covenant Code of Conduct. By participating, you agree to abide by its terms.

License

By contributing, you agree that your contributions will be licensed under the same MIT License that covers the project.