Commit afa61a59 authored by catch's avatar catch
Browse files

Issue #3130107 by stefanos.petrakis, rpayanm, smustgrave, jungle: Extend unit...

Issue #3130107 by stefanos.petrakis, rpayanm, smustgrave, jungle: Extend unit test coverage for LanguageNegotiationContentEntity

(cherry picked from commit d2eb0235)
parent f26c1f03
Loading
Loading
Loading
Loading
+165 −39
Original line number Diff line number Diff line
@@ -2,15 +2,18 @@

namespace Drupal\Tests\language\Unit\Plugin\LanguageNegotiation;

use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Url;
use Drupal\language\ConfigurableLanguageManagerInterface;
use Drupal\Tests\UnitTestCase;
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ServerBag;
use Symfony\Component\Routing\Route;

/**
 * Tests the LanguageNegotiationContentEntity plugin class.
@@ -19,7 +22,7 @@
 * @coversDefaultClass \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity
 * @see \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity
 */
class LanguageNegotiationContentEntityTest extends UnitTestCase {
class LanguageNegotiationContentEntityTest extends LanguageNegotiationTestBase {

  /**
   * An array of mock LanguageInterface objects.
@@ -36,11 +39,11 @@ class LanguageNegotiationContentEntityTest extends UnitTestCase {
  protected $languageManager;

  /**
   * A mock object implementing the AccountInterface.
   *
   * @var \Drupal\Core\Session\AccountInterface
   * {@inheritdoc}
   */
  protected $user;
  protected function getPluginClass(): string {
    return LanguageNegotiationContentEntity::class;
  }

  /**
   * {@inheritdoc}
@@ -53,32 +56,39 @@ protected function setUp(): void {
    $language_de->expects($this->any())
      ->method('getId')
      ->will($this->returnValue('de'));
    $language_de->expects($this->any())
      ->method('getName')
      ->will($this->returnValue('German'));
    $language_en = $this->createMock(LanguageInterface::class);
    $language_en->expects($this->any())
      ->method('getId')
      ->will($this->returnValue('en'));
    $languages = [
    $language_en->expects($this->any())
      ->method('getName')
      ->will($this->returnValue('English'));
    $this->languages = [
      'de' => $language_de,
      'en' => $language_en,
    ];
    $this->languages = $languages;

    $language_manager = $this->getMockBuilder(ConfigurableLanguageManagerInterface::class)
      ->getMock();
    $language_manager = $this->createMock(ConfigurableLanguageManagerInterface::class);
    $language_manager->expects($this->any())
      ->method('getLanguages')
      ->will($this->returnValue($languages));
      ->will($this->returnValue($this->languages));
    $language_manager->expects($this->any())
      ->method('getNativeLanguages')
      ->will($this->returnValue($this->languages));
    $this->languageManager = $language_manager;

    $this->user = $this->getMockBuilder(AccountInterface::class)
      ->getMock();
    $container = new ContainerBuilder();

    $cache_contexts_manager = $this->getMockBuilder(CacheContextsManager::class)
      ->disableOriginalConstructor()
      ->getMock();
    $cache_contexts_manager = $this->createMock(CacheContextsManager::class);
    $cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
    $container = new ContainerBuilder();
    $container->set('cache_contexts_manager', $cache_contexts_manager);

    $entityTypeManager = $this->createMock(EntityTypeManager::class);
    $container->set('entity_type.manager', $entityTypeManager);

    \Drupal::setContainer($container);
  }

@@ -86,32 +96,148 @@ protected function setUp(): void {
   * @covers ::getLangcode
   */
  public function testGetLangcode() {
    $entityTypeManagerMock = $this->getMockBuilder(EntityTypeManager::class)
      ->disableOriginalConstructor()
      ->getMock();
    $languageNegotiationContentEntity = new LanguageNegotiationContentEntity($entityTypeManagerMock);
    $languageNegotiationContentEntity->setLanguageManager($this->languageManager);
    $languageNegotiationContentEntity = $this->createLanguageNegotiationPlugin();

    // Case 1: NULL request object argument.
    $this->assertNull($languageNegotiationContentEntity->getLangcode());
    // Case 1: Empty request.
    $this->assertEquals(NULL, $languageNegotiationContentEntity->getLangcode());

    // Case 2: A request object is available, but the languageManager is not
    // set.
    $request = Request::create('/foo', 'GET');
    $this->assertNull($languageNegotiationContentEntity->getLangcode($request));
    // Case 2: A request is available, but the languageManager is not set and
    // the static::QUERY_PARAMETER is not provided as a named parameter.
    $request = Request::create('/de/foo', 'GET');
    $request->query = new ParameterBag();
    $this->assertEquals(NULL, $languageNegotiationContentEntity->getLangcode($request));

    // Case 3: A request object is available, but static::QUERY_PARAMETER is
    // set to a non-enabled language.
    $request = Request::create('/foo', 'GET',
      [LanguageNegotiationContentEntity::QUERY_PARAMETER => 'it']);
    // Case 3: A request is available, the languageManager is set, but the
    // static::QUERY_PARAMETER is not provided as a named parameter.
    $languageNegotiationContentEntity->setLanguageManager($this->languageManager);
    $this->assertEquals(NULL, $languageNegotiationContentEntity->getLangcode($request));

    // Case 4: A request is available, the languageManager is set and the
    // static::QUERY_PARAMETER is provided as a named parameter.
    $expectedLangcode = 'de';
    $request->query->set(LanguageNegotiationContentEntity::QUERY_PARAMETER, $expectedLangcode);
    $this->assertEquals($expectedLangcode, $languageNegotiationContentEntity->getLangcode($request));

    // Case 5: A request is available, the languageManager is set and the
    // static::QUERY_PARAMETER is provided as a named parameter with a given
    // langcode that is not one of the system supported ones.
    $unknownLangcode = 'xx';
    $request->query->set(LanguageNegotiationContentEntity::QUERY_PARAMETER, $unknownLangcode);
    $this->assertNull($languageNegotiationContentEntity->getLangcode($request));
  }

