Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663

This commit is contained in:
Greg Anderson 2015-10-08 11:40:12 -07:00
parent eb34d130a8
commit f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions

View file

@ -31,12 +31,36 @@ class InspectorTest extends PHPUnit_Framework_TestCase {
* Tests asserting all members are strings.
*
* @covers ::assertAllStrings
* @dataProvider providerTestAssertAllStrings
*/
public function testAssertAllStrings() {
$this->assertTrue(Inspector::assertAllStrings([]));
$this->assertTrue(Inspector::assertAllStrings(['foo', 'bar']));
$this->assertFalse(Inspector::assertAllStrings('foo'));
$this->assertFalse(Inspector::assertAllStrings(['foo', new StringObject()]));
public function testAssertAllStrings($input, $expected) {
$this->assertSame($expected, Inspector::assertAllStrings($input));
}
public function providerTestAssertAllStrings() {
$data = [
'empty-array' => [[], TRUE],
'array-with-strings' => [['foo', 'bar'], TRUE],
'string' => ['foo', FALSE],
'array-with-strings-with-colon' => [['foo', 'bar', 'llama:2001988', 'baz', 'llama:14031991'], TRUE],
'with-FALSE' => [[FALSE], FALSE],
'with-TRUE' => [[TRUE], FALSE],
'with-string-and-boolean' => [['foo', FALSE], FALSE],
'with-NULL' => [[NULL], FALSE],
'string-with-NULL' => [['foo', NULL], FALSE],
'integer' => [[1337], FALSE],
'string-and-integer' => [['foo', 1337], FALSE],
'double' => [[3.14], FALSE],
'string-and-double' => [['foo', 3.14], FALSE],
'array' => [[[]], FALSE],
'string-and-array' => [['foo', []], FALSE],
'string-and-nested-array' => [['foo', ['bar']], FALSE],
'object' => [[new \stdClass()], FALSE],
'string-and-object' => [['foo', new StringObject()], FALSE],
];
return $data;
}
/**

View file

@ -7,7 +7,11 @@
namespace Drupal\Tests\Component\Plugin;
use Drupal\Component\Plugin\Definition\PluginDefinitionInterface;
use Drupal\Component\Plugin\Factory\DefaultFactory;
use Drupal\plugin_test\Plugin\plugin_test\fruit\Cherry;
use Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface;
use Drupal\plugin_test\Plugin\plugin_test\fruit\Kale;
use Drupal\Tests\UnitTestCase;
/**
@ -17,41 +21,110 @@ use Drupal\Tests\UnitTestCase;
class DefaultFactoryTest extends UnitTestCase {
/**
* Tests getPluginClass() with a valid plugin.
* Tests getPluginClass() with a valid array plugin definition.
*
* @covers ::getPluginClass
*/
public function testGetPluginClassWithValidPlugin() {
$plugin_class = 'Drupal\plugin_test\Plugin\plugin_test\fruit\Cherry';
public function testGetPluginClassWithValidArrayPluginDefinition() {
$plugin_class = Cherry::class;
$class = DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class]);
$this->assertEquals($plugin_class, $class);
}
/**
* Tests getPluginClass() with a valid object plugin definition.
*
* @covers ::getPluginClass
*/
public function testGetPluginClassWithValidObjectPluginDefinition() {
$plugin_class = Cherry::class;
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
$plugin_definition->expects($this->atLeastOnce())
->method('getClass')
->willReturn($plugin_class);
$class = DefaultFactory::getPluginClass('cherry', $plugin_definition);
$this->assertEquals($plugin_class, $class);
}
/**
* Tests getPluginClass() with a missing class definition.
*
* @covers ::getPluginClass
*
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
* @expectedExceptionMessage The plugin (cherry) did not specify an instance class.
*/
public function testGetPluginClassWithMissingClass() {
public function testGetPluginClassWithMissingClassWithArrayPluginDefinition() {
DefaultFactory::getPluginClass('cherry', []);
}
/**
* Tests getPluginClass() with a missing class definition.
*
* @covers ::getPluginClass
*
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
* @expectedExceptionMessage The plugin (cherry) did not specify an instance class.
*/
public function testGetPluginClassWithMissingClassWithObjectPluginDefinition() {
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
DefaultFactory::getPluginClass('cherry', $plugin_definition);
}
/**
* Tests getPluginClass() with a not existing class definition.
*
* @covers ::getPluginClass
*
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
* @expectedExceptionMessage Plugin (kiwifruit) instance class "\Drupal\plugin_test\Plugin\plugin_test\fruit\Kiwifruit" does not exist.
*/
public function testGetPluginClassWithNotExistingClass() {
public function testGetPluginClassWithNotExistingClassWithArrayPluginDefinition() {
DefaultFactory::getPluginClass('kiwifruit', ['class' => '\Drupal\plugin_test\Plugin\plugin_test\fruit\Kiwifruit']);
}
/**
* Tests getPluginClass() with a required interface.
* Tests getPluginClass() with a not existing class definition.
*
* @covers ::getPluginClass
*
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
*/
public function testGetPluginClassWithInterface() {
$plugin_class = 'Drupal\plugin_test\Plugin\plugin_test\fruit\Cherry';
$class = DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class], '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
public function testGetPluginClassWithNotExistingClassWithObjectPluginDefinition() {
$plugin_class = '\Drupal\plugin_test\Plugin\plugin_test\fruit\Kiwifruit';
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
$plugin_definition->expects($this->atLeastOnce())
->method('getClass')
->willReturn($plugin_class);
DefaultFactory::getPluginClass('kiwifruit', $plugin_definition);
}
/**
* Tests getPluginClass() with a required interface.
*
* @covers ::getPluginClass
*/
public function testGetPluginClassWithInterfaceWithArrayPluginDefinition() {
$plugin_class = Cherry::class;
$class = DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class], FruitInterface::class);
$this->assertEquals($plugin_class, $class);
}
/**
* Tests getPluginClass() with a required interface.
*
* @covers ::getPluginClass
*/
public function testGetPluginClassWithInterfaceWithObjectPluginDefinition() {
$plugin_class = Cherry::class;
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
$plugin_definition->expects($this->atLeastOnce())
->method('getClass')
->willReturn($plugin_class);
$class = DefaultFactory::getPluginClass('cherry', $plugin_definition, FruitInterface::class);
$this->assertEquals($plugin_class, $class);
}
@ -59,12 +132,30 @@ class DefaultFactoryTest extends UnitTestCase {
/**
* Tests getPluginClass() with a required interface but no implementation.
*
* @covers ::getPluginClass
*
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
* @expectedExceptionMessage Plugin "cherry" (Drupal\plugin_test\Plugin\plugin_test\fruit\Kale) must implement interface \Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface.
* @expectedExceptionMessage Plugin "cherry" (Drupal\plugin_test\Plugin\plugin_test\fruit\Kale) must implement interface Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface.
*/
public function testGetPluginClassWithInterfaceAndInvalidClass() {
$plugin_class = 'Drupal\plugin_test\Plugin\plugin_test\fruit\Kale';
DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class, 'provider' => 'core'], '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
public function testGetPluginClassWithInterfaceAndInvalidClassWithArrayPluginDefinition() {
$plugin_class = Kale::class;
DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class, 'provider' => 'core'], FruitInterface::class);
}
/**
* Tests getPluginClass() with a required interface but no implementation.
*
* @covers ::getPluginClass
*
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
*/
public function testGetPluginClassWithInterfaceAndInvalidClassWithObjectPluginDefinition() {
$plugin_class = Kale::class;
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
$plugin_definition->expects($this->atLeastOnce())
->method('getClass')
->willReturn($plugin_class);
DefaultFactory::getPluginClass('cherry', $plugin_definition, FruitInterface::class);
}
}

