Update Composer, update everything

This commit is contained in:
Oliver Davies 2018-11-23 12:29:20 +00:00
parent ea3e94409f
commit dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions

View file

@ -0,0 +1,34 @@
<?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\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Input\StreamableInputInterface;
abstract class AbstractQuestionHelperTest extends TestCase
{
protected function createStreamableInputInterfaceMock($stream = null, $interactive = true)
{
$mock = $this->getMockBuilder(StreamableInputInterface::class)->getMock();
$mock->expects($this->any())
->method('isInteractive')
->will($this->returnValue($interactive));
if ($stream) {
$mock->expects($this->any())
->method('getStream')
->willReturn($stream);
}
return $mock;
}
}

View file

@ -0,0 +1,129 @@
<?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\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Helper\FormatterHelper;
class FormatterHelperTest extends TestCase
{
public function testFormatSection()
{
$formatter = new FormatterHelper();
$this->assertEquals(
'<info>[cli]</info> Some text to display',
$formatter->formatSection('cli', 'Some text to display'),
'::formatSection() formats a message in a section'
);
}
public function testFormatBlock()
{
$formatter = new FormatterHelper();
$this->assertEquals(
'<error> Some text to display </error>',
$formatter->formatBlock('Some text to display', 'error'),
'::formatBlock() formats a message in a block'
);
$this->assertEquals(
'<error> Some text to display </error>'."\n".
'<error> foo bar </error>',
$formatter->formatBlock(array('Some text to display', 'foo bar'), 'error'),
'::formatBlock() formats a message in a block'
);
$this->assertEquals(
'<error> </error>'."\n".
'<error> Some text to display </error>'."\n".
'<error> </error>',
$formatter->formatBlock('Some text to display', 'error', true),
'::formatBlock() formats a message in a block'
);
}
public function testFormatBlockWithDiacriticLetters()
{
$formatter = new FormatterHelper();
$this->assertEquals(
'<error> </error>'."\n".
'<error> Du texte à afficher </error>'."\n".
'<error> </error>',
$formatter->formatBlock('Du texte à afficher', 'error', true),
'::formatBlock() formats a message in a block'
);
}
public function testFormatBlockWithDoubleWidthDiacriticLetters()
{
$formatter = new FormatterHelper();
$this->assertEquals(
'<error> </error>'."\n".
'<error> 表示するテキスト </error>'."\n".
'<error> </error>',
$formatter->formatBlock('表示するテキスト', 'error', true),
'::formatBlock() formats a message in a block'
);
}
public function testFormatBlockLGEscaping()
{
$formatter = new FormatterHelper();
$this->assertEquals(
'<error> </error>'."\n".
'<error> \<info>some info\</info> </error>'."\n".
'<error> </error>',
$formatter->formatBlock('<info>some info</info>', 'error', true),
'::formatBlock() escapes \'<\' chars'
);
}
public function testTruncatingWithShorterLengthThanMessageWithSuffix()
{
$formatter = new FormatterHelper();
$message = 'testing truncate';
$this->assertSame('test...', $formatter->truncate($message, 4));
$this->assertSame('testing truncat...', $formatter->truncate($message, 15));
$this->assertSame('testing truncate...', $formatter->truncate($message, 16));
$this->assertSame('zażółć gęślą...', $formatter->truncate('zażółć gęślą jaźń', 12));
}
public function testTruncatingMessageWithCustomSuffix()
{
$formatter = new FormatterHelper();
$message = 'testing truncate';
$this->assertSame('test!', $formatter->truncate($message, 4, '!'));
}
public function testTruncatingWithLongerLengthThanMessageWithSuffix()
{
$formatter = new FormatterHelper();
$message = 'test';
$this->assertSame($message, $formatter->truncate($message, 10));
}
public function testTruncatingWithNegativeLength()
{
$formatter = new FormatterHelper();
$message = 'testing truncate';
$this->assertSame('testing tru...', $formatter->truncate($message, -5));
$this->assertSame('...', $formatter->truncate($message, -100));
}
}

View file

@ -0,0 +1,127 @@
<?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\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\HelperSet;
class HelperSetTest extends TestCase
{
public function testConstructor()
{
$mock_helper = $this->getGenericMockHelper('fake_helper');
$helperset = new HelperSet(array('fake_helper_alias' => $mock_helper));
$this->assertEquals($mock_helper, $helperset->get('fake_helper_alias'), '__construct sets given helper to helpers');
$this->assertTrue($helperset->has('fake_helper_alias'), '__construct sets helper alias for given helper');
}
public function testSet()
{
$helperset = new HelperSet();
$helperset->set($this->getGenericMockHelper('fake_helper', $helperset));
$this->assertTrue($helperset->has('fake_helper'), '->set() adds helper to helpers');
$helperset = new HelperSet();
$helperset->set($this->getGenericMockHelper('fake_helper_01', $helperset));
$helperset->set($this->getGenericMockHelper('fake_helper_02', $helperset));
$this->assertTrue($helperset->has('fake_helper_01'), '->set() will set multiple helpers on consecutive calls');
$this->assertTrue($helperset->has('fake_helper_02'), '->set() will set multiple helpers on consecutive calls');
$helperset = new HelperSet();
$helperset->set($this->getGenericMockHelper('fake_helper', $helperset), 'fake_helper_alias');
$this->assertTrue($helperset->has('fake_helper'), '->set() adds helper alias when set');
$this->assertTrue($helperset->has('fake_helper_alias'), '->set() adds helper alias when set');
}
public function testHas()
{
$helperset = new HelperSet(array('fake_helper_alias' => $this->getGenericMockHelper('fake_helper')));
$this->assertTrue($helperset->has('fake_helper'), '->has() finds set helper');
$this->assertTrue($helperset->has('fake_helper_alias'), '->has() finds set helper by alias');
}
public function testGet()
{
$helper_01 = $this->getGenericMockHelper('fake_helper_01');
$helper_02 = $this->getGenericMockHelper('fake_helper_02');
$helperset = new HelperSet(array('fake_helper_01_alias' => $helper_01, 'fake_helper_02_alias' => $helper_02));
$this->assertEquals($helper_01, $helperset->get('fake_helper_01'), '->get() returns correct helper by name');
$this->assertEquals($helper_01, $helperset->get('fake_helper_01_alias'), '->get() returns correct helper by alias');
$this->assertEquals($helper_02, $helperset->get('fake_helper_02'), '->get() returns correct helper by name');
$this->assertEquals($helper_02, $helperset->get('fake_helper_02_alias'), '->get() returns correct helper by alias');
$helperset = new HelperSet();
try {
$helperset->get('foo');
$this->fail('->get() throws InvalidArgumentException when helper not found');
} 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->assertContains('The helper "foo" is not defined.', $e->getMessage(), '->get() throws InvalidArgumentException when helper not found');
}
}
public function testSetCommand()
{
$cmd_01 = new Command('foo');
$cmd_02 = new Command('bar');
$helperset = new HelperSet();
$helperset->setCommand($cmd_01);
$this->assertEquals($cmd_01, $helperset->getCommand(), '->setCommand() stores given command');
$helperset = new HelperSet();
$helperset->setCommand($cmd_01);
$helperset->setCommand($cmd_02);
$this->assertEquals($cmd_02, $helperset->getCommand(), '->setCommand() overwrites stored command with consecutive calls');
}
public function testGetCommand()
{
$cmd = new Command('foo');
$helperset = new HelperSet();
$helperset->setCommand($cmd);
$this->assertEquals($cmd, $helperset->getCommand(), '->getCommand() retrieves stored command');
}
public function testIteration()
{
$helperset = new HelperSet();
$helperset->set($this->getGenericMockHelper('fake_helper_01', $helperset));
$helperset->set($this->getGenericMockHelper('fake_helper_02', $helperset));
$helpers = array('fake_helper_01', 'fake_helper_02');
$i = 0;
foreach ($helperset as $helper) {
$this->assertEquals($helpers[$i++], $helper->getName());
}
}
private function getGenericMockHelper($name, HelperSet $helperset = null)
{
$mock_helper = $this->getMockBuilder('\Symfony\Component\Console\Helper\HelperInterface')->getMock();
$mock_helper->expects($this->any())
->method('getName')
->will($this->returnValue($name));
if ($helperset) {
$mock_helper->expects($this->any())
->method('setHelperSet')
->with($this->equalTo($helperset));
}
return $mock_helper;
}
}

