Remove JSMinifier implementation

This commit is contained in:
Aaron Carlino 2017-05-11 10:17:54 +12:00
parent 7fa47e234f
commit 5b46461879
2 changed files with 832 additions and 863 deletions

View File

@ -1,30 +0,0 @@
<?php
namespace SilverStripe\View;
use Exception;
use JSMin;
class JSMinifier implements Requirements_Minifier
{
public function minify($content, $type, $filename)
{
// Non-js files aren't minified
if ($type !== 'js') {
return $content . "\n";
}
// Combine JS
try {
require_once('jsmin/jsmin.php');
increase_time_limit_to();
$content = JSMin::minify($content);
} catch (Exception $e) {
$message = $e->getMessage();
user_error("Failed to minify {$filename}, exception: {$message}", E_USER_WARNING);
} finally {
return $content . ";\n";
}
}
}

View File

@ -8,7 +8,6 @@ use SilverStripe\Control\ContentNegotiator;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Debug;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\i18n\i18n; use SilverStripe\i18n\i18n;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
@ -31,7 +30,7 @@ use SilverStripe\View\SSTemplateParser;
use SilverStripe\Assets\Tests\Storage\AssetStoreTest\TestAssetStore; use SilverStripe\Assets\Tests\Storage\AssetStoreTest\TestAssetStore;
use Exception; use Exception;
classSSViewerTest extends SapphireTest class SSViewerTest extends SapphireTest
{ {
/** /**
@ -39,90 +38,90 @@ classSSViewerTest extends SapphireTest
* *
* @var array * @var array
*/ */
protected $oldServer = array(); protected $oldServer = array();
protected static $extra_dataobjects = array( protected static $extra_dataobjects = array(
SSViewerTest\TestObject::class, SSViewerTest\TestObject::class,
); );
protected function setUp() protected function setUp()
{ {
parent::setUp(); parent::setUp();
SSViewer::config()->update('source_file_comments', false); SSViewer::config()->update('source_file_comments', false);
SSViewer_FromString::config()->update('cache_template', false); SSViewer_FromString::config()->update('cache_template', false);
TestAssetStore::activate('SSViewerTest'); TestAssetStore::activate('SSViewerTest');
$this->oldServer = $_SERVER; $this->oldServer = $_SERVER;
} }
protected function tearDown() protected function tearDown()
{ {
$_SERVER = $this->oldServer; $_SERVER = $this->oldServer;
TestAssetStore::reset(); TestAssetStore::reset();
parent::tearDown(); parent::tearDown();
} }
/** /**
* Tests for {@link Config::inst()->get('SSViewer', 'theme')} for different behaviour * Tests for {@link Config::inst()->get('SSViewer', 'theme')} for different behaviour
* of user defined themes via {@link SiteConfig} and default theme * of user defined themes via {@link SiteConfig} and default theme
* when no user themes are defined. * when no user themes are defined.
*/ */
public function testCurrentTheme() public function testCurrentTheme()
{ {
SSViewer::config()->update('theme', 'mytheme'); SSViewer::config()->update('theme', 'mytheme');
$this->assertEquals( $this->assertEquals(
'mytheme', 'mytheme',
SSViewer::config()->uninherited('theme'), SSViewer::config()->uninherited('theme'),
'Current theme is the default - user has not defined one' 'Current theme is the default - user has not defined one'
); );
} }
/** /**
* Test that a template without a <head> tag still renders. * Test that a template without a <head> tag still renders.
*/ */
public function testTemplateWithoutHeadRenders() public function testTemplateWithoutHeadRenders()
{ {
$data = new ArrayData( $data = new ArrayData(
array( array(
'Var' => 'var value' 'Var' => 'var value'
) )
); );
$result = $data->renderWith("SSViewerTestPartialTemplate"); $result = $data->renderWith("SSViewerTestPartialTemplate");
$this->assertEquals('Test partial template: var value', trim(preg_replace("/<!--.*-->/U", '', $result))); $this->assertEquals('Test partial template: var value', trim(preg_replace("/<!--.*-->/U", '', $result)));
} }
public function testIncludeScopeInheritance() public function testIncludeScopeInheritance()
{ {
$data = $this->getScopeInheritanceTestData(); $data = $this->getScopeInheritanceTestData();
$expected = array( $expected = array(
'Item 1 - First-ODD top:Item 1', 'Item 1 - First-ODD top:Item 1',
'Item 2 - EVEN top:Item 2', 'Item 2 - EVEN top:Item 2',
'Item 3 - ODD top:Item 3', 'Item 3 - ODD top:Item 3',
'Item 4 - EVEN top:Item 4', 'Item 4 - EVEN top:Item 4',
'Item 5 - ODD top:Item 5', 'Item 5 - ODD top:Item 5',
'Item 6 - Last-EVEN top:Item 6', 'Item 6 - Last-EVEN top:Item 6',
); );
$result = $data->renderWith('SSViewerTestIncludeScopeInheritance'); $result = $data->renderWith('SSViewerTestIncludeScopeInheritance');
$this->assertExpectedStrings($result, $expected); $this->assertExpectedStrings($result, $expected);
// reset results for the tests that include arguments (the title is passed as an arg) // reset results for the tests that include arguments (the title is passed as an arg)
$expected = array( $expected = array(
'Item 1 _ Item 1 - First-ODD top:Item 1', 'Item 1 _ Item 1 - First-ODD top:Item 1',
'Item 2 _ Item 2 - EVEN top:Item 2', 'Item 2 _ Item 2 - EVEN top:Item 2',
'Item 3 _ Item 3 - ODD top:Item 3', 'Item 3 _ Item 3 - ODD top:Item 3',
'Item 4 _ Item 4 - EVEN top:Item 4', 'Item 4 _ Item 4 - EVEN top:Item 4',
'Item 5 _ Item 5 - ODD top:Item 5', 'Item 5 _ Item 5 - ODD top:Item 5',
'Item 6 _ Item 6 - Last-EVEN top:Item 6', 'Item 6 _ Item 6 - Last-EVEN top:Item 6',
); );
$result = $data->renderWith('SSViewerTestIncludeScopeInheritanceWithArgs'); $result = $data->renderWith('SSViewerTestIncludeScopeInheritanceWithArgs');
$this->assertExpectedStrings($result, $expected); $this->assertExpectedStrings($result, $expected);
} }
public function testIncludeTruthyness() public function testIncludeTruthyness()
{ {
$data = new ArrayData( $data = new ArrayData(
array( array(
'Title' => 'TruthyTest', 'Title' => 'TruthyTest',
'Items' => new ArrayList( 'Items' => new ArrayList(
@ -137,11 +136,11 @@ public function testIncludeTruthyness()
) )
) )
) )
); );
$result = $data->renderWith('SSViewerTestIncludeScopeInheritanceWithArgs'); $result = $data->renderWith('SSViewerTestIncludeScopeInheritanceWithArgs');
// We should not end up with empty values appearing as empty // We should not end up with empty values appearing as empty
$expected = array( $expected = array(
'Item 1 _ Item 1 - First-ODD top:Item 1', 'Item 1 _ Item 1 - First-ODD top:Item 1',
'Untitled - EVEN top:', 'Untitled - EVEN top:',
'1 _ 1 - ODD top:1', '1 _ 1 - ODD top:1',
@ -149,13 +148,13 @@ public function testIncludeTruthyness()
'Untitled - ODD top:', 'Untitled - ODD top:',
'Untitled - EVEN top:0', 'Untitled - EVEN top:0',
'7 _ 7 - Last-ODD top:7' '7 _ 7 - Last-ODD top:7'
); );
$this->assertExpectedStrings($result, $expected); $this->assertExpectedStrings($result, $expected);
} }
private function getScopeInheritanceTestData() private function getScopeInheritanceTestData()
{ {
return new ArrayData( return new ArrayData(
array( array(
'Title' => 'TopTitleValue', 'Title' => 'TopTitleValue',
'Items' => new ArrayList( 'Items' => new ArrayList(
@ -169,18 +168,18 @@ private function getScopeInheritanceTestData()
) )
) )
) )
);
}
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 * Small helper to render templates from strings
@ -190,103 +189,103 @@ private function assertExpectedStrings($result, $expected)
* @param bool $cacheTemplate * @param bool $cacheTemplate
* @return string * @return string
*/ */
public function render($templateString, $data = null, $cacheTemplate = false) public function render($templateString, $data = null, $cacheTemplate = false)
{ {
$t = SSViewer::fromString($templateString, $cacheTemplate); $t = SSViewer::fromString($templateString, $cacheTemplate);
if (!$data) { if (!$data) {
$data = new SSViewerTest\TestFixture(); $data = new SSViewerTest\TestFixture();
}
return trim(''.$t->process($data));
} }
return trim(''.$t->process($data));
}
public function testRequirements() public function testRequirements()
{ {
$requirements = $this->getMockBuilder(Requirements_Backend::class)->setMethods(array("javascript", "css")) $requirements = $this->getMockBuilder(Requirements_Backend::class)->setMethods(array("javascript", "css"))
->getMock(); ->getMock();
$jsFile = FRAMEWORK_DIR . '/tests/forms/a.js'; $jsFile = FRAMEWORK_DIR . '/tests/forms/a.js';
$cssFile = 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('javascript')->with($jsFile);
$requirements->expects($this->once())->method('css')->with($cssFile); $requirements->expects($this->once())->method('css')->with($cssFile);
$origReq = Requirements::backend(); $origReq = Requirements::backend();
Requirements::set_backend($requirements); Requirements::set_backend($requirements);
$template = $this->render( $template = $this->render(
"<% require javascript($jsFile) %> "<% require javascript($jsFile) %>
<% require css($cssFile) %>" <% require css($cssFile) %>"
); );
Requirements::set_backend($origReq); Requirements::set_backend($origReq);
$this->assertFalse((bool)trim($template), "Should be no content in this return."); $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() public function testRequirementsCombine()
{ {
$testBackend = Injector::inst()->create(Requirements_Backend::class); $testBackend = Injector::inst()->create(Requirements_Backend::class);
$testBackend->setSuffixRequirements(false); $testBackend->setSuffixRequirements(false);
$testBackend->setMinifyCombinedFiles(true); //$combinedTestFilePath = BASE_PATH . '/' . $testBackend->getCombinedFilesFolder() . '/testRequirementsCombine.js';
$testFile = $this->getCurrentRelativePath() . '/SSViewerTest/javascript/RequirementsTest_a.js';
$testFileContent = file_get_contents($testFile);
$mockMinifier = $this->getMockBuilder(Requirements_Minifier::class) $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']) ->setMethods(['minify'])
->getMock(); ->getMock();
$mockMinifier->expects($this->once()) $mockMinifier->expects($this->once())
->method('minify') ->method('minify')
->with( ->with(
$testFileContent, $testFileContent,
'js', 'js',
$testFile $testFile
); );
$testBackend->setMinifier($mockMinifier); $testBackend->setMinifier($mockMinifier);
$testBackend->combineFiles('testRequirementsMinified.js', array($testFile)); $testBackend->combineFiles('testRequirementsMinified.js', array($testFile));
$testBackend->processCombinedFiles(); $testBackend->processCombinedFiles();
$testBackend->setMinifyCombinedFiles(false); $testBackend->setMinifyCombinedFiles(false);
$mockMinifier->expects($this->never()) $mockMinifier->expects($this->never())
->method('minify'); ->method('minify');
$testBackend->processCombinedFiles(); $testBackend->processCombinedFiles();
$this->setExpectedExceptionRegExp( $this->setExpectedExceptionRegExp(
Exception::class, Exception::class,
'/minification service/' '/minification service/'
); );
$testBackend->setMinifyCombinedFiles(true); $testBackend->setMinifyCombinedFiles(true);
$testBackend->setMinifier(null); $testBackend->setMinifier(null);
$testBackend->processCombinedFiles(); $testBackend->processCombinedFiles();
} }
public function testComments() public function testComments()
{ {
$output = $this->render( $output = $this->render(
<<<SS <<<SS
This is my template<%-- this is a comment --%>This is some content<%-- this is another comment --%>Final content This is my template<%-- this is a comment --%>This is some content<%-- this is another comment --%>Final content
<%-- Alone multi <%-- Alone multi
@ -296,8 +295,8 @@ Mixing content and <%-- multi
line comment --%> Final final line comment --%> Final final
content content
SS SS
); );
$shouldbe = <<<SS $shouldbe = <<<SS
This is my templateThis is some contentFinal content This is my templateThis is some contentFinal content
Some more content Some more content
@ -305,215 +304,215 @@ Mixing content and Final final
content content
SS; SS;
$this->assertEquals($shouldbe, $output); $this->assertEquals($shouldbe, $output);
} }
public function testBasicText() public function testBasicText()
{ {
$this->assertEquals('"', $this->render('"'), 'Double-quotes are left alone'); $this->assertEquals('"', $this->render('"'), 'Double-quotes are left alone');
$this->assertEquals("'", $this->render("'"), 'Single-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 characters are unescaped');
$this->assertEquals('\\A', $this->render('\\\\A'), 'Escaped back-slashed are correctly unescaped'); $this->assertEquals('\\A', $this->render('\\\\A'), 'Escaped back-slashed are correctly unescaped');
} }
public function testBasicInjection() public function testBasicInjection()
{ {
$this->assertEquals('[out:Test]', $this->render('$Test'), 'Basic stand-alone injection'); $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('[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]!', $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[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 $ 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 {$ 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('{$Test}', $this->render('{\\$Test}'), 'Escapes can be used to avoid injection');
$this->assertEquals( $this->assertEquals(
'{\\[out:Test]}', '{\\[out:Test]}',
$this->render('{\\\\$Test}'), $this->render('{\\\\$Test}'),
'Escapes before injections are correctly unescaped' 'Escapes before injections are correctly unescaped'
); );
} }
public function testGlobalVariableCalls() public function testGlobalVariableCalls()
{ {
$this->assertEquals('automatic', $this->render('$SSViewerTest_GlobalAutomatic')); $this->assertEquals('automatic', $this->render('$SSViewerTest_GlobalAutomatic'));
$this->assertEquals('reference', $this->render('$SSViewerTest_GlobalReferencedByString')); $this->assertEquals('reference', $this->render('$SSViewerTest_GlobalReferencedByString'));
$this->assertEquals('reference', $this->render('$SSViewerTest_GlobalReferencedInArray')); $this->assertEquals('reference', $this->render('$SSViewerTest_GlobalReferencedInArray'));
} }
public function testGlobalVariableCallsWithArguments() public function testGlobalVariableCallsWithArguments()
{ {
$this->assertEquals('zz', $this->render('$SSViewerTest_GlobalThatTakesArguments')); $this->assertEquals('zz', $this->render('$SSViewerTest_GlobalThatTakesArguments'));
$this->assertEquals('zFooz', $this->render('$SSViewerTest_GlobalThatTakesArguments("Foo")')); $this->assertEquals('zFooz', $this->render('$SSViewerTest_GlobalThatTakesArguments("Foo")'));
$this->assertEquals( $this->assertEquals(
'zFoo:Bar:Bazz', 'zFoo:Bar:Bazz',
$this->render('$SSViewerTest_GlobalThatTakesArguments("Foo", "Bar", "Baz")') $this->render('$SSViewerTest_GlobalThatTakesArguments("Foo", "Bar", "Baz")')
); );
$this->assertEquals( $this->assertEquals(
'zreferencez', 'zreferencez',
$this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalReferencedByString)') $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalReferencedByString)')
); );
} }
public function testGlobalVariablesAreEscaped() public function testGlobalVariablesAreEscaped()
{ {
$this->assertEquals('<div></div>', $this->render('$SSViewerTest_GlobalHTMLFragment')); $this->assertEquals('<div></div>', $this->render('$SSViewerTest_GlobalHTMLFragment'));
$this->assertEquals('&lt;div&gt;&lt;/div&gt;', $this->render('$SSViewerTest_GlobalHTMLEscaped')); $this->assertEquals('&lt;div&gt;&lt;/div&gt;', $this->render('$SSViewerTest_GlobalHTMLEscaped'));
$this->assertEquals( $this->assertEquals(
'z<div></div>z', 'z<div></div>z',
$this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLFragment)') $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLFragment)')
); );
$this->assertEquals( $this->assertEquals(
'z&lt;div&gt;&lt;/div&gt;z', 'z&lt;div&gt;&lt;/div&gt;z',
$this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLEscaped)') $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLEscaped)')
); );
} }
public function testCoreGlobalVariableCalls() public function testCoreGlobalVariableCalls()
{ {
$this->assertEquals( $this->assertEquals(
Director::absoluteBaseURL(), Director::absoluteBaseURL(),
$this->render('{$absoluteBaseURL}'), $this->render('{$absoluteBaseURL}'),
'Director::absoluteBaseURL can be called from within template' 'Director::absoluteBaseURL can be called from within template'
); );
$this->assertEquals( $this->assertEquals(
Director::absoluteBaseURL(), Director::absoluteBaseURL(),
$this->render('{$AbsoluteBaseURL}'), $this->render('{$AbsoluteBaseURL}'),
'Upper-case %AbsoluteBaseURL can be called from within template' 'Upper-case %AbsoluteBaseURL can be called from within template'
); );
$this->assertEquals( $this->assertEquals(
Director::is_ajax(), Director::is_ajax(),
$this->render('{$isAjax}'), $this->render('{$isAjax}'),
'All variations of is_ajax result in the correct call' 'All variations of is_ajax result in the correct call'
); );
$this->assertEquals( $this->assertEquals(
Director::is_ajax(), Director::is_ajax(),
$this->render('{$IsAjax}'), $this->render('{$IsAjax}'),
'All variations of is_ajax result in the correct call' 'All variations of is_ajax result in the correct call'
); );
$this->assertEquals( $this->assertEquals(
Director::is_ajax(), Director::is_ajax(),
$this->render('{$is_ajax}'), $this->render('{$is_ajax}'),
'All variations of is_ajax result in the correct call' 'All variations of is_ajax result in the correct call'
); );
$this->assertEquals( $this->assertEquals(
Director::is_ajax(), Director::is_ajax(),
$this->render('{$Is_ajax}'), $this->render('{$Is_ajax}'),
'All variations of is_ajax result in the correct call' 'All variations of is_ajax result in the correct call'
); );
$this->assertEquals( $this->assertEquals(
i18n::get_locale(), i18n::get_locale(),
$this->render('{$i18nLocale}'), $this->render('{$i18nLocale}'),
'i18n template functions result correct result' 'i18n template functions result correct result'
); );
$this->assertEquals( $this->assertEquals(
i18n::get_locale(), i18n::get_locale(),
$this->render('{$get_locale}'), $this->render('{$get_locale}'),
'i18n template functions result correct result' 'i18n template functions result correct result'
); );
$this->assertEquals( $this->assertEquals(
(string)Member::currentUser(), (string)Member::currentUser(),
$this->render('{$CurrentMember}'), $this->render('{$CurrentMember}'),
'Member template functions result correct result' 'Member template functions result correct result'
); );
$this->assertEquals( $this->assertEquals(
(string)Member::currentUser(), (string)Member::currentUser(),
$this->render('{$CurrentUser}'), $this->render('{$CurrentUser}'),
'Member template functions result correct result' 'Member template functions result correct result'
); );
$this->assertEquals( $this->assertEquals(
(string)Member::currentUser(), (string)Member::currentUser(),
$this->render('{$currentMember}'), $this->render('{$currentMember}'),
'Member template functions result correct result' 'Member template functions result correct result'
); );
$this->assertEquals( $this->assertEquals(
(string)Member::currentUser(), (string)Member::currentUser(),
$this->render('{$currentUser}'), $this->render('{$currentUser}'),
'Member template functions result correct result' 'Member template functions result correct result'
); );
$this->assertEquals( $this->assertEquals(
SecurityToken::getSecurityID(), SecurityToken::getSecurityID(),
$this->render('{$getSecurityID}'), $this->render('{$getSecurityID}'),
'SecurityToken template functions result correct result' 'SecurityToken template functions result correct result'
); );
$this->assertEquals( $this->assertEquals(
SecurityToken::getSecurityID(), SecurityToken::getSecurityID(),
$this->render('{$SecurityID}'), $this->render('{$SecurityID}'),
'SecurityToken template functions result correct result' 'SecurityToken template functions result correct result'
); );
$this->assertEquals( $this->assertEquals(
Permission::check("ADMIN"), Permission::check("ADMIN"),
(bool)$this->render('{$HasPerm(\'ADMIN\')}'), (bool)$this->render('{$HasPerm(\'ADMIN\')}'),
'Permissions template functions result correct result' 'Permissions template functions result correct result'
); );
$this->assertEquals( $this->assertEquals(
Permission::check("ADMIN"), Permission::check("ADMIN"),
(bool)$this->render('{$hasPerm(\'ADMIN\')}'), (bool)$this->render('{$hasPerm(\'ADMIN\')}'),
'Permissions template functions result correct result' 'Permissions template functions result correct result'
); );
} }
public function testNonFieldCastingHelpersNotUsedInHasValue() public function testNonFieldCastingHelpersNotUsedInHasValue()
{ {
// check if Link without $ in front of variable // check if Link without $ in front of variable
$result = $this->render( $result = $this->render(
'A<% if Link %>$Link<% end_if %>B', 'A<% if Link %>$Link<% end_if %>B',
new SSViewerTest\TestObject() new SSViewerTest\TestObject()
); );
$this->assertEquals('Asome/url.htmlB', $result, 'casting helper not used for <% if Link %>'); $this->assertEquals('Asome/url.htmlB', $result, 'casting helper not used for <% if Link %>');
// check if Link with $ in front of variable // check if Link with $ in front of variable
$result = $this->render( $result = $this->render(
'A<% if $Link %>$Link<% end_if %>B', 'A<% if $Link %>$Link<% end_if %>B',
new SSViewerTest\TestObject() new SSViewerTest\TestObject()
); );
$this->assertEquals('Asome/url.htmlB', $result, 'casting helper not used for <% if $Link %>'); $this->assertEquals('Asome/url.htmlB', $result, 'casting helper not used for <% if $Link %>');
} }
public function testLocalFunctionsTakePriorityOverGlobals() public function testLocalFunctionsTakePriorityOverGlobals()
{ {
$data = new ArrayData( $data = new ArrayData(
array( array(
'Page' => new SSViewerTest\TestObject() 'Page' => new SSViewerTest\TestObject()
) )
); );
//call method with lots of arguments //call method with lots of arguments
$result = $this->render( $result = $this->render(
'<% with Page %>$lotsOfArguments11("a","b","c","d","e","f","g","h","i","j","k")<% end_with %>', '<% with Page %>$lotsOfArguments11("a","b","c","d","e","f","g","h","i","j","k")<% end_with %>',
$data $data
); );
$this->assertEquals("abcdefghijk", $result, "public function can accept up to 11 arguments"); $this->assertEquals("abcdefghijk", $result, "public function can accept up to 11 arguments");
//call method that does not exist //call method that does not exist
$result = $this->render('<% with Page %><% if IDoNotExist %>hello<% end_if %><% end_with %>', $data); $result = $this->render('<% with Page %><% if IDoNotExist %>hello<% end_if %><% end_with %>', $data);
$this->assertEquals("", $result, "Method does not exist - empty result"); $this->assertEquals("", $result, "Method does not exist - empty result");
//call if that does not exist //call if that does not exist
$result = $this->render('<% with Page %>$IDoNotExist("hello")<% end_with %>', $data); $result = $this->render('<% with Page %>$IDoNotExist("hello")<% end_with %>', $data);
$this->assertEquals("", $result, "Method does not exist - empty result"); $this->assertEquals("", $result, "Method does not exist - empty result");
//call method with same name as a global method (local call should take priority) //call method with same name as a global method (local call should take priority)
$result = $this->render('<% with Page %>$absoluteBaseURL<% end_with %>', $data); $result = $this->render('<% with Page %>$absoluteBaseURL<% end_with %>', $data);
$this->assertEquals( $this->assertEquals(
"testLocalFunctionPriorityCalled", "testLocalFunctionPriorityCalled",
$result, $result,
"Local Object's public function called. Did not return the actual baseURL of the current site" "Local Object's public function called. Did not return the actual baseURL of the current site"
); );
} }
public function testCurrentScopeLoopWith() public function testCurrentScopeLoopWith()
{ {
// Data to run the loop tests on - one sequence of three items, each with a subitem // Data to run the loop tests on - one sequence of three items, each with a subitem
$data = new ArrayData( $data = new ArrayData(
array( array(
'Foo' => new ArrayList( 'Foo' => new ArrayList(
array( array(
@ -544,41 +543,41 @@ public function testCurrentScopeLoopWith()
) )
) )
) )
); );
$result = $this->render( $result = $this->render(
'<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>', '<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>',
$data $data
); );
$this->assertEquals("SubKid1SubKid2Number6", $result, "Loop works"); $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop works");
$result = $this->render( $result = $this->render(
'<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>', '<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>',
$data $data
); );
$this->assertEquals("SubKid1SubKid2Number6", $result, "Loop works"); $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop works");
$result = $this->render('<% with Foo %>$Count<% end_with %>', $data); $result = $this->render('<% with Foo %>$Count<% end_with %>', $data);
$this->assertEquals("4", $result, "4 items in the DataObjectSet"); $this->assertEquals("4", $result, "4 items in the DataObjectSet");
$result = $this->render( $result = $this->render(
'<% with Foo %><% loop Up.Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>' '<% with Foo %><% loop Up.Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>'
. '<% end_if %><% end_loop %><% end_with %>', . '<% end_if %><% end_loop %><% end_with %>',
$data $data
); );
$this->assertEquals("SubKid1SubKid2Number6", $result, "Loop in with Up.Foo scope works"); $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop in with Up.Foo scope works");
$result = $this->render( $result = $this->render(
'<% with Foo %><% loop %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>' '<% with Foo %><% loop %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>'
. '<% end_if %><% end_loop %><% end_with %>', . '<% end_if %><% end_loop %><% end_with %>',
$data $data
); );
$this->assertEquals("SubKid1SubKid2Number6", $result, "Loop in current scope works"); $this->assertEquals("SubKid1SubKid2Number6", $result, "Loop in current scope works");
} }
public function testObjectDotArguments() public function testObjectDotArguments()
{ {
$this->assertEquals( $this->assertEquals(
'[out:TestObject.methodWithOneArgument(one)] '[out:TestObject.methodWithOneArgument(one)]
[out:TestObject.methodWithTwoArguments(one,two)] [out:TestObject.methodWithTwoArguments(one,two)]
[out:TestMethod(Arg1,Arg2).Bar.Val] [out:TestMethod(Arg1,Arg2).Bar.Val]
@ -597,12 +596,12 @@ public function testObjectDotArguments()
$TestMethod(Arg1).Bar $TestMethod(Arg1).Bar
$TestMethod(Arg1)' $TestMethod(Arg1)'
) )
); );
} }
public function testEscapedArguments() public function testEscapedArguments()
{ {
$this->assertEquals( $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).Val]_Suffix
[out:Foo(Arg1,Arg2)]/Suffix [out:Foo(Arg1,Arg2)]/Suffix
@ -623,24 +622,24 @@ public function testEscapedArguments()
{$Foo.Bar}.Suffix {$Foo.Bar}.Suffix
{$Foo}.Suffix' {$Foo}.Suffix'
) )
); );
} }
public function testLoopWhitespace() public function testLoopWhitespace()
{ {
$this->assertEquals( $this->assertEquals(
'before[out:SingleItem.Test]after 'before[out:SingleItem.Test]after
beforeTestafter', beforeTestafter',
$this->render( $this->render(
'before<% loop SingleItem %>$Test<% end_loop %>after 'before<% loop SingleItem %>$Test<% end_loop %>after
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 // 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 // This is a quirk that could be changed, but included in the test to make the current
// behaviour explicit // behaviour explicit
$this->assertEquals( $this->assertEquals(
'before 'before
[out:SingleItem.ItemOnItsOwnLine] [out:SingleItem.ItemOnItsOwnLine]
@ -653,12 +652,12 @@ $ItemOnItsOwnLine
<% end_loop %> <% end_loop %>
after' after'
) )
); );
// The whitespace within the control tags is preserve in a loop // 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 // This is a quirk that could be changed, but included in the test to make the current
// behaviour explicit // behaviour explicit
$this->assertEquals( $this->assertEquals(
'before 'before
[out:Loop3.ItemOnItsOwnLine] [out:Loop3.ItemOnItsOwnLine]
@ -675,13 +674,13 @@ $ItemOnItsOwnLine
<% end_loop %> <% end_loop %>
after' after'
) )
); );
} }
public function testControls() public function testControls()
{ {
// Single item controls // Single item controls
$this->assertEquals( $this->assertEquals(
'a[out:Foo.Bar.Item]b 'a[out:Foo.Bar.Item]b
[out:Foo.Bar(Arg1).Item] [out:Foo.Bar(Arg1).Item]
[out:Foo(Arg1).Item] [out:Foo(Arg1).Item]
@ -694,309 +693,309 @@ public function testControls()
<% with Foo(Arg1, Arg2) %>$Item<% end_with %> <% with Foo(Arg1, Arg2) %>$Item<% end_with %>
<% with Foo(Arg1, Arg2, Arg3) %>$Item<% end_with %>' <% with Foo(Arg1, Arg2, Arg3) %>$Item<% end_with %>'
) )
); );
// Loop controls // Loop controls
$this->assertEquals( $this->assertEquals(
'a[out:Foo.Loop2.Item]ba[out:Foo.Loop2.Item]b', 'a[out:Foo.Loop2.Item]ba[out:Foo.Loop2.Item]b',
$this->render('<% loop Foo.Loop2 %>a{$Item}b<% end_loop %>') $this->render('<% loop Foo.Loop2 %>a{$Item}b<% end_loop %>')
); );
$this->assertEquals( $this->assertEquals(
'[out:Foo.Loop2(Arg1).Item][out:Foo.Loop2(Arg1).Item]', '[out:Foo.Loop2(Arg1).Item][out:Foo.Loop2(Arg1).Item]',
$this->render('<% loop Foo.Loop2(Arg1) %>$Item<% end_loop %>') $this->render('<% loop Foo.Loop2(Arg1) %>$Item<% end_loop %>')
); );
$this->assertEquals( $this->assertEquals(
'[out:Loop2(Arg1).Item][out:Loop2(Arg1).Item]', '[out:Loop2(Arg1).Item][out:Loop2(Arg1).Item]',
$this->render('<% loop Loop2(Arg1) %>$Item<% end_loop %>') $this->render('<% loop Loop2(Arg1) %>$Item<% end_loop %>')
); );
$this->assertEquals( $this->assertEquals(
'[out:Loop2(Arg1,Arg2).Item][out:Loop2(Arg1,Arg2).Item]', '[out:Loop2(Arg1,Arg2).Item][out:Loop2(Arg1,Arg2).Item]',
$this->render('<% loop Loop2(Arg1, Arg2) %>$Item<% end_loop %>') $this->render('<% loop Loop2(Arg1, Arg2) %>$Item<% end_loop %>')
); );
$this->assertEquals( $this->assertEquals(
'[out:Loop2(Arg1,Arg2,Arg3).Item][out:Loop2(Arg1,Arg2,Arg3).Item]', '[out:Loop2(Arg1,Arg2,Arg3).Item][out:Loop2(Arg1,Arg2,Arg3).Item]',
$this->render('<% loop Loop2(Arg1, Arg2, Arg3) %>$Item<% end_loop %>') $this->render('<% loop Loop2(Arg1, Arg2, Arg3) %>$Item<% end_loop %>')
); );
} }
public function testIfBlocks() public function testIfBlocks()
{ {
// Basic test // Basic test
$this->assertEquals( $this->assertEquals(
'AC', 'AC',
$this->render('A<% if NotSet %>B$NotSet<% end_if %>C') $this->render('A<% if NotSet %>B$NotSet<% end_if %>C')
); );
// Nested test // Nested test
$this->assertEquals( $this->assertEquals(
'AB1C', 'AB1C',
$this->render('A<% if IsSet %>B$NotSet<% if IsSet %>1<% else %>2<% end_if %><% end_if %>C') $this->render('A<% if IsSet %>B$NotSet<% if IsSet %>1<% else %>2<% end_if %><% end_if %>C')
); );
// else_if // else_if
$this->assertEquals( $this->assertEquals(
'ACD', 'ACD',
$this->render('A<% if NotSet %>B<% else_if IsSet %>C<% end_if %>D') $this->render('A<% if NotSet %>B<% else_if IsSet %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'AD', 'AD',
$this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% end_if %>D') $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'ADE', 'ADE',
$this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E') $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E')
); );
$this->assertEquals( $this->assertEquals(
'ADE', 'ADE',
$this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E') $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E')
); );
// Dot syntax // Dot syntax
$this->assertEquals( $this->assertEquals(
'ACD', 'ACD',
$this->render('A<% if Foo.NotSet %>B<% else_if Foo.IsSet %>C<% end_if %>D') $this->render('A<% if Foo.NotSet %>B<% else_if Foo.IsSet %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'ACD', 'ACD',
$this->render('A<% if Foo.Bar.NotSet %>B<% else_if Foo.Bar.IsSet %>C<% end_if %>D') $this->render('A<% if Foo.Bar.NotSet %>B<% else_if Foo.Bar.IsSet %>C<% end_if %>D')
); );
// Params // Params
$this->assertEquals( $this->assertEquals(
'ACD', 'ACD',
$this->render('A<% if NotSet(Param) %>B<% else %>C<% end_if %>D') $this->render('A<% if NotSet(Param) %>B<% else %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'ABD', 'ABD',
$this->render('A<% if IsSet(Param) %>B<% else %>C<% end_if %>D') $this->render('A<% if IsSet(Param) %>B<% else %>C<% end_if %>D')
); );
// Negation // Negation
$this->assertEquals( $this->assertEquals(
'AC', 'AC',
$this->render('A<% if not IsSet %>B<% end_if %>C') $this->render('A<% if not IsSet %>B<% end_if %>C')
); );
$this->assertEquals( $this->assertEquals(
'ABC', 'ABC',
$this->render('A<% if not NotSet %>B<% end_if %>C') $this->render('A<% if not NotSet %>B<% end_if %>C')
); );
// Or // Or
$this->assertEquals( $this->assertEquals(
'ABD', 'ABD',
$this->render('A<% if IsSet || NotSet %>B<% else_if A %>C<% end_if %>D') $this->render('A<% if IsSet || NotSet %>B<% else_if A %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'ACD', 'ACD',
$this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet %>C<% end_if %>D') $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'AD', 'AD',
$this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet3 %>C<% end_if %>D') $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet3 %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'ACD', 'ACD',
$this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet || NotSet %>C<% end_if %>D') $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet || NotSet %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'AD', 'AD',
$this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet2 || NotSet3 %>C<% end_if %>D') $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet2 || NotSet3 %>C<% end_if %>D')
); );
// Negated Or // Negated Or
$this->assertEquals( $this->assertEquals(
'ACD', 'ACD',
$this->render('A<% if not IsSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D') $this->render('A<% if not IsSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'ABD', 'ABD',
$this->render('A<% if not NotSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D') $this->render('A<% if not NotSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'ABD', 'ABD',
$this->render('A<% if NotSet || not AlsoNotSet %>B<% else_if A %>C<% end_if %>D') $this->render('A<% if NotSet || not AlsoNotSet %>B<% else_if A %>C<% end_if %>D')
); );
// And // And
$this->assertEquals( $this->assertEquals(
'ABD', 'ABD',
$this->render('A<% if IsSet && AlsoSet %>B<% else_if A %>C<% end_if %>D') $this->render('A<% if IsSet && AlsoSet %>B<% else_if A %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'ACD', 'ACD',
$this->render('A<% if IsSet && NotSet %>B<% else_if IsSet %>C<% end_if %>D') $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'AD', 'AD',
$this->render('A<% if NotSet && NotSet2 %>B<% else_if NotSet3 %>C<% end_if %>D') $this->render('A<% if NotSet && NotSet2 %>B<% else_if NotSet3 %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'ACD', 'ACD',
$this->render('A<% if IsSet && NotSet %>B<% else_if IsSet && AlsoSet %>C<% end_if %>D') $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet && AlsoSet %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'AD', 'AD',
$this->render('A<% if NotSet && NotSet2 %>B<% else_if IsSet && NotSet3 %>C<% end_if %>D') $this->render('A<% if NotSet && NotSet2 %>B<% else_if IsSet && NotSet3 %>C<% end_if %>D')
); );
// Equality // Equality
$this->assertEquals( $this->assertEquals(
'ABC', 'ABC',
$this->render('A<% if RawVal == RawVal %>B<% end_if %>C') $this->render('A<% if RawVal == RawVal %>B<% end_if %>C')
); );
$this->assertEquals( $this->assertEquals(
'ACD', 'ACD',
$this->render('A<% if Right == Wrong %>B<% else_if RawVal == RawVal %>C<% end_if %>D') $this->render('A<% if Right == Wrong %>B<% else_if RawVal == RawVal %>C<% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'ABC', 'ABC',
$this->render('A<% if Right != Wrong %>B<% end_if %>C') $this->render('A<% if Right != Wrong %>B<% end_if %>C')
); );
$this->assertEquals( $this->assertEquals(
'AD', 'AD',
$this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% end_if %>D') $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% end_if %>D')
); );
// test inequalities with simple numbers // 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('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('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('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('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('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('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, // empty else_if and else tags, if this would not be supported,
// the output would stop after A, thereby failing the assert // 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 IsSet %><% else %><% end_if %>D'));
$this->assertEquals( $this->assertEquals(
'AD', 'AD',
$this->render('A<% if NotSet %><% else_if IsSet %><% else %><% end_if %>D') $this->render('A<% if NotSet %><% else_if IsSet %><% else %><% end_if %>D')
); );
$this->assertEquals( $this->assertEquals(
'AD', 'AD',
$this->render('A<% if NotSet %><% else_if AlsoNotSet %><% else %><% end_if %>D') $this->render('A<% if NotSet %><% else_if AlsoNotSet %><% else %><% end_if %>D')
); );
// Bare words with ending space // Bare words with ending space
$this->assertEquals( $this->assertEquals(
'ABC', 'ABC',
$this->render('A<% if "RawVal" == RawVal %>B<% end_if %>C') $this->render('A<% if "RawVal" == RawVal %>B<% end_if %>C')
); );
// Else // Else
$this->assertEquals( $this->assertEquals(
'ADE', 'ADE',
$this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% else %>D<% end_if %>E') $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% else %>D<% end_if %>E')
); );
// Empty if with else // Empty if with else
$this->assertEquals( $this->assertEquals(
'ABC', 'ABC',
$this->render('A<% if NotSet %><% else %>B<% end_if %>C') $this->render('A<% if NotSet %><% else %>B<% end_if %>C')
); );
} }
public function testBaseTagGeneration() public function testBaseTagGeneration()
{ {
// XHTML wil have a closed base tag // XHTML wil have a closed base tag
$tmpl1 = '<?xml version="1.0" encoding="UTF-8"?> $tmpl1 = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
. ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> . ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html> <html>
<head><% base_tag %></head> <head><% base_tag %></head>
<body><p>test</p><body> <body><p>test</p><body>
</html>'; </html>';
$this->assertRegExp('/<head><base href=".*" \/><\/head>/', $this->render($tmpl1)); $this->assertRegExp('/<head><base href=".*" \/><\/head>/', $this->render($tmpl1));
// HTML4 and 5 will only have it for IE // HTML4 and 5 will only have it for IE
$tmpl2 = '<!DOCTYPE html> $tmpl2 = '<!DOCTYPE html>
<html> <html>
<head><% base_tag %></head> <head><% base_tag %></head>
<body><p>test</p><body> <body><p>test</p><body>
</html>'; </html>';
$this->assertRegExp( $this->assertRegExp(
'/<head><base href=".*"><!--\[if lte IE 6\]><\/base><!\[endif\]--><\/head>/', '/<head><base href=".*"><!--\[if lte IE 6\]><\/base><!\[endif\]--><\/head>/',
$this->render($tmpl2) $this->render($tmpl2)
); );
$tmpl3 = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> $tmpl3 = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html> <html>
<head><% base_tag %></head> <head><% base_tag %></head>
<body><p>test</p><body> <body><p>test</p><body>
</html>'; </html>';
$this->assertRegExp( $this->assertRegExp(
'/<head><base href=".*"><!--\[if lte IE 6\]><\/base><!\[endif\]--><\/head>/', '/<head><base href=".*"><!--\[if lte IE 6\]><\/base><!\[endif\]--><\/head>/',
$this->render($tmpl3) $this->render($tmpl3)
); );
// Check that the content negotiator converts to the equally legal formats // Check that the content negotiator converts to the equally legal formats
$negotiator = new ContentNegotiator(); $negotiator = new ContentNegotiator();
$response = new HTTPResponse($this->render($tmpl1)); $response = new HTTPResponse($this->render($tmpl1));
$negotiator->html($response); $negotiator->html($response);
$this->assertRegExp( $this->assertRegExp(
'/<head><base href=".*"><!--\[if lte IE 6\]><\/base><!\[endif\]--><\/head>/', '/<head><base href=".*"><!--\[if lte IE 6\]><\/base><!\[endif\]--><\/head>/',
$response->getBody() $response->getBody()
); );
$response = new HTTPResponse($this->render($tmpl1)); $response = new HTTPResponse($this->render($tmpl1));
$negotiator->xhtml($response); $negotiator->xhtml($response);
$this->assertRegExp('/<head><base href=".*" \/><\/head>/', $response->getBody()); $this->assertRegExp('/<head><base href=".*" \/><\/head>/', $response->getBody());
} }
public function testIncludeWithArguments() public function testIncludeWithArguments()
{ {
$this->assertEquals( $this->assertEquals(
$this->render('<% include SSViewerTestIncludeWithArguments %>'), $this->render('<% include SSViewerTestIncludeWithArguments %>'),
'<p>[out:Arg1]</p><p>[out:Arg2]</p>' '<p>[out:Arg1]</p><p>[out:Arg2]</p>'
); );
$this->assertEquals( $this->assertEquals(
$this->render('<% include SSViewerTestIncludeWithArguments Arg1=A %>'), $this->render('<% include SSViewerTestIncludeWithArguments Arg1=A %>'),
'<p>A</p><p>[out:Arg2]</p>' '<p>A</p><p>[out:Arg2]</p>'
); );
$this->assertEquals( $this->assertEquals(
$this->render('<% include SSViewerTestIncludeWithArguments Arg1=A, Arg2=B %>'), $this->render('<% include SSViewerTestIncludeWithArguments Arg1=A, Arg2=B %>'),
'<p>A</p><p>B</p>' '<p>A</p><p>B</p>'
); );
$this->assertEquals( $this->assertEquals(
$this->render('<% include SSViewerTestIncludeWithArguments Arg1=A Bare String, Arg2=B Bare String %>'), $this->render('<% include SSViewerTestIncludeWithArguments Arg1=A Bare String, Arg2=B Bare String %>'),
'<p>A Bare String</p><p>B Bare String</p>' '<p>A Bare String</p><p>B Bare String</p>'
); );
$this->assertEquals( $this->assertEquals(
$this->render( $this->render(
'<% include SSViewerTestIncludeWithArguments Arg1="A", Arg2=$B %>', '<% include SSViewerTestIncludeWithArguments Arg1="A", Arg2=$B %>',
new ArrayData(array('B' => 'Bar')) new ArrayData(array('B' => 'Bar'))
), ),
'<p>A</p><p>Bar</p>' '<p>A</p><p>Bar</p>'
); );
$this->assertEquals( $this->assertEquals(
$this->render( $this->render(
'<% include SSViewerTestIncludeWithArguments Arg1="A" %>', '<% include SSViewerTestIncludeWithArguments Arg1="A" %>',
new ArrayData(array('Arg1' => 'Foo', 'Arg2' => 'Bar')) new ArrayData(array('Arg1' => 'Foo', 'Arg2' => 'Bar'))
), ),
'<p>A</p><p>Bar</p>' '<p>A</p><p>Bar</p>'
); );
$this->assertEquals( $this->assertEquals(
$this->render( $this->render(
'<% include SSViewerTestIncludeScopeInheritanceWithArgsInLoop Title="SomeArg" %>', '<% include SSViewerTestIncludeScopeInheritanceWithArgsInLoop Title="SomeArg" %>',
new ArrayData( new ArrayData(
@ -1009,17 +1008,17 @@ public function testIncludeWithArguments()
) )
), ),
'SomeArg - Foo - Bar - SomeArg' 'SomeArg - Foo - Bar - SomeArg'
); );
$this->assertEquals( $this->assertEquals(
$this->render( $this->render(
'<% include SSViewerTestIncludeScopeInheritanceWithArgsInWith Title="A" %>', '<% include SSViewerTestIncludeScopeInheritanceWithArgsInWith Title="A" %>',
new ArrayData(array('Item' => new ArrayData(array('Title' =>'B')))) new ArrayData(array('Item' => new ArrayData(array('Title' =>'B'))))
), ),
'A - B - A' 'A - B - A'
); );
$this->assertEquals( $this->assertEquals(
$this->render( $this->render(
'<% include SSViewerTestIncludeScopeInheritanceWithArgsInNestedWith Title="A" %>', '<% include SSViewerTestIncludeScopeInheritanceWithArgsInNestedWith Title="A" %>',
new ArrayData( new ArrayData(
@ -1032,9 +1031,9 @@ public function testIncludeWithArguments()
) )
), ),
'A - B - C - B - A' 'A - B - C - B - A'
); );
$this->assertEquals( $this->assertEquals(
$this->render( $this->render(
'<% include SSViewerTestIncludeScopeInheritanceWithUpAndTop Title="A" %>', '<% include SSViewerTestIncludeScopeInheritanceWithUpAndTop Title="A" %>',
new ArrayData( new ArrayData(
@ -1047,9 +1046,9 @@ public function testIncludeWithArguments()
) )
), ),
'A - A - A' 'A - A - A'
); );
$data = new ArrayData( $data = new ArrayData(
array( array(
'Nested' => new ArrayData( 'Nested' => new ArrayData(
array( array(
@ -1058,36 +1057,36 @@ public function testIncludeWithArguments()
), ),
'Object' => new ArrayData(array('Key' => 'B')) 'Object' => new ArrayData(array('Key' => 'B'))
) )
); );
$tmpl = SSViewer::fromString('<% include SSViewerTestIncludeObjectArguments A=$Nested.Object, B=$Object %>'); $tmpl = SSViewer::fromString('<% include SSViewerTestIncludeObjectArguments A=$Nested.Object, B=$Object %>');
$res = $tmpl->process($data); $res = $tmpl->process($data);
$this->assertEqualIgnoringWhitespace('A B', $res, 'Objects can be passed as named arguments'); $this->assertEqualIgnoringWhitespace('A B', $res, 'Objects can be passed as named arguments');
} }
public function testNamespaceInclude() public function testNamespaceInclude()
{ {
$data = new ArrayData([]); $data = new ArrayData([]);
$this->assertEquals( $this->assertEquals(
"tests:( NamespaceInclude\n )", "tests:( NamespaceInclude\n )",
$this->render('tests:( <% include Namespace\NamespaceInclude %> )', $data), $this->render('tests:( <% include Namespace\NamespaceInclude %> )', $data),
'Backslashes work for namespace references in includes' 'Backslashes work for namespace references in includes'
); );
$this->assertEquals( $this->assertEquals(
"tests:( NamespaceInclude\n )", "tests:( NamespaceInclude\n )",
$this->render('tests:( <% include Namespace/NamespaceInclude %> )', $data), $this->render('tests:( <% include Namespace/NamespaceInclude %> )', $data),
'Forward slashes work for namespace references in includes' 'Forward slashes work for namespace references in includes'
); );
} }
public function testRecursiveInclude() public function testRecursiveInclude()
{ {
$view = new SSViewer(array('Includes/SSViewerTestRecursiveInclude')); $view = new SSViewer(array('Includes/SSViewerTestRecursiveInclude'));
$data = new ArrayData( $data = new ArrayData(
array( array(
'Title' => 'A', 'Title' => 'A',
'Children' => new ArrayList( 'Children' => new ArrayList(
@ -1108,79 +1107,79 @@ public function testRecursiveInclude()
) )
), ),
) )
); );
$result = $view->process($data); $result = $view->process($data);
// We don't care about whitespace // We don't care about whitespace
$rationalisedResult = trim(preg_replace('/\s+/', ' ', $result)); $rationalisedResult = trim(preg_replace('/\s+/', ' ', $result));
$this->assertEquals('A A1 A1 i A1 ii A2 A3', $rationalisedResult); $this->assertEquals('A A1 A1 i A1 ii A2 A3', $rationalisedResult);
} }
public function assertEqualIgnoringWhitespace($a, $b, $message = '') public function assertEqualIgnoringWhitespace($a, $b, $message = '')
{ {
$this->assertEquals(preg_replace('/\s+/', '', $a), preg_replace('/\s+/', '', $b), $message); $this->assertEquals(preg_replace('/\s+/', '', $a), preg_replace('/\s+/', '', $b), $message);
} }
/** /**
* See {@link ViewableDataTest} for more extensive casting tests, * See {@link ViewableDataTest} for more extensive casting tests,
* this test just ensures that basic casting is correctly applied during template parsing. * this test just ensures that basic casting is correctly applied during template parsing.
*/ */
public function testCastingHelpers() public function testCastingHelpers()
{ {
$vd = new SSViewerTest\TestViewableData(); $vd = new SSViewerTest\TestViewableData();
$vd->TextValue = '<b>html</b>'; $vd->TextValue = '<b>html</b>';
$vd->HTMLValue = '<b>html</b>'; $vd->HTMLValue = '<b>html</b>';
$vd->UncastedValue = '<b>html</b>'; $vd->UncastedValue = '<b>html</b>';
// Value casted as "Text" // Value casted as "Text"
$this->assertEquals( $this->assertEquals(
'&lt;b&gt;html&lt;/b&gt;', '&lt;b&gt;html&lt;/b&gt;',
$t = SSViewer::fromString('$TextValue')->process($vd) $t = SSViewer::fromString('$TextValue')->process($vd)
); );
$this->assertEquals( $this->assertEquals(
'<b>html</b>', '<b>html</b>',
$t = SSViewer::fromString('$TextValue.RAW')->process($vd) $t = SSViewer::fromString('$TextValue.RAW')->process($vd)
); );
$this->assertEquals( $this->assertEquals(
'&lt;b&gt;html&lt;/b&gt;', '&lt;b&gt;html&lt;/b&gt;',
$t = SSViewer::fromString('$TextValue.XML')->process($vd) $t = SSViewer::fromString('$TextValue.XML')->process($vd)
); );
// Value casted as "HTMLText" // Value casted as "HTMLText"
$this->assertEquals( $this->assertEquals(
'<b>html</b>', '<b>html</b>',
$t = SSViewer::fromString('$HTMLValue')->process($vd) $t = SSViewer::fromString('$HTMLValue')->process($vd)
); );
$this->assertEquals( $this->assertEquals(
'<b>html</b>', '<b>html</b>',
$t = SSViewer::fromString('$HTMLValue.RAW')->process($vd) $t = SSViewer::fromString('$HTMLValue.RAW')->process($vd)
); );
$this->assertEquals( $this->assertEquals(
'&lt;b&gt;html&lt;/b&gt;', '&lt;b&gt;html&lt;/b&gt;',
$t = SSViewer::fromString('$HTMLValue.XML')->process($vd) $t = SSViewer::fromString('$HTMLValue.XML')->process($vd)
); );
// Uncasted value (falls back to ViewableData::$default_cast="Text") // Uncasted value (falls back to ViewableData::$default_cast="Text")
$vd = new SSViewerTest\TestViewableData(); $vd = new SSViewerTest\TestViewableData();
$vd->UncastedValue = '<b>html</b>'; $vd->UncastedValue = '<b>html</b>';
$this->assertEquals( $this->assertEquals(
'&lt;b&gt;html&lt;/b&gt;', '&lt;b&gt;html&lt;/b&gt;',
$t = SSViewer::fromString('$UncastedValue')->process($vd) $t = SSViewer::fromString('$UncastedValue')->process($vd)
); );
$this->assertEquals( $this->assertEquals(
'<b>html</b>', '<b>html</b>',
$t = SSViewer::fromString('$UncastedValue.RAW')->process($vd) $t = SSViewer::fromString('$UncastedValue.RAW')->process($vd)
); );
$this->assertEquals( $this->assertEquals(
'&lt;b&gt;html&lt;/b&gt;', '&lt;b&gt;html&lt;/b&gt;',
$t = SSViewer::fromString('$UncastedValue.XML')->process($vd) $t = SSViewer::fromString('$UncastedValue.XML')->process($vd)
); );
} }
public function testSSViewerBasicIteratorSupport() public function testSSViewerBasicIteratorSupport()
{ {
$data = new ArrayData( $data = new ArrayData(
array( array(
'Set' => new ArrayList( 'Set' => new ArrayList(
array( array(
@ -1197,129 +1196,129 @@ public function testSSViewerBasicIteratorSupport()
) )
) )
) )
); );
//base test //base test
$result = $this->render('<% loop Set %>$Number<% end_loop %>', $data); $result = $this->render('<% loop Set %>$Number<% end_loop %>', $data);
$this->assertEquals("12345678910", $result, "Numbers rendered in order"); $this->assertEquals("12345678910", $result, "Numbers rendered in order");
//test First //test First
$result = $this->render('<% loop Set %><% if First %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if First %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("1", $result, "Only the first number is rendered"); $this->assertEquals("1", $result, "Only the first number is rendered");
//test Last //test Last
$result = $this->render('<% loop Set %><% if Last %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if Last %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("10", $result, "Only the last number is rendered"); $this->assertEquals("10", $result, "Only the last number is rendered");
//test Even //test Even
$result = $this->render('<% loop Set %><% if Even() %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if Even() %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("246810", $result, "Even numbers rendered in order"); $this->assertEquals("246810", $result, "Even numbers rendered in order");
//test Even with quotes //test Even with quotes
$result = $this->render('<% loop Set %><% if Even("1") %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if Even("1") %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("246810", $result, "Even numbers rendered in order"); $this->assertEquals("246810", $result, "Even numbers rendered in order");
//test Even without quotes //test Even without quotes
$result = $this->render('<% loop Set %><% if Even(1) %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if Even(1) %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("246810", $result, "Even numbers rendered in order"); $this->assertEquals("246810", $result, "Even numbers rendered in order");
//test Even with zero-based start index //test Even with zero-based start index
$result = $this->render('<% loop Set %><% if Even("0") %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if Even("0") %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("13579", $result, "Even (with zero-based index) numbers rendered in order"); $this->assertEquals("13579", $result, "Even (with zero-based index) numbers rendered in order");
//test Odd //test Odd
$result = $this->render('<% loop Set %><% if Odd %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if Odd %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("13579", $result, "Odd numbers rendered in order"); $this->assertEquals("13579", $result, "Odd numbers rendered in order");
//test FirstLast //test FirstLast
$result = $this->render('<% loop Set %><% if FirstLast %>$Number$FirstLast<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if FirstLast %>$Number$FirstLast<% end_if %><% end_loop %>', $data);
$this->assertEquals("1first10last", $result, "First and last numbers rendered in order"); $this->assertEquals("1first10last", $result, "First and last numbers rendered in order");
//test Middle //test Middle
$result = $this->render('<% loop Set %><% if Middle %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if Middle %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("23456789", $result, "Middle numbers rendered in order"); $this->assertEquals("23456789", $result, "Middle numbers rendered in order");
//test MiddleString //test MiddleString
$result = $this->render( $result = $this->render(
'<% loop Set %><% if MiddleString == "middle" %>$Number$MiddleString<% end_if %>' '<% loop Set %><% if MiddleString == "middle" %>$Number$MiddleString<% end_if %>'
. '<% end_loop %>', . '<% end_loop %>',
$data $data
); );
$this->assertEquals( $this->assertEquals(
"2middle3middle4middle5middle6middle7middle8middle9middle", "2middle3middle4middle5middle6middle7middle8middle9middle",
$result, $result,
"Middle numbers rendered in order" "Middle numbers rendered in order"
); );
//test EvenOdd //test EvenOdd
$result = $this->render('<% loop Set %>$EvenOdd<% end_loop %>', $data); $result = $this->render('<% loop Set %>$EvenOdd<% end_loop %>', $data);
$this->assertEquals( $this->assertEquals(
"oddevenoddevenoddevenoddevenoddeven", "oddevenoddevenoddevenoddevenoddeven",
$result, $result,
"Even and Odd is returned in sequence numbers rendered in order" "Even and Odd is returned in sequence numbers rendered in order"
); );
//test Pos //test Pos
$result = $this->render('<% loop Set %>$Pos<% end_loop %>', $data); $result = $this->render('<% loop Set %>$Pos<% end_loop %>', $data);
$this->assertEquals("12345678910", $result, '$Pos is rendered in order'); $this->assertEquals("12345678910", $result, '$Pos is rendered in order');
//test Pos //test Pos
$result = $this->render('<% loop Set %>$Pos(0)<% end_loop %>', $data); $result = $this->render('<% loop Set %>$Pos(0)<% end_loop %>', $data);
$this->assertEquals("0123456789", $result, '$Pos(0) is rendered in order'); $this->assertEquals("0123456789", $result, '$Pos(0) is rendered in order');
//test FromEnd //test FromEnd
$result = $this->render('<% loop Set %>$FromEnd<% end_loop %>', $data); $result = $this->render('<% loop Set %>$FromEnd<% end_loop %>', $data);
$this->assertEquals("10987654321", $result, '$FromEnd is rendered in order'); $this->assertEquals("10987654321", $result, '$FromEnd is rendered in order');
//test FromEnd //test FromEnd
$result = $this->render('<% loop Set %>$FromEnd(0)<% end_loop %>', $data); $result = $this->render('<% loop Set %>$FromEnd(0)<% end_loop %>', $data);
$this->assertEquals("9876543210", $result, '$FromEnd(0) rendered in order'); $this->assertEquals("9876543210", $result, '$FromEnd(0) rendered in order');
//test Total //test Total
$result = $this->render('<% loop Set %>$TotalItems<% end_loop %>', $data); $result = $this->render('<% loop Set %>$TotalItems<% end_loop %>', $data);
$this->assertEquals("10101010101010101010", $result, "10 total items X 10 are returned"); $this->assertEquals("10101010101010101010", $result, "10 total items X 10 are returned");
//test Modulus //test Modulus
$result = $this->render('<% loop Set %>$Modulus(2,1)<% end_loop %>', $data); $result = $this->render('<% loop Set %>$Modulus(2,1)<% end_loop %>', $data);
$this->assertEquals("1010101010", $result, "1-indexed pos modular divided by 2 rendered in order"); $this->assertEquals("1010101010", $result, "1-indexed pos modular divided by 2 rendered in order");
//test MultipleOf 3 //test MultipleOf 3
$result = $this->render('<% loop Set %><% if MultipleOf(3) %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if MultipleOf(3) %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("369", $result, "Only numbers that are multiples of 3 are returned"); $this->assertEquals("369", $result, "Only numbers that are multiples of 3 are returned");
//test MultipleOf 4 //test MultipleOf 4
$result = $this->render('<% loop Set %><% if MultipleOf(4) %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if MultipleOf(4) %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("48", $result, "Only numbers that are multiples of 4 are returned"); $this->assertEquals("48", $result, "Only numbers that are multiples of 4 are returned");
//test MultipleOf 5 //test MultipleOf 5
$result = $this->render('<% loop Set %><% if MultipleOf(5) %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if MultipleOf(5) %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("510", $result, "Only numbers that are multiples of 5 are returned"); $this->assertEquals("510", $result, "Only numbers that are multiples of 5 are returned");
//test MultipleOf 10 //test MultipleOf 10
$result = $this->render('<% loop Set %><% if MultipleOf(10,1) %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if MultipleOf(10,1) %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("10", $result, "Only numbers that are multiples of 10 (with 1-based indexing) are returned"); $this->assertEquals("10", $result, "Only numbers that are multiples of 10 (with 1-based indexing) are returned");
//test MultipleOf 9 zero-based //test MultipleOf 9 zero-based
$result = $this->render('<% loop Set %><% if MultipleOf(9,0) %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if MultipleOf(9,0) %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals( $this->assertEquals(
"110", "110",
$result, $result,
"Only numbers that are multiples of 9 with zero-based indexing are returned. (The first and last item)" "Only numbers that are multiples of 9 with zero-based indexing are returned. (The first and last item)"
); );
//test MultipleOf 11 //test MultipleOf 11
$result = $this->render('<% loop Set %><% if MultipleOf(11) %>$Number<% end_if %><% end_loop %>', $data); $result = $this->render('<% loop Set %><% if MultipleOf(11) %>$Number<% end_if %><% end_loop %>', $data);
$this->assertEquals("", $result, "Only numbers that are multiples of 11 are returned. I.e. nothing returned"); $this->assertEquals("", $result, "Only numbers that are multiples of 11 are returned. I.e. nothing returned");
} }
/** /**
* Test $Up works when the scope $Up refers to was entered with a "with" block * Test $Up works when the scope $Up refers to was entered with a "with" block
*/ */
public function testUpInWith() public function testUpInWith()
{ {
// Data to run the loop tests on - three levels deep // Data to run the loop tests on - three levels deep
$data = new ArrayData( $data = new ArrayData(
array( array(
'Name' => 'Top', 'Name' => 'Top',
'Foo' => new ArrayData( 'Foo' => new ArrayData(
@ -1343,71 +1342,71 @@ public function testUpInWith()
) )
) )
) )
); );
// Basic functionality // Basic functionality
$this->assertEquals( $this->assertEquals(
'BarFoo', 'BarFoo',
$this->render('<% with Foo %><% with Bar %>{$Name}{$Up.Name}<% end_with %><% end_with %>', $data) $this->render('<% with Foo %><% with Bar %>{$Name}{$Up.Name}<% end_with %><% end_with %>', $data)
); );
// Two level with block, up refers to internally referenced Bar // Two level with block, up refers to internally referenced Bar
$this->assertEquals( $this->assertEquals(
'BarFoo', 'BarFoo',
$this->render('<% with Foo.Bar %>{$Name}{$Up.Name}<% end_with %>', $data) $this->render('<% with Foo.Bar %>{$Name}{$Up.Name}<% end_with %>', $data)
); );
// Stepping up & back down the scope tree // Stepping up & back down the scope tree
$this->assertEquals( $this->assertEquals(
'BazBarQux', 'BazBarQux',
$this->render('<% with Foo.Bar.Baz %>{$Name}{$Up.Name}{$Up.Qux.Name}<% end_with %>', $data) $this->render('<% with Foo.Bar.Baz %>{$Name}{$Up.Name}{$Up.Qux.Name}<% end_with %>', $data)
); );
// Using $Up in a with block // Using $Up in a with block
$this->assertEquals( $this->assertEquals(
'BazBarQux', 'BazBarQux',
$this->render( $this->render(
'<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}{$Qux.Name}<% end_with %>' '<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}{$Qux.Name}<% end_with %>'
.'<% end_with %>', .'<% end_with %>',
$data $data
) )
); );
// Stepping up & back down the scope tree with with blocks // Stepping up & back down the scope tree with with blocks
$this->assertEquals( $this->assertEquals(
'BazBarQuxBarBaz', 'BazBarQuxBarBaz',
$this->render( $this->render(
'<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}<% with Qux %>{$Name}<% end_with %>' '<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}<% with Qux %>{$Name}<% end_with %>'
. '{$Name}<% end_with %>{$Name}<% end_with %>', . '{$Name}<% end_with %>{$Name}<% end_with %>',
$data $data
) )
); );
// Using $Up.Up, where first $Up points to a previous scope entered using $Up, thereby skipping up to Foo // Using $Up.Up, where first $Up points to a previous scope entered using $Up, thereby skipping up to Foo
$this->assertEquals( $this->assertEquals(
'Foo', 'Foo',
$this->render( $this->render(
'<% with Foo.Bar.Baz %><% with Up %><% with Qux %>{$Up.Up.Name}<% end_with %><% end_with %>' '<% with Foo.Bar.Baz %><% with Up %><% with Qux %>{$Up.Up.Name}<% end_with %><% end_with %>'
. '<% end_with %>', . '<% end_with %>',
$data $data
) )
); );
// Using $Up.Up, where first $Up points to an Up used in a local scope lookup, should still skip to Foo // Using $Up.Up, where first $Up points to an Up used in a local scope lookup, should still skip to Foo
$this->assertEquals( $this->assertEquals(
'Foo', 'Foo',
$this->render('<% with Foo.Bar.Baz.Up.Qux %>{$Up.Up.Name}<% end_with %>', $data) $this->render('<% with Foo.Bar.Baz.Up.Qux %>{$Up.Up.Name}<% end_with %>', $data)
); );
} }
/** /**
* Test $Up works when the scope $Up refers to was entered with a "loop" block * Test $Up works when the scope $Up refers to was entered with a "loop" block
*/ */
public function testUpInLoop() public function testUpInLoop()
{ {
// Data to run the loop tests on - one sequence of three items, each with a subitem // Data to run the loop tests on - one sequence of three items, each with a subitem
$data = new ArrayData( $data = new ArrayData(
array( array(
'Name' => 'Top', 'Name' => 'Top',
'Foo' => new ArrayList( 'Foo' => new ArrayList(
@ -1445,20 +1444,20 @@ public function testUpInLoop()
) )
) )
) )
); );
// Make sure inside a loop, $Up refers to the current item of the loop // Make sure inside a loop, $Up refers to the current item of the loop
$this->assertEqualIgnoringWhitespace( $this->assertEqualIgnoringWhitespace(
'111 222 333', '111 222 333',
$this->render( $this->render(
'<% loop $Foo %>$Name<% with $Sub %>$Up.Name<% end_with %>$Name<% end_loop %>', '<% loop $Foo %>$Name<% with $Sub %>$Up.Name<% end_with %>$Name<% end_loop %>',
$data $data
) )
); );
// Make sure inside a loop, looping over $Up uses a separate iterator, // Make sure inside a loop, looping over $Up uses a separate iterator,
// and doesn't interfere with the original iterator // and doesn't interfere with the original iterator
$this->assertEqualIgnoringWhitespace( $this->assertEqualIgnoringWhitespace(
'1Bar123Bar1 2Baz123Baz2 3Qux123Qux3', '1Bar123Bar1 2Baz123Baz2 3Qux123Qux3',
$this->render( $this->render(
'<% loop $Foo %> '<% loop $Foo %>
@ -1472,11 +1471,11 @@ public function testUpInLoop()
<% end_loop %>', <% end_loop %>',
$data $data
) )
); );
// Make sure inside a loop, looping over $Up uses a separate iterator, // Make sure inside a loop, looping over $Up uses a separate iterator,
// and doesn't interfere with the original iterator or local lookups // and doesn't interfere with the original iterator or local lookups
$this->assertEqualIgnoringWhitespace( $this->assertEqualIgnoringWhitespace(
'1 Bar1 123 1Bar 1 2 Baz2 123 2Baz 2 3 Qux3 123 3Qux 3', '1 Bar1 123 1Bar 1 2 Baz2 123 2Baz 2 3 Qux3 123 3Qux 3',
$this->render( $this->render(
'<% loop $Foo %> '<% loop $Foo %>
@ -1490,18 +1489,18 @@ public function testUpInLoop()
<% end_loop %>', <% end_loop %>',
$data $data
) )
); );
} }
/** /**
* Test that nested loops restore the loop variables correctly when pushing and popping states * Test that nested loops restore the loop variables correctly when pushing and popping states
*/ */
public function testNestedLoops() public function testNestedLoops()
{ {
// Data to run the loop tests on - one sequence of three items, one with child elements // Data to run the loop tests on - one sequence of three items, one with child elements
// (of a different size to the main sequence) // (of a different size to the main sequence)
$data = new ArrayData( $data = new ArrayData(
array( array(
'Foo' => new ArrayList( 'Foo' => new ArrayList(
array( array(
@ -1539,23 +1538,23 @@ public function testNestedLoops()
) )
), ),
) )
); );
// Make sure that including a loop inside a loop will not destroy the internal count of // Make sure that including a loop inside a loop will not destroy the internal count of
// items, checked by using "Last" // items, checked by using "Last"
$this->assertEqualIgnoringWhitespace( $this->assertEqualIgnoringWhitespace(
'1ab23last', '1ab23last',
$this->render( $this->render(
'<% loop $Foo %>$Name<% loop Children %>$Name<% end_loop %><% if Last %>last<% end_if %>' '<% loop $Foo %>$Name<% loop Children %>$Name<% end_loop %><% if Last %>last<% end_if %>'
. '<% end_loop %>', . '<% end_loop %>',
$data $data
) )
); );
} }
public function testLayout() public function testLayout()
{ {
$this->useTestTheme( $this->useTestTheme(
__DIR__.'/SSViewerTest', __DIR__.'/SSViewerTest',
'layouttest', 'layouttest',
function () { function () {
@ -1565,15 +1564,15 @@ public function testLayout()
$template = new SSViewer(array('Shortcodes', 'Page')); $template = new SSViewer(array('Shortcodes', 'Page'));
$this->assertEquals("[file_link]\n\n", $template->process(new ArrayData(array()))); $this->assertEquals("[file_link]\n\n", $template->process(new ArrayData(array())));
} }
); );
} }
/** /**
* @covers \SilverStripe\View\SSViewer::get_templates_by_class() * @covers \SilverStripe\View\SSViewer::get_templates_by_class()
*/ */
public function testGetTemplatesByClass() public function testGetTemplatesByClass()
{ {
$this->useTestTheme( $this->useTestTheme(
__DIR__ . '/SSViewerTest', __DIR__ . '/SSViewerTest',
'layouttest', 'layouttest',
function () { function () {
@ -1644,25 +1643,25 @@ public function testGetTemplatesByClass()
$this->setExpectedException('InvalidArgumentException'); $this->setExpectedException('InvalidArgumentException');
SSViewer::get_templates_by_class(array()); SSViewer::get_templates_by_class(array());
} }
); );
} }
public function testRewriteHashlinks() public function testRewriteHashlinks()
{ {
SSViewer::config()->update('rewrite_hash_links', true); SSViewer::config()->update('rewrite_hash_links', true);
$_SERVER['HTTP_HOST'] = 'www.mysite.com'; $_SERVER['HTTP_HOST'] = 'www.mysite.com';
$_SERVER['REQUEST_URI'] = '//file.com?foo"onclick="alert(\'xss\')""'; $_SERVER['REQUEST_URI'] = '//file.com?foo"onclick="alert(\'xss\')""';
// Emulate SSViewer::process() // Emulate SSViewer::process()
// Note that leading double slashes have been rewritten to prevent these being mis-interepreted // Note that leading double slashes have been rewritten to prevent these being mis-interepreted
// as protocol-less absolute urls // as protocol-less absolute urls
$base = Convert::raw2att('/file.com?foo"onclick="alert(\'xss\')""'); $base = Convert::raw2att('/file.com?foo"onclick="alert(\'xss\')""');
$tmplFile = TEMP_FOLDER . '/SSViewerTest_testRewriteHashlinks_' . sha1(rand()) . '.ss'; $tmplFile = TEMP_FOLDER . '/SSViewerTest_testRewriteHashlinks_' . sha1(rand()) . '.ss';
// Note: SSViewer_FromString doesn't rewrite hash links. // Note: SSViewer_FromString doesn't rewrite hash links.
file_put_contents( file_put_contents(
$tmplFile, $tmplFile,
'<!DOCTYPE html> '<!DOCTYPE html>
<html> <html>
@ -1675,51 +1674,51 @@ public function testRewriteHashlinks()
<svg><use xlink:href="#sprite"></use></svg> <svg><use xlink:href="#sprite"></use></svg>
<body> <body>
</html>' </html>'
); );
$tmpl = new SSViewer($tmplFile); $tmpl = new SSViewer($tmplFile);
$obj = new ViewableData(); $obj = new ViewableData();
$obj->InsertedLink = DBField::create_field( $obj->InsertedLink = DBField::create_field(
'HTMLFragment', 'HTMLFragment',
'<a class="inserted" href="#anchor">InsertedLink</a>' '<a class="inserted" href="#anchor">InsertedLink</a>'
); );
$obj->ExternalInsertedLink = DBField::create_field( $obj->ExternalInsertedLink = DBField::create_field(
'HTMLFragment', 'HTMLFragment',
'<a class="external-inserted" href="http://google.com#anchor">ExternalInsertedLink</a>' '<a class="external-inserted" href="http://google.com#anchor">ExternalInsertedLink</a>'
); );
$result = $tmpl->process($obj); $result = $tmpl->process($obj);
$this->assertContains( $this->assertContains(
'<a class="inserted" href="' . $base . '#anchor">InsertedLink</a>', '<a class="inserted" href="' . $base . '#anchor">InsertedLink</a>',
$result $result
); );
$this->assertContains( $this->assertContains(
'<a class="external-inserted" href="http://google.com#anchor">ExternalInsertedLink</a>', '<a class="external-inserted" href="http://google.com#anchor">ExternalInsertedLink</a>',
$result $result
); );
$this->assertContains( $this->assertContains(
'<a class="inline" href="' . $base . '#anchor">InlineLink</a>', '<a class="inline" href="' . $base . '#anchor">InlineLink</a>',
$result $result
); );
$this->assertContains( $this->assertContains(
'<a class="external-inline" href="http://google.com#anchor">ExternalInlineLink</a>', '<a class="external-inline" href="http://google.com#anchor">ExternalInlineLink</a>',
$result $result
); );
$this->assertContains( $this->assertContains(
'<svg><use xlink:href="#sprite"></use></svg>', '<svg><use xlink:href="#sprite"></use></svg>',
$result, $result,
'SSTemplateParser should only rewrite anchor hrefs' 'SSTemplateParser should only rewrite anchor hrefs'
); );
unlink($tmplFile); unlink($tmplFile);
} }
public function testRewriteHashlinksInPhpMode() public function testRewriteHashlinksInPhpMode()
{ {
SSViewer::config()->update('rewrite_hash_links', 'php'); SSViewer::config()->update('rewrite_hash_links', 'php');
$tmplFile = TEMP_FOLDER . '/SSViewerTest_testRewriteHashlinksInPhpMode_' . sha1(rand()) . '.ss'; $tmplFile = TEMP_FOLDER . '/SSViewerTest_testRewriteHashlinksInPhpMode_' . sha1(rand()) . '.ss';
// Note: SSViewer_FromString doesn't rewrite hash links. // Note: SSViewer_FromString doesn't rewrite hash links.
file_put_contents( file_put_contents(
$tmplFile, $tmplFile,
'<!DOCTYPE html> '<!DOCTYPE html>
<html> <html>
@ -1730,40 +1729,40 @@ public function testRewriteHashlinksInPhpMode()
<svg><use xlink:href="#sprite"></use></svg> <svg><use xlink:href="#sprite"></use></svg>
<body> <body>
</html>' </html>'
); );
$tmpl = new SSViewer($tmplFile); $tmpl = new SSViewer($tmplFile);
$obj = new ViewableData(); $obj = new ViewableData();
$obj->InsertedLink = DBField::create_field( $obj->InsertedLink = DBField::create_field(
'HTMLFragment', 'HTMLFragment',
'<a class="inserted" href="#anchor">InsertedLink</a>' '<a class="inserted" href="#anchor">InsertedLink</a>'
); );
$result = $tmpl->process($obj); $result = $tmpl->process($obj);
$code = <<<'EOC' $code = <<<'EOC'
<a class="inserted" href="<?php echo \SilverStripe\Core\Convert::raw2att(preg_replace("/^(\/)+/", "/", $_SERVER['REQUEST_URI'])); ?>#anchor">InsertedLink</a> <a class="inserted" href="<?php echo \SilverStripe\Core\Convert::raw2att(preg_replace("/^(\/)+/", "/", $_SERVER['REQUEST_URI'])); ?>#anchor">InsertedLink</a>
EOC; EOC;
$this->assertContains($code, $result); $this->assertContains($code, $result);
// TODO Fix inline links in PHP mode // TODO Fix inline links in PHP mode
// $this->assertContains( // $this->assertContains(
// '<a class="inline" href="<?php echo str_replace(', // '<a class="inline" href="<?php echo str_replace(',
// $result // $result
// ); // );
$this->assertContains( $this->assertContains(
'<svg><use xlink:href="#sprite"></use></svg>', '<svg><use xlink:href="#sprite"></use></svg>',
$result, $result,
'SSTemplateParser should only rewrite anchor hrefs' 'SSTemplateParser should only rewrite anchor hrefs'
); );
unlink($tmplFile); unlink($tmplFile);
} }
public function testRenderWithSourceFileComments() public function testRenderWithSourceFileComments()
{ {
Director::set_environment_type('dev'); Director::set_environment_type('dev');
SSViewer::config()->update('source_file_comments', true); SSViewer::config()->update('source_file_comments', true);
$i = __DIR__ . '/SSViewerTest/templates/Includes'; $i = __DIR__ . '/SSViewerTest/templates/Includes';
$f = __DIR__ . '/SSViewerTest/templates/SSViewerTestComments'; $f = __DIR__ . '/SSViewerTest/templates/SSViewerTestComments';
$templates = array( $templates = array(
array( array(
'name' => 'SSViewerTestCommentsFullSource', 'name' => 'SSViewerTestCommentsFullSource',
'expected' => "" 'expected' => ""
@ -1840,81 +1839,81 @@ public function testRenderWithSourceFileComments()
. "</div>" . "</div>"
. "<!-- end template $f/SSViewerTestCommentsWithInclude.ss -->", . "<!-- end template $f/SSViewerTestCommentsWithInclude.ss -->",
), ),
); );
foreach ($templates as $template) { foreach ($templates as $template) {
$this->_renderWithSourceFileComments('SSViewerTestComments/'.$template['name'], $template['expected']); $this->_renderWithSourceFileComments('SSViewerTestComments/'.$template['name'], $template['expected']);
}
}
private function _renderWithSourceFileComments($name, $expected)
{
$viewer = new SSViewer(array($name));
$data = new ArrayData(array());
$result = $viewer->process($data);
$expected = str_replace(array("\r", "\n"), '', $expected);
$result = str_replace(array("\r", "\n"), '', $result);
$this->assertEquals($result, $expected);
} }
}
private function _renderWithSourceFileComments($name, $expected)
{
$viewer = new SSViewer(array($name));
$data = new ArrayData(array());
$result = $viewer->process($data);
$expected = str_replace(array("\r", "\n"), '', $expected);
$result = str_replace(array("\r", "\n"), '', $result);
$this->assertEquals($result, $expected);
}
public function testLoopIteratorIterator() public function testLoopIteratorIterator()
{ {
$list = new PaginatedList(new ArrayList()); $list = new PaginatedList(new ArrayList());
$viewer = new SSViewer_FromString('<% loop List %>$ID - $FirstName<br /><% end_loop %>'); $viewer = new SSViewer_FromString('<% loop List %>$ID - $FirstName<br /><% end_loop %>');
$result = $viewer->process(new ArrayData(array('List' => $list))); $result = $viewer->process(new ArrayData(array('List' => $list)));
$this->assertEquals($result, ''); $this->assertEquals($result, '');
} }
public function testProcessOnlyIncludesRequirementsOnce() public function testProcessOnlyIncludesRequirementsOnce()
{ {
$template = new SSViewer(array('SSViewerTestProcess')); $template = new SSViewer(array('SSViewerTestProcess'));
$basePath = $this->getCurrentRelativePath() . '/SSViewerTest'; $basePath = $this->getCurrentRelativePath() . '/SSViewerTest';
$backend = Injector::inst()->create(Requirements_Backend::class); $backend = Injector::inst()->create(Requirements_Backend::class);
$backend->setCombinedFilesEnabled(false); $backend->setCombinedFilesEnabled(false);
$backend->combineFiles( $backend->combineFiles(
'RequirementsTest_ab.css', 'RequirementsTest_ab.css',
array( array(
$basePath . '/css/RequirementsTest_a.css', $basePath . '/css/RequirementsTest_a.css',
$basePath . '/css/RequirementsTest_b.css' $basePath . '/css/RequirementsTest_b.css'
) )
); );
Requirements::set_backend($backend); Requirements::set_backend($backend);
$this->assertEquals(1, substr_count($template->process(array()), "a.css")); $this->assertEquals(1, substr_count($template->process(array()), "a.css"));
$this->assertEquals(1, substr_count($template->process(array()), "b.css")); $this->assertEquals(1, substr_count($template->process(array()), "b.css"));
// if we disable the requirements then we should get nothing // if we disable the requirements then we should get nothing
$template->includeRequirements(false); $template->includeRequirements(false);
$this->assertEquals(0, substr_count($template->process(array()), "a.css")); $this->assertEquals(0, substr_count($template->process(array()), "a.css"));
$this->assertEquals(0, substr_count($template->process(array()), "b.css")); $this->assertEquals(0, substr_count($template->process(array()), "b.css"));
} }
public function testRequireCallInTemplateInclude() public function testRequireCallInTemplateInclude()
{ {
//TODO undo skip test on the event that templates ever obtain the ability to reference MODULE_DIR (or something to that effect) //TODO undo skip test on the event that templates ever obtain the ability to reference MODULE_DIR (or something to that effect)
if (FRAMEWORK_DIR === 'framework') { if (FRAMEWORK_DIR === 'framework') {
$template = new SSViewer(array('SSViewerTestProcess')); $template = new SSViewer(array('SSViewerTestProcess'));
Requirements::set_suffix_requirements(false); Requirements::set_suffix_requirements(false);
$this->assertEquals( $this->assertEquals(
1, 1,
substr_count( substr_count(
$template->process(array()), $template->process(array()),
"tests/php/View/SSViewerTest/javascript/RequirementsTest_a.js" "tests/php/View/SSViewerTest/javascript/RequirementsTest_a.js"
) )
); );
} else { } else {
$this->markTestSkipped( $this->markTestSkipped(
'Requirement will always fail if the framework dir is not '. 'Requirement will always fail if the framework dir is not '.
'named \'framework\', since templates require hard coded paths' 'named \'framework\', since templates require hard coded paths'
); );
}
} }
}
public function testCallsWithArguments() public function testCallsWithArguments()
{ {
$data = new ArrayData( $data = new ArrayData(
array( array(
'Set' => new ArrayList( 'Set' => new ArrayList(
array( array(
@ -1930,9 +1929,9 @@ public function testCallsWithArguments()
'Level' => new SSViewerTest\LevelTestData(2), 'Level' => new SSViewerTest\LevelTestData(2),
), ),
) )
); );
$tests = array( $tests = array(
'$Level.output(1)' => '1-1', '$Level.output(1)' => '1-1',
'$Nest.Level.output($Set.First.Number)' => '2-1', '$Nest.Level.output($Set.First.Number)' => '2-1',
'<% with $Set %>$Up.Level.output($First.Number)<% end_with %>' => '1-1', '<% with $Set %>$Up.Level.output($First.Number)<% end_with %>' => '1-1',
@ -1949,17 +1948,17 @@ public function testCallsWithArguments()
'<% with $Nest %> '<% with $Nest %>
<% loop $Level.forLoop($Top.Set.Last.Number) %>$Number<% end_loop %> <% loop $Level.forLoop($Top.Set.Last.Number) %>$Number<% end_loop %>
<% end_with %>' => '!0!1!2!3!4', <% end_with %>' => '!0!1!2!3!4',
); );
foreach ($tests as $template => $expected) { foreach ($tests as $template => $expected) {
$this->assertEquals($expected, trim($this->render($template, $data))); $this->assertEquals($expected, trim($this->render($template, $data)));
}
} }
}
public function testRepeatedCallsAreCached() public function testRepeatedCallsAreCached()
{ {
$data = new SSViewerTest\CacheTestData(); $data = new SSViewerTest\CacheTestData();
$template = ' $template = '
<% if $TestWithCall %> <% if $TestWithCall %>
<% with $TestWithCall %> <% with $TestWithCall %>
{$Message} {$Message}
@ -1968,89 +1967,89 @@ public function testRepeatedCallsAreCached()
{$TestWithCall.Message} {$TestWithCall.Message}
<% end_if %>'; <% end_if %>';
$this->assertEquals('HiHi', preg_replace('/\s+/', '', $this->render($template, $data))); $this->assertEquals('HiHi', preg_replace('/\s+/', '', $this->render($template, $data)));
$this->assertEquals( $this->assertEquals(
1, 1,
$data->testWithCalls, $data->testWithCalls,
'SSViewerTest_CacheTestData::TestWithCall() should only be called once. Subsequent calls should be cached' 'SSViewerTest_CacheTestData::TestWithCall() should only be called once. Subsequent calls should be cached'
); );
$data = new SSViewerTest\CacheTestData(); $data = new SSViewerTest\CacheTestData();
$template = ' $template = '
<% if $TestLoopCall %> <% if $TestLoopCall %>
<% loop $TestLoopCall %> <% loop $TestLoopCall %>
{$Message} {$Message}
<% end_loop %> <% end_loop %>
<% end_if %>'; <% end_if %>';
$this->assertEquals('OneTwo', preg_replace('/\s+/', '', $this->render($template, $data))); $this->assertEquals('OneTwo', preg_replace('/\s+/', '', $this->render($template, $data)));
$this->assertEquals( $this->assertEquals(
1, 1,
$data->testLoopCalls, $data->testLoopCalls,
'SSViewerTest_CacheTestData::TestLoopCall() should only be called once. Subsequent calls should be cached' 'SSViewerTest_CacheTestData::TestLoopCall() should only be called once. Subsequent calls should be cached'
); );
} }
public function testClosedBlockExtension() public function testClosedBlockExtension()
{ {
$count = 0; $count = 0;
$parser = new SSTemplateParser(); $parser = new SSTemplateParser();
$parser->addClosedBlock( $parser->addClosedBlock(
'test', 'test',
function ($res) use (&$count) { function ($res) use (&$count) {
$count++; $count++;
} }
); );
$template = new SSViewer_FromString("<% test %><% end_test %>", $parser); $template = new SSViewer_FromString("<% test %><% end_test %>", $parser);
$template->process(new SSViewerTest\TestFixture()); $template->process(new SSViewerTest\TestFixture());
$this->assertEquals(1, $count); $this->assertEquals(1, $count);
} }
public function testOpenBlockExtension() public function testOpenBlockExtension()
{ {
$count = 0; $count = 0;
$parser = new SSTemplateParser(); $parser = new SSTemplateParser();
$parser->addOpenBlock( $parser->addOpenBlock(
'test', 'test',
function ($res) use (&$count) { function ($res) use (&$count) {
$count++; $count++;
} }
); );
$template = new SSViewer_FromString("<% test %>", $parser); $template = new SSViewer_FromString("<% test %>", $parser);
$template->process(new SSViewerTest\TestFixture()); $template->process(new SSViewerTest\TestFixture());
$this->assertEquals(1, $count); $this->assertEquals(1, $count);
} }
/** /**
* Tests if caching for SSViewer_FromString is working * Tests if caching for SSViewer_FromString is working
*/ */
public function testFromStringCaching() public function testFromStringCaching()
{ {
$content = 'Test content'; $content = 'Test content';
$cacheFile = TEMP_FOLDER . '/.cache.' . sha1($content); $cacheFile = TEMP_FOLDER . '/.cache.' . sha1($content);
if (file_exists($cacheFile)) { if (file_exists($cacheFile)) {
unlink($cacheFile);
}
// Test global behaviors
$this->render($content, null, null);
$this->assertFalse(file_exists($cacheFile), 'Cache file was created when caching was off');
SSViewer_FromString::config()->update('cache_template', true);
$this->render($content, null, null);
$this->assertTrue(file_exists($cacheFile), 'Cache file wasn\'t created when it was meant to');
unlink($cacheFile);
// Test instance behaviors
$this->render($content, null, false);
$this->assertFalse(file_exists($cacheFile), 'Cache file was created when caching was off');
$this->render($content, null, true);
$this->assertTrue(file_exists($cacheFile), 'Cache file wasn\'t created when it was meant to');
unlink($cacheFile); unlink($cacheFile);
} }
// Test global behaviors
$this->render($content, null, null);
$this->assertFalse(file_exists($cacheFile), 'Cache file was created when caching was off');
SSViewer_FromString::config()->update('cache_template', true);
$this->render($content, null, null);
$this->assertTrue(file_exists($cacheFile), 'Cache file wasn\'t created when it was meant to');
unlink($cacheFile);
// Test instance behaviors
$this->render($content, null, false);
$this->assertFalse(file_exists($cacheFile), 'Cache file was created when caching was off');
$this->render($content, null, true);
$this->assertTrue(file_exists($cacheFile), 'Cache file wasn\'t created when it was meant to');
unlink($cacheFile);
}
} }