Skip to content

Commit fcaa2c8

Browse files
committed
Add null, mixed and string literal tests
1 parent a2aa029 commit fcaa2c8

File tree

9 files changed

+213
-5
lines changed

9 files changed

+213
-5
lines changed

src/Runtime/Extractor/NativeTypeExtractor.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@ final class NativeTypeExtractor implements TypeExtractorInterface
1111
{
1212
public function getDefinitionByValue(mixed $value): string
1313
{
14+
if (\is_resource($value)) {
15+
return 'resource';
16+
}
17+
1418
/** @var non-empty-string $result */
1519
$result = \get_debug_type($value);
1620

17-
if ($result === 'class@anonymous') {
18-
return 'object';
19-
}
20-
21-
return $result;
21+
return match ($result) {
22+
'class@anonymous' => 'object',
23+
'resource (closed)' => 'resource',
24+
default => $result,
25+
};
2226
}
2327
}

tests/Type/MixedTypeTest.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Mapper\Tests\Type;
6+
7+
use PHPUnit\Framework\Attributes\CoversClass;
8+
use PHPUnit\Framework\Attributes\Group;
9+
use TypeLang\Mapper\Context\Direction;
10+
use TypeLang\Mapper\Platform\PlatformInterface;
11+
use TypeLang\Mapper\Platform\StandardPlatform;
12+
use TypeLang\Mapper\Tests\Type\Stub\AnyTypeStub;
13+
use TypeLang\Mapper\Tests\Type\Stub\IntBackedEnumStub;
14+
use TypeLang\Mapper\Tests\Type\Stub\StringBackedEnumStub;
15+
use TypeLang\Mapper\Tests\Type\Stub\UnitEnumStub;
16+
use TypeLang\Mapper\Type\Builder\SimpleTypeBuilder;
17+
use TypeLang\Mapper\Type\MixedType;
18+
use TypeLang\Mapper\Type\TypeInterface;
19+
20+
#[Group('type')]
21+
#[CoversClass(MixedType::class)]
22+
final class MixedTypeTest extends TypeTestCase
23+
{
24+
protected function createPlatform(): PlatformInterface
25+
{
26+
return new class extends StandardPlatform {
27+
public function getTypes(Direction $direction): iterable
28+
{
29+
yield new SimpleTypeBuilder('resource', AnyTypeStub::class);
30+
31+
yield from parent::getTypes($direction);
32+
}
33+
};
34+
}
35+
36+
protected static function createType(): TypeInterface
37+
{
38+
return new MixedType();
39+
}
40+
41+
protected static function matchValues(bool $normalize): iterable
42+
{
43+
foreach (self::defaultMatchDataProviderSamples() as $value => $_) {
44+
yield $value => true;
45+
}
46+
}
47+
48+
protected static function castValues(bool $normalize): iterable
49+
{
50+
foreach (self::defaultCastDataProviderSamples() as $value => $_) {
51+
yield $value => $normalize === true
52+
? match (true) {
53+
\is_object($value) => match (true) {
54+
// Unit enum coverts to enum's name
55+
$value === UnitEnumStub::ExampleCase => $value->name,
56+
// Int backed enum coverts to enum's int value
57+
$value === IntBackedEnumStub::ExampleCase => $value->value,
58+
// String backed enum coverts to enum's string value
59+
$value === StringBackedEnumStub::ExampleCase => $value->value,
60+
// Empty object converts to empty array
61+
$value == (object)[] => [],
62+
// Object with 1 property converts to hash-map
63+
$value == (object)['key' => 'val'] => ['key' => 'val'],
64+
// Object without named properties converts to list<string>
65+
$value == (object)['val'] => ['val'],
66+
default => $value,
67+
},
68+
default => $value,
69+
}
70+
: match (true) {
71+
// Denormalization does not supports enums
72+
$value === UnitEnumStub::ExampleCase => new \ValueError('Passed value "ExampleCase" is invalid'),
73+
$value === IntBackedEnumStub::ExampleCase => new \ValueError('Passed value 3735928559 is invalid'),
74+
$value === StringBackedEnumStub::ExampleCase => new \ValueError('Passed value "case" is invalid'),
75+
default => $value,
76+
};
77+
}
78+
}
79+
}

