OutputFormatterTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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\Formatter;
  11. use Symfony\Component\Console\Formatter\OutputFormatter;
  12. use Symfony\Component\Console\Formatter\OutputFormatterStyle;
  13. class OutputFormatterTest extends \PHPUnit_Framework_TestCase
  14. {
  15. public function testEmptyTag()
  16. {
  17. $formatter = new OutputFormatter(true);
  18. $this->assertEquals('foo<>bar', $formatter->format('foo<>bar'));
  19. }
  20. public function testLGCharEscaping()
  21. {
  22. $formatter = new OutputFormatter(true);
  23. $this->assertEquals('foo<bar', $formatter->format('foo\\<bar'));
  24. $this->assertEquals('<info>some info</info>', $formatter->format('\\<info>some info\\</info>'));
  25. $this->assertEquals('\\<info>some info\\</info>', OutputFormatter::escape('<info>some info</info>'));
  26. $this->assertEquals(
  27. "\033[33mSymfony\\Component\\Console does work very well!\033[39m",
  28. $formatter->format('<comment>Symfony\Component\Console does work very well!</comment>')
  29. );
  30. }
  31. public function testBundledStyles()
  32. {
  33. $formatter = new OutputFormatter(true);
  34. $this->assertTrue($formatter->hasStyle('error'));
  35. $this->assertTrue($formatter->hasStyle('info'));
  36. $this->assertTrue($formatter->hasStyle('comment'));
  37. $this->assertTrue($formatter->hasStyle('question'));
  38. $this->assertEquals(
  39. "\033[37;41msome error\033[39;49m",
  40. $formatter->format('<error>some error</error>')
  41. );
  42. $this->assertEquals(
  43. "\033[32msome info\033[39m",
  44. $formatter->format('<info>some info</info>')
  45. );
  46. $this->assertEquals(
  47. "\033[33msome comment\033[39m",
  48. $formatter->format('<comment>some comment</comment>')
  49. );
  50. $this->assertEquals(
  51. "\033[30;46msome question\033[39;49m",
  52. $formatter->format('<question>some question</question>')
  53. );
  54. }
  55. public function testNestedStyles()
  56. {
  57. $formatter = new OutputFormatter(true);
  58. $this->assertEquals(
  59. "\033[37;41msome \033[39;49m\033[32msome info\033[39m\033[37;41m error\033[39;49m",
  60. $formatter->format('<error>some <info>some info</info> error</error>')
  61. );
  62. }
  63. public function testAdjacentStyles()
  64. {
  65. $formatter = new OutputFormatter(true);
  66. $this->assertEquals(
  67. "\033[37;41msome error\033[39;49m\033[32msome info\033[39m",
  68. $formatter->format('<error>some error</error><info>some info</info>')
  69. );
  70. }
  71. public function testStyleMatchingNotGreedy()
  72. {
  73. $formatter = new OutputFormatter(true);
  74. $this->assertEquals(
  75. "(\033[32m>=2.0,<2.3\033[39m)",
  76. $formatter->format('(<info>>=2.0,<2.3</info>)')
  77. );
  78. }
  79. public function testStyleEscaping()
  80. {
  81. $formatter = new OutputFormatter(true);
  82. $this->assertEquals(
  83. "(\033[32mz>=2.0,<<<a2.3\\\033[39m)",
  84. $formatter->format('(<info>'.$formatter->escape('z>=2.0,<\\<<a2.3\\').'</info>)')
  85. );
  86. $this->assertEquals(
  87. "\033[32m<error>some error</error>\033[39m",
  88. $formatter->format('<info>'.$formatter->escape('<error>some error</error>').'</info>')
  89. );
  90. }
  91. public function testDeepNestedStyles()
  92. {
  93. $formatter = new OutputFormatter(true);
  94. $this->assertEquals(
  95. "\033[37;41merror\033[39;49m\033[32minfo\033[39m\033[33mcomment\033[39m\033[37;41merror\033[39;49m",
  96. $formatter->format('<error>error<info>info<comment>comment</info>error</error>')
  97. );
  98. }
  99. public function testNewStyle()
  100. {
  101. $formatter = new OutputFormatter(true);
  102. $style = new OutputFormatterStyle('blue', 'white');
  103. $formatter->setStyle('test', $style);
  104. $this->assertEquals($style, $formatter->getStyle('test'));
  105. $this->assertNotEquals($style, $formatter->getStyle('info'));
  106. $style = new OutputFormatterStyle('blue', 'white');
  107. $formatter->setStyle('b', $style);
  108. $this->assertEquals("\033[34;47msome \033[39;49m\033[34;47mcustom\033[39;49m\033[34;47m msg\033[39;49m", $formatter->format('<test>some <b>custom</b> msg</test>'));
  109. }
  110. public function testRedefineStyle()
  111. {
  112. $formatter = new OutputFormatter(true);
  113. $style = new OutputFormatterStyle('blue', 'white');
  114. $formatter->setStyle('info', $style);
  115. $this->assertEquals("\033[34;47msome custom msg\033[39;49m", $formatter->format('<info>some custom msg</info>'));
  116. }
  117. public function testInlineStyle()
  118. {
  119. $formatter = new OutputFormatter(true);
  120. $this->assertEquals("\033[34;41msome text\033[39;49m", $formatter->format('<fg=blue;bg=red>some text</>'));
  121. $this->assertEquals("\033[34;41msome text\033[39;49m", $formatter->format('<fg=blue;bg=red>some text</fg=blue;bg=red>'));
  122. }
  123. /**
  124. * @param string $tag
  125. * @param string|null $expected
  126. * @param string|null $input
  127. *
  128. * @dataProvider provideInlineStyleOptionsCases
  129. */
  130. public function testInlineStyleOptions($tag, $expected = null, $input = null)
  131. {
  132. $styleString = substr($tag, 1, -1);
  133. $formatter = new OutputFormatter(true);
  134. $method = new \ReflectionMethod($formatter, 'createStyleFromString');
  135. $method->setAccessible(true);
  136. $result = $method->invoke($formatter, $styleString);
  137. if (null === $expected) {
  138. $this->assertFalse($result);
  139. $expected = $tag.$input.'</'.$styleString.'>';
  140. $this->assertSame($expected, $formatter->format($expected));
  141. } else {
  142. /* @var OutputFormatterStyle $result */
  143. $this->assertInstanceOf(OutputFormatterStyle::class, $result);
  144. $this->assertSame($expected, $formatter->format($tag.$input.'</>'));
  145. $this->assertSame($expected, $formatter->format($tag.$input.'</'.$styleString.'>'));
  146. }
  147. }
  148. public function provideInlineStyleOptionsCases()
  149. {
  150. return array(
  151. array('<unknown=_unknown_>'),
  152. array('<unknown=_unknown_;a=1;b>'),
  153. array('<fg=green;>', "\033[32m[test]\033[39m", '[test]'),
  154. array('<fg=green;bg=blue;>', "\033[32;44ma\033[39;49m", 'a'),
  155. array('<fg=green;options=bold>', "\033[32;1mb\033[39;22m", 'b'),
  156. array('<fg=green;options=reverse;>', "\033[32;7m<a>\033[39;27m", '<a>'),
  157. array('<fg=green;options=bold,underscore>', "\033[32;1;4mz\033[39;22;24m", 'z'),
  158. array('<fg=green;options=bold,underscore,reverse;>', "\033[32;1;4;7md\033[39;22;24;27m", 'd'),
  159. );
  160. }
  161. /**
  162. * @group legacy
  163. * @dataProvider provideInlineStyleTagsWithUnknownOptions
  164. * @expectedDeprecation Unknown style options are deprecated since version 3.2 and will be removed in 4.0. Exception "Invalid option specified: "%s". Expected one of (bold, underscore, blink, reverse, conceal)".
  165. */
  166. public function testInlineStyleOptionsUnknownAreDeprecated($tag, $option)
  167. {
  168. $formatter = new OutputFormatter(true);
  169. $formatter->format($tag);
  170. }
  171. public function provideInlineStyleTagsWithUnknownOptions()
  172. {
  173. return array(
  174. array('<options=abc;>', 'abc'),
  175. array('<options=abc,def;>', 'abc'),
  176. array('<fg=green;options=xyz;>', 'xyz'),
  177. array('<fg=green;options=efg,abc>', 'efg'),
  178. );
  179. }
  180. public function testNonStyleTag()
  181. {
  182. $formatter = new OutputFormatter(true);
  183. $this->assertEquals("\033[32msome \033[39m\033[32m<tag>\033[39m\033[32m \033[39m\033[32m<setting=value>\033[39m\033[32m styled \033[39m\033[32m<p>\033[39m\033[32msingle-char tag\033[39m\033[32m</p>\033[39m", $formatter->format('<info>some <tag> <setting=value> styled <p>single-char tag</p></info>'));
  184. }
  185. public function testFormatLongString()
  186. {
  187. $formatter = new OutputFormatter(true);
  188. $long = str_repeat('\\', 14000);
  189. $this->assertEquals("\033[37;41msome error\033[39;49m".$long, $formatter->format('<error>some error</error>'.$long));
  190. }
  191. public function testFormatToStringObject()
  192. {
  193. $formatter = new OutputFormatter(false);
  194. $this->assertEquals(
  195. 'some info', $formatter->format(new TableCell())
  196. );
  197. }
  198. public function testNotDecoratedFormatter()
  199. {
  200. $formatter = new OutputFormatter(false);
  201. $this->assertTrue($formatter->hasStyle('error'));
  202. $this->assertTrue($formatter->hasStyle('info'));
  203. $this->assertTrue($formatter->hasStyle('comment'));
  204. $this->assertTrue($formatter->hasStyle('question'));
  205. $this->assertEquals(
  206. 'some error', $formatter->format('<error>some error</error>')
  207. );
  208. $this->assertEquals(
  209. 'some info', $formatter->format('<info>some info</info>')
  210. );
  211. $this->assertEquals(
  212. 'some comment', $formatter->format('<comment>some comment</comment>')
  213. );
  214. $this->assertEquals(
  215. 'some question', $formatter->format('<question>some question</question>')
  216. );
  217. $formatter->setDecorated(true);
  218. $this->assertEquals(
  219. "\033[37;41msome error\033[39;49m", $formatter->format('<error>some error</error>')
  220. );
  221. $this->assertEquals(
  222. "\033[32msome info\033[39m", $formatter->format('<info>some info</info>')
  223. );
  224. $this->assertEquals(
  225. "\033[33msome comment\033[39m", $formatter->format('<comment>some comment</comment>')
  226. );
  227. $this->assertEquals(
  228. "\033[30;46msome question\033[39;49m", $formatter->format('<question>some question</question>')
  229. );
  230. }
  231. public function testContentWithLineBreaks()
  232. {
  233. $formatter = new OutputFormatter(true);
  234. $this->assertEquals(<<<EOF
  235. \033[32m
  236. some text\033[39m
  237. EOF
  238. , $formatter->format(<<<'EOF'
  239. <info>
  240. some text</info>
  241. EOF
  242. ));
  243. $this->assertEquals(<<<EOF
  244. \033[32msome text
  245. \033[39m
  246. EOF
  247. , $formatter->format(<<<'EOF'
  248. <info>some text
  249. </info>
  250. EOF
  251. ));
  252. $this->assertEquals(<<<EOF
  253. \033[32m
  254. some text
  255. \033[39m
  256. EOF
  257. , $formatter->format(<<<'EOF'
  258. <info>
  259. some text
  260. </info>
  261. EOF
  262. ));
  263. $this->assertEquals(<<<EOF
  264. \033[32m
  265. some text
  266. more text
  267. \033[39m
  268. EOF
  269. , $formatter->format(<<<'EOF'
  270. <info>
  271. some text
  272. more text
  273. </info>
  274. EOF
  275. ));
  276. }
  277. }
  278. class TableCell
  279. {
  280. public function __toString()
  281. {
  282. return '<info>some info</info>';
  283. }
  284. }