TYPO3  7.6
ProgressBarTest.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11 
12 namespace Symfony\Component\Console\Tests\Helper;
13 
17 
18 class ProgressBarTest extends \PHPUnit_Framework_TestCase
19 {
20  public function testMultipleStart()
21  {
22  $bar = new ProgressBar($output = $this->getOutputStream());
23  $bar->start();
24  $bar->advance();
25  $bar->start();
26 
27  rewind($output->getStream());
28  $this->assertEquals(
29  $this->generateOutput(' 0 [>---------------------------]').
30  $this->generateOutput(' 1 [->--------------------------]').
31  $this->generateOutput(' 0 [>---------------------------]'),
32  stream_get_contents($output->getStream())
33  );
34  }
35 
36  public function testAdvance()
37  {
38  $bar = new ProgressBar($output = $this->getOutputStream());
39  $bar->start();
40  $bar->advance();
41 
42  rewind($output->getStream());
43  $this->assertEquals(
44  $this->generateOutput(' 0 [>---------------------------]').
45  $this->generateOutput(' 1 [->--------------------------]'),
46  stream_get_contents($output->getStream())
47  );
48  }
49 
50  public function testAdvanceWithStep()
51  {
52  $bar = new ProgressBar($output = $this->getOutputStream());
53  $bar->start();
54  $bar->advance(5);
55 
56  rewind($output->getStream());
57  $this->assertEquals(
58  $this->generateOutput(' 0 [>---------------------------]').
59  $this->generateOutput(' 5 [----->----------------------]'),
60  stream_get_contents($output->getStream())
61  );
62  }
63 
64  public function testAdvanceMultipleTimes()
65  {
66  $bar = new ProgressBar($output = $this->getOutputStream());
67  $bar->start();
68  $bar->advance(3);
69  $bar->advance(2);
70 
71  rewind($output->getStream());
72  $this->assertEquals(
73  $this->generateOutput(' 0 [>---------------------------]').
74  $this->generateOutput(' 3 [--->------------------------]').
75  $this->generateOutput(' 5 [----->----------------------]'),
76  stream_get_contents($output->getStream())
77  );
78  }
79 
80  public function testAdvanceOverMax()
81  {
82  $bar = new ProgressBar($output = $this->getOutputStream(), 10);
83  $bar->setProgress(9);
84  $bar->advance();
85  $bar->advance();
86 
87  rewind($output->getStream());
88  $this->assertEquals(
89  $this->generateOutput(' 9/10 [=========================>--] 90%').
90  $this->generateOutput(' 10/10 [============================] 100%').
91  $this->generateOutput(' 11/11 [============================] 100%'),
92  stream_get_contents($output->getStream())
93  );
94  }
95 
96  public function testCustomizations()
97  {
98  $bar = new ProgressBar($output = $this->getOutputStream(), 10);
99  $bar->setBarWidth(10);
100  $bar->setBarCharacter('_');
101  $bar->setEmptyBarCharacter(' ');
102  $bar->setProgressCharacter('/');
103  $bar->setFormat(' %current%/%max% [%bar%] %percent:3s%%');
104  $bar->start();
105  $bar->advance();
106 
107  rewind($output->getStream());
108  $this->assertEquals(
109  $this->generateOutput(' 0/10 [/ ] 0%').
110  $this->generateOutput(' 1/10 [_/ ] 10%'),
111  stream_get_contents($output->getStream())
112  );
113  }
114 
115  public function testDisplayWithoutStart()
116  {
117  $bar = new ProgressBar($output = $this->getOutputStream(), 50);
118  $bar->display();
119 
120  rewind($output->getStream());
121  $this->assertEquals(
122  $this->generateOutput(' 0/50 [>---------------------------] 0%'),
123  stream_get_contents($output->getStream())
124  );
125  }
126 
128  {
129  $bar = new ProgressBar($output = $this->getOutputStream(true, StreamOutput::VERBOSITY_QUIET), 50);
130  $bar->display();
131 
132  rewind($output->getStream());
133  $this->assertEquals(
134  '',
135  stream_get_contents($output->getStream())
136  );
137  }
138 
139  public function testFinishWithoutStart()
140  {
141  $bar = new ProgressBar($output = $this->getOutputStream(), 50);
142  $bar->finish();
143 
144  rewind($output->getStream());
145  $this->assertEquals(
146  $this->generateOutput(' 50/50 [============================] 100%'),
147  stream_get_contents($output->getStream())
148  );
149  }
150 
151  public function testPercent()
152  {
153  $bar = new ProgressBar($output = $this->getOutputStream(), 50);
154  $bar->start();
155  $bar->display();
156  $bar->advance();
157  $bar->advance();
158 
159  rewind($output->getStream());
160  $this->assertEquals(
161  $this->generateOutput(' 0/50 [>---------------------------] 0%').
162  $this->generateOutput(' 0/50 [>---------------------------] 0%').
163  $this->generateOutput(' 1/50 [>---------------------------] 2%').
164  $this->generateOutput(' 2/50 [=>--------------------------] 4%'),
165  stream_get_contents($output->getStream())
166  );
167  }
168 
170  {
171  $bar = new ProgressBar($output = $this->getOutputStream(), 50);
172  $bar->setFormat(' %current%/%max% [%bar%] %percent:3s%%');
173  $bar->start();
174  $bar->display();
175  $bar->advance();
176 
177  // set shorter format
178  $bar->setFormat(' %current%/%max% [%bar%]');
179  $bar->advance();
180 
181  rewind($output->getStream());
182  $this->assertEquals(
183  $this->generateOutput(' 0/50 [>---------------------------] 0%').
184  $this->generateOutput(' 0/50 [>---------------------------] 0%').
185  $this->generateOutput(' 1/50 [>---------------------------] 2%').
186  $this->generateOutput(' 2/50 [=>--------------------------] '),
187  stream_get_contents($output->getStream())
188  );
189  }
190 
191  public function testStartWithMax()
192  {
193  $bar = new ProgressBar($output = $this->getOutputStream());
194  $bar->setFormat('%current%/%max% [%bar%]');
195  $bar->start(50);
196  $bar->advance();
197 
198  rewind($output->getStream());
199  $this->assertEquals(
200  $this->generateOutput(' 0/50 [>---------------------------]').
201  $this->generateOutput(' 1/50 [>---------------------------]'),
202  stream_get_contents($output->getStream())
203  );
204  }
205 
206  public function testSetCurrentProgress()
207  {
208  $bar = new ProgressBar($output = $this->getOutputStream(), 50);
209  $bar->start();
210  $bar->display();
211  $bar->advance();
212  $bar->setProgress(15);
213  $bar->setProgress(25);
214 
215  rewind($output->getStream());
216  $this->assertEquals(
217  $this->generateOutput(' 0/50 [>---------------------------] 0%').
218  $this->generateOutput(' 0/50 [>---------------------------] 0%').
219  $this->generateOutput(' 1/50 [>---------------------------] 2%').
220  $this->generateOutput(' 15/50 [========>-------------------] 30%').
221  $this->generateOutput(' 25/50 [==============>-------------] 50%'),
222  stream_get_contents($output->getStream())
223  );
224  }
225 
229  {
230  $bar = new ProgressBar($this->getOutputStream());
231  $bar->setProgress(15);
232  $this->assertNotNull($bar->getStartTime());
233  }
234 
239  public function testRegressProgress()
240  {
241  $bar = new ProgressBar($output = $this->getOutputStream(), 50);
242  $bar->start();
243  $bar->setProgress(15);
244  $bar->setProgress(10);
245  }
246 
247  public function testRedrawFrequency()
248  {
249  $bar = $this->getMock('Symfony\Component\Console\Helper\ProgressBar', array('display'), array($output = $this->getOutputStream(), 6));
250  $bar->expects($this->exactly(4))->method('display');
251 
252  $bar->setRedrawFrequency(2);
253  $bar->start();
254  $bar->setProgress(1);
255  $bar->advance(2);
256  $bar->advance(2);
257  $bar->advance(1);
258  }
259 
260  public function testMultiByteSupport()
261  {
262  if (!function_exists('mb_strlen') || (false === $encoding = mb_detect_encoding('■'))) {
263  $this->markTestSkipped('The mbstring extension is needed for multi-byte support');
264  }
265 
266  $bar = new ProgressBar($output = $this->getOutputStream());
267  $bar->start();
268  $bar->setBarCharacter('■');
269  $bar->advance(3);
270 
271  rewind($output->getStream());
272  $this->assertEquals(
273  $this->generateOutput(' 0 [>---------------------------]').
274  $this->generateOutput(' 3 [■■■>------------------------]'),
275  stream_get_contents($output->getStream())
276  );
277  }
278 
279  public function testClear()
280  {
281  $bar = new ProgressBar($output = $this->getOutputStream(), 50);
282  $bar->start();
283  $bar->setProgress(25);
284  $bar->clear();
285 
286  rewind($output->getStream());
287  $this->assertEquals(
288  $this->generateOutput(' 0/50 [>---------------------------] 0%').
289  $this->generateOutput(' 25/50 [==============>-------------] 50%').
290  $this->generateOutput(' '),
291  stream_get_contents($output->getStream())
292  );
293  }
294 
296  {
297  $bar = new ProgressBar($output = $this->getOutputStream(), 200);
298  $bar->start();
299  $bar->display();
300  $bar->advance(199);
301  $bar->advance();
302 
303  rewind($output->getStream());
304  $this->assertEquals(
305  $this->generateOutput(' 0/200 [>---------------------------] 0%').
306  $this->generateOutput(' 0/200 [>---------------------------] 0%').
307  $this->generateOutput(' 199/200 [===========================>] 99%').
308  $this->generateOutput(' 200/200 [============================] 100%'),
309  stream_get_contents($output->getStream())
310  );
311  }
312 
313  public function testNonDecoratedOutput()
314  {
315  $bar = new ProgressBar($output = $this->getOutputStream(false), 200);
316  $bar->start();
317 
318  for ($i = 0; $i < 200; ++$i) {
319  $bar->advance();
320  }
321 
322  $bar->finish();
323 
324  rewind($output->getStream());
325  $this->assertEquals(
326  ' 0/200 [>---------------------------] 0%'.PHP_EOL.
327  ' 20/200 [==>-------------------------] 10%'.PHP_EOL.
328  ' 40/200 [=====>----------------------] 20%'.PHP_EOL.
329  ' 60/200 [========>-------------------] 30%'.PHP_EOL.
330  ' 80/200 [===========>----------------] 40%'.PHP_EOL.
331  ' 100/200 [==============>-------------] 50%'.PHP_EOL.
332  ' 120/200 [================>-----------] 60%'.PHP_EOL.
333  ' 140/200 [===================>--------] 70%'.PHP_EOL.
334  ' 160/200 [======================>-----] 80%'.PHP_EOL.
335  ' 180/200 [=========================>--] 90%'.PHP_EOL.
336  ' 200/200 [============================] 100%',
337  stream_get_contents($output->getStream())
338  );
339  }
340 
342  {
343  $bar = new ProgressBar($output = $this->getOutputStream(false), 50);
344  $bar->start();
345  $bar->setProgress(25);
346  $bar->clear();
347  $bar->setProgress(50);
348  $bar->finish();
349 
350  rewind($output->getStream());
351  $this->assertEquals(
352  ' 0/50 [>---------------------------] 0%'.PHP_EOL.
353  ' 25/50 [==============>-------------] 50%'.PHP_EOL.
354  ' 50/50 [============================] 100%',
355  stream_get_contents($output->getStream())
356  );
357  }
358 
360  {
361  $bar = new ProgressBar($output = $this->getOutputStream(false));
362  $bar->start();
363  $bar->advance();
364 
365  rewind($output->getStream());
366  $this->assertEquals(
367  ' 0 [>---------------------------]'.PHP_EOL.
368  ' 1 [->--------------------------]',
369  stream_get_contents($output->getStream())
370  );
371  }
372 
373  public function testParallelBars()
374  {
375  $output = $this->getOutputStream();
376  $bar1 = new ProgressBar($output, 2);
377  $bar2 = new ProgressBar($output, 3);
378  $bar2->setProgressCharacter('#');
379  $bar3 = new ProgressBar($output);
380 
381  $bar1->start();
382  $output->write("\n");
383  $bar2->start();
384  $output->write("\n");
385  $bar3->start();
386 
387  for ($i = 1; $i <= 3; ++$i) {
388  // up two lines
389  $output->write("\033[2A");
390  if ($i <= 2) {
391  $bar1->advance();
392  }
393  $output->write("\n");
394  $bar2->advance();
395  $output->write("\n");
396  $bar3->advance();
397  }
398  $output->write("\033[2A");
399  $output->write("\n");
400  $output->write("\n");
401  $bar3->finish();
402 
403  rewind($output->getStream());
404  $this->assertEquals(
405  $this->generateOutput(' 0/2 [>---------------------------] 0%')."\n".
406  $this->generateOutput(' 0/3 [#---------------------------] 0%')."\n".
407  rtrim($this->generateOutput(' 0 [>---------------------------]')).
408 
409  "\033[2A".
410  $this->generateOutput(' 1/2 [==============>-------------] 50%')."\n".
411  $this->generateOutput(' 1/3 [=========#------------------] 33%')."\n".
412  rtrim($this->generateOutput(' 1 [->--------------------------]')).
413 
414  "\033[2A".
415  $this->generateOutput(' 2/2 [============================] 100%')."\n".
416  $this->generateOutput(' 2/3 [==================#---------] 66%')."\n".
417  rtrim($this->generateOutput(' 2 [-->-------------------------]')).
418 
419  "\033[2A".
420  "\n".
421  $this->generateOutput(' 3/3 [============================] 100%')."\n".
422  rtrim($this->generateOutput(' 3 [--->------------------------]')).
423 
424  "\033[2A".
425  "\n".
426  "\n".
427  rtrim($this->generateOutput(' 3 [============================]')),
428  stream_get_contents($output->getStream())
429  );
430  }
431 
432  public function testWithoutMax()
433  {
434  $output = $this->getOutputStream();
435 
436  $bar = new ProgressBar($output);
437  $bar->start();
438  $bar->advance();
439  $bar->advance();
440  $bar->advance();
441  $bar->finish();
442 
443  rewind($output->getStream());
444  $this->assertEquals(
445  rtrim($this->generateOutput(' 0 [>---------------------------]')).
446  rtrim($this->generateOutput(' 1 [->--------------------------]')).
447  rtrim($this->generateOutput(' 2 [-->-------------------------]')).
448  rtrim($this->generateOutput(' 3 [--->------------------------]')).
449  rtrim($this->generateOutput(' 3 [============================]')),
450  stream_get_contents($output->getStream())
451  );
452  }
453 
455  {
456  ProgressBar::setPlaceholderFormatterDefinition('remaining_steps', function (ProgressBar $bar) {
457  return $bar->getMaxSteps() - $bar->getProgress();
458  });
459  $bar = new ProgressBar($output = $this->getOutputStream(), 3);
460  $bar->setFormat(' %remaining_steps% [%bar%]');
461 
462  $bar->start();
463  $bar->advance();
464  $bar->finish();
465 
466  rewind($output->getStream());
467  $this->assertEquals(
468  $this->generateOutput(' 3 [>---------------------------]').
469  $this->generateOutput(' 2 [=========>------------------]').
470  $this->generateOutput(' 0 [============================]'),
471  stream_get_contents($output->getStream())
472  );
473  }
474 
475  public function testMultilineFormat()
476  {
477  $bar = new ProgressBar($output = $this->getOutputStream(), 3);
478  $bar->setFormat("%bar%\nfoobar");
479 
480  $bar->start();
481  $bar->advance();
482  $bar->clear();
483  $bar->finish();
484 
485  rewind($output->getStream());
486  $this->assertEquals(
487  $this->generateOutput(">---------------------------\nfoobar").
488  $this->generateOutput("=========>------------------\nfoobar ").
489  $this->generateOutput(" \n ").
490  $this->generateOutput("============================\nfoobar "),
491  stream_get_contents($output->getStream())
492  );
493  }
494 
498  public function testAnsiColorsAndEmojis()
499  {
500  $bar = new ProgressBar($output = $this->getOutputStream(), 15);
502  static $i = 0;
503  $mem = 100000 * $i;
504  $colors = $i++ ? '41;37' : '44;37';
505 
506  return "\033[".$colors.'m '.Helper::formatMemory($mem)." \033[0m";
507  });
508  $bar->setFormat(" \033[44;37m %title:-37s% \033[0m\n %current%/%max% %bar% %percent:3s%%\n 🏁 %remaining:-10s% %memory:37s%");
509  $bar->setBarCharacter($done = "\033[32m●\033[0m");
510  $bar->setEmptyBarCharacter($empty = "\033[31m●\033[0m");
511  $bar->setProgressCharacter($progress = "\033[32m➤ \033[0m");
512 
513  $bar->setMessage('Starting the demo... fingers crossed', 'title');
514  $bar->start();
515  $bar->setMessage('Looks good to me...', 'title');
516  $bar->advance(4);
517  $bar->setMessage('Thanks, bye', 'title');
518  $bar->finish();
519 
520  rewind($output->getStream());
521  $this->assertEquals(
522  $this->generateOutput(
523  " \033[44;37m Starting the demo... fingers crossed \033[0m\n".
524  ' 0/15 '.$progress.str_repeat($empty, 26)." 0%\n".
525  " \xf0\x9f\x8f\x81 1 sec \033[44;37m 0 B \033[0m"
526  ).
527  $this->generateOutput(
528  " \033[44;37m Looks good to me... \033[0m\n".
529  ' 4/15 '.str_repeat($done, 7).$progress.str_repeat($empty, 19)." 26%\n".
530  " \xf0\x9f\x8f\x81 1 sec \033[41;37m 97 KiB \033[0m"
531  ).
532  $this->generateOutput(
533  " \033[44;37m Thanks, bye \033[0m\n".
534  ' 15/15 '.str_repeat($done, 28)." 100%\n".
535  " \xf0\x9f\x8f\x81 1 sec \033[41;37m 195 KiB \033[0m"
536  ),
537  stream_get_contents($output->getStream())
538  );
539  }
540 
541  public function testSetFormat()
542  {
543  $bar = new ProgressBar($output = $this->getOutputStream());
544  $bar->setFormat('normal');
545  $bar->start();
546  rewind($output->getStream());
547  $this->assertEquals(
548  $this->generateOutput(' 0 [>---------------------------]'),
549  stream_get_contents($output->getStream())
550  );
551 
552  $bar = new ProgressBar($output = $this->getOutputStream(), 10);
553  $bar->setFormat('normal');
554  $bar->start();
555  rewind($output->getStream());
556  $this->assertEquals(
557  $this->generateOutput(' 0/10 [>---------------------------] 0%'),
558  stream_get_contents($output->getStream())
559  );
560  }
561 
565  public function testFormatsWithoutMax($format)
566  {
567  $bar = new ProgressBar($output = $this->getOutputStream());
568  $bar->setFormat($format);
569  $bar->start();
570 
571  rewind($output->getStream());
572  $this->assertNotEmpty(stream_get_contents($output->getStream()));
573  }
574 
580  public function provideFormat()
581  {
582  return array(
583  array('normal'),
584  array('verbose'),
585  array('very_verbose'),
586  array('debug'),
587  );
588  }
589 
590  protected function getOutputStream($decorated = true, $verbosity = StreamOutput::VERBOSITY_NORMAL)
591  {
592  return new StreamOutput(fopen('php://memory', 'r+', false), $verbosity, $decorated);
593  }
594 
595  protected function generateOutput($expected)
596  {
597  $count = substr_count($expected, "\n");
598 
599  return "\x0D".($count ? sprintf("\033[%dA", $count) : '').$expected;
600  }
601 }