/vendor/symfony/console/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php

https://gitlab.com/techniconline/kmc · PHP · 598 lines · 496 code · 78 blank · 24 comment · 5 complexity · f1eba3e9d724ad144f62830bf94c2680 MD5 · raw file

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