Skip to content

Commit 334aa5f

Browse files
Goosterhofclaude
andcommitted
test: cover EnforceCurrentUserAttributeRule fixtures
Adds 10 fixtures and 10 test methods covering every detection branch and every legitimate-skip case: Fire (4): - RequestUserInController — shape 1 (Request subtype receiver) - AuthFacadeInController — shape 3 (Auth::user() static call) - AuthHelperInController — shape 2 (auth() helper receiver) - RequestUserInControllerWithAssert — exact PR #263 shape; fires once on the \$request->user() call (assert is downstream noise) Silent (5): - UsesCurrentUserAttribute — already-canonical #[CurrentUser] adoption - RequestUserInFormRequest — FormRequest descendant, by-design exclusion - AuthInMiddleware — not a Controller descendant - AuthInAction — not a Controller descendant - AuthInJob — not a Controller descendant Mutation-killing: - TopLevelAuthCall — top-level call outside any class (kills FalseValue mutant on the null-class-reflection branch) The _stubs.php file provides bracketed-namespace stubs for Illuminate\Routing\Controller, Illuminate\Http\Request, Illuminate\Foundation\Http\FormRequest, App\Models\User, and the global auth() helper — illuminate/routing / illuminate/http are not vendor-installed on this package, mirroring the AuditSnapshotOnRetry _stubs.php pattern. 60 tests pass, 101 assertions. Coverage 86.00% (≥83 gate); MSI 82.47% (≥75 gate); Covered MSI 82.47% (≥75 gate). Two LogicalOr mutants on the Identifier-name guard clauses escape — equivalent-mutant precedent already accepted on LogRule lines 84/99. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 0b9c350 commit 334aa5f

12 files changed

Lines changed: 391 additions & 0 deletions
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace App\Http\Controllers;
6+
7+
use Illuminate\Routing\Controller;
8+
use Illuminate\Support\Facades\Auth;
9+
10+
final class AuthFacadeInController extends Controller
11+
{
12+
public function store(): ?object
13+
{
14+
return Auth::user();
15+
}
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace App\Http\Controllers;
6+
7+
use Illuminate\Routing\Controller;
8+
9+
final class AuthHelperInController extends Controller
10+
{
11+
public function store(): ?object
12+
{
13+
return auth()->user();
14+
}
15+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace App\Actions;
6+
7+
use Illuminate\Support\Facades\Auth;
8+
9+
final readonly class AuthInAction
10+
{
11+
// Actions handle authenticated-user resolution via constructor DI (or
12+
// explicit DTO passing). The class does not extend Controller — silent.
13+
public function execute(): ?object
14+
{
15+
return Auth::user();
16+
}
17+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace App\Jobs;
6+
7+
use Illuminate\Support\Facades\Auth;
8+
9+
final class AuthInJob
10+
{
11+
// Queue jobs run outside an HTTP request scope; authenticated user
12+
// resolution by attribute does not apply. Not a Controller descendant —
13+
// silent.
14+
public function handle(): ?object
15+
{
16+
return Auth::user();
17+
}
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace App\Http\Middleware;
6+
7+
use Illuminate\Support\Facades\Auth;
8+
9+
final class AuthInMiddleware
10+
{
11+
// Middleware does not extend Illuminate\Routing\Controller — silent.
12+
public function handle(): ?object
13+
{
14+
return Auth::user();
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace App\Http\Controllers;
6+
7+
use Illuminate\Http\Request;
8+
use Illuminate\Routing\Controller;
9+
10+
final class RequestUserInController extends Controller
11+
{
12+
public function store(Request $request): ?object
13+
{
14+
return $request->user();
15+
}
16+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace App\Http\Controllers;
6+
7+
use App\Models\User;
8+
use Illuminate\Http\Request;
9+
use Illuminate\Routing\Controller;
10+
11+
use function assert;
12+
13+
final class RequestUserInControllerWithAssert extends Controller
14+
{
15+
public function store(Request $request): User
16+
{
17+
// Exact PR #263 shape — the assert is downstream noise; only the
18+
// $request->user() call fires.
19+
$user = $request->user();
20+
assert($user instanceof User);
21+
22+
return $user;
23+
}
24+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace App\Http\Requests;
6+
7+
use Illuminate\Foundation\Http\FormRequest;
8+
use Illuminate\Http\Request;
9+
10+
final class RequestUserInFormRequest extends FormRequest
11+
{
12+
// FormRequest descendants are intentionally out of scope — container-
13+
// attribute injection does not apply to FormRequest::rules() / toDto() /
14+
// authorize() invocations. Both call shapes below must be silent.
15+
public function authorize(): bool
16+
{
17+
return $this->user() !== null;
18+
}
19+
20+
/**
21+
* @return array<string, mixed>
22+
*/
23+
public function payload(Request $request): array
24+
{
25+
return ['user' => $request->user()];
26+
}
27+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
use Illuminate\Support\Facades\Auth;
6+
7+
// Top-level call outside any class — `$scope->getClassReflection()` returns
8+
// null, so the rule must short-circuit at the no-class-reflection gate.
9+
// Silent. Kills the FalseValue mutant on the null-reflection guard.
10+
Auth::user();
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace App\Http\Controllers;
6+
7+
use App\Models\User;
8+
use Illuminate\Container\Attributes\CurrentUser;
9+
use Illuminate\Routing\Controller;
10+
11+
final class UsesCurrentUserAttribute extends Controller
12+
{
13+
// Canonical replacement shape — container-attribute injection resolves
14+
// the authenticated user. No body call required; the rule must not fire.
15+
public function store(#[CurrentUser] User $user): User
16+
{
17+
return $user;
18+
}
19+
}

0 commit comments

Comments
 (0)