You are here

class TwigSandboxTest in Drupal 9

Same name and namespace in other branches
  1. 8 core/tests/Drupal/Tests/Core/Template/TwigSandboxTest.php \Drupal\Tests\Core\Template\TwigSandboxTest

Tests the twig sandbox policy.

@group Template

@coversDefaultClass \Drupal\Core\Template\TwigSandboxPolicy

Hierarchy

Expanded class hierarchy of TwigSandboxTest

File

core/tests/Drupal/Tests/Core/Template/TwigSandboxTest.php, line 25
Contains \Drupal\Tests\Core\Template\TwigSandboxTest.

Namespace

Drupal\Tests\Core\Template
View source
class TwigSandboxTest extends UnitTestCase {

  /**
   * The Twig environment loaded with the sandbox extension.
   *
   * @var \Twig\Environment
   */
  protected $twig;

  /**
   * {@inheritdoc}
   */
  protected function setUp() : void {
    parent::setUp();
    $loader = new StringLoader();
    $this->twig = new Environment($loader);
    $policy = new TwigSandboxPolicy();
    $sandbox = new SandboxExtension($policy, TRUE);
    $this->twig
      ->addExtension($sandbox);
  }

  /**
   * Tests that dangerous methods cannot be called in entity objects.
   *
   * @dataProvider getTwigEntityDangerousMethods
   */
  public function testEntityDangerousMethods($template) {
    $entity = $this
      ->createMock('Drupal\\Core\\Entity\\EntityInterface');
    $this
      ->expectException(SecurityError::class);
    $this->twig
      ->render($template, [
      'entity' => $entity,
    ]);
  }

  /**
   * Data provider for ::testEntityDangerousMethods.
   *
   * @return array
   */
  public function getTwigEntityDangerousMethods() {
    return [
      [
        '{{ entity.delete }}',
      ],
      [
        '{{ entity.save }}',
      ],
      [
        '{{ entity.create }}',
      ],
    ];
  }

  /**
   * Tests that white listed classes can be extended.
   */
  public function testExtendedClass() {
    $this
      ->assertEquals(' class="kitten"', $this->twig
      ->render('{{ attribute.addClass("kitten") }}', [
      'attribute' => new TestAttribute(),
    ]));
  }

  /**
   * Tests that prefixed methods can be called from within Twig templates.
   *
   * Currently "get", "has", and "is" are the only allowed prefixes.
   */
  public function testEntitySafePrefixes() {
    $entity = $this
      ->createMock('Drupal\\Core\\Entity\\EntityInterface');
    $entity
      ->expects($this
      ->atLeastOnce())
      ->method('hasLinkTemplate')
      ->with('test')
      ->willReturn(TRUE);
    $result = $this->twig
      ->render('{{ entity.hasLinkTemplate("test") }}', [
      'entity' => $entity,
    ]);
    $this
      ->assertTrue((bool) $result, 'Sandbox policy allows has* functions to be called.');
    $entity = $this
      ->createMock('Drupal\\Core\\Entity\\EntityInterface');
    $entity
      ->expects($this
      ->atLeastOnce())
      ->method('isNew')
      ->willReturn(TRUE);
    $result = $this->twig
      ->render('{{ entity.isNew }}', [
      'entity' => $entity,
    ]);
    $this
      ->assertTrue((bool) $result, 'Sandbox policy allows is* functions to be called.');
    $entity = $this
      ->createMock('Drupal\\Core\\Entity\\EntityInterface');
    $entity
      ->expects($this
      ->atLeastOnce())
      ->method('getEntityType')
      ->willReturn('test');
    $result = $this->twig
      ->render('{{ entity.getEntityType }}', [
      'entity' => $entity,
    ]);
    $this
      ->assertEquals('test', $result, 'Sandbox policy allows get* functions to be called.');
  }

