ProgressBarTest.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  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 PHPUnit\Framework\TestCase;
  12. use Symfony\Component\Console\Helper\Helper;
  13. use Symfony\Component\Console\Helper\ProgressBar;
  14. use Symfony\Component\Console\Output\StreamOutput;
  15. /**
  16. * @group time-sensitive
  17. */
  18. class ProgressBarTest extends TestCase
  19. {
  20. private $colSize;
  21. protected function setUp()
  22. {
  23. $this->colSize = getenv('COLUMNS');
  24. putenv('COLUMNS=120');
  25. }
  26. protected function tearDown()
  27. {
  28. putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS');
  29. }
  30. public function testMultipleStart()
  31. {
  32. $bar = new ProgressBar($output = $this->getOutputStream());
  33. $bar->start();
  34. $bar->advance();
  35. $bar->start();
  36. rewind($output->getStream());
  37. $this->assertEquals(
  38. ' 0 [>---------------------------]'.
  39. $this->generateOutput(' 1 [->--------------------------]').
  40. $this->generateOutput(' 0 [>---------------------------]'),
  41. stream_get_contents($output->getStream())
  42. );
  43. }
  44. public function testAdvance()
  45. {
  46. $bar = new ProgressBar($output = $this->getOutputStream());
  47. $bar->start();
  48. $bar->advance();
  49. rewind($output->getStream());
  50. $this->assertEquals(
  51. ' 0 [>---------------------------]'.
  52. $this->generateOutput(' 1 [->--------------------------]'),
  53. stream_get_contents($output->getStream())
  54. );
  55. }
  56. public function testAdvanceWithStep()
  57. {
  58. $bar = new ProgressBar($output = $this->getOutputStream());
  59. $bar->start();
  60. $bar->advance(5);
  61. rewind($output->getStream());
  62. $this->assertEquals(
  63. ' 0 [>---------------------------]'.
  64. $this->generateOutput(' 5 [----->----------------------]'),
  65. stream_get_contents($output->getStream())
  66. );
  67. }
  68. public function testAdvanceMultipleTimes()
  69. {
  70. $bar = new ProgressBar($output = $this->getOutputStream());
  71. $bar->start();
  72. $bar->advance(3);
  73. $bar->advance(2);
  74. rewind($output->getStream());
  75. $this->assertEquals(
  76. ' 0 [>---------------------------]'.
  77. $this->generateOutput(' 3 [--->------------------------]').
  78. $this->generateOutput(' 5 [----->----------------------]'),
  79. stream_get_contents($output->getStream())
  80. );
  81. }
  82. public function testAdvanceOverMax()
  83. {
  84. $bar = new ProgressBar($output = $this->getOutputStream(), 10);
  85. $bar->setProgress(9);
  86. $bar->advance();
  87. $bar->advance();
  88. rewind($output->getStream());
  89. $this->assertEquals(
  90. ' 9/10 [=========================>--] 90%'.
  91. $this->generateOutput(' 10/10 [============================] 100%').
  92. $this->generateOutput(' 11/11 [============================] 100%'),
  93. stream_get_contents($output->getStream())
  94. );
  95. }
  96. public function testRegress()
  97. {
  98. $bar = new ProgressBar($output = $this->getOutputStream());
  99. $bar->start();
  100. $bar->advance();
  101. $bar->advance();
  102. $bar->advance(-1);
  103. rewind($output->getStream());
  104. $this->assertEquals(
  105. ' 0 [>---------------------------]'.
  106. $this->generateOutput(' 1 [->--------------------------]').
  107. $this->generateOutput(' 2 [-->-------------------------]').
  108. $this->generateOutput(' 1 [->--------------------------]'),
  109. stream_get_contents($output->getStream())
  110. );
  111. }
  112. public function testRegressWithStep()
  113. {
  114. $bar = new ProgressBar($output = $this->getOutputStream());
  115. $bar->start();
  116. $bar->advance(4);
  117. $bar->advance(4);
  118. $bar->advance(-2);
  119. rewind($output->getStream());
  120. $this->assertEquals(
  121. ' 0 [>---------------------------]'.
  122. $this->generateOutput(' 4 [---->-----------------------]').
  123. $this->generateOutput(' 8 [-------->-------------------]').
  124. $this->generateOutput(' 6 [------>---------------------]'),
  125. stream_get_contents($output->getStream())
  126. );
  127. }
  128. public function testRegressMultipleTimes()
  129. {
  130. $bar = new ProgressBar($output = $this->getOutputStream());
  131. $bar->start();
  132. $bar->advance(3);
  133. $bar->advance(3);
  134. $bar->advance(-1);
  135. $bar->advance(-2);
  136. rewind($output->getStream());
  137. $this->assertEquals(
  138. ' 0 [>---------------------------]'.
  139. $this->generateOutput(' 3 [--->------------------------]').
  140. $this->generateOutput(' 6 [------>---------------------]').
  141. $this->generateOutput(' 5 [----->----------------------]').
  142. $this->generateOutput(' 3 [--->------------------------]'),
  143. stream_get_contents($output->getStream())
  144. );
  145. }
  146. public function testRegressBelowMin()
  147. {
  148. $bar = new ProgressBar($output = $this->getOutputStream(), 10);
  149. $bar->setProgress(1);
  150. $bar->advance(-1);
  151. $bar->advance(-1);
  152. rewind($output->getStream());
  153. $this->assertEquals(
  154. ' 1/10 [==>-------------------------] 10%'.
  155. $this->generateOutput(' 0/10 [>---------------------------] 0%'),
  156. stream_get_contents($output->getStream())
  157. );
  158. }
  159. public function testFormat()
  160. {
  161. $expected =
  162. ' 0/10 [>---------------------------] 0%'.
  163. $this->generateOutput(' 10/10 [============================] 100%').
  164. $this->generateOutput(' 10/10 [============================] 100%')
  165. ;
  166. // max in construct, no format
  167. $bar = new ProgressBar($output = $this->getOutputStream(), 10);
  168. $bar->start();
  169. $bar->advance(10);
  170. $bar->finish();
  171. rewind($output->getStream());
  172. $this->assertEquals($expected, stream_get_contents($output->getStream()));
  173. // max in start, no format
  174. $bar = new ProgressBar($output = $this->getOutputStream());
  175. $bar->start(10);
  176. $bar->advance(10);
  177. $bar->finish();
  178. rewind($output->getStream());
  179. $this->assertEquals($expected, stream_get_contents($output->getStream()));
  180. // max in construct, explicit format before
  181. $bar = new ProgressBar($output = $this->getOutputStream(), 10);
  182. $bar->setFormat('normal');
  183. $bar->start();
  184. $bar->advance(10);
  185. $bar->finish();
  186. rewind($output->getStream());
  187. $this->assertEquals($expected, stream_get_contents($output->getStream()));
  188. // max in start, explicit format before
  189. $bar = new ProgressBar($output = $this->getOutputStream());
  190. $bar->setFormat('normal');
  191. $bar->start(10);
  192. $bar->advance(10);
  193. $bar->finish();
  194. rewind($output->getStream());
  195. $this->assertEquals($expected, stream_get_contents($output->getStream()));
  196. }
  197. public function testCustomizations()
  198. {
  199. $bar = new ProgressBar($output = $this->getOutputStream(), 10);
  200. $bar->setBarWidth(10);
  201. $bar->setBarCharacter('_');
  202. $bar->setEmptyBarCharacter(' ');
  203. $bar->setProgressCharacter('/');
  204. $bar->setFormat(' %current%/%max% [%bar%] %percent:3s%%');
  205. $bar->start();
  206. $bar->advance();
  207. rewind($output->getStream());
  208. $this->assertEquals(
  209. ' 0/10 [/ ] 0%'.
  210. $this->generateOutput(' 1/10 [_/ ] 10%'),
  211. stream_get_contents($output->getStream())
  212. );
  213. }
  214. public function testDisplayWithoutStart()
  215. {
  216. $bar = new ProgressBar($output = $this->getOutputStream(), 50);
  217. $bar->display();
  218. rewind($output->getStream());
  219. $this->assertEquals(
  220. ' 0/50 [>---------------------------] 0%',
  221. stream_get_contents($output->getStream())
  222. );
  223. }
  224. public function testDisplayWithQuietVerbosity()
  225. {
  226. $bar = new ProgressBar($output = $this->getOutputStream(true, StreamOutput::VERBOSITY_QUIET), 50);
  227. $bar->display();
  228. rewind($output->getStream());
  229. $this->assertEquals(
  230. '',
  231. stream_get_contents($output->getStream())
  232. );
  233. }
  234. public function testFinishWithoutStart()
  235. {
  236. $bar = new ProgressBar($output = $this->getOutputStream(), 50);
  237. $bar->finish();
  238. rewind($output->getStream());
  239. $this->assertEquals(
  240. ' 50/50 [============================] 100%',
  241. stream_get_contents($output->getStream())
  242. );
  243. }
  244. public function testPercent()
  245. {
  246. $bar = new ProgressBar($output = $this->getOutputStream(), 50);
  247. $bar->start();
  248. $bar->display();
  249. $bar->advance();
  250. $bar->advance();
  251. rewind($output->getStream());
  252. $this->assertEquals(
  253. ' 0/50 [>---------------------------] 0%'.
  254. $this->generateOutput(' 0/50 [>---------------------------] 0%').
  255. $this->generateOutput(' 1/50 [>---------------------------] 2%').
  256. $this->generateOutput(' 2/50 [=>--------------------------] 4%'),
  257. stream_get_contents($output->getStream())
  258. );
  259. }
  260. public function testOverwriteWithShorterLine()
  261. {
  262. $bar = new ProgressBar($output = $this->getOutputStream(), 50);
  263. $bar->setFormat(' %current%/%max% [%bar%] %percent:3s%%');
  264. $bar->start();
  265. $bar->display();
  266. $bar->advance();
  267. // set shorter format
  268. $bar->setFormat(' %current%/%max% [%bar%]');
  269. $bar->advance();
  270. rewind($output->getStream());
  271. $this->assertEquals(
  272. ' 0/50 [>---------------------------] 0%'.
  273. $this->generateOutput(' 0/50 [>---------------------------] 0%').
  274. $this->generateOutput(' 1/50 [>---------------------------] 2%').
  275. $this->generateOutput(' 2/50 [=>--------------------------]'),
  276. stream_get_contents($output->getStream())
  277. );
  278. }
  279. public function testStartWithMax()
  280. {
  281. $bar = new ProgressBar($output = $this->getOutputStream());
  282. $bar->setFormat('%current%/%max% [%bar%]');
  283. $bar->start(50);
  284. $bar->advance();
  285. rewind($output->getStream());
  286. $this->assertEquals(
  287. ' 0/50 [>---------------------------]'.
  288. $this->generateOutput(' 1/50 [>---------------------------]'),
  289. stream_get_contents($output->getStream())
  290. );
  291. }
  292. public function testSetCurrentProgress()
  293. {
  294. $bar = new ProgressBar($output = $this->getOutputStream(), 50);
  295. $bar->start();
  296. $bar->display();
  297. $bar->advance();
  298. $bar->setProgress(15);
  299. $bar->setProgress(25);
  300. rewind($output->getStream());
  301. $this->assertEquals(
  302. ' 0/50 [>---------------------------] 0%'.
  303. $this->generateOutput(' 0/50 [>---------------------------] 0%').
  304. $this->generateOutput(' 1/50 [>---------------------------] 2%').
  305. $this->generateOutput(' 15/50 [========>-------------------] 30%').
  306. $this->generateOutput(' 25/50 [==============>-------------] 50%'),
  307. stream_get_contents($output->getStream())
  308. );
  309. }
  310. public function testSetCurrentBeforeStarting()
  311. {
  312. $bar = new ProgressBar($this->getOutputStream());
  313. $bar->setProgress(15);
  314. $this->assertNotNull($bar->getStartTime());
  315. }
  316. public function testRedrawFrequency()
  317. {
  318. $bar = new ProgressBar($output = $this->getOutputStream(), 6);
  319. $bar->setRedrawFrequency(2);
  320. $bar->start();
  321. $bar->setProgress(1);
  322. $bar->advance(2);
  323. $bar->advance(2);
  324. $bar->advance(1);
  325. rewind($output->getStream());
  326. $this->assertEquals(
  327. ' 0/6 [>---------------------------] 0%'.
  328. $this->generateOutput(' 3/6 [==============>-------------] 50%').
  329. $this->generateOutput(' 5/6 [=======================>----] 83%').
  330. $this->generateOutput(' 6/6 [============================] 100%'),
  331. stream_get_contents($output->getStream())
  332. );
  333. }
  334. public function testRedrawFrequencyIsAtLeastOneIfZeroGiven()
  335. {
  336. $bar = new ProgressBar($output = $this->getOutputStream());
  337. $bar->setRedrawFrequency(0);
  338. $bar->start();
  339. $bar->advance();
  340. rewind($output->getStream());
  341. $this->assertEquals(
  342. ' 0 [>---------------------------]'.
  343. $this->generateOutput(' 1 [->--------------------------]'),
  344. stream_get_contents($output->getStream())
  345. );
  346. }
  347. public function testRedrawFrequencyIsAtLeastOneIfSmallerOneGiven()
  348. {
  349. $bar = new ProgressBar($output = $this->getOutputStream());
  350. $bar->setRedrawFrequency(0.9);
  351. $bar->start();
  352. $bar->advance();
  353. rewind($output->getStream());
  354. $this->assertEquals(
  355. ' 0 [>---------------------------]'.
  356. $this->generateOutput(' 1 [->--------------------------]'),
  357. stream_get_contents($output->getStream())
  358. );
  359. }
  360. public function testMultiByteSupport()
  361. {
  362. $bar = new ProgressBar($output = $this->getOutputStream());
  363. $bar->start();
  364. $bar->setBarCharacter('■');
  365. $bar->advance(3);
  366. rewind($output->getStream());
  367. $this->assertEquals(
  368. ' 0 [>---------------------------]'.
  369. $this->generateOutput(' 3 [■■■>------------------------]'),
  370. stream_get_contents($output->getStream())
  371. );
  372. }
  373. public function testClear()
  374. {
  375. $bar = new ProgressBar($output = $this->getOutputStream(), 50);
  376. $bar->start();
  377. $bar->setProgress(25);
  378. $bar->clear();
  379. rewind($output->getStream());
  380. $this->assertEquals(
  381. ' 0/50 [>---------------------------] 0%'.
  382. $this->generateOutput(' 25/50 [==============>-------------] 50%').
  383. $this->generateOutput(''),
  384. stream_get_contents($output->getStream())
  385. );
  386. }
  387. public function testPercentNotHundredBeforeComplete()
  388. {
  389. $bar = new ProgressBar($output = $this->getOutputStream(), 200);
  390. $bar->start();
  391. $bar->display();
  392. $bar->advance(199);
  393. $bar->advance();
  394. rewind($output->getStream());
  395. $this->assertEquals(
  396. ' 0/200 [>---------------------------] 0%'.
  397. $this->generateOutput(' 0/200 [>---------------------------] 0%').
  398. $this->generateOutput(' 199/200 [===========================>] 99%').
  399. $this->generateOutput(' 200/200 [============================] 100%'),
  400. stream_get_contents($output->getStream())
  401. );
  402. }
  403. public function testNonDecoratedOutput()
  404. {
  405. $bar = new ProgressBar($output = $this->getOutputStream(false), 200);
  406. $bar->start();
  407. for ($i = 0; $i < 200; ++$i) {
  408. $bar->advance();
  409. }
  410. $bar->finish();
  411. rewind($output->getStream());
  412. $this->assertEquals(
  413. ' 0/200 [>---------------------------] 0%'.PHP_EOL.
  414. ' 20/200 [==>-------------------------] 10%'.PHP_EOL.
  415. ' 40/200 [=====>----------------------] 20%'.PHP_EOL.
  416. ' 60/200 [========>-------------------] 30%'.PHP_EOL.
  417. ' 80/200 [===========>----------------] 40%'.PHP_EOL.
  418. ' 100/200 [==============>-------------] 50%'.PHP_EOL.
  419. ' 120/200 [================>-----------] 60%'.PHP_EOL.
  420. ' 140/200 [===================>--------] 70%'.PHP_EOL.
  421. ' 160/200 [======================>-----] 80%'.PHP_EOL.
  422. ' 180/200 [=========================>--] 90%'.PHP_EOL.
  423. ' 200/200 [============================] 100%',
  424. stream_get_contents($output->getStream())
  425. );
  426. }
  427. public function testNonDecoratedOutputWithClear()
  428. {
  429. $bar = new ProgressBar($output = $this->getOutputStream(false), 50);
  430. $bar->start();
  431. $bar->setProgress(25);
  432. $bar->clear();
  433. $bar->setProgress(50);
  434. $bar->finish();
  435. rewind($output->getStream());
  436. $this->assertEquals(
  437. ' 0/50 [>---------------------------] 0%'.PHP_EOL.
  438. ' 25/50 [==============>-------------] 50%'.PHP_EOL.
  439. ' 50/50 [============================] 100%',
  440. stream_get_contents($output->getStream())
  441. );
  442. }
  443. public function testNonDecoratedOutputWithoutMax()
  444. {
  445. $bar = new ProgressBar($output = $this->getOutputStream(false));
  446. $bar->start();
  447. $bar->advance();
  448. rewind($output->getStream());
  449. $this->assertEquals(
  450. ' 0 [>---------------------------]'.PHP_EOL.
  451. ' 1 [->--------------------------]',
  452. stream_get_contents($output->getStream())
  453. );
  454. }
  455. public function testParallelBars()
  456. {
  457. $output = $this->getOutputStream();
  458. $bar1 = new ProgressBar($output, 2);
  459. $bar2 = new ProgressBar($output, 3);
  460. $bar2->setProgressCharacter('#');
  461. $bar3 = new ProgressBar($output);
  462. $bar1->start();
  463. $output->write("\n");
  464. $bar2->start();
  465. $output->write("\n");
  466. $bar3->start();
  467. for ($i = 1; $i <= 3; ++$i) {
  468. // up two lines
  469. $output->write("\033[2A");
  470. if ($i <= 2) {
  471. $bar1->advance();
  472. }
  473. $output->write("\n");
  474. $bar2->advance();
  475. $output->write("\n");
  476. $bar3->advance();
  477. }
  478. $output->write("\033[2A");
  479. $output->write("\n");
  480. $output->write("\n");
  481. $bar3->finish();
  482. rewind($output->getStream());
  483. $this->assertEquals(
  484. ' 0/2 [>---------------------------] 0%'."\n".
  485. ' 0/3 [#---------------------------] 0%'."\n".
  486. rtrim(' 0 [>---------------------------]').
  487. "\033[2A".
  488. $this->generateOutput(' 1/2 [==============>-------------] 50%')."\n".
  489. $this->generateOutput(' 1/3 [=========#------------------] 33%')."\n".
  490. rtrim($this->generateOutput(' 1 [->--------------------------]')).
  491. "\033[2A".
  492. $this->generateOutput(' 2/2 [============================] 100%')."\n".
  493. $this->generateOutput(' 2/3 [==================#---------] 66%')."\n".
  494. rtrim($this->generateOutput(' 2 [-->-------------------------]')).
  495. "\033[2A".
  496. "\n".
  497. $this->generateOutput(' 3/3 [============================] 100%')."\n".
  498. rtrim($this->generateOutput(' 3 [--->------------------------]')).
  499. "\033[2A".
  500. "\n".
  501. "\n".
  502. rtrim($this->generateOutput(' 3 [============================]')),
  503. stream_get_contents($output->getStream())
  504. );
  505. }
  506. public function testWithoutMax()
  507. {
  508. $output = $this->getOutputStream();
  509. $bar = new ProgressBar($output);
  510. $bar->start();
  511. $bar->advance();
  512. $bar->advance();
  513. $bar->advance();
  514. $bar->finish();
  515. rewind($output->getStream());
  516. $this->assertEquals(
  517. rtrim(' 0 [>---------------------------]').
  518. rtrim($this->generateOutput(' 1 [->--------------------------]')).
  519. rtrim($this->generateOutput(' 2 [-->-------------------------]')).
  520. rtrim($this->generateOutput(' 3 [--->------------------------]')).
  521. rtrim($this->generateOutput(' 3 [============================]')),
  522. stream_get_contents($output->getStream())
  523. );
  524. }
  525. public function testWithSmallScreen()
  526. {
  527. $output = $this->getOutputStream();
  528. $bar = new ProgressBar($output);
  529. putenv('COLUMNS=12');
  530. $bar->start();
  531. $bar->advance();
  532. putenv('COLUMNS=120');
  533. rewind($output->getStream());
  534. $this->assertEquals(
  535. ' 0 [>---]'.
  536. $this->generateOutput(' 1 [->--]'),
  537. stream_get_contents($output->getStream())
  538. );
  539. }
  540. public function testAddingPlaceholderFormatter()
  541. {
  542. ProgressBar::setPlaceholderFormatterDefinition('remaining_steps', function (ProgressBar $bar) {
  543. return $bar->getMaxSteps() - $bar->getProgress();
  544. });
  545. $bar = new ProgressBar($output = $this->getOutputStream(), 3);
  546. $bar->setFormat(' %remaining_steps% [%bar%]');
  547. $bar->start();
  548. $bar->advance();
  549. $bar->finish();
  550. rewind($output->getStream());
  551. $this->assertEquals(
  552. ' 3 [>---------------------------]'.
  553. $this->generateOutput(' 2 [=========>------------------]').
  554. $this->generateOutput(' 0 [============================]'),
  555. stream_get_contents($output->getStream())
  556. );
  557. }
  558. public function testMultilineFormat()
  559. {
  560. $bar = new ProgressBar($output = $this->getOutputStream(), 3);
  561. $bar->setFormat("%bar%\nfoobar");
  562. $bar->start();
  563. $bar->advance();
  564. $bar->clear();
  565. $bar->finish();
  566. rewind($output->getStream());
  567. $this->assertEquals(
  568. ">---------------------------\nfoobar".
  569. $this->generateOutput("=========>------------------\nfoobar").
  570. "\x0D\x1B[2K\x1B[1A\x1B[2K".
  571. $this->generateOutput("============================\nfoobar"),
  572. stream_get_contents($output->getStream())
  573. );
  574. }
  575. public function testAnsiColorsAndEmojis()
  576. {
  577. putenv('COLUMNS=156');
  578. $bar = new ProgressBar($output = $this->getOutputStream(), 15);
  579. ProgressBar::setPlaceholderFormatterDefinition('memory', function (ProgressBar $bar) {
  580. static $i = 0;
  581. $mem = 100000 * $i;
  582. $colors = $i++ ? '41;37' : '44;37';
  583. return "\033[".$colors.'m '.Helper::formatMemory($mem)." \033[0m";
  584. });
  585. $bar->setFormat(" \033[44;37m %title:-37s% \033[0m\n %current%/%max% %bar% %percent:3s%%\n 🏁 %remaining:-10s% %memory:37s%");
  586. $bar->setBarCharacter($done = "\033[32m●\033[0m");
  587. $bar->setEmptyBarCharacter($empty = "\033[31m●\033[0m");
  588. $bar->setProgressCharacter($progress = "\033[32m➤ \033[0m");
  589. $bar->setMessage('Starting the demo... fingers crossed', 'title');
  590. $bar->start();
  591. rewind($output->getStream());
  592. $this->assertEquals(
  593. " \033[44;37m Starting the demo... fingers crossed \033[0m\n".
  594. ' 0/15 '.$progress.str_repeat($empty, 26)." 0%\n".
  595. " \xf0\x9f\x8f\x81 < 1 sec \033[44;37m 0 B \033[0m",
  596. stream_get_contents($output->getStream())
  597. );
  598. ftruncate($output->getStream(), 0);
  599. rewind($output->getStream());
  600. $bar->setMessage('Looks good to me...', 'title');
  601. $bar->advance(4);
  602. rewind($output->getStream());
  603. $this->assertEquals(
  604. $this->generateOutput(
  605. " \033[44;37m Looks good to me... \033[0m\n".
  606. ' 4/15 '.str_repeat($done, 7).$progress.str_repeat($empty, 19)." 26%\n".
  607. " \xf0\x9f\x8f\x81 < 1 sec \033[41;37m 97 KiB \033[0m"
  608. ),
  609. stream_get_contents($output->getStream())
  610. );
  611. ftruncate($output->getStream(), 0);
  612. rewind($output->getStream());
  613. $bar->setMessage('Thanks, bye', 'title');
  614. $bar->finish();
  615. rewind($output->getStream());
  616. $this->assertEquals(
  617. $this->generateOutput(
  618. " \033[44;37m Thanks, bye \033[0m\n".
  619. ' 15/15 '.str_repeat($done, 28)." 100%\n".
  620. " \xf0\x9f\x8f\x81 < 1 sec \033[41;37m 195 KiB \033[0m"
  621. ),
  622. stream_get_contents($output->getStream())
  623. );
  624. putenv('COLUMNS=120');
  625. }
  626. public function testSetFormat()
  627. {
  628. $bar = new ProgressBar($output = $this->getOutputStream());
  629. $bar->setFormat('normal');
  630. $bar->start();
  631. rewind($output->getStream());
  632. $this->assertEquals(
  633. ' 0 [>---------------------------]',
  634. stream_get_contents($output->getStream())
  635. );
  636. $bar = new ProgressBar($output = $this->getOutputStream(), 10);
  637. $bar->setFormat('normal');
  638. $bar->start();
  639. rewind($output->getStream());
  640. $this->assertEquals(
  641. ' 0/10 [>---------------------------] 0%',
  642. stream_get_contents($output->getStream())
  643. );
  644. }
  645. /**
  646. * @dataProvider provideFormat
  647. */
  648. public function testFormatsWithoutMax($format)
  649. {
  650. $bar = new ProgressBar($output = $this->getOutputStream());
  651. $bar->setFormat($format);
  652. $bar->start();
  653. rewind($output->getStream());
  654. $this->assertNotEmpty(stream_get_contents($output->getStream()));
  655. }
  656. /**
  657. * Provides each defined format.
  658. *
  659. * @return array
  660. */
  661. public function provideFormat()
  662. {
  663. return [
  664. ['normal'],
  665. ['verbose'],
  666. ['very_verbose'],
  667. ['debug'],
  668. ];
  669. }
  670. protected function getOutputStream($decorated = true, $verbosity = StreamOutput::VERBOSITY_NORMAL)
  671. {
  672. return new StreamOutput(fopen('php://memory', 'r+', false), $verbosity, $decorated);
  673. }
  674. protected function generateOutput($expected)
  675. {
  676. $count = substr_count($expected, "\n");
  677. return "\x0D\x1B[2K".($count ? str_repeat("\x1B[1A\x1B[2K", $count) : '').$expected;
  678. }
  679. public function testBarWidthWithMultilineFormat()
  680. {
  681. putenv('COLUMNS=10');
  682. $bar = new ProgressBar($output = $this->getOutputStream());
  683. $bar->setFormat("%bar%\n0123456789");
  684. // before starting
  685. $bar->setBarWidth(5);
  686. $this->assertEquals(5, $bar->getBarWidth());
  687. // after starting
  688. $bar->start();
  689. rewind($output->getStream());
  690. $this->assertEquals(5, $bar->getBarWidth(), stream_get_contents($output->getStream()));
  691. putenv('COLUMNS=120');
  692. }
  693. }