diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 00000000..010a8c12 --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-stryker": { + "version": "4.16.0", + "commands": [ + "dotnet-stryker" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml new file mode 100644 index 00000000..055ace1a --- /dev/null +++ b/.github/workflows/mutation.yml @@ -0,0 +1,60 @@ +name: Mutation Testing + +on: + pull_request: + branches: [main] + schedule: + - cron: "0 6 * * *" + +env: + DOTNET_ROLL_FORWARD: Major + +permissions: + contents: read + +jobs: + mutation: + name: Mutation (${{ matrix.project }}) + runs-on: ubuntu-latest + timeout-minutes: 45 + + strategy: + fail-fast: false + matrix: + project: [domain, application, infrastructure] + + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: "10.0.x" + + - name: Restore + run: dotnet restore + + - name: Restore local tools + run: dotnet tool restore + + - name: Run Stryker (PR — changed in-scope files only) + if: github.event_name == 'pull_request' + run: | + git fetch origin main + dotnet stryker -f stryker-config.${{ matrix.project }}.json --since:origin/main + + - name: Run Stryker (nightly — full in-scope) + if: github.event_name == 'schedule' + run: dotnet stryker -f stryker-config.${{ matrix.project }}.json --concurrency 2 + + - name: Upload mutation report + if: always() + uses: actions/upload-artifact@v7 + with: + name: mutation-report-${{ github.event_name }}-${{ matrix.project }} + path: | + StrykerOutput/**/reports/*.html + StrykerOutput/**/reports/*.json + if-no-files-found: ignore diff --git a/.gitignore b/.gitignore index bdfc8909..ca82231a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,8 @@ ## Build Results [Bb]in/ [Oo]bj/ -.config/ +.config/* +!.config/dotnet-tools.json .fake/ ## JetBrains / Rider @@ -31,6 +32,9 @@ TestResults/ *.trhx +## Mutation testing (Stryker) +StrykerOutput/ + ## Environment Variables & Secrets (CRÍTICO PARA SEU PROJETO) .env appsettings.Development.json @@ -49,7 +53,7 @@ Desktop.ini ## Docker / Caddy caddy_data/ -caddy_config/.claude/worktrees/ +caddy_config/ ## Claude Code worktrees .claude/worktrees/ diff --git a/stryker-config.application.json b/stryker-config.application.json new file mode 100644 index 00000000..23187e00 --- /dev/null +++ b/stryker-config.application.json @@ -0,0 +1,22 @@ +{ + "stryker-config": { + "project": "Orbit.Application.csproj", + "test-projects": ["tests/Orbit.Application.Tests/Orbit.Application.Tests.csproj"], + "mutate": [ + "**/Subscriptions/Commands/VerifyPlayPurchaseCommand.cs", + "**/Subscriptions/Commands/HandlePlayNotificationCommand.cs", + "**/Subscriptions/Services/PlayReferralCouponConsumer.cs", + "**/Common/PlaySubscriptionStateExtensions.cs", + "**/Common/SubscriptionSourceExtensions.cs", + "**/Auth/Commands/*.cs", + "**/Habits/Services/HabitScheduleService.cs" + ], + "mutation-level": "Standard", + "reporters": ["cleartext", "html", "json"], + "thresholds": { + "high": 80, + "low": 60, + "break": 0 + } + } +} diff --git a/stryker-config.domain.json b/stryker-config.domain.json new file mode 100644 index 00000000..4452190d --- /dev/null +++ b/stryker-config.domain.json @@ -0,0 +1,19 @@ +{ + "stryker-config": { + "project": "Orbit.Domain.csproj", + "test-projects": ["tests/Orbit.Domain.Tests/Orbit.Domain.Tests.csproj"], + "mutate": [ + "**/Entities/Habit.cs", + "**/Entities/HabitInvariants.cs", + "**/Entities/User.cs", + "**/Entities/StreakFreeze.cs" + ], + "mutation-level": "Standard", + "reporters": ["cleartext", "html", "json"], + "thresholds": { + "high": 80, + "low": 60, + "break": 0 + } + } +} diff --git a/stryker-config.infrastructure.json b/stryker-config.infrastructure.json new file mode 100644 index 00000000..bc3bd5c6 --- /dev/null +++ b/stryker-config.infrastructure.json @@ -0,0 +1,24 @@ +{ + "stryker-config": { + "project": "Orbit.Infrastructure.csproj", + "test-projects": ["tests/Orbit.Infrastructure.Tests/Orbit.Infrastructure.Tests.csproj"], + "mutate": [ + "**/Services/JwtTokenService.cs", + "**/Services/AuthSessionService.cs", + "**/Services/UserStreakService.cs", + "**/Services/HabitDueDateAdvancementService.cs", + "!**/Services/GooglePlayBillingService.cs", + "!**/Services/GoogleTokenService.cs", + "!**/Services/GooglePlayPushTokenValidator.cs", + "!**/Services/UserDateService.cs", + "!**/Services/StreakFreezeAutoActivationService.cs" + ], + "mutation-level": "Standard", + "reporters": ["cleartext", "html", "json"], + "thresholds": { + "high": 80, + "low": 60, + "break": 0 + } + } +} diff --git a/tests/Orbit.Application.Tests/Commands/Auth/LogoutAndRefreshSessionTests.cs b/tests/Orbit.Application.Tests/Commands/Auth/LogoutAndRefreshSessionTests.cs deleted file mode 100644 index e69de29b..00000000