Update to Drupal 8.0.0-beta15. For more information, see: https://www.drupal.org/node/2563023

This commit is contained in:
Pantheon Automation 2015-09-04 13:20:09 -07:00 committed by Greg Anderson
parent 2720a9ec4b
commit f3791f1da3
1898 changed files with 54300 additions and 11481 deletions

View file

@ -0,0 +1,129 @@
<?php
/**
* @file
* Contains \Drupal\KernelTests\AssertLegacyTrait.
*/
namespace Drupal\KernelTests;
/**
* Translates Simpletest assertion methods to PHPUnit.
*
* Protected methods are custom. Public static methods override methods of
* \PHPUnit_Framework_Assert.
*
* @deprecated Scheduled for removal in Drupal 9.0.0. Use PHPUnit's native
* assert methods instead.
*/
trait AssertLegacyTrait {
/**
* @see \Drupal\simpletest\TestBase::assert()
*
* @deprecated Scheduled for removal in Drupal 9.0.0. Use self::assertTrue()
* instead.
*/
protected function assert($actual, $message = '') {
parent::assertTrue((bool) $actual, $message);
}
/**
* @see \Drupal\simpletest\TestBase::assertTrue()
*/
public static function assertTrue($actual, $message = '') {
if (is_bool($actual)) {
parent::assertTrue($actual, $message);
}
else {
parent::assertNotEmpty($actual, $message);
}
}
/**
* @see \Drupal\simpletest\TestBase::assertFalse()
*/
public static function assertFalse($actual, $message = '') {
if (is_bool($actual)) {
parent::assertFalse($actual, $message);
}
else {
parent::assertEmpty($actual, $message);
}
}
/**
* @see \Drupal\simpletest\TestBase::assertEqual()
*
* @deprecated Scheduled for removal in Drupal 9.0.0. Use self::assertEquals()
* instead.
*/
protected function assertEqual($actual, $expected, $message = '') {
$this->assertEquals($expected, $actual, $message);
}
/**
* @see \Drupal\simpletest\TestBase::assertNotEqual()
*
* @deprecated Scheduled for removal in Drupal 9.0.0. Use
* self::assertNotEquals() instead.
*/
protected function assertNotEqual($actual, $expected, $message = '') {
$this->assertNotEquals($expected, $actual, $message);
}
/**
* @see \Drupal\simpletest\TestBase::assertIdentical()
*
* @deprecated Scheduled for removal in Drupal 9.0.0. Use self::assertSame()
* instead.
*/
protected function assertIdentical($actual, $expected, $message = '') {
$this->assertSame($expected, $actual, $message);
}
/**
* @see \Drupal\simpletest\TestBase::assertNotIdentical()
*
* @deprecated Scheduled for removal in Drupal 9.0.0. Use
* self::assertNotSame() instead.
*/
protected function assertNotIdentical($actual, $expected, $message = '') {
$this->assertNotSame($expected, $actual, $message);
}
/**
* @see \Drupal\simpletest\TestBase::assertIdenticalObject()
*
* @deprecated Scheduled for removal in Drupal 9.0.0. Use self::assertEquals()
* instead.
*/
protected function assertIdenticalObject($actual, $expected, $message = '') {
// Note: ::assertSame checks whether its the same object. ::assertEquals
// though compares
$this->assertEquals($expected, $actual, $message);
}
/**
* @see \Drupal\simpletest\TestBase::pass()
*
* @deprecated Scheduled for removal in Drupal 9.0.0. Use self::assertTrue()
* instead.
*/
protected function pass($message) {
$this->assertTrue(TRUE, $message);
}
/**
* @see \Drupal\simpletest\TestBase::verbose()
*/
protected function verbose($message) {
if (in_array('--debug', $_SERVER['argv'], TRUE)) {
// Write directly to STDOUT to not produce unexpected test output.
// The STDOUT stream does not obey output buffering.
fwrite(STDOUT, $message . "\n");
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,229 @@
<?php
/**
* @file
* Contains \Drupal\KernelTests\KernelTestBaseTest.
*/
namespace Drupal\KernelTests;
use Drupal\Core\Database\Database;
use org\bovigo\vfs\vfsStream;
use org\bovigo\vfs\visitor\vfsStreamStructureVisitor;
/**
* @coversDefaultClass \Drupal\KernelTests\KernelTestBase
* @group PHPUnit
*/
class KernelTestBaseTest extends KernelTestBase {
/**
* @covers ::setUpBeforeClass
*/
public function testSetUpBeforeClass() {
// Note: PHPUnit automatically restores the original working directory.
$this->assertSame(realpath(__DIR__ . '/../../../../'), getcwd());
}
/**
* @covers ::bootEnvironment
*/
public function testBootEnvironment() {
$this->assertRegExp('/^simpletest\d{6}$/', $this->databasePrefix);
$this->assertStringStartsWith('vfs://root/sites/simpletest/', $this->siteDirectory);
$this->assertEquals(array(
'root' => array(
'sites' => array(
'simpletest' => array(
substr($this->databasePrefix, 10) => array(
'files' => array(
'config' => array(
'active' => array(),
'staging' => array(),
),
),
),
),
),
),
), vfsStream::inspect(new vfsStreamStructureVisitor())->getStructure());
}
/**
* @covers ::getDatabaseConnectionInfo
*/
public function testGetDatabaseConnectionInfoWithOutManualSetDbUrl() {
$options = $this->container->get('database')->getConnectionOptions();
$this->assertSame($this->databasePrefix, $options['prefix']['default']);
}
/**
* @covers ::setUp
*/
public function testSetUp() {
$this->assertTrue($this->container->has('request_stack'));
$this->assertTrue($this->container->initialized('request_stack'));
$request = $this->container->get('request_stack')->getCurrentRequest();
$this->assertNotEmpty($request);
$this->assertEquals('/', $request->getPathInfo());
$this->assertSame($request, \Drupal::request());
$this->assertEquals($this, $GLOBALS['conf']['container_service_providers']['test']);
$GLOBALS['destroy-me'] = TRUE;
$this->assertArrayHasKey('destroy-me', $GLOBALS);
$schema = $this->container->get('database')->schema();
$schema->createTable('foo', array(
'fields' => array(
'number' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
),
),
));
$this->assertTrue($schema->tableExists('foo'));
}
/**
* @covers ::setUp
* @depends testSetUp
*/
public function testSetUpDoesNotLeak() {
$this->assertArrayNotHasKey('destroy-me', $GLOBALS);
// Ensure that we have a different database prefix.
$schema = $this->container->get('database')->schema();
$this->assertFalse($schema->tableExists('foo'));
}
/**
* @covers ::register
*/
public function testRegister() {
// Verify that this container is identical to the actual container.
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerInterface', $this->container);
$this->assertSame($this->container, \Drupal::getContainer());
// The request service should never exist.
$this->assertFalse($this->container->has('request'));
// Verify that there is a request stack.
$request = $this->container->get('request_stack')->getCurrentRequest();
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Request', $request);
$this->assertSame($request, \Drupal::request());
// Trigger a container rebuild.
$this->enableModules(array('system'));
// Verify that this container is identical to the actual container.
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerInterface', $this->container);
$this->assertSame($this->container, \Drupal::getContainer());
// The request service should never exist.
$this->assertFalse($this->container->has('request'));
// Verify that there is a request stack (and that it persisted).
$new_request = $this->container->get('request_stack')->getCurrentRequest();
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Request', $new_request);
$this->assertSame($new_request, \Drupal::request());
$this->assertSame($request, $new_request);
}
/**
* @covers ::getCompiledContainerBuilder
*
* The point of this test is to have integration level testing.
*/
public function testCompiledContainer() {
$this->enableModules(['system', 'user']);
$this->assertNull($this->installConfig('user'));
}
/**
* @covers ::getCompiledContainerBuilder
* @depends testCompiledContainer
*
* The point of this test is to have integration level testing.
*/
public function testCompiledContainerIsDestructed() {
$this->enableModules(['system', 'user']);
$this->assertNull($this->installConfig('user'));
}
/**
* @covers ::render
*/
public function testRender() {
$type = 'processed_text';
$element_info = $this->container->get('element_info');
$this->assertSame(['#defaults_loaded' => TRUE], $element_info->getInfo($type));
$this->enableModules(array('filter'));
$this->assertNotSame($element_info, $this->container->get('element_info'));
$this->assertNotEmpty($this->container->get('element_info')->getInfo($type));
$build = array(
'#type' => 'html_tag',
'#tag' => 'h3',
'#value' => 'Inner',
);
$expected = "<h3>Inner</h3>\n";
$this->assertEquals('core', \Drupal::theme()->getActiveTheme()->getName());
$output = \Drupal::service('renderer')->renderRoot($build);
$this->assertEquals('core', \Drupal::theme()->getActiveTheme()->getName());
$this->assertEquals($expected, $build['#children']);
$this->assertEquals($expected, $output);
}
/**
* @covers ::render
*/
public function testRenderWithTheme() {
$this->enableModules(array('system'));
$build = array(
'#type' => 'textfield',
'#name' => 'test',
);
$expected = '/' . preg_quote('<input type="text" name="test"', '/') . '/';
$this->assertArrayNotHasKey('theme', $GLOBALS);
$output = \Drupal::service('renderer')->renderRoot($build);
$this->assertEquals('core', \Drupal::theme()->getActiveTheme()->getName());
$this->assertRegExp($expected, (string) $build['#children']);
$this->assertRegExp($expected, (string) $output);
}
/**
* {@inheritdoc}
*/
protected function tearDown() {
parent::tearDown();
// Check that all tables of the test instance have been deleted. At this
// point the original database connection is restored so we need to prefix
// the tables.
$connection = Database::getConnection();
if ($connection->databaseType() != 'sqlite') {
$tables = $connection->schema()->findTables($this->databasePrefix . '%');
$this->assertTrue(empty($tables), 'All test tables have been removed.');
}
else {
$result = $connection->query("SELECT name FROM " . $this->databasePrefix . ".sqlite_master WHERE type = :type AND name LIKE :table_name AND name NOT LIKE :pattern", array(
':type' => 'table',
':table_name' => '%',
':pattern' => 'sqlite_%',
))->fetchAllKeyed(0, 0);
$this->assertTrue(empty($result), 'All test tables have been removed.');
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,621 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Component\DependencyInjection\Dumper\OptimizedPhpArrayDumperTest.
*/
namespace Drupal\Tests\Component\DependencyInjection\Dumper {
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* @coversDefaultClass \Drupal\Component\DependencyInjection\Dumper\OptimizedPhpArrayDumper
* @group DependencyInjection
*/
class OptimizedPhpArrayDumperTest extends \PHPUnit_Framework_TestCase {
/**
* The container builder instance.
*
* @var \Symfony\Component\DependencyInjection\ContainerBuilder
*/
protected $containerBuilder;
/**
* The definition for the container to build in tests.
*
* @var array
*/
protected $containerDefinition;
/**
* Whether the dumper uses the machine-optimized format or not.
*
* @var bool
*/
protected $machineFormat = TRUE;
/**
* Stores the dumper class to use.
*
* @var string
*/
protected $dumperClass = '\Drupal\Component\DependencyInjection\Dumper\OptimizedPhpArrayDumper';
/**
* The dumper instance.
*
* @var \Symfony\Component\DependencyInjection\Dumper\DumperInterface
*/
protected $dumper;
/**
* {@inheritdoc}
*/
public function setUp() {
// Setup a mock container builder.
$this->containerBuilder = $this->prophesize('\Symfony\Component\DependencyInjection\ContainerBuilder');
$this->containerBuilder->getAliases()->willReturn(array());
$this->containerBuilder->getParameterBag()->willReturn(new ParameterBag());
$this->containerBuilder->getDefinitions()->willReturn(NULL);
$this->containerBuilder->isFrozen()->willReturn(TRUE);
$definition = array();
$definition['aliases'] = array();
$definition['parameters'] = array();
$definition['services'] = array();
$definition['frozen'] = TRUE;
$definition['machine_format'] = $this->machineFormat;
$this->containerDefinition = $definition;
// Create the dumper.
$this->dumper = new $this->dumperClass($this->containerBuilder->reveal());
}
/**
* Tests that an empty container works properly.
*
* @covers ::dump
* @covers ::getArray
* @covers ::supportsMachineFormat
*/
public function testDumpForEmptyContainer() {
$serialized_definition = $this->dumper->dump();
$this->assertEquals(serialize($this->containerDefinition), $serialized_definition);
}
/**
* Tests that alias processing works properly.
*
* @covers ::getAliases
*
* @dataProvider getAliasesDataProvider
*/
public function testGetAliases($aliases, $definition_aliases) {
$this->containerDefinition['aliases'] = $definition_aliases;
$this->containerBuilder->getAliases()->willReturn($aliases);
$this->assertEquals($this->containerDefinition, $this->dumper->getArray(), 'Expected definition matches dump.');
}
/**
* Data provider for testGetAliases().
*
* @return array[]
* Returns data-set elements with:
* - aliases as returned by ContainerBuilder.
* - aliases as expected in the container definition.
*/
public function getAliasesDataProvider() {
return array(
array(array(), array()),
array(
array('foo' => 'foo.alias'),
array('foo' => 'foo.alias'),
),
array(
array('foo' => 'foo.alias', 'foo.alias' => 'foo.alias.alias'),
array('foo' => 'foo.alias.alias', 'foo.alias' => 'foo.alias.alias'),
),
);
}
/**
* Tests that parameter processing works properly.
*
* @covers ::getParameters
* @covers ::prepareParameters
* @covers ::escape
* @covers ::dumpValue
* @covers ::getReferenceCall
*
* @dataProvider getParametersDataProvider
*/
public function testGetParameters($parameters, $definition_parameters, $is_frozen) {
$this->containerDefinition['parameters'] = $definition_parameters;
$this->containerDefinition['frozen'] = $is_frozen;
$parameter_bag = new ParameterBag($parameters);
$this->containerBuilder->getParameterBag()->willReturn($parameter_bag);
$this->containerBuilder->isFrozen()->willReturn($is_frozen);
if (isset($parameters['reference'])) {
$definition = new Definition('\stdClass');
$this->containerBuilder->getDefinition('referenced_service')->willReturn($definition);
}
$this->assertEquals($this->containerDefinition, $this->dumper->getArray(), 'Expected definition matches dump.');
}
/**
* Data provider for testGetParameters().
*
* @return array[]
* Returns data-set elements with:
* - parameters as returned by ContainerBuilder.
* - parameters as expected in the container definition.
* - frozen value
*/
public function getParametersDataProvider() {
return array(
array(array(), array(), TRUE),
array(
array('foo' => 'value_foo'),
array('foo' => 'value_foo'),
TRUE,
),
array(
array('foo' => array('llama' => 'yes')),
array('foo' => array('llama' => 'yes')),
TRUE,
),
array(
array('foo' => '%llama%', 'llama' => 'yes'),
array('foo' => '%%llama%%', 'llama' => 'yes'),
TRUE,
),
array(
array('foo' => '%llama%', 'llama' => 'yes'),
array('foo' => '%llama%', 'llama' => 'yes'),
FALSE,
),
array(
array('reference' => new Reference('referenced_service')),
array('reference' => $this->getServiceCall('referenced_service')),
TRUE,
),
);
}
/**
* Tests that service processing works properly.
*
* @covers ::getServiceDefinitions
* @covers ::getServiceDefinition
* @covers ::dumpMethodCalls
* @covers ::dumpCollection
* @covers ::dumpCallable
* @covers ::dumpValue
* @covers ::getPrivateServiceCall
* @covers ::getReferenceCall
* @covers ::getServiceCall
* @covers ::getParameterCall
*
* @dataProvider getDefinitionsDataProvider
*/
public function testGetServiceDefinitions($services, $definition_services) {
$this->containerDefinition['services'] = $definition_services;
$this->containerBuilder->getDefinitions()->willReturn($services);
$bar_definition = new Definition('\stdClass');
$this->containerBuilder->getDefinition('bar')->willReturn($bar_definition);
$private_definition = new Definition('\stdClass');
$private_definition->setPublic(FALSE);
$this->containerBuilder->getDefinition('private_definition')->willReturn($private_definition);
$this->assertEquals($this->containerDefinition, $this->dumper->getArray(), 'Expected definition matches dump.');
}
/**
* Data provider for testGetServiceDefinitions().
*
* @return array[]
* Returns data-set elements with:
* - parameters as returned by ContainerBuilder.
* - parameters as expected in the container definition.
* - frozen value
*/
public function getDefinitionsDataProvider() {
$base_service_definition = array(
'class' => '\stdClass',
'public' => TRUE,
'file' => FALSE,
'synthetic' => FALSE,
'lazy' => FALSE,
'arguments' => array(),
'arguments_count' => 0,
'properties' => array(),
'calls' => array(),
'scope' => ContainerInterface::SCOPE_CONTAINER,
'shared' => TRUE,
'factory' => FALSE,
'configurator' => FALSE,
);
// Test basic flags.
$service_definitions[] = array() + $base_service_definition;
$service_definitions[] = array(
'public' => FALSE,
) + $base_service_definition;
$service_definitions[] = array(
'file' => 'test_include.php',
) + $base_service_definition;
$service_definitions[] = array(
'synthetic' => TRUE,
) + $base_service_definition;
$service_definitions[] = array(
'lazy' => TRUE,
) + $base_service_definition;
// Test a basic public Reference.
$service_definitions[] = array(
'arguments' => array('foo', new Reference('bar')),
'arguments_count' => 2,
'arguments_expected' => $this->getCollection(array('foo', $this->getServiceCall('bar'))),
) + $base_service_definition;
// Test a public reference that should not throw an Exception.
$reference = new Reference('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE);
$service_definitions[] = array(
'arguments' => array($reference),
'arguments_count' => 1,
'arguments_expected' => $this->getCollection(array($this->getServiceCall('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE))),
) + $base_service_definition;
// Test a private shared service, denoted by having a Reference.
$private_definition = array(
'class' => '\stdClass',
'public' => FALSE,
'arguments_count' => 0,
);
$service_definitions[] = array(
'arguments' => array('foo', new Reference('private_definition')),
'arguments_count' => 2,
'arguments_expected' => $this->getCollection(array(
'foo',
$this->getPrivateServiceCall('private_definition', $private_definition, TRUE),
)),
) + $base_service_definition;
// Test a private non-shared service, denoted by having a Definition.
$private_definition_object = new Definition('\stdClass');
$private_definition_object->setPublic(FALSE);
$service_definitions[] = array(
'arguments' => array('foo', $private_definition_object),
'arguments_count' => 2,
'arguments_expected' => $this->getCollection(array(
'foo',
$this->getPrivateServiceCall(NULL, $private_definition),
)),
) + $base_service_definition;
// Test a deep collection without a reference.
$service_definitions[] = array(
'arguments' => array(array(array('foo'))),
'arguments_count' => 1,
) + $base_service_definition;
// Test a deep collection with a reference to resolve.
$service_definitions[] = array(
'arguments' => array(array(new Reference('bar'))),
'arguments_count' => 1,
'arguments_expected' => $this->getCollection(array($this->getCollection(array($this->getServiceCall('bar'))))),
) + $base_service_definition;
// Test a collection with a variable to resolve.
$service_definitions[] = array(
'arguments' => array(new Parameter('llama_parameter')),
'arguments_count' => 1,
'arguments_expected' => $this->getCollection(array($this->getParameterCall('llama_parameter'))),
) + $base_service_definition;
// Test objects that have _serviceId property.
$drupal_service = new \stdClass();
$drupal_service->_serviceId = 'bar';
$service_definitions[] = array(
'arguments' => array($drupal_service),
'arguments_count' => 1,
'arguments_expected' => $this->getCollection(array($this->getServiceCall('bar'))),
) + $base_service_definition;
// Test getMethodCalls.
$calls = array(
array('method', $this->getCollection(array())),
array('method2', $this->getCollection(array())),
);
$service_definitions[] = array(
'calls' => $calls,
) + $base_service_definition;
$service_definitions[] = array(
'scope' => ContainerInterface::SCOPE_PROTOTYPE,
'shared' => FALSE,
) + $base_service_definition;
// Test factory.
$service_definitions[] = array(
'factory' => array(new Reference('bar'), 'factoryMethod'),
'factory_expected' => array($this->getServiceCall('bar'), 'factoryMethod'),
) + $base_service_definition;
// Test invalid factory - needed to test deep dumpValue().
$service_definitions[] = array(
'factory' => array(array('foo', 'llama'), 'factoryMethod'),
) + $base_service_definition;
// Test properties.
$service_definitions[] = array(
'properties' => array('_value' => 'llama'),
) + $base_service_definition;
// Test configurator.
$service_definitions[] = array(
'configurator' => array(new Reference('bar'), 'configureService'),
'configurator_expected' => array($this->getServiceCall('bar'), 'configureService'),
) + $base_service_definition;
$services_provided = array();
$services_provided[] = array(
array(),
array(),
);
foreach ($service_definitions as $service_definition) {
$definition = $this->prophesize('\Symfony\Component\DependencyInjection\Definition');
$definition->getClass()->willReturn($service_definition['class']);
$definition->isPublic()->willReturn($service_definition['public']);
$definition->getFile()->willReturn($service_definition['file']);
$definition->isSynthetic()->willReturn($service_definition['synthetic']);
$definition->isLazy()->willReturn($service_definition['lazy']);
$definition->getArguments()->willReturn($service_definition['arguments']);
$definition->getProperties()->willReturn($service_definition['properties']);
$definition->getMethodCalls()->willReturn($service_definition['calls']);
$definition->getScope()->willReturn($service_definition['scope']);
$definition->getDecoratedService()->willReturn(NULL);
$definition->getFactory()->willReturn($service_definition['factory']);
$definition->getConfigurator()->willReturn($service_definition['configurator']);
// Preserve order.
$filtered_service_definition = array();
foreach ($base_service_definition as $key => $value) {
$filtered_service_definition[$key] = $service_definition[$key];
unset($service_definition[$key]);
if ($key == 'class' || $key == 'arguments_count') {
continue;
}
if ($filtered_service_definition[$key] === $base_service_definition[$key]) {
unset($filtered_service_definition[$key]);
}
}
// Add remaining properties.
$filtered_service_definition += $service_definition;
// Allow to set _expected values.
foreach (array('arguments', 'factory', 'configurator') as $key) {
$expected = $key . '_expected';
if (isset($filtered_service_definition[$expected])) {
$filtered_service_definition[$key] = $filtered_service_definition[$expected];
unset($filtered_service_definition[$expected]);
}
}
// Remove any remaining scope.
unset($filtered_service_definition['scope']);
if (isset($filtered_service_definition['public']) && $filtered_service_definition['public'] === FALSE) {
$services_provided[] = array(
array('foo_service' => $definition->reveal()),
array(),
);
continue;
}
$services_provided[] = array(
array('foo_service' => $definition->reveal()),
array('foo_service' => $this->serializeDefinition($filtered_service_definition)),
);
}
return $services_provided;
}
/**
* Helper function to serialize a definition.
*
* Used to override serialization.
*/
protected function serializeDefinition(array $service_definition) {
return serialize($service_definition);
}
/**
* Helper function to return a service definition.
*/
protected function getServiceCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
return (object) array(
'type' => 'service',
'id' => $id,
'invalidBehavior' => $invalid_behavior,
);
}
/**
* Tests that the correct InvalidArgumentException is thrown for getScope().
*
* @covers ::getServiceDefinition
*
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
*/
public function testGetServiceDefinitionWithInvalidScope() {
$bar_definition = new Definition('\stdClass');
$bar_definition->setScope('foo_scope');
$services['bar'] = $bar_definition;
$this->containerBuilder->getDefinitions()->willReturn($services);
$this->dumper->getArray();
}
/**
* Tests that getDecoratedService() is unsupported.
*
* Tests that the correct InvalidArgumentException is thrown for
* getDecoratedService().
*
* @covers ::getServiceDefinition
*
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
*/
public function testGetServiceDefinitionForDecoratedService() {
$bar_definition = new Definition('\stdClass');
$bar_definition->setDecoratedService(new Reference('foo'));
$services['bar'] = $bar_definition;
$this->containerBuilder->getDefinitions()->willReturn($services);
$this->dumper->getArray();
}
/**
* Tests that the correct RuntimeException is thrown for expressions.
*
* @covers ::dumpValue
*
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
*/
public function testGetServiceDefinitionForExpression() {
$expression = new Expression();
$bar_definition = new Definition('\stdClass');
$bar_definition->addArgument($expression);
$services['bar'] = $bar_definition;
$this->containerBuilder->getDefinitions()->willReturn($services);
$this->dumper->getArray();
}
/**
* Tests that the correct RuntimeException is thrown for dumping an object.
*
* @covers ::dumpValue
*
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
*/
public function testGetServiceDefinitionForObject() {
$service = new \stdClass();
$bar_definition = new Definition('\stdClass');
$bar_definition->addArgument($service);
$services['bar'] = $bar_definition;
$this->containerBuilder->getDefinitions()->willReturn($services);
$this->dumper->getArray();
}
/**
* Tests that the correct RuntimeException is thrown for dumping a resource.
*
* @covers ::dumpValue
*
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
*/
public function testGetServiceDefinitionForResource() {
$resource = fopen('php://memory', 'r');
$bar_definition = new Definition('\stdClass');
$bar_definition->addArgument($resource);
$services['bar'] = $bar_definition;
$this->containerBuilder->getDefinitions()->willReturn($services);
$this->dumper->getArray();
}
/**
* Helper function to return a private service definition.
*/
protected function getPrivateServiceCall($id, $service_definition, $shared = FALSE) {
if (!$id) {
$hash = sha1(serialize($service_definition));
$id = 'private__' . $hash;
}
return (object) array(
'type' => 'private_service',
'id' => $id,
'value' => $service_definition,
'shared' => $shared,
);
}
/**
* Helper function to return a machine-optimized collection.
*/
protected function getCollection($collection, $resolve = TRUE) {
return (object) array(
'type' => 'collection',
'value' => $collection,
'resolve' => $resolve,
);
}
/**
* Helper function to return a parameter definition.
*/
protected function getParameterCall($name) {
return (object) array(
'type' => 'parameter',
'name' => $name,
);
}
}
}
/**
* As Drupal Core does not ship with ExpressionLanguage component we need to
* define a dummy, else it cannot be tested.
*/
namespace Symfony\Component\ExpressionLanguage {
if (!class_exists('\Symfony\Component\ExpressionLanguage\Expression')) {
/**
* Dummy class to ensure non-existent Symfony component can be tested.
*/
class Expression {
/**
* Gets the string representation of the expression.
*/
public function __toString() {
return 'dummy_expression';
}
}
}
}

View file

@ -0,0 +1,59 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Component\DependencyInjection\Dumper\PhpArrayDumperTest.
*/
namespace Drupal\Tests\Component\DependencyInjection\Dumper;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* @coversDefaultClass \Drupal\Component\DependencyInjection\Dumper\PhpArrayDumper
* @group DependencyInjection
*/
class PhpArrayDumperTest extends OptimizedPhpArrayDumperTest {
/**
* {@inheritdoc}
*/
public function setUp() {
$this->machineFormat = FALSE;
$this->dumperClass = '\Drupal\Component\DependencyInjection\Dumper\PhpArrayDumper';
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function serializeDefinition(array $service_definition) {
return $service_definition;
}
/**
* {@inheritdoc}
*/
protected function getServiceCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
if ($invalid_behavior !== ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
return sprintf('@?%s', $id);
}
return sprintf('@%s', $id);
}
/**
* {@inheritdoc}
*/
protected function getParameterCall($name) {
return '%' . $name . '%';
}
/**
* {@inheritdoc}
*/
protected function getCollection($collection, $resolve = TRUE) {
return $collection;
}
}

View file

@ -0,0 +1,16 @@
<?php
/**
* @file
* Contains a test function for container 'file' include testing.
*/
/**
* Test function for container testing.
*
* @return string
* A string just for testing.
*/
function container_test_file_service_test_service_function() {
return 'Hello Container';
}

View file

@ -0,0 +1,54 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Component\DependencyInjection\PhpArrayContainerTest.
*/
namespace Drupal\Tests\Component\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\LogicException;
/**
* @coversDefaultClass \Drupal\Component\DependencyInjection\PhpArrayContainer
* @group DependencyInjection
*/
class PhpArrayContainerTest extends ContainerTest {
/**
* {@inheritdoc}
*/
public function setUp() {
$this->machineFormat = FALSE;
$this->containerClass = '\Drupal\Component\DependencyInjection\PhpArrayContainer';
$this->containerDefinition = $this->getMockContainerDefinition();
$this->container = new $this->containerClass($this->containerDefinition);
}
/**
* Helper function to return a service definition.
*/
protected function getServiceCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
if ($invalid_behavior !== ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
return sprintf('@?%s', $id);
}
return sprintf('@%s', $id);
}
/**
* Helper function to return a service definition.
*/
protected function getParameterCall($name) {
return '%' . $name . '%';
}
/**
* Helper function to return a machine-optimized '@notation'.
*/
protected function getCollection($collection, $resolve = TRUE) {
return $collection;
}
}

View file

@ -68,15 +68,12 @@ class DrupalComponentTest extends UnitTestCase {
*/
protected function assertNoCoreUsage($class_path) {
$contents = file_get_contents($class_path);
if (preg_match_all('/^.*Drupal\\\Core.*$/m', $contents, $matches)) {
foreach ($matches[0] as $line) {
if ((strpos($line, '@see ') === FALSE)) {
$this->fail(
"Illegal reference to 'Drupal\\Core' namespace in $class_path"
);
}
}
}
preg_match_all('/^.*Drupal\\\Core.*$/m', $contents, $matches);
$matches = array_filter($matches[0], function($line) {
// Filter references to @see as they don't really matter.
return strpos($line, '@see') === FALSE;
});
$this->assertEmpty($matches, "Checking for illegal reference to 'Drupal\\Core' namespace in $class_path");
}
/**

View file

@ -75,6 +75,7 @@ class FileStorageReadOnlyTest extends PhpStorageTestBase {
// Saving and deleting should always fail.
$this->assertFalse($php_read->save($name, $code));
$this->assertFalse($php_read->delete($name));
unset($GLOBALS[$random]);
}
/**

View file

@ -86,6 +86,7 @@ class FileStorageTest extends PhpStorageTestBase {
// Should still return TRUE if directory has already been deleted.
$this->assertTrue($php->deleteAll(), 'Delete all succeeds with nothing to delete');
unset($GLOBALS[$random]);
}
}

View file

@ -124,6 +124,7 @@ abstract class MTimeProtectedFileStorageBase extends PhpStorageTestBase {
$this->assertSame($php->load($name), $this->expected[$i]);
$this->assertSame($GLOBALS['hacked'], $this->expected[$i]);
}
unset($GLOBALS['hacked']);
}
}

View file

@ -7,6 +7,7 @@
namespace Drupal\Tests\Component\PhpStorage;
use Drupal\Component\PhpStorage\PhpStorageInterface;
use Drupal\Tests\UnitTestCase;
use org\bovigo\vfs\vfsStream;
@ -49,6 +50,9 @@ abstract class PhpStorageTestBase extends UnitTestCase {
$php->load($name);
$this->assertTrue($GLOBALS[$random], 'File saved correctly with correct value');
// Run additional asserts.
$this->additionalAssertCRUD($php, $name);
// If the file was successfully loaded, it must also exist, but ensure the
// exists() method returns that correctly.
$this->assertTrue($php->exists($name), 'Exists works correctly');
@ -60,6 +64,20 @@ abstract class PhpStorageTestBase extends UnitTestCase {
// Ensure delete() can be called on a non-existing file. It should return
// FALSE, but not trigger errors.
$this->assertFalse($php->delete($name), 'Delete fails on missing file');
unset($GLOBALS[$random]);
}
/**
* Additional asserts to be run.
*
* @param \Drupal\Component\PhpStorage\PhpStorageInterface $php
* The PHP storage object.
* @param string $name
* The name of an object. It should exist in the storage.
*/
protected function additionalAssertCRUD(PhpStorageInterface $php, $name) {
// By default do not do any additional asserts. This is a way of extending
// tests in contrib.
}
}

View file

@ -259,4 +259,55 @@ class HtmlTest extends UnitTestCase {
);
}
/**
* Tests Html::escape().
*
* @dataProvider providerEscape
* @covers ::escape
*/
public function testEscape($expected, $text) {
$this->assertEquals($expected, Html::escape($text));
}
/**
* Data provider for testEscape().
*
* @see testCheckPlain()
*/
public function providerEscape() {
return array(
array('Drupal', 'Drupal'),
array('&lt;script&gt;', '<script>'),
array('&amp;lt;script&amp;gt;', '&lt;script&gt;'),
array('&amp;#34;', '&#34;'),
array('&quot;', '"'),
array('&amp;quot;', '&quot;'),
array('&#039;', "'"),
array('&amp;#039;', '&#039;'),
array('©', '©'),
array('→', '→'),
array('➼', '➼'),
array('€', '€'),
array('Drup<75>al', "Drup\x80al"),
);
}
/**
* Tests relationship between escaping and decoding HTML entities.
*
* @covers ::decodeEntities
* @covers ::escape
*/
public function testDecodeEntitiesAndEscape() {
$string = "<em>répét&eacute;</em>";
$escaped = Html::escape($string);
$this->assertSame('&lt;em&gt;répét&amp;eacute;&lt;/em&gt;', $escaped);
$decoded = Html::decodeEntities($escaped);
$this->assertSame('<em>répét&eacute;</em>', $decoded);
$decoded = Html::decodeEntities($decoded);
$this->assertSame('<em>répété</em>', $decoded);
$escaped = Html::escape($decoded);
$this->assertSame('&lt;em&gt;répété&lt;/em&gt;', $escaped);
}
}

View file

@ -8,7 +8,6 @@
namespace Drupal\Tests\Component\Utility;
use Drupal\Component\Utility\Random;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Tests\UnitTestCase;
/**
@ -39,7 +38,7 @@ class RandomTest extends UnitTestCase {
$random = new Random();
for ($i = 0; $i <= 50; $i++) {
$str = $random->string(1, TRUE);
$this->assertFalse(isset($strings[$str]), SafeMarkup::format('Generated duplicate random string !string', array('!string' => $str)));
$this->assertFalse(isset($strings[$str]), 'Generated duplicate random string ' . $str);
$strings[$str] = TRUE;
}
}
@ -54,7 +53,7 @@ class RandomTest extends UnitTestCase {
$random = new Random();
for ($i = 0; $i <= 10; $i++) {
$str = $random->name(1, TRUE);
$this->assertFalse(isset($names[$str]), SafeMarkup::format('Generated duplicate random name !name', array('!name' => $str)));
$this->assertFalse(isset($names[$str]), 'Generated duplicate random name ' . $str);
$names[$str] = TRUE;
}
}

View file

@ -8,7 +8,8 @@
namespace Drupal\Tests\Component\Utility;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Component\Utility\SafeStringInterface;
use Drupal\Component\Utility\SafeStringTrait;
use Drupal\Tests\UnitTestCase;
/**
@ -20,54 +21,81 @@ use Drupal\Tests\UnitTestCase;
class SafeMarkupTest extends UnitTestCase {
/**
* Tests SafeMarkup::set() and SafeMarkup::isSafe().
* Helper function to add a string to the safe list for testing.
*
* @dataProvider providerSet
* @param string $string
* The content to be marked as secure.
* @param string $strategy
* The escaping strategy used for this string. Two values are supported
* by default:
* - 'html': (default) The string is safe for use in HTML code.
* - 'all': The string is safe for all use cases.
* See the
* @link http://twig.sensiolabs.org/doc/filters/escape.html Twig escape documentation @endlink
* for more information on escaping strategies in Twig.
*
* @param string $text
* The text or object to provide to SafeMarkup::set().
* @param string $message
* The message to provide as output for the test.
*
* @covers ::set
* @return string
* The input string that was marked as safe.
*/
public function testSet($text, $message) {
$returned = SafeMarkup::set($text);
$this->assertTrue(is_string($returned), 'The return value of SafeMarkup::set() is really a string');
$this->assertEquals($returned, $text, 'The passed in value should be equal to the string value according to PHP');
$this->assertTrue(SafeMarkup::isSafe($text), $message);
$this->assertTrue(SafeMarkup::isSafe($returned), 'The return value has been marked as safe');
protected function safeMarkupSet($string, $strategy = 'html') {
$reflected_class = new \ReflectionClass('\Drupal\Component\Utility\SafeMarkup');
$reflected_property = $reflected_class->getProperty('safeStrings');
$reflected_property->setAccessible(true);
$current_value = $reflected_property->getValue();
$current_value[$string][$strategy] = TRUE;
$reflected_property->setValue($current_value);
return $string;
}
/**
* Tests SafeMarkup::isSafe() with different providers.
*
* @covers ::isSafe
*/
public function testStrategy() {
$returned = $this->safeMarkupSet('string0', 'html');
$this->assertTrue(SafeMarkup::isSafe($returned), 'String set with "html" provider is safe for default (html)');
$returned = $this->safeMarkupSet('string1', 'all');
$this->assertTrue(SafeMarkup::isSafe($returned), 'String set with "all" provider is safe for default (html)');
$returned = $this->safeMarkupSet('string2', 'css');
$this->assertFalse(SafeMarkup::isSafe($returned), 'String set with "css" provider is not safe for default (html)');
$returned = $this->safeMarkupSet('string3');
$this->assertFalse(SafeMarkup::isSafe($returned, 'all'), 'String set with "html" provider is not safe for "all"');
}
/**
* Data provider for testSet().
*
* @see testSet()
*/
public function providerSet() {
// Checks that invalid multi-byte sequences are rejected.
$tests[] = array("Foo\xC0barbaz", '', 'SafeMarkup::checkPlain() rejects invalid sequence "Foo\xC0barbaz"', TRUE);
$tests[] = array("Fooÿñ", 'SafeMarkup::set() accepts valid sequence "Fooÿñ"');
$tests[] = array(new TextWrapper("Fooÿñ"), 'SafeMarkup::set() accepts valid sequence "Fooÿñ" in an object implementing __toString()');
$tests[] = array("<div>", 'SafeMarkup::set() accepts HTML');
// Checks that invalid multi-byte sequences are escaped.
$tests[] = array(
'Foo<6F>barbaz',
'SafeMarkup::setMarkup() functions with valid sequence "Foo<6F>barbaz"',
TRUE
);
$tests[] = array(
"Fooÿñ",
'SafeMarkup::setMarkup() functions with valid sequence "Fooÿñ"'
);
$tests[] = array("<div>", 'SafeMarkup::setMultiple() does not escape HTML');
return $tests;
}
/**
* Tests SafeMarkup::set() and SafeMarkup::isSafe() with different providers.
* Tests SafeMarkup::setMultiple().
* @dataProvider providerSet
*
* @covers ::isSafe
* @param string $text
* The text or object to provide to SafeMarkup::setMultiple().
* @param string $message
* The message to provide as output for the test.
*
* @covers ::setMultiple
*/
public function testStrategy() {
$returned = SafeMarkup::set('string0', 'html');
$this->assertTrue(SafeMarkup::isSafe($returned), 'String set with "html" provider is safe for default (html)');
$returned = SafeMarkup::set('string1', 'all');
$this->assertTrue(SafeMarkup::isSafe($returned), 'String set with "all" provider is safe for default (html)');
$returned = SafeMarkup::set('string2', 'css');
$this->assertFalse(SafeMarkup::isSafe($returned), 'String set with "css" provider is not safe for default (html)');
$returned = SafeMarkup::set('string3');
$this->assertFalse(SafeMarkup::isSafe($returned, 'all'), 'String set with "html" provider is not safe for "all"');
public function testSet($text, $message) {
SafeMarkup::setMultiple([$text => ['html' => TRUE]]);
$this->assertTrue(SafeMarkup::isSafe($text), $message);
}
/**
@ -140,10 +168,10 @@ class SafeMarkupTest extends UnitTestCase {
* @see testCheckPlain()
*/
function providerCheckPlain() {
// Checks that invalid multi-byte sequences are rejected.
$tests[] = array("Foo\xC0barbaz", '', 'SafeMarkup::checkPlain() rejects invalid sequence "Foo\xC0barbaz"', TRUE);
$tests[] = array("\xc2\"", '', 'SafeMarkup::checkPlain() rejects invalid sequence "\xc2\""', TRUE);
$tests[] = array("Fooÿñ", "Fooÿñ", 'SafeMarkup::checkPlain() accepts valid sequence "Fooÿñ"');
// Checks that invalid multi-byte sequences are escaped.
$tests[] = array("Foo\xC0barbaz", 'Foo<EFBFBD>barbaz', 'SafeMarkup::checkPlain() escapes invalid sequence "Foo\xC0barbaz"', TRUE);
$tests[] = array("\xc2\"", '<EFBFBD>&quot;', 'SafeMarkup::checkPlain() escapes invalid sequence "\xc2\""', TRUE);
$tests[] = array("Fooÿñ", "Fooÿñ", 'SafeMarkup::checkPlain() does not escape valid sequence "Fooÿñ"');
// Checks that special characters are escaped.
$tests[] = array("<script>", '&lt;script&gt;', 'SafeMarkup::checkPlain() escapes &lt;script&gt;');
@ -160,7 +188,7 @@ class SafeMarkupTest extends UnitTestCase {
*
* @param string $string
* The string to run through SafeMarkup::format().
* @param string $args
* @param string[] $args
* The arguments to pass into SafeMarkup::format().
* @param string $expected
* The expected result from calling the function.
@ -169,10 +197,14 @@ class SafeMarkupTest extends UnitTestCase {
* @param bool $expected_is_safe
* Whether the result is expected to be safe for HTML display.
*/
function testFormat($string, $args, $expected, $message, $expected_is_safe) {
public function testFormat($string, array $args, $expected, $message, $expected_is_safe) {
$result = SafeMarkup::format($string, $args);
$this->assertEquals($expected, $result, $message);
$this->assertEquals($expected_is_safe, SafeMarkup::isSafe($result), 'SafeMarkup::format correctly sets the result as safe or not safe.');
foreach ($args as $arg) {
$this->assertSame($arg instanceof SafeMarkupTestSafeString, SafeMarkup::isSafe($arg));
}
}
/**
@ -183,124 +215,11 @@ class SafeMarkupTest extends UnitTestCase {
function providerFormat() {
$tests[] = array('Simple text', array(), 'Simple text', 'SafeMarkup::format leaves simple text alone.', TRUE);
$tests[] = array('Escaped text: @value', array('@value' => '<script>'), 'Escaped text: &lt;script&gt;', 'SafeMarkup::format replaces and escapes string.', TRUE);
$tests[] = array('Escaped text: @value', array('@value' => SafeMarkup::set('<span>Safe HTML</span>')), 'Escaped text: <span>Safe HTML</span>', 'SafeMarkup::format does not escape an already safe string.', TRUE);
$tests[] = array('Escaped text: @value', array('@value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Escaped text: <span>Safe HTML</span>', 'SafeMarkup::format does not escape an already safe string.', TRUE);
$tests[] = array('Placeholder text: %value', array('%value' => '<script>'), 'Placeholder text: <em class="placeholder">&lt;script&gt;</em>', 'SafeMarkup::format replaces, escapes and themes string.', TRUE);
$tests[] = array('Placeholder text: %value', array('%value' => SafeMarkup::set('<span>Safe HTML</span>')), 'Placeholder text: <em class="placeholder"><span>Safe HTML</span></em>', 'SafeMarkup::format does not escape an already safe string themed as a placeholder.', TRUE);
$tests[] = array('Placeholder text: %value', array('%value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Placeholder text: <em class="placeholder"><span>Safe HTML</span></em>', 'SafeMarkup::format does not escape an already safe string themed as a placeholder.', TRUE);
$tests[] = array('Verbatim text: !value', array('!value' => '<script>'), 'Verbatim text: <script>', 'SafeMarkup::format replaces verbatim string as-is.', FALSE);
$tests[] = array('Verbatim text: !value', array('!value' => SafeMarkup::set('<span>Safe HTML</span>')), 'Verbatim text: <span>Safe HTML</span>', 'SafeMarkup::format replaces verbatim string as-is.', TRUE);
return $tests;
}
/**
* Tests SafeMarkup::placeholder().
*
* @covers ::placeholder
*/
function testPlaceholder() {
$this->assertEquals('<em class="placeholder">Some text</em>', SafeMarkup::placeholder('Some text'));
}
/**
* Tests SafeMarkup::replace().
*
* @dataProvider providerReplace
* @covers ::replace
*/
public function testReplace($search, $replace, $subject, $expected, $is_safe) {
$result = SafeMarkup::replace($search, $replace, $subject);
$this->assertEquals($expected, $result);
$this->assertEquals($is_safe, SafeMarkup::isSafe($result));
}
/**
* Tests the interaction between the safe list and XSS filtering.
*
* @covers ::xssFilter
* @covers ::escape
*/
public function testAdminXss() {
// Use the predefined XSS admin tag list. This strips the <marquee> tags.
$this->assertEquals('text', SafeMarkup::xssFilter('<marquee>text</marquee>', Xss::getAdminTagList()));
$this->assertTrue(SafeMarkup::isSafe('text'), 'The string \'text\' is marked as safe.');
// This won't strip the <marquee> tags and the string with HTML will be
// marked as safe.
$filtered = SafeMarkup::xssFilter('<marquee>text</marquee>', array('marquee'));
$this->assertEquals('<marquee>text</marquee>', $filtered);
$this->assertTrue(SafeMarkup::isSafe('<marquee>text</marquee>'), 'The string \'<marquee>text</marquee>\' is marked as safe.');
// SafeMarkup::xssFilter() with the default tag list will strip the
// <marquee> tag even though the string was marked safe above.
$this->assertEquals('text', SafeMarkup::xssFilter('<marquee>text</marquee>'));
// SafeMarkup::escape() will not escape the markup tag since the string was
// marked safe above.
$this->assertEquals('<marquee>text</marquee>', SafeMarkup::escape($filtered));
// SafeMarkup::checkPlain() will escape the markup tag even though the
// string was marked safe above.
$this->assertEquals('&lt;marquee&gt;text&lt;/marquee&gt;', SafeMarkup::checkPlain($filtered));
// Ensure that SafeMarkup::xssFilter strips all tags when passed an empty
// array and uses the default tag list when not passed a tag list.
$this->assertEquals('text', SafeMarkup::xssFilter('<em>text</em>', []));
$this->assertEquals('<em>text</em>', SafeMarkup::xssFilter('<em>text</em>'));
}
/**
* Data provider for testReplace().
*
* @see testReplace()
*/
public function providerReplace() {
$tests = [];
// Subject unsafe.
$tests[] = [
'<placeholder>',
SafeMarkup::set('foo'),
'<placeholder>bazqux',
'foobazqux',
FALSE,
];
// All safe.
$tests[] = [
'<placeholder>',
SafeMarkup::set('foo'),
SafeMarkup::set('<placeholder>barbaz'),
'foobarbaz',
TRUE,
];
// Safe subject, but should result in unsafe string because replacement is
// unsafe.
$tests[] = [
'<placeholder>',
'fubar',
SafeMarkup::set('<placeholder>barbaz'),
'fubarbarbaz',
FALSE,
];
// Array with all safe.
$tests[] = [
['<placeholder1>', '<placeholder2>', '<placeholder3>'],
[SafeMarkup::set('foo'), SafeMarkup::set('bar'), SafeMarkup::set('baz')],
SafeMarkup::set('<placeholder1><placeholder2><placeholder3>'),
'foobarbaz',
TRUE,
];
// Array with unsafe replacement.
$tests[] = [
['<placeholder1>', '<placeholder2>', '<placeholder3>',],
[SafeMarkup::set('bar'), SafeMarkup::set('baz'), 'qux'],
SafeMarkup::set('<placeholder1><placeholder2><placeholder3>'),
'barbazqux',
FALSE,
];
$tests[] = array('Verbatim text: !value', array('!value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Verbatim text: <span>Safe HTML</span>', 'SafeMarkup::format replaces verbatim string as-is.', TRUE);
return $tests;
}
@ -320,3 +239,13 @@ class SafeMarkupTestString {
}
}
/**
* Marks text as safe.
*
* SafeMarkupTestSafeString is used to mark text as safe because
* SafeMarkup::$safeStrings is a global static that affects all tests.
*/
class SafeMarkupTestSafeString implements SafeStringInterface {
use SafeStringTrait;
}

View file

@ -8,7 +8,6 @@
namespace Drupal\Tests\Component\Utility;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Tests\UnitTestCase;
/**
@ -94,7 +93,7 @@ class UrlHelperTest extends UnitTestCase {
public function testValidAbsolute($url, $scheme) {
$test_url = $scheme . '://' . $url;
$valid_url = UrlHelper::isValid($test_url, TRUE);
$this->assertTrue($valid_url, SafeMarkup::format('@url is a valid URL.', array('@url' => $test_url)));
$this->assertTrue($valid_url, $test_url . ' is a valid URL.');
}
/**
@ -125,7 +124,7 @@ class UrlHelperTest extends UnitTestCase {
public function testInvalidAbsolute($url, $scheme) {
$test_url = $scheme . '://' . $url;
$valid_url = UrlHelper::isValid($test_url, TRUE);
$this->assertFalse($valid_url, SafeMarkup::format('@url is NOT a valid URL.', array('@url' => $test_url)));
$this->assertFalse($valid_url, $test_url . ' is NOT a valid URL.');
}
/**
@ -159,7 +158,7 @@ class UrlHelperTest extends UnitTestCase {
public function testValidRelative($url, $prefix) {
$test_url = $prefix . $url;
$valid_url = UrlHelper::isValid($test_url);
$this->assertTrue($valid_url, SafeMarkup::format('@url is a valid URL.', array('@url' => $test_url)));
$this->assertTrue($valid_url, $test_url . ' is a valid URL.');
}
/**
@ -190,7 +189,7 @@ class UrlHelperTest extends UnitTestCase {
public function testInvalidRelative($url, $prefix) {
$test_url = $prefix . $url;
$valid_url = UrlHelper::isValid($test_url);
$this->assertFalse($valid_url, SafeMarkup::format('@url is NOT a valid URL.', array('@url' => $test_url)));
$this->assertFalse($valid_url, $test_url . ' is NOT a valid URL.');
}
/**
@ -381,8 +380,10 @@ class UrlHelperTest extends UnitTestCase {
*/
public function testFilterBadProtocol($uri, $expected, $protocols) {
UrlHelper::setAllowedProtocols($protocols);
$filtered = UrlHelper::filterBadProtocol($uri);
$this->assertEquals($expected, $filtered);
$this->assertEquals($expected, UrlHelper::filterBadProtocol($uri));
// Multiple calls to UrlHelper::filterBadProtocol() do not cause double
// escaping.
$this->assertEquals($expected, UrlHelper::filterBadProtocol(UrlHelper::filterBadProtocol($uri)));
}
/**

View file

@ -78,6 +78,11 @@ class VariableTest extends UnitTestCase {
'"\'"',
"'",
),
array(
// Quotes with $ symbols.
'"\$settings[\'foo\']"',
'$settings[\'foo\']',
),
// Object.
array(
// A stdClass object.

View file

@ -22,6 +22,7 @@ class ComposerIntegrationTest extends UnitTestCase {
*/
protected function getErrorMessages() {
$messages = [
0 => 'No errors found',
JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded',
JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
@ -63,10 +64,32 @@ class ComposerIntegrationTest extends UnitTestCase {
$json = file_get_contents($path . '/composer.json');
$result = json_decode($json);
if (is_null($result)) {
$this->fail($this->getErrorMessages()[json_last_error()]);
$this->assertNotNull($result, $this->getErrorMessages()[json_last_error()]);
}
}
/**
* Tests core's composer.json replace section.
*
* Verify that all core modules are also listed in the 'replace' section of
* core's composer.json.
*/
public function testAllModulesReplaced() {
$json = json_decode(file_get_contents($this->root . '/core/composer.json'));
$composer_replace_packages = $json->replace;
$folders = scandir($this->root . '/core/modules');
$module_names = [];
foreach ($folders as $file_name) {
if ($file_name !== '.' && $file_name !== '..' && is_dir($file_name)) {
$module_names[] = $file_name;
}
}
foreach ($module_names as $module_name) {
$this->assertTrue(array_key_exists('drupal/'.$module_name, $composer_replace_packages), 'Found ' . $module_name . ' in replace list of composer.json');
}
}
}

View file

@ -11,6 +11,7 @@ use Drupal\Core\Access\AccessCheckInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessManagerInterface;
use Drupal\Core\Access\CheckProvider;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\Routing\RouteMatch;
use Drupal\Core\Access\AccessManager;
use Drupal\Core\Access\DefaultAccessCheck;
@ -94,6 +95,9 @@ class AccessManagerTest extends UnitTestCase {
parent::setUp();
$this->container = new ContainerBuilder();
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class)->reveal();
$this->container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($this->container);
$this->routeCollection = new RouteCollection();
$this->routeCollection->add('test_route_1', new Route('/test-route-1'));

View file

@ -52,7 +52,6 @@ class AccessResultTest extends UnitTestCase {
/**
* Tests the construction of an AccessResult object.
*
* @covers ::__construct
* @covers ::neutral
*/
public function testConstruction() {
@ -852,8 +851,15 @@ class AccessResultTest extends UnitTestCase {
* @covers ::allowedIfHasPermissions
*
* @dataProvider providerTestAllowedIfHasPermissions
*
* @param string[] $permissions
* The permissions to check for.
* @param string $conjunction
* The conjunction to use when checking for permission. 'AND' or 'OR'.
* @param \Drupal\Core\Access\AccessResult $expected_access
* The expected access check result.
*/
public function testAllowedIfHasPermissions($permissions, $conjunction, $expected_access) {
public function testAllowedIfHasPermissions($permissions, $conjunction, AccessResult $expected_access) {
$account = $this->getMock('\Drupal\Core\Session\AccountInterface');
$account->expects($this->any())
->method('hasPermission')
@ -862,6 +868,10 @@ class AccessResultTest extends UnitTestCase {
['denied', FALSE],
]);
if ($permissions) {
$expected_access->cachePerPermissions();
}
$access_result = AccessResult::allowedIfHasPermissions($account, $permissions, $conjunction);
$this->assertEquals($expected_access, $access_result);
}
@ -875,14 +885,14 @@ class AccessResultTest extends UnitTestCase {
return [
[[], 'AND', AccessResult::allowedIf(FALSE)],
[[], 'OR', AccessResult::allowedIf(FALSE)],
[['allowed'], 'OR', AccessResult::allowedIf(TRUE)->addCacheContexts(['user.permissions'])],
[['allowed'], 'AND', AccessResult::allowedIf(TRUE)->addCacheContexts(['user.permissions'])],
[['denied'], 'OR', AccessResult::allowedIf(FALSE)->addCacheContexts(['user.permissions'])],
[['denied'], 'AND', AccessResult::allowedIf(FALSE)->addCacheContexts(['user.permissions'])],
[['allowed', 'denied'], 'OR', AccessResult::allowedIf(TRUE)->addCacheContexts(['user.permissions'])],
[['denied', 'allowed'], 'OR', AccessResult::allowedIf(TRUE)->addCacheContexts(['user.permissions'])],
[['allowed', 'denied', 'other'], 'OR', AccessResult::allowedIf(TRUE)->addCacheContexts(['user.permissions'])],
[['allowed', 'denied'], 'AND', AccessResult::allowedIf(FALSE)->addCacheContexts(['user.permissions'])],
[['allowed'], 'OR', AccessResult::allowedIf(TRUE)],
[['allowed'], 'AND', AccessResult::allowedIf(TRUE)],
[['denied'], 'OR', AccessResult::allowedIf(FALSE)],
[['denied'], 'AND', AccessResult::allowedIf(FALSE)],
[['allowed', 'denied'], 'OR', AccessResult::allowedIf(TRUE)],
[['denied', 'allowed'], 'OR', AccessResult::allowedIf(TRUE)],
[['allowed', 'denied', 'other'], 'OR', AccessResult::allowedIf(TRUE)],
[['allowed', 'denied'], 'AND', AccessResult::allowedIf(FALSE)],
];
}

View file

@ -38,7 +38,6 @@ class CssCollectionGrouperUnitTest extends UnitTestCase {
$css_assets = array(
'system.base.css' => array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.012,
'media' => 'all',
@ -49,7 +48,6 @@ class CssCollectionGrouperUnitTest extends UnitTestCase {
),
'system.theme.css' => array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.013,
'media' => 'all',
@ -62,7 +60,6 @@ class CssCollectionGrouperUnitTest extends UnitTestCase {
'group' => -100,
'type' => 'file',
'weight' => 0.004,
'every_page' => FALSE,
'media' => 'all',
'preprocess' => TRUE,
'data' => 'core/misc/ui/themes/base/jquery.ui.core.css',
@ -70,7 +67,6 @@ class CssCollectionGrouperUnitTest extends UnitTestCase {
'basename' => 'jquery.ui.core.css',
),
'field.css' => array(
'every_page' => TRUE,
'group' => 0,
'type' => 'file',
'weight' => 0.011,
@ -81,7 +77,6 @@ class CssCollectionGrouperUnitTest extends UnitTestCase {
'basename' => 'field.css',
),
'external.css' => array(
'every_page' => FALSE,
'group' => 0,
'type' => 'external',
'weight' => 0.009,
@ -93,7 +88,6 @@ class CssCollectionGrouperUnitTest extends UnitTestCase {
),
'elements.css' => array(
'group' => 100,
'every_page' => TRUE,
'media' => 'all',
'type' => 'file',
'weight' => 0.001,
@ -104,7 +98,6 @@ class CssCollectionGrouperUnitTest extends UnitTestCase {
),
'print.css' => array(
'group' => 100,
'every_page' => TRUE,
'media' => 'print',
'type' => 'file',
'weight' => 0.003,
@ -117,62 +110,53 @@ class CssCollectionGrouperUnitTest extends UnitTestCase {
$groups = $this->grouper->group($css_assets);
$this->assertSame(count($groups), 6, "6 groups created.");
$this->assertSame(count($groups), 5, "5 groups created.");
// Check group 1.
$this->assertSame($groups[0]['group'], -100);
$this->assertSame($groups[0]['every_page'], TRUE);
$this->assertSame($groups[0]['type'], 'file');
$this->assertSame($groups[0]['media'], 'all');
$this->assertSame($groups[0]['preprocess'], TRUE);
$this->assertSame(count($groups[0]['items']), 2);
$this->assertContains($css_assets['system.base.css'], $groups[0]['items']);
$this->assertContains($css_assets['system.theme.css'], $groups[0]['items']);
$group = $groups[0];
$this->assertSame($group['group'], -100);
$this->assertSame($group['type'], 'file');
$this->assertSame($group['media'], 'all');
$this->assertSame($group['preprocess'], TRUE);
$this->assertSame(count($group['items']), 3);
$this->assertContains($css_assets['system.base.css'], $group['items']);
$this->assertContains($css_assets['system.theme.css'], $group['items']);
// Check group 2.
$this->assertSame($groups[1]['group'], -100);
$this->assertSame($groups[1]['every_page'], FALSE);
$this->assertSame($groups[1]['type'], 'file');
$this->assertSame($groups[1]['media'], 'all');
$this->assertSame($groups[1]['preprocess'], TRUE);
$this->assertSame(count($groups[1]['items']), 1);
$this->assertContains($css_assets['jquery.ui.core.css'], $groups[1]['items']);
$group = $groups[1];
$this->assertSame($group['group'], 0);
$this->assertSame($group['type'], 'file');
$this->assertSame($group['media'], 'all');
$this->assertSame($group['preprocess'], TRUE);
$this->assertSame(count($group['items']), 1);
$this->assertContains($css_assets['field.css'], $group['items']);
// Check group 3.
$this->assertSame($groups[2]['group'], 0);
$this->assertSame($groups[2]['every_page'], TRUE);
$this->assertSame($groups[2]['type'], 'file');
$this->assertSame($groups[2]['media'], 'all');
$this->assertSame($groups[2]['preprocess'], TRUE);
$this->assertSame(count($groups[2]['items']), 1);
$this->assertContains($css_assets['field.css'], $groups[2]['items']);
$group = $groups[2];
$this->assertSame($group['group'], 0);
$this->assertSame($group['type'], 'external');
$this->assertSame($group['media'], 'all');
$this->assertSame($group['preprocess'], TRUE);
$this->assertSame(count($group['items']), 1);
$this->assertContains($css_assets['external.css'], $group['items']);
// Check group 4.
$this->assertSame($groups[3]['group'], 0);
$this->assertSame($groups[3]['every_page'], FALSE);
$this->assertSame($groups[3]['type'], 'external');
$this->assertSame($groups[3]['media'], 'all');
$this->assertSame($groups[3]['preprocess'], TRUE);
$this->assertSame(count($groups[3]['items']), 1);
$this->assertContains($css_assets['external.css'], $groups[3]['items']);
$group = $groups[3];
$this->assertSame($group['group'], 100);
$this->assertSame($group['type'], 'file');
$this->assertSame($group['media'], 'all');
$this->assertSame($group['preprocess'], TRUE);
$this->assertSame(count($group['items']), 1);
$this->assertContains($css_assets['elements.css'], $group['items']);
// Check group 5.
$this->assertSame($groups[4]['group'], 100);
$this->assertSame($groups[4]['every_page'], TRUE);
$this->assertSame($groups[4]['type'], 'file');
$this->assertSame($groups[4]['media'], 'all');
$this->assertSame($groups[4]['preprocess'], TRUE);
$this->assertSame(count($groups[4]['items']), 1);
$this->assertContains($css_assets['elements.css'], $groups[4]['items']);
// Check group 6.
$this->assertSame($groups[5]['group'], 100);
$this->assertSame($groups[5]['every_page'], TRUE);
$this->assertSame($groups[5]['type'], 'file');
$this->assertSame($groups[5]['media'], 'print');
$this->assertSame($groups[5]['preprocess'], TRUE);
$this->assertSame(count($groups[5]['items']), 1);
$this->assertContains($css_assets['print.css'], $groups[5]['items']);
$group = $groups[4];
$this->assertSame($group['group'], 100);
$this->assertSame($group['type'], 'file');
$this->assertSame($group['media'], 'print');
$this->assertSame($group['preprocess'], TRUE);
$this->assertSame(count($group['items']), 1);
$this->assertContains($css_assets['print.css'], $group['items']);
}
}

View file

@ -71,7 +71,6 @@ class CssCollectionRendererUnitTest extends UnitTestCase {
$this->renderer = new CssCollectionRenderer($this->state);
$this->fileCssGroup = array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'media' => 'all',
'preprocess' => TRUE,
@ -79,7 +78,6 @@ class CssCollectionRendererUnitTest extends UnitTestCase {
'items' => array(
0 => array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.012,
'media' => 'all',
@ -90,7 +88,6 @@ class CssCollectionRendererUnitTest extends UnitTestCase {
),
1 => array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.013,
'media' => 'all',
@ -121,7 +118,7 @@ class CssCollectionRendererUnitTest extends UnitTestCase {
'#browsers' => $browsers,
);
};
$create_style_element = function($value, $media, $browsers = array(), $wrap_in_cdata = FALSE) {
$create_style_element = function($value, $media, $browsers = array()) {
$style_element = array(
'#type' => 'html_tag',
'#tag' => 'style',
@ -131,15 +128,11 @@ class CssCollectionRendererUnitTest extends UnitTestCase {
),
'#browsers' => $browsers,
);
if ($wrap_in_cdata) {
$style_element['#value_prefix'] = "\n/* <![CDATA[ */\n";
$style_element['#value_suffix'] = "\n/* ]]> */\n";
}
return $style_element;
};
$create_file_css_asset = function($data, $media = 'all', $preprocess = TRUE) {
return array('group' => 0, 'every_page' => FALSE, 'type' => 'file', 'media' => $media, 'preprocess' => $preprocess, 'data' => $data, 'browsers' => array());
return array('group' => 0, 'type' => 'file', 'media' => $media, 'preprocess' => $preprocess, 'data' => $data, 'browsers' => array());
};
return array(
@ -147,7 +140,7 @@ class CssCollectionRendererUnitTest extends UnitTestCase {
0 => array(
// CSS assets.
array(
0 => array('group' => 0, 'every_page' => TRUE, 'type' => 'external', 'media' => 'all', 'preprocess' => TRUE, 'data' => 'http://example.com/popular.js', 'browsers' => array()),
0 => array('group' => 0, 'type' => 'external', 'media' => 'all', 'preprocess' => TRUE, 'data' => 'http://example.com/popular.js', 'browsers' => array()),
),
// Render elements.
array(
@ -157,10 +150,10 @@ class CssCollectionRendererUnitTest extends UnitTestCase {
// Single file CSS asset.
2 => array(
array(
0 => array('group' => 0, 'every_page' => TRUE, 'type' => 'file', 'media' => 'all', 'preprocess' => TRUE, 'data' => 'public://css/file-every_page-all', 'browsers' => array()),
0 => array('group' => 0, 'type' => 'file', 'media' => 'all', 'preprocess' => TRUE, 'data' => 'public://css/file-all', 'browsers' => array()),
),
array(
0 => $create_link_element(file_create_url('public://css/file-every_page-all') . '?0', 'all'),
0 => $create_link_element(file_create_url('public://css/file-all') . '?0', 'all'),
),
),
// 31 file CSS assets: expect 31 link elements.
@ -494,7 +487,6 @@ class CssCollectionRendererUnitTest extends UnitTestCase {
$css_group = array(
'group' => 0,
'every_page' => TRUE,
'type' => 'internal',
'media' => 'all',
'preprocess' => TRUE,

View file

@ -74,7 +74,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
array(
array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.012,
'media' => 'all',
@ -95,7 +94,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
array(
array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.013,
'media' => 'all',
@ -111,7 +109,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
array(
array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.013,
'media' => 'all',
@ -129,7 +126,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
array(
array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.013,
'media' => 'all',
@ -146,7 +142,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
array(
array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.013,
'media' => 'all',
@ -160,7 +155,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
array(
array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.013,
'media' => 'all',
@ -174,7 +168,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
array(
array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.013,
'media' => 'all',
@ -188,7 +181,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
array(
array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.013,
'media' => 'all',
@ -202,7 +194,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
array(
array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.013,
'media' => 'all',
@ -216,7 +207,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
array(
array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.013,
'media' => 'all',
@ -247,7 +237,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
$css_asset = array(
'group' => -100,
'every_page' => TRUE,
'type' => 'file',
'weight' => 0.012,
'media' => 'all',
@ -268,7 +257,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
$css_asset = array(
'group' => -100,
'every_page' => TRUE,
// Type external.
'type' => 'external',
'weight' => 0.012,

View file

@ -7,7 +7,9 @@
namespace Drupal\Tests\Core\Breadcrumb;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Breadcrumb\BreadcrumbManager;
use Drupal\Core\Cache\Cache;
use Drupal\Tests\UnitTestCase;
/**
@ -16,6 +18,13 @@ use Drupal\Tests\UnitTestCase;
*/
class BreadcrumbManagerTest extends UnitTestCase {
/**
* The breadcrumb object.
*
* @var \Drupal\Core\Breadcrumb\Breadcrumb
*/
protected $breadcrumb;
/**
* The tested breadcrumb manager.
*
@ -36,14 +45,23 @@ class BreadcrumbManagerTest extends UnitTestCase {
protected function setUp() {
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
$this->breadcrumbManager = new BreadcrumbManager($this->moduleHandler);
$this->breadcrumb = new Breadcrumb();
}
/**
* Tests the breadcrumb manager without any set breadcrumb.
*/
public function testBuildWithoutBuilder() {
$result = $this->breadcrumbManager->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals(array(), $result);
$route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
$this->moduleHandler->expects($this->once())
->method('alter')
->with('system_breadcrumb', $this->breadcrumb, $route_match, ['builder' => NULL]);
$breadcrumb = $this->breadcrumbManager->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([], $breadcrumb->getLinks());
$this->assertEquals([], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
/**
@ -51,7 +69,9 @@ class BreadcrumbManagerTest extends UnitTestCase {
*/
public function testBuildWithSingleBuilder() {
$builder = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
$breadcrumb = array('<a href="/example">Test</a>');
$links = array('<a href="/example">Test</a>');
$this->breadcrumb->setLinks($links);
$this->breadcrumb->setCacheContexts(['foo'])->setCacheTags(['bar']);
$builder->expects($this->once())
->method('applies')
@ -59,17 +79,20 @@ class BreadcrumbManagerTest extends UnitTestCase {
$builder->expects($this->once())
->method('build')
->will($this->returnValue($breadcrumb));
->willReturn($this->breadcrumb);
$route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
$this->moduleHandler->expects($this->once())
->method('alter')
->with('system_breadcrumb', $breadcrumb, $route_match, array('builder' => $builder));
->with('system_breadcrumb', $this->breadcrumb, $route_match, array('builder' => $builder));
$this->breadcrumbManager->addBuilder($builder, 0);
$result = $this->breadcrumbManager->build($route_match);
$this->assertEquals($breadcrumb, $result);
$breadcrumb = $this->breadcrumbManager->build($route_match);
$this->assertEquals($links, $breadcrumb->getLinks());
$this->assertEquals(['foo'], $breadcrumb->getCacheContexts());
$this->assertEquals(['bar'], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
/**
@ -83,25 +106,30 @@ class BreadcrumbManagerTest extends UnitTestCase {
->method('build');
$builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
$breadcrumb2 = array('<a href="/example2">Test2</a>');
$links2 = array('<a href="/example2">Test2</a>');
$this->breadcrumb->setLinks($links2);
$this->breadcrumb->setCacheContexts(['baz'])->setCacheTags(['qux']);
$builder2->expects($this->once())
->method('applies')
->will($this->returnValue(TRUE));
$builder2->expects($this->once())
->method('build')
->will($this->returnValue($breadcrumb2));
->willReturn($this->breadcrumb);
$route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
$this->moduleHandler->expects($this->once())
->method('alter')
->with('system_breadcrumb', $breadcrumb2, $route_match, array('builder' => $builder2));
->with('system_breadcrumb', $this->breadcrumb, $route_match, array('builder' => $builder2));
$this->breadcrumbManager->addBuilder($builder1, 0);
$this->breadcrumbManager->addBuilder($builder2, 10);
$result = $this->breadcrumbManager->build($route_match);
$this->assertEquals($breadcrumb2, $result);
$breadcrumb = $this->breadcrumbManager->build($route_match);
$this->assertEquals($links2, $breadcrumb->getLinks());
$this->assertEquals(['baz'], $breadcrumb->getCacheContexts());
$this->assertEquals(['qux'], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
/**
@ -116,25 +144,30 @@ class BreadcrumbManagerTest extends UnitTestCase {
->method('build');
$builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
$breadcrumb2 = array('<a href="/example2">Test2</a>');
$links2 = ['<a href="/example2">Test2</a>'];
$this->breadcrumb->setLinks($links2);
$this->breadcrumb->setCacheContexts(['baz'])->setCacheTags(['qux']);
$builder2->expects($this->once())
->method('applies')
->will($this->returnValue(TRUE));
$builder2->expects($this->once())
->method('build')
->will($this->returnValue($breadcrumb2));
->willReturn($this->breadcrumb);
$route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
$this->moduleHandler->expects($this->once())
->method('alter')
->with('system_breadcrumb', $breadcrumb2, $route_match, array('builder' => $builder2));
->with('system_breadcrumb', $this->breadcrumb, $route_match, array('builder' => $builder2));
$this->breadcrumbManager->addBuilder($builder1, 10);
$this->breadcrumbManager->addBuilder($builder2, 0);
$result = $this->breadcrumbManager->build($route_match);
$this->assertEquals($breadcrumb2, $result);
$breadcrumb = $this->breadcrumbManager->build($route_match);
$this->assertEquals($links2, $breadcrumb->getLinks());
$this->assertEquals(['baz'], $breadcrumb->getCacheContexts());
$this->assertEquals(['qux'], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
/**

View file

@ -0,0 +1,32 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Breadcrumb\BreadcrumbTest.
*/
namespace Drupal\Tests\Core\Breadcrumb;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Breadcrumb\Breadcrumb
* @group Breadcrumb
*/
class BreadcrumbTest extends UnitTestCase {
/**
* @covers ::setLinks
* @expectedException \LogicException
* @expectedExceptionMessage Once breadcrumb links are set, only additional breadcrumb links can be added.
*/
public function testSetLinks() {
$breadcrumb = new Breadcrumb();
$breadcrumb->setLinks([new Link('Home', Url::fromRoute('<front>'))]);
$breadcrumb->setLinks([new Link('None', Url::fromRoute('<none>'))]);
}
}

View file

@ -19,6 +19,8 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
use Psr\Http\Message\ServerRequestInterface;
/**
* @coversDefaultClass \Drupal\Core\Controller\ControllerResolver
@ -40,6 +42,13 @@ class ControllerResolverTest extends UnitTestCase {
*/
protected $container;
/**
* The PSR-7 converter.
*
* @var \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface
*/
protected $httpMessageFactory;
/**
* {@inheritdoc}
*/
@ -49,7 +58,8 @@ class ControllerResolverTest extends UnitTestCase {
$this->container = new ContainerBuilder();
$class_resolver = new ClassResolver();
$class_resolver->setContainer($this->container);
$this->controllerResolver = new ControllerResolver($class_resolver);
$this->httpMessageFactory = new DiactorosFactory();
$this->controllerResolver = new ControllerResolver($this->httpMessageFactory, $class_resolver);
}
/**
@ -61,7 +71,7 @@ class ControllerResolverTest extends UnitTestCase {
* @see \Drupal\Core\Controller\ControllerResolver::doGetArguments()
*/
public function testGetArguments() {
$controller = function(EntityInterface $entity, $user, RouteMatchInterface $route_match) {
$controller = function(EntityInterface $entity, $user, RouteMatchInterface $route_match, ServerRequestInterface $psr_7) {
};
$mock_entity = $this->getMockBuilder('Drupal\Core\Entity\Entity')
->disableOriginalConstructor()
@ -71,12 +81,13 @@ class ControllerResolverTest extends UnitTestCase {
'entity' => $mock_entity,
'user' => $mock_account,
'_raw_variables' => new ParameterBag(array('entity' => 1, 'user' => 1)),
));
), array(), array(), array('HTTP_HOST' => 'drupal.org'));
$arguments = $this->controllerResolver->getArguments($request, $controller);
$this->assertEquals($mock_entity, $arguments[0]);
$this->assertEquals($mock_account, $arguments[1]);
$this->assertEquals(RouteMatch::createFromRequest($request), $arguments[2], 'Ensure that the route match object is passed along as well');
$this->assertInstanceOf(ServerRequestInterface::class, $arguments[3], 'Ensure that the PSR-7 object is passed along as well');
}
/**
@ -219,6 +230,20 @@ class ControllerResolverTest extends UnitTestCase {
$this->assertEquals([RouteMatch::createFromRequest($request), $request], $arguments);
}
/**
* Tests getArguments with a route match and a PSR-7 request.
*
* @covers ::getArguments
* @covers ::doGetArguments
*/
public function testGetArgumentsWithRouteMatchAndPsr7Request() {
$request = Request::create('/test');
$mock_controller = new MockControllerPsr7();
$arguments = $this->controllerResolver->getArguments($request, [$mock_controller, 'getControllerWithRequestAndRouteMatch']);
$this->assertEquals(RouteMatch::createFromRequest($request), $arguments[0], 'Ensure that the route match object is passed along as well');
$this->assertInstanceOf('Psr\Http\Message\ServerRequestInterface', $arguments[1], 'Ensure that the PSR-7 object is passed along as well');
}
}
class MockController {
@ -231,6 +256,17 @@ class MockController {
}
}
class MockControllerPsr7 {
public function getResult() {
return ['#markup' => 'This is a regular controller'];
}
public function getControllerWithRequestAndRouteMatch(RouteMatchInterface $route_match, ServerRequestInterface $request) {
return ['#markup' => 'this is another example controller'];
}
}
class MockContainerInjection implements ContainerInjectionInterface {
protected $result;
public function __construct($result) {

View file

@ -7,7 +7,6 @@
namespace Drupal\Tests\Core\Controller;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Controller\TitleResolver;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\ParameterBag;
@ -151,7 +150,7 @@ class TitleCallback {
* Returns the example string.
*/
public function example($value) {
return SafeMarkup::format('test @value', array('@value' => $value));
return 'test ' . $value;
}
}

View file

@ -254,12 +254,12 @@ class ConnectionTest extends UnitTestCase {
array(''),
),
array(
'/* Exploit * / DROP TABLE node; -- */ ',
'/* Exploit * / DROP TABLE node; -- */ ',
array('Exploit * / DROP TABLE node; --'),
),
array(
'/* Exploit DROP TABLE node; --; another comment */ ',
array('Exploit */ DROP TABLE node; --', 'another comment'),
'/* Exploit * / DROP TABLE node; --; another comment */ ',
array('Exploit * / DROP TABLE node; --', 'another comment'),
),
);
}
@ -286,8 +286,8 @@ class ConnectionTest extends UnitTestCase {
public function providerFilterComments() {
return array(
array('', ''),
array('Exploit * / DROP TABLE node; --', 'Exploit * / DROP TABLE node; --'),
array('Exploit DROP TABLE node; --', 'Exploit */ DROP TABLE node; --'),
array('Exploit * / DROP TABLE node; --', 'Exploit * / DROP TABLE node; --'),
array('Exploit * / DROP TABLE node; --', 'Exploit */ DROP TABLE node; --'),
);
}

View file

@ -0,0 +1,81 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Database\Driver\pgsql\PostgresqlSchemaTest.
*/
namespace Drupal\Tests\Core\Database\Driver\pgsql;
use Drupal\Core\Database\Driver\pgsql\Schema;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Database\Driver\pgsql\Schema
* @group Database
*/
class PostgresqlSchemaTest extends UnitTestCase {
/**
* The PostgreSql DB connection.
*
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Database\Driver\pgsql\Connection
*/
protected $connection;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->connection = $this->getMockBuilder('\Drupal\Core\Database\Driver\pgsql\Connection')
->disableOriginalConstructor()
->getMock();
}
/**
* Tests whether the actual constraint name is correctly computed.
*
* @param string $table_name
* The table name the constrained column belongs to.
* @param string $name
* The constraint name.
* @param string $expected
* The expected computed constraint name.
*
* @covers ::constraintExists
* @dataProvider providerComputedConstraintName
*/
public function testComputedConstraintName($table_name, $name, $expected) {
$max_identifier_length = 63;
$schema = new Schema($this->connection);
$statement = $this->getMock('\Drupal\Core\Database\StatementInterface');
$statement->expects($this->any())
->method('fetchField')
->willReturn($max_identifier_length);
$this->connection->expects($this->any())
->method('query')
->willReturn($statement);
$this->connection->expects($this->at(2))
->method('query')
->with("SELECT 1 FROM pg_constraint WHERE conname = '$expected'")
->willReturn($this->getMock('\Drupal\Core\Database\StatementInterface'));
$schema->constraintExists($table_name, $name);
}
/**
* Data provider for ::testComputedConstraintName().
*/
public function providerComputedConstraintName() {
return [
['user_field_data', 'pkey', 'user_field_data____pkey'],
['user_field_data', 'name__key', 'user_field_data__name__key'],
['user_field_data', 'a_veeeery_veery_very_super_long_field_name__key', 'drupal_BGGYAXgbqlAF1rMOyFTdZGj9zIMXZtSvEjMAKZ9wGIk_key'],
];
}
}

View file

@ -169,7 +169,7 @@ class DateTest extends UnitTestCase {
*/
public function testGetSampleDateFormats() {
$timestamp = strtotime('2015-03-22 14:23:00');
$expected = $this->dateFormatter->getSampleDateFormats('en', $timestamp, 'Europe/London');
$expected = $this->dateFormatter->getSampleDateFormats('en', $timestamp, 'Australia/Sydney');
// Removed characters related to timezone 'e' and 'T', as test does not have
// timezone set.

View file

@ -70,4 +70,14 @@ class ContainerBuilderTest extends UnitTestCase {
$container->register('Bar');
}
/**
* Tests serialization.
*
* @expectedException \AssertionError
*/
public function testSerialize() {
$container = new ContainerBuilder();
serialize($container);
}
}

View file

@ -20,7 +20,7 @@ class ContainerTest extends UnitTestCase {
/**
* Tests serialization.
*
* @expectedException \PHPUnit_Framework_Error
* @expectedException \AssertionError
*/
public function testSerialize() {
$container = new Container();

View file

@ -46,14 +46,20 @@ class DiscoverServiceProvidersTest extends UnitTestCase {
/**
* Tests the exception when container_yamls is not set.
*
* @covers ::discoverServiceProviders
* @expectedException \Exception
*/
public function testDiscoverServiceNoContainerYamls() {
new Settings([]);
$kernel = new DrupalKernel('prod', new \Composer\Autoload\ClassLoader());
$kernel->discoverServiceProviders();
$expect = [
'app' => [
'core' => 'core/core.services.yml',
],
'site' => [
],
];
$this->assertAttributeSame($expect, 'serviceYamls', $kernel);
}
}

View file

@ -7,6 +7,11 @@
namespace Drupal\Tests\Core\Entity;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\DependencyInjection\Container;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\Routing\Route;
use Drupal\Core\Access\AccessResult;
@ -16,32 +21,67 @@ use Drupal\Tests\UnitTestCase;
/**
* Unit test of entity access checking system.
*
* @coversDefaultClass \Drupal\Core\Entity\EntityAccessCheck
*
* @group Access
* @group Entity
*/
class EntityAccessCheckTest extends UnitTestCase {
/**
* {@inheritdoc}
*/
protected function setUp() {
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class)->reveal();
$container = new Container();
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
}
/**
* Tests the method for checking access to routes.
*/
public function testAccess() {
$route = new Route('/foo', array(), array('_entity_access' => 'node.update'));
$upcasted_arguments = new ParameterBag();
$route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
$route_match->expects($this->once())
->method('getParameters')
->will($this->returnValue($upcasted_arguments));
$node = $this->getMockBuilder('Drupal\node\Entity\Node')
->disableOriginalConstructor()
->getMock();
$node->expects($this->any())
->method('access')
->will($this->returnValue(AccessResult::allowed()->cachePerPermissions()));
$route = new Route('/foo/{var_name}', [], ['_entity_access' => 'var_name.update'], ['parameters' => ['var_name' => ['type' => 'entity:node']]]);
/** @var \Drupal\Core\Session\AccountInterface $account */
$account = $this->prophesize(AccountInterface::class)->reveal();
/** @var \Drupal\node\NodeInterface|\Prophecy\Prophecy\ObjectProphecy $route_match */
$node = $this->prophesize(NodeInterface::class);
$node->access('update', $account, TRUE)->willReturn(AccessResult::allowed());
$node = $node->reveal();
/** @var \Drupal\Core\Routing\RouteMatchInterface|\Prophecy\Prophecy\ObjectProphecy $route_match */
$route_match = $this->prophesize(RouteMatchInterface::class);
$route_match->getRawParameters()->willReturn(new ParameterBag(['var_name' => 1]));
$route_match->getParameters()->willReturn(new ParameterBag(['var_name' => $node]));
$route_match = $route_match->reveal();
$access_check = new EntityAccessCheck();
$upcasted_arguments->set('node', $node);
$account = $this->getMock('Drupal\Core\Session\AccountInterface');
$access = $access_check->access($route, $route_match, $account);
$this->assertEquals(AccessResult::allowed()->cachePerPermissions(), $access);
$this->assertEquals(AccessResult::allowed(), $access_check->access($route, $route_match, $account));
}
/**
* @covers ::access
*/
public function testAccessWithTypePlaceholder() {
$route = new Route('/foo/{entity_type}/{var_name}', [], ['_entity_access' => 'var_name.update'], ['parameters' => ['var_name' => ['type' => 'entity:{entity_type}']]]);
/** @var \Drupal\Core\Session\AccountInterface $account */
$account = $this->prophesize(AccountInterface::class)->reveal();
/** @var \Drupal\node\NodeInterface|\Prophecy\Prophecy\ObjectProphecy $node */
$node = $this->prophesize(NodeInterface::class);
$node->access('update', $account, TRUE)->willReturn(AccessResult::allowed());
$node = $node->reveal();
/** @var \Drupal\Core\Routing\RouteMatchInterface|\Prophecy\Prophecy\ObjectProphecy $route_match */
$route_match = $this->prophesize(RouteMatchInterface::class);
$route_match->getRawParameters()->willReturn(new ParameterBag(['entity_type' => 'node', 'var_name' => 1]));
$route_match->getParameters()->willReturn(new ParameterBag(['entity_type' => 'node', 'var_name' => $node]));
$route_match = $route_match->reveal();
$access_check = new EntityAccessCheck();
$this->assertEquals(AccessResult::allowed(), $access_check->access($route, $route_match, $account));
}
}

View file

@ -8,6 +8,8 @@
namespace Drupal\Tests\Core\Entity;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\DependencyInjection\Container;
use Drupal\Core\Entity\EntityCreateAccessCheck;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
@ -32,6 +34,11 @@ class EntityCreateAccessCheckTest extends UnitTestCase {
*/
protected function setUp() {
parent::setUp();
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class)->reveal();
$container = new Container();
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
}
/**
@ -40,9 +47,8 @@ class EntityCreateAccessCheckTest extends UnitTestCase {
* @return array
*/
public function providerTestAccess() {
$no_access = AccessResult::neutral()->cachePerPermissions();
$access = AccessResult::allowed()->cachePerPermissions();
$no_access_due_to_errors = AccessResult::neutral();
$no_access = FALSE;
$access = TRUE;
return array(
array('', 'entity_test', $no_access, $no_access),
@ -51,10 +57,10 @@ class EntityCreateAccessCheckTest extends UnitTestCase {
array('test_entity', 'entity_test:test_entity', $no_access, $no_access),
array('test_entity', 'entity_test:{bundle_argument}', $access, $access),
array('test_entity', 'entity_test:{bundle_argument}', $no_access, $no_access),
array('', 'entity_test:{bundle_argument}', $no_access, $no_access_due_to_errors),
array('', 'entity_test:{bundle_argument}', $no_access, $no_access, FALSE),
// When the bundle is not provided, access should be denied even if the
// access control handler would allow access.
array('', 'entity_test:{bundle_argument}', $access, $no_access_due_to_errors),
array('', 'entity_test:{bundle_argument}', $access, $no_access, FALSE),
);
}
@ -63,7 +69,15 @@ class EntityCreateAccessCheckTest extends UnitTestCase {
*
* @dataProvider providerTestAccess
*/
public function testAccess($entity_bundle, $requirement, $access, $expected) {
public function testAccess($entity_bundle, $requirement, $access, $expected, $expect_permission_context = TRUE) {
// Set up the access result objects for allowing or denying access.
$access_result = $access ? AccessResult::allowed()->cachePerPermissions() : AccessResult::neutral()->cachePerPermissions();
$expected_access_result = $expected ? AccessResult::allowed() : AccessResult::neutral();
if ($expect_permission_context) {
$expected_access_result->cachePerPermissions();
}
$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
// Don't expect a call to the access control handler when we have a bundle
@ -73,7 +87,7 @@ class EntityCreateAccessCheckTest extends UnitTestCase {
$access_control_handler->expects($this->once())
->method('createAccess')
->with($entity_bundle)
->will($this->returnValue($access));
->will($this->returnValue($access_result));
$entity_manager->expects($this->any())
->method('getAccessControlHandler')
@ -101,7 +115,7 @@ class EntityCreateAccessCheckTest extends UnitTestCase {
->will($this->returnValue($raw_variables));
$account = $this->getMock('Drupal\Core\Session\AccountInterface');
$this->assertEquals($expected, $applies_check->access($route, $route_match, $account));
$this->assertEquals($expected_access_result, $applies_check->access($route, $route_match, $account));
}
}

View file

@ -137,64 +137,6 @@ class EntityListBuilderTest extends UnitTestCase {
$this->assertArrayHasKey('title', $operations[$operation_name]);
}
/**
* Tests that buildRow() returns a string which has been run through
* SafeMarkup::checkPlain().
*
* @dataProvider providerTestBuildRow
*
* @param string $input
* The entity label being passed into buildRow.
* @param string $expected
* The expected output of the label from buildRow.
* @param string $message
* The message to provide as output for the test.
* @param bool $ignorewarnings
* Whether or not to ignore PHP 5.3+ invalid multibyte sequence warnings.
*
* @see \Drupal\Core\Entity\EntityListBuilder::buildRow()
*/
public function testBuildRow($input, $expected, $message, $ignorewarnings = FALSE) {
$this->role->expects($this->any())
->method('label')
->will($this->returnValue($input));
if ($ignorewarnings) {
$built_row = @$this->entityListBuilder->buildRow($this->role);
}
else {
$built_row = $this->entityListBuilder->buildRow($this->role);
}
$this->assertEquals($built_row['label'], $expected, $message);
}
/**
* Data provider for testBuildRow().
*
* @see self::testBuildRow()
* @see \Drupal\Tests\Component\Utility\SafeMarkupTest::providerCheckPlain()
*
* @return array
* An array containing a string, the expected return from
* SafeMarkup::checkPlain, a message to be output for failures, and whether the
* test should be processed as multibyte.
*/
public function providerTestBuildRow() {
$tests = array();
// Checks that invalid multi-byte sequences are rejected.
$tests[] = array("Foo\xC0barbaz", '', 'EntityTestListBuilder::buildRow() rejects invalid sequence "Foo\xC0barbaz"', TRUE);
$tests[] = array("\xc2\"", '', 'EntityTestListBuilder::buildRow() rejects invalid sequence "\xc2\""', TRUE);
$tests[] = array("Fooÿñ", "Fooÿñ", 'EntityTestListBuilder::buildRow() accepts valid sequence "Fooÿñ"');
// Checks that special characters are escaped.
$tests[] = array("<script>", '&lt;script&gt;', 'EntityTestListBuilder::buildRow() escapes &lt;script&gt;');
$tests[] = array('<>&"\'', '&lt;&gt;&amp;&quot;&#039;', 'EntityTestListBuilder::buildRow() escapes reserved HTML characters.');
return $tests;
}
}
class TestEntityListBuilder extends EntityTestListBuilder {

File diff suppressed because it is too large Load diff

View file

@ -8,6 +8,7 @@
namespace Drupal\Tests\Core\Entity;
use Drupal\Core\Entity\EntityType;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Tests\UnitTestCase;
/**
@ -31,6 +32,29 @@ class EntityTypeTest extends UnitTestCase {
return new EntityType($definition);
}
/**
* @covers ::get
*
* @dataProvider providerTestGet
*/
public function testGet(array $defintion, $key, $expected) {
$entity_type = $this->setUpEntityType($defintion);
$this->assertSame($expected, $entity_type->get($key));
}
/**
* @covers ::set
* @covers ::get
*
* @dataProvider providerTestSet
*/
public function testSet($key, $value) {
$entity_type = $this->setUpEntityType([]);
$this->assertInstanceOf('Drupal\Core\Entity\EntityTypeInterface', $entity_type->set($key, $value));
$this->assertSame($value, $entity_type->get($key));
$this->assertNoPublicProperties($entity_type);
}
/**
* Tests the getKeys() method.
*
@ -64,6 +88,34 @@ class EntityTypeTest extends UnitTestCase {
$this->assertSame(FALSE, $entity_type->hasKey('bananas'));
}
/**
* Provides test data for testGet.
*/
public function providerTestGet() {
return [
[[], 'provider', NULL],
[['provider' => ''], 'provider', ''],
[['provider' => 'test'], 'provider', 'test'],
[[], 'something_additional', NULL],
[['something_additional' => ''], 'something_additional', ''],
[['something_additional' => 'additional'], 'something_additional', 'additional'],
];
}
/**
* Provides test data for testSet.
*/
public function providerTestSet() {
return [
['provider', NULL],
['provider', ''],
['provider', 'test'],
['something_additional', NULL],
['something_additional', ''],
['something_additional', 'additional'],
];
}
/**
* Provides test data.
*/
@ -272,4 +324,14 @@ class EntityTypeTest extends UnitTestCase {
$this->assertEquals([], $entity_type->getConstraints());
}
/**
* Asserts there on no public properties on the object instance.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
*/
protected function assertNoPublicProperties(EntityTypeInterface $entity_type) {
$reflection = new \ReflectionObject($entity_type);
$this->assertEmpty($reflection->getProperties(\ReflectionProperty::IS_PUBLIC));
}
}

View file

@ -18,6 +18,13 @@ use Drupal\Tests\UnitTestCase;
*/
class SqlContentEntityStorageSchemaTest extends UnitTestCase {
/**
* The mocked DB schema handler.
*
* @var \Drupal\Core\Database\Schema|\PHPUnit_Framework_MockObject_MockObject
*/
protected $dbSchemaHandler;
/**
* The mocked entity manager used in this test.
*
@ -1298,7 +1305,7 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
->with($this->entityType->id())
->will($this->returnValue($this->storageDefinitions));
$db_schema_handler = $this->getMockBuilder('Drupal\Core\Database\Schema')
$this->dbSchemaHandler = $this->getMockBuilder('Drupal\Core\Database\Schema')
->disableOriginalConstructor()
->getMock();
@ -1307,7 +1314,7 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
$expected_table_names = array_keys($expected);
$expected_table_schemas = array_values($expected);
$db_schema_handler->expects($this->any())
$this->dbSchemaHandler->expects($this->any())
->method('createTable')
->with(
$this->callback(function($table_name) use (&$invocation_count, $expected_table_names) {
@ -1327,17 +1334,21 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
->getMock();
$connection->expects($this->any())
->method('schema')
->will($this->returnValue($db_schema_handler));
->will($this->returnValue($this->dbSchemaHandler));
$key_value = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreInterface');
$this->storageSchema = $this->getMockBuilder('Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema')
->setConstructorArgs(array($this->entityManager, $this->entityType, $this->storage, $connection))
->setMethods(array('installedStorageSchema', 'loadEntitySchemaData', 'hasSharedTableNameChanges'))
->setMethods(array('installedStorageSchema', 'loadEntitySchemaData', 'hasSharedTableNameChanges', 'isTableEmpty'))
->getMock();
$this->storageSchema
->expects($this->any())
->method('installedStorageSchema')
->will($this->returnValue($key_value));
$this->storageSchema
->expects($this->any())
->method('isTableEmpty')
->willReturn(FALSE);
}
/**
@ -1380,4 +1391,95 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
}
}
/**
* ::onEntityTypeUpdate
*/
public function testonEntityTypeUpdateWithNewIndex() {
$this->entityType = $original_entity_type = new ContentEntityType(array(
'id' => 'entity_test',
'entity_keys' => array('id' => 'id'),
));
// Add a field with a really long index.
$this->setUpStorageDefinition('long_index_name', array(
'columns' => array(
'long_index_name' => array(
'type' => 'int',
),
),
'indexes' => array(
'long_index_name_really_long_long_name' => array(array('long_index_name', 10)),
),
));
$expected = array(
'entity_test' => array(
'description' => 'The base table for entity_test entities.',
'fields' => array(
'id' => array(
'type' => 'serial',
'not null' => TRUE,
),
'long_index_name' => array(
'type' => 'int',
'not null' => FALSE,
),
),
'indexes' => array(
'entity_test__b588603cb9' => array(
array('long_index_name', 10),
),
),
),
);
$this->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$table_mapping->setExtraColumns('entity_test', array('default_langcode'));
$this->storage->expects($this->any())
->method('getTableMapping')
->will($this->returnValue($table_mapping));
$this->storageSchema->expects($this->any())
->method('loadEntitySchemaData')
->willReturn([
'entity_test' => [
'indexes' => [
// A changed index definition.
'entity_test__b588603cb9' => ['longer_index_name'],
// An index that has been removed.
'entity_test__removed_field' => ['removed_field'],
],
],
]);
// The original indexes should be dropped before the new one is added.
$this->dbSchemaHandler->expects($this->at(0))
->method('dropIndex')
->with('entity_test', 'entity_test__b588603cb9');
$this->dbSchemaHandler->expects($this->at(1))
->method('dropIndex')
->with('entity_test', 'entity_test__removed_field');
$this->dbSchemaHandler->expects($this->atLeastOnce())
->method('fieldExists')
->willReturn(TRUE);
$this->dbSchemaHandler->expects($this->atLeastOnce())
->method('addIndex')
->with('entity_test', 'entity_test__b588603cb9', [['long_index_name', 10]], $this->callback(function($actual_value) use ($expected) {
$this->assertEquals($expected['entity_test']['indexes'], $actual_value['indexes']);
$this->assertEquals($expected['entity_test']['fields'], $actual_value['fields']);
// If the parameters don't match, the assertions above will throw an
// exception.
return TRUE;
}));
$this->assertNull(
$this->storageSchema->onEntityTypeUpdate($this->entityType, $original_entity_type)
);
}
}

View file

@ -12,7 +12,6 @@ use Drupal\Core\Routing\RouteBuildEvent;
use Drupal\Tests\UnitTestCase;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* @coversDefaultClass \Drupal\Core\EventSubscriber\SpecialAttributesRouteSubscriber
@ -20,22 +19,6 @@ use Symfony\Component\Routing\RouteCollection;
*/
class SpecialAttributesRouteSubscriberTest extends UnitTestCase {
/**
* The tested route subscriber.
*
* @var \Drupal\Core\EventSubscriber\SpecialAttributesRouteSubscriber
*/
protected $specialAttributesRouteSubscriber;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->specialAttributesRouteSubscriber = new SpecialAttributesRouteSubscriber();
}
/**
* Provides a list of routes with invalid route variables.
*
@ -43,14 +26,21 @@ class SpecialAttributesRouteSubscriberTest extends UnitTestCase {
* An array of invalid routes.
*/
public function providerTestOnRouteBuildingInvalidVariables() {
$routes = array();
$routes[] = array(new Route('/test/{system_path}'));
$routes[] = array(new Route('/test/{_legacy}'));
$routes[] = array(new Route('/test/{' . RouteObjectInterface::ROUTE_OBJECT . '}'));
$routes[] = array(new Route('/test/{' . RouteObjectInterface::ROUTE_NAME . '}'));
$routes[] = array(new Route('/test/{_content}'));
$routes[] = array(new Route('/test/{_form}'));
$routes[] = array(new Route('/test/{_raw_variables}'));
// Build an array of mock route objects based on paths.
$routes = [];
$paths = [
'/test/{system_path}',
'/test/{_legacy}',
'/test/{' . RouteObjectInterface::ROUTE_OBJECT . '}',
'/test/{' . RouteObjectInterface::ROUTE_NAME . '}',
'/test/{_content}',
'/test/{_form}',
'/test/{_raw_variables}',
];
foreach ($paths as $path) {
$routes[] = [new Route($path)];
}
return $routes;
}
@ -62,11 +52,18 @@ class SpecialAttributesRouteSubscriberTest extends UnitTestCase {
* An array of valid routes.
*/
public function providerTestOnRouteBuildingValidVariables() {
$routes = array();
$routes[] = array(new Route('/test/{account}'));
$routes[] = array(new Route('/test/{node}'));
$routes[] = array(new Route('/test/{user}'));
$routes[] = array(new Route('/test/{entity_test}'));
// Build an array of mock route objects based on paths.
$routes = [];
$paths = [
'/test/{account}',
'/test/{node}',
'/test/{user}',
'/test/{entity_test}',
];
foreach ($paths as $path) {
$routes[] = [new Route($path)];
}
return $routes;
}
@ -78,12 +75,16 @@ class SpecialAttributesRouteSubscriberTest extends UnitTestCase {
* The route to check.
*
* @dataProvider providerTestOnRouteBuildingValidVariables
*
* @covers ::onAlterRoutes
*/
public function testOnRouteBuildingValidVariables(Route $route) {
$route_collection = new RouteCollection();
$route_collection = $this->getMock('Symfony\Component\Routing\RouteCollection', NULL);
$route_collection->add('test', $route);
$event = new RouteBuildEvent($route_collection, 'test');
$this->specialAttributesRouteSubscriber->onAlterRoutes($event);
$subscriber = new SpecialAttributesRouteSubscriber();
$this->assertNull($subscriber->onAlterRoutes($event));
}
/**
@ -95,12 +96,16 @@ class SpecialAttributesRouteSubscriberTest extends UnitTestCase {
* @dataProvider providerTestOnRouteBuildingInvalidVariables
* @expectedException \PHPUnit_Framework_Error_Warning
* @expectedExceptionMessage uses reserved variable names
*
* @covers ::onAlterRoutes
*/
public function testOnRouteBuildingInvalidVariables(Route $route) {
$route_collection = new RouteCollection();
$route_collection = $this->getMock('Symfony\Component\Routing\RouteCollection', NULL);
$route_collection->add('test', $route);
$event = new RouteBuildEvent($route_collection, 'test');
$this->specialAttributesRouteSubscriber->onAlterRoutes($event);
$subscriber = new SpecialAttributesRouteSubscriber();
$subscriber->onAlterRoutes($event);
}
}

View file

@ -0,0 +1,170 @@
<?php
/**
* @file
* Contains \Drupal\system\Tests\Extension\InfoParserUnitTest.
*/
namespace Drupal\Tests\Core\Extension;
use Drupal\Core\Extension\InfoParser;
use Drupal\Tests\UnitTestCase;
use org\bovigo\vfs\vfsStream;
/**
* Tests InfoParser class and exception.
*
* Files for this test are stored in core/modules/system/tests/fixtures and end
* with .info.txt instead of info.yml in order not not be considered as real
* extensions.
*
* @coversDefaultClass \Drupal\Core\Extension\InfoParser
*
* @group Extension
*/
class InfoParserUnitTest extends UnitTestCase {
/**
* The InfoParser object.
*
* @var \Drupal\Core\Extension\InfoParser
*/
protected $infoParser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->infoParser = new InfoParser();
}
/**
* Tests the functionality of the infoParser object.
*
* @covers ::parse
*/
public function testInfoParserNonExisting() {
vfsStream::setup('modules');
$info = $this->infoParser->parse(vfsStream::url('modules') . '/does_not_exist.info.txt');
$this->assertTrue(empty($info), 'Non existing info.yml returns empty array.');
}
/**
* Test if correct exception is thrown for a broken info file.
*
* @covers ::parse
*
* @expectedException \Drupal\Core\Extension\InfoParserException
* @expectedExceptionMessageRegExp #broken\.info\.txt#
*/
public function testInfoParserBroken() {
$broken_info = <<<BROKEN_INFO
# info.yml for testing broken YAML parsing exception handling.
name: File
type: module
description: 'Defines a file field type.'
package: Core
version: VERSION
core: 8.x
dependencies::;;
- field
BROKEN_INFO;
vfsStream::setup('modules');
vfsStream::create([
'fixtures' => [
'broken.info.txt' => $broken_info,
],
]);
$filename = vfsStream::url('modules/fixtures/broken.info.txt');
$this->infoParser->parse($filename);
}
/**
* Tests that missing required keys are detected.
*
* @covers ::parse
*
* @expectedException \Drupal\Core\Extension\InfoParserException
* @expectedExceptionMessageRegExp #Missing required keys \(type, core, name\) in .+?missing_keys\.info\.txt#
*/
public function testInfoParserMissingKeys() {
$missing_keys = <<<MISSINGKEYS
# info.yml for testing missing name, description, and type keys.
package: Core
version: VERSION
dependencies:
- field
MISSINGKEYS;
vfsStream::setup('modules');
vfsStream::create([
'fixtures' => [
'missing_keys.info.txt' => $missing_keys,
],
]);
$filename = vfsStream::url('modules/fixtures/missing_keys.info.txt');
$this->infoParser->parse($filename);
}
/**
* Tests that missing required key is detected.
*
* @covers ::parse
*
* @expectedException \Drupal\Core\Extension\InfoParserException
* @expectedExceptionMessageRegExp #Missing required keys \(type\) in .+?missing_key\.info\.txt#
*/
public function testInfoParserMissingKey() {
$missing_key = <<<MISSINGKEY
# info.yml for testing missing type key.
name: File
description: 'Defines a file field type.'
package: Core
version: VERSION
core: 8.x
dependencies:
- field
MISSINGKEY;
vfsStream::setup('modules');
vfsStream::create([
'fixtures' => [
'missing_key.info.txt' => $missing_key,
],
]);
$filename = vfsStream::url('modules/fixtures/missing_key.info.txt');
$this->infoParser->parse($filename);
}
/**
* Tests common info file.
*
* @covers ::parse
*/
public function testInfoParserCommonInfo() {
$common = <<<COMMONTEST
core: 8.x
name: common_test
type: module
description: 'testing info file parsing'
simple_string: 'A simple string'
version: "VERSION"
double_colon: dummyClassName::
COMMONTEST;
vfsStream::setup('modules');
vfsStream::create([
'fixtures' => [
'common_test.info.txt' => $common,
],
]);
$info_values = $this->infoParser->parse(vfsStream::url('modules/fixtures/common_test.info.txt'));
$this->assertEquals($info_values['simple_string'], 'A simple string', 'Simple string value was parsed correctly.');
$this->assertEquals($info_values['version'], \Drupal::VERSION, 'Constant value was parsed correctly.');
$this->assertEquals($info_values['double_colon'], 'dummyClassName::', 'Value containing double-colon was parsed correctly.');
}
}

View file

@ -7,7 +7,6 @@
namespace Drupal\Tests\Core\Extension;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Tests\UnitTestCase;
/**
@ -72,7 +71,7 @@ class RequiredModuleUninstallValidatorTest extends UnitTestCase {
->method('getModuleInfoByModule')
->willReturn(['required' => TRUE, 'name' => $module]);
$expected = [SafeMarkup::format('The @module module is required', ['@module' => $module])];
$expected = ["The $module module is required"];
$reasons = $this->uninstallValidator->validate($module);
$this->assertSame($expected, $reasons);
}

View file

@ -0,0 +1,63 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Field\FieldFilteredStringTest.
*/
namespace Drupal\Tests\Core\Field;
use Drupal\Tests\UnitTestCase;
use Drupal\Core\Field\FieldFilteredString;
use Drupal\Component\Utility\SafeStringInterface;
/**
* @coversDefaultClass \Drupal\Core\Field\FieldFilteredString
* @group Field
*/
class FieldFilteredStringTest extends UnitTestCase {
/**
* @covers ::create
* @dataProvider providerTestCreate
*/
public function testCreate($string, $expected, $instance_of_check) {
$filtered_string = FieldFilteredString::create($string);
if ($instance_of_check) {
$this->assertInstanceOf(FieldFilteredString::class, $filtered_string);
}
$this->assertSame($expected, (string) $filtered_string);
}
/**
* Provides data for testCreate().
*/
public function providerTestCreate() {
$data = [];
$data[] = ['', '', FALSE];
// Certain tags are filtered.
$data[] = ['<script>teststring</script>', 'teststring', TRUE];
// Certain tags are not filtered.
$data[] = ['<em>teststring</em>', '<em>teststring</em>', TRUE];
// HTML will be normalized.
$data[] = ['<em>teststring', '<em>teststring</em>', TRUE];
// Even safe strings will be escaped.
$safe_string = $this->prophesize(SafeStringInterface::class);
$safe_string->__toString()->willReturn('<script>teststring</script>');
$data[] = [$safe_string->reveal(), 'teststring', TRUE];
return $data;
}
/**
* @covers: ::displayAllowedTags
*/
public function testdisplayAllowedTags() {
$expected = '<a> <b> <big> <code> <del> <em> <i> <ins> <pre> <q> <small> <span> <strong> <sub> <sup> <tt> <ol> <ul> <li> <p> <br> <img>';
$this->assertSame($expected, FieldFilteredString::displayAllowedTags());
}
}

View file

@ -12,13 +12,18 @@ use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultForbidden;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Form\EnforcedResponseException;
use Drupal\Core\Form\FormBuilder;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* @coversDefaultClass \Drupal\Core\Form\FormBuilder
@ -26,6 +31,25 @@ use Symfony\Component\HttpFoundation\RequestStack;
*/
class FormBuilderTest extends FormTestBase {
/**
* The dependency injection container.
*
* @var \Symfony\Component\DependencyInjection\ContainerBuilder
*/
protected $container;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->container = new ContainerBuilder();
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class)->reveal();
$this->container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($this->container);
}
/**
* Tests the getFormId() method with a string based form ID.
*
@ -571,7 +595,7 @@ class FormBuilderTest extends FormTestBase {
$data['access-false-root'] = [$clone, $expected_access];
$clone = $element;
$access_result = AccessResult::forbidden()->addCacheContexts(['user']);
$access_result = AccessResult::forbidden();
$clone['#access'] = $access_result;
$expected_access = [];
@ -603,11 +627,9 @@ class FormBuilderTest extends FormTestBase {
// Allow access on the most outer level but forbid otherwise.
$clone = $element;
$access_result_allowed = AccessResult::allowed()
->addCacheContexts(['user']);
$access_result_allowed = AccessResult::allowed();
$clone['#access'] = $access_result_allowed;
$access_result_forbidden = AccessResult::forbidden()
->addCacheContexts(['user']);
$access_result_forbidden = AccessResult::forbidden();
$clone['child0']['#access'] = $access_result_forbidden;
$expected_access = [];
@ -662,6 +684,149 @@ class FormBuilderTest extends FormTestBase {
return $data;
}
/**
* @covers ::valueCallableIsSafe
*
* @dataProvider providerTestValueCallableIsSafe
*/
public function testValueCallableIsSafe($callback, $expected) {
$method = new \ReflectionMethod(FormBuilder::class, 'valueCallableIsSafe');
$method->setAccessible(true);
$is_safe = $method->invoke($this->formBuilder, $callback);
$this->assertSame($expected, $is_safe);
}
public function providerTestValueCallableIsSafe() {
$data = [];
$data['string_no_slash'] = [
'Drupal\Core\Render\Element\Token::valueCallback',
TRUE,
];
$data['string_with_slash'] = [
'\Drupal\Core\Render\Element\Token::valueCallback',
TRUE,
];
$data['array_no_slash'] = [
['Drupal\Core\Render\Element\Token', 'valueCallback'],
TRUE,
];
$data['array_with_slash'] = [
['\Drupal\Core\Render\Element\Token', 'valueCallback'],
TRUE,
];
$data['closure'] = [
function () {},
FALSE,
];
return $data;
}
/**
* @covers ::doBuildForm
*
* @dataProvider providerTestInvalidToken
*/
public function testInvalidToken($expected, $valid_token, $user_is_authenticated) {
$form_token = 'the_form_token';
$form_id = 'test_form_id';
if (is_bool($valid_token)) {
$this->csrfToken->expects($this->any())
->method('get')
->willReturnArgument(0);
$this->csrfToken->expects($this->atLeastOnce())
->method('validate')
->will($this->returnValueMap([
[$form_token, $form_id, $valid_token],
[$form_id, $form_id, $valid_token],
]));
}
$current_user = $this->prophesize(AccountInterface::class);
$current_user->isAuthenticated()->willReturn($user_is_authenticated);
$property = new \ReflectionProperty(FormBuilder::class, 'currentUser');
$property->setAccessible(TRUE);
$property->setValue($this->formBuilder, $current_user->reveal());
$expected_form = $form_id();
$form_arg = $this->getMockForm($form_id, $expected_form);
$form_state = new FormState();
$input['form_id'] = $form_id;
$input['form_token'] = $form_token;
$form_state->setUserInput($input);
$this->simulateFormSubmission($form_id, $form_arg, $form_state, FALSE);
$this->assertSame($expected, $form_state->hasInvalidToken());
}
public function providerTestInvalidToken() {
$data = [];
$data['authenticated_invalid'] = [TRUE, FALSE, TRUE];
$data['authenticated_valid'] = [FALSE, TRUE, TRUE];
// If the user is not authenticated, we will not have a token.
$data['anonymous'] = [FALSE, NULL, FALSE];
return $data;
}
/**
* @covers ::prepareForm
*
* @dataProvider providerTestFormTokenCacheability
*/
function testFormTokenCacheability($token, $is_authenticated, $expected_form_cacheability, $expected_token_cacheability) {
$user = $this->prophesize(AccountProxyInterface::class);
$user->isAuthenticated()
->willReturn($is_authenticated);
$this->container->set('current_user', $user->reveal());
\Drupal::setContainer($this->container);
$form_id = 'test_form_id';
$form = $form_id();
if (isset($token)) {
$form['#token'] = $token;
}
$form_arg = $this->getMock('Drupal\Core\Form\FormInterface');
$form_arg->expects($this->once())
->method('getFormId')
->will($this->returnValue($form_id));
$form_arg->expects($this->once())
->method('buildForm')
->will($this->returnValue($form));
$form_state = new FormState();
$built_form = $this->formBuilder->buildForm($form_arg, $form_state);
if (!isset($expected_form_cacheability)) {
$this->assertFalse(isset($built_form['#cache']));
}
else {
$this->assertTrue(isset($built_form['#cache']));
$this->assertEquals($expected_form_cacheability, $built_form['#cache']);
}
if (!isset($expected_token_cacheability)) {
$this->assertFalse(isset($built_form['form_token']));
}
else {
$this->assertTrue(isset($built_form['form_token']));
$this->assertEquals($expected_token_cacheability, $built_form['form_token']['#cache']);
}
}
/**
* Data provider for testFormTokenCacheability.
*
* @return array
*/
function providerTestFormTokenCacheability() {
return [
'token:none,authenticated:true' => [NULL, TRUE, ['contexts' => ['user.roles:authenticated']], ['max-age' => 0]],
'token:false,authenticated:true' => [FALSE, TRUE, NULL, NULL],
'token:none,authenticated:false' => [NULL, FALSE, ['contexts' => ['user.roles:authenticated']], NULL],
'token:false,authenticated:false' => [FALSE, FALSE, NULL, NULL],
];
}
}
class TestForm implements FormInterface {

View file

@ -427,9 +427,9 @@ class FormCacheTest extends UnitTestCase {
* @covers ::setCache
*/
public function testSetCacheWithSafeStrings() {
// A call to SafeMarkup::set() is appropriate in this test as a way to add a
// string to the safe list in the simplest way possible. Normally, avoid it.
SafeMarkup::set('a_safe_string');
// A call to SafeMarkup::format() is appropriate in this test as a way to
// add a string to the safe list in the simplest way possible.
SafeMarkup::format('@value', ['@value' => 'a_safe_string']);
$form_build_id = 'the_form_build_id';
$form = [
'#form_id' => 'the_form_id'

View file

@ -25,8 +25,9 @@ class FormErrorHandlerTest extends UnitTestCase {
$link_generator->expects($this->any())
->method('generate')
->willReturnArgument(0);
$renderer = $this->getMock('\Drupal\Core\Render\RendererInterface');
$form_error_handler = $this->getMockBuilder('Drupal\Core\Form\FormErrorHandler')
->setConstructorArgs([$this->getStringTranslationStub(), $link_generator])
->setConstructorArgs([$this->getStringTranslationStub(), $link_generator, $renderer])
->setMethods(['drupalSetMessage'])
->getMock();
@ -41,7 +42,13 @@ class FormErrorHandlerTest extends UnitTestCase {
->with('this missing element is invalid', 'error');
$form_error_handler->expects($this->at(3))
->method('drupalSetMessage')
->with('3 errors have been found: Test 1, Test 2 &amp; a half, Test 3', 'error');
->with('3 errors have been found: <ul-comma-list-mock><li-mock>Test 1</li-mock><li-mock>Test 2 &amp; a half</li-mock><li-mock>Test 3</li-mock></ul-comma-list-mock>', 'error');
$renderer->expects($this->any())
->method('renderPlain')
->will($this->returnCallback(function ($render_array) {
return $render_array[0]['#markup'] . '<ul-comma-list-mock><li-mock>' . implode(array_map('htmlspecialchars', $render_array[1]['#items']), '</li-mock><li-mock>') . '</li-mock></ul-comma-list-mock>';
}));
$form = [
'#parents' => [],
@ -103,7 +110,7 @@ class FormErrorHandlerTest extends UnitTestCase {
*/
public function testSetElementErrorsFromFormState() {
$form_error_handler = $this->getMockBuilder('Drupal\Core\Form\FormErrorHandler')
->setConstructorArgs([$this->getStringTranslationStub(), $this->getMock('Drupal\Core\Utility\LinkGeneratorInterface')])
->setConstructorArgs([$this->getStringTranslationStub(), $this->getMock('Drupal\Core\Utility\LinkGeneratorInterface'), $this->getMock('\Drupal\Core\Render\RendererInterface')])
->setMethods(['drupalSetMessage'])
->getMock();

View file

@ -209,8 +209,7 @@ abstract class FormTestBase extends UnitTestCase {
* Provides a mocked form object.
*
* @param string $form_id
* (optional) The form ID to be used. If none is provided, the form will be
* set with no expectation about getFormId().
* The form ID to be used.
* @param mixed $expected_form
* (optional) If provided, the expected form response for buildForm() to
* return. Defaults to NULL.

View file

@ -7,7 +7,6 @@
namespace Drupal\Tests\Core\Form;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Form\FormState;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
@ -468,7 +467,7 @@ class FormValidatorTest extends UnitTestCase {
'#maxlength' => 7,
'#value' => $this->randomMachineName(8),
),
SafeMarkup::format('!name cannot be longer than %max characters but is currently %length characters long.', array('!name' => 'Test', '%max' => '7', '%length' => 8)),
'Test cannot be longer than <em class="placeholder">7</em> characters but is currently <em class="placeholder">8</em> characters long.',
FALSE,
),
);

View file

@ -8,6 +8,8 @@
namespace Drupal\Tests\Core\Menu;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\DependencyInjection\Container;
use Drupal\Core\Menu\DefaultMenuLinkTreeManipulators;
use Drupal\Core\Menu\MenuLinkTreeElement;
use Drupal\Tests\UnitTestCase;
@ -76,6 +78,11 @@ class DefaultMenuLinkTreeManipulatorsTest extends UnitTestCase {
->getMock();
$this->defaultMenuTreeManipulators = new DefaultMenuLinkTreeManipulators($this->accessManager, $this->currentUser, $this->queryFactory);
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class)->reveal();
$container = new Container();
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
}
/**

View file

@ -10,6 +10,8 @@ namespace Drupal\Tests\Core\Menu;
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Component\Plugin\Factory\FactoryInterface;
use Drupal\Core\Access\AccessManagerInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultForbidden;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\Language;
@ -109,10 +111,11 @@ class LocalActionManagerTest extends UnitTestCase {
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
$this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
$access_result = new AccessResultForbidden();
$this->accessManager = $this->getMock('Drupal\Core\Access\AccessManagerInterface');
$this->accessManager->expects($this->any())
->method('checkNamedRoute')
->will($this->returnValue(FALSE));
->willReturn($access_result);
$this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
$this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
$this->factory = $this->getMock('Drupal\Component\Plugin\Factory\FactoryInterface');
@ -202,7 +205,7 @@ class LocalActionManagerTest extends UnitTestCase {
'url' => Url::fromRoute('test_route_2'),
'localized_options' => '',
),
'#access' => FALSE,
'#access' => AccessResult::forbidden(),
'#weight' => 0,
),
),
@ -236,7 +239,7 @@ class LocalActionManagerTest extends UnitTestCase {
'url' => Url::fromRoute('test_route_2'),
'localized_options' => '',
),
'#access' => FALSE,
'#access' => AccessResult::forbidden(),
'#weight' => 0,
),
),
@ -271,7 +274,7 @@ class LocalActionManagerTest extends UnitTestCase {
'url' => Url::fromRoute('test_route_2'),
'localized_options' => '',
),
'#access' => FALSE,
'#access' => AccessResult::forbidden(),
'#weight' => 1,
),
'plugin_id_2' => array(
@ -281,7 +284,7 @@ class LocalActionManagerTest extends UnitTestCase {
'url' => Url::fromRoute('test_route_3'),
'localized_options' => '',
),
'#access' => FALSE,
'#access' => AccessResult::forbidden(),
'#weight' => 0,
),
),
@ -318,7 +321,7 @@ class LocalActionManagerTest extends UnitTestCase {
'url' => Url::fromRoute('test_route_2', ['test1']),
'localized_options' => '',
),
'#access' => FALSE,
'#access' => AccessResult::forbidden(),
'#weight' => 1,
),
'plugin_id_2' => array(
@ -328,7 +331,7 @@ class LocalActionManagerTest extends UnitTestCase {
'url' => Url::fromRoute('test_route_2', ['test2']),
'localized_options' => '',
),
'#access' => FALSE,
'#access' => AccessResult::forbidden(),
'#weight' => 0,
),
),

View file

@ -0,0 +1,68 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Menu\MenuLinkDefaultTest.
*/
namespace Drupal\Tests\Core\Menu;
use Drupal\Core\Menu\MenuLinkDefault;
use Drupal\Core\Menu\StaticMenuLinkOverridesInterface;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Menu\MenuLinkDefault
* @group Menu
*/
class MenuLinkDefaultTest extends UnitTestCase {
/**
* @covers ::updateLink
*/
public function testUpdateLink() {
$plugin_definition = [
'title' => 'Hey jude',
'enabled' => 1,
'expanded' => 1,
'menu_name' => 'admin',
'parent' => '',
'weight' => 10,
];
$expected_plugin_definition = $plugin_definition;
$expected_plugin_definition['weight'] = -10;
$static_override = $this->prophesize(StaticMenuLinkOverridesInterface::class);
$static_override->saveOverride('example_menu_link', $expected_plugin_definition);
$static_override = $static_override->reveal();
$menu_link = new MenuLinkDefault([], 'example_menu_link', $plugin_definition, $static_override);
$this->assertEquals($expected_plugin_definition, $menu_link->updateLink(['weight' => -10], TRUE));
}
/**
* @covers ::updateLink
*/
public function testUpdateLinkWithoutPersist() {
$plugin_definition = [
'title' => 'Hey jude',
'enabled' => 1,
'expanded' => 1,
'menu_name' => 'admin',
'parent' => '',
'weight' => 10,
];
$expected_plugin_definition = $plugin_definition;
$expected_plugin_definition['weight'] = -10;
$static_override = $this->prophesize(StaticMenuLinkOverridesInterface::class);
$static_override->saveOverride()->shouldNotBeCalled();
$static_override = $static_override->reveal();
$menu_link = new MenuLinkDefault([], 'example_menu_link', $plugin_definition, $static_override);
$this->assertEquals($expected_plugin_definition, $menu_link->updateLink(['weight' => -10], FALSE));
}
}

View file

@ -7,7 +7,6 @@
namespace Drupal\Tests\Core\Path;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Path\PathMatcher;
use Drupal\Tests\UnitTestCase;
@ -49,12 +48,7 @@ class PathMatcherTest extends UnitTestCase {
public function testMatchPath($patterns, $paths) {
foreach ($paths as $path => $expected_result) {
$actual_result = $this->pathMatcher->matchPath($path, $patterns);
$this->assertEquals($actual_result, $expected_result, SafeMarkup::format('Tried matching the path <code>@path</code> to the pattern <pre>@patterns</pre> - expected @expected, got @actual.', array(
'@path' => $path,
'@patterns' => $patterns,
'@expected' => var_export($expected_result, TRUE),
'@actual' => var_export($actual_result, TRUE),
)));
$this->assertEquals($actual_result, $expected_result, "Tried matching the path '$path' to the pattern '$patterns'.");
}
}

View file

@ -7,6 +7,7 @@
namespace Drupal\Tests\Core\Render\Element;
use Drupal\Core\Render\SafeString;
use Drupal\Tests\UnitTestCase;
use Drupal\Core\Render\Element\HtmlTag;
@ -34,7 +35,7 @@ class HtmlTagTest extends UnitTestCase {
public function testPreRenderHtmlTag($element, $expected) {
$result = HtmlTag::preRenderHtmlTag($element);
$this->assertArrayHasKey('#markup', $result);
$this->assertSame($expected, $result['#markup']);
$this->assertEquals($expected, $result['#markup']);
}
/**
@ -45,12 +46,10 @@ class HtmlTagTest extends UnitTestCase {
// Value prefix/suffix.
$element = array(
'#value_prefix' => 'value_prefix|',
'#value_suffix' => '|value_suffix',
'#value' => 'value',
'#tag' => 'p',
);
$tags[] = array($element, '<p>value_prefix|value|value_suffix</p>' . "\n");
$tags[] = array($element, '<p>value</p>' . "\n");
// Normal element without a value should not result in a void element.
$element = array(
@ -77,6 +76,27 @@ class HtmlTagTest extends UnitTestCase {
$element['#noscript'] = TRUE;
$tags[] = array($element, '<noscript><div class="test" id="id">value</div>' . "\n" . '</noscript>');
// Ensure that #tag is sanitised.
$element = array(
'#tag' => 'p><script>alert()</script><p',
'#value' => 'value',
);
$tags[] = array($element, "<p&gt;&lt;script&gt;alert()&lt;/script&gt;&lt;p>value</p&gt;&lt;script&gt;alert()&lt;/script&gt;&lt;p>\n");
// Ensure that #value is not filtered if it is marked as safe.
$element = array(
'#tag' => 'p',
'#value' => SafeString::create('<script>value</script>'),
);
$tags[] = array($element, "<p><script>value</script></p>\n");
// Ensure that #value is filtered if it is not safe.
$element = array(
'#tag' => 'p',
'#value' => '<script>value</script>',
);
$tags[] = array($element, "<p>value</p>\n");
return $tags;
}
@ -84,8 +104,12 @@ class HtmlTagTest extends UnitTestCase {
* @covers ::preRenderConditionalComments
* @dataProvider providerPreRenderConditionalComments
*/
public function testPreRenderConditionalComments($element, $expected) {
$this->assertSame($expected, HtmlTag::preRenderConditionalComments($element));
public function testPreRenderConditionalComments($element, $expected, $set_safe = FALSE) {
if ($set_safe) {
$element['#prefix'] = SafeString::create($element['#prefix']);
$element['#suffix'] = SafeString::create($element['#suffix']);
}
$this->assertEquals($expected, HtmlTag::preRenderConditionalComments($element));
}
/**
@ -142,6 +166,26 @@ class HtmlTagTest extends UnitTestCase {
$expected['#suffix'] = "<!--<![endif]-->\n";
$tags[] = array($element, $expected);
// Prefix and suffix filtering if not safe.
$element = array(
'#tag' => 'link',
'#browsers' => array(
'IE' => FALSE,
),
'#prefix' => '<blink>prefix</blink>',
'#suffix' => '<blink>suffix</blink>',
);
$expected = $element;
$expected['#prefix'] = "\n<!--[if !IE]><!-->\nprefix";
$expected['#suffix'] = "suffix<!--<![endif]-->\n";
$tags[] = array($element, $expected);
// Prefix and suffix filtering if marked as safe. This has to come after the
// previous test case.
$expected['#prefix'] = "\n<!--[if !IE]><!-->\n<blink>prefix</blink>";
$expected['#suffix'] = "<blink>suffix</blink><!--<![endif]-->\n";
$tags[] = array($element, $expected, TRUE);
return $tags;
}

View file

@ -0,0 +1,45 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Render\Element\MachineNameTest.
*/
namespace Drupal\Tests\Core\Render\Element;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\MachineName;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Render\Element\MachineName
* @group Render
*/
class MachineNameTest extends UnitTestCase {
/**
* @covers ::valueCallback
*
* @dataProvider providerTestValueCallback
*/
public function testValueCallback($expected, $input) {
$element = [];
$form_state = $this->prophesize(FormStateInterface::class)->reveal();
$this->assertSame($expected, MachineName::valueCallback($element, $input, $form_state));
}
/**
* Data provider for testValueCallback().
*/
public function providerTestValueCallback() {
$data = [];
$data[] = [NULL, FALSE];
$data[] = [NULL, NULL];
$data[] = ['', ['test']];
$data[] = ['test', 'test'];
$data[] = ['123', 123];
return $data;
}
}

View file

@ -0,0 +1,45 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Render\Element\PasswordConfirmTest.
*/
namespace Drupal\Tests\Core\Render\Element;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\PasswordConfirm;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Render\Element\PasswordConfirm
* @group Render
*/
class PasswordConfirmTest extends UnitTestCase {
/**
* @covers ::valueCallback
*
* @dataProvider providerTestValueCallback
*/
public function testValueCallback($expected, $element, $input) {
$form_state = $this->prophesize(FormStateInterface::class)->reveal();
$this->assertSame($expected, PasswordConfirm::valueCallback($element, $input, $form_state));
}
/**
* Data provider for testValueCallback().
*/
public function providerTestValueCallback() {
$data = [];
$data[] = [['pass1' => '', 'pass2' => ''], [], NULL];
$data[] = [['pass1' => '', 'pass2' => ''], ['#default_value' => ['pass2' => 'value']], NULL];
$data[] = [['pass2' => 'value', 'pass1' => ''], ['#default_value' => ['pass2' => 'value']], FALSE];
$data[] = [['pass1' => '123456', 'pass2' => 'qwerty'], [], ['pass1' => '123456', 'pass2' => 'qwerty']];
$data[] = [['pass1' => '123', 'pass2' => '234'], [], ['pass1' => 123, 'pass2' => 234]];
$data[] = [['pass1' => '', 'pass2' => '234'], [], ['pass1' => ['array'], 'pass2' => 234]];
return $data;
}
}

View file

@ -0,0 +1,45 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Render\Element\PasswordTest.
*/
namespace Drupal\Tests\Core\Render\Element;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\Password;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Render\Element\Password
* @group Render
*/
class PasswordTest extends UnitTestCase {
/**
* @covers ::valueCallback
*
* @dataProvider providerTestValueCallback
*/
public function testValueCallback($expected, $input) {
$element = [];
$form_state = $this->prophesize(FormStateInterface::class)->reveal();
$this->assertSame($expected, Password::valueCallback($element, $input, $form_state));
}
/**
* Data provider for testValueCallback().
*/
public function providerTestValueCallback() {
$data = [];
$data[] = [NULL, FALSE];
$data[] = [NULL, NULL];
$data[] = ['', ['test']];
$data[] = ['test', 'test'];
$data[] = ['123', 123];
return $data;
}
}

View file

@ -0,0 +1,45 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Render\Element\TextareaTest.
*/
namespace Drupal\Tests\Core\Render\Element;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\Textarea;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Render\Element\Textarea
* @group Render
*/
class TextareaTest extends UnitTestCase {
/**
* @covers ::valueCallback
*
* @dataProvider providerTestValueCallback
*/
public function testValueCallback($expected, $input) {
$element = [];
$form_state = $this->prophesize(FormStateInterface::class)->reveal();
$this->assertSame($expected, Textarea::valueCallback($element, $input, $form_state));
}
/**
* Data provider for testValueCallback().
*/
public function providerTestValueCallback() {
$data = [];
$data[] = [NULL, FALSE];
$data[] = [NULL, NULL];
$data[] = ['', ['test']];
$data[] = ['test', 'test'];
$data[] = ['123', 123];
return $data;
}
}

View file

@ -0,0 +1,46 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Render\Element\TextfieldTest.
*/
namespace Drupal\Tests\Core\Render\Element;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\Textfield;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Render\Element\Textfield
* @group Render
*/
class TextfieldTest extends UnitTestCase {
/**
* @covers ::valueCallback
*
* @dataProvider providerTestValueCallback
*/
public function testValueCallback($expected, $input) {
$element = [];
$form_state = $this->prophesize(FormStateInterface::class)->reveal();
$this->assertSame($expected, Textfield::valueCallback($element, $input, $form_state));
}
/**
* Data provider for testValueCallback().
*/
public function providerTestValueCallback() {
$data = [];
$data[] = [NULL, FALSE];
$data[] = [NULL, NULL];
$data[] = ['', ['test']];
$data[] = ['test', 'test'];
$data[] = ['123', 123];
$data[] = ['testwithnewline', "test\nwith\rnewline"];
return $data;
}
}

View file

@ -0,0 +1,45 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Render\Element\TokenTest.
*/
namespace Drupal\Tests\Core\Render\Element;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\Token;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Render\Element\Token
* @group Render
*/
class TokenTest extends UnitTestCase {
/**
* @covers ::valueCallback
*
* @dataProvider providerTestValueCallback
*/
public function testValueCallback($expected, $input) {
$element = [];
$form_state = $this->prophesize(FormStateInterface::class)->reveal();
$this->assertSame($expected, Token::valueCallback($element, $input, $form_state));
}
/**
* Data provider for testValueCallback().
*/
public function providerTestValueCallback() {
$data = [];
$data[] = [NULL, FALSE];
$data[] = [NULL, NULL];
$data[] = ['', ['test']];
$data[] = ['test', 'test'];
$data[] = ['123', 123];
return $data;
}
}

View file

@ -66,101 +66,6 @@ class ElementInfoManagerTest extends UnitTestCase {
$this->elementInfo = new ElementInfoManager(new \ArrayObject(), $this->cache, $this->cacheTagsInvalidator, $this->moduleHandler, $this->themeManager);
}
/**
* Tests the getInfo method.
*
* @covers ::getInfo
* @covers ::buildInfo
*
* @dataProvider providerTestGetInfo
*/
public function testGetInfo($type, $expected_info, $element_info, callable $alter_callback = NULL) {
$this->moduleHandler->expects($this->once())
->method('invokeAll')
->with('element_info')
->will($this->returnValue($element_info));
$this->moduleHandler->expects($this->once())
->method('alter')
->with('element_info', $this->anything())
->will($this->returnCallback($alter_callback ?: function($info) {
return $info;
}));
$this->themeManager->expects($this->once())
->method('getActiveTheme')
->willReturn(new ActiveTheme(['name' => 'test']));
$this->themeManager->expects($this->once())
->method('alter')
->with('element_info', $this->anything())
->will($this->returnCallback($alter_callback ?: function($info) {
return $info;
}));
$this->cache->expects($this->at(0))
->method('get')
->with('element_info_build:test')
->will($this->returnValue(FALSE));
$this->cache->expects($this->at(1))
->method('get')
->with('element_info')
->will($this->returnValue(FALSE));
$this->cache->expects($this->at(2))
->method('set')
->with('element_info');
$this->cache->expects($this->at(3))
->method('set')
->with('element_info_build:test');
$this->assertEquals($expected_info, $this->elementInfo->getInfo($type));
}
/**
* Provides tests data for getInfo.
*
* @return array
*/
public function providerTestGetInfo() {
$data = array();
// Provide an element and expect it is returned.
$data[] = array(
'page',
array(
'#type' => 'page',
'#theme' => 'page',
'#defaults_loaded' => TRUE,
),
array('page' => array(
'#theme' => 'page',
)),
);
// Provide an element but request an non existent one.
$data[] = array(
'form',
array(
'#defaults_loaded' => TRUE,
),
array('page' => array(
'#theme' => 'page',
)),
);
// Provide an element and alter it to ensure it is altered.
$data[] = array(
'page',
array(
'#type' => 'page',
'#theme' => 'page',
'#number' => 597219,
'#defaults_loaded' => TRUE,
),
array('page' => array(
'#theme' => 'page',
)),
function ($alter_name, array &$info) {
$info['page']['#number'] = 597219;
}
);
return $data;
}
/**
* Tests the getInfo() method when render element plugins are used.
*
@ -170,10 +75,6 @@ class ElementInfoManagerTest extends UnitTestCase {
* @dataProvider providerTestGetInfoElementPlugin
*/
public function testGetInfoElementPlugin($plugin_class, $expected_info) {
$this->moduleHandler->expects($this->once())
->method('invokeAll')
->with('element_info')
->willReturn(array());
$this->moduleHandler->expects($this->once())
->method('alter')
->with('element_info', $this->anything())

View file

@ -38,9 +38,6 @@ class RendererBubblingTest extends RendererTestBase {
$this->setUpRequest();
$this->setupMemoryCache();
$this->elementInfo->expects($this->any())
->method('getInfo')
->willReturn([]);
$this->cacheContextsManager->expects($this->any())
->method('convertTokensToKeys')
->willReturnArgument(0);
@ -302,7 +299,7 @@ class RendererBubblingTest extends RendererTestBase {
* Tests the self-healing of the redirect with conditional cache contexts.
*/
public function testConditionalCacheContextBubblingSelfHealing() {
global $current_user_role;
$current_user_role = &$this->currentUserRole;
$this->setUpRequest();
$this->setupMemoryCache();
@ -319,8 +316,7 @@ class RendererBubblingTest extends RendererTestBase {
'tags' => ['b'],
],
'grandchild' => [
'#access_callback' => function () {
global $current_user_role;
'#access_callback' => function() use (&$current_user_role) {
// Only role A cannot access this subtree.
return $current_user_role !== 'A';
},
@ -331,8 +327,7 @@ class RendererBubblingTest extends RendererTestBase {
'max-age' => 1800,
],
'grandgrandchild' => [
'#access_callback' => function () {
global $current_user_role;
'#access_callback' => function () use (&$current_user_role) {
// Only role C can access this subtree.
return $current_user_role === 'C';
},

View file

@ -8,9 +8,9 @@
namespace Drupal\Tests\Core\Render;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Render\Element;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Render\SafeString;
/**
* @coversDefaultClass \Drupal\Core\Render\Renderer
@ -37,13 +37,24 @@ class RendererPlaceholdersTest extends RendererTestBase {
* Also, different types:
* - A) automatically generated placeholder
* - 1) manually triggered (#create_placeholder = TRUE)
* - 2) automatically triggered (based on max-age = 0 in its subtree)
* - 2) automatically triggered (based on max-age = 0 at the top level)
* - 3) automatically triggered (based on high cardinality cache contexts at
* the top level)
* - 4) automatically triggered (based on high-invalidation frequency cache
* tags at the top level)
* - 5) automatically triggered (based on max-age = 0 in its subtree, i.e.
* via bubbling)
* - 6) automatically triggered (based on high cardinality cache contexts in
* its subtree, i.e. via bubbling)
* - 7) automatically triggered (based on high-invalidation frequency cache
* tags in its subtree, i.e. via bubbling)
* - B) manually generated placeholder
*
* So, in total 2*3 = 6 permutations.
* So, in total 2*5 = 10 permutations.
*
* @todo Case A2 is not yet supported by core. So that makes for only 4
* permutations currently.
* @todo Cases A5, A6 and A7 are not yet supported by core. So that makes for
* only 10 permutations currently, instead of 16. That will be done in
* https://www.drupal.org/node/2543334
*
* @return array
*/
@ -52,23 +63,23 @@ class RendererPlaceholdersTest extends RendererTestBase {
$generate_placeholder_markup = function($cache_keys = NULL) use ($args) {
$token_render_array = [
'#cache' => [],
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
];
if (is_array($cache_keys)) {
$token_render_array['#cache']['keys'] = $cache_keys;
}
else {
unset($token_render_array['#cache']);
}
$token = hash('sha1', serialize($token_render_array));
return SafeMarkup::format('<drupal-render-placeholder callback="@callback" arguments="@arguments" token="@token"></drupal-render-placeholder>', [
'@callback' => 'Drupal\Tests\Core\Render\PlaceholdersTest::callback',
'@arguments' => '0=' . $args[0],
'@token' => $token,
]);
$token = hash('crc32b', serialize($token_render_array));
// \Drupal\Core\Render\SafeString::create() is necessary as the render
// system would mangle this markup. As this is exactly what happens at
// runtime this is a valid use-case.
return SafeString::create('<drupal-render-placeholder callback="Drupal\Tests\Core\Render\PlaceholdersTest::callback" arguments="' . '0=' . $args[0] . '" token="' . $token . '"></drupal-render-placeholder>');
};
$extract_placeholder_render_array = function ($placeholder_render_array) {
return array_intersect_key($placeholder_render_array, ['#lazy_builder' => TRUE, '#cache' => TRUE]);
};
// Note the presence of '#create_placeholder'.
$base_element_a1 = [
'#attached' => [
'drupalSettings' => [
@ -83,9 +94,55 @@ class RendererPlaceholdersTest extends RendererTestBase {
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
],
];
// Note the absence of '#create_placeholder', presence of max-age=0 at the
// top level.
$base_element_a2 = [
// @todo, see docblock
'#attached' => [
'drupalSettings' => [
'foo' => 'bar',
],
],
'placeholder' => [
'#cache' => [
'contexts' => [],
'max-age' => 0,
],
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
],
];
// Note the absence of '#create_placeholder', presence of high cardinality
// cache context at the top level.
$base_element_a3 = [
'#attached' => [
'drupalSettings' => [
'foo' => 'bar',
],
],
'placeholder' => [
'#cache' => [
'contexts' => ['user'],
],
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
],
];
// Note the absence of '#create_placeholder', presence of high-invalidation
// frequency cache tag at the top level.
$base_element_a4 = [
'#attached' => [
'drupalSettings' => [
'foo' => 'bar',
],
],
'placeholder' => [
'#cache' => [
'contexts' => [],
'tags' => ['current-temperature'],
],
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
],
];
// Note the absence of '#create_placeholder', but the presence of
// '#attached[placeholders]'.
$base_element_b = [
'#markup' => $generate_placeholder_markup(),
'#attached' => [
@ -93,8 +150,7 @@ class RendererPlaceholdersTest extends RendererTestBase {
'foo' => 'bar',
],
'placeholders' => [
$generate_placeholder_markup() => [
'#cache' => [],
(string) $generate_placeholder_markup() => [
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
],
],
@ -109,9 +165,11 @@ class RendererPlaceholdersTest extends RendererTestBase {
// - automatically created, but manually triggered (#create_placeholder = TRUE)
// - uncacheable
$element_without_cache_keys = $base_element_a1;
$expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a1['placeholder']);
$cases[] = [
$element_without_cache_keys,
$args,
$expected_placeholder_render_array,
FALSE,
[],
];
@ -121,9 +179,11 @@ class RendererPlaceholdersTest extends RendererTestBase {
// - cacheable
$element_with_cache_keys = $base_element_a1;
$element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
$expected_placeholder_render_array['#cache']['keys'] = $keys;
$cases[] = [
$element_with_cache_keys,
$args,
$expected_placeholder_render_array,
$keys,
[
'#markup' => '<p>This is a rendered placeholder!</p>',
@ -141,31 +201,149 @@ class RendererPlaceholdersTest extends RendererTestBase {
];
// Case three: render array that has a placeholder that is:
// - manually created
// - automatically created, and automatically triggered due to max-age=0
// - uncacheable
$x = $base_element_b;
unset($x['#attached']['placeholders'][$generate_placeholder_markup()]['#cache']);
$element_without_cache_keys = $base_element_a2;
$expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a2['placeholder']);
$cases[] = [
$x,
$element_without_cache_keys,
$args,
$expected_placeholder_render_array,
FALSE,
[],
];
// Case four: render array that has a placeholder that is:
// - automatically created, but automatically triggered due to max-age=0
// - cacheable
$element_with_cache_keys = $base_element_a2;
$element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
$expected_placeholder_render_array['#cache']['keys'] = $keys;
$cases[] = [
$element_with_cache_keys,
$args,
$expected_placeholder_render_array,
FALSE,
[]
];
// Case five: render array that has a placeholder that is:
// - automatically created, and automatically triggered due to high
// cardinality cache contexts
// - uncacheable
$element_without_cache_keys = $base_element_a3;
$expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a3['placeholder']);
$cases[] = [
$element_without_cache_keys,
$args,
$expected_placeholder_render_array,
FALSE,
[],
];
// Case six: render array that has a placeholder that is:
// - automatically created, and automatically triggered due to high
// cardinality cache contexts
// - cacheable
$element_with_cache_keys = $base_element_a3;
$element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
$expected_placeholder_render_array['#cache']['keys'] = $keys;
// The CID parts here consist of the cache keys plus the 'user' cache
// context, which in this unit test is simply the given cache context token,
// see \Drupal\Tests\Core\Render\RendererTestBase::setUp().
$cid_parts = array_merge($keys, ['user']);
$cases[] = [
$element_with_cache_keys,
$args,
$expected_placeholder_render_array,
$cid_parts,
[
'#markup' => '<p>This is a rendered placeholder!</p>',
'#attached' => [
'drupalSettings' => [
'dynamic_animal' => $args[0],
],
],
'#cache' => [
'contexts' => ['user'],
'tags' => [],
'max-age' => Cache::PERMANENT,
],
],
];
// Case seven: render array that has a placeholder that is:
// - automatically created, and automatically triggered due to high
// invalidation frequency cache tags
// - uncacheable
$element_without_cache_keys = $base_element_a4;
$expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a4['placeholder']);
$cases[] = [
$element_without_cache_keys,
$args,
$expected_placeholder_render_array,
FALSE,
[],
];
// Case eight: render array that has a placeholder that is:
// - automatically created, and automatically triggered due to high
// invalidation frequency cache tags
// - cacheable
$element_with_cache_keys = $base_element_a4;
$element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
$expected_placeholder_render_array['#cache']['keys'] = $keys;
$cases[] = [
$element_with_cache_keys,
$args,
$expected_placeholder_render_array,
$keys,
[
'#markup' => '<p>This is a rendered placeholder!</p>',
'#attached' => [
'drupalSettings' => [
'dynamic_animal' => $args[0],
],
],
'#cache' => [
'contexts' => [],
'tags' => ['current-temperature'],
'max-age' => Cache::PERMANENT,
],
],
];
// Case nine: render array that has a placeholder that is:
// - manually created
// - uncacheable
$x = $base_element_b;
$expected_placeholder_render_array = $x['#attached']['placeholders'][(string) $generate_placeholder_markup()];
unset($x['#attached']['placeholders'][(string) $generate_placeholder_markup()]['#cache']);
$cases[] = [
$x,
$args,
$expected_placeholder_render_array,
FALSE,
[],
];
// Case ten: render array that has a placeholder that is:
// - manually created
// - cacheable
$x = $base_element_b;
$x['#markup'] = $generate_placeholder_markup($keys);
$x['#markup'] = $placeholder_markup = $generate_placeholder_markup($keys);
$placeholder_markup = (string) $placeholder_markup;
$x['#attached']['placeholders'] = [
$generate_placeholder_markup($keys) => [
$placeholder_markup => [
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
'#cache' => ['keys' => $keys],
],
];
$expected_placeholder_render_array = $x['#attached']['placeholders'][$placeholder_markup];
$cases[] = [
$x,
$args,
$expected_placeholder_render_array,
$keys,
[
'#markup' => '<p>This is a rendered placeholder!</p>',
@ -224,8 +402,8 @@ class RendererPlaceholdersTest extends RendererTestBase {
*
* @dataProvider providerPlaceholders
*/
public function testUncacheableParent($element, $args, $placeholder_cid_keys, array $placeholder_expected_render_cache_array) {
if ($placeholder_cid_keys) {
public function testUncacheableParent($element, $args, array $expected_placeholder_render_array, $placeholder_cid_parts, array $placeholder_expected_render_cache_array) {
if ($placeholder_cid_parts) {
$this->setupMemoryCache();
}
else {
@ -244,7 +422,7 @@ class RendererPlaceholdersTest extends RendererTestBase {
'dynamic_animal' => $args[0],
];
$this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the one added by the placeholder #lazy_builder callback exist.');
$this->assertPlaceholderRenderCache($placeholder_cid_keys, $placeholder_expected_render_cache_array);
$this->assertPlaceholderRenderCache($placeholder_cid_parts, $placeholder_expected_render_cache_array);
}
/**
@ -256,26 +434,13 @@ class RendererPlaceholdersTest extends RendererTestBase {
*
* @dataProvider providerPlaceholders
*/
public function testCacheableParent($test_element, $args, $placeholder_cid_keys, array $placeholder_expected_render_cache_array) {
public function testCacheableParent($test_element, $args, array $expected_placeholder_render_array, $placeholder_cid_parts, array $placeholder_expected_render_cache_array) {
$element = $test_element;
$this->setupMemoryCache();
$this->setUpRequest('GET');
// Generate the expected placeholder render array, so that we can generate
// the expected placeholder markup.
$expected_placeholder_render_array = [];
// When there was a child element that created a placeholder, the Renderer
// automatically initializes #cache[contexts].
if (Element::children($test_element)) {
$expected_placeholder_render_array['#cache']['contexts'] = [];
}
// When the placeholder itself is cacheable, its cache keys are present.
if ($placeholder_cid_keys) {
$expected_placeholder_render_array['#cache']['keys'] = $placeholder_cid_keys;
}
$expected_placeholder_render_array['#lazy_builder'] = ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args];
$token = hash('sha1', serialize($expected_placeholder_render_array));
$token = hash('crc32b', serialize($expected_placeholder_render_array));
$expected_placeholder_markup = '<drupal-render-placeholder callback="Drupal\Tests\Core\Render\PlaceholdersTest::callback" arguments="0=' . $args[0] . '" token="' . $token . '"></drupal-render-placeholder>';
$this->assertSame($expected_placeholder_markup, Html::normalize($expected_placeholder_markup), 'Placeholder unaltered by Html::normalize() which is used by FilterHtmlCorrector.');
@ -291,7 +456,7 @@ class RendererPlaceholdersTest extends RendererTestBase {
'dynamic_animal' => $args[0],
];
$this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the one added by the placeholder #lazy_builder callback exist.');
$this->assertPlaceholderRenderCache($placeholder_cid_keys, $placeholder_expected_render_cache_array);
$this->assertPlaceholderRenderCache($placeholder_cid_parts, $placeholder_expected_render_cache_array);
// GET request: validate cached data.
$cached_element = $this->memoryCache->get('placeholder_test_GET')->data;
@ -434,7 +599,9 @@ class RendererPlaceholdersTest extends RendererTestBase {
'null' => NULL,
]];
$this->renderer->renderRoot($element);
$result = $this->renderer->renderRoot($element);
$this->assertInstanceOf('\Drupal\Core\Render\SafeString', $result);
$this->assertEquals('<p>This is a rendered placeholder!</p>', (string) $result);
}
/**
@ -521,10 +688,6 @@ class RendererPlaceholdersTest extends RendererTestBase {
$this->cacheContextsManager->expects($this->any())
->method('convertTokensToKeys')
->willReturnArgument(0);
$this->elementInfo->expects($this->any())
->method('getInfo')
->with('details')
->willReturn(['#theme_wrappers' => ['details']]);
$this->controllerResolver->expects($this->any())
->method('getControllerFromDefinition')
->willReturnArgument(0);

View file

@ -35,6 +35,18 @@ class RendererTest extends RendererTestBase {
'#children' => '',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Reset the static list of SafeStrings to prevent bleeding between tests.
$reflected_class = new \ReflectionClass('\Drupal\Component\Utility\SafeMarkup');
$reflected_property = $reflected_class->getProperty('safeStrings');
$reflected_property->setAccessible(true);
$reflected_property->setValue([]);
}
/**
* @covers ::render
* @covers ::doRender
@ -47,7 +59,15 @@ class RendererTest extends RendererTestBase {
$setup_code();
}
$this->assertSame($expected, (string) $this->renderer->renderRoot($build));
if (isset($build['#markup'])) {
$this->assertFalse(SafeMarkup::isSafe($build['#markup']), 'The #markup value is not marked safe before rendering.');
}
$render_output = $this->renderer->renderRoot($build);
$this->assertSame($expected, (string) $render_output);
if ($render_output !== '') {
$this->assertTrue(SafeMarkup::isSafe($render_output), 'Output of render is marked safe.');
$this->assertTrue(SafeMarkup::isSafe($build['#markup']), 'The #markup value is marked safe after rendering.');
}
}
/**
@ -80,6 +100,19 @@ class RendererTest extends RendererTestBase {
$data[] = [[
'#markup' => 'foo',
], 'foo'];
// Basic #plain_text based renderable array.
$data[] = [[
'#plain_text' => 'foo',
], 'foo'];
// Mixing #plain_text and #markup based renderable array.
$data[] = [[
'#plain_text' => '<em>foo</em>',
'#markup' => 'bar',
], '&lt;em&gt;foo&lt;/em&gt;'];
// Safe strings in #plain_text are are still escaped.
$data[] = [[
'#plain_text' => SafeString::create('<em>foo</em>'),
], '&lt;em&gt;foo&lt;/em&gt;'];
// Renderable child element.
$data[] = [[
'child' => ['#markup' => 'bar'],
@ -88,6 +121,22 @@ class RendererTest extends RendererTestBase {
$data[] = [[
'child' => ['#markup' => "This is <script>alert('XSS')</script> test"],
], "This is alert('XSS') test"];
// XSS filtering test.
$data[] = [[
'child' => ['#markup' => "This is <script>alert('XSS')</script> test", '#allowed_tags' => ['script']],
], "This is <script>alert('XSS')</script> test"];
// XSS filtering test.
$data[] = [[
'child' => ['#markup' => "This is <script><em>alert('XSS')</em></script> <strong>test</strong>", '#allowed_tags' => ['em', 'strong']],
], "This is <em>alert('XSS')</em> <strong>test</strong>"];
// Html escaping test.
$data[] = [[
'child' => ['#plain_text' => "This is <script><em>alert('XSS')</em></script> <strong>test</strong>"],
], "This is &lt;script&gt;&lt;em&gt;alert(&#039;XSS&#039;)&lt;/em&gt;&lt;/script&gt; &lt;strong&gt;test&lt;/strong&gt;"];
// XSS filtering by default test.
$data[] = [[
'child' => ['#markup' => "This is <script><em>alert('XSS')</em></script> <strong>test</strong>"],
], "This is <em>alert('XSS')</em> <strong>test</strong>"];
// Ensure non-XSS tags are not filtered out.
$data[] = [[
'child' => ['#markup' => "This is <strong><script>alert('not a giraffe')</script></strong> test"],
@ -150,10 +199,6 @@ class RendererTest extends RendererTestBase {
$attributes = new Attribute(['href' => $vars['#url']] + (isset($vars['#attributes']) ? $vars['#attributes'] : []));
return '<a' . (string) $attributes . '>' . $vars['#title'] . '</a>';
});
$this->elementInfo->expects($this->atLeastOnce())
->method('getInfo')
->with('link')
->willReturn(['#theme' => 'link']);
};
$data[] = [$build, '<div class="baz"><a href="https://www.drupal.org" id="foo">bar</a></div>' . "\n", $setup_code_type_link];

View file

@ -79,6 +79,13 @@ class RendererTestBase extends UnitTestCase {
*/
protected $memoryCache;
/**
* The simulated "current" user role, for use in tests with cache contexts.
*
* @var string
*/
protected $currentUserRole;
/**
* The mocked renderer configuration.
*
@ -89,6 +96,11 @@ class RendererTestBase extends UnitTestCase {
'languages:language_interface',
'theme',
],
'auto_placeholder_conditions' => [
'max-age' => 0,
'contexts' => ['session', 'user'],
'tags' => ['current-temperature'],
],
];
/**
@ -100,6 +112,22 @@ class RendererTestBase extends UnitTestCase {
$this->controllerResolver = $this->getMock('Drupal\Core\Controller\ControllerResolverInterface');
$this->themeManager = $this->getMock('Drupal\Core\Theme\ThemeManagerInterface');
$this->elementInfo = $this->getMock('Drupal\Core\Render\ElementInfoManagerInterface');
$this->elementInfo->expects($this->any())
->method('getInfo')
->willReturnCallback(function ($type) {
switch ($type) {
case 'details':
$info = ['#theme_wrappers' => ['details']];
break;
case 'link':
$info = ['#theme' => 'link'];
break;
default:
$info = [];
}
$info['#defaults_loaded'] = TRUE;
return $info;
});
$this->requestStack = new RequestStack();
$request = new Request();
$request->server->set('REQUEST_TIME', $_SERVER['REQUEST_TIME']);
@ -108,10 +136,10 @@ class RendererTestBase extends UnitTestCase {
$this->cacheContextsManager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
->disableOriginalConstructor()
->getMock();
$current_user_role = &$this->currentUserRole;
$this->cacheContextsManager->expects($this->any())
->method('convertTokensToKeys')
->willReturnCallback(function($context_tokens) {
global $current_user_role;
->willReturnCallback(function($context_tokens) use (&$current_user_role) {
$keys = [];
foreach ($context_tokens as $context_id) {
switch ($context_id) {

View file

@ -8,6 +8,8 @@
namespace Drupal\Tests\Core\Route;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\DependencyInjection\Container;
use Drupal\Core\Session\UserSession;
use Drupal\Tests\UnitTestCase;
use Drupal\user\Access\RoleAccessCheck;
@ -143,6 +145,11 @@ class RoleAccessCheckTest extends UnitTestCase {
* @dataProvider roleAccessProvider
*/
public function testRoleAccess($path, $grant_accounts, $deny_accounts) {
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class)->reveal();
$container = new Container();
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
$role_access_check = new RoleAccessCheck();
$collection = $this->getTestRouteCollection();

View file

@ -41,13 +41,21 @@ class RoutePreloaderTest extends UnitTestCase {
*/
protected $preloader;
/**
* The mocked cache.
*
* @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $cache;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->routeProvider = $this->getMock('Drupal\Core\Routing\PreloadableRouteProviderInterface');
$this->state = $this->getMock('\Drupal\Core\State\StateInterface');
$this->preloader = new RoutePreloader($this->routeProvider, $this->state);
$this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
$this->preloader = new RoutePreloader($this->routeProvider, $this->state, $this->cache);
}
/**

View file

@ -61,6 +61,13 @@ class PermissionsHashGeneratorTest extends UnitTestCase {
*/
protected $cache;
/**
* The mocked cache backend.
*
* @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $staticCache;
/**
* The permission hash class being tested.
*
@ -138,12 +145,15 @@ class PermissionsHashGeneratorTest extends UnitTestCase {
$this->cache = $this->getMockBuilder('Drupal\Core\Cache\CacheBackendInterface')
->disableOriginalConstructor()
->getMock();
$this->staticCache = $this->getMockBuilder('Drupal\Core\Cache\CacheBackendInterface')
->disableOriginalConstructor()
->getMock();
$this->permissionsHash = new PermissionsHashGenerator($this->privateKey, $this->cache);
$this->permissionsHash = new PermissionsHashGenerator($this->privateKey, $this->cache, $this->staticCache);
}
/**
* Tests the generate() method.
* @covers ::generate
*/
public function testGenerate() {
// Ensure that the super user (user 1) always gets the same hash.
@ -162,15 +172,23 @@ class PermissionsHashGeneratorTest extends UnitTestCase {
}
/**
* Tests the generate method with cache returned.
* @covers ::generate
*/
public function testGenerateCache() {
public function testGeneratePersistentCache() {
// Set expectations for the mocked cache backend.
$expected_cid = 'user_permissions_hash:administrator,authenticated';
$mock_cache = new \stdClass();
$mock_cache->data = 'test_hash_here';
$this->staticCache->expects($this->once())
->method('get')
->with($expected_cid)
->will($this->returnValue(FALSE));
$this->staticCache->expects($this->once())
->method('set')
->with($expected_cid, $this->isType('string'));
$this->cache->expects($this->once())
->method('get')
->with($expected_cid)
@ -181,6 +199,31 @@ class PermissionsHashGeneratorTest extends UnitTestCase {
$this->permissionsHash->generate($this->account2);
}
/**
* @covers ::generate
*/
public function testGenerateStaticCache() {
// Set expectations for the mocked cache backend.
$expected_cid = 'user_permissions_hash:administrator,authenticated';
$mock_cache = new \stdClass();
$mock_cache->data = 'test_hash_here';
$this->staticCache->expects($this->once())
->method('get')
->with($expected_cid)
->will($this->returnValue($mock_cache));
$this->staticCache->expects($this->never())
->method('set');
$this->cache->expects($this->never())
->method('get');
$this->cache->expects($this->never())
->method('set');
$this->permissionsHash->generate($this->account2);
}
/**
* Tests the generate method with no cache returned.
*/
@ -188,6 +231,14 @@ class PermissionsHashGeneratorTest extends UnitTestCase {
// Set expectations for the mocked cache backend.
$expected_cid = 'user_permissions_hash:administrator,authenticated';
$this->staticCache->expects($this->once())
->method('get')
->with($expected_cid)
->will($this->returnValue(FALSE));
$this->staticCache->expects($this->once())
->method('set')
->with($expected_cid, $this->isType('string'));
$this->cache->expects($this->once())
->method('get')
->with($expected_cid)

View file

@ -0,0 +1,142 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\StackMiddleware\NegotiationMiddlewareTest.
*/
namespace Drupal\Tests\Core\StackMiddleware;
use Drupal\Core\StackMiddleware\NegotiationMiddleware;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* @coversDefaultClass \Drupal\Core\StackMiddleware\NegotiationMiddleware
* @group NegotiationMiddleware
*/
class NegotiationMiddlewareTest extends UnitTestCase {
/**
* @var \Symfony\Component\HttpKernel\HttpKernelInterface
*/
protected $app;
/**
* @var \Drupal\Tests\Core\StackMiddleware\StubNegotiationMiddleware
*/
protected $contentNegotiation;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->app = $this->prophesize(HttpKernelInterface::class);
$this->contentNegotiation = new StubNegotiationMiddleware($this->app->reveal());
}
/**
* Tests the getContentType() method with AJAX iframe upload.
*
* @covers ::getContentType
*/
public function testAjaxIframeUpload() {
$request = new Request();
$request->attributes->set('ajax_iframe_upload', '1');
$this->assertSame('iframeupload', $this->contentNegotiation->getContentType($request));
}
/**
* Tests the specifying a format via query parameters gets used.
*
* @covers ::getContentType
*/
public function testFormatViaQueryParameter() {
$request = new Request();
$request->query->set('_format', 'bob');
$this->assertSame('bob', $this->contentNegotiation->getContentType($request));
}
/**
* Tests the getContentType() method when no priority format is found.
*
* @covers ::getContentType
*/
public function testUnknowContentTypeReturnsHtmlByDefault() {
$request = new Request();
$this->assertSame('html', $this->contentNegotiation->getContentType($request));
}
/**
* Tests the getContentType() method when no priority format is found but it's an AJAX request.
*
* @covers ::getContentType
*/
public function testUnknowContentTypeButAjaxRequest() {
$request = new Request();
$request->headers->set('X-Requested-With', 'XMLHttpRequest');
$this->assertSame('html', $this->contentNegotiation->getContentType($request));
}
/**
* Test that handle() correctly hands off to sub application.
*
* @covers ::handle
*/
public function testHandle() {
$request = $this->prophesize(Request::class);
// Default empty format list should not set any formats.
$request->setFormat()->shouldNotBeCalled();
// Request format will be set with default format.
$request->setRequestFormat('html')->shouldBeCalled();
// Some getContentType calls we don't really care about but have to mock.
$request->get('ajax_iframe_upload', false)->shouldBeCalled();
$request_mock = $request->reveal();
$request_mock->query = new ParameterBag([]);
// Calling kernel app with default arguments.
$this->app->handle($request_mock, HttpKernelInterface::MASTER_REQUEST, TRUE)
->shouldBeCalled();
$this->contentNegotiation->handle($request_mock);
// Calling kernel app with specified arguments.
$this->app->handle($request_mock, HttpKernelInterface::SUB_REQUEST, FALSE)
->shouldBeCalled();
$this->contentNegotiation->handle($request_mock, HttpKernelInterface::SUB_REQUEST, FALSE);
}
/**
* @covers ::registerFormat
*/
public function testSetFormat() {
$request = $this->prophesize(Request::class);
// Default empty format list should not set any formats.
$request->setFormat('david', 'geeky/david')->shouldBeCalled();
// Some calls we don't care about.
$request->setRequestFormat('html')->shouldBeCalled();
$request->get('ajax_iframe_upload', false)->shouldBeCalled();
$request_mock = $request->reveal();
$request_mock->query = new ParameterBag([]);
// Trigger handle.
$this->contentNegotiation->registerFormat('david', 'geeky/david');
$this->contentNegotiation->handle($request_mock);
}
}
class StubNegotiationMiddleware extends NegotiationMiddleware {
public function getContentType(Request $request) { return parent::getContentType($request); }
}

View file

@ -7,6 +7,9 @@
namespace Drupal\Tests\Core\Template;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Template\TwigEnvironment;
use Drupal\Core\Template\TwigExtension;
use Drupal\Tests\UnitTestCase;
@ -124,6 +127,31 @@ class TwigExtensionTest extends UnitTestCase {
$this->assertSame('&lt;script&gt;alert(&#039;here&#039;);&lt;/script&gt;', $twig_extension->escapeFilter($twig, $string_object, 'html', 'UTF-8', TRUE));
}
/**
* @covers ::safeJoin
*/
public function testSafeJoin() {
$renderer = $this->prophesize(RendererInterface::class);
$renderer->render(['#markup' => '<strong>will be rendered</strong>', '#printed' => FALSE])->willReturn('<strong>will be rendered</strong>');
$renderer = $renderer->reveal();
$twig_extension = new TwigExtension($renderer);
$twig_environment = $this->prophesize(TwigEnvironment::class)->reveal();
// Simulate t().
$string = '<em>will be markup</em>';
SafeMarkup::setMultiple([$string => ['html' => TRUE]]);
$items = [
'<em>will be escaped</em>',
$string,
['#markup' => '<strong>will be rendered</strong>']
];
$result = $twig_extension->safeJoin($twig_environment, $items, '<br/>');
$this->assertEquals('&lt;em&gt;will be escaped&lt;/em&gt;<br/><em>will be markup</em><br/><strong>will be rendered</strong>', $result);
}
}
class TwigExtensionTestString {

View file

@ -105,6 +105,9 @@ class RegistryTest extends UnitTestCase {
->method('getImplementations')
->with('theme')
->will($this->returnValue(array('theme_test')));
$this->moduleHandler->expects($this->atLeastOnce())
->method('getModuleList')
->willReturn([]);
$registry = $this->registry->get();

View file

@ -8,7 +8,6 @@
namespace Drupal\Tests\Core\Transliteration;
use Drupal\Component\Utility\Random;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Transliteration\PhpTransliteration;
use Drupal\Tests\UnitTestCase;
@ -59,12 +58,7 @@ class PhpTransliterationTest extends UnitTestCase {
$transliteration = new PhpTransliteration(NULL, $module_handler);
$actual = $transliteration->transliterate($original, $langcode);
$this->assertSame($expected, $actual, SafeMarkup::format('@original transliteration to @actual is identical to @expected for language @langcode in service instance.', array(
'@original' => $printable,
'@langcode' => $langcode,
'@expected' => $expected,
'@actual' => $actual,
)));
$this->assertSame($expected, $actual, "'$printable' transliteration to '$actual' is identical to '$expected' for language '$langcode' in service instance.");
}
/**

View file

@ -7,10 +7,10 @@
namespace Drupal\Tests\Core\Utility {
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\GeneratedUrl;
use Drupal\Core\Language\Language;
use Drupal\Core\Link;
use Drupal\Core\Render\SafeString;
use Drupal\Core\Url;
use Drupal\Core\Utility\LinkGenerator;
use Drupal\Tests\UnitTestCase;
@ -372,11 +372,11 @@ class LinkGeneratorTest extends UnitTestCase {
), $result);
// Test that safe HTML is output inside the anchor tag unescaped. The
// SafeMarkup::set() call is an intentional unit test for the interaction
// between SafeMarkup and the LinkGenerator.
// SafeString::create() call is an intentional unit test for the interaction
// between SafeStringInterface and the LinkGenerator.
$url = new Url('test_route_5', array());
$url->setUrlGenerator($this->urlGenerator);
$result = $this->linkGenerator->generate(SafeMarkup::set('<em>HTML output</em>'), $url);
$result = $this->linkGenerator->generate(SafeString::create('<em>HTML output</em>'), $url);
$this->assertLink(array(
'attributes' => array('href' => '/test-route-5'),
'child' => array(

View file

@ -0,0 +1,165 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Listeners\DrupalStandardsListener.
*
* Listener for PHPUnit tests, to enforce various coding standards within test
* runs.
*/
namespace Drupal\Tests\Listeners;
/**
* Listens for PHPUnit tests and fails those with invalid coverage annotations.
*/
class DrupalStandardsListener extends \PHPUnit_Framework_BaseTestListener {
/**
* Signals a coding standards failure to the user.
*
* @param \PHPUnit_Framework_TestCase $test
* The test where we should insert our test failure.
* @param string $message
* The message to add to the failure notice. The test class name and test
* name will be appended to this message automatically.
*/
protected function fail(\PHPUnit_Framework_TestCase $test, $message) {
// Add the report to the test's results.
$message .= ': ' . get_class($test) . '::' . $test->getName();
$fail = new \PHPUnit_Framework_AssertionFailedError($message);
$result = $test->getTestResultObject();
$result->addFailure($test, $fail, 0);
}
/**
* Helper method to check if a string names a valid class or trait.
*
* @param string $class
* Name of the class to check.
*
* @return bool
* TRUE if the class exists, FALSE otherwise.
*/
protected function classExists($class) {
return class_exists($class, TRUE) || trait_exists($class, TRUE) || interface_exists($class, TRUE);
}
/**
* Check an individual test run for valid @covers annotation.
*
* This method is called from $this::endTest().
*
* @param \PHPUnit_Framework_TestCase $test
* The test to examine.
*/
public function checkValidCoversForTest(\PHPUnit_Framework_TestCase $test) {
// If we're generating a coverage report already, don't do anything here.
if ($test->getTestResultObject() && $test->getTestResultObject()->getCollectCodeCoverageInformation()) {
return;
}
// Gather our annotations.
$annotations = $test->getAnnotations();
// Glean the @coversDefaultClass annotation.
$default_class = '';
$valid_default_class = FALSE;
if (isset($annotations['class']['coversDefaultClass'])) {
if (count($annotations['class']['coversDefaultClass']) > 1) {
$this->fail($test, '@coversDefaultClass has too many values');
}
// Grab the first one.
$default_class = reset($annotations['class']['coversDefaultClass']);
// Check whether the default class exists.
$valid_default_class = $this->classExists($default_class);
if (!$valid_default_class) {
$this->fail($test, "@coversDefaultClass does not exist '$default_class'");
}
}
// Glean @covers annotation.
if (isset($annotations['method']['covers'])) {
// Drupal allows multiple @covers per test method, so we have to check
// them all.
foreach ($annotations['method']['covers'] as $covers) {
// Ensure the annotation isn't empty.
if (trim($covers) === '') {
$this->fail($test, '@covers should not be empty');
// If @covers is empty, we can't proceed.
return;
}
// Ensure we don't have ().
if (strpos($covers, '()') !== FALSE) {
$this->fail($test, "@covers invalid syntax: Do not use '()'");
}
// Glean the class and method from @covers.
$class = $covers;
$method = '';
if (strpos($covers, '::') !== FALSE) {
list($class, $method) = explode('::', $covers);
}
// Check for the existence of the class if it's specified by @covers.
if (!empty($class)) {
// If the class doesn't exist we have either a bad classname or
// are missing the :: for a method. Either way we can't proceed.
if (!$this->classExists($class)) {
if (empty($method)) {
$this->fail($test, "@covers invalid syntax: Needs '::' or class does not exist in $covers");
return;
}
else {
$this->fail($test, '@covers class does not exist ' . $class);
return;
}
}
}
else {
// The class isn't specified and we have the ::, so therefore this
// test either covers a function, or relies on a default class.
if (empty($default_class)) {
// If there's no default class, then we need to check if the global
// function exists. Since this listener should always be listening
// for endTest(), the function should have already been loaded from
// its .module or .inc file.
if (!function_exists($method)) {
$this->fail($test, '@covers global method does not exist ' . $method);
}
}
else {
// We have a default class and this annotation doesn't act like a
// global function, so we should use the default class if it's
// valid.
if ($valid_default_class) {
$class = $default_class;
}
}
}
// Finally, after all that, let's see if the method exists.
if (!empty($class) && !empty($method)) {
$ref_class = new \ReflectionClass($class);
if (!$ref_class->hasMethod($method)) {
$this->fail($test, '@covers method does not exist ' . $class . '::' . $method);
}
}
}
}
}
/**
* {@inheritdoc}
*/
public function endTest(\PHPUnit_Framework_Test $test, $time) {
// \PHPUnit_Framework_Test does not have any useful methods of its own for
// our purpose, so we have to distinguish between the different known
// subclasses.
if ($test instanceof \PHPUnit_Framework_TestCase) {
$this->checkValidCoversForTest($test);
}
elseif ($test instanceof \PHPUnit_Framework_TestSuite) {
foreach ($test->getGroupDetails() as $tests) {
foreach ($tests as $test) {
$this->endTest($test, $time);
}
}
}
}
}

View file

@ -0,0 +1,35 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Listeners\SafeMarkupSideEffects.
*
* Listener for PHPUnit tests, to enforce that data providers don't add to the
* SafeMarkup static safe string list.
*/
namespace Drupal\Tests\Listeners;
use Drupal\Component\Utility\SafeMarkup;
/**
* Listens for PHPUnit tests and fails those with SafeMarkup side effects.
*/
class SafeMarkupSideEffects extends \PHPUnit_Framework_BaseTestListener {
/**
* {@inheritdoc}
*/
public function startTestSuite(\PHPUnit_Framework_TestSuite $suite) {
// Use a static so we only do this test once after all the data providers
// have run.
static $tested = FALSE;
if ($suite->getName() !== '' && !$tested) {
$tested = TRUE;
if (!empty(SafeMarkup::getAll())) {
throw new \RuntimeException('SafeMarkup string list polluted by data providers');
}
}
}
}

View file

@ -48,6 +48,12 @@ abstract class UnitTestCase extends \PHPUnit_Framework_TestCase {
FileCacheFactory::setConfiguration(['default' => ['class' => '\Drupal\Component\FileCache\NullFileCache']]);
$this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
// Reset the static list of SafeStrings to prevent bleeding between tests.
$reflected_class = new \ReflectionClass('\Drupal\Component\Utility\SafeMarkup');
$reflected_property = $reflected_class->getProperty('safeStrings');
$reflected_property->setAccessible(true);
$reflected_property->setValue([]);
}
/**