common.test 105 KB
Newer Older
1
2
<?php

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * @file
 * Tests for common.inc functionality.
 */

/**
 * Tests for URL generation functions.
 */
class DrupalAlterTestCase extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'drupal_alter() tests',
      'description' => 'Confirm that alteration of arguments passed to drupal_alter() works correctly.',
      'group' => 'System',
    );
  }

  function setUp() {
    parent::setUp('common_test');
  }

  function testDrupalAlter() {
25
    // This test depends on Bartik, so make sure that it is always the current
26
27
    // active theme.
    global $theme, $base_theme_info;
28
    $theme = 'bartik';
29
30
    $base_theme_info = array();

31
    $array = array('foo' => 'bar');
32
    $entity = new stdClass();
33
    $entity->foo = 'bar';
34
35
36

    // Verify alteration of a single argument.
    $array_copy = $array;
37
    $array_expected = array('foo' => 'Drupal theme');
38
    drupal_alter('drupal_alter', $array_copy);
39
    $this->assertEqual($array_copy, $array_expected, t('Single array was altered.'));
40

41
42
43
44
    $entity_copy = clone $entity;
    $entity_expected = clone $entity;
    $entity_expected->foo = 'Drupal theme';
    drupal_alter('drupal_alter', $entity_copy);
45
    $this->assertEqual($entity_copy, $entity_expected, t('Single object was altered.'));
46
47
48

    // Verify alteration of multiple arguments.
    $array_copy = $array;
49
    $array_expected = array('foo' => 'Drupal theme');
50
51
52
    $entity_copy = clone $entity;
    $entity_expected = clone $entity;
    $entity_expected->foo = 'Drupal theme';
53
    $array2_copy = $array;
54
    $array2_expected = array('foo' => 'Drupal theme');
55
    drupal_alter('drupal_alter', $array_copy, $entity_copy, $array2_copy);
56
57
58
    $this->assertEqual($array_copy, $array_expected, t('First argument to drupal_alter() was altered.'));
    $this->assertEqual($entity_copy, $entity_expected, t('Second argument to drupal_alter() was altered.'));
    $this->assertEqual($array2_copy, $array2_expected, t('Third argument to drupal_alter() was altered.'));
59
60
61
  }
}

62
/**
63
 * Tests for URL generation functions.
64
65
66
 *
 * url() calls module_implements(), which may issue a db query, which requires
 * inheriting from a web test case rather than a unit test case.
67
 */
68
class CommonURLUnitTest extends DrupalWebTestCase {
69
  public static function getInfo() {
70
    return array(
71
      'name' => 'URL generation tests',
72
      'description' => 'Confirm that url(), drupal_get_query_parameters(), drupal_http_build_query(), and l() work correctly with various input.',
73
      'group' => 'System',
74
75
76
77
78
79
80
81
82
83
84
    );
  }

  /**
   * Confirm that invalid text given as $path is filtered.
   */
  function testLXSS() {
    $text = $this->randomName();
    $path = "<SCRIPT>alert('XSS')</SCRIPT>";
    $link = l($text, $path);
    $sanitized_path = check_url(url($path));
85
    $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, t('XSS attack @path was filtered', array('@path' => $path)));
86
  }
87

88
89
90
91
92
  /*
   * Tests for active class in l() function.
   */
  function testLActiveClass() {
    $link = l($this->randomName(), $_GET['q']);
93
    $this->assertTrue($this->hasClass($link, 'active'), t('Class @class is present on link to the current page', array('@class' => 'active')));
94
95
96
97
98
99
100
101
  }

  /**
   * Tests for custom class in l() function.
   */
  function testLCustomClass() {
    $class = $this->randomName();
    $link = l($this->randomName(), $_GET['q'], array('attributes' => array('class' => array($class))));
102
103
    $this->assertTrue($this->hasClass($link, $class), t('Custom class @class is present on link when requested', array('@class' => $class)));
    $this->assertTrue($this->hasClass($link, 'active'), t('Class @class is present on link to the current page', array('@class' => 'active')));
104
105
106
107
108
  }

  private function hasClass($link, $class) {
    return preg_match('|class="([^\"\s]+\s+)*' . $class . '|', $link);
  }
109

