Upgrade 1-11.38

This commit is contained in:
xesmyd
2026-03-30 14:10:30 +02:00
parent f2a7e6d1fc
commit ac648ef29d
24665 changed files with 69682 additions and 2205004 deletions
+227 -177
View File
@@ -18,9 +18,9 @@ use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Exception\NamespaceNotFoundException;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Input\ArgvInput;
@@ -72,14 +72,14 @@ class ApplicationTest extends TestCase
require_once self::$fixturesPath.'/BarBucCommand.php';
require_once self::$fixturesPath.'/FooSubnamespaced1Command.php';
require_once self::$fixturesPath.'/FooSubnamespaced2Command.php';
require_once self::$fixturesPath.'/FooWithoutAliasCommand.php';
require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering.php';
require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering2.php';
require_once self::$fixturesPath.'/FooHiddenCommand.php';
}
protected function normalizeLineBreaks($text)
{
return str_replace(\PHP_EOL, "\n", $text);
return str_replace(PHP_EOL, "\n", $text);
}
/**
@@ -184,7 +184,7 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run(['test']);
$this->assertStringContainsString('It works!', $tester->getDisplay(true));
$this->assertContains('It works!', $tester->getDisplay(true));
}
public function testAdd()
@@ -200,10 +200,12 @@ class ApplicationTest extends TestCase
$this->assertEquals([$foo, $foo1], [$commands['foo:bar'], $commands['foo:bar1']], '->addCommands() registers an array of commands');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Command class "Foo5Command" is not correctly initialized. You probably forgot to call the parent constructor.
*/
public function testAddCommandWithEmptyConstructor()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('Command class "Foo5Command" is not correctly initialized. You probably forgot to call the parent constructor.');
$application = new Application();
$application->add(new \Foo5Command());
}
@@ -266,10 +268,12 @@ class ApplicationTest extends TestCase
$this->assertEmpty($tester->getDisplay(true));
}
/**
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
* @expectedExceptionMessage The command "foofoo" does not exist.
*/
public function testGetInvalidCommand()
{
$this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException');
$this->expectExceptionMessage('The command "foofoo" does not exist.');
$application = new Application();
$application->get('foofoo');
}
@@ -309,8 +313,12 @@ class ApplicationTest extends TestCase
$expectedMsg = "The namespace \"f\" is ambiguous.\nDid you mean one of these?\n foo\n foo1";
$this->expectException(CommandNotFoundException::class);
$this->expectExceptionMessage($expectedMsg);
if (method_exists($this, 'expectException')) {
$this->expectException(NamespaceNotFoundException::class);
$this->expectExceptionMessage($expectedMsg);
} else {
$this->setExpectedException(NamespaceNotFoundException::class, $expectedMsg);
}
$application->findNamespace('f');
}
@@ -323,18 +331,22 @@ class ApplicationTest extends TestCase
$this->assertEquals('test-ambiguous', $application->find('test')->getName());
}
/**
* @expectedException \Symfony\Component\Console\Exception\NamespaceNotFoundException
* @expectedExceptionMessage There are no commands defined in the "bar" namespace.
*/
public function testFindInvalidNamespace()
{
$this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException');
$this->expectExceptionMessage('There are no commands defined in the "bar" namespace.');
$application = new Application();
$application->findNamespace('bar');
}
/**
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
* @expectedExceptionMessage Command "foo1" is not defined
*/
public function testFindUniqueNameButNamespaceName()
{
$this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException');
$this->expectExceptionMessage('Command "foo1" is not defined');
$application = new Application();
$application->add(new \FooCommand());
$application->add(new \Foo1Command());
@@ -377,10 +389,12 @@ class ApplicationTest extends TestCase
$this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('FoO:BaR'), '->find() will fallback to case insensitivity');
}
/**
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
* @expectedExceptionMessage Command "FoO:BaR" is ambiguous
*/
public function testFindCaseInsensitiveSuggestions()
{
$this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException');
$this->expectExceptionMessage('Command "FoO:BaR" is ambiguous');
$application = new Application();
$application->add(new \FooSameCaseLowercaseCommand());
$application->add(new \FooSameCaseUppercaseCommand());
@@ -408,8 +422,12 @@ class ApplicationTest extends TestCase
public function testFindWithAmbiguousAbbreviations($abbreviation, $expectedExceptionMessage)
{
putenv('COLUMNS=120');
$this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException');
$this->expectExceptionMessage($expectedExceptionMessage);
if (method_exists($this, 'expectException')) {
$this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException');
$this->expectExceptionMessage($expectedExceptionMessage);
} else {
$this->setExpectedException('Symfony\Component\Console\Exception\CommandNotFoundException', $expectedExceptionMessage);
}
$application = new Application();
$application->add(new \FooCommand());
@@ -468,17 +486,63 @@ class ApplicationTest extends TestCase
}
/**
* @dataProvider provideInvalidCommandNamesSingle
* @dataProvider provideInvalidCommandNamesSingle
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
* @expectedExceptionMessage Did you mean this
*/
public function testFindAlternativeExceptionMessageSingle($name)
{
$this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException');
$this->expectExceptionMessage('Did you mean this');
$application = new Application();
$application->add(new \Foo3Command());
$application->find($name);
}
public function testDontRunAlternativeNamespaceName()
{
$application = new Application();
$application->add(new \Foo1Command());
$application->setAutoExit(false);
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foos:bar1'], ['decorated' => false]);
$this->assertSame('
There are no commands defined in the "foos" namespace.
Did you mean this?
foo
', $tester->getDisplay(true));
}
public function testCanRunAlternativeCommandName()
{
$application = new Application();
$application->add(new \FooWithoutAliasCommand());
$application->setAutoExit(false);
$tester = new ApplicationTester($application);
$tester->setInputs(['y']);
$tester->run(['command' => 'foos'], ['decorated' => false]);
$display = trim($tester->getDisplay(true));
$this->assertContains('Command "foos" is not defined', $display);
$this->assertContains('Do you want to run "foo" instead? (yes/no) [no]:', $display);
$this->assertContains('called', $display);
}
public function testDontRunAlternativeCommandName()
{
$application = new Application();
$application->add(new \FooWithoutAliasCommand());
$application->setAutoExit(false);
$tester = new ApplicationTester($application);
$tester->setInputs(['n']);
$exitCode = $tester->run(['command' => 'foos'], ['decorated' => false]);
$this->assertSame(1, $exitCode);
$display = trim($tester->getDisplay(true));
$this->assertContains('Command "foos" is not defined', $display);
$this->assertContains('Do you want to run "foo" instead? (yes/no) [no]:', $display);
}
public function provideInvalidCommandNamesSingle()
{
return [
@@ -501,9 +565,9 @@ class ApplicationTest extends TestCase
$this->fail('->find() throws a CommandNotFoundException if command does not exist, with alternatives');
} catch (\Exception $e) {
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
$this->assertMatchesRegularExpression('/Did you mean one of these/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
$this->assertMatchesRegularExpression('/foo1:bar/', $e->getMessage());
$this->assertMatchesRegularExpression('/foo:bar/', $e->getMessage());
$this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
$this->assertRegExp('/foo1:bar/', $e->getMessage());
$this->assertRegExp('/foo:bar/', $e->getMessage());
}
// Namespace + plural
@@ -512,8 +576,8 @@ class ApplicationTest extends TestCase
$this->fail('->find() throws a CommandNotFoundException if command does not exist, with alternatives');
} catch (\Exception $e) {
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
$this->assertMatchesRegularExpression('/Did you mean one of these/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
$this->assertMatchesRegularExpression('/foo1/', $e->getMessage());
$this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
$this->assertRegExp('/foo1/', $e->getMessage());
}
$application->add(new \Foo3Command());
@@ -521,12 +585,12 @@ class ApplicationTest extends TestCase
// Subnamespace + plural
try {
$application->find('foo3:');
$a = $application->find('foo3:');
$this->fail('->find() should throw an Symfony\Component\Console\Exception\CommandNotFoundException if a command is ambiguous because of a subnamespace, with alternatives');
} catch (\Exception $e) {
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e);
$this->assertMatchesRegularExpression('/foo3:bar/', $e->getMessage());
$this->assertMatchesRegularExpression('/foo3:bar:toh/', $e->getMessage());
$this->assertRegExp('/foo3:bar/', $e->getMessage());
$this->assertRegExp('/foo3:bar:toh/', $e->getMessage());
}
}
@@ -555,10 +619,10 @@ class ApplicationTest extends TestCase
} catch (\Exception $e) {
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if command does not exist');
$this->assertSame(['afoobar1', 'foo:bar1'], $e->getAlternatives());
$this->assertMatchesRegularExpression(sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
$this->assertMatchesRegularExpression('/afoobar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "afoobar1"');
$this->assertMatchesRegularExpression('/foo:bar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "foo:bar1"');
$this->assertDoesNotMatchRegularExpression('/foo:bar(?!1)/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without "foo:bar" alternative');
$this->assertRegExp(sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
$this->assertRegExp('/afoobar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "afoobar1"');
$this->assertRegExp('/foo:bar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "foo:bar1"');
$this->assertNotRegExp('/foo:bar(?>!1)/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without "foo:bar" alternative');
}
}
@@ -568,9 +632,6 @@ class ApplicationTest extends TestCase
$fooCommand->setAliases(['foo2']);
$application = new Application();
$application->setCommandLoader(new FactoryCommandLoader([
'foo3' => static function () use ($fooCommand) { return $fooCommand; },
]));
$application->add($fooCommand);
$result = $application->find('foo');
@@ -600,15 +661,16 @@ class ApplicationTest extends TestCase
$application->find('foo2:command');
$this->fail('->find() throws a CommandNotFoundException if namespace does not exist');
} catch (\Exception $e) {
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if namespace does not exist');
$this->assertInstanceOf('Symfony\Component\Console\Exception\NamespaceNotFoundException', $e, '->find() throws a NamespaceNotFoundException if namespace does not exist');
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, 'NamespaceNotFoundException extends from CommandNotFoundException');
$this->assertCount(3, $e->getAlternatives());
$this->assertContains('foo', $e->getAlternatives());
$this->assertContains('foo1', $e->getAlternatives());
$this->assertContains('foo3', $e->getAlternatives());
$this->assertMatchesRegularExpression('/There are no commands defined in the "foo2" namespace./', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative');
$this->assertMatchesRegularExpression('/foo/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo"');
$this->assertMatchesRegularExpression('/foo1/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo1"');
$this->assertMatchesRegularExpression('/foo3/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo3"');
$this->assertRegExp('/There are no commands defined in the "foo2" namespace./', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative');
$this->assertRegExp('/foo/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo"');
$this->assertRegExp('/foo1/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo1"');
$this->assertRegExp('/foo3/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo3"');
}
}
@@ -620,7 +682,6 @@ class ApplicationTest extends TestCase
$application->add(new \Foo1Command());
$application->add(new \Foo2Command());
$application->add(new \Foo3Command());
$application->add(new \FooHiddenCommand());
$expectedAlternatives = [
'afoobar',
@@ -639,7 +700,7 @@ class ApplicationTest extends TestCase
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if command is not defined');
$this->assertSame($expectedAlternatives, $e->getAlternatives());
$this->assertMatchesRegularExpression('/Command "foo" is not defined\..*Did you mean one of these\?.*/Ums', $e->getMessage());
$this->assertRegExp('/Command "foo" is not defined\..*Did you mean one of these\?.*/Ums', $e->getMessage());
}
}
@@ -653,10 +714,12 @@ class ApplicationTest extends TestCase
$this->assertEquals('foo:sublong', $application->findNamespace('f:sub'));
}
/**
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
* @expectedExceptionMessage Command "foo::bar" is not defined.
*/
public function testFindWithDoubleColonInNameThrowsException()
{
$this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException');
$this->expectExceptionMessage('Command "foo::bar" is not defined.');
$application = new Application();
$application->add(new \FooCommand());
$application->add(new \Foo4Command());
@@ -710,7 +773,7 @@ class ApplicationTest extends TestCase
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $tester->getErrorOutput(true), '->renderException() renders a pretty exception');
$tester->run(['command' => 'foo'], ['decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE, 'capture_stderr_separately' => true]);
$this->assertStringContainsString('Exception trace', $tester->getErrorOutput(), '->renderException() renders a pretty exception with a stack trace when verbosity is verbose');
$this->assertContains('Exception trace', $tester->getErrorOutput(), '->renderException() renders a pretty exception with a stack trace when verbosity is verbose');
$tester->run(['command' => 'list', '--foo' => true], ['decorated' => false, 'capture_stderr_separately' => true]);
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception2.txt', $tester->getErrorOutput(true), '->renderException() renders the command synopsis when an exception occurs in the context of a command');
@@ -721,9 +784,9 @@ class ApplicationTest extends TestCase
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3.txt', $tester->getErrorOutput(true), '->renderException() renders a pretty exceptions with previous exceptions');
$tester->run(['command' => 'foo3:bar'], ['decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE]);
$this->assertMatchesRegularExpression('/\[Exception\]\s*First exception/', $tester->getDisplay(), '->renderException() renders a pretty exception without code exception when code exception is default and verbosity is verbose');
$this->assertMatchesRegularExpression('/\[Exception\]\s*Second exception/', $tester->getDisplay(), '->renderException() renders a pretty exception without code exception when code exception is 0 and verbosity is verbose');
$this->assertMatchesRegularExpression('/\[Exception \(404\)\]\s*Third exception/', $tester->getDisplay(), '->renderException() renders a pretty exception with code exception when code exception is 404 and verbosity is verbose');
$this->assertRegExp('/\[Exception\]\s*First exception/', $tester->getDisplay(), '->renderException() renders a pretty exception without code exception when code exception is default and verbosity is verbose');
$this->assertRegExp('/\[Exception\]\s*Second exception/', $tester->getDisplay(), '->renderException() renders a pretty exception without code exception when code exception is 0 and verbosity is verbose');
$this->assertRegExp('/\[Exception \(404\)\]\s*Third exception/', $tester->getDisplay(), '->renderException() renders a pretty exception with code exception when code exception is 404 and verbosity is verbose');
$tester->run(['command' => 'foo3:bar'], ['decorated' => true]);
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3decorated.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions');
@@ -800,18 +863,54 @@ class ApplicationTest extends TestCase
$this->assertStringMatchesFormatFile(self::$fixturesPath.'/application_renderexception_linebreaks.txt', $tester->getDisplay(true), '->renderException() keep multiple line breaks');
}
public function testRenderAnonymousException()
{
$application = new Application();
$application->setAutoExit(false);
$application->register('foo')->setCode(function () {
throw new class('') extends \InvalidArgumentException {
};
});
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foo'], ['decorated' => false]);
$this->assertContains('[InvalidArgumentException@anonymous]', $tester->getDisplay(true));
$application = new Application();
$application->setAutoExit(false);
$application->register('foo')->setCode(function () {
throw new \InvalidArgumentException(sprintf('Dummy type "%s" is invalid.', \get_class(new class() {
})));
});
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foo'], ['decorated' => false]);
$this->assertContains('Dummy type "@anonymous" is invalid.', $tester->getDisplay(true));
}
public function testRenderExceptionStackTraceContainsRootException()
{
$application = new Application();
$application->setAutoExit(false);
$application->register('foo')->setCode(function () {
throw new \Exception('Verbose exception');
throw new class('') extends \InvalidArgumentException {
};
});
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foo'], ['decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE]);
$this->assertStringContainsString(sprintf('() at %s:', __FILE__), $tester->getDisplay());
$tester->run(['command' => 'foo'], ['decorated' => false]);
$this->assertContains('[InvalidArgumentException@anonymous]', $tester->getDisplay(true));
$application = new Application();
$application->setAutoExit(false);
$application->register('foo')->setCode(function () {
throw new \InvalidArgumentException(sprintf('Dummy type "%s" is invalid.', \get_class(new class() {
})));
});
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foo'], ['decorated' => false]);
$this->assertContains('Dummy type "@anonymous" is invalid.', $tester->getDisplay(true));
}
public function testRun()
@@ -902,10 +1001,10 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foo:bar', '--no-interaction' => true], ['decorated' => false]);
$this->assertSame('called'.\PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if --no-interaction is passed');
$this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if --no-interaction is passed');
$tester->run(['command' => 'foo:bar', '-n' => true], ['decorated' => false]);
$this->assertSame('called'.\PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if -n is passed');
$this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if -n is passed');
}
public function testRunWithGlobalOptionAndNoCommand()
@@ -1026,10 +1125,12 @@ class ApplicationTest extends TestCase
$this->assertTrue($passedRightValue, '-> exit code 1 was passed in the console.terminate event');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage An option with shortcut "e" already exists.
*/
public function testAddingOptionWithDuplicateShortcut()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('An option with shortcut "e" already exists.');
$dispatcher = new EventDispatcher();
$application = new Application();
$application->setAutoExit(false);
@@ -1052,11 +1153,11 @@ class ApplicationTest extends TestCase
}
/**
* @expectedException \LogicException
* @dataProvider getAddingAlreadySetDefinitionElementData
*/
public function testAddingAlreadySetDefinitionElementData($def)
{
$this->expectException('LogicException');
$application = new Application();
$application->setAutoExit(false);
$application->setCatchExceptions(false);
@@ -1202,13 +1303,15 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foo']);
$this->assertEquals('before.foo.after.'.\PHP_EOL, $tester->getDisplay());
$this->assertEquals('before.foo.after.'.PHP_EOL, $tester->getDisplay());
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage error
*/
public function testRunWithExceptionAndDispatcher()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('error');
$application = new Application();
$application->setDispatcher($this->getDispatcher());
$application->setAutoExit(false);
@@ -1236,7 +1339,7 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foo']);
$this->assertStringContainsString('before.foo.error.after.', $tester->getDisplay());
$this->assertContains('before.foo.error.after.', $tester->getDisplay());
}
public function testRunDispatchesAllEventsWithExceptionInListener()
@@ -1256,12 +1359,9 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foo']);
$this->assertStringContainsString('before.error.after.', $tester->getDisplay());
$this->assertContains('before.error.after.', $tester->getDisplay());
}
/**
* @requires PHP 7
*/
public function testRunWithError()
{
$application = new Application();
@@ -1307,7 +1407,7 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foo']);
$this->assertStringContainsString('before.error.silenced.after.', $tester->getDisplay());
$this->assertContains('before.error.silenced.after.', $tester->getDisplay());
$this->assertEquals(ConsoleCommandEvent::RETURN_CODE_DISABLED, $tester->getStatusCode());
}
@@ -1326,40 +1426,10 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run(['command' => 'unknown']);
$this->assertStringContainsString('silenced command not found', $tester->getDisplay());
$this->assertContains('silenced command not found', $tester->getDisplay());
$this->assertEquals(1, $tester->getStatusCode());
}
/**
* @group legacy
* @expectedDeprecation The "ConsoleEvents::EXCEPTION" event is deprecated since Symfony 3.3 and will be removed in 4.0. Listen to the "ConsoleEvents::ERROR" event instead.
*/
public function testLegacyExceptionListenersAreStillTriggered()
{
$dispatcher = $this->getDispatcher();
$dispatcher->addListener('console.exception', function (ConsoleExceptionEvent $event) {
$event->getOutput()->write('caught.');
$event->setException(new \RuntimeException('replaced in caught.'));
});
$application = new Application();
$application->setDispatcher($dispatcher);
$application->setAutoExit(false);
$application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) {
throw new \RuntimeException('foo');
});
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foo']);
$this->assertStringContainsString('before.caught.error.after.', $tester->getDisplay());
$this->assertStringContainsString('replaced in caught.', $tester->getDisplay());
}
/**
* @requires PHP 7
*/
public function testErrorIsRethrownIfNotHandledByConsoleErrorEvent()
{
$application = new Application();
@@ -1367,8 +1437,8 @@ class ApplicationTest extends TestCase
$application->setCatchExceptions(false);
$application->setDispatcher(new EventDispatcher());
$application->register('dym')->setCode(function () {
throw new \Error('Something went wrong.');
$application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) {
new \UnknownClass();
});
$tester = new ApplicationTester($application);
@@ -1377,17 +1447,16 @@ class ApplicationTest extends TestCase
$tester->run(['command' => 'dym']);
$this->fail('->run() should rethrow PHP errors if not handled via ConsoleErrorEvent.');
} catch (\Error $e) {
$this->assertSame('Something went wrong.', $e->getMessage());
$this->assertSame($e->getMessage(), 'Class \'UnknownClass\' not found');
}
}
/**
* @requires PHP 7
* @expectedException \LogicException
* @expectedExceptionMessage error
*/
public function testRunWithErrorAndDispatcher()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('error');
$application = new Application();
$application->setDispatcher($this->getDispatcher());
$application->setAutoExit(false);
@@ -1401,12 +1470,9 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run(['command' => 'dym']);
$this->assertStringContainsString('before.dym.error.after.', $tester->getDisplay(), 'The PHP Error did not dispached events');
$this->assertContains('before.dym.error.after.', $tester->getDisplay(), 'The PHP Error did not dispached events');
}
/**
* @requires PHP 7
*/
public function testRunDispatchesAllEventsWithError()
{
$application = new Application();
@@ -1421,12 +1487,9 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run(['command' => 'dym']);
$this->assertStringContainsString('before.dym.error.after.', $tester->getDisplay(), 'The PHP Error did not dispached events');
$this->assertContains('before.dym.error.after.', $tester->getDisplay(), 'The PHP Error did not dispached events');
}
/**
* @requires PHP 7
*/
public function testRunWithErrorFailingStatusCode()
{
$application = new Application();
@@ -1456,7 +1519,7 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$exitCode = $tester->run(['command' => 'foo']);
$this->assertStringContainsString('before.after.', $tester->getDisplay());
$this->assertContains('before.after.', $tester->getDisplay());
$this->assertEquals(ConsoleCommandEvent::RETURN_CODE_DISABLED, $exitCode);
}
@@ -1517,24 +1580,6 @@ class ApplicationTest extends TestCase
$this->assertEquals('some test value', $extraValue);
}
/**
* @group legacy
*/
public function testTerminalDimensions()
{
$application = new Application();
$originalDimensions = $application->getTerminalDimensions();
$this->assertCount(2, $originalDimensions);
$width = 80;
if ($originalDimensions[0] == $width) {
$width = 100;
}
$application->setTerminalDimensions($width, 80);
$this->assertSame([$width, 80], $application->getTerminalDimensions());
}
public function testSetRunCustomDefaultCommand()
{
$command = new \FooCommand();
@@ -1546,7 +1591,7 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run([], ['interactive' => false]);
$this->assertEquals('called'.\PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command');
$this->assertEquals('called'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command');
$application = new CustomDefaultCommandApplication();
$application->setAutoExit(false);
@@ -1554,7 +1599,7 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run([], ['interactive' => false]);
$this->assertEquals('called'.\PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command');
$this->assertEquals('called'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command');
}
public function testSetRunCustomDefaultCommandWithOption()
@@ -1569,7 +1614,7 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run(['--fooopt' => 'opt'], ['interactive' => false]);
$this->assertEquals('called'.\PHP_EOL.'opt'.\PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command');
$this->assertEquals('called'.PHP_EOL.'opt'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command');
}
public function testSetRunCustomSingleCommand()
@@ -1584,10 +1629,27 @@ class ApplicationTest extends TestCase
$tester = new ApplicationTester($application);
$tester->run([]);
$this->assertStringContainsString('called', $tester->getDisplay());
$this->assertContains('called', $tester->getDisplay());
$tester->run(['--help' => true]);
$this->assertStringContainsString('The foo:bar command', $tester->getDisplay());
$this->assertContains('The foo:bar command', $tester->getDisplay());
}
/**
* @requires function posix_isatty
*/
public function testCanCheckIfTerminalIsInteractive()
{
$application = new CustomDefaultCommandApplication();
$application->setAutoExit(false);
$tester = new ApplicationTester($application);
$tester->run(['command' => 'help']);
$this->assertFalse($tester->getInput()->hasParameterOption(['--no-interaction', '-n']));
$inputStream = $tester->getInput()->getStream();
$this->assertEquals($tester->getInput()->isInteractive(), @posix_isatty($inputStream));
}
public function testRunLazyCommandService()
@@ -1620,9 +1682,11 @@ class ApplicationTest extends TestCase
$this->assertSame(['lazy:alias', 'lazy:alias2'], $command->getAliases());
}
/**
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
*/
public function testGetDisabledLazyCommand()
{
$this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException');
$application = new Application();
$application->setCommandLoader(new FactoryCommandLoader(['disabled' => function () { return new DisabledCommand(); }]));
$application->get('disabled');
@@ -1642,31 +1706,6 @@ class ApplicationTest extends TestCase
$this->assertArrayNotHasKey('disabled', $application->all());
}
public function testFindAlternativesDoesNotLoadSameNamespaceCommandsOnExactMatch()
{
$application = new Application();
$application->setAutoExit(false);
$loaded = [];
$application->setCommandLoader(new FactoryCommandLoader([
'foo:bar' => function () use (&$loaded) {
$loaded['foo:bar'] = true;
return (new Command('foo:bar'))->setCode(function () {});
},
'foo' => function () use (&$loaded) {
$loaded['foo'] = true;
return (new Command('foo'))->setCode(function () {});
},
]));
$application->run(new ArrayInput(['command' => 'foo']), new NullOutput());
$this->assertSame(['foo' => true], $loaded);
}
protected function getDispatcher($skipCommand = false)
{
$dispatcher = new EventDispatcher();
@@ -1693,17 +1732,14 @@ class ApplicationTest extends TestCase
return $dispatcher;
}
/**
* @requires PHP 7
*/
public function testErrorIsRethrownIfNotHandledByConsoleErrorEventWithCatchingEnabled()
{
$application = new Application();
$application->setAutoExit(false);
$application->setDispatcher(new EventDispatcher());
$application->register('dym')->setCode(function () {
throw new \Error('Something went wrong.');
$application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) {
new \UnknownClass();
});
$tester = new ApplicationTester($application);
@@ -1712,22 +1748,36 @@ class ApplicationTest extends TestCase
$tester->run(['command' => 'dym']);
$this->fail('->run() should rethrow PHP errors if not handled via ConsoleErrorEvent.');
} catch (\Error $e) {
$this->assertSame('Something went wrong.', $e->getMessage());
$this->assertSame($e->getMessage(), 'Class \'UnknownClass\' not found');
}
}
public function testCommandNameMismatchWithCommandLoaderKeyThrows()
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage foo
*/
public function testThrowingErrorListener()
{
$this->expectException(CommandNotFoundException::class);
$this->expectExceptionMessage('The "test" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".');
$dispatcher = $this->getDispatcher();
$dispatcher->addListener('console.error', function (ConsoleErrorEvent $event) {
throw new \RuntimeException('foo');
});
$app = new Application();
$loader = new FactoryCommandLoader([
'test' => static function () { return new Command('test-command'); },
]);
$dispatcher->addListener('console.command', function () {
throw new \RuntimeException('bar');
});
$app->setCommandLoader($loader);
$app->get('test');
$application = new Application();
$application->setDispatcher($dispatcher);
$application->setAutoExit(false);
$application->setCatchExceptions(false);
$application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) {
$output->write('foo.');
});
$tester = new ApplicationTester($application);
$tester->run(['command' => 'foo']);
}
}
+35 -29
View File
@@ -40,10 +40,12 @@ class CommandTest extends TestCase
$this->assertEquals('foo:bar', $command->getName(), '__construct() takes the command name as its first argument');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage The command defined in "Symfony\Component\Console\Command\Command" cannot have an empty name.
*/
public function testCommandNameCannotBeEmpty()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('The command defined in "Symfony\Component\Console\Command\Command" cannot have an empty name.');
(new Application())->add(new Command());
}
@@ -115,8 +117,12 @@ class CommandTest extends TestCase
*/
public function testInvalidCommandNames($name)
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage(sprintf('Command name "%s" is invalid.', $name));
if (method_exists($this, 'expectException')) {
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage(sprintf('Command name "%s" is invalid.', $name));
} else {
$this->setExpectedException('InvalidArgumentException', sprintf('Command name "%s" is invalid.', $name));
}
$command = new \TestCommand();
$command->setName($name);
@@ -154,20 +160,20 @@ class CommandTest extends TestCase
{
$command = new \TestCommand();
$command->setHelp('The %command.name% command does... Example: php %command.full_name%.');
$this->assertStringContainsString('The namespace:name command does...', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.name% correctly');
$this->assertStringNotContainsString('%command.full_name%', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.full_name%');
$this->assertContains('The namespace:name command does...', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.name% correctly');
$this->assertNotContains('%command.full_name%', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.full_name%');
$command = new \TestCommand();
$command->setHelp('');
$this->assertStringContainsString('description', $command->getProcessedHelp(), '->getProcessedHelp() falls back to the description');
$this->assertContains('description', $command->getProcessedHelp(), '->getProcessedHelp() falls back to the description');
$command = new \TestCommand();
$command->setHelp('The %command.name% command does... Example: php %command.full_name%.');
$application = new Application();
$application->add($command);
$application->setDefaultCommand('namespace:name', true);
$this->assertStringContainsString('The namespace:name command does...', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.name% correctly in single command applications');
$this->assertStringNotContainsString('%command.full_name%', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.full_name% in single command applications');
$this->assertContains('The namespace:name command does...', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.name% correctly in single command applications');
$this->assertNotContains('%command.full_name%', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.full_name% in single command applications');
}
public function testGetSetAliases()
@@ -182,7 +188,7 @@ class CommandTest extends TestCase
public function testSetAliasesNull()
{
$command = new \TestCommand();
$this->expectException('InvalidArgumentException');
$this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException');
$command->setAliases(null);
}
@@ -212,10 +218,12 @@ class CommandTest extends TestCase
$this->assertEquals($formatterHelper->getName(), $command->getHelper('formatter')->getName(), '->getHelper() returns the correct helper');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot retrieve helper "formatter" because there is no HelperSet defined.
*/
public function testGetHelperWithoutHelperSet()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('Cannot retrieve helper "formatter" because there is no HelperSet defined.');
$command = new \TestCommand();
$command->getHelper('formatter');
}
@@ -271,7 +279,7 @@ class CommandTest extends TestCase
$tester->execute([], ['interactive' => true]);
$this->assertEquals('interact called'.\PHP_EOL.'execute called'.\PHP_EOL, $tester->getDisplay(), '->run() calls the interact() method if the input is interactive');
$this->assertEquals('interact called'.PHP_EOL.'execute called'.PHP_EOL, $tester->getDisplay(), '->run() calls the interact() method if the input is interactive');
}
public function testRunNonInteractive()
@@ -280,21 +288,25 @@ class CommandTest extends TestCase
$tester->execute([], ['interactive' => false]);
$this->assertEquals('execute called'.\PHP_EOL, $tester->getDisplay(), '->run() does not call the interact() method if the input is not interactive');
$this->assertEquals('execute called'.PHP_EOL, $tester->getDisplay(), '->run() does not call the interact() method if the input is not interactive');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage You must override the execute() method in the concrete command class.
*/
public function testExecuteMethodNeedsToBeOverridden()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('You must override the execute() method in the concrete command class.');
$command = new Command('foo');
$command->run(new StringInput(''), new NullOutput());
}
/**
* @expectedException \Symfony\Component\Console\Exception\InvalidOptionException
* @expectedExceptionMessage The "--bar" option does not exist.
*/
public function testRunWithInvalidOption()
{
$this->expectException('Symfony\Component\Console\Exception\InvalidOptionException');
$this->expectExceptionMessage('The "--bar" option does not exist.');
$command = new \TestCommand();
$tester = new CommandTester($command);
$tester->execute(['--bar' => true]);
@@ -337,7 +349,7 @@ class CommandTest extends TestCase
$command->setProcessTitle('foo');
$this->assertSame(0, $command->run(new StringInput(''), new NullOutput()));
if (\function_exists('cli_set_process_title')) {
if (null === @cli_get_process_title() && 'Darwin' === \PHP_OS) {
if (null === @cli_get_process_title() && 'Darwin' === PHP_OS) {
$this->markTestSkipped('Running "cli_get_process_title" as an unprivileged user is not supported on MacOS.');
}
$this->assertEquals('foo', cli_get_process_title());
@@ -353,7 +365,7 @@ class CommandTest extends TestCase
$this->assertEquals($command, $ret, '->setCode() implements a fluent interface');
$tester = new CommandTester($command);
$tester->execute([]);
$this->assertEquals('interact called'.\PHP_EOL.'from the code...'.\PHP_EOL, $tester->getDisplay());
$this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay());
}
public function getSetCodeBindToClosureTests()
@@ -378,7 +390,7 @@ class CommandTest extends TestCase
$command->setCode($code);
$tester = new CommandTester($command);
$tester->execute([]);
$this->assertEquals('interact called'.\PHP_EOL.$expected.\PHP_EOL, $tester->getDisplay());
$this->assertEquals('interact called'.PHP_EOL.$expected.PHP_EOL, $tester->getDisplay());
}
public function testSetCodeWithStaticClosure()
@@ -388,13 +400,7 @@ class CommandTest extends TestCase
$tester = new CommandTester($command);
$tester->execute([]);
if (\PHP_VERSION_ID < 70000) {
// Cannot bind static closures in PHP 5
$this->assertEquals('interact called'.\PHP_EOL.'not bound'.\PHP_EOL, $tester->getDisplay());
} else {
// Can bind static closures in PHP 7
$this->assertEquals('interact called'.\PHP_EOL.'bound'.\PHP_EOL, $tester->getDisplay());
}
$this->assertEquals('interact called'.PHP_EOL.'bound'.PHP_EOL, $tester->getDisplay());
}
private static function createClosure()
@@ -411,7 +417,7 @@ class CommandTest extends TestCase
$this->assertEquals($command, $ret, '->setCode() implements a fluent interface');
$tester = new CommandTester($command);
$tester->execute([]);
$this->assertEquals('interact called'.\PHP_EOL.'from the code...'.\PHP_EOL, $tester->getDisplay());
$this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay());
}
public function callableMethodCommand(InputInterface $input, OutputInterface $output)
+12 -12
View File
@@ -25,9 +25,9 @@ class HelpCommandTest extends TestCase
$command->setApplication(new Application());
$commandTester = new CommandTester($command);
$commandTester->execute(['command_name' => 'li'], ['decorated' => false]);
$this->assertStringContainsString('list [options] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias');
$this->assertStringContainsString('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias');
$this->assertStringContainsString('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias');
$this->assertContains('list [options] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias');
$this->assertContains('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias');
$this->assertContains('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias');
}
public function testExecuteForCommand()
@@ -36,9 +36,9 @@ class HelpCommandTest extends TestCase
$commandTester = new CommandTester($command);
$command->setCommand(new ListCommand());
$commandTester->execute([], ['decorated' => false]);
$this->assertStringContainsString('list [options] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertStringContainsString('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertStringContainsString('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertContains('list [options] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertContains('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertContains('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
}
public function testExecuteForCommandWithXmlOption()
@@ -47,7 +47,7 @@ class HelpCommandTest extends TestCase
$commandTester = new CommandTester($command);
$command->setCommand(new ListCommand());
$commandTester->execute(['--format' => 'xml']);
$this->assertStringContainsString('<command', $commandTester->getDisplay(), '->execute() returns an XML help text if --xml is passed');
$this->assertContains('<command', $commandTester->getDisplay(), '->execute() returns an XML help text if --xml is passed');
}
public function testExecuteForApplicationCommand()
@@ -55,9 +55,9 @@ class HelpCommandTest extends TestCase
$application = new Application();
$commandTester = new CommandTester($application->get('help'));
$commandTester->execute(['command_name' => 'list']);
$this->assertStringContainsString('list [options] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertStringContainsString('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertStringContainsString('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertContains('list [options] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertContains('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertContains('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
}
public function testExecuteForApplicationCommandWithXmlOption()
@@ -65,7 +65,7 @@ class HelpCommandTest extends TestCase
$application = new Application();
$commandTester = new CommandTester($application->get('help'));
$commandTester->execute(['command_name' => 'list', '--format' => 'xml']);
$this->assertStringContainsString('list [--raw] [--format FORMAT] [--] [&lt;namespace&gt;]', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertStringContainsString('<command', $commandTester->getDisplay(), '->execute() returns an XML help text if --format=xml is passed');
$this->assertContains('list [--raw] [--format FORMAT] [--] [&lt;namespace&gt;]', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertContains('<command', $commandTester->getDisplay(), '->execute() returns an XML help text if --format=xml is passed');
}
}
+2 -2
View File
@@ -23,7 +23,7 @@ class ListCommandTest extends TestCase
$commandTester = new CommandTester($command = $application->get('list'));
$commandTester->execute(['command' => $command->getName()], ['decorated' => false]);
$this->assertMatchesRegularExpression('/help\s{2,}Displays help for a command/', $commandTester->getDisplay(), '->execute() returns a list of available commands');
$this->assertRegExp('/help\s{2,}Displays help for a command/', $commandTester->getDisplay(), '->execute() returns a list of available commands');
}
public function testExecuteListsCommandsWithXmlOption()
@@ -31,7 +31,7 @@ class ListCommandTest extends TestCase
$application = new Application();
$commandTester = new CommandTester($command = $application->get('list'));
$commandTester->execute(['command' => $command->getName(), '--format' => 'xml']);
$this->assertMatchesRegularExpression('/<command id="list" name="list" hidden="0">/', $commandTester->getDisplay(), '->execute() returns a list of available commands in XML if --xml is passed');
$this->assertRegExp('/<command id="list" name="list" hidden="0">/', $commandTester->getDisplay(), '->execute() returns a list of available commands in XML if --xml is passed');
}
public function testExecuteListsCommandsWithRawOption()
+1 -1
View File
@@ -41,7 +41,7 @@ class LockableTraitTest extends TestCase
{
$command = new \FooLockCommand();
if (SemaphoreStore::isSupported(false)) {
if (SemaphoreStore::isSupported()) {
$store = new SemaphoreStore();
} else {
$store = new FlockStore();
@@ -41,9 +41,11 @@ class ContainerCommandLoaderTest extends TestCase
$this->assertInstanceOf(Command::class, $loader->get('bar'));
}
/**
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
*/
public function testGetUnknownCommandThrows()
{
$this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException');
(new ContainerCommandLoader(new ServiceLocator([]), []))->get('unknown');
}
@@ -40,9 +40,11 @@ class FactoryCommandLoaderTest extends TestCase
$this->assertInstanceOf(Command::class, $loader->get('bar'));
}
/**
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
*/
public function testGetUnknownCommandThrows()
{
$this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException');
(new FactoryCommandLoader([]))->get('unknown');
}
@@ -33,28 +33,27 @@ class AddConsoleCommandPassTest extends TestCase
$container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->setParameter('my-command.class', 'Symfony\Component\Console\Tests\DependencyInjection\MyCommand');
$id = 'my-command';
$definition = new Definition('%my-command.class%');
$definition->setPublic($public);
$definition->addTag('console.command');
$container->setDefinition('my-command', $definition);
$container->setDefinition($id, $definition);
$container->compile();
$alias = 'console.command.symfony_component_console_tests_dependencyinjection_mycommand';
$alias = 'console.command.public_alias.my-command';
if ($public) {
$this->assertFalse($container->hasAlias($alias));
$id = 'my-command';
} else {
$id = $alias;
// The alias is replaced by a Definition by the ReplaceAliasByActualDefinitionPass
// in case the original service is private
$this->assertFalse($container->hasDefinition('my-command'));
$this->assertFalse($container->hasDefinition($id));
$this->assertTrue($container->hasDefinition($alias));
}
$this->assertTrue($container->hasParameter('console.command.ids'));
$this->assertSame([$alias => $id], $container->getParameter('console.command.ids'));
$this->assertSame([$public ? $id : $alias], $container->getParameter('console.command.ids'));
}
public function testProcessRegistersLazyCommands()
@@ -75,8 +74,7 @@ class AddConsoleCommandPassTest extends TestCase
$this->assertSame(ContainerCommandLoader::class, $commandLoader->getClass());
$this->assertSame(['my:command' => 'my-command', 'my:alias' => 'my-command'], $commandLoader->getArgument(1));
$this->assertEquals([['my-command' => new ServiceClosureArgument(new TypedReference('my-command', MyCommand::class))]], $commandLocator->getArguments());
$this->assertSame(['console.command.symfony_component_console_tests_dependencyinjection_mycommand' => 'my-command'], $container->getParameter('console.command.ids'));
$this->assertSame(['my-command' => true], $container->getParameter('console.lazy_command.ids'));
$this->assertSame([], $container->getParameter('console.command.ids'));
$this->assertSame([['setName', ['my:command']], ['setAliases', [['my:alias']]]], $command->getMethodCalls());
}
@@ -98,8 +96,7 @@ class AddConsoleCommandPassTest extends TestCase
$this->assertSame(ContainerCommandLoader::class, $commandLoader->getClass());
$this->assertSame(['default' => 'with-default-name'], $commandLoader->getArgument(1));
$this->assertEquals([['with-default-name' => new ServiceClosureArgument(new TypedReference('with-default-name', NamedCommand::class))]], $commandLocator->getArguments());
$this->assertSame(['console.command.symfony_component_console_tests_dependencyinjection_namedcommand' => 'with-default-name'], $container->getParameter('console.command.ids'));
$this->assertSame(['with-default-name' => true], $container->getParameter('console.lazy_command.ids'));
$this->assertSame([], $container->getParameter('console.command.ids'));
$container = new ContainerBuilder();
$container
@@ -121,10 +118,12 @@ class AddConsoleCommandPassTest extends TestCase
];
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The service "my-command" tagged "console.command" must not be abstract.
*/
public function testProcessThrowAnExceptionIfTheServiceIsAbstract()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The service "my-command" tagged "console.command" must not be abstract.');
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
@@ -137,10 +136,12 @@ class AddConsoleCommandPassTest extends TestCase
$container->compile();
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The service "my-command" tagged "console.command" must be a subclass of "Symfony\Component\Console\Command\Command".
*/
public function testProcessThrowAnExceptionIfTheServiceIsNotASubclassOfCommand()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The service "my-command" tagged "console.command" must be a subclass of "Symfony\Component\Console\Command\Command".');
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
@@ -168,10 +169,9 @@ class AddConsoleCommandPassTest extends TestCase
(new AddConsoleCommandPass())->process($container);
$alias1 = 'console.command.symfony_component_console_tests_dependencyinjection_mycommand';
$alias2 = $alias1.'_my-command2';
$this->assertTrue($container->hasAlias($alias1));
$this->assertTrue($container->hasAlias($alias2));
$aliasPrefix = 'console.command.public_alias.';
$this->assertTrue($container->hasAlias($aliasPrefix.'my-command1'));
$this->assertTrue($container->hasAlias($aliasPrefix.'my-command2'));
}
public function testProcessOnChildDefinitionWithClass()
@@ -223,10 +223,12 @@ class AddConsoleCommandPassTest extends TestCase
$this->assertInstanceOf($className, $command);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage The definition for "my-child-command" has no class.
*/
public function testProcessOnChildDefinitionWithoutClass()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('The definition for "my-child-command" has no class.');
$container = new ContainerBuilder();
$container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
@@ -102,6 +102,6 @@ abstract class AbstractDescriptorTest extends TestCase
{
$output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
$this->getDescriptor()->describe($output, $describedObject, $options + ['raw_output' => true]);
$this->assertEquals(trim($expectedDescription), trim(str_replace(\PHP_EOL, "\n", $output->fetch())));
$this->assertEquals(trim($expectedDescription), trim(str_replace(PHP_EOL, "\n", $output->fetch())));
}
}
@@ -1,53 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Tests\Descriptor;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Descriptor\ApplicationDescription;
final class ApplicationDescriptionTest extends TestCase
{
/**
* @dataProvider getNamespacesProvider
*/
public function testGetNamespaces(array $expected, array $names)
{
$application = new TestApplication();
foreach ($names as $name) {
$application->add(new Command($name));
}
$this->assertSame($expected, array_keys((new ApplicationDescription($application))->getNamespaces()));
}
public function getNamespacesProvider()
{
return [
[['_global'], ['foobar']],
[['a', 'b'], ['b:foo', 'a:foo', 'b:bar']],
[['_global', 'b', 'z', 22, 33], ['z:foo', '1', '33:foo', 'b:foo', '22:foo:bar']],
];
}
}
final class TestApplication extends Application
{
/**
* {@inheritdoc}
*/
protected function getDefaultCommands()
{
return [];
}
}
@@ -30,6 +30,6 @@ class JsonDescriptorTest extends AbstractDescriptorTest
{
$output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
$this->getDescriptor()->describe($output, $describedObject, $options + ['raw_output' => true]);
$this->assertEquals(json_decode(trim($expectedDescription), true), json_decode(trim(str_replace(\PHP_EOL, "\n", $output->fetch())), true));
$this->assertEquals(json_decode(trim($expectedDescription), true), json_decode(trim(str_replace(PHP_EOL, "\n", $output->fetch())), true));
}
}
@@ -32,7 +32,7 @@ class ObjectsProvider
'input_argument_3' => new InputArgument('argument_name', InputArgument::OPTIONAL, 'argument description', 'default_value'),
'input_argument_4' => new InputArgument('argument_name', InputArgument::REQUIRED, "multiline\nargument description"),
'input_argument_with_style' => new InputArgument('argument_name', InputArgument::OPTIONAL, 'argument description', '<comment>style</>'),
'input_argument_with_default_inf_value' => new InputArgument('argument_name', InputArgument::OPTIONAL, 'argument description', \INF),
'input_argument_with_default_inf_value' => new InputArgument('argument_name', InputArgument::OPTIONAL, 'argument description', INF),
];
}
@@ -47,7 +47,7 @@ class ObjectsProvider
'input_option_6' => new InputOption('option_name', ['o', 'O'], InputOption::VALUE_REQUIRED, 'option with multiple shortcuts'),
'input_option_with_style' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, 'option description', '<comment>style</>'),
'input_option_with_style_array' => new InputOption('option_name', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'option description', ['<comment>Hello</comment>', '<info>world</info>']),
'input_option_with_default_inf_value' => new InputOption('option_name', 'o', InputOption::VALUE_OPTIONAL, 'option description', \INF),
'input_option_with_default_inf_value' => new InputOption('option_name', 'o', InputOption::VALUE_OPTIONAL, 'option description', INF),
];
}
@@ -1,21 +0,0 @@
<?php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class FooHiddenCommand extends Command
{
protected function configure()
{
$this
->setName('foo:hidden')
->setAliases(['afoohidden'])
->setHidden(true)
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
}
}
@@ -1,3 +1,6 @@
Description:
Lists commands
Usage:
list [options] [--] [<namespace>]
@@ -1,3 +1,6 @@
Description:
Lists commands
Usage:
list [options] [--] [<namespace>]
+3
View File
@@ -1,3 +1,6 @@
<comment>Description:</comment>
command 1 description
<comment>Usage:</comment>
descriptor:command1
alias1
+3
View File
@@ -1,3 +1,6 @@
<comment>Description:</comment>
command 2 description
<comment>Usage:</comment>
descriptor:command2 [options] [--] \<argument_name>
descriptor:command2 -o|--option_name \<argument_name>
@@ -1,3 +1,6 @@
<comment>Description:</comment>
command åèä description
<comment>Usage:</comment>
descriptor:åèä [options] [--] \<argument_åèä>
descriptor:åèä -o|--option_name \<argument_name>
@@ -59,9 +59,11 @@ class OutputFormatterStyleStackTest extends TestCase
$this->assertEquals($s1, $stack->pop());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testInvalidPop()
{
$this->expectException('InvalidArgumentException');
$stack = new OutputFormatterStyleStack();
$stack->push(new OutputFormatterStyle('white', 'black'));
$stack->pop(new OutputFormatterStyle('yellow', 'blue'));
@@ -41,7 +41,7 @@ class OutputFormatterStyleTest extends TestCase
$style->setForeground('default');
$this->assertEquals("\033[39mfoo\033[39m", $style->apply('foo'));
$this->expectException('InvalidArgumentException');
$this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException');
$style->setForeground('undefined-color');
}
@@ -58,7 +58,7 @@ class OutputFormatterStyleTest extends TestCase
$style->setBackground('default');
$this->assertEquals("\033[49mfoo\033[49m", $style->apply('foo'));
$this->expectException('InvalidArgumentException');
$this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException');
$style->setBackground('undefined-color');
}
@@ -86,7 +86,7 @@ class OutputFormatterStyleTest extends TestCase
$this->fail('->setOption() throws an \InvalidArgumentException when the option does not exist in the available options');
} catch (\Exception $e) {
$this->assertInstanceOf('\InvalidArgumentException', $e, '->setOption() throws an \InvalidArgumentException when the option does not exist in the available options');
$this->assertStringContainsString('Invalid option specified: "foo"', $e->getMessage(), '->setOption() throws an \InvalidArgumentException when the option does not exist in the available options');
$this->assertContains('Invalid option specified: "foo"', $e->getMessage(), '->setOption() throws an \InvalidArgumentException when the option does not exist in the available options');
}
try {
@@ -94,7 +94,7 @@ class OutputFormatterStyleTest extends TestCase
$this->fail('->unsetOption() throws an \InvalidArgumentException when the option does not exist in the available options');
} catch (\Exception $e) {
$this->assertInstanceOf('\InvalidArgumentException', $e, '->unsetOption() throws an \InvalidArgumentException when the option does not exist in the available options');
$this->assertStringContainsString('Invalid option specified: "foo"', $e->getMessage(), '->unsetOption() throws an \InvalidArgumentException when the option does not exist in the available options');
$this->assertContains('Invalid option specified: "foo"', $e->getMessage(), '->unsetOption() throws an \InvalidArgumentException when the option does not exist in the available options');
}
}
}
@@ -196,17 +196,6 @@ class OutputFormatterTest extends TestCase
];
}
/**
* @group legacy
* @dataProvider provideInlineStyleTagsWithUnknownOptions
* @expectedDeprecation Unknown style options are deprecated since Symfony 3.2 and will be removed in 4.0. Exception "Invalid option specified: "%s". Expected one of (bold, underscore, blink, reverse, conceal).".
*/
public function testInlineStyleOptionsUnknownAreDeprecated($tag, $option)
{
$formatter = new OutputFormatter(true);
$formatter->format($tag);
}
public function provideInlineStyleTagsWithUnknownOptions()
{
return [
@@ -333,6 +322,28 @@ more text
EOF
));
}
public function testFormatAndWrap()
{
$formatter = new OutputFormatter(true);
$this->assertSame("fo\no\e[37;41mb\e[39;49m\n\e[37;41mar\e[39;49m\nba\nz", $formatter->formatAndWrap('foo<error>bar</error> baz', 2));
$this->assertSame("pr\ne \e[37;41m\e[39;49m\n\e[37;41mfo\e[39;49m\n\e[37;41mo \e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mr \e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mz\e[39;49m \npo\nst", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 2));
$this->assertSame("pre\e[37;41m\e[39;49m\n\e[37;41mfoo\e[39;49m\n\e[37;41mbar\e[39;49m\n\e[37;41mbaz\e[39;49m\npos\nt", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 3));
$this->assertSame("pre \e[37;41m\e[39;49m\n\e[37;41mfoo \e[39;49m\n\e[37;41mbar \e[39;49m\n\e[37;41mbaz\e[39;49m \npost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 4));
$this->assertSame("pre \e[37;41mf\e[39;49m\n\e[37;41moo ba\e[39;49m\n\e[37;41mr baz\e[39;49m\npost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 5));
$this->assertSame("Lore\nm \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m \ndolo\nr \e[32msi\e[39m\n\e[32mt\e[39m am\net", $formatter->formatAndWrap('Lorem <error>ipsum</error> dolor <info>sit</info> amet', 4));
$this->assertSame("Lorem \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m dolo\nr \e[32msit\e[39m am\net", $formatter->formatAndWrap('Lorem <error>ipsum</error> dolor <info>sit</info> amet', 8));
$this->assertSame("Lorem \e[37;41mipsum\e[39;49m dolor \e[32m\e[39m\n\e[32msit\e[39m, \e[37;41mamet\e[39;49m et \e[32mlauda\e[39m\n\e[32mntium\e[39m architecto", $formatter->formatAndWrap('Lorem <error>ipsum</error> dolor <info>sit</info>, <error>amet</error> et <info>laudantium</info> architecto', 18));
$formatter = new OutputFormatter();
$this->assertSame("fo\nob\nar\nba\nz", $formatter->formatAndWrap('foo<error>bar</error> baz', 2));
$this->assertSame("pr\ne \nfo\no \nba\nr \nba\nz \npo\nst", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 2));
$this->assertSame("pre\nfoo\nbar\nbaz\npos\nt", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 3));
$this->assertSame("pre \nfoo \nbar \nbaz \npost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 4));
$this->assertSame("pre f\noo ba\nr baz\npost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 5));
}
}
class TableCell
+1 -1
View File
@@ -68,7 +68,7 @@ class HelperSetTest extends TestCase
} catch (\Exception $e) {
$this->assertInstanceOf('\InvalidArgumentException', $e, '->get() throws InvalidArgumentException when helper not found');
$this->assertInstanceOf('Symfony\Component\Console\Exception\ExceptionInterface', $e, '->get() throws domain specific exception when helper not found');
$this->assertStringContainsString('The helper "foo" is not defined.', $e->getMessage(), '->get() throws InvalidArgumentException when helper not found');
$this->assertContains('The helper "foo" is not defined.', $e->getMessage(), '->get() throws InvalidArgumentException when helper not found');
}
}
+20 -5
View File
@@ -25,6 +25,10 @@ class ProcessHelperTest extends TestCase
*/
public function testVariousProcessRuns($expected, $cmd, $verbosity, $error)
{
if (\is_string($cmd)) {
$cmd = method_exists(Process::class, 'fromShellCommandline') ? Process::fromShellCommandline($cmd) : new Process($cmd);
}
$helper = new ProcessHelper();
$helper->setHelperSet(new HelperSet([new DebugFormatterHelper()]));
$output = $this->getOutputStream($verbosity);
@@ -41,7 +45,7 @@ class ProcessHelperTest extends TestCase
$executed = false;
$callback = function () use (&$executed) { $executed = true; };
$helper->run($output, 'php -r "echo 42;"', null, $callback);
$helper->run($output, ['php', '-r', 'echo 42;'], null, $callback);
$this->assertTrue($executed);
}
@@ -81,12 +85,21 @@ EOT;
OUT out message
RES 252 Command did not run successfully
EOT;
$PHP = '\\' === \DIRECTORY_SEPARATOR ? '"!PHP!"' : '"$PHP"';
$successOutputPhp = <<<EOT
RUN php -r $PHP
OUT 42
RES Command ran successfully
EOT;
$errorMessage = 'An error occurred';
$args = new Process(['php', '-r', 'echo 42;']);
$args = $args->getCommandLine();
$successOutputProcessDebug = str_replace("'php' '-r' 'echo 42;'", $args, $successOutputProcessDebug);
$fromShellCommandline = method_exists(Process::class, 'fromShellCommandline') ? [Process::class, 'fromShellCommandline'] : function ($cmd) { return new Process($cmd); };
return [
['', 'php -r "echo 42;"', StreamOutput::VERBOSITY_VERBOSE, null],
@@ -96,11 +109,13 @@ EOT;
['', 'php -r "syntax error"', StreamOutput::VERBOSITY_VERBOSE, null],
[$syntaxErrorOutputVerbose, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERY_VERBOSE, null],
[$syntaxErrorOutputDebug, 'php -r "fwrite(STDERR, \'error message\');usleep(500000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_DEBUG, null],
[$errorMessage.\PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERBOSE, $errorMessage],
[$syntaxErrorOutputVerbose.$errorMessage.\PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERY_VERBOSE, $errorMessage],
[$syntaxErrorOutputDebug.$errorMessage.\PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(500000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_DEBUG, $errorMessage],
[$errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERBOSE, $errorMessage],
[$syntaxErrorOutputVerbose.$errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERY_VERBOSE, $errorMessage],
[$syntaxErrorOutputDebug.$errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(500000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_DEBUG, $errorMessage],
[$successOutputProcessDebug, ['php', '-r', 'echo 42;'], StreamOutput::VERBOSITY_DEBUG, null],
[$successOutputDebug, new Process('php -r "echo 42;"'), StreamOutput::VERBOSITY_DEBUG, null],
[$successOutputDebug, $fromShellCommandline('php -r "echo 42;"'), StreamOutput::VERBOSITY_DEBUG, null],
[$successOutputProcessDebug, [new Process(['php', '-r', 'echo 42;'])], StreamOutput::VERBOSITY_DEBUG, null],
[$successOutputPhp, [$fromShellCommandline('php -r '.$PHP), 'PHP' => 'echo 42;'], StreamOutput::VERBOSITY_DEBUG, null],
];
}
+120 -13
View File
@@ -12,8 +12,10 @@
namespace Symfony\Component\Console\Tests\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\StreamOutput;
/**
@@ -323,6 +325,88 @@ class ProgressBarTest extends TestCase
);
}
public function testOverwriteWithSectionOutput()
{
$sections = [];
$stream = $this->getOutputStream(true);
$output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
$bar = new ProgressBar($output, 50);
$bar->start();
$bar->display();
$bar->advance();
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
' 0/50 [>---------------------------] 0%'.PHP_EOL.
"\x1b[1A\x1b[0J".' 0/50 [>---------------------------] 0%'.PHP_EOL.
"\x1b[1A\x1b[0J".' 1/50 [>---------------------------] 2%'.PHP_EOL.
"\x1b[1A\x1b[0J".' 2/50 [=>--------------------------] 4%'.PHP_EOL,
stream_get_contents($output->getStream())
);
}
public function testOverwriteMultipleProgressBarsWithSectionOutputs()
{
$sections = [];
$stream = $this->getOutputStream(true);
$output1 = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
$output2 = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
$progress = new ProgressBar($output1, 50);
$progress2 = new ProgressBar($output2, 50);
$progress->start();
$progress2->start();
$progress2->advance();
$progress->advance();
rewind($stream->getStream());
$this->assertEquals(
' 0/50 [>---------------------------] 0%'.PHP_EOL.
' 0/50 [>---------------------------] 0%'.PHP_EOL.
"\x1b[1A\x1b[0J".' 1/50 [>---------------------------] 2%'.PHP_EOL.
"\x1b[2A\x1b[0J".' 1/50 [>---------------------------] 2%'.PHP_EOL.
"\x1b[1A\x1b[0J".' 1/50 [>---------------------------] 2%'.PHP_EOL.
' 1/50 [>---------------------------] 2%'.PHP_EOL,
stream_get_contents($stream->getStream())
);
}
public function testMultipleSectionsWithCustomFormat()
{
$sections = [];
$stream = $this->getOutputStream(true);
$output1 = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
$output2 = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
ProgressBar::setFormatDefinition('test', '%current%/%max% [%bar%] %percent:3s%% Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.');
$progress = new ProgressBar($output1, 50);
$progress2 = new ProgressBar($output2, 50);
$progress2->setFormat('test');
$progress->start();
$progress2->start();
$progress->advance();
$progress2->advance();
rewind($stream->getStream());
$this->assertEquals(' 0/50 [>---------------------------] 0%'.PHP_EOL.
' 0/50 [>] 0% Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.'.PHP_EOL.
"\x1b[4A\x1b[0J".' 0/50 [>] 0% Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.'.PHP_EOL.
"\x1b[3A\x1b[0J".' 1/50 [>---------------------------] 2%'.PHP_EOL.
' 0/50 [>] 0% Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.'.PHP_EOL.
"\x1b[3A\x1b[0J".' 1/50 [>] 2% Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.'.PHP_EOL,
stream_get_contents($stream->getStream())
);
}
public function testStartWithMax()
{
$bar = new ProgressBar($output = $this->getOutputStream());
@@ -477,16 +561,16 @@ class ProgressBarTest extends TestCase
rewind($output->getStream());
$this->assertEquals(
' 0/200 [>---------------------------] 0%'.\PHP_EOL.
' 20/200 [==>-------------------------] 10%'.\PHP_EOL.
' 40/200 [=====>----------------------] 20%'.\PHP_EOL.
' 60/200 [========>-------------------] 30%'.\PHP_EOL.
' 80/200 [===========>----------------] 40%'.\PHP_EOL.
' 100/200 [==============>-------------] 50%'.\PHP_EOL.
' 120/200 [================>-----------] 60%'.\PHP_EOL.
' 140/200 [===================>--------] 70%'.\PHP_EOL.
' 160/200 [======================>-----] 80%'.\PHP_EOL.
' 180/200 [=========================>--] 90%'.\PHP_EOL.
' 0/200 [>---------------------------] 0%'.PHP_EOL.
' 20/200 [==>-------------------------] 10%'.PHP_EOL.
' 40/200 [=====>----------------------] 20%'.PHP_EOL.
' 60/200 [========>-------------------] 30%'.PHP_EOL.
' 80/200 [===========>----------------] 40%'.PHP_EOL.
' 100/200 [==============>-------------] 50%'.PHP_EOL.
' 120/200 [================>-----------] 60%'.PHP_EOL.
' 140/200 [===================>--------] 70%'.PHP_EOL.
' 160/200 [======================>-----] 80%'.PHP_EOL.
' 180/200 [=========================>--] 90%'.PHP_EOL.
' 200/200 [============================] 100%',
stream_get_contents($output->getStream())
);
@@ -503,8 +587,8 @@ class ProgressBarTest extends TestCase
rewind($output->getStream());
$this->assertEquals(
' 0/50 [>---------------------------] 0%'.\PHP_EOL.
' 25/50 [==============>-------------] 50%'.\PHP_EOL.
' 0/50 [>---------------------------] 0%'.PHP_EOL.
' 25/50 [==============>-------------] 50%'.PHP_EOL.
' 50/50 [============================] 100%',
stream_get_contents($output->getStream())
);
@@ -518,7 +602,7 @@ class ProgressBarTest extends TestCase
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.\PHP_EOL.
' 0 [>---------------------------]'.PHP_EOL.
' 1 [->--------------------------]',
stream_get_contents($output->getStream())
);
@@ -605,6 +689,29 @@ class ProgressBarTest extends TestCase
);
}
public function testSettingMaxStepsDuringProgressing()
{
$output = $this->getOutputStream();
$bar = new ProgressBar($output);
$bar->start();
$bar->setProgress(2);
$bar->setMaxSteps(10);
$bar->setProgress(5);
$bar->setMaxSteps(100);
$bar->setProgress(10);
$bar->finish();
rewind($output->getStream());
$this->assertEquals(
rtrim(' 0 [>---------------------------]').
rtrim($this->generateOutput(' 2 [-->-------------------------]')).
rtrim($this->generateOutput(' 5/10 [==============>-------------] 50%')).
rtrim($this->generateOutput(' 10/100 [==>-------------------------] 10%')).
rtrim($this->generateOutput(' 100/100 [============================] 100%')),
stream_get_contents($output->getStream())
);
}
public function testWithSmallScreen()
{
$output = $this->getOutputStream();
+22 -14
View File
@@ -46,11 +46,11 @@ class ProgressIndicatorTest extends TestCase
$this->generateOutput(' \\ Advancing...').
$this->generateOutput(' | Advancing...').
$this->generateOutput(' | Done...').
\PHP_EOL.
PHP_EOL.
$this->generateOutput(' - Starting Again...').
$this->generateOutput(' \\ Starting Again...').
$this->generateOutput(' \\ Done Again...').
\PHP_EOL,
PHP_EOL,
stream_get_contents($output->getStream())
);
}
@@ -70,9 +70,9 @@ class ProgressIndicatorTest extends TestCase
rewind($output->getStream());
$this->assertEquals(
' Starting...'.\PHP_EOL.
' Midway...'.\PHP_EOL.
' Done...'.\PHP_EOL.\PHP_EOL,
' Starting...'.PHP_EOL.
' Midway...'.PHP_EOL.
' Done...'.PHP_EOL.PHP_EOL,
stream_get_contents($output->getStream())
);
}
@@ -100,34 +100,42 @@ class ProgressIndicatorTest extends TestCase
);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Must have at least 2 indicator value characters.
*/
public function testCannotSetInvalidIndicatorCharacters()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('Must have at least 2 indicator value characters.');
new ProgressIndicator($this->getOutputStream(), null, 100, ['1']);
$bar = new ProgressIndicator($this->getOutputStream(), null, 100, ['1']);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Progress indicator already started.
*/
public function testCannotStartAlreadyStartedIndicator()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('Progress indicator already started.');
$bar = new ProgressIndicator($this->getOutputStream());
$bar->start('Starting...');
$bar->start('Starting Again.');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Progress indicator has not yet been started.
*/
public function testCannotAdvanceUnstartedIndicator()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('Progress indicator has not yet been started.');
$bar = new ProgressIndicator($this->getOutputStream());
$bar->advance();
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Progress indicator has not yet been started.
*/
public function testCannotFinishUnstartedIndicator()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('Progress indicator has not yet been started.');
$bar = new ProgressIndicator($this->getOutputStream());
$bar->finish('Finished');
}
+37 -406
View File
@@ -11,7 +11,6 @@
namespace Symfony\Component\Console\Tests\Helper;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Helper\HelperSet;
@@ -20,7 +19,6 @@ use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Terminal;
/**
* @group tty
@@ -55,7 +53,7 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
rewind($output->getStream());
$stream = stream_get_contents($output->getStream());
$this->assertStringContainsString('Input "Fabien" is not a superhero!', $stream);
$this->assertContains('Input "Fabien" is not a superhero!', $stream);
try {
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '1');
@@ -169,27 +167,26 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
public function testAskWithAutocomplete()
{
if (!Terminal::hasSttyAvailable()) {
if (!$this->hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}
// Acm<NEWLINE>
// Ac<BACKSPACE><BACKSPACE>s<TAB>Test<NEWLINE>
// <NEWLINE>
// <UP ARROW><UP ARROW><UP ARROW><NEWLINE>
// <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
// <UP ARROW><UP ARROW><NEWLINE>
// <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
// <DOWN ARROW><NEWLINE>
// S<BACKSPACE><BACKSPACE><DOWN ARROW><DOWN ARROW><NEWLINE>
// F00<BACKSPACE><BACKSPACE>oo<TAB><NEWLINE>
// F⭐<TAB><BACKSPACE><BACKSPACE>⭐<TAB><NEWLINE>
$inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\nF⭐\t\177\177\t\n");
$inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\n");
$dialog = new QuestionHelper();
$helperSet = new HelperSet([new FormatterHelper()]);
$dialog->setHelperSet($helperSet);
$question = new Question('Please select a bundle', 'FrameworkBundle');
$question->setAutocompleterValues(['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle', 'F⭐Y']);
$question->setAutocompleterValues(['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle']);
$this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('AsseticBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
@@ -199,12 +196,11 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
$this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('AsseticBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('F⭐Y', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
}
public function testAskWithAutocompleteWithNonSequentialKeys()
{
if (!Terminal::hasSttyAvailable()) {
if (!$this->hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}
@@ -223,7 +219,7 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
public function testAskWithAutocompleteWithExactMatch()
{
if (!Terminal::hasSttyAvailable()) {
if (!$this->hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}
@@ -259,7 +255,7 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
*/
public function testAskWithAutocompleteWithMultiByteCharacter($character)
{
if (!Terminal::hasSttyAvailable()) {
if (!$this->hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}
@@ -283,7 +279,7 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
public function testAutocompleteWithTrailingBackslash()
{
if (!Terminal::hasSttyAvailable()) {
if (!$this->hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}
@@ -522,10 +518,12 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
$this->assertSame($expectedValue, $answer);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The provided answer is ambiguous. Value should be one of env_2 or env_3.
*/
public function testAmbiguousChoiceFromChoicelist()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The provided answer is ambiguous. Value should be one of "env_2" or "env_3".');
$possibleChoices = [
'env_1' => 'My first environment',
'env_2' => 'My environment',
@@ -590,382 +588,35 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
}
/**
* @group legacy
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
* @expectedExceptionMessage Aborted.
*/
public function testLegacyAskChoice()
{
$questionHelper = new QuestionHelper();
$helperSet = new HelperSet([new FormatterHelper()]);
$questionHelper->setHelperSet($helperSet);
$heroes = ['Superman', 'Batman', 'Spiderman'];
$questionHelper->setInputStream($this->getInputStream("\n1\n 1 \nFabien\n1\nFabien\n1\n0,2\n 0 , 2 \n\n\n"));
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '2');
$question->setMaxAttempts(1);
// first answer is an empty answer, we're supposed to receive the default value
$this->assertEquals('Spiderman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes);
$question->setMaxAttempts(1);
$this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes);
$question->setErrorMessage('Input "%s" is not a superhero!');
$question->setMaxAttempts(2);
$this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question));
rewind($output->getStream());
$stream = stream_get_contents($output->getStream());
$this->assertStringContainsString('Input "Fabien" is not a superhero!', $stream);
try {
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '1');
$question->setMaxAttempts(1);
$questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question);
$this->fail();
} catch (\InvalidArgumentException $e) {
$this->assertEquals('Value "Fabien" is invalid', $e->getMessage());
}
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, null);
$question->setMaxAttempts(1);
$question->setMultiselect(true);
$this->assertEquals(['Batman'], $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals(['Superman', 'Spiderman'], $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals(['Superman', 'Spiderman'], $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '0,1');
$question->setMaxAttempts(1);
$question->setMultiselect(true);
$this->assertEquals(['Superman', 'Batman'], $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, ' 0 , 1 ');
$question->setMaxAttempts(1);
$question->setMultiselect(true);
$this->assertEquals(['Superman', 'Batman'], $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
}
/**
* @group legacy
*/
public function testLegacyAsk()
{
$dialog = new QuestionHelper();
$dialog->setInputStream($this->getInputStream("\n8AM\n"));
$question = new Question('What time is it?', '2PM');
$this->assertEquals('2PM', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$question = new Question('What time is it?', '2PM');
$this->assertEquals('8AM', $dialog->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question));
rewind($output->getStream());
$this->assertEquals('What time is it?', stream_get_contents($output->getStream()));
}
/**
* @group legacy
*/
public function testLegacyAskWithAutocomplete()
{
if (!Terminal::hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}
// Acm<NEWLINE>
// Ac<BACKSPACE><BACKSPACE>s<TAB>Test<NEWLINE>
// <NEWLINE>
// <UP ARROW><UP ARROW><UP ARROW><NEWLINE>
// <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
// <DOWN ARROW><NEWLINE>
// S<BACKSPACE><BACKSPACE><DOWN ARROW><DOWN ARROW><NEWLINE>
// F00<BACKSPACE><BACKSPACE>oo<TAB><NEWLINE>
// F⭐<TAB><BACKSPACE><BACKSPACE>⭐<TAB><NEWLINE>
$inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\nF⭐\t\t\n");
$dialog = new QuestionHelper();
$dialog->setInputStream($inputStream);
$helperSet = new HelperSet([new FormatterHelper()]);
$dialog->setHelperSet($helperSet);
$question = new Question('Please select a bundle', 'FrameworkBundle');
$question->setAutocompleterValues(['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle', 'F⭐Y']);
$this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals('AsseticBundleTest', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals('FrameworkBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals('SecurityBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals('FooBundleTest', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals('AsseticBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals('FooBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals('F⭐Y', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
}
/**
* @group legacy
*/
public function testLegacyAskWithAutocompleteWithNonSequentialKeys()
{
if (!Terminal::hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}
// <UP ARROW><UP ARROW><NEWLINE><DOWN ARROW><DOWN ARROW><NEWLINE>
$inputStream = $this->getInputStream("\033[A\033[A\n\033[B\033[B\n");
$dialog = new QuestionHelper();
$dialog->setInputStream($inputStream);
$dialog->setHelperSet(new HelperSet([new FormatterHelper()]));
$question = new ChoiceQuestion('Please select a bundle', [1 => 'AcmeDemoBundle', 4 => 'AsseticBundle']);
$question->setMaxAttempts(1);
$this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals('AsseticBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
}
/**
* @group legacy
*/
public function testLegacyAskHiddenResponse()
{
if ('\\' === \DIRECTORY_SEPARATOR) {
$this->markTestSkipped('This test is not supported on Windows');
}
$dialog = new QuestionHelper();
$dialog->setInputStream($this->getInputStream("8AM\n"));
$question = new Question('What time is it?');
$question->setHidden(true);
$this->assertEquals('8AM', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
}
/**
* @group legacy
* @dataProvider getAskConfirmationData
*/
public function testLegacyAskConfirmation($question, $expected, $default = true)
{
$dialog = new QuestionHelper();
$dialog->setInputStream($this->getInputStream($question."\n"));
$question = new ConfirmationQuestion('Do you like French fries?', $default);
$this->assertEquals($expected, $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question), 'confirmation question should '.($expected ? 'pass' : 'cancel'));
}
/**
* @group legacy
*/
public function testLegacyAskConfirmationWithCustomTrueAnswer()
{
$dialog = new QuestionHelper();
$dialog->setInputStream($this->getInputStream("j\ny\n"));
$question = new ConfirmationQuestion('Do you like French fries?', false, '/^(j|y)/i');
$this->assertTrue($dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$question = new ConfirmationQuestion('Do you like French fries?', false, '/^(j|y)/i');
$this->assertTrue($dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
}
/**
* @group legacy
*/
public function testLegacyAskAndValidate()
{
$dialog = new QuestionHelper();
$helperSet = new HelperSet([new FormatterHelper()]);
$dialog->setHelperSet($helperSet);
$error = 'This is not a color!';
$validator = function ($color) use ($error) {
if (!\in_array($color, ['white', 'black'])) {
throw new \InvalidArgumentException($error);
}
return $color;
};
$question = new Question('What color was the white horse of Henry IV?', 'white');
$question->setValidator($validator);
$question->setMaxAttempts(2);
$dialog->setInputStream($this->getInputStream("\nblack\n"));
$this->assertEquals('white', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$this->assertEquals('black', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
$dialog->setInputStream($this->getInputStream("green\nyellow\norange\n"));
try {
$dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
$this->fail();
} catch (\InvalidArgumentException $e) {
$this->assertEquals($error, $e->getMessage());
}
}
/**
* @group legacy
* @dataProvider simpleAnswerProvider
*/
public function testLegacySelectChoiceFromSimpleChoices($providedAnswer, $expectedValue)
{
$possibleChoices = [
'My environment 1',
'My environment 2',
'My environment 3',
];
$dialog = new QuestionHelper();
$dialog->setInputStream($this->getInputStream($providedAnswer."\n"));
$helperSet = new HelperSet([new FormatterHelper()]);
$dialog->setHelperSet($helperSet);
$question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
$question->setMaxAttempts(1);
$answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
$this->assertSame($expectedValue, $answer);
}
/**
* @group legacy
* @dataProvider mixedKeysChoiceListAnswerProvider
*/
public function testLegacyChoiceFromChoicelistWithMixedKeys($providedAnswer, $expectedValue)
{
$possibleChoices = [
'0' => 'No environment',
'1' => 'My environment 1',
'env_2' => 'My environment 2',
3 => 'My environment 3',
];
$dialog = new QuestionHelper();
$dialog->setInputStream($this->getInputStream($providedAnswer."\n"));
$helperSet = new HelperSet([new FormatterHelper()]);
$dialog->setHelperSet($helperSet);
$question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
$question->setMaxAttempts(1);
$answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
$this->assertSame($expectedValue, $answer);
}
/**
* @group legacy
* @dataProvider answerProvider
*/
public function testLegacySelectChoiceFromChoiceList($providedAnswer, $expectedValue)
{
$possibleChoices = [
'env_1' => 'My environment 1',
'env_2' => 'My environment',
'env_3' => 'My environment',
];
$dialog = new QuestionHelper();
$dialog->setInputStream($this->getInputStream($providedAnswer."\n"));
$helperSet = new HelperSet([new FormatterHelper()]);
$dialog->setHelperSet($helperSet);
$question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
$question->setMaxAttempts(1);
$answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
$this->assertSame($expectedValue, $answer);
}
/**
* @group legacy
*/
public function testLegacyAmbiguousChoiceFromChoicelist()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The provided answer is ambiguous. Value should be one of "env_2" or "env_3".');
$possibleChoices = [
'env_1' => 'My first environment',
'env_2' => 'My environment',
'env_3' => 'My environment',
];
$dialog = new QuestionHelper();
$dialog->setInputStream($this->getInputStream("My environment\n"));
$helperSet = new HelperSet([new FormatterHelper()]);
$dialog->setHelperSet($helperSet);
$question = new ChoiceQuestion('Please select the environment to load', $possibleChoices);
$question->setMaxAttempts(1);
$dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
}
/**
* @requires function mb_strwidth
* @group legacy
*/
public function testLegacyChoiceOutputFormattingQuestionForUtf8Keys()
{
$question = 'Lorem ipsum?';
$possibleChoices = [
'foo' => 'foo',
'żółw' => 'bar',
'łabądź' => 'baz',
];
$outputShown = [
$question,
' [<info>foo </info>] foo',
' [<info>żółw </info>] bar',
' [<info>łabądź</info>] baz',
];
$output = $this->getMockBuilder('\Symfony\Component\Console\Output\OutputInterface')->getMock();
$output->method('getFormatter')->willReturn(new OutputFormatter());
$dialog = new QuestionHelper();
$dialog->setInputStream($this->getInputStream("\n"));
$helperSet = new HelperSet([new FormatterHelper()]);
$dialog->setHelperSet($helperSet);
$output->expects($this->once())->method('writeln')->with($this->equalTo($outputShown));
$question = new ChoiceQuestion($question, $possibleChoices, 'foo');
$dialog->ask($this->createInputInterfaceMock(), $output, $question);
}
public function testAskThrowsExceptionOnMissingInput()
{
$this->expectException('Symfony\Component\Console\Exception\RuntimeException');
$this->expectExceptionMessage('Aborted.');
$dialog = new QuestionHelper();
$dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new Question('What\'s your name?'));
}
/**
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
* @expectedExceptionMessage Aborted.
*/
public function testAskThrowsExceptionOnMissingInputForChoiceQuestion()
{
$this->expectException('Symfony\Component\Console\Exception\RuntimeException');
$this->expectExceptionMessage('Aborted.');
$dialog = new QuestionHelper();
$dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new ChoiceQuestion('Choice', ['a', 'b']));
}
/**
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
* @expectedExceptionMessage Aborted.
*/
public function testAskThrowsExceptionOnMissingInputWithValidator()
{
$this->expectException('Symfony\Component\Console\Exception\RuntimeException');
$this->expectExceptionMessage('Aborted.');
$dialog = new QuestionHelper();
$question = new Question('What\'s your name?');
$question->setValidator(function ($value) {
$question->setValidator(function () {
if (!$value) {
throw new \Exception('A value is required.');
}
@@ -974,16 +625,18 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
$dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), $question);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Choice question must have at least 1 choice available.
*/
public function testEmptyChoices()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('Choice question must have at least 1 choice available.');
new ChoiceQuestion('Question', [], 'irrelevant');
}
public function testTraversableAutocomplete()
{
if (!Terminal::hasSttyAvailable()) {
if (!$this->hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}
@@ -1014,35 +667,6 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
$this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
}
public function testDisableStty()
{
if (!Terminal::hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('invalid');
QuestionHelper::disableStty();
$dialog = new QuestionHelper();
$dialog->setHelperSet(new HelperSet([new FormatterHelper()]));
$question = new ChoiceQuestion('Please select a bundle', [1 => 'AcmeDemoBundle', 4 => 'AsseticBundle']);
$question->setMaxAttempts(1);
// <UP ARROW><UP ARROW><NEWLINE><DOWN ARROW><DOWN ARROW><NEWLINE>
// Gives `AcmeDemoBundle` with stty
$inputStream = $this->getInputStream("\033[A\033[A\n\033[B\033[B\n");
try {
$dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question);
} finally {
$reflection = new \ReflectionProperty(QuestionHelper::class, 'stty');
$reflection->setAccessible(true);
$reflection->setValue(null, true);
}
}
public function testTraversableMultiselectAutocomplete()
{
// <NEWLINE>
@@ -1097,6 +721,13 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
return $mock;
}
private function hasSttyAvailable()
{
exec('stty 2>&1', $output, $exitcode);
return 0 === $exitcode;
}
}
class AutocompleteValues implements \IteratorAggregate
@@ -122,57 +122,16 @@ class SymfonyQuestionHelperTest extends AbstractQuestionHelperTest
$this->assertOutputContains('Question with a trailing \\', $output);
}
/**
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
* @expectedExceptionMessage Aborted.
*/
public function testAskThrowsExceptionOnMissingInput()
{
$this->expectException('Symfony\Component\Console\Exception\RuntimeException');
$this->expectExceptionMessage('Aborted.');
$dialog = new SymfonyQuestionHelper();
$dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new Question('What\'s your name?'));
}
public function testChoiceQuestionPadding()
{
$choiceQuestion = new ChoiceQuestion('qqq', [
'foo' => 'foo',
'żółw' => 'bar',
'łabądź' => 'baz',
]);
(new SymfonyQuestionHelper())->ask(
$this->createStreamableInputInterfaceMock($this->getInputStream("foo\n")),
$output = $this->createOutputInterface(),
$choiceQuestion
);
$this->assertOutputContains(<<<EOT
qqq:
[foo ] foo
[żółw ] bar
[łabądź] baz
>
EOT
, $output, true);
}
public function testChoiceQuestionCustomPrompt()
{
$choiceQuestion = new ChoiceQuestion('qqq', ['foo']);
$choiceQuestion->setPrompt(' >ccc> ');
(new SymfonyQuestionHelper())->ask(
$this->createStreamableInputInterfaceMock($this->getInputStream("foo\n")),
$output = $this->createOutputInterface(),
$choiceQuestion
);
$this->assertOutputContains(<<<EOT
qqq:
[0] foo
>ccc>
EOT
, $output, true);
}
protected function getInputStream($input)
{
$stream = fopen('php://memory', 'r+', false);
@@ -200,15 +159,10 @@ EOT
return $mock;
}
private function assertOutputContains($expected, StreamOutput $output, $normalize = false)
private function assertOutputContains($expected, StreamOutput $output)
{
rewind($output->getStream());
$stream = stream_get_contents($output->getStream());
if ($normalize) {
$stream = str_replace(\PHP_EOL, "\n", $stream);
}
$this->assertStringContainsString($expected, $stream);
$this->assertContains($expected, $stream);
}
}
+4 -2
View File
@@ -16,10 +16,12 @@ use Symfony\Component\Console\Helper\TableStyle;
class TableStyleTest extends TestCase
{
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).
*/
public function testSetPadTypeWithInvalidType()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
$style = new TableStyle();
$style->setPadType('TEST');
}
+351 -20
View File
@@ -12,10 +12,12 @@
namespace Symfony\Component\Console\Tests\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Helper\TableStyle;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\StreamOutput;
class TableTest extends TestCase
@@ -136,6 +138,45 @@ TABLE
80-902734-1-6 And Then There Were None Agatha Christie
=============== ========================== ==================
TABLE
],
[
['ISBN', 'Title', 'Author'],
$books,
'box',
<<<'TABLE'
┌───────────────┬──────────────────────────┬──────────────────┐
│ ISBN │ Title │ Author │
├───────────────┼──────────────────────────┼──────────────────┤
│ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri │
│ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens │
│ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien │
│ 80-902734-1-6 │ And Then There Were None │ Agatha Christie │
└───────────────┴──────────────────────────┴──────────────────┘
TABLE
],
[
['ISBN', 'Title', 'Author'],
[
['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'],
['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'],
new TableSeparator(),
['960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'],
['80-902734-1-6', 'And Then There Were None', 'Agatha Christie'],
],
'box-double',
<<<'TABLE'
╔═══════════════╤══════════════════════════╤══════════════════╗
║ ISBN │ Title │ Author ║
╠═══════════════╪══════════════════════════╪══════════════════╣
║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║
║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║
╟───────────────┼──────────────────────────┼──────────────────╢
║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║
║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║
╚═══════════════╧══════════════════════════╧══════════════════╝
TABLE
],
[
@@ -610,9 +651,9 @@ TABLE;
{
$style = new TableStyle();
$style
->setHorizontalBorderChar('.')
->setVerticalBorderChar('.')
->setCrossingChar('.')
->setHorizontalBorderChars('.')
->setVerticalBorderChars('.')
->setDefaultCrossingChar('.')
;
Table::setStyleDefinition('dotfull', $style);
@@ -707,7 +748,7 @@ TABLE;
]);
$style = new TableStyle();
$style->setPadType(\STR_PAD_LEFT);
$style->setPadType(STR_PAD_LEFT);
$table->setColumnStyle(3, $style);
$table->render();
@@ -726,10 +767,12 @@ TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
/**
* @expectedException \Symfony\Component\Console\Exception\InvalidArgumentException
* @expectedExceptionMessage A cell must be a TableCell, a scalar or an object implementing __toString, array given.
*/
public function testThrowsWhenTheCellInAnArray()
{
$this->expectException('Symfony\Component\Console\Exception\InvalidArgumentException');
$this->expectExceptionMessage('A cell must be a TableCell, a scalar or an object implementing "__toString()", "array" given.');
$table = new Table($output = $this->getOutputStream());
$table
->setHeaders(['ISBN', 'Title', 'Author', 'Price'])
@@ -753,7 +796,7 @@ TABLE;
->setColumnWidth(3, 10);
$style = new TableStyle();
$style->setPadType(\STR_PAD_LEFT);
$style->setPadType(STR_PAD_LEFT);
$table->setColumnStyle(3, $style);
$table->render();
@@ -784,7 +827,7 @@ TABLE;
->setColumnWidths([15, 0, -1, 10]);
$style = new TableStyle();
$style->setPadType(\STR_PAD_LEFT);
$style->setPadType(STR_PAD_LEFT);
$table->setColumnStyle(3, $style);
$table->render();
@@ -803,28 +846,264 @@ TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testSectionOutput()
{
$sections = [];
$stream = $this->getOutputStream(true);
$output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
$table = new Table($output);
$table
->setHeaders(['ISBN', 'Title', 'Author', 'Price'])
->setRows([
['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'],
]);
$table->render();
$table->appendRow(['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25']);
$expected =
<<<TABLE
+---------------+---------------+-----------------+-------+
|\033[32m ISBN \033[39m|\033[32m Title \033[39m|\033[32m Author \033[39m|\033[32m Price \033[39m|
+---------------+---------------+-----------------+-------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 9.95 |
+---------------+---------------+-----------------+-------+
\x1b[5A\x1b[0J+---------------+----------------------+-----------------+--------+
|\033[32m ISBN \033[39m|\033[32m Title \033[39m|\033[32m Author \033[39m|\033[32m Price \033[39m|
+---------------+----------------------+-----------------+--------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 9.95 |
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 139.25 |
+---------------+----------------------+-----------------+--------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testSectionOutputDoesntClearIfTableIsntRendered()
{
$sections = [];
$stream = $this->getOutputStream(true);
$output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
$table = new Table($output);
$table
->setHeaders(['ISBN', 'Title', 'Author', 'Price'])
->setRows([
['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'],
]);
$table->appendRow(['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25']);
$expected =
<<<TABLE
+---------------+----------------------+-----------------+--------+
|\033[32m ISBN \033[39m|\033[32m Title \033[39m|\033[32m Author \033[39m|\033[32m Price \033[39m|
+---------------+----------------------+-----------------+--------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 9.95 |
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 139.25 |
+---------------+----------------------+-----------------+--------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testSectionOutputWithoutDecoration()
{
$sections = [];
$stream = $this->getOutputStream();
$output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
$table = new Table($output);
$table
->setHeaders(['ISBN', 'Title', 'Author', 'Price'])
->setRows([
['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'],
]);
$table->render();
$table->appendRow(['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25']);
$expected =
<<<TABLE
+---------------+---------------+-----------------+-------+
| ISBN | Title | Author | Price |
+---------------+---------------+-----------------+-------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 9.95 |
+---------------+---------------+-----------------+-------+
+---------------+----------------------+-----------------+--------+
| ISBN | Title | Author | Price |
+---------------+----------------------+-----------------+--------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 9.95 |
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 139.25 |
+---------------+----------------------+-----------------+--------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
/**
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
* @expectedExceptionMessage Output should be an instance of "Symfony\Component\Console\Output\ConsoleSectionOutput" when calling "Symfony\Component\Console\Helper\Table::appendRow".
*/
public function testAppendRowWithoutSectionOutput()
{
$table = new Table($this->getOutputStream());
$table->appendRow(['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25']);
}
/**
* @expectedException \Symfony\Component\Console\Exception\InvalidArgumentException
* @expectedExceptionMessage Style "absent" is not defined.
*/
public function testIsNotDefinedStyleException()
{
$this->expectException('Symfony\Component\Console\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Style "absent" is not defined.');
$table = new Table($this->getOutputStream());
$table->setStyle('absent');
}
/**
* @expectedException \Symfony\Component\Console\Exception\InvalidArgumentException
* @expectedExceptionMessage Style "absent" is not defined.
*/
public function testGetStyleDefinition()
{
$this->expectException('Symfony\Component\Console\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Style "absent" is not defined.');
Table::getStyleDefinition('absent');
}
/**
* @dataProvider renderSetTitle
*/
public function testSetTitle($headerTitle, $footerTitle, $style, $expected)
{
(new Table($output = $this->getOutputStream()))
->setHeaderTitle($headerTitle)
->setFooterTitle($footerTitle)
->setHeaders(['ISBN', 'Title', 'Author'])
->setRows([
['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'],
['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'],
['960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'],
['80-902734-1-6', 'And Then There Were None', 'Agatha Christie'],
])
->setStyle($style)
->render()
;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function renderSetTitle()
{
return [
[
'Books',
'Page 1/2',
'default',
<<<'TABLE'
+---------------+----------- Books --------+------------------+
| ISBN | Title | Author |
+---------------+--------------------------+------------------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri |
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
| 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
| 80-902734-1-6 | And Then There Were None | Agatha Christie |
+---------------+--------- Page 1/2 -------+------------------+
TABLE
],
[
'Books',
'Page 1/2',
'box',
<<<'TABLE'
┌───────────────┬─────────── Books ────────┬──────────────────┐
│ ISBN │ Title │ Author │
├───────────────┼──────────────────────────┼──────────────────┤
│ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri │
│ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens │
│ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien │
│ 80-902734-1-6 │ And Then There Were None │ Agatha Christie │
└───────────────┴───────── Page 1/2 ───────┴──────────────────┘
TABLE
],
[
'Boooooooooooooooooooooooooooooooooooooooooooooooooooooooks',
'Page 1/999999999999999999999999999999999999999999999999999',
'default',
<<<'TABLE'
+- Booooooooooooooooooooooooooooooooooooooooooooooooooooo... -+
| ISBN | Title | Author |
+---------------+--------------------------+------------------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri |
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
| 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
| 80-902734-1-6 | And Then There Were None | Agatha Christie |
+- Page 1/99999999999999999999999999999999999999999999999... -+
TABLE
],
];
}
public function testColumnMaxWidths()
{
$table = new Table($output = $this->getOutputStream());
$table
->setRows([
['Divine Comedy', 'A Tale of Two Cities', 'The Lord of the Rings', 'And Then There Were None'],
])
->setColumnMaxWidth(1, 5)
->setColumnMaxWidth(2, 10)
->setColumnMaxWidth(3, 15);
$table->render();
$expected =
<<<TABLE
+---------------+-------+------------+-----------------+
| Divine Comedy | A Tal | The Lord o | And Then There |
| | e of | f the Ring | Were None |
| | Two C | s | |
| | ities | | |
+---------------+-------+------------+-----------------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testColumnMaxWidthsWithTrailingBackslash()
{
(new Table($output = $this->getOutputStream()))
->setColumnMaxWidth(0, 5)
->setRows([['1234\6']])
->render()
;
$expected =
<<<'TABLE'
+-------+
| 1234\ |
| 6 |
+-------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testBoxedStyleWithColspan()
{
$boxed = new TableStyle();
$boxed
->setHorizontalBorderChar('─')
->setVerticalBorderChar('│')
->setCrossingChar('┼')
->setHorizontalBorderChars('─')
->setVerticalBorderChars('│')
->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├')
;
$table = new Table($output = $this->getOutputStream());
@@ -841,13 +1120,13 @@ TABLE;
$expected =
<<<TABLE
───────────────────────────────────────────────
───────────────────────────────────────────────
│ ISBN │ Title │ Author │
───────────────┼───────────────┼─────────────────
───────────────┼───────────────┼─────────────────
│ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri │
───────────────┼───────────────┼─────────────────
───────────────┼───────────────┼─────────────────
│ This value spans 3 columns. │
───────────────────────────────────────────────
───────────────────────────────────────────────
TABLE;
@@ -863,6 +1142,58 @@ TABLE;
{
rewind($output->getStream());
return str_replace(\PHP_EOL, "\n", stream_get_contents($output->getStream()));
return str_replace(PHP_EOL, "\n", stream_get_contents($output->getStream()));
}
public function testWithColspanAndMaxWith(): void
{
$table = new Table($output = $this->getOutputStream());
$table->setColumnMaxWidth(0, 15);
$table->setColumnMaxWidth(1, 15);
$table->setColumnMaxWidth(2, 15);
$table->setRows([
[new TableCell('Lorem ipsum dolor sit amet, <fg=white;bg=green>consectetur</> adipiscing elit, <fg=white;bg=red>sed</> do <fg=white;bg=red>eiusmod</> tempor', ['colspan' => 3])],
new TableSeparator(),
[new TableCell('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor', ['colspan' => 3])],
new TableSeparator(),
[new TableCell('Lorem ipsum <fg=white;bg=red>dolor</> sit amet, consectetur ', ['colspan' => 2]), 'hello world'],
new TableSeparator(),
['hello <fg=white;bg=green>world</>', new TableCell('Lorem ipsum dolor sit amet, <fg=white;bg=green>consectetur</> adipiscing elit', ['colspan' => 2])],
new TableSeparator(),
['hello ', new TableCell('world', ['colspan' => 1]), 'Lorem ipsum dolor sit amet, consectetur'],
new TableSeparator(),
['Symfony ', new TableCell('Test', ['colspan' => 1]), 'Lorem <fg=white;bg=green>ipsum</> dolor sit amet, consectetur'],
])
;
$table->render();
$expected =
<<<TABLE
+-----------------+-----------------+-----------------+
| Lorem ipsum dolor sit amet, consectetur adipi |
| scing elit, sed do eiusmod tempor |
+-----------------+-----------------+-----------------+
| Lorem ipsum dolor sit amet, consectetur adipi |
| scing elit, sed do eiusmod tempor |
+-----------------+-----------------+-----------------+
| Lorem ipsum dolor sit amet, co | hello world |
| nsectetur | |
+-----------------+-----------------+-----------------+
| hello world | Lorem ipsum dolor sit amet, co |
| | nsectetur adipiscing elit |
+-----------------+-----------------+-----------------+
| hello | world | Lorem ipsum dol |
| | | or sit amet, co |
| | | nsectetur |
+-----------------+-----------------+-----------------+
| Symfony | Test | Lorem ipsum dol |
| | | or sit amet, co |
| | | nsectetur |
+-----------------+-----------------+-----------------+
TABLE;
$this->assertSame($expected, $this->getOutputContent($output));
}
}
+6 -2
View File
@@ -182,8 +182,12 @@ class ArgvInputTest extends TestCase
*/
public function testInvalidInput($argv, $definition, $expectedExceptionMessage)
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage($expectedExceptionMessage);
if (method_exists($this, 'expectException')) {
$this->expectException('RuntimeException');
$this->expectExceptionMessage($expectedExceptionMessage);
} else {
$this->setExpectedException('RuntimeException', $expectedExceptionMessage);
}
$input = new ArgvInput($argv);
$input->bind($definition);
+6 -2
View File
@@ -127,8 +127,12 @@ class ArrayInputTest extends TestCase
*/
public function testParseInvalidInput($parameters, $definition, $expectedExceptionMessage)
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage($expectedExceptionMessage);
if (method_exists($this, 'expectException')) {
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage($expectedExceptionMessage);
} else {
$this->setExpectedException('InvalidArgumentException', $expectedExceptionMessage);
}
new ArrayInput($parameters, $definition);
}
+12 -18
View File
@@ -38,22 +38,12 @@ class InputArgumentTest extends TestCase
}
/**
* @dataProvider provideInvalidModes
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Argument mode "-1" is not valid.
*/
public function testInvalidModes($mode)
public function testInvalidModes()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage(sprintf('Argument mode "%s" is not valid.', $mode));
new InputArgument('foo', $mode);
}
public function provideInvalidModes()
{
return [
['ANOTHER_ONE'],
[-1],
];
new InputArgument('foo', '-1');
}
public function testIsArray()
@@ -91,18 +81,22 @@ class InputArgumentTest extends TestCase
$this->assertEquals([1, 2], $argument->getDefault(), '->setDefault() changes the default value');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot set a default value except for InputArgument::OPTIONAL mode.
*/
public function testSetDefaultWithRequiredArgument()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('Cannot set a default value except for InputArgument::OPTIONAL mode.');
$argument = new InputArgument('foo', InputArgument::REQUIRED);
$argument->setDefault('default');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage A default value for an array argument must be an array.
*/
public function testSetDefaultWithArrayArgument()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('A default value for an array argument must be an array.');
$argument = new InputArgument('foo', InputArgument::IS_ARRAY);
$argument->setDefault('default');
}
+39 -21
View File
@@ -20,7 +20,6 @@ class InputDefinitionTest extends TestCase
{
protected static $fixtures;
protected $multi;
protected $foo;
protected $bar;
protected $foo1;
@@ -87,10 +86,12 @@ class InputDefinitionTest extends TestCase
$this->assertEquals(['foo' => $this->foo, 'bar' => $this->bar], $definition->getArguments(), '->addArgument() adds a InputArgument object');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage An argument with name "foo" already exists.
*/
public function testArgumentsMustHaveDifferentNames()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('An argument with name "foo" already exists.');
$this->initializeArguments();
$definition = new InputDefinition();
@@ -98,10 +99,12 @@ class InputDefinitionTest extends TestCase
$definition->addArgument($this->foo1);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot add an argument after an array argument.
*/
public function testArrayArgumentHasToBeLast()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('Cannot add an argument after an array argument.');
$this->initializeArguments();
$definition = new InputDefinition();
@@ -109,10 +112,12 @@ class InputDefinitionTest extends TestCase
$definition->addArgument(new InputArgument('anotherbar'));
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot add a required argument after an optional one.
*/
public function testRequiredArgumentCannotFollowAnOptionalOne()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('Cannot add a required argument after an optional one.');
$this->initializeArguments();
$definition = new InputDefinition();
@@ -129,10 +134,12 @@ class InputDefinitionTest extends TestCase
$this->assertEquals($this->foo, $definition->getArgument('foo'), '->getArgument() returns a InputArgument by its name');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The "bar" argument does not exist.
*/
public function testGetInvalidArgument()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The "bar" argument does not exist.');
$this->initializeArguments();
$definition = new InputDefinition();
@@ -199,10 +206,12 @@ class InputDefinitionTest extends TestCase
$this->assertEquals(['bar' => $this->bar], $definition->getOptions(), '->setOptions() clears all InputOption objects');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The "-f" option does not exist.
*/
public function testSetOptionsClearsOptions()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The "-f" option does not exist.');
$this->initializeOptions();
$definition = new InputDefinition([$this->foo]);
@@ -231,10 +240,12 @@ class InputDefinitionTest extends TestCase
$this->assertEquals(['foo' => $this->foo, 'bar' => $this->bar], $definition->getOptions(), '->addOption() adds a InputOption object');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage An option named "foo" already exists.
*/
public function testAddDuplicateOption()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('An option named "foo" already exists.');
$this->initializeOptions();
$definition = new InputDefinition();
@@ -242,10 +253,12 @@ class InputDefinitionTest extends TestCase
$definition->addOption($this->foo2);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage An option with shortcut "f" already exists.
*/
public function testAddDuplicateShortcutOption()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('An option with shortcut "f" already exists.');
$this->initializeOptions();
$definition = new InputDefinition();
@@ -261,10 +274,12 @@ class InputDefinitionTest extends TestCase
$this->assertEquals($this->foo, $definition->getOption('foo'), '->getOption() returns a InputOption by its name');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The "--bar" option does not exist.
*/
public function testGetInvalidOption()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The "--bar" option does not exist.');
$this->initializeOptions();
$definition = new InputDefinition([$this->foo]);
@@ -306,10 +321,12 @@ class InputDefinitionTest extends TestCase
$this->assertEquals($this->multi, $definition->getOptionForShortcut('mmm'), '->getOptionForShortcut() returns a InputOption by its shortcut');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The "-l" option does not exist.
*/
public function testGetOptionForInvalidShortcut()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The "-l" option does not exist.');
$this->initializeOptions();
$definition = new InputDefinition([$this->foo]);
@@ -357,8 +374,9 @@ class InputDefinitionTest extends TestCase
[new InputDefinition([new InputArgument('foo', InputArgument::REQUIRED)]), '<foo>', 'puts arguments in angle brackets'],
[new InputDefinition([new InputArgument('foo')]), '[<foo>]', 'puts optional arguments in square brackets'],
[new InputDefinition([new InputArgument('foo', InputArgument::IS_ARRAY)]), '[<foo>]...', 'uses an ellipsis for array arguments'],
[new InputDefinition([new InputArgument('foo', InputArgument::REQUIRED | InputArgument::IS_ARRAY)]), '<foo> (<foo>)...', 'uses parenthesis and ellipsis for required array arguments'],
[new InputDefinition([new InputArgument('foo'), new InputArgument('bar')]), '[<foo> [<bar>]]', 'chains optional arguments inside brackets'],
[new InputDefinition([new InputArgument('foo', InputArgument::IS_ARRAY)]), '[<foo>...]', 'uses an ellipsis for array arguments'],
[new InputDefinition([new InputArgument('foo', InputArgument::REQUIRED | InputArgument::IS_ARRAY)]), '<foo>...', 'uses an ellipsis for required array arguments'],
[new InputDefinition([new InputOption('foo'), new InputArgument('foo', InputArgument::REQUIRED)]), '[--foo] [--] <foo>', 'puts [--] between options and arguments'],
];
+25 -23
View File
@@ -24,10 +24,12 @@ class InputOptionTest extends TestCase
$this->assertEquals('foo', $option->getName(), '__construct() removes the leading -- of the option name');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.
*/
public function testArrayModeWithoutValue()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
new InputOption('foo', 'f', InputOption::VALUE_IS_ARRAY);
}
@@ -72,39 +74,35 @@ class InputOptionTest extends TestCase
}
/**
* @dataProvider provideInvalidModes
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Option mode "-1" is not valid.
*/
public function testInvalidModes($mode)
public function testInvalidModes()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage(sprintf('Option mode "%s" is not valid.', $mode));
new InputOption('foo', 'f', $mode);
}
public function provideInvalidModes()
{
return [
['ANOTHER_ONE'],
[-1],
];
new InputOption('foo', 'f', '-1');
}
/**
* @expectedException \InvalidArgumentException
*/
public function testEmptyNameIsInvalid()
{
$this->expectException('InvalidArgumentException');
new InputOption('');
}
/**
* @expectedException \InvalidArgumentException
*/
public function testDoubleDashNameIsInvalid()
{
$this->expectException('InvalidArgumentException');
new InputOption('--');
}
/**
* @expectedException \InvalidArgumentException
*/
public function testSingleDashOptionIsInvalid()
{
$this->expectException('InvalidArgumentException');
new InputOption('foo', '-');
}
@@ -153,18 +151,22 @@ class InputOptionTest extends TestCase
$this->assertEquals([1, 2], $option->getDefault(), '->setDefault() changes the default value');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot set a default value when using InputOption::VALUE_NONE mode.
*/
public function testDefaultValueWithValueNoneMode()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('Cannot set a default value when using InputOption::VALUE_NONE mode.');
$option = new InputOption('foo', 'f', InputOption::VALUE_NONE);
$option->setDefault('default');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage A default value for an array option must be an array.
*/
public function testDefaultValueWithIsArrayMode()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('A default value for an array option must be an array.');
$option = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY);
$option->setDefault('default');
}
+24 -12
View File
@@ -47,18 +47,22 @@ class InputTest extends TestCase
$this->assertEquals(['name' => 'foo', 'bar' => null], $input->getOptions(), '->getOptions() returns all option values');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The "foo" option does not exist.
*/
public function testSetInvalidOption()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The "foo" option does not exist.');
$input = new ArrayInput(['--name' => 'foo'], new InputDefinition([new InputOption('name'), new InputOption('bar', '', InputOption::VALUE_OPTIONAL, '', 'default')]));
$input->setOption('foo', 'bar');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The "foo" option does not exist.
*/
public function testGetInvalidOption()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The "foo" option does not exist.');
$input = new ArrayInput(['--name' => 'foo'], new InputDefinition([new InputOption('name'), new InputOption('bar', '', InputOption::VALUE_OPTIONAL, '', 'default')]));
$input->getOption('foo');
}
@@ -77,35 +81,43 @@ class InputTest extends TestCase
$this->assertEquals(['name' => 'foo', 'bar' => 'default'], $input->getArguments(), '->getArguments() returns all argument values, even optional ones');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The "foo" argument does not exist.
*/
public function testSetInvalidArgument()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The "foo" argument does not exist.');
$input = new ArrayInput(['name' => 'foo'], new InputDefinition([new InputArgument('name'), new InputArgument('bar', InputArgument::OPTIONAL, '', 'default')]));
$input->setArgument('foo', 'bar');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The "foo" argument does not exist.
*/
public function testGetInvalidArgument()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The "foo" argument does not exist.');
$input = new ArrayInput(['name' => 'foo'], new InputDefinition([new InputArgument('name'), new InputArgument('bar', InputArgument::OPTIONAL, '', 'default')]));
$input->getArgument('foo');
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Not enough arguments (missing: "name").
*/
public function testValidateWithMissingArguments()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('Not enough arguments (missing: "name").');
$input = new ArrayInput([]);
$input->bind(new InputDefinition([new InputArgument('name', InputArgument::REQUIRED)]));
$input->validate();
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Not enough arguments (missing: "name").
*/
public function testValidateWithMissingRequiredArguments()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('Not enough arguments (missing: "name").');
$input = new ArrayInput(['bar' => 'baz']);
$input->bind(new InputDefinition([new InputArgument('name', InputArgument::REQUIRED), new InputArgument('bar', InputArgument::OPTIONAL)]));
$input->validate();
+5 -3
View File
@@ -70,7 +70,7 @@ class ConsoleLoggerTest extends TestCase
$logger = new ConsoleLogger($out, $addVerbosityLevelMap);
$logger->log($logLevel, 'foo bar');
$logs = $out->fetch();
$this->assertEquals($isOutput ? "[$logLevel] foo bar".\PHP_EOL : '', $logs);
$this->assertEquals($isOutput ? "[$logLevel] foo bar".PHP_EOL : '', $logs);
}
public function provideOutputMappingParams()
@@ -141,9 +141,11 @@ class ConsoleLoggerTest extends TestCase
];
}
/**
* @expectedException \Psr\Log\InvalidArgumentException
*/
public function testThrowsOnInvalidLevel()
{
$this->expectException('Psr\Log\InvalidArgumentException');
$logger = $this->getLogger();
$logger->log('invalid level', 'Foo');
}
@@ -162,7 +164,7 @@ class ConsoleLoggerTest extends TestCase
if (method_exists($this, 'createPartialMock')) {
$dummy = $this->createPartialMock('Symfony\Component\Console\Tests\Logger\DummyTest', ['__toString']);
} else {
$dummy = $this->createPartialMock('Symfony\Component\Console\Tests\Logger\DummyTest', ['__toString']);
$dummy = $this->getMock('Symfony\Component\Console\Tests\Logger\DummyTest', ['__toString']);
}
$dummy->method('__toString')->willReturn('DUMMY');
+13
View File
@@ -81,6 +81,19 @@ class OutputTest extends TestCase
$this->assertEquals("foo\nbar\n", $output->output, '->writeln() can take an array of messages to output');
}
public function testWriteAnIterableOfMessages()
{
$output = new TestOutput();
$output->writeln($this->generateMessages());
$this->assertEquals("foo\nbar\n", $output->output, '->writeln() can take an iterable of messages to output');
}
private function generateMessages(): iterable
{
yield 'foo';
yield 'bar';
}
/**
* @dataProvider provideWriteArguments
*/
+5 -11
View File
@@ -36,10 +36,12 @@ class StreamOutputTest extends TestCase
$this->assertTrue($output->isDecorated(), '__construct() takes the decorated flag as its second argument');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The StreamOutput class needs a stream as its first argument.
*/
public function testStreamIsRequired()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The StreamOutput class needs a stream as its first argument.');
new StreamOutput('foo');
}
@@ -54,14 +56,6 @@ class StreamOutputTest extends TestCase
$output = new StreamOutput($this->stream);
$output->writeln('foo');
rewind($output->getStream());
$this->assertEquals('foo'.\PHP_EOL, stream_get_contents($output->getStream()), '->doWrite() writes to the stream');
}
public function testDoWriteOnFailure()
{
$resource = fopen(__DIR__.'/../Fixtures/stream_output_file.txt', 'r', false);
$output = new StreamOutput($resource);
rewind($output->getStream());
$this->assertEquals('', stream_get_contents($output->getStream()));
$this->assertEquals('foo'.PHP_EOL, stream_get_contents($output->getStream()), '->doWrite() writes to the stream');
}
}
+1 -39
View File
@@ -18,31 +18,17 @@ class TerminalTest extends TestCase
{
private $colSize;
private $lineSize;
private $ansiCon;
protected function setUp()
{
$this->colSize = getenv('COLUMNS');
$this->lineSize = getenv('LINES');
$this->ansiCon = getenv('ANSICON');
$this->resetStatics();
}
protected function tearDown()
{
putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS');
putenv($this->lineSize ? 'LINES' : 'LINES='.$this->lineSize);
putenv($this->ansiCon ? 'ANSICON='.$this->ansiCon : 'ANSICON');
$this->resetStatics();
}
private function resetStatics()
{
foreach (['height', 'width', 'stty'] as $name) {
$property = new \ReflectionProperty(Terminal::class, $name);
$property->setAccessible(true);
$property->setValue(null);
}
}
public function test()
@@ -60,7 +46,7 @@ class TerminalTest extends TestCase
$this->assertSame(60, $terminal->getHeight());
}
public function testZeroValues()
public function test_zero_values()
{
putenv('COLUMNS=0');
putenv('LINES=0');
@@ -70,28 +56,4 @@ class TerminalTest extends TestCase
$this->assertSame(0, $terminal->getWidth());
$this->assertSame(0, $terminal->getHeight());
}
public function testSttyOnWindows()
{
if ('\\' !== \DIRECTORY_SEPARATOR) {
$this->markTestSkipped('Must be on windows');
}
$sttyString = exec('(stty -a | grep columns) 2>&1', $output, $exitcode);
if (0 !== $exitcode) {
$this->markTestSkipped('Must have stty support');
}
$matches = [];
if (0 === preg_match('/columns.(\d+)/i', $sttyString, $matches)) {
$this->fail('Could not determine existing stty columns');
}
putenv('COLUMNS');
putenv('LINES');
putenv('ANSICON');
$terminal = new Terminal();
$this->assertSame((int) $matches[1], $terminal->getWidth());
}
}
@@ -13,7 +13,9 @@ namespace Symfony\Component\Console\Tests\Tester;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Output\Output;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Tester\ApplicationTester;
class ApplicationTesterTest extends TestCase
@@ -27,7 +29,9 @@ class ApplicationTesterTest extends TestCase
$this->application->setAutoExit(false);
$this->application->register('foo')
->addArgument('foo')
->setCode(function ($input, $output) { $output->writeln('foo'); })
->setCode(function ($input, $output) {
$output->writeln('foo');
})
;
$this->tester = new ApplicationTester($this->application);
@@ -55,16 +59,55 @@ class ApplicationTesterTest extends TestCase
public function testGetOutput()
{
rewind($this->tester->getOutput()->getStream());
$this->assertEquals('foo'.\PHP_EOL, stream_get_contents($this->tester->getOutput()->getStream()), '->getOutput() returns the current output instance');
$this->assertEquals('foo'.PHP_EOL, stream_get_contents($this->tester->getOutput()->getStream()), '->getOutput() returns the current output instance');
}
public function testGetDisplay()
{
$this->assertEquals('foo'.\PHP_EOL, $this->tester->getDisplay(), '->getDisplay() returns the display of the last execution');
$this->assertEquals('foo'.PHP_EOL, $this->tester->getDisplay(), '->getDisplay() returns the display of the last execution');
}
public function testSetInputs()
{
$application = new Application();
$application->setAutoExit(false);
$application->register('foo')->setCode(function ($input, $output) {
$helper = new QuestionHelper();
$helper->ask($input, $output, new Question('Q1'));
$helper->ask($input, $output, new Question('Q2'));
$helper->ask($input, $output, new Question('Q3'));
});
$tester = new ApplicationTester($application);
$tester->setInputs(['I1', 'I2', 'I3']);
$tester->run(['command' => 'foo']);
$this->assertSame(0, $tester->getStatusCode());
$this->assertEquals('Q1Q2Q3', $tester->getDisplay(true));
}
public function testGetStatusCode()
{
$this->assertSame(0, $this->tester->getStatusCode(), '->getStatusCode() returns the status code');
}
public function testErrorOutput()
{
$application = new Application();
$application->setAutoExit(false);
$application->register('foo')
->addArgument('foo')
->setCode(function ($input, $output) {
$output->getErrorOutput()->write('foo');
})
;
$tester = new ApplicationTester($application);
$tester->run(
['command' => 'foo', 'foo' => 'bar'],
['capture_stderr_separately' => true]
);
$this->assertSame('foo', $tester->getErrorOutput());
}
}
+30 -7
View File
@@ -59,12 +59,12 @@ class CommandTesterTest extends TestCase
public function testGetOutput()
{
rewind($this->tester->getOutput()->getStream());
$this->assertEquals('foo'.\PHP_EOL, stream_get_contents($this->tester->getOutput()->getStream()), '->getOutput() returns the current output instance');
$this->assertEquals('foo'.PHP_EOL, stream_get_contents($this->tester->getOutput()->getStream()), '->getOutput() returns the current output instance');
}
public function testGetDisplay()
{
$this->assertEquals('foo'.\PHP_EOL, $this->tester->getDisplay(), '->getDisplay() returns the display of the last execution');
$this->assertEquals('foo'.PHP_EOL, $this->tester->getDisplay(), '->getDisplay() returns the display of the last execution');
}
public function testGetStatusCode()
@@ -138,10 +138,12 @@ class CommandTesterTest extends TestCase
$this->assertEquals(implode('', $questions), $tester->getDisplay(true));
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Aborted.
*/
public function testCommandWithWrongInputsNumber()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('Aborted.');
$questions = [
'What\'s your name?',
'How are you?',
@@ -163,10 +165,12 @@ class CommandTesterTest extends TestCase
$tester->execute([]);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Aborted.
*/
public function testCommandWithQuestionsButNoInputs()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('Aborted.');
$questions = [
'What\'s your name?',
'How are you?',
@@ -196,7 +200,7 @@ class CommandTesterTest extends TestCase
];
$command = new Command('foo');
$command->setCode(function ($input, $output) use ($questions) {
$command->setCode(function ($input, $output) use ($questions, $command) {
$io = new SymfonyStyle($input, $output);
$io->ask($questions[0]);
$io->ask($questions[1]);
@@ -209,4 +213,23 @@ class CommandTesterTest extends TestCase
$this->assertEquals(0, $tester->getStatusCode());
}
public function testErrorOutput()
{
$command = new Command('foo');
$command->addArgument('command');
$command->addArgument('foo');
$command->setCode(function ($input, $output) {
$output->getErrorOutput()->write('foo');
}
);
$tester = new CommandTester($command);
$tester->execute(
['foo' => 'bar'],
['capture_stderr_separately' => true]
);
$this->assertSame('foo', $tester->getErrorOutput());
}
}