Update to Drupal 8.0.0 beta 14. For more information, see https://drupal.org/node/2544542

This commit is contained in:
Pantheon Automation 2015-08-27 12:03:05 -07:00 committed by Greg Anderson
parent 3b2511d96d
commit 81ccda77eb
2155 changed files with 54307 additions and 46870 deletions

View file

@ -0,0 +1,21 @@
id: d6_simpletest_settings
label: Drupal 6 simpletest configuration
migration_tags:
- Drupal 6
source:
plugin: variable
variables:
- simpletest_clear_results
- simpletest_httpauth_method
- simpletest_httpauth_password
- simpletest_httpauth_username
- simpletest_verbose
process:
clear_results: simpletest_clear_results
'httpauth/method': simpletest_httpauth_method
'httpauth/password': simpletest_httpauth_password
'httpauth/username': simpletest_httpauth_username
verbose: simpletest_verbose
destination:
plugin: config
config_name: simpletest.settings

View file

@ -487,41 +487,47 @@ function simpletest_classloader_register() {
}
/**
* Generates test file.
* Generates a test file.
*
* @param string $filename
* The name of the file, including the path.
* The name of the file, including the path. The suffix '.txt' is appended to
* the supplied file name and the file is put into the public:// files
* directory.
* @param int $width
* The number of characters on one line.
* @param int $lines
* The number of lines in the file.
* @param string $type
* (optional) The type, for example: "text", "binary", or "binary-text".
* (optional) The type, one of:
* - text: The generated file contains random ASCII characters.
* - binary: The generated file contains random characters whose codes are in
* the range of 0 to 31.
* - binary-text: The generated file contains random sequence of '0' and '1'
* values.
*
* @return string
* The name of the file, including the path.
*/
function simpletest_generate_file($filename, $width, $lines, $type = 'binary-text') {
$size = $width * $lines - $lines;
// Generate random text
$text = '';
for ($i = 0; $i < $size; $i++) {
switch ($type) {
case 'text':
$text .= chr(rand(32, 126));
break;
case 'binary':
$text .= chr(rand(0, 31));
break;
case 'binary-text':
default:
$text .= rand(0, 1);
break;
for ($i = 0; $i < $lines; $i++) {
// Generate $width - 1 characters to leave space for the "\n" character.
for ($j = 0; $j < $width - 1; $j++) {
switch ($type) {
case 'text':
$text .= chr(rand(32, 126));
break;
case 'binary':
$text .= chr(rand(0, 31));
break;
case 'binary-text':
default:
$text .= rand(0, 1);
break;
}
}
$text .= "\n";
}
}
// Add \n for symmetrical file.
$text = wordwrap($text, $width - 1, "\n", TRUE) . "\n";
// Create filename.
file_put_contents('public://' . $filename . '.txt', $text);

View file

@ -10,6 +10,7 @@ namespace Drupal\simpletest;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Render\RenderContext;
use Symfony\Component\CssSelector\CssSelector;
/**
@ -397,7 +398,7 @@ trait AssertContentTrait {
if (!$message) {
$message = SafeMarkup::format('Raw "@raw" found', array('@raw' => $raw));
}
return $this->assert(strpos($this->getRawContent(), $raw) !== FALSE, $message, $group);
return $this->assert(strpos($this->getRawContent(), (string) $raw) !== FALSE, $message, $group);
}
/**
@ -424,7 +425,7 @@ trait AssertContentTrait {
if (!$message) {
$message = SafeMarkup::format('Raw "@raw" not found', array('@raw' => $raw));
}
return $this->assert(strpos($this->getRawContent(), $raw) === FALSE, $message, $group);
return $this->assert(strpos($this->getRawContent(), (string) $raw) === FALSE, $message, $group);
}
/**
@ -808,7 +809,12 @@ trait AssertContentTrait {
* TRUE on pass, FALSE on fail.
*/
protected function assertThemeOutput($callback, array $variables = array(), $expected = '', $message = '', $group = 'Other') {
$output = \Drupal::theme()->render($callback, $variables);
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$output = $renderer->executeInRenderContext(new RenderContext(), function() use ($callback, $variables) {
return \Drupal::theme()->render($callback, $variables);
});
$this->verbose(
'<hr />' . 'Result:' . '<pre>' . SafeMarkup::checkPlain(var_export($output, TRUE)) . '</pre>'
. '<hr />' . 'Expected:' . '<pre>' . SafeMarkup::checkPlain(var_export($expected, TRUE)) . '</pre>'

View file

@ -950,7 +950,7 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
// Reset/rebuild all data structures after enabling the modules, primarily
// to synchronize all data structures and caches between the test runner and
// the child site.
// Affects e.g. file_get_stream_wrappers().
// Affects e.g. StreamWrapperManagerInterface::getWrappers().
// @see \Drupal\Core\DrupalKernel::bootCode()
// @todo Test-specific setUp() methods may set up further fixtures; find a
// way to execute this after setUp() is done, or to eliminate it entirely.

View file

@ -313,7 +313,7 @@ class SimpletestResultsForm extends FormBase {
$rows = array();
foreach ($assertions as $assertion) {
$row = array();
$row[] = SafeMarkup::checkAdminXss($assertion->message);
$row[] = ['data' => ['#markup' => $assertion->message]];
$row[] = $assertion->message_group;
$row[] = \Drupal::service('file_system')->basename(($assertion->file));
$row[] = $assertion->line;

View file

@ -127,8 +127,8 @@ class SimpletestTestForm extends FormBase {
'#suffix' => '<a href="#" class="simpletest-collapse">(' . $this->t('Collapse') . ')</a>',
);
$form['tests']['#attached']['drupalSettings']['simpleTest']['images'] = [
$this->renderer->renderPlain($image_collapsed),
$this->renderer->renderPlain($image_extended),
(string) $this->renderer->renderPlain($image_collapsed),
(string) $this->renderer->renderPlain($image_extended),
];
// Generate the list of tests arranged by group.

View file

@ -381,9 +381,7 @@ EOD;
protected function installConfig(array $modules) {
foreach ($modules as $module) {
if (!$this->container->get('module_handler')->moduleExists($module)) {
throw new \RuntimeException(format_string("'@module' module is not enabled.", array(
'@module' => $module,
)));
throw new \RuntimeException("'$module' module is not enabled");
}
\Drupal::service('config.installer')->installDefaultConfig('module', $module);
}
@ -411,18 +409,13 @@ EOD;
// behavior and non-reproducible test failures, we only allow the schema of
// explicitly loaded/enabled modules to be installed.
if (!$this->container->get('module_handler')->moduleExists($module)) {
throw new \RuntimeException(format_string("'@module' module is not enabled.", array(
'@module' => $module,
)));
throw new \RuntimeException("'$module' module is not enabled");
}
$tables = (array) $tables;
foreach ($tables as $table) {
$schema = drupal_get_module_schema($module, $table);
if (empty($schema)) {
throw new \RuntimeException(format_string("Unknown '@table' table schema in '@module' module.", array(
'@module' => $module,
'@table' => $table,
)));
throw new \RuntimeException("Unknown '$table' table schema in '$module' module.");
}
$this->container->get('database')->schema()->createTable($table, $schema);
}

View file

@ -1423,9 +1423,9 @@ abstract class TestBase {
* Do not use this method when special characters are not possible (e.g., in
* machine or file names that have already been validated); instead, use
* \Drupal\simpletest\TestBase::randomMachineName(). If $length is greater
* than 2 the random string will include at least one ampersand ('&')
* character to ensure coverage for special characters and avoid the
* introduction of random test failures.
* than 3 the random string will include at least one ampersand ('&') and
* at least one greater than ('>') character to ensure coverage for special
* characters and avoid the introduction of random test failures.
*
* @param int $length
* Length of random string to generate.
@ -1436,7 +1436,7 @@ abstract class TestBase {
* @see \Drupal\Component\Utility\Random::string()
*/
public function randomString($length = 8) {
if ($length < 3) {
if ($length < 4) {
return $this->getRandomGenerator()->string($length, TRUE, array($this, 'randomStringValidate'));
}
@ -1444,9 +1444,10 @@ abstract class TestBase {
// returned string contains a character that needs to be escaped in HTML by
// injecting an ampersand into it.
$replacement_pos = floor($length / 2);
// Remove 1 from the length to account for the ampersand character.
$string = $this->getRandomGenerator()->string($length - 1, TRUE, array($this, 'randomStringValidate'));
return substr_replace($string, '&', $replacement_pos, 0);
// Remove 2 from the length to account for the ampersand and greater than
// characters.
$string = $this->getRandomGenerator()->string($length - 2, TRUE, array($this, 'randomStringValidate'));
return substr_replace($string, '>&', $replacement_pos, 0);
}
/**

View file

@ -0,0 +1,55 @@
<?php
/**
* @file
* Contains \Drupal\simpletest\Tests\Migrate\d6\MigrateSimpletestConfigsTest.
*/
namespace Drupal\simpletest\Tests\Migrate\d6;
use Drupal\config\Tests\SchemaCheckTestTrait;
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
/**
* Upgrade variables to simpletest.settings.yml.
*
* @group simpletest
*/
class MigrateSimpletestConfigsTest extends MigrateDrupal6TestBase {
use SchemaCheckTestTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('simpletest');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['simpletest']);
$this->loadDumps(['Variable.php']);
$this->executeMigration('d6_simpletest_settings');
}
/**
* Tests migration of simpletest variables to simpletest.settings.yml.
*/
public function testSimpletestSettings() {
$config = $this->config('simpletest.settings');
$this->assertIdentical(TRUE, $config->get('clear_results'));
$this->assertIdentical(CURLAUTH_BASIC, $config->get('httpauth.method'));
// NULL in the dump means defaults which is empty string. Same as omitting
// them.
$this->assertIdentical('', $config->get('httpauth.password'));
$this->assertIdentical('', $config->get('httpauth.username'));
$this->assertIdentical(TRUE, $config->get('verbose'));
$this->assertConfigSchema(\Drupal::service('config.typed'), 'simpletest.settings', $config->get());
}
}

View file

@ -124,6 +124,8 @@ class SimpleTestBrowserTest extends WebTestBase {
* Tests that PHPUnit and KernelTestBase tests work through the UI.
*/
public function testTestingThroughUI() {
$this->drupalGet('admin/config/development/testing');
$this->assertTrue(strpos($this->drupalSettings['simpleTest']['images'][0], 'core/misc/menu-collapsed.png') > 0, 'drupalSettings contains a link to core/misc/menu-collapsed.png.');
// We can not test WebTestBase tests here since they require a valid .htkey
// to be created. However this scenario is covered by the testception of
// \Drupal\simpletest\Tests\SimpleTestTest.

View file

@ -157,7 +157,7 @@ EOD;
// request. This allows the stub test to make requests. The event does not
// fire here and drupal_generate_test_ua() can not generate a key for a
// test in a test since the prefix has changed.
// @see \Drupal\Core\Test\EventSubscriber\HttpRequestSubscriber::onBeforeSendRequest()
// @see \Drupal\Core\Test\HttpClientMiddleware\TestHttpClientMiddleware::onBeforeSendRequest()
// @see drupal_generate_test_ua();
$key_file = DRUPAL_ROOT . '/sites/simpletest/' . substr($this->databasePrefix, 10) . '/.htkey';
$private_key = Crypt::randomBytesBase64(55);

View file

@ -32,6 +32,7 @@ use Drupal\Core\Url;
use Drupal\node\Entity\NodeType;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Zend\Diactoros\Uri;
/**
* Test case for typical Drupal tests.
@ -457,16 +458,37 @@ abstract class WebTestBase extends TestBase {
}
/**
* Gets a list files that can be used in tests.
* Gets a list of files that can be used in tests.
*
* The first time this method is called, it will call
* simpletest_generate_file() to generate binary and ASCII text files in the
* public:// directory. It will also copy all files in
* core/modules/simpletest/files to public://. These contain image, SQL, PHP,
* JavaScript, and HTML files.
*
* All filenames are prefixed with their type and have appropriate extensions:
* - text-*.txt
* - binary-*.txt
* - html-*.html and html-*.txt
* - image-*.png, image-*.jpg, and image-*.gif
* - javascript-*.txt and javascript-*.script
* - php-*.txt and php-*.php
* - sql-*.txt and sql-*.sql
*
* Any subsequent calls will not generate any new files, or copy the files
* over again. However, if a test class adds a new file to public:// that
* is prefixed with one of the above types, it will get returned as well, even
* on subsequent calls.
*
* @param $type
* File type, possible values: 'binary', 'html', 'image', 'javascript',
* 'php', 'sql', 'text'.
* @param $size
* File size in bytes to match. Please check the tests/files folder.
* (optional) File size in bytes to match. Defaults to NULL, which will not
* filter the returned list by size.
*
* @return
* List of files that match filter.
* List of files in public:// that match the filter(s).
*/
protected function drupalGetTestFiles($type, $size = NULL) {
if (empty($this->generatedTestFiles)) {
@ -477,11 +499,11 @@ abstract class WebTestBase extends TestBase {
simpletest_generate_file('binary-' . $count++, 64, $line, 'binary');
}
// Generate text test files.
// Generate ASCII text test files.
$lines = array(16, 256, 1024, 2048, 20480);
$count = 0;
foreach ($lines as $line) {
simpletest_generate_file('text-' . $count++, 64, $line);
simpletest_generate_file('text-' . $count++, 64, $line, 'text');
}
// Copy other test files from simpletest.
@ -1533,7 +1555,15 @@ abstract class WebTestBase extends TestBase {
if (!isset($options['query'][MainContentViewSubscriber::WRAPPER_FORMAT])) {
$options['query'][MainContentViewSubscriber::WRAPPER_FORMAT] = 'drupal_ajax';
}
return Json::decode($this->drupalGet($path, $options, $headers));
return Json::decode($this->drupalGetXHR($path, $options, $headers));
}
/**
* Requests a Drupal path as if it is a XMLHttpRequest.
*/
protected function drupalGetXHR($path, array $options = array(), array $headers = array()) {
$headers[] = 'X-Requested-With: XMLHttpRequest';
return $this->drupalGet($path, $options, $headers);
}
/**
@ -1591,17 +1621,14 @@ abstract class WebTestBase extends TestBase {
*
* This function can also be called to emulate an Ajax submission. In this
* case, this value needs to be an array with the following keys:
* - path: A path to submit the form values to for Ajax-specific processing,
* which is likely different than the $path parameter used for retrieving
* the initial form. Defaults to 'system/ajax'.
* - triggering_element: If the value for the 'path' key is 'system/ajax' or
* another generic Ajax processing path, this needs to be set to the name
* of the element. If the name doesn't identify the element uniquely, then
* this should instead be an array with a single key/value pair,
* corresponding to the element name and value. The callback for the
* generic Ajax processing path uses this to find the #ajax information
* for the element, including which specific callback to use for
* processing the request.
* - path: A path to submit the form values to for Ajax-specific processing.
* - triggering_element: If the value for the 'path' key is a generic Ajax
* processing path, this needs to be set to the name of the element. If
* the name doesn't identify the element uniquely, then this should
* instead be an array with a single key/value pair, corresponding to the
* element name and value. The \Drupal\Core\Form\FormAjaxResponseBuilder
* uses this to find the #ajax information for the element, including
* which specific callback to use for processing the request.
*
* This can also be set to NULL in order to emulate an Internet Explorer
* submission of a form with a single text field, and pressing ENTER in that
@ -1649,7 +1676,10 @@ abstract class WebTestBase extends TestBase {
$submit_matches = $this->handleForm($post, $edit, $upload, $ajax ? NULL : $submit, $form);
$action = isset($form['action']) ? $this->getAbsoluteUrl((string) $form['action']) : $this->getUrl();
if ($ajax) {
$action = $this->getAbsoluteUrl(!empty($submit['path']) ? $submit['path'] : 'system/ajax');
if (empty($submit['path'])) {
throw new \Exception('No #ajax path specified.');
}
$action = $this->getAbsoluteUrl($submit['path']);
// Ajax callbacks verify the triggering element if necessary, so while
// we may eventually want extra code that verifies it in the
// handleForm() function, it's not currently a requirement.
@ -1661,16 +1691,20 @@ abstract class WebTestBase extends TestBase {
$post_array = $post;
if ($upload) {
foreach ($upload as $key => $file) {
$file = drupal_realpath($file);
if ($file && is_file($file)) {
// Use the new CurlFile class for file uploads when using PHP
// 5.5.
if (class_exists('CurlFile')) {
$post[$key] = curl_file_create($file);
if (is_array($file) && count($file)) {
// There seems to be no way via php's API to cURL to upload
// several files with the same post field name. However, Drupal
// still sees array-index syntax in a similar way.
for ($i = 0; $i < count($file); $i++) {
$postfield = str_replace('[]', '', $key) . '[' . $i . ']';
$file_path = $this->container->get('file_system')->realpath($file[$i]);
$post[$postfield] = curl_file_create($file_path);
}
else {
// @todo: Drop support for this when PHP 5.5 is required.
$post[$key] = '@' . $file;
}
else {
$file = $this->container->get('file_system')->realpath($file);
if ($file && is_file($file)) {
$post[$key] = curl_file_create($file);
}
}
}
@ -1735,8 +1769,7 @@ abstract class WebTestBase extends TestBase {
* and the value is the button label. i.e.) array('op' => t('Refresh')).
* @param $ajax_path
* (optional) Override the path set by the Ajax settings of the triggering
* element. In the absence of both the triggering element's Ajax path and
* $ajax_path 'system/ajax' will be used.
* element.
* @param $options
* (optional) Options to be forwarded to the url generator.
* @param $headers
@ -1807,7 +1840,7 @@ abstract class WebTestBase extends TestBase {
$extra_post = '&' . $this->serializePostValues($extra_post);
// Unless a particular path is specified, use the one specified by the
// Ajax settings, or else 'system/ajax'.
// Ajax settings.
if (!isset($ajax_path)) {
if (isset($ajax_settings['url'])) {
// In order to allow to set for example the wrapper envelope query
@ -1824,10 +1857,12 @@ abstract class WebTestBase extends TestBase {
$parsed_url['path']
);
}
else {
$ajax_path = 'system/ajax';
}
}
if (empty($ajax_path)) {
throw new \Exception('No #ajax path specified.');
}
$ajax_path = $this->container->get('unrouted_url_assembler')->assemble('base://' . $ajax_path, $options);
// Submit the POST request.
@ -2324,7 +2359,7 @@ abstract class WebTestBase extends TestBase {
}
/**
* Follows a link by name.
* Follows a link by complete name.
*
* Will click the first link found with this link text by default, or a later
* one if an index is given. Match is case sensitive with normalized space.
@ -2332,17 +2367,54 @@ abstract class WebTestBase extends TestBase {
*
* If the link is discovered and clicked, the test passes. Fail otherwise.
*
* @param $label
* @param string $label
* Text between the anchor tags.
* @param $index
* @param int $index
* Link position counting from zero.
*
* @return
* @return string|bool
* Page contents on success, or FALSE on failure.
*/
protected function clickLink($label, $index = 0) {
return $this->clickLinkHelper($label, $index, '//a[normalize-space()=:label]');
}
/**
* Follows a link by partial name.
*
*
* If the link is discovered and clicked, the test passes. Fail otherwise.
*
* @param string $label
* Text between the anchor tags, uses starts-with().
* @param int $index
* Link position counting from zero.
*
* @return string|bool
* Page contents on success, or FALSE on failure.
*
* @see ::clickLink()
*/
protected function clickLinkPartialName($label, $index = 0) {
return $this->clickLinkHelper($label, $index, '//a[starts-with(normalize-space(), :label)]');
}
/**
* Provides a helper for ::clickLink() and ::clickLinkPartialName().
*
* @param string $label
* Text between the anchor tags, uses starts-with().
* @param int $index
* Link position counting from zero.
* @param string $pattern
* A pattern to use for the XPath.
*
* @return bool|string
* Page contents on success, or FALSE on failure.
*/
protected function clickLinkHelper($label, $index, $pattern) {
$url_before = $this->getUrl();
$urls = $this->xpath('//a[normalize-space()=:label]', array(':label' => $label));
$urls = $this->xpath($pattern, array(':label' => $label));
if (isset($urls[$index])) {
$url_target = $this->getAbsoluteUrl($urls[$index]['href']);
$this->pass(SafeMarkup::format('Clicked link %label (@url_target) from @url_before', array('%label' => $label, '@url_target' => $url_target, '@url_before' => $url_before)), 'Browser');
@ -2355,16 +2427,35 @@ abstract class WebTestBase extends TestBase {
/**
* Takes a path and returns an absolute path.
*
* @param $path
* This method is implemented in the way that browsers work, see
* https://url.spec.whatwg.org/#relative-state for more information about the
* possible cases.
*
* @param string $path
* A path from the internal browser content.
*
* @return
* @return string
* The $path with $base_url prepended, if necessary.
*/
protected function getAbsoluteUrl($path) {
global $base_url, $base_path;
$parts = parse_url($path);
// In case the $path has a host, it is already an absolute URL and we are
// done.
if (!empty($parts['host'])) {
return $path;
}
// In case the $path contains just a query, we turn it into an absolute URL
// with the same scheme, host and path, see
// https://url.spec.whatwg.org/#relative-state.
if (array_keys($parts) === ['query']) {
$current_uri = new Uri($this->getUrl());
return (string) $current_uri->withQuery($parts['query']);
}
if (empty($parts['host'])) {
// Ensure that we have a string (and no xpath object).
$path = (string) $path;
@ -2822,6 +2913,17 @@ abstract class WebTestBase extends TestBase {
$this->assertTrue(in_array($expected_cache_context, $cache_contexts), "'" . $expected_cache_context . "' is present in the X-Drupal-Cache-Contexts header.");
}
/**
* Asserts that a cache context was not present in the last response.
*
* @param string $not_expected_cache_context
* The expected cache context.
*/
protected function assertNoCacheContext($not_expected_cache_context) {
$cache_contexts = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Contexts'));
$this->assertFalse(in_array($not_expected_cache_context, $cache_contexts), "'" . $not_expected_cache_context . "' is not present in the X-Drupal-Cache-Contexts header.");
}
/**
* Asserts whether an expected cache tag was present in the last response.
*

View file

@ -115,10 +115,11 @@ class TestBaseTest extends UnitTestCase {
$mock_test_base = $this->getMockForAbstractClass('Drupal\simpletest\TestBase');
$string = $mock_test_base->randomString($length);
$this->assertEquals($length, strlen($string));
// randomString() should always include an ampersand ('&') if $length is
// greater than 2.
if ($length > 2) {
// randomString() should always include an ampersand ('&') and a
// greater than ('>') if $length is greater than 3.
if ($length > 3) {
$this->assertContains('&', $string);
$this->assertContains('>', $string);
}
}

View file

@ -198,4 +198,41 @@ class WebTestBaseTest extends UnitTestCase {
$this->assertSame($expected, $clicklink_method->invoke($web_test, $label, $index));
}
/**
* @dataProvider providerTestGetAbsoluteUrl
*/
public function testGetAbsoluteUrl($href, $expected_absolute_path) {
$web_test = $this->getMockBuilder('Drupal\simpletest\WebTestBase')
->disableOriginalConstructor()
->setMethods(['getUrl'])
->getMock();
$web_test->expects($this->any())
->method('getUrl')
->willReturn('http://example.com/drupal/current-path?foo=baz');
$GLOBALS['base_url'] = 'http://example.com';
$GLOBALS['base_path'] = 'drupal';
$get_absolute_url_method = new \ReflectionMethod($web_test, 'getAbsoluteUrl');
$get_absolute_url_method->setAccessible(TRUE);
$this->assertSame($expected_absolute_path, $get_absolute_url_method->invoke($web_test, $href));
}
/**
* Provides test data for testGetAbsoluteUrl.
*
* @return array
*/
public function providerTestGetAbsoluteUrl() {
$data = [];
$data['host'] = ['http://example.com/drupal/test-example', 'http://example.com/drupal/test-example'];
$data['path'] = ['/drupal/test-example', 'http://example.com/drupal/test-example'];
$data['path-with-query'] = ['/drupal/test-example?foo=bar', 'http://example.com/drupal/test-example?foo=bar'];
$data['just-query'] = ['?foo=bar', 'http://example.com/drupal/current-path?foo=bar'];
return $data;
}
}