Skip to content

Commit b4d9a47

Browse files
committed
fix: properly handle large string integer casting
1 parent 1217986 commit b4d9a47

File tree

6 files changed

+60
-16
lines changed

6 files changed

+60
-16
lines changed

src/Type/Types/IntegerRangeType.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
use function is_int;
2020
use function is_string;
2121
use function ltrim;
22-
use function preg_match;
2322
use function sprintf;
2423

2524
/** @internal */
@@ -97,10 +96,8 @@ public function inferGenericsFrom(Type $other, Generics $generics): Generics
9796

9897
public function canCast(mixed $value): bool
9998
{
100-
if (is_string($value)) {
101-
$value = preg_match('/^0+$/', $value)
102-
? '0'
103-
: ltrim($value, '0');
99+
if (is_string($value) && $value !== '') {
100+
$value = ltrim($value, '0') ?: '0';
104101
}
105102

106103
return ! is_bool($value)

src/Type/Types/IntegerValueType.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use function is_bool;
1818
use function is_string;
1919
use function ltrim;
20-
use function preg_match;
2120

2221
/** @internal */
2322
final class IntegerValueType implements IntegerType, FixedType
@@ -46,10 +45,8 @@ public function inferGenericsFrom(Type $other, Generics $generics): Generics
4645

4746
public function canCast(mixed $value): bool
4847
{
49-
if (is_string($value)) {
50-
$value = preg_match('/^0+$/', $value)
51-
? '0'
52-
: ltrim($value, '0');
48+
if (is_string($value) && $value !== '') {
49+
$value = ltrim($value, '0') ?: '0';
5350
}
5451

5552
return ! is_bool($value)

src/Type/Types/NativeIntegerType.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ public function inferGenericsFrom(Type $other, Generics $generics): Generics
5656

5757
public function canCast(mixed $value): bool
5858
{
59-
if (is_string($value)) {
60-
$value = ltrim($value, '0') . '0';
59+
if (is_string($value) && $value !== '') {
60+
$value = ltrim($value, '0') ?: '0';
6161
}
6262

6363
return ! is_bool($value) && filter_var($value, FILTER_VALIDATE_INT) !== false;

src/Type/Types/NonNegativeIntegerType.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ public function inferGenericsFrom(Type $other, Generics $generics): Generics
5757

5858
public function canCast(mixed $value): bool
5959
{
60-
if (is_string($value)) {
61-
$value = ltrim($value, '0') . '0';
60+
if (is_string($value) && $value !== '') {
61+
$value = ltrim($value, '0') ?: '0';
6262
}
6363

6464
return ! is_bool($value)

src/Type/Types/PositiveIntegerType.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ public function inferGenericsFrom(Type $other, Generics $generics): Generics
5757

5858
public function canCast(mixed $value): bool
5959
{
60-
if (is_string($value)) {
61-
$value = ltrim($value, '0');
60+
if (is_string($value) && $value !== '') {
61+
$value = ltrim($value, '0') ?: '0';
6262
}
6363

6464
return ! is_bool($value)

tests/Integration/Mapping/Other/ScalarValueCastingMappingTest.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use CuyZ\Valinor\Tests\Fixture\Enum\BackedStringEnum;
1010
use CuyZ\Valinor\Tests\Fixture\Object\StringableObject;
1111
use CuyZ\Valinor\Tests\Integration\IntegrationTestCase;
12+
use PHPUnit\Framework\Attributes\DataProvider;
1213
use PHPUnit\Framework\Attributes\TestWith;
1314

1415
final class ScalarValueCastingMappingTest extends IntegrationTestCase
@@ -50,4 +51,53 @@ public function test_scalar_values_are_casted_properly(string $type, mixed $valu
5051
$this->mappingFail($error);
5152
}
5253
}
54+
55+
#[DataProvider('integer_values_are_casted_properly_data_provider')]
56+
public function test_integer_values_are_casted_properly(string $type, mixed $value, mixed $expected): void
57+
{
58+
try {
59+
$result = $this
60+
->mapperBuilder()
61+
->allowScalarValueCasting()
62+
->mapper()
63+
->map($type, $value);
64+
65+
self::assertSame($expected, $result);
66+
} catch (MappingError $error) {
67+
$this->mappingFail($error);
68+
}
69+
}
70+
71+
public static function integer_values_are_casted_properly_data_provider(): iterable
72+
{
73+
yield 'int with very large integer from string' => [
74+
'type' => 'int',
75+
'value' => (string)(PHP_INT_MAX - 1),
76+
'expected' => PHP_INT_MAX - 1,
77+
];
78+
79+
yield 'non negative int with very large integer from string' => [
80+
'type' => 'non-negative-int',
81+
'value' => (string)(PHP_INT_MAX - 1),
82+
'expected' => PHP_INT_MAX - 1,
83+
];
84+
85+
yield 'positive int with very large integer from string' => [
86+
'type' => 'positive-int',
87+
'value' => (string)(PHP_INT_MAX - 1),
88+
'expected' => PHP_INT_MAX - 1,
89+
];
90+
91+
yield 'integer range with very large integer from string' => [
92+
'type' => 'int<0, max>',
93+
'value' => (string)(PHP_INT_MAX - 1),
94+
'expected' => PHP_INT_MAX - 1,
95+
];
96+
97+
yield 'integer value with very large integer from string' => [
98+
'type' => (string)(PHP_INT_MAX - 1),
99+
'value' => (string)(PHP_INT_MAX - 1),
100+
'expected' => PHP_INT_MAX - 1,
101+
];
102+
}
53103
}

0 commit comments

Comments
 (0)