View file

@ -0,0 +1,43 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Component\Render\FormattableMarkupTest.
*/
namespace Drupal\Tests\Component\Render;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Tests\UnitTestCase;
/**
* Tests the TranslatableMarkup class.
*
* @coversDefaultClass \Drupal\Component\Render\FormattableMarkup
* @group utility
*/
class FormattableMarkupTest extends UnitTestCase {
/**
* @covers ::__toString
* @covers ::jsonSerialize
*/
public function testToString() {
$string = 'Can I please have a @replacement';
$formattable_string = new FormattableMarkup($string, ['@replacement' => 'kitten']);
$text = (string) $formattable_string;
$this->assertEquals('Can I please have a kitten', $text);
$text = $formattable_string->jsonSerialize();
$this->assertEquals('Can I please have a kitten', $text);
}
/**
* @covers ::count
*/
public function testCount() {
$string = 'Can I please have a @replacement';
$formattable_string = new FormattableMarkup($string, ['@replacement' => 'kitten']);
$this->assertEquals(strlen($string), $formattable_string->count());
}
}

View file

@ -0,0 +1,69 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Component\Render\HtmlEscapedTextTest.
*/
namespace Drupal\Tests\Component\Render;
use Drupal\Component\Render\HtmlEscapedText;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Tests\UnitTestCase;
/**
* Tests the HtmlEscapedText class.
*
* @coversDefaultClass \Drupal\Component\Render\HtmlEscapedText
* @group utility
*/
class HtmlEscapedTextTest extends UnitTestCase {
/**
* @covers ::__toString
* @covers ::jsonSerialize
*
* @dataProvider providerToString
*/
public function testToString($text, $expected, $message) {
$escapeable_string = new HtmlEscapedText($text);
$this->assertEquals($expected, (string) $escapeable_string, $message);
$this->assertEquals($expected, $escapeable_string->jsonSerialize());
}
/**
* Data provider for testToString().
*
* @see testToString()
*/
function providerToString() {
// Checks that invalid multi-byte sequences are escaped.
$tests[] = array("Foo\xC0barbaz", 'Foo<6F>barbaz', 'Escapes invalid sequence "Foo\xC0barbaz"');
$tests[] = array("\xc2\"", '<27>&quot;', 'Escapes invalid sequence "\xc2\""');
$tests[] = array("Fooÿñ", "Fooÿñ", 'Does not escape valid sequence "Fooÿñ"');
// Checks that special characters are escaped.
$script_tag = $this->prophesize(MarkupInterface::class);
$script_tag->__toString()->willReturn('<script>');
$script_tag = $script_tag->reveal();
$tests[] = array($script_tag, '&lt;script&gt;', 'Escapes &lt;script&gt; even inside an object that implements MarkupInterface.');
$tests[] = array("<script>", '&lt;script&gt;', 'Escapes &lt;script&gt;');
$tests[] = array('<>&"\'', '&lt;&gt;&amp;&quot;&#039;', 'Escapes reserved HTML characters.');
$specialchars = $this->prophesize(MarkupInterface::class);
$specialchars->__toString()->willReturn('<>&"\'');
$specialchars = $specialchars->reveal();
$tests[] = array($specialchars, '&lt;&gt;&amp;&quot;&#039;', 'Escapes reserved HTML characters even inside an object that implements MarkupInterface.');
return $tests;
}
/**
* @covers ::count
*/
public function testCount() {
$string = 'Can I please have a <em>kitten</em>';
$escapeable_string = new HtmlEscapedText($string);
$this->assertEquals(strlen($string), $escapeable_string->count());
}
}

