diff --git a/src/Commands/LinkCommand.php b/src/Commands/LinkCommand.php index 97431ef..5cf35aa 100644 --- a/src/Commands/LinkCommand.php +++ b/src/Commands/LinkCommand.php @@ -16,7 +16,7 @@ namespace ComposerLink\Commands; use ComposerLink\PathHelper; -use RuntimeException; +use InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -35,25 +35,26 @@ protected function configure(): void */ protected function execute(InputInterface $input, OutputInterface $output): int { - $path = $input->getArgument('path'); + $helper = new PathHelper($input->getArgument('path')); // When run in global we should transform path to absolute path if ($this->plugin->isGlobal()) { - $transform = new PathHelper($path); /** @var string $working */ $working = $this->getApplication()->getInitialWorkingDirectory(); - $path = $transform->getAbsolutePath($working); + $helper = $helper->toAbsolutePath($working); } - $linkedPackage = $this->plugin->getPackageFactory()->fromPath($path); + $linkedPackage = $this->plugin->getPackageFactory()->fromPath($helper->getNormalizedPath()); - if (!is_null($this->plugin->getRepository()->findByPath($path))) { - throw new RuntimeException(sprintf('Package in path "%s" already linked', $path)); + if (!is_null($this->plugin->getRepository()->findByPath($helper->getNormalizedPath()))) { + throw new InvalidArgumentException( + sprintf('Package in path "%s" already linked', $helper->getNormalizedPath()) + ); } $currentLinked = $this->plugin->getRepository()->findByName($linkedPackage->getName()); if (!is_null($currentLinked)) { - throw new RuntimeException( + throw new InvalidArgumentException( sprintf( 'Package "%s" already linked from path "%s"', $linkedPackage->getName(), diff --git a/src/Commands/UnlinkCommand.php b/src/Commands/UnlinkCommand.php index 72717d2..4a9c6ba 100644 --- a/src/Commands/UnlinkCommand.php +++ b/src/Commands/UnlinkCommand.php @@ -16,6 +16,7 @@ namespace ComposerLink\Commands; use ComposerLink\PathHelper; +use InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -34,25 +35,24 @@ protected function configure(): void */ protected function execute(InputInterface $input, OutputInterface $output): int { - $path = $input->getArgument('path'); + $helper = new PathHelper($input->getArgument('path')); // When run in global we should transform path to absolute path if ($this->plugin->isGlobal()) { - $transform = new PathHelper($path); /** @var string $working */ $working = $this->getApplication()->getInitialWorkingDirectory(); - $path = $transform->getAbsolutePath($working); + $helper = $helper->toAbsolutePath($working); } - $linkedPackage = $this->plugin->getPackageFactory()->fromPath($path); + $linkedPackage = $this->plugin->getPackageFactory()->fromPath($helper->getNormalizedPath()); $repository = $this->plugin->getRepository(); $linkedPackage = $repository->findByPath($linkedPackage->getPath()); if ($linkedPackage === null) { - $this->getIO()->warning(sprintf('No linked package found in path "%s"', $path)); - - return 1; + throw new InvalidArgumentException( + sprintf('No linked package found in path "%s"', $helper->getNormalizedPath()) + ); } $this->plugin->getLinkManager()->unlinkPackage($linkedPackage); diff --git a/src/PathHelper.php b/src/PathHelper.php index 6869274..c087fee 100644 --- a/src/PathHelper.php +++ b/src/PathHelper.php @@ -28,7 +28,7 @@ public function __construct(string $path) $this->path = $path; } - public function getAbsolutePath(string $workingDirectory): string + public function toAbsolutePath(string $workingDirectory): PathHelper { $real = realpath($workingDirectory . DIRECTORY_SEPARATOR . $this->path); if ($real === false) { @@ -37,6 +37,15 @@ public function getAbsolutePath(string $workingDirectory): string ); } - return $real; + return new PathHelper($real); + } + + public function getNormalizedPath(): string + { + if (substr($this->path, -1) === DIRECTORY_SEPARATOR) { + return substr($this->path, 0, -1); + } + + return $this->path; } } diff --git a/tests/Unit/Commands/LinkCommandTest.php b/tests/Unit/Commands/LinkCommandTest.php index 41a96f2..f0e83ee 100644 --- a/tests/Unit/Commands/LinkCommandTest.php +++ b/tests/Unit/Commands/LinkCommandTest.php @@ -22,9 +22,9 @@ use ComposerLink\LinkManager; use ComposerLink\Plugin; use ComposerLink\Repository\Repository; +use InvalidArgumentException; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use RuntimeException; use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\OutputInterface; @@ -107,7 +107,7 @@ public function test_existing_path(): void ->with('/test-path') ->willReturn($this->createMock(LinkedPackage::class)); - $this->expectException(RuntimeException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Package in path "/test-path" already linked'); $input = new StringInput('link /test-path'); @@ -131,7 +131,7 @@ public function test_existing_package_name(): void $command = new LinkCommand($this->plugin); static::assertSame('link', $command->getName()); - $this->expectException(RuntimeException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Package "test/package" already linked from path "/test-path"'); $input = new StringInput('link /test-path'); diff --git a/tests/Unit/Commands/UnlinkCommandTest.php b/tests/Unit/Commands/UnlinkCommandTest.php index 256398d..ffb0a26 100644 --- a/tests/Unit/Commands/UnlinkCommandTest.php +++ b/tests/Unit/Commands/UnlinkCommandTest.php @@ -21,6 +21,7 @@ use ComposerLink\LinkManager; use ComposerLink\Plugin; use ComposerLink\Repository\Repository; +use InvalidArgumentException; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Input\StringInput; @@ -90,8 +91,9 @@ public function test_link_command_for_existing_package_global(): void public function test_link_command_for_non_existing_package(): void { $this->repository->expects(static::once())->method('findByPath')->willReturn(null); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('No linked package found in path "/test-path"'); - $input = new StringInput('unlink /test-path'); - static::assertSame(1, $this->application->run($input, $this->output)); + $this->application->run(new StringInput('unlink /test-path'), $this->output); } } diff --git a/tests/Unit/PathHelperTest.php b/tests/Unit/PathHelperTest.php index 6335c2c..eb0f44f 100644 --- a/tests/Unit/PathHelperTest.php +++ b/tests/Unit/PathHelperTest.php @@ -25,11 +25,13 @@ class PathHelperTest extends TestCase */ public function test_get_absolute_path(string $pah): void { - $root = realpath(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..'); + $testPath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..'; + $root = realpath($testPath); $helper = new PathHelper($pah); static::assertEquals( $root . DIRECTORY_SEPARATOR . $pah, - $helper->getAbsolutePath(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..') + $helper->toAbsolutePath($testPath) + ->getNormalizedPath() ); } @@ -38,7 +40,17 @@ public function test_get_invalid_absolute_path(): void $this->expectException(InvalidArgumentException::class); $helper = new PathHelper('some-path-non-existing-path'); $root = PHP_OS_FAMILY === 'Windows' ? 'C:\\' : '/'; - $helper->getAbsolutePath($root); + $helper->toAbsolutePath($root); + } + + public function test_paths_considered_equal_without_trailing_separator(): void + { + $path = PHP_OS_FAMILY === 'Windows' ? 'C:\\some\\path' : '/some/path'; + + $helper1 = new PathHelper($path); + $helper2 = new PathHelper($path . DIRECTORY_SEPARATOR); + + static::assertSame($helper1->getNormalizedPath(), $helper2->getNormalizedPath()); } /**