2008-07-21 13:59:24 +02:00
< ? php
class SSViewerTest extends SapphireTest {
2015-02-12 14:15:32 +01:00
2015-10-28 23:53:44 +01:00
/**
* Backup of $_SERVER global
*
* @ var array
*/
protected $oldServer = array ();
2015-02-12 14:15:32 +01:00
protected $extraDataObjects = array (
'SSViewerTest_Object' ,
);
2012-09-19 12:07:39 +02:00
public function setUp () {
2011-12-17 05:35:26 +01:00
parent :: setUp ();
2013-03-21 19:48:54 +01:00
Config :: inst () -> update ( 'SSViewer' , 'source_file_comments' , false );
2013-07-11 03:58:45 +02:00
Config :: inst () -> update ( 'SSViewer_FromString' , 'cache_template' , false );
2015-10-28 23:53:44 +01:00
$this -> oldServer = $_SERVER ;
}
public function tearDown () {
$_SERVER = $this -> oldServer ;
parent :: tearDown ();
2011-12-17 05:35:26 +01:00
}
2014-08-15 08:53:05 +02:00
2010-04-13 04:13:12 +02:00
/**
2013-03-21 19:48:54 +01:00
* Tests for { @ link Config :: inst () -> get ( 'SSViewer' , 'theme' )} for different behaviour
2010-04-13 04:13:12 +02:00
* of user defined themes via { @ link SiteConfig } and default theme
* when no user themes are defined .
*/
2012-09-19 12:07:39 +02:00
public function testCurrentTheme () {
2014-08-15 08:53:05 +02:00
//TODO: SiteConfig moved to CMS
2013-03-21 19:48:54 +01:00
Config :: inst () -> update ( 'SSViewer' , 'theme' , 'mytheme' );
$this -> assertEquals ( 'mytheme' , Config :: inst () -> get ( 'SSViewer' , 'theme' ),
2012-09-26 23:34:00 +02:00
'Current theme is the default - user has not defined one' );
2010-04-13 04:13:12 +02:00
}
2014-08-15 08:53:05 +02:00
2008-07-21 13:59:24 +02:00
/**
* Test that a template without a < head > tag still renders .
*/
2012-09-19 12:07:39 +02:00
public function testTemplateWithoutHeadRenders () {
2008-07-21 13:59:24 +02:00
$data = new ArrayData ( array (
'Var' => 'var value'
));
2014-08-15 08:53:05 +02:00
2008-07-21 13:59:24 +02:00
$result = $data -> renderWith ( " SSViewerTestPartialTemplate " );
2008-11-24 20:28:46 +01:00
$this -> assertEquals ( 'Test partial template: var value' , trim ( preg_replace ( " /<!--.*-->/U " , '' , $result )));
2008-07-21 13:59:24 +02:00
}
2013-06-26 14:57:53 +02:00
public function testIncludeScopeInheritance () {
$data = $this -> getScopeInheritanceTestData ();
$expected = array (
'Item 1 - First-ODD top:Item 1' ,
'Item 2 - EVEN top:Item 2' ,
'Item 3 - ODD top:Item 3' ,
'Item 4 - EVEN top:Item 4' ,
'Item 5 - ODD top:Item 5' ,
'Item 6 - Last-EVEN top:Item 6' ,
);
$result = $data -> renderWith ( 'SSViewerTestIncludeScopeInheritance' );
$this -> assertExpectedStrings ( $result , $expected );
// reset results for the tests that include arguments (the title is passed as an arg)
$expected = array (
2015-04-01 03:31:55 +02:00
'Item 1 _ Item 1 - First-ODD top:Item 1' ,
'Item 2 _ Item 2 - EVEN top:Item 2' ,
'Item 3 _ Item 3 - ODD top:Item 3' ,
'Item 4 _ Item 4 - EVEN top:Item 4' ,
'Item 5 _ Item 5 - ODD top:Item 5' ,
'Item 6 _ Item 6 - Last-EVEN top:Item 6' ,
2013-06-26 14:57:53 +02:00
);
$result = $data -> renderWith ( 'SSViewerTestIncludeScopeInheritanceWithArgs' );
$this -> assertExpectedStrings ( $result , $expected );
}
2016-01-06 00:34:58 +01:00
2015-04-01 03:31:55 +02:00
public function testIncludeTruthyness () {
$data = new ArrayData ( array (
'Title' => 'TruthyTest' ,
'Items' => new ArrayList ( array (
new ArrayData ( array ( 'Title' => 'Item 1' )),
new ArrayData ( array ( 'Title' => '' )),
new ArrayData ( array ( 'Title' => true )),
new ArrayData ( array ( 'Title' => false )),
new ArrayData ( array ( 'Title' => null )),
new ArrayData ( array ( 'Title' => 0 )),
new ArrayData ( array ( 'Title' => 7 ))
))
));
$result = $data -> renderWith ( 'SSViewerTestIncludeScopeInheritanceWithArgs' );
2016-01-06 00:34:58 +01:00
2015-04-01 03:31:55 +02:00
// We should not end up with empty values appearing as empty
$expected = array (
'Item 1 _ Item 1 - First-ODD top:Item 1' ,
'Untitled - EVEN top:' ,
'1 _ 1 - ODD top:1' ,
'Untitled - EVEN top:' ,
'Untitled - ODD top:' ,
'Untitled - EVEN top:0' ,
'7 _ 7 - Last-ODD top:7'
);
$this -> assertExpectedStrings ( $result , $expected );
}
2013-06-26 14:57:53 +02:00
private function getScopeInheritanceTestData () {
return new ArrayData ( array (
'Title' => 'TopTitleValue' ,
'Items' => new ArrayList ( array (
new ArrayData ( array ( 'Title' => 'Item 1' )),
new ArrayData ( array ( 'Title' => 'Item 2' )),
new ArrayData ( array ( 'Title' => 'Item 3' )),
new ArrayData ( array ( 'Title' => 'Item 4' )),
new ArrayData ( array ( 'Title' => 'Item 5' )),
new ArrayData ( array ( 'Title' => 'Item 6' ))
))
));
}
private function assertExpectedStrings ( $result , $expected ) {
foreach ( $expected as $expectedStr ) {
$this -> assertTrue (
( boolean ) preg_match ( " / { $expectedStr } / " , $result ),
" Didn't find ' { $expectedStr } ' in: \n { $result } "
);
}
}
2014-08-15 08:53:05 +02:00
2009-11-27 01:24:57 +01:00
/**
* Small helper to render templates from strings
*/
2013-07-11 03:58:45 +02:00
public function render ( $templateString , $data = null , $cacheTemplate = false ) {
$t = SSViewer :: fromString ( $templateString , $cacheTemplate );
2009-11-27 01:24:57 +01:00
if ( ! $data ) $data = new SSViewerTestFixture ();
2016-01-06 22:27:46 +01:00
return trim ( '' . $t -> process ( $data ));
2009-11-27 01:24:57 +01:00
}
2014-08-15 08:53:05 +02:00
2012-09-19 12:07:39 +02:00
public function testRequirements () {
2017-11-24 15:30:47 +01:00
$requirements = $this -> getMockBuilder ( " Requirements_Backend " )
-> setMethods ( array ( " javascript " , " css " ))
-> getMock ();
2012-03-24 04:38:57 +01:00
$jsFile = FRAMEWORK_DIR . '/tests/forms/a.js' ;
$cssFile = FRAMEWORK_DIR . '/tests/forms/a.js' ;
2014-08-15 08:53:05 +02:00
2008-11-10 02:01:55 +01:00
$requirements -> expects ( $this -> once ()) -> method ( 'javascript' ) -> with ( $jsFile );
$requirements -> expects ( $this -> once ()) -> method ( 'css' ) -> with ( $cssFile );
2014-08-15 08:53:05 +02:00
2008-11-10 02:13:42 +01:00
Requirements :: set_backend ( $requirements );
2014-08-15 08:53:05 +02:00
2009-11-27 01:24:57 +01:00
$template = $this -> render ( " <% require javascript( $jsFile ) %>
<% require css ( $cssFile ) %> " );
2008-11-10 02:01:55 +01:00
$this -> assertFalse (( bool ) trim ( $template ), " Should be no content in this return. " );
}
2016-01-06 00:34:58 +01:00
2014-08-25 01:49:38 +02:00
public function testRequirementsCombine (){
$oldBackend = Requirements :: backend ();
$testBackend = new Requirements_Backend ();
Requirements :: set_backend ( $testBackend );
$combinedTestFilePath = BASE_PATH . '/' . $testBackend -> getCombinedFilesFolder () . '/testRequirementsCombine.js' ;
$jsFile = FRAMEWORK_DIR . '/tests/view/themes/javascript/bad.js' ;
$jsFileContents = file_get_contents ( BASE_PATH . '/' . $jsFile );
Requirements :: combine_files ( 'testRequirementsCombine.js' , array ( $jsFile ));
require_once ( 'thirdparty/jsmin/jsmin.php' );
2016-01-06 00:34:58 +01:00
2014-08-25 01:49:38 +02:00
// first make sure that our test js file causes an exception to be thrown
try {
$content = JSMin :: minify ( $content );
Requirements :: set_backend ( $oldBackend );
2014-11-26 03:31:07 +01:00
$this -> fail ( 'JSMin did not throw exception on minify bad file: ' );
2014-08-25 01:49:38 +02:00
} catch ( Exception $e ){
// exception thrown... good
}
2014-11-26 03:27:54 +01:00
// secondly, make sure that requirements combine throws the correct warning, and only that warning
2014-08-25 01:49:38 +02:00
@ unlink ( $combinedTestFilePath );
try {
2014-11-26 03:27:54 +01:00
Requirements :: process_combined_files ();
} catch ( PHPUnit_Framework_Error_Warning $e ){
if ( strstr ( $e -> getMessage (), 'Failed to minify' ) === false ){
Requirements :: set_backend ( $oldBackend );
2014-11-26 03:31:07 +01:00
$this -> fail ( 'Requirements::process_combined_files raised a warning, which is good, but this is not the expected warning ("Failed to minify..."): ' . $e );
2014-11-26 03:27:54 +01:00
}
2014-08-25 01:49:38 +02:00
} catch ( Exception $e ){
Requirements :: set_backend ( $oldBackend );
2014-11-26 03:31:07 +01:00
$this -> fail ( 'Requirements::process_combined_files did not catch exception caused by minifying bad js file: ' . $e );
2014-08-25 01:49:38 +02:00
}
2016-01-06 00:34:58 +01:00
2014-08-25 01:49:38 +02:00
// and make sure the combined content matches the input content, i.e. no loss of functionality
if ( ! file_exists ( $combinedTestFilePath )){
Requirements :: set_backend ( $oldBackend );
2014-11-26 03:31:07 +01:00
$this -> fail ( 'No combined file was created at expected path: ' . $combinedTestFilePath );
2014-08-25 01:49:38 +02:00
}
$combinedTestFileContents = file_get_contents ( $combinedTestFilePath );
$this -> assertContains ( $jsFileContents , $combinedTestFileContents );
// reset
Requirements :: set_backend ( $oldBackend );
}
2016-01-06 00:34:58 +01:00
2014-08-25 01:49:38 +02:00
2012-05-19 02:55:49 +02:00
2012-09-19 12:07:39 +02:00
public function testComments () {
2009-11-27 01:24:57 +01:00
$output = $this -> render ( <<< SS
2012-09-26 23:34:00 +02:00
This is my template <%-- this is a comment --%> This is some content <%-- this is another comment --%> Final content
2013-03-05 16:22:09 +01:00
<%-- Alone multi
line comment --%>
Some more content
Mixing content and <%-- multi
2014-08-15 08:53:05 +02:00
line comment --%> Final final
2013-03-05 16:22:09 +01:00
content
2008-11-14 04:43:26 +01:00
SS
);
2013-03-05 16:22:09 +01:00
$shouldbe = <<< SS
This is my templateThis is some contentFinal content
Some more content
2014-08-15 08:53:05 +02:00
Mixing content and Final final
2013-03-05 16:22:09 +01:00
content
SS ;
2014-08-15 08:53:05 +02:00
2013-03-05 16:22:09 +01:00
$this -> assertEquals ( $shouldbe , $output );
2008-11-14 04:43:26 +01:00
}
2014-08-15 08:53:05 +02:00
2012-09-19 12:07:39 +02:00
public function testBasicText () {
2011-03-17 01:08:13 +01:00
$this -> assertEquals ( '"' , $this -> render ( '"' ), 'Double-quotes are left alone' );
$this -> assertEquals ( " ' " , $this -> render ( " ' " ), 'Single-quotes are left alone' );
$this -> assertEquals ( 'A' , $this -> render ( '\\A' ), 'Escaped characters are unescaped' );
$this -> assertEquals ( '\\A' , $this -> render ( '\\\\A' ), 'Escaped back-slashed are correctly unescaped' );
}
2014-08-15 08:53:05 +02:00
2012-09-19 12:07:39 +02:00
public function testBasicInjection () {
2011-03-17 01:08:13 +01:00
$this -> assertEquals ( '[out:Test]' , $this -> render ( '$Test' ), 'Basic stand-alone injection' );
$this -> assertEquals ( '[out:Test]' , $this -> render ( '{$Test}' ), 'Basic stand-alone wrapped injection' );
$this -> assertEquals ( 'A[out:Test]!' , $this -> render ( 'A$Test!' ), 'Basic surrounded injection' );
$this -> assertEquals ( 'A[out:Test]B' , $this -> render ( 'A{$Test}B' ), 'Basic surrounded wrapped injection' );
2014-08-15 08:53:05 +02:00
2011-03-17 01:08:13 +01:00
$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' );
2014-08-15 08:53:05 +02:00
2011-03-17 01:08:13 +01:00
$this -> assertEquals ( '{$Test}' , $this -> render ( '{\\$Test}' ), 'Escapes can be used to avoid injection' );
2014-08-15 08:53:05 +02:00
$this -> assertEquals ( '{\\[out:Test]}' , $this -> render ( '{\\\\$Test}' ),
2012-09-26 23:34:00 +02:00
'Escapes before injections are correctly unescaped' );
2011-03-17 01:08:13 +01:00
}
2012-02-11 03:08:39 +01:00
2012-02-20 23:45:43 +01:00
2012-09-19 12:07:39 +02:00
public function testGlobalVariableCalls () {
2012-02-20 23:45:43 +01:00
$this -> assertEquals ( 'automatic' , $this -> render ( '$SSViewerTest_GlobalAutomatic' ));
$this -> assertEquals ( 'reference' , $this -> render ( '$SSViewerTest_GlobalReferencedByString' ));
$this -> assertEquals ( 'reference' , $this -> render ( '$SSViewerTest_GlobalReferencedInArray' ));
}
2012-09-19 12:07:39 +02:00
public function testGlobalVariableCallsWithArguments () {
2012-02-20 23:45:43 +01:00
$this -> assertEquals ( 'zz' , $this -> render ( '$SSViewerTest_GlobalThatTakesArguments' ));
$this -> assertEquals ( 'zFooz' , $this -> render ( '$SSViewerTest_GlobalThatTakesArguments("Foo")' ));
2012-09-26 23:34:00 +02:00
$this -> assertEquals ( 'zFoo:Bar:Bazz' ,
$this -> render ( '$SSViewerTest_GlobalThatTakesArguments("Foo", "Bar", "Baz")' ));
$this -> assertEquals ( 'zreferencez' ,
$this -> render ( '$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalReferencedByString)' ));
2012-02-20 23:45:43 +01:00
}
2012-09-19 12:07:39 +02:00
public function testGlobalVariablesAreEscaped () {
2012-02-20 23:45:43 +01:00
$this -> assertEquals ( '<div></div>' , $this -> render ( '$SSViewerTest_GlobalHTMLFragment' ));
$this -> assertEquals ( '<div></div>' , $this -> render ( '$SSViewerTest_GlobalHTMLEscaped' ));
2012-09-26 23:34:00 +02:00
$this -> assertEquals ( 'z<div></div>z' ,
$this -> render ( '$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLFragment)' ));
$this -> assertEquals ( 'z<div></div>z' ,
$this -> render ( '$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLEscaped)' ));
2012-02-20 23:45:43 +01:00
}
2012-09-19 12:07:39 +02:00
public function testCoreGlobalVariableCalls () {
2012-09-26 23:34:00 +02:00
$this -> assertEquals ( Director :: absoluteBaseURL (),
$this -> render ( '{$absoluteBaseURL}' ), 'Director::absoluteBaseURL can be called from within template' );
$this -> assertEquals ( Director :: absoluteBaseURL (), $this -> render ( '{$AbsoluteBaseURL}' ),
'Upper-case %AbsoluteBaseURL can be called from within template' );
$this -> assertEquals ( Director :: is_ajax (), $this -> render ( '{$isAjax}' ),
'All variations of is_ajax result in the correct call' );
$this -> assertEquals ( Director :: is_ajax (), $this -> render ( '{$IsAjax}' ),
'All variations of is_ajax result in the correct call' );
$this -> assertEquals ( Director :: is_ajax (), $this -> render ( '{$is_ajax}' ),
'All variations of is_ajax result in the correct call' );
$this -> assertEquals ( Director :: is_ajax (), $this -> render ( '{$Is_ajax}' ),
'All variations of is_ajax result in the correct call' );
$this -> assertEquals ( i18n :: get_locale (), $this -> render ( '{$i18nLocale}' ),
'i18n template functions result correct result' );
$this -> assertEquals ( i18n :: get_locale (), $this -> render ( '{$get_locale}' ),
'i18n template functions result correct result' );
$this -> assertEquals (( string ) Member :: currentUser (), $this -> render ( '{$CurrentMember}' ),
'Member template functions result correct result' );
$this -> assertEquals (( string ) Member :: currentUser (), $this -> render ( '{$CurrentUser}' ),
'Member template functions result correct result' );
$this -> assertEquals (( string ) Member :: currentUser (), $this -> render ( '{$currentMember}' ),
'Member template functions result correct result' );
$this -> assertEquals (( string ) Member :: currentUser (), $this -> render ( '{$currentUser}' ),
'Member template functions result correct result' );
$this -> assertEquals ( SecurityToken :: getSecurityID (), $this -> render ( '{$getSecurityID}' ),
'SecurityToken template functions result correct result' );
$this -> assertEquals ( SecurityToken :: getSecurityID (), $this -> render ( '{$SecurityID}' ),
'SecurityToken template functions result correct result' );
$this -> assertEquals ( Permission :: check ( " ADMIN " ), ( bool ) $this -> render ( '{$HasPerm(\'ADMIN\')}' ),
'Permissions template functions result correct result' );
$this -> assertEquals ( Permission :: check ( " ADMIN " ), ( bool ) $this -> render ( '{$hasPerm(\'ADMIN\')}' ),
'Permissions template functions result correct result' );
2012-02-11 03:08:39 +01:00
}
2013-06-15 15:40:33 +02:00
public function testNonFieldCastingHelpersNotUsedInHasValue () {
// check if Link without $ in front of variable
$result = $this -> render (
'A<% if Link %>$Link<% end_if %>B' , new SSViewerTest_Object ());
$this -> assertEquals ( 'Asome/url.htmlB' , $result , 'casting helper not used for <% if Link %>' );
// check if Link with $ in front of variable
$result = $this -> render (
'A<% if $Link %>$Link<% end_if %>B' , new SSViewerTest_Object ());
$this -> assertEquals ( 'Asome/url.htmlB' , $result , 'casting helper not used for <% if $Link %>' );
}
2012-09-19 12:07:39 +02:00
public function testLocalFunctionsTakePriorityOverGlobals () {
2012-02-11 03:08:39 +01:00
$data = new ArrayData ( array (
2012-03-14 16:11:23 +01:00
'Page' => new SSViewerTest_Object ()
2012-02-11 03:08:39 +01:00
));
2012-02-11 03:26:26 +01:00
//call method with lots of arguments
2012-09-26 23:34:00 +02:00
$result = $this -> render (
'<% with Page %>$lotsOfArguments11("a","b","c","d","e","f","g","h","i","j","k")<% end_with %>' , $data );
2012-09-19 12:07:39 +02:00
$this -> assertEquals ( " abcdefghijk " , $result , " public function can accept up to 11 arguments " );
2012-02-11 03:26:26 +01:00
//call method that does not exist
2012-02-11 03:30:46 +01:00
$result = $this -> render ( '<% with Page %><% if IDoNotExist %>hello<% end_if %><% end_with %>' , $data );
2012-02-11 03:26:26 +01:00
$this -> assertEquals ( " " , $result , " Method does not exist - empty result " );
//call if that does not exist
2012-02-11 03:30:46 +01:00
$result = $this -> render ( '<% with Page %>$IDoNotExist("hello")<% end_with %>' , $data );
2012-02-11 03:26:26 +01:00
$this -> assertEquals ( " " , $result , " Method does not exist - empty result " );
//call method with same name as a global method (local call should take priority)
2012-02-11 03:30:46 +01:00
$result = $this -> render ( '<% with Page %>$absoluteBaseURL<% end_with %>' , $data );
2012-09-26 23:34:00 +02:00
$this -> assertEquals ( " testLocalFunctionPriorityCalled " , $result ,
" Local Object's public function called. Did not return the actual baseURL of the current site " );
2012-02-11 03:26:26 +01:00
}
2012-02-11 03:30:46 +01:00
2012-09-19 12:07:39 +02:00
public function testCurrentScopeLoopWith () {
2012-02-11 03:30:46 +01:00
// Data to run the loop tests on - one sequence of three items, each with a subitem
$data = new ArrayData ( array (
2012-02-17 00:01:09 +01:00
'Foo' => new ArrayList ( array (
2012-02-11 03:30:46 +01:00
'Subocean' => new ArrayData ( array (
'Name' => 'Higher'
)),
new ArrayData ( array (
'Sub' => new ArrayData ( array (
'Name' => 'SubKid1'
))
)),
new ArrayData ( array (
'Sub' => new ArrayData ( array (
'Name' => 'SubKid2'
))
)),
2012-03-14 16:11:23 +01:00
new SSViewerTest_Object ( 'Number6' )
2012-02-11 03:30:46 +01:00
))
));
2012-09-26 23:34:00 +02:00
$result = $this -> render (
'<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>' , $data );
2012-02-11 03:30:46 +01:00
$this -> assertEquals ( " SubKid1SubKid2Number6 " , $result , " Loop works " );
2012-09-26 23:34:00 +02:00
$result = $this -> render (
'<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>' , $data );
2012-02-11 03:30:46 +01:00
$this -> assertEquals ( " SubKid1SubKid2Number6 " , $result , " Loop works " );
$result = $this -> render ( '<% with Foo %>$Count<% end_with %>' , $data );
$this -> assertEquals ( " 4 " , $result , " 4 items in the DataObjectSet " );
2012-09-26 23:34:00 +02:00
$result = $this -> render ( '<% with Foo %><% loop Up.Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>'
. '<% end_if %><% end_loop %><% end_with %>' , $data );
2012-02-11 03:30:46 +01:00
$this -> assertEquals ( " SubKid1SubKid2Number6 " , $result , " Loop in with Up.Foo scope works " );
2012-09-26 23:34:00 +02:00
$result = $this -> render ( '<% with Foo %><% loop %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>'
. '<% end_if %><% end_loop %><% end_with %>' , $data );
2012-02-11 03:30:46 +01:00
$this -> assertEquals ( " SubKid1SubKid2Number6 " , $result , " Loop in current scope works " );
}
2014-08-15 08:53:05 +02:00
2012-09-19 12:07:39 +02:00
public function testObjectDotArguments () {
2009-01-04 23:20:36 +01:00
$this -> assertEquals (
2009-11-27 01:24:57 +01:00
' [ out : TestObject . methodWithOneArgument ( one )]
[ out : TestObject . methodWithTwoArguments ( one , two )]
[ out : TestMethod ( Arg1 , Arg2 ) . Bar . Val ]
[ out : TestMethod ( Arg1 , Arg2 ) . Bar ]
[ out : TestMethod ( Arg1 , Arg2 )]
[ out : TestMethod ( Arg1 ) . Bar . Val ]
[ out : TestMethod ( Arg1 ) . Bar ]
[ out : TestMethod ( Arg1 )] ' ,
$this -> render ( ' $TestObject . methodWithOneArgument ( one )
$TestObject . methodWithTwoArguments ( one , two )
$TestMethod ( Arg1 , Arg2 ) . Bar . Val
$TestMethod ( Arg1 , Arg2 ) . Bar
$TestMethod ( Arg1 , Arg2 )
$TestMethod ( Arg1 ) . Bar . Val
$TestMethod ( Arg1 ) . Bar
$TestMethod ( Arg1 ) ' )
2009-01-04 23:20:36 +01:00
);
2009-11-27 01:24:57 +01:00
}
2012-09-19 12:07:39 +02:00
public function testEscapedArguments () {
2009-01-04 23:20:36 +01:00
$this -> assertEquals (
2009-11-27 01:24:57 +01:00
' [ out : Foo ( Arg1 , Arg2 ) . Bar . Val ] . Suffix
[ out : Foo ( Arg1 , Arg2 ) . Val ] _Suffix
[ out : Foo ( Arg1 , Arg2 )] / Suffix
[ out : Foo ( Arg1 ) . Bar . Val ] textSuffix
[ out : Foo ( Arg1 ) . Bar ] . Suffix
[ out : Foo ( Arg1 )] . Suffix
[ out : Foo . Bar . Val ] . Suffix
[ out : Foo . Bar ] . Suffix
[ out : Foo ] . Suffix ' ,
$this -> render ( ' { $Foo ( Arg1 , Arg2 ) . Bar . Val } . Suffix
{ $Foo ( Arg1 , Arg2 ) . Val } _Suffix
{ $Foo ( Arg1 , Arg2 )} / Suffix
{ $Foo ( Arg1 ) . Bar . Val } textSuffix
{ $Foo ( Arg1 ) . Bar } . Suffix
{ $Foo ( Arg1 )} . Suffix
{ $Foo . Bar . Val } . Suffix
{ $Foo . Bar } . Suffix
{ $Foo } . Suffix ' )
2009-01-04 23:20:36 +01:00
);
}
2014-08-15 08:53:05 +02:00
2013-03-19 11:43:23 +01:00
public function testLoopWhitespace () {
2009-11-27 01:24:58 +01:00
$this -> assertEquals (
' before [ out : SingleItem . Test ] after
beforeTestafter ' ,
2013-03-19 11:43:23 +01:00
$this -> render ( ' before <% loop SingleItem %> $Test <% end_loop %> after
before <% loop SingleItem %> Test <% end_loop %> after ' )
2009-11-27 01:24:58 +01:00
);
// The control tags are removed from the output, but no whitespace
// This is a quirk that could be changed, but included in the test to make the current
// behaviour explicit
$this -> assertEquals (
' before
[ out : SingleItem . ItemOnItsOwnLine ]
after ' ,
$this -> render ( ' before
2013-03-19 11:43:23 +01:00
<% loop SingleItem %>
2009-11-27 01:24:58 +01:00
$ItemOnItsOwnLine
2013-03-19 11:43:23 +01:00
<% end_loop %>
2009-11-27 01:24:58 +01:00
after ' )
);
// The whitespace within the control tags is preserve in a loop
// This is a quirk that could be changed, but included in the test to make the current
// behaviour explicit
$this -> assertEquals (
' before
[ out : Loop3 . ItemOnItsOwnLine ]
[ out : Loop3 . ItemOnItsOwnLine ]
[ out : Loop3 . ItemOnItsOwnLine ]
after ' ,
$this -> render ( ' before
2013-03-19 11:43:23 +01:00
<% loop Loop3 %>
2009-11-27 01:24:58 +01:00
$ItemOnItsOwnLine
2013-03-19 11:43:23 +01:00
<% end_loop %>
2009-11-27 01:24:58 +01:00
after ' )
);
}
2012-09-19 12:07:39 +02:00
public function testControls () {
2009-11-27 01:24:58 +01:00
// Single item controls
$this -> assertEquals (
' a [ out : Foo . Bar . Item ] b
[ out : Foo . Bar ( Arg1 ) . Item ]
[ out : Foo ( Arg1 ) . Item ]
[ out : Foo ( Arg1 , Arg2 ) . Item ]
[ out : Foo ( Arg1 , Arg2 , Arg3 ) . Item ] ' ,
2013-03-19 11:43:23 +01:00
$this -> render ( ' <% with Foo . Bar %> a { $Item } b <% end_with %>
<% with Foo . Bar ( Arg1 ) %> $Item <% end_with %>
<% with Foo ( Arg1 ) %> $Item <% end_with %>
<% with Foo ( Arg1 , Arg2 ) %> $Item <% end_with %>
<% with Foo ( Arg1 , Arg2 , Arg3 ) %> $Item <% end_with %> ' )
2009-11-27 01:24:58 +01:00
);
// Loop controls
$this -> assertEquals ( 'a[out:Foo.Loop2.Item]ba[out:Foo.Loop2.Item]b' ,
2013-03-19 11:43:23 +01:00
$this -> render ( '<% loop Foo.Loop2 %>a{$Item}b<% end_loop %>' ));
2009-11-27 01:24:58 +01:00
$this -> assertEquals ( '[out:Foo.Loop2(Arg1).Item][out:Foo.Loop2(Arg1).Item]' ,
2013-03-19 11:43:23 +01:00
$this -> render ( '<% loop Foo.Loop2(Arg1) %>$Item<% end_loop %>' ));
2009-11-27 01:24:58 +01:00
$this -> assertEquals ( '[out:Loop2(Arg1).Item][out:Loop2(Arg1).Item]' ,
2013-03-19 11:43:23 +01:00
$this -> render ( '<% loop Loop2(Arg1) %>$Item<% end_loop %>' ));
2009-11-27 01:24:58 +01:00
$this -> assertEquals ( '[out:Loop2(Arg1,Arg2).Item][out:Loop2(Arg1,Arg2).Item]' ,
2013-03-19 11:43:23 +01:00
$this -> render ( '<% loop Loop2(Arg1, Arg2) %>$Item<% end_loop %>' ));
2009-11-27 01:24:58 +01:00
$this -> assertEquals ( '[out:Loop2(Arg1,Arg2,Arg3).Item][out:Loop2(Arg1,Arg2,Arg3).Item]' ,
2013-03-19 11:43:23 +01:00
$this -> render ( '<% loop Loop2(Arg1, Arg2, Arg3) %>$Item<% end_loop %>' ));
2009-11-27 01:24:58 +01:00
}
2012-09-19 12:07:39 +02:00
public function testIfBlocks () {
2009-11-27 01:24:58 +01:00
// Basic test
$this -> assertEquals ( 'AC' ,
$this -> render ( 'A<% if NotSet %>B$NotSet<% end_if %>C' ));
2011-12-21 17:15:18 +01:00
// Nested test
$this -> assertEquals ( 'AB1C' ,
$this -> render ( 'A<% if IsSet %>B$NotSet<% if IsSet %>1<% else %>2<% end_if %><% end_if %>C' ));
2009-11-27 01:24:58 +01:00
// else_if
$this -> assertEquals ( 'ACD' ,
$this -> render ( 'A<% if NotSet %>B<% else_if IsSet %>C<% end_if %>D' ));
$this -> assertEquals ( 'AD' ,
$this -> render ( 'A<% if NotSet %>B<% else_if AlsoNotset %>C<% end_if %>D' ));
$this -> assertEquals ( 'ADE' ,
$this -> render ( 'A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E' ));
$this -> assertEquals ( 'ADE' ,
$this -> render ( 'A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E' ));
// Dot syntax
$this -> assertEquals ( 'ACD' ,
$this -> render ( 'A<% if Foo.NotSet %>B<% else_if Foo.IsSet %>C<% end_if %>D' ));
2011-02-14 02:10:17 +01:00
$this -> assertEquals ( 'ACD' ,
$this -> render ( 'A<% if Foo.Bar.NotSet %>B<% else_if Foo.Bar.IsSet %>C<% end_if %>D' ));
2009-11-27 01:24:58 +01:00
// Params
$this -> assertEquals ( 'ACD' ,
$this -> render ( 'A<% if NotSet(Param) %>B<% else %>C<% end_if %>D' ));
$this -> assertEquals ( 'ABD' ,
$this -> render ( 'A<% if IsSet(Param) %>B<% else %>C<% end_if %>D' ));
2011-02-21 03:24:14 +01:00
// Negation
$this -> assertEquals ( 'AC' ,
$this -> render ( 'A<% if not IsSet %>B<% end_if %>C' ));
$this -> assertEquals ( 'ABC' ,
$this -> render ( 'A<% if not NotSet %>B<% end_if %>C' ));
2014-08-15 08:53:05 +02:00
2009-11-27 01:24:58 +01:00
// Or
$this -> assertEquals ( 'ABD' ,
$this -> render ( 'A<% if IsSet || NotSet %>B<% else_if A %>C<% end_if %>D' ));
$this -> assertEquals ( 'ACD' ,
$this -> render ( 'A<% if NotSet || AlsoNotSet %>B<% else_if IsSet %>C<% end_if %>D' ));
$this -> assertEquals ( 'AD' ,
$this -> render ( 'A<% if NotSet || AlsoNotSet %>B<% else_if NotSet3 %>C<% end_if %>D' ));
2011-02-14 02:10:17 +01:00
$this -> assertEquals ( 'ACD' ,
$this -> render ( 'A<% if NotSet || AlsoNotSet %>B<% else_if IsSet || NotSet %>C<% end_if %>D' ));
$this -> assertEquals ( 'AD' ,
$this -> render ( 'A<% if NotSet || AlsoNotSet %>B<% else_if NotSet2 || NotSet3 %>C<% end_if %>D' ));
2014-08-15 08:53:05 +02:00
2011-02-21 03:24:14 +01:00
// Negated Or
$this -> assertEquals ( 'ACD' ,
$this -> render ( 'A<% if not IsSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D' ));
$this -> assertEquals ( 'ABD' ,
$this -> render ( 'A<% if not NotSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D' ));
$this -> assertEquals ( 'ABD' ,
$this -> render ( 'A<% if NotSet || not AlsoNotSet %>B<% else_if A %>C<% end_if %>D' ));
2009-11-27 01:24:58 +01:00
// And
$this -> assertEquals ( 'ABD' ,
$this -> render ( 'A<% if IsSet && AlsoSet %>B<% else_if A %>C<% end_if %>D' ));
$this -> assertEquals ( 'ACD' ,
$this -> render ( 'A<% if IsSet && NotSet %>B<% else_if IsSet %>C<% end_if %>D' ));
$this -> assertEquals ( 'AD' ,
$this -> render ( 'A<% if NotSet && NotSet2 %>B<% else_if NotSet3 %>C<% end_if %>D' ));
2011-02-14 02:10:17 +01:00
$this -> assertEquals ( 'ACD' ,
$this -> render ( 'A<% if IsSet && NotSet %>B<% else_if IsSet && AlsoSet %>C<% end_if %>D' ));
$this -> assertEquals ( 'AD' ,
$this -> render ( 'A<% if NotSet && NotSet2 %>B<% else_if IsSet && NotSet3 %>C<% end_if %>D' ));
2009-11-27 01:24:58 +01:00
// Equality
$this -> assertEquals ( 'ABC' ,
$this -> render ( 'A<% if RawVal == RawVal %>B<% end_if %>C' ));
$this -> assertEquals ( 'ACD' ,
$this -> render ( 'A<% if Right == Wrong %>B<% else_if RawVal == RawVal %>C<% end_if %>D' ));
$this -> assertEquals ( 'ABC' ,
$this -> render ( 'A<% if Right != Wrong %>B<% end_if %>C' ));
$this -> assertEquals ( 'AD' ,
$this -> render ( 'A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% end_if %>D' ));
2013-04-07 09:46:50 +02:00
// test inequalities with simple numbers
$this -> assertEquals ( 'ABD' , $this -> render ( 'A<% if 5 > 3 %>B<% else %>C<% end_if %>D' ));
$this -> assertEquals ( 'ABD' , $this -> render ( 'A<% if 5 >= 3 %>B<% else %>C<% end_if %>D' ));
$this -> assertEquals ( 'ACD' , $this -> render ( 'A<% if 3 > 5 %>B<% else %>C<% end_if %>D' ));
$this -> assertEquals ( 'ACD' , $this -> render ( 'A<% if 3 >= 5 %>B<% else %>C<% end_if %>D' ));
$this -> assertEquals ( 'ABD' , $this -> render ( 'A<% if 3 < 5 %>B<% else %>C<% end_if %>D' ));
$this -> assertEquals ( 'ABD' , $this -> render ( 'A<% if 3 <= 5 %>B<% else %>C<% end_if %>D' ));
$this -> assertEquals ( 'ACD' , $this -> render ( 'A<% if 5 < 3 %>B<% else %>C<% end_if %>D' ));
$this -> assertEquals ( 'ACD' , $this -> render ( 'A<% if 5 <= 3 %>B<% else %>C<% end_if %>D' ));
$this -> assertEquals ( 'ABD' , $this -> render ( 'A<% if 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' ));
2013-04-10 16:12:51 +02:00
// empty else_if and else tags, if this would not be supported,
// the output would stop after A, thereby failing the assert
$this -> assertEquals ( 'AD' , $this -> render ( 'A<% if IsSet %><% else %><% end_if %>D' ));
2014-08-15 08:53:05 +02:00
$this -> assertEquals ( 'AD' ,
2013-04-10 16:12:51 +02:00
$this -> render ( 'A<% if NotSet %><% else_if IsSet %><% else %><% end_if %>D' ));
2014-08-15 08:53:05 +02:00
$this -> assertEquals ( 'AD' ,
2013-04-10 16:12:51 +02:00
$this -> render ( 'A<% if NotSet %><% else_if AlsoNotSet %><% else %><% end_if %>D' ));
2012-07-23 01:56:44 +02:00
// Bare words with ending space
$this -> assertEquals ( 'ABC' ,
$this -> render ( 'A<% if "RawVal" == RawVal %>B<% end_if %>C' ));
2009-11-27 01:24:58 +01:00
// Else
$this -> assertEquals ( 'ADE' ,
$this -> render ( 'A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% else %>D<% end_if %>E' ));
2014-08-15 08:53:05 +02:00
2011-02-21 04:19:10 +01:00
// Empty if with else
$this -> assertEquals ( 'ABC' ,
$this -> render ( 'A<% if NotSet %><% else %>B<% end_if %>C' ));
2009-11-27 01:24:58 +01:00
}
2012-09-19 12:07:39 +02:00
public function testBaseTagGeneration () {
2009-10-31 01:16:54 +01:00
// XHTML wil have a closed base tag
2009-11-27 01:24:57 +01:00
$tmpl1 = ' < ? xml version = " 1.0 " encoding = " UTF-8 " ?>
2012-09-26 23:34:00 +02:00
<! DOCTYPE html PUBLIC " -//W3C//DTD XHTML 1.0 Transitional//EN " '
. ' " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd " >
2009-10-31 01:16:54 +01:00
< html >
< head ><% base_tag %></ head >
< body >< p > test </ p >< body >
2009-11-27 01:24:57 +01:00
</ html > ' ;
2010-10-19 03:20:07 +02:00
$this -> assertRegExp ( '/<head><base href=".*" \/><\/head>/' , $this -> render ( $tmpl1 ));
2014-08-15 08:53:05 +02:00
2009-10-31 01:16:54 +01:00
// HTML4 and 5 will only have it for IE
2009-11-27 01:24:57 +01:00
$tmpl2 = ' <! DOCTYPE html >
2009-10-31 01:16:54 +01:00
< html >
< head ><% base_tag %></ head >
< body >< p > test </ p >< body >
2009-11-27 01:24:57 +01:00
</ html > ' ;
2012-09-26 23:34:00 +02:00
$this -> assertRegExp ( '/<head><base href=".*"><!--\[if lte IE 6\]><\/base><!\[endif\]--><\/head>/' ,
$this -> render ( $tmpl2 ));
2014-08-15 08:53:05 +02:00
2009-11-27 01:24:57 +01:00
$tmpl3 = ' <! DOCTYPE HTML PUBLIC " -//W3C//DTD HTML 4.01//EN " " http://www.w3.org/TR/html4/strict.dtd " >
2009-10-31 01:16:54 +01:00
< html >
< head ><% base_tag %></ head >
< body >< p > test </ p >< body >
2009-11-27 01:24:57 +01:00
</ html > ' ;
2012-09-26 23:34:00 +02:00
$this -> assertRegExp ( '/<head><base href=".*"><!--\[if lte IE 6\]><\/base><!\[endif\]--><\/head>/' ,
$this -> render ( $tmpl3 ));
2009-10-31 01:16:54 +01:00
// Check that the content negotiator converts to the equally legal formats
$negotiator = new ContentNegotiator ();
2014-08-15 08:53:05 +02:00
2009-11-27 01:24:57 +01:00
$response = new SS_HTTPResponse ( $this -> render ( $tmpl1 ));
2009-10-31 01:16:54 +01:00
$negotiator -> html ( $response );
2012-09-26 23:34:00 +02:00
$this -> assertRegExp ( '/<head><base href=".*"><!--\[if lte IE 6\]><\/base><!\[endif\]--><\/head>/' ,
$response -> getBody ());
2009-10-31 01:16:54 +01:00
2009-11-27 01:24:57 +01:00
$response = new SS_HTTPResponse ( $this -> render ( $tmpl1 ));
2009-10-31 01:16:54 +01:00
$negotiator -> xhtml ( $response );
2010-10-19 03:20:07 +02:00
$this -> assertRegExp ( '/<head><base href=".*" \/><\/head>/' , $response -> getBody ());
2009-10-31 01:16:54 +01:00
}
2010-03-12 04:08:59 +01:00
2012-09-19 12:07:39 +02:00
public function testIncludeWithArguments () {
2012-04-11 11:34:27 +02:00
$this -> assertEquals (
$this -> render ( '<% include SSViewerTestIncludeWithArguments %>' ),
'<p>[out:Arg1]</p><p>[out:Arg2]</p>'
);
$this -> assertEquals (
$this -> render ( '<% include SSViewerTestIncludeWithArguments Arg1=A %>' ),
'<p>A</p><p>[out:Arg2]</p>'
);
$this -> assertEquals (
$this -> render ( '<% include SSViewerTestIncludeWithArguments Arg1=A, Arg2=B %>' ),
'<p>A</p><p>B</p>'
);
$this -> assertEquals (
$this -> render ( '<% include SSViewerTestIncludeWithArguments Arg1=A Bare String, Arg2=B Bare String %>' ),
2012-07-23 01:56:44 +02:00
'<p>A Bare String</p><p>B Bare String</p>'
2012-04-11 11:34:27 +02:00
);
$this -> assertEquals (
2012-09-26 23:34:00 +02:00
$this -> render ( '<% include SSViewerTestIncludeWithArguments Arg1="A", Arg2=$B %>' ,
new ArrayData ( array ( 'B' => 'Bar' ))),
2012-04-11 11:34:27 +02:00
'<p>A</p><p>Bar</p>'
);
2012-04-13 02:14:33 +02:00
$this -> assertEquals (
2012-09-26 23:34:00 +02:00
$this -> render ( '<% include SSViewerTestIncludeWithArguments Arg1="A" %>' ,
new ArrayData ( array ( 'Arg1' => 'Foo' , 'Arg2' => 'Bar' ))),
2012-04-13 02:14:33 +02:00
'<p>A</p><p>Bar</p>'
);
2013-02-14 08:31:40 +01:00
2015-12-22 15:48:04 +01:00
$this -> assertEquals (
$this -> render ( '<% include SSViewerTestIncludeScopeInheritanceWithArgsInLoop Title="SomeArg" %>' ,
new ArrayData ( array ( 'Items' => new ArrayList ( array (
new ArrayData ( array ( 'Title' => 'Foo' )),
new ArrayData ( array ( 'Title' => 'Bar' ))
))))),
'SomeArg - Foo - Bar - SomeArg'
);
$this -> assertEquals (
$this -> render ( '<% include SSViewerTestIncludeScopeInheritanceWithArgsInWith Title="A" %>' ,
new ArrayData ( array ( 'Item' => new ArrayData ( array ( 'Title' => 'B' ))))),
'A - B - A'
);
$this -> assertEquals (
$this -> render ( '<% include SSViewerTestIncludeScopeInheritanceWithArgsInNestedWith Title="A" %>' ,
new ArrayData ( array (
'Item' => new ArrayData ( array (
'Title' => 'B' , 'NestedItem' => new ArrayData ( array ( 'Title' => 'C' ))
)))
)),
'A - B - C - B - A'
);
2016-06-06 11:14:07 +02:00
$this -> assertEquals (
$this -> render ( '<% include SSViewerTestIncludeScopeInheritanceWithUpAndTop Title="A" %>' ,
new ArrayData ( array (
'Item' => new ArrayData ( array (
'Title' => 'B' , 'NestedItem' => new ArrayData ( array ( 'Title' => 'C' ))
)))
)),
'A - A - A'
);
2013-02-14 08:31:40 +01:00
$data = new ArrayData ( array (
'Nested' => new ArrayData ( array (
'Object' => new ArrayData ( array ( 'Key' => 'A' ))
)),
'Object' => new ArrayData ( array ( 'Key' => 'B' ))
));
$tmpl = SSViewer :: fromString ( '<% include SSViewerTestIncludeObjectArguments A=$Nested.Object, B=$Object %>' );
$res = $tmpl -> process ( $data );
$this -> assertEqualIgnoringWhitespace ( 'A B' , $res , 'Objects can be passed as named arguments' );
2012-04-11 11:34:27 +02:00
}
2014-08-15 08:53:05 +02:00
2012-09-19 12:07:39 +02:00
public function testRecursiveInclude () {
2010-03-12 04:08:59 +01:00
$view = new SSViewer ( array ( 'SSViewerTestRecursiveInclude' ));
2012-02-11 03:26:26 +01:00
2010-03-12 04:08:59 +01:00
$data = new ArrayData ( array (
'Title' => 'A' ,
2011-05-05 12:40:24 +02:00
'Children' => new ArrayList ( array (
2010-03-12 04:08:59 +01:00
new ArrayData ( array (
'Title' => 'A1' ,
2011-05-05 12:40:24 +02:00
'Children' => new ArrayList ( array (
2010-03-12 04:08:59 +01:00
new ArrayData ( array ( 'Title' => 'A1 i' , )),
new ArrayData ( array ( 'Title' => 'A1 ii' , )),
)),
)),
new ArrayData ( array ( 'Title' => 'A2' , )),
new ArrayData ( array ( 'Title' => 'A3' , )),
)),
));
2014-08-15 08:53:05 +02:00
2010-03-12 04:08:59 +01:00
$result = $view -> process ( $data );
// We don't care about whitespace
$rationalisedResult = trim ( preg_replace ( '/\s+/' , ' ' , $result ));
2014-08-15 08:53:05 +02:00
2010-03-12 04:08:59 +01:00
$this -> assertEquals ( 'A A1 A1 i A1 ii A2 A3' , $rationalisedResult );
}
2014-08-15 08:53:05 +02:00
2012-09-19 12:07:39 +02:00
public function assertEqualIgnoringWhitespace ( $a , $b ) {
2011-02-18 05:06:11 +01:00
$this -> assertEquals ( preg_replace ( '/\s+/' , '' , $a ), preg_replace ( '/\s+/' , '' , $b ));
}
2012-02-29 20:35:48 +01:00
/**
* See { @ link ViewableDataTest } for more extensive casting tests ,
* this test just ensures that basic casting is correctly applied during template parsing .
*/
2012-09-19 12:07:39 +02:00
public function testCastingHelpers () {
2012-02-29 20:35:48 +01:00
$vd = new SSViewerTest_ViewableData ();
$vd -> TextValue = '<b>html</b>' ;
$vd -> HTMLValue = '<b>html</b>' ;
$vd -> UncastedValue = '<b>html</b>' ;
// Value casted as "Text"
$this -> assertEquals (
'<b>html</b>' ,
$t = SSViewer :: fromString ( '$TextValue' ) -> process ( $vd )
);
$this -> assertEquals (
'<b>html</b>' ,
$t = SSViewer :: fromString ( '$TextValue.RAW' ) -> process ( $vd )
);
$this -> assertEquals (
'<b>html</b>' ,
$t = SSViewer :: fromString ( '$TextValue.XML' ) -> process ( $vd )
);
// Value casted as "HTMLText"
$this -> assertEquals (
'<b>html</b>' ,
$t = SSViewer :: fromString ( '$HTMLValue' ) -> process ( $vd )
);
$this -> assertEquals (
'<b>html</b>' ,
$t = SSViewer :: fromString ( '$HTMLValue.RAW' ) -> process ( $vd )
);
$this -> assertEquals (
'<b>html</b>' ,
$t = SSViewer :: fromString ( '$HTMLValue.XML' ) -> process ( $vd )
);
// Uncasted value (falls back to ViewableData::$default_cast="HTMLText")
$vd = new SSViewerTest_ViewableData (); // TODO Fix caching
$vd -> UncastedValue = '<b>html</b>' ;
$this -> assertEquals (
'<b>html</b>' ,
$t = SSViewer :: fromString ( '$UncastedValue' ) -> process ( $vd )
);
$vd = new SSViewerTest_ViewableData (); // TODO Fix caching
$vd -> UncastedValue = '<b>html</b>' ;
$this -> assertEquals (
'<b>html</b>' ,
$t = SSViewer :: fromString ( '$UncastedValue.RAW' ) -> process ( $vd )
);
$vd = new SSViewerTest_ViewableData (); // TODO Fix caching
$vd -> UncastedValue = '<b>html</b>' ;
$this -> assertEquals (
'<b>html</b>' ,
$t = SSViewer :: fromString ( '$UncastedValue.XML' ) -> process ( $vd )
);
}
2014-08-15 08:53:05 +02:00
2012-09-19 12:07:39 +02:00
public function testSSViewerBasicIteratorSupport () {
2012-02-11 03:26:26 +01:00
$data = new ArrayData ( array (
2012-02-17 00:01:09 +01:00
'Set' => new ArrayList ( array (
2012-03-14 16:11:23 +01:00
new SSViewerTest_Object ( " 1 " ),
new SSViewerTest_Object ( " 2 " ),
new SSViewerTest_Object ( " 3 " ),
new SSViewerTest_Object ( " 4 " ),
new SSViewerTest_Object ( " 5 " ),
new SSViewerTest_Object ( " 6 " ),
new SSViewerTest_Object ( " 7 " ),
new SSViewerTest_Object ( " 8 " ),
new SSViewerTest_Object ( " 9 " ),
new SSViewerTest_Object ( " 10 " ),
2012-02-11 03:26:26 +01:00
))
));
//base test
$result = $this -> render ( '<% loop Set %>$Number<% end_loop %>' , $data );
$this -> assertEquals ( " 12345678910 " , $result , " Numbers rendered in order " );
//test First
$result = $this -> render ( '<% loop Set %><% if First %>$Number<% end_if %><% end_loop %>' , $data );
$this -> assertEquals ( " 1 " , $result , " Only the first number is rendered " );
//test Last
$result = $this -> render ( '<% loop Set %><% if Last %>$Number<% end_if %><% end_loop %>' , $data );
$this -> assertEquals ( " 10 " , $result , " Only the last number is rendered " );
2014-08-15 08:53:05 +02:00
2012-02-11 03:26:26 +01:00
//test Even
$result = $this -> render ( '<% loop Set %><% if Even() %>$Number<% end_if %><% end_loop %>' , $data );
$this -> assertEquals ( " 246810 " , $result , " Even numbers rendered in order " );
//test Even with quotes
$result = $this -> render ( '<% loop Set %><% if Even("1") %>$Number<% end_if %><% end_loop %>' , $data );
$this -> assertEquals ( " 246810 " , $result , " Even numbers rendered in order " );
//test Even without quotes
$result = $this -> render ( '<% loop Set %><% if Even(1) %>$Number<% end_if %><% end_loop %>' , $data );
$this -> assertEquals ( " 246810 " , $result , " Even numbers rendered in order " );
//test Even with zero-based start index
$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 " );
//test Odd
$result = $this -> render ( '<% loop Set %><% if Odd %>$Number<% end_if %><% end_loop %>' , $data );
$this -> assertEquals ( " 13579 " , $result , " Odd numbers rendered in order " );
//test FirstLast
$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 " );
//test Middle
$result = $this -> render ( '<% loop Set %><% if Middle %>$Number<% end_if %><% end_loop %>' , $data );
$this -> assertEquals ( " 23456789 " , $result , " Middle numbers rendered in order " );
//test MiddleString
2012-09-26 23:34:00 +02:00
$result = $this -> render ( '<% loop Set %><% if MiddleString == "middle" %>$Number$MiddleString<% end_if %>'
. '<% end_loop %>' , $data );
$this -> assertEquals ( " 2middle3middle4middle5middle6middle7middle8middle9middle " , $result ,
" Middle numbers rendered in order " );
2012-02-11 03:26:26 +01:00
//test EvenOdd
$result = $this -> render ( '<% loop Set %>$EvenOdd<% end_loop %>' , $data );
2012-09-26 23:34:00 +02:00
$this -> assertEquals ( " oddevenoddevenoddevenoddevenoddeven " , $result ,
" Even and Odd is returned in sequence numbers rendered in order " );
2012-02-11 03:26:26 +01:00
//test Pos
$result = $this -> render ( '<% loop Set %>$Pos<% end_loop %>' , $data );
2015-04-09 06:39:49 +02:00
$this -> assertEquals ( " 12345678910 " , $result , '$Pos is rendered in order' );
//test Pos
$result = $this -> render ( '<% loop Set %>$Pos(0)<% end_loop %>' , $data );
$this -> assertEquals ( " 0123456789 " , $result , '$Pos(0) is rendered in order' );
//test FromEnd
$result = $this -> render ( '<% loop Set %>$FromEnd<% end_loop %>' , $data );
$this -> assertEquals ( " 10987654321 " , $result , '$FromEnd is rendered in order' );
//test FromEnd
$result = $this -> render ( '<% loop Set %>$FromEnd(0)<% end_loop %>' , $data );
$this -> assertEquals ( " 9876543210 " , $result , '$FromEnd(0) rendered in order' );
2012-02-11 03:26:26 +01:00
//test Total
$result = $this -> render ( '<% loop Set %>$TotalItems<% end_loop %>' , $data );
$this -> assertEquals ( " 10101010101010101010 " , $result , " 10 total items X 10 are returned " );
//test Modulus
$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 " );
//test MultipleOf 3
$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 " );
//test MultipleOf 4
$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 " );
//test MultipleOf 5
$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 " );
//test MultipleOf 10
$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 " );
//test MultipleOf 9 zero-based
$result = $this -> render ( '<% loop Set %><% if MultipleOf(9,0) %>$Number<% end_if %><% end_loop %>' , $data );
2012-09-26 23:34:00 +02:00
$this -> assertEquals ( " 110 " , $result ,
" Only numbers that are multiples of 9 with zero-based indexing are returned. (The first and last item) " );
2012-02-11 03:26:26 +01:00
//test MultipleOf 11
$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 " );
}
2011-02-18 05:06:11 +01:00
/**
* Test $Up works when the scope $Up refers to was entered with a " with " block
*/
2012-09-19 12:07:39 +02:00
public function testUpInWith () {
2011-02-18 05:06:11 +01:00
// Data to run the loop tests on - three levels deep
$data = new ArrayData ( array (
'Name' => 'Top' ,
'Foo' => new ArrayData ( array (
'Name' => 'Foo' ,
'Bar' => new ArrayData ( array (
'Name' => 'Bar' ,
'Baz' => new ArrayData ( array (
'Name' => 'Baz'
)),
'Qux' => new ArrayData ( array (
'Name' => 'Qux'
))
))
))
));
2014-08-15 08:53:05 +02:00
2011-02-18 05:06:11 +01:00
// Basic functionality
$this -> assertEquals ( 'BarFoo' ,
$this -> render ( '<% with Foo %><% with Bar %>{$Name}{$Up.Name}<% end_with %><% end_with %>' , $data ));
2014-08-15 08:53:05 +02:00
2011-02-18 05:06:11 +01:00
// Two level with block, up refers to internally referenced Bar
$this -> assertEquals ( 'BarFoo' ,
$this -> render ( '<% with Foo.Bar %>{$Name}{$Up.Name}<% end_with %>' , $data ));
// Stepping up & back down the scope tree
$this -> assertEquals ( 'BazBarQux' ,
$this -> render ( '<% with Foo.Bar.Baz %>{$Name}{$Up.Name}{$Up.Qux.Name}<% end_with %>' , $data ));
2014-08-15 08:53:05 +02:00
2011-02-18 05:06:11 +01:00
// Using $Up in a with block
$this -> assertEquals ( 'BazBarQux' ,
2012-09-26 23:34:00 +02:00
$this -> render ( '<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}{$Qux.Name}<% end_with %>'
. '<% end_with %>' , $data ));
2011-02-18 05:06:11 +01:00
// Stepping up & back down the scope tree with with blocks
$this -> assertEquals ( 'BazBarQuxBarBaz' ,
2012-09-26 23:34:00 +02:00
$this -> render ( '<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}<% with Qux %>{$Name}<% end_with %>'
. '{$Name}<% end_with %>{$Name}<% end_with %>' , $data ));
2011-02-18 05:06:11 +01:00
2014-08-15 08:53:05 +02:00
// Using $Up.Up, where first $Up points to a previous scope entered using $Up, thereby skipping up to Foo
2011-02-18 05:06:11 +01:00
$this -> assertEquals ( 'Foo' ,
2012-09-26 23:34:00 +02:00
$this -> render ( '<% with Foo.Bar.Baz %><% with Up %><% with Qux %>{$Up.Up.Name}<% end_with %><% end_with %>'
. '<% end_with %>' , $data ));
2014-08-15 08:53:05 +02:00
// Using $Up.Up, where first $Up points to an Up used in a local scope lookup, should still skip to Foo
2011-02-18 05:06:11 +01:00
$this -> assertEquals ( 'Foo' ,
$this -> render ( '<% with Foo.Bar.Baz.Up.Qux %>{$Up.Up.Name}<% end_with %>' , $data ));
}
2014-08-15 08:53:05 +02:00
2011-02-18 05:06:11 +01:00
/**
* Test $Up works when the scope $Up refers to was entered with a " loop " block
*/
2012-09-19 12:07:39 +02:00
public function testUpInLoop (){
2014-08-15 08:53:05 +02:00
2011-02-18 05:06:11 +01:00
// Data to run the loop tests on - one sequence of three items, each with a subitem
$data = new ArrayData ( array (
'Name' => 'Top' ,
2011-05-05 12:40:24 +02:00
'Foo' => new ArrayList ( array (
2011-02-18 05:06:11 +01:00
new ArrayData ( array (
'Name' => '1' ,
'Sub' => new ArrayData ( array (
'Name' => 'Bar'
))
)),
new ArrayData ( array (
'Name' => '2' ,
'Sub' => new ArrayData ( array (
'Name' => 'Baz'
))
)),
new ArrayData ( array (
'Name' => '3' ,
'Sub' => new ArrayData ( array (
'Name' => 'Qux'
))
))
))
));
// Make sure inside a loop, $Up refers to the current item of the loop
$this -> assertEqualIgnoringWhitespace (
'111 222 333' ,
$this -> render (
'<% loop $Foo %>$Name<% with $Sub %>$Up.Name<% end_with %>$Name<% end_loop %>' ,
$data
)
);
// Make sure inside a loop, looping over $Up uses a separate iterator,
// and doesn't interfere with the original iterator
$this -> assertEqualIgnoringWhitespace (
'1Bar123Bar1 2Baz123Baz2 3Qux123Qux3' ,
$this -> render (
' <% loop $Foo %>
$Name
<% with $Sub %>
2011-02-21 03:24:14 +01:00
$Name
<% loop $Up %> $Name <% end_loop %>
2011-02-18 05:06:11 +01:00
$Name
<% end_with %>
2014-08-15 08:53:05 +02:00
$Name
<% end_loop %> ' ,
2011-02-18 05:06:11 +01:00
$data
)
);
2014-08-15 08:53:05 +02:00
2011-02-18 05:06:11 +01:00
// Make sure inside a loop, looping over $Up uses a separate iterator,
// and doesn't interfere with the original iterator or local lookups
$this -> assertEqualIgnoringWhitespace (
'1 Bar1 123 1Bar 1 2 Baz2 123 2Baz 2 3 Qux3 123 3Qux 3' ,
$this -> render (
' <% loop $Foo %>
$Name
<% with $Sub %>
{ $Name }{ $Up . Name }
<% loop $Up %> $Name <% end_loop %>
{ $Up . Name }{ $Name }
<% end_with %>
$Name
<% end_loop %> ' ,
$data
)
);
}
2014-08-15 08:53:05 +02:00
2012-04-12 01:55:35 +02:00
/**
* Test that nested loops restore the loop variables correctly when pushing and popping states
*/
2012-09-19 12:07:39 +02:00
public function testNestedLoops (){
2014-08-15 08:53:05 +02:00
2012-04-12 01:55:35 +02:00
// Data to run the loop tests on - one sequence of three items, one with child elements
// (of a different size to the main sequence)
$data = new ArrayData ( array (
'Foo' => new ArrayList ( array (
new ArrayData ( array (
'Name' => '1' ,
'Children' => new ArrayList ( array (
new ArrayData ( array (
'Name' => 'a'
)),
new ArrayData ( array (
'Name' => 'b'
)),
)),
)),
new ArrayData ( array (
'Name' => '2' ,
'Children' => new ArrayList (),
)),
new ArrayData ( array (
'Name' => '3' ,
'Children' => new ArrayList (),
)),
)),
));
// Make sure that including a loop inside a loop will not destroy the internal count of
// items, checked by using "Last"
$this -> assertEqualIgnoringWhitespace (
'1ab23last' ,
2012-09-26 23:34:00 +02:00
$this -> render ( '<% loop $Foo %>$Name<% loop Children %>$Name<% end_loop %><% if Last %>last<% end_if %>'
. '<% end_loop %>' , $data
2012-04-12 01:55:35 +02:00
)
);
}
2011-02-26 07:55:04 +01:00
2013-03-11 21:53:00 +01:00
public function testLayout () {
$self = $this ;
2013-12-23 22:54:20 +01:00
$this -> useTestTheme ( dirname ( __FILE__ ), 'layouttest' , function () use ( $self ) {
2013-03-11 21:53:00 +01:00
$template = new SSViewer ( array ( 'Page' ));
2016-01-06 22:27:46 +01:00
$self -> assertEquals ( " Foo \n \n " , $template -> process ( new ArrayData ( array ())));
2013-03-11 21:53:00 +01:00
$template = new SSViewer ( array ( 'Shortcodes' , 'Page' ));
2016-01-06 22:27:46 +01:00
$self -> assertEquals ( " [file_link] \n \n " , $template -> process ( new ArrayData ( array ())));
2013-03-11 21:53:00 +01:00
});
}
2013-11-21 20:44:54 +01:00
/**
* @ covers SSViewer :: get_templates_by_class ()
*/
public function testGetTemplatesByClass () {
$self = $this ;
2013-12-23 22:54:20 +01:00
$this -> useTestTheme ( dirname ( __FILE__ ), 'layouttest' , function () use ( $self ) {
2013-11-21 20:44:54 +01:00
// Test passing a string
$templates = SSViewer :: get_templates_by_class ( 'SSViewerTest_Controller' , '' , 'Controller' );
$self -> assertCount ( 2 , $templates );
// Test to ensure we're stopping at the base class.
$templates = SSViewer :: get_templates_by_class ( 'SSViewerTest_Controller' , '' , 'SSViewerTest_Controller' );
$self -> assertCount ( 1 , $templates );
// Make sure we can filter our templates by suffix.
$templates = SSViewer :: get_templates_by_class ( 'SSViewerTest' , '_Controller' );
$self -> assertCount ( 1 , $templates );
// Test passing a valid object
$templates = SSViewer :: get_templates_by_class ( " SSViewerTest_Controller " , '' , 'Controller' );
// Test that templates are returned in the correct order
$self -> assertEquals ( 'SSViewerTest_Controller' , array_shift ( $templates ));
$self -> assertEquals ( 'Controller' , array_shift ( $templates ));
// Let's throw something random in there.
$self -> setExpectedException ( 'InvalidArgumentException' );
$templates = SSViewer :: get_templates_by_class ( array ());
});
}
2011-02-26 07:55:04 +01:00
/**
* @ covers SSViewer :: get_themes ()
*/
2012-09-19 12:07:39 +02:00
public function testThemeRetrieval () {
2011-02-26 07:55:04 +01:00
$ds = DIRECTORY_SEPARATOR ;
$testThemeBaseDir = TEMP_FOLDER . $ds . 'test-themes' ;
if ( file_exists ( $testThemeBaseDir )) Filesystem :: removeFolder ( $testThemeBaseDir );
mkdir ( $testThemeBaseDir );
mkdir ( $testThemeBaseDir . $ds . 'blackcandy' );
mkdir ( $testThemeBaseDir . $ds . 'blackcandy_blog' );
mkdir ( $testThemeBaseDir . $ds . 'darkshades' );
mkdir ( $testThemeBaseDir . $ds . 'darkshades_blog' );
$this -> assertEquals ( array (
'blackcandy' => 'blackcandy' ,
'darkshades' => 'darkshades'
), SSViewer :: get_themes ( $testThemeBaseDir ), 'Our test theme directory contains 2 themes' );
$this -> assertEquals ( array (
'blackcandy' => 'blackcandy' ,
'blackcandy_blog' => 'blackcandy_blog' ,
'darkshades' => 'darkshades' ,
'darkshades_blog' => 'darkshades_blog'
2012-09-26 23:34:00 +02:00
), SSViewer :: get_themes ( $testThemeBaseDir , true ),
'Our test theme directory contains 2 themes and 2 sub-themes' );
2011-02-26 07:55:04 +01:00
// Remove all the test themes we created
Filesystem :: removeFolder ( $testThemeBaseDir );
}
2013-03-11 21:53:00 +01:00
2012-09-19 12:07:39 +02:00
public function testRewriteHashlinks () {
2016-01-06 00:34:58 +01:00
$orig = Config :: inst () -> get ( 'SSViewer' , 'rewrite_hash_links' );
2014-08-15 08:53:05 +02:00
Config :: inst () -> update ( 'SSViewer' , 'rewrite_hash_links' , true );
2015-10-28 23:53:44 +01:00
$_SERVER [ 'HTTP_HOST' ] = 'www.mysite.com' ;
$_SERVER [ 'REQUEST_URI' ] = '//file.com?foo"onclick="alert(\'xss\')""' ;
2015-03-20 06:17:51 +01:00
2011-10-18 11:42:55 +02:00
// Emulate SSViewer::process()
2015-10-28 23:53:44 +01:00
// Note that leading double slashes have been rewritten to prevent these being mis-interepreted
// as protocol-less absolute urls
$base = Convert :: raw2att ( '/file.com?foo"onclick="alert(\'xss\')""' );
2014-08-15 08:53:05 +02:00
2011-10-18 11:42:55 +02:00
$tmplFile = TEMP_FOLDER . '/SSViewerTest_testRewriteHashlinks_' . sha1 ( rand ()) . '.ss' ;
2014-08-15 08:53:05 +02:00
2011-10-18 11:42:55 +02:00
// Note: SSViewer_FromString doesn't rewrite hash links.
file_put_contents ( $tmplFile , ' <! DOCTYPE html >
< html >
< head ><% base_tag %></ head >
< body >
2015-03-20 06:17:51 +01:00
< a class = " external-inline " href = " http://google.com#anchor " > ExternalInlineLink </ a >
$ExternalInsertedLink
2011-10-18 11:42:55 +02:00
< a class = " inline " href = " #anchor " > InlineLink </ a >
$InsertedLink
2014-09-26 07:41:27 +02:00
< svg >< use xlink : href = " #sprite " ></ use ></ svg >
2011-10-18 11:42:55 +02:00
< body >
</ html > ' );
$tmpl = new SSViewer ( $tmplFile );
$obj = new ViewableData ();
$obj -> InsertedLink = '<a class="inserted" href="#anchor">InsertedLink</a>' ;
2015-03-20 06:17:51 +01:00
$obj -> ExternalInsertedLink = '<a class="external-inserted" href="http://google.com#anchor">ExternalInsertedLink</a>' ;
2011-10-18 11:42:55 +02:00
$result = $tmpl -> process ( $obj );
$this -> assertContains (
'<a class="inserted" href="' . $base . '#anchor">InsertedLink</a>' ,
$result
);
2015-03-20 06:17:51 +01:00
$this -> assertContains (
'<a class="external-inserted" href="http://google.com#anchor">ExternalInsertedLink</a>' ,
$result
);
2011-10-18 11:42:55 +02:00
$this -> assertContains (
'<a class="inline" href="' . $base . '#anchor">InlineLink</a>' ,
$result
);
2015-03-20 06:17:51 +01:00
$this -> assertContains (
'<a class="external-inline" href="http://google.com#anchor">ExternalInlineLink</a>' ,
$result
);
2014-09-26 07:41:27 +02:00
$this -> assertContains (
'<svg><use xlink:href="#sprite"></use></svg>' ,
$result ,
'SSTemplateParser should only rewrite anchor hrefs'
);
2014-08-15 08:53:05 +02:00
2011-10-18 11:42:55 +02:00
unlink ( $tmplFile );
2013-03-21 19:48:54 +01:00
2014-08-15 08:53:05 +02:00
Config :: inst () -> update ( 'SSViewer' , 'rewrite_hash_links' , $orig );
2011-10-18 11:42:55 +02:00
}
2014-08-15 08:53:05 +02:00
2012-09-19 12:07:39 +02:00
public function testRewriteHashlinksInPhpMode () {
2014-08-15 08:53:05 +02:00
$orig = Config :: inst () -> get ( 'SSViewer' , 'rewrite_hash_links' );
Config :: inst () -> update ( 'SSViewer' , 'rewrite_hash_links' , 'php' );
2011-10-18 11:42:55 +02:00
$tmplFile = TEMP_FOLDER . '/SSViewerTest_testRewriteHashlinksInPhpMode_' . sha1 ( rand ()) . '.ss' ;
2014-08-15 08:53:05 +02:00
2011-10-18 11:42:55 +02:00
// Note: SSViewer_FromString doesn't rewrite hash links.
file_put_contents ( $tmplFile , ' <! DOCTYPE html >
< html >
< head ><% base_tag %></ head >
< body >
< a class = " inline " href = " #anchor " > InlineLink </ a >
$InsertedLink
2014-09-26 07:41:27 +02:00
< svg >< use xlink : href = " #sprite " ></ use ></ svg >
2011-10-18 11:42:55 +02:00
< body >
</ html > ' );
$tmpl = new SSViewer ( $tmplFile );
$obj = new ViewableData ();
$obj -> InsertedLink = '<a class="inserted" href="#anchor">InsertedLink</a>' ;
$result = $tmpl -> process ( $obj );
2015-10-28 23:53:44 +01:00
$code = <<< 'EOC'
< a class = " inserted " href = " <?php echo Convert::raw2att(preg_replace( " /^ ( \ / ) +/ " , " / " , $_SERVER['REQUEST_URI'] )); ?>#anchor " > InsertedLink </ a >
EOC ;
$this -> assertContains ( $code , $result );
2011-10-18 11:42:55 +02:00
// TODO Fix inline links in PHP mode
// $this->assertContains(
// '<a class="inline" href="<?php echo str_replace(',
// $result
// );
2014-09-26 07:41:27 +02:00
$this -> assertContains (
'<svg><use xlink:href="#sprite"></use></svg>' ,
$result ,
'SSTemplateParser should only rewrite anchor hrefs'
);
2016-01-06 00:34:58 +01:00
2011-10-18 11:42:55 +02:00
unlink ( $tmplFile );
2013-03-21 19:48:54 +01:00
2014-08-15 08:53:05 +02:00
Config :: inst () -> update ( 'SSViewer' , 'rewrite_hash_links' , $orig );
2011-10-18 11:42:55 +02:00
}
2014-08-15 08:53:05 +02:00
2012-09-19 12:07:39 +02:00
public function testRenderWithSourceFileComments () {
2013-03-21 19:48:54 +01:00
$origEnv = Config :: inst () -> get ( 'Director' , 'environment_type' );
Config :: inst () -> update ( 'Director' , 'environment_type' , 'dev' );
Config :: inst () -> update ( 'SSViewer' , 'source_file_comments' , true );
2013-06-25 07:35:16 +02:00
$f = FRAMEWORK_PATH . '/tests/templates/SSViewerTestComments' ;
2013-04-22 20:17:31 +02:00
$templates = array (
array (
'name' => 'SSViewerTestCommentsFullSource' ,
'expected' => " "
. " <!doctype html> "
. " <!-- template $f /SSViewerTestCommentsFullSource.ss --> "
. " <html> "
. " \t <head></head> "
. " \t <body></body> "
. " </html> "
. " <!-- end template $f /SSViewerTestCommentsFullSource.ss --> " ,
),
array (
'name' => 'SSViewerTestCommentsFullSourceHTML4Doctype' ,
'expected' => " "
2013-06-25 07:35:16 +02:00
. " <!DOCTYPE HTML PUBLIC \" -//W3C//DTD HTML "
. " 4.01//EN \" \t \t \" http://www.w3.org/TR/html4/strict.dtd \" > "
2013-04-22 20:17:31 +02:00
. " <!-- template $f /SSViewerTestCommentsFullSourceHTML4Doctype.ss --> "
. " <html> "
. " \t <head></head> "
. " \t <body></body> "
. " </html> "
. " <!-- end template $f /SSViewerTestCommentsFullSourceHTML4Doctype.ss --> " ,
),
array (
'name' => 'SSViewerTestCommentsFullSourceNoDoctype' ,
'expected' => " "
. " <html><!-- template $f /SSViewerTestCommentsFullSourceNoDoctype.ss --> "
. " \t <head></head> "
. " \t <body></body> "
. " <!-- end template $f /SSViewerTestCommentsFullSourceNoDoctype.ss --></html> " ,
),
array (
'name' => 'SSViewerTestCommentsFullSourceIfIE' ,
'expected' => " "
. " <!doctype html> "
. " <!-- template $f /SSViewerTestCommentsFullSourceIfIE.ss --> "
. " <!--[if lte IE 8]> <html class='old-ie'> <![endif]--> "
. " <!--[if gt IE 8]> <html class='new-ie'> <![endif]--> "
. " <!--[if !IE]><!--> <html class='no-ie'> <!--<![endif]--> "
. " \t <head></head> "
. " \t <body></body> "
. " </html> "
. " <!-- end template $f /SSViewerTestCommentsFullSourceIfIE.ss --> " ,
),
array (
'name' => 'SSViewerTestCommentsFullSourceIfIENoDoctype' ,
'expected' => " "
. " <!--[if lte IE 8]> <html class='old-ie'> <![endif]--> "
. " <!--[if gt IE 8]> <html class='new-ie'> <![endif]--> "
. " <!--[if !IE]><!--> <html class='no-ie'> "
. " <!-- template $f /SSViewerTestCommentsFullSourceIfIENoDoctype.ss --> "
. " <!--<![endif]--> "
. " \t <head></head> "
. " \t <body></body> "
. " <!-- end template $f /SSViewerTestCommentsFullSourceIfIENoDoctype.ss --></html> " ,
),
array (
'name' => 'SSViewerTestCommentsPartialSource' ,
'expected' =>
" <!-- template $f /SSViewerTestCommentsPartialSource.ss --> "
. " <div class='typography'></div> "
. " <!-- end template $f /SSViewerTestCommentsPartialSource.ss --> " ,
),
array (
'name' => 'SSViewerTestCommentsWithInclude' ,
'expected' =>
" <!-- template $f /SSViewerTestCommentsWithInclude.ss --> "
. " <div class='typography'> "
. " <!-- include 'SSViewerTestCommentsInclude' --> "
. " <!-- template $f /SSViewerTestCommentsInclude.ss --> "
. " Included "
. " <!-- end template $f /SSViewerTestCommentsInclude.ss --> "
. " <!-- end include 'SSViewerTestCommentsInclude' --> "
. " </div> "
. " <!-- end template $f /SSViewerTestCommentsWithInclude.ss --> " ,
),
);
foreach ( $templates as $template ) {
$this -> _renderWithSourceFileComments ( $template [ 'name' ], $template [ 'expected' ]);
}
2013-03-21 19:48:54 +01:00
Config :: inst () -> update ( 'SSViewer' , 'source_file_comments' , false );
Config :: inst () -> update ( 'Director' , 'environment_type' , $origEnv );
2011-12-17 05:35:26 +01:00
}
2013-04-22 20:17:31 +02:00
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 );
}
2011-02-26 07:55:04 +01:00
2012-09-19 12:07:39 +02:00
public function testLoopIteratorIterator () {
2012-05-11 04:03:31 +02:00
$list = new PaginatedList ( new ArrayList ());
$viewer = new SSViewer_FromString ( '<% loop List %>$ID - $FirstName<br /><% end_loop %>' );
$result = $viewer -> process ( new ArrayData ( array ( 'List' => $list )));
$this -> assertEquals ( $result , '' );
}
2012-11-04 00:59:40 +01:00
public function testProcessOnlyIncludesRequirementsOnce () {
$template = new SSViewer ( array ( 'SSViewerTestProcess' ));
$basePath = dirname ( $this -> getCurrentRelativePath ()) . '/forms' ;
$backend = new Requirements_Backend ;
$backend -> set_combined_files_enabled ( false );
$backend -> combine_files (
'RequirementsTest_ab.css' ,
array (
$basePath . '/RequirementsTest_a.css' ,
$basePath . '/RequirementsTest_b.css'
)
);
Requirements :: set_backend ( $backend );
$this -> assertEquals ( 1 , substr_count ( $template -> process ( array ()), " a.css " ));
$this -> assertEquals ( 1 , substr_count ( $template -> process ( array ()), " b.css " ));
// if we disable the requirements then we should get nothing
$template -> includeRequirements ( false );
$this -> assertEquals ( 0 , substr_count ( $template -> process ( array ()), " a.css " ));
$this -> assertEquals ( 0 , substr_count ( $template -> process ( array ()), " b.css " ));
}
public function testRequireCallInTemplateInclude () {
2014-08-31 17:37:08 +02:00
//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' ) {
$template = new SSViewer ( array ( 'SSViewerTestProcess' ));
2014-08-15 08:53:05 +02:00
2014-08-31 17:37:08 +02:00
Requirements :: set_suffix_requirements ( false );
2012-11-04 00:59:40 +01:00
2014-08-31 17:37:08 +02:00
$this -> assertEquals ( 1 , substr_count (
$template -> process ( array ()),
" tests/forms/RequirementsTest_a.js "
));
}
else {
$this -> markTestSkipped ( 'Requirement will always fail if the framework dir is not ' .
'named \'framework\', since templates require hard coded paths' );
}
2012-11-04 00:59:40 +01:00
}
2013-06-25 07:35:16 +02:00
public function testCallsWithArguments () {
$data = new ArrayData ( array (
'Set' => new ArrayList ( array (
new SSViewerTest_Object ( " 1 " ),
new SSViewerTest_Object ( " 2 " ),
new SSViewerTest_Object ( " 3 " ),
new SSViewerTest_Object ( " 4 " ),
new SSViewerTest_Object ( " 5 " ),
)),
'Level' => new SSViewerTest_LevelTest ( 1 ),
'Nest' => array (
'Level' => new SSViewerTest_LevelTest ( 2 ),
),
));
$tests = array (
'$Level.output(1)' => '1-1' ,
'$Nest.Level.output($Set.First.Number)' => '2-1' ,
'<% with $Set %>$Up.Level.output($First.Number)<% end_with %>' => '1-1' ,
'<% with $Set %>$Top.Nest.Level.output($First.Number)<% end_with %>' => '2-1' ,
'<% loop $Set %>$Up.Nest.Level.output($Number)<% end_loop %>' => '2-12-22-32-42-5' ,
'<% loop $Set %>$Top.Level.output($Number)<% end_loop %>' => '1-11-21-31-41-5' ,
'<% with $Nest %>$Level.output($Top.Set.First.Number)<% end_with %>' => '2-1' ,
'<% with $Level %>$output($Up.Set.Last.Number)<% end_with %>' => '1-5' ,
'<% with $Level.forWith($Set.Last.Number) %>$output("hi")<% end_with %>' => '5-hi' ,
'<% loop $Level.forLoop($Set.First.Number) %>$Number<% end_loop %>' => '!0' ,
' <% with $Nest %>
<% with $Level . forWith ( $Up . Set . First . Number ) %> $output ( " hi " ) <% end_with %>
<% end_with %> ' => ' 1 - hi ' ,
' <% with $Nest %>
<% loop $Level . forLoop ( $Top . Set . Last . Number ) %> $Number <% end_loop %>
<% end_with %> ' => ' ! 0 ! 1 ! 2 ! 3 ! 4 ' ,
);
foreach ( $tests as $template => $expected ) {
$this -> assertEquals ( $expected , trim ( $this -> render ( $template , $data )));
}
}
2013-10-24 01:43:20 +02:00
public function testClosedBlockExtension () {
$count = 0 ;
$parser = new SSTemplateParser ();
$parser -> addClosedBlock (
'test' ,
function ( & $res ) use ( & $count ) {
$count ++ ;
}
);
$template = new SSViewer_FromString ( " <% test %><% end_test %> " , $parser );
$template -> process ( new SSViewerTestFixture ());
$this -> assertEquals ( 1 , $count );
}
public function testOpenBlockExtension () {
$count = 0 ;
$parser = new SSTemplateParser ();
$parser -> addOpenBlock (
'test' ,
function ( & $res ) use ( & $count ) {
$count ++ ;
}
);
$template = new SSViewer_FromString ( " <% test %> " , $parser );
$template -> process ( new SSViewerTestFixture ());
$this -> assertEquals ( 1 , $count );
}
2013-07-11 03:58:45 +02:00
/**
* Tests if caching for SSViewer_FromString is working
*/
public function testFromStringCaching () {
$content = 'Test content' ;
$cacheFile = TEMP_FOLDER . '/.cache.' . sha1 ( $content );
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' );
Config :: inst () -> update ( 'SSViewer_FromString' , '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 );
}
2009-01-04 23:20:36 +01:00
}
2009-11-27 01:24:57 +01:00
/**
* A test fixture that will echo back the template item
*/
class SSViewerTestFixture extends ViewableData {
protected $name ;
2012-09-19 12:07:39 +02:00
public function __construct ( $name = null ) {
2009-11-27 01:24:57 +01:00
$this -> name = $name ;
2011-02-14 02:10:17 +01:00
parent :: __construct ();
2009-11-27 01:24:57 +01:00
}
2014-08-15 08:53:05 +02:00
2009-11-27 01:24:57 +01:00
private function argedName ( $fieldName , $arguments ) {
$childName = $this -> name ? " $this->name . $fieldName " : $fieldName ;
if ( $arguments ) return $childName . '(' . implode ( ',' , $arguments ) . ')' ;
else return $childName ;
}
2012-09-19 12:07:39 +02:00
public function obj ( $fieldName , $arguments = null , $forceReturnedObject = true , $cache = false , $cacheName = null ) {
2009-11-27 01:24:57 +01:00
$childName = $this -> argedName ( $fieldName , $arguments );
// Special field name Loop### to create a list
if ( preg_match ( '/^Loop([0-9]+)$/' , $fieldName , $matches )) {
2011-05-05 12:40:24 +02:00
$output = new ArrayList ();
2009-11-27 01:24:57 +01:00
for ( $i = 0 ; $i < $matches [ 1 ]; $i ++ ) $output -> push ( new SSViewerTestFixture ( $childName ));
return $output ;
} else if ( preg_match ( '/NotSet/i' , $fieldName )) {
return new ViewableData ();
} else {
return new SSViewerTestFixture ( $childName );
}
}
2014-08-15 08:53:05 +02:00
2009-11-27 01:24:57 +01:00
2012-09-19 12:07:39 +02:00
public function XML_val ( $fieldName , $arguments = null , $cache = false ) {
2009-11-27 01:24:57 +01:00
if ( preg_match ( '/NotSet/i' , $fieldName )) {
return '' ;
} else if ( preg_match ( '/Raw/i' , $fieldName )) {
return $fieldName ;
} else {
return '[out:' . $this -> argedName ( $fieldName , $arguments ) . ']' ;
}
}
2012-09-19 12:07:39 +02:00
public function hasValue ( $fieldName , $arguments = null , $cache = true ) {
2009-11-27 01:24:57 +01:00
return ( bool ) $this -> XML_val ( $fieldName , $arguments );
}
}
2010-10-19 02:58:23 +02:00
2009-01-04 23:20:36 +01:00
class SSViewerTest_ViewableData extends ViewableData implements TestOnly {
2012-02-29 20:35:48 +01:00
2013-03-21 19:48:54 +01:00
private static $casting = array (
2012-02-29 20:35:48 +01:00
'TextValue' => 'Text' ,
'HTMLValue' => 'HTMLText'
);
2012-09-19 12:07:39 +02:00
public function methodWithOneArgument ( $arg1 ) {
2009-01-04 23:20:36 +01:00
return " arg1: { $arg1 } " ;
}
2014-08-15 08:53:05 +02:00
2012-09-19 12:07:39 +02:00
public function methodWithTwoArguments ( $arg1 , $arg2 ) {
2009-01-04 23:20:36 +01:00
return " arg1: { $arg1 } ,arg2: { $arg2 } " ;
}
2009-11-27 01:24:57 +01:00
}
2011-03-18 03:04:43 +01:00
class SSViewerTest_Controller extends Controller {
2014-08-15 08:53:05 +02:00
2011-03-18 03:04:43 +01:00
}
2012-02-11 03:08:39 +01:00
2015-02-12 14:15:32 +01:00
class SSViewerTest_Object extends DataObject implements TestOnly {
2012-02-11 03:08:39 +01:00
2012-02-11 03:26:26 +01:00
public $number = null ;
2013-06-15 15:40:33 +02:00
private static $casting = array (
'Link' => 'Text' ,
);
2012-09-19 12:07:39 +02:00
public function __construct ( $number = null ) {
2012-02-11 03:26:26 +01:00
parent :: __construct ();
$this -> number = $number ;
}
2012-09-19 12:07:39 +02:00
public function Number () {
2012-02-11 03:26:26 +01:00
return $this -> number ;
}
2012-09-19 12:07:39 +02:00
public function absoluteBaseURL () {
2012-02-11 03:26:26 +01:00
return " testLocalFunctionPriorityCalled " ;
}
2012-09-19 12:07:39 +02:00
public function lotsOfArguments11 ( $a , $b , $c , $d , $e , $f , $g , $h , $i , $j , $k ) {
2012-02-11 03:26:26 +01:00
return $a . $b . $c . $d . $e . $f . $g . $h . $i . $j . $k ;
2012-02-11 03:08:39 +01:00
}
2013-06-15 15:40:33 +02:00
public function Link () {
return 'some/url.html' ;
}
2012-02-11 03:08:39 +01:00
}
2012-02-20 23:45:43 +01:00
class SSViewerTest_GlobalProvider implements TemplateGlobalProvider , TestOnly {
2012-02-21 01:36:34 +01:00
public static function get_template_global_variables () {
2012-02-20 23:45:43 +01:00
return array (
2013-03-11 22:42:02 +01:00
'SSViewerTest_GlobalHTMLFragment' => array ( 'method' => 'get_html' , 'casting' => 'HTMLText' ),
'SSViewerTest_GlobalHTMLEscaped' => array ( 'method' => 'get_html' ),
2012-02-20 23:45:43 +01:00
'SSViewerTest_GlobalAutomatic' ,
'SSViewerTest_GlobalReferencedByString' => 'get_reference' ,
'SSViewerTest_GlobalReferencedInArray' => array ( 'method' => 'get_reference' ),
2013-03-11 22:42:02 +01:00
'SSViewerTest_GlobalThatTakesArguments' => array ( 'method' => 'get_argmix' , 'casting' => 'HTMLText' )
2012-02-20 23:45:43 +01:00
);
}
2012-09-19 12:07:39 +02:00
public static function get_html () {
2012-02-20 23:45:43 +01:00
return '<div></div>' ;
}
2012-09-19 12:07:39 +02:00
public static function SSViewerTest_GlobalAutomatic () {
2012-02-20 23:45:43 +01:00
return 'automatic' ;
}
2012-09-19 12:07:39 +02:00
public static function get_reference () {
2012-02-20 23:45:43 +01:00
return 'reference' ;
}
2012-09-19 12:07:39 +02:00
public static function get_argmix () {
2012-03-09 06:32:10 +01:00
$args = func_get_args ();
return 'z' . implode ( ':' , $args ) . 'z' ;
2012-02-20 23:45:43 +01:00
}
2012-03-27 06:04:11 +02:00
}
2013-06-25 07:35:16 +02:00
class SSViewerTest_LevelTest extends ViewableData implements TestOnly {
protected $depth ;
public function __construct ( $depth = 1 ) {
$this -> depth = $depth ;
}
public function output ( $val ) {
return " $this->depth - $val " ;
}
public function forLoop ( $number ) {
$ret = array ();
for ( $i = 0 ; $i < ( int ) $number ; ++ $i ) {
$ret [] = new SSViewerTest_Object ( " ! $i " );
}
return new ArrayList ( $ret );
}
public function forWith ( $number ) {
return new self ( $number );
}
}