TemplateTest.php

File

drupal/core/vendor/twig/twig/test/Twig/Tests/TemplateTest.php
View source
<?php

/*
 * This file is part of Twig.
 *
 * (c) Fabien Potencier
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase {

  /**
   * @dataProvider getAttributeExceptions
   */
  public function testGetAttributeExceptions($template, $message, $useExt) {
    $name = 'index_' . ($useExt ? 1 : 0);
    $templates = array(
      $name => $template . $useExt,
    );
    $env = new Twig_Environment(new Twig_Loader_Array($templates), array(
      'strict_variables' => true,
    ));
    if (!$useExt) {
      $env
        ->addNodeVisitor(new CExtDisablingNodeVisitor());
    }
    $template = $env
      ->loadTemplate($name);
    $context = array(
      'string' => 'foo',
      'array' => array(
        'foo' => 'foo',
      ),
      'array_access' => new Twig_TemplateArrayAccessObject(),
    );
    try {
      $template
        ->render($context);
    } catch (Twig_Error_Runtime $e) {
      $this
        ->assertEquals(sprintf($message, $name), $e
        ->getMessage());
    }
  }
  public function getAttributeExceptions() {
    $tests = array(
      array(
        '{{ string["a"] }}',
        'Impossible to access a key ("a") on a "string" variable in "%s" at line 1',
        false,
      ),
      array(
        '{{ array["a"] }}',
        'Key "a" for array with keys "foo" does not exist in "%s" at line 1',
        false,
      ),
      array(
        '{{ array_access["a"] }}',
        'Key "a" in object (with ArrayAccess) of type "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1',
        false,
      ),
      array(
        '{{ string.a }}',
        'Item "a" for "foo" does not exist in "%s" at line 1',
        false,
      ),
      array(
        '{{ array.a }}',
        'Item "a" for "Array" does not exist in "%s" at line 1',
        false,
      ),
      array(
        '{{ array_access.a }}',
        'Method "a" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1',
        false,
      ),
      array(
        '{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ _self.foo(array_access) }}',
        'Method "missing_method" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1',
        false,
      ),
    );
    if (function_exists('twig_template_get_attributes')) {
      foreach (array_slice($tests, 0) as $test) {
        $test[2] = true;
        $tests[] = $test;
      }
    }
    return $tests;
  }

  /**
   * @dataProvider getGetAttributeWithSandbox
   */
  public function testGetAttributeWithSandbox($object, $item, $allowed, $useExt) {
    $twig = new Twig_Environment();
    $policy = new Twig_Sandbox_SecurityPolicy(array(), array(), array(), array(), array());
    $twig
      ->addExtension(new Twig_Extension_Sandbox($policy, !$allowed));
    $template = new Twig_TemplateTest($twig, $useExt);
    try {
      $template
        ->getAttribute($object, $item, array(), 'any');
      if (!$allowed) {
        $this
          ->fail();
      }
    } catch (Twig_Sandbox_SecurityError $e) {
      if ($allowed) {
        $this
          ->fail();
      }
      $this
        ->assertContains('is not allowed', $e
        ->getMessage());
    }
  }
  public function getGetAttributeWithSandbox() {
    $tests = array(
      array(
        new Twig_TemplatePropertyObject(),
        'defined',
        false,
        false,
      ),
      array(
        new Twig_TemplatePropertyObject(),
        'defined',
        true,
        false,
      ),
      array(
        new Twig_TemplateMethodObject(),
        'defined',
        false,
        false,
      ),
      array(
        new Twig_TemplateMethodObject(),
        'defined',
        true,
        false,
      ),
    );
    if (function_exists('twig_template_get_attributes')) {
      foreach (array_slice($tests, 0) as $test) {
        $test[3] = true;
        $tests[] = $test;
      }
    }
    return $tests;
  }

  /**
   * @dataProvider getGetAttributeWithTemplateAsObject
   */
  public function testGetAttributeWithTemplateAsObject($useExt) {
    $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
    $template1 = new Twig_TemplateTest(new Twig_Environment(), false);
    $this
      ->assertInstanceof('Twig_Markup', $template
      ->getAttribute($template1, 'string'));
    $this
      ->assertEquals('some_string', $template
      ->getAttribute($template1, 'string'));
    $this
      ->assertInstanceof('Twig_Markup', $template
      ->getAttribute($template1, 'true'));
    $this
      ->assertEquals('1', $template
      ->getAttribute($template1, 'true'));
    $this
      ->assertInstanceof('Twig_Markup', $template
      ->getAttribute($template1, 'zero'));
    $this
      ->assertEquals('0', $template
      ->getAttribute($template1, 'zero'));
    $this
      ->assertNotInstanceof('Twig_Markup', $template
      ->getAttribute($template1, 'empty'));
    $this
      ->assertSame('', $template
      ->getAttribute($template1, 'empty'));
  }
  public function getGetAttributeWithTemplateAsObject() {
    $bools = array(
      array(
        false,
      ),
    );
    if (function_exists('twig_template_get_attributes')) {
      $bools[] = array(
        true,
      );
    }
    return $bools;
  }

  /**
   * @dataProvider getGetAttributeTests
   */
  public function testGetAttribute($defined, $value, $object, $item, $arguments, $type, $useExt = false) {
    $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
    $this
      ->assertEquals($value, $template
      ->getAttribute($object, $item, $arguments, $type));
  }

  /**
   * @dataProvider getGetAttributeTests
   */
  public function testGetAttributeStrict($defined, $value, $object, $item, $arguments, $type, $useExt = false, $exceptionMessage = null) {
    $template = new Twig_TemplateTest(new Twig_Environment(null, array(
      'strict_variables' => true,
    )), $useExt);
    if ($defined) {
      $this
        ->assertEquals($value, $template
        ->getAttribute($object, $item, $arguments, $type));
    }
    else {
      try {
        $this
          ->assertEquals($value, $template
          ->getAttribute($object, $item, $arguments, $type));
        throw new Exception('Expected Twig_Error_Runtime exception.');
      } catch (Twig_Error_Runtime $e) {
        if (null !== $exceptionMessage) {
          $this
            ->assertSame($exceptionMessage, $e
            ->getMessage());
        }
      }
    }
  }

  /**
   * @dataProvider getGetAttributeTests
   */
  public function testGetAttributeDefined($defined, $value, $object, $item, $arguments, $type, $useExt = false) {
    $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
    $this
      ->assertEquals($defined, $template
      ->getAttribute($object, $item, $arguments, $type, true));
  }

  /**
   * @dataProvider getGetAttributeTests
   */
  public function testGetAttributeDefinedStrict($defined, $value, $object, $item, $arguments, $type, $useExt = false) {
    $template = new Twig_TemplateTest(new Twig_Environment(null, array(
      'strict_variables' => true,
    )), $useExt);
    $this
      ->assertEquals($defined, $template
      ->getAttribute($object, $item, $arguments, $type, true));
  }
  public function getGetAttributeTests() {
    $array = array(
      'defined' => 'defined',
      'zero' => 0,
      'null' => null,
      '1' => 1,
      'bar' => true,
    );
    $objectArray = new Twig_TemplateArrayAccessObject();
    $stdObject = (object) $array;
    $magicPropertyObject = new Twig_TemplateMagicPropertyObject();
    $propertyObject = new Twig_TemplatePropertyObject();
    $propertyObject1 = new Twig_TemplatePropertyObjectAndIterator();
    $propertyObject2 = new Twig_TemplatePropertyObjectAndArrayAccess();
    $methodObject = new Twig_TemplateMethodObject();
    $magicMethodObject = new Twig_TemplateMagicMethodObject();
    $anyType = Twig_TemplateInterface::ANY_CALL;
    $methodType = Twig_TemplateInterface::METHOD_CALL;
    $arrayType = Twig_TemplateInterface::ARRAY_CALL;
    $basicTests = array(
      // array(defined, value, property to fetch)
      array(
        true,
        'defined',
        'defined',
      ),
      array(
        false,
        null,
        'undefined',
      ),
      array(
        false,
        null,
        'protected',
      ),
      array(
        true,
        0,
        'zero',
      ),
      array(
        true,
        1,
        1,
      ),
      array(
        true,
        1,
        1.0,
      ),
      array(
        true,
        null,
        'null',
      ),
      array(
        true,
        true,
        'bar',
      ),
    );
    $testObjects = array(
      // array(object, type of fetch)
      array(
        $array,
        $arrayType,
      ),
      array(
        $objectArray,
        $arrayType,
      ),
      array(
        $stdObject,
        $anyType,
      ),
      array(
        $magicPropertyObject,
        $anyType,
      ),
      array(
        $methodObject,
        $methodType,
      ),
      array(
        $methodObject,
        $anyType,
      ),
      array(
        $propertyObject,
        $anyType,
      ),
      array(
        $propertyObject1,
        $anyType,
      ),
      array(
        $propertyObject2,
        $anyType,
      ),
    );
    $tests = array();
    foreach ($testObjects as $testObject) {
      foreach ($basicTests as $test) {

        // properties cannot be numbers
        if (($testObject[0] instanceof stdClass || $testObject[0] instanceof Twig_TemplatePropertyObject) && is_numeric($test[2])) {
          continue;
        }
        $tests[] = array(
          $test[0],
          $test[1],
          $testObject[0],
          $test[2],
          array(),
          $testObject[1],
        );
      }
    }

    // additional method tests
    $tests = array_merge($tests, array(
      array(
        true,
        'defined',
        $methodObject,
        'defined',
        array(),
        $methodType,
      ),
      array(
        true,
        'defined',
        $methodObject,
        'DEFINED',
        array(),
        $methodType,
      ),
      array(
        true,
        'defined',
        $methodObject,
        'getDefined',
        array(),
        $methodType,
      ),
      array(
        true,
        'defined',
        $methodObject,
        'GETDEFINED',
        array(),
        $methodType,
      ),
      array(
        true,
        'static',
        $methodObject,
        'static',
        array(),
        $methodType,
      ),
      array(
        true,
        'static',
        $methodObject,
        'getStatic',
        array(),
        $methodType,
      ),
      array(
        true,
        '__call_undefined',
        $magicMethodObject,
        'undefined',
        array(),
        $methodType,
      ),
      array(
        true,
        '__call_UNDEFINED',
        $magicMethodObject,
        'UNDEFINED',
        array(),
        $methodType,
      ),
    ));

    // add the same tests for the any type
    foreach ($tests as $test) {
      if ($anyType !== $test[5]) {
        $test[5] = $anyType;
        $tests[] = $test;
      }
    }
    $methodAndPropObject = new Twig_TemplateMethodAndPropObject();

    // additional method tests
    $tests = array_merge($tests, array(
      array(
        true,
        'a',
        $methodAndPropObject,
        'a',
        array(),
        $anyType,
      ),
      array(
        true,
        'a',
        $methodAndPropObject,
        'a',
        array(),
        $methodType,
      ),
      array(
        false,
        null,
        $methodAndPropObject,
        'a',
        array(),
        $arrayType,
      ),
      array(
        true,
        'b_prop',
        $methodAndPropObject,
        'b',
        array(),
        $anyType,
      ),
      array(
        true,
        'b',
        $methodAndPropObject,
        'B',
        array(),
        $anyType,
      ),
      array(
        true,
        'b',
        $methodAndPropObject,
        'b',
        array(),
        $methodType,
      ),
      array(
        true,
        'b',
        $methodAndPropObject,
        'B',
        array(),
        $methodType,
      ),
      array(
        false,
        null,
        $methodAndPropObject,
        'b',
        array(),
        $arrayType,
      ),
      array(
        false,
        null,
        $methodAndPropObject,
        'c',
        array(),
        $anyType,
      ),
      array(
        false,
        null,
        $methodAndPropObject,
        'c',
        array(),
        $methodType,
      ),
      array(
        false,
        null,
        $methodAndPropObject,
        'c',
        array(),
        $arrayType,
      ),
    ));

    // tests when input is not an array or object
    $tests = array_merge($tests, array(
      array(
        false,
        null,
        42,
        'a',
        array(),
        $anyType,
        false,
        'Item "a" for "42" does not exist',
      ),
      array(
        false,
        null,
        "string",
        'a',
        array(),
        $anyType,
        false,
        'Item "a" for "string" does not exist',
      ),
      array(
        false,
        null,
        array(),
        'a',
        array(),
        $anyType,
        false,
        'Item "a" for "Array" does not exist',
      ),
    ));

    // add twig_template_get_attributes tests
    if (function_exists('twig_template_get_attributes')) {
      foreach (array_slice($tests, 0) as $test) {
        $test = array_pad($test, 7, null);
        $test[6] = true;
        $tests[] = $test;
      }
    }
    return $tests;
  }

}
class Twig_TemplateTest extends Twig_Template {
  protected $useExtGetAttribute = false;
  public function __construct(Twig_Environment $env, $useExtGetAttribute = false) {
    parent::__construct($env);
    $this->useExtGetAttribute = $useExtGetAttribute;
    Twig_Template::clearCache();
  }
  public function getZero() {
    return 0;
  }
  public function getEmpty() {
    return '';
  }
  public function getString() {
    return 'some_string';
  }
  public function getTrue() {
    return true;
  }
  public function getTemplateName() {
  }
  public function getDebugInfo() {
    return array();
  }
  protected function doGetParent(array $context) {
  }
  protected function doDisplay(array $context, array $blocks = array()) {
  }
  public function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) {
    if ($this->useExtGetAttribute) {
      return twig_template_get_attributes($this, $object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
    }
    else {
      return parent::getAttribute($object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
    }
  }

}
class Twig_TemplateArrayAccessObject implements ArrayAccess {
  protected $protected = 'protected';
  public $attributes = array(
    'defined' => 'defined',
    'zero' => 0,
    'null' => null,
    '1' => 1,
    'bar' => true,
  );
  public function offsetExists($name) {
    return array_key_exists($name, $this->attributes);
  }
  public function offsetGet($name) {
    return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null;
  }
  public function offsetSet($name, $value) {
  }
  public function offsetUnset($name) {
  }

}
class Twig_TemplateMagicPropertyObject {
  public $defined = 'defined';
  public $attributes = array(
    'zero' => 0,
    'null' => null,
    '1' => 1,
    'bar' => true,
  );
  protected $protected = 'protected';
  public function __isset($name) {
    return array_key_exists($name, $this->attributes);
  }
  public function __get($name) {
    return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null;
  }

}
class Twig_TemplatePropertyObject {
  public $defined = 'defined';
  public $zero = 0;
  public $null = null;
  public $bar = true;
  protected $protected = 'protected';

}
class Twig_TemplatePropertyObjectAndIterator extends Twig_TemplatePropertyObject implements IteratorAggregate {
  public function getIterator() {
    return new ArrayIterator(array(
      'foo',
      'bar',
    ));
  }

}
class Twig_TemplatePropertyObjectAndArrayAccess extends Twig_TemplatePropertyObject implements ArrayAccess {
  private $data = array();
  public function offsetExists($offset) {
    return array_key_exists($offset, $this->data);
  }
  public function offsetGet($offset) {
    return $this
      ->offsetExists($offset) ? $this->data[$offset] : 'n/a';
  }
  public function offsetSet($offset, $value) {
  }
  public function offsetUnset($offset) {
  }

}
class Twig_TemplateMethodObject {
  public function getDefined() {
    return 'defined';
  }
  public function get1() {
    return 1;
  }
  public function getZero() {
    return 0;
  }
  public function getNull() {
    return null;
  }
  public function isBar() {
    return true;
  }
  protected function getProtected() {
    return 'protected';
  }
  public static function getStatic() {
    return 'static';
  }

}
class Twig_TemplateMethodAndPropObject {
  private $a = 'a_prop';
  public function getA() {
    return 'a';
  }
  public $b = 'b_prop';
  public function getB() {
    return 'b';
  }
  private $c = 'c_prop';
  private function getC() {
    return 'c';
  }

}
class Twig_TemplateMagicMethodObject {
  public function __call($method, $arguments) {
    return '__call_' . $method;
  }

}
class CExtDisablingNodeVisitor implements Twig_NodeVisitorInterface {
  public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) {
    if ($node instanceof Twig_Node_Expression_GetAttr) {
      $node
        ->setAttribute('disable_c_ext', true);
    }
    return $node;
  }
  public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) {
    return $node;
  }
  public function getPriority() {
    return 0;
  }

}

Classes