Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge release 3.6.3 into 3.7.x #44

Merged
merged 8 commits into from
Dec 24, 2021
7 changes: 6 additions & 1 deletion src/ArrayUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace Laminas\Stdlib;

use Iterator;
use Laminas\Stdlib\ArrayUtils\MergeRemoveKey;
use Laminas\Stdlib\ArrayUtils\MergeReplaceKeyInterface;
use Traversable;
Expand Down Expand Up @@ -240,7 +241,11 @@ public static function iteratorToArray($iterator, $recursive = true)
return iterator_to_array($iterator);
}

if (is_object($iterator) && method_exists($iterator, 'toArray')) {
if (
is_object($iterator)
&& ! $iterator instanceof Iterator
&& method_exists($iterator, 'toArray')
) {
return $iterator->toArray();
}

Expand Down
17 changes: 14 additions & 3 deletions src/Glob.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ protected static function systemGlob($pattern, $flags)
*/
protected static function fallbackGlob($pattern, $flags)
{
if (! $flags & self::GLOB_BRACE) {
if (self::flagsIsEqualTo($flags, self::GLOB_BRACE)) {
return static::systemGlob($pattern, $flags);
}

Expand Down Expand Up @@ -195,14 +195,19 @@ protected static function nextBraceSub($pattern, $begin, $flags)
$current = $begin;

while ($current < $length) {
if (! $flags & self::GLOB_NOESCAPE && $pattern[$current] === '\\') {
$flagsEqualsNoEscape = self::flagsIsEqualTo($flags, self::GLOB_NOESCAPE);

if ($flagsEqualsNoEscape && $pattern[$current] === '\\') {
if (++$current === $length) {
break;
}

$current++;
} else {
if (($pattern[$current] === '}' && $depth-- === 0) || ($pattern[$current] === ',' && $depth === 0)) {
if (
($pattern[$current] === '}' && $depth-- === 0)
|| ($pattern[$current] === ',' && $depth === 0)
) {
break;
} elseif ($pattern[$current++] === '{') {
$depth++;
Expand All @@ -212,4 +217,10 @@ protected static function nextBraceSub($pattern, $begin, $flags)

return $current < $length ? $current : null;
}

/** @internal */
public static function flagsIsEqualTo(int $flags, int $otherFlags): bool
{
return (bool) ($flags & $otherFlags);
}
}
27 changes: 27 additions & 0 deletions test/ArrayUtilsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Laminas\Stdlib\ArrayUtils\MergeReplaceKeyInterface;
use Laminas\Stdlib\Exception\InvalidArgumentException;
use Laminas\Stdlib\Parameters;
use LaminasTest\Stdlib\TestAsset\IteratorWithToArrayMethod;
use PHPUnit\Framework\TestCase;
use stdClass;
use Traversable;
Expand Down Expand Up @@ -579,4 +580,30 @@ public function testInvalidCallableRaiseInvalidArgumentException(): void
$this->expectException(InvalidArgumentException::class);
ArrayUtils::filter([], "INVALID");
}

/**
* @link https://github.com/laminas/laminas-stdlib/issues/18
*/
public function testIteratorToArrayWithIteratorHavingMethodToArrayAndRecursiveIsFalse(): void
{
$arrayB = [
'foo' => 'bar',
];
$iteratorB = new IteratorWithToArrayMethod($arrayB);

$arrayA = [
'iteratorB' => $iteratorB,
];
$iterator = new IteratorWithToArrayMethod($arrayA);

$result = ArrayUtils::iteratorToArray($iterator, true);

$expectedResult = [
'iteratorB' => [
'foo' => 'bar',
],
];

$this->assertEquals($expectedResult, $result);
}
}
75 changes: 71 additions & 4 deletions test/GlobTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use function count;
use function defined;
use function glob;
use function realpath;
use function str_repeat;

use const GLOB_BRACE;
Expand All @@ -23,15 +24,29 @@ public function testFallback(): void
$this->markTestSkipped('GLOB_BRACE not available');
}

self::assertEquals(
glob(__DIR__ . '/_files/{alph,bet}a', GLOB_BRACE),
Glob::glob(__DIR__ . '/_files/{alph,bet}a', Glob::GLOB_BRACE, true)
$expected = glob(__DIR__ . '/_files/{alph,bet}a', GLOB_BRACE);
$actual = Glob::glob(
__DIR__ . '/_files/{alph,bet}a',
Glob::GLOB_BRACE,
true
);

self::assertEquals($actual, $expected);

$notExpectedPath = realpath(__DIR__ . '/_files/{alph,bet}a');

self::assertNotContains(
$notExpectedPath,
$actual
);
}

public function testNonMatchingGlobReturnsArray(): void
{
$result = Glob::glob('/some/path/{,*.}{this,orthis}.php', Glob::GLOB_BRACE);
$result = Glob::glob(
'/some/path/{,*.}{this,orthis}.php',
Glob::GLOB_BRACE
);
self::assertIsArray($result);
}

Expand Down Expand Up @@ -80,4 +95,56 @@ public function patternsProvider(): array
],
];
}

public function testGlobWithoutGlobBraceFlag(): void
{
$expected = [
realpath(__DIR__ . '/_files/{alph,bet}a'),
];

self::assertEquals(
glob(__DIR__ . '/_files/{alph,bet}a', 0),
$expected
);
}

/**
* @psalm-return array<array-key, array{
* int,
* int,
* bool
* }>
*/
public function flagsIsEqualsToMethodDataProvider(): array
{
return [
[
Glob::GLOB_BRACE,
Glob::GLOB_BRACE,
true,
],
[
Glob::GLOB_BRACE,
Glob::GLOB_NOSORT,
false,
],
];
}

/**
* @dataProvider flagsIsEqualsToMethodDataProvider
*/
public function testFlagsIsEqualsToMethod(
int $flags,
int $otherFlags,
bool $expected
): void {
/**
* @psalm-suppress InternalMethod this test is specifically testing the behavior of this method,
* to prevent regressions
*/
$actual = Glob::flagsIsEqualTo($flags, $otherFlags);

$this->assertEquals($expected, $actual);
}
}
67 changes: 67 additions & 0 deletions test/TestAsset/IteratorWithToArrayMethod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

namespace LaminasTest\Stdlib\TestAsset;

use Iterator;
use ReturnTypeWillChange;

use function current;
use function key;
use function next;
use function reset;

class IteratorWithToArrayMethod implements Iterator
{
/** @var array */
private $elements = [];

public function __construct(array $elements)
{
$this->elements = $elements;
}

/** @return void */
#[ReturnTypeWillChange]
public function rewind()
{
reset($this->elements);
}

/** @return mixed */
#[ReturnTypeWillChange]
public function current()
{
return current($this->elements);
}

/** @return int|string */
#[ReturnTypeWillChange]
public function key()
{
return key($this->elements);
}

/** @return mixed */
#[ReturnTypeWillChange]
public function next()
{
return next($this->elements);
}

/** @return bool */
#[ReturnTypeWillChange]
public function valid()
{
$key = key($this->elements);
return $key !== null && $key !== false;
}

public function toArray(): array
{
return [
'data from to array' => 'not good',
];
}
}
Empty file added test/_files/{alph,bet}a
Empty file.