[Console][ProgressBar] Developer experience

- Create getProgress/setProgress methods to replace getStep/setCurrent
 - ProgressBar::setCurrent should auto-start the ProgressBar.
 - You should be able to pass max to start
 - getStepWidth is internal information that should not be public
 - when verbosity set to quiet, the progress bar does not even need to
   execute all the logic to generate output that is then thrown away
This commit is contained in:
Stefano Sala 2014-07-07 15:59:31 +02:00
parent 27a2280d29
commit 73ca340827
2 changed files with 98 additions and 21 deletions

View File

@ -55,6 +55,10 @@ class ProgressBar
*/ */
public function __construct(OutputInterface $output, $max = 0) public function __construct(OutputInterface $output, $max = 0)
{ {
if (!is_integer($max) || $max < 0) {
throw new \InvalidArgumentException('Max steps should be a positive integer, 0 or null. Got "%s".', $max);
}
// Disabling output when it does not support ANSI codes as it would result in a broken display anyway. // Disabling output when it does not support ANSI codes as it would result in a broken display anyway.
$this->output = $output->isDecorated() ? $output : new NullOutput(); $this->output = $output->isDecorated() ? $output : new NullOutput();
$this->max = (int) $max; $this->max = (int) $max;
@ -69,6 +73,12 @@ class ProgressBar
} }
$this->setFormat($this->determineBestFormat()); $this->setFormat($this->determineBestFormat());
$this->startTime = time();
$this->step = 0;
$this->percent = 0;
$this->lastMessagesLength = 0;
$this->barCharOriginal = '';
} }
/** /**
@ -170,9 +180,21 @@ class ProgressBar
/** /**
* Gets the progress bar step. * Gets the progress bar step.
* *
* @deprecated since 2.6, to be removed in 3.0. Use {@link getCurrent()} instead.
*
* @return int The progress bar step * @return int The progress bar step
*/ */
public function getStep() public function getStep()
{
return $this->getCurrent();
}
/**
* Gets the progress bar step.
*
* @return int The progress bar step
*/
public function getCurrent()
{ {
return $this->step; return $this->step;
} }
@ -180,6 +202,8 @@ class ProgressBar
/** /**
* Gets the progress bar step width. * Gets the progress bar step width.
* *
* @deprecated since 2.6, it will be marked private from 3.0.
*
* @return int The progress bar step width * @return int The progress bar step width
*/ */
public function getStepWidth() public function getStepWidth()
@ -308,14 +332,15 @@ class ProgressBar
/** /**
* Starts the progress output. * Starts the progress output.
*
* @param int $max Maximum Step (0 if unknown)
*/ */
public function start() public function start($max = 0)
{ {
$this->startTime = time(); if (0 !== $max) {
$this->step = 0; $this->max = $max;
$this->percent = 0; $this->stepWidth = $this->max > 0 ? Helper::strlen($this->max) : 4;
$this->lastMessagesLength = 0; }
$this->barCharOriginal = '';
if (!$this->max) { if (!$this->max) {
$this->barCharOriginal = $this->barChar; $this->barCharOriginal = $this->barChar;
@ -346,10 +371,6 @@ class ProgressBar
*/ */
public function setCurrent($step) public function setCurrent($step)
{ {
if (null === $this->startTime) {
throw new \LogicException('You must start the progress bar before calling setCurrent().');
}
$step = (int) $step; $step = (int) $step;
if ($step < $this->step) { if ($step < $this->step) {
throw new \LogicException('You can\'t regress the progress bar.'); throw new \LogicException('You can\'t regress the progress bar.');
@ -373,10 +394,6 @@ class ProgressBar
*/ */
public function finish() public function finish()
{ {
if (null === $this->startTime) {
throw new \LogicException('You must start the progress bar before calling finish().');
}
if (!$this->max) { if (!$this->max) {
$this->barChar = $this->barCharOriginal; $this->barChar = $this->barCharOriginal;
$this->max = $this->step; $this->max = $this->step;
@ -397,8 +414,8 @@ class ProgressBar
*/ */
public function display() public function display()
{ {
if (null === $this->startTime) { if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
throw new \LogicException('You must start the progress bar before calling display().'); return;
} }
// these 3 variables can be removed in favor of using $this in the closure when support for PHP 5.3 will be dropped. // these 3 variables can be removed in favor of using $this in the closure when support for PHP 5.3 will be dropped.

View File

@ -19,6 +19,14 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase
{ {
protected $lastMessagesLength; protected $lastMessagesLength;
/**
* @expectedException InvalidArgumentException
*/
public function testInitializeWithNegativeMax()
{
$bar = new ProgressBar($output = $this->getOutputStream(), -1);
}
public function testAdvance() public function testAdvance()
{ {
$bar = new ProgressBar($output = $this->getOutputStream()); $bar = new ProgressBar($output = $this->getOutputStream());
@ -82,6 +90,42 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase
); );
} }
public function testDisplayWithoutStart()
{
$bar = new ProgressBar($output = $this->getOutputStream(), 50);
$bar->display();
rewind($output->getStream());
$this->assertEquals(
$this->generateOutput(' 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(
$this->generateOutput(' 50/50 [============================] 100%'),
stream_get_contents($output->getStream())
);
}
public function testPercent() public function testPercent()
{ {
$bar = new ProgressBar($output = $this->getOutputStream(), 50); $bar = new ProgressBar($output = $this->getOutputStream(), 50);
@ -122,6 +166,23 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase
); );
} }
public function testStartWithMax()
{
$bar = new ProgressBar($output = $this->getOutputStream());
$bar->setFormat('%current%/%max% [%bar%]');
$bar->start(50);
$bar->display();
$bar->advance();
rewind($output->getStream());
$this->assertEquals(
$this->generateOutput(' 0/50 [>---------------------------]').
$this->generateOutput(' 0/50 [>---------------------------]').
$this->generateOutput(' 1/50 [>---------------------------]'),
stream_get_contents($output->getStream())
);
}
public function testSetCurrentProgress() public function testSetCurrentProgress()
{ {
$bar = new ProgressBar($output = $this->getOutputStream(), 50); $bar = new ProgressBar($output = $this->getOutputStream(), 50);
@ -143,13 +204,12 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase
} }
/** /**
* @expectedException \LogicException
* @expectedExceptionMessage You must start the progress bar
*/ */
public function testSetCurrentBeforeStarting() public function testSetCurrentBeforeStarting()
{ {
$bar = new ProgressBar($this->getOutputStream()); $bar = new ProgressBar($this->getOutputStream());
$bar->setCurrent(15); $bar->setCurrent(15);
$this->assertNotNull($bar->getStartTime());
} }
/** /**
@ -302,7 +362,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase
public function testAddingPlaceholderFormatter() public function testAddingPlaceholderFormatter()
{ {
ProgressBar::setPlaceholderFormatterDefinition('remaining_steps', function (ProgressBar $bar) { ProgressBar::setPlaceholderFormatterDefinition('remaining_steps', function (ProgressBar $bar) {
return $bar->getMaxSteps() - $bar->getStep(); return $bar->getMaxSteps() - $bar->getCurrent();
}); });
$bar = new ProgressBar($output = $this->getOutputStream(), 3); $bar = new ProgressBar($output = $this->getOutputStream(), 3);
$bar->setFormat(' %remaining_steps% [%bar%]'); $bar->setFormat(' %remaining_steps% [%bar%]');
@ -432,9 +492,9 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase
); );
} }
protected function getOutputStream($decorated = true) protected function getOutputStream($decorated = true, $verbosity = StreamOutput::VERBOSITY_NORMAL)
{ {
return new StreamOutput(fopen('php://memory', 'r+', false), StreamOutput::VERBOSITY_NORMAL, $decorated); return new StreamOutput(fopen('php://memory', 'r+', false), $verbosity, $decorated);
} }
protected function generateOutput($expected) protected function generateOutput($expected)