tests/Type/NullTypeTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Mapper\Tests\Type;
6+
7+
use PHPUnit\Framework\Attributes\CoversClass;
8+
use PHPUnit\Framework\Attributes\Group;
9+
use TypeLang\Mapper\Type\NullType;
10+
use TypeLang\Mapper\Type\TypeInterface;
11+
12+
#[Group('type')]
13+
#[CoversClass(NullType::class)]
14+
final class NullTypeTest extends TypeTestCase
15+
{
16+
protected static function createType(): TypeInterface
17+
{
18+
return new NullType();
19+
}
20+
21+
protected static function matchValues(bool $normalize): iterable
22+
{
23+
foreach (self::defaultMatchDataProviderSamples() as $value => $default) {
24+
yield $value => match (true) {
25+
$value === null => true,
26+
default => $default,
27+
};
28+
}
29+
}
30+
31+
protected static function castValues(bool $normalize): iterable
32+
{
33+
foreach (self::defaultCastDataProviderSamples() as $value => $default) {
34+
yield $value => match (true) {
35+
$value === null => null,
36+
default => $default,
37+
};
38+
}
39+
}
40+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Mapper\Tests\Type;
6+
7+
use PHPUnit\Framework\Attributes\CoversClass;
8+
use PHPUnit\Framework\Attributes\Group;
9+
use TypeLang\Mapper\Type\Coercer\TypeCoercerInterface;
10+
use TypeLang\Mapper\Type\StringLiteralType;
11+
use TypeLang\Mapper\Type\TypeInterface;
12+
13+
#[Group('type')]
14+
#[CoversClass(StringLiteralType::class)]
15+
final class StringLiteralTypeTest extends CoercibleTypeTestCase
16+
{
17+
protected static function createType(?TypeCoercerInterface $coercer = null): TypeInterface
18+
{
19+
if ($coercer !== null) {
20+
return new StringLiteralType('', coercer: $coercer);
21+
}
22+
23+
return new StringLiteralType('');
24+
}
25+
26+
protected static function matchValues(bool $normalize): iterable
27+
{
28+
foreach (self::defaultMatchDataProviderSamples() as $value => $default) {
29+
yield $value => match (true) {
30+
$value === '' => true,
31+
default => $default,
32+
};
33+
}
34+
}
35+
36+
protected static function castValues(bool $normalize): iterable
37+
{
38+
foreach (self::defaultCastDataProviderSamples() as $value => $default) {
39+
yield $value => match (true) {
40+
$value === '' => '',
41+
default => $default,
42+
};
43+
}
44+
}
45+
}

tests/Type/Stub/AnyTypeStub.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Mapper\Tests\Type\Stub;
6+
7+
use TypeLang\Mapper\Context\Context;
8+
use TypeLang\Mapper\Type\TypeInterface;
9+
10+
/**
11+
* @internal this is an internal library class, please do not use it in your code
12+
* @psalm-internal TypeLang\Mapper\Tests\Type
13+
*/
14+
final class AnyTypeStub implements TypeInterface
15+
{
16+
public function match(mixed $value, Context $context): bool
17+
{
18+
return true;
19+
}
20+
21+
public function cast(mixed $value, Context $context): mixed
22+
{
23+
return $value;
24+
}
25+
}

tests/Type/Stub/DataSamples.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
use TypeLang\Mapper\Runtime\Value\JsonLikeValuePrinter;
88

99
/**
10+
* @internal this is an internal library class, please do not use it in your code
11+
* @psalm-internal TypeLang\Mapper\Tests\Type
12+
*
1013
* @template-implements \IteratorAggregate<array-key, mixed>
1114
*/
1215
final class DataSamples implements \IteratorAggregate

tests/Type/Stub/IntBackedEnumStub.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
namespace TypeLang\Mapper\Tests\Type\Stub;
66

7+
/**
8+
* @internal this is an internal library class, please do not use it in your code
9+
* @psalm-internal TypeLang\Mapper\Tests\Type
10+
*/
711
enum IntBackedEnumStub: int
812
{
913
case ExampleCase = 0xDEAD_BEEF;

tests/Type/Stub/StringBackedEnumStub.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
namespace TypeLang\Mapper\Tests\Type\Stub;
66

7+
/**
8+
* @internal this is an internal library class, please do not use it in your code
9+
* @psalm-internal TypeLang\Mapper\Tests\Type
10+
*/
711
enum StringBackedEnumStub: string
812
{
913
case ExampleCase = 'case';

tests/Type/Stub/UnitEnumStub.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
namespace TypeLang\Mapper\Tests\Type\Stub;
66

7+
/**
8+
* @internal this is an internal library class, please do not use it in your code
9+
* @psalm-internal TypeLang\Mapper\Tests\Type
10+
*/
711
enum UnitEnumStub
812
{
913
case ExampleCase;

0 commit comments

Comments
 (0)