Skip to content

Commit a5a41b5

Browse files
committed
allow to set ->length
1 parent f617212 commit a5a41b5

3 files changed

Lines changed: 178 additions & 57 deletions

File tree

infection.json

Lines changed: 73 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -18,87 +18,103 @@
1818
"@default": true,
1919
"DecrementInteger": {
2020
"ignore": [
21-
"Chubbyphp\\Typescript\\Arr::copyWithin::183",
22-
"Chubbyphp\\Typescript\\Arr::copyWithin::189",
23-
"Chubbyphp\\Typescript\\Arr::every::228",
24-
"Chubbyphp\\Typescript\\Arr::fill::252",
25-
"Chubbyphp\\Typescript\\Arr::filter::274",
26-
"Chubbyphp\\Typescript\\Arr::forEach::406",
27-
"Chubbyphp\\Typescript\\Arr::indexOf::436",
28-
"Chubbyphp\\Typescript\\Arr::lastIndexOf::474",
29-
"Chubbyphp\\Typescript\\Arr::lastIndexOf::478",
30-
"Chubbyphp\\Typescript\\Arr::lastIndexOf::479",
31-
"Chubbyphp\\Typescript\\Arr::map::506",
32-
"Chubbyphp\\Typescript\\Arr::reduce::566",
33-
"Chubbyphp\\Typescript\\Arr::reduce::569",
34-
"Chubbyphp\\Typescript\\Arr::reduceRight::609",
35-
"Chubbyphp\\Typescript\\Arr::reduceRight::612",
36-
"Chubbyphp\\Typescript\\Arr::slice::685",
37-
"Chubbyphp\\Typescript\\Arr::some::725",
38-
"Chubbyphp\\Typescript\\Arr::splice::810",
39-
"Chubbyphp\\Typescript\\Arr::toSpliced::887",
40-
"Chubbyphp\\Typescript\\Arr::with::918"
21+
"Chubbyphp\\Typescript\\Arr::__set::75",
22+
"Chubbyphp\\Typescript\\Arr::copyWithin::206",
23+
"Chubbyphp\\Typescript\\Arr::copyWithin::212",
24+
"Chubbyphp\\Typescript\\Arr::every::251",
25+
"Chubbyphp\\Typescript\\Arr::fill::275",
26+
"Chubbyphp\\Typescript\\Arr::filter::297",
27+
"Chubbyphp\\Typescript\\Arr::forEach::429",
28+
"Chubbyphp\\Typescript\\Arr::indexOf::459",
29+
"Chubbyphp\\Typescript\\Arr::lastIndexOf::497",
30+
"Chubbyphp\\Typescript\\Arr::lastIndexOf::501",
31+
"Chubbyphp\\Typescript\\Arr::lastIndexOf::502",
32+
"Chubbyphp\\Typescript\\Arr::map::529",
33+
"Chubbyphp\\Typescript\\Arr::reduce::589",
34+
"Chubbyphp\\Typescript\\Arr::reduce::592",
35+
"Chubbyphp\\Typescript\\Arr::reduceRight::632",
36+
"Chubbyphp\\Typescript\\Arr::reduceRight::635",
37+
"Chubbyphp\\Typescript\\Arr::slice::708",
38+
"Chubbyphp\\Typescript\\Arr::some::748",
39+
"Chubbyphp\\Typescript\\Arr::splice::833",
40+
"Chubbyphp\\Typescript\\Arr::toSpliced::910",
41+
"Chubbyphp\\Typescript\\Arr::with::941"
42+
]
43+
},
44+
"Foreach_": {
45+
"ignore": [
46+
"Chubbyphp\\Typescript\\Arr::__set::80"
4147
]
4248
},
4349
"GreaterThan": {
4450
"ignore": [
45-
"Chubbyphp\\Typescript\\Arr::slice::692",
46-
"Chubbyphp\\Typescript\\Arr::slice::696",
47-
"Chubbyphp\\Typescript\\Arr::splice::766",
48-
"Chubbyphp\\Typescript\\Arr::splice::771",
49-
"Chubbyphp\\Typescript\\Arr::splice::772",
50-
"Chubbyphp\\Typescript\\Arr::toSpliced::876",
51-
"Chubbyphp\\Typescript\\Arr::toSpliced::881",
52-
"Chubbyphp\\Typescript\\Arr::mixedToString::1032"
51+
"Chubbyphp\\Typescript\\Arr::mixedToString::1055",
52+
"Chubbyphp\\Typescript\\Arr::slice::715",
53+
"Chubbyphp\\Typescript\\Arr::slice::719",
54+
"Chubbyphp\\Typescript\\Arr::splice::789",
55+
"Chubbyphp\\Typescript\\Arr::splice::794",
56+
"Chubbyphp\\Typescript\\Arr::splice::795",
57+
"Chubbyphp\\Typescript\\Arr::toSpliced::899",
58+
"Chubbyphp\\Typescript\\Arr::toSpliced::904"
5359
]
5460
},
5561
"GreaterThanOrEqualTo": {
5662
"ignore": [
57-
"Chubbyphp\\Typescript\\Arr::slice::700"
63+
"Chubbyphp\\Typescript\\Arr::__set::81",
64+
"Chubbyphp\\Typescript\\Arr::slice::723"
65+
]
66+
},
67+
"IncrementInteger": {
68+
"ignore": [
69+
"Chubbyphp\\Typescript\\Arr::__set::75"
5870
]
5971
},
6072
"LessThan": {
6173
"ignore": [
62-
"Chubbyphp\\Typescript\\Arr::copyWithin::187",
63-
"Chubbyphp\\Typescript\\Arr::copyWithin::189",
64-
"Chubbyphp\\Typescript\\Arr::every::228",
65-
"Chubbyphp\\Typescript\\Arr::indexOf::438",
66-
"Chubbyphp\\Typescript\\Arr::map::506",
67-
"Chubbyphp\\Typescript\\Arr::reduce::569",
68-
"Chubbyphp\\Typescript\\Arr::reduce::584",
69-
"Chubbyphp\\Typescript\\Arr::some::725",
70-
"Chubbyphp\\Typescript\\Arr::with::907",
71-
"Chubbyphp\\Typescript\\Arr::with::911",
72-
"Chubbyphp\\Typescript\\Arr::with::918"
74+
"Chubbyphp\\Typescript\\Arr::__set::75",
75+
"Chubbyphp\\Typescript\\Arr::__set::79",
76+
"Chubbyphp\\Typescript\\Arr::copyWithin::210",
77+
"Chubbyphp\\Typescript\\Arr::copyWithin::212",
78+
"Chubbyphp\\Typescript\\Arr::every::251",
79+
"Chubbyphp\\Typescript\\Arr::indexOf::461",
80+
"Chubbyphp\\Typescript\\Arr::map::529",
81+
"Chubbyphp\\Typescript\\Arr::reduce::592",
82+
"Chubbyphp\\Typescript\\Arr::reduce::607",
83+
"Chubbyphp\\Typescript\\Arr::some::748",
84+
"Chubbyphp\\Typescript\\Arr::with::930",
85+
"Chubbyphp\\Typescript\\Arr::with::934",
86+
"Chubbyphp\\Typescript\\Arr::with::941"
87+
]
88+
},
89+
"LessThanNegotiation": {
90+
"ignore": [
91+
"Chubbyphp\\Typescript\\Arr::__set::79"
7392
]
7493
},
7594
"LogicalAndSingleSubExprNegation": {
7695
"ignore": [
77-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1062",
78-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1066"
96+
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1085",
97+
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1089"
7998
]
8099
},
81100
"Minus": {
82101
"ignore": [
83-
"Chubbyphp\\Typescript\\Arr::lastIndexOf::478",
84-
"Chubbyphp\\Typescript\\Arr::lastIndexOf::479",
85-
"Chubbyphp\\Typescript\\Arr::reduceRight::609",
86-
"Chubbyphp\\Typescript\\Arr::reduceRight::612",
87-
"Chubbyphp\\Typescript\\Arr::splice::771",
88-
"Chubbyphp\\Typescript\\Arr::toSpliced::881",
89-
"Chubbyphp\\Typescript\\Arr::toSpliced::887"
102+
"Chubbyphp\\Typescript\\Arr::lastIndexOf::501",
103+
"Chubbyphp\\Typescript\\Arr::lastIndexOf::502",
104+
"Chubbyphp\\Typescript\\Arr::reduceRight::632",
105+
"Chubbyphp\\Typescript\\Arr::reduceRight::635",
106+
"Chubbyphp\\Typescript\\Arr::splice::794",
107+
"Chubbyphp\\Typescript\\Arr::toSpliced::904",
108+
"Chubbyphp\\Typescript\\Arr::toSpliced::910"
90109
]
91110
},
92111
"ReturnRemoval": {
93112
"ignore": [
94-
"Chubbyphp\\Typescript\\Arr::lastIndexOf::475",
95-
"Chubbyphp\\Typescript\\Arr::offsetSet::1006",
96-
"Chubbyphp\\Typescript\\Arr::offsetSet::1010",
97-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1063",
98-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1067",
99-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1070",
100-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1073"
113+
"Chubbyphp\\Typescript\\Arr::lastIndexOf::498",
114+
"Chubbyphp\\Typescript\\Arr::offsetSet::1029",
115+
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1086",
116+
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1090"
101117
]
102118
}
103119
}
104-
}
120+
}

