From ce652be170a68dce787d14aedea3647404cce136 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 7 Oct 2026 19:50:18 +0700 Subject: [PATCH 1/3] Add ability to setup basepath via --basepath in CLI --- docs/cli.md | 28 ++++ src/Cli/AnalyseCommand.php | 16 +- src/Cli/ClearCacheCommand.php | 38 +++-- src/Cli/Usage.php | 6 +- src/Config/ConfigLoader.php | 24 +-- ...ructArmedApplicationCommandRoutingTest.php | 22 +++ tests/Cli/StructArmedApplicationTest.php | 142 ++++++++++++++++++ tests/Config/ConfigLoaderTest.php | 9 ++ 8 files changed, 260 insertions(+), 25 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index 9663ef2e..c37aba8c 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -46,6 +46,34 @@ vendor/bin/structarmed analyse --config=path/to/structarmed.php vendor/bin/structarmed analyze --config=path/to/structarmed.php ``` +## Base Path + +The project root defaults to the directory the command runs in. Pass `--basepath` when StructArmed is installed somewhere else, for example in a `tools/structarmed` directory with its own `composer.json`: + +```text +composer.json +src/ +tests/ +tools/ +└── structarmed/ + ├── composer.json + ├── structarmed.php + └── vendor/ +``` + +```bash +cd tools/structarmed +vendor/bin/structarmed analyse --basepath=../../ +``` + +Everything relative to the project root now resolves against the base path: layer paths such as `->layer('Config', 'src/ConfigProvider.php')`, scan paths given on the command line, the `composer.json` read by the composer rules and PSR-4 layers, the cache directory, and baseline paths. The config file is discovered in the current directory first, then in the base path; `--config` keeps pointing to a path relative to the current directory. + +`--clear-cache` accepts the same option, so the cache of a project analysed through `--basepath` is cleared with: + +```bash +vendor/bin/structarmed --clear-cache --basepath=../../ +``` + ## Auto-Fix Violations Use `--fix` to automatically apply fixes for violations produced by rules that implement `Boundwize\StructArmed\Rule\FixableInterface`. diff --git a/src/Cli/AnalyseCommand.php b/src/Cli/AnalyseCommand.php index 5ece1701..16df289b 100644 --- a/src/Cli/AnalyseCommand.php +++ b/src/Cli/AnalyseCommand.php @@ -42,6 +42,7 @@ * @phpstan-type CommandOptions array{ * report?: string, * config?: string, + * basepath?: string, * generate-baseline?: string, * no-progress?: true, * clear-cache?: true, @@ -54,6 +55,7 @@ private const VALUE_OPTIONS = [ '--report' => 'report', '--config' => 'config', + '--basepath' => 'basepath', '--generate-baseline' => 'generate-baseline', ]; @@ -98,6 +100,18 @@ public function run(array $arguments, string $basePath): int return 1; } + $workingDirectory = $basePath; + + if (isset($options['basepath'])) { + $basePath = Path::normalise(Path::resolve($options['basepath'], $workingDirectory), canonicalise: true); + + if (! is_dir($basePath)) { + echo sprintf("Error: base path [%s] not found.\n", $options['basepath']); + + return 1; + } + } + foreach ($scanPaths as $scanPath) { $fullScanPath = Path::resolve($scanPath, $basePath); @@ -123,7 +137,7 @@ public function run(array $arguments, string $basePath): int } try { - $configFile = $options['config'] ?? ConfigLoader::discover($basePath); + $configFile = $options['config'] ?? ConfigLoader::discover($workingDirectory, $basePath); $architecture = ConfigLoader::load($configFile); } catch (RuntimeException $runtimeException) { return $this->reportError($runtimeException); diff --git a/src/Cli/ClearCacheCommand.php b/src/Cli/ClearCacheCommand.php index 6585c726..90467500 100644 --- a/src/Cli/ClearCacheCommand.php +++ b/src/Cli/ClearCacheCommand.php @@ -7,18 +7,23 @@ use Boundwize\StructArmed\Cache\AnalysisResultCache; use Boundwize\StructArmed\Cache\FileHashProvider; use Boundwize\StructArmed\Config\ConfigLoader; +use Boundwize\StructArmed\Util\Path; use RuntimeException; use function count; +use function explode; +use function is_dir; use function sprintf; -use function str_starts_with; -use function strlen; -use function substr; use const PHP_EOL; final readonly class ClearCacheCommand { + private const VALUE_OPTIONS = [ + '--config' => 'config', + '--basepath' => 'basepath', + ]; + /** * @param list $arguments */ @@ -28,15 +33,12 @@ public function run(array $arguments, string $basePath): int $counter = count($arguments); for ($i = 0; $i < $counter; $i++) { - $argument = $arguments[$i]; - - if (str_starts_with($argument, '--config=')) { - $options['config'] = substr($argument, strlen('--config=')); - continue; - } + $argument = $arguments[$i]; + $optionAndValue = explode('=', $argument, 2); + $option = $optionAndValue[0]; - if ($argument === '--config') { - $options['config'] = $arguments[++$i] ?? ''; + if (isset(self::VALUE_OPTIONS[$option])) { + $options[self::VALUE_OPTIONS[$option]] = $optionAndValue[1] ?? $arguments[++$i] ?? ''; continue; } @@ -46,10 +48,22 @@ public function run(array $arguments, string $basePath): int return 1; } + $workingDirectory = $basePath; + + if (isset($options['basepath'])) { + $basePath = Path::normalise(Path::resolve($options['basepath'], $workingDirectory), canonicalise: true); + + if (! is_dir($basePath)) { + echo sprintf("Error: base path [%s] not found.\n", $options['basepath']); + + return 1; + } + } + $cacheDirectory = null; try { - $configFile = $options['config'] ?? ConfigLoader::discover($basePath); + $configFile = $options['config'] ?? ConfigLoader::discover($workingDirectory, $basePath); $cacheDirectory = ConfigLoader::load($configFile)->getCacheDirectory(); } catch (RuntimeException $runtimeException) { if (isset($options['config'])) { diff --git a/src/Cli/Usage.php b/src/Cli/Usage.php index 7c89fd0b..2055660b 100644 --- a/src/Cli/Usage.php +++ b/src/Cli/Usage.php @@ -13,9 +13,9 @@ public static function render(): string structarmed --version structarmed init [--preset=ddd|mvc|psr4|psr1|psr12|per|psr15|yagni|codequality|all] structarmed analyse|analyze [path ...] [--config=path/to/structarmed.php] - [--report=console|json|github] [--no-progress] [--clear-cache] [--disable-parallel] - [--fix] [--generate-baseline=structarmed-baseline.php] - structarmed --clear-cache [--config=path/to/structarmed.php] + [--basepath=path/to/project] [--report=console|json|github] [--no-progress] + [--clear-cache] [--disable-parallel] [--fix] [--generate-baseline=structarmed-baseline.php] + structarmed --clear-cache [--config=path/to/structarmed.php] [--basepath=path/to/project] TXT; } diff --git a/src/Config/ConfigLoader.php b/src/Config/ConfigLoader.php index 35833363..2b669d8b 100644 --- a/src/Config/ConfigLoader.php +++ b/src/Config/ConfigLoader.php @@ -35,16 +35,22 @@ public static function load(string $configPath): Architecture return $architecture; } - public static function discover(string $basePath): string + /** + * Searches the base paths in order, so the CLI's working directory wins over + * a --basepath project root that also holds a config file. + */ + public static function discover(string ...$basePaths): string { - $candidates = [ - $basePath . '/structarmed.php', - $basePath . '/structarmed.dist.php', - ]; - - foreach ($candidates as $candidate) { - if (file_exists($candidate)) { - return $candidate; + foreach ($basePaths as $basePath) { + $candidates = [ + $basePath . '/structarmed.php', + $basePath . '/structarmed.dist.php', + ]; + + foreach ($candidates as $candidate) { + if (file_exists($candidate)) { + return $candidate; + } } } diff --git a/tests/Cli/StructArmedApplicationCommandRoutingTest.php b/tests/Cli/StructArmedApplicationCommandRoutingTest.php index fb8f6229..e80d33dc 100644 --- a/tests/Cli/StructArmedApplicationCommandRoutingTest.php +++ b/tests/Cli/StructArmedApplicationCommandRoutingTest.php @@ -79,6 +79,17 @@ public function testApplicationRejectsUnknownClearCacheOption(): void $this->assertStringContainsString('Unknown option: --bad-option', $output); } + public function testApplicationRejectsMissingClearCacheBasePath(): void + { + [$exitCode, $output] = $this->runApplication( + ['structarmed', '--clear-cache', '--basepath', 'missing'], + self::BASE_PATH + ); + + $this->assertSame(1, $exitCode); + $this->assertStringContainsString('Error: base path [missing] not found.', $output); + } + public function testInitCommandRejectsUnknownOption(): void { [$exitCode, $output] = $this->runApplication(['structarmed', 'init', '--bad-option'], self::BASE_PATH); @@ -119,6 +130,17 @@ public function testAnalyseCommandRejectsMissingScanPath(): void $this->assertStringContainsString('Error: path [missing] not found.', $output); } + public function testAnalyseCommandRejectsMissingBasePath(): void + { + [$exitCode, $output] = $this->runApplication( + ['structarmed', 'analyse', '--basepath=missing'], + self::BASE_PATH + ); + + $this->assertSame(1, $exitCode); + $this->assertStringContainsString('Error: base path [missing] not found.', $output); + } + public function testAnalyseCommandAcceptsAbsoluteScanPath(): void { [$exitCode, $output] = $this->runApplication( diff --git a/tests/Cli/StructArmedApplicationTest.php b/tests/Cli/StructArmedApplicationTest.php index ead2a5ab..e4617169 100644 --- a/tests/Cli/StructArmedApplicationTest.php +++ b/tests/Cli/StructArmedApplicationTest.php @@ -32,6 +32,7 @@ use function preg_replace; use function random_bytes; use function realpath; +use function rename; use function rmdir; use function serialize; use function str_replace; @@ -97,6 +98,41 @@ public function testApplicationClearsConfiguredCacheWithoutAnalyseCommand(): voi } } + public function testApplicationClearsConfiguredCacheFromBasePathOption(): void + { + $basePath = (string) realpath($this->createProjectDirectory()); + $toolsPath = $basePath . '/tools/structarmed'; + $cacheDirectory = $basePath . '/var/cache/structarmed'; + + try { + mkdir($toolsPath, 0777, true); + mkdir($cacheDirectory, 0777, true); + + file_put_contents($cacheDirectory . '/key.json', '{}'); + file_put_contents($toolsPath . '/structarmed.php', <<<'PHP' +cacheDirectory('var/cache/structarmed'); +PHP); + + [$exitCode, $output] = $this->runApplication( + ['structarmed', '--clear-cache', '--basepath=../../'], + $toolsPath + ); + + $this->assertSame(0, $exitCode, $output); + $this->assertStringContainsString('StructArmed cache cleared.', $output); + $this->assertDirectoryDoesNotExist($cacheDirectory); + } finally { + $this->removeTempDirectory($basePath); + } + } + public function testApplicationClearsConfiguredCacheWithSeparateConfigOption(): void { $basePath = $this->createProjectDirectory(); @@ -426,6 +462,92 @@ class Foo } } + public function testAnalyseCommandResolvesProjectPathsAgainstBasePathOption(): void + { + $basePath = (string) realpath($this->createTempDirectory()); + $toolsPath = $basePath . '/tools/structarmed'; + + mkdir($toolsPath, 0777, true); + mkdir($basePath . '/src/Exception', 0777, true); + file_put_contents($basePath . '/src/ConfigProvider.php', <<<'PHP' +layer('Config', 'src/ConfigProvider.php') + ->layer('Exception', 'src/Exception') + ->rule('config.must_be_final', new MustBeFinalRule('Config')) + ->rule('exception.must_be_final', new MustBeFinalRule('Exception')) + ->rule('composer.psr4_directory_exists', new Psr4DirectoryExistsRule()); +PHP); + + try { + [$exitCode, $output] = $this->runApplication( + ['structarmed', 'analyse', '--basepath=../../', '--no-progress'], + $toolsPath + ); + + $this->assertSame(1, $exitCode, $output); + $this->assertStringContainsString('Class [App\ConfigProvider] must be declared final', $output); + $this->assertStringContainsString('Class [App\Exception\NotFound] must be declared final', $output); + $this->assertStringContainsString('declared in composer.json do not exist on disk', $output); + $this->assertStringContainsString( + $this->normalisePath($basePath . '/src/ConfigProvider.php'), + $this->normalisePath($output) + ); + $this->assertStringContainsString( + $this->normalisePath($basePath . '/src/Exception/NotFound.php'), + $this->normalisePath($output) + ); + + // Without a config next to the tool, discovery falls back to the base path. + rename($toolsPath . '/structarmed.php', $basePath . '/structarmed.php'); + + [$fallbackExitCode, $fallbackOutput] = $this->runApplication( + ['structarmed', 'analyse', '--basepath', '../../', '--no-progress'], + $toolsPath + ); + + $this->assertSame(1, $fallbackExitCode, $fallbackOutput); + $this->assertStringContainsString('Class [App\ConfigProvider] must be declared final', $fallbackOutput); + } finally { + $this->removeTempDirectory($basePath); + } + } + public function testAnalyseCommandOnlyParsesNewFilesAfterCacheWarmup(): void { $basePath = $this->createProjectDirectory(); @@ -1807,6 +1929,10 @@ private function removeTempDirectory(string $basePath): void unlink($basePath . '/structarmed-custom.php'); } + if (file_exists($basePath . '/tools/structarmed/structarmed.php')) { + unlink($basePath . '/tools/structarmed/structarmed.php'); + } + if (file_exists($basePath . '/structarmed-baseline.php')) { unlink($basePath . '/structarmed-baseline.php'); } @@ -1827,6 +1953,14 @@ private function removeTempDirectory(string $basePath): void unlink($sourceFile); } + foreach (glob($basePath . '/src/Exception/*.php') ?: [] as $sourceFile) { + unlink($sourceFile); + } + + if (is_dir($basePath . '/src/Exception')) { + rmdir($basePath . '/src/Exception'); + } + if (is_dir($basePath . '/src/Domain')) { rmdir($basePath . '/src/Domain'); } @@ -1851,6 +1985,14 @@ private function removeTempDirectory(string $basePath): void rmdir($basePath . '/nested'); } + if (is_dir($basePath . '/tools/structarmed')) { + rmdir($basePath . '/tools/structarmed'); + } + + if (is_dir($basePath . '/tools')) { + rmdir($basePath . '/tools'); + } + if (is_dir($basePath)) { rmdir($basePath); } diff --git a/tests/Config/ConfigLoaderTest.php b/tests/Config/ConfigLoaderTest.php index fbe57257..9d58a5d7 100644 --- a/tests/Config/ConfigLoaderTest.php +++ b/tests/Config/ConfigLoaderTest.php @@ -53,6 +53,15 @@ public function testDiscoverFallsBackToDistConfig(): void $this->assertSame($basePath . '/structarmed.dist.php', ConfigLoader::discover($basePath)); } + public function testDiscoverFallsBackToNextBasePath(): void + { + $workingDirectory = $this->makeTempDir(); + $basePath = $this->makeTempDir(); + touch($basePath . '/structarmed.php'); + + $this->assertSame($basePath . '/structarmed.php', ConfigLoader::discover($workingDirectory, $basePath)); + } + private function writeTempConfig(string $body): string { $path = $this->makeTemporaryFile('structarmed-config'); From 81696cb9fa0d83e8751c4c4b48a9eb58a34926cb Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 7 Oct 2026 20:04:51 +0700 Subject: [PATCH 2/3] allow clear cache per base path --- docs/cli.md | 4 +++- src/Cli/StructArmedApplication.php | 23 +++++++++++++++---- ...ructArmedApplicationCommandRoutingTest.php | 11 +++++++++ tests/Cli/StructArmedApplicationTest.php | 2 +- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index c37aba8c..b0db2c9b 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -71,9 +71,11 @@ Everything relative to the project root now resolves against the base path: laye `--clear-cache` accepts the same option, so the cache of a project analysed through `--basepath` is cleared with: ```bash -vendor/bin/structarmed --clear-cache --basepath=../../ +vendor/bin/structarmed --basepath=../../ --clear-cache ``` +Options may be given before or after the command. + ## Auto-Fix Violations Use `--fix` to automatically apply fixes for violations produced by rules that implement `Boundwize\StructArmed\Rule\FixableInterface`. diff --git a/src/Cli/StructArmedApplication.php b/src/Cli/StructArmedApplication.php index 90660ea6..5f7244e8 100644 --- a/src/Cli/StructArmedApplication.php +++ b/src/Cli/StructArmedApplication.php @@ -8,24 +8,39 @@ use Boundwize\StructArmed\Version; use function array_slice; +use function array_values; use function getcwd; use function in_array; use function sprintf; final readonly class StructArmedApplication { + private const COMMANDS = ['init', 'analyse', 'analyze', '--clear-cache', '--version', '-V', '--help', '-h']; + /** * @param list $argv */ public function run(array $argv, ?string $basePath = null): int { $basePath ??= (string) getcwd(); - $command = $argv[1] ?? null; + $arguments = array_slice($argv, 1); + $command = $arguments[0] ?? null; if ($command === '--internal-worker') { return AnalysisNodeWorker::run($argv[2] ?? '', $argv[3] ?? ''); } + // Options may precede the command: `structarmed --basepath=../../ --clear-cache`. + foreach ($arguments as $index => $argument) { + if (in_array($argument, self::COMMANDS, true)) { + $command = $argument; + unset($arguments[$index]); + break; + } + } + + $arguments = array_values($arguments); + if (in_array($command, ['--version', '-V'], true)) { echo sprintf("StructArmed %s\n", Version::current()); @@ -39,15 +54,15 @@ public function run(array $argv, ?string $basePath = null): int } if ($command === 'init') { - return (new InitCommand())->run(array_slice($argv, 2), $basePath); + return (new InitCommand())->run($arguments, $basePath); } if ($command === '--clear-cache') { - return (new ClearCacheCommand())->run(array_slice($argv, 2), $basePath); + return (new ClearCacheCommand())->run($arguments, $basePath); } if (in_array($command, ['analyse', 'analyze'], true)) { - return (new AnalyseCommand())->run(array_slice($argv, 2), $basePath); + return (new AnalyseCommand())->run($arguments, $basePath); } echo sprintf("Unknown command: %s\n\n", $command); diff --git a/tests/Cli/StructArmedApplicationCommandRoutingTest.php b/tests/Cli/StructArmedApplicationCommandRoutingTest.php index e80d33dc..2dce6eca 100644 --- a/tests/Cli/StructArmedApplicationCommandRoutingTest.php +++ b/tests/Cli/StructArmedApplicationCommandRoutingTest.php @@ -90,6 +90,17 @@ public function testApplicationRejectsMissingClearCacheBasePath(): void $this->assertStringContainsString('Error: base path [missing] not found.', $output); } + public function testApplicationAcceptsOptionsBeforeClearCacheCommand(): void + { + [$exitCode, $output] = $this->runApplication( + ['structarmed', '--basepath=missing', '--clear-cache'], + self::BASE_PATH + ); + + $this->assertSame(1, $exitCode); + $this->assertStringContainsString('Error: base path [missing] not found.', $output); + } + public function testInitCommandRejectsUnknownOption(): void { [$exitCode, $output] = $this->runApplication(['structarmed', 'init', '--bad-option'], self::BASE_PATH); diff --git a/tests/Cli/StructArmedApplicationTest.php b/tests/Cli/StructArmedApplicationTest.php index e4617169..35df6162 100644 --- a/tests/Cli/StructArmedApplicationTest.php +++ b/tests/Cli/StructArmedApplicationTest.php @@ -121,7 +121,7 @@ public function testApplicationClearsConfiguredCacheFromBasePathOption(): void PHP); [$exitCode, $output] = $this->runApplication( - ['structarmed', '--clear-cache', '--basepath=../../'], + ['structarmed', '--basepath=../../', '--clear-cache'], $toolsPath ); From eb1c5f853ad08a28978fc5a314d4c70f68004ce3 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 7 Oct 2026 20:36:15 +0700 Subject: [PATCH 3/3] add alias -d for --basepath --- docs/cli.md | 6 +++++ src/Cli/AnalyseCommand.php | 1 + src/Cli/ClearCacheCommand.php | 1 + src/Cli/Usage.php | 4 ++-- ...ructArmedApplicationCommandRoutingTest.php | 22 +++++++++++++++++++ tests/Cli/StructArmedApplicationTest.php | 2 +- 6 files changed, 33 insertions(+), 3 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index b0db2c9b..e32fed27 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -66,6 +66,12 @@ cd tools/structarmed vendor/bin/structarmed analyse --basepath=../../ ``` +`-d` is a short alias for `--basepath`: + +```bash +vendor/bin/structarmed analyse -d ../../ +``` + Everything relative to the project root now resolves against the base path: layer paths such as `->layer('Config', 'src/ConfigProvider.php')`, scan paths given on the command line, the `composer.json` read by the composer rules and PSR-4 layers, the cache directory, and baseline paths. The config file is discovered in the current directory first, then in the base path; `--config` keeps pointing to a path relative to the current directory. `--clear-cache` accepts the same option, so the cache of a project analysed through `--basepath` is cleared with: diff --git a/src/Cli/AnalyseCommand.php b/src/Cli/AnalyseCommand.php index 16df289b..ebe1d571 100644 --- a/src/Cli/AnalyseCommand.php +++ b/src/Cli/AnalyseCommand.php @@ -56,6 +56,7 @@ '--report' => 'report', '--config' => 'config', '--basepath' => 'basepath', + '-d' => 'basepath', '--generate-baseline' => 'generate-baseline', ]; diff --git a/src/Cli/ClearCacheCommand.php b/src/Cli/ClearCacheCommand.php index 90467500..3da1eccb 100644 --- a/src/Cli/ClearCacheCommand.php +++ b/src/Cli/ClearCacheCommand.php @@ -22,6 +22,7 @@ private const VALUE_OPTIONS = [ '--config' => 'config', '--basepath' => 'basepath', + '-d' => 'basepath', ]; /** diff --git a/src/Cli/Usage.php b/src/Cli/Usage.php index 2055660b..8e80bdef 100644 --- a/src/Cli/Usage.php +++ b/src/Cli/Usage.php @@ -13,9 +13,9 @@ public static function render(): string structarmed --version structarmed init [--preset=ddd|mvc|psr4|psr1|psr12|per|psr15|yagni|codequality|all] structarmed analyse|analyze [path ...] [--config=path/to/structarmed.php] - [--basepath=path/to/project] [--report=console|json|github] [--no-progress] + [-d|--basepath=path/to/project] [--report=console|json|github] [--no-progress] [--clear-cache] [--disable-parallel] [--fix] [--generate-baseline=structarmed-baseline.php] - structarmed --clear-cache [--config=path/to/structarmed.php] [--basepath=path/to/project] + structarmed --clear-cache [--config=path/to/structarmed.php] [-d|--basepath=path/to/project] TXT; } diff --git a/tests/Cli/StructArmedApplicationCommandRoutingTest.php b/tests/Cli/StructArmedApplicationCommandRoutingTest.php index 2dce6eca..8b3ca7c8 100644 --- a/tests/Cli/StructArmedApplicationCommandRoutingTest.php +++ b/tests/Cli/StructArmedApplicationCommandRoutingTest.php @@ -101,6 +101,17 @@ public function testApplicationAcceptsOptionsBeforeClearCacheCommand(): void $this->assertStringContainsString('Error: base path [missing] not found.', $output); } + public function testApplicationAcceptsShortClearCacheBasePathOption(): void + { + [$exitCode, $output] = $this->runApplication( + ['structarmed', '--clear-cache', '-d=missing'], + self::BASE_PATH + ); + + $this->assertSame(1, $exitCode); + $this->assertStringContainsString('Error: base path [missing] not found.', $output); + } + public function testInitCommandRejectsUnknownOption(): void { [$exitCode, $output] = $this->runApplication(['structarmed', 'init', '--bad-option'], self::BASE_PATH); @@ -152,6 +163,17 @@ public function testAnalyseCommandRejectsMissingBasePath(): void $this->assertStringContainsString('Error: base path [missing] not found.', $output); } + public function testAnalyseCommandAcceptsShortBasePathOption(): void + { + [$exitCode, $output] = $this->runApplication( + ['structarmed', 'analyse', '-d', 'missing'], + self::BASE_PATH + ); + + $this->assertSame(1, $exitCode); + $this->assertStringContainsString('Error: base path [missing] not found.', $output); + } + public function testAnalyseCommandAcceptsAbsoluteScanPath(): void { [$exitCode, $output] = $this->runApplication( diff --git a/tests/Cli/StructArmedApplicationTest.php b/tests/Cli/StructArmedApplicationTest.php index 35df6162..147a9901 100644 --- a/tests/Cli/StructArmedApplicationTest.php +++ b/tests/Cli/StructArmedApplicationTest.php @@ -537,7 +537,7 @@ class NotFound rename($toolsPath . '/structarmed.php', $basePath . '/structarmed.php'); [$fallbackExitCode, $fallbackOutput] = $this->runApplication( - ['structarmed', 'analyse', '--basepath', '../../', '--no-progress'], + ['structarmed', 'analyse', '-d', '../../', '--no-progress'], $toolsPath );