application = new Application($kernel); $this->application->add(new $className()); return $this->application->find('kimai:bundle:test:install'); } public function testFullRun(): void { $command = $this->getCommand(TestBundleInstallerCommand::class); $commandTester = new CommandTester($command); $commandTester->execute(['command' => $command->getName()]); $result = $commandTester->getDisplay(); self::assertStringContainsString('Starting installation of plugin: Test', $result); self::assertStringContainsString('[OK] Congratulations! Plugin was successful installed: Test', $result); self::assertEquals(0, $commandTester->getStatusCode()); } public function testMissingMigrationThrowsException(): void { $command = $this->getCommand(InstallerWithMissingMigrationsCommand::class); $commandTester = new CommandTester($command); $commandTester->execute(['command' => $command->getName()]); $result = $commandTester->getDisplay(); self::assertStringContainsString('[ERROR] Failed to install database for bundle TestBundle.', $result); self::assertEquals(1, $commandTester->getStatusCode()); } public function testInvalidNamespaceWillRaiseException(): void { $this->expectException(LogicException::class); $this->expectExceptionMessage('Unsupported namespace given, expected "KimaiPlugin" but received "App". Please overwrite getBundleName() and return the correct bundle name.'); $command = $this->getCommand(InvalidNamespaceTestBundleInstallerCommand::class); $commandTester = new CommandTester($command); $commandTester->execute(['command' => $command->getName()]); } public function testAssetsInstallIsOk(): void { $command = $this->getCommand(InstallerWithAssetsCommand::class); $this->application->add(new FakeCommand('assets:install', 0, null)); $commandTester = new CommandTester($command); $commandTester->execute(['command' => $command->getName()]); $result = $commandTester->getDisplay(); self::assertStringContainsString('Command assets:install was executed successfully :-)', $result); self::assertEquals(0, $commandTester->getStatusCode()); } public function testAssetsInstallReturnsNonZeroExitCode(): void { $command = $this->getCommand(InstallerWithAssetsCommand::class); $this->application->add(new FakeCommand('assets:install', 1, null)); $commandTester = new CommandTester($command); $commandTester->execute(['command' => $command->getName()]); $result = $commandTester->getDisplay(); self::assertStringContainsString('[ERROR] Failed to install assets for bundle TestBundle.', $result); self::assertEquals(1, $commandTester->getStatusCode()); } } class FakeCommand extends Command { public function __construct(string $commandName, private int $exitCode, private ?string $exception = null) { parent::__construct($commandName); } protected function execute(InputInterface $input, OutputInterface $output): int { if (null !== $this->exception) { throw new \Exception($this->exception); } if ($this->exitCode === 0) { $output->write('Command ' . $this->getName() . ' was executed successfully :-)'); } return $this->exitCode; } } class InvalidNamespaceTestBundleInstallerCommand extends AbstractBundleInstallerCommand { protected function getBundleCommandNamePart(): string { return 'test'; } } class TestBundleInstallerCommand extends AbstractBundleInstallerCommand { protected function getBundleCommandNamePart(): string { return 'test'; } protected function getBundleName(): string { return 'TestBundle'; } } class InstallerWithMissingMigrationsCommand extends TestBundleInstallerCommand { protected function getMigrationConfigFilename(): ?string { return __DIR__ . '/sdfsdfsdfsdf'; } } class InstallerWithAssetsCommand extends TestBundleInstallerCommand { protected function hasAssets(): bool { return true; } }