110
  /**
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
   * Test drupal_get_query_parameters().
   */
  function testDrupalGetQueryParameters() {
    $original = array(
      'a' => 1,
      'b' => array(
        'd' => 4,
        'e' => array(
          'f' => 5,
        ),
      ),
      'c' => 3,
      'q' => 'foo/bar',
    );

    // Default arguments.
    $result = $_GET;
    unset($result['q']);
129
    $this->assertEqual(drupal_get_query_parameters(), $result, t("\$_GET['q'] was removed."));
130
131
132
133

    // Default exclusion.
    $result = $original;
    unset($result['q']);
134
    $this->assertEqual(drupal_get_query_parameters($original), $result, t("'q' was removed."));
135
136
137
138

    // First-level exclusion.
    $result = $original;
    unset($result['b']);
139
    $this->assertEqual(drupal_get_query_parameters($original, array('b')), $result, t("'b' was removed."));
140
141
142
143

    // Second-level exclusion.
    $result = $original;
    unset($result['b']['d']);
144
    $this->assertEqual(drupal_get_query_parameters($original, array('b[d]')), $result, t("'b[d]' was removed."));
145
146
147
148

    // Third-level exclusion.
    $result = $original;
    unset($result['b']['e']['f']);
149
    $this->assertEqual(drupal_get_query_parameters($original, array('b[e][f]')), $result, t("'b[e][f]' was removed."));
150
151
152
153

    // Multiple exclusions.
    $result = $original;
    unset($result['a'], $result['b']['e'], $result['c']);
154
    $this->assertEqual(drupal_get_query_parameters($original, array('a', 'b[e]', 'c')), $result, t("'a', 'b[e]', 'c' were removed."));
155
156
157
158
159
160
  }

  /**
   * Test drupal_http_build_query().
   */
  function testDrupalHttpBuildQuery() {
161
162
163
164
    $this->assertEqual(drupal_http_build_query(array('a' => ' &#//+%20@۞')), 'a=%20%26%23//%2B%2520%40%DB%9E', t('Value was properly encoded.'));
    $this->assertEqual(drupal_http_build_query(array(' &#//+%20@۞' => 'a')), '%20%26%23%2F%2F%2B%2520%40%DB%9E=a', t('Key was properly encoded.'));
    $this->assertEqual(drupal_http_build_query(array('a' => '1', 'b' => '2', 'c' => '3')), 'a=1&b=2&c=3', t('Multiple values were properly concatenated.'));
    $this->assertEqual(drupal_http_build_query(array('a' => array('b' => '2', 'c' => '3'), 'd' => 'foo')), 'a[b]=2&a[c]=3&d=foo', t('Nested array was properly encoded.'));
165
166
167
168
169
170
171
172
173
174
175
176
177
  }

  /**
   * Test drupal_parse_url().
   */
  function testDrupalParseUrl() {
    // Relative URL.
    $url = 'foo/bar?foo=bar&bar=baz&baz#foo';
    $result = array(
      'path' => 'foo/bar',
      'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''),
      'fragment' => 'foo',
    );
178
    $this->assertEqual(drupal_parse_url($url), $result, t('Relative URL parsed correctly.'));
179

180
181
182
183
184
185
186
    // Relative URL that is known to confuse parse_url().
    $url = 'foo/bar:1';
    $result = array(
      'path' => 'foo/bar:1',
      'query' => array(),
      'fragment' => '',
    );
187
    $this->assertEqual(drupal_parse_url($url), $result, t('Relative URL parsed correctly.'));
188

189
190
191
192
193
194
195
    // Absolute URL.
    $url = '/foo/bar?foo=bar&bar=baz&baz#foo';
    $result = array(
      'path' => '/foo/bar',
      'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''),
      'fragment' => 'foo',
    );
196
    $this->assertEqual(drupal_parse_url($url), $result, t('Absolute URL parsed correctly.'));
197

198
    // External URL testing.
199
    $url = 'http://drupal.org/foo/bar?foo=bar&bar=baz&baz#foo';
200
201

    // Test that drupal can recognize an absolute URL. Used to prevent attack vectors.
202
    $this->assertTrue(url_is_external($url), t('Correctly identified an external URL.'));
203
204

    // Test the parsing of absolute URLs.
205
206
207
208
209
    $result = array(
      'path' => 'http://drupal.org/foo/bar',
      'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''),
      'fragment' => 'foo',
    );
210
    $this->assertEqual(drupal_parse_url($url), $result, t('External URL parsed correctly.'));
211
212
213
214
215
216
217
218
219

    // Verify proper parsing of URLs when clean URLs are disabled.
    $result = array(
      'path' => 'foo/bar',
      'query' => array('bar' => 'baz'),
      'fragment' => 'foo',
    );
    // Non-clean URLs #1: Absolute URL generated by url().
    $url = $GLOBALS['base_url'] . '/?q=foo/bar&bar=baz#foo';
220
    $this->assertEqual(drupal_parse_url($url), $result, t('Absolute URL with clean URLs disabled parsed correctly.'));
221
222
223

    // Non-clean URLs #2: Relative URL generated by url().
    $url = '?q=foo/bar&bar=baz#foo';
224
    $this->assertEqual(drupal_parse_url($url), $result, t('Relative URL with clean URLs disabled parsed correctly.'));
225
226
227

    // Non-clean URLs #3: URL generated by url() on non-Apache webserver.
    $url = 'index.php?q=foo/bar&bar=baz#foo';
228
    $this->assertEqual(drupal_parse_url($url), $result, t('Relative URL on non-Apache webserver with clean URLs disabled parsed correctly.'));
229
230
231

    // Test that drupal_parse_url() does not allow spoofing a URL to force a malicious redirect.
    $parts = drupal_parse_url('forged:http://cwe.mitre.org/data/definitions/601.html');
232
    $this->assertFalse(valid_url($parts['path'], TRUE), t('drupal_parse_url() correctly parsed a forged URL.'));
233
234
  }

