Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ updates:
fallout:
patterns:
- "Fallout*"
xunit:
tunit:
patterns:
- "xunit*"
- "TUnit*"
aweXpect:
patterns:
- "aweXpect*"
Expand Down
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Mockolate is a source-generated mocking library for .NET. Users write `IFoo.Crea

## SDK and Build

- Use the SDK pinned in `global.json` (.NET 10, `rollForward: latestMinor`). Tests also run on .NET 8, and on .NET Framework 4.8 on Windows only.
- Build from the root with `dotnet build Mockolate.slnx`. Shared settings live in the root `Directory.Build.props` (strong naming, `MinimumRoslynVersion`), `Source/Directory.Build.props` (target frameworks, warnings as errors, AOT and trimming flags) and `Tests/Directory.Build.props` (test frameworks, xUnit, aweXpect).
- Use the SDK pinned in `global.json` (.NET 10, `rollForward: latestPatch`). Tests also run on .NET 8, and on .NET Framework 4.8 on Windows only.
- Build from the root with `dotnet build Mockolate.slnx`. Shared settings live in the root `Directory.Build.props` (strong naming, `MinimumRoslynVersion`), `Source/Directory.Build.props` (target frameworks, warnings as errors, AOT and trimming flags) and `Tests/Directory.Build.props` (test frameworks, TUnit, aweXpect).
- Package versions belong only in `Directory.Packages.props`. `VersionOverride` is used only to pin Roslyn packages to `$(MinimumRoslynVersion)`.

## Design Goals
Expand All @@ -22,7 +22,7 @@ Correctness is a must. The other goals are strong defaults and win in this order
- **Performance**: recording, setup matching and verification are hot paths with allocation-free fast paths (`FastMockInteractions`, the `Fast*Buffer` types). Measure hot-path changes with the benchmarks before and after.
- **Public API**: every change to the public surface of `Mockolate` shows up in the API snapshots. Document new public members with XML comments. Mark breaking changes with `!` in the PR title (`feat!:`, `refactor!:`).
- **Strong naming**: all assemblies are signed with `strongname.snk`; an `InternalsVisibleTo` needs `PublicKey="$(PublicKey)"`.
- **Style**: follow `.editorconfig`: tabs, explicit types instead of `var`, `_camelCase` private fields, no `this.`, `System` usings first. Tests use xUnit with aweXpect (`await That(...)`).
- **Style**: follow `.editorconfig`: tabs, explicit types instead of `var`, `_camelCase` private fields, no `this.`, `System` usings first. Tests use TUnit with aweXpect (`await That(...)`).

## Validation

Expand Down
8 changes: 3 additions & 5 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,10 @@
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="10.0.401"/>
</ItemGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.10.1"/>
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8"/>
<PackageVersion Include="xunit" Version="2.9.3"/>
<PackageVersion Include="xunit.v3" Version="3.2.2"/>
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5"/>
<PackageVersion Include="coverlet.collector" Version="10.1.0"/>
<PackageVersion Include="TUnit.Engine" Version="1.72.16"/>
<PackageVersion Include="Microsoft.Testing.Extensions.TrxReport" Version="2.5.1"/>
<PackageVersion Include="Microsoft.Testing.Extensions.CodeCoverage" Version="18.12.0"/>
<PackageVersion Include="aweXpect.Snapshots.PublicApi" Version="0.3.0"/>
<PackageVersion Include="aweXpect" Version="3.4.0"/>
<PackageVersion Include="aweXpect.Chronology" Version="1.1.0"/>
Expand Down
29 changes: 17 additions & 12 deletions Docs/agents/workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,20 @@ The test projects reference the generator as an analyzer through a project refer

## Test

The tests use TUnit on the Microsoft.Testing.Platform, which `global.json` selects as the runner of `dotnet test`. Each test project is an executable, so `dotnet run` works as well. The explicit tests (the snapshot acceptance tests) run only when the filter selects nothing but explicit tests.

```powershell
# One project, all of its target frameworks
dotnet test Tests/Mockolate.Tests
dotnet test --project Tests/Mockolate.Tests

# One framework and a tree node filter (/assembly/namespace/class/test, nested classes match with a wildcard)
dotnet test --project Tests/Mockolate.Tests -f net10.0 --treenode-filter "/*/*/*IsTrueTests/*"

