Skip to content

Commit f3e82b7

Browse files
committed
SequentialArray: Proberly handle Generators that have begun already
1 parent c057b8d commit f3e82b7

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-4
lines changed

src/Constraint/SequentialArray.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
namespace PhrozenByte\PHPUnitArrayAsserts\Constraint;
2121

2222
use EmptyIterator;
23+
use Exception;
2324
use Generator;
2425
use Iterator;
2526
use IteratorAggregate;
@@ -175,10 +176,13 @@ protected function matches($other): bool
175176
* FALSE otherwise.
176177
*
177178
* Please note that this method will fully traverse a Traversable object.
178-
* If an Iterator is given, this method will try to restore the object's
179-
* pointer to its previous state. This will silently fail for instances of
180-
* NoRewindIterator. Generators will be fully exhausted by this method. The
181-
* behaviour for Iterators with non-unique keys is undefined.
179+
* It expects Traversables to be rewindable. For NoRewindIterator instances
180+
* it assumes that the iterator is still in its initial state. Generators
181+
* will be fully exhausted; if the iterator has begun already, the object
182+
* is considered invalid. If an Iterator is given, this method will try to
183+
* restore the object's pointer to its previous state. This will silently
184+
* fail for NoRewindIterator instances. The behaviour for Iterators with
185+
* non-unique keys is undefined.
182186
*
183187
* The second item of the result array holds an integer representing the
184188
* number of items given. The integer will be ≥ 0 for any traversable data,
@@ -227,6 +231,14 @@ protected function inspectData($other): array
227231
$other = $other->getIterator();
228232
}
229233

234+
if ($other instanceof Generator) {
235+
try {
236+
$other->rewind();
237+
} catch (Exception $e) {
238+
return [ false, -1, false ];
239+
}
240+
}
241+
230242
$restorePointer = null;
231243
if ($other instanceof Iterator) {
232244
if (!($other instanceof Generator) && !($other instanceof NoRewindIterator)) {

tests/Unit/Constraint/SequentialArrayTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,29 @@ public function __construct()
230230
$this->assertSame(4, $other->current());
231231
}
232232

233+
public function testGeneratorWithIntermediatePointer(): void
234+
{
235+
$expectedException = ExpectationFailedException::class;
236+
$expectedExceptionMessage = 'Failed asserting that %s is a sequential array.';
237+
238+
$itemConstraint = new SequentialArray();
239+
$other = (function () {
240+
for ($i = 1; $i <= 10; $i++) {
241+
yield $i;
242+
}
243+
})();
244+
245+
// move pointer after item #2
246+
$other->next();
247+
$other->next();
248+
249+
$this->assertCallableThrows(
250+
$this->callableProxy([ $itemConstraint, 'evaluate' ], $other),
251+
$expectedException,
252+
sprintf($expectedExceptionMessage, (new Exporter())->export($other))
253+
);
254+
}
255+
233256
/**
234257
* @dataProvider dataProviderCountable
235258
*

0 commit comments

Comments
 (0)