Trax.Core.Testing
The base package of Trax's architecture guards: the options and result types every guard shares, the helpers that find a repository's files, and three sets of guards of its own. The other guard packages (Trax.Effect.Data.Testing, Trax.Mediator.Testing, Trax.Api.GraphQL.Testing) build on it. See Architecture Guards for how they fit together.
Each guard is available two ways: as a static checker that returns a GuardResult you assert on with any framework, and, for the hygiene and repo-convention guards, as an NUnit fixture you subclass.
ArchitectureGuardOptions
namespace Trax.Core.Testing;
public sealed record ArchitectureGuardOptions
{
public string? RepoRootOverride { get; init; }
public IReadOnlyList<string> TestScanRoots { get; init; } // ["tests"]
public IReadOnlyList<string> SourceScanRoots { get; init; } // ["src"]
public IReadOnlySet<string> NoIgnoreKnownExceptions { get; init; }
public IReadOnlySet<string> FixedDelayKnownExceptions { get; init; }
public string ExpectedDirectoryBuildPropsVersion { get; init; } // "1.99.99"
public string TraxPackagePrefix { get; init; } // "Trax."
public IReadOnlySet<string> CrossRepoPackageKnownExceptions { get; init; }
}| Property | Default | Description |
|---|---|---|
RepoRootOverride | null | The root to scan instead of the detected one, mainly for testing a guard against a synthetic tree |
TestScanRoots | ["tests"] | Top-level folders holding test code, scanned by the hygiene guards |
SourceScanRoots | ["src"] | Top-level folders holding production code |
NoIgnoreKnownExceptions | empty | Repo-relative files exempt from the no-[Ignore] guard |
FixedDelayKnownExceptions | empty | Repo-relative files exempt from the no-fixed-delay guard |
ExpectedDirectoryBuildPropsVersion | "1.99.99" | The <Version> the root Directory.Build.props must declare |
TraxPackagePrefix | "Trax." | Package ids that count as cross-repo Trax references |
CrossRepoPackageKnownExceptions | empty | Repo-relative project files exempt from the cross-repo package guard |
Allowlist paths are repo-relative with forward slashes.
GuardResult
public sealed record GuardResult(IReadOnlyList<string> Offenders, int Inspected, string FailureMessage)
{
public bool Passed { get; }
}| Member | Description |
|---|---|
Offenders | One description per violation, usually path:line (reason) |
Inspected | How many files or items the guard examined. A guard that inspected nothing checked nothing; assert it is above zero. |
FailureMessage | The rule, how to fix a violation, and the offender list |
Passed | Offenders is empty |
Infrastructure
| Type | Members | Description |
|---|---|---|
RepoRoot (Trax.Core.Testing.Infrastructure) | Path, Combine(params string[]), Relative(string) | The repository root: the first directory above the test assembly that contains a *.slnx file. Throws InvalidOperationException when none is found, so a repository with only a .sln must set RepoRootOverride. |
SourceFiles | CSharp, Projects, Markdown, CSharpUnder, ProjectsUnder | Enumerate *.cs, *.csproj and *.md files under the root, or under an explicit root |
SourceText | StripCommentsAndStrings(string), MatchingLines(string, Regex) | Blank out comments and string literals so a pattern matches code only; list the matching lines with their numbers |
Hygiene guards
Checker (HygieneGuards) | Flags, in TestScanRoots |
|---|---|
NoIgnoreAttribute(options) | [Ignore] in any form, and Ignore = or IgnoreReason = on a TestCase, TestCaseSource or fixture attribute |
NoLegacyAsserts(options) | NUnit's own asserts: Assert.That, Assert.AreEqual and the rest of the classic family, ClassicAssert, CollectionAssert, StringAssert. The convention is one assertion library. |
NoFixedDelays(options) | Task.Delay( and Thread.Sleep(, unless the line or one of the three above it carries a comment with determinism:, allowed-delay:, measuring-interval: or negative-wait: |
HygieneGuardFixture (Trax.Core.Testing.Fixtures) runs all three as NUnit tests. Subclass it, override Options if the defaults do not fit, and the inherited tests run in your assembly. Each test fails first if the guard inspected nothing, then on any offender.
Repo-convention guards
Checker (RepoConventionGuards) | Checks |
|---|---|
DirectoryBuildPropsVersion(options) | The root Directory.Build.props exists and its <Version> equals ExpectedDirectoryBuildPropsVersion |
CrossRepoPackageVersions(options) | Every PackageReference whose id starts with TraxPackagePrefix carries no Version or VersionOverride and has a <PackageVersion> pin in the root Directory.Packages.props |
RepoConventionGuardFixture runs both as NUnit tests.
These encode the Trax repositories' own build conventions. The version check in particular expects the local-development placeholder 1.99.99 that the Trax repositories keep in Directory.Build.props. A consumer repository that versions differently either sets ExpectedDirectoryBuildPropsVersion to its own value or does not use this fixture.
Vocabulary guard
public sealed record ForeignVocabulary(string Library, IReadOnlyList<string> Attributes, string Replacement);
public static class VocabularyGuards
{
public static GuardResult TraxVocabularyIsUsed(
IReadOnlyList<ForeignVocabulary> banned,
ArchitectureGuardOptions? options = null,
IReadOnlyDictionary<string, string>? allowed = null
);
}Reports every use of a listed third-party attribute where Trax has its own, in both SourceScanRoots and TestScanRoots.
| Parameter | Description |
|---|---|
banned | The vocabularies to refuse. Library is a token that must appear in a file (normally the library's root namespace) before its attributes count, unless a global or project-level using imports it. Attributes are names without the Attribute suffix. Replacement is what to write instead. |
options | Scan roots and repo root; defaults apply when null |
allowed | Repo-relative paths exempt from the scan, each mapped to the reason: the translation layer that has to speak the library's language, and the tests that write the refused attribute on purpose |
Comments and string literals are ignored.
[Test]
public void Resolvers_use_Trax_authorization_attributes()
{
var result = VocabularyGuards.TraxVocabularyIsUsed(
[new ForeignVocabulary("HotChocolate", ["Authorize", "AllowAnonymous"],
"[TraxAuthorize] or [TraxAllowAnonymous]")]);
result.Inspected.Should().BeGreaterThan(0);
result.Offenders.Should().BeEmpty(result.FailureMessage);
}Package
dotnet add package Trax.Core.TestingIt references NUnit, for the fixtures.