testCastingHelpers()} for more tests related to casting and ViewableData behaviour, * from a template-parsing perspective. * * @package framework * @subpackage tests */ class ViewableDataTest extends SapphireTest { public function testCasting() { $htmlString = """; $textString = '"'; $htmlField = DBField::create_field('HTMLFragment', $textString); $this->assertEquals($textString, $htmlField->forTemplate()); $this->assertEquals($htmlString, $htmlField->obj('HTMLATT')->forTemplate()); $this->assertEquals('%22', $htmlField->obj('URLATT')->forTemplate()); $this->assertEquals('%22', $htmlField->obj('RAWURLATT')->forTemplate()); $this->assertEquals($htmlString, $htmlField->obj('ATT')->forTemplate()); $this->assertEquals($textString, $htmlField->obj('RAW')->forTemplate()); $this->assertEquals('\"', $htmlField->obj('JS')->forTemplate()); $this->assertEquals($textString, $htmlField->obj('HTML')->forTemplate()); $this->assertEquals($textString, $htmlField->obj('XML')->forTemplate()); $textField = DBField::create_field('Text', $textString); $this->assertEquals($htmlString, $textField->forTemplate()); $this->assertEquals($htmlString, $textField->obj('HTMLATT')->forTemplate()); $this->assertEquals('%22', $textField->obj('URLATT')->forTemplate()); $this->assertEquals('%22', $textField->obj('RAWURLATT')->forTemplate()); $this->assertEquals($htmlString, $textField->obj('ATT')->forTemplate()); $this->assertEquals($textString, $textField->obj('RAW')->forTemplate()); $this->assertEquals('\"', $textField->obj('JS')->forTemplate()); $this->assertEquals($htmlString, $textField->obj('HTML')->forTemplate()); $this->assertEquals($htmlString, $textField->obj('XML')->forTemplate()); } public function testRequiresCasting() { $caster = new ViewableDataTest_Castable(); $this->assertInstanceOf('ViewableDataTest_RequiresCasting', $caster->obj('alwaysCasted')); $this->assertInstanceOf('ViewableData_Caster', $caster->obj('noCastingInformation')); } public function testFailoverRequiresCasting() { $caster = new ViewableDataTest_Castable(); $container = new ViewableDataTest_Container(); $container->setFailover($caster); $this->assertInstanceOf('ViewableDataTest_RequiresCasting', $container->obj('alwaysCasted')); $this->assertInstanceOf('ViewableDataTest_RequiresCasting', $caster->obj('alwaysCasted')); $this->assertInstanceOf('ViewableData_Caster', $container->obj('noCastingInformation')); $this->assertInstanceOf('ViewableData_Caster', $caster->obj('noCastingInformation')); } public function testCastingXMLVal() { $caster = new ViewableDataTest_Castable(); $this->assertEquals('casted', $caster->XML_val('alwaysCasted')); $this->assertEquals('casted', $caster->XML_val('noCastingInformation')); // Test automatic escaping is applied even to fields with no 'casting' $this->assertEquals('casted', $caster->XML_val('unsafeXML')); $this->assertEquals('<foo>', $caster->XML_val('castedUnsafeXML')); } public function testArrayCustomise() { $viewableData = new ViewableDataTest_Castable(); $newViewableData = $viewableData->customise(array ( 'test' => 'overwritten', 'alwaysCasted' => 'overwritten' )); $this->assertEquals('test', $viewableData->XML_val('test')); $this->assertEquals('casted', $viewableData->XML_val('alwaysCasted')); $this->assertEquals('overwritten', $newViewableData->XML_val('test')); $this->assertEquals('overwritten', $newViewableData->XML_val('alwaysCasted')); $this->assertEquals('castable', $viewableData->forTemplate()); $this->assertEquals('castable', $newViewableData->forTemplate()); } public function testObjectCustomise() { $viewableData = new ViewableDataTest_Castable(); $newViewableData = $viewableData->customise(new ViewableDataTest_RequiresCasting()); $this->assertEquals('test', $viewableData->XML_val('test')); $this->assertEquals('casted', $viewableData->XML_val('alwaysCasted')); $this->assertEquals('overwritten', $newViewableData->XML_val('test')); $this->assertEquals('casted', $newViewableData->XML_val('alwaysCasted')); $this->assertEquals('castable', $viewableData->forTemplate()); $this->assertEquals('casted', $newViewableData->forTemplate()); } public function testDefaultValueWrapping() { $data = new ArrayData(array('Title' => 'SomeTitleValue')); // this results in a cached raw string in ViewableData: $this->assertTrue($data->hasValue('Title')); $this->assertFalse($data->hasValue('SomethingElse')); // this should cast the raw string to a StringField since we are // passing true as the third argument: $obj = $data->obj('Title', null, true); $this->assertTrue(is_object($obj)); // and the string field should have the value of the raw string: $this->assertEquals('SomeTitleValue', $obj->forTemplate()); } public function testCastingClass() { $expected = array( //'NonExistant' => null, 'Field' => 'CastingType', 'Argument' => 'ArgumentType', 'ArrayArgument' => 'ArrayArgumentType' ); $obj = new ViewableDataTest_CastingClass(); foreach($expected as $field => $class) { $this->assertEquals( $class, $obj->castingClass($field), "castingClass() returns correct results for ::\$$field" ); } } public function testObjWithCachedStringValueReturnsValidObject() { $obj = new ViewableDataTest_NoCastingInformation(); // Save a literal string into cache $cache = true; $uncastedData = $obj->obj('noCastingInformation', null, false, $cache); // Fetch the cached string as an object $forceReturnedObject = true; $castedData = $obj->obj('noCastingInformation', null, $forceReturnedObject); // Uncasted data should always be the nonempty string $this->assertNotEmpty($uncastedData, 'Uncasted data was empty.'); //$this->assertTrue(is_string($uncastedData), 'Uncasted data should be a string.'); // Casted data should be the string wrapped in a DBField-object. $this->assertNotEmpty($castedData, 'Casted data was empty.'); $this->assertInstanceOf('SilverStripe\\ORM\\FieldType\\DBField', $castedData, 'Casted data should be instance of DBField.'); $this->assertEquals($uncastedData, $castedData->getValue(), 'Casted and uncasted strings are not equal.'); } public function testCaching() { $objCached = new ViewableDataTest_Cached(); $objNotCached = new ViewableDataTest_NotCached(); $objCached->Test = 'AAA'; $objNotCached->Test = 'AAA'; $this->assertEquals('AAA', $objCached->obj('Test', null, true, true)); $this->assertEquals('AAA', $objNotCached->obj('Test', null, true, true)); $objCached->Test = 'BBB'; $objNotCached->Test = 'BBB'; // Cached data must be always the same $this->assertEquals('AAA', $objCached->obj('Test', null, true, true)); $this->assertEquals('BBB', $objNotCached->obj('Test', null, true, true)); } public function testSetFailover() { $failover = new ViewableData(); $container = new ViewableDataTest_Container(); $container->setFailover($failover); $this->assertSame($failover, $container->getFailover(), 'getFailover() returned a different object'); $this->assertFalse($container->hasMethod('testMethod'), 'testMethod() is already defined when it shouldn’t be'); // Ensure that defined methods detected from the failover aren't cached when setting a new failover $container->setFailover(new ViewableDataTest_Failover); $this->assertTrue($container->hasMethod('testMethod')); // Test the reverse - that defined methods previously detected in a failover are removed if they no longer exist $container->setFailover($failover); $this->assertSame($failover, $container->getFailover(), 'getFailover() returned a different object'); $this->assertFalse($container->hasMethod('testMethod'), 'testMethod() incorrectly reported as existing'); } } /**#@+ * @ignore */ class ViewableDataTest_Castable extends ViewableData { private static $default_cast = 'ViewableData_Caster'; private static $casting = array ( 'alwaysCasted' => 'ViewableDataTest_RequiresCasting', 'castedUnsafeXML' => 'ViewableData_UnescaptedCaster', 'test' => 'Text', ); public $test = 'test'; public $uncastedZeroValue = 0; public function alwaysCasted() { return 'alwaysCasted'; } public function noCastingInformation() { return 'noCastingInformation'; } public function unsafeXML() { return ''; } public function castedUnsafeXML() { return $this->unsafeXML(); } public function forTemplate() { return 'castable'; } } class ViewableDataTest_RequiresCasting extends ViewableData { public $test = 'overwritten'; public function forTemplate() { return 'casted'; } public function setValue() {} } class ViewableData_UnescaptedCaster extends ViewableData { protected $value; public function setValue($value) { $this->value = $value; } public function forTemplate() { return Convert::raw2xml($this->value); } } class ViewableData_Caster extends ViewableData { public function forTemplate() { return 'casted'; } public function setValue() {} } class ViewableDataTest_Container extends ViewableData { } class ViewableDataTest_CastingClass extends ViewableData { private static $casting = array( 'Field' => 'CastingType', 'Argument' => 'ArgumentType(Argument)', 'ArrayArgument' => 'ArrayArgumentType(array(foo, bar))' ); } class ViewableDataTest_NoCastingInformation extends ViewableData { public function noCastingInformation() { return "No casting information"; } } class ViewableDataTest_Cached extends ViewableData { public $Test; } class ViewableDataTest_NotCached extends ViewableData { public $Test; protected function objCacheGet($key) { // Disable caching return null; } } class ViewableDataTest_Failover extends ViewableData { public function testMethod() {} }