ConsoleLoggerTest.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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\Logger;
  11. use PHPUnit\Framework\TestCase;
  12. use Psr\Log\InvalidArgumentException;
  13. use Psr\Log\LoggerInterface;
  14. use Psr\Log\LogLevel;
  15. use Symfony\Component\Console\Logger\ConsoleLogger;
  16. use Symfony\Component\Console\Output\BufferedOutput;
  17. use Symfony\Component\Console\Output\OutputInterface;
  18. use Symfony\Component\Console\Tests\Fixtures\DummyOutput;
  19. /**
  20. * @author Kévin Dunglas <dunglas@gmail.com>
  21. * @author Jordi Boggiano <j.boggiano@seld.be>
  22. */
  23. class ConsoleLoggerTest extends TestCase
  24. {
  25. /**
  26. * @var DummyOutput
  27. */
  28. protected $output;
  29. public function getLogger(): LoggerInterface
  30. {
  31. $this->output = new DummyOutput(OutputInterface::VERBOSITY_VERBOSE);
  32. return new ConsoleLogger($this->output, [
  33. LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
  34. LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
  35. LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
  36. LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,
  37. LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,
  38. LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL,
  39. LogLevel::INFO => OutputInterface::VERBOSITY_NORMAL,
  40. LogLevel::DEBUG => OutputInterface::VERBOSITY_NORMAL,
  41. ]);
  42. }
  43. /**
  44. * Return the log messages in order.
  45. *
  46. * @return string[]
  47. */
  48. public function getLogs(): array
  49. {
  50. return $this->output->getLogs();
  51. }
  52. /**
  53. * @dataProvider provideOutputMappingParams
  54. */
  55. public function testOutputMapping($logLevel, $outputVerbosity, $isOutput, $addVerbosityLevelMap = [])
  56. {
  57. $out = new BufferedOutput($outputVerbosity);
  58. $logger = new ConsoleLogger($out, $addVerbosityLevelMap);
  59. $logger->log($logLevel, 'foo bar');
  60. $logs = $out->fetch();
  61. $this->assertEquals($isOutput ? "[$logLevel] foo bar".\PHP_EOL : '', $logs);
  62. }
  63. public static function provideOutputMappingParams()
  64. {
  65. $quietMap = [LogLevel::EMERGENCY => OutputInterface::VERBOSITY_QUIET];
  66. return [
  67. [LogLevel::EMERGENCY, OutputInterface::VERBOSITY_NORMAL, true],
  68. [LogLevel::WARNING, OutputInterface::VERBOSITY_NORMAL, true],
  69. [LogLevel::INFO, OutputInterface::VERBOSITY_NORMAL, false],
  70. [LogLevel::DEBUG, OutputInterface::VERBOSITY_NORMAL, false],
  71. [LogLevel::INFO, OutputInterface::VERBOSITY_VERBOSE, false],
  72. [LogLevel::INFO, OutputInterface::VERBOSITY_VERY_VERBOSE, true],
  73. [LogLevel::DEBUG, OutputInterface::VERBOSITY_VERY_VERBOSE, false],
  74. [LogLevel::DEBUG, OutputInterface::VERBOSITY_DEBUG, true],
  75. [LogLevel::ALERT, OutputInterface::VERBOSITY_QUIET, false],
  76. [LogLevel::EMERGENCY, OutputInterface::VERBOSITY_QUIET, false],
  77. [LogLevel::ALERT, OutputInterface::VERBOSITY_QUIET, false, $quietMap],
  78. [LogLevel::EMERGENCY, OutputInterface::VERBOSITY_QUIET, true, $quietMap],
  79. ];
  80. }
  81. public function testHasErrored()
  82. {
  83. $logger = new ConsoleLogger(new BufferedOutput());
  84. $this->assertFalse($logger->hasErrored());
  85. $logger->warning('foo');
  86. $this->assertFalse($logger->hasErrored());
  87. $logger->error('bar');
  88. $this->assertTrue($logger->hasErrored());
  89. }
  90. public function testImplements()
  91. {
  92. $this->assertInstanceOf(LoggerInterface::class, $this->getLogger());
  93. }
  94. /**
  95. * @dataProvider provideLevelsAndMessages
  96. */
  97. public function testLogsAtAllLevels($level, $message)
  98. {
  99. $logger = $this->getLogger();
  100. $logger->{$level}($message, ['user' => 'Bob']);
  101. $logger->log($level, $message, ['user' => 'Bob']);
  102. $expected = [
  103. $level.' message of level '.$level.' with context: Bob',
  104. $level.' message of level '.$level.' with context: Bob',
  105. ];
  106. $this->assertEquals($expected, $this->getLogs());
  107. }
  108. public static function provideLevelsAndMessages()
  109. {
  110. return [
  111. LogLevel::EMERGENCY => [LogLevel::EMERGENCY, 'message of level emergency with context: {user}'],
  112. LogLevel::ALERT => [LogLevel::ALERT, 'message of level alert with context: {user}'],
  113. LogLevel::CRITICAL => [LogLevel::CRITICAL, 'message of level critical with context: {user}'],
  114. LogLevel::ERROR => [LogLevel::ERROR, 'message of level error with context: {user}'],
  115. LogLevel::WARNING => [LogLevel::WARNING, 'message of level warning with context: {user}'],
  116. LogLevel::NOTICE => [LogLevel::NOTICE, 'message of level notice with context: {user}'],
  117. LogLevel::INFO => [LogLevel::INFO, 'message of level info with context: {user}'],
  118. LogLevel::DEBUG => [LogLevel::DEBUG, 'message of level debug with context: {user}'],
  119. ];
  120. }
  121. public function testThrowsOnInvalidLevel()
  122. {
  123. $this->expectException(InvalidArgumentException::class);
  124. $logger = $this->getLogger();
  125. $logger->log('invalid level', 'Foo');
  126. }
  127. public function testContextReplacement()
  128. {
  129. $logger = $this->getLogger();
  130. $logger->info('{Message {nothing} {user} {foo.bar} a}', ['user' => 'Bob', 'foo.bar' => 'Bar']);
  131. $expected = ['info {Message {nothing} Bob Bar a}'];
  132. $this->assertEquals($expected, $this->getLogs());
  133. }
  134. public function testObjectCastToString()
  135. {
  136. if (method_exists($this, 'createPartialMock')) {
  137. $dummy = $this->createPartialMock(DummyTest::class, ['__toString']);
  138. } else {
  139. $dummy = $this->createPartialMock(DummyTest::class, ['__toString']);
  140. }
  141. $dummy->method('__toString')->willReturn('DUMMY');
  142. $this->getLogger()->warning($dummy);
  143. $expected = ['warning DUMMY'];
  144. $this->assertEquals($expected, $this->getLogs());
  145. }
  146. public function testContextCanContainAnything()
  147. {
  148. $context = [
  149. 'bool' => true,
  150. 'null' => null,
  151. 'string' => 'Foo',
  152. 'int' => 0,
  153. 'float' => 0.5,
  154. 'nested' => ['with object' => new DummyTest()],
  155. 'object' => new \DateTime(),
  156. 'resource' => fopen('php://memory', 'r'),
  157. ];
  158. $this->getLogger()->warning('Crazy context data', $context);
  159. $expected = ['warning Crazy context data'];
  160. $this->assertEquals($expected, $this->getLogs());
  161. }
  162. public function testContextExceptionKeyCanBeExceptionOrOtherValues()
  163. {
  164. $logger = $this->getLogger();
  165. $logger->warning('Random message', ['exception' => 'oops']);
  166. $logger->critical('Uncaught Exception!', ['exception' => new \LogicException('Fail')]);
  167. $expected = [
  168. 'warning Random message',
  169. 'critical Uncaught Exception!',
  170. ];
  171. $this->assertEquals($expected, $this->getLogs());
  172. }
  173. }
  174. class DummyTest
  175. {
  176. public function __toString(): string
  177. {
  178. }
  179. }