1<?php 2/* 3 * This file is part of the Exporter package. 4 * 5 * (c) Sebastian Bergmann <sebastian@phpunit.de> 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 */ 10 11namespace SebastianBergmann\Exporter; 12 13/** 14 * @covers SebastianBergmann\Exporter\Exporter 15 */ 16class ExporterTest extends \PHPUnit_Framework_TestCase 17{ 18 /** 19 * @var Exporter 20 */ 21 private $exporter; 22 23 protected function setUp() 24 { 25 $this->exporter = new Exporter; 26 } 27 28 public function exportProvider() 29 { 30 $obj2 = new \stdClass; 31 $obj2->foo = 'bar'; 32 33 $obj3 = (object)array(1,2,"Test\r\n",4,5,6,7,8); 34 35 $obj = new \stdClass; 36 //@codingStandardsIgnoreStart 37 $obj->null = null; 38 //@codingStandardsIgnoreEnd 39 $obj->boolean = true; 40 $obj->integer = 1; 41 $obj->double = 1.2; 42 $obj->string = '1'; 43 $obj->text = "this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext"; 44 $obj->object = $obj2; 45 $obj->objectagain = $obj2; 46 $obj->array = array('foo' => 'bar'); 47 $obj->self = $obj; 48 49 $storage = new \SplObjectStorage; 50 $storage->attach($obj2); 51 $storage->foo = $obj2; 52 53 return array( 54 array(null, 'null'), 55 array(true, 'true'), 56 array(false, 'false'), 57 array(1, '1'), 58 array(1.0, '1.0'), 59 array(1.2, '1.2'), 60 array(fopen('php://memory', 'r'), 'resource(%d) of type (stream)'), 61 array('1', "'1'"), 62 array(array(array(1,2,3), array(3,4,5)), 63 <<<EOF 64Array &0 ( 65 0 => Array &1 ( 66 0 => 1 67 1 => 2 68 2 => 3 69 ) 70 1 => Array &2 ( 71 0 => 3 72 1 => 4 73 2 => 5 74 ) 75) 76EOF 77 ), 78 // \n\r and \r is converted to \n 79 array("this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext", 80 <<<EOF 81'this 82is 83a 84very 85very 86very 87very 88very 89very 90long 91text' 92EOF 93 ), 94 array(new \stdClass, 'stdClass Object &%x ()'), 95 array($obj, 96 <<<EOF 97stdClass Object &%x ( 98 'null' => null 99 'boolean' => true 100 'integer' => 1 101 'double' => 1.2 102 'string' => '1' 103 'text' => 'this 104is 105a 106very 107very 108very 109very 110very 111very 112long 113text' 114 'object' => stdClass Object &%x ( 115 'foo' => 'bar' 116 ) 117 'objectagain' => stdClass Object &%x 118 'array' => Array &%d ( 119 'foo' => 'bar' 120 ) 121 'self' => stdClass Object &%x 122) 123EOF 124 ), 125 array(array(), 'Array &%d ()'), 126 array($storage, 127 <<<EOF 128SplObjectStorage Object &%x ( 129 'foo' => stdClass Object &%x ( 130 'foo' => 'bar' 131 ) 132 '%x' => Array &0 ( 133 'obj' => stdClass Object &%x 134 'inf' => null 135 ) 136) 137EOF 138 ), 139 array($obj3, 140 <<<EOF 141stdClass Object &%x ( 142 0 => 1 143 1 => 2 144 2 => 'Test\n' 145 3 => 4 146 4 => 5 147 5 => 6 148 6 => 7 149 7 => 8 150) 151EOF 152 ), 153 array( 154 chr(0) . chr(1) . chr(2) . chr(3) . chr(4) . chr(5), 155 'Binary String: 0x000102030405' 156 ), 157 array( 158 implode('', array_map('chr', range(0x0e, 0x1f))), 159 'Binary String: 0x0e0f101112131415161718191a1b1c1d1e1f' 160 ), 161 array( 162 chr(0x00) . chr(0x09), 163 'Binary String: 0x0009' 164 ), 165 array( 166 '', 167 "''" 168 ), 169 ); 170 } 171 172 /** 173 * @dataProvider exportProvider 174 */ 175 public function testExport($value, $expected) 176 { 177 $this->assertStringMatchesFormat( 178 $expected, 179 $this->trimNewline($this->exporter->export($value)) 180 ); 181 } 182 183 public function testExport2() 184 { 185 if (PHP_VERSION === '5.3.3') { 186 $this->markTestSkipped('Skipped due to "Nesting level too deep - recursive dependency?" fatal error'); 187 } 188 189 $obj = new \stdClass; 190 $obj->foo = 'bar'; 191 192 $array = array( 193 0 => 0, 194 'null' => null, 195 'boolean' => true, 196 'integer' => 1, 197 'double' => 1.2, 198 'string' => '1', 199 'text' => "this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext", 200 'object' => $obj, 201 'objectagain' => $obj, 202 'array' => array('foo' => 'bar'), 203 ); 204 205 $array['self'] = &$array; 206 207 $expected = <<<EOF 208Array &%d ( 209 0 => 0 210 'null' => null 211 'boolean' => true 212 'integer' => 1 213 'double' => 1.2 214 'string' => '1' 215 'text' => 'this 216is 217a 218very 219very 220very 221very 222very 223very 224long 225text' 226 'object' => stdClass Object &%x ( 227 'foo' => 'bar' 228 ) 229 'objectagain' => stdClass Object &%x 230 'array' => Array &%d ( 231 'foo' => 'bar' 232 ) 233 'self' => Array &%d ( 234 0 => 0 235 'null' => null 236 'boolean' => true 237 'integer' => 1 238 'double' => 1.2 239 'string' => '1' 240 'text' => 'this 241is 242a 243very 244very 245very 246very 247very 248very 249long 250text' 251 'object' => stdClass Object &%x 252 'objectagain' => stdClass Object &%x 253 'array' => Array &%d ( 254 'foo' => 'bar' 255 ) 256 'self' => Array &%d 257 ) 258) 259EOF; 260 261 $this->assertStringMatchesFormat( 262 $expected, 263 $this->trimNewline($this->exporter->export($array)) 264 ); 265 } 266 267 public function shortenedExportProvider() 268 { 269 $obj = new \stdClass; 270 $obj->foo = 'bar'; 271 272 $array = array( 273 'foo' => 'bar', 274 ); 275 276 return array( 277 array(null, 'null'), 278 array(true, 'true'), 279 array(1, '1'), 280 array(1.0, '1.0'), 281 array(1.2, '1.2'), 282 array('1', "'1'"), 283 // \n\r and \r is converted to \n 284 array("this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext", "'this\\nis\\na\\nvery\\nvery\\nvery\\nvery...g\\ntext'"), 285 array(new \stdClass, 'stdClass Object ()'), 286 array($obj, 'stdClass Object (...)'), 287 array(array(), 'Array ()'), 288 array($array, 'Array (...)'), 289 ); 290 } 291 292 /** 293 * @dataProvider shortenedExportProvider 294 */ 295 public function testShortenedExport($value, $expected) 296 { 297 $this->assertSame( 298 $expected, 299 $this->trimNewline($this->exporter->shortenedExport($value)) 300 ); 301 } 302 303 /** 304 * @requires extension mbstring 305 */ 306 public function testShortenedExportForMultibyteCharacters() 307 { 308 $oldMbLanguage = mb_language(); 309 mb_language('Japanese'); 310 $oldMbInternalEncoding = mb_internal_encoding(); 311 mb_internal_encoding('UTF-8'); 312 313 try { 314 $this->assertSame( 315 "'いろはにほへとちりぬるをわかよたれそつねならむうゐのおくや...しゑひもせす'", 316 $this->trimNewline($this->exporter->shortenedExport('いろはにほへとちりぬるをわかよたれそつねならむうゐのおくやまけふこえてあさきゆめみしゑひもせす')) 317 ); 318 } catch (\Exception $e) { 319 mb_internal_encoding($oldMbInternalEncoding); 320 mb_language($oldMbLanguage); 321 throw $e; 322 } 323 324 mb_internal_encoding($oldMbInternalEncoding); 325 mb_language($oldMbLanguage); 326 } 327 328 public function provideNonBinaryMultibyteStrings() 329 { 330 return array( 331 array(implode('', array_map('chr', range(0x09, 0x0d))), 5), 332 array(implode('', array_map('chr', range(0x20, 0x7f))), 96), 333 array(implode('', array_map('chr', range(0x80, 0xff))), 128), 334 ); 335 } 336 337 338 /** 339 * @dataProvider provideNonBinaryMultibyteStrings 340 */ 341 public function testNonBinaryStringExport($value, $expectedLength) 342 { 343 $this->assertRegExp( 344 "~'.{{$expectedLength}}'\$~s", 345 $this->exporter->export($value) 346 ); 347 } 348 349 public function testNonObjectCanBeReturnedAsArray() 350 { 351 $this->assertEquals(array(true), $this->exporter->toArray(true)); 352 } 353 354 private function trimNewline($string) 355 { 356 return preg_replace('/[ ]*\n/', "\n", $string); 357 } 358} 359