Skip to content

Commit 96598da

Browse files
committed
Better type tests around instantiation and validation scenarios
These added tests verify that: * `Enum::assert*` methods can be used in a pure form * `Enum::from*` methods can be used in a pure form * `Enum#__construct()` properly binds the instance type of the enumerable with the input value * `Enum::assert*` methods currently **CANNOT** bind the input to an enumerable potential value (BUG) * `Enum::from*` methods currently **CANNOT** bind the input to an enumerable potential value (BUG) In addition to that, `psalm.xml` has been made a bit stricter: * `resolveFromConfigFile` was removed (we were using the default value) * `findUnusedPsalmSuppress` was added, allowing us to find whether intentional suppressions are now invalid. This allows us to verify negative scenarios, in which we **expect** a type error to appear * `restrictReturnTypes` better refines templated types, requiring inputs/outputs to match for those too
1 parent af4b562 commit 96598da

File tree

4 files changed

+106
-5
lines changed

4 files changed

+106
-5
lines changed

psalm.xml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
<?xml version="1.0"?>
22
<psalm
3-
totallyTyped="true"
4-
resolveFromConfigFile="true"
53
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
64
xmlns="https://getpsalm.org/schema/config"
75
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
6+
restrictReturnTypes="true"
7+
findUnusedPsalmSuppress="true"
8+
totallyTyped="true"
89
>
910
<projectFiles>
1011
<directory name="src" />
@@ -16,8 +17,6 @@
1617
</projectFiles>
1718

1819
<issueHandlers>
19-
<MixedAssignment errorLevel="info" />
20-
2120
<ImpureStaticProperty>
2221
<!-- self::$... usages in Enum are used to populate an internal cache, and cause no side-effects -->
2322
<errorLevel type="suppress">

static-analysis/EnumInstantiation.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MyCLabs\Tests\Enum\StaticAnalysis;
6+
7+
use MyCLabs\Enum\Enum;
8+
9+
/**
10+
* @psalm-immutable
11+
* @psalm-template T of 'A'|'C'
12+
* @template-extends Enum<T>
13+
*/
14+
final class InstantiatedEnum extends Enum
15+
{
16+
const A = 'A';
17+
const C = 'C';
18+
}
19+
20+
/**
21+
* @psalm-pure
22+
* @psalm-return InstantiatedEnum<'A'>
23+
*/
24+
function canCallConstructorWithConstantValue(): InstantiatedEnum
25+
{
26+
return new InstantiatedEnum('A');
27+
}
28+
29+
/**
30+
* @psalm-pure
31+
* @psalm-return InstantiatedEnum<'C'>
32+
*/
33+
function canCallConstructorWithConstantReference(): InstantiatedEnum
34+
{
35+
return new InstantiatedEnum(InstantiatedEnum::C);
36+
}
37+
38+
/** @psalm-pure */
39+
function canCallFromWithKnownValue(): InstantiatedEnum
40+
{
41+
return InstantiatedEnum::from('C');
42+
}
43+
44+
/** @psalm-pure */
45+
function canCallFromWithUnknownValue(): InstantiatedEnum
46+
{
47+
return InstantiatedEnum::from(123123);
48+
}

static-analysis/EnumIsPure.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* @method static PureEnum C()
1212
*
1313
* @psalm-immutable
14-
* @psalm-template T of 'A'|'B'
14+
* @psalm-template T of 'A'|'C'
1515
* @template-extends Enum<T>
1616
*/
1717
final class PureEnum extends Enum

static-analysis/EnumValidation.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MyCLabs\Tests\Enum\StaticAnalysis;
6+
7+
use MyCLabs\Enum\Enum;
8+
9+
/**
10+
* @psalm-immutable
11+
* @psalm-template T of 'A'|'C'
12+
* @template-extends Enum<T>
13+
*/
14+
final class ValidationEnum extends Enum
15+
{
16+
const A = 'A';
17+
const C = 'C';
18+
}
19+
20+
/**
21+
* @psalm-pure
22+
* @param mixed $input
23+
* @psalm-return 'A'|'C'
24+
*
25+
* @psalm-suppress MixedReturnStatement
26+
* @psalm-suppress MixedInferredReturnType at the time of this writing, we did not yet find
27+
* a proper approach to constraint input values through
28+
* validation via static methods.
29+
*/
30+
function canValidateValue($input): string
31+
{
32+
ValidationEnum::assertValidValue($input);
33+
34+
return $input;
35+
}
36+
37+
/**
38+
* @psalm-pure
39+
* @param mixed $input
40+
* @psalm-return 'A'|'C'
41+
*
42+
* @psalm-suppress MixedReturnStatement
43+
* @psalm-suppress MixedInferredReturnType at the time of this writing, we did not yet find
44+
* a proper approach to constraint input values through
45+
* validation via static methods.
46+
*/
47+
function canValidateValueThroughIsValid($input): string
48+
{
49+
if (! ValidationEnum::isValid($input)) {
50+
throw new \InvalidArgumentException('Value not valid');
51+
}
52+
53+
return $input;
54+
}

0 commit comments

Comments
 (0)