    // Case 4: A request object is available and static::QUERY_PARAMETER is
    // set to an enabled language.
    $request = Request::create('/foo', 'GET',
      [LanguageNegotiationContentEntity::QUERY_PARAMETER => 'de']);
    $this->assertSame('de', $languageNegotiationContentEntity->getLangcode($request));
  /**
   * @covers ::processOutbound
   */
  public function testProcessOutbound() {

    // Case 1: Not all processing conditions are met.
    $languageNegotiationContentEntityMock = $this->createPartialMock($this->getPluginClass(),
      ['hasLowerLanguageNegotiationWeight', 'meetsContentEntityRoutesCondition']);
    $languageNegotiationContentEntityMock->expects($this->exactly(2))
      ->method('hasLowerLanguageNegotiationWeight')
      ->willReturnOnConsecutiveCalls(
        FALSE,
        TRUE
      );
    $languageNegotiationContentEntityMock->expects($this->once())
      ->method('meetsContentEntityRoutesCondition')
      ->willReturnOnConsecutiveCalls(
        FALSE
      );
    $options = [];
    $path = $this->randomMachineName();

    // Case 1a: Empty request.
    $this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path));
    $request = Request::create('/foo', 'GET');
    $request->server = new ServerBag();
    // Case 1b: Missing the route key in $options.
    $this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request));
    $options = ['route' => $this->createMock(Route::class)];
    // Case 1c: hasLowerLanguageNegotiationWeight() returns FALSE.
    $this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request));
    // Case 1d: meetsContentEntityRoutesCondition() returns FALSE.
    $this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request));

    // Case 2: Cannot figure out the langcode.
    $languageNegotiationContentEntityMock = $this->createPartialMock($this->getPluginClass(),
      ['hasLowerLanguageNegotiationWeight', 'meetsContentEntityRoutesCondition', 'getLangcode']);
    $languageNegotiationContentEntityMock->expects($this->any())
      ->method('hasLowerLanguageNegotiationWeight')
      ->will($this->returnValue(TRUE));
    $languageNegotiationContentEntityMock->expects($this->any())
      ->method('meetsContentEntityRoutesCondition')
      ->will($this->returnValue(TRUE));
    $languageNegotiationContentEntityMock->expects($this->exactly(2))
      ->method('getLangcode')
      ->willReturnOnConsecutiveCalls(
        NULL,
        'de'
      );
    $this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request));

    // Case 3: Can figure out the langcode.
    // Case 3a: via $options['language'].
    $options['language'] = $this->languages['en'];
    $options['query'] = NULL;
    $bubbleableMetadataMock = $this->createMock(BubbleableMetadata::class);
    $bubbleableMetadataMock->expects($this->exactly(3))
      ->method('addCacheContexts')
      ->with(['url.query_args:' . LanguageNegotiationContentEntity::QUERY_PARAMETER]);
    $this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request, $bubbleableMetadataMock));
    $this->assertFalse(isset($options['language']));
    $this->assertTrue(isset($options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER]));
    $this->assertEquals('en', $options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER]);

    // Case 3a1: via $options['language'] with an additional $options['query'][static::QUERY_PARAMETER].
    $options['language'] = $this->languages['en'];
    $options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER] = 'xx';
    $this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request, $bubbleableMetadataMock));
    $this->assertFalse(isset($options['language']));
    $this->assertEquals('xx', $options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER]);

    // Case 3b: via getLangcode().
    unset($options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER]);
    $this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request, $bubbleableMetadataMock));
    $this->assertEquals('de', $options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER]);
  }

  /**
   * @covers ::getLanguageSwitchLinks
   */
  public function testGetLanguageSwitchLinks() {
    $languageNegotiationContentEntity = $this->createLanguageNegotiationPlugin();
    $languageNegotiationContentEntity->setLanguageManager($this->languageManager);

    $request = Request::create('/foo', 'GET', ['param1' => 'xyz']);
    $url = Url::fromUri('base:' . $this->randomMachineName());

    $expectedLanguageSwitchLinksArray = [
      'de' => [
        'url' => $url,
        'title' => $this->languages['de']->getName(),
        'attributes' => ['class' => ['language-link']],
        'query' => [
          LanguageNegotiationContentEntity::QUERY_PARAMETER => 'de',
          'param1' => 'xyz',
        ],
      ],
      'en' => [
        'url' => $url,
        'title' => $this->languages['en']->getName(),
        'attributes' => ['class' => ['language-link']],
        'query' => [
          LanguageNegotiationContentEntity::QUERY_PARAMETER => 'en',
          'param1' => 'xyz',
        ],
      ],
    ];
    $providedLanguageSwitchLinksArray = $languageNegotiationContentEntity->getLanguageSwitchLinks($request, $this->randomMachineName(), $url);
    $this->assertEquals(
      $expectedLanguageSwitchLinksArray,
      $providedLanguageSwitchLinksArray
    );
  }

}
+34 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Tests\language\Unit\Plugin\LanguageNegotiation;

use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Tests\UnitTestCase;

/**
 * Base class used for testing the various LanguageNegotiation plugins.
 *
 * @group language
 */
abstract class LanguageNegotiationTestBase extends UnitTestCase {

  /**
   * Returns the plugin class to use for creating the language negotiation plugin.
   *
   * @return string
   *   The plugin class name.
   */
  abstract protected function getPluginClass(): string;

  /**
   * Creates a @LanguageNegotiation plugin using the factory ::create method.
   *
   * @return \Drupal\language\LanguageNegotiationMethodInterface
   */
  protected function createLanguageNegotiationPlugin(array $configuration = [], $plugin_definition = NULL) {
    $class = $this->getPluginClass();
    $this->assertTrue(in_array(ContainerFactoryPluginInterface::class, class_implements($class)));
    return $class::create(\Drupal::getContainer(), $configuration, $class::METHOD_ID, $plugin_definition);
  }

}