mirror of
https://github.com/danog/Valinor.git
synced 2025-01-22 05:11:52 +01:00
feat: handle literal boolean true
/ false
types
Allows the usage of boolean values, as follows: ```php class Foo { /** @var int|false */ public readonly int|bool $value; } ```
This commit is contained in:
parent
790df8a3b8
commit
afcedf9e56
10
README.md
10
README.md
@ -782,11 +782,17 @@ final class SomeClass
|
||||
/** @var array<SomeInterface|AnotherInterface> */
|
||||
private array $unionInsideArray,
|
||||
|
||||
/** @var int|true */
|
||||
private int|bool $unionWithLiteralTrueType;
|
||||
|
||||
/** @var int|false */
|
||||
private int|bool $unionWithLiteralFalseType;
|
||||
|
||||
/** @var 404.42|1337.42 */
|
||||
private string $unionOfFloatValues,
|
||||
private float $unionOfFloatValues,
|
||||
|
||||
/** @var 42|1337 */
|
||||
private string $unionOfIntegerValues,
|
||||
private int $unionOfIntegerValues,
|
||||
|
||||
/** @var 'foo'|'bar' */
|
||||
private string $unionOfStringValues,
|
||||
|
@ -7,12 +7,11 @@ namespace CuyZ\Valinor\Definition\Repository\Cache\Compiler;
|
||||
use CuyZ\Valinor\Definition\Repository\Cache\Compiler\Exception\TypeCannotBeCompiled;
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Type\Types\ArrayKeyType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanType;
|
||||
use CuyZ\Valinor\Type\Types\ArrayType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanValueType;
|
||||
use CuyZ\Valinor\Type\Types\ClassStringType;
|
||||
use CuyZ\Valinor\Type\Types\ClassType;
|
||||
use CuyZ\Valinor\Type\Types\ArrayType;
|
||||
use CuyZ\Valinor\Type\Types\EnumType;
|
||||
use CuyZ\Valinor\Type\Types\NativeFloatType;
|
||||
use CuyZ\Valinor\Type\Types\FloatValueType;
|
||||
use CuyZ\Valinor\Type\Types\IntegerRangeType;
|
||||
use CuyZ\Valinor\Type\Types\IntegerValueType;
|
||||
@ -21,6 +20,8 @@ use CuyZ\Valinor\Type\Types\IntersectionType;
|
||||
use CuyZ\Valinor\Type\Types\IterableType;
|
||||
use CuyZ\Valinor\Type\Types\ListType;
|
||||
use CuyZ\Valinor\Type\Types\MixedType;
|
||||
use CuyZ\Valinor\Type\Types\NativeBooleanType;
|
||||
use CuyZ\Valinor\Type\Types\NativeFloatType;
|
||||
use CuyZ\Valinor\Type\Types\NativeIntegerType;
|
||||
use CuyZ\Valinor\Type\Types\NativeStringType;
|
||||
use CuyZ\Valinor\Type\Types\NegativeIntegerType;
|
||||
@ -50,7 +51,7 @@ final class TypeCompiler
|
||||
|
||||
switch (true) {
|
||||
case $type instanceof NullType:
|
||||
case $type instanceof BooleanType:
|
||||
case $type instanceof NativeBooleanType:
|
||||
case $type instanceof NativeFloatType:
|
||||
case $type instanceof NativeIntegerType:
|
||||
case $type instanceof PositiveIntegerType:
|
||||
@ -60,6 +61,10 @@ final class TypeCompiler
|
||||
case $type instanceof UndefinedObjectType:
|
||||
case $type instanceof MixedType:
|
||||
return "$class::get()";
|
||||
case $type instanceof BooleanValueType:
|
||||
return $type->value() === true
|
||||
? "$class::true()"
|
||||
: "$class::false()";
|
||||
case $type instanceof IntegerRangeType:
|
||||
return "new $class({$type->min()}, {$type->max()})";
|
||||
case $type instanceof StringValueType:
|
||||
|
11
src/Type/BooleanType.php
Normal file
11
src/Type/BooleanType.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Type;
|
||||
|
||||
/** @api */
|
||||
interface BooleanType extends ScalarType
|
||||
{
|
||||
public function cast($value): bool;
|
||||
}
|
@ -7,9 +7,10 @@ namespace CuyZ\Valinor\Type\Parser\Lexer\Token;
|
||||
use CuyZ\Valinor\Type\Parser\Lexer\TokenStream;
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Type\Types\ArrayKeyType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanType;
|
||||
use CuyZ\Valinor\Type\Types\NativeFloatType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanValueType;
|
||||
use CuyZ\Valinor\Type\Types\MixedType;
|
||||
use CuyZ\Valinor\Type\Types\NativeBooleanType;
|
||||
use CuyZ\Valinor\Type\Types\NativeFloatType;
|
||||
use CuyZ\Valinor\Type\Types\NativeStringType;
|
||||
use CuyZ\Valinor\Type\Types\NegativeIntegerType;
|
||||
use CuyZ\Valinor\Type\Types\NonEmptyStringType;
|
||||
@ -57,6 +58,10 @@ final class NativeToken implements TraversingToken
|
||||
switch (strtolower($symbol)) {
|
||||
case 'null':
|
||||
return NullType::get();
|
||||
case 'true':
|
||||
return BooleanValueType::true();
|
||||
case 'false':
|
||||
return BooleanValueType::false();
|
||||
case 'mixed':
|
||||
return MixedType::get();
|
||||
case 'float':
|
||||
@ -71,7 +76,7 @@ final class NativeToken implements TraversingToken
|
||||
return NonEmptyStringType::get();
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
return BooleanType::get();
|
||||
return NativeBooleanType::get();
|
||||
case 'array-key':
|
||||
return ArrayKeyType::default();
|
||||
case 'object':
|
||||
|
86
src/Type/Types/BooleanValueType.php
Normal file
86
src/Type/Types/BooleanValueType.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Type\Types;
|
||||
|
||||
use CuyZ\Valinor\Type\BooleanType;
|
||||
use CuyZ\Valinor\Type\FixedType;
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Type\Types\Exception\CannotCastValue;
|
||||
|
||||
/** @api */
|
||||
final class BooleanValueType implements BooleanType, FixedType
|
||||
{
|
||||
private static self $true;
|
||||
|
||||
private static self $false;
|
||||
|
||||
private bool $value;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function __construct(bool $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public static function true(): self
|
||||
{
|
||||
return self::$true ??= new self(true);
|
||||
}
|
||||
|
||||
public static function false(): self
|
||||
{
|
||||
return self::$false ??= new self(false);
|
||||
}
|
||||
|
||||
public function accepts($value): bool
|
||||
{
|
||||
return $value === $this->value;
|
||||
}
|
||||
|
||||
public function matches(Type $other): bool
|
||||
{
|
||||
if ($other instanceof UnionType) {
|
||||
return $other->isMatchedBy($this);
|
||||
}
|
||||
|
||||
return $other === $this
|
||||
|| $other instanceof MixedType
|
||||
|| $other instanceof NativeBooleanType;
|
||||
}
|
||||
|
||||
public function canCast($value): bool
|
||||
{
|
||||
if ($value === $this->value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->value === true) {
|
||||
return $value === '1' || $value === 1 || $value === 'true';
|
||||
}
|
||||
|
||||
return $value === '0' || $value === 0 || $value === 'false';
|
||||
}
|
||||
|
||||
public function cast($value): bool
|
||||
{
|
||||
if (! $this->canCast($value)) {
|
||||
throw new CannotCastValue($value, $this);
|
||||
}
|
||||
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function value(): bool
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->value ? 'true' : 'false';
|
||||
}
|
||||
}
|
@ -58,7 +58,7 @@ final class FloatValueType implements FloatType, FixedType
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function value()
|
||||
public function value(): float
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use CuyZ\Valinor\Utility\IsSingleton;
|
||||
use function is_bool;
|
||||
|
||||
/** @api */
|
||||
final class BooleanType implements ScalarType
|
||||
final class NativeBooleanType implements ScalarType
|
||||
{
|
||||
use IsSingleton;
|
||||
|
@ -7,7 +7,7 @@ namespace CuyZ\Valinor\Tests\Fake\Type;
|
||||
use CuyZ\Valinor\Tests\Fixture\Object\StringableObject;
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Type\Types\ArrayKeyType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanType;
|
||||
use CuyZ\Valinor\Type\Types\NativeBooleanType;
|
||||
use CuyZ\Valinor\Type\Types\ClassType;
|
||||
use CuyZ\Valinor\Type\Types\MixedType;
|
||||
use CuyZ\Valinor\Type\Types\NativeStringType;
|
||||
@ -40,7 +40,7 @@ final class FakeType implements Type
|
||||
}
|
||||
|
||||
if ($raw === 'bool') {
|
||||
return BooleanType::get();
|
||||
return NativeBooleanType::get();
|
||||
}
|
||||
|
||||
if ($raw === 'array-key') {
|
||||
|
@ -7,11 +7,10 @@ namespace CuyZ\Valinor\Tests\Functional\Definition\Repository\Cache\Compiler;
|
||||
use CuyZ\Valinor\Definition\Repository\Cache\Compiler\TypeCompiler;
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Type\Types\ArrayKeyType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanType;
|
||||
use CuyZ\Valinor\Type\Types\ArrayType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanValueType;
|
||||
use CuyZ\Valinor\Type\Types\ClassStringType;
|
||||
use CuyZ\Valinor\Type\Types\ClassType;
|
||||
use CuyZ\Valinor\Type\Types\ArrayType;
|
||||
use CuyZ\Valinor\Type\Types\NativeFloatType;
|
||||
use CuyZ\Valinor\Type\Types\FloatValueType;
|
||||
use CuyZ\Valinor\Type\Types\IntegerRangeType;
|
||||
use CuyZ\Valinor\Type\Types\IntegerValueType;
|
||||
@ -20,6 +19,8 @@ use CuyZ\Valinor\Type\Types\IntersectionType;
|
||||
use CuyZ\Valinor\Type\Types\IterableType;
|
||||
use CuyZ\Valinor\Type\Types\ListType;
|
||||
use CuyZ\Valinor\Type\Types\MixedType;
|
||||
use CuyZ\Valinor\Type\Types\NativeBooleanType;
|
||||
use CuyZ\Valinor\Type\Types\NativeFloatType;
|
||||
use CuyZ\Valinor\Type\Types\NativeIntegerType;
|
||||
use CuyZ\Valinor\Type\Types\NativeStringType;
|
||||
use CuyZ\Valinor\Type\Types\NegativeIntegerType;
|
||||
@ -73,7 +74,9 @@ final class TypeCompilerTest extends TestCase
|
||||
public function type_is_compiled_correctly_data_provider(): iterable
|
||||
{
|
||||
yield [NullType::get()];
|
||||
yield [BooleanType::get()];
|
||||
yield [BooleanValueType::true()];
|
||||
yield [BooleanValueType::false()];
|
||||
yield [NativeBooleanType::get()];
|
||||
yield [NativeFloatType::get()];
|
||||
yield [new FloatValueType(1337.42)];
|
||||
yield [new FloatValueType(-1337.42)];
|
||||
|
@ -37,10 +37,9 @@ use CuyZ\Valinor\Type\Parser\TypeParser;
|
||||
use CuyZ\Valinor\Type\StringType;
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Type\Types\ArrayType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanValueType;
|
||||
use CuyZ\Valinor\Type\Types\ClassStringType;
|
||||
use CuyZ\Valinor\Type\Types\ClassType;
|
||||
use CuyZ\Valinor\Type\Types\NativeFloatType;
|
||||
use CuyZ\Valinor\Type\Types\FloatValueType;
|
||||
use CuyZ\Valinor\Type\Types\IntegerRangeType;
|
||||
use CuyZ\Valinor\Type\Types\IntegerValueType;
|
||||
@ -49,6 +48,8 @@ use CuyZ\Valinor\Type\Types\IntersectionType;
|
||||
use CuyZ\Valinor\Type\Types\IterableType;
|
||||
use CuyZ\Valinor\Type\Types\ListType;
|
||||
use CuyZ\Valinor\Type\Types\MixedType;
|
||||
use CuyZ\Valinor\Type\Types\NativeBooleanType;
|
||||
use CuyZ\Valinor\Type\Types\NativeFloatType;
|
||||
use CuyZ\Valinor\Type\Types\NonEmptyArrayType;
|
||||
use CuyZ\Valinor\Type\Types\NonEmptyListType;
|
||||
use CuyZ\Valinor\Type\Types\NonEmptyStringType;
|
||||
@ -106,6 +107,26 @@ final class NativeLexerTest extends TestCase
|
||||
'transformed' => 'null',
|
||||
'type' => NullType::class,
|
||||
],
|
||||
'True type' => [
|
||||
'raw' => 'true',
|
||||
'transformed' => 'true',
|
||||
'type' => BooleanValueType::class,
|
||||
],
|
||||
'True type - uppercase' => [
|
||||
'raw' => 'TRUE',
|
||||
'transformed' => 'true',
|
||||
'type' => BooleanValueType::class,
|
||||
],
|
||||
'False type' => [
|
||||
'raw' => 'false',
|
||||
'transformed' => 'false',
|
||||
'type' => BooleanValueType::class,
|
||||
],
|
||||
'False type - uppercase' => [
|
||||
'raw' => 'FALSE',
|
||||
'transformed' => 'false',
|
||||
'type' => BooleanValueType::class,
|
||||
],
|
||||
'Mixed type' => [
|
||||
'raw' => 'mixed',
|
||||
'transformed' => 'mixed',
|
||||
@ -304,27 +325,27 @@ final class NativeLexerTest extends TestCase
|
||||
'Boolean type' => [
|
||||
'raw' => 'bool',
|
||||
'transformed' => 'bool',
|
||||
'type' => BooleanType::class,
|
||||
'type' => NativeBooleanType::class,
|
||||
],
|
||||
'Boolean type - uppercase' => [
|
||||
'raw' => 'BOOL',
|
||||
'transformed' => 'bool',
|
||||
'type' => BooleanType::class,
|
||||
'type' => NativeBooleanType::class,
|
||||
],
|
||||
'Boolean type (longer version)' => [
|
||||
'raw' => 'boolean',
|
||||
'transformed' => 'bool',
|
||||
'type' => BooleanType::class,
|
||||
'type' => NativeBooleanType::class,
|
||||
],
|
||||
'Boolean type (longer version) - uppercase' => [
|
||||
'raw' => 'BOOLEAN',
|
||||
'transformed' => 'bool',
|
||||
'type' => BooleanType::class,
|
||||
'type' => NativeBooleanType::class,
|
||||
],
|
||||
'Boolean type followed by description' => [
|
||||
'raw' => 'bool lorem ipsum',
|
||||
'transformed' => 'bool',
|
||||
'type' => BooleanType::class,
|
||||
'type' => NativeBooleanType::class,
|
||||
],
|
||||
'Undefined object type' => [
|
||||
'raw' => 'object',
|
||||
|
@ -18,17 +18,29 @@ class NativeUnionValues
|
||||
public string|null $nullableWithString = 'Schwifty!';
|
||||
|
||||
public string|null $nullableWithNull = 'Schwifty!';
|
||||
|
||||
/** @var int|true */
|
||||
public int|bool $intOrLiteralTrue = 42;
|
||||
|
||||
/** @var int|false */
|
||||
public int|bool $intOrLiteralFalse = 42;
|
||||
}
|
||||
|
||||
class NativeUnionValuesWithConstructor extends NativeUnionValues
|
||||
{
|
||||
/**
|
||||
* @param int|true $intOrLiteralTrue
|
||||
* @param int|false $intOrLiteralFalse
|
||||
*/
|
||||
public function __construct(
|
||||
bool|float|int|string $scalarWithBoolean = 'Schwifty!',
|
||||
bool|float|int|string $scalarWithFloat = 'Schwifty!',
|
||||
bool|float|int|string $scalarWithInteger = 'Schwifty!',
|
||||
bool|float|int|string $scalarWithString = 'Schwifty!',
|
||||
string|null $nullableWithString = 'Schwifty!',
|
||||
string|null $nullableWithNull = 'Schwifty!'
|
||||
string|null $nullableWithNull = 'Schwifty!',
|
||||
int|bool $intOrLiteralTrue = 42,
|
||||
int|bool $intOrLiteralFalse = 42
|
||||
) {
|
||||
$this->scalarWithBoolean = $scalarWithBoolean;
|
||||
$this->scalarWithFloat = $scalarWithFloat;
|
||||
@ -36,5 +48,7 @@ class NativeUnionValuesWithConstructor extends NativeUnionValues
|
||||
$this->scalarWithString = $scalarWithString;
|
||||
$this->nullableWithString = $nullableWithString;
|
||||
$this->nullableWithNull = $nullableWithNull;
|
||||
$this->intOrLiteralTrue = $intOrLiteralTrue;
|
||||
$this->intOrLiteralFalse = $intOrLiteralFalse;
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ final class UnionValuesMappingTest extends IntegrationTest
|
||||
'scalarWithString' => 'foo',
|
||||
'nullableWithString' => 'bar',
|
||||
'nullableWithNull' => null,
|
||||
'intOrLiteralTrue' => true,
|
||||
'intOrLiteralFalse' => false,
|
||||
'positiveFloatValue' => 1337.42,
|
||||
'negativeFloatValue' => -1337.42,
|
||||
'positiveIntegerValue' => 1337,
|
||||
@ -48,6 +50,8 @@ final class UnionValuesMappingTest extends IntegrationTest
|
||||
self::assertSame('foo', $result->scalarWithString);
|
||||
self::assertSame('bar', $result->nullableWithString);
|
||||
self::assertSame(null, $result->nullableWithNull);
|
||||
self::assertSame(true, $result->intOrLiteralTrue);
|
||||
self::assertSame(false, $result->intOrLiteralFalse);
|
||||
|
||||
if ($result instanceof UnionValues) {
|
||||
self::assertSame(1337.42, $result->positiveFloatValue);
|
||||
@ -81,6 +85,12 @@ class UnionValues
|
||||
/** @var string|null|float */
|
||||
public $nullableWithNull = 'Schwifty!';
|
||||
|
||||
/** @var int|true */
|
||||
public $intOrLiteralTrue = 42;
|
||||
|
||||
/** @var int|false */
|
||||
public $intOrLiteralFalse = 42;
|
||||
|
||||
/** @var 404.42|1337.42 */
|
||||
public float $positiveFloatValue = 404.42;
|
||||
|
||||
@ -109,6 +119,8 @@ class UnionValuesWithConstructor extends UnionValues
|
||||
* @param bool|float|int|string $scalarWithString
|
||||
* @param string|null|float $nullableWithString
|
||||
* @param string|null|float $nullableWithNull
|
||||
* @param int|true $intOrLiteralTrue
|
||||
* @param int|false $intOrLiteralFalse
|
||||
* @param 404.42|1337.42 $positiveFloatValue
|
||||
* @param -404.42|-1337.42 $negativeFloatValue
|
||||
* @param 42|1337 $positiveIntegerValue
|
||||
@ -123,6 +135,8 @@ class UnionValuesWithConstructor extends UnionValues
|
||||
$scalarWithString = 'Schwifty!',
|
||||
$nullableWithString = 'Schwifty!',
|
||||
$nullableWithNull = 'Schwifty!',
|
||||
$intOrLiteralTrue = 42,
|
||||
$intOrLiteralFalse = 42,
|
||||
float $positiveFloatValue = 404.42,
|
||||
float $negativeFloatValue = -404.42,
|
||||
int $positiveIntegerValue = 42,
|
||||
@ -136,6 +150,8 @@ class UnionValuesWithConstructor extends UnionValues
|
||||
$this->scalarWithString = $scalarWithString;
|
||||
$this->nullableWithString = $nullableWithString;
|
||||
$this->nullableWithNull = $nullableWithNull;
|
||||
$this->intOrLiteralTrue = $intOrLiteralTrue;
|
||||
$this->intOrLiteralFalse = $intOrLiteralFalse;
|
||||
$this->positiveFloatValue = $positiveFloatValue;
|
||||
$this->negativeFloatValue = $negativeFloatValue;
|
||||
$this->positiveIntegerValue = $positiveIntegerValue;
|
||||
|
@ -16,7 +16,7 @@ use CuyZ\Valinor\Tests\Fake\Definition\Repository\FakeAttributesRepository;
|
||||
use CuyZ\Valinor\Tests\Fake\Type\FakeType;
|
||||
use CuyZ\Valinor\Tests\Fake\Type\Parser\Factory\FakeTypeParserFactory;
|
||||
use CuyZ\Valinor\Type\StringType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanType;
|
||||
use CuyZ\Valinor\Type\Types\NativeBooleanType;
|
||||
use CuyZ\Valinor\Type\Types\ClassType;
|
||||
use CuyZ\Valinor\Type\Types\MixedType;
|
||||
use CuyZ\Valinor\Type\Types\UnresolvableType;
|
||||
@ -61,7 +61,7 @@ final class ReflectionClassDefinitionRepositoryTest extends TestCase
|
||||
self::assertTrue($properties->get('propertyWithDefaultValue')->hasDefaultValue());
|
||||
self::assertSame('Default value for property', $properties->get('propertyWithDefaultValue')->defaultValue());
|
||||
|
||||
self::assertInstanceOf(BooleanType::class, $properties->get('propertyWithDocBlockType')->type());
|
||||
self::assertInstanceOf(NativeBooleanType::class, $properties->get('propertyWithDocBlockType')->type());
|
||||
|
||||
self::assertInstanceOf(MixedType::class, $properties->get('propertyWithNoType')->type());
|
||||
|
||||
@ -71,7 +71,7 @@ final class ReflectionClassDefinitionRepositoryTest extends TestCase
|
||||
self::assertInstanceOf(StringType::class, $properties->get('protectedProperty')->type());
|
||||
self::assertFalse($properties->get('protectedProperty')->isPublic());
|
||||
|
||||
self::assertInstanceOf(BooleanType::class, $properties->get('privateProperty')->type());
|
||||
self::assertInstanceOf(NativeBooleanType::class, $properties->get('privateProperty')->type());
|
||||
self::assertFalse($properties->get('privateProperty')->isPublic());
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ final class ReflectionClassDefinitionRepositoryTest extends TestCase
|
||||
self::assertSame($className . '::publicMethod($parameterWithDocBlockType)', $parameterWithDocBlockType->signature());
|
||||
self::assertSame($className . '::publicMethod($optionalParameter)', $optionalParameter->signature());
|
||||
|
||||
self::assertInstanceOf(BooleanType::class, $mandatoryParameter->type());
|
||||
self::assertInstanceOf(NativeBooleanType::class, $mandatoryParameter->type());
|
||||
self::assertFalse($mandatoryParameter->isOptional());
|
||||
|
||||
self::assertInstanceOf(MixedType::class, $parameterWithNoType->type());
|
||||
|
@ -10,7 +10,7 @@ use CuyZ\Valinor\Type\Resolver\Exception\CannotResolveTypeFromUnion;
|
||||
use CuyZ\Valinor\Type\Resolver\Union\UnionScalarNarrower;
|
||||
use CuyZ\Valinor\Type\StringType;
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Type\Types\BooleanType;
|
||||
use CuyZ\Valinor\Type\Types\NativeBooleanType;
|
||||
use CuyZ\Valinor\Type\Types\NativeFloatType;
|
||||
use CuyZ\Valinor\Type\Types\NativeIntegerType;
|
||||
use CuyZ\Valinor\Type\Types\NativeStringType;
|
||||
@ -49,7 +49,7 @@ final class UnionScalarNarrowerTest extends TestCase
|
||||
NativeIntegerType::get(),
|
||||
NativeFloatType::get(),
|
||||
NativeStringType::get(),
|
||||
BooleanType::get(),
|
||||
NativeBooleanType::get(),
|
||||
);
|
||||
|
||||
return [
|
||||
@ -76,7 +76,7 @@ final class UnionScalarNarrowerTest extends TestCase
|
||||
'int|float|string|bool with boolean value' => [
|
||||
'Union type' => $scalarUnion,
|
||||
'Source' => true,
|
||||
'Expected type' => BooleanType::class,
|
||||
'Expected type' => NativeBooleanType::class,
|
||||
],
|
||||
'int|object with object value' => [
|
||||
'Union type' => new UnionType(NativeIntegerType::get(), UndefinedObjectType::get()),
|
||||
@ -97,7 +97,7 @@ final class UnionScalarNarrowerTest extends TestCase
|
||||
|
||||
public function test_several_possible_types_throws_exception(): void
|
||||
{
|
||||
$unionType = new UnionType(BooleanType::get(), NativeIntegerType::get(), NativeFloatType::get());
|
||||
$unionType = new UnionType(NativeBooleanType::get(), NativeIntegerType::get(), NativeFloatType::get());
|
||||
|
||||
$this->expectException(CannotResolveTypeFromUnion::class);
|
||||
$this->expectExceptionCode(1607027306);
|
||||
|
172
tests/Unit/Type/Types/BooleanValueTypeTest.php
Normal file
172
tests/Unit/Type/Types/BooleanValueTypeTest.php
Normal file
@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Tests\Unit\Type\Types;
|
||||
|
||||
use CuyZ\Valinor\Tests\Fake\Type\FakeType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanValueType;
|
||||
use CuyZ\Valinor\Type\Types\Exception\CannotCastValue;
|
||||
use CuyZ\Valinor\Type\Types\MixedType;
|
||||
use CuyZ\Valinor\Type\Types\NativeBooleanType;
|
||||
use CuyZ\Valinor\Type\Types\UnionType;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use stdClass;
|
||||
|
||||
final class BooleanValueTypeTest extends TestCase
|
||||
{
|
||||
public function test_named_constructors_return_singleton_instances(): void
|
||||
{
|
||||
self::assertSame(BooleanValueType::true(), BooleanValueType::true());
|
||||
self::assertSame(BooleanValueType::false(), BooleanValueType::false());
|
||||
}
|
||||
|
||||
public function test_string_value_is_correct(): void
|
||||
{
|
||||
self::assertSame('true', (string)BooleanValueType::true());
|
||||
self::assertSame('false', (string)BooleanValueType::false());
|
||||
}
|
||||
|
||||
public function test_accepts_correct_values(): void
|
||||
{
|
||||
self::assertTrue(BooleanValueType::true()->accepts(true));
|
||||
self::assertTrue(BooleanValueType::false()->accepts(false));
|
||||
}
|
||||
|
||||
public function test_does_not_accept_incorrect_values(): void
|
||||
{
|
||||
self::assertFalse(BooleanValueType::true()->accepts('Schwifty!'));
|
||||
self::assertFalse(BooleanValueType::true()->accepts(42.1337));
|
||||
self::assertFalse(BooleanValueType::true()->accepts(404));
|
||||
self::assertFalse(BooleanValueType::true()->accepts(['foo' => 'bar']));
|
||||
self::assertFalse(BooleanValueType::true()->accepts(false));
|
||||
self::assertFalse(BooleanValueType::true()->accepts(null));
|
||||
self::assertFalse(BooleanValueType::true()->accepts(new stdClass()));
|
||||
|
||||
self::assertFalse(BooleanValueType::false()->accepts('Schwifty!'));
|
||||
self::assertFalse(BooleanValueType::false()->accepts(42.1337));
|
||||
self::assertFalse(BooleanValueType::false()->accepts(404));
|
||||
self::assertFalse(BooleanValueType::false()->accepts(['foo' => 'bar']));
|
||||
self::assertFalse(BooleanValueType::false()->accepts(true));
|
||||
self::assertFalse(BooleanValueType::false()->accepts(null));
|
||||
self::assertFalse(BooleanValueType::false()->accepts(new stdClass()));
|
||||
}
|
||||
|
||||
public function test_can_cast_boolean_value(): void
|
||||
{
|
||||
self::assertTrue(BooleanValueType::true()->canCast(true));
|
||||
self::assertTrue(BooleanValueType::false()->canCast(false));
|
||||
}
|
||||
|
||||
public function test_can_cast_string_integer_value(): void
|
||||
{
|
||||
self::assertTrue(BooleanValueType::true()->canCast('1'));
|
||||
self::assertTrue(BooleanValueType::false()->canCast('0'));
|
||||
}
|
||||
|
||||
public function test_can_cast_integer_value(): void
|
||||
{
|
||||
self::assertTrue(BooleanValueType::true()->canCast(1));
|
||||
self::assertTrue(BooleanValueType::false()->canCast(0));
|
||||
}
|
||||
|
||||
public function test_can_cast_string_value(): void
|
||||
{
|
||||
self::assertTrue(BooleanValueType::true()->canCast('true'));
|
||||
self::assertTrue(BooleanValueType::false()->canCast('false'));
|
||||
}
|
||||
|
||||
public function test_cannot_cast_other_types(): void
|
||||
{
|
||||
self::assertFalse(BooleanValueType::true()->canCast(null));
|
||||
self::assertFalse(BooleanValueType::true()->canCast(false));
|
||||
self::assertFalse(BooleanValueType::true()->canCast(42.1337));
|
||||
self::assertFalse(BooleanValueType::true()->canCast(404));
|
||||
self::assertFalse(BooleanValueType::true()->canCast('Schwifty!'));
|
||||
self::assertFalse(BooleanValueType::true()->canCast(['foo' => 'bar']));
|
||||
self::assertFalse(BooleanValueType::true()->canCast(new stdClass()));
|
||||
|
||||
self::assertFalse(BooleanValueType::false()->canCast(null));
|
||||
self::assertFalse(BooleanValueType::false()->canCast(true));
|
||||
self::assertFalse(BooleanValueType::false()->canCast(42.1337));
|
||||
self::assertFalse(BooleanValueType::false()->canCast(404));
|
||||
self::assertFalse(BooleanValueType::false()->canCast('Schwifty!'));
|
||||
self::assertFalse(BooleanValueType::false()->canCast(['foo' => 'bar']));
|
||||
self::assertFalse(BooleanValueType::false()->canCast(new stdClass()));
|
||||
}
|
||||
|
||||
public function test_cast_value_returns_correct_result(): void
|
||||
{
|
||||
self::assertSame(true, BooleanValueType::true()->cast(true));
|
||||
self::assertSame(true, BooleanValueType::true()->cast('1'));
|
||||
self::assertSame(true, BooleanValueType::true()->cast(1));
|
||||
self::assertSame(true, BooleanValueType::true()->cast('true'));
|
||||
|
||||
self::assertSame(false, BooleanValueType::false()->cast(false));
|
||||
self::assertSame(false, BooleanValueType::false()->cast('0'));
|
||||
self::assertSame(false, BooleanValueType::false()->cast(0));
|
||||
self::assertSame(false, BooleanValueType::false()->cast('false'));
|
||||
}
|
||||
|
||||
public function test_cast_invalid_value_to_true_throws_exception(): void
|
||||
{
|
||||
$this->expectException(CannotCastValue::class);
|
||||
$this->expectExceptionCode(1603216198);
|
||||
$this->expectExceptionMessage('Cannot cast from `string` to `true`.');
|
||||
|
||||
BooleanValueType::true()->cast('foo');
|
||||
}
|
||||
|
||||
public function test_cast_invalid_value_to_false_throws_exception(): void
|
||||
{
|
||||
$this->expectException(CannotCastValue::class);
|
||||
$this->expectExceptionCode(1603216198);
|
||||
$this->expectExceptionMessage('Cannot cast from `string` to `false`.');
|
||||
|
||||
BooleanValueType::false()->cast('foo');
|
||||
}
|
||||
|
||||
public function test_matches_same_type(): void
|
||||
{
|
||||
self::assertTrue(BooleanValueType::true()->matches(BooleanValueType::true()));
|
||||
self::assertTrue(BooleanValueType::false()->matches(BooleanValueType::false()));
|
||||
}
|
||||
|
||||
public function test_matches_native_boolean_type(): void
|
||||
{
|
||||
self::assertTrue(BooleanValueType::true()->matches(new NativeBooleanType()));
|
||||
self::assertTrue(BooleanValueType::false()->matches(new NativeBooleanType()));
|
||||
}
|
||||
|
||||
public function test_matches_mixed_type(): void
|
||||
{
|
||||
self::assertTrue(BooleanValueType::true()->matches(new MixedType()));
|
||||
self::assertTrue(BooleanValueType::false()->matches(new MixedType()));
|
||||
}
|
||||
|
||||
public function test_matches_union_type_containing_same_type(): void
|
||||
{
|
||||
$unionTypeWithTrue = new UnionType(
|
||||
new FakeType(),
|
||||
BooleanValueType::true(),
|
||||
new FakeType(),
|
||||
);
|
||||
|
||||
$unionTypeWithFalse = new UnionType(
|
||||
new FakeType(),
|
||||
BooleanValueType::false(),
|
||||
new FakeType(),
|
||||
);
|
||||
|
||||
self::assertTrue(BooleanValueType::true()->matches($unionTypeWithTrue));
|
||||
self::assertTrue(BooleanValueType::false()->matches($unionTypeWithFalse));
|
||||
}
|
||||
|
||||
public function test_does_not_match_union_type_not_containing_same_type(): void
|
||||
{
|
||||
$unionType = new UnionType(new FakeType(), new FakeType());
|
||||
|
||||
self::assertFalse(BooleanValueType::true()->matches($unionType));
|
||||
self::assertFalse(BooleanValueType::false()->matches($unionType));
|
||||
}
|
||||
}
|
@ -6,24 +6,24 @@ namespace CuyZ\Valinor\Tests\Unit\Type\Types;
|
||||
|
||||
use CuyZ\Valinor\Tests\Fake\Type\FakeType;
|
||||
use CuyZ\Valinor\Tests\Traits\TestIsSingleton;
|
||||
use CuyZ\Valinor\Type\Types\BooleanType;
|
||||
use CuyZ\Valinor\Type\Types\NativeBooleanType;
|
||||
use CuyZ\Valinor\Type\Types\Exception\CannotCastValue;
|
||||
use CuyZ\Valinor\Type\Types\MixedType;
|
||||
use CuyZ\Valinor\Type\Types\UnionType;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use stdClass;
|
||||
|
||||
final class BooleanTypeTest extends TestCase
|
||||
final class NativeBooleanTypeTest extends TestCase
|
||||
{
|
||||
use TestIsSingleton;
|
||||
|
||||
private BooleanType $booleanType;
|
||||
private NativeBooleanType $booleanType;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->booleanType = new BooleanType();
|
||||
$this->booleanType = new NativeBooleanType();
|
||||
}
|
||||
|
||||
public function test_accepts_correct_values(): void
|
||||
@ -123,7 +123,7 @@ final class BooleanTypeTest extends TestCase
|
||||
|
||||
public function test_matches_same_type(): void
|
||||
{
|
||||
self::assertTrue((new BooleanType())->matches(new BooleanType()));
|
||||
self::assertTrue((new NativeBooleanType())->matches(new NativeBooleanType()));
|
||||
}
|
||||
|
||||
public function test_does_not_match_other_type(): void
|
||||
@ -140,7 +140,7 @@ final class BooleanTypeTest extends TestCase
|
||||
{
|
||||
$unionType = new UnionType(
|
||||
new FakeType(),
|
||||
new BooleanType(),
|
||||
new NativeBooleanType(),
|
||||
new FakeType(),
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user