API CHANGE Refactored Requirements to use Requirements_Backend at all times - this makes testing far easier. Thanks tobych!

MINOR Updated RequirementsTest to test Requirements_Backend instead of global statics


git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/branches/2.4@100513 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Sean Harvey 2010-03-04 21:25:18 +00:00 committed by Sam Minnee
parent 81fd7f09d1
commit 450c3cb408
2 changed files with 147 additions and 133 deletions

View File

@ -10,27 +10,19 @@ class Requirements {
/**
* Enable combining of css/javascript files.
*
* @var boolean
* @param boolean $enable
*/
private static $combined_files_enabled = true;
public static function set_combined_files_enabled($enable) {
self::$combined_files_enabled = (bool) $enable;
}
public static function get_combined_files_enabled() {
return self::$combined_files_enabled;
self::backend()->set_combined_files_enabled($enable);
}
/**
* Do we want requirements to suffix onto the requirement link
* tags for caching or is it disabled. Getter / Setter available
* through {@link Requirements::set_suffix_requirements()}
*
* @var bool
* Checks whether combining of css/javascript files is enabled.
* @return boolean
*/
private static $suffix_requirements = true;
public static function get_combined_files_enabled() {
return self::backend()->get_combined_files_enabled();
}
/**
* Set whether we want to suffix requirements with the time /
@ -39,7 +31,7 @@ class Requirements {
* @param bool
*/
public static function set_suffix_requirements($var) {
self::$suffix_requirements = $var;
self::backend()->set_suffix_requirements($var);
}
/**
@ -48,7 +40,7 @@ class Requirements {
* @return bool
*/
public static function get_suffix_requirements() {
return self::$suffix_requirements;
return self::backend()->get_suffix_requirements();
}
/**
@ -57,10 +49,10 @@ class Requirements {
* @var Requirements
*/
private static $backend = null;
public static function backend() {
if(!self::$backend) {
self::$backend = new Requirements_Backend();
}
return self::$backend;
}
@ -73,7 +65,6 @@ class Requirements {
public static function set_backend(Requirements_Backend $backend) {
self::$backend = $backend;
}
/**
* Register the given javascript file as required.
@ -85,7 +76,6 @@ class Requirements {
self::backend()->javascript($file);
}
/**
* Add the javascript code to the header of the page
*
@ -119,8 +109,6 @@ class Requirements {
static function insertHeadTags($html, $uniquenessID = null) {
self::backend()->insertHeadTags($html, $uniquenessID);
}
/**
* Load the given javascript template with the page.
@ -195,7 +183,6 @@ class Requirements {
self::backend()->unblock_all();
}
/**
* Restore requirements cleared by call to Requirements::clear
* See {@link Requirements_Backend::restore()}
@ -305,16 +292,33 @@ class Requirements {
}
class Requirements_Backend {
/**
/**
* Do we want requirements to suffix onto the requirement link
* tags for caching or is it disabled. Getter / Setter available
* through {@link Requirements::set_suffix_requirements()}
*
* @var bool
*/
protected $suffix_requirements = true;
/**
* Enable combining of css/javascript files.
*
* @var boolean
*/
protected $combined_files_enabled = true;
/**
* Paths to all required .js files relative to the webroot.
*
*
* @var array $javascript
*/
protected $javascript = array();
/**
* Paths to all required .css files relative to the webroot.
*
*
* @var array $css
*/
protected $css = array();
@ -329,7 +333,7 @@ class Requirements_Backend {
/**
* All custom CSS rules which are inserted
* directly at the bottom of the HTML <head> tag.
* directly at the bottom of the HTML <head> tag.
*
* @var array $customCSS
*/
@ -338,7 +342,7 @@ class Requirements_Backend {
/**
* All custom HTML markup which is added before
* the closing <head> tag, e.g. additional metatags.
* This is preferred to entering tags directly into
* This is preferred to entering tags directly into
*/
protected $customHeadTags = array();
@ -349,7 +353,7 @@ class Requirements_Backend {
* @var array $disabled
*/
protected $disabled = array();
/**
* The filepaths (relative to webroot) or
* uniquenessIDs of any included requirements
@ -357,18 +361,18 @@ class Requirements_Backend {
* This is useful to e.g. prevent core classes to modifying
* Requirements without subclassing the entire functionality.
* Use {@link unblock()} or {@link unblock_all()} to revert changes.
*
*
* @var array $blocked
*/
protected $blocked = array();
/**
* See {@link combine_files()}.
*
*
* @var array $combine_files
*/
public $combine_files = array();
/**
* Using the JSMin library to minify any
* javascript file passed to {@link combine_files()}.
@ -376,7 +380,7 @@ class Requirements_Backend {
* @var boolean
*/
public $combine_js_with_jsmin = true;
/**
* Put all javascript includes at the bottom of the template
* before the closing <body> tag instead of the <head> tag.
@ -392,6 +396,33 @@ class Requirements_Backend {
*/
public $write_js_to_body = true;
function set_combined_files_enabled($enable) {
$this->combined_files_enabled = (bool) $enable;
}
function get_combined_files_enabled() {
return $this->combined_files_enabled;
}
/**
* Set whether we want to suffix requirements with the time /
* location on to the requirements
*
* @param bool
*/
function set_suffix_requirements($var) {
$this->suffix_requirements = $var;
}
/**
* Return whether we want to suffix requirements
*
* @return bool
*/
function get_suffix_requirements() {
return $this->suffix_requirements;
}
/**
* Set whether you want the files written to the head or the body. It
* writes to the body by default which can break some scripts
@ -580,7 +611,7 @@ class Requirements_Backend {
$this->process_combined_files();
foreach(array_diff_key($this->javascript,$this->blocked) as $file => $dummy) {
$path = self::path_for_file($file);
$path = $this->path_for_file($file);
if($path) {
$jsRequirements .= "<script type=\"text/javascript\" src=\"$path\"></script>\n";
}
@ -597,7 +628,7 @@ class Requirements_Backend {
}
foreach(array_diff_key($this->css,$this->blocked) as $file => $params) {
$path = self::path_for_file($file);
$path = $this->path_for_file($file);
if($path) {
$media = (isset($params['media']) && !empty($params['media'])) ? " media=\"{$params['media']}\"" : "";
$requirements .= "<link rel=\"stylesheet\" type=\"text/css\"{$media} href=\"$path\" />\n";
@ -692,7 +723,7 @@ class Requirements_Backend {
* @param string $fileOrUrl
* @return string|boolean
*/
protected static function path_for_file($fileOrUrl) {
protected function path_for_file($fileOrUrl) {
if(preg_match('/^http[s]?/', $fileOrUrl)) {
return $fileOrUrl;
} elseif(Director::fileExists($fileOrUrl)) {
@ -703,7 +734,7 @@ class Requirements_Backend {
$suffix = '&' . substr($fileOrUrl, strpos($fileOrUrl, '?')+1);
$fileOrUrl = substr($fileOrUrl, 0, strpos($fileOrUrl, '?'));
}
if(Requirements::get_suffix_requirements()) {
if($this->suffix_requirements) {
$mtimesuffix = "?m=" . filemtime(Director::baseFolder() . '/' . $fileOrUrl);
}
return "{$prefix}{$fileOrUrl}{$mtimesuffix}{$suffix}";
@ -771,7 +802,7 @@ class Requirements_Backend {
foreach($this->combine_files as $_combinedFileName => $_files) {
$duplicates = array_intersect($_files, $files);
if($duplicates) {
user_error("Requirements::combine_files(): Already included files " . implode(',', $duplicates) . " in combined file '{$_combinedFileName}'", E_USER_NOTICE);
user_error("Requirements_Backend::combine_files(): Already included files " . implode(',', $duplicates) . " in combined file '{$_combinedFileName}'", E_USER_NOTICE);
return false;
}
}
@ -817,7 +848,7 @@ class Requirements_Backend {
if(class_exists('SapphireTest',false)) $runningTest = SapphireTest::is_running_test();
else $runningTest = false;
if((Director::isDev() && !$runningTest) || !Requirements::get_combined_files_enabled()) {
if((Director::isDev() && !$runningTest) || !$this->combined_files_enabled) {
return;
}
@ -826,7 +857,7 @@ class Requirements_Backend {
foreach($this->combine_files as $combinedFile => $sourceItems) {
foreach($sourceItems as $sourceItem) {
if(isset($combinerCheck[$sourceItem]) && $combinerCheck[$sourceItem] != $combinedFile){
user_error("Requirements::process_combined_files - file '$sourceItem' appears in two combined files:" . " '{$combinerCheck[$sourceItem]}' and '$combinedFile'", E_USER_WARNING);
user_error("Requirements_Backend::process_combined_files - file '$sourceItem' appears in two combined files:" . " '{$combinerCheck[$sourceItem]}' and '$combinedFile'", E_USER_WARNING);
}
$combinerCheck[$sourceItem] = $combinedFile;
@ -942,7 +973,7 @@ class Requirements_Backend {
if($theme && isset($_CSS_MANIFEST[$name]) && isset($_CSS_MANIFEST[$name]['themes'])
&& isset($_CSS_MANIFEST[$name]['themes'][$theme]))
Requirements::css($_CSS_MANIFEST[$name]['themes'][$theme], $media);
$this->css($_CSS_MANIFEST[$name]['themes'][$theme], $media);
else if(isset($_CSS_MANIFEST[$name]) && isset($_CSS_MANIFEST[$name]['unthemed'])) $this->css($_CSS_MANIFEST[$name]['unthemed'], $media);
// Normal requirements fails quietly when there is no css - we should do the same

View File

@ -10,28 +10,16 @@ class RequirementsTest extends SapphireTest {
static $html_template = '<html><head></head><body></body></html>';
protected $orig = array();
function setUp() {
parent::setUp();
$this->orig['SetCombineFiles'] = Requirements::get_combined_files_enabled();
Requirements::set_combined_files_enabled(true);
}
function tearDown() {
parent::tearDown();
Requirements::set_combined_files_enabled($this->orig['SetCombineFiles']);
}
function testExternalUrls() {
Requirements::javascript('http://www.mydomain.com/test.js');
Requirements::javascript('https://www.mysecuredomain.com/test.js');
Requirements::css('http://www.mydomain.com/test.css');
Requirements::css('https://www.mysecuredomain.com/test.css');
$backend = new Requirements_Backend;
$backend->set_combined_files_enabled(true);
$backend->javascript('http://www.mydomain.com/test.js');
$backend->javascript('https://www.mysecuredomain.com/test.js');
$backend->css('http://www.mydomain.com/test.css');
$backend->css('https://www.mysecuredomain.com/test.css');
$html = Requirements::includeInHTML(false, self::$html_template);
$html = $backend->includeInHTML(false, self::$html_template);
$this->assertTrue(
(strpos($html, 'http://www.mydomain.com/test.js') !== false),
@ -50,13 +38,38 @@ class RequirementsTest extends SapphireTest {
'Load external secure CSS URL'
);
}
protected function setupCombinedRequirements($backend) {
$backend->clear();
// clearing all previously generated requirements (just in case)
$backend->clear_combined_files();
$backend->delete_combined_files('RequirementsTest_bc.js');
// require files normally (e.g. called from a FormField instance)
$backend->javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.js');
$backend->javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_b.js');
$backend->javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_c.js');
// require two of those files as combined includes
$backend->combine_files(
'RequirementsTest_bc.js',
array(
SAPPHIRE_DIR . '/tests/forms/RequirementsTest_b.js',
SAPPHIRE_DIR . '/tests/forms/RequirementsTest_c.js'
)
);
}
function testCombinedJavascript() {
$this->setupCombinedRequirements();
$backend = new Requirements_Backend;
$backend->set_combined_files_enabled(true);
$this->setupCombinedRequirements($backend);
$combinedFilePath = Director::baseFolder() . '/' . 'RequirementsTest_bc.js';
$html = Requirements::includeInHTML(false, self::$html_template);
$html = $backend->includeInHTML(false, self::$html_template);
/* COMBINED JAVASCRIPT FILE IS INCLUDED IN HTML HEADER */
$this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_bc\.js/', $html), 'combined javascript file is included in html header');
@ -75,40 +88,41 @@ class RequirementsTest extends SapphireTest {
/* NORMAL REQUIREMENTS ARE STILL INCLUDED */
$this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_a\.js/', $html), 'normal requirements are still included');
Requirements::delete_combined_files('RequirementsTest_bc.js');
$backend->delete_combined_files('RequirementsTest_bc.js');
}
function testBlockedCombinedJavascript() {
$backend = new Requirements_Backend;
$backend->set_combined_files_enabled(true);
$combinedFilePath = Director::baseFolder() . '/' . 'RequirementsTest_bc.js';
/* BLOCKED COMBINED FILES ARE NOT INCLUDED */
$this->setupCombinedRequirements();
Requirements::block('RequirementsTest_bc.js');
Requirements::delete_combined_files('RequirementsTest_bc.js');
$this->setupCombinedRequirements($backend);
$backend->block('RequirementsTest_bc.js');
$backend->delete_combined_files('RequirementsTest_bc.js');
clearstatcache(); // needed to get accurate file_exists() results
$html = Requirements::includeInHTML(false, self::$html_template);
$html = $backend->includeInHTML(false, self::$html_template);
$this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_bc\.js/', $html), 'blocked combined files are not included ');
Requirements::unblock('RequirementsTest_bc.js');
$backend->unblock('RequirementsTest_bc.js');
/* BLOCKED UNCOMBINED FILES ARE NOT INCLUDED */
// need to re-add requirements, as Requirements::process_combined_includes() alters the
// original arrays grml...
$this->setupCombinedRequirements();
Requirements::block('sapphire/tests/forms/RequirementsTest_b.js');
Requirements::delete_combined_files('RequirementsTest_bc.js');
$this->setupCombinedRequirements($backend);
$backend->block('sapphire/tests/forms/RequirementsTest_b.js');
$backend->delete_combined_files('RequirementsTest_bc.js');
clearstatcache(); // needed to get accurate file_exists() results
$html = Requirements::includeInHTML(false, self::$html_template);
$html = $backend->includeInHTML(false, self::$html_template);
$this->assertFalse((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false), 'blocked uncombined files are not included');
Requirements::unblock('RequirementsTest_b.js');
$backend->unblock('RequirementsTest_b.js');
/* A SINGLE FILE CAN'T BE INCLUDED IN TWO COMBINED FILES */
$this->setupCombinedRequirements();
$this->setupCombinedRequirements($backend);
clearstatcache(); // needed to get accurate file_exists() results
// This throws a notice-level error, so we prefix with @
@Requirements::combine_files(
@$backend->combine_files(
'RequirementsTest_ac.js',
array(
'sapphire/tests/forms/RequirementsTest_a.js',
@ -116,28 +130,25 @@ class RequirementsTest extends SapphireTest {
)
);
$combinedFiles = Requirements::get_combine_files();
$combinedFiles = $backend->get_combine_files();
$this->assertEquals(
array_keys($combinedFiles),
array('RequirementsTest_bc.js'),
"A single file can't be included in two combined files"
);
Requirements::delete_combined_files('RequirementsTest_bc.js');
$backend->delete_combined_files('RequirementsTest_bc.js');
}
function testArgsInUrls() {
// Clear previous requirements
Requirements::clear();
$backend = new Requirements_Backend;
$backend->set_combined_files_enabled(true);
// clearing all previously generated requirements (just in case)
Requirements::clear_combined_files();
$backend->javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.js?test=1&test=2&test=3');
$backend->css(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.css?test=1&test=2&test=3');
Requirements::delete_combined_files('RequirementsTest_bc.js');
Requirements::javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.js?test=1&test=2&test=3');
Requirements::css(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.css?test=1&test=2&test=3');
$html = Requirements::includeInHTML(false, self::$html_template);
$html = $backend->includeInHTML(false, self::$html_template);
/* Javascript has correct path */
$this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_a\.js\?m=\d\d+&test=1&test=2&test=3/', $html), 'javascript has correct path');
@ -146,55 +157,27 @@ class RequirementsTest extends SapphireTest {
$this->assertTrue((bool)preg_match('/href=".*\/RequirementsTest_a\.css\?m=\d\d+&test=1&test=2&test=3/', $html), 'css has correct path');
}
/**
* This is a bit of a hack, as it alters the Requirements
* statics globally for all tests.
*
* @todo Refactor Requirements to work on test instance level
*/
protected function setupCombinedRequirements() {
Requirements::clear();
// clearing all previously generated requirements (just in case)
Requirements::clear_combined_files();
Requirements::delete_combined_files('RequirementsTest_bc.js');
// require files normally (e.g. called from a FormField instance)
Requirements::javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.js');
Requirements::javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_b.js');
Requirements::javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_c.js');
// require two of those files as combined includes
Requirements::combine_files(
'RequirementsTest_bc.js',
array(
SAPPHIRE_DIR . '/tests/forms/RequirementsTest_b.js',
SAPPHIRE_DIR . '/tests/forms/RequirementsTest_c.js'
)
);
}
function testRequirementsBackend() {
$requirements = new Requirements_Backend();
$requirements->javascript(SAPPHIRE_DIR . '/tests/forms/a.js');
$backend = new Requirements_Backend();
$backend->javascript(SAPPHIRE_DIR . '/tests/forms/a.js');
$this->assertTrue(count($requirements->get_javascript()) == 1, "There should be only 1 file included in required javascript.");
$this->assertTrue(in_array(SAPPHIRE_DIR . '/tests/forms/a.js', $requirements->get_javascript()), "/test/forms/a.js should be included in required javascript.");
$this->assertTrue(count($backend->get_javascript()) == 1, "There should be only 1 file included in required javascript.");
$this->assertTrue(in_array(SAPPHIRE_DIR . '/tests/forms/a.js', $backend->get_javascript()), "/test/forms/a.js should be included in required javascript.");
$requirements->javascript(SAPPHIRE_DIR . '/tests/forms/b.js');
$this->assertTrue(count($requirements->get_javascript()) == 2, "There should be 2 files included in required javascript.");
$backend->javascript(SAPPHIRE_DIR . '/tests/forms/b.js');
$this->assertTrue(count($backend->get_javascript()) == 2, "There should be 2 files included in required javascript.");
$requirements->block(SAPPHIRE_DIR . '/tests/forms/a.js');
$this->assertTrue(count($requirements->get_javascript()) == 1, "There should be only 1 file included in required javascript.");
$this->assertFalse(in_array(SAPPHIRE_DIR . '/tests/forms/a.js', $requirements->get_javascript()), "/test/forms/a.js should not be included in required javascript after it has been blocked.");
$this->assertTrue(in_array(SAPPHIRE_DIR . '/tests/forms/b.js', $requirements->get_javascript()), "/test/forms/b.js should be included in required javascript.");
$backend->block(SAPPHIRE_DIR . '/tests/forms/a.js');
$this->assertTrue(count($backend->get_javascript()) == 1, "There should be only 1 file included in required javascript.");
$this->assertFalse(in_array(SAPPHIRE_DIR . '/tests/forms/a.js', $backend->get_javascript()), "/test/forms/a.js should not be included in required javascript after it has been blocked.");
$this->assertTrue(in_array(SAPPHIRE_DIR . '/tests/forms/b.js', $backend->get_javascript()), "/test/forms/b.js should be included in required javascript.");
$requirements->css(SAPPHIRE_DIR . '/tests/forms/a.css');
$this->assertTrue(count($requirements->get_css()) == 1, "There should be only 1 file included in required css.");
$this->assertArrayHasKey(SAPPHIRE_DIR . '/tests/forms/a.css', $requirements->get_css(), "/tests/forms/a.css should be in required css.");
$backend->css(SAPPHIRE_DIR . '/tests/forms/a.css');
$this->assertTrue(count($backend->get_css()) == 1, "There should be only 1 file included in required css.");
$this->assertArrayHasKey(SAPPHIRE_DIR . '/tests/forms/a.css', $backend->get_css(), "/tests/forms/a.css should be in required css.");
$requirements->block(SAPPHIRE_DIR . '/tests/forms/a.css');
$this->assertTrue(count($requirements->get_css()) == 0, "There should be nothing in required css after file has been blocked.");
$backend->block(SAPPHIRE_DIR . '/tests/forms/a.css');
$this->assertTrue(count($backend->get_css()) == 0, "There should be nothing in required css after file has been blocked.");