From 790df8a3b8e9b608e33086f673372b8dff7775c7 Mon Sep 17 00:00:00 2001 From: Romain Canon Date: Mon, 9 May 2022 19:12:13 +0200 Subject: [PATCH] feat: handle float value type Allows the usage of float values, as follows: ```php class Foo { /** @var 404.42|1337.42 */ public readonly float $value; } ``` --- README.md | 3 + .../Cache/Compiler/TypeCompiler.php | 6 +- src/Type/FloatType.php | 11 ++ src/Type/Parser/Lexer/NativeLexer.php | 6 + .../Parser/Lexer/Token/FloatValueToken.php | 25 +++ src/Type/Parser/Lexer/Token/NativeToken.php | 4 +- .../Types/Exception/InvalidFloatValue.php | 19 +++ .../Types/Exception/InvalidFloatValueType.php | 25 +++ src/Type/Types/FloatValueType.php | 70 +++++++++ .../{FloatType.php => NativeFloatType.php} | 4 +- .../Cache/Compiler/TypeCompilerTest.php | 21 ++- .../Type/Parser/Lexer/NativeLexerTest.php | 31 +++- .../Object/ScalarValuesMappingTest.php | 16 ++ .../Mapping/Object/UnionValuesMappingTest.php | 16 ++ .../Union/UnionScalarNarrowerTest.php | 14 +- tests/Unit/Type/Types/FloatValueTypeTest.php | 142 ++++++++++++++++++ .../Unit/Type/Types/IntegerValueTypeTest.php | 7 +- ...atTypeTest.php => NativeFloatTypeTest.php} | 14 +- tests/Unit/Type/Types/ShapedArrayTypeTest.php | 4 +- tests/Unit/Type/Types/StringValueTypeTest.php | 5 + 20 files changed, 407 insertions(+), 36 deletions(-) create mode 100644 src/Type/FloatType.php create mode 100644 src/Type/Parser/Lexer/Token/FloatValueToken.php create mode 100644 src/Type/Types/Exception/InvalidFloatValue.php create mode 100644 src/Type/Types/Exception/InvalidFloatValueType.php create mode 100644 src/Type/Types/FloatValueType.php rename src/Type/Types/{FloatType.php => NativeFloatType.php} (92%) create mode 100644 tests/Unit/Type/Types/FloatValueTypeTest.php rename tests/Unit/Type/Types/{FloatTypeTest.php => NativeFloatTypeTest.php} (92%) diff --git a/README.md b/README.md index 68f1bded..3014b575 100644 --- a/README.md +++ b/README.md @@ -782,6 +782,9 @@ final class SomeClass /** @var array */ private array $unionInsideArray, + /** @var 404.42|1337.42 */ + private string $unionOfFloatValues, + /** @var 42|1337 */ private string $unionOfIntegerValues, diff --git a/src/Definition/Repository/Cache/Compiler/TypeCompiler.php b/src/Definition/Repository/Cache/Compiler/TypeCompiler.php index a629cb21..fc92e203 100644 --- a/src/Definition/Repository/Cache/Compiler/TypeCompiler.php +++ b/src/Definition/Repository/Cache/Compiler/TypeCompiler.php @@ -12,7 +12,8 @@ use CuyZ\Valinor\Type\Types\ClassType; use CuyZ\Valinor\Type\Types\ArrayType; use CuyZ\Valinor\Type\Types\EnumType; -use CuyZ\Valinor\Type\Types\FloatType; +use CuyZ\Valinor\Type\Types\NativeFloatType; +use CuyZ\Valinor\Type\Types\FloatValueType; use CuyZ\Valinor\Type\Types\IntegerRangeType; use CuyZ\Valinor\Type\Types\IntegerValueType; use CuyZ\Valinor\Type\Types\InterfaceType; @@ -50,7 +51,7 @@ public function compile(Type $type): string switch (true) { case $type instanceof NullType: case $type instanceof BooleanType: - case $type instanceof FloatType: + case $type instanceof NativeFloatType: case $type instanceof NativeIntegerType: case $type instanceof PositiveIntegerType: case $type instanceof NegativeIntegerType: @@ -63,6 +64,7 @@ public function compile(Type $type): string return "new $class({$type->min()}, {$type->max()})"; case $type instanceof StringValueType: case $type instanceof IntegerValueType: + case $type instanceof FloatValueType: $value = var_export($type->value(), true); return "new $class($value)"; diff --git a/src/Type/FloatType.php b/src/Type/FloatType.php new file mode 100644 index 00000000..f856edb4 --- /dev/null +++ b/src/Type/FloatType.php @@ -0,0 +1,11 @@ += 8_01_00 && enum_exists($symbol)) { /** @var class-string $symbol */ diff --git a/src/Type/Parser/Lexer/Token/FloatValueToken.php b/src/Type/Parser/Lexer/Token/FloatValueToken.php new file mode 100644 index 00000000..e999cc07 --- /dev/null +++ b/src/Type/Parser/Lexer/Token/FloatValueToken.php @@ -0,0 +1,25 @@ +value = $value; + } + + public function traverse(TokenStream $stream): Type + { + return new FloatValueType($this->value); + } +} diff --git a/src/Type/Parser/Lexer/Token/NativeToken.php b/src/Type/Parser/Lexer/Token/NativeToken.php index 26dbf7c9..038280c6 100644 --- a/src/Type/Parser/Lexer/Token/NativeToken.php +++ b/src/Type/Parser/Lexer/Token/NativeToken.php @@ -8,7 +8,7 @@ use CuyZ\Valinor\Type\Type; use CuyZ\Valinor\Type\Types\ArrayKeyType; use CuyZ\Valinor\Type\Types\BooleanType; -use CuyZ\Valinor\Type\Types\FloatType; +use CuyZ\Valinor\Type\Types\NativeFloatType; use CuyZ\Valinor\Type\Types\MixedType; use CuyZ\Valinor\Type\Types\NativeStringType; use CuyZ\Valinor\Type\Types\NegativeIntegerType; @@ -60,7 +60,7 @@ private static function type(string $symbol): ?Type case 'mixed': return MixedType::get(); case 'float': - return FloatType::get(); + return NativeFloatType::get(); case 'positive-int': return PositiveIntegerType::get(); case 'negative-int': diff --git a/src/Type/Types/Exception/InvalidFloatValue.php b/src/Type/Types/Exception/InvalidFloatValue.php new file mode 100644 index 00000000..1b9ba709 --- /dev/null +++ b/src/Type/Types/Exception/InvalidFloatValue.php @@ -0,0 +1,19 @@ +value = $value; + } + + public function accepts($value): bool + { + return $value === $this->value; + } + + public function matches(Type $other): bool + { + if ($other instanceof UnionType) { + return $other->isMatchedBy($this); + } + + if ($other instanceof self) { + return $this->value === $other->value; + } + + return $other instanceof NativeFloatType || $other instanceof MixedType; + } + + public function canCast($value): bool + { + return is_numeric($value); + } + + public function cast($value): float + { + if (! $this->canCast($value)) { + throw new InvalidFloatValueType($value, $this->value); + } + + $value = (float)$value; // @phpstan-ignore-line + + if (! $this->accepts($value)) { + throw new InvalidFloatValue($value, $this->value); + } + + return $value; + } + + public function value() + { + return $this->value; + } + + public function __toString(): string + { + return (string)$this->value; + } +} diff --git a/src/Type/Types/FloatType.php b/src/Type/Types/NativeFloatType.php similarity index 92% rename from src/Type/Types/FloatType.php rename to src/Type/Types/NativeFloatType.php index a6a09c7f..56a9cccb 100644 --- a/src/Type/Types/FloatType.php +++ b/src/Type/Types/NativeFloatType.php @@ -4,7 +4,7 @@ namespace CuyZ\Valinor\Type\Types; -use CuyZ\Valinor\Type\ScalarType; +use CuyZ\Valinor\Type\FloatType; use CuyZ\Valinor\Type\Type; use CuyZ\Valinor\Type\Types\Exception\CannotCastValue; use CuyZ\Valinor\Utility\IsSingleton; @@ -13,7 +13,7 @@ use function is_numeric; /** @api */ -final class FloatType implements ScalarType +final class NativeFloatType implements FloatType { use IsSingleton; diff --git a/tests/Functional/Definition/Repository/Cache/Compiler/TypeCompilerTest.php b/tests/Functional/Definition/Repository/Cache/Compiler/TypeCompilerTest.php index 2653ab1b..44a97a3f 100644 --- a/tests/Functional/Definition/Repository/Cache/Compiler/TypeCompilerTest.php +++ b/tests/Functional/Definition/Repository/Cache/Compiler/TypeCompilerTest.php @@ -11,7 +11,8 @@ use CuyZ\Valinor\Type\Types\ClassStringType; use CuyZ\Valinor\Type\Types\ClassType; use CuyZ\Valinor\Type\Types\ArrayType; -use CuyZ\Valinor\Type\Types\FloatType; +use CuyZ\Valinor\Type\Types\NativeFloatType; +use CuyZ\Valinor\Type\Types\FloatValueType; use CuyZ\Valinor\Type\Types\IntegerRangeType; use CuyZ\Valinor\Type\Types\IntegerValueType; use CuyZ\Valinor\Type\Types\InterfaceType; @@ -73,10 +74,14 @@ public function type_is_compiled_correctly_data_provider(): iterable { yield [NullType::get()]; yield [BooleanType::get()]; - yield [FloatType::get()]; + yield [NativeFloatType::get()]; + yield [new FloatValueType(1337.42)]; + yield [new FloatValueType(-1337.42)]; yield [NativeIntegerType::get()]; yield [PositiveIntegerType::get()]; yield [NegativeIntegerType::get()]; + yield [new IntegerValueType(1337)]; + yield [new IntegerValueType(-1337)]; yield [new IntegerRangeType(42, 1337)]; yield [new IntegerRangeType(-1337, -42)]; yield [new IntegerRangeType(PHP_INT_MIN, PHP_INT_MAX)]; @@ -87,28 +92,28 @@ public function type_is_compiled_correctly_data_provider(): iterable yield [new InterfaceType(DateTimeInterface::class, ['Template' => NativeStringType::get()])]; yield [new ClassType(stdClass::class, ['Template' => NativeStringType::get()])]; yield [new IntersectionType(new InterfaceType(DateTimeInterface::class), new ClassType(DateTime::class))]; - yield [new UnionType(NativeStringType::get(), NativeIntegerType::get(), FloatType::get())]; + yield [new UnionType(NativeStringType::get(), NativeIntegerType::get(), NativeFloatType::get())]; yield [ArrayType::native()]; - yield [new ArrayType(ArrayKeyType::default(), FloatType::get())]; + yield [new ArrayType(ArrayKeyType::default(), NativeFloatType::get())]; yield [new ArrayType(ArrayKeyType::integer(), NativeIntegerType::get())]; yield [new ArrayType(ArrayKeyType::string(), NativeStringType::get())]; yield [NonEmptyArrayType::native()]; - yield [new NonEmptyArrayType(ArrayKeyType::default(), FloatType::get())]; + yield [new NonEmptyArrayType(ArrayKeyType::default(), NativeFloatType::get())]; yield [new NonEmptyArrayType(ArrayKeyType::integer(), NativeIntegerType::get())]; yield [new NonEmptyArrayType(ArrayKeyType::string(), NativeStringType::get())]; yield [ListType::native()]; - yield [new ListType(FloatType::get())]; + yield [new ListType(NativeFloatType::get())]; yield [new ListType(NativeIntegerType::get())]; yield [new ListType(NativeStringType::get())]; yield [NonEmptyListType::native()]; - yield [new NonEmptyListType(FloatType::get())]; + yield [new NonEmptyListType(NativeFloatType::get())]; yield [new NonEmptyListType(NativeIntegerType::get())]; yield [new NonEmptyListType(NativeStringType::get())]; yield [new ShapedArrayType( new ShapedArrayElement(new StringValueType('foo'), NativeStringType::get()), new ShapedArrayElement(new IntegerValueType(1337), NativeIntegerType::get(), true) )]; - yield [new IterableType(ArrayKeyType::default(), FloatType::get())]; + yield [new IterableType(ArrayKeyType::default(), NativeFloatType::get())]; yield [new IterableType(ArrayKeyType::integer(), NativeIntegerType::get())]; yield [new IterableType(ArrayKeyType::string(), NativeStringType::get())]; yield [new ClassStringType()]; diff --git a/tests/Functional/Type/Parser/Lexer/NativeLexerTest.php b/tests/Functional/Type/Parser/Lexer/NativeLexerTest.php index f422a620..b80acbbf 100644 --- a/tests/Functional/Type/Parser/Lexer/NativeLexerTest.php +++ b/tests/Functional/Type/Parser/Lexer/NativeLexerTest.php @@ -40,7 +40,8 @@ use CuyZ\Valinor\Type\Types\BooleanType; use CuyZ\Valinor\Type\Types\ClassStringType; use CuyZ\Valinor\Type\Types\ClassType; -use CuyZ\Valinor\Type\Types\FloatType; +use CuyZ\Valinor\Type\Types\NativeFloatType; +use CuyZ\Valinor\Type\Types\FloatValueType; use CuyZ\Valinor\Type\Types\IntegerRangeType; use CuyZ\Valinor\Type\Types\IntegerValueType; use CuyZ\Valinor\Type\Types\InterfaceType; @@ -123,17 +124,37 @@ public function parse_valid_types_returns_valid_result_data_provider(): array 'Float type' => [ 'raw' => 'float', 'transformed' => 'float', - 'type' => FloatType::class, + 'type' => NativeFloatType::class, ], 'Float type - uppercase' => [ 'raw' => 'FLOAT', 'transformed' => 'float', - 'type' => FloatType::class, + 'type' => NativeFloatType::class, ], 'Float type followed by description' => [ 'raw' => 'float lorem ipsum', 'transformed' => 'float', - 'type' => FloatType::class, + 'type' => NativeFloatType::class, + ], + 'Positive float value' => [ + 'raw' => '1337.42', + 'transformed' => '1337.42', + 'type' => FloatValueType::class, + ], + 'Positive float value followed by description' => [ + 'raw' => '1337.42 lorem ipsum', + 'transformed' => '1337.42', + 'type' => FloatValueType::class, + ], + 'Negative float value' => [ + 'raw' => '-1337.42', + 'transformed' => '-1337.42', + 'type' => FloatValueType::class, + ], + 'Negative float value followed by description' => [ + 'raw' => '-1337.42 lorem ipsum', + 'transformed' => '-1337.42', + 'type' => FloatValueType::class, ], 'Integer type' => [ 'raw' => 'int', @@ -659,7 +680,7 @@ public function test_multiple_union_types_are_parsed(): void $types = $unionType->types(); self::assertInstanceOf(IntegerType::class, $types[0]); - self::assertInstanceOf(FloatType::class, $types[1]); + self::assertInstanceOf(NativeFloatType::class, $types[1]); self::assertInstanceOf(StringType::class, $types[2]); } diff --git a/tests/Integration/Mapping/Object/ScalarValuesMappingTest.php b/tests/Integration/Mapping/Object/ScalarValuesMappingTest.php index 48f63063..e6cd2bbf 100644 --- a/tests/Integration/Mapping/Object/ScalarValuesMappingTest.php +++ b/tests/Integration/Mapping/Object/ScalarValuesMappingTest.php @@ -20,6 +20,8 @@ public function test_values_are_mapped_properly(): void $source = [ 'boolean' => true, 'float' => 42.404, + 'positiveFloatValue' => 42.404, + 'negativeFloatValue' => -42.404, 'integer' => 1337, 'positiveInteger' => 1337, 'negativeInteger' => -1337, @@ -46,6 +48,8 @@ public function test_values_are_mapped_properly(): void self::assertSame(true, $result->boolean); self::assertSame(42.404, $result->float); + self::assertSame(42.404, $result->positiveFloatValue); // @phpstan-ignore-line + self::assertSame(-42.404, $result->negativeFloatValue); // @phpstan-ignore-line self::assertSame(1337, $result->integer); self::assertSame(1337, $result->positiveInteger); self::assertSame(-1337, $result->negativeInteger); @@ -99,6 +103,12 @@ class ScalarValues public float $float = -1.0; + /** @var 42.404 */ + public float $positiveFloatValue; + + /** @var -42.404 */ + public float $negativeFloatValue; + public int $integer = -1; /** @var positive-int */ @@ -146,6 +156,8 @@ class ScalarValues class ScalarValuesWithConstructor extends ScalarValues { /** + * @param 42.404 $positiveFloatValue + * @param -42.404 $negativeFloatValue * @param positive-int $positiveInteger * @param negative-int $negativeInteger * @param int<-1337, 1337> $integerRangeWithPositiveValue @@ -163,6 +175,8 @@ class ScalarValuesWithConstructor extends ScalarValues public function __construct( bool $boolean, float $float, + float $positiveFloatValue, + float $negativeFloatValue, int $integer, int $positiveInteger, int $negativeInteger, @@ -181,6 +195,8 @@ public function __construct( ) { $this->boolean = $boolean; $this->float = $float; + $this->positiveFloatValue = $positiveFloatValue; + $this->negativeFloatValue = $negativeFloatValue; $this->integer = $integer; $this->positiveInteger = $positiveInteger; $this->negativeInteger = $negativeInteger; diff --git a/tests/Integration/Mapping/Object/UnionValuesMappingTest.php b/tests/Integration/Mapping/Object/UnionValuesMappingTest.php index 461a3fc6..ea6c512e 100644 --- a/tests/Integration/Mapping/Object/UnionValuesMappingTest.php +++ b/tests/Integration/Mapping/Object/UnionValuesMappingTest.php @@ -20,6 +20,8 @@ public function test_values_are_mapped_properly(): void 'scalarWithString' => 'foo', 'nullableWithString' => 'bar', 'nullableWithNull' => null, + 'positiveFloatValue' => 1337.42, + 'negativeFloatValue' => -1337.42, 'positiveIntegerValue' => 1337, 'negativeIntegerValue' => -1337, 'stringValueWithSingleQuote' => 'bar', @@ -48,6 +50,8 @@ public function test_values_are_mapped_properly(): void self::assertSame(null, $result->nullableWithNull); if ($result instanceof UnionValues) { + self::assertSame(1337.42, $result->positiveFloatValue); + self::assertSame(-1337.42, $result->negativeFloatValue); self::assertSame(1337, $result->positiveIntegerValue); self::assertSame(-1337, $result->negativeIntegerValue); self::assertSame('bar', $result->stringValueWithSingleQuote); @@ -77,6 +81,12 @@ class UnionValues /** @var string|null|float */ public $nullableWithNull = 'Schwifty!'; + /** @var 404.42|1337.42 */ + public float $positiveFloatValue = 404.42; + + /** @var -404.42|-1337.42 */ + public float $negativeFloatValue = -404.42; + /** @var 42|1337 */ public int $positiveIntegerValue = 42; @@ -99,6 +109,8 @@ class UnionValuesWithConstructor extends UnionValues * @param bool|float|int|string $scalarWithString * @param string|null|float $nullableWithString * @param string|null|float $nullableWithNull + * @param 404.42|1337.42 $positiveFloatValue + * @param -404.42|-1337.42 $negativeFloatValue * @param 42|1337 $positiveIntegerValue * @param -42|-1337 $negativeIntegerValue * @param 'foo'|'bar' $stringValueWithSingleQuote @@ -111,6 +123,8 @@ public function __construct( $scalarWithString = 'Schwifty!', $nullableWithString = 'Schwifty!', $nullableWithNull = 'Schwifty!', + float $positiveFloatValue = 404.42, + float $negativeFloatValue = -404.42, int $positiveIntegerValue = 42, int $negativeIntegerValue = -42, string $stringValueWithSingleQuote = 'foo', @@ -122,6 +136,8 @@ public function __construct( $this->scalarWithString = $scalarWithString; $this->nullableWithString = $nullableWithString; $this->nullableWithNull = $nullableWithNull; + $this->positiveFloatValue = $positiveFloatValue; + $this->negativeFloatValue = $negativeFloatValue; $this->positiveIntegerValue = $positiveIntegerValue; $this->negativeIntegerValue = $negativeIntegerValue; $this->stringValueWithSingleQuote = $stringValueWithSingleQuote; diff --git a/tests/Unit/Type/Resolver/Union/UnionScalarNarrowerTest.php b/tests/Unit/Type/Resolver/Union/UnionScalarNarrowerTest.php index a7ea450c..55613185 100644 --- a/tests/Unit/Type/Resolver/Union/UnionScalarNarrowerTest.php +++ b/tests/Unit/Type/Resolver/Union/UnionScalarNarrowerTest.php @@ -11,7 +11,7 @@ use CuyZ\Valinor\Type\StringType; use CuyZ\Valinor\Type\Type; use CuyZ\Valinor\Type\Types\BooleanType; -use CuyZ\Valinor\Type\Types\FloatType; +use CuyZ\Valinor\Type\Types\NativeFloatType; use CuyZ\Valinor\Type\Types\NativeIntegerType; use CuyZ\Valinor\Type\Types\NativeStringType; use CuyZ\Valinor\Type\Types\UndefinedObjectType; @@ -47,7 +47,7 @@ public function matching_types_are_resolved_data_provider(): iterable { $scalarUnion = new UnionType( NativeIntegerType::get(), - FloatType::get(), + NativeFloatType::get(), NativeStringType::get(), BooleanType::get(), ); @@ -61,12 +61,12 @@ public function matching_types_are_resolved_data_provider(): iterable 'int|float|string|bool with float value' => [ 'Union type' => $scalarUnion, 'Source' => 1337.42, - 'Expected type' => FloatType::class, + 'Expected type' => NativeFloatType::class, ], 'int|float with stringed-float value' => [ - 'Union type' => new UnionType(NativeIntegerType::get(), FloatType::get()), + 'Union type' => new UnionType(NativeIntegerType::get(), NativeFloatType::get()), 'Source' => '1337.42', - 'Expected type' => FloatType::class, + 'Expected type' => NativeFloatType::class, ], 'int|float|string|bool with string value' => [ 'Union type' => $scalarUnion, @@ -88,7 +88,7 @@ public function matching_types_are_resolved_data_provider(): iterable public function test_integer_type_is_narrowed_over_float_when_an_integer_value_is_given(): void { - $unionType = new UnionType(FloatType::get(), NativeIntegerType::get()); + $unionType = new UnionType(NativeFloatType::get(), NativeIntegerType::get()); $type = $this->unionScalarNarrower->narrow($unionType, 42); @@ -97,7 +97,7 @@ public function test_integer_type_is_narrowed_over_float_when_an_integer_value_i public function test_several_possible_types_throws_exception(): void { - $unionType = new UnionType(BooleanType::get(), NativeIntegerType::get(), FloatType::get()); + $unionType = new UnionType(BooleanType::get(), NativeIntegerType::get(), NativeFloatType::get()); $this->expectException(CannotResolveTypeFromUnion::class); $this->expectExceptionCode(1607027306); diff --git a/tests/Unit/Type/Types/FloatValueTypeTest.php b/tests/Unit/Type/Types/FloatValueTypeTest.php new file mode 100644 index 00000000..40ab23f8 --- /dev/null +++ b/tests/Unit/Type/Types/FloatValueTypeTest.php @@ -0,0 +1,142 @@ +floatValueType = new FloatValueType(1337.42); + } + + public function test_value_can_be_retrieved(): void + { + self::assertSame(1337.42, $this->floatValueType->value()); + } + + public function test_accepts_correct_values(): void + { + self::assertTrue($this->floatValueType->accepts(1337.42)); + } + + public function test_does_not_accept_incorrect_values(): void + { + self::assertFalse($this->floatValueType->accepts(null)); + self::assertFalse($this->floatValueType->accepts('Schwifty!')); + self::assertFalse($this->floatValueType->accepts(404)); + self::assertFalse($this->floatValueType->accepts(404.42)); + self::assertFalse($this->floatValueType->accepts(['foo' => 'bar'])); + self::assertFalse($this->floatValueType->accepts(false)); + self::assertFalse($this->floatValueType->accepts(new stdClass())); + } + + public function test_can_cast_float_value(): void + { + self::assertTrue($this->floatValueType->canCast(404)); + self::assertTrue($this->floatValueType->canCast(42.1337)); + self::assertTrue($this->floatValueType->canCast('42.1337')); + } + + public function test_cannot_cast_other_types(): void + { + self::assertFalse($this->floatValueType->canCast(null)); + self::assertFalse($this->floatValueType->canCast(['foo' => 'bar'])); + self::assertFalse($this->floatValueType->canCast('Schwifty!')); + self::assertFalse($this->floatValueType->canCast(false)); + self::assertFalse($this->floatValueType->canCast(new stdClass())); + } + + public function test_cast_value_returns_correct_result(): void + { + self::assertSame(1337.42, $this->floatValueType->cast('1337.42')); + self::assertSame(1337.42, $this->floatValueType->cast(1337.42)); + } + + public function test_cast_invalid_value_throws_exception(): void + { + $this->expectException(InvalidFloatValueType::class); + $this->expectExceptionCode(1652110003); + $this->expectExceptionMessage('Value of type `string` does not match float value `1337.42`.'); + + $this->floatValueType->cast('foo'); + } + + public function test_cast_another_float_value_throws_exception(): void + { + $this->expectException(InvalidFloatValue::class); + $this->expectExceptionCode(1652110115); + $this->expectExceptionMessage('Value `404.42` does not match expected value `1337.42`.'); + + $this->floatValueType->cast('404.42'); + } + + public function test_string_value_is_correct(): void + { + self::assertSame('1337.42', (string)$this->floatValueType); + } + + public function test_matches_native_float_type(): void + { + self::assertTrue($this->floatValueType->matches(new NativeFloatType())); + } + + public function test_matches_other_float_type_with_same_value(): void + { + self::assertTrue($this->floatValueType->matches(new FloatValueType(1337.42))); + } + + public function test_does_not_match_other_type(): void + { + self::assertFalse($this->floatValueType->matches(new FakeType())); + } + + public function test_matches_mixed_type(): void + { + self::assertTrue($this->floatValueType->matches(new MixedType())); + } + + public function test_matches_union_type_containing_native_float_type(): void + { + $unionType = new UnionType( + new FakeType(), + new NativeFloatType(), + new FakeType(), + ); + + self::assertTrue($this->floatValueType->matches($unionType)); + } + + public function test_matches_union_type_containing_float_type_with_same_value(): void + { + $unionType = new UnionType( + new FakeType(), + new FloatValueType(1337.42), + new FakeType(), + ); + + self::assertTrue($this->floatValueType->matches($unionType)); + } + + public function test_does_not_match_union_type_not_containing_float_type(): void + { + $unionType = new UnionType(new FakeType(), new FakeType()); + + self::assertFalse($this->floatValueType->matches($unionType)); + } +} diff --git a/tests/Unit/Type/Types/IntegerValueTypeTest.php b/tests/Unit/Type/Types/IntegerValueTypeTest.php index 1ecc6c0c..1e3dedbf 100644 --- a/tests/Unit/Type/Types/IntegerValueTypeTest.php +++ b/tests/Unit/Type/Types/IntegerValueTypeTest.php @@ -27,6 +27,11 @@ protected function setUp(): void $this->type = new IntegerValueType(1337); } + public function test_value_can_be_retrieved(): void + { + self::assertSame(1337, $this->type->value()); + } + public function test_accepts_correct_values(): void { self::assertTrue($this->type->accepts(1337)); @@ -104,7 +109,7 @@ public function test_cast_another_integer_value_throws_exception(): void $this->expectExceptionCode(1631090798); $this->expectExceptionMessage('Value `42` does not match integer value `1337`.'); - $this->type->cast(42); + $this->type->cast('42'); } public function test_string_value_is_correct(): void diff --git a/tests/Unit/Type/Types/FloatTypeTest.php b/tests/Unit/Type/Types/NativeFloatTypeTest.php similarity index 92% rename from tests/Unit/Type/Types/FloatTypeTest.php rename to tests/Unit/Type/Types/NativeFloatTypeTest.php index 7c75d64f..7d4bd8a6 100644 --- a/tests/Unit/Type/Types/FloatTypeTest.php +++ b/tests/Unit/Type/Types/NativeFloatTypeTest.php @@ -7,23 +7,23 @@ use CuyZ\Valinor\Tests\Fake\Type\FakeType; use CuyZ\Valinor\Tests\Traits\TestIsSingleton; use CuyZ\Valinor\Type\Types\Exception\CannotCastValue; -use CuyZ\Valinor\Type\Types\FloatType; +use CuyZ\Valinor\Type\Types\NativeFloatType; use CuyZ\Valinor\Type\Types\MixedType; use CuyZ\Valinor\Type\Types\UnionType; use PHPUnit\Framework\TestCase; use stdClass; -final class FloatTypeTest extends TestCase +final class NativeFloatTypeTest extends TestCase { use TestIsSingleton; - private FloatType $floatType; + private NativeFloatType $floatType; protected function setUp(): void { parent::setUp(); - $this->floatType = new FloatType(); + $this->floatType = new NativeFloatType(); } public function test_accepts_correct_values(): void @@ -101,8 +101,8 @@ public function test_string_value_is_correct(): void public function test_matches_valid_types(): void { - $floatTypeA = new FloatType(); - $floatTypeB = new FloatType(); + $floatTypeA = new NativeFloatType(); + $floatTypeB = new NativeFloatType(); self::assertTrue($floatTypeA->matches($floatTypeB)); } @@ -121,7 +121,7 @@ public function test_matches_union_type_containing_float_type(): void { $unionType = new UnionType( new FakeType(), - new FloatType(), + new NativeFloatType(), new FakeType(), ); diff --git a/tests/Unit/Type/Types/ShapedArrayTypeTest.php b/tests/Unit/Type/Types/ShapedArrayTypeTest.php index c1ebef06..77350a8a 100644 --- a/tests/Unit/Type/Types/ShapedArrayTypeTest.php +++ b/tests/Unit/Type/Types/ShapedArrayTypeTest.php @@ -9,7 +9,7 @@ use CuyZ\Valinor\Type\Parser\Exception\Iterable\ShapedArrayElementDuplicatedKey; use CuyZ\Valinor\Type\Types\ArrayKeyType; use CuyZ\Valinor\Type\Types\ArrayType; -use CuyZ\Valinor\Type\Types\FloatType; +use CuyZ\Valinor\Type\Types\NativeFloatType; use CuyZ\Valinor\Type\Types\IntegerValueType; use CuyZ\Valinor\Type\Types\MixedType; use CuyZ\Valinor\Type\Types\NativeIntegerType; @@ -105,7 +105,7 @@ public function test_matches_valid_array_shaped_type(): void public function test_does_not_match_invalid_array_shaped_type(): void { $otherA = new ShapedArrayType( - new ShapedArrayElement(new StringValueType('foo'), new FloatType()), + new ShapedArrayElement(new StringValueType('foo'), new NativeFloatType()), ); $otherB = new ShapedArrayType( diff --git a/tests/Unit/Type/Types/StringValueTypeTest.php b/tests/Unit/Type/Types/StringValueTypeTest.php index 86939cef..b574249c 100644 --- a/tests/Unit/Type/Types/StringValueTypeTest.php +++ b/tests/Unit/Type/Types/StringValueTypeTest.php @@ -25,6 +25,11 @@ protected function setUp(): void $this->type = new StringValueType('Schwifty!'); } + public function test_value_can_be_retrieved(): void + { + self::assertSame('Schwifty!', $this->type->value()); + } + public function test_accepts_correct_values(): void { $type = new StringValueType('Schwifty!');