diff --git a/docs/en/02_Developer_Guides/01_Templates/03_Requirements.md b/docs/en/02_Developer_Guides/01_Templates/03_Requirements.md index 251362c87..8cbeb9767 100644 --- a/docs/en/02_Developer_Guides/01_Templates/03_Requirements.md +++ b/docs/en/02_Developer_Guides/01_Templates/03_Requirements.md @@ -169,13 +169,13 @@ replaced. For instance, the below will set a new set of dependencies to write to --- Name: myrequirements --- - Requirements: + SilverStripe\View\Requirements: disable_flush_combined: true - Requirements_Backend: + SilverStripe\View\Requirements_Backend: combine_in_dev: true combine_hash_querystring: true default_combined_files_folder: 'combined' - Injector: + SilverStripe\Core\Injector\Injector: MySiteAdapter: class: 'SilverStripe\Filesystem\Flysystem\AssetAdapter' constructor: @@ -192,7 +192,7 @@ replaced. For instance, the below will set a new set of dependencies to write to class: SilverStripe\Filesystem\Storage\FlysystemGeneratedAssetHandler properties: Filesystem: '%$MySiteBackend' - Requirements_Backend: + SilverStripe\View\Requirements_Backend: properties: AssetHandler: '%$MySiteAssetHandler' @@ -248,6 +248,49 @@ $scripts = array( Requirements::combine_files('scripts.js', $scripts, array('async' => true, 'defer' => true)); ``` +### Minification of CSS and JS files + +You can minify combined Javascript and CSS files at runtime using an implementation of the +`SilverStripe\View\Requirements_Minifier` interface. + +```php +namespace MyProject; + +use SilverStripe\View\Requirements_Minifier; + +class MyMinifier implements Requirements_Minifier +{ + /** + * Minify the given content + * + * @param string $content + * @param string $type Either js or css + * @param string $filename Name of file to display in case of error + * @return string minified content + */ + public function minify ($content, $type, $fileName) + { + // Minify $content; + + return $minifiedContent; + } +} +``` + +Then, inject this service in `Requirements_Backend`. + +```yaml +SilverStripe\Core\Injector\Injector: + SilverStripe\View\Requirements_Backend: + properties: + Minifier: %$MyProject\MyMinifier +``` + +
+While the framework does afford you the option of minification at runtime, we recommend using one of many frontend build +tools to do this for you, e.g. [Webpack](https://webpack.github.io/), [Gulp](http://gulpjs.com/), or [Grunt](https://gruntjs.com/). +
+ ## Clearing assets diff --git a/src/View/JSMinifier.php b/src/View/JSMinifier.php deleted file mode 100644 index d63be3dd2..000000000 --- a/src/View/JSMinifier.php +++ /dev/null @@ -1,30 +0,0 @@ -getMessage(); - user_error("Failed to minify {$filename}, exception: {$message}", E_USER_WARNING); - } finally { - return $content . ";\n"; - } - } -} diff --git a/src/View/Requirements_Backend.php b/src/View/Requirements_Backend.php index 78f642ca7..fa5a26b5e 100644 --- a/src/View/Requirements_Backend.php +++ b/src/View/Requirements_Backend.php @@ -3,6 +3,7 @@ namespace SilverStripe\View; use InvalidArgumentException; +use Exception; use SilverStripe\Assets\File; use SilverStripe\Assets\Storage\GeneratedAssetHandler; use SilverStripe\Control\Director; @@ -10,7 +11,6 @@ use SilverStripe\Control\HTTPResponse; use SilverStripe\Core\Config\Config; use SilverStripe\Core\Convert; use SilverStripe\Core\Injector\Injectable; -use SilverStripe\Core\Injector\Injector; use SilverStripe\Dev\Debug; use SilverStripe\Dev\Deprecation; use SilverStripe\Dev\SapphireTest; @@ -121,11 +121,11 @@ class Requirements_Backend protected $combinedFiles = array(); /** - * Use the JSMin library to minify any javascript file passed to {@link combine_files()}. + * Use the injected minification service to minify any javascript file passed to {@link combine_files()}. * * @var bool */ - protected $minifyCombinedJSFiles = true; + protected $minifyCombinedFiles = false; /** * Whether or not file headers should be written when combining files @@ -191,6 +191,11 @@ class Requirements_Backend */ protected $assetHandler = null; + /** + * @var Requirements_Minifier + */ + protected $minifier = null; + /** * Gets the backend storage for generated files * @@ -211,6 +216,27 @@ class Requirements_Backend $this->assetHandler = $handler; } + /** + * Gets the minification service for this backend + * + * @deprecated 4.0..5.0 + * @return Requirements_Minifier + */ + public function getMinifier() + { + return $this->minifier; + } + + /** + * Set a new minification service for this backend + * + * @param Requirements_Minifier $minifier + */ + public function setMinifier(Requirements_Minifier $minifier = null) + { + $this->minifier = $minifier; + } + /** * Enable or disable the combination of CSS and JavaScript files * @@ -340,24 +366,24 @@ class Requirements_Backend } /** - * Check if minify js files should be combined + * Check if minify files should be combined * * @return bool */ - public function getMinifyCombinedJSFiles() + public function getMinifyCombinedFiles() { - return $this->minifyCombinedJSFiles; + return $this->minifyCombinedFiles; } /** - * Set if combined js files should be minified + * Set if combined files should be minified * * @param bool $minify * @return $this */ - public function setMinifyCombinedJSFiles($minify) + public function setMinifyCombinedFiles($minify) { - $this->minifyCombinedJSFiles = $minify; + $this->minifyCombinedFiles = $minify; return $this; } @@ -1278,7 +1304,20 @@ class Requirements_Backend $combinedFileID = File::join_paths($this->getCombinedFilesFolder(), $combinedFile); // Send file combination request to the backend, with an optional callback to perform regeneration - $minify = $this->getMinifyCombinedJSFiles(); + $minify = $this->getMinifyCombinedFiles(); + if ($minify && !$this->minifier) { + throw new Exception( + sprintf( + 'Cannot minify files without a minification service defined. + Set %s::minifyCombinedFiles to false, or inject a %s service on + %s.properties.minifier', + __CLASS__, + Requirements_Minifier::class, + __CLASS__ + ) + ); + } + $combinedURL = $this ->getAssetHandler() ->getContentURL( @@ -1287,12 +1326,11 @@ class Requirements_Backend // Physically combine all file content $combinedData = ''; $base = Director::baseFolder() . '/'; - $minifier = Injector::inst()->get('SilverStripe\\View\\Requirements_Minifier'); foreach ($fileList as $file) { $fileContent = file_get_contents($base . $file); // Use configured minifier if ($minify) { - $fileContent = $minifier->minify($fileContent, $type, $file); + $fileContent = $this->minifier->minify($fileContent, $type, $file); } if ($this->writeHeaderComment) { diff --git a/src/View/Requirements_Minifier.php b/src/View/Requirements_Minifier.php index 0994d639c..5fc16c413 100644 --- a/src/View/Requirements_Minifier.php +++ b/src/View/Requirements_Minifier.php @@ -4,6 +4,8 @@ namespace SilverStripe\View; /** * Provides an abstract interface for minifying content + * + * @deprecated 4.0..5.0 */ interface Requirements_Minifier { diff --git a/tests/php/View/RequirementsTest.php b/tests/php/View/RequirementsTest.php index 6208fa3e4..85da1a3de 100644 --- a/tests/php/View/RequirementsTest.php +++ b/tests/php/View/RequirementsTest.php @@ -86,7 +86,7 @@ class RequirementsTest extends SapphireTest $backend->clear(); $backend->clearCombinedFiles(); $backend->setCombinedFilesFolder('_combinedfiles'); - $backend->setMinifyCombinedJSFiles(false); + $backend->setMinifyCombinedFiles(false); Requirements::flush(); } diff --git a/tests/php/View/SSViewerTest.php b/tests/php/View/SSViewerTest.php index ab83cd0d9..bb58fd184 100644 --- a/tests/php/View/SSViewerTest.php +++ b/tests/php/View/SSViewerTest.php @@ -8,7 +8,6 @@ use SilverStripe\Control\ContentNegotiator; use SilverStripe\Control\HTTPResponse; use SilverStripe\Core\Convert; use SilverStripe\Core\Injector\Injector; -use SilverStripe\Dev\Debug; use SilverStripe\Dev\SapphireTest; use SilverStripe\i18n\i18n; use SilverStripe\ORM\DataObject; @@ -20,6 +19,7 @@ use SilverStripe\Security\SecurityToken; use SilverStripe\Security\Permission; use SilverStripe\View\ArrayData; use SilverStripe\View\Requirements_Backend; +use SilverStripe\View\Requirements_Minifier; use SilverStripe\View\SSViewer; use SilverStripe\View\Requirements; use SilverStripe\View\Tests\SSViewerTest\SSViewerTestModel; @@ -28,7 +28,6 @@ use SilverStripe\View\ViewableData; use SilverStripe\View\SSViewer_FromString; use SilverStripe\View\SSTemplateParser; use SilverStripe\Assets\Tests\Storage\AssetStoreTest\TestAssetStore; -use JSMin; use Exception; class SSViewerTest extends SapphireTest @@ -70,9 +69,9 @@ class SSViewerTest extends SapphireTest { SSViewer::config()->update('theme', 'mytheme'); $this->assertEquals( - 'mytheme', - SSViewer::config()->uninherited('theme'), - 'Current theme is the default - user has not defined one' + 'mytheme', + SSViewer::config()->uninherited('theme'), + 'Current theme is the default - user has not defined one' ); } @@ -82,9 +81,9 @@ class SSViewerTest extends SapphireTest public function testTemplateWithoutHeadRenders() { $data = new ArrayData( - array( - 'Var' => 'var value' - ) + array( + 'Var' => 'var value' + ) ); $result = $data->renderWith("SSViewerTestPartialTemplate"); @@ -95,12 +94,12 @@ class SSViewerTest extends SapphireTest { $data = $this->getScopeInheritanceTestData(); $expected = array( - 'Item 1 - First-ODD top:Item 1', - 'Item 2 - EVEN top:Item 2', - 'Item 3 - ODD top:Item 3', - 'Item 4 - EVEN top:Item 4', - 'Item 5 - ODD top:Item 5', - 'Item 6 - Last-EVEN top:Item 6', + 'Item 1 - First-ODD top:Item 1', + 'Item 2 - EVEN top:Item 2', + 'Item 3 - ODD top:Item 3', + 'Item 4 - EVEN top:Item 4', + 'Item 5 - ODD top:Item 5', + 'Item 6 - Last-EVEN top:Item 6', ); $result = $data->renderWith('SSViewerTestIncludeScopeInheritance'); @@ -108,12 +107,12 @@ class SSViewerTest extends SapphireTest // reset results for the tests that include arguments (the title is passed as an arg) $expected = array( - 'Item 1 _ Item 1 - First-ODD top:Item 1', - 'Item 2 _ Item 2 - EVEN top:Item 2', - 'Item 3 _ Item 3 - ODD top:Item 3', - 'Item 4 _ Item 4 - EVEN top:Item 4', - 'Item 5 _ Item 5 - ODD top:Item 5', - 'Item 6 _ Item 6 - Last-EVEN top:Item 6', + 'Item 1 _ Item 1 - First-ODD top:Item 1', + 'Item 2 _ Item 2 - EVEN top:Item 2', + 'Item 3 _ Item 3 - ODD top:Item 3', + 'Item 4 _ Item 4 - EVEN top:Item 4', + 'Item 5 _ Item 5 - ODD top:Item 5', + 'Item 6 _ Item 6 - Last-EVEN top:Item 6', ); $result = $data->renderWith('SSViewerTestIncludeScopeInheritanceWithArgs'); @@ -123,32 +122,32 @@ class SSViewerTest extends SapphireTest public function testIncludeTruthyness() { $data = new ArrayData( + array( + 'Title' => 'TruthyTest', + 'Items' => new ArrayList( array( - 'Title' => 'TruthyTest', - 'Items' => new ArrayList( - array( - new ArrayData(array('Title' => 'Item 1')), - new ArrayData(array('Title' => '')), - new ArrayData(array('Title' => true)), - new ArrayData(array('Title' => false)), - new ArrayData(array('Title' => null)), - new ArrayData(array('Title' => 0)), - new ArrayData(array('Title' => 7)) - ) - ) + new ArrayData(array('Title' => 'Item 1')), + new ArrayData(array('Title' => '')), + new ArrayData(array('Title' => true)), + new ArrayData(array('Title' => false)), + new ArrayData(array('Title' => null)), + new ArrayData(array('Title' => 0)), + new ArrayData(array('Title' => 7)) ) + ) + ) ); $result = $data->renderWith('SSViewerTestIncludeScopeInheritanceWithArgs'); // We should not end up with empty values appearing as empty $expected = array( - 'Item 1 _ Item 1 - First-ODD top:Item 1', - 'Untitled - EVEN top:', - '1 _ 1 - ODD top:1', - 'Untitled - EVEN top:', - 'Untitled - ODD top:', - 'Untitled - EVEN top:0', - '7 _ 7 - Last-ODD top:7' + 'Item 1 _ Item 1 - First-ODD top:Item 1', + 'Untitled - EVEN top:', + '1 _ 1 - ODD top:1', + 'Untitled - EVEN top:', + 'Untitled - ODD top:', + 'Untitled - EVEN top:0', + '7 _ 7 - Last-ODD top:7' ); $this->assertExpectedStrings($result, $expected); } @@ -156,19 +155,19 @@ class SSViewerTest extends SapphireTest private function getScopeInheritanceTestData() { return new ArrayData( + array( + 'Title' => 'TopTitleValue', + 'Items' => new ArrayList( array( - 'Title' => 'TopTitleValue', - 'Items' => new ArrayList( - array( - new ArrayData(array('Title' => 'Item 1')), - new ArrayData(array('Title' => 'Item 2')), - new ArrayData(array('Title' => 'Item 3')), - new ArrayData(array('Title' => 'Item 4')), - new ArrayData(array('Title' => 'Item 5')), - new ArrayData(array('Title' => 'Item 6')) - ) - ) + new ArrayData(array('Title' => 'Item 1')), + new ArrayData(array('Title' => 'Item 2')), + new ArrayData(array('Title' => 'Item 3')), + new ArrayData(array('Title' => 'Item 4')), + new ArrayData(array('Title' => 'Item 5')), + new ArrayData(array('Title' => 'Item 6')) ) + ) + ) ); } @@ -176,8 +175,8 @@ class SSViewerTest extends SapphireTest { foreach ($expected as $expectedStr) { $this->assertTrue( - (boolean) preg_match("/{$expectedStr}/", $result), - "Didn't find '{$expectedStr}' in:\n{$result}" + (boolean) preg_match("/{$expectedStr}/", $result), + "Didn't find '{$expectedStr}' in:\n{$result}" ); } } @@ -202,7 +201,7 @@ class SSViewerTest extends SapphireTest public function testRequirements() { $requirements = $this->getMockBuilder(Requirements_Backend::class)->setMethods(array("javascript", "css")) - ->getMock(); + ->getMock(); $jsFile = FRAMEWORK_DIR . '/tests/forms/a.js'; $cssFile = FRAMEWORK_DIR . '/tests/forms/a.js'; @@ -212,7 +211,7 @@ class SSViewerTest extends SapphireTest $origReq = Requirements::backend(); Requirements::set_backend($requirements); $template = $this->render( - "<% require javascript($jsFile) %> + "<% require javascript($jsFile) %> <% require css($cssFile) %>" ); Requirements::set_backend($origReq); @@ -230,15 +229,6 @@ class SSViewerTest extends SapphireTest $jsFileContents = file_get_contents(BASE_PATH . '/' . $jsFile); $testBackend->combineFiles('testRequirementsCombine.js', array($jsFile)); - // first make sure that our test js file causes an exception to be thrown - try { - include_once 'jsmin/jsmin.php'; - JSMin::minify($jsFileContents); - $this->fail('JSMin did not throw exception on minify bad file: '); - } catch (Exception $e) { - // exception thrown... good - } - // secondly, make sure that requirements is generated, even though minification failed $testBackend->processCombinedFiles(); $js = array_keys($testBackend->getJavascript()); @@ -253,12 +243,50 @@ class SSViewerTest extends SapphireTest $this->assertContains($jsFileContents, $combinedTestFileContents); } + public function testRequirementsMinification() + { + $testBackend = Injector::inst()->create(Requirements_Backend::class); + $testBackend->setSuffixRequirements(false); + $testBackend->setMinifyCombinedFiles(true); + $testFile = $this->getCurrentRelativePath() . '/SSViewerTest/javascript/RequirementsTest_a.js'; + $testFileContent = file_get_contents($testFile); + + $mockMinifier = $this->getMockBuilder(Requirements_Minifier::class) + ->setMethods(['minify']) + ->getMock(); + + $mockMinifier->expects($this->once()) + ->method('minify') + ->with( + $testFileContent, + 'js', + $testFile + ); + $testBackend->setMinifier($mockMinifier); + $testBackend->combineFiles('testRequirementsMinified.js', array($testFile)); + $testBackend->processCombinedFiles(); + + $testBackend->setMinifyCombinedFiles(false); + $mockMinifier->expects($this->never()) + ->method('minify'); + $testBackend->processCombinedFiles(); + + $this->setExpectedExceptionRegExp( + Exception::class, + '/minification service/' + ); + + $testBackend->setMinifyCombinedFiles(true); + $testBackend->setMinifier(null); + $testBackend->processCombinedFiles(); + } + public function testComments() { $output = $this->render( - <<This is some content<%-- this is another comment --%>Final content <%-- Alone multi line comment --%> @@ -300,9 +328,9 @@ SS; $this->assertEquals('{$Test}', $this->render('{\\$Test}'), 'Escapes can be used to avoid injection'); $this->assertEquals( - '{\\[out:Test]}', - $this->render('{\\\\$Test}'), - 'Escapes before injections are correctly unescaped' + '{\\[out:Test]}', + $this->render('{\\\\$Test}'), + 'Escapes before injections are correctly unescaped' ); } @@ -319,12 +347,12 @@ SS; $this->assertEquals('zz', $this->render('$SSViewerTest_GlobalThatTakesArguments')); $this->assertEquals('zFooz', $this->render('$SSViewerTest_GlobalThatTakesArguments("Foo")')); $this->assertEquals( - 'zFoo:Bar:Bazz', - $this->render('$SSViewerTest_GlobalThatTakesArguments("Foo", "Bar", "Baz")') + 'zFoo:Bar:Bazz', + $this->render('$SSViewerTest_GlobalThatTakesArguments("Foo", "Bar", "Baz")') ); $this->assertEquals( - 'zreferencez', - $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalReferencedByString)') + 'zreferencez', + $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalReferencedByString)') ); } @@ -334,101 +362,101 @@ SS; $this->assertEquals('<div></div>', $this->render('$SSViewerTest_GlobalHTMLEscaped')); $this->assertEquals( - 'z
z', - $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLFragment)') + 'z
z', + $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLFragment)') ); $this->assertEquals( - 'z<div></div>z', - $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLEscaped)') + 'z<div></div>z', + $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLEscaped)') ); } public function testCoreGlobalVariableCalls() { $this->assertEquals( - Director::absoluteBaseURL(), - $this->render('{$absoluteBaseURL}'), - 'Director::absoluteBaseURL can be called from within template' + Director::absoluteBaseURL(), + $this->render('{$absoluteBaseURL}'), + 'Director::absoluteBaseURL can be called from within template' ); $this->assertEquals( - Director::absoluteBaseURL(), - $this->render('{$AbsoluteBaseURL}'), - 'Upper-case %AbsoluteBaseURL can be called from within template' + Director::absoluteBaseURL(), + $this->render('{$AbsoluteBaseURL}'), + 'Upper-case %AbsoluteBaseURL can be called from within template' ); $this->assertEquals( - Director::is_ajax(), - $this->render('{$isAjax}'), - 'All variations of is_ajax result in the correct call' + Director::is_ajax(), + $this->render('{$isAjax}'), + 'All variations of is_ajax result in the correct call' ); $this->assertEquals( - Director::is_ajax(), - $this->render('{$IsAjax}'), - 'All variations of is_ajax result in the correct call' + Director::is_ajax(), + $this->render('{$IsAjax}'), + 'All variations of is_ajax result in the correct call' ); $this->assertEquals( - Director::is_ajax(), - $this->render('{$is_ajax}'), - 'All variations of is_ajax result in the correct call' + Director::is_ajax(), + $this->render('{$is_ajax}'), + 'All variations of is_ajax result in the correct call' ); $this->assertEquals( - Director::is_ajax(), - $this->render('{$Is_ajax}'), - 'All variations of is_ajax result in the correct call' + Director::is_ajax(), + $this->render('{$Is_ajax}'), + 'All variations of is_ajax result in the correct call' ); $this->assertEquals( - i18n::get_locale(), - $this->render('{$i18nLocale}'), - 'i18n template functions result correct result' + i18n::get_locale(), + $this->render('{$i18nLocale}'), + 'i18n template functions result correct result' ); $this->assertEquals( - i18n::get_locale(), - $this->render('{$get_locale}'), - 'i18n template functions result correct result' + i18n::get_locale(), + $this->render('{$get_locale}'), + 'i18n template functions result correct result' ); $this->assertEquals( - (string)Member::currentUser(), - $this->render('{$CurrentMember}'), - 'Member template functions result correct result' + (string)Member::currentUser(), + $this->render('{$CurrentMember}'), + 'Member template functions result correct result' ); $this->assertEquals( - (string)Member::currentUser(), - $this->render('{$CurrentUser}'), - 'Member template functions result correct result' + (string)Member::currentUser(), + $this->render('{$CurrentUser}'), + 'Member template functions result correct result' ); $this->assertEquals( - (string)Member::currentUser(), - $this->render('{$currentMember}'), - 'Member template functions result correct result' + (string)Member::currentUser(), + $this->render('{$currentMember}'), + 'Member template functions result correct result' ); $this->assertEquals( - (string)Member::currentUser(), - $this->render('{$currentUser}'), - 'Member template functions result correct result' + (string)Member::currentUser(), + $this->render('{$currentUser}'), + 'Member template functions result correct result' ); $this->assertEquals( - SecurityToken::getSecurityID(), - $this->render('{$getSecurityID}'), - 'SecurityToken template functions result correct result' + SecurityToken::getSecurityID(), + $this->render('{$getSecurityID}'), + 'SecurityToken template functions result correct result' ); $this->assertEquals( - SecurityToken::getSecurityID(), - $this->render('{$SecurityID}'), - 'SecurityToken template functions result correct result' + SecurityToken::getSecurityID(), + $this->render('{$SecurityID}'), + 'SecurityToken template functions result correct result' ); $this->assertEquals( - Permission::check("ADMIN"), - (bool)$this->render('{$HasPerm(\'ADMIN\')}'), - 'Permissions template functions result correct result' + Permission::check("ADMIN"), + (bool)$this->render('{$HasPerm(\'ADMIN\')}'), + 'Permissions template functions result correct result' ); $this->assertEquals( - Permission::check("ADMIN"), - (bool)$this->render('{$hasPerm(\'ADMIN\')}'), - 'Permissions template functions result correct result' + Permission::check("ADMIN"), + (bool)$this->render('{$hasPerm(\'ADMIN\')}'), + 'Permissions template functions result correct result' ); } @@ -436,15 +464,15 @@ SS; { // check if Link without $ in front of variable $result = $this->render( - 'A<% if Link %>$Link<% end_if %>B', - new SSViewerTest\TestObject() + 'A<% if Link %>$Link<% end_if %>B', + new SSViewerTest\TestObject() ); $this->assertEquals('Asome/url.htmlB', $result, 'casting helper not used for <% if Link %>'); // check if Link with $ in front of variable $result = $this->render( - 'A<% if $Link %>$Link<% end_if %>B', - new SSViewerTest\TestObject() + 'A<% if $Link %>$Link<% end_if %>B', + new SSViewerTest\TestObject() ); $this->assertEquals('Asome/url.htmlB', $result, 'casting helper not used for <% if $Link %>'); } @@ -452,15 +480,15 @@ SS; public function testLocalFunctionsTakePriorityOverGlobals() { $data = new ArrayData( - array( - 'Page' => new SSViewerTest\TestObject() - ) + array( + 'Page' => new SSViewerTest\TestObject() + ) ); //call method with lots of arguments $result = $this->render( - '<% with Page %>$lotsOfArguments11("a","b","c","d","e","f","g","h","i","j","k")<% end_with %>', - $data + '<% with Page %>$lotsOfArguments11("a","b","c","d","e","f","g","h","i","j","k")<% end_with %>', + $data ); $this->assertEquals("abcdefghijk", $result, "public function can accept up to 11 arguments"); @@ -475,9 +503,9 @@ SS; //call method with same name as a global method (local call should take priority) $result = $this->render('<% with Page %>$absoluteBaseURL<% end_with %>', $data); $this->assertEquals( - "testLocalFunctionPriorityCalled", - $result, - "Local Object's public function called. Did not return the actual baseURL of the current site" + "testLocalFunctionPriorityCalled", + $result, + "Local Object's public function called. Did not return the actual baseURL of the current site" ); } @@ -485,47 +513,47 @@ SS; { // Data to run the loop tests on - one sequence of three items, each with a subitem $data = new ArrayData( + array( + 'Foo' => new ArrayList( array( - 'Foo' => new ArrayList( + 'Subocean' => new ArrayData( array( - 'Subocean' => new ArrayData( - array( - 'Name' => 'Higher' - ) - ), - new ArrayData( - array( - 'Sub' => new ArrayData( - array( - 'Name' => 'SubKid1' - ) - ) - ) - ), - new ArrayData( - array( - 'Sub' => new ArrayData( - array( - 'Name' => 'SubKid2' - ) - ) - ) - ), - new SSViewerTest\TestObject('Number6') + 'Name' => 'Higher' ) + ), + new ArrayData( + array( + 'Sub' => new ArrayData( + array( + 'Name' => 'SubKid1' + ) + ) + ) + ), + new ArrayData( + array( + 'Sub' => new ArrayData( + array( + 'Name' => 'SubKid2' + ) + ) + ) + ), + new SSViewerTest\TestObject('Number6') ) - ) + ) + ) ); $result = $this->render( - '<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>', - $data + '<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>', + $data ); $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop works"); $result = $this->render( - '<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>', - $data + '<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>', + $data ); $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop works"); @@ -533,16 +561,16 @@ SS; $this->assertEquals("4", $result, "4 items in the DataObjectSet"); $result = $this->render( - '<% with Foo %><% loop Up.Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>' - . '<% end_if %><% end_loop %><% end_with %>', - $data + '<% with Foo %><% loop Up.Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>' + . '<% end_if %><% end_loop %><% end_with %>', + $data ); $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop in with Up.Foo scope works"); $result = $this->render( - '<% with Foo %><% loop %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>' - . '<% end_if %><% end_loop %><% end_with %>', - $data + '<% with Foo %><% loop %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>' + . '<% end_if %><% end_loop %><% end_with %>', + $data ); $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop in current scope works"); } @@ -550,7 +578,7 @@ SS; public function testObjectDotArguments() { $this->assertEquals( - '[out:TestObject.methodWithOneArgument(one)] + '[out:TestObject.methodWithOneArgument(one)] [out:TestObject.methodWithTwoArguments(one,two)] [out:TestMethod(Arg1,Arg2).Bar.Val] [out:TestMethod(Arg1,Arg2).Bar] @@ -558,8 +586,8 @@ SS; [out:TestMethod(Arg1).Bar.Val] [out:TestMethod(Arg1).Bar] [out:TestMethod(Arg1)]', - $this->render( - '$TestObject.methodWithOneArgument(one) + $this->render( + '$TestObject.methodWithOneArgument(one) $TestObject.methodWithTwoArguments(one,two) $TestMethod(Arg1, Arg2).Bar.Val $TestMethod(Arg1, Arg2).Bar @@ -567,14 +595,14 @@ SS; $TestMethod(Arg1).Bar.Val $TestMethod(Arg1).Bar $TestMethod(Arg1)' - ) + ) ); } public function testEscapedArguments() { $this->assertEquals( - '[out:Foo(Arg1,Arg2).Bar.Val].Suffix + '[out:Foo(Arg1,Arg2).Bar.Val].Suffix [out:Foo(Arg1,Arg2).Val]_Suffix [out:Foo(Arg1,Arg2)]/Suffix [out:Foo(Arg1).Bar.Val]textSuffix @@ -583,8 +611,8 @@ SS; [out:Foo.Bar.Val].Suffix [out:Foo.Bar].Suffix [out:Foo].Suffix', - $this->render( - '{$Foo(Arg1, Arg2).Bar.Val}.Suffix + $this->render( + '{$Foo(Arg1, Arg2).Bar.Val}.Suffix {$Foo(Arg1, Arg2).Val}_Suffix {$Foo(Arg1, Arg2)}/Suffix {$Foo(Arg1).Bar.Val}textSuffix @@ -593,44 +621,44 @@ SS; {$Foo.Bar.Val}.Suffix {$Foo.Bar}.Suffix {$Foo}.Suffix' - ) + ) ); } public function testLoopWhitespace() { $this->assertEquals( - 'before[out:SingleItem.Test]after + 'before[out:SingleItem.Test]after beforeTestafter', - $this->render( - 'before<% loop SingleItem %>$Test<% end_loop %>after + $this->render( + 'before<% loop SingleItem %>$Test<% end_loop %>after before<% loop SingleItem %>Test<% end_loop %>after' - ) + ) ); // The control tags are removed from the output, but no whitespace // This is a quirk that could be changed, but included in the test to make the current // behaviour explicit $this->assertEquals( - 'before + 'before [out:SingleItem.ItemOnItsOwnLine] after', - $this->render( - 'before + $this->render( + 'before <% loop SingleItem %> $ItemOnItsOwnLine <% end_loop %> after' - ) + ) ); // The whitespace within the control tags is preserve in a loop // This is a quirk that could be changed, but included in the test to make the current // behaviour explicit $this->assertEquals( - 'before + 'before [out:Loop3.ItemOnItsOwnLine] @@ -639,13 +667,13 @@ after' [out:Loop3.ItemOnItsOwnLine] after', - $this->render( - 'before + $this->render( + 'before <% loop Loop3 %> $ItemOnItsOwnLine <% end_loop %> after' - ) + ) ); } @@ -653,44 +681,44 @@ after' { // Single item controls $this->assertEquals( - 'a[out:Foo.Bar.Item]b + 'a[out:Foo.Bar.Item]b [out:Foo.Bar(Arg1).Item] [out:Foo(Arg1).Item] [out:Foo(Arg1,Arg2).Item] [out:Foo(Arg1,Arg2,Arg3).Item]', - $this->render( - '<% with Foo.Bar %>a{$Item}b<% end_with %> + $this->render( + '<% with Foo.Bar %>a{$Item}b<% end_with %> <% with Foo.Bar(Arg1) %>$Item<% end_with %> <% with Foo(Arg1) %>$Item<% end_with %> <% with Foo(Arg1, Arg2) %>$Item<% end_with %> <% with Foo(Arg1, Arg2, Arg3) %>$Item<% end_with %>' - ) + ) ); // Loop controls $this->assertEquals( - 'a[out:Foo.Loop2.Item]ba[out:Foo.Loop2.Item]b', - $this->render('<% loop Foo.Loop2 %>a{$Item}b<% end_loop %>') + 'a[out:Foo.Loop2.Item]ba[out:Foo.Loop2.Item]b', + $this->render('<% loop Foo.Loop2 %>a{$Item}b<% end_loop %>') ); $this->assertEquals( - '[out:Foo.Loop2(Arg1).Item][out:Foo.Loop2(Arg1).Item]', - $this->render('<% loop Foo.Loop2(Arg1) %>$Item<% end_loop %>') + '[out:Foo.Loop2(Arg1).Item][out:Foo.Loop2(Arg1).Item]', + $this->render('<% loop Foo.Loop2(Arg1) %>$Item<% end_loop %>') ); $this->assertEquals( - '[out:Loop2(Arg1).Item][out:Loop2(Arg1).Item]', - $this->render('<% loop Loop2(Arg1) %>$Item<% end_loop %>') + '[out:Loop2(Arg1).Item][out:Loop2(Arg1).Item]', + $this->render('<% loop Loop2(Arg1) %>$Item<% end_loop %>') ); $this->assertEquals( - '[out:Loop2(Arg1,Arg2).Item][out:Loop2(Arg1,Arg2).Item]', - $this->render('<% loop Loop2(Arg1, Arg2) %>$Item<% end_loop %>') + '[out:Loop2(Arg1,Arg2).Item][out:Loop2(Arg1,Arg2).Item]', + $this->render('<% loop Loop2(Arg1, Arg2) %>$Item<% end_loop %>') ); $this->assertEquals( - '[out:Loop2(Arg1,Arg2,Arg3).Item][out:Loop2(Arg1,Arg2,Arg3).Item]', - $this->render('<% loop Loop2(Arg1, Arg2, Arg3) %>$Item<% end_loop %>') + '[out:Loop2(Arg1,Arg2,Arg3).Item][out:Loop2(Arg1,Arg2,Arg3).Item]', + $this->render('<% loop Loop2(Arg1, Arg2, Arg3) %>$Item<% end_loop %>') ); } @@ -698,139 +726,139 @@ after' { // Basic test $this->assertEquals( - 'AC', - $this->render('A<% if NotSet %>B$NotSet<% end_if %>C') + 'AC', + $this->render('A<% if NotSet %>B$NotSet<% end_if %>C') ); // Nested test $this->assertEquals( - 'AB1C', - $this->render('A<% if IsSet %>B$NotSet<% if IsSet %>1<% else %>2<% end_if %><% end_if %>C') + 'AB1C', + $this->render('A<% if IsSet %>B$NotSet<% if IsSet %>1<% else %>2<% end_if %><% end_if %>C') ); // else_if $this->assertEquals( - 'ACD', - $this->render('A<% if NotSet %>B<% else_if IsSet %>C<% end_if %>D') + 'ACD', + $this->render('A<% if NotSet %>B<% else_if IsSet %>C<% end_if %>D') ); $this->assertEquals( - 'AD', - $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% end_if %>D') + 'AD', + $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% end_if %>D') ); $this->assertEquals( - 'ADE', - $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E') + 'ADE', + $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E') ); $this->assertEquals( - 'ADE', - $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E') + 'ADE', + $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E') ); // Dot syntax $this->assertEquals( - 'ACD', - $this->render('A<% if Foo.NotSet %>B<% else_if Foo.IsSet %>C<% end_if %>D') + 'ACD', + $this->render('A<% if Foo.NotSet %>B<% else_if Foo.IsSet %>C<% end_if %>D') ); $this->assertEquals( - 'ACD', - $this->render('A<% if Foo.Bar.NotSet %>B<% else_if Foo.Bar.IsSet %>C<% end_if %>D') + 'ACD', + $this->render('A<% if Foo.Bar.NotSet %>B<% else_if Foo.Bar.IsSet %>C<% end_if %>D') ); // Params $this->assertEquals( - 'ACD', - $this->render('A<% if NotSet(Param) %>B<% else %>C<% end_if %>D') + 'ACD', + $this->render('A<% if NotSet(Param) %>B<% else %>C<% end_if %>D') ); $this->assertEquals( - 'ABD', - $this->render('A<% if IsSet(Param) %>B<% else %>C<% end_if %>D') + 'ABD', + $this->render('A<% if IsSet(Param) %>B<% else %>C<% end_if %>D') ); // Negation $this->assertEquals( - 'AC', - $this->render('A<% if not IsSet %>B<% end_if %>C') + 'AC', + $this->render('A<% if not IsSet %>B<% end_if %>C') ); $this->assertEquals( - 'ABC', - $this->render('A<% if not NotSet %>B<% end_if %>C') + 'ABC', + $this->render('A<% if not NotSet %>B<% end_if %>C') ); // Or $this->assertEquals( - 'ABD', - $this->render('A<% if IsSet || NotSet %>B<% else_if A %>C<% end_if %>D') + 'ABD', + $this->render('A<% if IsSet || NotSet %>B<% else_if A %>C<% end_if %>D') ); $this->assertEquals( - 'ACD', - $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet %>C<% end_if %>D') + 'ACD', + $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet %>C<% end_if %>D') ); $this->assertEquals( - 'AD', - $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet3 %>C<% end_if %>D') + 'AD', + $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet3 %>C<% end_if %>D') ); $this->assertEquals( - 'ACD', - $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet || NotSet %>C<% end_if %>D') + 'ACD', + $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet || NotSet %>C<% end_if %>D') ); $this->assertEquals( - 'AD', - $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet2 || NotSet3 %>C<% end_if %>D') + 'AD', + $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet2 || NotSet3 %>C<% end_if %>D') ); // Negated Or $this->assertEquals( - 'ACD', - $this->render('A<% if not IsSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D') + 'ACD', + $this->render('A<% if not IsSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D') ); $this->assertEquals( - 'ABD', - $this->render('A<% if not NotSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D') + 'ABD', + $this->render('A<% if not NotSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D') ); $this->assertEquals( - 'ABD', - $this->render('A<% if NotSet || not AlsoNotSet %>B<% else_if A %>C<% end_if %>D') + 'ABD', + $this->render('A<% if NotSet || not AlsoNotSet %>B<% else_if A %>C<% end_if %>D') ); // And $this->assertEquals( - 'ABD', - $this->render('A<% if IsSet && AlsoSet %>B<% else_if A %>C<% end_if %>D') + 'ABD', + $this->render('A<% if IsSet && AlsoSet %>B<% else_if A %>C<% end_if %>D') ); $this->assertEquals( - 'ACD', - $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet %>C<% end_if %>D') + 'ACD', + $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet %>C<% end_if %>D') ); $this->assertEquals( - 'AD', - $this->render('A<% if NotSet && NotSet2 %>B<% else_if NotSet3 %>C<% end_if %>D') + 'AD', + $this->render('A<% if NotSet && NotSet2 %>B<% else_if NotSet3 %>C<% end_if %>D') ); $this->assertEquals( - 'ACD', - $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet && AlsoSet %>C<% end_if %>D') + 'ACD', + $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet && AlsoSet %>C<% end_if %>D') ); $this->assertEquals( - 'AD', - $this->render('A<% if NotSet && NotSet2 %>B<% else_if IsSet && NotSet3 %>C<% end_if %>D') + 'AD', + $this->render('A<% if NotSet && NotSet2 %>B<% else_if IsSet && NotSet3 %>C<% end_if %>D') ); // Equality $this->assertEquals( - 'ABC', - $this->render('A<% if RawVal == RawVal %>B<% end_if %>C') + 'ABC', + $this->render('A<% if RawVal == RawVal %>B<% end_if %>C') ); $this->assertEquals( - 'ACD', - $this->render('A<% if Right == Wrong %>B<% else_if RawVal == RawVal %>C<% end_if %>D') + 'ACD', + $this->render('A<% if Right == Wrong %>B<% else_if RawVal == RawVal %>C<% end_if %>D') ); $this->assertEquals( - 'ABC', - $this->render('A<% if Right != Wrong %>B<% end_if %>C') + 'ABC', + $this->render('A<% if Right != Wrong %>B<% end_if %>C') ); $this->assertEquals( - 'AD', - $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% end_if %>D') + 'AD', + $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% end_if %>D') ); // test inequalities with simple numbers @@ -853,30 +881,30 @@ after' // the output would stop after A, thereby failing the assert $this->assertEquals('AD', $this->render('A<% if IsSet %><% else %><% end_if %>D')); $this->assertEquals( - 'AD', - $this->render('A<% if NotSet %><% else_if IsSet %><% else %><% end_if %>D') + 'AD', + $this->render('A<% if NotSet %><% else_if IsSet %><% else %><% end_if %>D') ); $this->assertEquals( - 'AD', - $this->render('A<% if NotSet %><% else_if AlsoNotSet %><% else %><% end_if %>D') + 'AD', + $this->render('A<% if NotSet %><% else_if AlsoNotSet %><% else %><% end_if %>D') ); // Bare words with ending space $this->assertEquals( - 'ABC', - $this->render('A<% if "RawVal" == RawVal %>B<% end_if %>C') + 'ABC', + $this->render('A<% if "RawVal" == RawVal %>B<% end_if %>C') ); // Else $this->assertEquals( - 'ADE', - $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% else %>D<% end_if %>E') + 'ADE', + $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% else %>D<% end_if %>E') ); // Empty if with else $this->assertEquals( - 'ABC', - $this->render('A<% if NotSet %><% else %>B<% end_if %>C') + 'ABC', + $this->render('A<% if NotSet %><% else %>B<% end_if %>C') ); } @@ -885,7 +913,7 @@ after' // XHTML wil have a closed base tag $tmpl1 = ' + . ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <% base_tag %>

test

@@ -899,8 +927,8 @@ after'

test

'; $this->assertRegExp( - '/<\/head>/', - $this->render($tmpl2) + '/<\/head>/', + $this->render($tmpl2) ); @@ -910,8 +938,8 @@ after'

test

'; $this->assertRegExp( - '/<\/head>/', - $this->render($tmpl3) + '/<\/head>/', + $this->render($tmpl3) ); // Check that the content negotiator converts to the equally legal formats @@ -920,8 +948,8 @@ after' $response = new HTTPResponse($this->render($tmpl1)); $negotiator->html($response); $this->assertRegExp( - '/<\/head>/', - $response->getBody() + '/<\/head>/', + $response->getBody() ); $response = new HTTPResponse($this->render($tmpl1)); @@ -932,103 +960,103 @@ after' public function testIncludeWithArguments() { $this->assertEquals( - $this->render('<% include SSViewerTestIncludeWithArguments %>'), - '

[out:Arg1]

[out:Arg2]

' + $this->render('<% include SSViewerTestIncludeWithArguments %>'), + '

[out:Arg1]

[out:Arg2]

' ); $this->assertEquals( - $this->render('<% include SSViewerTestIncludeWithArguments Arg1=A %>'), - '

A

[out:Arg2]

' + $this->render('<% include SSViewerTestIncludeWithArguments Arg1=A %>'), + '

A

[out:Arg2]

' ); $this->assertEquals( - $this->render('<% include SSViewerTestIncludeWithArguments Arg1=A, Arg2=B %>'), - '

A

B

' + $this->render('<% include SSViewerTestIncludeWithArguments Arg1=A, Arg2=B %>'), + '

A

B

' ); $this->assertEquals( - $this->render('<% include SSViewerTestIncludeWithArguments Arg1=A Bare String, Arg2=B Bare String %>'), - '

A Bare String

B Bare String

' + $this->render('<% include SSViewerTestIncludeWithArguments Arg1=A Bare String, Arg2=B Bare String %>'), + '

A Bare String

B Bare String

' ); $this->assertEquals( - $this->render( - '<% include SSViewerTestIncludeWithArguments Arg1="A", Arg2=$B %>', - new ArrayData(array('B' => 'Bar')) - ), - '

A

Bar

' + $this->render( + '<% include SSViewerTestIncludeWithArguments Arg1="A", Arg2=$B %>', + new ArrayData(array('B' => 'Bar')) + ), + '

A

Bar

' ); $this->assertEquals( - $this->render( - '<% include SSViewerTestIncludeWithArguments Arg1="A" %>', - new ArrayData(array('Arg1' => 'Foo', 'Arg2' => 'Bar')) - ), - '

A

Bar

' + $this->render( + '<% include SSViewerTestIncludeWithArguments Arg1="A" %>', + new ArrayData(array('Arg1' => 'Foo', 'Arg2' => 'Bar')) + ), + '

A

Bar

' ); $this->assertEquals( - $this->render( - '<% include SSViewerTestIncludeScopeInheritanceWithArgsInLoop Title="SomeArg" %>', - new ArrayData( - array('Items' => new ArrayList( - array( - new ArrayData(array('Title' => 'Foo')), - new ArrayData(array('Title' => 'Bar')) - ) - )) - ) - ), - 'SomeArg - Foo - Bar - SomeArg' - ); - - $this->assertEquals( - $this->render( - '<% include SSViewerTestIncludeScopeInheritanceWithArgsInWith Title="A" %>', - new ArrayData(array('Item' => new ArrayData(array('Title' =>'B')))) - ), - 'A - B - A' - ); - - $this->assertEquals( - $this->render( - '<% include SSViewerTestIncludeScopeInheritanceWithArgsInNestedWith Title="A" %>', - new ArrayData( + $this->render( + '<% include SSViewerTestIncludeScopeInheritanceWithArgsInLoop Title="SomeArg" %>', + new ArrayData( + array('Items' => new ArrayList( array( - 'Item' => new ArrayData( - array( - 'Title' =>'B', 'NestedItem' => new ArrayData(array('Title' => 'C')) - ) - )) - ) - ), - 'A - B - C - B - A' + new ArrayData(array('Title' => 'Foo')), + new ArrayData(array('Title' => 'Bar')) + ) + )) + ) + ), + 'SomeArg - Foo - Bar - SomeArg' ); $this->assertEquals( - $this->render( - '<% include SSViewerTestIncludeScopeInheritanceWithUpAndTop Title="A" %>', - new ArrayData( + $this->render( + '<% include SSViewerTestIncludeScopeInheritanceWithArgsInWith Title="A" %>', + new ArrayData(array('Item' => new ArrayData(array('Title' =>'B')))) + ), + 'A - B - A' + ); + + $this->assertEquals( + $this->render( + '<% include SSViewerTestIncludeScopeInheritanceWithArgsInNestedWith Title="A" %>', + new ArrayData( + array( + 'Item' => new ArrayData( array( - 'Item' => new ArrayData( - array( - 'Title' =>'B', 'NestedItem' => new ArrayData(array('Title' => 'C')) - ) - )) - ) - ), - 'A - A - A' + 'Title' =>'B', 'NestedItem' => new ArrayData(array('Title' => 'C')) + ) + )) + ) + ), + 'A - B - C - B - A' + ); + + $this->assertEquals( + $this->render( + '<% include SSViewerTestIncludeScopeInheritanceWithUpAndTop Title="A" %>', + new ArrayData( + array( + 'Item' => new ArrayData( + array( + 'Title' =>'B', 'NestedItem' => new ArrayData(array('Title' => 'C')) + ) + )) + ) + ), + 'A - A - A' ); $data = new ArrayData( + array( + 'Nested' => new ArrayData( array( - 'Nested' => new ArrayData( - array( - 'Object' => new ArrayData(array('Key' => 'A')) - ) - ), - 'Object' => new ArrayData(array('Key' => 'B')) + 'Object' => new ArrayData(array('Key' => 'A')) ) + ), + 'Object' => new ArrayData(array('Key' => 'B')) + ) ); $tmpl = SSViewer::fromString('<% include SSViewerTestIncludeObjectArguments A=$Nested.Object, B=$Object %>'); @@ -1041,15 +1069,15 @@ after' $data = new ArrayData([]); $this->assertEquals( - "tests:( NamespaceInclude\n )", - $this->render('tests:( <% include Namespace\NamespaceInclude %> )', $data), - 'Backslashes work for namespace references in includes' + "tests:( NamespaceInclude\n )", + $this->render('tests:( <% include Namespace\NamespaceInclude %> )', $data), + 'Backslashes work for namespace references in includes' ); $this->assertEquals( - "tests:( NamespaceInclude\n )", - $this->render('tests:( <% include Namespace/NamespaceInclude %> )', $data), - 'Forward slashes work for namespace references in includes' + "tests:( NamespaceInclude\n )", + $this->render('tests:( <% include Namespace/NamespaceInclude %> )', $data), + 'Forward slashes work for namespace references in includes' ); } @@ -1059,26 +1087,26 @@ after' $view = new SSViewer(array('Includes/SSViewerTestRecursiveInclude')); $data = new ArrayData( + array( + 'Title' => 'A', + 'Children' => new ArrayList( array( - 'Title' => 'A', - 'Children' => new ArrayList( + new ArrayData( array( - new ArrayData( + 'Title' => 'A1', + 'Children' => new ArrayList( array( - 'Title' => 'A1', - 'Children' => new ArrayList( - array( - new ArrayData(array( 'Title' => 'A1 i', )), - new ArrayData(array( 'Title' => 'A1 ii', )), - ) - ), + new ArrayData(array( 'Title' => 'A1 i', )), + new ArrayData(array( 'Title' => 'A1 ii', )), ) ), - new ArrayData(array( 'Title' => 'A2', )), - new ArrayData(array( 'Title' => 'A3', )), ) ), + new ArrayData(array( 'Title' => 'A2', )), + new ArrayData(array( 'Title' => 'A3', )), ) + ), + ) ); $result = $view->process($data); @@ -1106,68 +1134,68 @@ after' // Value casted as "Text" $this->assertEquals( - '<b>html</b>', - $t = SSViewer::fromString('$TextValue')->process($vd) + '<b>html</b>', + $t = SSViewer::fromString('$TextValue')->process($vd) ); $this->assertEquals( - 'html', - $t = SSViewer::fromString('$TextValue.RAW')->process($vd) + 'html', + $t = SSViewer::fromString('$TextValue.RAW')->process($vd) ); $this->assertEquals( - '<b>html</b>', - $t = SSViewer::fromString('$TextValue.XML')->process($vd) + '<b>html</b>', + $t = SSViewer::fromString('$TextValue.XML')->process($vd) ); // Value casted as "HTMLText" $this->assertEquals( - 'html', - $t = SSViewer::fromString('$HTMLValue')->process($vd) + 'html', + $t = SSViewer::fromString('$HTMLValue')->process($vd) ); $this->assertEquals( - 'html', - $t = SSViewer::fromString('$HTMLValue.RAW')->process($vd) + 'html', + $t = SSViewer::fromString('$HTMLValue.RAW')->process($vd) ); $this->assertEquals( - '<b>html</b>', - $t = SSViewer::fromString('$HTMLValue.XML')->process($vd) + '<b>html</b>', + $t = SSViewer::fromString('$HTMLValue.XML')->process($vd) ); // Uncasted value (falls back to ViewableData::$default_cast="Text") $vd = new SSViewerTest\TestViewableData(); $vd->UncastedValue = 'html'; $this->assertEquals( - '<b>html</b>', - $t = SSViewer::fromString('$UncastedValue')->process($vd) + '<b>html</b>', + $t = SSViewer::fromString('$UncastedValue')->process($vd) ); $this->assertEquals( - 'html', - $t = SSViewer::fromString('$UncastedValue.RAW')->process($vd) + 'html', + $t = SSViewer::fromString('$UncastedValue.RAW')->process($vd) ); $this->assertEquals( - '<b>html</b>', - $t = SSViewer::fromString('$UncastedValue.XML')->process($vd) + '<b>html</b>', + $t = SSViewer::fromString('$UncastedValue.XML')->process($vd) ); } public function testSSViewerBasicIteratorSupport() { $data = new ArrayData( + array( + 'Set' => new ArrayList( array( - 'Set' => new ArrayList( - array( - new SSViewerTest\TestObject("1"), - new SSViewerTest\TestObject("2"), - new SSViewerTest\TestObject("3"), - new SSViewerTest\TestObject("4"), - new SSViewerTest\TestObject("5"), - new SSViewerTest\TestObject("6"), - new SSViewerTest\TestObject("7"), - new SSViewerTest\TestObject("8"), - new SSViewerTest\TestObject("9"), - new SSViewerTest\TestObject("10"), - ) - ) + new SSViewerTest\TestObject("1"), + new SSViewerTest\TestObject("2"), + new SSViewerTest\TestObject("3"), + new SSViewerTest\TestObject("4"), + new SSViewerTest\TestObject("5"), + new SSViewerTest\TestObject("6"), + new SSViewerTest\TestObject("7"), + new SSViewerTest\TestObject("8"), + new SSViewerTest\TestObject("9"), + new SSViewerTest\TestObject("10"), ) + ) + ) ); //base test @@ -1212,22 +1240,22 @@ after' //test MiddleString $result = $this->render( - '<% loop Set %><% if MiddleString == "middle" %>$Number$MiddleString<% end_if %>' - . '<% end_loop %>', - $data + '<% loop Set %><% if MiddleString == "middle" %>$Number$MiddleString<% end_if %>' + . '<% end_loop %>', + $data ); $this->assertEquals( - "2middle3middle4middle5middle6middle7middle8middle9middle", - $result, - "Middle numbers rendered in order" + "2middle3middle4middle5middle6middle7middle8middle9middle", + $result, + "Middle numbers rendered in order" ); //test EvenOdd $result = $this->render('<% loop Set %>$EvenOdd<% end_loop %>', $data); $this->assertEquals( - "oddevenoddevenoddevenoddevenoddeven", - $result, - "Even and Odd is returned in sequence numbers rendered in order" + "oddevenoddevenoddevenoddevenoddeven", + $result, + "Even and Odd is returned in sequence numbers rendered in order" ); //test Pos @@ -1273,9 +1301,9 @@ after' //test MultipleOf 9 zero-based $result = $this->render('<% loop Set %><% if MultipleOf(9,0) %>$Number<% end_if %><% end_loop %>', $data); $this->assertEquals( - "110", - $result, - "Only numbers that are multiples of 9 with zero-based indexing are returned. (The first and last item)" + "110", + $result, + "Only numbers that are multiples of 9 with zero-based indexing are returned. (The first and last item)" ); //test MultipleOf 11 @@ -1291,83 +1319,83 @@ after' // Data to run the loop tests on - three levels deep $data = new ArrayData( + array( + 'Name' => 'Top', + 'Foo' => new ArrayData( array( - 'Name' => 'Top', - 'Foo' => new ArrayData( + 'Name' => 'Foo', + 'Bar' => new ArrayData( array( - 'Name' => 'Foo', - 'Bar' => new ArrayData( + 'Name' => 'Bar', + 'Baz' => new ArrayData( array( - 'Name' => 'Bar', - 'Baz' => new ArrayData( - array( - 'Name' => 'Baz' - ) - ), - 'Qux' => new ArrayData( - array( - 'Name' => 'Qux' - ) + 'Name' => 'Baz' ) + ), + 'Qux' => new ArrayData( + array( + 'Name' => 'Qux' ) ) ) ) ) + ) + ) ); // Basic functionality $this->assertEquals( - 'BarFoo', - $this->render('<% with Foo %><% with Bar %>{$Name}{$Up.Name}<% end_with %><% end_with %>', $data) + 'BarFoo', + $this->render('<% with Foo %><% with Bar %>{$Name}{$Up.Name}<% end_with %><% end_with %>', $data) ); // Two level with block, up refers to internally referenced Bar $this->assertEquals( - 'BarFoo', - $this->render('<% with Foo.Bar %>{$Name}{$Up.Name}<% end_with %>', $data) + 'BarFoo', + $this->render('<% with Foo.Bar %>{$Name}{$Up.Name}<% end_with %>', $data) ); // Stepping up & back down the scope tree $this->assertEquals( - 'BazBarQux', - $this->render('<% with Foo.Bar.Baz %>{$Name}{$Up.Name}{$Up.Qux.Name}<% end_with %>', $data) + 'BazBarQux', + $this->render('<% with Foo.Bar.Baz %>{$Name}{$Up.Name}{$Up.Qux.Name}<% end_with %>', $data) ); // Using $Up in a with block $this->assertEquals( - 'BazBarQux', - $this->render( - '<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}{$Qux.Name}<% end_with %>' - .'<% end_with %>', - $data - ) + 'BazBarQux', + $this->render( + '<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}{$Qux.Name}<% end_with %>' + .'<% end_with %>', + $data + ) ); // Stepping up & back down the scope tree with with blocks $this->assertEquals( - 'BazBarQuxBarBaz', - $this->render( - '<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}<% with Qux %>{$Name}<% end_with %>' - . '{$Name}<% end_with %>{$Name}<% end_with %>', - $data - ) + 'BazBarQuxBarBaz', + $this->render( + '<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}<% with Qux %>{$Name}<% end_with %>' + . '{$Name}<% end_with %>{$Name}<% end_with %>', + $data + ) ); // Using $Up.Up, where first $Up points to a previous scope entered using $Up, thereby skipping up to Foo $this->assertEquals( - 'Foo', - $this->render( - '<% with Foo.Bar.Baz %><% with Up %><% with Qux %>{$Up.Up.Name}<% end_with %><% end_with %>' - . '<% end_with %>', - $data - ) + 'Foo', + $this->render( + '<% with Foo.Bar.Baz %><% with Up %><% with Qux %>{$Up.Up.Name}<% end_with %><% end_with %>' + . '<% end_with %>', + $data + ) ); // Using $Up.Up, where first $Up points to an Up used in a local scope lookup, should still skip to Foo $this->assertEquals( - 'Foo', - $this->render('<% with Foo.Bar.Baz.Up.Qux %>{$Up.Up.Name}<% end_with %>', $data) + 'Foo', + $this->render('<% with Foo.Bar.Baz.Up.Qux %>{$Up.Up.Name}<% end_with %>', $data) ); } @@ -1379,60 +1407,60 @@ after' // Data to run the loop tests on - one sequence of three items, each with a subitem $data = new ArrayData( + array( + 'Name' => 'Top', + 'Foo' => new ArrayList( array( - 'Name' => 'Top', - 'Foo' => new ArrayList( + new ArrayData( array( - new ArrayData( + 'Name' => '1', + 'Sub' => new ArrayData( array( - 'Name' => '1', - 'Sub' => new ArrayData( - array( - 'Name' => 'Bar' - ) + 'Name' => 'Bar' ) - ) - ), - new ArrayData( + ) + ) + ), + new ArrayData( + array( + 'Name' => '2', + 'Sub' => new ArrayData( array( - 'Name' => '2', - 'Sub' => new ArrayData( - array( - 'Name' => 'Baz' - ) + 'Name' => 'Baz' ) - ) - ), - new ArrayData( + ) + ) + ), + new ArrayData( + array( + 'Name' => '3', + 'Sub' => new ArrayData( array( - 'Name' => '3', - 'Sub' => new ArrayData( - array( - 'Name' => 'Qux' - ) - ) + 'Name' => 'Qux' ) ) ) ) ) + ) + ) ); // Make sure inside a loop, $Up refers to the current item of the loop $this->assertEqualIgnoringWhitespace( - '111 222 333', - $this->render( - '<% loop $Foo %>$Name<% with $Sub %>$Up.Name<% end_with %>$Name<% end_loop %>', - $data - ) + '111 222 333', + $this->render( + '<% loop $Foo %>$Name<% with $Sub %>$Up.Name<% end_with %>$Name<% end_loop %>', + $data + ) ); // Make sure inside a loop, looping over $Up uses a separate iterator, // and doesn't interfere with the original iterator $this->assertEqualIgnoringWhitespace( - '1Bar123Bar1 2Baz123Baz2 3Qux123Qux3', - $this->render( - '<% loop $Foo %> + '1Bar123Bar1 2Baz123Baz2 3Qux123Qux3', + $this->render( + '<% loop $Foo %> $Name <% with $Sub %> $Name @@ -1441,16 +1469,16 @@ after' <% end_with %> $Name <% end_loop %>', - $data - ) + $data + ) ); // Make sure inside a loop, looping over $Up uses a separate iterator, // and doesn't interfere with the original iterator or local lookups $this->assertEqualIgnoringWhitespace( - '1 Bar1 123 1Bar 1 2 Baz2 123 2Baz 2 3 Qux3 123 3Qux 3', - $this->render( - '<% loop $Foo %> + '1 Bar1 123 1Bar 1 2 Baz2 123 2Baz 2 3 Qux3 123 3Qux 3', + $this->render( + '<% loop $Foo %> $Name <% with $Sub %> {$Name}{$Up.Name} @@ -1459,8 +1487,8 @@ after' <% end_with %> $Name <% end_loop %>', - $data - ) + $data + ) ); } @@ -1473,69 +1501,69 @@ after' // Data to run the loop tests on - one sequence of three items, one with child elements // (of a different size to the main sequence) $data = new ArrayData( + array( + 'Foo' => new ArrayList( array( - 'Foo' => new ArrayList( + new ArrayData( array( - new ArrayData( + 'Name' => '1', + 'Children' => new ArrayList( array( - 'Name' => '1', - 'Children' => new ArrayList( + new ArrayData( array( - new ArrayData( - array( - 'Name' => 'a' - ) - ), - new ArrayData( - array( - 'Name' => 'b' - ) - ), + 'Name' => 'a' + ) + ), + new ArrayData( + array( + 'Name' => 'b' ) ), ) ), - new ArrayData( - array( - 'Name' => '2', - 'Children' => new ArrayList(), - ) - ), - new ArrayData( - array( - 'Name' => '3', - 'Children' => new ArrayList(), - ) - ), + ) + ), + new ArrayData( + array( + 'Name' => '2', + 'Children' => new ArrayList(), + ) + ), + new ArrayData( + array( + 'Name' => '3', + 'Children' => new ArrayList(), ) ), ) + ), + ) ); // Make sure that including a loop inside a loop will not destroy the internal count of // items, checked by using "Last" $this->assertEqualIgnoringWhitespace( - '1ab23last', - $this->render( - '<% loop $Foo %>$Name<% loop Children %>$Name<% end_loop %><% if Last %>last<% end_if %>' - . '<% end_loop %>', - $data - ) + '1ab23last', + $this->render( + '<% loop $Foo %>$Name<% loop Children %>$Name<% end_loop %><% if Last %>last<% end_if %>' + . '<% end_loop %>', + $data + ) ); } public function testLayout() { $this->useTestTheme( - __DIR__.'/SSViewerTest', - 'layouttest', - function () { - $template = new SSViewer(array('Page')); - $this->assertEquals("Foo\n\n", $template->process(new ArrayData(array()))); + __DIR__.'/SSViewerTest', + 'layouttest', + function () { + $template = new SSViewer(array('Page')); + $this->assertEquals("Foo\n\n", $template->process(new ArrayData(array()))); - $template = new SSViewer(array('Shortcodes', 'Page')); - $this->assertEquals("[file_link]\n\n", $template->process(new ArrayData(array()))); - } + $template = new SSViewer(array('Shortcodes', 'Page')); + $this->assertEquals("[file_link]\n\n", $template->process(new ArrayData(array()))); + } ); } @@ -1545,76 +1573,76 @@ after' public function testGetTemplatesByClass() { $this->useTestTheme( - __DIR__ . '/SSViewerTest', - 'layouttest', - function () { - // Test passing a string - $templates = SSViewer::get_templates_by_class( + __DIR__ . '/SSViewerTest', + 'layouttest', + function () { + // Test passing a string + $templates = SSViewer::get_templates_by_class( + SSViewerTestModelController::class, + '', + Controller::class + ); + $this->assertEquals( + [ SSViewerTestModelController::class, - '', - Controller::class - ); - $this->assertEquals( [ + 'type' => 'Includes', SSViewerTestModelController::class, - [ - 'type' => 'Includes', - SSViewerTestModelController::class, - ], - SSViewerTestModel::class, - Controller::class, - [ - 'type' => 'Includes', - Controller::class, - ], ], - $templates - ); - - // Test to ensure we're stopping at the base class. - $templates = SSViewer::get_templates_by_class( - SSViewerTestModelController::class, - '', - SSViewerTestModelController::class - ); - $this->assertEquals( - [ - SSViewerTestModelController::class, - [ - 'type' => 'Includes', - SSViewerTestModelController::class, - ], - SSViewerTestModel::class, - ], - $templates - ); - - // Make sure we can search templates by suffix. - $templates = SSViewer::get_templates_by_class( SSViewerTestModel::class, - 'Controller', - DataObject::class - ); - $this->assertEquals( + Controller::class, [ - SSViewerTestModelController::class, - [ - 'type' => 'Includes', - SSViewerTestModelController::class, - ], - DataObject::class . 'Controller', - [ - 'type' => 'Includes', - DataObject::class . 'Controller', - ], + 'type' => 'Includes', + Controller::class, ], - $templates - ); + ], + $templates + ); - // Let's throw something random in there. - $this->setExpectedException('InvalidArgumentException'); - SSViewer::get_templates_by_class(array()); - } + // Test to ensure we're stopping at the base class. + $templates = SSViewer::get_templates_by_class( + SSViewerTestModelController::class, + '', + SSViewerTestModelController::class + ); + $this->assertEquals( + [ + SSViewerTestModelController::class, + [ + 'type' => 'Includes', + SSViewerTestModelController::class, + ], + SSViewerTestModel::class, + ], + $templates + ); + + // Make sure we can search templates by suffix. + $templates = SSViewer::get_templates_by_class( + SSViewerTestModel::class, + 'Controller', + DataObject::class + ); + $this->assertEquals( + [ + SSViewerTestModelController::class, + [ + 'type' => 'Includes', + SSViewerTestModelController::class, + ], + DataObject::class . 'Controller', + [ + 'type' => 'Includes', + DataObject::class . 'Controller', + ], + ], + $templates + ); + + // Let's throw something random in there. + $this->setExpectedException('InvalidArgumentException'); + SSViewer::get_templates_by_class(array()); + } ); } @@ -1634,8 +1662,8 @@ after' // Note: SSViewer_FromString doesn't rewrite hash links. file_put_contents( - $tmplFile, - ' + $tmplFile, + ' <% base_tag %> @@ -1650,34 +1678,34 @@ after' $tmpl = new SSViewer($tmplFile); $obj = new ViewableData(); $obj->InsertedLink = DBField::create_field( - 'HTMLFragment', - 'InsertedLink' + 'HTMLFragment', + 'InsertedLink' ); $obj->ExternalInsertedLink = DBField::create_field( - 'HTMLFragment', - 'ExternalInsertedLink' + 'HTMLFragment', + 'ExternalInsertedLink' ); $result = $tmpl->process($obj); $this->assertContains( - 'InsertedLink', - $result + 'InsertedLink', + $result ); $this->assertContains( - 'ExternalInsertedLink', - $result + 'ExternalInsertedLink', + $result ); $this->assertContains( - 'InlineLink', - $result + 'InlineLink', + $result ); $this->assertContains( - 'ExternalInlineLink', - $result + 'ExternalInlineLink', + $result ); $this->assertContains( - '', - $result, - 'SSTemplateParser should only rewrite anchor hrefs' + '', + $result, + 'SSTemplateParser should only rewrite anchor hrefs' ); unlink($tmplFile); @@ -1691,8 +1719,8 @@ after' // Note: SSViewer_FromString doesn't rewrite hash links. file_put_contents( - $tmplFile, - ' + $tmplFile, + ' <% base_tag %> @@ -1705,8 +1733,8 @@ after' $tmpl = new SSViewer($tmplFile); $obj = new ViewableData(); $obj->InsertedLink = DBField::create_field( - 'HTMLFragment', - 'InsertedLink' + 'HTMLFragment', + 'InsertedLink' ); $result = $tmpl->process($obj); @@ -1720,9 +1748,9 @@ EOC; // $result // ); $this->assertContains( - '', - $result, - 'SSTemplateParser should only rewrite anchor hrefs' + '', + $result, + 'SSTemplateParser should only rewrite anchor hrefs' ); unlink($tmplFile); @@ -1735,82 +1763,82 @@ EOC; $i = __DIR__ . '/SSViewerTest/templates/Includes'; $f = __DIR__ . '/SSViewerTest/templates/SSViewerTestComments'; $templates = array( - array( - 'name' => 'SSViewerTestCommentsFullSource', - 'expected' => "" - . "" - . "" - . "" - . "\t" - . "\t" - . "" - . "", - ), - array( - 'name' => 'SSViewerTestCommentsFullSourceHTML4Doctype', - 'expected' => "" - . "" - . "" - . "" - . "\t" - . "\t" - . "" - . "", - ), - array( - 'name' => 'SSViewerTestCommentsFullSourceNoDoctype', - 'expected' => "" - . "" - . "\t" - . "\t" - . "", - ), - array( - 'name' => 'SSViewerTestCommentsFullSourceIfIE', - 'expected' => "" - . "" - . "" - . "" - . "" - . " " - . "\t" - . "\t" - . "" - . "", - ), - array( - 'name' => 'SSViewerTestCommentsFullSourceIfIENoDoctype', - 'expected' => "" - . "" - . "" - . " " - . "" - . " " - . "\t" - . "\t" - . "", - ), - array( - 'name' => 'SSViewerTestCommentsPartialSource', - 'expected' => - "" - . "
" - . "", - ), - array( - 'name' => 'SSViewerTestCommentsWithInclude', - 'expected' => - "" - . "
" - . "" - . "" - . "Included" - . "" - . "" - . "
" - . "", - ), + array( + 'name' => 'SSViewerTestCommentsFullSource', + 'expected' => "" + . "" + . "" + . "" + . "\t" + . "\t" + . "" + . "", + ), + array( + 'name' => 'SSViewerTestCommentsFullSourceHTML4Doctype', + 'expected' => "" + . "" + . "" + . "" + . "\t" + . "\t" + . "" + . "", + ), + array( + 'name' => 'SSViewerTestCommentsFullSourceNoDoctype', + 'expected' => "" + . "" + . "\t" + . "\t" + . "", + ), + array( + 'name' => 'SSViewerTestCommentsFullSourceIfIE', + 'expected' => "" + . "" + . "" + . "" + . "" + . " " + . "\t" + . "\t" + . "" + . "", + ), + array( + 'name' => 'SSViewerTestCommentsFullSourceIfIENoDoctype', + 'expected' => "" + . "" + . "" + . " " + . "" + . " " + . "\t" + . "\t" + . "", + ), + array( + 'name' => 'SSViewerTestCommentsPartialSource', + 'expected' => + "" + . "
" + . "", + ), + array( + 'name' => 'SSViewerTestCommentsWithInclude', + 'expected' => + "" + . "
" + . "" + . "" + . "Included" + . "" + . "" + . "
" + . "", + ), ); foreach ($templates as $template) { $this->_renderWithSourceFileComments('SSViewerTestComments/'.$template['name'], $template['expected']); @@ -1842,11 +1870,11 @@ EOC; $backend = Injector::inst()->create(Requirements_Backend::class); $backend->setCombinedFilesEnabled(false); $backend->combineFiles( - 'RequirementsTest_ab.css', - array( - $basePath . '/css/RequirementsTest_a.css', - $basePath . '/css/RequirementsTest_b.css' - ) + 'RequirementsTest_ab.css', + array( + $basePath . '/css/RequirementsTest_a.css', + $basePath . '/css/RequirementsTest_b.css' + ) ); Requirements::set_backend($backend); @@ -1869,16 +1897,16 @@ EOC; Requirements::set_suffix_requirements(false); $this->assertEquals( - 1, - substr_count( - $template->process(array()), - "tests/php/View/SSViewerTest/javascript/RequirementsTest_a.js" - ) + 1, + substr_count( + $template->process(array()), + "tests/php/View/SSViewerTest/javascript/RequirementsTest_a.js" + ) ); } else { $this->markTestSkipped( - 'Requirement will always fail if the framework dir is not '. - 'named \'framework\', since templates require hard coded paths' + 'Requirement will always fail if the framework dir is not '. + 'named \'framework\', since templates require hard coded paths' ); } } @@ -1886,38 +1914,38 @@ EOC; public function testCallsWithArguments() { $data = new ArrayData( + array( + 'Set' => new ArrayList( array( - 'Set' => new ArrayList( - array( - new SSViewerTest\TestObject("1"), - new SSViewerTest\TestObject("2"), - new SSViewerTest\TestObject("3"), - new SSViewerTest\TestObject("4"), - new SSViewerTest\TestObject("5"), - ) - ), - 'Level' => new SSViewerTest\LevelTestData(1), - 'Nest' => array( - 'Level' => new SSViewerTest\LevelTestData(2), - ), + new SSViewerTest\TestObject("1"), + new SSViewerTest\TestObject("2"), + new SSViewerTest\TestObject("3"), + new SSViewerTest\TestObject("4"), + new SSViewerTest\TestObject("5"), ) + ), + 'Level' => new SSViewerTest\LevelTestData(1), + 'Nest' => array( + 'Level' => new SSViewerTest\LevelTestData(2), + ), + ) ); $tests = array( - '$Level.output(1)' => '1-1', - '$Nest.Level.output($Set.First.Number)' => '2-1', - '<% with $Set %>$Up.Level.output($First.Number)<% end_with %>' => '1-1', - '<% with $Set %>$Top.Nest.Level.output($First.Number)<% end_with %>' => '2-1', - '<% loop $Set %>$Up.Nest.Level.output($Number)<% end_loop %>' => '2-12-22-32-42-5', - '<% loop $Set %>$Top.Level.output($Number)<% end_loop %>' => '1-11-21-31-41-5', - '<% with $Nest %>$Level.output($Top.Set.First.Number)<% end_with %>' => '2-1', - '<% with $Level %>$output($Up.Set.Last.Number)<% end_with %>' => '1-5', - '<% with $Level.forWith($Set.Last.Number) %>$output("hi")<% end_with %>' => '5-hi', - '<% loop $Level.forLoop($Set.First.Number) %>$Number<% end_loop %>' => '!0', - '<% with $Nest %> + '$Level.output(1)' => '1-1', + '$Nest.Level.output($Set.First.Number)' => '2-1', + '<% with $Set %>$Up.Level.output($First.Number)<% end_with %>' => '1-1', + '<% with $Set %>$Top.Nest.Level.output($First.Number)<% end_with %>' => '2-1', + '<% loop $Set %>$Up.Nest.Level.output($Number)<% end_loop %>' => '2-12-22-32-42-5', + '<% loop $Set %>$Top.Level.output($Number)<% end_loop %>' => '1-11-21-31-41-5', + '<% with $Nest %>$Level.output($Top.Set.First.Number)<% end_with %>' => '2-1', + '<% with $Level %>$output($Up.Set.Last.Number)<% end_with %>' => '1-5', + '<% with $Level.forWith($Set.Last.Number) %>$output("hi")<% end_with %>' => '5-hi', + '<% loop $Level.forLoop($Set.First.Number) %>$Number<% end_loop %>' => '!0', + '<% with $Nest %> <% with $Level.forWith($Up.Set.First.Number) %>$output("hi")<% end_with %> <% end_with %>' => '1-hi', - '<% with $Nest %> + '<% with $Nest %> <% loop $Level.forLoop($Top.Set.Last.Number) %>$Number<% end_loop %> <% end_with %>' => '!0!1!2!3!4', ); @@ -1941,9 +1969,9 @@ EOC; $this->assertEquals('HiHi', preg_replace('/\s+/', '', $this->render($template, $data))); $this->assertEquals( - 1, - $data->testWithCalls, - 'SSViewerTest_CacheTestData::TestWithCall() should only be called once. Subsequent calls should be cached' + 1, + $data->testWithCalls, + 'SSViewerTest_CacheTestData::TestWithCall() should only be called once. Subsequent calls should be cached' ); $data = new SSViewerTest\CacheTestData(); @@ -1956,9 +1984,9 @@ EOC; $this->assertEquals('OneTwo', preg_replace('/\s+/', '', $this->render($template, $data))); $this->assertEquals( - 1, - $data->testLoopCalls, - 'SSViewerTest_CacheTestData::TestLoopCall() should only be called once. Subsequent calls should be cached' + 1, + $data->testLoopCalls, + 'SSViewerTest_CacheTestData::TestLoopCall() should only be called once. Subsequent calls should be cached' ); } @@ -1967,10 +1995,10 @@ EOC; $count = 0; $parser = new SSTemplateParser(); $parser->addClosedBlock( - 'test', - function ($res) use (&$count) { - $count++; - } + 'test', + function ($res) use (&$count) { + $count++; + } ); $template = new SSViewer_FromString("<% test %><% end_test %>", $parser); @@ -1984,10 +2012,10 @@ EOC; $count = 0; $parser = new SSTemplateParser(); $parser->addOpenBlock( - 'test', - function ($res) use (&$count) { - $count++; - } + 'test', + function ($res) use (&$count) { + $count++; + } ); $template = new SSViewer_FromString("<% test %>", $parser); diff --git a/thirdparty/jsmin/.piston.yml b/thirdparty/jsmin/.piston.yml deleted file mode 100644 index 2ffe105da..000000000 --- a/thirdparty/jsmin/.piston.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -format: 1 -handler: - commit: e71eac35ce7a0f191d199be9e35a8d12f1f999fd - branch: master -lock: false -repository_class: Piston::Git::Repository -repository_url: https://github.com/rgrove/jsmin-php/ diff --git a/thirdparty/jsmin/jsmin.php b/thirdparty/jsmin/jsmin.php deleted file mode 100644 index 121d0612b..000000000 --- a/thirdparty/jsmin/jsmin.php +++ /dev/null @@ -1,325 +0,0 @@ - - * @copyright 2002 Douglas Crockford (jsmin.c) - * @copyright 2008 Ryan Grove (PHP port) - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 1.1.1 (2008-03-02) - * @link http://code.google.com/p/jsmin-php/ - */ - -class JSMin { - const ORD_LF = 10; - const ORD_SPACE = 32; - - protected $a = ''; - protected $b = ''; - protected $input = ''; - protected $inputIndex = 0; - protected $inputLength = 0; - protected $lookAhead = null; - protected $output = ''; - - // -- Public Static Methods -------------------------------------------------- - - public static function minify($js) { - $jsmin = new JSMin($js); - return $jsmin->min(); - } - - // -- Public Instance Methods ------------------------------------------------ - - public function __construct($input) { - $this->input = str_replace("\r\n", "\n", $input); - $this->inputLength = strlen($this->input); - } - - // -- Protected Instance Methods --------------------------------------------- - - - - /* action -- do something! What you do is determined by the argument: - 1 Output A. Copy B to A. Get the next B. - 2 Copy B to A. Get the next B. (Delete A). - 3 Get the next B. (Delete B). - action treats a string as a single character. Wow! - action recognizes a regular expression if it is preceded by ( or , or =. - */ - protected function action($d) { - switch($d) { - case 1: - $this->output .= $this->a; - - case 2: - $this->a = $this->b; - - if ($this->a === "'" || $this->a === '"') { - for (;;) { - $this->output .= $this->a; - $this->a = $this->get(); - - if ($this->a === $this->b) { - break; - } - - if (ord($this->a) <= self::ORD_LF) { - throw new JSMinException('Unterminated string literal.'); - } - - if ($this->a === '\\') { - $this->output .= $this->a; - $this->a = $this->get(); - } - } - } - - case 3: - $this->b = $this->next(); - - if ($this->b === '/' && ( - $this->a === '(' || $this->a === ',' || $this->a === '=' || - $this->a === ':' || $this->a === '[' || $this->a === '!' || - $this->a === '&' || $this->a === '|' || $this->a === '?' || - $this->a === '{' || $this->a === '}' || $this->a === ';' || - $this->a === "\n" )) { - - $this->output .= $this->a . $this->b; - - for (;;) { - $this->a = $this->get(); - - if ($this->a === '[') { - /* - inside a regex [...] set, which MAY contain a '/' itself. Example: mootools Form.Validator near line 460: - return Form.Validator.getValidator('IsEmpty').test(element) || (/^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]\.?){0,63}[a-z0-9!#$%&'*+/=?^_`{|}~-]@(?:(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])$/i).test(element.get('value')); - */ - for (;;) { - $this->output .= $this->a; - $this->a = $this->get(); - - if ($this->a === ']') { - break; - } elseif ($this->a === '\\') { - $this->output .= $this->a; - $this->a = $this->get(); - } elseif (ord($this->a) <= self::ORD_LF) { - throw new JSMinException('Unterminated regular expression set in regex literal.'); - } - } - } elseif ($this->a === '/') { - break; - } elseif ($this->a === '\\') { - $this->output .= $this->a; - $this->a = $this->get(); - } elseif (ord($this->a) <= self::ORD_LF) { - throw new JSMinException('Unterminated regular expression literal.'); - } - - $this->output .= $this->a; - } - - $this->b = $this->next(); - } - } - } - - protected function get() { - $c = $this->lookAhead; - $this->lookAhead = null; - - if ($c === null) { - if ($this->inputIndex < $this->inputLength) { - $c = substr($this->input, $this->inputIndex, 1); - $this->inputIndex += 1; - } else { - $c = null; - } - } - - if ($c === "\r") { - return "\n"; - } - - if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) { - return $c; - } - - return ' '; - } - - /* isAlphanum -- return true if the character is a letter, digit, underscore, - dollar sign, or non-ASCII character. - */ - protected function isAlphaNum($c) { - return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1; - } - - protected function min() { - $this->a = "\n"; - $this->action(3); - - while ($this->a !== null) { - switch ($this->a) { - case ' ': - if ($this->isAlphaNum($this->b)) { - $this->action(1); - } else { - $this->action(2); - } - break; - - case "\n": - switch ($this->b) { - case '{': - case '[': - case '(': - case '+': - case '-': - $this->action(1); - break; - - case ' ': - $this->action(3); - break; - - default: - if ($this->isAlphaNum($this->b)) { - $this->action(1); - } - else { - $this->action(2); - } - } - break; - - default: - switch ($this->b) { - case ' ': - if ($this->isAlphaNum($this->a)) { - $this->action(1); - break; - } - - $this->action(3); - break; - - case "\n": - switch ($this->a) { - case '}': - case ']': - case ')': - case '+': - case '-': - case '"': - case "'": - $this->action(1); - break; - - default: - if ($this->isAlphaNum($this->a)) { - $this->action(1); - } - else { - $this->action(3); - } - } - break; - - default: - $this->action(1); - break; - } - } - } - - return $this->output; - } - - /* next -- get the next character, excluding comments. peek() is used to see - if a '/' is followed by a '/' or '*'. - */ - protected function next() { - $c = $this->get(); - - if ($c === '/') { - switch($this->peek()) { - case '/': - for (;;) { - $c = $this->get(); - - if (ord($c) <= self::ORD_LF) { - return $c; - } - } - - case '*': - $this->get(); - - for (;;) { - switch($this->get()) { - case '*': - if ($this->peek() === '/') { - $this->get(); - return ' '; - } - break; - - case null: - throw new JSMinException('Unterminated comment.'); - } - } - - default: - return $c; - } - } - - return $c; - } - - protected function peek() { - $this->lookAhead = $this->get(); - return $this->lookAhead; - } -} - -// -- Exceptions --------------------------------------------------------------- -class JSMinException extends Exception {} -?>