View file

@ -0,0 +1,55 @@
<?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\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Helper\Helper;
class HelperTest extends TestCase
{
public function formatTimeProvider()
{
return array(
array(0, '< 1 sec'),
array(1, '1 sec'),
array(2, '2 secs'),
array(59, '59 secs'),
array(60, '1 min'),
array(61, '1 min'),
array(119, '1 min'),
array(120, '2 mins'),
array(121, '2 mins'),
array(3599, '59 mins'),
array(3600, '1 hr'),
array(7199, '1 hr'),
array(7200, '2 hrs'),
array(7201, '2 hrs'),
array(86399, '23 hrs'),
array(86400, '1 day'),
array(86401, '1 day'),
array(172799, '1 day'),
array(172800, '2 days'),
array(172801, '2 days'),
);
}
/**
* @dataProvider formatTimeProvider
*
* @param int $secs
* @param string $expectedFormat
*/
public function testFormatTime($secs, $expectedFormat)
{
$this->assertEquals($expectedFormat, Helper::formatTime($secs));
}
}

View file

@ -0,0 +1,118 @@
<?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\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Helper\DebugFormatterHelper;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\ProcessHelper;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Process\Process;
class ProcessHelperTest extends TestCase
{
/**
* @dataProvider provideCommandsAndOutput
*/
public function testVariousProcessRuns($expected, $cmd, $verbosity, $error)
{
$helper = new ProcessHelper();
$helper->setHelperSet(new HelperSet(array(new DebugFormatterHelper())));
$output = $this->getOutputStream($verbosity);
$helper->run($output, $cmd, $error);
$this->assertEquals($expected, $this->getOutput($output));
}
public function testPassedCallbackIsExecuted()
{
$helper = new ProcessHelper();
$helper->setHelperSet(new HelperSet(array(new DebugFormatterHelper())));
$output = $this->getOutputStream(StreamOutput::VERBOSITY_NORMAL);
$executed = false;
$callback = function () use (&$executed) { $executed = true; };
$helper->run($output, 'php -r "echo 42;"', null, $callback);
$this->assertTrue($executed);
}
public function provideCommandsAndOutput()
{
$successOutputVerbose = <<<'EOT'
RUN php -r "echo 42;"
RES Command ran successfully
EOT;
$successOutputDebug = <<<'EOT'
RUN php -r "echo 42;"
OUT 42
RES Command ran successfully
EOT;
$successOutputDebugWithTags = <<<'EOT'
RUN php -r "echo '<info>42</info>';"
OUT <info>42</info>
RES Command ran successfully
EOT;
$successOutputProcessDebug = <<<'EOT'
RUN 'php' '-r' 'echo 42;'
OUT 42
RES Command ran successfully
EOT;
$syntaxErrorOutputVerbose = <<<'EOT'
RUN php -r "fwrite(STDERR, 'error message');usleep(50000);fwrite(STDOUT, 'out message');exit(252);"
RES 252 Command did not run successfully
EOT;
$syntaxErrorOutputDebug = <<<'EOT'
RUN php -r "fwrite(STDERR, 'error message');usleep(500000);fwrite(STDOUT, 'out message');exit(252);"
ERR error message
OUT out message
RES 252 Command did not run successfully
EOT;
$errorMessage = 'An error occurred';
$args = new Process(array('php', '-r', 'echo 42;'));
$args = $args->getCommandLine();
$successOutputProcessDebug = str_replace("'php' '-r' 'echo 42;'", $args, $successOutputProcessDebug);
return array(
array('', 'php -r "echo 42;"', StreamOutput::VERBOSITY_VERBOSE, null),
array($successOutputVerbose, 'php -r "echo 42;"', StreamOutput::VERBOSITY_VERY_VERBOSE, null),
array($successOutputDebug, 'php -r "echo 42;"', StreamOutput::VERBOSITY_DEBUG, null),
array($successOutputDebugWithTags, 'php -r "echo \'<info>42</info>\';"', StreamOutput::VERBOSITY_DEBUG, null),
array('', 'php -r "syntax error"', StreamOutput::VERBOSITY_VERBOSE, null),
array($syntaxErrorOutputVerbose, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERY_VERBOSE, null),
array($syntaxErrorOutputDebug, 'php -r "fwrite(STDERR, \'error message\');usleep(500000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_DEBUG, null),
array($errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERBOSE, $errorMessage),
array($syntaxErrorOutputVerbose.$errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERY_VERBOSE, $errorMessage),
array($syntaxErrorOutputDebug.$errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(500000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_DEBUG, $errorMessage),
array($successOutputProcessDebug, array('php', '-r', 'echo 42;'), StreamOutput::VERBOSITY_DEBUG, null),
array($successOutputDebug, new Process('php -r "echo 42;"'), StreamOutput::VERBOSITY_DEBUG, null),
);
}
private function getOutputStream($verbosity)
{
return new StreamOutput(fopen('php://memory', 'r+', false), $verbosity, false);
}
private function getOutput(StreamOutput $output)
{
rewind($output->getStream());
return stream_get_contents($output->getStream());
}
}

View file

@ -0,0 +1,792 @@
<?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\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Output\StreamOutput;
/**
* @group time-sensitive
*/
class ProgressBarTest extends TestCase
{
public function testMultipleStart()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->start();
$bar->advance();
$bar->start();
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.
$this->generateOutput(' 1 [->--------------------------]').
$this->generateOutput(' 0 [>---------------------------]'),
stream_get_contents($output->getStream())
);
}
public function testAdvance()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->start();
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.
$this->generateOutput(' 1 [->--------------------------]'),
stream_get_contents($output->getStream())
);
}
public function testAdvanceWithStep()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->start();
$bar->advance(5);
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.
$this->generateOutput(' 5 [----->----------------------]'),
stream_get_contents($output->getStream())
);
}
public function testAdvanceMultipleTimes()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->start();
$bar->advance(3);
$bar->advance(2);
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.
$this->generateOutput(' 3 [--->------------------------]').
$this->generateOutput(' 5 [----->----------------------]'),
stream_get_contents($output->getStream())
);
}
public function testAdvanceOverMax()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 10);
$bar->setProgress(9);
$bar->advance();
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
' 9/10 [=========================>--] 90%'.
$this->generateOutput(' 10/10 [============================] 100%').
$this->generateOutput(' 11/11 [============================] 100%'),
stream_get_contents($output->getStream())
);
}
public function testRegress()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->start();
$bar->advance();
$bar->advance();
$bar->advance(-1);
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.
$this->generateOutput(' 1 [->--------------------------]').
$this->generateOutput(' 2 [-->-------------------------]').
$this->generateOutput(' 1 [->--------------------------]'),
stream_get_contents($output->getStream())
);
}
public function testRegressWithStep()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->start();
$bar->advance(4);
$bar->advance(4);
$bar->advance(-2);
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.
$this->generateOutput(' 4 [---->-----------------------]').
$this->generateOutput(' 8 [-------->-------------------]').
$this->generateOutput(' 6 [------>---------------------]'),
stream_get_contents($output->getStream())
);
}
public function testRegressMultipleTimes()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->start();
$bar->advance(3);
$bar->advance(3);
$bar->advance(-1);
$bar->advance(-2);
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.
$this->generateOutput(' 3 [--->------------------------]').
$this->generateOutput(' 6 [------>---------------------]').
$this->generateOutput(' 5 [----->----------------------]').
$this->generateOutput(' 3 [--->------------------------]'),
stream_get_contents($output->getStream())
);
}
public function testRegressBelowMin()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 10);
$bar->setProgress(1);
$bar->advance(-1);
$bar->advance(-1);
rewind($output->getStream());
$this->assertEquals(
' 1/10 [==>-------------------------] 10%'.
$this->generateOutput(' 0/10 [>---------------------------] 0%'),
stream_get_contents($output->getStream())
);
}
public function testFormat()
{
$expected =
' 0/10 [>---------------------------] 0%'.
$this->generateOutput(' 10/10 [============================] 100%').
$this->generateOutput(' 10/10 [============================] 100%')
;
// max in construct, no format
$bar = new ProgressBar($output = $this->getOutputStream(), 10);
$bar->start();
$bar->advance(10);
$bar->finish();
rewind($output->getStream());
$this->assertEquals($expected, stream_get_contents($output->getStream()));
// max in start, no format
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->start(10);
$bar->advance(10);
$bar->finish();
rewind($output->getStream());
$this->assertEquals($expected, stream_get_contents($output->getStream()));
// max in construct, explicit format before
$bar = new ProgressBar($output = $this->getOutputStream(), 10);
$bar->setFormat('normal');
$bar->start();
$bar->advance(10);
$bar->finish();
rewind($output->getStream());
$this->assertEquals($expected, stream_get_contents($output->getStream()));
// max in start, explicit format before
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->setFormat('normal');
$bar->start(10);
$bar->advance(10);
$bar->finish();
rewind($output->getStream());
$this->assertEquals($expected, stream_get_contents($output->getStream()));
}
public function testCustomizations()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 10);
$bar->setBarWidth(10);
$bar->setBarCharacter('_');
$bar->setEmptyBarCharacter(' ');
$bar->setProgressCharacter('/');
$bar->setFormat(' %current%/%max% [%bar%] %percent:3s%%');
$bar->start();
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
' 0/10 [/ ] 0%'.
$this->generateOutput(' 1/10 [_/ ] 10%'),
stream_get_contents($output->getStream())
);
}
public function testDisplayWithoutStart()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 50);
$bar->display();
rewind($output->getStream());
$this->assertEquals(
' 0/50 [>---------------------------] 0%',
stream_get_contents($output->getStream())
);
}
public function testDisplayWithQuietVerbosity()
{
$bar = new ProgressBar($output = $this->getOutputStream(true, StreamOutput::VERBOSITY_QUIET), 50);
$bar->display();
rewind($output->getStream());
$this->assertEquals(
'',
stream_get_contents($output->getStream())
);
}
public function testFinishWithoutStart()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 50);
$bar->finish();
rewind($output->getStream());
$this->assertEquals(
' 50/50 [============================] 100%',
stream_get_contents($output->getStream())
);
}
public function testPercent()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 50);
$bar->start();
$bar->display();
$bar->advance();
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
' 0/50 [>---------------------------] 0%'.
$this->generateOutput(' 0/50 [>---------------------------] 0%').
$this->generateOutput(' 1/50 [>---------------------------] 2%').
$this->generateOutput(' 2/50 [=>--------------------------] 4%'),
stream_get_contents($output->getStream())
);
}
public function testOverwriteWithShorterLine()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 50);
$bar->setFormat(' %current%/%max% [%bar%] %percent:3s%%');
$bar->start();
$bar->display();
$bar->advance();
// set shorter format
$bar->setFormat(' %current%/%max% [%bar%]');
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
' 0/50 [>---------------------------] 0%'.
$this->generateOutput(' 0/50 [>---------------------------] 0%').
$this->generateOutput(' 1/50 [>---------------------------] 2%').
$this->generateOutput(' 2/50 [=>--------------------------]'),
stream_get_contents($output->getStream())
);
}
public function testStartWithMax()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->setFormat('%current%/%max% [%bar%]');
$bar->start(50);
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
' 0/50 [>---------------------------]'.
$this->generateOutput(' 1/50 [>---------------------------]'),
stream_get_contents($output->getStream())
);
}
public function testSetCurrentProgress()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 50);
$bar->start();
$bar->display();
$bar->advance();
$bar->setProgress(15);
$bar->setProgress(25);
rewind($output->getStream());
$this->assertEquals(
' 0/50 [>---------------------------] 0%'.
$this->generateOutput(' 0/50 [>---------------------------] 0%').
$this->generateOutput(' 1/50 [>---------------------------] 2%').
$this->generateOutput(' 15/50 [========>-------------------] 30%').
$this->generateOutput(' 25/50 [==============>-------------] 50%'),
stream_get_contents($output->getStream())
);
}
public function testSetCurrentBeforeStarting()
{
$bar = new ProgressBar($this->getOutputStream());
$bar->setProgress(15);
$this->assertNotNull($bar->getStartTime());
}
public function testRedrawFrequency()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 6);
$bar->setRedrawFrequency(2);
$bar->start();
$bar->setProgress(1);
$bar->advance(2);
$bar->advance(2);
$bar->advance(1);
rewind($output->getStream());
$this->assertEquals(
' 0/6 [>---------------------------] 0%'.
$this->generateOutput(' 3/6 [==============>-------------] 50%').
$this->generateOutput(' 5/6 [=======================>----] 83%').
$this->generateOutput(' 6/6 [============================] 100%'),
stream_get_contents($output->getStream())
);
}
public function testRedrawFrequencyIsAtLeastOneIfZeroGiven()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->setRedrawFrequency(0);
$bar->start();
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.
$this->generateOutput(' 1 [->--------------------------]'),
stream_get_contents($output->getStream())
);
}
public function testRedrawFrequencyIsAtLeastOneIfSmallerOneGiven()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->setRedrawFrequency(0.9);
$bar->start();
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.
$this->generateOutput(' 1 [->--------------------------]'),
stream_get_contents($output->getStream())
);
}
public function testMultiByteSupport()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->start();
$bar->setBarCharacter('■');
$bar->advance(3);
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.
$this->generateOutput(' 3 [■■■>------------------------]'),
stream_get_contents($output->getStream())
);
}
public function testClear()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 50);
$bar->start();
$bar->setProgress(25);
$bar->clear();
rewind($output->getStream());
$this->assertEquals(
' 0/50 [>---------------------------] 0%'.
$this->generateOutput(' 25/50 [==============>-------------] 50%').
$this->generateOutput(''),
stream_get_contents($output->getStream())
);
}
public function testPercentNotHundredBeforeComplete()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 200);
$bar->start();
$bar->display();
$bar->advance(199);
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
' 0/200 [>---------------------------] 0%'.
$this->generateOutput(' 0/200 [>---------------------------] 0%').
$this->generateOutput(' 199/200 [===========================>] 99%').
$this->generateOutput(' 200/200 [============================] 100%'),
stream_get_contents($output->getStream())
);
}
public function testNonDecoratedOutput()
{
$bar = new ProgressBar($output = $this->getOutputStream(false), 200);
$bar->start();
for ($i = 0; $i < 200; ++$i) {
$bar->advance();
}
$bar->finish();
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.
' 200/200 [============================] 100%',
stream_get_contents($output->getStream())
);
}
public function testNonDecoratedOutputWithClear()
{
$bar = new ProgressBar($output = $this->getOutputStream(false), 50);
$bar->start();
$bar->setProgress(25);
$bar->clear();
$bar->setProgress(50);
$bar->finish();
rewind($output->getStream());
$this->assertEquals(
' 0/50 [>---------------------------] 0%'.PHP_EOL.
' 25/50 [==============>-------------] 50%'.PHP_EOL.
' 50/50 [============================] 100%',
stream_get_contents($output->getStream())
);
}
public function testNonDecoratedOutputWithoutMax()
{
$bar = new ProgressBar($output = $this->getOutputStream(false));
$bar->start();
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]'.PHP_EOL.
' 1 [->--------------------------]',
stream_get_contents($output->getStream())
);
}
public function testParallelBars()
{
$output = $this->getOutputStream();
$bar1 = new ProgressBar($output, 2);
$bar2 = new ProgressBar($output, 3);
$bar2->setProgressCharacter('#');
$bar3 = new ProgressBar($output);
$bar1->start();
$output->write("\n");
$bar2->start();
$output->write("\n");
$bar3->start();
for ($i = 1; $i <= 3; ++$i) {
// up two lines
$output->write("\033[2A");
if ($i <= 2) {
$bar1->advance();
}
$output->write("\n");
$bar2->advance();
$output->write("\n");
$bar3->advance();
}
$output->write("\033[2A");
$output->write("\n");
$output->write("\n");
$bar3->finish();
rewind($output->getStream());
$this->assertEquals(
' 0/2 [>---------------------------] 0%'."\n".
' 0/3 [#---------------------------] 0%'."\n".
rtrim(' 0 [>---------------------------]').
"\033[2A".
$this->generateOutput(' 1/2 [==============>-------------] 50%')."\n".
$this->generateOutput(' 1/3 [=========#------------------] 33%')."\n".
rtrim($this->generateOutput(' 1 [->--------------------------]')).
"\033[2A".
$this->generateOutput(' 2/2 [============================] 100%')."\n".
$this->generateOutput(' 2/3 [==================#---------] 66%')."\n".
rtrim($this->generateOutput(' 2 [-->-------------------------]')).
"\033[2A".
"\n".
$this->generateOutput(' 3/3 [============================] 100%')."\n".
rtrim($this->generateOutput(' 3 [--->------------------------]')).
"\033[2A".
"\n".
"\n".
rtrim($this->generateOutput(' 3 [============================]')),
stream_get_contents($output->getStream())
);
}
public function testWithoutMax()
{
$output = $this->getOutputStream();
$bar = new ProgressBar($output);
$bar->start();
$bar->advance();
$bar->advance();
$bar->advance();
$bar->finish();
rewind($output->getStream());
$this->assertEquals(
rtrim(' 0 [>---------------------------]').
rtrim($this->generateOutput(' 1 [->--------------------------]')).
rtrim($this->generateOutput(' 2 [-->-------------------------]')).
rtrim($this->generateOutput(' 3 [--->------------------------]')).
rtrim($this->generateOutput(' 3 [============================]')),
stream_get_contents($output->getStream())
);
}
public function testWithSmallScreen()
{
$output = $this->getOutputStream();
$bar = new ProgressBar($output);
putenv('COLUMNS=12');
$bar->start();
$bar->advance();
putenv('COLUMNS=120');
rewind($output->getStream());
$this->assertEquals(
' 0 [>---]'.
$this->generateOutput(' 1 [->--]'),
stream_get_contents($output->getStream())
);
}
public function testAddingPlaceholderFormatter()
{
ProgressBar::setPlaceholderFormatterDefinition('remaining_steps', function (ProgressBar $bar) {
return $bar->getMaxSteps() - $bar->getProgress();
});
$bar = new ProgressBar($output = $this->getOutputStream(), 3);
$bar->setFormat(' %remaining_steps% [%bar%]');
$bar->start();
$bar->advance();
$bar->finish();
rewind($output->getStream());
$this->assertEquals(
' 3 [>---------------------------]'.
$this->generateOutput(' 2 [=========>------------------]').
$this->generateOutput(' 0 [============================]'),
stream_get_contents($output->getStream())
);
}
public function testMultilineFormat()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 3);
$bar->setFormat("%bar%\nfoobar");
$bar->start();
$bar->advance();
$bar->clear();
$bar->finish();
rewind($output->getStream());
$this->assertEquals(
">---------------------------\nfoobar".
$this->generateOutput("=========>------------------\nfoobar").
"\x0D\x1B[2K\x1B[1A\x1B[2K".
$this->generateOutput("============================\nfoobar"),
stream_get_contents($output->getStream())
);
}
public function testAnsiColorsAndEmojis()
{
putenv('COLUMNS=156');
$bar = new ProgressBar($output = $this->getOutputStream(), 15);
ProgressBar::setPlaceholderFormatterDefinition('memory', function (ProgressBar $bar) {
static $i = 0;
$mem = 100000 * $i;
$colors = $i++ ? '41;37' : '44;37';
return "\033[".$colors.'m '.Helper::formatMemory($mem)." \033[0m";
});
$bar->setFormat(" \033[44;37m %title:-37s% \033[0m\n %current%/%max% %bar% %percent:3s%%\n 🏁 %remaining:-10s% %memory:37s%");
$bar->setBarCharacter($done = "\033[32m●\033[0m");
$bar->setEmptyBarCharacter($empty = "\033[31m●\033[0m");
$bar->setProgressCharacter($progress = "\033[32m➤ \033[0m");
$bar->setMessage('Starting the demo... fingers crossed', 'title');
$bar->start();
rewind($output->getStream());
$this->assertEquals(
" \033[44;37m Starting the demo... fingers crossed \033[0m\n".
' 0/15 '.$progress.str_repeat($empty, 26)." 0%\n".
" \xf0\x9f\x8f\x81 < 1 sec \033[44;37m 0 B \033[0m",
stream_get_contents($output->getStream())
);
ftruncate($output->getStream(), 0);
rewind($output->getStream());
$bar->setMessage('Looks good to me...', 'title');
$bar->advance(4);
rewind($output->getStream());
$this->assertEquals(
$this->generateOutput(
" \033[44;37m Looks good to me... \033[0m\n".
' 4/15 '.str_repeat($done, 7).$progress.str_repeat($empty, 19)." 26%\n".
" \xf0\x9f\x8f\x81 < 1 sec \033[41;37m 97 KiB \033[0m"
),
stream_get_contents($output->getStream())
);
ftruncate($output->getStream(), 0);
rewind($output->getStream());
$bar->setMessage('Thanks, bye', 'title');
$bar->finish();
rewind($output->getStream());
$this->assertEquals(
$this->generateOutput(
" \033[44;37m Thanks, bye \033[0m\n".
' 15/15 '.str_repeat($done, 28)." 100%\n".
" \xf0\x9f\x8f\x81 < 1 sec \033[41;37m 195 KiB \033[0m"
),
stream_get_contents($output->getStream())
);
putenv('COLUMNS=120');
}
public function testSetFormat()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->setFormat('normal');
$bar->start();
rewind($output->getStream());
$this->assertEquals(
' 0 [>---------------------------]',
stream_get_contents($output->getStream())
);
$bar = new ProgressBar($output = $this->getOutputStream(), 10);
$bar->setFormat('normal');
$bar->start();
rewind($output->getStream());
$this->assertEquals(
' 0/10 [>---------------------------] 0%',
stream_get_contents($output->getStream())
);
}
/**
* @dataProvider provideFormat
*/
public function testFormatsWithoutMax($format)
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->setFormat($format);
$bar->start();
rewind($output->getStream());
$this->assertNotEmpty(stream_get_contents($output->getStream()));
}
/**
* Provides each defined format.
*
* @return array
*/
public function provideFormat()
{
return array(
array('normal'),
array('verbose'),
array('very_verbose'),
array('debug'),
);
}
protected function getOutputStream($decorated = true, $verbosity = StreamOutput::VERBOSITY_NORMAL)
{
return new StreamOutput(fopen('php://memory', 'r+', false), $verbosity, $decorated);
}
protected function generateOutput($expected)
{
$count = substr_count($expected, "\n");
return "\x0D\x1B[2K".($count ? str_repeat("\x1B[1A\x1B[2K", $count) : '').$expected;
}
public function testBarWidthWithMultilineFormat()
{
putenv('COLUMNS=10');
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->setFormat("%bar%\n0123456789");
// before starting
$bar->setBarWidth(5);
$this->assertEquals(5, $bar->getBarWidth());
// after starting
$bar->start();
rewind($output->getStream());
$this->assertEquals(5, $bar->getBarWidth(), stream_get_contents($output->getStream()));
putenv('COLUMNS=120');
}
}