  /**
   * Tests that valid methods can be called from within Twig templates.
   *
   * Currently the following methods are whitelisted: id, label, bundle, and
   * get.
   */
  public function testEntitySafeMethods() {
    $entity = $this
      ->getMockBuilder('Drupal\\Core\\Entity\\ContentEntityBase')
      ->disableOriginalConstructor()
      ->getMock();
    $entity
      ->expects($this
      ->atLeastOnce())
      ->method('get')
      ->with('title')
      ->willReturn('test');
    $result = $this->twig
      ->render('{{ entity.get("title") }}', [
      'entity' => $entity,
    ]);
    $this
      ->assertEquals('test', $result, 'Sandbox policy allows get() to be called.');
    $entity = $this
      ->createMock('Drupal\\Core\\Entity\\EntityInterface');
    $entity
      ->expects($this
      ->atLeastOnce())
      ->method('id')
      ->willReturn('1234');
    $result = $this->twig
      ->render('{{ entity.id }}', [
      'entity' => $entity,
    ]);
    $this
      ->assertEquals('1234', $result, 'Sandbox policy allows get() to be called.');
    $entity = $this
      ->createMock('Drupal\\Core\\Entity\\EntityInterface');
    $entity
      ->expects($this
      ->atLeastOnce())
      ->method('label')
      ->willReturn('testing');
    $result = $this->twig
      ->render('{{ entity.label }}', [
      'entity' => $entity,
    ]);
    $this
      ->assertEquals('testing', $result, 'Sandbox policy allows get() to be called.');
    $entity = $this
      ->createMock('Drupal\\Core\\Entity\\EntityInterface');
    $entity
      ->expects($this
      ->atLeastOnce())
      ->method('bundle')
      ->willReturn('testing');
    $result = $this->twig
      ->render('{{ entity.bundle }}', [
      'entity' => $entity,
    ]);
    $this
      ->assertEquals('testing', $result, 'Sandbox policy allows get() to be called.');
  }

  /**
   * Tests that safe methods inside Url objects can be called.
   */
  public function testUrlSafeMethods() {
    $url = $this
      ->getMockBuilder('Drupal\\Core\\Url')
      ->disableOriginalConstructor()
      ->getMock();
    $url
      ->expects($this
      ->once())
      ->method('toString')
      ->willReturn('http://kittens.cat/are/cute');
    $result = $this->twig
      ->render('{{ url.toString }}', [
      'url' => $url,
    ]);
    $this
      ->assertEquals('http://kittens.cat/are/cute', $result, 'Sandbox policy allows toString() to be called.');
  }

}

Members

Namesort descending Modifiers Type Description Overrides
PhpUnitWarnings::$deprecationWarnings private static property Deprecation warnings from PHPUnit to raise with @trigger_error().
PhpUnitWarnings::addWarning public function Converts PHPUnit deprecation warnings to E_USER_DEPRECATED.
TwigSandboxTest::$twig protected property The Twig environment loaded with the sandbox extension.
TwigSandboxTest::getTwigEntityDangerousMethods public function Data provider for ::testEntityDangerousMethods.
TwigSandboxTest::setUp protected function Overrides UnitTestCase::setUp
TwigSandboxTest::testEntityDangerousMethods public function Tests that dangerous methods cannot be called in entity objects.
TwigSandboxTest::testEntitySafeMethods public function Tests that valid methods can be called from within Twig templates.
TwigSandboxTest::testEntitySafePrefixes public function Tests that prefixed methods can be called from within Twig templates.
TwigSandboxTest::testExtendedClass public function Tests that white listed classes can be extended.
TwigSandboxTest::testUrlSafeMethods public function Tests that safe methods inside Url objects can be called.
UnitTestCase::$randomGenerator protected property The random generator.
UnitTestCase::$root protected property The app root. 1
UnitTestCase::assertArrayEquals Deprecated protected function Asserts if two arrays are equal by sorting them first.
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.
UnitTestCase::setUpBeforeClass public static function