ExporterTest.php 9.0 KB

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