View file

@ -0,0 +1,183 @@
<?php
namespace Symfony\Component\Console\Tests\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Helper\ProgressIndicator;
use Symfony\Component\Console\Output\StreamOutput;
/**
* @group time-sensitive
*/
class ProgressIndicatorTest extends TestCase
{
public function testDefaultIndicator()
{
$bar = new ProgressIndicator($output = $this->getOutputStream());
$bar->start('Starting...');
usleep(101000);
$bar->advance();
usleep(101000);
$bar->advance();
usleep(101000);
$bar->advance();
usleep(101000);
$bar->advance();
usleep(101000);
$bar->advance();
usleep(101000);
$bar->setMessage('Advancing...');
$bar->advance();
$bar->finish('Done...');
$bar->start('Starting Again...');
usleep(101000);
$bar->advance();
$bar->finish('Done Again...');
rewind($output->getStream());
$this->assertEquals(
$this->generateOutput(' - Starting...').
$this->generateOutput(' \\ Starting...').
$this->generateOutput(' | Starting...').
$this->generateOutput(' / Starting...').
$this->generateOutput(' - Starting...').
$this->generateOutput(' \\ Starting...').
$this->generateOutput(' \\ Advancing...').
$this->generateOutput(' | Advancing...').
$this->generateOutput(' | Done...').
PHP_EOL.
$this->generateOutput(' - Starting Again...').
$this->generateOutput(' \\ Starting Again...').
$this->generateOutput(' \\ Done Again...').
PHP_EOL,
stream_get_contents($output->getStream())
);
}
public function testNonDecoratedOutput()
{
$bar = new ProgressIndicator($output = $this->getOutputStream(false));
$bar->start('Starting...');
$bar->advance();
$bar->advance();
$bar->setMessage('Midway...');
$bar->advance();
$bar->advance();
$bar->finish('Done...');
rewind($output->getStream());
$this->assertEquals(
' Starting...'.PHP_EOL.
' Midway...'.PHP_EOL.
' Done...'.PHP_EOL.PHP_EOL,
stream_get_contents($output->getStream())
);
}
public function testCustomIndicatorValues()
{
$bar = new ProgressIndicator($output = $this->getOutputStream(), null, 100, array('a', 'b', 'c'));
$bar->start('Starting...');
usleep(101000);
$bar->advance();
usleep(101000);
$bar->advance();
usleep(101000);
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
$this->generateOutput(' a Starting...').
$this->generateOutput(' b Starting...').
$this->generateOutput(' c Starting...').
$this->generateOutput(' a Starting...'),
stream_get_contents($output->getStream())
);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Must have at least 2 indicator value characters.
*/
public function testCannotSetInvalidIndicatorCharacters()
{
$bar = new ProgressIndicator($this->getOutputStream(), null, 100, array('1'));
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Progress indicator already started.
*/
public function testCannotStartAlreadyStartedIndicator()
{
$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()
{
$bar = new ProgressIndicator($this->getOutputStream());
$bar->advance();
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Progress indicator has not yet been started.
*/
public function testCannotFinishUnstartedIndicator()
{
$bar = new ProgressIndicator($this->getOutputStream());
$bar->finish('Finished');
}
/**
* @dataProvider provideFormat
*/
public function testFormats($format)
{
$bar = new ProgressIndicator($output = $this->getOutputStream(), $format);
$bar->start('Starting...');
$bar->advance();
rewind($output->getStream());
$this->assertNotEmpty(stream_get_contents($output->getStream()));
}
/**
* Provides each defined format.
*
* @return array
*/
public function provideFormat()
{
return array(
array('normal'),
array('verbose'),
array('very_verbose'),
array('debug'),
);
}
protected function getOutputStream($decorated = true, $verbosity = StreamOutput::VERBOSITY_NORMAL)
{
return new StreamOutput(fopen('php://memory', 'r+', false), $verbosity, $decorated);
}
protected function generateOutput($expected)
{
$count = substr_count($expected, "\n");
return "\x0D\x1B[2K".($count ? sprintf("\033[%dA", $count) : '').$expected;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,168 @@
<?php
namespace Symfony\Component\Console\Tests\Helper;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\Question;
/**
* @group tty
*/
class SymfonyQuestionHelperTest extends AbstractQuestionHelperTest
{
public function testAskChoice()
{
$questionHelper = new SymfonyQuestionHelper();
$helperSet = new HelperSet(array(new FormatterHelper()));
$questionHelper->setHelperSet($helperSet);
$heroes = array('Superman', 'Batman', 'Spiderman');
$inputStream = $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->createStreamableInputInterfaceMock($inputStream), $output = $this->createOutputInterface(), $question));
$this->assertOutputContains('What is your favorite superhero? [Spiderman]', $output);
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes);
$question->setMaxAttempts(1);
$this->assertEquals('Batman', $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('Batman', $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $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->createStreamableInputInterfaceMock($inputStream), $output = $this->createOutputInterface(), $question));
$this->assertOutputContains('Input "Fabien" is not a superhero!', $output);
try {
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '1');
$question->setMaxAttempts(1);
$questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $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(array('Batman'), $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '0,1');
$question->setMaxAttempts(1);
$question->setMultiselect(true);
$this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $output = $this->createOutputInterface(), $question));
$this->assertOutputContains('What is your favorite superhero? [Superman, Batman]', $output);
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, ' 0 , 1 ');
$question->setMaxAttempts(1);
$question->setMultiselect(true);
$this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream), $output = $this->createOutputInterface(), $question));
$this->assertOutputContains('What is your favorite superhero? [Superman, Batman]', $output);
}
public function testAskChoiceWithChoiceValueAsDefault()
{
$questionHelper = new SymfonyQuestionHelper();
$helperSet = new HelperSet(array(new FormatterHelper()));
$questionHelper->setHelperSet($helperSet);
$question = new ChoiceQuestion('What is your favorite superhero?', array('Superman', 'Batman', 'Spiderman'), 'Batman');
$question->setMaxAttempts(1);
$this->assertSame('Batman', $questionHelper->ask($this->createStreamableInputInterfaceMock($this->getInputStream("Batman\n")), $output = $this->createOutputInterface(), $question));
$this->assertOutputContains('What is your favorite superhero? [Batman]', $output);
}
public function testAskReturnsNullIfValidatorAllowsIt()
{
$questionHelper = new SymfonyQuestionHelper();
$question = new Question('What is your favorite superhero?');
$question->setValidator(function ($value) { return $value; });
$input = $this->createStreamableInputInterfaceMock($this->getInputStream("\n"));
$this->assertNull($questionHelper->ask($input, $this->createOutputInterface(), $question));
}
public function testAskEscapeDefaultValue()
{
$helper = new SymfonyQuestionHelper();
$input = $this->createStreamableInputInterfaceMock($this->getInputStream('\\'));
$helper->ask($input, $output = $this->createOutputInterface(), new Question('Can I have a backslash?', '\\'));
$this->assertOutputContains('Can I have a backslash? [\]', $output);
}
public function testAskEscapeAndFormatLabel()
{
$helper = new SymfonyQuestionHelper();
$input = $this->createStreamableInputInterfaceMock($this->getInputStream('Foo\\Bar'));
$helper->ask($input, $output = $this->createOutputInterface(), new Question('Do you want to use Foo\\Bar <comment>or</comment> Foo\\Baz\\?', 'Foo\\Baz'));
$this->assertOutputContains('Do you want to use Foo\\Bar or Foo\\Baz\\? [Foo\\Baz]:', $output);
}
public function testLabelTrailingBackslash()
{
$helper = new SymfonyQuestionHelper();
$input = $this->createStreamableInputInterfaceMock($this->getInputStream('sure'));
$helper->ask($input, $output = $this->createOutputInterface(), new Question('Question with a trailing \\'));
$this->assertOutputContains('Question with a trailing \\', $output);
}
/**
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
* @expectedExceptionMessage Aborted
*/
public function testAskThrowsExceptionOnMissingInput()
{
$dialog = new SymfonyQuestionHelper();
$dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new Question('What\'s your name?'));
}
protected function getInputStream($input)
{
$stream = fopen('php://memory', 'r+', false);
fwrite($stream, $input);
rewind($stream);
return $stream;
}
protected function createOutputInterface()
{
$output = new StreamOutput(fopen('php://memory', 'r+', false));
$output->setDecorated(false);
return $output;
}
protected function createInputInterfaceMock($interactive = true)
{
$mock = $this->getMockBuilder('Symfony\Component\Console\Input\InputInterface')->getMock();
$mock->expects($this->any())
->method('isInteractive')
->will($this->returnValue($interactive));
return $mock;
}
private function assertOutputContains($expected, StreamOutput $output)
{
rewind($output->getStream());
$stream = stream_get_contents($output->getStream());
$this->assertContains($expected, $stream);
}
}

