diff --git a/composer.json b/composer.json
index 25d4a32..256d351 100644
--- a/composer.json
+++ b/composer.json
@@ -28,7 +28,7 @@
"phpstan/phpstan": "^2.1.2",
"phpstan/phpdoc-parser": "^1.30.1",
"bnf/phpstan-psr-container": "^1.1.0",
- "phpunit/phpunit": "9.6.22",
+ "phpunit/phpunit": "^9.6.33",
"phpstan/phpstan-phpunit": "^2.0.4",
"phpstan/phpstan-symfony": "^2.0.2",
"phpstan/phpstan-deprecation-rules": "^2.0.1"
diff --git a/src/Composer/Repository/FixturePathRepository.php b/src/Composer/Repository/FixturePathRepository.php
index 6154a8c..67d0089 100644
--- a/src/Composer/Repository/FixturePathRepository.php
+++ b/src/Composer/Repository/FixturePathRepository.php
@@ -172,7 +172,7 @@ protected function initialize(): void
// copy symlink/relative options to transport options
$package['transport-options'] = array_intersect_key($this->options, ['symlink' => true, 'relative' => true]);
// use the version provided as option if available
- if (isset($package['name'], $this->options['versions'][$package['name']])) {
+ if (isset($package['name']) && is_string($package['name']) && isset($this->options['versions'][$package['name']])) {
$package['version'] = $this->options['versions'][$package['name']];
}
diff --git a/src/Plugin/Config.php b/src/Plugin/Config.php
index cc235c0..7e8eccb 100644
--- a/src/Plugin/Config.php
+++ b/src/Plugin/Config.php
@@ -142,10 +142,21 @@ protected function processFixtureExtensionPaths(array $paths, int $flags = 0): a
$relativePaths = $this->isRelativePathsFlag($flags);
$returnPaths = [];
foreach ($paths as $path => $selection) {
- $path = rtrim(($relativePaths ? $path : $this->realpath($path)), '/\\');
- $returnPaths[$path] = $selection;
+ if ($relativePaths) {
+ $path = $this->normalizePath((string)$path);
+ if ($path === '') {
+ // Keep the current directory, an empty url is not a valid fixture-path repository url.
+ $path = '.';
+ }
+ } else {
+ $path = $this->realpath((string)$path);
+ }
+ // Different notations of the same path must not drop the selection of the former ones.
+ $returnPaths[$path] = isset($returnPaths[$path])
+ ? array_values(array_unique(array_merge($returnPaths[$path], $selection)))
+ : $selection;
}
- return $paths;
+ return $returnPaths;
}
/**
@@ -155,7 +166,7 @@ protected function processFixtureExtensionPaths(array $paths, int $flags = 0): a
*/
private function isRelativePathsFlag(int $flags): bool
{
- return ($flags & self::FLAG_PATHS_RELATIVE) === 1;
+ return ($flags & self::FLAG_PATHS_RELATIVE) !== 0;
}
/**
@@ -165,10 +176,10 @@ private function isRelativePathsFlag(int $flags): bool
*/
private function realpath(string $path): string
{
+ $path = $this->normalizePath($path);
if ($path === '') {
return $this->baseDir;
}
- $path = $this->normalizePath($path);
if ($path[0] === '/' || (!empty($path[1]) && $path[1] === ':')) {
return $path;
}
@@ -224,8 +235,6 @@ private static function handleRootPackageExtraConfig(IOInterface $io, RootPackag
if (empty($fixtureExtensionPaths)) {
return $rootPackageExtraConfig;
}
- $basePath = '/fake/root';
- $config = new self($basePath);
$validPaths = [];
foreach ($fixtureExtensionPaths as $path => $selection) {
if (!is_array($selection)) {
diff --git a/tests/Unit/Plugin/ConfigTest.php b/tests/Unit/Plugin/ConfigTest.php
index 29e47b7..abb2997 100644
--- a/tests/Unit/Plugin/ConfigTest.php
+++ b/tests/Unit/Plugin/ConfigTest.php
@@ -116,6 +116,16 @@ public static function realpathDataSets(): \Generator
'path' => '/',
'expectedPath' => '/',
];
+ yield 'Current directory path returns baseDir' => [
+ 'baseDir' => '/fake/root',
+ 'path' => './',
+ 'expectedPath' => '/fake/root',
+ ];
+ yield 'Relative path is prefixed with baseDir and trimmed' => [
+ 'baseDir' => '/fake/root',
+ 'path' => 'some/relative/path/',
+ 'expectedPath' => '/fake/root/some/relative/path',
+ ];
}
/**
@@ -193,7 +203,8 @@ public static function loadCreatesConfigWithExpectedPathsDataSets(): \Generator
{
yield 'Empty extra config returns empty array' => [
'extraConfig' => [],
- 'expectedPaths' => [],
+ 'expectedRelativePaths' => [],
+ 'expectedAbsolutePaths' => [],
'expectedOutput' => '',
];
yield 'Other extra configuration are kept' => [
@@ -202,7 +213,8 @@ public static function loadCreatesConfigWithExpectedPathsDataSets(): \Generator
'extension-key' => 'some_extension_key',
],
],
- 'expectedPaths' => [],
+ 'expectedRelativePaths' => [],
+ 'expectedAbsolutePaths' => [],
'expectedOutput' => '',
];
yield 'Non-array extra->sbuerk/fixture-packages/paths value is removed' => [
@@ -211,7 +223,8 @@ public static function loadCreatesConfigWithExpectedPathsDataSets(): \Generator
'paths' => false,
],
],
- 'expectedPaths' => [],
+ 'expectedRelativePaths' => [],
+ 'expectedAbsolutePaths' => [],
'expectedOutput' => 'extra->sbuerk/fixture-packages/paths must be an array, "boolean" given.' . PHP_EOL,
];
yield 'Non-array extra->sbuerk/fixture-packages/paths value is removed keeping other settings' => [
@@ -221,16 +234,148 @@ public static function loadCreatesConfigWithExpectedPathsDataSets(): \Generator
'paths' => false,
],
],
- 'expectedPaths' => [],
+ 'expectedRelativePaths' => [],
+ 'expectedAbsolutePaths' => [],
'expectedOutput' => 'extra->sbuerk/fixture-packages/paths must be an array, "boolean" given.' . PHP_EOL,
];
+ yield 'Path without trailing slash' => [
+ 'extraConfig' => [
+ 'sbuerk/fixture-packages' => [
+ 'paths' => [
+ 'Tests/Functional/Fixtures/Extensions/*' => ['autoload'],
+ ],
+ ],
+ ],
+ 'expectedRelativePaths' => [
+ 'Tests/Functional/Fixtures/Extensions/*' => ['autoload'],
+ ],
+ 'expectedAbsolutePaths' => [
+ '/fake/root/Tests/Functional/Fixtures/Extensions/*' => ['autoload'],
+ ],
+ 'expectedOutput' => '',
+ ];
+ yield 'Path with trailing slash is trimmed' => [
+ 'extraConfig' => [
+ 'sbuerk/fixture-packages' => [
+ 'paths' => [
+ 'Tests/Functional/Fixtures/Extensions/' => ['autoload'],
+ ],
+ ],
+ ],
+ 'expectedRelativePaths' => [
+ 'Tests/Functional/Fixtures/Extensions' => ['autoload'],
+ ],
+ 'expectedAbsolutePaths' => [
+ '/fake/root/Tests/Functional/Fixtures/Extensions' => ['autoload'],
+ ],
+ 'expectedOutput' => '',
+ ];
+ yield 'Path with trailing backslash is trimmed' => [
+ 'extraConfig' => [
+ 'sbuerk/fixture-packages' => [
+ 'paths' => [
+ 'Tests\\Functional\\Fixtures\\Extensions\\' => ['autoload-dev'],
+ ],
+ ],
+ ],
+ 'expectedRelativePaths' => [
+ 'Tests/Functional/Fixtures/Extensions' => ['autoload-dev'],
+ ],
+ 'expectedAbsolutePaths' => [
+ '/fake/root/Tests/Functional/Fixtures/Extensions' => ['autoload-dev'],
+ ],
+ 'expectedOutput' => '',
+ ];
+ yield 'Path list syntax with trailing slash is trimmed' => [
+ 'extraConfig' => [
+ 'sbuerk/fixture-packages' => [
+ 'paths' => [
+ 'Tests/Functional/Fixtures/Extensions/*/',
+ ],
+ ],
+ ],
+ 'expectedRelativePaths' => [
+ 'Tests/Functional/Fixtures/Extensions/*' => ['autoload'],
+ ],
+ 'expectedAbsolutePaths' => [
+ '/fake/root/Tests/Functional/Fixtures/Extensions/*' => ['autoload'],
+ ],
+ 'expectedOutput' => '',
+ ];
+ yield 'Path outside project is kept relative or resolved against base dir' => [
+ 'extraConfig' => [
+ 'sbuerk/fixture-packages' => [
+ 'paths' => [
+ '../other-project/Fixtures/*/' => ['autoload', 'autoload-dev'],
+ ],
+ ],
+ ],
+ 'expectedRelativePaths' => [
+ '../other-project/Fixtures/*' => ['autoload', 'autoload-dev'],
+ ],
+ 'expectedAbsolutePaths' => [
+ '/fake/root/../other-project/Fixtures/*' => ['autoload', 'autoload-dev'],
+ ],
+ 'expectedOutput' => '',
+ ];
+ yield 'Current directory path is kept as current directory or resolved to base dir' => [
+ 'extraConfig' => [
+ 'sbuerk/fixture-packages' => [
+ 'paths' => [
+ './' => ['autoload'],
+ ],
+ ],
+ ],
+ 'expectedRelativePaths' => [
+ '.' => ['autoload'],
+ ],
+ 'expectedAbsolutePaths' => [
+ '/fake/root' => ['autoload'],
+ ],
+ 'expectedOutput' => '',
+ ];
+ yield 'Selections of paths normalized to the same path are merged' => [
+ 'extraConfig' => [
+ 'sbuerk/fixture-packages' => [
+ 'paths' => [
+ 'Tests/Fixtures/' => ['autoload'],
+ 'Tests/Fixtures' => ['autoload-dev', 'autoload'],
+ '/fake/root/Tests/Fixtures' => ['autoload-dev'],
+ ],
+ ],
+ ],
+ 'expectedRelativePaths' => [
+ 'Tests/Fixtures' => ['autoload', 'autoload-dev'],
+ '/fake/root/Tests/Fixtures' => ['autoload-dev'],
+ ],
+ 'expectedAbsolutePaths' => [
+ '/fake/root/Tests/Fixtures' => ['autoload', 'autoload-dev'],
+ ],
+ 'expectedOutput' => '',
+ ];
+ yield 'Absolute path is kept absolute and trimmed' => [
+ 'extraConfig' => [
+ 'sbuerk/fixture-packages' => [
+ 'paths' => [
+ '/some/absolute/Fixtures/' => ['autoload'],
+ ],
+ ],
+ ],
+ 'expectedRelativePaths' => [
+ '/some/absolute/Fixtures' => ['autoload'],
+ ],
+ 'expectedAbsolutePaths' => [
+ '/some/absolute/Fixtures' => ['autoload'],
+ ],
+ 'expectedOutput' => '',
+ ];
}
/**
* @dataProvider loadCreatesConfigWithExpectedPathsDataSets
* @test
*/
- public function loadCreatesConfigWithExpectedPaths(array $extraConfig, array $expectedPaths, string $expectedOutput): void
+ public function loadCreatesConfigWithExpectedPaths(array $extraConfig, array $expectedRelativePaths, array $expectedAbsolutePaths, string $expectedOutput): void
{
$rootPackage = new RootPackage('fake/package', '1.0.0', '1.0.0.0');
$rootPackage->setExtra($extraConfig);
@@ -241,7 +386,13 @@ public function loadCreatesConfigWithExpectedPaths(array $extraConfig, array $ex
$bufferedIO = new BufferIO();
$config = Config::load($composer, $bufferedIO);
self::assertInstanceOf(Config::class, $config);
- self::assertSame($expectedPaths, $config->paths(Config::FLAG_PATHS_RELATIVE));
+ self::assertSame($expectedRelativePaths, $config->paths(Config::FLAG_PATHS_RELATIVE));
+ self::assertSame($expectedRelativePaths, $config->get('paths', Config::FLAG_PATHS_RELATIVE));
+ self::assertSame(['config' => ['paths' => $expectedRelativePaths]], $config->all(Config::FLAG_PATHS_RELATIVE));
+ self::assertSame($expectedAbsolutePaths, $config->paths());
+ self::assertSame($expectedAbsolutePaths, $config->paths(Config::FLAG_PATHS_DEFAULT));
+ self::assertSame($expectedAbsolutePaths, $config->get('paths'));
+ self::assertSame(['config' => ['paths' => $expectedAbsolutePaths]], $config->all());
self::assertSame($expectedOutput, $bufferedIO->getOutput());
}
}