View file

@ -0,0 +1,68 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Component\Render\PlainTextOutputTest.
*/
namespace Drupal\Tests\Component\Render;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Component\Render\PlainTextOutput
* @group Utility
*/
class PlainTextOutputTest extends UnitTestCase {
/**
* Tests ::renderFromHtml().
*
* @param $expected
* The expected formatted value.
* @param $string
* A string to be formatted.
* @param array $args
* (optional) An associative array of replacements to make. Defaults to
* none.
*
* @covers ::renderFromHtml
* @dataProvider providerRenderFromHtml
*/
public function testRenderFromHtml($expected, $string, $args = []) {
$markup = SafeMarkup::format($string, $args);
$output = PlainTextOutput::renderFromHtml($markup);
$this->assertSame($expected, $output);
}
/**
* Data provider for ::testRenderFromHtml()
*/
public function providerRenderFromHtml() {
$data = [];
$data['simple-text'] = ['Giraffes and wombats', 'Giraffes and wombats'];
$data['simple-html'] = ['Giraffes and wombats', '<a href="/muh">Giraffes</a> and <strong>wombats</strong>'];
$data['html-with-quote'] = ['Giraffes and quote"s', '<a href="/muh">Giraffes</a> and <strong>quote"s</strong>'];
$expected = 'The <em> tag makes your text look like "this".';
$string = 'The &lt;em&gt; tag makes your text look like <em>"this"</em>.';
$data['escaped-html-with-quotes'] = [$expected, $string];
$safe_string = $this->prophesize(MarkupInterface::class);
$safe_string->__toString()->willReturn('<em>"this"</em>');
$safe_string = $safe_string->reveal();
$data['escaped-html-with-quotes-and-placeholders'] = [$expected, 'The @tag tag makes your text look like @result.', ['@tag' =>'<em>', '@result' => $safe_string]];
$safe_string = $this->prophesize(MarkupInterface::class);
$safe_string->__toString()->willReturn($string);
$safe_string = $safe_string->reveal();
$data['safe-string'] = [$expected, $safe_string];
return $data;
}
}