src/Arr.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,29 @@ public function __get(string $name): mixed
6969
return null;
7070
}
7171

72+
public function __set(string $name, mixed $value): void
73+
{
74+
if ('length' === $name) {
75+
if (!\is_int($value) || 0 > $value || (2 ** 32) - 1 < $value) {
76+
throw new RangeError(self::RANGE_ERROR_INVALID_LENGTH);
77+
}
78+
79+
if ($value < $this->internalLength) {
80+
foreach ($this->internalArray as $key => $v) {
81+
if ($key >= $value) {
82+
unset($this->internalArray[$key]);
83+
}
84+
}
85+
}
86+
87+
$this->internalLength = $value;
88+
89+
return;
90+
}
91+
92+
trigger_error('Undefined property: A::$'.$name, E_USER_WARNING);
93+
}
94+
7295
public function __toString(): string
7396
{
7497
return $this->toString();

tests/Unit/ArrTest.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,88 @@ public function testArrayGetUnknownProperty(): void
293293
self::assertSame('Undefined property: A::$unknown', $lastError['message']);
294294
}
295295

296+
// __set
297+
298+
public function testArraySetLengthTruncatesArray(): void
299+
{
300+
$array = new Arr(1, 2, 3, 4, 5);
301+
$array->length = 2;
302+
303+
self::assertSame(2, $array->length);
304+
self::assertSame([1, 2], $array->toArray());
305+
}
306+
307+
public function testArraySetLengthExtendsWithHoles(): void
308+
{
309+
$array = new Arr(1, 2);
310+
$array->length = 5;
311+
312+
self::assertSame(5, $array->length);
313+
self::assertSame([1, 2, null, null, null], $array->toArray());
314+
}
315+
316+
public function testArraySetLengthToZeroEmptiesArray(): void
317+
{
318+
$array = new Arr(1, 2, 3);
319+
$array->length = 0;
320+
321+
self::assertSame(0, $array->length);
322+
self::assertSame([], $array->toArray());
323+
}
324+
325+
public function testArraySetLengthToSameValueIsNoop(): void
326+
{
327+
$array = new Arr(1, 2, 3);
328+
$array->length = 3;
329+
330+
self::assertSame(3, $array->length);
331+
self::assertSame([1, 2, 3], $array->toArray());
332+
}
333+
334+
public function testArraySetLengthThrowsRangeErrorForNegative(): void
335+
{
336+
$this->expectException(RangeError::class);
337+
$this->expectExceptionMessage('Invalid array length');
338+
339+
$array = new Arr(1, 2, 3);
340+
$array->length = -1;
341+
}
342+
343+
public function testArraySetLengthThrowsRangeErrorForFloat(): void
344+
{
345+
$this->expectException(RangeError::class);
346+
$this->expectExceptionMessage('Invalid array length');
347+
348+
$array = new Arr(1, 2, 3);
349+
$array->length = 1.5;
350+
}
351+
352+
public function testArraySetLengthThrowsRangeErrorForTooLarge(): void
353+
{
354+
$this->expectException(RangeError::class);
355+
$this->expectExceptionMessage('Invalid array length');
356+
357+
$array = new Arr(1, 2, 3);
358+
$array->length = 2 ** 32;
359+
}
360+
361+
public function testArraySetUnknownPropertyTriggersWarning(): void
362+
{
363+
$array = new Arr(1, 2, 3);
364+
365+
error_clear_last();
366+
367+
@$array->unknown = 'x';
368+
369+
$lastError = error_get_last();
370+
371+
self::assertNotNull($lastError);
372+
self::assertArrayHasKey('type', $lastError);
373+
self::assertSame(E_USER_WARNING, $lastError['type']);
374+
self::assertArrayHasKey('message', $lastError);
375+
self::assertSame('Undefined property: A::$unknown', $lastError['message']);
376+
}
377+
296378
// __toString
297379

298380
public function testMagicToStringDelegatesToJoin(): void

0 commit comments

Comments
 (0)