diff --git a/tests/acceptance/TestCase.feature b/tests/acceptance/TestCase.feature
index 3ce1e92..bd0e7af 100644
--- a/tests/acceptance/TestCase.feature
+++ b/tests/acceptance/TestCase.feature
@@ -18,10 +18,6 @@ Feature: TestCase
-
-
-
-
"""
@@ -36,7 +32,11 @@ Feature: TestCase
Scenario: Stateful test case with setUp produces no MissingConstructor
Given I have the following code
"""
- interface I { public function work(): int; }
+ /** @psalm-mutable */
+ interface I {
+ /** @psalm-impure */
+ public function work(): int;
+ }
final class MyTestCase extends TestCase
{
@@ -63,7 +63,11 @@ Feature: TestCase
Scenario: Stateful test case with @before produces no MissingConstructor
Given I have the following code
"""
- interface I { public function work(): int; }
+ /** @psalm-mutable */
+ interface I {
+ /** @psalm-impure */
+ public function work(): int;
+ }
final class MyTestCase extends TestCase
{
@@ -91,7 +95,11 @@ Feature: TestCase
"""
use PHPUnit\Framework\Attributes;
- interface I { public function work(): int; }
+ /** @psalm-mutable */
+ interface I {
+ /** @psalm-impure */
+ public function work(): int;
+ }
class BaseTestCase extends TestCase {
/** @var I&\PHPUnit\Framework\MockObject\Stub */
@@ -121,7 +129,11 @@ Feature: TestCase
Scenario: Stateful test case without @before or setUp produces MissingConstructor
Given I have the following code
"""
- interface I { public function work(): int; }
+ /** @psalm-mutable */
+ interface I {
+ /** @psalm-impure */
+ public function work(): int;
+ }
final class MyTestCase extends TestCase
{
@@ -174,7 +186,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() {
yield 1;
}
@@ -190,7 +205,7 @@ Feature: TestCase
When I run Psalm
Then I see these errors
| Type | Message |
- | InvalidReturnType | Providers must return iterable>, iterable provided |
+ | InvalidReturnType | Providers must return iterable>, iterable[pure] provided |
And I see no other errors
Scenario: Valid iterable data provider is allowed
@@ -198,7 +213,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide() {
yield [1];
}
@@ -221,7 +239,10 @@ Feature: TestCase
final class MyTestCase extends TestCase
{
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide() {
yield [1];
}
@@ -242,12 +263,18 @@ Feature: TestCase
final class MyTestCase extends TestCase
{
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provider1() {
yield [1];
}
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provider2() {
yield [1];
}
@@ -271,12 +298,18 @@ Feature: TestCase
final class MyTestCase extends TestCase
{
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provider1() {
yield [1];
}
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provider2() {
yield [1];
}
@@ -296,7 +329,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return \Generator */
+ /**
+ * @return \Generator
+ * @psalm-pure
+ */
public function provide() {
yield 1;
}
@@ -312,7 +348,7 @@ Feature: TestCase
When I run Psalm
Then I see these errors
| Type | Message |
- | InvalidReturnType | Providers must return iterable>, Generator provided |
+ | InvalidReturnType | Providers must return iterable>, Generator[pure] provided |
And I see no other errors
Scenario: Valid generator data provider is allowed
@@ -320,7 +356,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return \Generator,mixed,void> */
+ /**
+ * @return \Generator,mixed,void>
+ * @psalm-pure
+ */
public function provide() {
yield [1];
}
@@ -341,7 +380,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return array */
+ /**
+ * @return array
+ * @psalm-pure
+ */
public function provide() {
return [1 => 1];
}
@@ -365,7 +407,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return array */
+ /**
+ * @return array
+ * @psalm-pure
+ */
public function provide() {
return [1 => [1]];
}
@@ -389,7 +434,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() {
return [1 => [1]];
}
@@ -413,7 +461,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return \Generator */
+ /**
+ * @return \Generator
+ * @psalm-pure
+ */
public function provide() {
yield 1 => [1];
}
@@ -429,7 +480,7 @@ Feature: TestCase
When I run Psalm
Then I see these errors
| Type | Message |
- | MixedReturnStatement | Providers must return iterable>, possibly different Generator provided |
+ | MixedReturnStatement | Providers must return iterable>, possibly different Generator[pure] provided |
And I see no other errors
Scenario: Valid array data provider is allowed
@@ -437,7 +488,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return array> */
+ /**
+ * @return array>
+ * @psalm-pure
+ */
public function provide() {
return [
"data set name" => [1],
@@ -460,7 +514,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return \ArrayObject> */
+ /**
+ * @return \ArrayObject>
+ * @psalm-pure
+ */
public function provide() {
/** @var \ArrayObject> */
return new \ArrayObject([
@@ -484,7 +541,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() {
yield "data set name" => ["str"];
}
@@ -500,7 +560,7 @@ Feature: TestCase
When I run Psalm
Then I see these errors
| Type | Message |
- | InvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string provided by NS\MyTestCase::provide():(iterable) |
+ | InvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string provided by NS\MyTestCase::provide():(iterable[pure]) |
And I see no other errors
Scenario: Invalid dataset array is reported
@@ -508,7 +568,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide() {
yield "data set name" => ["str"];
}
@@ -524,7 +587,7 @@ Feature: TestCase
When I run Psalm
Then I see these errors
| Type | Message |
- | PossiblyInvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, int\|string provided by NS\MyTestCase::provide():(iterable>) |
+ | PossiblyInvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, int\|string provided by NS\MyTestCase::provide():(iterable[pure]>) |
And I see no other errors
Scenario: Shape dataset with missing params is reported
@@ -532,7 +595,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() {
yield "data set name" => [1];
}
@@ -548,7 +614,7 @@ Feature: TestCase
When I run Psalm
Then I see these errors
| Type | Message |
- | TooFewArguments |Too few arguments for NS\MyTestCase::testSomething - expecting at least 2, but saw 1 provided by NS\MyTestCase::provide():(iterable) |
+ | TooFewArguments |Too few arguments for NS\MyTestCase::testSomething - expecting at least 2, but saw 1 provided by NS\MyTestCase::provide():(iterable[pure]) |
And I see no other errors
Scenario: Referenced providers are not marked as unused
@@ -556,7 +622,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() {
yield "data set name" => [1];
}
@@ -577,7 +646,10 @@ Feature: TestCase
"""
final class MyTestCase extends TestCase
{
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() {
yield "data set name" => [1];
}
@@ -654,6 +726,7 @@ Feature: TestCase
Scenario: Unreferenced non-test classes are marked as unused
Given I have the following code
"""
+ /** @psalm-pure */
final class UtilityClass
{
}
@@ -784,7 +857,11 @@ Feature: TestCase
"""
class BaseTestCase extends TestCase {}
- interface I { public function work(): int; }
+ /** @psalm-mutable */
+ interface I {
+ /** @psalm-impure */
+ public function work(): int;
+ }
final class MyTestCase extends BaseTestCase
{
@@ -811,7 +888,11 @@ Feature: TestCase
Scenario: Descendant of a test that has setUp produces no MissingConstructor
Given I have the following code
"""
- interface I { public function work(): int; }
+ /** @psalm-mutable */
+ interface I {
+ /** @psalm-impure */
+ public function work(): int;
+ }
class BaseTestCase extends TestCase {
/** @var I&\PHPUnit\Framework\MockObject\Stub */
@@ -842,7 +923,11 @@ Feature: TestCase
Scenario: Descendant of a test that has @before produces no MissingConstructor
Given I have the following code
"""
- interface I { public function work(): int; }
+ /** @psalm-mutable */
+ interface I {
+ /** @psalm-impure */
+ public function work(): int;
+ }
class BaseTestCase extends TestCase {
/** @var I&\PHPUnit\Framework\MockObject\Stub */
@@ -873,7 +958,11 @@ Feature: TestCase
"""
use PHPUnit\Framework\Attributes;
- interface I { public function work(): int; }
+ /** @psalm-mutable */
+ interface I {
+ /** @psalm-impure */
+ public function work(): int;
+ }
class BaseTestCase extends TestCase {
/** @var I&\PHPUnit\Framework\MockObject\Stub */
@@ -902,8 +991,12 @@ Feature: TestCase
Scenario: Test methods in traits are not marked as unused
Given I have the following code
"""
+ /** @psalm-immutable */
trait MyTestTrait {
- /** @return void */
+ /**
+ * @return void
+ * @psalm-capabilities read-props
+ */
public function testSomething() {}
}
final class MyTestCase extends TestCase {
@@ -919,7 +1012,9 @@ Feature: TestCase
*/
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() { return [[1]]; }
}
final class MyTestCase extends TestCase {
@@ -1027,6 +1134,7 @@ Feature: TestCase
/**
* @return void
* @dataProvider provide
+ * @psalm-capabilities read-props
*/
public function testSomething(int $_i) {}
}
@@ -1037,16 +1145,21 @@ Feature: TestCase
Scenario: Data providers in test case when test methods are in trait are not marked as unused
Given I have the following code
"""
+ /** @psalm-immutable */
trait MyTestTrait {
/**
* @return void
* @dataProvider provide
+ * @psalm-capabilities read-props
*/
public function testSomething(int $_i) {}
}
final class MyTestCase extends TestCase {
use MyTestTrait;
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() { return [[1]]; }
}
"""
@@ -1056,10 +1169,12 @@ Feature: TestCase
Scenario: Renamed imported test methods are validated
Given I have the following code
"""
+ /** @psalm-immutable */
trait MyTestTrait {
/**
* @return void
* @dataProvider provide
+ * @psalm-capabilities read-props
*/
public function foo(int $_i) {}
}
@@ -1076,14 +1191,17 @@ Feature: TestCase
Scenario: Test methods and providers in trait used by a test case are validated
Given I have the following code
"""
+ /** @psalm-immutable */
trait MyTestTrait {
/**
* @return void
* @dataProvider provide
+ * @psalm-capabilities read-props
*/
public function testSomething(string $_p) {}
/**
* @return iterable
+ * @psalm-pure
*/
public function provide() { return [[1]]; }
}
@@ -1102,7 +1220,10 @@ Feature: TestCase
Given I have the following code
"""
final class MyTestCase extends TestCase {
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() {
yield "data set" => [1];
}
@@ -1110,6 +1231,7 @@ Feature: TestCase
* @dataProvider provide
* @param int ...$rest
* @return void
+ * @psalm-capabilities read-props
*/
public function testSomething(int $i, ...$rest) {}
}
@@ -1121,7 +1243,10 @@ Feature: TestCase
Given I have the following code
"""
final class MyTestCase extends TestCase {
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() {
yield "data set" => [1];
}
@@ -1129,6 +1254,7 @@ Feature: TestCase
* @dataProvider provide
* @param int ...$rest
* @return void
+ * @psalm-capabilities read-props
*/
public function testSomething(int $i, string $s = "", ...$rest) {}
}
@@ -1140,7 +1266,10 @@ Feature: TestCase
Given I have the following code
"""
final class MyTestCase extends TestCase {
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() {
yield "data set" => [1];
}
@@ -1148,6 +1277,7 @@ Feature: TestCase
* @dataProvider provide
* @param int ...$rest
* @return void
+ * @psalm-capabilities read-props
*/
public function testSomething(int $i, string $s, ...$rest) {}
}
@@ -1155,20 +1285,24 @@ Feature: TestCase
When I run Psalm
Then I see these errors
| Type | Message |
- | TooFewArguments | Too few arguments for NS\MyTestCase::testSomething - expecting at least 2, but saw 1 provided by NS\MyTestCase::provide():(iterable) |
+ | TooFewArguments | Too few arguments for NS\MyTestCase::testSomething - expecting at least 2, but saw 1 provided by NS\MyTestCase::provide():(iterable[pure]) |
And I see no other errors
Scenario: Providers generating incompatible datasets for variadic tests are reported
Given I have the following code
"""
final class MyTestCase extends TestCase {
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide() {
yield "data set" => [1., "a"];
}
/**
* @dataProvider provide
* @return void
+ * @psalm-capabilities read-props
*/
public function testSomething(float ...$rest) {}
}
@@ -1176,20 +1310,24 @@ Feature: TestCase
When I run Psalm
Then I see these errors
| Type | Message |
- | InvalidArgument | Argument 2 of NS\MyTestCase::testSomething expects float, string provided by NS\MyTestCase::provide():(iterable) |
+ | InvalidArgument | Argument 2 of NS\MyTestCase::testSomething expects float, string provided by NS\MyTestCase::provide():(iterable[pure]) |
And I see no other errors
Scenario: Untyped providers returns are not checked against test method signatures
Given I have the following code
"""
final class MyTestCase extends TestCase {
- /** @psalm-suppress MissingReturnType */
+ /**
+ * @psalm-suppress MissingReturnType
+ * @psalm-pure
+ */
public function provide() {
yield "data set" => ["a"];
}
/**
* @dataProvider provide
* @return void
+ * @psalm-capabilities read-props
*/
public function testSomething(string $_s) {}
}
@@ -1217,6 +1355,7 @@ Feature: TestCase
* @before
* @psalm-rm-Rf-slash
* @return void
+ * @psalm-capabilities read-props
*/
public function preparation() {}
}
@@ -1234,6 +1373,7 @@ Feature: TestCase
* @test
* @psalm-force-push-master
* @return void
+ * @psalm-capabilities read-props
*/
public function doThings() {}
}
@@ -1250,10 +1390,14 @@ Feature: TestCase
/**
* @dataProvider provide
* @psalm-suppress MissingParamType
+ * @psalm-capabilities read-props
*/
public function testSomething($data): void {}
- /** @return iterable */
+ /**
+ * @return iterable
+ * @psalm-pure
+ */
public function provide(): iterable {
return ['case 1' => [1]];
}
@@ -1267,11 +1411,17 @@ Feature: TestCase
Given I have the following code
"""
final class MyTestCase extends TestCase {
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide(): iterable {
yield "dataset name" => [1];
}
- /** @dataProvider provide */
+ /**
+ * @dataProvider provide
+ * @psalm-capabilities read-props
+ */
public function testSomething(int $_p): void {}
}
"""
@@ -1283,15 +1433,22 @@ Feature: TestCase
Scenario: External providers are allowed
Given I have the following code
"""
+ /** @psalm-pure */
final class External {
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide(): iterable {
yield "dataset name" => [1];
}
}
final class MyTestCase extends TestCase {
- /** @dataProvider External::provide */
+ /**
+ * @dataProvider External::provide
+ * @psalm-capabilities read-props
+ */
public function testSomething(int $_p): void {}
}
"""
@@ -1302,15 +1459,22 @@ Feature: TestCase
Scenario: External providers with parens are allowed
Given I have the following code
"""
+ /** @psalm-pure */
final class External {
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide(): iterable {
yield "dataset name" => [1];
}
}
final class MyTestCase extends TestCase {
- /** @dataProvider External::provide() */
+ /**
+ * @dataProvider External::provide()
+ * @psalm-capabilities read-props
+ */
public function testSomething(int $_p): void {}
}
"""
@@ -1321,15 +1485,22 @@ Feature: TestCase
Scenario: External fully qualified providers are allowed
Given I have the following code
"""
+ /** @psalm-pure */
final class External {
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide(): iterable {
yield "dataset name" => [1];
}
}
final class MyTestCase extends TestCase {
- /** @dataProvider \NS\External::provide */
+ /**
+ * @dataProvider \NS\External::provide
+ * @psalm-capabilities read-props
+ */
public function testSomething(int $_p): void {}
}
"""
@@ -1340,15 +1511,22 @@ Feature: TestCase
Scenario: External providers are not marked as unused
Given I have the following code
"""
+ /** @psalm-pure */
final class External {
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide(): iterable {
yield "dataset name" => [1];
}
}
final class MyTestCase extends TestCase {
- /** @dataProvider External::provide */
+ /**
+ * @dataProvider External::provide
+ * @psalm-capabilities read-props
+ */
public function testSomething(int $_p): void {}
}
"""
@@ -1359,22 +1537,29 @@ Feature: TestCase
Scenario: Mismatched external providers are reported
Given I have the following code
"""
+ /** @psalm-pure */
final class External {
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide(): iterable {
yield "dataset name" => ["1"];
}
}
final class MyTestCase extends TestCase {
- /** @dataProvider External::provide */
+ /**
+ * @dataProvider External::provide
+ * @psalm-capabilities read-props
+ */
public function testSomething(int $_p): void {}
}
"""
When I run Psalm
Then I see these errors
| Type | Message |
- | InvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string provided by NS\External::provide():(iterable>) |
+ | InvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string provided by NS\External::provide():(iterable[pure]>) |
@ExternalProviders
Scenario: External providers are available even when Psalm is asked to analyze single test case
@@ -1385,7 +1570,10 @@ Feature: TestCase
use PHPUnit\Framework\TestCase;
final class MyTestCase extends TestCase {
- /** @dataProvider External::provide */
+ /**
+ * @dataProvider External::provide
+ * @psalm-capabilities read-props
+ */
public function testSomething(int $_p): void {}
}
"""
@@ -1394,8 +1582,12 @@ Feature: TestCase
> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide(): iterable {
yield "dataset name" => [1];
}
@@ -1435,10 +1627,6 @@ Feature: TestCase
-
-
-
-
"""
@@ -1450,7 +1638,10 @@ Feature: TestCase
Given I have the following code
"""
final class MyTestCase extends TestCase {
- /** @dataProvider External::provide */
+ /**
+ * @dataProvider External::provide
+ * @psalm-capabilities read-props
+ */
public function testSomething(int $_p): void {}
}
"""
@@ -1464,11 +1655,17 @@ Feature: TestCase
Given I have the following code
"""
final class MyTestCase extends TestCase {
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide(): iterable {
yield "dataset name" => [1];
}
- /** @dataProvider provide */
+ /**
+ * @dataProvider provide
+ * @psalm-capabilities read-props
+ */
public function testSomething(int $_p): void {}
}
"""
@@ -1480,28 +1677,40 @@ Feature: TestCase
Given I have the following code
"""
final class MyTestCase extends TestCase {
- /** @return iterable> */
+ /**
+ * @return iterable>
+ * @psalm-pure
+ */
public function provide(): iterable {
yield "dataset name" => ["1"];
}
- /** @dataProvider provide */
+ /**
+ * @dataProvider provide
+ * @psalm-capabilities read-props
+ */
public function testSomething(int $_p): void {}
}
"""
When I run Psalm
Then I see these errors
| Type | Message |
- | InvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string provided by NS\MyTestCase::provide():(iterable>) |
+ | InvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string provided by NS\MyTestCase::provide():(iterable[pure]>) |
Scenario: Providers returning nullable generator are ok
Given I have the following code
"""
final class MyTestCase extends TestCase {
- /** @return ?\Generator> */
+ /**
+ * @return ?\Generator>
+ * @psalm-pure
+ */
public function provide(): ?\Generator {
return null;
}
- /** @dataProvider provide */
+ /**
+ * @dataProvider provide
+ * @psalm-capabilities read-props
+ */
public function testSomething(int $_p): void {}
}
"""
@@ -1512,11 +1721,17 @@ Feature: TestCase
Given I have the following code
"""
final class MyTestCase extends TestCase {
- /** @return null */
+ /**
+ * @return null
+ * @psalm-pure
+ */
public function provide() {
return null;
}
- /** @dataProvider provide */
+ /**
+ * @dataProvider provide
+ * @psalm-capabilities read-props
+ */
public function testSomething(): void {}
}
"""