View file

@ -79,7 +79,9 @@ class HtmlTest extends UnitTestCase {
// replaced.
array('__cssidentifier', '-1cssidentifier', array()),
// Verify that an identifier starting with two hyphens is replaced.
array('__cssidentifier', '--cssidentifier', array())
array('__cssidentifier', '--cssidentifier', array()),
// Verify that passing double underscores as a filter is processed.
array('_cssidentifier', '__cssidentifier', array('__' => '_')),
);
}
@ -231,7 +233,7 @@ class HtmlTest extends UnitTestCase {
/**
* Data provider for testDecodeEntities().
*
* @see testCheckPlain()
* @see testDecodeEntities()
*/
public function providerDecodeEntities() {
return array(
@ -272,7 +274,7 @@ class HtmlTest extends UnitTestCase {
/**
* Data provider for testEscape().
*
* @see testCheckPlain()
* @see testEscape()
*/
public function providerEscape() {
return array(
@ -310,4 +312,17 @@ class HtmlTest extends UnitTestCase {
$this->assertSame('&lt;em&gt;répété&lt;/em&gt;', $escaped);
}
}
/**
* Tests Html::serialize().
*
* Resolves an issue by where an empty DOMDocument object sent to serialization would
* cause errors in getElementsByTagName() in the serialization function.
*
* @covers ::serialize
*/
public function testSerialize() {
$document = new \DOMDocument();
$result = Html::serialize($document);
$this->assertSame('', $result);
}
}

View file

@ -7,9 +7,11 @@
namespace Drupal\Tests\Component\Utility;
use Drupal\Component\Render\HtmlEscapedText;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\SafeStringInterface;
use Drupal\Component\Utility\SafeStringTrait;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Render\MarkupTrait;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Tests\UnitTestCase;
/**
@ -21,81 +23,12 @@ use Drupal\Tests\UnitTestCase;
class SafeMarkupTest extends UnitTestCase {
/**
* Helper function to add a string to the safe list for testing.
*
* @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.
*
* @return string
* The input string that was marked as safe.
* {@inheritdoc}
*/
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;
}
protected function tearDown() {
parent::tearDown();
/**
* 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().
*/
public function providerSet() {
// 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::setMultiple().
* @dataProvider providerSet
*
* @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 testSet($text, $message) {
SafeMarkup::setMultiple([$text => ['html' => TRUE]]);
$this->assertTrue(SafeMarkup::isSafe($text), $message);
UrlHelper::setAllowedProtocols(['http', 'https']);
}
/**
@ -104,44 +37,12 @@ class SafeMarkupTest extends UnitTestCase {
* @covers ::isSafe
*/
public function testIsSafe() {
$safe_string = $this->getMock('\Drupal\Component\Utility\SafeStringInterface');
$safe_string = $this->getMock('\Drupal\Component\Render\MarkupInterface');
$this->assertTrue(SafeMarkup::isSafe($safe_string));
$string_object = new SafeMarkupTestString('test');
$this->assertFalse(SafeMarkup::isSafe($string_object));
}
/**
* Tests SafeMarkup::setMultiple().
*
* @covers ::setMultiple
*/
public function testSetMultiple() {
$texts = array(
'multistring0' => array('html' => TRUE),
'multistring1' => array('all' => TRUE),
);
SafeMarkup::setMultiple($texts);
foreach ($texts as $string => $providers) {
$this->assertTrue(SafeMarkup::isSafe($string), 'The value has been marked as safe for html');
}
}
/**
* Tests SafeMarkup::setMultiple().
*
* Only TRUE may be passed in as the value.
*
* @covers ::setMultiple
*
* @expectedException \UnexpectedValueException
*/
public function testInvalidSetMultiple() {
$texts = array(
'invalidstring0' => array('html' => 1),
);
SafeMarkup::setMultiple($texts);
}
/**
* Tests SafeMarkup::checkPlain().
*
@ -154,28 +55,49 @@ class SafeMarkupTest extends UnitTestCase {
* The expected output from the function.
* @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.
*/
function testCheckPlain($text, $expected, $message, $ignorewarnings = FALSE) {
$result = $ignorewarnings ? @SafeMarkup::checkPlain($text) : SafeMarkup::checkPlain($text);
function testCheckPlain($text, $expected, $message) {
$result = SafeMarkup::checkPlain($text);
$this->assertTrue($result instanceof HtmlEscapedText);
$this->assertEquals($expected, $result, $message);
}
/**
* Data provider for testCheckPlain().
* Tests Drupal\Component\Render\HtmlEscapedText.
*
* Verifies that the result of SafeMarkup::checkPlain() is the same as using
* HtmlEscapedText directly.
*
* @dataProvider providerCheckPlain
*
* @param string $text
* The text to provide to the HtmlEscapedText constructor.
* @param string $expected
* The expected output from the function.
* @param string $message
* The message to provide as output for the test.
*/
function testHtmlEscapedText($text, $expected, $message) {
$result = new HtmlEscapedText($text);
$this->assertEquals($expected, $result, $message);
}
/**
* Data provider for testCheckPlain() and testEscapeString().
*
* @see testCheckPlain()
*/
function providerCheckPlain() {
// Checks that invalid multi-byte sequences are escaped.
$tests[] = array("Foo\xC0barbaz", 'Foo<6F>barbaz', 'SafeMarkup::checkPlain() escapes invalid sequence "Foo\xC0barbaz"', TRUE);
$tests[] = array("\xc2\"", '<27>&quot;', 'SafeMarkup::checkPlain() escapes invalid sequence "\xc2\""', TRUE);
$tests[] = array("Fooÿñ", "Fooÿñ", 'SafeMarkup::checkPlain() does not escape valid sequence "Fooÿñ"');
$tests[] = array("Foo\xC0barbaz", 'Foo<6F>barbaz', 'Escapes invalid sequence "Foo\xC0barbaz"');
$tests[] = array("\xc2\"", '<27>&quot;', 'Escapes invalid sequence "\xc2\""');
$tests[] = array("Fooÿñ", "Fooÿñ", 'Does not escape valid sequence "Fooÿñ"');
// Checks that special characters are escaped.
$tests[] = array("<script>", '&lt;script&gt;', 'SafeMarkup::checkPlain() escapes &lt;script&gt;');
$tests[] = array('<>&"\'', '&lt;&gt;&amp;&quot;&#039;', 'SafeMarkup::checkPlain() escapes reserved HTML characters.');
$tests[] = array(SafeMarkupTestMarkup::create("<script>"), '&lt;script&gt;', 'Escapes &lt;script&gt; even inside an object that implements MarkupInterface.');
$tests[] = array("<script>", '&lt;script&gt;', 'Escapes &lt;script&gt;');
$tests[] = array('<>&"\'', '&lt;&gt;&amp;&quot;&#039;', 'Escapes reserved HTML characters.');
$tests[] = array(SafeMarkupTestMarkup::create('<>&"\''), '&lt;&gt;&amp;&quot;&#039;', 'Escapes reserved HTML characters even inside an object that implements MarkupInterface.');
return $tests;
}
@ -198,12 +120,14 @@ class SafeMarkupTest extends UnitTestCase {
* Whether the result is expected to be safe for HTML display.
*/
public function testFormat($string, array $args, $expected, $message, $expected_is_safe) {
UrlHelper::setAllowedProtocols(['http', 'https', 'mailto']);
$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));
$this->assertSame($arg instanceof SafeMarkupTestMarkup, SafeMarkup::isSafe($arg));
}
}
@ -215,11 +139,23 @@ 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' => SafeMarkupTestSafeString::create('<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' => SafeMarkupTestMarkup::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' => 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' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Verbatim text: <span>Safe HTML</span>', 'SafeMarkup::format replaces verbatim string as-is.', TRUE);
$tests[] = array('Placeholder text: %value', array('%value' => SafeMarkupTestMarkup::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['javascript-protocol-url'] = ['Simple text <a href=":url">giraffe</a>', [':url' => 'javascript://example.com?foo&bar'], 'Simple text <a href="//example.com?foo&amp;bar">giraffe</a>', 'Support for filtering bad protocols', TRUE];
$tests['external-url'] = ['Simple text <a href=":url">giraffe</a>', [':url' => 'http://example.com?foo&bar'], 'Simple text <a href="http://example.com?foo&amp;bar">giraffe</a>', 'Support for filtering bad protocols', TRUE];
$tests['relative-url'] = ['Simple text <a href=":url">giraffe</a>', [':url' => '/node/1?foo&bar'], 'Simple text <a href="/node/1?foo&amp;bar">giraffe</a>', 'Support for filtering bad protocols', TRUE];
$tests['fragment-with-special-chars'] = ['Simple text <a href=":url">giraffe</a>', [':url' => 'http://example.com/#&lt;'], 'Simple text <a href="http://example.com/#&amp;lt;">giraffe</a>', 'Support for filtering bad protocols', TRUE];
$tests['mailto-protocol'] = ['Hey giraffe <a href=":url">MUUUH</a>', [':url' => 'mailto:test@example.com'], 'Hey giraffe <a href="mailto:test@example.com">MUUUH</a>', '', TRUE];
$tests['js-with-fromCharCode'] = ['Hey giraffe <a href=":url">MUUUH</a>', [':url' => "javascript:alert(String.fromCharCode(88,83,83))"], 'Hey giraffe <a href="alert(String.fromCharCode(88,83,83))">MUUUH</a>', '', TRUE];
// Test some "URL" values that are not RFC 3986 compliant URLs. The result
// of SafeMarkup::format() should still be valid HTML (other than the
// value of the "href" attribute not being a valid URL), and not
// vulnerable to XSS.
$tests['non-url-with-colon'] = ['Hey giraffe <a href=":url">MUUUH</a>', [':url' => "llamas: they are not URLs"], 'Hey giraffe <a href=" they are not URLs">MUUUH</a>', '', TRUE];
$tests['non-url-with-html'] = ['Hey giraffe <a href=":url">MUUUH</a>', [':url' => "<span>not a url</span>"], 'Hey giraffe <a href="&lt;span&gt;not a url&lt;/span&gt;">MUUUH</a>', '', TRUE];
return $tests;
}
@ -241,11 +177,8 @@ 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.
* Marks an object's __toString() method as returning markup.
*/
class SafeMarkupTestSafeString implements SafeStringInterface {
use SafeStringTrait;
class SafeMarkupTestMarkup implements MarkupInterface {
use MarkupTrait;
}

View file

@ -291,6 +291,7 @@ class UnicodeTest extends UnitTestCase {
return array(
array('tHe QUIcK bRoWn', 15),
array('ÜBER-åwesome', 12),
array('以呂波耳・ほへとち。リヌルヲ。', 15),
);
}
@ -529,4 +530,46 @@ class UnicodeTest extends UnitTestCase {
);
}
/**
* Tests multibyte strpos.
*
* @dataProvider providerStrpos
* @covers ::strpos
*/
public function testStrpos($haystack, $needle, $offset, $expected) {
// Run through multibyte code path.
Unicode::setStatus(Unicode::STATUS_MULTIBYTE);
$this->assertEquals($expected, Unicode::strpos($haystack, $needle, $offset));
// Run through singlebyte code path.
Unicode::setStatus(Unicode::STATUS_SINGLEBYTE);
$this->assertEquals($expected, Unicode::strpos($haystack, $needle, $offset));
}
/**
* Data provider for testStrpos().
*
* @see testStrpos()
*
* @return array
* An array containing:
* - The haystack string to be searched in.
* - The needle string to search for.
* - The offset integer to start at.
* - The expected integer/FALSE result.
*/
public function providerStrpos() {
return array(
array('frànçAIS is über-åwesome', 'frànçAIS is über-åwesome', 0, 0),
array('frànçAIS is über-åwesome', 'rànçAIS is über-åwesome', 0, 1),
array('frànçAIS is über-åwesome', 'not in string', 0, FALSE),
array('frànçAIS is über-åwesome', 'r', 0, 1),
array('frànçAIS is über-åwesome', 'nçAIS', 0, 3),
array('frànçAIS is über-åwesome', 'nçAIS', 2, 3),
array('frànçAIS is über-åwesome', 'nçAIS', 3, 3),
array('以呂波耳・ほへとち。リヌルヲ。', '波耳', 0, 2),
array('以呂波耳・ほへとち。リヌルヲ。', '波耳', 1, 2),
array('以呂波耳・ほへとち。リヌルヲ。', '波耳', 2, 2),
);
}
}