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/Requirements_Backend.php b/src/View/Requirements_Backend.php
index 78f642ca7..f41ef33c3 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,26 @@ class Requirements_Backend
$this->assetHandler = $handler;
}
+ /**
+ * Gets the minification service for this backend
+ *
+ * @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 +365,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 +1303,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 +1325,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/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..a3403719e 100644
--- a/tests/php/View/SSViewerTest.php
+++ b/tests/php/View/SSViewerTest.php
@@ -20,6 +20,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,10 +29,9 @@ 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
+classSSViewerTest extends SapphireTest
{
/**
@@ -39,148 +39,148 @@ class SSViewerTest extends SapphireTest
*
* @var array
*/
- protected $oldServer = array();
+protected $oldServer = array();
- protected static $extra_dataobjects = array(
+protected static $extra_dataobjects = array(
SSViewerTest\TestObject::class,
);
- protected function setUp()
- {
- parent::setUp();
- SSViewer::config()->update('source_file_comments', false);
- SSViewer_FromString::config()->update('cache_template', false);
- TestAssetStore::activate('SSViewerTest');
- $this->oldServer = $_SERVER;
- }
+protected function setUp()
+{
+ parent::setUp();
+ SSViewer::config()->update('source_file_comments', false);
+ SSViewer_FromString::config()->update('cache_template', false);
+ TestAssetStore::activate('SSViewerTest');
+ $this->oldServer = $_SERVER;
+}
- protected function tearDown()
- {
- $_SERVER = $this->oldServer;
- TestAssetStore::reset();
- parent::tearDown();
- }
+protected function tearDown()
+{
+ $_SERVER = $this->oldServer;
+ TestAssetStore::reset();
+ parent::tearDown();
+}
/**
* Tests for {@link Config::inst()->get('SSViewer', 'theme')} for different behaviour
* of user defined themes via {@link SiteConfig} and default theme
* when no user themes are defined.
*/
- public function testCurrentTheme()
- {
- SSViewer::config()->update('theme', 'mytheme');
- $this->assertEquals(
- 'mytheme',
- SSViewer::config()->uninherited('theme'),
- 'Current theme is the default - user has not defined one'
- );
- }
+public function testCurrentTheme()
+{
+ SSViewer::config()->update('theme', 'mytheme');
+ $this->assertEquals(
+ 'mytheme',
+ SSViewer::config()->uninherited('theme'),
+ 'Current theme is the default - user has not defined one'
+ );
+}
/**
* Test that a template without a tag still renders.
*/
- public function testTemplateWithoutHeadRenders()
- {
- $data = new ArrayData(
+public function testTemplateWithoutHeadRenders()
+{
+ $data = new ArrayData(
+ array(
+ 'Var' => 'var value'
+ )
+ );
+
+ $result = $data->renderWith("SSViewerTestPartialTemplate");
+ $this->assertEquals('Test partial template: var value', trim(preg_replace("//U", '', $result)));
+}
+
+public function testIncludeScopeInheritance()
+{
+ $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',
+ );
+
+ $result = $data->renderWith('SSViewerTestIncludeScopeInheritance');
+ $this->assertExpectedStrings($result, $expected);
+
+ // 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',
+ );
+
+ $result = $data->renderWith('SSViewerTestIncludeScopeInheritanceWithArgs');
+ $this->assertExpectedStrings($result, $expected);
+}
+
+public function testIncludeTruthyness()
+{
+ $data = new ArrayData(
+ array(
+ 'Title' => 'TruthyTest',
+ 'Items' => new ArrayList(
array(
- 'Var' => 'var value'
+ 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');
- $result = $data->renderWith("SSViewerTestPartialTemplate");
- $this->assertEquals('Test partial template: var value', trim(preg_replace("//U", '', $result)));
- }
+ // 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'
+ );
+ $this->assertExpectedStrings($result, $expected);
+}
- public function testIncludeScopeInheritance()
- {
- $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',
- );
-
- $result = $data->renderWith('SSViewerTestIncludeScopeInheritance');
- $this->assertExpectedStrings($result, $expected);
-
- // 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',
- );
-
- $result = $data->renderWith('SSViewerTestIncludeScopeInheritanceWithArgs');
- $this->assertExpectedStrings($result, $expected);
- }
-
- public function testIncludeTruthyness()
- {
- $data = new ArrayData(
+private function getScopeInheritanceTestData()
+{
+ return new ArrayData(
+ array(
+ 'Title' => 'TopTitleValue',
+ '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' => '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'))
)
- )
- );
- $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'
- );
- $this->assertExpectedStrings($result, $expected);
- }
-
- private function getScopeInheritanceTestData()
- {
- return new ArrayData(
- 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'))
- )
- )
- )
+private function assertExpectedStrings($result, $expected)
+{
+ foreach ($expected as $expectedStr) {
+ $this->assertTrue(
+ (boolean) preg_match("/{$expectedStr}/", $result),
+ "Didn't find '{$expectedStr}' in:\n{$result}"
);
}
-
- private function assertExpectedStrings($result, $expected)
- {
- foreach ($expected as $expectedStr) {
- $this->assertTrue(
- (boolean) preg_match("/{$expectedStr}/", $result),
- "Didn't find '{$expectedStr}' in:\n{$result}"
- );
- }
- }
+}
/**
* Small helper to render templates from strings
@@ -190,75 +190,104 @@ class SSViewerTest extends SapphireTest
* @param bool $cacheTemplate
* @return string
*/
- public function render($templateString, $data = null, $cacheTemplate = false)
- {
- $t = SSViewer::fromString($templateString, $cacheTemplate);
- if (!$data) {
- $data = new SSViewerTest\TestFixture();
- }
- return trim(''.$t->process($data));
+public function render($templateString, $data = null, $cacheTemplate = false)
+{
+ $t = SSViewer::fromString($templateString, $cacheTemplate);
+ if (!$data) {
+ $data = new SSViewerTest\TestFixture();
}
+ return trim(''.$t->process($data));
+}
- public function testRequirements()
- {
- $requirements = $this->getMockBuilder(Requirements_Backend::class)->setMethods(array("javascript", "css"))
- ->getMock();
- $jsFile = FRAMEWORK_DIR . '/tests/forms/a.js';
- $cssFile = FRAMEWORK_DIR . '/tests/forms/a.js';
+public function testRequirements()
+{
+ $requirements = $this->getMockBuilder(Requirements_Backend::class)->setMethods(array("javascript", "css"))
+ ->getMock();
+ $jsFile = FRAMEWORK_DIR . '/tests/forms/a.js';
+ $cssFile = FRAMEWORK_DIR . '/tests/forms/a.js';
- $requirements->expects($this->once())->method('javascript')->with($jsFile);
- $requirements->expects($this->once())->method('css')->with($cssFile);
+ $requirements->expects($this->once())->method('javascript')->with($jsFile);
+ $requirements->expects($this->once())->method('css')->with($cssFile);
- $origReq = Requirements::backend();
- Requirements::set_backend($requirements);
- $template = $this->render(
- "<% require javascript($jsFile) %>
+ $origReq = Requirements::backend();
+ Requirements::set_backend($requirements);
+ $template = $this->render(
+ "<% require javascript($jsFile) %>
<% require css($cssFile) %>"
+ );
+ Requirements::set_backend($origReq);
+
+ $this->assertFalse((bool)trim($template), "Should be no content in this return.");
+}
+
+public function testRequirementsCombine()
+{
+ $testBackend = Injector::inst()->create(Requirements_Backend::class);
+ $testBackend->setSuffixRequirements(false);
+ //$combinedTestFilePath = BASE_PATH . '/' . $testBackend->getCombinedFilesFolder() . '/testRequirementsCombine.js';
+
+ $jsFile = $this->getCurrentRelativePath() . '/SSViewerTest/javascript/bad.js';
+ $jsFileContents = file_get_contents(BASE_PATH . '/' . $jsFile);
+ $testBackend->combineFiles('testRequirementsCombine.js', array($jsFile));
+
+ // secondly, make sure that requirements is generated, even though minification failed
+ $testBackend->processCombinedFiles();
+ $js = array_keys($testBackend->getJavascript());
+ $combinedTestFilePath = BASE_PATH . reset($js);
+ $this->assertContains('_combinedfiles/testRequirementsCombine-4c0e97a.js', $combinedTestFilePath);
+
+ // and make sure the combined content matches the input content, i.e. no loss of functionality
+ if (!file_exists($combinedTestFilePath)) {
+ $this->fail('No combined file was created at expected path: '.$combinedTestFilePath);
+ }
+ $combinedTestFileContents = file_get_contents($combinedTestFilePath);
+ $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
);
- Requirements::set_backend($origReq);
+ $testBackend->setMinifier($mockMinifier);
+ $testBackend->combineFiles('testRequirementsMinified.js', array($testFile));
+ $testBackend->processCombinedFiles();
- $this->assertFalse((bool)trim($template), "Should be no content in this return.");
- }
+ $testBackend->setMinifyCombinedFiles(false);
+ $mockMinifier->expects($this->never())
+ ->method('minify');
+ $testBackend->processCombinedFiles();
- public function testRequirementsCombine()
- {
- $testBackend = Injector::inst()->create(Requirements_Backend::class);
- $testBackend->setSuffixRequirements(false);
- //$combinedTestFilePath = BASE_PATH . '/' . $testBackend->getCombinedFilesFolder() . '/testRequirementsCombine.js';
+ $this->setExpectedExceptionRegExp(
+ Exception::class,
+ '/minification service/'
+ );
- $jsFile = $this->getCurrentRelativePath() . '/SSViewerTest/javascript/bad.js';
- $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());
- $combinedTestFilePath = BASE_PATH . reset($js);
- $this->assertContains('_combinedfiles/testRequirementsCombine-4c0e97a.js', $combinedTestFilePath);
-
- // and make sure the combined content matches the input content, i.e. no loss of functionality
- if (!file_exists($combinedTestFilePath)) {
- $this->fail('No combined file was created at expected path: '.$combinedTestFilePath);
- }
- $combinedTestFileContents = file_get_contents($combinedTestFilePath);
- $this->assertContains($jsFileContents, $combinedTestFileContents);
- }
+ $testBackend->setMinifyCombinedFiles(true);
+ $testBackend->setMinifier(null);
+ $testBackend->processCombinedFiles();
+}
- public function testComments()
- {
- $output = $this->render(
- <<render(
+ <<This is some content<%-- this is another comment --%>Final content
<%-- Alone multi
line comment --%>
@@ -267,8 +296,8 @@ Mixing content and <%-- multi
line comment --%> Final final
content
SS
- );
- $shouldbe = <<assertEquals($shouldbe, $output);
- }
+ $this->assertEquals($shouldbe, $output);
+}
- public function testBasicText()
- {
- $this->assertEquals('"', $this->render('"'), 'Double-quotes are left alone');
- $this->assertEquals("'", $this->render("'"), 'Single-quotes are left alone');
- $this->assertEquals('A', $this->render('\\A'), 'Escaped characters are unescaped');
- $this->assertEquals('\\A', $this->render('\\\\A'), 'Escaped back-slashed are correctly unescaped');
- }
+public function testBasicText()
+{
+ $this->assertEquals('"', $this->render('"'), 'Double-quotes are left alone');
+ $this->assertEquals("'", $this->render("'"), 'Single-quotes are left alone');
+ $this->assertEquals('A', $this->render('\\A'), 'Escaped characters are unescaped');
+ $this->assertEquals('\\A', $this->render('\\\\A'), 'Escaped back-slashed are correctly unescaped');
+}
- public function testBasicInjection()
- {
- $this->assertEquals('[out:Test]', $this->render('$Test'), 'Basic stand-alone injection');
- $this->assertEquals('[out:Test]', $this->render('{$Test}'), 'Basic stand-alone wrapped injection');
- $this->assertEquals('A[out:Test]!', $this->render('A$Test!'), 'Basic surrounded injection');
- $this->assertEquals('A[out:Test]B', $this->render('A{$Test}B'), 'Basic surrounded wrapped injection');
+public function testBasicInjection()
+{
+ $this->assertEquals('[out:Test]', $this->render('$Test'), 'Basic stand-alone injection');
+ $this->assertEquals('[out:Test]', $this->render('{$Test}'), 'Basic stand-alone wrapped injection');
+ $this->assertEquals('A[out:Test]!', $this->render('A$Test!'), 'Basic surrounded injection');
+ $this->assertEquals('A[out:Test]B', $this->render('A{$Test}B'), 'Basic surrounded wrapped injection');
- $this->assertEquals('A$B', $this->render('A\\$B'), 'No injection as $ escaped');
- $this->assertEquals('A$ B', $this->render('A$ B'), 'No injection as $ not followed by word character');
- $this->assertEquals('A{$ B', $this->render('A{$ B'), 'No injection as {$ not followed by word character');
+ $this->assertEquals('A$B', $this->render('A\\$B'), 'No injection as $ escaped');
+ $this->assertEquals('A$ B', $this->render('A$ B'), 'No injection as $ not followed by word character');
+ $this->assertEquals('A{$ B', $this->render('A{$ B'), 'No injection as {$ not followed by word character');
- $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'
- );
- }
+ $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'
+ );
+}
- public function testGlobalVariableCalls()
- {
- $this->assertEquals('automatic', $this->render('$SSViewerTest_GlobalAutomatic'));
- $this->assertEquals('reference', $this->render('$SSViewerTest_GlobalReferencedByString'));
- $this->assertEquals('reference', $this->render('$SSViewerTest_GlobalReferencedInArray'));
- }
+public function testGlobalVariableCalls()
+{
+ $this->assertEquals('automatic', $this->render('$SSViewerTest_GlobalAutomatic'));
+ $this->assertEquals('reference', $this->render('$SSViewerTest_GlobalReferencedByString'));
+ $this->assertEquals('reference', $this->render('$SSViewerTest_GlobalReferencedInArray'));
+}
- public function testGlobalVariableCallsWithArguments()
- {
- $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")')
- );
- $this->assertEquals(
- 'zreferencez',
- $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalReferencedByString)')
- );
- }
+public function testGlobalVariableCallsWithArguments()
+{
+ $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")')
+ );
+ $this->assertEquals(
+ 'zreferencez',
+ $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalReferencedByString)')
+ );
+}
- public function testGlobalVariablesAreEscaped()
- {
- $this->assertEquals('', $this->render('$SSViewerTest_GlobalHTMLFragment'));
- $this->assertEquals('<div></div>', $this->render('$SSViewerTest_GlobalHTMLEscaped'));
+public function testGlobalVariablesAreEscaped()
+{
+ $this->assertEquals('', $this->render('$SSViewerTest_GlobalHTMLFragment'));
+ $this->assertEquals('<div></div>', $this->render('$SSViewerTest_GlobalHTMLEscaped'));
- $this->assertEquals(
- 'zz',
- $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLFragment)')
- );
- $this->assertEquals(
- 'z<div></div>z',
- $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLEscaped)')
- );
- }
+ $this->assertEquals(
+ 'zz',
+ $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLFragment)')
+ );
+ $this->assertEquals(
+ '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'
- );
- $this->assertEquals(
- Director::absoluteBaseURL(),
- $this->render('{$AbsoluteBaseURL}'),
- 'Upper-case %AbsoluteBaseURL can be called from within template'
- );
+public function testCoreGlobalVariableCalls()
+{
+ $this->assertEquals(
+ 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'
+ );
- $this->assertEquals(
- 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'
- );
- $this->assertEquals(
- 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'
- );
+ $this->assertEquals(
+ 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'
+ );
+ $this->assertEquals(
+ 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'
+ );
- $this->assertEquals(
- 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'
- );
+ $this->assertEquals(
+ 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'
+ );
- $this->assertEquals(
- (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'
- );
- $this->assertEquals(
- (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'
- );
+ $this->assertEquals(
+ (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'
+ );
+ $this->assertEquals(
+ (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'
+ );
- $this->assertEquals(
- SecurityToken::getSecurityID(),
- $this->render('{$getSecurityID}'),
- 'SecurityToken template functions result correct result'
- );
- $this->assertEquals(
- SecurityToken::getSecurityID(),
- $this->render('{$SecurityID}'),
- 'SecurityToken template functions result correct result'
- );
+ $this->assertEquals(
+ SecurityToken::getSecurityID(),
+ $this->render('{$getSecurityID}'),
+ 'SecurityToken template functions result correct result'
+ );
+ $this->assertEquals(
+ 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'
- );
- $this->assertEquals(
- 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'
+ );
+ $this->assertEquals(
+ Permission::check("ADMIN"),
+ (bool)$this->render('{$hasPerm(\'ADMIN\')}'),
+ 'Permissions template functions result correct result'
+ );
+}
- public function testNonFieldCastingHelpersNotUsedInHasValue()
- {
- // check if Link without $ in front of variable
- $result = $this->render(
- 'A<% if Link %>$Link<% end_if %>B',
- new SSViewerTest\TestObject()
- );
- $this->assertEquals('Asome/url.htmlB', $result, 'casting helper not used for <% if Link %>');
+public function testNonFieldCastingHelpersNotUsedInHasValue()
+{
+ // check if Link without $ in front of variable
+ $result = $this->render(
+ '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()
- );
- $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()
+ );
+ $this->assertEquals('Asome/url.htmlB', $result, 'casting helper not used for <% if $Link %>');
+}
- public function testLocalFunctionsTakePriorityOverGlobals()
- {
- $data = new ArrayData(
+public function testLocalFunctionsTakePriorityOverGlobals()
+{
+ $data = new ArrayData(
+ 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
+ );
+ $this->assertEquals("abcdefghijk", $result, "public function can accept up to 11 arguments");
+
+ //call method that does not exist
+ $result = $this->render('<% with Page %><% if IDoNotExist %>hello<% end_if %><% end_with %>', $data);
+ $this->assertEquals("", $result, "Method does not exist - empty result");
+
+ //call if that does not exist
+ $result = $this->render('<% with Page %>$IDoNotExist("hello")<% end_with %>', $data);
+ $this->assertEquals("", $result, "Method does not exist - empty result");
+
+ //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"
+ );
+}
+
+public function testCurrentScopeLoopWith()
+{
+ // Data to run the loop tests on - one sequence of three items, each with a subitem
+ $data = new ArrayData(
+ array(
+ 'Foo' => new ArrayList(
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
- );
- $this->assertEquals("abcdefghijk", $result, "public function can accept up to 11 arguments");
-
- //call method that does not exist
- $result = $this->render('<% with Page %><% if IDoNotExist %>hello<% end_if %><% end_with %>', $data);
- $this->assertEquals("", $result, "Method does not exist - empty result");
-
- //call if that does not exist
- $result = $this->render('<% with Page %>$IDoNotExist("hello")<% end_with %>', $data);
- $this->assertEquals("", $result, "Method does not exist - empty result");
-
- //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"
- );
- }
-
- public function testCurrentScopeLoopWith()
- {
- // Data to run the loop tests on - one sequence of three items, each with a subitem
- $data = new ArrayData(
- 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
- );
- $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop works");
+ $result = $this->render(
+ '<% 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
- );
- $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop works");
+ $result = $this->render(
+ '<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>',
+ $data
+ );
+ $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop works");
- $result = $this->render('<% with Foo %>$Count<% end_with %>', $data);
- $this->assertEquals("4", $result, "4 items in the DataObjectSet");
+ $result = $this->render('<% with Foo %>$Count<% end_with %>', $data);
+ $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
- );
- $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop in with Up.Foo scope works");
+ $result = $this->render(
+ '<% 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
- );
- $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop in current scope works");
- }
+ $result = $this->render(
+ '<% 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");
+}
- public function testObjectDotArguments()
- {
- $this->assertEquals(
- '[out:TestObject.methodWithOneArgument(one)]
+public function testObjectDotArguments()
+{
+ $this->assertEquals(
+ '[out:TestObject.methodWithOneArgument(one)]
[out:TestObject.methodWithTwoArguments(one,two)]
[out:TestMethod(Arg1,Arg2).Bar.Val]
[out:TestMethod(Arg1,Arg2).Bar]
@@ -558,8 +587,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 +596,14 @@ SS;
$TestMethod(Arg1).Bar.Val
$TestMethod(Arg1).Bar
$TestMethod(Arg1)'
- )
- );
- }
+ )
+ );
+}
- public function testEscapedArguments()
- {
- $this->assertEquals(
- '[out:Foo(Arg1,Arg2).Bar.Val].Suffix
+public function testEscapedArguments()
+{
+ $this->assertEquals(
+ '[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 +612,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 +622,44 @@ SS;
{$Foo.Bar.Val}.Suffix
{$Foo.Bar}.Suffix
{$Foo}.Suffix'
- )
- );
- }
+ )
+ );
+}
- public function testLoopWhitespace()
- {
- $this->assertEquals(
- 'before[out:SingleItem.Test]after
+public function testLoopWhitespace()
+{
+ $this->assertEquals(
+ '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
+ // 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
[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
+ // 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
[out:Loop3.ItemOnItsOwnLine]
@@ -639,800 +668,800 @@ after'
[out:Loop3.ItemOnItsOwnLine]
after',
- $this->render(
- 'before
+ $this->render(
+ 'before
<% loop Loop3 %>
$ItemOnItsOwnLine
<% end_loop %>
after'
- )
- );
- }
+ )
+ );
+}
- public function testControls()
- {
- // Single item controls
- $this->assertEquals(
- 'a[out:Foo.Bar.Item]b
+public function testControls()
+{
+ // Single item controls
+ $this->assertEquals(
+ '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 %>')
- );
+ // 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 %>')
+ );
- $this->assertEquals(
- '[out:Foo.Loop2(Arg1).Item][out:Foo.Loop2(Arg1).Item]',
- $this->render('<% loop Foo.Loop2(Arg1) %>$Item<% end_loop %>')
- );
+ $this->assertEquals(
+ '[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 %>')
- );
+ $this->assertEquals(
+ '[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 %>')
- );
+ $this->assertEquals(
+ '[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 %>')
- );
- }
+ $this->assertEquals(
+ '[out:Loop2(Arg1,Arg2,Arg3).Item][out:Loop2(Arg1,Arg2,Arg3).Item]',
+ $this->render('<% loop Loop2(Arg1, Arg2, Arg3) %>$Item<% end_loop %>')
+ );
+}
- public function testIfBlocks()
- {
- // Basic test
- $this->assertEquals(
- 'AC',
- $this->render('A<% if NotSet %>B$NotSet<% end_if %>C')
- );
+public function testIfBlocks()
+{
+ // Basic test
+ $this->assertEquals(
+ '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')
- );
+ // Nested test
+ $this->assertEquals(
+ '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')
- );
- $this->assertEquals(
- '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')
- );
+ // else_if
+ $this->assertEquals(
+ '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')
+ );
+ $this->assertEquals(
+ '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')
- );
+ $this->assertEquals(
+ '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')
- );
- $this->assertEquals(
- 'ACD',
- $this->render('A<% if Foo.Bar.NotSet %>B<% else_if Foo.Bar.IsSet %>C<% end_if %>D')
- );
+ // Dot syntax
+ $this->assertEquals(
+ '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')
+ );
- // Params
- $this->assertEquals(
- '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')
- );
+ // Params
+ $this->assertEquals(
+ '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')
+ );
- // Negation
- $this->assertEquals(
- 'AC',
- $this->render('A<% if not IsSet %>B<% end_if %>C')
- );
- $this->assertEquals(
- 'ABC',
- $this->render('A<% if not NotSet %>B<% end_if %>C')
- );
+ // Negation
+ $this->assertEquals(
+ 'AC',
+ $this->render('A<% if not IsSet %>B<% end_if %>C')
+ );
+ $this->assertEquals(
+ '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')
- );
- $this->assertEquals(
- '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')
- );
- $this->assertEquals(
- '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')
- );
+ // Or
+ $this->assertEquals(
+ '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')
+ );
+ $this->assertEquals(
+ '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')
+ );
+ $this->assertEquals(
+ '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')
- );
- $this->assertEquals(
- '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')
- );
+ // Negated Or
+ $this->assertEquals(
+ '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')
+ );
+ $this->assertEquals(
+ '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')
- );
- $this->assertEquals(
- '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')
- );
- $this->assertEquals(
- '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')
- );
+ // And
+ $this->assertEquals(
+ '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')
+ );
+ $this->assertEquals(
+ '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')
+ );
+ $this->assertEquals(
+ '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')
- );
- $this->assertEquals(
- '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')
- );
- $this->assertEquals(
- 'AD',
- $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% end_if %>D')
- );
+ // Equality
+ $this->assertEquals(
+ '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')
+ );
+ $this->assertEquals(
+ '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')
+ );
- // test inequalities with simple numbers
- $this->assertEquals('ABD', $this->render('A<% if 5 > 3 %>B<% else %>C<% end_if %>D'));
- $this->assertEquals('ABD', $this->render('A<% if 5 >= 3 %>B<% else %>C<% end_if %>D'));
- $this->assertEquals('ACD', $this->render('A<% if 3 > 5 %>B<% else %>C<% end_if %>D'));
- $this->assertEquals('ACD', $this->render('A<% if 3 >= 5 %>B<% else %>C<% end_if %>D'));
+ // test inequalities with simple numbers
+ $this->assertEquals('ABD', $this->render('A<% if 5 > 3 %>B<% else %>C<% end_if %>D'));
+ $this->assertEquals('ABD', $this->render('A<% if 5 >= 3 %>B<% else %>C<% end_if %>D'));
+ $this->assertEquals('ACD', $this->render('A<% if 3 > 5 %>B<% else %>C<% end_if %>D'));
+ $this->assertEquals('ACD', $this->render('A<% if 3 >= 5 %>B<% else %>C<% end_if %>D'));
- $this->assertEquals('ABD', $this->render('A<% if 3 < 5 %>B<% else %>C<% end_if %>D'));
- $this->assertEquals('ABD', $this->render('A<% if 3 <= 5 %>B<% else %>C<% end_if %>D'));
- $this->assertEquals('ACD', $this->render('A<% if 5 < 3 %>B<% else %>C<% end_if %>D'));
- $this->assertEquals('ACD', $this->render('A<% if 5 <= 3 %>B<% else %>C<% end_if %>D'));
+ $this->assertEquals('ABD', $this->render('A<% if 3 < 5 %>B<% else %>C<% end_if %>D'));
+ $this->assertEquals('ABD', $this->render('A<% if 3 <= 5 %>B<% else %>C<% end_if %>D'));
+ $this->assertEquals('ACD', $this->render('A<% if 5 < 3 %>B<% else %>C<% end_if %>D'));
+ $this->assertEquals('ACD', $this->render('A<% if 5 <= 3 %>B<% else %>C<% end_if %>D'));
- $this->assertEquals('ABD', $this->render('A<% if 4 <= 4 %>B<% else %>C<% end_if %>D'));
- $this->assertEquals('ABD', $this->render('A<% if 4 >= 4 %>B<% else %>C<% end_if %>D'));
- $this->assertEquals('ACD', $this->render('A<% if 4 > 4 %>B<% else %>C<% end_if %>D'));
- $this->assertEquals('ACD', $this->render('A<% if 4 < 4 %>B<% else %>C<% end_if %>D'));
+ $this->assertEquals('ABD', $this->render('A<% if 4 <= 4 %>B<% else %>C<% end_if %>D'));
+ $this->assertEquals('ABD', $this->render('A<% if 4 >= 4 %>B<% else %>C<% end_if %>D'));
+ $this->assertEquals('ACD', $this->render('A<% if 4 > 4 %>B<% else %>C<% end_if %>D'));
+ $this->assertEquals('ACD', $this->render('A<% if 4 < 4 %>B<% else %>C<% end_if %>D'));
- // empty else_if and else tags, if this would not be supported,
- // 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')
- );
- $this->assertEquals(
- 'AD',
- $this->render('A<% if NotSet %><% else_if AlsoNotSet %><% else %><% end_if %>D')
- );
+ // empty else_if and else tags, if this would not be supported,
+ // 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')
+ );
+ $this->assertEquals(
+ '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')
- );
+ // Bare words with ending space
+ $this->assertEquals(
+ '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')
- );
+ // Else
+ $this->assertEquals(
+ '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')
- );
- }
+ // Empty if with else
+ $this->assertEquals(
+ 'ABC',
+ $this->render('A<% if NotSet %><% else %>B<% end_if %>C')
+ );
+}
- public function testBaseTagGeneration()
- {
- // XHTML wil have a closed base tag
- $tmpl1 = '
+public function testBaseTagGeneration()
+{
+ // XHTML wil have a closed base tag
+ $tmpl1 = '
+ . ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<% base_tag %>
test
';
- $this->assertRegExp('/<\/head>/', $this->render($tmpl1));
+ $this->assertRegExp('/<\/head>/', $this->render($tmpl1));
- // HTML4 and 5 will only have it for IE
- $tmpl2 = '
+ // HTML4 and 5 will only have it for IE
+ $tmpl2 = '
<% base_tag %>