From e91825634b381c512b5ca7ee553f1df681a8c5d6 Mon Sep 17 00:00:00 2001 From: Thoriq Firdaus <2067467+tfirdaus@users.noreply.github.com> Date: Tue, 29 Jul 2025 08:15:38 +0700 Subject: [PATCH 1/3] Add `lt` command --- app/Commands/LessThanCommand.php | 71 ++++++++++++++++++++++++++ app/Exceptions/InvalidArgumentType.php | 15 ++++-- 2 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 app/Commands/LessThanCommand.php diff --git a/app/Commands/LessThanCommand.php b/app/Commands/LessThanCommand.php new file mode 100644 index 0000000..e52335a --- /dev/null +++ b/app/Commands/LessThanCommand.php @@ -0,0 +1,71 @@ +setName('lt'); + $this->setDescription('Compare if a version is less than another'); + $this->addArgument('version-a', InputArgument::REQUIRED, 'First version to compare'); + $this->addArgument('version-b', InputArgument::REQUIRED, 'Second version to compare against the first'); + $this->setHelp(<<<'HELP' + This command compares two versions and checks if the first version is less than the second. + + Usage: + version lt 0.9.0 1.0.0 + version lt 2.1.0 2.1.0 + HELP); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $style = new SymfonyStyle($input, $output); + $versionA = $input->getArgument('version-a'); + $versionB = $input->getArgument('version-b'); + + try { + if (! is_string($versionA) || ! is_string($versionB)) { + throw new InvalidArgumentType($versionA, $versionB); + } + + /** @var Version $a */ + $a = Version::fromString($versionA); + + /** @var Version $b */ + $b = Version::fromString($versionB); + + if ($a->isLessThan($b)) { + $style->success(sprintf("Version '%s' is less than '%s'.", $a, $b)); + + return Command::SUCCESS; + } + + $style->error(sprintf("Version '%s' is not less than '%s'.", $a, $b)); + + return Command::FAILURE; + } catch (Throwable $th) { + $style->error($th->getMessage()); + + return Command::FAILURE; + } + } +} diff --git a/app/Exceptions/InvalidArgumentType.php b/app/Exceptions/InvalidArgumentType.php index 0132414..ee97d17 100644 --- a/app/Exceptions/InvalidArgumentType.php +++ b/app/Exceptions/InvalidArgumentType.php @@ -6,14 +6,23 @@ use InvalidArgumentException; -use function gettype; +use function array_map; +use function implode; use function sprintf; class InvalidArgumentType extends InvalidArgumentException { /** @param mixed $value */ - public function __construct($value) + public function __construct(...$value) { - parent::__construct(sprintf("Invalid type of value. Expected '%s', '%s' given", 'string', gettype($value))); + $types = array_map('gettype', $value); + + parent::__construct( + sprintf( + "Invalid type of value. Expected '%s', '%s' given", + 'string', + implode(', ', $types), + ), + ); } } From bf6dd6a68157aa5f6f6e6aae4374357cfb4635b3 Mon Sep 17 00:00:00 2001 From: Thoriq Firdaus <2067467+tfirdaus@users.noreply.github.com> Date: Tue, 29 Jul 2025 08:18:25 +0700 Subject: [PATCH 2/3] Add assertion --- app/Commands/GreaterThanCommand.php | 13 +++---------- app/Commands/LessThanCommand.php | 9 +++------ app/Commands/ValidateCommand.php | 14 +++++--------- app/Exceptions/InvalidArgumentType.php | 15 +++------------ composer.json | 2 ++ 5 files changed, 16 insertions(+), 37 deletions(-) diff --git a/app/Commands/GreaterThanCommand.php b/app/Commands/GreaterThanCommand.php index 70a6280..1da27eb 100644 --- a/app/Commands/GreaterThanCommand.php +++ b/app/Commands/GreaterThanCommand.php @@ -4,16 +4,15 @@ namespace Syntatis\Version\CLI\Commands; +use Assert\Assertion; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -use Syntatis\Version\CLI\Exceptions\InvalidArgumentType; use Throwable; use Version\Version; -use function is_string; use function sprintf; final class GreaterThanCommand extends Command @@ -43,17 +42,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $versionB = $input->getArgument('version-b'); try { - if (! is_string($versionA)) { - throw new InvalidArgumentType($versionA); - } - - if (! is_string($versionB)) { - throw new InvalidArgumentType($versionB); - } + Assertion::string($versionA); + Assertion::string($versionB); /** @var Version $a */ $a = Version::fromString($versionA); - /** @var Version $b */ $b = Version::fromString($versionB); diff --git a/app/Commands/LessThanCommand.php b/app/Commands/LessThanCommand.php index e52335a..8b591ee 100644 --- a/app/Commands/LessThanCommand.php +++ b/app/Commands/LessThanCommand.php @@ -4,16 +4,15 @@ namespace Syntatis\Version\CLI\Commands; +use Assert\Assertion; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -use Syntatis\Version\CLI\Exceptions\InvalidArgumentType; use Throwable; use Version\Version; -use function is_string; use function sprintf; final class LessThanCommand extends Command @@ -43,13 +42,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $versionB = $input->getArgument('version-b'); try { - if (! is_string($versionA) || ! is_string($versionB)) { - throw new InvalidArgumentType($versionA, $versionB); - } + Assertion::string($versionA); + Assertion::string($versionB); /** @var Version $a */ $a = Version::fromString($versionA); - /** @var Version $b */ $b = Version::fromString($versionB); diff --git a/app/Commands/ValidateCommand.php b/app/Commands/ValidateCommand.php index 7d62b47..74f44bb 100644 --- a/app/Commands/ValidateCommand.php +++ b/app/Commands/ValidateCommand.php @@ -4,16 +4,15 @@ namespace Syntatis\Version\CLI\Commands; +use Assert\Assertion; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -use Syntatis\Version\CLI\Exceptions\InvalidArgumentType; use Throwable; use Version\Version; -use function is_string; use function sprintf; final class ValidateCommand extends Command @@ -36,15 +35,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $version = $input->getArgument('version'); try { - if (is_string($version)) { - Version::fromString($version); + Assertion::string($version); + Version::fromString($version); - $style->success(sprintf("Version string '%s' is valid and can be parsed", $version)); + $style->success(sprintf("Version string '%s' is valid and can be parsed", $version)); - return Command::SUCCESS; - } - - throw new InvalidArgumentType($version); + return Command::SUCCESS; } catch (Throwable $th) { $style->error($th->getMessage()); diff --git a/app/Exceptions/InvalidArgumentType.php b/app/Exceptions/InvalidArgumentType.php index ee97d17..0132414 100644 --- a/app/Exceptions/InvalidArgumentType.php +++ b/app/Exceptions/InvalidArgumentType.php @@ -6,23 +6,14 @@ use InvalidArgumentException; -use function array_map; -use function implode; +use function gettype; use function sprintf; class InvalidArgumentType extends InvalidArgumentException { /** @param mixed $value */ - public function __construct(...$value) + public function __construct($value) { - $types = array_map('gettype', $value); - - parent::__construct( - sprintf( - "Invalid type of value. Expected '%s', '%s' given", - 'string', - implode(', ', $types), - ), - ); + parent::__construct(sprintf("Invalid type of value. Expected '%s', '%s' given", 'string', gettype($value))); } } diff --git a/composer.json b/composer.json index 38f57f5..f0137d7 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,7 @@ }, "require": { "php": "^7.4 || ^8.0", + "beberlei/assert": "^3.3", "nikolaposa/version": "^4.1.1", "symfony/console": "^5.4 || ^6.0 || ^7.0" }, @@ -37,6 +38,7 @@ "phpcompatibility/php-compatibility": "^9.3", "phpstan/extension-installer": "^1.4", "phpstan/phpstan": "^2.1", + "phpstan/phpstan-beberlei-assert": "^2.0", "phpstan/phpstan-deprecation-rules": "^2.0", "phpstan/phpstan-phpunit": "^2.0", "phpstan/phpstan-strict-rules": "^2.0", From 58d07eb9da27660b289725d39f024b111e54de56 Mon Sep 17 00:00:00 2001 From: Thoriq Firdaus <2067467+tfirdaus@users.noreply.github.com> Date: Tue, 29 Jul 2025 08:27:12 +0700 Subject: [PATCH 3/3] Load `lt` command, and add tests --- app/Commander.php | 2 + .../phpunit/Commands/LessThanCommandTest.php | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tests/phpunit/Commands/LessThanCommandTest.php diff --git a/app/Commander.php b/app/Commander.php index 6ba4b4d..511c0e9 100644 --- a/app/Commander.php +++ b/app/Commander.php @@ -8,6 +8,7 @@ use Symfony\Component\Console\Command\Command; use Syntatis\Version\CLI\Commands\GreaterThanCommand; use Syntatis\Version\CLI\Commands\IncrementCommand; +use Syntatis\Version\CLI\Commands\LessThanCommand; use Syntatis\Version\CLI\Commands\ValidateCommand; final class Commander extends Application @@ -31,6 +32,7 @@ private function getCommands(): array new IncrementCommand(), new ValidateCommand(), new GreaterThanCommand(), + new LessThanCommand(), ]; } } diff --git a/tests/phpunit/Commands/LessThanCommandTest.php b/tests/phpunit/Commands/LessThanCommandTest.php new file mode 100644 index 0000000..c125bb7 --- /dev/null +++ b/tests/phpunit/Commands/LessThanCommandTest.php @@ -0,0 +1,45 @@ +commander = new Commander(); + $this->tester = new CommandTester($this->commander->get('lt')); + } + + /** @dataProvider dataComparison */ + public function testComparison(string $versionA, string $versionB, string $expect): void + { + $this->tester->execute(['version-a' => $versionA, 'version-b' => $versionB]); + + self::assertStringContainsString( + $expect, + $this->tester->getDisplay(), + ); + } + + public static function dataComparison(): iterable + { + yield ['1.0.0', '2.0.0', sprintf("[OK] Version '%s' is less than '%s'.", '1.0.0', '2.0.0')]; + yield ['2.0.0', '1.0.0', sprintf("[ERROR] Version '%s' is not less than '%s'.", '2.0.0', '1.0.0')]; + yield ['1.0.0', '1.0.0', sprintf("[ERROR] Version '%s' is not less than '%s'.", '1.0.0', '1.0.0')]; + yield ['1.0.0-alpha.1', '1.0.0-alpha.2', sprintf("[OK] Version '%s' is less than '%s'.", '1.0.0-alpha.1', '1.0.0-alpha.2')]; + yield ['1.0.0-alpha.2', '1.0.0-alpha.1', sprintf("[ERROR] Version '%s' is not less than '%s'.", '1.0.0-alpha.2', '1.0.0-alpha.1')]; + } +}