235
  /**
236
237
   * Test url() with/without query, with/without fragment, absolute on/off and
   * assert all that works when clean URLs are on and off.
238
239
240
   */
  function testUrl() {
    global $base_url;
241

242
243
244
245
    foreach (array(FALSE, TRUE) as $absolute) {
      // Get the expected start of the path string.
      $base = $absolute ? $base_url . '/' : base_path();
      $absolute_string = $absolute ? 'absolute' : NULL;
246
247

      // Disable Clean URLs.
248
      $GLOBALS['conf']['clean_url'] = 0;
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269

      $url = $base . '?q=node/123';
      $result = url('node/123', array('absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

      $url = $base . '?q=node/123#foo';
      $result = url('node/123', array('fragment' => 'foo', 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

      $url = $base . '?q=node/123&foo';
      $result = url('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

      $url = $base . '?q=node/123&foo=bar&bar=baz';
      $result = url('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

      $url = $base . '?q=node/123&foo#bar';
      $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

270
271
272
273
274
275
276
277
      $url = $base . '?q=node/123&foo#0';
      $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => '0', 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

      $url = $base . '?q=node/123&foo';
      $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => '', 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

278
279
280
281
282
      $url = $base;
      $result = url('<front>', array('absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

      // Enable Clean URLs.
283
      $GLOBALS['conf']['clean_url'] = 1;
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

      $url = $base . 'node/123';
      $result = url('node/123', array('absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

      $url = $base . 'node/123#foo';
      $result = url('node/123', array('fragment' => 'foo', 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

      $url = $base . 'node/123?foo';
      $result = url('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

      $url = $base . 'node/123?foo=bar&bar=baz';
      $result = url('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

      $url = $base . 'node/123?foo#bar';
      $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");

      $url = $base;
      $result = url('<front>', array('absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");
308
309
    }
  }
310
311
312
313
314
315
316
317
318
319

  /**
   * Test external URL handling.
   */
  function testExternalUrls() {
    $test_url = 'http://drupal.org/';

    // Verify external URL can contain a fragment.
    $url = $test_url . '#drupal';
    $result = url($url);
320
    $this->assertEqual($url, $result, t('External URL with fragment works without a fragment in $options.'));
321
322
323
324
325

    // Verify fragment can be overidden in an external URL.
    $url = $test_url . '#drupal';
    $fragment = $this->randomName(10);
    $result = url($url, array('fragment' => $fragment));
326
    $this->assertEqual($test_url . '#' . $fragment, $result, t('External URL fragment is overidden with a custom fragment in $options.'));
327
328
329
330

    // Verify external URL can contain a query string.
    $url = $test_url . '?drupal=awesome';
    $result = url($url);
331
    $this->assertEqual($url, $result, t('External URL with query string works without a query string in $options.'));
332
333
334
335
336

    // Verify external URL can be extended with a query string.
    $url = $test_url;
    $query = array($this->randomName(5) => $this->randomName(5));
    $result = url($url, array('query' => $query));
337
    $this->assertEqual($url . '?' . http_build_query($query, '', '&'), $result, t('External URL can be extended with a query string in $options.'));
338
339
340
341
342

    // Verify query string can be extended in an external URL.
    $url = $test_url . '?drupal=awesome';
    $query = array($this->randomName(5) => $this->randomName(5));
    $result = url($url, array('query' => $query));
343
    $this->assertEqual($url . '&' . http_build_query($query, '', '&'), $result, t('External URL query string can be extended with a custom query string in $options.'));
344
  }
345
346
}

347
/**
348
 * Tests for the check_plain(), filter_xss() and format_string() functions.
349
350
351
352
353
354
 */
class CommonXssUnitTest extends DrupalUnitTestCase {

  public static function getInfo() {
    return array(
      'name' => 'String filtering tests',
355
      'description' => 'Confirm that check_plain(), filter_xss(), format_string() and check_url() work correctly, including invalid multi-byte sequences.',
356
357
358
359
360
361
362
363
      'group' => 'System',
    );
  }

  /**
   * Check that invalid multi-byte sequences are rejected.
   */
  function testInvalidMultiByte() {
364
365
366
     // Ignore PHP 5.3+ invalid multibyte sequence warning.
     $text = @check_plain("Foo\xC0barbaz");
     $this->assertEqual($text, '', 'check_plain() rejects invalid sequence "Foo\xC0barbaz"');
367
368
369
     // Ignore PHP 5.3+ invalid multibyte sequence warning.
     $text = @check_plain("\xc2\"");
     $this->assertEqual($text, '', 'check_plain() rejects invalid sequence "\xc2\""');
370
371
372
373
374
375
     $text = check_plain("Fooÿñ");
     $this->assertEqual($text, "Fooÿñ", 'check_plain() accepts valid sequence "Fooÿñ"');
     $text = filter_xss("Foo\xC0barbaz");
     $this->assertEqual($text, '', 'filter_xss() rejects invalid sequence "Foo\xC0barbaz"');
     $text = filter_xss("Fooÿñ");
     $this->assertEqual($text, "Fooÿñ", 'filter_xss() accepts valid sequence Fooÿñ');
376
377
378
379
380
381
  }

  /**
   * Check that special characters are escaped.
   */
  function testEscaping() {
382
383
     $text = check_plain("<script>");
     $this->assertEqual($text, '&lt;script&gt;', 'check_plain() escapes &lt;script&gt;');
384
385
     $text = check_plain('<>&"\'');
     $this->assertEqual($text, '&lt;&gt;&amp;&quot;&#039;', 'check_plain() escapes reserved HTML characters.');
386
  }
387

388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  /**
   * Test t() and format_string() replacement functionality.
   */
  function testFormatStringAndT() {
    foreach (array('format_string', 't') as $function) {
      $text = $function('Simple text');
      $this->assertEqual($text, 'Simple text', $function . ' leaves simple text alone.');
      $text = $function('Escaped text: @value', array('@value' => '<script>'));
      $this->assertEqual($text, 'Escaped text: &lt;script&gt;', $function . ' replaces and escapes string.');
      $text = $function('Placeholder text: %value', array('%value' => '<script>'));
      $this->assertEqual($text, 'Placeholder text: <em class="placeholder">&lt;script&gt;</em>', $function . ' replaces, escapes and themes string.');
      $text = $function('Verbatim text: !value', array('!value' => '<script>'));
      $this->assertEqual($text, 'Verbatim text: <script>', $function . ' replaces verbatim string as-is.');
    }
  }

404
405
406
407
408
409
410
411
412
413
  /**
   * Check that harmful protocols are stripped.
   */
  function testBadProtocolStripping() {
    // Ensure that check_url() strips out harmful protocols, and encodes for
    // HTML. Ensure drupal_strip_dangerous_protocols() can be used to return a
    // plain-text string stripped of harmful protocols.
    $url = 'javascript:http://www.example.com/?x=1&y=2';
    $expected_plain = 'http://www.example.com/?x=1&y=2';
    $expected_html = 'http://www.example.com/?x=1&amp;y=2';
414
415
    $this->assertIdentical(check_url($url), $expected_html, t('check_url() filters a URL and encodes it for HTML.'));
    $this->assertIdentical(drupal_strip_dangerous_protocols($url), $expected_plain, t('drupal_strip_dangerous_protocols() filters a URL and returns plain text.'));
416
  }
417
418
}

419
class CommonSizeTestCase extends DrupalUnitTestCase {
420
421
  protected $exact_test_cases;
  protected $rounded_test_cases;
422

423
  public static function getInfo() {
424
    return array(
425
426
427
      'name' => 'Size parsing test',
      'description' => 'Parse a predefined amount of bytes and compare the output with the expected value.',
      'group' => 'System'
428
429
430
431
    );
  }

  function setUp() {
432
    $kb = DRUPAL_KILOBYTE;
433
    $this->exact_test_cases = array(
434
435
436
437
438
439
440
441
442
      '1 byte' => 1,
      '1 KB'   => $kb,
      '1 MB'   => $kb * $kb,
      '1 GB'   => $kb * $kb * $kb,
      '1 TB'   => $kb * $kb * $kb * $kb,
      '1 PB'   => $kb * $kb * $kb * $kb * $kb,
      '1 EB'   => $kb * $kb * $kb * $kb * $kb * $kb,
      '1 ZB'   => $kb * $kb * $kb * $kb * $kb * $kb * $kb,
      '1 YB'   => $kb * $kb * $kb * $kb * $kb * $kb * $kb * $kb,
443
444
    );
    $this->rounded_test_cases = array(
445
446
447
448
449
      '2 bytes' => 2,
      '1 MB' => ($kb * $kb) - 1, // rounded to 1 MB (not 1000 or 1024 kilobyte!)
      round(3623651 / ($this->exact_test_cases['1 MB']), 2) . ' MB' => 3623651, // megabytes
      round(67234178751368124 / ($this->exact_test_cases['1 PB']), 2) . ' PB' => 67234178751368124, // petabytes
      round(235346823821125814962843827 / ($this->exact_test_cases['1 YB']), 2) . ' YB' => 235346823821125814962843827, // yottabytes
450
451
452
453
454
    );
    parent::setUp();
  }

  /**
455
   * Check that format_size() returns the expected string.
456
457
458
   */
  function testCommonFormatSize() {
    foreach (array($this->exact_test_cases, $this->rounded_test_cases) as $test_cases) {
459
460
461
462
463
      foreach ($test_cases as $expected => $input) {
        $this->assertEqual(
          ($result = format_size($input, NULL)),
          $expected,
          $expected . ' == ' . $result . ' (' . $input . ' bytes)'
464
465
466
467
        );
      }
    }
  }
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513

  /**
   * Check that parse_size() returns the proper byte sizes.
   */
  function testCommonParseSize() {
    foreach ($this->exact_test_cases as $string => $size) {
      $this->assertEqual(
        $parsed_size = parse_size($string),
        $size,
        $size . ' == ' . $parsed_size . ' (' . $string . ')'
      );
    }

    // Some custom parsing tests
    $string = '23476892 bytes';
    $this->assertEqual(
      ($parsed_size = parse_size($string)),
      $size = 23476892,
      $string . ' == ' . $parsed_size . ' bytes'
    );
    $string = '76MRandomStringThatShouldBeIgnoredByParseSize.'; // 76 MB
    $this->assertEqual(
      $parsed_size = parse_size($string),
      $size = 79691776,
      $string . ' == ' . $parsed_size . ' bytes'
    );
    $string = '76.24 Giggabyte'; // Misspeld text -> 76.24 GB
    $this->assertEqual(
      $parsed_size = parse_size($string),
      $size = 81862076662,
      $string . ' == ' . $parsed_size . ' bytes'
    );
  }

  /**
   * Cross-test parse_size() and format_size().
   */
  function testCommonParseSizeFormatSize() {
    foreach ($this->exact_test_cases as $size) {
      $this->assertEqual(
        $size,
        ($parsed_size = parse_size($string = format_size($size, NULL))),
        $size . ' == ' . $parsed_size . ' (' . $string . ')'
      );
    }
  }
514
}
515
516
517
518
519
520
521
522
523
524
525
526

/**
 * Test drupal_explode_tags() and drupal_implode_tags().
 */
class DrupalTagsHandlingTestCase extends DrupalWebTestCase {
  var $validTags = array(
    'Drupal' => 'Drupal',
    'Drupal with some spaces' => 'Drupal with some spaces',
    '"Legendary Drupal mascot of doom: ""Druplicon"""' => 'Legendary Drupal mascot of doom: "Druplicon"',
    '"Drupal, although it rhymes with sloopal, is as awesome as a troopal!"' => 'Drupal, although it rhymes with sloopal, is as awesome as a troopal!',
  );

527
  public static function getInfo() {
528
    return array(
529
530
531
      'name' => 'Drupal tags handling',
      'description' => "Performs tests on Drupal's handling of tags, both explosion and implosion tactics used.",
      'group' => 'System'
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
    );
  }

  /**
   * Explode a series of tags.
   */
  function testDrupalExplodeTags() {
    $string = implode(', ', array_keys($this->validTags));
    $tags = drupal_explode_tags($string);
    $this->assertTags($tags);
  }

  /**
   * Implode a series of tags.
   */
  function testDrupalImplodeTags() {
    $tags = array_values($this->validTags);
    // Let's explode and implode to our heart's content.
    for ($i = 0; $i < 10; $i++) {
      $string = drupal_implode_tags($tags);
      $tags = drupal_explode_tags($string);
    }
    $this->assertTags($tags);
  }

  /**
   * Helper function: asserts that the ending array of tags is what we wanted.
   */
  function assertTags($tags) {
    $original = $this->validTags;
    foreach ($tags as $tag) {
      $key = array_search($tag, $original);
564
      $this->assertTrue($key, t('Make sure tag %tag shows up in the final tags array (originally %original)', array('%tag' => $tag, '%original' => $key)));
565
566
567
      unset($original[$key]);
    }
    foreach ($original as $leftover) {
568
      $this->fail(t('Leftover tag %leftover was left over.', array('%leftover' => $leftover)));
569
570
    }
  }
571
572
}

573
574
575
576
/**
 * Test the Drupal CSS system.
 */
class CascadingStylesheetsTestCase extends DrupalWebTestCase {
577
  public static function getInfo() {
578
    return array(
579
580
581
      'name' => 'Cascading stylesheets',
      'description' => 'Tests adding various cascading stylesheets to the page.',
      'group' => 'System',
582
583
584
585
    );
  }

  function setUp() {
586
    parent::setUp('php', 'locale', 'common_test');
587
    // Reset drupal_add_css() before each test.
588
    drupal_static_reset('drupal_add_css');
589
590
591
592
593
594
  }

  /**
   * Check default stylesheets as empty.
   */
  function testDefault() {
595
    $this->assertEqual(array(), drupal_add_css(), t('Default CSS is empty.'));
596
597
  }

598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
  /**
   * Test that stylesheets in module .info files are loaded.
   */
  function testModuleInfo() {
    $this->drupalGet('');

    // Verify common_test.css in a STYLE media="all" tag.
    $elements = $this->xpath('//style[@media=:media and contains(text(), :filename)]', array(
      ':media' => 'all',
      ':filename' => 'tests/common_test.css',
    ));
    $this->assertTrue(count($elements), "Stylesheet with media 'all' in module .info file found.");

    // Verify common_test.print.css in a STYLE media="print" tag.
    $elements = $this->xpath('//style[@media=:media and contains(text(), :filename)]', array(
      ':media' => 'print',
      ':filename' => 'tests/common_test.print.css',
    ));
    $this->assertTrue(count($elements), "Stylesheet with media 'print' in module .info file found.");
  }

619
620
621
622
623
624
  /**
   * Tests adding a file stylesheet.
   */
  function testAddFile() {
    $path = drupal_get_path('module', 'simpletest') . '/simpletest.css';
    $css = drupal_add_css($path);
625
    $this->assertEqual($css[$path]['data'], $path, t('Adding a CSS file caches it properly.'));
626
627
  }

628
629
630
631
632
633
  /**
   * Tests adding an external stylesheet.
   */
  function testAddExternal() {
    $path = 'http://example.com/style.css';
    $css = drupal_add_css($path, 'external');
634
    $this->assertEqual($css[$path]['type'], 'external', t('Adding an external CSS file caches it properly.'));
635
636
  }

637
638
639
640
  /**
   * Makes sure that reseting the CSS empties the cache.
   */
  function testReset() {
641
    drupal_static_reset('drupal_add_css');
642
    $this->assertEqual(array(), drupal_add_css(), t('Resetting the CSS empties the cache.'));
643
644
  }

645
646
647
648
649
650
  /**
   * Tests rendering the stylesheets.
   */
  function testRenderFile() {
    $css = drupal_get_path('module', 'simpletest') . '/simpletest.css';
    drupal_add_css($css);
651
    $styles = drupal_get_css();
652
    $this->assertTrue(strpos($styles, $css) > 0, t('Rendered CSS includes the added stylesheet.'));
653
654
655
656
657
658
659
660
661
  }

  /**
   * Tests rendering an external stylesheet.
   */
  function testRenderExternal() {
    $css = 'http://example.com/style.css';
    drupal_add_css($css, 'external');
    $styles = drupal_get_css();
662
663
    // Stylesheet URL may be the href of a LINK tag or in an @import statement
    // of a STYLE tag.
664
    $this->assertTrue(strpos($styles, 'href="' . $css) > 0 || strpos($styles, '@import url("' . $css . '")') > 0, t('Rendering an external CSS file.'));
665
  }
666
667
668
669
670
671

  /**
   * Tests rendering inline stylesheets with preprocessing on.
   */
  function testRenderInlinePreprocess() {
    $css = 'body { padding: 0px; }';
672
    $css_preprocessed = '<style type="text/css" media="all">' . "\n<!--/*--><![CDATA[/*><!--*/\n" . drupal_load_stylesheet_content($css, TRUE) . "\n/*]]>*/-->\n" . '</style>';
673
    drupal_add_css($css, array('type' => 'inline'));
674
    $styles = drupal_get_css();
675
    $this->assertEqual(trim($styles), $css_preprocessed, t('Rendering preprocessed inline CSS adds it to the page.'));
676
677
678
679
680
681
682
  }

  /**
   * Tests rendering inline stylesheets with preprocessing off.
   */
  function testRenderInlineNoPreprocess() {
    $css = 'body { padding: 0px; }';
683
    drupal_add_css($css, array('type' => 'inline', 'preprocess' => FALSE));
684
    $styles = drupal_get_css();
685
    $this->assertTrue(strpos($styles, $css) > 0, t('Rendering non-preprocessed inline CSS adds it to the page.'));
686
687
688
689
690
691
  }

  /**
   * Tests rendering inline stylesheets through a full page request.
   */
  function testRenderInlineFullPage() {
692
    $css = 'body { font-size: 254px; }';
693
694
695
    // Inline CSS is minified unless 'preprocess' => FALSE is passed as a
    // drupal_add_css() option.
    $expected = 'body{font-size:254px;}';
696
697

    // Create a node, using the PHP filter that tests drupal_add_css().
698
    $php_format_id = 'php_code';
699
700
    $settings = array(
      'type' => 'page',
701
      'body' => array(
702
        LANGUAGE_NONE => array(
703
704
          array(
            'value' => t('This tests the inline CSS!') . "<?php drupal_add_css('$css', 'inline'); ?>",
705
            'format' => $php_format_id,
706
707
708
          ),
        ),
      ),
709
710
711
712
713
714
      'promote' => 1,
    );
    $node = $this->drupalCreateNode($settings);

    // Fetch the page.
    $this->drupalGet('node/' . $node->nid);
715
    $this->assertRaw($expected, t('Inline stylesheets appear in the full page rendering.'));
716
  }
717
718
719
720
721
722
723
724
725

  /**
   * Test CSS ordering.
   */
  function testRenderOrder() {
    // A module CSS file.
    drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css');
    // A few system CSS files, ordered in a strange way.
    $system_path = drupal_get_path('module', 'system');
726
727
    drupal_add_css($system_path . '/system.base.css', array('group' => CSS_SYSTEM, 'weight' => -10));
    drupal_add_css($system_path . '/system.theme.css', array('group' => CSS_SYSTEM));
728
729

    $expected = array(
730
731
      $system_path . '/system.base.css',
      $system_path . '/system.theme.css',
732
733
734
      drupal_get_path('module', 'simpletest') . '/simpletest.css',
    );

735

736
    $styles = drupal_get_css();
737
738
739
740
    // Stylesheet URL may be the href of a LINK tag or in an @import statement
    // of a STYLE tag.
    if (preg_match_all('/(href="|url\(")' . preg_quote($GLOBALS['base_url'] . '/', '/') . '([^?]+)\?/', $styles, $matches)) {
      $result = $matches[2];
741
742
743
744
745
    }
    else {
      $result = array();
    }

746
    $this->assertIdentical($result, $expected, t('The CSS files are in the expected order.'));
747
748
749
750
751
752
  }

  /**
   * Test CSS override.
   */
  function testRenderOverride() {
753
754
755
756
757
    $system = drupal_get_path('module', 'system');
    $simpletest = drupal_get_path('module', 'simpletest');

    drupal_add_css($system . '/system.base.css');
    drupal_add_css($simpletest . '/tests/system.base.css');
758
759

    // The dummy stylesheet should be the only one included.
760
    $styles = drupal_get_css();
761
762
    $this->assert(strpos($styles, $simpletest . '/tests/system.base.css') !== FALSE, t('The overriding CSS file is output.'));
    $this->assert(strpos($styles, $system . '/system.base.css') === FALSE, t('The overridden CSS file is not output.'));
763

764
765
    drupal_add_css($simpletest . '/tests/system.base.css');
    drupal_add_css($system . '/system.base.css');
766
767

    // The standard stylesheet should be the only one included.
768
    $styles = drupal_get_css();
769
770
    $this->assert(strpos($styles, $system . '/system.base.css') !== FALSE, t('The overriding CSS file is output.'));
    $this->assert(strpos($styles, $simpletest . '/tests/system.base.css') === FALSE, t('The overridden CSS file is not output.'));
771
772
773
774
775
776
  }

  /**
   * Tests Locale module's CSS Alter to include RTL overrides.
   */
  function testAlter() {
777
    // Switch the language to a right to left language and add system.base.css.
778
779
    global $language;
    $language->direction = LANGUAGE_RTL;
780
781
    $path = drupal_get_path('module', 'system');
    drupal_add_css($path . '/system.base.css');
782

783
    // Check to see if system.base-rtl.css was also added.
784
    $styles = drupal_get_css();
785
    $this->assert(strpos($styles, $path . '/system.base-rtl.css') !== FALSE, t('CSS is alterable as right to left overrides are added.'));
786
787
788
789

    // Change the language back to left to right.
    $language->direction = LANGUAGE_LTR;
  }
790
791
792
793
794
795
796

  /**
   * Tests that the query string remains intact when adding CSS files that have
   * query string parameters.
   */
  function testAddCssFileWithQueryString() {
    $this->drupalGet('common-test/query-string');
797
798
799
    $query_string = variable_get('css_js_query_string', '0');
    $this->assertRaw(drupal_get_path('module', 'node') . '/node.css?' . $query_string, t('Query string was appended correctly to css.'));
    $this->assertRaw(drupal_get_path('module', 'node') . '/node-fake.css?arg1=value1&amp;arg2=value2', t('Query string not escaped on a URI.'));
800
  }
801
802
}

803
/**
804
 * Test for cleaning HTML identifiers.
805
 */
806
class DrupalHTMLIdentifierTestCase extends DrupalUnitTestCase {
807
808
  public static function getInfo() {
    return array(
809
810
      'name' => 'HTML identifiers',
      'description' => 'Test the functions drupal_html_class(), drupal_html_id() and drupal_clean_css_identifier() for expected behavior',
811
812
813
814
815
      'group' => 'System',
    );
  }

  /**
816
   * Tests that drupal_clean_css_identifier() cleans the identifier properly.
817
818
   */
  function testDrupalCleanCSSIdentifier() {
819
820
    // Verify that no valid ASCII characters are stripped from the identifier.
    $identifier = 'abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789';
821
    $this->assertIdentical(drupal_clean_css_identifier($identifier, array()), $identifier, t('Verify valid ASCII characters pass through.'));
822

823
824
    // Verify that valid UTF-8 characters are not stripped from the identifier.
    $identifier = '¡¢£¤¥';
825
    $this->assertIdentical(drupal_clean_css_identifier($identifier, array()), $identifier, t('Verify valid UTF-8 characters pass through.'));
826

827
    // Verify that invalid characters (including non-breaking space) are stripped from the identifier.
828
    $this->assertIdentical(drupal_clean_css_identifier('invalid !"#$%&\'()*+,./:;<=>?@[\\]^`{|}~ identifier', array()), 'invalididentifier', t('Strip invalid characters.'));
829
830
831
  }

  /**
832
   * Tests that drupal_html_class() cleans the class name properly.
833
   */
834
  function testDrupalHTMLClass() {
835
    // Verify Drupal coding standards are enforced.
836
    $this->assertIdentical(drupal_html_class('CLASS NAME_[Ü]'), 'class-name--ü', t('Enforce Drupal coding standards.'));
837
838
839
  }

  /**
840
   * Tests that drupal_html_id() cleans the ID properly.
841
   */
842
843
844
  function testDrupalHTMLId() {
    // Verify that letters, digits, and hyphens are not stripped from the ID.
    $id = 'abcdefghijklmnopqrstuvwxyz-0123456789';
845
    $this->assertIdentical(drupal_html_id($id), $id, t('Verify valid characters pass through.'));
846
847

    // Verify that invalid characters are stripped from the ID.
848
    $this->assertIdentical(drupal_html_id('invalid,./:@\\^`{Üidentifier'), 'invalididentifier', t('Strip invalid characters.'));
849

850
    // Verify Drupal coding standards are enforced.
851
    $this->assertIdentical(drupal_html_id('ID NAME_[1]'), 'id-name-1', t('Enforce Drupal coding standards.'));
852
853

    // Reset the static cache so we can ensure the unique id count is at zero.
854
    drupal_static_reset('drupal_html_id');
855
856

    // Clean up IDs with invalid starting characters.
857
858
859
    $this->assertIdentical(drupal_html_id('test-unique-id'), 'test-unique-id', t('Test the uniqueness of IDs #1.'));
    $this->assertIdentical(drupal_html_id('test-unique-id'), 'test-unique-id--2', t('Test the uniqueness of IDs #2.'));
    $this->assertIdentical(drupal_html_id('test-unique-id'), 'test-unique-id--3', t('Test the uniqueness of IDs #3.'));
860
861
862
  }
}

863
864
865
/**
 * CSS Unit Tests.
 */
866
class CascadingStylesheetsUnitTest extends DrupalUnitTestCase {
867
868
869
870
871
872
873
874
875
  public static function getInfo() {
    return array(
      'name' => 'CSS Unit Tests',
      'description' => 'Unit tests on CSS functions like aggregation.',
      'group' => 'System',
    );
  }

  /**
876
877
   * Tests basic CSS loading with and without optimization via drupal_load_stylesheet().
   *
878
879
880
881
   * Known tests:
   * - Retain white-space in selectors. (http://drupal.org/node/472820)
   * - Proper URLs in imported files. (http://drupal.org/node/265719)
   * - Retain pseudo-selectors. (http://drupal.org/node/460448)
882
883
   */
  function testLoadCssBasic() {
884
885
886
887
888
889
    // Array of files to test living in 'simpletest/files/css_test_files/'.
    // - Original: name.css
    // - Unoptimized expected content: name.css.unoptimized.css
    // - Optimized expected content: name.css.optimized.css
    $testfiles = array(
      'css_input_without_import.css',
890
891
      'css_input_with_import.css',
      'comment_hacks.css'
892
    );
893
894
895
    $path = drupal_get_path('module', 'simpletest') . '/files/css_test_files';
    foreach ($testfiles as $file) {
      $expected = file_get_contents("$path/$file.unoptimized.css");
896
      $unoptimized_output = drupal_load_stylesheet("$path/$file.unoptimized.css", FALSE);
897
      $this->assertEqual($unoptimized_output, $expected, t('Unoptimized CSS file has expected contents (@file)', array('@file' => $file)));
898

899
900
      $expected = file_get_contents("$path/$file.optimized.css");
      $optimized_output = drupal_load_stylesheet("$path/$file", TRUE);
901
      $this->assertEqual($optimized_output, $expected, t('Optimized CSS file has expected contents (@file)', array('@file' => $file)));
902
903
904
905
906
907
908
909
910

      // Repeat the tests by accessing the stylesheets by URL.
      $expected = file_get_contents("$path/$file.unoptimized.css");
      $unoptimized_output_url = drupal_load_stylesheet($GLOBALS['base_url'] . "/$path/$file.unoptimized.css", FALSE);
      $this->assertEqual($unoptimized_output, $expected, t('Unoptimized CSS file (loaded from an URL) has expected contents (@file)', array('@file' => $file)));

      $expected = file_get_contents("$path/$file.optimized.css");
      $optimized_output = drupal_load_stylesheet($GLOBALS['base_url'] . "/$path/$file", TRUE);
      $this->assertEqual($optimized_output, $expected, t('Optimized CSS file (loaded from an URL) has expected contents (@file)', array('@file' => $file)));
911
912
913
914
    }
  }
}

915
916
917
918
/**
 * Test drupal_http_request().
 */
class DrupalHTTPRequestTestCase extends DrupalWebTestCase {
919
  public static function getInfo() {
920
    return array(
921
922
923
      'name' => 'Drupal HTTP request',
      'description' => "Performs tests on Drupal's HTTP request mechanism.",
      'group' => 'System'
924
925
926
    );
  }

927
928
929
930
  function setUp() {
    parent::setUp('system_test');
  }

931
  function testDrupalHTTPRequest() {
932
933
    global $is_https;

934
    // Parse URL schema.
935
    $missing_scheme = drupal_http_request('example.com/path');
936
937
    $this->assertEqual($missing_scheme->code, -1002, t('Returned with "-1002" error code.'));
    $this->assertEqual($missing_scheme->error, 'missing schema', t('Returned with "missing schema" error message.'));
938
939

    $unable_to_parse = drupal_http_request('http:///path');
940
941
    $this->assertEqual($unable_to_parse->code, -1001, t('Returned with "-1001" error code.'));
    $this->assertEqual($unable_to_parse->error, 'unable to parse URL', t('Returned with "unable to parse URL" error message.'));
942
943
944

    // Fetch page.
    $result = drupal_http_request(url('node', array('absolute' => TRUE)));
945
    $this->assertEqual($result->code, 200, t('Fetched page successfully.'));
946
    $this->drupalSetContent($result->data);
947
    $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), t('Site title matches.'));
948
949
950

    // Test that code and status message is returned.
    $result = drupal_http_request(url('pagedoesnotexist', array('absolute' => TRUE)));
951
952
953
    $this->assertTrue(!empty($result->protocol),  t('Result protocol is returned.'));
    $this->assertEqual($result->code, '404', t('Result code is 404'));
    $this->assertEqual($result->status_message, 'Not Found', t('Result status message is "Not Found"'));
954

955
956
957
958
959
960
961
962
963
964
965
966
967
    // Skip the timeout tests when the testing environment is HTTPS because
    // stream_set_timeout() does not work for SSL connections.
    // @link http://bugs.php.net/bug.php?id=47929
    if (!$is_https) {
      // Test that timeout is respected. The test machine is expected to be able
      // to make the connection (i.e. complete the fsockopen()) in 2 seconds and
      // return within a total of 5 seconds. If the test machine is extremely
      // slow, the test will fail. fsockopen() has been seen to time out in
      // slightly less than the specified timeout, so allow a little slack on
      // the minimum expected time (i.e. 1.8 instead of 2).
      timer_start(__METHOD__);
      $result = drupal_http_request(url('system-test/sleep/10', array('absolute' => TRUE)), array('timeout' => 2));
      $time = timer_read(__METHOD__) / 1000;
968
969
970
      $this->assertTrue(1.8 < $time && $time < 5, t('Request timed out (%time seconds).', array('%time' => $time)));
      $this->assertTrue($result->error, t('An error message was returned.'));
      $this->assertEqual($result->code, HTTP_REQUEST_TIMEOUT, t('Proper error code was returned.'));
971
    }
972
  }
973
974
975
976
977
978

  function testDrupalHTTPRequestBasicAuth() {
    $username = $this->randomName();
    $password = $this->randomName();
    $url = url('system-test/auth', array('absolute' => TRUE));

979
    $auth = str_replace('://', '://' . $username . ':' . $password . '@', $url);
980
981
    $result = drupal_http_request($auth);

982
    $this->drupalSetContent($result->data);
983
984
    $this->assertRaw($username, t('$_SERVER["PHP_AUTH_USER"] is passed correctly.'));
    $this->assertRaw($password, t('$_SERVER["PHP_AUTH_PW"] is passed correctly.'));
985
986
987
  }

  function testDrupalHTTPRequestRedirect() {
988
    $redirect_301 = drupal_http_request(url('system-test/redirect/301', array('absolute' => TRUE)), array('max_redirects' => 1));
989
    $this->assertEqual($redirect_301->redirect_code, 301, t('drupal_http_request follows the 301 redirect.'));
990

991
    $redirect_301 = drupal_http_request(url('system-test/redirect/301', array('absolute' => TRUE)), array('max_redirects' => 0));
992
    $this->assertFalse(isset($redirect_301->redirect_code), t('drupal_http_request does not follow 301 redirect if max_redirects = 0.'));
993

994
    $redirect_invalid = drupal_http_request(url('system-test/redirect-noscheme', array('absolute' => TRUE)), array('max_redirects' => 1));
995
996
    $this->assertEqual($redirect_invalid->code, -1002, t('301 redirect to invalid URL returned with error code !error.', array('!error' => $redirect_invalid->error)));
    $this->assertEqual($redirect_invalid->error, 'missing schema', t('301 redirect to invalid URL returned with error message "!error".', array('!error' => $redirect_invalid->error)));
997

998
    $redirect_invalid = drupal_http_request(url('system-test/redirect-noparse', array('absolute' => TRUE)), array('max_redirects' => 1));
999
1000
    $this->assertEqual($redirect_invalid->code, -1001, t('301 redirect to invalid URL returned with error message code "!error".', array('!error' => $redirect_invalid->error)));
    $this->assertEqual($redirect_invalid->error, 'unable to parse URL', t('301 redirect to invalid URL returned with error message "!error".', array('!error' => $redirect_invalid->error)));
1001

1002
    $redirect_invalid = drupal_http_request(url('system-test/redirect-invalid-scheme', array('absolute' => TRUE)), array('max_redirects' => 1));
1003
1004
    $this->assertEqual($redirect_invalid->code, -1003, t('301 redirect to invalid URL returned with error code !error.', array('!error' => $redirect_invalid->error)));
    $this->assertEqual($redirect_invalid->error, 'invalid schema ftp', t('301 redirect to invalid URL returned with error message "!error".', array('!error' => $redirect_invalid->error)));
1005

1006
    $redirect_302 = drupal_http_request(url('system-test/redirect/302', array('absolute' => TRUE)), array('max_redirects' => 1));
1007
    $this->assertEqual($redirect_302->redirect_code, 302, t('drupal_http_request follows the 302 redirect.'));
1008

1009
    $redirect_302 = drupal_http_request(url('system-test/redirect/302', array('absolute' => TRUE)), array('max_redirects' => 0));
1010
    $this->assertFalse(isset($redirect_302->redirect_code), t('drupal_http_request does not follow 302 redirect if $retry = 0.'));
1011

1012
    $redirect_307 = drupal_http_request(url('system-test/redirect/307', array('absolute' => TRUE)), array('max_redirects' => 1));
1013
    $this->assertEqual($redirect_307->redirect_code, 307, t('drupal_http_request follows the 307 redirect.'));
1014

1015
    $redirect_307 = drupal_http_request(url('system-test/redirect/307', array('absolute' => TRUE)), array('max_redirects' => 0));
1016
    $this->assertFalse(isset($redirect_307->redirect_code), t('drupal_http_request does not follow 307 redirect if max_redirects = 0.'));
1017
1018
1019
1020
1021
1022
1023

    $multiple_redirect_final_url = url('system-test/multiple-redirects/0', array('absolute' => TRUE));
    $multiple_redirect_1 = drupal_http_request(url('system-test/multiple-redirects/1', array('absolute' => TRUE)), array('max_redirects' => 1));
    $this->assertEqual($multiple_redirect_1->redirect_url, $multiple_redirect_final_url, t('redirect_url contains the final redirection location after 1 redirect.'));

    $multiple_redirect_3 = drupal_http_request(url('system-test/multiple-redirects/3', array('absolute' => TRUE)), array('max_redirects' => 3));
    $this->assertEqual($multiple_redirect_3->redirect_url, $multiple_redirect_final_url, t('redirect_url contains the final redirection location after 3 redirects.'));
1024
  }
1025
}
1026
1027

/**
1028
 * Testing drupal_add_region_content and drupal_get_region_content.
1029
1030
 */
class DrupalSetContentTestCase extends DrupalWebTestCase {
1031
  public static function getInfo() {
1032
    return array(
1033
1034
1035
      'name' => 'Drupal set/get regions',
      'description' => 'Performs tests on setting and retrieiving content from theme regions.',
      'group' => 'System'
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
    );
  }


  /**
   * Test setting and retrieving content for theme regions.
   */
  function testRegions() {
    global $theme_key;

    $block_regions = array_keys(system_region_list($theme_key));
    $delimiter = $this->randomName(32);
    $values = array();
    // Set some random content for each region available.
    foreach ($block_regions as $region) {
      $first_chunk = $this->randomName(32);
1052
      drupal_add_region_content($region, $first_chunk);
1053
      $second_chunk = $this->randomName(32);
1054
1055
      drupal_add_region_content($region, $second_chunk);
      // Store the expected result for a drupal_get_region_content call for this region.
1056
1057
1058
      $values[$region] = $first_chunk . $delimiter . $second_chunk;
    }

1059
1060
    // Ensure drupal_get_region_content returns expected results when fetching all regions.
    $content = drupal_get_region_content(NULL, $delimiter);
1061
    foreach ($content as $region => $region_content) {
1062
      $this->assertEqual($region_content, $values[$region], t('@region region text verified when fetching all regions', array('@region' => $region)));
1063
1064
    }

1065
    // Ensure drupal_get_region_content returns expected results when fetching a single region.
1066
    foreach ($block_regions as $region) {
1067
      $region_content = drupal_get_region_content($region, $delimiter);
1068
      $this->assertEqual($region_content, $values[$region], t('@region region text verified when fetching single region.', array('@region' => $region)));
1069
1070
1071
    }
  }
}
1072

1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
/**
 * Testing drupal_goto and hook_drupal_goto_alter().
 */
class DrupalGotoTest extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Drupal goto',
      'description' => 'Performs tests on the drupal_goto function and hook_drupal_goto_alter',
      'group' => 'System'
    );
  }

  function setUp() {
    parent::setUp('common_test');
  }

  /**
1090
   * Test drupal_goto().
1091
1092
1093
   */
  function testDrupalGoto() {
    $this->drupalGet('common-test/drupal_goto/redirect');
1094
1095
    $headers = $this->drupalGetHeaders(TRUE);
    list(, $status) = explode(' ', $headers[0][':status'], 3);
1096
1097
1098
    $this->assertEqual($status, 302, t('Expected response code was sent.'));
    $this->assertText('drupal_goto', t('Drupal goto redirect succeeded.'));
    $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('absolute' => TRUE)), t('Drupal goto redirected to expected URL.'));
1099
1100
1101
1102

    $this->drupalGet('common-test/drupal_goto/redirect_advanced');
    $headers = $this->drupalGetHeaders(TRUE);
    list(, $status) = explode(' ', $headers[0][':status'], 3);
1103
1104
1105
    $this->assertEqual($status, 301, t('Expected response code was sent.'));
    $this->assertText('drupal_goto', t('Drupal goto redirect succeeded.'));
    $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('query' => array('foo' => '123'), 'absolute' => TRUE)), t('Drupal goto redirected to expected URL.'));
1106
1107
1108
1109
1110

    // Test that drupal_goto() respects ?destination=xxx. Use an complicated URL
    // to test that the path is encoded and decoded properly.
    $destination = 'common-test/drupal_goto/destination?foo=%2525&bar=123';
    $this->drupalGet('common-test/drupal_goto/redirect', array('query' => array('destination' => $destination)));
1111
    $this->assertText('drupal_goto', t('Drupal goto redirect with destination succeeded.'));
1112
    $this->assertEqual($this->getUrl(), url('common-test/drupal_goto/destination', array('query' => array('foo' => '%25', 'bar' => '123'), 'absolute' => TRUE)), t('Drupal goto redirected to given query string destination.'));
1113
1114
1115
  }

  /**
1116
   * Test hook_drupal_goto_alter().
1117
1118
1119
1120
   */
  function testDrupalGotoAlter() {
    $this->drupalGet('common-test/drupal_goto/redirect_fail');