View file

@ -0,0 +1,28 @@
<?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\Helper;
use PHPUnit\Framework\TestCase;
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()
{
$style = new TableStyle();
$style->setPadType('TEST');
}
}

View file

@ -0,0 +1,874 @@
<?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\Helper;
use PHPUnit\Framework\TestCase;
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\StreamOutput;
class TableTest extends TestCase
{
protected $stream;
protected function setUp()
{
$this->stream = fopen('php://memory', 'r+');
}
protected function tearDown()
{
fclose($this->stream);
$this->stream = null;
}
/**
* @dataProvider renderProvider
*/
public function testRender($headers, $rows, $style, $expected, $decorated = false)
{
$table = new Table($output = $this->getOutputStream($decorated));
$table
->setHeaders($headers)
->setRows($rows)
->setStyle($style)
;
$table->render();
$this->assertEquals($expected, $this->getOutputContent($output));
}
/**
* @dataProvider renderProvider
*/
public function testRenderAddRows($headers, $rows, $style, $expected, $decorated = false)
{
$table = new Table($output = $this->getOutputStream($decorated));
$table
->setHeaders($headers)
->addRows($rows)
->setStyle($style)
;
$table->render();
$this->assertEquals($expected, $this->getOutputContent($output));
}
/**
* @dataProvider renderProvider
*/
public function testRenderAddRowsOneByOne($headers, $rows, $style, $expected, $decorated = false)
{
$table = new Table($output = $this->getOutputStream($decorated));
$table
->setHeaders($headers)
->setStyle($style)
;
foreach ($rows as $row) {
$table->addRow($row);
}
$table->render();
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function renderProvider()
{
$books = array(
array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'),
array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'),
array('960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'),
array('80-902734-1-6', 'And Then There Were None', 'Agatha Christie'),
);
return array(
array(
array('ISBN', 'Title', 'Author'),
$books,
'default',
<<<'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
),
array(
array('ISBN', 'Title', 'Author'),
$books,
'compact',
<<<'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
),
array(
array('ISBN', 'Title', 'Author'),
$books,
'borderless',
<<<'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
),
array(
array('ISBN', 'Title'),
array(
array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'),
array('9971-5-0210-0'),
array('960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'),
array('80-902734-1-6', 'And Then There Were None', 'Agatha Christie'),
),
'default',
<<<'TABLE'
+---------------+--------------------------+------------------+
| ISBN | Title | |
+---------------+--------------------------+------------------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri |
| 9971-5-0210-0 | | |
| 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
),
array(
array(),
array(
array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'),
array('9971-5-0210-0'),
array('960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'),
array('80-902734-1-6', 'And Then There Were None', 'Agatha Christie'),
),
'default',
<<<'TABLE'
+---------------+--------------------------+------------------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri |
| 9971-5-0210-0 | | |
| 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
),
array(
array('ISBN', 'Title', 'Author'),
array(
array('99921-58-10-7', "Divine\nComedy", 'Dante Alighieri'),
array('9971-5-0210-2', "Harry Potter\nand the Chamber of Secrets", "Rowling\nJoanne K."),
array('9971-5-0210-2', "Harry Potter\nand the Chamber of Secrets", "Rowling\nJoanne K."),
array('960-425-059-0', 'The Lord of the Rings', "J. R. R.\nTolkien"),
),
'default',
<<<'TABLE'
+---------------+----------------------------+-----------------+
| ISBN | Title | Author |
+---------------+----------------------------+-----------------+
| 99921-58-10-7 | Divine | Dante Alighieri |
| | Comedy | |
| 9971-5-0210-2 | Harry Potter | Rowling |
| | and the Chamber of Secrets | Joanne K. |
| 9971-5-0210-2 | Harry Potter | Rowling |
| | and the Chamber of Secrets | Joanne K. |
| 960-425-059-0 | The Lord of the Rings | J. R. R. |
| | | Tolkien |
+---------------+----------------------------+-----------------+
TABLE
),
array(
array('ISBN', 'Title'),
array(),
'default',
<<<'TABLE'
+------+-------+
| ISBN | Title |
+------+-------+
TABLE
),
array(
array(),
array(),
'default',
'',
),
'Cell text with tags used for Output styling' => array(
array('ISBN', 'Title', 'Author'),
array(
array('<info>99921-58-10-7</info>', '<error>Divine Comedy</error>', '<fg=blue;bg=white>Dante Alighieri</fg=blue;bg=white>'),
array('9971-5-0210-0', 'A Tale of Two Cities', '<info>Charles Dickens</>'),
),
'default',
<<<'TABLE'
+---------------+----------------------+-----------------+
| ISBN | Title | Author |
+---------------+----------------------+-----------------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri |
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
+---------------+----------------------+-----------------+
TABLE
),
'Cell text with tags not used for Output styling' => array(
array('ISBN', 'Title', 'Author'),
array(
array('<strong>99921-58-10-700</strong>', '<f>Divine Com</f>', 'Dante Alighieri'),
array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'),
),
'default',
<<<'TABLE'
+----------------------------------+----------------------+-----------------+
| ISBN | Title | Author |
+----------------------------------+----------------------+-----------------+
| <strong>99921-58-10-700</strong> | <f>Divine Com</f> | Dante Alighieri |
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
+----------------------------------+----------------------+-----------------+
TABLE
),
'Cell with colspan' => array(
array('ISBN', 'Title', 'Author'),
array(
array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'),
new TableSeparator(),
array(new TableCell('Divine Comedy(Dante Alighieri)', array('colspan' => 3))),
new TableSeparator(),
array(
new TableCell('Arduino: A Quick-Start Guide', array('colspan' => 2)),
'Mark Schmidt',
),
new TableSeparator(),
array(
'9971-5-0210-0',
new TableCell("A Tale of \nTwo Cities", array('colspan' => 2)),
),
new TableSeparator(),
array(
new TableCell('Cupiditate dicta atque porro, tempora exercitationem modi animi nulla nemo vel nihil!', array('colspan' => 3)),
),
),
'default',
<<<'TABLE'
+-------------------------------+-------------------------------+-----------------------------+
| ISBN | Title | Author |
+-------------------------------+-------------------------------+-----------------------------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri |
+-------------------------------+-------------------------------+-----------------------------+
| Divine Comedy(Dante Alighieri) |
+-------------------------------+-------------------------------+-----------------------------+
| Arduino: A Quick-Start Guide | Mark Schmidt |
+-------------------------------+-------------------------------+-----------------------------+
| 9971-5-0210-0 | A Tale of |
| | Two Cities |
+-------------------------------+-------------------------------+-----------------------------+
| Cupiditate dicta atque porro, tempora exercitationem modi animi nulla nemo vel nihil! |
+-------------------------------+-------------------------------+-----------------------------+
TABLE
),
'Cell with rowspan' => array(
array('ISBN', 'Title', 'Author'),
array(
array(
new TableCell('9971-5-0210-0', array('rowspan' => 3)),
new TableCell('Divine Comedy', array('rowspan' => 2)),
'Dante Alighieri',
),
array(),
array("The Lord of \nthe Rings", "J. R. \nR. Tolkien"),
new TableSeparator(),
array('80-902734-1-6', new TableCell("And Then \nThere \nWere None", array('rowspan' => 3)), 'Agatha Christie'),
array('80-902734-1-7', 'Test'),
),
'default',
<<<'TABLE'
+---------------+---------------+-----------------+
| ISBN | Title | Author |
+---------------+---------------+-----------------+
| 9971-5-0210-0 | Divine Comedy | Dante Alighieri |
| | | |
| | The Lord of | J. R. |
| | the Rings | R. Tolkien |
+---------------+---------------+-----------------+
| 80-902734-1-6 | And Then | Agatha Christie |
| 80-902734-1-7 | There | Test |
| | Were None | |
+---------------+---------------+-----------------+
TABLE
),
'Cell with rowspan and colspan' => array(
array('ISBN', 'Title', 'Author'),
array(
array(
new TableCell('9971-5-0210-0', array('rowspan' => 2, 'colspan' => 2)),
'Dante Alighieri',
),
array('Charles Dickens'),
new TableSeparator(),
array(
'Dante Alighieri',
new TableCell('9971-5-0210-0', array('rowspan' => 3, 'colspan' => 2)),
),
array('J. R. R. Tolkien'),
array('J. R. R'),
),
'default',
<<<'TABLE'
+------------------+---------+-----------------+
| ISBN | Title | Author |
+------------------+---------+-----------------+
| 9971-5-0210-0 | Dante Alighieri |
| | Charles Dickens |
+------------------+---------+-----------------+
| Dante Alighieri | 9971-5-0210-0 |
| J. R. R. Tolkien | |
| J. R. R | |
+------------------+---------+-----------------+
TABLE
),
'Cell with rowspan and colspan contains new line break' => array(
array('ISBN', 'Title', 'Author'),
array(
array(
new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)),
'Dante Alighieri',
),
array('Charles Dickens'),
new TableSeparator(),
array(
'Dante Alighieri',
new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)),
),
array('Charles Dickens'),
new TableSeparator(),
array(
new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)),
new TableCell("Dante \nAlighieri", array('rowspan' => 2, 'colspan' => 1)),
),
),
'default',
<<<'TABLE'
+-----------------+-------+-----------------+
| ISBN | Title | Author |
+-----------------+-------+-----------------+
| 9971 | Dante Alighieri |
| -5- | Charles Dickens |
| 021 | |
| 0-0 | |
+-----------------+-------+-----------------+
| Dante Alighieri | 9971 |
| Charles Dickens | -5- |
| | 021 |
| | 0-0 |
+-----------------+-------+-----------------+
| 9971 | Dante |
| -5- | Alighieri |
| 021 | |
| 0-0 | |
+-----------------+-------+-----------------+
TABLE
),
'Cell with rowspan and colspan without using TableSeparator' => array(
array('ISBN', 'Title', 'Author'),
array(
array(
new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)),
'Dante Alighieri',
),
array('Charles Dickens'),
array(
'Dante Alighieri',
new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)),
),
array('Charles Dickens'),
),
'default',
<<<'TABLE'
+-----------------+-------+-----------------+
| ISBN | Title | Author |
+-----------------+-------+-----------------+
| 9971 | Dante Alighieri |
| -5- | Charles Dickens |
| 021 | |
| 0-0 | |
| Dante Alighieri | 9971 |
| Charles Dickens | -5- |
| | 021 |
| | 0-0 |
+-----------------+-------+-----------------+
TABLE
),
'Cell with rowspan and colspan with separator inside a rowspan' => array(
array('ISBN', 'Author'),
array(
array(
new TableCell('9971-5-0210-0', array('rowspan' => 3, 'colspan' => 1)),
'Dante Alighieri',
),
array(new TableSeparator()),
array('Charles Dickens'),
),
'default',
<<<'TABLE'
+---------------+-----------------+
| ISBN | Author |
+---------------+-----------------+
| 9971-5-0210-0 | Dante Alighieri |
| |-----------------|
| | Charles Dickens |
+---------------+-----------------+
TABLE
),
'Multiple header lines' => array(
array(
array(new TableCell('Main title', array('colspan' => 3))),
array('ISBN', 'Title', 'Author'),
),
array(),
'default',
<<<'TABLE'
+------+-------+--------+
| Main title |
+------+-------+--------+
| ISBN | Title | Author |
+------+-------+--------+
TABLE
),
'Row with multiple cells' => array(
array(),
array(
array(
new TableCell('1', array('colspan' => 3)),
new TableCell('2', array('colspan' => 2)),
new TableCell('3', array('colspan' => 2)),
new TableCell('4', array('colspan' => 2)),
),
),
'default',
<<<'TABLE'
+---+--+--+---+--+---+--+---+--+
| 1 | 2 | 3 | 4 |
+---+--+--+---+--+---+--+---+--+
TABLE
),
'Coslpan and table cells with comment style' => array(
array(
new TableCell('<comment>Long Title</comment>', array('colspan' => 3)),
),
array(
array(
new TableCell('9971-5-0210-0', array('colspan' => 3)),
),
new TableSeparator(),
array(
'Dante Alighieri',
'J. R. R. Tolkien',
'J. R. R',
),
),
'default',
<<<TABLE
+-----------------+------------------+---------+
|\033[32m \033[39m\033[33mLong Title\033[39m\033[32m \033[39m|
+-----------------+------------------+---------+
| 9971-5-0210-0 |
+-----------------+------------------+---------+
| Dante Alighieri | J. R. R. Tolkien | J. R. R |
+-----------------+------------------+---------+
TABLE
,
true,
),
'Row with formatted cells containing a newline' => array(
array(),
array(
array(
new TableCell('<error>Dont break'."\n".'here</error>', array('colspan' => 2)),
),
new TableSeparator(),
array(
'foo',
new TableCell('<error>Dont break'."\n".'here</error>', array('rowspan' => 2)),
),
array(
'bar',
),
),
'default',
<<<'TABLE'
+-------+------------+
| Dont break |
| here |
+-------+------------+
| foo | Dont break |
| bar | here |
+-------+------------+
TABLE
,
true,
),
);
}
public function testRenderMultiByte()
{
$table = new Table($output = $this->getOutputStream());
$table
->setHeaders(array('■■'))
->setRows(array(array(1234)))
->setStyle('default')
;
$table->render();
$expected =
<<<'TABLE'
+------+
| ■■ |
+------+
| 1234 |
+------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testTableCellWithNumericIntValue()
{
$table = new Table($output = $this->getOutputStream());
$table->setRows(array(array(new TableCell(12345))));
$table->render();
$expected =
<<<'TABLE'
+-------+
| 12345 |
+-------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testTableCellWithNumericFloatValue()
{
$table = new Table($output = $this->getOutputStream());
$table->setRows(array(array(new TableCell(12345.01))));
$table->render();
$expected =
<<<'TABLE'
+----------+
| 12345.01 |
+----------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testStyle()
{
$style = new TableStyle();
$style
->setHorizontalBorderChar('.')
->setVerticalBorderChar('.')
->setCrossingChar('.')
;
Table::setStyleDefinition('dotfull', $style);
$table = new Table($output = $this->getOutputStream());
$table
->setHeaders(array('Foo'))
->setRows(array(array('Bar')))
->setStyle('dotfull');
$table->render();
$expected =
<<<'TABLE'
.......
. Foo .
.......
. Bar .
.......
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testRowSeparator()
{
$table = new Table($output = $this->getOutputStream());
$table
->setHeaders(array('Foo'))
->setRows(array(
array('Bar1'),
new TableSeparator(),
array('Bar2'),
new TableSeparator(),
array('Bar3'),
));
$table->render();
$expected =
<<<'TABLE'
+------+
| Foo |
+------+
| Bar1 |
+------+
| Bar2 |
+------+
| Bar3 |
+------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
$this->assertEquals($table, $table->addRow(new TableSeparator()), 'fluent interface on addRow() with a single TableSeparator() works');
}
public function testRenderMultiCalls()
{
$table = new Table($output = $this->getOutputStream());
$table->setRows(array(
array(new TableCell('foo', array('colspan' => 2))),
));
$table->render();
$table->render();
$table->render();
$expected =
<<<TABLE
+----+---+
| foo |
+----+---+
+----+---+
| foo |
+----+---+
+----+---+
| foo |
+----+---+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testColumnStyle()
{
$table = new Table($output = $this->getOutputStream());
$table
->setHeaders(array('ISBN', 'Title', 'Author', 'Price'))
->setRows(array(
array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'),
array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25'),
));
$style = new TableStyle();
$style->setPadType(STR_PAD_LEFT);
$table->setColumnStyle(3, $style);
$table->render();
$expected =
<<<TABLE
+---------------+----------------------+-----------------+--------+
| 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\InvalidArgumentException
* @expectedExceptionMessage A cell must be a TableCell, a scalar or an object implementing __toString, array given.
*/
public function testThrowsWhenTheCellInAnArray()
{
$table = new Table($output = $this->getOutputStream());
$table
->setHeaders(array('ISBN', 'Title', 'Author', 'Price'))
->setRows(array(
array('99921-58-10-7', array(), 'Dante Alighieri', '9.95'),
));
$table->render();
}
public function testColumnWidth()
{
$table = new Table($output = $this->getOutputStream());
$table
->setHeaders(array('ISBN', 'Title', 'Author', 'Price'))
->setRows(array(
array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'),
array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25'),
))
->setColumnWidth(0, 15)
->setColumnWidth(3, 10);
$style = new TableStyle();
$style->setPadType(STR_PAD_LEFT);
$table->setColumnStyle(3, $style);
$table->render();
$expected =
<<<TABLE
+-----------------+----------------------+-----------------+------------+
| 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));
}
public function testColumnWidths()
{
$table = new Table($output = $this->getOutputStream());
$table
->setHeaders(array('ISBN', 'Title', 'Author', 'Price'))
->setRows(array(
array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'),
array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25'),
))
->setColumnWidths(array(15, 0, -1, 10));
$style = new TableStyle();
$style->setPadType(STR_PAD_LEFT);
$table->setColumnStyle(3, $style);
$table->render();
$expected =
<<<TABLE
+-----------------+----------------------+-----------------+------------+
| 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\InvalidArgumentException
* @expectedExceptionMessage Style "absent" is not defined.
*/
public function testIsNotDefinedStyleException()
{
$table = new Table($this->getOutputStream());
$table->setStyle('absent');
}
/**
* @expectedException \Symfony\Component\Console\Exception\InvalidArgumentException
* @expectedExceptionMessage Style "absent" is not defined.
*/
public function testGetStyleDefinition()
{
Table::getStyleDefinition('absent');
}
public function testBoxedStyleWithColspan()
{
$boxed = new TableStyle();
$boxed
->setHorizontalBorderChar('─')
->setVerticalBorderChar('│')
->setCrossingChar('┼')
;
$table = new Table($output = $this->getOutputStream());
$table->setStyle($boxed);
$table
->setHeaders(array('ISBN', 'Title', 'Author'))
->setRows(array(
array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'),
new TableSeparator(),
array(new TableCell('This value spans 3 columns.', array('colspan' => 3))),
))
;
$table->render();
$expected =
<<<TABLE
┼───────────────┼───────────────┼─────────────────┼
ISBN Title Author
┼───────────────┼───────────────┼─────────────────┼
99921-58-10-7 Divine Comedy Dante Alighieri
┼───────────────┼───────────────┼─────────────────┼
This value spans 3 columns.
┼───────────────┼───────────────┼─────────────────┼
TABLE;
$this->assertSame($expected, $this->getOutputContent($output));
}
protected function getOutputStream($decorated = false)
{
return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, $decorated);
}
protected function getOutputContent(StreamOutput $output)
{
rewind($output->getStream());
return str_replace(PHP_EOL, "\n", stream_get_contents($output->getStream()));
}
}