|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Tests for common.inc functionality. |
|
6 */ |
|
7 |
|
8 /** |
|
9 * Tests for URL generation functions. |
|
10 */ |
|
11 class DrupalAlterTestCase extends DrupalWebTestCase { |
|
12 public static function getInfo() { |
|
13 return array( |
|
14 'name' => 'drupal_alter() tests', |
|
15 'description' => 'Confirm that alteration of arguments passed to drupal_alter() works correctly.', |
|
16 'group' => 'System', |
|
17 ); |
|
18 } |
|
19 |
|
20 function setUp() { |
|
21 parent::setUp('common_test'); |
|
22 } |
|
23 |
|
24 function testDrupalAlter() { |
|
25 // This test depends on Bartik, so make sure that it is always the current |
|
26 // active theme. |
|
27 global $theme, $base_theme_info; |
|
28 $theme = 'bartik'; |
|
29 $base_theme_info = array(); |
|
30 |
|
31 $array = array('foo' => 'bar'); |
|
32 $entity = new stdClass(); |
|
33 $entity->foo = 'bar'; |
|
34 |
|
35 // Verify alteration of a single argument. |
|
36 $array_copy = $array; |
|
37 $array_expected = array('foo' => 'Drupal theme'); |
|
38 drupal_alter('drupal_alter', $array_copy); |
|
39 $this->assertEqual($array_copy, $array_expected, 'Single array was altered.'); |
|
40 |
|
41 $entity_copy = clone $entity; |
|
42 $entity_expected = clone $entity; |
|
43 $entity_expected->foo = 'Drupal theme'; |
|
44 drupal_alter('drupal_alter', $entity_copy); |
|
45 $this->assertEqual($entity_copy, $entity_expected, 'Single object was altered.'); |
|
46 |
|
47 // Verify alteration of multiple arguments. |
|
48 $array_copy = $array; |
|
49 $array_expected = array('foo' => 'Drupal theme'); |
|
50 $entity_copy = clone $entity; |
|
51 $entity_expected = clone $entity; |
|
52 $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 $this->assertEqual($array_copy, $array_expected, 'First argument to drupal_alter() was altered.'); |
|
57 $this->assertEqual($entity_copy, $entity_expected, 'Second argument to drupal_alter() was altered.'); |
|
58 $this->assertEqual($array2_copy, $array2_expected, 'Third argument to drupal_alter() was altered.'); |
|
59 |
|
60 // Verify alteration order when passing an array of types to drupal_alter(). |
|
61 // common_test_module_implements_alter() places 'block' implementation after |
|
62 // other modules. |
|
63 $array_copy = $array; |
|
64 $array_expected = array('foo' => 'Drupal block theme'); |
|
65 drupal_alter(array('drupal_alter', 'drupal_alter_foo'), $array_copy); |
|
66 $this->assertEqual($array_copy, $array_expected, 'hook_TYPE_alter() implementations ran in correct order.'); |
|
67 } |
|
68 } |
|
69 |
|
70 /** |
|
71 * Tests for URL generation functions. |
|
72 * |
|
73 * url() calls module_implements(), which may issue a db query, which requires |
|
74 * inheriting from a web test case rather than a unit test case. |
|
75 */ |
|
76 class CommonURLUnitTest extends DrupalWebTestCase { |
|
77 public static function getInfo() { |
|
78 return array( |
|
79 'name' => 'URL generation tests', |
|
80 'description' => 'Confirm that url(), drupal_get_query_parameters(), drupal_http_build_query(), and l() work correctly with various input.', |
|
81 'group' => 'System', |
|
82 ); |
|
83 } |
|
84 |
|
85 /** |
|
86 * Confirm that invalid text given as $path is filtered. |
|
87 */ |
|
88 function testLXSS() { |
|
89 $text = $this->randomName(); |
|
90 $path = "<SCRIPT>alert('XSS')</SCRIPT>"; |
|
91 $link = l($text, $path); |
|
92 $sanitized_path = check_url(url($path)); |
|
93 $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered', array('@path' => $path))); |
|
94 } |
|
95 |
|
96 /* |
|
97 * Tests for active class in l() function. |
|
98 */ |
|
99 function testLActiveClass() { |
|
100 $link = l($this->randomName(), $_GET['q']); |
|
101 $this->assertTrue($this->hasClass($link, 'active'), format_string('Class @class is present on link to the current page', array('@class' => 'active'))); |
|
102 } |
|
103 |
|
104 /** |
|
105 * Tests for custom class in l() function. |
|
106 */ |
|
107 function testLCustomClass() { |
|
108 $class = $this->randomName(); |
|
109 $link = l($this->randomName(), $_GET['q'], array('attributes' => array('class' => array($class)))); |
|
110 $this->assertTrue($this->hasClass($link, $class), format_string('Custom class @class is present on link when requested', array('@class' => $class))); |
|
111 $this->assertTrue($this->hasClass($link, 'active'), format_string('Class @class is present on link to the current page', array('@class' => 'active'))); |
|
112 } |
|
113 |
|
114 private function hasClass($link, $class) { |
|
115 return preg_match('|class="([^\"\s]+\s+)*' . $class . '|', $link); |
|
116 } |
|
117 |
|
118 /** |
|
119 * Test drupal_get_query_parameters(). |
|
120 */ |
|
121 function testDrupalGetQueryParameters() { |
|
122 $original = array( |
|
123 'a' => 1, |
|
124 'b' => array( |
|
125 'd' => 4, |
|
126 'e' => array( |
|
127 'f' => 5, |
|
128 ), |
|
129 ), |
|
130 'c' => 3, |
|
131 'q' => 'foo/bar', |
|
132 ); |
|
133 |
|
134 // Default arguments. |
|
135 $result = $_GET; |
|
136 unset($result['q']); |
|
137 $this->assertEqual(drupal_get_query_parameters(), $result, "\$_GET['q'] was removed."); |
|
138 |
|
139 // Default exclusion. |
|
140 $result = $original; |
|
141 unset($result['q']); |
|
142 $this->assertEqual(drupal_get_query_parameters($original), $result, "'q' was removed."); |
|
143 |
|
144 // First-level exclusion. |
|
145 $result = $original; |
|
146 unset($result['b']); |
|
147 $this->assertEqual(drupal_get_query_parameters($original, array('b')), $result, "'b' was removed."); |
|
148 |
|
149 // Second-level exclusion. |
|
150 $result = $original; |
|
151 unset($result['b']['d']); |
|
152 $this->assertEqual(drupal_get_query_parameters($original, array('b[d]')), $result, "'b[d]' was removed."); |
|
153 |
|
154 // Third-level exclusion. |
|
155 $result = $original; |
|
156 unset($result['b']['e']['f']); |
|
157 $this->assertEqual(drupal_get_query_parameters($original, array('b[e][f]')), $result, "'b[e][f]' was removed."); |
|
158 |
|
159 // Multiple exclusions. |
|
160 $result = $original; |
|
161 unset($result['a'], $result['b']['e'], $result['c']); |
|
162 $this->assertEqual(drupal_get_query_parameters($original, array('a', 'b[e]', 'c')), $result, "'a', 'b[e]', 'c' were removed."); |
|
163 } |
|
164 |
|
165 /** |
|
166 * Test drupal_http_build_query(). |
|
167 */ |
|
168 function testDrupalHttpBuildQuery() { |
|
169 $this->assertEqual(drupal_http_build_query(array('a' => ' &#//+%20@۞')), 'a=%20%26%23//%2B%2520%40%DB%9E', 'Value was properly encoded.'); |
|
170 $this->assertEqual(drupal_http_build_query(array(' &#//+%20@۞' => 'a')), '%20%26%23%2F%2F%2B%2520%40%DB%9E=a', 'Key was properly encoded.'); |
|
171 $this->assertEqual(drupal_http_build_query(array('a' => '1', 'b' => '2', 'c' => '3')), 'a=1&b=2&c=3', 'Multiple values were properly concatenated.'); |
|
172 $this->assertEqual(drupal_http_build_query(array('a' => array('b' => '2', 'c' => '3'), 'd' => 'foo')), 'a%5Bb%5D=2&a%5Bc%5D=3&d=foo', 'Nested array was properly encoded.'); |
|
173 } |
|
174 |
|
175 /** |
|
176 * Test drupal_parse_url(). |
|
177 */ |
|
178 function testDrupalParseUrl() { |
|
179 // Relative URL. |
|
180 $url = 'foo/bar?foo=bar&bar=baz&baz#foo'; |
|
181 $result = array( |
|
182 'path' => 'foo/bar', |
|
183 'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''), |
|
184 'fragment' => 'foo', |
|
185 ); |
|
186 $this->assertEqual(drupal_parse_url($url), $result, 'Relative URL parsed correctly.'); |
|
187 |
|
188 // Relative URL that is known to confuse parse_url(). |
|
189 $url = 'foo/bar:1'; |
|
190 $result = array( |
|
191 'path' => 'foo/bar:1', |
|
192 'query' => array(), |
|
193 'fragment' => '', |
|
194 ); |
|
195 $this->assertEqual(drupal_parse_url($url), $result, 'Relative URL parsed correctly.'); |
|
196 |
|
197 // Absolute URL. |
|
198 $url = '/foo/bar?foo=bar&bar=baz&baz#foo'; |
|
199 $result = array( |
|
200 'path' => '/foo/bar', |
|
201 'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''), |
|
202 'fragment' => 'foo', |
|
203 ); |
|
204 $this->assertEqual(drupal_parse_url($url), $result, 'Absolute URL parsed correctly.'); |
|
205 |
|
206 // External URL testing. |
|
207 $url = 'http://drupal.org/foo/bar?foo=bar&bar=baz&baz#foo'; |
|
208 |
|
209 // Test that drupal can recognize an absolute URL. Used to prevent attack vectors. |
|
210 $this->assertTrue(url_is_external($url), 'Correctly identified an external URL.'); |
|
211 |
|
212 // External URL without an explicit protocol. |
|
213 $url = '//drupal.org/foo/bar?foo=bar&bar=baz&baz#foo'; |
|
214 $this->assertTrue(url_is_external($url), 'Correctly identified an external URL without a protocol part.'); |
|
215 |
|
216 // Internal URL starting with a slash. |
|
217 $url = '/drupal.org'; |
|
218 $this->assertFalse(url_is_external($url), 'Correctly identified an internal URL with a leading slash.'); |
|
219 |
|
220 // Test the parsing of absolute URLs. |
|
221 $url = 'http://drupal.org/foo/bar?foo=bar&bar=baz&baz#foo'; |
|
222 $result = array( |
|
223 'path' => 'http://drupal.org/foo/bar', |
|
224 'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''), |
|
225 'fragment' => 'foo', |
|
226 ); |
|
227 $this->assertEqual(drupal_parse_url($url), $result, 'External URL parsed correctly.'); |
|
228 |
|
229 // Verify proper parsing of URLs when clean URLs are disabled. |
|
230 $result = array( |
|
231 'path' => 'foo/bar', |
|
232 'query' => array('bar' => 'baz'), |
|
233 'fragment' => 'foo', |
|
234 ); |
|
235 // Non-clean URLs #1: Absolute URL generated by url(). |
|
236 $url = $GLOBALS['base_url'] . '/?q=foo/bar&bar=baz#foo'; |
|
237 $this->assertEqual(drupal_parse_url($url), $result, 'Absolute URL with clean URLs disabled parsed correctly.'); |
|
238 |
|
239 // Non-clean URLs #2: Relative URL generated by url(). |
|
240 $url = '?q=foo/bar&bar=baz#foo'; |
|
241 $this->assertEqual(drupal_parse_url($url), $result, 'Relative URL with clean URLs disabled parsed correctly.'); |
|
242 |
|
243 // Non-clean URLs #3: URL generated by url() on non-Apache webserver. |
|
244 $url = 'index.php?q=foo/bar&bar=baz#foo'; |
|
245 $this->assertEqual(drupal_parse_url($url), $result, 'Relative URL on non-Apache webserver with clean URLs disabled parsed correctly.'); |
|
246 |
|
247 // Test that drupal_parse_url() does not allow spoofing a URL to force a malicious redirect. |
|
248 $parts = drupal_parse_url('forged:http://cwe.mitre.org/data/definitions/601.html'); |
|
249 $this->assertFalse(valid_url($parts['path'], TRUE), 'drupal_parse_url() correctly parsed a forged URL.'); |
|
250 } |
|
251 |
|
252 /** |
|
253 * Test url() with/without query, with/without fragment, absolute on/off and |
|
254 * assert all that works when clean URLs are on and off. |
|
255 */ |
|
256 function testUrl() { |
|
257 global $base_url; |
|
258 |
|
259 foreach (array(FALSE, TRUE) as $absolute) { |
|
260 // Get the expected start of the path string. |
|
261 $base = $absolute ? $base_url . '/' : base_path(); |
|
262 $absolute_string = $absolute ? 'absolute' : NULL; |
|
263 |
|
264 // Disable Clean URLs. |
|
265 $GLOBALS['conf']['clean_url'] = 0; |
|
266 |
|
267 $url = $base . '?q=node/123'; |
|
268 $result = url('node/123', array('absolute' => $absolute)); |
|
269 $this->assertEqual($url, $result, "$url == $result"); |
|
270 |
|
271 $url = $base . '?q=node/123#foo'; |
|
272 $result = url('node/123', array('fragment' => 'foo', 'absolute' => $absolute)); |
|
273 $this->assertEqual($url, $result, "$url == $result"); |
|
274 |
|
275 $url = $base . '?q=node/123&foo'; |
|
276 $result = url('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute)); |
|
277 $this->assertEqual($url, $result, "$url == $result"); |
|
278 |
|
279 $url = $base . '?q=node/123&foo=bar&bar=baz'; |
|
280 $result = url('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute)); |
|
281 $this->assertEqual($url, $result, "$url == $result"); |
|
282 |
|
283 $url = $base . '?q=node/123&foo#bar'; |
|
284 $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute)); |
|
285 $this->assertEqual($url, $result, "$url == $result"); |
|
286 |
|
287 $url = $base . '?q=node/123&foo#0'; |
|
288 $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => '0', 'absolute' => $absolute)); |
|
289 $this->assertEqual($url, $result, "$url == $result"); |
|
290 |
|
291 $url = $base . '?q=node/123&foo'; |
|
292 $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => '', 'absolute' => $absolute)); |
|
293 $this->assertEqual($url, $result, "$url == $result"); |
|
294 |
|
295 $url = $base; |
|
296 $result = url('<front>', array('absolute' => $absolute)); |
|
297 $this->assertEqual($url, $result, "$url == $result"); |
|
298 |
|
299 // Enable Clean URLs. |
|
300 $GLOBALS['conf']['clean_url'] = 1; |
|
301 |
|
302 $url = $base . 'node/123'; |
|
303 $result = url('node/123', array('absolute' => $absolute)); |
|
304 $this->assertEqual($url, $result, "$url == $result"); |
|
305 |
|
306 $url = $base . 'node/123#foo'; |
|
307 $result = url('node/123', array('fragment' => 'foo', 'absolute' => $absolute)); |
|
308 $this->assertEqual($url, $result, "$url == $result"); |
|
309 |
|
310 $url = $base . 'node/123?foo'; |
|
311 $result = url('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute)); |
|
312 $this->assertEqual($url, $result, "$url == $result"); |
|
313 |
|
314 $url = $base . 'node/123?foo=bar&bar=baz'; |
|
315 $result = url('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute)); |
|
316 $this->assertEqual($url, $result, "$url == $result"); |
|
317 |
|
318 $url = $base . 'node/123?foo#bar'; |
|
319 $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute)); |
|
320 $this->assertEqual($url, $result, "$url == $result"); |
|
321 |
|
322 $url = $base; |
|
323 $result = url('<front>', array('absolute' => $absolute)); |
|
324 $this->assertEqual($url, $result, "$url == $result"); |
|
325 } |
|
326 } |
|
327 |
|
328 /** |
|
329 * Test external URL handling. |
|
330 */ |
|
331 function testExternalUrls() { |
|
332 $test_url = 'http://drupal.org/'; |
|
333 |
|
334 // Verify external URL can contain a fragment. |
|
335 $url = $test_url . '#drupal'; |
|
336 $result = url($url); |
|
337 $this->assertEqual($url, $result, 'External URL with fragment works without a fragment in $options.'); |
|
338 |
|
339 // Verify fragment can be overidden in an external URL. |
|
340 $url = $test_url . '#drupal'; |
|
341 $fragment = $this->randomName(10); |
|
342 $result = url($url, array('fragment' => $fragment)); |
|
343 $this->assertEqual($test_url . '#' . $fragment, $result, 'External URL fragment is overidden with a custom fragment in $options.'); |
|
344 |
|
345 // Verify external URL can contain a query string. |
|
346 $url = $test_url . '?drupal=awesome'; |
|
347 $result = url($url); |
|
348 $this->assertEqual($url, $result, 'External URL with query string works without a query string in $options.'); |
|
349 |
|
350 // Verify external URL can be extended with a query string. |
|
351 $url = $test_url; |
|
352 $query = array($this->randomName(5) => $this->randomName(5)); |
|
353 $result = url($url, array('query' => $query)); |
|
354 $this->assertEqual($url . '?' . http_build_query($query, '', '&'), $result, 'External URL can be extended with a query string in $options.'); |
|
355 |
|
356 // Verify query string can be extended in an external URL. |
|
357 $url = $test_url . '?drupal=awesome'; |
|
358 $query = array($this->randomName(5) => $this->randomName(5)); |
|
359 $result = url($url, array('query' => $query)); |
|
360 $this->assertEqual($url . '&' . http_build_query($query, '', '&'), $result, 'External URL query string can be extended with a custom query string in $options.'); |
|
361 |
|
362 // Verify that an internal URL does not result in an external URL without |
|
363 // protocol part. |
|
364 $url = '/drupal.org'; |
|
365 $result = url($url); |
|
366 $this->assertTrue(strpos($result, '//') === FALSE, 'Internal URL does not turn into an external URL.'); |
|
367 |
|
368 // Verify that an external URL without protocol part is recognized as such. |
|
369 $url = '//drupal.org'; |
|
370 $result = url($url); |
|
371 $this->assertEqual($url, $result, 'External URL without protocol is not altered.'); |
|
372 } |
|
373 } |
|
374 |
|
375 /** |
|
376 * Tests url_is_external(). |
|
377 */ |
|
378 class UrlIsExternalUnitTest extends DrupalUnitTestCase { |
|
379 |
|
380 public static function getInfo() { |
|
381 return array( |
|
382 'name' => 'External URL checking', |
|
383 'description' => 'Performs tests on url_is_external().', |
|
384 'group' => 'System', |
|
385 ); |
|
386 } |
|
387 |
|
388 /** |
|
389 * Tests if each URL is external or not. |
|
390 */ |
|
391 function testUrlIsExternal() { |
|
392 foreach ($this->examples() as $path => $expected) { |
|
393 $this->assertIdentical(url_is_external($path), $expected, $path); |
|
394 } |
|
395 } |
|
396 |
|
397 /** |
|
398 * Provides data for testUrlIsExternal(). |
|
399 * |
|
400 * @return array |
|
401 * An array of test data, keyed by a path, with the expected value where |
|
402 * TRUE is external, and FALSE is not external. |
|
403 */ |
|
404 protected function examples() { |
|
405 return array( |
|
406 // Simple external URLs. |
|
407 'http://example.com' => TRUE, |
|
408 'https://example.com' => TRUE, |
|
409 'http://drupal.org/foo/bar?foo=bar&bar=baz&baz#foo' => TRUE, |
|
410 '//drupal.org' => TRUE, |
|
411 // Some browsers ignore or strip leading control characters. |
|
412 "\x00//www.example.com" => TRUE, |
|
413 "\x08//www.example.com" => TRUE, |
|
414 "\x1F//www.example.com" => TRUE, |
|
415 "\n//www.example.com" => TRUE, |
|
416 // JSON supports decoding directly from UTF-8 code points. |
|
417 json_decode('"\u00AD"') . "//www.example.com" => TRUE, |
|
418 json_decode('"\u200E"') . "//www.example.com" => TRUE, |
|
419 json_decode('"\uE0020"') . "//www.example.com" => TRUE, |
|
420 json_decode('"\uE000"') . "//www.example.com" => TRUE, |
|
421 // Backslashes should be normalized to forward. |
|
422 '\\\\example.com' => TRUE, |
|
423 // Local URLs. |
|
424 'node' => FALSE, |
|
425 '/system/ajax' => FALSE, |
|
426 '?q=foo:bar' => FALSE, |
|
427 'node/edit:me' => FALSE, |
|
428 '/drupal.org' => FALSE, |
|
429 '<front>' => FALSE, |
|
430 ); |
|
431 } |
|
432 } |
|
433 |
|
434 /** |
|
435 * Tests for check_plain(), filter_xss(), format_string(), and check_url(). |
|
436 */ |
|
437 class CommonXssUnitTest extends DrupalUnitTestCase { |
|
438 |
|
439 public static function getInfo() { |
|
440 return array( |
|
441 'name' => 'String filtering tests', |
|
442 'description' => 'Confirm that check_plain(), filter_xss(), format_string() and check_url() work correctly, including invalid multi-byte sequences.', |
|
443 'group' => 'System', |
|
444 ); |
|
445 } |
|
446 |
|
447 /** |
|
448 * Check that invalid multi-byte sequences are rejected. |
|
449 */ |
|
450 function testInvalidMultiByte() { |
|
451 // Ignore PHP 5.3+ invalid multibyte sequence warning. |
|
452 $text = @check_plain("Foo\xC0barbaz"); |
|
453 $this->assertEqual($text, '', 'check_plain() rejects invalid sequence "Foo\xC0barbaz"'); |
|
454 // Ignore PHP 5.3+ invalid multibyte sequence warning. |
|
455 $text = @check_plain("\xc2\""); |
|
456 $this->assertEqual($text, '', 'check_plain() rejects invalid sequence "\xc2\""'); |
|
457 $text = check_plain("Fooÿñ"); |
|
458 $this->assertEqual($text, "Fooÿñ", 'check_plain() accepts valid sequence "Fooÿñ"'); |
|
459 $text = filter_xss("Foo\xC0barbaz"); |
|
460 $this->assertEqual($text, '', 'filter_xss() rejects invalid sequence "Foo\xC0barbaz"'); |
|
461 $text = filter_xss("Fooÿñ"); |
|
462 $this->assertEqual($text, "Fooÿñ", 'filter_xss() accepts valid sequence Fooÿñ'); |
|
463 } |
|
464 |
|
465 /** |
|
466 * Check that special characters are escaped. |
|
467 */ |
|
468 function testEscaping() { |
|
469 $text = check_plain("<script>"); |
|
470 $this->assertEqual($text, '<script>', 'check_plain() escapes <script>'); |
|
471 $text = check_plain('<>&"\''); |
|
472 $this->assertEqual($text, '<>&"'', 'check_plain() escapes reserved HTML characters.'); |
|
473 } |
|
474 |
|
475 /** |
|
476 * Test t() and format_string() replacement functionality. |
|
477 */ |
|
478 function testFormatStringAndT() { |
|
479 foreach (array('format_string', 't') as $function) { |
|
480 $text = $function('Simple text'); |
|
481 $this->assertEqual($text, 'Simple text', $function . ' leaves simple text alone.'); |
|
482 $text = $function('Escaped text: @value', array('@value' => '<script>')); |
|
483 $this->assertEqual($text, 'Escaped text: <script>', $function . ' replaces and escapes string.'); |
|
484 $text = $function('Placeholder text: %value', array('%value' => '<script>')); |
|
485 $this->assertEqual($text, 'Placeholder text: <em class="placeholder"><script></em>', $function . ' replaces, escapes and themes string.'); |
|
486 $text = $function('Verbatim text: !value', array('!value' => '<script>')); |
|
487 $this->assertEqual($text, 'Verbatim text: <script>', $function . ' replaces verbatim string as-is.'); |
|
488 } |
|
489 } |
|
490 |
|
491 /** |
|
492 * Check that harmful protocols are stripped. |
|
493 */ |
|
494 function testBadProtocolStripping() { |
|
495 // Ensure that check_url() strips out harmful protocols, and encodes for |
|
496 // HTML. Ensure drupal_strip_dangerous_protocols() can be used to return a |
|
497 // plain-text string stripped of harmful protocols. |
|
498 $url = 'javascript:http://www.example.com/?x=1&y=2'; |
|
499 $expected_plain = 'http://www.example.com/?x=1&y=2'; |
|
500 $expected_html = 'http://www.example.com/?x=1&y=2'; |
|
501 $this->assertIdentical(check_url($url), $expected_html, 'check_url() filters a URL and encodes it for HTML.'); |
|
502 $this->assertIdentical(drupal_strip_dangerous_protocols($url), $expected_plain, 'drupal_strip_dangerous_protocols() filters a URL and returns plain text.'); |
|
503 } |
|
504 } |
|
505 |
|
506 /** |
|
507 * Tests file size parsing and formatting functions. |
|
508 */ |
|
509 class CommonSizeTestCase extends DrupalUnitTestCase { |
|
510 protected $exact_test_cases; |
|
511 protected $rounded_test_cases; |
|
512 |
|
513 public static function getInfo() { |
|
514 return array( |
|
515 'name' => 'Size parsing test', |
|
516 'description' => 'Parse a predefined amount of bytes and compare the output with the expected value.', |
|
517 'group' => 'System' |
|
518 ); |
|
519 } |
|
520 |
|
521 function setUp() { |
|
522 $kb = DRUPAL_KILOBYTE; |
|
523 $this->exact_test_cases = array( |
|
524 '1 byte' => 1, |
|
525 '1 KB' => $kb, |
|
526 '1 MB' => $kb * $kb, |
|
527 '1 GB' => $kb * $kb * $kb, |
|
528 '1 TB' => $kb * $kb * $kb * $kb, |
|
529 '1 PB' => $kb * $kb * $kb * $kb * $kb, |
|
530 '1 EB' => $kb * $kb * $kb * $kb * $kb * $kb, |
|
531 '1 ZB' => $kb * $kb * $kb * $kb * $kb * $kb * $kb, |
|
532 '1 YB' => $kb * $kb * $kb * $kb * $kb * $kb * $kb * $kb, |
|
533 ); |
|
534 $this->rounded_test_cases = array( |
|
535 '2 bytes' => 2, |
|
536 '1 MB' => ($kb * $kb) - 1, // rounded to 1 MB (not 1000 or 1024 kilobyte!) |
|
537 round(3623651 / ($this->exact_test_cases['1 MB']), 2) . ' MB' => 3623651, // megabytes |
|
538 round(67234178751368124 / ($this->exact_test_cases['1 PB']), 2) . ' PB' => 67234178751368124, // petabytes |
|
539 round(235346823821125814962843827 / ($this->exact_test_cases['1 YB']), 2) . ' YB' => 235346823821125814962843827, // yottabytes |
|
540 ); |
|
541 parent::setUp(); |
|
542 } |
|
543 |
|
544 /** |
|
545 * Check that format_size() returns the expected string. |
|
546 */ |
|
547 function testCommonFormatSize() { |
|
548 foreach (array($this->exact_test_cases, $this->rounded_test_cases) as $test_cases) { |
|
549 foreach ($test_cases as $expected => $input) { |
|
550 $this->assertEqual( |
|
551 ($result = format_size($input, NULL)), |
|
552 $expected, |
|
553 $expected . ' == ' . $result . ' (' . $input . ' bytes)' |
|
554 ); |
|
555 } |
|
556 } |
|
557 } |
|
558 |
|
559 /** |
|
560 * Check that parse_size() returns the proper byte sizes. |
|
561 */ |
|
562 function testCommonParseSize() { |
|
563 foreach ($this->exact_test_cases as $string => $size) { |
|
564 $this->assertEqual( |
|
565 $parsed_size = parse_size($string), |
|
566 $size, |
|
567 $size . ' == ' . $parsed_size . ' (' . $string . ')' |
|
568 ); |
|
569 } |
|
570 |
|
571 // Some custom parsing tests |
|
572 $string = '23476892 bytes'; |
|
573 $this->assertEqual( |
|
574 ($parsed_size = parse_size($string)), |
|
575 $size = 23476892, |
|
576 $string . ' == ' . $parsed_size . ' bytes' |
|
577 ); |
|
578 $string = '76MRandomStringThatShouldBeIgnoredByParseSize.'; // 76 MB |
|
579 $this->assertEqual( |
|
580 $parsed_size = parse_size($string), |
|
581 $size = 79691776, |
|
582 $string . ' == ' . $parsed_size . ' bytes' |
|
583 ); |
|
584 $string = '76.24 Giggabyte'; // Misspeld text -> 76.24 GB |
|
585 $this->assertEqual( |
|
586 $parsed_size = parse_size($string), |
|
587 $size = 81862076662, |
|
588 $string . ' == ' . $parsed_size . ' bytes' |
|
589 ); |
|
590 } |
|
591 |
|
592 /** |
|
593 * Cross-test parse_size() and format_size(). |
|
594 */ |
|
595 function testCommonParseSizeFormatSize() { |
|
596 foreach ($this->exact_test_cases as $size) { |
|
597 $this->assertEqual( |
|
598 $size, |
|
599 ($parsed_size = parse_size($string = format_size($size, NULL))), |
|
600 $size . ' == ' . $parsed_size . ' (' . $string . ')' |
|
601 ); |
|
602 } |
|
603 } |
|
604 } |
|
605 |
|
606 /** |
|
607 * Test drupal_explode_tags() and drupal_implode_tags(). |
|
608 */ |
|
609 class DrupalTagsHandlingTestCase extends DrupalUnitTestCase { |
|
610 var $validTags = array( |
|
611 'Drupal' => 'Drupal', |
|
612 'Drupal with some spaces' => 'Drupal with some spaces', |
|
613 '"Legendary Drupal mascot of doom: ""Druplicon"""' => 'Legendary Drupal mascot of doom: "Druplicon"', |
|
614 '"Drupal, although it rhymes with sloopal, is as awesome as a troopal!"' => 'Drupal, although it rhymes with sloopal, is as awesome as a troopal!', |
|
615 ); |
|
616 |
|
617 public static function getInfo() { |
|
618 return array( |
|
619 'name' => 'Drupal tags handling', |
|
620 'description' => "Performs tests on Drupal's handling of tags, both explosion and implosion tactics used.", |
|
621 'group' => 'System' |
|
622 ); |
|
623 } |
|
624 |
|
625 /** |
|
626 * Explode a series of tags. |
|
627 */ |
|
628 function testDrupalExplodeTags() { |
|
629 $string = implode(', ', array_keys($this->validTags)); |
|
630 $tags = drupal_explode_tags($string); |
|
631 $this->assertTags($tags); |
|
632 } |
|
633 |
|
634 /** |
|
635 * Implode a series of tags. |
|
636 */ |
|
637 function testDrupalImplodeTags() { |
|
638 $tags = array_values($this->validTags); |
|
639 // Let's explode and implode to our heart's content. |
|
640 for ($i = 0; $i < 10; $i++) { |
|
641 $string = drupal_implode_tags($tags); |
|
642 $tags = drupal_explode_tags($string); |
|
643 } |
|
644 $this->assertTags($tags); |
|
645 } |
|
646 |
|
647 /** |
|
648 * Helper function: asserts that the ending array of tags is what we wanted. |
|
649 */ |
|
650 function assertTags($tags) { |
|
651 $original = $this->validTags; |
|
652 foreach ($tags as $tag) { |
|
653 $key = array_search($tag, $original); |
|
654 $this->assertTrue($key, format_string('Make sure tag %tag shows up in the final tags array (originally %original)', array('%tag' => $tag, '%original' => $key))); |
|
655 unset($original[$key]); |
|
656 } |
|
657 foreach ($original as $leftover) { |
|
658 $this->fail(format_string('Leftover tag %leftover was left over.', array('%leftover' => $leftover))); |
|
659 } |
|
660 } |
|
661 } |
|
662 |
|
663 /** |
|
664 * Test the Drupal CSS system. |
|
665 */ |
|
666 class CascadingStylesheetsTestCase extends DrupalWebTestCase { |
|
667 public static function getInfo() { |
|
668 return array( |
|
669 'name' => 'Cascading stylesheets', |
|
670 'description' => 'Tests adding various cascading stylesheets to the page.', |
|
671 'group' => 'System', |
|
672 ); |
|
673 } |
|
674 |
|
675 function setUp() { |
|
676 parent::setUp('php', 'locale', 'common_test'); |
|
677 // Reset drupal_add_css() before each test. |
|
678 drupal_static_reset('drupal_add_css'); |
|
679 } |
|
680 |
|
681 /** |
|
682 * Check default stylesheets as empty. |
|
683 */ |
|
684 function testDefault() { |
|
685 $this->assertEqual(array(), drupal_add_css(), 'Default CSS is empty.'); |
|
686 } |
|
687 |
|
688 /** |
|
689 * Test that stylesheets in module .info files are loaded. |
|
690 */ |
|
691 function testModuleInfo() { |
|
692 $this->drupalGet(''); |
|
693 |
|
694 // Verify common_test.css in a STYLE media="all" tag. |
|
695 $elements = $this->xpath('//style[@media=:media and contains(text(), :filename)]', array( |
|
696 ':media' => 'all', |
|
697 ':filename' => 'tests/common_test.css', |
|
698 )); |
|
699 $this->assertTrue(count($elements), "Stylesheet with media 'all' in module .info file found."); |
|
700 |
|
701 // Verify common_test.print.css in a STYLE media="print" tag. |
|
702 $elements = $this->xpath('//style[@media=:media and contains(text(), :filename)]', array( |
|
703 ':media' => 'print', |
|
704 ':filename' => 'tests/common_test.print.css', |
|
705 )); |
|
706 $this->assertTrue(count($elements), "Stylesheet with media 'print' in module .info file found."); |
|
707 } |
|
708 |
|
709 /** |
|
710 * Tests adding a file stylesheet. |
|
711 */ |
|
712 function testAddFile() { |
|
713 $path = drupal_get_path('module', 'simpletest') . '/simpletest.css'; |
|
714 $css = drupal_add_css($path); |
|
715 $this->assertEqual($css[$path]['data'], $path, 'Adding a CSS file caches it properly.'); |
|
716 } |
|
717 |
|
718 /** |
|
719 * Tests adding an external stylesheet. |
|
720 */ |
|
721 function testAddExternal() { |
|
722 $path = 'http://example.com/style.css'; |
|
723 $css = drupal_add_css($path, 'external'); |
|
724 $this->assertEqual($css[$path]['type'], 'external', 'Adding an external CSS file caches it properly.'); |
|
725 } |
|
726 |
|
727 /** |
|
728 * Makes sure that reseting the CSS empties the cache. |
|
729 */ |
|
730 function testReset() { |
|
731 drupal_static_reset('drupal_add_css'); |
|
732 $this->assertEqual(array(), drupal_add_css(), 'Resetting the CSS empties the cache.'); |
|
733 } |
|
734 |
|
735 /** |
|
736 * Tests rendering the stylesheets. |
|
737 */ |
|
738 function testRenderFile() { |
|
739 $css = drupal_get_path('module', 'simpletest') . '/simpletest.css'; |
|
740 drupal_add_css($css); |
|
741 $styles = drupal_get_css(); |
|
742 $this->assertTrue(strpos($styles, $css) > 0, 'Rendered CSS includes the added stylesheet.'); |
|
743 // Verify that newlines are properly added inside style tags. |
|
744 $query_string = variable_get('css_js_query_string', '0'); |
|
745 $css_processed = "<style type=\"text/css\" media=\"all\">\n@import url(\"" . check_plain(file_create_url($css)) . "?" . $query_string ."\");\n</style>"; |
|
746 $this->assertEqual(trim($styles), $css_processed, 'Rendered CSS includes newlines inside style tags for JavaScript use.'); |
|
747 } |
|
748 |
|
749 /** |
|
750 * Tests rendering an external stylesheet. |
|
751 */ |
|
752 function testRenderExternal() { |
|
753 $css = 'http://example.com/style.css'; |
|
754 drupal_add_css($css, 'external'); |
|
755 $styles = drupal_get_css(); |
|
756 // Stylesheet URL may be the href of a LINK tag or in an @import statement |
|
757 // of a STYLE tag. |
|
758 $this->assertTrue(strpos($styles, 'href="' . $css) > 0 || strpos($styles, '@import url("' . $css . '")') > 0, 'Rendering an external CSS file.'); |
|
759 } |
|
760 |
|
761 /** |
|
762 * Tests rendering inline stylesheets with preprocessing on. |
|
763 */ |
|
764 function testRenderInlinePreprocess() { |
|
765 $css = 'body { padding: 0px; }'; |
|
766 $css_preprocessed = '<style type="text/css" media="all">' . "\n<!--/*--><![CDATA[/*><!--*/\n" . drupal_load_stylesheet_content($css, TRUE) . "\n/*]]>*/-->\n" . '</style>'; |
|
767 drupal_add_css($css, array('type' => 'inline')); |
|
768 $styles = drupal_get_css(); |
|
769 $this->assertEqual(trim($styles), $css_preprocessed, 'Rendering preprocessed inline CSS adds it to the page.'); |
|
770 } |
|
771 |
|
772 /** |
|
773 * Tests removing charset when rendering stylesheets with preprocessing on. |
|
774 */ |
|
775 function testRenderRemoveCharsetPreprocess() { |
|
776 $cases = array( |
|
777 array( |
|
778 'asset' => '@charset "UTF-8";html{font-family:"sans-serif";}', |
|
779 'expected' => 'html{font-family:"sans-serif";}', |
|
780 ), |
|
781 // This asset contains extra \n character. |
|
782 array( |
|
783 'asset' => "@charset 'UTF-8';\nhtml{font-family:'sans-serif';}", |
|
784 'expected' => "\nhtml{font-family:'sans-serif';}", |
|
785 ), |
|
786 ); |
|
787 |
|
788 foreach ($cases as $case) { |
|
789 $this->assertEqual( |
|
790 $case['expected'], |
|
791 drupal_load_stylesheet_content($case['asset']), |
|
792 'CSS optimizing correctly removes the charset declaration.' |
|
793 ); |
|
794 } |
|
795 } |
|
796 |
|
797 /** |
|
798 * Tests rendering inline stylesheets with preprocessing off. |
|
799 */ |
|
800 function testRenderInlineNoPreprocess() { |
|
801 $css = 'body { padding: 0px; }'; |
|
802 drupal_add_css($css, array('type' => 'inline', 'preprocess' => FALSE)); |
|
803 $styles = drupal_get_css(); |
|
804 $this->assertTrue(strpos($styles, $css) > 0, 'Rendering non-preprocessed inline CSS adds it to the page.'); |
|
805 } |
|
806 |
|
807 /** |
|
808 * Tests rendering inline stylesheets through a full page request. |
|
809 */ |
|
810 function testRenderInlineFullPage() { |
|
811 $css = 'body { font-size: 254px; }'; |
|
812 // Inline CSS is minified unless 'preprocess' => FALSE is passed as a |
|
813 // drupal_add_css() option. |
|
814 $expected = 'body{font-size:254px;}'; |
|
815 |
|
816 // Create a node, using the PHP filter that tests drupal_add_css(). |
|
817 $php_format_id = 'php_code'; |
|
818 $settings = array( |
|
819 'type' => 'page', |
|
820 'body' => array( |
|
821 LANGUAGE_NONE => array( |
|
822 array( |
|
823 'value' => t('This tests the inline CSS!') . "<?php drupal_add_css('$css', 'inline'); ?>", |
|
824 'format' => $php_format_id, |
|
825 ), |
|
826 ), |
|
827 ), |
|
828 'promote' => 1, |
|
829 ); |
|
830 $node = $this->drupalCreateNode($settings); |
|
831 |
|
832 // Fetch the page. |
|
833 $this->drupalGet('node/' . $node->nid); |
|
834 $this->assertRaw($expected, 'Inline stylesheets appear in the full page rendering.'); |
|
835 } |
|
836 |
|
837 /** |
|
838 * Test CSS ordering. |
|
839 */ |
|
840 function testRenderOrder() { |
|
841 // A module CSS file. |
|
842 drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css'); |
|
843 // A few system CSS files, ordered in a strange way. |
|
844 $system_path = drupal_get_path('module', 'system'); |
|
845 drupal_add_css($system_path . '/system.menus.css', array('group' => CSS_SYSTEM)); |
|
846 drupal_add_css($system_path . '/system.base.css', array('group' => CSS_SYSTEM, 'weight' => -10)); |
|
847 drupal_add_css($system_path . '/system.theme.css', array('group' => CSS_SYSTEM)); |
|
848 |
|
849 $expected = array( |
|
850 $system_path . '/system.base.css', |
|
851 $system_path . '/system.menus.css', |
|
852 $system_path . '/system.theme.css', |
|
853 drupal_get_path('module', 'simpletest') . '/simpletest.css', |
|
854 ); |
|
855 |
|
856 |
|
857 $styles = drupal_get_css(); |
|
858 // Stylesheet URL may be the href of a LINK tag or in an @import statement |
|
859 // of a STYLE tag. |
|
860 if (preg_match_all('/(href="|url\(")' . preg_quote($GLOBALS['base_url'] . '/', '/') . '([^?]+)\?/', $styles, $matches)) { |
|
861 $result = $matches[2]; |
|
862 } |
|
863 else { |
|
864 $result = array(); |
|
865 } |
|
866 |
|
867 $this->assertIdentical($result, $expected, 'The CSS files are in the expected order.'); |
|
868 } |
|
869 |
|
870 /** |
|
871 * Test CSS override. |
|
872 */ |
|
873 function testRenderOverride() { |
|
874 $system = drupal_get_path('module', 'system'); |
|
875 $simpletest = drupal_get_path('module', 'simpletest'); |
|
876 |
|
877 drupal_add_css($system . '/system.base.css'); |
|
878 drupal_add_css($simpletest . '/tests/system.base.css'); |
|
879 |
|
880 // The dummy stylesheet should be the only one included. |
|
881 $styles = drupal_get_css(); |
|
882 $this->assert(strpos($styles, $simpletest . '/tests/system.base.css') !== FALSE, 'The overriding CSS file is output.'); |
|
883 $this->assert(strpos($styles, $system . '/system.base.css') === FALSE, 'The overridden CSS file is not output.'); |
|
884 |
|
885 drupal_add_css($simpletest . '/tests/system.base.css'); |
|
886 drupal_add_css($system . '/system.base.css'); |
|
887 |
|
888 // The standard stylesheet should be the only one included. |
|
889 $styles = drupal_get_css(); |
|
890 $this->assert(strpos($styles, $system . '/system.base.css') !== FALSE, 'The overriding CSS file is output.'); |
|
891 $this->assert(strpos($styles, $simpletest . '/tests/system.base.css') === FALSE, 'The overridden CSS file is not output.'); |
|
892 } |
|
893 |
|
894 /** |
|
895 * Tests Locale module's CSS Alter to include RTL overrides. |
|
896 */ |
|
897 function testAlter() { |
|
898 // Switch the language to a right to left language and add system.base.css. |
|
899 global $language; |
|
900 $language->direction = LANGUAGE_RTL; |
|
901 $path = drupal_get_path('module', 'system'); |
|
902 drupal_add_css($path . '/system.base.css'); |
|
903 |
|
904 // Check to see if system.base-rtl.css was also added. |
|
905 $styles = drupal_get_css(); |
|
906 $this->assert(strpos($styles, $path . '/system.base-rtl.css') !== FALSE, 'CSS is alterable as right to left overrides are added.'); |
|
907 |
|
908 // Change the language back to left to right. |
|
909 $language->direction = LANGUAGE_LTR; |
|
910 } |
|
911 |
|
912 /** |
|
913 * Tests that the query string remains intact when adding CSS files that have |
|
914 * query string parameters. |
|
915 */ |
|
916 function testAddCssFileWithQueryString() { |
|
917 $this->drupalGet('common-test/query-string'); |
|
918 $query_string = variable_get('css_js_query_string', '0'); |
|
919 $this->assertRaw(drupal_get_path('module', 'node') . '/node.css?' . $query_string, 'Query string was appended correctly to css.'); |
|
920 $this->assertRaw(drupal_get_path('module', 'node') . '/node-fake.css?arg1=value1&arg2=value2', 'Query string not escaped on a URI.'); |
|
921 } |
|
922 } |
|
923 |
|
924 /** |
|
925 * Test for cleaning HTML identifiers. |
|
926 */ |
|
927 class DrupalHTMLIdentifierTestCase extends DrupalUnitTestCase { |
|
928 public static function getInfo() { |
|
929 return array( |
|
930 'name' => 'HTML identifiers', |
|
931 'description' => 'Test the functions drupal_html_class(), drupal_html_id() and drupal_clean_css_identifier() for expected behavior', |
|
932 'group' => 'System', |
|
933 ); |
|
934 } |
|
935 |
|
936 /** |
|
937 * Tests that drupal_clean_css_identifier() cleans the identifier properly. |
|
938 */ |
|
939 function testDrupalCleanCSSIdentifier() { |
|
940 // Verify that no valid ASCII characters are stripped from the identifier. |
|
941 $identifier = 'abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789'; |
|
942 $this->assertIdentical(drupal_clean_css_identifier($identifier, array()), $identifier, 'Verify valid ASCII characters pass through.'); |
|
943 |
|
944 // Verify that valid UTF-8 characters are not stripped from the identifier. |
|
945 $identifier = '¡¢£¤¥'; |
|
946 $this->assertIdentical(drupal_clean_css_identifier($identifier, array()), $identifier, 'Verify valid UTF-8 characters pass through.'); |
|
947 |
|
948 // Verify that invalid characters (including non-breaking space) are stripped from the identifier. |
|
949 $this->assertIdentical(drupal_clean_css_identifier('invalid !"#$%&\'()*+,./:;<=>?@[\\]^`{|}~ identifier', array()), 'invalididentifier', 'Strip invalid characters.'); |
|
950 |
|
951 // Verify that double underscores are replaced in the identifier by default. |
|
952 $identifier = 'css__identifier__with__double__underscores'; |
|
953 $expected = 'css--identifier--with--double--underscores'; |
|
954 $this->assertIdentical(drupal_clean_css_identifier($identifier), $expected, 'Verify double underscores are replaced with double hyphens by default.'); |
|
955 |
|
956 // Verify that double underscores are preserved in the identifier if the |
|
957 // variable allow_css_double_underscores is set to TRUE. |
|
958 $this->setAllowCSSDoubleUnderscores(TRUE); |
|
959 $this->assertIdentical(drupal_clean_css_identifier($identifier), $identifier, 'Verify double underscores are preserved if the allow_css_double_underscores set to TRUE.'); |
|
960 |
|
961 // To avoid affecting other test cases, set the variable |
|
962 // allow_css_double_underscores to FALSE which is the default value. |
|
963 $this->setAllowCSSDoubleUnderscores(FALSE); |
|
964 } |
|
965 |
|
966 /** |
|
967 * Set the variable allow_css_double_underscores and reset the cache. |
|
968 * |
|
969 * @param $value bool |
|
970 * A new value to be set to allow_css_double_underscores. |
|
971 */ |
|
972 function setAllowCSSDoubleUnderscores($value) { |
|
973 $GLOBALS['conf']['allow_css_double_underscores'] = $value; |
|
974 drupal_static_reset('drupal_clean_css_identifier:allow_css_double_underscores'); |
|
975 } |
|
976 |
|
977 /** |
|
978 * Tests that drupal_html_class() cleans the class name properly. |
|
979 */ |
|
980 function testDrupalHTMLClass() { |
|
981 // Verify Drupal coding standards are enforced. |
|
982 $this->assertIdentical(drupal_html_class('CLASS NAME_[Ü]'), 'class-name--ü', 'Enforce Drupal coding standards.'); |
|
983 } |
|
984 |
|
985 /** |
|
986 * Tests that drupal_html_id() cleans the ID properly. |
|
987 */ |
|
988 function testDrupalHTMLId() { |
|
989 // Verify that letters, digits, and hyphens are not stripped from the ID. |
|
990 $id = 'abcdefghijklmnopqrstuvwxyz-0123456789'; |
|
991 $this->assertIdentical(drupal_html_id($id), $id, 'Verify valid characters pass through.'); |
|
992 |
|
993 // Verify that invalid characters are stripped from the ID. |
|
994 $this->assertIdentical(drupal_html_id('invalid,./:@\\^`{Üidentifier'), 'invalididentifier', 'Strip invalid characters.'); |
|
995 |
|
996 // Verify Drupal coding standards are enforced. |
|
997 $this->assertIdentical(drupal_html_id('ID NAME_[1]'), 'id-name-1', 'Enforce Drupal coding standards.'); |
|
998 |
|
999 // Reset the static cache so we can ensure the unique id count is at zero. |
|
1000 drupal_static_reset('drupal_html_id'); |
|
1001 |
|
1002 // Clean up IDs with invalid starting characters. |
|
1003 $this->assertIdentical(drupal_html_id('test-unique-id'), 'test-unique-id', 'Test the uniqueness of IDs #1.'); |
|
1004 $this->assertIdentical(drupal_html_id('test-unique-id'), 'test-unique-id--2', 'Test the uniqueness of IDs #2.'); |
|
1005 $this->assertIdentical(drupal_html_id('test-unique-id'), 'test-unique-id--3', 'Test the uniqueness of IDs #3.'); |
|
1006 } |
|
1007 } |
|
1008 |
|
1009 /** |
|
1010 * CSS Unit Tests. |
|
1011 */ |
|
1012 class CascadingStylesheetsUnitTest extends DrupalUnitTestCase { |
|
1013 public static function getInfo() { |
|
1014 return array( |
|
1015 'name' => 'CSS Unit Tests', |
|
1016 'description' => 'Unit tests on CSS functions like aggregation.', |
|
1017 'group' => 'System', |
|
1018 ); |
|
1019 } |
|
1020 |
|
1021 /** |
|
1022 * Tests basic CSS loading with and without optimization via drupal_load_stylesheet(). |
|
1023 * |
|
1024 * Known tests: |
|
1025 * - Retain white-space in selectors. (https://drupal.org/node/472820) |
|
1026 * - Proper URLs in imported files. (https://drupal.org/node/265719) |
|
1027 * - Retain pseudo-selectors. (https://drupal.org/node/460448) |
|
1028 * - Don't adjust data URIs. (https://drupal.org/node/2142441) |
|
1029 * - Files imported from external URLs. (https://drupal.org/node/2014851) |
|
1030 */ |
|
1031 function testLoadCssBasic() { |
|
1032 // Array of files to test living in 'simpletest/files/css_test_files/'. |
|
1033 // - Original: name.css |
|
1034 // - Unoptimized expected content: name.css.unoptimized.css |
|
1035 // - Optimized expected content: name.css.optimized.css |
|
1036 $testfiles = array( |
|
1037 'css_input_without_import.css', |
|
1038 'css_input_with_import.css', |
|
1039 'css_subfolder/css_input_with_import.css', |
|
1040 'comment_hacks.css' |
|
1041 ); |
|
1042 $path = drupal_get_path('module', 'simpletest') . '/files/css_test_files'; |
|
1043 foreach ($testfiles as $file) { |
|
1044 $file_path = $path . '/' . $file; |
|
1045 $file_url = $GLOBALS['base_url'] . '/' . $file_path; |
|
1046 |
|
1047 $expected = file_get_contents($file_path . '.unoptimized.css'); |
|
1048 $unoptimized_output = drupal_load_stylesheet($file_path, FALSE); |
|
1049 $this->assertEqual($unoptimized_output, $expected, format_string('Unoptimized CSS file has expected contents (@file)', array('@file' => $file))); |
|
1050 |
|
1051 $expected = file_get_contents($file_path . '.optimized.css'); |
|
1052 $optimized_output = drupal_load_stylesheet($file_path, TRUE); |
|
1053 $this->assertEqual($optimized_output, $expected, format_string('Optimized CSS file has expected contents (@file)', array('@file' => $file))); |
|
1054 |
|
1055 // Repeat the tests by accessing the stylesheets by URL. |
|
1056 $expected = file_get_contents($file_path . '.unoptimized.css'); |
|
1057 $unoptimized_output_url = drupal_load_stylesheet($file_url, FALSE); |
|
1058 $this->assertEqual($unoptimized_output_url, $expected, format_string('Unoptimized CSS file (loaded from an URL) has expected contents (@file)', array('@file' => $file))); |
|
1059 |
|
1060 $expected = file_get_contents($file_path . '.optimized.css'); |
|
1061 $optimized_output_url = drupal_load_stylesheet($file_url, TRUE); |
|
1062 $this->assertEqual($optimized_output_url, $expected, format_string('Optimized CSS file (loaded from an URL) has expected contents (@file)', array('@file' => $file))); |
|
1063 } |
|
1064 } |
|
1065 } |
|
1066 |
|
1067 /** |
|
1068 * Test drupal_http_request(). |
|
1069 */ |
|
1070 class DrupalHTTPRequestTestCase extends DrupalWebTestCase { |
|
1071 public static function getInfo() { |
|
1072 return array( |
|
1073 'name' => 'Drupal HTTP request', |
|
1074 'description' => "Performs tests on Drupal's HTTP request mechanism.", |
|
1075 'group' => 'System' |
|
1076 ); |
|
1077 } |
|
1078 |
|
1079 function setUp() { |
|
1080 parent::setUp('system_test', 'locale'); |
|
1081 } |
|
1082 |
|
1083 function testDrupalHTTPRequest() { |
|
1084 global $is_https; |
|
1085 |
|
1086 // Parse URL schema. |
|
1087 $missing_scheme = drupal_http_request('example.com/path'); |
|
1088 $this->assertEqual($missing_scheme->code, -1002, 'Returned with "-1002" error code.'); |
|
1089 $this->assertEqual($missing_scheme->error, 'missing schema', 'Returned with "missing schema" error message.'); |
|
1090 |
|
1091 $unable_to_parse = drupal_http_request('http:///path'); |
|
1092 $this->assertEqual($unable_to_parse->code, -1001, 'Returned with "-1001" error code.'); |
|
1093 $this->assertEqual($unable_to_parse->error, 'unable to parse URL', 'Returned with "unable to parse URL" error message.'); |
|
1094 |
|
1095 // Fetch page. |
|
1096 $result = drupal_http_request(url('node', array('absolute' => TRUE))); |
|
1097 $this->assertEqual($result->code, 200, 'Fetched page successfully.'); |
|
1098 $this->drupalSetContent($result->data); |
|
1099 $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), 'Site title matches.'); |
|
1100 |
|
1101 // Test that code and status message is returned. |
|
1102 $result = drupal_http_request(url('pagedoesnotexist', array('absolute' => TRUE))); |
|
1103 $this->assertTrue(!empty($result->protocol), 'Result protocol is returned.'); |
|
1104 $this->assertEqual($result->code, '404', 'Result code is 404'); |
|
1105 $this->assertEqual($result->status_message, 'Not Found', 'Result status message is "Not Found"'); |
|
1106 |
|
1107 // Skip the timeout tests when the testing environment is HTTPS because |
|
1108 // stream_set_timeout() does not work for SSL connections. |
|
1109 // @link http://bugs.php.net/bug.php?id=47929 |
|
1110 if (!$is_https) { |
|
1111 // Test that timeout is respected. The test machine is expected to be able |
|
1112 // to make the connection (i.e. complete the fsockopen()) in 2 seconds and |
|
1113 // return within a total of 5 seconds. If the test machine is extremely |
|
1114 // slow, the test will fail. fsockopen() has been seen to time out in |
|
1115 // slightly less than the specified timeout, so allow a little slack on |
|
1116 // the minimum expected time (i.e. 1.8 instead of 2). |
|
1117 timer_start(__METHOD__); |
|
1118 $result = drupal_http_request(url('system-test/sleep/10', array('absolute' => TRUE)), array('timeout' => 2)); |
|
1119 $time = timer_read(__METHOD__) / 1000; |
|
1120 $this->assertTrue(1.8 < $time && $time < 5, format_string('Request timed out (%time seconds).', array('%time' => $time))); |
|
1121 $this->assertTrue($result->error, 'An error message was returned.'); |
|
1122 $this->assertEqual($result->code, HTTP_REQUEST_TIMEOUT, 'Proper error code was returned.'); |
|
1123 } |
|
1124 } |
|
1125 |
|
1126 function testDrupalHTTPRequestBasicAuth() { |
|
1127 $username = $this->randomName(); |
|
1128 $password = $this->randomName(); |
|
1129 $url = url('system-test/auth', array('absolute' => TRUE)); |
|
1130 |
|
1131 $auth = str_replace('://', '://' . $username . ':' . $password . '@', $url); |
|
1132 $result = drupal_http_request($auth); |
|
1133 |
|
1134 $this->drupalSetContent($result->data); |
|
1135 $this->assertRaw($username, 'Username is passed correctly.'); |
|
1136 $this->assertRaw($password, 'Password is passed correctly.'); |
|
1137 } |
|
1138 |
|
1139 function testDrupalHTTPRequestRedirect() { |
|
1140 $redirect_301 = drupal_http_request(url('system-test/redirect/301', array('absolute' => TRUE)), array('max_redirects' => 1)); |
|
1141 $this->assertEqual($redirect_301->redirect_code, 301, 'drupal_http_request follows the 301 redirect.'); |
|
1142 |
|
1143 $redirect_301 = drupal_http_request(url('system-test/redirect/301', array('absolute' => TRUE)), array('max_redirects' => 0)); |
|
1144 $this->assertFalse(isset($redirect_301->redirect_code), 'drupal_http_request does not follow 301 redirect if max_redirects = 0.'); |
|
1145 |
|
1146 $redirect_invalid = drupal_http_request(url('system-test/redirect-noscheme', array('absolute' => TRUE)), array('max_redirects' => 1)); |
|
1147 $this->assertEqual($redirect_invalid->code, -1002, format_string('301 redirect to invalid URL returned with error code !error.', array('!error' => $redirect_invalid->error))); |
|
1148 $this->assertEqual($redirect_invalid->error, 'missing schema', format_string('301 redirect to invalid URL returned with error message "!error".', array('!error' => $redirect_invalid->error))); |
|
1149 |
|
1150 $redirect_invalid = drupal_http_request(url('system-test/redirect-noparse', array('absolute' => TRUE)), array('max_redirects' => 1)); |
|
1151 $this->assertEqual($redirect_invalid->code, -1001, format_string('301 redirect to invalid URL returned with error message code "!error".', array('!error' => $redirect_invalid->error))); |
|
1152 $this->assertEqual($redirect_invalid->error, 'unable to parse URL', format_string('301 redirect to invalid URL returned with error message "!error".', array('!error' => $redirect_invalid->error))); |
|
1153 |
|
1154 $redirect_invalid = drupal_http_request(url('system-test/redirect-invalid-scheme', array('absolute' => TRUE)), array('max_redirects' => 1)); |
|
1155 $this->assertEqual($redirect_invalid->code, -1003, format_string('301 redirect to invalid URL returned with error code !error.', array('!error' => $redirect_invalid->error))); |
|
1156 $this->assertEqual($redirect_invalid->error, 'invalid schema ftp', format_string('301 redirect to invalid URL returned with error message "!error".', array('!error' => $redirect_invalid->error))); |
|
1157 |
|
1158 $redirect_302 = drupal_http_request(url('system-test/redirect/302', array('absolute' => TRUE)), array('max_redirects' => 1)); |
|
1159 $this->assertEqual($redirect_302->redirect_code, 302, 'drupal_http_request follows the 302 redirect.'); |
|
1160 |
|
1161 $redirect_302 = drupal_http_request(url('system-test/redirect/302', array('absolute' => TRUE)), array('max_redirects' => 0)); |
|
1162 $this->assertFalse(isset($redirect_302->redirect_code), 'drupal_http_request does not follow 302 redirect if $retry = 0.'); |
|
1163 |
|
1164 $redirect_307 = drupal_http_request(url('system-test/redirect/307', array('absolute' => TRUE)), array('max_redirects' => 1)); |
|
1165 $this->assertEqual($redirect_307->redirect_code, 307, 'drupal_http_request follows the 307 redirect.'); |
|
1166 |
|
1167 $redirect_307 = drupal_http_request(url('system-test/redirect/307', array('absolute' => TRUE)), array('max_redirects' => 0)); |
|
1168 $this->assertFalse(isset($redirect_307->redirect_code), 'drupal_http_request does not follow 307 redirect if max_redirects = 0.'); |
|
1169 |
|
1170 $multiple_redirect_final_url = url('system-test/multiple-redirects/0', array('absolute' => TRUE)); |
|
1171 $multiple_redirect_1 = drupal_http_request(url('system-test/multiple-redirects/1', array('absolute' => TRUE)), array('max_redirects' => 1)); |
|
1172 $this->assertEqual($multiple_redirect_1->redirect_url, $multiple_redirect_final_url, 'redirect_url contains the final redirection location after 1 redirect.'); |
|
1173 |
|
1174 $multiple_redirect_3 = drupal_http_request(url('system-test/multiple-redirects/3', array('absolute' => TRUE)), array('max_redirects' => 3)); |
|
1175 $this->assertEqual($multiple_redirect_3->redirect_url, $multiple_redirect_final_url, 'redirect_url contains the final redirection location after 3 redirects.'); |
|
1176 } |
|
1177 |
|
1178 /** |
|
1179 * Tests Content-language headers generated by Drupal. |
|
1180 */ |
|
1181 function testDrupalHTTPRequestHeaders() { |
|
1182 // Check the default header. |
|
1183 $request = drupal_http_request(url('<front>', array('absolute' => TRUE))); |
|
1184 $this->assertEqual($request->headers['content-language'], 'en', 'Content-Language HTTP header is English.'); |
|
1185 |
|
1186 // Add German language and set as default. |
|
1187 locale_add_language('de', 'German', 'Deutsch', LANGUAGE_LTR, '', '', TRUE, TRUE); |
|
1188 |
|
1189 // Request front page and check for matching Content-Language. |
|
1190 $request = drupal_http_request(url('<front>', array('absolute' => TRUE))); |
|
1191 $this->assertEqual($request->headers['content-language'], 'de', 'Content-Language HTTP header is German.'); |
|
1192 } |
|
1193 } |
|
1194 |
|
1195 /** |
|
1196 * Tests parsing of the HTTP response status line. |
|
1197 */ |
|
1198 class DrupalHTTPResponseStatusLineTest extends DrupalUnitTestCase { |
|
1199 public static function getInfo() { |
|
1200 return array( |
|
1201 'name' => 'Drupal HTTP request response status parsing', |
|
1202 'description' => 'Perform unit tests on _drupal_parse_response_status().', |
|
1203 'group' => 'System', |
|
1204 ); |
|
1205 } |
|
1206 |
|
1207 /** |
|
1208 * Tests parsing HTTP response status line. |
|
1209 */ |
|
1210 public function testStatusLine() { |
|
1211 // Grab the big array of test data from statusLineData(). |
|
1212 $data = $this->statusLineData(); |
|
1213 foreach($data as $test_case) { |
|
1214 $test_data = array_shift($test_case); |
|
1215 $expected = array_shift($test_case); |
|
1216 |
|
1217 $outcome = _drupal_parse_response_status($test_data); |
|
1218 |
|
1219 foreach(array_keys($expected) as $key) { |
|
1220 $this->assertIdentical($outcome[$key], $expected[$key]); |
|
1221 } |
|
1222 } |
|
1223 } |
|
1224 |
|
1225 /** |
|
1226 * Data provider for testStatusLine(). |
|
1227 * |
|
1228 * @return array |
|
1229 * Test data. |
|
1230 */ |
|
1231 protected function statusLineData() { |
|
1232 return array( |
|
1233 array( |
|
1234 'HTTP/1.1 200 OK', |
|
1235 array( |
|
1236 'http_version' => 'HTTP/1.1', |
|
1237 'response_code' => '200', |
|
1238 'reason_phrase' => 'OK', |
|
1239 ), |
|
1240 ), |
|
1241 // Data set with no reason phrase. |
|
1242 array( |
|
1243 'HTTP/1.1 200', |
|
1244 array( |
|
1245 'http_version' => 'HTTP/1.1', |
|
1246 'response_code' => '200', |
|
1247 'reason_phrase' => '', |
|
1248 ), |
|
1249 ), |
|
1250 // Arbitrary strings. |
|
1251 array( |
|
1252 'version code multi word explanation', |
|
1253 array( |
|
1254 'http_version' => 'version', |
|
1255 'response_code' => 'code', |
|
1256 'reason_phrase' => 'multi word explanation', |
|
1257 ), |
|
1258 ), |
|
1259 ); |
|
1260 } |
|
1261 } |
|
1262 |
|
1263 /** |
|
1264 * Testing drupal_add_region_content and drupal_get_region_content. |
|
1265 */ |
|
1266 class DrupalSetContentTestCase extends DrupalWebTestCase { |
|
1267 public static function getInfo() { |
|
1268 return array( |
|
1269 'name' => 'Drupal set/get regions', |
|
1270 'description' => 'Performs tests on setting and retrieiving content from theme regions.', |
|
1271 'group' => 'System' |
|
1272 ); |
|
1273 } |
|
1274 |
|
1275 |
|
1276 /** |
|
1277 * Test setting and retrieving content for theme regions. |
|
1278 */ |
|
1279 function testRegions() { |
|
1280 global $theme_key; |
|
1281 |
|
1282 $block_regions = system_region_list($theme_key, REGIONS_ALL, FALSE); |
|
1283 $delimiter = $this->randomName(32); |
|
1284 $values = array(); |
|
1285 // Set some random content for each region available. |
|
1286 foreach ($block_regions as $region) { |
|
1287 $first_chunk = $this->randomName(32); |
|
1288 drupal_add_region_content($region, $first_chunk); |
|
1289 $second_chunk = $this->randomName(32); |
|
1290 drupal_add_region_content($region, $second_chunk); |
|
1291 // Store the expected result for a drupal_get_region_content call for this region. |
|
1292 $values[$region] = $first_chunk . $delimiter . $second_chunk; |
|
1293 } |
|
1294 |
|
1295 // Ensure drupal_get_region_content returns expected results when fetching all regions. |
|
1296 $content = drupal_get_region_content(NULL, $delimiter); |
|
1297 foreach ($content as $region => $region_content) { |
|
1298 $this->assertEqual($region_content, $values[$region], format_string('@region region text verified when fetching all regions', array('@region' => $region))); |
|
1299 } |
|
1300 |
|
1301 // Ensure drupal_get_region_content returns expected results when fetching a single region. |
|
1302 foreach ($block_regions as $region) { |
|
1303 $region_content = drupal_get_region_content($region, $delimiter); |
|
1304 $this->assertEqual($region_content, $values[$region], format_string('@region region text verified when fetching single region.', array('@region' => $region))); |
|
1305 } |
|
1306 } |
|
1307 } |
|
1308 |
|
1309 /** |
|
1310 * Testing drupal_goto and hook_drupal_goto_alter(). |
|
1311 */ |
|
1312 class DrupalGotoTest extends DrupalWebTestCase { |
|
1313 public static function getInfo() { |
|
1314 return array( |
|
1315 'name' => 'Drupal goto', |
|
1316 'description' => 'Performs tests on the drupal_goto function and hook_drupal_goto_alter', |
|
1317 'group' => 'System' |
|
1318 ); |
|
1319 } |
|
1320 |
|
1321 function setUp() { |
|
1322 parent::setUp('common_test'); |
|
1323 } |
|
1324 |
|
1325 /** |
|
1326 * Test drupal_goto(). |
|
1327 */ |
|
1328 function testDrupalGoto() { |
|
1329 $this->drupalGet('common-test/drupal_goto/redirect'); |
|
1330 $headers = $this->drupalGetHeaders(TRUE); |
|
1331 list(, $status) = explode(' ', $headers[0][':status'], 3); |
|
1332 $this->assertEqual($status, 302, 'Expected response code was sent.'); |
|
1333 $this->assertText('drupal_goto', 'Drupal goto redirect succeeded.'); |
|
1334 $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('absolute' => TRUE)), 'Drupal goto redirected to expected URL.'); |
|
1335 |
|
1336 $this->drupalGet('common-test/drupal_goto/redirect_advanced'); |
|
1337 $headers = $this->drupalGetHeaders(TRUE); |
|
1338 list(, $status) = explode(' ', $headers[0][':status'], 3); |
|
1339 $this->assertEqual($status, 301, 'Expected response code was sent.'); |
|
1340 $this->assertText('drupal_goto', 'Drupal goto redirect succeeded.'); |
|
1341 $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('query' => array('foo' => '123'), 'absolute' => TRUE)), 'Drupal goto redirected to expected URL.'); |
|
1342 |
|
1343 // Test that calling drupal_goto() on the current path is not dangerous. |
|
1344 variable_set('common_test_redirect_current_path', TRUE); |
|
1345 $this->drupalGet('', array('query' => array('q' => 'http://www.example.com/'))); |
|
1346 $headers = $this->drupalGetHeaders(TRUE); |
|
1347 list(, $status) = explode(' ', $headers[0][':status'], 3); |
|
1348 $this->assertEqual($status, 302, 'Expected response code was sent.'); |
|
1349 $this->assertNotEqual($this->getUrl(), 'http://www.example.com/', 'Drupal goto did not redirect to external URL.'); |
|
1350 $this->assertTrue(strpos($this->getUrl(), url('<front>', array('absolute' => TRUE))) === 0, 'Drupal redirected to itself.'); |
|
1351 variable_del('common_test_redirect_current_path'); |
|
1352 // Test that drupal_goto() respects ?destination=xxx. Use an complicated URL |
|
1353 // to test that the path is encoded and decoded properly. |
|
1354 $destination = 'common-test/drupal_goto/destination?foo=%2525&bar=123'; |
|
1355 $this->drupalGet('common-test/drupal_goto/redirect', array('query' => array('destination' => $destination))); |
|
1356 $this->assertText('drupal_goto', 'Drupal goto redirect with destination succeeded.'); |
|
1357 $this->assertEqual($this->getUrl(), url('common-test/drupal_goto/destination', array('query' => array('foo' => '%25', 'bar' => '123'), 'absolute' => TRUE)), 'Drupal goto redirected to given query string destination.'); |
|
1358 } |
|
1359 |
|
1360 /** |
|
1361 * Test hook_drupal_goto_alter(). |
|
1362 */ |
|
1363 function testDrupalGotoAlter() { |
|
1364 $this->drupalGet('common-test/drupal_goto/redirect_fail'); |
|
1365 |
|
1366 $this->assertNoText(t("Drupal goto failed to stop program"), "Drupal goto stopped program."); |
|
1367 $this->assertNoText('drupal_goto_fail', "Drupal goto redirect failed."); |
|
1368 } |
|
1369 |
|
1370 /** |
|
1371 * Test drupal_get_destination(). |
|
1372 */ |
|
1373 function testDrupalGetDestination() { |
|
1374 $query = $this->randomName(10); |
|
1375 |
|
1376 // Verify that a 'destination' query string is used as destination. |
|
1377 $this->drupalGet('common-test/destination', array('query' => array('destination' => $query))); |
|
1378 $this->assertText('The destination: ' . $query, 'The given query string destination is determined as destination.'); |
|
1379 |
|
1380 // Verify that the current path is used as destination. |
|
1381 $this->drupalGet('common-test/destination', array('query' => array($query => NULL))); |
|
1382 $url = 'common-test/destination?' . $query; |
|
1383 $this->assertText('The destination: ' . $url, 'The current path is determined as destination.'); |
|
1384 } |
|
1385 } |
|
1386 |
|
1387 /** |
|
1388 * Tests for the JavaScript system. |
|
1389 */ |
|
1390 class JavaScriptTestCase extends DrupalWebTestCase { |
|
1391 /** |
|
1392 * Store configured value for JavaScript preprocessing. |
|
1393 */ |
|
1394 protected $preprocess_js = NULL; |
|
1395 |
|
1396 public static function getInfo() { |
|
1397 return array( |
|
1398 'name' => 'JavaScript', |
|
1399 'description' => 'Tests the JavaScript system.', |
|
1400 'group' => 'System' |
|
1401 ); |
|
1402 } |
|
1403 |
|
1404 function setUp() { |
|
1405 // Enable Locale and SimpleTest in the test environment. |
|
1406 parent::setUp('locale', 'simpletest', 'common_test'); |
|
1407 |
|
1408 // Disable preprocessing |
|
1409 $this->preprocess_js = variable_get('preprocess_js', 0); |
|
1410 variable_set('preprocess_js', 0); |
|
1411 |
|
1412 // Reset drupal_add_js() and drupal_add_library() statics before each test. |
|
1413 drupal_static_reset('drupal_add_js'); |
|
1414 drupal_static_reset('drupal_add_library'); |
|
1415 } |
|
1416 |
|
1417 function tearDown() { |
|
1418 // Restore configured value for JavaScript preprocessing. |
|
1419 variable_set('preprocess_js', $this->preprocess_js); |
|
1420 parent::tearDown(); |
|
1421 } |
|
1422 |
|
1423 /** |
|
1424 * Test default JavaScript is empty. |
|
1425 */ |
|
1426 function testDefault() { |
|
1427 $this->assertEqual(array(), drupal_add_js(), 'Default JavaScript is empty.'); |
|
1428 } |
|
1429 |
|
1430 /** |
|
1431 * Test adding a JavaScript file. |
|
1432 */ |
|
1433 function testAddFile() { |
|
1434 $javascript = drupal_add_js('misc/collapse.js'); |
|
1435 $this->assertTrue(array_key_exists('misc/jquery.js', $javascript), 'jQuery is added when a file is added.'); |
|
1436 $this->assertTrue(array_key_exists('misc/drupal.js', $javascript), 'Drupal.js is added when file is added.'); |
|
1437 $this->assertTrue(array_key_exists('misc/collapse.js', $javascript), 'JavaScript files are correctly added.'); |
|
1438 $this->assertEqual(base_path(), $javascript['settings']['data'][0]['basePath'], 'Base path JavaScript setting is correctly set.'); |
|
1439 url('', array('prefix' => &$prefix)); |
|
1440 $this->assertEqual(empty($prefix) ? '' : $prefix, $javascript['settings']['data'][1]['pathPrefix'], 'Path prefix JavaScript setting is correctly set.'); |
|
1441 } |
|
1442 |
|
1443 /** |
|
1444 * Test adding settings. |
|
1445 */ |
|
1446 function testAddSetting() { |
|
1447 $javascript = drupal_add_js(array('drupal' => 'rocks', 'dries' => 280342800), 'setting'); |
|
1448 $this->assertEqual(280342800, $javascript['settings']['data'][2]['dries'], 'JavaScript setting is set correctly.'); |
|
1449 $this->assertEqual('rocks', $javascript['settings']['data'][2]['drupal'], 'The other JavaScript setting is set correctly.'); |
|
1450 } |
|
1451 |
|
1452 /** |
|
1453 * Tests adding an external JavaScript File. |
|
1454 */ |
|
1455 function testAddExternal() { |
|
1456 $path = 'http://example.com/script.js'; |
|
1457 $javascript = drupal_add_js($path, 'external'); |
|
1458 $this->assertTrue(array_key_exists('http://example.com/script.js', $javascript), 'Added an external JavaScript file.'); |
|
1459 } |
|
1460 |
|
1461 /** |
|
1462 * Test drupal_get_js() for JavaScript settings. |
|
1463 */ |
|
1464 function testHeaderSetting() { |
|
1465 // Only the second of these two entries should appear in Drupal.settings. |
|
1466 drupal_add_js(array('commonTest' => 'commonTestShouldNotAppear'), 'setting'); |
|
1467 drupal_add_js(array('commonTest' => 'commonTestShouldAppear'), 'setting'); |
|
1468 // All three of these entries should appear in Drupal.settings. |
|
1469 drupal_add_js(array('commonTestArray' => array('commonTestValue0')), 'setting'); |
|
1470 drupal_add_js(array('commonTestArray' => array('commonTestValue1')), 'setting'); |
|
1471 drupal_add_js(array('commonTestArray' => array('commonTestValue2')), 'setting'); |
|
1472 // Only the second of these two entries should appear in Drupal.settings. |
|
1473 drupal_add_js(array('commonTestArray' => array('key' => 'commonTestOldValue')), 'setting'); |
|
1474 drupal_add_js(array('commonTestArray' => array('key' => 'commonTestNewValue')), 'setting'); |
|
1475 |
|
1476 $javascript = drupal_get_js('header'); |
|
1477 $this->assertTrue(strpos($javascript, 'basePath') > 0, 'Rendered JavaScript header returns basePath setting.'); |
|
1478 $this->assertTrue(strpos($javascript, 'misc/jquery.js') > 0, 'Rendered JavaScript header includes jQuery.'); |
|
1479 $this->assertTrue(strpos($javascript, 'pathPrefix') > 0, 'Rendered JavaScript header returns pathPrefix setting.'); |
|
1480 |
|
1481 // Test whether drupal_add_js can be used to override a previous setting. |
|
1482 $this->assertTrue(strpos($javascript, 'commonTestShouldAppear') > 0, 'Rendered JavaScript header returns custom setting.'); |
|
1483 $this->assertTrue(strpos($javascript, 'commonTestShouldNotAppear') === FALSE, 'drupal_add_js() correctly overrides a custom setting.'); |
|
1484 |
|
1485 // Test whether drupal_add_js can be used to add numerically indexed values |
|
1486 // to an array. |
|
1487 $array_values_appear = strpos($javascript, 'commonTestValue0') > 0 && strpos($javascript, 'commonTestValue1') > 0 && strpos($javascript, 'commonTestValue2') > 0; |
|
1488 $this->assertTrue($array_values_appear, 'drupal_add_js() correctly adds settings to the end of an indexed array.'); |
|
1489 |
|
1490 // Test whether drupal_add_js can be used to override the entry for an |
|
1491 // existing key in an associative array. |
|
1492 $associative_array_override = strpos($javascript, 'commonTestNewValue') > 0 && strpos($javascript, 'commonTestOldValue') === FALSE; |
|
1493 $this->assertTrue($associative_array_override, 'drupal_add_js() correctly overrides settings within an associative array.'); |
|
1494 } |
|
1495 |
|
1496 /** |
|
1497 * Test to see if resetting the JavaScript empties the cache. |
|
1498 */ |
|
1499 function testReset() { |
|
1500 drupal_add_js('misc/collapse.js'); |
|
1501 drupal_static_reset('drupal_add_js'); |
|
1502 $this->assertEqual(array(), drupal_add_js(), 'Resetting the JavaScript correctly empties the cache.'); |
|
1503 } |
|
1504 |
|
1505 /** |
|
1506 * Test adding inline scripts. |
|
1507 */ |
|
1508 function testAddInline() { |
|
1509 $inline = 'jQuery(function () { });'; |
|
1510 $javascript = drupal_add_js($inline, array('type' => 'inline', 'scope' => 'footer')); |
|
1511 $this->assertTrue(array_key_exists('misc/jquery.js', $javascript), 'jQuery is added when inline scripts are added.'); |
|
1512 $data = end($javascript); |
|
1513 $this->assertEqual($inline, $data['data'], 'Inline JavaScript is correctly added to the footer.'); |
|
1514 } |
|
1515 |
|
1516 /** |
|
1517 * Test rendering an external JavaScript file. |
|
1518 */ |
|
1519 function testRenderExternal() { |
|
1520 $external = 'http://example.com/example.js'; |
|
1521 drupal_add_js($external, 'external'); |
|
1522 $javascript = drupal_get_js(); |
|
1523 // Local files have a base_path() prefix, external files should not. |
|
1524 $this->assertTrue(strpos($javascript, 'src="' . $external) > 0, 'Rendering an external JavaScript file.'); |
|
1525 } |
|
1526 |
|
1527 /** |
|
1528 * Test drupal_get_js() with a footer scope. |
|
1529 */ |
|
1530 function testFooterHTML() { |
|
1531 $inline = 'jQuery(function () { });'; |
|
1532 drupal_add_js($inline, array('type' => 'inline', 'scope' => 'footer')); |
|
1533 $javascript = drupal_get_js('footer'); |
|
1534 $this->assertTrue(strpos($javascript, $inline) > 0, 'Rendered JavaScript footer returns the inline code.'); |
|
1535 } |
|
1536 |
|
1537 /** |
|
1538 * Test the 'javascript_always_use_jquery' variable. |
|
1539 */ |
|
1540 function testJavaScriptAlwaysUseJQuery() { |
|
1541 // The default front page of the site should use jQuery and other standard |
|
1542 // scripts and settings. |
|
1543 $this->drupalGet(''); |
|
1544 $this->assertRaw('misc/jquery.js', 'Default behavior: The front page of the site includes jquery.js.'); |
|
1545 $this->assertRaw('misc/drupal.js', 'Default behavior: The front page of the site includes drupal.js.'); |
|
1546 $this->assertRaw('Drupal.settings', 'Default behavior: The front page of the site includes Drupal settings.'); |
|
1547 $this->assertRaw('basePath', 'Default behavior: The front page of the site includes the basePath Drupal setting.'); |
|
1548 |
|
1549 // The default front page should not use jQuery and other standard scripts |
|
1550 // and settings when the 'javascript_always_use_jquery' variable is set to |
|
1551 // FALSE. |
|
1552 variable_set('javascript_always_use_jquery', FALSE); |
|
1553 $this->drupalGet(''); |
|
1554 $this->assertNoRaw('misc/jquery.js', 'When "javascript_always_use_jquery" is FALSE: The front page of the site does not include jquery.js.'); |
|
1555 $this->assertNoRaw('misc/drupal.js', 'When "javascript_always_use_jquery" is FALSE: The front page of the site does not include drupal.js.'); |
|
1556 $this->assertNoRaw('Drupal.settings', 'When "javascript_always_use_jquery" is FALSE: The front page of the site does not include Drupal settings.'); |
|
1557 $this->assertNoRaw('basePath', 'When "javascript_always_use_jquery" is FALSE: The front page of the site does not include the basePath Drupal setting.'); |
|
1558 variable_del('javascript_always_use_jquery'); |
|
1559 |
|
1560 // When only settings have been added via drupal_add_js(), drupal_get_js() |
|
1561 // should still return jQuery and other standard scripts and settings. |
|
1562 $this->resetStaticVariables(); |
|
1563 drupal_add_js(array('testJavaScriptSetting' => 'test'), 'setting'); |
|
1564 $javascript = drupal_get_js(); |
|
1565 $this->assertTrue(strpos($javascript, 'misc/jquery.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when only settings have been added includes jquery.js.'); |
|
1566 $this->assertTrue(strpos($javascript, 'misc/drupal.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when only settings have been added includes drupal.js.'); |
|
1567 $this->assertTrue(strpos($javascript, 'Drupal.settings') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when only settings have been added includes Drupal.settings.'); |
|
1568 $this->assertTrue(strpos($javascript, 'basePath') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when only settings have been added includes the basePath Drupal setting.'); |
|
1569 $this->assertTrue(strpos($javascript, 'testJavaScriptSetting') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when only settings have been added includes the added Drupal settings.'); |
|
1570 |
|
1571 // When only settings have been added via drupal_add_js() and the |
|
1572 // 'javascript_always_use_jquery' variable is set to FALSE, drupal_get_js() |
|
1573 // should not return jQuery and other standard scripts and settings, nor |
|
1574 // should it return the requested settings (since they cannot actually be |
|
1575 // addded to the page without jQuery). |
|
1576 $this->resetStaticVariables(); |
|
1577 variable_set('javascript_always_use_jquery', FALSE); |
|
1578 drupal_add_js(array('testJavaScriptSetting' => 'test'), 'setting'); |
|
1579 $javascript = drupal_get_js(); |
|
1580 $this->assertTrue(strpos($javascript, 'misc/jquery.js') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when only settings have been added does not include jquery.js.'); |
|
1581 $this->assertTrue(strpos($javascript, 'misc/drupal.js') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when only settings have been added does not include drupal.js.'); |
|
1582 $this->assertTrue(strpos($javascript, 'Drupal.settings') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when only settings have been added does not include Drupal.settings.'); |
|
1583 $this->assertTrue(strpos($javascript, 'basePath') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when only settings have been added does not include the basePath Drupal setting.'); |
|
1584 $this->assertTrue(strpos($javascript, 'testJavaScriptSetting') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when only settings have been added does not include the added Drupal settings.'); |
|
1585 variable_del('javascript_always_use_jquery'); |
|
1586 |
|
1587 // When a regular file has been added via drupal_add_js(), drupal_get_js() |
|
1588 // should return jQuery and other standard scripts and settings. |
|
1589 $this->resetStaticVariables(); |
|
1590 drupal_add_js('misc/collapse.js'); |
|
1591 $javascript = drupal_get_js(); |
|
1592 $this->assertTrue(strpos($javascript, 'misc/jquery.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes jquery.js.'); |
|
1593 $this->assertTrue(strpos($javascript, 'misc/drupal.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes drupal.js.'); |
|
1594 $this->assertTrue(strpos($javascript, 'Drupal.settings') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes Drupal.settings.'); |
|
1595 $this->assertTrue(strpos($javascript, 'basePath') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes the basePath Drupal setting.'); |
|
1596 $this->assertTrue(strpos($javascript, 'misc/collapse.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes the custom file.'); |
|
1597 |
|
1598 // When a regular file has been added via drupal_add_js() and the |
|
1599 // 'javascript_always_use_jquery' variable is set to FALSE, drupal_get_js() |
|
1600 // should still return jQuery and other standard scripts and settings |
|
1601 // (since the file is assumed to require jQuery by default). |
|
1602 $this->resetStaticVariables(); |
|
1603 variable_set('javascript_always_use_jquery', FALSE); |
|
1604 drupal_add_js('misc/collapse.js'); |
|
1605 $javascript = drupal_get_js(); |
|
1606 $this->assertTrue(strpos($javascript, 'misc/jquery.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes jquery.js.'); |
|
1607 $this->assertTrue(strpos($javascript, 'misc/drupal.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes drupal.js.'); |
|
1608 $this->assertTrue(strpos($javascript, 'Drupal.settings') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes Drupal.settings.'); |
|
1609 $this->assertTrue(strpos($javascript, 'basePath') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes the basePath Drupal setting.'); |
|
1610 $this->assertTrue(strpos($javascript, 'misc/collapse.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes the custom file.'); |
|
1611 variable_del('javascript_always_use_jquery'); |
|
1612 |
|
1613 // When a file that does not require jQuery has been added via |
|
1614 // drupal_add_js(), drupal_get_js() should still return jQuery and other |
|
1615 // standard scripts and settings by default. |
|
1616 $this->resetStaticVariables(); |
|
1617 drupal_add_js('misc/collapse.js', array('requires_jquery' => FALSE)); |
|
1618 $javascript = drupal_get_js(); |
|
1619 $this->assertTrue(strpos($javascript, 'misc/jquery.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes jquery.js.'); |
|
1620 $this->assertTrue(strpos($javascript, 'misc/drupal.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes drupal.js.'); |
|
1621 $this->assertTrue(strpos($javascript, 'Drupal.settings') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes Drupal.settings.'); |
|
1622 $this->assertTrue(strpos($javascript, 'basePath') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes the basePath Drupal setting.'); |
|
1623 $this->assertTrue(strpos($javascript, 'misc/collapse.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes the custom file.'); |
|
1624 |
|
1625 // When a file that does not require jQuery has been added via |
|
1626 // drupal_add_js() and the 'javascript_always_use_jquery' variable is set |
|
1627 // to FALSE, drupal_get_js() should not return jQuery and other standard |
|
1628 // scripts and setting, but it should still return the requested file. |
|
1629 $this->resetStaticVariables(); |
|
1630 variable_set('javascript_always_use_jquery', FALSE); |
|
1631 drupal_add_js('misc/collapse.js', array('requires_jquery' => FALSE)); |
|
1632 $javascript = drupal_get_js(); |
|
1633 $this->assertTrue(strpos($javascript, 'misc/jquery.js') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added does not include jquery.js.'); |
|
1634 $this->assertTrue(strpos($javascript, 'misc/drupal.js') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added does not include drupal.js.'); |
|
1635 $this->assertTrue(strpos($javascript, 'Drupal.settings') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added does not include Drupal.settings.'); |
|
1636 $this->assertTrue(strpos($javascript, 'basePath') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added does not include the basePath Drupal setting.'); |
|
1637 $this->assertTrue(strpos($javascript, 'misc/collapse.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes the custom file.'); |
|
1638 variable_del('javascript_always_use_jquery'); |
|
1639 |
|
1640 // When 'javascript_always_use_jquery' is set to FALSE and a file that does |
|
1641 // not require jQuery is added, followed by one that does, drupal_get_js() |
|
1642 // should return jQuery and other standard scripts and settings, in |
|
1643 // addition to both of the requested files. |
|
1644 $this->resetStaticVariables(); |
|
1645 variable_set('javascript_always_use_jquery', FALSE); |
|
1646 drupal_add_js('misc/collapse.js', array('requires_jquery' => FALSE)); |
|
1647 drupal_add_js('misc/ajax.js'); |
|
1648 $javascript = drupal_get_js(); |
|
1649 $this->assertTrue(strpos($javascript, 'misc/jquery.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes jquery.js.'); |
|
1650 $this->assertTrue(strpos($javascript, 'misc/drupal.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes drupal.js.'); |
|
1651 $this->assertTrue(strpos($javascript, 'Drupal.settings') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes Drupal.settings.'); |
|
1652 $this->assertTrue(strpos($javascript, 'basePath') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes the basePath Drupal setting.'); |
|
1653 $this->assertTrue(strpos($javascript, 'misc/collapse.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes the first custom file.'); |
|
1654 $this->assertTrue(strpos($javascript, 'misc/ajax.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes the second custom file.'); |
|
1655 variable_del('javascript_always_use_jquery'); |
|
1656 } |
|
1657 |
|
1658 /** |
|
1659 * Test drupal_add_js() sets preproccess to false when cache is set to false. |
|
1660 */ |
|
1661 function testNoCache() { |
|
1662 $javascript = drupal_add_js('misc/collapse.js', array('cache' => FALSE)); |
|
1663 $this->assertFalse($javascript['misc/collapse.js']['preprocess'], 'Setting cache to FALSE sets proprocess to FALSE when adding JavaScript.'); |
|
1664 } |
|
1665 |
|
1666 /** |
|
1667 * Test adding a JavaScript file with a different group. |
|
1668 */ |
|
1669 function testDifferentGroup() { |
|
1670 $javascript = drupal_add_js('misc/collapse.js', array('group' => JS_THEME)); |
|
1671 $this->assertEqual($javascript['misc/collapse.js']['group'], JS_THEME, 'Adding a JavaScript file with a different group caches the given group.'); |
|
1672 } |
|
1673 |
|
1674 /** |
|
1675 * Test adding a JavaScript file with a different weight. |
|
1676 */ |
|
1677 function testDifferentWeight() { |
|
1678 $javascript = drupal_add_js('misc/collapse.js', array('weight' => 2)); |
|
1679 $this->assertEqual($javascript['misc/collapse.js']['weight'], 2, 'Adding a JavaScript file with a different weight caches the given weight.'); |
|
1680 } |
|
1681 |
|
1682 /** |
|
1683 * Tests JavaScript aggregation when files are added to a different scope. |
|
1684 */ |
|
1685 function testAggregationOrder() { |
|
1686 // Enable JavaScript aggregation. |
|
1687 variable_set('preprocess_js', 1); |
|
1688 drupal_static_reset('drupal_add_js'); |
|
1689 |
|
1690 // Add two JavaScript files to the current request and build the cache. |
|
1691 drupal_add_js('misc/ajax.js'); |
|
1692 drupal_add_js('misc/autocomplete.js'); |
|
1693 |
|
1694 $js_items = drupal_add_js(); |
|
1695 drupal_build_js_cache(array( |
|
1696 'misc/ajax.js' => $js_items['misc/ajax.js'], |
|
1697 'misc/autocomplete.js' => $js_items['misc/autocomplete.js'] |
|
1698 )); |
|
1699 |
|
1700 // Store the expected key for the first item in the cache. |
|
1701 $cache = array_keys(variable_get('drupal_js_cache_files', array())); |
|
1702 $expected_key = $cache[0]; |
|
1703 |
|
1704 // Reset variables and add a file in a different scope first. |
|
1705 variable_del('drupal_js_cache_files'); |
|
1706 drupal_static_reset('drupal_add_js'); |
|
1707 drupal_add_js('some/custom/javascript_file.js', array('scope' => 'footer')); |
|
1708 drupal_add_js('misc/ajax.js'); |
|
1709 drupal_add_js('misc/autocomplete.js'); |
|
1710 |
|
1711 // Rebuild the cache. |
|
1712 $js_items = drupal_add_js(); |
|
1713 drupal_build_js_cache(array( |
|
1714 'misc/ajax.js' => $js_items['misc/ajax.js'], |
|
1715 'misc/autocomplete.js' => $js_items['misc/autocomplete.js'] |
|
1716 )); |
|
1717 |
|
1718 // Compare the expected key for the first file to the current one. |
|
1719 $cache = array_keys(variable_get('drupal_js_cache_files', array())); |
|
1720 $key = $cache[0]; |
|
1721 $this->assertEqual($key, $expected_key, 'JavaScript aggregation is not affected by ordering in different scopes.'); |
|
1722 } |
|
1723 |
|
1724 /** |
|
1725 * Test JavaScript ordering. |
|
1726 */ |
|
1727 function testRenderOrder() { |
|
1728 // Add a bunch of JavaScript in strange ordering. |
|
1729 drupal_add_js('(function($){alert("Weight 5 #1");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => 5)); |
|
1730 drupal_add_js('(function($){alert("Weight 0 #1");})(jQuery);', array('type' => 'inline', 'scope' => 'footer')); |
|
1731 drupal_add_js('(function($){alert("Weight 0 #2");})(jQuery);', array('type' => 'inline', 'scope' => 'footer')); |
|
1732 drupal_add_js('(function($){alert("Weight -8 #1");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8)); |
|
1733 drupal_add_js('(function($){alert("Weight -8 #2");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8)); |
|
1734 drupal_add_js('(function($){alert("Weight -8 #3");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8)); |
|
1735 drupal_add_js('http://example.com/example.js?Weight -5 #1', array('type' => 'external', 'scope' => 'footer', 'weight' => -5)); |
|
1736 drupal_add_js('(function($){alert("Weight -8 #4");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8)); |
|
1737 drupal_add_js('(function($){alert("Weight 5 #2");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => 5)); |
|
1738 drupal_add_js('(function($){alert("Weight 0 #3");})(jQuery);', array('type' => 'inline', 'scope' => 'footer')); |
|
1739 |
|
1740 // Construct the expected result from the regex. |
|
1741 $expected = array( |
|
1742 "-8 #1", |
|
1743 "-8 #2", |
|
1744 "-8 #3", |
|
1745 "-8 #4", |
|
1746 "-5 #1", // The external script. |
|
1747 "0 #1", |
|
1748 "0 #2", |
|
1749 "0 #3", |
|
1750 "5 #1", |
|
1751 "5 #2", |
|
1752 ); |
|
1753 |
|
1754 // Retrieve the rendered JavaScript and test against the regex. |
|
1755 $js = drupal_get_js('footer'); |
|
1756 $matches = array(); |
|
1757 if (preg_match_all('/Weight\s([-0-9]+\s[#0-9]+)/', $js, $matches)) { |
|
1758 $result = $matches[1]; |
|
1759 } |
|
1760 else { |
|
1761 $result = array(); |
|
1762 } |
|
1763 $this->assertIdentical($result, $expected, 'JavaScript is added in the expected weight order.'); |
|
1764 } |
|
1765 |
|
1766 /** |
|
1767 * Test rendering the JavaScript with a file's weight above jQuery's. |
|
1768 */ |
|
1769 function testRenderDifferentWeight() { |
|
1770 // JavaScript files are sorted first by group, then by the 'every_page' |
|
1771 // flag, then by weight (see drupal_sort_css_js()), so to test the effect of |
|
1772 // weight, we need the other two options to be the same. |
|
1773 drupal_add_js('misc/collapse.js', array('group' => JS_LIBRARY, 'every_page' => TRUE, 'weight' => -21)); |
|
1774 $javascript = drupal_get_js(); |
|
1775 $this->assertTrue(strpos($javascript, 'misc/collapse.js') < strpos($javascript, 'misc/jquery.js'), 'Rendering a JavaScript file above jQuery.'); |
|
1776 } |
|
1777 |
|
1778 /** |
|
1779 * Test altering a JavaScript's weight via hook_js_alter(). |
|
1780 * |
|
1781 * @see simpletest_js_alter() |
|
1782 */ |
|
1783 function testAlter() { |
|
1784 // Add both tableselect.js and simpletest.js, with a larger weight on SimpleTest. |
|
1785 drupal_add_js('misc/tableselect.js'); |
|
1786 drupal_add_js(drupal_get_path('module', 'simpletest') . '/simpletest.js', array('weight' => 9999)); |
|
1787 |
|
1788 // Render the JavaScript, testing if simpletest.js was altered to be before |
|
1789 // tableselect.js. See simpletest_js_alter() to see where this alteration |
|
1790 // takes place. |
|
1791 $javascript = drupal_get_js(); |
|
1792 $this->assertTrue(strpos($javascript, 'simpletest.js') < strpos($javascript, 'misc/tableselect.js'), 'Altering JavaScript weight through the alter hook.'); |
|
1793 } |
|
1794 |
|
1795 /** |
|
1796 * Adds a library to the page and tests for both its JavaScript and its CSS. |
|
1797 */ |
|
1798 function testLibraryRender() { |
|
1799 $result = drupal_add_library('system', 'farbtastic'); |
|
1800 $this->assertTrue($result !== FALSE, 'Library was added without errors.'); |
|
1801 $scripts = drupal_get_js(); |
|
1802 $styles = drupal_get_css(); |
|
1803 $this->assertTrue(strpos($scripts, 'misc/farbtastic/farbtastic.js'), 'JavaScript of library was added to the page.'); |
|
1804 $this->assertTrue(strpos($styles, 'misc/farbtastic/farbtastic.css'), 'Stylesheet of library was added to the page.'); |
|
1805 } |
|
1806 |
|
1807 /** |
|
1808 * Adds a JavaScript library to the page and alters it. |
|
1809 * |
|
1810 * @see common_test_library_alter() |
|
1811 */ |
|
1812 function testLibraryAlter() { |
|
1813 // Verify that common_test altered the title of Farbtastic. |
|
1814 $library = drupal_get_library('system', 'farbtastic'); |
|
1815 $this->assertEqual($library['title'], 'Farbtastic: Altered Library', 'Registered libraries were altered.'); |
|
1816 |
|
1817 // common_test_library_alter() also added a dependency on jQuery Form. |
|
1818 drupal_add_library('system', 'farbtastic'); |
|
1819 $scripts = drupal_get_js(); |
|
1820 $this->assertTrue(strpos($scripts, 'misc/jquery.form.js'), 'Altered library dependencies are added to the page.'); |
|
1821 } |
|
1822 |
|
1823 /** |
|
1824 * Tests that multiple modules can implement the same library. |
|
1825 * |
|
1826 * @see common_test_library() |
|
1827 */ |
|
1828 function testLibraryNameConflicts() { |
|
1829 $farbtastic = drupal_get_library('common_test', 'farbtastic'); |
|
1830 $this->assertEqual($farbtastic['title'], 'Custom Farbtastic Library', 'Alternative libraries can be added to the page.'); |
|
1831 } |
|
1832 |
|
1833 /** |
|
1834 * Tests non-existing libraries. |
|
1835 */ |
|
1836 function testLibraryUnknown() { |
|
1837 $result = drupal_get_library('unknown', 'unknown'); |
|
1838 $this->assertFalse($result, 'Unknown library returned FALSE.'); |
|
1839 drupal_static_reset('drupal_get_library'); |
|
1840 |
|
1841 $result = drupal_add_library('unknown', 'unknown'); |
|
1842 $this->assertFalse($result, 'Unknown library returned FALSE.'); |
|
1843 $scripts = drupal_get_js(); |
|
1844 $this->assertTrue(strpos($scripts, 'unknown') === FALSE, 'Unknown library was not added to the page.'); |
|
1845 } |
|
1846 |
|
1847 /** |
|
1848 * Tests the addition of libraries through the #attached['library'] property. |
|
1849 */ |
|
1850 function testAttachedLibrary() { |
|
1851 $element['#attached']['library'][] = array('system', 'farbtastic'); |
|
1852 drupal_render($element); |
|
1853 $scripts = drupal_get_js(); |
|
1854 $this->assertTrue(strpos($scripts, 'misc/farbtastic/farbtastic.js'), 'The attached_library property adds the additional libraries.'); |
|
1855 } |
|
1856 |
|
1857 /** |
|
1858 * Tests retrieval of libraries via drupal_get_library(). |
|
1859 */ |
|
1860 function testGetLibrary() { |
|
1861 // Retrieve all libraries registered by a module. |
|
1862 $libraries = drupal_get_library('common_test'); |
|
1863 $this->assertTrue(isset($libraries['farbtastic']), 'Retrieved all module libraries.'); |
|
1864 // Retrieve all libraries for a module not implementing hook_library(). |
|
1865 // Note: This test installs Locale module. |
|
1866 $libraries = drupal_get_library('locale'); |
|
1867 $this->assertEqual($libraries, array(), 'Retrieving libraries from a module not implementing hook_library() returns an emtpy array.'); |
|
1868 |
|
1869 // Retrieve a specific library by module and name. |
|
1870 $farbtastic = drupal_get_library('common_test', 'farbtastic'); |
|
1871 $this->assertEqual($farbtastic['version'], '5.3', 'Retrieved a single library.'); |
|
1872 // Retrieve a non-existing library by module and name. |
|
1873 $farbtastic = drupal_get_library('common_test', 'foo'); |
|
1874 $this->assertIdentical($farbtastic, FALSE, 'Retrieving a non-existing library returns FALSE.'); |
|
1875 } |
|
1876 |
|
1877 /** |
|
1878 * Tests that the query string remains intact when adding JavaScript files |
|
1879 * that have query string parameters. |
|
1880 */ |
|
1881 function testAddJsFileWithQueryString() { |
|
1882 $this->drupalGet('common-test/query-string'); |
|
1883 $query_string = variable_get('css_js_query_string', '0'); |
|
1884 $this->assertRaw(drupal_get_path('module', 'node') . '/node.js?' . $query_string, 'Query string was appended correctly to js.'); |
|
1885 } |
|
1886 |
|
1887 /** |
|
1888 * Resets static variables related to adding JavaScript to a page. |
|
1889 */ |
|
1890 function resetStaticVariables() { |
|
1891 drupal_static_reset('drupal_add_js'); |
|
1892 drupal_static_reset('drupal_add_library'); |
|
1893 drupal_static_reset('drupal_get_library'); |
|
1894 } |
|
1895 } |
|
1896 |
|
1897 /** |
|
1898 * Tests for drupal_render(). |
|
1899 */ |
|
1900 class DrupalRenderTestCase extends DrupalWebTestCase { |
|
1901 public static function getInfo() { |
|
1902 return array( |
|
1903 'name' => 'drupal_render()', |
|
1904 'description' => 'Performs functional tests on drupal_render().', |
|
1905 'group' => 'System', |
|
1906 ); |
|
1907 } |
|
1908 |
|
1909 function setUp() { |
|
1910 parent::setUp('common_test'); |
|
1911 } |
|
1912 |
|
1913 /** |
|
1914 * Tests the output drupal_render() for some elementary input values. |
|
1915 */ |
|
1916 function testDrupalRenderBasics() { |
|
1917 $types = array( |
|
1918 array( |
|
1919 'name' => 'null', |
|
1920 'value' => NULL, |
|
1921 'expected' => '', |
|
1922 ), |
|
1923 array( |
|
1924 'name' => 'no value', |
|
1925 'expected' => '', |
|
1926 ), |
|
1927 array( |
|
1928 'name' => 'empty string', |
|
1929 'value' => '', |
|
1930 'expected' => '', |
|
1931 ), |
|
1932 array( |
|
1933 'name' => 'no access', |
|
1934 'value' => array( |
|
1935 '#markup' => 'foo', |
|
1936 '#access' => FALSE, |
|
1937 ), |
|
1938 'expected' => '', |
|
1939 ), |
|
1940 array( |
|
1941 'name' => 'previously printed', |
|
1942 'value' => array( |
|
1943 '#markup' => 'foo', |
|
1944 '#printed' => TRUE, |
|
1945 ), |
|
1946 'expected' => '', |
|
1947 ), |
|
1948 array( |
|
1949 'name' => 'printed in prerender', |
|
1950 'value' => array( |
|
1951 '#markup' => 'foo', |
|
1952 '#pre_render' => array('common_test_drupal_render_printing_pre_render'), |
|
1953 ), |
|
1954 'expected' => '', |
|
1955 ), |
|
1956 array( |
|
1957 'name' => 'basic renderable array', |
|
1958 'value' => array('#markup' => 'foo'), |
|
1959 'expected' => 'foo', |
|
1960 ), |
|
1961 ); |
|
1962 foreach($types as $type) { |
|
1963 $this->assertIdentical(drupal_render($type['value']), $type['expected'], '"' . $type['name'] . '" input rendered correctly by drupal_render().'); |
|
1964 } |
|
1965 } |
|
1966 |
|
1967 /** |
|
1968 * Test sorting by weight. |
|
1969 */ |
|
1970 function testDrupalRenderSorting() { |
|
1971 $first = $this->randomName(); |
|
1972 $second = $this->randomName(); |
|
1973 // Build an array with '#weight' set for each element. |
|
1974 $elements = array( |
|
1975 'second' => array( |
|
1976 '#weight' => 10, |
|
1977 '#markup' => $second, |
|
1978 ), |
|
1979 'first' => array( |
|
1980 '#weight' => 0, |
|
1981 '#markup' => $first, |
|
1982 ), |
|
1983 ); |
|
1984 $output = drupal_render($elements); |
|
1985 |
|
1986 // The lowest weight element should appear last in $output. |
|
1987 $this->assertTrue(strpos($output, $second) > strpos($output, $first), 'Elements were sorted correctly by weight.'); |
|
1988 |
|
1989 // Confirm that the $elements array has '#sorted' set to TRUE. |
|
1990 $this->assertTrue($elements['#sorted'], "'#sorted' => TRUE was added to the array"); |
|
1991 |
|
1992 // Pass $elements through element_children() and ensure it remains |
|
1993 // sorted in the correct order. drupal_render() will return an empty string |
|
1994 // if used on the same array in the same request. |
|
1995 $children = element_children($elements); |
|
1996 $this->assertTrue(array_shift($children) == 'first', 'Child found in the correct order.'); |
|
1997 $this->assertTrue(array_shift($children) == 'second', 'Child found in the correct order.'); |
|
1998 |
|
1999 |
|
2000 // The same array structure again, but with #sorted set to TRUE. |
|
2001 $elements = array( |
|
2002 'second' => array( |
|
2003 '#weight' => 10, |
|
2004 '#markup' => $second, |
|
2005 ), |
|
2006 'first' => array( |
|
2007 '#weight' => 0, |
|
2008 '#markup' => $first, |
|
2009 ), |
|
2010 '#sorted' => TRUE, |
|
2011 ); |
|
2012 $output = drupal_render($elements); |
|
2013 |
|
2014 // The elements should appear in output in the same order as the array. |
|
2015 $this->assertTrue(strpos($output, $second) < strpos($output, $first), 'Elements were not sorted.'); |
|
2016 } |
|
2017 |
|
2018 /** |
|
2019 * Test #attached functionality in children elements. |
|
2020 */ |
|
2021 function testDrupalRenderChildrenAttached() { |
|
2022 // The cache system is turned off for POST requests. |
|
2023 $request_method = $_SERVER['REQUEST_METHOD']; |
|
2024 $_SERVER['REQUEST_METHOD'] = 'GET'; |
|
2025 |
|
2026 // Create an element with a child and subchild. Each element loads a |
|
2027 // different JavaScript file using #attached. |
|
2028 $parent_js = drupal_get_path('module', 'user') . '/user.js'; |
|
2029 $child_js = drupal_get_path('module', 'forum') . '/forum.js'; |
|
2030 $subchild_js = drupal_get_path('module', 'book') . '/book.js'; |
|
2031 $element = array( |
|
2032 '#type' => 'fieldset', |
|
2033 '#cache' => array( |
|
2034 'keys' => array('simpletest', 'drupal_render', 'children_attached'), |
|
2035 ), |
|
2036 '#attached' => array('js' => array($parent_js)), |
|
2037 '#title' => 'Parent', |
|
2038 ); |
|
2039 $element['child'] = array( |
|
2040 '#type' => 'fieldset', |
|
2041 '#attached' => array('js' => array($child_js)), |
|
2042 '#title' => 'Child', |
|
2043 ); |
|
2044 $element['child']['subchild'] = array( |
|
2045 '#attached' => array('js' => array($subchild_js)), |
|
2046 '#markup' => 'Subchild', |
|
2047 ); |
|
2048 |
|
2049 // Render the element and verify the presence of #attached JavaScript. |
|
2050 drupal_render($element); |
|
2051 $scripts = drupal_get_js(); |
|
2052 $this->assertTrue(strpos($scripts, $parent_js), 'The element #attached JavaScript was included.'); |
|
2053 $this->assertTrue(strpos($scripts, $child_js), 'The child #attached JavaScript was included.'); |
|
2054 $this->assertTrue(strpos($scripts, $subchild_js), 'The subchild #attached JavaScript was included.'); |
|
2055 |
|
2056 // Load the element from cache and verify the presence of the #attached |
|
2057 // JavaScript. |
|
2058 drupal_static_reset('drupal_add_js'); |
|
2059 $this->assertTrue(drupal_render_cache_get($element), 'The element was retrieved from cache.'); |
|
2060 $scripts = drupal_get_js(); |
|
2061 $this->assertTrue(strpos($scripts, $parent_js), 'The element #attached JavaScript was included when loading from cache.'); |
|
2062 $this->assertTrue(strpos($scripts, $child_js), 'The child #attached JavaScript was included when loading from cache.'); |
|
2063 $this->assertTrue(strpos($scripts, $subchild_js), 'The subchild #attached JavaScript was included when loading from cache.'); |
|
2064 |
|
2065 $_SERVER['REQUEST_METHOD'] = $request_method; |
|
2066 } |
|
2067 |
|
2068 /** |
|
2069 * Test passing arguments to the theme function. |
|
2070 */ |
|
2071 function testDrupalRenderThemeArguments() { |
|
2072 $element = array( |
|
2073 '#theme' => 'common_test_foo', |
|
2074 ); |
|
2075 // Test that defaults work. |
|
2076 $this->assertEqual(drupal_render($element), 'foobar', 'Defaults work'); |
|
2077 $element = array( |
|
2078 '#theme' => 'common_test_foo', |
|
2079 '#foo' => $this->randomName(), |
|
2080 '#bar' => $this->randomName(), |
|
2081 ); |
|
2082 // Test that passing arguments to the theme function works. |
|
2083 $this->assertEqual(drupal_render($element), $element['#foo'] . $element['#bar'], 'Passing arguments to theme functions works'); |
|
2084 } |
|
2085 |
|
2086 /** |
|
2087 * Test rendering form elements without passing through form_builder(). |
|
2088 */ |
|
2089 function testDrupalRenderFormElements() { |
|
2090 // Define a series of form elements. |
|
2091 $element = array( |
|
2092 '#type' => 'button', |
|
2093 '#value' => $this->randomName(), |
|
2094 ); |
|
2095 $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'submit')); |
|
2096 |
|
2097 $element = array( |
|
2098 '#type' => 'textfield', |
|
2099 '#title' => $this->randomName(), |
|
2100 '#value' => $this->randomName(), |
|
2101 ); |
|
2102 $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'text')); |
|
2103 |
|
2104 $element = array( |
|
2105 '#type' => 'password', |
|
2106 '#title' => $this->randomName(), |
|
2107 ); |
|
2108 $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'password')); |
|
2109 |
|
2110 $element = array( |
|
2111 '#type' => 'textarea', |
|
2112 '#title' => $this->randomName(), |
|
2113 '#value' => $this->randomName(), |
|
2114 ); |
|
2115 $this->assertRenderedElement($element, '//textarea'); |
|
2116 |
|
2117 $element = array( |
|
2118 '#type' => 'radio', |
|
2119 '#title' => $this->randomName(), |
|
2120 '#value' => FALSE, |
|
2121 ); |
|
2122 $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'radio')); |
|
2123 |
|
2124 $element = array( |
|
2125 '#type' => 'checkbox', |
|
2126 '#title' => $this->randomName(), |
|
2127 ); |
|
2128 $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'checkbox')); |
|
2129 |
|
2130 $element = array( |
|
2131 '#type' => 'select', |
|
2132 '#title' => $this->randomName(), |
|
2133 '#options' => array( |
|
2134 0 => $this->randomName(), |
|
2135 1 => $this->randomName(), |
|
2136 ), |
|
2137 ); |
|
2138 $this->assertRenderedElement($element, '//select'); |
|
2139 |
|
2140 $element = array( |
|
2141 '#type' => 'file', |
|
2142 '#title' => $this->randomName(), |
|
2143 ); |
|
2144 $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'file')); |
|
2145 |
|
2146 $element = array( |
|
2147 '#type' => 'item', |
|
2148 '#title' => $this->randomName(), |
|
2149 '#markup' => $this->randomName(), |
|
2150 ); |
|
2151 $this->assertRenderedElement($element, '//div[contains(@class, :class) and contains(., :markup)]/label[contains(., :label)]', array( |
|
2152 ':class' => 'form-type-item', |
|
2153 ':markup' => $element['#markup'], |
|
2154 ':label' => $element['#title'], |
|
2155 )); |
|
2156 |
|
2157 $element = array( |
|
2158 '#type' => 'hidden', |
|
2159 '#title' => $this->randomName(), |
|
2160 '#value' => $this->randomName(), |
|
2161 ); |
|
2162 $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'hidden')); |
|
2163 |
|
2164 $element = array( |
|
2165 '#type' => 'link', |
|
2166 '#title' => $this->randomName(), |
|
2167 '#href' => $this->randomName(), |
|
2168 '#options' => array( |
|
2169 'absolute' => TRUE, |
|
2170 ), |
|
2171 ); |
|
2172 $this->assertRenderedElement($element, '//a[@href=:href and contains(., :title)]', array( |
|
2173 ':href' => url($element['#href'], array('absolute' => TRUE)), |
|
2174 ':title' => $element['#title'], |
|
2175 )); |
|
2176 |
|
2177 $element = array( |
|
2178 '#type' => 'fieldset', |
|
2179 '#title' => $this->randomName(), |
|
2180 ); |
|
2181 $this->assertRenderedElement($element, '//fieldset/legend[contains(., :title)]', array( |
|
2182 ':title' => $element['#title'], |
|
2183 )); |
|
2184 |
|
2185 $element['item'] = array( |
|
2186 '#type' => 'item', |
|
2187 '#title' => $this->randomName(), |
|
2188 '#markup' => $this->randomName(), |
|
2189 ); |
|
2190 $this->assertRenderedElement($element, '//fieldset/div/div[contains(@class, :class) and contains(., :markup)]', array( |
|
2191 ':class' => 'form-type-item', |
|
2192 ':markup' => $element['item']['#markup'], |
|
2193 )); |
|
2194 } |
|
2195 |
|
2196 protected function assertRenderedElement(array $element, $xpath, array $xpath_args = array()) { |
|
2197 $original_element = $element; |
|
2198 $this->drupalSetContent(drupal_render($element)); |
|
2199 $this->verbose('<pre>' . check_plain(var_export($original_element, TRUE)) . '</pre>' |
|
2200 . '<pre>' . check_plain(var_export($element, TRUE)) . '</pre>' |
|
2201 . '<hr />' . $this->drupalGetContent() |
|
2202 ); |
|
2203 |
|
2204 // @see DrupalWebTestCase::xpath() |
|
2205 $xpath = $this->buildXPathQuery($xpath, $xpath_args); |
|
2206 $element += array('#value' => NULL); |
|
2207 $this->assertFieldByXPath($xpath, $element['#value'], format_string('#type @type was properly rendered.', array( |
|
2208 '@type' => var_export($element['#type'], TRUE), |
|
2209 ))); |
|
2210 } |
|
2211 |
|
2212 /** |
|
2213 * Tests caching of render items. |
|
2214 */ |
|
2215 function testDrupalRenderCache() { |
|
2216 // Force a request via GET. |
|
2217 $request_method = $_SERVER['REQUEST_METHOD']; |
|
2218 $_SERVER['REQUEST_METHOD'] = 'GET'; |
|
2219 // Create an empty element. |
|
2220 $test_element = array( |
|
2221 '#cache' => array( |
|
2222 'cid' => 'render_cache_test', |
|
2223 ), |
|
2224 '#markup' => '', |
|
2225 ); |
|
2226 |
|
2227 // Render the element and confirm that it goes through the rendering |
|
2228 // process (which will set $element['#printed']). |
|
2229 $element = $test_element; |
|
2230 drupal_render($element); |
|
2231 $this->assertTrue(isset($element['#printed']), 'No cache hit'); |
|
2232 |
|
2233 // Render the element again and confirm that it is retrieved from the cache |
|
2234 // instead (so $element['#printed'] will not be set). |
|
2235 $element = $test_element; |
|
2236 drupal_render($element); |
|
2237 $this->assertFalse(isset($element['#printed']), 'Cache hit'); |
|
2238 |
|
2239 // Test that user 1 does not share the cache with other users who have the |
|
2240 // same roles, even when DRUPAL_CACHE_PER_ROLE is used. |
|
2241 $user1 = user_load(1); |
|
2242 $first_authenticated_user = $this->drupalCreateUser(); |
|
2243 $second_authenticated_user = $this->drupalCreateUser(); |
|
2244 $user1->roles = array_intersect_key($user1->roles, array(DRUPAL_AUTHENTICATED_RID => TRUE)); |
|
2245 user_save($user1); |
|
2246 // Load all the accounts again, to make sure we have complete account |
|
2247 // objects. |
|
2248 $user1 = user_load(1); |
|
2249 $first_authenticated_user = user_load($first_authenticated_user->uid); |
|
2250 $second_authenticated_user = user_load($second_authenticated_user->uid); |
|
2251 $this->assertEqual($user1->roles, $first_authenticated_user->roles, 'User 1 has the same roles as an authenticated user.'); |
|
2252 // Impersonate user 1 and render content that only user 1 should have |
|
2253 // permission to see. |
|
2254 $original_user = $GLOBALS['user']; |
|
2255 $original_session_state = drupal_save_session(); |
|
2256 drupal_save_session(FALSE); |
|
2257 $GLOBALS['user'] = $user1; |
|
2258 $test_element = array( |
|
2259 '#cache' => array( |
|
2260 'keys' => array('test'), |
|
2261 'granularity' => DRUPAL_CACHE_PER_ROLE, |
|
2262 ), |
|
2263 ); |
|
2264 $element = $test_element; |
|
2265 $element['#markup'] = 'content for user 1'; |
|
2266 $output = drupal_render($element); |
|
2267 $this->assertEqual($output, 'content for user 1'); |
|
2268 // Verify the cache is working by rendering the same element but with |
|
2269 // different markup passed in; the result should be the same. |
|
2270 $element = $test_element; |
|
2271 $element['#markup'] = 'should not be used'; |
|
2272 $output = drupal_render($element); |
|
2273 $this->assertEqual($output, 'content for user 1'); |
|
2274 // Verify that the first authenticated user does not see the same content |
|
2275 // as user 1. |
|
2276 $GLOBALS['user'] = $first_authenticated_user; |
|
2277 $element = $test_element; |
|
2278 $element['#markup'] = 'content for authenticated users'; |
|
2279 $output = drupal_render($element); |
|
2280 $this->assertEqual($output, 'content for authenticated users'); |
|
2281 // Verify that the second authenticated user shares the cache with the |
|
2282 // first authenticated user. |
|
2283 $GLOBALS['user'] = $second_authenticated_user; |
|
2284 $element = $test_element; |
|
2285 $element['#markup'] = 'should not be used'; |
|
2286 $output = drupal_render($element); |
|
2287 $this->assertEqual($output, 'content for authenticated users'); |
|
2288 // Restore the original logged-in user. |
|
2289 $GLOBALS['user'] = $original_user; |
|
2290 drupal_save_session($original_session_state); |
|
2291 |
|
2292 // Restore the previous request method. |
|
2293 $_SERVER['REQUEST_METHOD'] = $request_method; |
|
2294 } |
|
2295 } |
|
2296 |
|
2297 /** |
|
2298 * Test for valid_url(). |
|
2299 */ |
|
2300 class ValidUrlTestCase extends DrupalUnitTestCase { |
|
2301 public static function getInfo() { |
|
2302 return array( |
|
2303 'name' => 'Valid URL', |
|
2304 'description' => "Performs tests on Drupal's valid URL function.", |
|
2305 'group' => 'System' |
|
2306 ); |
|
2307 } |
|
2308 |
|
2309 /** |
|
2310 * Test valid absolute URLs. |
|
2311 */ |
|
2312 function testValidAbsolute() { |
|
2313 $url_schemes = array('http', 'https', 'ftp'); |
|
2314 $valid_absolute_urls = array( |
|
2315 'example.com', |
|
2316 'www.example.com', |
|
2317 'ex-ample.com', |
|
2318 '3xampl3.com', |
|
2319 'example.com/paren(the)sis', |
|
2320 'example.com/index.html#pagetop', |
|
2321 'example.com:8080', |
|
2322 'subdomain.example.com', |
|
2323 'example.com/index.php?q=node', |
|
2324 'example.com/index.php?q=node¶m=false', |
|
2325 'user@www.example.com', |
|
2326 'user:pass@www.example.com:8080/login.php?do=login&style=%23#pagetop', |
|
2327 '127.0.0.1', |
|
2328 'example.org?', |
|
2329 'john%20doe:secret:foo@example.org/', |
|
2330 'example.org/~,$\'*;', |
|
2331 'caf%C3%A9.example.org', |
|
2332 '[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html', |
|
2333 ); |
|
2334 |
|
2335 foreach ($url_schemes as $scheme) { |
|
2336 foreach ($valid_absolute_urls as $url) { |
|
2337 $test_url = $scheme . '://' . $url; |
|
2338 $valid_url = valid_url($test_url, TRUE); |
|
2339 $this->assertTrue($valid_url, format_string('@url is a valid url.', array('@url' => $test_url))); |
|
2340 } |
|
2341 } |
|
2342 } |
|
2343 |
|
2344 /** |
|
2345 * Test invalid absolute URLs. |
|
2346 */ |
|
2347 function testInvalidAbsolute() { |
|
2348 $url_schemes = array('http', 'https', 'ftp'); |
|
2349 $invalid_ablosule_urls = array( |
|
2350 '', |
|
2351 'ex!ample.com', |
|
2352 'ex%ample.com', |
|
2353 ); |
|
2354 |
|
2355 foreach ($url_schemes as $scheme) { |
|
2356 foreach ($invalid_ablosule_urls as $url) { |
|
2357 $test_url = $scheme . '://' . $url; |
|
2358 $valid_url = valid_url($test_url, TRUE); |
|
2359 $this->assertFalse($valid_url, format_string('@url is NOT a valid url.', array('@url' => $test_url))); |
|
2360 } |
|
2361 } |
|
2362 } |
|
2363 |
|
2364 /** |
|
2365 * Test valid relative URLs. |
|
2366 */ |
|
2367 function testValidRelative() { |
|
2368 $valid_relative_urls = array( |
|
2369 'paren(the)sis', |
|
2370 'index.html#pagetop', |
|
2371 'index.php?q=node', |
|
2372 'index.php?q=node¶m=false', |
|
2373 'login.php?do=login&style=%23#pagetop', |
|
2374 ); |
|
2375 |
|
2376 foreach (array('', '/') as $front) { |
|
2377 foreach ($valid_relative_urls as $url) { |
|
2378 $test_url = $front . $url; |
|
2379 $valid_url = valid_url($test_url); |
|
2380 $this->assertTrue($valid_url, format_string('@url is a valid url.', array('@url' => $test_url))); |
|
2381 } |
|
2382 } |
|
2383 } |
|
2384 |
|
2385 /** |
|
2386 * Test invalid relative URLs. |
|
2387 */ |
|
2388 function testInvalidRelative() { |
|
2389 $invalid_relative_urls = array( |
|
2390 'ex^mple', |
|
2391 'example<>', |
|
2392 'ex%ample', |
|
2393 ); |
|
2394 |
|
2395 foreach (array('', '/') as $front) { |
|
2396 foreach ($invalid_relative_urls as $url) { |
|
2397 $test_url = $front . $url; |
|
2398 $valid_url = valid_url($test_url); |
|
2399 $this->assertFALSE($valid_url, format_string('@url is NOT a valid url.', array('@url' => $test_url))); |
|
2400 } |
|
2401 } |
|
2402 } |
|
2403 } |
|
2404 |
|
2405 /** |
|
2406 * Tests for CRUD API functions. |
|
2407 */ |
|
2408 class DrupalDataApiTest extends DrupalWebTestCase { |
|
2409 public static function getInfo() { |
|
2410 return array( |
|
2411 'name' => 'Data API functions', |
|
2412 'description' => 'Tests the performance of CRUD APIs.', |
|
2413 'group' => 'System', |
|
2414 ); |
|
2415 } |
|
2416 |
|
2417 function setUp() { |
|
2418 parent::setUp('database_test'); |
|
2419 } |
|
2420 |
|
2421 /** |
|
2422 * Test the drupal_write_record() API function. |
|
2423 */ |
|
2424 function testDrupalWriteRecord() { |
|
2425 // Insert a record - no columns allow NULL values. |
|
2426 $person = new stdClass(); |
|
2427 $person->name = 'John'; |
|
2428 $person->unknown_column = 123; |
|
2429 $insert_result = drupal_write_record('test', $person); |
|
2430 $this->assertTrue($insert_result == SAVED_NEW, 'Correct value returned when a record is inserted with drupal_write_record() for a table with a single-field primary key.'); |
|
2431 $this->assertTrue(isset($person->id), 'Primary key is set on record created with drupal_write_record().'); |
|
2432 $this->assertIdentical($person->age, 0, 'Age field set to default value.'); |
|
2433 $this->assertIdentical($person->job, 'Undefined', 'Job field set to default value.'); |
|
2434 |
|
2435 // Verify that the record was inserted. |
|
2436 $result = db_query("SELECT * FROM {test} WHERE id = :id", array(':id' => $person->id))->fetchObject(); |
|
2437 $this->assertIdentical($result->name, 'John', 'Name field set.'); |
|
2438 $this->assertIdentical($result->age, '0', 'Age field set to default value.'); |
|
2439 $this->assertIdentical($result->job, 'Undefined', 'Job field set to default value.'); |
|
2440 $this->assertFalse(isset($result->unknown_column), 'Unknown column was ignored.'); |
|
2441 |
|
2442 // Update the newly created record. |
|
2443 $person->name = 'Peter'; |
|
2444 $person->age = 27; |
|
2445 $person->job = NULL; |
|
2446 $update_result = drupal_write_record('test', $person, array('id')); |
|
2447 $this->assertTrue($update_result == SAVED_UPDATED, 'Correct value returned when a record updated with drupal_write_record() for table with single-field primary key.'); |
|
2448 |
|
2449 // Verify that the record was updated. |
|
2450 $result = db_query("SELECT * FROM {test} WHERE id = :id", array(':id' => $person->id))->fetchObject(); |
|
2451 $this->assertIdentical($result->name, 'Peter', 'Name field set.'); |
|
2452 $this->assertIdentical($result->age, '27', 'Age field set.'); |
|
2453 $this->assertIdentical($result->job, '', 'Job field set and cast to string.'); |
|
2454 |
|
2455 // Try to insert NULL in columns that does not allow this. |
|
2456 $person = new stdClass(); |
|
2457 $person->name = 'Ringo'; |
|
2458 $person->age = NULL; |
|
2459 $person->job = NULL; |
|
2460 $insert_result = drupal_write_record('test', $person); |
|
2461 $this->assertTrue(isset($person->id), 'Primary key is set on record created with drupal_write_record().'); |
|
2462 $result = db_query("SELECT * FROM {test} WHERE id = :id", array(':id' => $person->id))->fetchObject(); |
|
2463 $this->assertIdentical($result->name, 'Ringo', 'Name field set.'); |
|
2464 $this->assertIdentical($result->age, '0', 'Age field set.'); |
|
2465 $this->assertIdentical($result->job, '', 'Job field set.'); |
|
2466 |
|
2467 // Insert a record - the "age" column allows NULL. |
|
2468 $person = new stdClass(); |
|
2469 $person->name = 'Paul'; |
|
2470 $person->age = NULL; |
|
2471 $insert_result = drupal_write_record('test_null', $person); |
|
2472 $this->assertTrue(isset($person->id), 'Primary key is set on record created with drupal_write_record().'); |
|
2473 $result = db_query("SELECT * FROM {test_null} WHERE id = :id", array(':id' => $person->id))->fetchObject(); |
|
2474 $this->assertIdentical($result->name, 'Paul', 'Name field set.'); |
|
2475 $this->assertIdentical($result->age, NULL, 'Age field set.'); |
|
2476 |
|
2477 // Insert a record - do not specify the value of a column that allows NULL. |
|
2478 $person = new stdClass(); |
|
2479 $person->name = 'Meredith'; |
|
2480 $insert_result = drupal_write_record('test_null', $person); |
|
2481 $this->assertTrue(isset($person->id), 'Primary key is set on record created with drupal_write_record().'); |
|
2482 $this->assertIdentical($person->age, 0, 'Age field set to default value.'); |
|
2483 $result = db_query("SELECT * FROM {test_null} WHERE id = :id", array(':id' => $person->id))->fetchObject(); |
|
2484 $this->assertIdentical($result->name, 'Meredith', 'Name field set.'); |
|
2485 $this->assertIdentical($result->age, '0', 'Age field set to default value.'); |
|
2486 |
|
2487 // Update the newly created record. |
|
2488 $person->name = 'Mary'; |
|
2489 $person->age = NULL; |
|
2490 $update_result = drupal_write_record('test_null', $person, array('id')); |
|
2491 $result = db_query("SELECT * FROM {test_null} WHERE id = :id", array(':id' => $person->id))->fetchObject(); |
|
2492 $this->assertIdentical($result->name, 'Mary', 'Name field set.'); |
|
2493 $this->assertIdentical($result->age, NULL, 'Age field set.'); |
|
2494 |
|
2495 // Insert a record - the "data" column should be serialized. |
|
2496 $person = new stdClass(); |
|
2497 $person->name = 'Dave'; |
|
2498 $update_result = drupal_write_record('test_serialized', $person); |
|
2499 $result = db_query("SELECT * FROM {test_serialized} WHERE id = :id", array(':id' => $person->id))->fetchObject(); |
|
2500 $this->assertIdentical($result->name, 'Dave', 'Name field set.'); |
|
2501 $this->assertIdentical($result->info, NULL, 'Info field set.'); |
|
2502 |
|
2503 $person->info = array(); |
|
2504 $update_result = drupal_write_record('test_serialized', $person, array('id')); |
|
2505 $result = db_query("SELECT * FROM {test_serialized} WHERE id = :id", array(':id' => $person->id))->fetchObject(); |
|
2506 $this->assertIdentical(unserialize($result->info), array(), 'Info field updated.'); |
|
2507 |
|
2508 // Update the serialized record. |
|
2509 $data = array('foo' => 'bar', 1 => 2, 'empty' => '', 'null' => NULL); |
|
2510 $person->info = $data; |
|
2511 $update_result = drupal_write_record('test_serialized', $person, array('id')); |
|
2512 $result = db_query("SELECT * FROM {test_serialized} WHERE id = :id", array(':id' => $person->id))->fetchObject(); |
|
2513 $this->assertIdentical(unserialize($result->info), $data, 'Info field updated.'); |
|
2514 |
|
2515 // Run an update query where no field values are changed. The database |
|
2516 // layer should return zero for number of affected rows, but |
|
2517 // db_write_record() should still return SAVED_UPDATED. |
|
2518 $update_result = drupal_write_record('test_null', $person, array('id')); |
|
2519 $this->assertTrue($update_result == SAVED_UPDATED, 'Correct value returned when a valid update is run without changing any values.'); |
|
2520 |
|
2521 // Insert an object record for a table with a multi-field primary key. |
|
2522 $node_access = new stdClass(); |
|
2523 $node_access->nid = mt_rand(); |
|
2524 $node_access->gid = mt_rand(); |
|
2525 $node_access->realm = $this->randomName(); |
|
2526 $insert_result = drupal_write_record('node_access', $node_access); |
|
2527 $this->assertTrue($insert_result == SAVED_NEW, 'Correct value returned when a record is inserted with drupal_write_record() for a table with a multi-field primary key.'); |
|
2528 |
|
2529 // Update the record. |
|
2530 $update_result = drupal_write_record('node_access', $node_access, array('nid', 'gid', 'realm')); |
|
2531 $this->assertTrue($update_result == SAVED_UPDATED, 'Correct value returned when a record is updated with drupal_write_record() for a table with a multi-field primary key.'); |
|
2532 } |
|
2533 |
|
2534 } |
|
2535 |
|
2536 /** |
|
2537 * Tests Simpletest error and exception collector. |
|
2538 */ |
|
2539 class DrupalErrorCollectionUnitTest extends DrupalWebTestCase { |
|
2540 |
|
2541 /** |
|
2542 * Errors triggered during the test. |
|
2543 * |
|
2544 * Errors are intercepted by the overriden implementation |
|
2545 * of DrupalWebTestCase::error below. |
|
2546 * |
|
2547 * @var Array |
|
2548 */ |
|
2549 protected $collectedErrors = array(); |
|
2550 |
|
2551 public static function getInfo() { |
|
2552 return array( |
|
2553 'name' => 'SimpleTest error collector', |
|
2554 'description' => 'Performs tests on the Simpletest error and exception collector.', |
|
2555 'group' => 'SimpleTest', |
|
2556 ); |
|
2557 } |
|
2558 |
|
2559 function setUp() { |
|
2560 parent::setUp('system_test', 'error_test'); |
|
2561 } |
|
2562 |
|
2563 /** |
|
2564 * Test that simpletest collects errors from the tested site. |
|
2565 */ |
|
2566 function testErrorCollect() { |
|
2567 $this->collectedErrors = array(); |
|
2568 $this->drupalGet('error-test/generate-warnings-with-report'); |
|
2569 $this->assertEqual(count($this->collectedErrors), 3, 'Three errors were collected'); |
|
2570 |
|
2571 if (count($this->collectedErrors) == 3) { |
|
2572 $this->assertError($this->collectedErrors[0], 'Notice', 'error_test_generate_warnings()', 'error_test.module', 'Undefined variable: bananas'); |
|
2573 $this->assertError($this->collectedErrors[1], 'Warning', 'error_test_generate_warnings()', 'error_test.module', 'Division by zero'); |
|
2574 $this->assertError($this->collectedErrors[2], 'User warning', 'error_test_generate_warnings()', 'error_test.module', 'Drupal is awesome'); |
|
2575 } |
|
2576 else { |
|
2577 // Give back the errors to the log report. |
|
2578 foreach ($this->collectedErrors as $error) { |
|
2579 parent::error($error['message'], $error['group'], $error['caller']); |
|
2580 } |
|
2581 } |
|
2582 } |
|
2583 |
|
2584 /** |
|
2585 * Error handler that collects errors in an array. |
|
2586 * |
|
2587 * This test class is trying to verify that simpletest correctly sees errors |
|
2588 * and warnings. However, it can't generate errors and warnings that |
|
2589 * propagate up to the testing framework itself, or these tests would always |
|
2590 * fail. So, this special copy of error() doesn't propagate the errors up |
|
2591 * the class hierarchy. It just stuffs them into a protected collectedErrors |
|
2592 * array for various assertions to inspect. |
|
2593 */ |
|
2594 protected function error($message = '', $group = 'Other', array $caller = NULL) { |
|
2595 // Due to a WTF elsewhere, simpletest treats debug() and verbose() |
|
2596 // messages as if they were an 'error'. But, we don't want to collect |
|
2597 // those here. This function just wants to collect the real errors (PHP |
|
2598 // notices, PHP fatal errors, etc.), and let all the 'errors' from the |
|
2599 // 'User notice' group bubble up to the parent classes to be handled (and |
|
2600 // eventually displayed) as normal. |
|
2601 if ($group == 'User notice') { |
|
2602 parent::error($message, $group, $caller); |
|
2603 } |
|
2604 // Everything else should be collected but not propagated. |
|
2605 else { |
|
2606 $this->collectedErrors[] = array( |
|
2607 'message' => $message, |
|
2608 'group' => $group, |
|
2609 'caller' => $caller |
|
2610 ); |
|
2611 } |
|
2612 } |
|
2613 |
|
2614 /** |
|
2615 * Assert that a collected error matches what we are expecting. |
|
2616 */ |
|
2617 function assertError($error, $group, $function, $file, $message = NULL) { |
|
2618 $this->assertEqual($error['group'], $group, format_string("Group was %group", array('%group' => $group))); |
|
2619 $this->assertEqual($error['caller']['function'], $function, format_string("Function was %function", array('%function' => $function))); |
|
2620 $this->assertEqual(drupal_basename($error['caller']['file']), $file, format_string("File was %file", array('%file' => $file))); |
|
2621 if (isset($message)) { |
|
2622 $this->assertEqual($error['message'], $message, format_string("Message was %message", array('%message' => $message))); |
|
2623 } |
|
2624 } |
|
2625 } |
|
2626 |
|
2627 /** |
|
2628 * Test the drupal_parse_info_file() API function. |
|
2629 */ |
|
2630 class ParseInfoFilesTestCase extends DrupalUnitTestCase { |
|
2631 public static function getInfo() { |
|
2632 return array( |
|
2633 'name' => 'Parsing .info files', |
|
2634 'description' => 'Tests parsing .info files.', |
|
2635 'group' => 'System', |
|
2636 ); |
|
2637 } |
|
2638 |
|
2639 /** |
|
2640 * Parse an example .info file an verify the results. |
|
2641 */ |
|
2642 function testParseInfoFile() { |
|
2643 $info_values = drupal_parse_info_file(drupal_get_path('module', 'simpletest') . '/tests/common_test_info.txt'); |
|
2644 $this->assertEqual($info_values['simple_string'], 'A simple string', 'Simple string value was parsed correctly.', 'System'); |
|
2645 $this->assertEqual($info_values['simple_constant'], WATCHDOG_INFO, 'Constant value was parsed correctly.', 'System'); |
|
2646 $this->assertEqual($info_values['double_colon'], 'dummyClassName::', 'Value containing double-colon was parsed correctly.', 'System'); |
|
2647 } |
|
2648 } |
|
2649 |
|
2650 /** |
|
2651 * Tests for the drupal_system_listing() function. |
|
2652 */ |
|
2653 class DrupalSystemListingTestCase extends DrupalWebTestCase { |
|
2654 /** |
|
2655 * Use the testing profile; this is needed for testDirectoryPrecedence(). |
|
2656 */ |
|
2657 protected $profile = 'testing'; |
|
2658 |
|
2659 public static function getInfo() { |
|
2660 return array( |
|
2661 'name' => 'Drupal system listing', |
|
2662 'description' => 'Tests the mechanism for scanning system directories in drupal_system_listing().', |
|
2663 'group' => 'System', |
|
2664 ); |
|
2665 } |
|
2666 |
|
2667 /** |
|
2668 * Test that files in different directories take precedence as expected. |
|
2669 */ |
|
2670 function testDirectoryPrecedence() { |
|
2671 // Define the module files we will search for, and the directory precedence |
|
2672 // we expect. |
|
2673 $expected_directories = array( |
|
2674 // When the copy of the module in the profile directory is incompatible |
|
2675 // with Drupal core, the copy in the core modules directory takes |
|
2676 // precedence. |
|
2677 'drupal_system_listing_incompatible_test' => array( |
|
2678 'modules/simpletest/tests', |
|
2679 'profiles/testing/modules', |
|
2680 ), |
|
2681 // When both copies of the module are compatible with Drupal core, the |
|
2682 // copy in the profile directory takes precedence. |
|
2683 'drupal_system_listing_compatible_test' => array( |
|
2684 'profiles/testing/modules', |
|
2685 'modules/simpletest/tests', |
|
2686 ), |
|
2687 ); |
|
2688 |
|
2689 // This test relies on two versions of the same module existing in |
|
2690 // different places in the filesystem. Without that, the test has no |
|
2691 // meaning, so assert their presence first. |
|
2692 foreach ($expected_directories as $module => $directories) { |
|
2693 foreach ($directories as $directory) { |
|
2694 $filename = "$directory/$module/$module.module"; |
|
2695 $this->assertTrue(file_exists(DRUPAL_ROOT . '/' . $filename), format_string('@filename exists.', array('@filename' => $filename))); |
|
2696 } |
|
2697 } |
|
2698 |
|
2699 // Now scan the directories and check that the files take precedence as |
|
2700 // expected. |
|
2701 $files = drupal_system_listing('/\.module$/', 'modules', 'name', 1); |
|
2702 foreach ($expected_directories as $module => $directories) { |
|
2703 $expected_directory = array_shift($directories); |
|
2704 $expected_filename = "$expected_directory/$module/$module.module"; |
|
2705 $this->assertEqual($files[$module]->uri, $expected_filename, format_string('Module @module was found at @filename.', array('@module' => $module, '@filename' => $expected_filename))); |
|
2706 } |
|
2707 } |
|
2708 } |
|
2709 |
|
2710 /** |
|
2711 * Tests for the format_date() function. |
|
2712 */ |
|
2713 class FormatDateUnitTest extends DrupalWebTestCase { |
|
2714 |
|
2715 /** |
|
2716 * Arbitrary langcode for a custom language. |
|
2717 */ |
|
2718 const LANGCODE = 'xx'; |
|
2719 |
|
2720 public static function getInfo() { |
|
2721 return array( |
|
2722 'name' => 'Format date', |
|
2723 'description' => 'Test the format_date() function.', |
|
2724 'group' => 'System', |
|
2725 ); |
|
2726 } |
|
2727 |
|
2728 function setUp() { |
|
2729 parent::setUp('locale'); |
|
2730 variable_set('configurable_timezones', 1); |
|
2731 variable_set('date_format_long', 'l, j. F Y - G:i'); |
|
2732 variable_set('date_format_medium', 'j. F Y - G:i'); |
|
2733 variable_set('date_format_short', 'Y M j - g:ia'); |
|
2734 variable_set('locale_custom_strings_' . self::LANGCODE, array( |
|
2735 '' => array('Sunday' => 'domingo'), |
|
2736 'Long month name' => array('March' => 'marzo'), |
|
2737 )); |
|
2738 $this->refreshVariables(); |
|
2739 } |
|
2740 |
|
2741 /** |
|
2742 * Test admin-defined formats in format_date(). |
|
2743 */ |
|
2744 function testAdminDefinedFormatDate() { |
|
2745 // Create an admin user. |
|
2746 $this->admin_user = $this->drupalCreateUser(array('administer site configuration')); |
|
2747 $this->drupalLogin($this->admin_user); |
|
2748 |
|
2749 // Add new date format. |
|
2750 $admin_date_format = 'j M y'; |
|
2751 $edit = array('date_format' => $admin_date_format); |
|
2752 $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, 'Add format'); |
|
2753 |
|
2754 // Add a new date format which just differs in the case. |
|
2755 $admin_date_format_uppercase = 'j M Y'; |
|
2756 $edit = array('date_format' => $admin_date_format_uppercase); |
|
2757 $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format')); |
|
2758 $this->assertText(t('Custom date format added.')); |
|
2759 |
|
2760 // Add new date type. |
|
2761 $edit = array( |
|
2762 'date_type' => 'Example Style', |
|
2763 'machine_name' => 'example_style', |
|
2764 'date_format' => $admin_date_format, |
|
2765 ); |
|
2766 $this->drupalPost('admin/config/regional/date-time/types/add', $edit, 'Add date type'); |
|
2767 |
|
2768 // Add a second date format with a different case than the first. |
|
2769 $edit = array( |
|
2770 'machine_name' => 'example_style_uppercase', |
|
2771 'date_type' => 'Example Style Uppercase', |
|
2772 'date_format' => $admin_date_format_uppercase, |
|
2773 ); |
|
2774 $this->drupalPost('admin/config/regional/date-time/types/add', $edit, t('Add date type')); |
|
2775 $this->assertText(t('New date type added successfully.')); |
|
2776 |
|
2777 $timestamp = strtotime('2007-03-10T00:00:00+00:00'); |
|
2778 $this->assertIdentical(format_date($timestamp, 'example_style', '', 'America/Los_Angeles'), '9 Mar 07', 'Test format_date() using an admin-defined date type.'); |
|
2779 $this->assertIdentical(format_date($timestamp, 'example_style_uppercase', '', 'America/Los_Angeles'), '9 Mar 2007', 'Test format_date() using an admin-defined date type with different case.'); |
|
2780 $this->assertIdentical(format_date($timestamp, 'undefined_style'), format_date($timestamp, 'medium'), 'Test format_date() defaulting to medium when $type not found.'); |
|
2781 } |
|
2782 |
|
2783 /** |
|
2784 * Tests for the format_date() function. |
|
2785 */ |
|
2786 function testFormatDate() { |
|
2787 global $user, $language; |
|
2788 |
|
2789 $timestamp = strtotime('2007-03-26T00:00:00+00:00'); |
|
2790 $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', 'en'), 'Sunday, 25-Mar-07 17:00:00 PDT', 'Test all parameters.'); |
|
2791 $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), 'domingo, 25-Mar-07 17:00:00 PDT', 'Test translated format.'); |
|
2792 $this->assertIdentical(format_date($timestamp, 'custom', '\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), 'l, 25-Mar-07 17:00:00 PDT', 'Test an escaped format string.'); |
|
2793 $this->assertIdentical(format_date($timestamp, 'custom', '\\\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), '\\domingo, 25-Mar-07 17:00:00 PDT', 'Test format containing backslash character.'); |
|
2794 $this->assertIdentical(format_date($timestamp, 'custom', '\\\\\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), '\\l, 25-Mar-07 17:00:00 PDT', 'Test format containing backslash followed by escaped format string.'); |
|
2795 $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'Europe/London', 'en'), 'Monday, 26-Mar-07 01:00:00 BST', 'Test a different time zone.'); |
|
2796 |
|
2797 // Create an admin user and add Spanish language. |
|
2798 $admin_user = $this->drupalCreateUser(array('administer languages')); |
|
2799 $this->drupalLogin($admin_user); |
|
2800 $edit = array( |
|
2801 'langcode' => self::LANGCODE, |
|
2802 'name' => self::LANGCODE, |
|
2803 'native' => self::LANGCODE, |
|
2804 'direction' => LANGUAGE_LTR, |
|
2805 'prefix' => self::LANGCODE, |
|
2806 ); |
|
2807 $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language')); |
|
2808 |
|
2809 // Create a test user to carry out the tests. |
|
2810 $test_user = $this->drupalCreateUser(); |
|
2811 $this->drupalLogin($test_user); |
|
2812 $edit = array('language' => self::LANGCODE, 'mail' => $test_user->mail, 'timezone' => 'America/Los_Angeles'); |
|
2813 $this->drupalPost('user/' . $test_user->uid . '/edit', $edit, t('Save')); |
|
2814 |
|
2815 // Disable session saving as we are about to modify the global $user. |
|
2816 drupal_save_session(FALSE); |
|
2817 // Save the original user and language and then replace it with the test user and language. |
|
2818 $real_user = $user; |
|
2819 $user = user_load($test_user->uid, TRUE); |
|
2820 $real_language = $language->language; |
|
2821 $language->language = $user->language; |
|
2822 // Simulate a Drupal bootstrap with the logged-in user. |
|
2823 date_default_timezone_set(drupal_get_user_timezone()); |
|
2824 |
|
2825 $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', 'en'), 'Sunday, 25-Mar-07 17:00:00 PDT', 'Test a different language.'); |
|
2826 $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'Europe/London'), 'Monday, 26-Mar-07 01:00:00 BST', 'Test a different time zone.'); |
|
2827 $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T'), 'domingo, 25-Mar-07 17:00:00 PDT', 'Test custom date format.'); |
|
2828 $this->assertIdentical(format_date($timestamp, 'long'), 'domingo, 25. marzo 2007 - 17:00', 'Test long date format.'); |
|
2829 $this->assertIdentical(format_date($timestamp, 'medium'), '25. marzo 2007 - 17:00', 'Test medium date format.'); |
|
2830 $this->assertIdentical(format_date($timestamp, 'short'), '2007 Mar 25 - 5:00pm', 'Test short date format.'); |
|
2831 $this->assertIdentical(format_date($timestamp), '25. marzo 2007 - 17:00', 'Test default date format.'); |
|
2832 |
|
2833 // Restore the original user and language, and enable session saving. |
|
2834 $user = $real_user; |
|
2835 $language->language = $real_language; |
|
2836 // Restore default time zone. |
|
2837 date_default_timezone_set(drupal_get_user_timezone()); |
|
2838 drupal_save_session(TRUE); |
|
2839 } |
|
2840 } |
|
2841 |
|
2842 /** |
|
2843 * Tests for the format_date() function. |
|
2844 */ |
|
2845 class DrupalAttributesUnitTest extends DrupalUnitTestCase { |
|
2846 public static function getInfo() { |
|
2847 return array( |
|
2848 'name' => 'HTML Attributes', |
|
2849 'description' => 'Perform unit tests on the drupal_attributes() function.', |
|
2850 'group' => 'System', |
|
2851 ); |
|
2852 } |
|
2853 |
|
2854 /** |
|
2855 * Tests that drupal_html_class() cleans the class name properly. |
|
2856 */ |
|
2857 function testDrupalAttributes() { |
|
2858 // Verify that special characters are HTML encoded. |
|
2859 $this->assertIdentical(drupal_attributes(array('title' => '&"\'<>')), ' title="&"'<>"', 'HTML encode attribute values.'); |
|
2860 |
|
2861 // Verify multi-value attributes are concatenated with spaces. |
|
2862 $attributes = array('class' => array('first', 'last')); |
|
2863 $this->assertIdentical(drupal_attributes(array('class' => array('first', 'last'))), ' class="first last"', 'Concatenate multi-value attributes.'); |
|
2864 |
|
2865 // Verify empty attribute values are rendered. |
|
2866 $this->assertIdentical(drupal_attributes(array('alt' => '')), ' alt=""', 'Empty attribute value #1.'); |
|
2867 $this->assertIdentical(drupal_attributes(array('alt' => NULL)), ' alt=""', 'Empty attribute value #2.'); |
|
2868 |
|
2869 // Verify multiple attributes are rendered. |
|
2870 $attributes = array( |
|
2871 'id' => 'id-test', |
|
2872 'class' => array('first', 'last'), |
|
2873 'alt' => 'Alternate', |
|
2874 ); |
|
2875 $this->assertIdentical(drupal_attributes($attributes), ' id="id-test" class="first last" alt="Alternate"', 'Multiple attributes.'); |
|
2876 |
|
2877 // Verify empty attributes array is rendered. |
|
2878 $this->assertIdentical(drupal_attributes(array()), '', 'Empty attributes array.'); |
|
2879 } |
|
2880 } |
|
2881 |
|
2882 /** |
|
2883 * Tests converting PHP variables to JSON strings and back. |
|
2884 */ |
|
2885 class DrupalJSONTest extends DrupalUnitTestCase { |
|
2886 public static function getInfo() { |
|
2887 return array( |
|
2888 'name' => 'JSON', |
|
2889 'description' => 'Perform unit tests on the drupal_json_encode() and drupal_json_decode() functions.', |
|
2890 'group' => 'System', |
|
2891 ); |
|
2892 } |
|
2893 |
|
2894 /** |
|
2895 * Tests converting PHP variables to JSON strings and back. |
|
2896 */ |
|
2897 function testJSON() { |
|
2898 // Setup a string with the full ASCII table. |
|
2899 // @todo: Add tests for non-ASCII characters and Unicode. |
|
2900 $str = ''; |
|
2901 for ($i=0; $i < 128; $i++) { |
|
2902 $str .= chr($i); |
|
2903 } |
|
2904 // Characters that must be escaped. |
|
2905 // We check for unescaped " separately. |
|
2906 $html_unsafe = array('<', '>', '\'', '&'); |
|
2907 // The following are the encoded forms of: < > ' & " |
|
2908 $html_unsafe_escaped = array('\u003C', '\u003E', '\u0027', '\u0026', '\u0022'); |
|
2909 |
|
2910 // Verify there aren't character encoding problems with the source string. |
|
2911 $this->assertIdentical(strlen($str), 128, 'A string with the full ASCII table has the correct length.'); |
|
2912 foreach ($html_unsafe as $char) { |
|
2913 $this->assertTrue(strpos($str, $char) > 0, format_string('A string with the full ASCII table includes @s.', array('@s' => $char))); |
|
2914 } |
|
2915 |
|
2916 // Verify that JSON encoding produces a string with all of the characters. |
|
2917 $json = drupal_json_encode($str); |
|
2918 $this->assertTrue(strlen($json) > strlen($str), 'A JSON encoded string is larger than the source string.'); |
|
2919 |
|
2920 // The first and last characters should be ", and no others. |
|
2921 $this->assertTrue($json[0] == '"', 'A JSON encoded string begins with ".'); |
|
2922 $this->assertTrue($json[strlen($json) - 1] == '"', 'A JSON encoded string ends with ".'); |
|
2923 $this->assertTrue(substr_count($json, '"') == 2, 'A JSON encoded string contains exactly two ".'); |
|
2924 |
|
2925 // Verify that encoding/decoding is reversible. |
|
2926 $json_decoded = drupal_json_decode($json); |
|
2927 $this->assertIdentical($str, $json_decoded, 'Encoding a string to JSON and decoding back results in the original string.'); |
|
2928 |
|
2929 // Verify reversibility for structured data. Also verify that necessary |
|
2930 // characters are escaped. |
|
2931 $source = array(TRUE, FALSE, 0, 1, '0', '1', $str, array('key1' => $str, 'key2' => array('nested' => TRUE))); |
|
2932 $json = drupal_json_encode($source); |
|
2933 foreach ($html_unsafe as $char) { |
|
2934 $this->assertTrue(strpos($json, $char) === FALSE, format_string('A JSON encoded string does not contain @s.', array('@s' => $char))); |
|
2935 } |
|
2936 // Verify that JSON encoding escapes the HTML unsafe characters |
|
2937 foreach ($html_unsafe_escaped as $char) { |
|
2938 $this->assertTrue(strpos($json, $char) > 0, format_string('A JSON encoded string contains @s.', array('@s' => $char))); |
|
2939 } |
|
2940 $json_decoded = drupal_json_decode($json); |
|
2941 $this->assertNotIdentical($source, $json, 'An array encoded in JSON is not identical to the source.'); |
|
2942 $this->assertIdentical($source, $json_decoded, 'Encoding structured data to JSON and decoding back results in the original data.'); |
|
2943 } |
|
2944 } |
|
2945 |
|
2946 /** |
|
2947 * Tests for RDF namespaces XML serialization. |
|
2948 */ |
|
2949 class DrupalGetRdfNamespacesTestCase extends DrupalWebTestCase { |
|
2950 public static function getInfo() { |
|
2951 return array( |
|
2952 'name' => 'RDF namespaces XML serialization tests', |
|
2953 'description' => 'Confirm that the serialization of RDF namespaces via drupal_get_rdf_namespaces() is output and parsed correctly in the XHTML document.', |
|
2954 'group' => 'System', |
|
2955 ); |
|
2956 } |
|
2957 |
|
2958 function setUp() { |
|
2959 parent::setUp('rdf', 'rdf_test'); |
|
2960 } |
|
2961 |
|
2962 /** |
|
2963 * Test RDF namespaces. |
|
2964 */ |
|
2965 function testGetRdfNamespaces() { |
|
2966 // Fetches the front page and extracts XML namespaces. |
|
2967 $this->drupalGet(''); |
|
2968 $xml = new SimpleXMLElement($this->content); |
|
2969 $ns = $xml->getDocNamespaces(); |
|
2970 |
|
2971 $this->assertEqual($ns['rdfs'], 'http://www.w3.org/2000/01/rdf-schema#', 'A prefix declared once is displayed.'); |
|
2972 $this->assertEqual($ns['foaf'], 'http://xmlns.com/foaf/0.1/', 'The same prefix declared in several implementations of hook_rdf_namespaces() is valid as long as all the namespaces are the same.'); |
|
2973 $this->assertEqual($ns['foaf1'], 'http://xmlns.com/foaf/0.1/', 'Two prefixes can be assigned the same namespace.'); |
|
2974 $this->assertTrue(!isset($ns['dc']), 'A prefix with conflicting namespaces is discarded.'); |
|
2975 } |
|
2976 } |
|
2977 |
|
2978 /** |
|
2979 * Basic tests for drupal_add_feed(). |
|
2980 */ |
|
2981 class DrupalAddFeedTestCase extends DrupalWebTestCase { |
|
2982 public static function getInfo() { |
|
2983 return array( |
|
2984 'name' => 'drupal_add_feed() tests', |
|
2985 'description' => 'Make sure that drupal_add_feed() works correctly with various constructs.', |
|
2986 'group' => 'System', |
|
2987 ); |
|
2988 } |
|
2989 |
|
2990 /** |
|
2991 * Test drupal_add_feed() with paths, URLs, and titles. |
|
2992 */ |
|
2993 function testBasicFeedAddNoTitle() { |
|
2994 $path = $this->randomName(12); |
|
2995 $external_url = 'http://' . $this->randomName(12) . '/' . $this->randomName(12); |
|
2996 $fully_qualified_local_url = url($this->randomName(12), array('absolute' => TRUE)); |
|
2997 |
|
2998 $path_for_title = $this->randomName(12); |
|
2999 $external_for_title = 'http://' . $this->randomName(12) . '/' . $this->randomName(12); |
|
3000 $fully_qualified_for_title = url($this->randomName(12), array('absolute' => TRUE)); |
|
3001 |
|
3002 // Possible permutations of drupal_add_feed() to test. |
|
3003 // - 'input_url': the path passed to drupal_add_feed(), |
|
3004 // - 'output_url': the expected URL to be found in the header. |
|
3005 // - 'title' == the title of the feed as passed into drupal_add_feed(). |
|
3006 $urls = array( |
|
3007 'path without title' => array( |
|
3008 'input_url' => $path, |
|
3009 'output_url' => url($path, array('absolute' => TRUE)), |
|
3010 'title' => '', |
|
3011 ), |
|
3012 'external URL without title' => array( |
|
3013 'input_url' => $external_url, |
|
3014 'output_url' => $external_url, |
|
3015 'title' => '', |
|
3016 ), |
|
3017 'local URL without title' => array( |
|
3018 'input_url' => $fully_qualified_local_url, |
|
3019 'output_url' => $fully_qualified_local_url, |
|
3020 'title' => '', |
|
3021 ), |
|
3022 'path with title' => array( |
|
3023 'input_url' => $path_for_title, |
|
3024 'output_url' => url($path_for_title, array('absolute' => TRUE)), |
|
3025 'title' => $this->randomName(12), |
|
3026 ), |
|
3027 'external URL with title' => array( |
|
3028 'input_url' => $external_for_title, |
|
3029 'output_url' => $external_for_title, |
|
3030 'title' => $this->randomName(12), |
|
3031 ), |
|
3032 'local URL with title' => array( |
|
3033 'input_url' => $fully_qualified_for_title, |
|
3034 'output_url' => $fully_qualified_for_title, |
|
3035 'title' => $this->randomName(12), |
|
3036 ), |
|
3037 ); |
|
3038 |
|
3039 foreach ($urls as $description => $feed_info) { |
|
3040 drupal_add_feed($feed_info['input_url'], $feed_info['title']); |
|
3041 } |
|
3042 |
|
3043 $this->drupalSetContent(drupal_get_html_head()); |
|
3044 foreach ($urls as $description => $feed_info) { |
|
3045 $this->assertPattern($this->urlToRSSLinkPattern($feed_info['output_url'], $feed_info['title']), format_string('Found correct feed header for %description', array('%description' => $description))); |
|
3046 } |
|
3047 } |
|
3048 |
|
3049 /** |
|
3050 * Create a pattern representing the RSS feed in the page. |
|
3051 */ |
|
3052 function urlToRSSLinkPattern($url, $title = '') { |
|
3053 // Escape any regular expression characters in the URL ('?' is the worst). |
|
3054 $url = preg_replace('/([+?.*])/', '[$0]', $url); |
|
3055 $generated_pattern = '%<link +rel="alternate" +type="application/rss.xml" +title="' . $title . '" +href="' . $url . '" */>%'; |
|
3056 return $generated_pattern; |
|
3057 } |
|
3058 } |
|
3059 |
|
3060 /** |
|
3061 * Test for theme_feed_icon(). |
|
3062 */ |
|
3063 class FeedIconTest extends DrupalWebTestCase { |
|
3064 |
|
3065 public static function getInfo() { |
|
3066 return array( |
|
3067 'name' => 'Feed icon', |
|
3068 'description' => 'Check escaping of theme_feed_icon()', |
|
3069 'group' => 'System', |
|
3070 ); |
|
3071 } |
|
3072 |
|
3073 /** |
|
3074 * Check that special characters are correctly escaped. Test for issue #1211668. |
|
3075 */ |
|
3076 function testFeedIconEscaping() { |
|
3077 $variables = array(); |
|
3078 $variables['url'] = 'node'; |
|
3079 $variables['title'] = '<>&"\''; |
|
3080 $text = theme_feed_icon($variables); |
|
3081 preg_match('/title="(.*?)"/', $text, $matches); |
|
3082 $this->assertEqual($matches[1], 'Subscribe to &"'', 'theme_feed_icon() escapes reserved HTML characters.'); |
|
3083 } |
|
3084 |
|
3085 } |
|
3086 |
|
3087 /** |
|
3088 * Test array diff functions. |
|
3089 */ |
|
3090 class ArrayDiffUnitTest extends DrupalUnitTestCase { |
|
3091 |
|
3092 /** |
|
3093 * Array to use for testing. |
|
3094 * |
|
3095 * @var array |
|
3096 */ |
|
3097 protected $array1; |
|
3098 |
|
3099 /** |
|
3100 * Array to use for testing. |
|
3101 * |
|
3102 * @var array |
|
3103 */ |
|
3104 protected $array2; |
|
3105 |
|
3106 public static function getInfo() { |
|
3107 return array( |
|
3108 'name' => 'Array differences', |
|
3109 'description' => 'Performs tests on drupal_array_diff_assoc_recursive().', |
|
3110 'group' => 'System', |
|
3111 ); |
|
3112 } |
|
3113 |
|
3114 function setUp() { |
|
3115 parent::setUp(); |
|
3116 |
|
3117 $this->array1 = array( |
|
3118 'same' => 'yes', |
|
3119 'different' => 'no', |
|
3120 'array_empty_diff' => array(), |
|
3121 'null' => NULL, |
|
3122 'int_diff' => 1, |
|
3123 'array_diff' => array('same' => 'same', 'array' => array('same' => 'same')), |
|
3124 'array_compared_to_string' => array('value'), |
|
3125 'string_compared_to_array' => 'value', |
|
3126 'new' => 'new', |
|
3127 ); |
|
3128 $this->array2 = array( |
|
3129 'same' => 'yes', |
|
3130 'different' => 'yes', |
|
3131 'array_empty_diff' => array(), |
|
3132 'null' => NULL, |
|
3133 'int_diff' => '1', |
|
3134 'array_diff' => array('same' => 'different', 'array' => array('same' => 'same')), |
|
3135 'array_compared_to_string' => 'value', |
|
3136 'string_compared_to_array' => array('value'), |
|
3137 ); |
|
3138 } |
|
3139 |
|
3140 |
|
3141 /** |
|
3142 * Tests drupal_array_diff_assoc_recursive(). |
|
3143 */ |
|
3144 public function testArrayDiffAssocRecursive() { |
|
3145 $expected = array( |
|
3146 'different' => 'no', |
|
3147 'int_diff' => 1, |
|
3148 // The 'array' key should not be returned, as it's the same. |
|
3149 'array_diff' => array('same' => 'same'), |
|
3150 'array_compared_to_string' => array('value'), |
|
3151 'string_compared_to_array' => 'value', |
|
3152 'new' => 'new', |
|
3153 ); |
|
3154 |
|
3155 $this->assertIdentical(drupal_array_diff_assoc_recursive($this->array1, $this->array2), $expected); |
|
3156 } |
|
3157 } |
|
3158 |
|
3159 /** |
|
3160 * Tests the functionality of drupal_get_query_array(). |
|
3161 */ |
|
3162 class DrupalGetQueryArrayTestCase extends DrupalWebTestCase { |
|
3163 |
|
3164 public static function getInfo() { |
|
3165 return array( |
|
3166 'name' => 'Query parsing using drupal_get_query_array()', |
|
3167 'description' => 'Tests that drupal_get_query_array() correctly parses query parameters.', |
|
3168 'group' => 'System', |
|
3169 ); |
|
3170 } |
|
3171 |
|
3172 /** |
|
3173 * Tests that drupal_get_query_array() correctly explodes query parameters. |
|
3174 */ |
|
3175 public function testDrupalGetQueryArray() { |
|
3176 $url = "http://my.site.com/somepath?foo=/content/folder[@name='foo']/folder[@name='bar']"; |
|
3177 $parsed = parse_url($url); |
|
3178 $result = drupal_get_query_array($parsed['query']); |
|
3179 $this->assertEqual($result['foo'], "/content/folder[@name='foo']/folder[@name='bar']", 'drupal_get_query_array() should only explode parameters on the first equals sign.'); |
|
3180 } |
|
3181 |
|
3182 } |