You are here

class FileLogTokenTest in File Log 8

Same name and namespace in other branches
  1. 2.0.x tests/src/Unit/FileLogTokenTest.php \Drupal\Tests\filelog\Unit\FileLogTokenTest

Test the filelog message token integration.

@group filelog

Hierarchy

Expanded class hierarchy of FileLogTokenTest

File

tests/src/Unit/FileLogTokenTest.php, line 28

Namespace

Drupal\Tests\filelog\Unit
View source
class FileLogTokenTest extends UnitTestCase {

  /**
   * The logger.log_message_parser service.
   *
   * @var \Drupal\Core\Logger\LogMessageParserInterface
   */
  protected $logMessageParser;

  /**
   * A mock of the token service.
   *
   * @var \Drupal\Core\Utility\Token
   */
  protected $token;

  /**
   * A mock of the date.formatter service.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected $dateFormatter;

  /**
   * A mock of the user entity storage.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected $userStorage;

  /**
   * {@inheritdoc}
   */
  protected function setUp() : void {
    parent::setUp();

    // Get from filelog/tests/src/Unit to filelog/.
    $root = dirname(__DIR__, 3);
    require_once $root . '/filelog.tokens.inc';
    $this->logMessageParser = new LogMessageParser();
    $this->token = $this
      ->getMockBuilder(Token::class)
      ->disableOriginalConstructor()
      ->getMock();
    $this->dateFormatter = $this
      ->createMock(DateFormatterInterface::class);
    $entityTypeManager = $this
      ->createMock(EntityTypeManagerInterface::class);
    $entityTypeRepository = $this
      ->createMock(EntityTypeRepositoryInterface::class);
    $this->userStorage = $this
      ->createMock(EntityStorageInterface::class);

    // Mock the User entity type resolution.
    // InvocationMocker::with(...$arguments) incorrectly documented.
    // Suppress until phpunit/phpunit:8.2.1.

    /* @noinspection PhpParamsInspection */
    $entityTypeRepository
      ->method('getEntityTypeFromClass')
      ->with(User::class)
      ->willReturn('user');

    // Mock the user entity storage (actual user-loading mocked each test).
    // InvocationMocker::with(...$arguments) incorrectly documented.
    // Suppress until phpunit/phpunit:8.2.1.

    /* @noinspection PhpParamsInspection */
    $entityTypeManager
      ->method('getStorage')
      ->with('user')
      ->willReturn($this->userStorage);
    $this->token
      ->method('findWithPrefix')
      ->willReturnCallback([
      static::class,
      'tokenFindWithPrefix',
    ]);

    // Set up the container with the required mocks.
    $container = new ContainerBuilder();
    $container
      ->set('token', $this->token);
    $container
      ->set('date.formatter', $this->dateFormatter);
    $container
      ->set('entity_type.manager', $entityTypeManager);
    $container
      ->set('entity_type.repository', $entityTypeRepository);
    Drupal::setContainer($container);
  }

  /**
   * Test the tokens of the log message.
   *
   * @param mixed $level
   *   Severity level of the log message.
   * @param string $message
   *   Content of the log message.
   * @param array $context
   *   Context of the log message.
   *
   * @dataProvider providerMessages
   */
  public function testTokens($level, $message, array $context) : void {
    $variables = $this->logMessageParser
      ->parseMessagePlaceholders($message, $context);
    $logMessage = new LogMessage($level, $message, $variables, $context);
    $levels = LogMessage::getLevels();
    $expectedTokens = [
      'type' => $context['channel'],
      'level' => $levels[$level],
      'message' => strtr($message, $variables),
      'location' => $context['request_uri'],
      'referrer' => $context['referer'] ?? NULL,
      'ip' => $context['ip'] ?? '0.0.0.0',
      'created' => 'date:default:' . $context['timestamp'],
      'created:format' => 'date:format:' . $context['timestamp'],
      'user' => 'user:' . $context['uid'],
      'user:token' => 'user:token:' . $context['uid'],
    ];
    foreach ($variables as $name => $value) {
      $expectedTokens['variable:' . substr($name, 1)] = $value;
    }
    foreach ($context as $name => $value) {
      $expectedTokens['context:' . $name] = $value;
    }
    $tokens = [];
    foreach ($expectedTokens as $name => $value) {
      $tokens[$name] = 'log:' . $name;
    }
    $user = $this
      ->getMockBuilder(User::class)
      ->disableOriginalConstructor()
      ->getMock();
    $this->userStorage
      ->expects($this
      ->once())
      ->method('load')
      ->with($context['uid'])
      ->willReturn($user);
    $user
      ->expects($this
      ->once())
      ->method('label')
      ->willReturn('user:' . $context['uid']);
    $this->dateFormatter
      ->expects($this
      ->once())
      ->method('format')
      ->with($context['timestamp'])
      ->willReturn('date:default:' . $context['timestamp']);
    $options = [];

    /** @var \Drupal\Core\Render\BubbleableMetadata $metadata */
    $metadata = $this
      ->createMock(BubbleableMetadata::class);

    // Mock the token service calls.
    $this->token
      ->expects($this
      ->exactly(2))
      ->method('generate')
      ->withConsecutive([
      'user',
      [
        'token' => 'log:user:token',
      ],
      [
        'user' => $user,
      ],
      $options,
      $metadata,
    ], [
      'date',
      [
        'format' => 'log:created:format',
      ],
      [
        'date' => $context['timestamp'],
      ],
      $options,
      $metadata,
    ])
      ->willReturnOnConsecutiveCalls([
      'log:user:token' => 'user:token:' . $context['uid'],
    ], [
      'log:created:format' => 'date:format:' . $context['timestamp'],
    ]);
    $values = filelog_tokens('log', $tokens, [
      'log' => $logMessage,
    ], $options, $metadata);

    // Check that each token was replaced by the correct value.
    foreach ($tokens as $name => $original) {
      $this
        ->assertEquals($expectedTokens[$name], $values[$original]);
    }

    // Make sure that nothing else was replaced.
    $this
      ->assertCount(count($expectedTokens), $values);
  }