# One framework and a name filter (VSTest filter syntax)
dotnet test Tests/Mockolate.Tests -f net10.0 --filter "FullyQualifiedName~IsTrueTests"
# The same without dotnet test
dotnet run --project Tests/Mockolate.Tests -f net10.0 -- --treenode-filter "/*/*/*IsTrueTests/*"

# Everything in the solution
dotnet test Mockolate.slnx
dotnet test --solution Mockolate.slnx
```

Target frameworks per test project:
Expand Down Expand Up @@ -52,7 +57,7 @@ A newer language feature can compile for `net10.0` and fail for `net48`; build o
After an intended change, overwrite the expected files with the explicit acceptance test and review the diff:

```powershell
dotnet test Tests/Mockolate.SourceGenerators.Tests --filter "FullyQualifiedName~AcceptSnapshotChanges" -- xUnit.Explicit=only
dotnet test --project Tests/Mockolate.SourceGenerators.Tests --treenode-filter "/*/*/*/AcceptSnapshotChanges"
git diff -- Tests/Mockolate.SourceGenerators.Tests/Snapshot
```

Expand All @@ -67,7 +72,7 @@ To add a scenario, add an entry to `Scenarios` and run the acceptance test.
- run the tests with `AWEXPECT_ACCEPT_SNAPSHOTS=all`.

```powershell
dotnet test Tests/Mockolate.Api.Tests --filter "FullyQualifiedName~AcceptApiChanges" -- xUnit.Explicit=only
dotnet test --project Tests/Mockolate.Api.Tests --treenode-filter "/*/*/*/AcceptApiChanges"
```

Commit the updated snapshots with the change; never commit pending files.
Expand Down Expand Up @@ -96,13 +101,13 @@ CI runs one job per class: `CallbackBenchmarks`, `CompleteEventBenchmarks`, `Com

## Mutation Tests

Stryker mutates `Source/Mockolate` against `Mockolate.Tests` and `Mockolate.Internal.Tests` on `net8.0` with mutation level `Advanced`. Outside `main` it only mutates code changed since `main`. A full run takes long; run it only when asked:
Stryker mutates `Source/Mockolate` against `Mockolate.Tests` and `Mockolate.Internal.Tests` on `net8.0` with mutation level `Advanced`, through its runner for the Microsoft.Testing.Platform (`--test-runner mtp`). The version is the `dotnet-stryker` `PackageDownload` in `Pipeline/Build.csproj`. Outside `main` it only mutates code changed since `main`. A full run takes long; run it only when asked:

```powershell
./build.ps1 MutationTestExecution
./build.ps1 MutationTests
```

Reports go to `Artifacts/Stryker`. The `MutationTests` target also prepares the PR comment and expects to run in GitHub Actions.
Reports go to `Artifacts/Stryker`, together with the Markdown body of the PR comment. `MutationTestsComment` and `MutationTestsDashboard` post the comment and upload the report, and expect to run in GitHub Actions.

## Build Pipeline (Fallout)

Expand All @@ -111,14 +116,14 @@ Reports go to `Artifacts/Stryker`. The `MutationTests` target also prepares the
| Target | Purpose |
|---|---|
| `Compile` | Restore and build the solution with the GitVersion-derived version |
| `UnitTests` | Run `Build.Tests`, `Mockolate.Tests`, `Mockolate.Internal.Tests`, `Mockolate.Analyzers.Tests` and `Mockolate.SourceGenerators.Tests` for each framework (`net48` only on Windows) with coverage |
| `CodeCoverage` | `UnitTests` plus a ReportGenerator OpenCover report in `TestResults/reports` |
| `UnitTests` | Run `Build.Tests`, `Mockolate.Tests`, `Mockolate.Internal.Tests`, `Mockolate.Analyzers.Tests` and `Mockolate.SourceGenerators.Tests` for each framework (`net48` only on Windows), with a TRX and a Cobertura coverage file per project and framework in `TestResults` |
| `CodeCoverage` | `UnitTests` plus a ReportGenerator SonarQube report in `TestResults/reports` |
| `ApiChecks` | Run `Mockolate.Api.Tests` |
| `CodeAnalysis` | SonarCloud analysis (needs `SonarToken`) |
| `Pack` | Build the NuGet package into `Artifacts/Packages`, with a release-specific README |
| `Benchmarks` | Run the benchmarks (`--benchmark-filter`, default `*`) and print the reports |
| `BenchmarkComment`, `PublishBenchmarkReport` | CI only: PR comment and docs site data |
| `MutationTests`, `MutationTestExecution`, `MutationTestComment`, `MutationTestDashboard` | Stryker run, PR comment and dashboard upload |
| `MutationTests`, `MutationTestsComment`, `MutationTestsDashboard` | Stryker run, PR comment and dashboard upload |
| `UpdateReadme` | Write the packaged README to `Artifacts/README.md` |

