Skip to content

ForbidCheckedExceptionInCallableRuleTest: Split test methods into individual test cases #310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 4, 2025
Merged
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
134 changes: 127 additions & 7 deletions tests/Rule/data/ForbidCheckedExceptionInCallableRule/code.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,23 @@ public function allowThrowInBaseClass(callable $callable): void

class FirstClassCallableTest extends BaseCallableTest {

public function testDeclarations(): void
public function testDeclarations1(): void
{
$this->noop(...);
}

public function testDeclarations2(): void
{
$this->throws(...); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
}

public function testDeclarations3(): void
{
// $this?->throws(...); // https://github.com/phpstan/phpstan/issues/9746
}

public function testDeclarations4(): void
{
throwing_function(...); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
}

Expand All @@ -62,27 +71,51 @@ public function testExplicitExecution2(): void
(throwing_function(...))();
}

public function testPassedCallbacks(): void
public function testPassedCallbacksA1(): void
{
$this->immediateThrow(null, $this->throws(...));
}

public function testPassedCallbacksA2(): void
{
array_map($this->throws(...), []);
}

public function testPassedCallbacksA3(): void
{
array_map(throwing_function(...), []);
}

public function testPassedCallbacksA4(): void
{
$this->allowThrow(42, $this->throws(...));
}

public function testPassedCallbacksA5(): void
{
$this->allowThrow(42, throwing_function(...));
}

public function testPassedCallbacksA6(): void
{
$this->immediateThrow(
$this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
function () {},
);
}

public function testPassedCallbacksA7(): void
{
$this->allowThrowInBaseClass(throwing_function(...));
}

public function testPassedCallbacksA8(): void
{
$this->allowThrowInInterface(throwing_function(...));
}

public function testPassedCallbacksA9(): void
{
$this->denied($this->throws(...)); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
}

Expand Down Expand Up @@ -124,20 +157,29 @@ public function allowThrow(int $dummy, callable $callable): void

class ClosureTest extends BaseCallableTest {

public function testDeclarations(): void
public function testDeclarationsB1(): void
{
$fn = function () {
throw new CheckedException(); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in closure!
};
}

public function testDeclarationsB2(): void
{
$fn2 = function () {
$this->throws(); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in closure!
};
}

public function testDeclarationsB3(): void
{
$fn3 = function () {
$this->noop(); // implicit throw is ignored
};
}

public function testDeclarationsB4(): void
{
$fn4 = function (callable $c) {
$c(); // implicit throw is ignored (https://github.com/phpstan/phpstan/issues/9779)
};
Expand All @@ -150,58 +192,91 @@ public function testExplicitExecution(): void
})();
}

public function testPassedCallbacks(): void
public function testPassedCallbacks1(): void
{
$this->immediateThrow(function () {
throw new CheckedException();
});
}

public function testPassedCallbacks2(): void
{
$self = $this; // self is unknown variable in scope of the closure
$self->immediateThrow(function () {
throw new CheckedException();
});
}

public function testPassedCallbacks3(): void
{
array_map(function () {
throw new CheckedException();
}, []);
}

public function testPassedCallbacks4(): void
{
array_map(function () {
$this->throws();
}, []);
}

public function testPassedCallbacks5(): void
{
$this->allowThrow(function () {
$this->throws();
});
}

public function testPassedCallbacks6(): void
{
$this->immediateThrow(
function () {},
function () {
throw new CheckedException(); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in closure!
},
);
}

public function testPassedCallbacks7(): void
{
$this->immediateThrow(
denied: function () {},
);
}

public function testPassedCallbacks8(): void
{
$this->immediateThrow(
denied: function () {
throw new CheckedException(); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in closure!
},
);
}

public function testPassedCallbacks9(): void
{
$this->allowThrowInBaseClass(function () {
$this->throws();
});
}

public function testPassedCallbacks10(): void
{
$this->allowThrowInInterface(function () {
$this->throws();
});
}

public function testPassedCallbacks11(): void
{
$this->denied(function () {
throw new CheckedException(); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in closure!
});
}

public function testPassedCallbacks12(): void
{
$this?->denied(function () {
$this->throws(); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in closure!
});
Expand Down Expand Up @@ -250,14 +325,23 @@ public function __construct($callable)
new self(fn () => throw new CheckedException());
}

public function testDeclarations(): void
public function testDeclarationsC1(): void
{
$fn = fn () => throw new CheckedException(); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in arrow function!
}

public function testDeclarationsC2(): void
{
$fn2 = fn () => $this->throws(); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in arrow function!
}

public function testDeclarationsC3(): void
{
$fn3 = fn () => $this->noop(); // implicit throw is ignored
}

public function testDeclarationsC4(): void
{
$fn4 = fn (callable $c) => $c(); // implicit throw is ignored (https://github.com/phpstan/phpstan/issues/9779)
}

Expand All @@ -266,22 +350,43 @@ public function testExplicitExecution(): void
(fn () => throw new CheckedException())();
}

public function testPassedCallbacks(): void
public function testPassedCallbacksC1(): void
{
$this->immediateThrow(fn () => throw new CheckedException());
}

public function testPassedCallbacksC2(): void
{
array_map(fn () => throw new CheckedException(), []);
}

public function testPassedCallbacksC3(): void
{
array_map(fn () => $this->throws(), []);
}

public function testPassedCallbacksC4(): void
{
$this->allowThrow(fn () => $this->throws());
}

public function testPassedCallbacksC5(): void
{
$this->allowThrowInBaseClass(fn () => $this->throws());
}

public function testPassedCallbacksC6(): void
{
$this->allowThrowInInterface(fn () => $this->throws());
}

public function testPassedCallbacksC7(): void
{
$this->denied(fn () => throw new CheckedException()); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in arrow function!
}

public function testPassedCallbacksC8(): void
{
$this?->denied(fn () => throw new CheckedException()); // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in arrow function!
}

Expand Down Expand Up @@ -323,40 +428,55 @@ public function allowThrow(callable $callable): void

class ArgumentSwappingTest {

public function test()
public function testD1(): void
{
$this->call(
$this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
$this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
$this->throws(...),
$this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
);
}

public function testD2(): void
{
$this->call(
second: $this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
first: $this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
third: $this->throws(...),
);
}

public function testD3(): void
{
$this->call(
forth: $this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
first: $this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
);
}

public function testD4(): void
{
$this->call(
$this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
forth: $this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
second: $this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
third: $this->throws(...),
);
}

public function testD5(): void
{
$this->call(
$this->noop(...),
$this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
forth: $this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
third: $this->noop(...),
);
}

public function testD6(): void
{
// this is not yet supported, the rule do not see this as argument pass
$this->call(... [
'third' => $this->throws(...), // error: Throwing checked exception ForbidCheckedExceptionInCallableRule\CheckedException in first-class-callable!
Expand Down