Merge pull request #1 from civicrm/master
[civicrm-core.git] / tests / phpunit / CRM / Core / ResourcesTest.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
2fe49090 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035 27
6a488035
TO
28/**
29 * Tests for linking to resource files
acb109b7 30 * @group headless
6a488035
TO
31 */
32class CRM_Core_ResourcesTest extends CiviUnitTestCase {
6a488035
TO
33
34 /**
35 * @var CRM_Core_Resources
36 */
37 protected $res;
38
39 /**
40 * @var CRM_Extension_Mapper
41 */
42 protected $mapper;
43
6f12c6eb 44 /**
45 * @var string for testing cache buster generation
46 */
47 protected $cacheBusterString = 'xBkdk3';
48
42a40a1c 49 protected $originalRequest;
50 protected $originalGet;
51
00be9182 52 public function setUp() {
6a488035
TO
53 parent::setUp();
54
55 list ($this->basedir, $this->container, $this->mapper) = $this->_createMapper();
56 $cache = new CRM_Utils_Cache_Arraycache(array());
57 $this->res = new CRM_Core_Resources($this->mapper, $cache, NULL);
58 $this->res->setCacheCode('resTest');
59 CRM_Core_Resources::singleton($this->res);
60
61 // Templates injected into regions should normally be file names, but for unit-testing it's handy to use "string:" notation
62 require_once 'CRM/Core/Smarty/resources/String.php';
481a74f4 63 civicrm_smarty_register_string_resource();
42a40a1c 64
65 $this->originalRequest = $_REQUEST;
66 $this->originalGet = $_GET;
67 }
68
69 /**
70 * Restore globals so this test doesn't interfere with others.
71 */
72 public function tearDown() {
73 $_REQUEST = $this->originalRequest;
74 $_GET = $this->originalGet;
6a488035
TO
75 }
76
00be9182 77 public function testAddScriptFile() {
6a488035
TO
78 $this->res
79 ->addScriptFile('com.example.ext', 'foo%20bar.js', 0, 'testAddScriptFile')
39b959db
SL
80 // extra
81 ->addScriptFile('com.example.ext', 'foo%20bar.js', 0, 'testAddScriptFile')
6c6e6187 82 ->addScriptFile('civicrm', 'foo%20bar.js', 0, 'testAddScriptFile');
6a488035
TO
83
84 $smarty = CRM_Core_Smarty::singleton();
85 $actual = $smarty->fetch('string:{crmRegion name=testAddScriptFile}{/crmRegion}');
39b959db
SL
86 // stable ordering: alphabetical by (snippet.weight,snippet.name)
87 $expected = ""
6a488035 88 . "<script type=\"text/javascript\" src=\"http://core-app/foo%20bar.js?r=resTest\">\n</script>\n"
6c6e6187 89 . "<script type=\"text/javascript\" src=\"http://ext-dir/com.example.ext/foo%20bar.js?r=resTest\">\n</script>\n";
6a488035
TO
90 $this->assertEquals($expected, $actual);
91 }
92
93 /**
94 * When adding a script file, any ts() expressions should be translated and added to the 'strings'
95 *
96 * FIXME: This can't work because the tests run in English and CRM_Core_Resources optimizes
97 * away the English data from $settings['strings']
92915c55
TO
98 * public function testAddScriptFile_strings() {
99 * file_put_contents($this->mapper->keyToBasePath('com.example.ext') . '/hello.js', 'alert(ts("Hello world"));');
100 * $this->res->addScriptFile('com.example.ext', 'hello.js', 0, 'testAddScriptFile_strings');
101 * $settings = $this->res->getSettings();
102 * $expected = array('Hello world');
103 * $this->assertEquals($expected, $settings['strings']);
104 * }
6c6e6187 105 */
6a488035 106
a1a2a83d
TO
107 /**
108 * Ensure that adding a script URL creates expected markup.
109 */
00be9182 110 public function testAddScriptURL() {
6a488035
TO
111 $this->res
112 ->addScriptUrl('/whiz/foo%20bar.js', 0, 'testAddScriptURL')
39b959db
SL
113 // extra
114 ->addScriptUrl('/whiz/foo%20bar.js', 0, 'testAddScriptURL')
6c6e6187 115 ->addScriptUrl('/whizbang/foo%20bar.js', 0, 'testAddScriptURL');
6a488035
TO
116
117 $smarty = CRM_Core_Smarty::singleton();
118 $actual = $smarty->fetch('string:{crmRegion name=testAddScriptURL}{/crmRegion}');
39b959db
SL
119 // stable ordering: alphabetical by (snippet.weight,snippet.name)
120 $expected = ""
6a488035 121 . "<script type=\"text/javascript\" src=\"/whiz/foo%20bar.js\">\n</script>\n"
6c6e6187 122 . "<script type=\"text/javascript\" src=\"/whizbang/foo%20bar.js\">\n</script>\n";
6a488035
TO
123 $this->assertEquals($expected, $actual);
124 }
125
00be9182 126 public function testAddScript() {
6a488035
TO
127 $this->res
128 ->addScript('alert("hi");', 0, 'testAddScript')
6c6e6187 129 ->addScript('alert("there");', 0, 'testAddScript');
6a488035
TO
130
131 $smarty = CRM_Core_Smarty::singleton();
132 $actual = $smarty->fetch('string:{crmRegion name=testAddScript}{/crmRegion}');
133 $expected = ""
134 . "<script type=\"text/javascript\">\nalert(\"hi\");\n</script>\n"
6c6e6187 135 . "<script type=\"text/javascript\">\nalert(\"there\");\n</script>\n";
6a488035
TO
136 $this->assertEquals($expected, $actual);
137 }
138
00be9182 139 public function testAddVars() {
73bcd446
CW
140 $this->res
141 ->addVars('food', array('fruit' => array('mine' => 'apple', 'ours' => 'banana')))
6c6e6187 142 ->addVars('food', array('fruit' => array('mine' => 'new apple', 'yours' => 'orange')));
73bcd446 143 $this->assertTreeEquals(
92915c55
TO
144 array(
145 'vars' => array(
146 'food' => array(
147 'fruit' => array(
148 'yours' => 'orange',
149 'mine' => 'new apple',
af9b09df
TO
150 'ours' => 'banana',
151 ),
152 ),
153 ),
92915c55 154 ),
73bcd446
CW
155 $this->res->getSettings()
156 );
157 }
158
00be9182 159 public function testAddSetting() {
6a488035
TO
160 $this->res
161 ->addSetting(array('fruit' => array('mine' => 'apple')))
6c6e6187 162 ->addSetting(array('fruit' => array('yours' => 'orange')));
6a488035
TO
163 $this->assertTreeEquals(
164 array('fruit' => array('yours' => 'orange', 'mine' => 'apple')),
165 $this->res->getSettings()
166 );
167 $actual = $this->res->renderSetting();
6521a306
CW
168 $expected = json_encode(array('fruit' => array('yours' => 'orange', 'mine' => 'apple')));
169 $this->assertTrue(strpos($actual, $expected) !== FALSE);
6a488035
TO
170 }
171
898951c6
TO
172 public function testAddSettingHook() {
173 $test = $this;
174 Civi::dispatcher()->addListener('hook_civicrm_alterResourceSettings', function($event) use ($test) {
175 $test->assertEquals('apple', $event->data['fruit']['mine']);
176 $event->data['fruit']['mine'] = 'banana';
177 });
178 $this->res->addSetting(array('fruit' => array('mine' => 'apple')));
179 $settings = $this->res->getSettings();
180 $this->assertTreeEquals(array('fruit' => array('mine' => 'banana')), $settings);
181 }
182
00be9182 183 public function testAddSettingFactory() {
92915c55 184 $this->res->addSettingsFactory(function () {
6a488035
TO
185 return array('fruit' => array('yours' => 'orange'));
186 });
92915c55 187 $this->res->addSettingsFactory(function () {
6a488035
TO
188 return array('fruit' => array('mine' => 'apple'));
189 });
190
191 $actual = $this->res->getSettings();
192 $expected = array('fruit' => array('yours' => 'orange', 'mine' => 'apple'));
193 $this->assertTreeEquals($expected, $actual);
194 }
195
00be9182 196 public function testAddSettingAndSettingFactory() {
6a488035
TO
197 $this->res->addSetting(array('fruit' => array('mine' => 'apple')));
198
199 $muckableValue = array('fruit' => array('yours' => 'orange', 'theirs' => 'apricot'));
92915c55 200 $this->res->addSettingsFactory(function () use (&$muckableValue) {
6a488035
TO
201 return $muckableValue;
202 });
203 $actual = $this->res->getSettings();
204 $expected = array('fruit' => array('mine' => 'apple', 'yours' => 'orange', 'theirs' => 'apricot'));
205 $this->assertTreeEquals($expected, $actual);
206
207 // note: the setting is not fixed based on what the factory returns when registered; it's based
208 // on what the factory returns when getSettings is called
209 $muckableValue = array('fruit' => array('yours' => 'banana'));
210 $actual = $this->res->getSettings();
211 $expected = array('fruit' => array('mine' => 'apple', 'yours' => 'banana'));
212 $this->assertTreeEquals($expected, $actual);
213 }
214
00be9182 215 public function testCrmJS() {
6a488035
TO
216 $smarty = CRM_Core_Smarty::singleton();
217
218 $actual = $smarty->fetch('string:{crmScript ext=com.example.ext file=foo%20bar.js region=testCrmJS}');
219 $this->assertEquals('', $actual);
220
221 $actual = $smarty->fetch('string:{crmScript url=/whiz/foo%20bar.js region=testCrmJS weight=1}');
222 $this->assertEquals('', $actual);
223
224 $actual = $smarty->fetch('string:{crmRegion name=testCrmJS}{/crmRegion}');
39b959db
SL
225 // stable ordering: alphabetical by (snippet.weight,snippet.name)
226 $expected = ""
6a488035 227 . "<script type=\"text/javascript\" src=\"http://ext-dir/com.example.ext/foo%20bar.js?r=resTest\">\n</script>\n"
6c6e6187 228 . "<script type=\"text/javascript\" src=\"/whiz/foo%20bar.js\">\n</script>\n";
6a488035
TO
229 $this->assertEquals($expected, $actual);
230 }
231
00be9182 232 public function testAddStyleFile() {
6a488035
TO
233 $this->res
234 ->addStyleFile('com.example.ext', 'foo%20bar.css', 0, 'testAddStyleFile')
39b959db
SL
235 // extra
236 ->addStyleFile('com.example.ext', 'foo%20bar.css', 0, 'testAddStyleFile')
6c6e6187 237 ->addStyleFile('civicrm', 'foo%20bar.css', 0, 'testAddStyleFile');
6a488035
TO
238
239 $smarty = CRM_Core_Smarty::singleton();
240 $actual = $smarty->fetch('string:{crmRegion name=testAddStyleFile}{/crmRegion}');
39b959db
SL
241 // stable ordering: alphabetical by (snippet.weight,snippet.name)
242 $expected = ""
6a488035 243 . "<link href=\"http://core-app/foo%20bar.css?r=resTest\" rel=\"stylesheet\" type=\"text/css\"/>\n"
6c6e6187 244 . "<link href=\"http://ext-dir/com.example.ext/foo%20bar.css?r=resTest\" rel=\"stylesheet\" type=\"text/css\"/>\n";
6a488035
TO
245 $this->assertEquals($expected, $actual);
246 }
247
00be9182 248 public function testAddStyleURL() {
6a488035
TO
249 $this->res
250 ->addStyleUrl('/whiz/foo%20bar.css', 0, 'testAddStyleURL')
39b959db
SL
251 // extra
252 ->addStyleUrl('/whiz/foo%20bar.css', 0, 'testAddStyleURL')
6c6e6187 253 ->addStyleUrl('/whizbang/foo%20bar.css', 0, 'testAddStyleURL');
6a488035
TO
254
255 $smarty = CRM_Core_Smarty::singleton();
256 $actual = $smarty->fetch('string:{crmRegion name=testAddStyleURL}{/crmRegion}');
39b959db
SL
257 // stable ordering: alphabetical by (snippet.weight,snippet.name)
258 $expected = ""
6a488035 259 . "<link href=\"/whiz/foo%20bar.css\" rel=\"stylesheet\" type=\"text/css\"/>\n"
6c6e6187 260 . "<link href=\"/whizbang/foo%20bar.css\" rel=\"stylesheet\" type=\"text/css\"/>\n";
6a488035
TO
261 $this->assertEquals($expected, $actual);
262 }
263
00be9182 264 public function testAddStyle() {
6a488035
TO
265 $this->res
266 ->addStyle('body { background: black; }', 0, 'testAddStyle')
6c6e6187 267 ->addStyle('body { text-color: black; }', 0, 'testAddStyle');
6a488035
TO
268
269 $smarty = CRM_Core_Smarty::singleton();
270 $actual = $smarty->fetch('string:{crmRegion name=testAddStyle}{/crmRegion}');
271 $expected = ""
272 . "<style type=\"text/css\">\nbody { background: black; }\n</style>\n"
6c6e6187 273 . "<style type=\"text/css\">\nbody { text-color: black; }\n</style>\n";
6a488035
TO
274 $this->assertEquals($expected, $actual);
275 }
276
00be9182 277 public function testCrmCSS() {
6a488035
TO
278 $smarty = CRM_Core_Smarty::singleton();
279
280 $actual = $smarty->fetch('string:{crmStyle ext=com.example.ext file=foo%20bar.css region=testCrmCSS}');
281 $this->assertEquals('', $actual);
282
283 $actual = $smarty->fetch('string:{crmStyle url=/whiz/foo%20bar.css region=testCrmCSS weight=1}');
284 $this->assertEquals('', $actual);
285
286 $actual = $smarty->fetch('string:{crmRegion name=testCrmCSS}{/crmRegion}');
39b959db
SL
287 // stable ordering: alphabetical by (snippet.weight,snippet.name)
288 $expected = ""
6a488035 289 . "<link href=\"http://ext-dir/com.example.ext/foo%20bar.css?r=resTest\" rel=\"stylesheet\" type=\"text/css\"/>\n"
6c6e6187 290 . "<link href=\"/whiz/foo%20bar.css\" rel=\"stylesheet\" type=\"text/css\"/>\n";
6a488035
TO
291 $this->assertEquals($expected, $actual);
292 }
293
00be9182 294 public function testGetURL() {
6a488035
TO
295 $this->assertEquals(
296 'http://core-app/dir/file%20name.txt',
297 $this->res->getURL('civicrm', 'dir/file%20name.txt')
298 );
299 $this->assertEquals(
300 'http://ext-dir/com.example.ext/dir/file%20name.txt',
301 $this->res->getURL('com.example.ext', 'dir/file%20name.txt')
302 );
303 $this->assertEquals(
304 'http://core-app/',
305 $this->res->getURL('civicrm')
306 );
307 $this->assertEquals(
308 'http://ext-dir/com.example.ext/',
309 $this->res->getURL('com.example.ext')
310 );
311 }
312
00be9182 313 public function testCrmResURL() {
6a488035
TO
314 $smarty = CRM_Core_Smarty::singleton();
315
316 $actual = $smarty->fetch('string:{crmResURL ext=com.example.ext file=foo%20bar.png}');
317 $this->assertEquals('http://ext-dir/com.example.ext/foo%20bar.png', $actual);
318
319 $actual = $smarty->fetch('string:{crmResURL ext=com.example.ext file=foo%20bar.png addCacheCode=1}');
320 $this->assertEquals('http://ext-dir/com.example.ext/foo%20bar.png?r=resTest', $actual);
321
322 $actual = $smarty->fetch('string:{crmResURL ext=com.example.ext}');
323 $this->assertEquals('http://ext-dir/com.example.ext/', $actual);
324 }
325
16cd1eca
TO
326 public function testGlob() {
327 $this->assertEquals(
328 array('info.xml'),
329 $this->res->glob('com.example.ext', 'info.xml')
330 );
331 $this->assertEquals(
332 array('js/example.js'),
333 $this->res->glob('com.example.ext', 'js/*.js')
334 );
335 $this->assertEquals(
336 array('js/example.js'),
337 $this->res->glob('com.example.ext', array('js/*.js'))
338 );
339 }
340
42a40a1c 341 /**
342 * @dataProvider ajaxModeData
343 */
344 public function testIsAjaxMode($query, $result) {
345 $_REQUEST = $_GET = $query;
346 $this->assertEquals($result, CRM_Core_Resources::isAjaxMode());
347 }
348
349 public function ajaxModeData() {
350 return array(
351 array(array('q' => 'civicrm/ajax/foo'), TRUE),
e83561bf 352 array(array('q' => 'civicrm/angularprofiles/template'), TRUE),
60c3b6e9 353 array(array('q' => 'civicrm/asset/builder'), TRUE),
42a40a1c 354 array(array('q' => 'civicrm/test/page'), FALSE),
355 array(array('q' => 'civicrm/test/page', 'snippet' => 'json'), TRUE),
356 array(array('q' => 'civicrm/test/page', 'snippet' => 'foo'), FALSE),
357 );
358 }
359
6a488035
TO
360 /**
361 * @param CRM_Utils_Cache_Interface $cache
72b3a70c 362 * @param string $cacheKey
2a6da8d7 363 *
72b3a70c
CW
364 * @return array
365 * [string $basedir, CRM_Extension_Container_Interface, CRM_Extension_Mapper]
6a488035 366 */
00be9182 367 public function _createMapper(CRM_Utils_Cache_Interface $cache = NULL, $cacheKey = NULL) {
6a488035
TO
368 $basedir = rtrim($this->createTempDir('ext-'), '/');
369 mkdir("$basedir/com.example.ext");
16cd1eca 370 mkdir("$basedir/com.example.ext/js");
6a488035 371 file_put_contents("$basedir/com.example.ext/info.xml", "<extension key='com.example.ext' type='report'><file>oddball</file></extension>");
16cd1eca 372 file_put_contents("$basedir/com.example.ext/js/example.js", "alert('Boo!');");
6a488035
TO
373 // not needed for now // file_put_contents("$basedir/weird/bar/oddball.php", "<?php\n");
374 $c = new CRM_Extension_Container_Basic($basedir, 'http://ext-dir', $cache, $cacheKey);
375 $mapper = new CRM_Extension_Mapper($c, NULL, NULL, '/pathto/civicrm', 'http://core-app');
376 return array($basedir, $c, $mapper);
377 }
378
6f12c6eb 379 /**
380 * @param string $url
381 * @param string $expected
382 *
383 * @dataProvider urlForCacheCodeProvider
384 */
385 public function testAddingCacheCode($url, $expected) {
386 $resources = CRM_Core_Resources::singleton();
595caa48 387 $resources->setCacheCode($this->cacheBusterString);
6f12c6eb 388 $this->assertEquals($expected, $resources->addCacheCode($url));
389 }
390
391 /**
392 * @return array
393 */
394 public function urlForCacheCodeProvider() {
395 return array(
396 array(
397 'http://www.civicrm.org',
398 'http://www.civicrm.org?r=' . $this->cacheBusterString,
399 ),
400 array(
401 'www.civicrm.org/custom.css?foo=bar',
402 'www.civicrm.org/custom.css?foo=bar&r=' . $this->cacheBusterString,
403 ),
6f12c6eb 404 array(
405 'civicrm.org/custom.css?car=blue&foo=bar',
406 'civicrm.org/custom.css?car=blue&foo=bar&r=' . $this->cacheBusterString,
407 ),
408 );
409 }
410
adcd4bf7
CW
411 /**
412 * return array
413 */
414 public function urlsToCheckIfFullyFormed() {
415 return [
416 ['civicrm/test/page', FALSE],
417 ['#', FALSE],
418 ['', FALSE],
419 ['/civicrm/test/page', TRUE],
420 ['http://test.com/civicrm/test/page', TRUE],
421 ['https://test.com/civicrm/test/page', TRUE],
422 ];
423 }
424
425 /**
426 * @param string $url
427 * @param string $expected
428 *
429 * @dataProvider urlsToCheckIfFullyFormed
430 */
431 public function testIsFullyFormedUrl($url, $expected) {
432 $this->assertEquals($expected, CRM_Core_Resources::isFullyFormedUrl($url));
433 }
434
6a488035 435}