<?php namespace Doctrine\Tests\DBAL\Tools\Console; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Tools\Console\Command\RunSqlCommand; use Doctrine\DBAL\Tools\Console\ConsoleRunner; use LogicException; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use RuntimeException; use Symfony\Component\Console\Application; use Symfony\Component\Console\Tester\CommandTester; class RunSqlCommandTest extends TestCase { /** @var CommandTester */ private $commandTester; /** @var RunSqlCommand */ private $command; /** @var Connection&MockObject */ private $connectionMock; protected function setUp(): void { $application = new Application(); $application->add(new RunSqlCommand()); $this->command = $application->find('dbal:run-sql'); $this->commandTester = new CommandTester($this->command); $this->connectionMock = $this->createMock(Connection::class); $helperSet = ConsoleRunner::createHelperSet($this->connectionMock); $this->command->setHelperSet($helperSet); } public function testMissingSqlArgument(): void { try { $this->commandTester->execute([ 'command' => $this->command->getName(), 'sql' => null, ]); $this->fail('Expected a runtime exception when omitting sql argument'); } catch (RuntimeException $e) { self::assertStringContainsString("Argument 'SQL", $e->getMessage()); } } public function testIncorrectDepthOption(): void { try { $this->commandTester->execute([ 'command' => $this->command->getName(), 'sql' => 'SELECT 1', '--depth' => 'string', ]); $this->fail('Expected a logic exception when executing with a stringy depth'); } catch (LogicException $e) { self::assertStringContainsString("Option 'depth'", $e->getMessage()); } } public function testSelectStatementsPrintsResult(): void { $this->expectConnectionFetchAllAssociative(); $exitCode = $this->commandTester->execute([ 'command' => $this->command->getName(), 'sql' => 'SELECT 1', ]); $this->assertSame(0, $exitCode); self::assertMatchesRegularExpression('@int.*1.*@', $this->commandTester->getDisplay()); self::assertMatchesRegularExpression('@array.*1.*@', $this->commandTester->getDisplay()); } public function testUpdateStatementsPrintsAffectedLines(): void { $this->expectConnectionExecuteStatement(); $this->commandTester->execute([ 'command' => $this->command->getName(), 'sql' => 'UPDATE foo SET bar = 42', ]); self::assertMatchesRegularExpression('@int.*42.*@', $this->commandTester->getDisplay()); self::assertDoesNotMatchRegularExpression('@array.*1.*@', $this->commandTester->getDisplay()); } private function expectConnectionExecuteStatement(): void { $this->connectionMock ->expects($this->once()) ->method('executeStatement') ->willReturn(42); $this->connectionMock ->expects($this->never()) ->method('fetchAllAssociative'); } private function expectConnectionFetchAllAssociative(): void { $this->connectionMock ->expects($this->once()) ->method('fetchAllAssociative') ->willReturn([[1]]); $this->connectionMock ->expects($this->never()) ->method('executeStatement'); } public function testStatementsWithFetchResultPrintsResult(): void { $this->expectConnectionFetchAllAssociative(); $this->commandTester->execute([ 'command' => $this->command->getName(), 'sql' => '"WITH bar as (SELECT 1) SELECT * FROM bar', '--force-fetch' => true, ]); self::assertMatchesRegularExpression('@int.*1.*@', $this->commandTester->getDisplay()); self::assertMatchesRegularExpression('@array.*1.*@', $this->commandTester->getDisplay()); } }