From be108ff07edc6ee56a7fd5b2bab2f69851bccedb Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Mon, 19 Jan 2026 07:39:02 -0500 Subject: [PATCH 1/5] feat(config): add opencode configuration file - Introduced `opencode.json` for configuring permissions. - Set `git` permission level to require explicit confirmation. --- opencode.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 opencode.json diff --git a/opencode.json b/opencode.json new file mode 100644 index 00000000..81bc9f48 --- /dev/null +++ b/opencode.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://opencode.ai/config.json", + "permission": { + "git": "ask" + } +} \ No newline at end of file From be953527c5bc61583351b5f40bf544bc6ec3e5d3 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Mon, 19 Jan 2026 08:15:48 -0500 Subject: [PATCH 2/5] feat(testing): enhance testing with improved coverage support - Switched to `--coverage` and `cobertura` output format for streamlined coverage reporting. - Added `Microsoft.Testing.Extensions.CodeCoverage` dependency across all unit test projects. - Introduced test commands and filtering examples in documentation. - Improved GitHub Actions workflows to upload consistent coverage reports. - Enforced a minimum shutdown timeout of 30 seconds in `LambdaApplicationFactory`. --- .github/workflows/main-build.yaml | 4 +- .github/workflows/pr-build.yaml | 4 +- CLAUDE.md | 56 +++++++++++++++++++ CONTRIBUTING.md | 4 +- Directory.Packages.props | 1 + global.json | 5 +- .../LambdaApplicationFactory.cs | 7 +++ tasks/TestTasks.yml | 6 +- .../MinimalLambda.Envelopes.UnitTests.csproj | 3 +- ...nimalLambda.OpenTelemetry.UnitTests.csproj | 3 +- ...alLambda.SourceGenerators.UnitTests.csproj | 3 +- .../MinimalLambda.Testing.UnitTests.csproj | 3 +- .../MinimalLambda.UnitTests.csproj | 3 +- 13 files changed, 87 insertions(+), 15 deletions(-) diff --git a/.github/workflows/main-build.yaml b/.github/workflows/main-build.yaml index 2e98281b..3207e8b0 100644 --- a/.github/workflows/main-build.yaml +++ b/.github/workflows/main-build.yaml @@ -86,7 +86,7 @@ jobs: run: dotnet build --no-restore --configuration Release /p:TreatWarningsAsErrors=true - name: Run tests - run: dotnet test --no-build --configuration Release --verbosity normal --collect:"XPlat Code Coverage" --results-directory ./coverage + run: dotnet test --no-build --configuration Release --verbosity normal --results-directory ./coverage --coverage --coverage-output-format cobertura - name: Stop SonarQube env: @@ -99,7 +99,7 @@ jobs: - name: Upload coverage reports uses: codecov/codecov-action@v5 with: - files: ./coverage/**/coverage.cobertura.xml + files: ./coverage/**/*.cobertura.xml disable_search: true token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true \ No newline at end of file diff --git a/.github/workflows/pr-build.yaml b/.github/workflows/pr-build.yaml index 1dc945b3..a9c8e0ff 100644 --- a/.github/workflows/pr-build.yaml +++ b/.github/workflows/pr-build.yaml @@ -107,7 +107,7 @@ jobs: run: dotnet build --no-restore --configuration Release /p:TreatWarningsAsErrors=true - name: Run tests - run: dotnet test --no-build --configuration Release --verbosity normal --collect:"XPlat Code Coverage" --results-directory ./coverage + run: dotnet test --no-build --configuration Release --verbosity normal --results-directory ./coverage --coverage --coverage-output-format cobertura - name: Stop SonarQube env: @@ -120,7 +120,7 @@ jobs: - name: Upload coverage reports uses: codecov/codecov-action@v5 with: - files: ./coverage/**/coverage.cobertura.xml + files: ./coverage/**/*.cobertura.xml disable_search: true token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true diff --git a/CLAUDE.md b/CLAUDE.md index bb29332c..735701ee 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -82,6 +82,62 @@ internal async Task MyTest( - Combine both: use `[AutoNSubstituteData]` with `[Frozen]` to inject configured mocks from a manual fixture +# Test Commands + +```bash +# Run all tests across all target frameworks (net8.0, net9.0, net10.0) +dotnet test + +# Run tests for a specific framework +# (recommended when working on a single test failure) +dotnet test --framework net8.0 + +# Run tests with verbose output +dotnet test --logger "console;verbosity=detailed" + +# Run tests in a specific project (avoid running other test projects) +dotnet test --project test/LayeredCraft.DynamoMapper.Generators.Tests/LayeredCraft.DynamoMapper.Generators.Tests.csproj + +# Discover available tests (xUnit v3 + Microsoft.Testing.Platform) +# Copy the fully-qualified test name from this output. +DOTNET_NOLOGO=1 dotnet test \ + --project test/LayeredCraft.DynamoMapper.Generators.Tests/LayeredCraft.DynamoMapper.Generators.Tests.csproj \ + -f net10.0 \ + -v q \ + --list-tests \ + --no-progress \ + --no-ansi + +# Run a single test method (exact fully-qualified name) +DOTNET_NOLOGO=1 dotnet test \ + --project test/LayeredCraft.DynamoMapper.Generators.Tests/LayeredCraft.DynamoMapper.Generators.Tests.csproj \ + -f net10.0 \ + -v q \ + --filter-method "MyNamespace.MyTestClass.MyTestMethod" \ + --minimum-expected-tests 1 \ + --no-progress \ + --no-ansi + +# Common filter variants +DOTNET_NOLOGO=1 dotnet test \ + --project test/LayeredCraft.DynamoMapper.Generators.Tests/LayeredCraft.DynamoMapper.Generators.Tests.csproj \ + -f net10.0 \ + -v q \ + --filter-class "MyNamespace.MyTestClass" \ + --minimum-expected-tests 1 \ + --no-progress \ + --no-ansi + +DOTNET_NOLOGO=1 dotnet test \ + --project test/LayeredCraft.DynamoMapper.Generators.Tests/LayeredCraft.DynamoMapper.Generators.Tests.csproj \ + -f net10.0 \ + -v q \ + --filter-namespace "MyNamespace.Tests" \ + --minimum-expected-tests 1 \ + --no-progress \ + --no-ansi +``` + # C# 14 Extension Members - Valid Syntax ## This is VALID C# 14 syntax - do NOT change it diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5021eb3..482713cd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -293,8 +293,8 @@ dotnet test tests/MinimalLambda.UnitTests # Run with verbose output dotnet test --verbosity detailed -# Run with coverage (if configured) -dotnet test /p:CollectCoverage=true +# Run with coverage (MTP) +dotnet test --coverage --coverage-output-format cobertura ``` ### Test Requirements diff --git a/Directory.Packages.props b/Directory.Packages.props index b430d226..c2b4f5db 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -50,6 +50,7 @@ + diff --git a/global.json b/global.json index 38f47fae..4ea65709 100644 --- a/global.json +++ b/global.json @@ -2,5 +2,8 @@ "sdk": { "rollForward": "latestMinor", "version": "10.0.101" + }, + "test": { + "runner": "Microsoft.Testing.Platform" } -} \ No newline at end of file +} diff --git a/src/MinimalLambda.Testing/LambdaApplicationFactory.cs b/src/MinimalLambda.Testing/LambdaApplicationFactory.cs index a10e0b2c..e2c5bbfc 100644 --- a/src/MinimalLambda.Testing/LambdaApplicationFactory.cs +++ b/src/MinimalLambda.Testing/LambdaApplicationFactory.cs @@ -286,6 +286,13 @@ private void ConfigureHostBuilder( if (string.IsNullOrEmpty(options.BootstrapOptions.RuntimeApiEndpoint)) options.BootstrapOptions.RuntimeApiEndpoint = "localhost"; }); + + services.PostConfigure(options => + { + var minShutdownTimeout = TimeSpan.FromSeconds(30); + if (options.ShutdownTimeout < minShutdownTimeout) + options.ShutdownTimeout = minShutdownTimeout; + }); }); // Build the host but DON'T start it - server will start it diff --git a/tasks/TestTasks.yml b/tasks/TestTasks.yml index 92b53388..6c25f337 100644 --- a/tasks/TestTasks.yml +++ b/tasks/TestTasks.yml @@ -14,7 +14,7 @@ tasks: silent: true cmds: - echo "🧪 Running unit tests" - - dotnet test --configuration Release --filter "Category=Unit" --no-build + - dotnet test --configuration Release --filter-trait "Category=Unit" --no-build - echo "✅ Unit tests completed!" coverage: @@ -22,7 +22,7 @@ tasks: silent: true cmds: - echo "📊 Running tests with coverage collection" - - dotnet test --configuration Release --collect:"XPlat Code Coverage" --no-build + - dotnet test --configuration Release --coverage --coverage-output-format cobertura --no-build - echo "✅ Coverage collection completed!" watch: @@ -30,7 +30,7 @@ tasks: silent: true cmds: - echo "👀 Starting test watch mode" - - dotnet watch --project tests/MinimalLambda.Tests test --configuration Release + - dotnet watch --project tests/MinimalLambda.UnitTests test --configuration Release verbose: desc: Run tests with detailed output for debugging diff --git a/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj b/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj index 3aedce4e..5fbe672a 100644 --- a/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj +++ b/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj @@ -1,4 +1,4 @@ - + net8.0;net9.0;net10.0 preview @@ -17,6 +17,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj b/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj index e8940ea9..fb086804 100644 --- a/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj +++ b/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj @@ -1,4 +1,4 @@ - + net9.0;net10.0 preview @@ -26,6 +26,7 @@ + all diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj b/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj index 56bd27fd..a25fbcdc 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj @@ -1,4 +1,4 @@ - + net8.0;net9.0;net10.0 latest @@ -18,6 +18,7 @@ + diff --git a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj index b9a2609d..cd12180b 100644 --- a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj +++ b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj @@ -1,4 +1,4 @@ - + net8.0;net9.0;net10.0 enable @@ -23,6 +23,7 @@ + all diff --git a/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj b/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj index 7cf404d3..40a8c650 100644 --- a/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj +++ b/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj @@ -1,4 +1,4 @@ - + net8.0;net9.0;net10.0 enable @@ -33,6 +33,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive From 347a2ca28faad88fd7f43248b4c7f1a876dc08f1 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Mon, 19 Jan 2026 08:34:59 -0500 Subject: [PATCH 3/5] docs(testing): update test commands and examples in documentation - Introduced task wrappers for common testing workflows. - Updated direct `dotnet` command examples with detailed use cases. - Added test filtering examples for improved usability. - Replaced outdated project references with `MinimalLambda.UnitTests`. --- CLAUDE.md | 86 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 735701ee..4de85d18 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -84,58 +84,60 @@ internal async Task MyTest( # Test Commands -```bash -# Run all tests across all target frameworks (net8.0, net9.0, net10.0) -dotnet test +Task wrappers (recommended): -# Run tests for a specific framework -# (recommended when working on a single test failure) -dotnet test --framework net8.0 +```bash +task test:all # dotnet test (Release) +task test:verbose # dotnet test (detailed logs) +task test:coverage # dotnet test + coverage +task test:watch # dotnet watch ... test +``` -# Run tests with verbose output -dotnet test --logger "console;verbosity=detailed" +Direct `dotnet` commands: +```bash +# Run the full test suite (solution-level) +DOTNET_NOLOGO=1 dotnet test --configuration Release -# Run tests in a specific project (avoid running other test projects) -dotnet test --project test/LayeredCraft.DynamoMapper.Generators.Tests/LayeredCraft.DynamoMapper.Generators.Tests.csproj +# Faster inner loop: run a single target framework (projects are multi-targeted) +DOTNET_NOLOGO=1 dotnet test --configuration Release -f net10.0 -# Discover available tests (xUnit v3 + Microsoft.Testing.Platform) -# Copy the fully-qualified test name from this output. -DOTNET_NOLOGO=1 dotnet test \ - --project test/LayeredCraft.DynamoMapper.Generators.Tests/LayeredCraft.DynamoMapper.Generators.Tests.csproj \ - -f net10.0 \ - -v q \ - --list-tests \ - --no-progress \ - --no-ansi - -# Run a single test method (exact fully-qualified name) +# Run a single test project DOTNET_NOLOGO=1 dotnet test \ - --project test/LayeredCraft.DynamoMapper.Generators.Tests/LayeredCraft.DynamoMapper.Generators.Tests.csproj \ - -f net10.0 \ - -v q \ - --filter-method "MyNamespace.MyTestClass.MyTestMethod" \ - --minimum-expected-tests 1 \ - --no-progress \ - --no-ansi + --project tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj \ + --configuration Release -f net10.0 + +# Verbose output for debugging +DOTNET_NOLOGO=1 dotnet test --configuration Release --logger "console;verbosity=detailed" +``` -# Common filter variants +Run a single test (xUnit v3 + Microsoft.Testing.Platform) + +This repo pins the test runner in `global.json`: + +```json +"test": {"runner": "Microsoft.Testing.Platform"} +``` + +```bash +# list tests (copy fully-qualified name) DOTNET_NOLOGO=1 dotnet test \ - --project test/LayeredCraft.DynamoMapper.Generators.Tests/LayeredCraft.DynamoMapper.Generators.Tests.csproj \ - -f net10.0 \ - -v q \ - --filter-class "MyNamespace.MyTestClass" \ - --minimum-expected-tests 1 \ - --no-progress \ - --no-ansi + --project tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj \ + -f net10.0 -v q \ + --list-tests --no-progress --no-ansi +# run one test method DOTNET_NOLOGO=1 dotnet test \ - --project test/LayeredCraft.DynamoMapper.Generators.Tests/LayeredCraft.DynamoMapper.Generators.Tests.csproj \ - -f net10.0 \ - -v q \ - --filter-namespace "MyNamespace.Tests" \ + --project tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj \ + -f net10.0 -v q \ + --filter-method "MyNamespace.MyTestClass.MyTestMethod" \ --minimum-expected-tests 1 \ - --no-progress \ - --no-ansi + --no-progress --no-ansi + +# handy filters +DOTNET_NOLOGO=1 dotnet test --project tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj -f net10.0 -v q \ + --filter-class "MyNamespace.MyTestClass" --minimum-expected-tests 1 --no-progress --no-ansi +DOTNET_NOLOGO=1 dotnet test --project tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj -f net10.0 -v q \ + --filter-namespace "MyNamespace.Tests" --minimum-expected-tests 1 --no-progress --no-ansi ``` # C# 14 Extension Members - Valid Syntax From a52619932db68a199efb58f9c061ef5d0d61d5c2 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Mon, 19 Jan 2026 10:13:46 -0500 Subject: [PATCH 4/5] refactor(dependencies): normalize and align package references across projects - Fixed inconsistent formatting of `Microsoft.Testing.Extensions.CodeCoverage` references. - Adjusted SDK version in `global.json` from `10.0.102` to `10.0.101`. --- global.json | 2 +- .../MinimalLambda.Envelopes.UnitTests.csproj | 2 +- .../MinimalLambda.OpenTelemetry.UnitTests.csproj | 2 +- .../MinimalLambda.SourceGenerators.UnitTests.csproj | 2 +- .../MinimalLambda.Testing.UnitTests.csproj | 2 +- tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/global.json b/global.json index eb470ca2..4ea65709 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { "rollForward": "latestMinor", - "version": "10.0.102" + "version": "10.0.101" }, "test": { "runner": "Microsoft.Testing.Platform" diff --git a/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj b/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj index 5fbe672a..775bccf4 100644 --- a/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj +++ b/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj @@ -17,7 +17,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj b/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj index fb086804..6e6496bd 100644 --- a/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj +++ b/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj @@ -26,7 +26,7 @@ - + all diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj b/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj index a25fbcdc..03343d24 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj @@ -18,7 +18,7 @@ - + diff --git a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj index cd12180b..ef7cfe69 100644 --- a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj +++ b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj @@ -23,7 +23,7 @@ - + all diff --git a/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj b/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj index 40a8c650..20855508 100644 --- a/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj +++ b/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj @@ -33,7 +33,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From b0a619e0dbfb5db25d9df4f05c6376fa7929aa28 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Mon, 19 Jan 2026 10:16:22 -0500 Subject: [PATCH 5/5] style(dependencies): fix formatting inconsistency in package reference - Corrected whitespace formatting for `Microsoft.Testing.Extensions.CodeCoverage` in `Directory.Packages.props`. --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index ef622d98..4df426c3 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -50,7 +50,7 @@ - +