## CI Workflows
Expand Down
7 changes: 4 additions & 3 deletions Pipeline/Build.ApiChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ partial class Build
.SetProcessEnvironmentVariable("DOTNET_CLI_UI_LANGUAGE", "en-US")
.EnableNoBuild()
.SetResultsDirectory(TestResultsDirectory)
.CombineWith(cc => cc
.SetProjectFile(project)
.AddLoggers($"trx;LogFileName={project.Name}.trx")), completeOnFailure: true);
.AddProcessAdditionalArguments(
$"--project \"{project.Path}\"",
"--report-trx",
$"--report-trx-filename {project.Name}.trx"));
});
}
2 changes: 1 addition & 1 deletion Pipeline/Build.CodeCoverage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ partial class Build
.SetProcessToolPath(NuGetToolPathResolver.GetPackageExecutable("ReportGenerator", "ReportGenerator.dll",
framework: "net10.0"))
.SetTargetDirectory(TestResultsDirectory / "reports")
.AddReports(TestResultsDirectory / "**/coverage.cobertura.xml")
.AddReports(TestResultsDirectory / "**/*.cobertura.xml")
// The generic format of Sonar lists the lines per file. A format that lists them per method leaves out the
// lines of a lambda in a generic class, because ReportGenerator keeps them in a class without methods.
.AddReportTypes(ReportTypes.SonarQube)
Expand Down
3 changes: 2 additions & 1 deletion Pipeline/Build.MutationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,9 @@ partial class Build
File.WriteAllText(configFile, configText);
Log.Debug($"Created '{configFile}':{Environment.NewLine}{configText}");

// The unit tests are executables of the Microsoft.Testing.Platform, which the default runner (VSTest) cannot run.
string arguments =
$"-f \"{configFile}\" -O \"{strykerOutputDirectory}\" -r \"Markdown\" -r \"cleartext\" -r \"json\"";
$"-f \"{configFile}\" -O \"{strykerOutputDirectory}\" -r \"Markdown\" -r \"cleartext\" -r \"json\" --test-runner mtp";

string executable = EnvironmentInfo.IsWin ? "dotnet-stryker.exe" : "dotnet-stryker";
IProcess process = ProcessTasks.StartProcess(
Expand Down
10 changes: 7 additions & 3 deletions Pipeline/Build.UnitTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,21 @@ partial class Build
.SetConfiguration(Configuration)
.SetProcessEnvironmentVariable("DOTNET_CLI_UI_LANGUAGE", "en-US")
.EnableNoBuild()
.SetDataCollector("XPlat Code Coverage")
.SetResultsDirectory(TestResultsDirectory)
.CombineWith(
UnitTestProjects,
(settings, project) => settings
.SetProjectFile(project)
.CombineWith(
project.GetTargetFrameworks()?.Except(excludedFrameworks),
(frameworkSettings, framework) => frameworkSettings
.SetFramework(framework)
.AddLoggers($"trx;LogFileName={project.Name}_{framework}.trx")
.AddProcessAdditionalArguments(
$"--project \"{project.Path}\"",
"--report-trx",
$"--report-trx-filename {project.Name}_{framework}.trx",
"--coverage",
"--coverage-output-format cobertura",
$"--coverage-output {project.Name}_{framework}.cobertura.xml")
)
), completeOnFailure: true
);
Expand Down
2 changes: 0 additions & 2 deletions Pipeline/Build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@
</ItemGroup>

<ItemGroup>
<PackageDownload Include="coverlet.console" Version="[3.1.2]"/>
<PackageDownload Include="dotnet-sonarscanner" Version="[9.0.2]"/>
<PackageDownload Include="dotnet-stryker" Version="[5.0.0]"/>
<PackageDownload Include="GitVersion.Tool" Version="[6.0.5]"/>
<PackageDownload Include="ReportGenerator" Version="[5.4.1]"/>
<PackageDownload Include="xunit.runner.console" Version="[2.9.2]"/>
</ItemGroup>

</Project>
Loading
Loading