  /**
   * Data provider for messages.
   *
   * @return array
   *   The datasets for ::testTokens().
   */
  public function providerMessages() : array {
    return [
      [
        'level' => RfcLogLevel::EMERGENCY,
        'message' => 'This is a message.',
        'context' => [
          'uid' => 7,
          'ip' => '255.255.255.255',
          'timestamp' => 123456789,
          'channel' => 'channel1',
          'request_uri' => 'a/b/c',
        ],
      ],
      [
        'level' => RfcLogLevel::WARNING,
        'message' => 'This is message (@abc, %def, :ghi).',
        'context' => [
          '@abc' => '.LD5}5~\\"8AiU*VH',
          '%def' => '6(0XvYDAhZ9.Ecd ',
          ':ghi' => '7bU3p6ap4:G_1.w"',
          'uid' => -1,
          'channel' => 'channel2',
          'request_uri' => 'd/e/f',
          'timestamp' => 0,
        ],
      ],
      [
        'level' => RfcLogLevel::DEBUG,
        'message' => 'This is message (@abc).',
        'context' => [
          '@abc' => '7bU3p6ap4:G_1.w"',
          'uid' => 42,
          'ip' => '0.0.0.0',
          'timestamp' => 987654321,
          'referer' => 'https://localhost',
          'channel' => 'channel3',
          'request_uri' => 'g/h/i',
        ],
      ],
    ];
  }

  /**
   * Duplicate \Drupal\Core\Utility\Token::findWithPrefix as static.
   *
   * @param array $tokens
   *   A keyed array of tokens, and their original raw form in the source text.
   * @param string $prefix
   *   A textual string to be matched at the beginning of the token.
   * @param string $delimiter
   *   A string containing the character that separates the prefix from
   *   the rest of the token. Defaults to ':'.
   *
   * @return array
   *   An associative array of discovered tokens, with the prefix and delimiter
   *   stripped from the key.
   *
   * @see \Drupal\Core\Utility\Token::findWithPrefix()
   */
  public static function tokenFindWithPrefix(array $tokens, $prefix, $delimiter = ':') : array {
    $results = [];
    foreach ($tokens as $token => $raw) {
      $parts = explode($delimiter, $token, 2);
      if (count($parts) === 2 && $parts[0] === $prefix) {
        $results[$parts[1]] = $raw;
      }
    }
    return $results;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
FileLogTokenTest::$dateFormatter protected property A mock of the date.formatter service.
FileLogTokenTest::$logMessageParser protected property The logger.log_message_parser service.
FileLogTokenTest::$token protected property A mock of the token service.
FileLogTokenTest::$userStorage protected property A mock of the user entity storage.
FileLogTokenTest::providerMessages public function Data provider for messages.
FileLogTokenTest::setUp protected function Overrides UnitTestCase::setUp
FileLogTokenTest::testTokens public function Test the tokens of the log message.
FileLogTokenTest::tokenFindWithPrefix public static function Duplicate \Drupal\Core\Utility\Token::findWithPrefix as static.
PhpunitCompatibilityTrait::getMock Deprecated public function Returns a mock object for the specified class using the available method.
PhpunitCompatibilityTrait::setExpectedException Deprecated public function Compatibility layer for PHPUnit 6 to support PHPUnit 4 code.
UnitTestCase::$randomGenerator protected property The random generator.
UnitTestCase::$root protected property The app root. 1
UnitTestCase::assertArrayEquals protected function Asserts if two arrays are equal by sorting them first.
UnitTestCase::getBlockMockWithMachineName Deprecated protected function Mocks a block with a block plugin. 1
UnitTestCase::getClassResolverStub protected function Returns a stub class resolver.
UnitTestCase::getConfigFactoryStub public function Returns a stub config factory that behaves according to the passed array.
UnitTestCase::getConfigStorageStub public function Returns a stub config storage that returns the supplied configuration.
UnitTestCase::getContainerWithCacheTagsInvalidator protected function Sets up a container with a cache tags invalidator.
UnitTestCase::getRandomGenerator protected function Gets the random generator for the utility methods.
UnitTestCase::getStringTranslationStub public function Returns a stub translation manager that just returns the passed string.
UnitTestCase::randomMachineName public function Generates a unique random string containing letters and numbers.