ExporterTest.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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. array(null, 'null'),
  48. array(true, 'true'),
  49. array(false, 'false'),
  50. array(1, '1'),
  51. array(1.0, '1.0'),
  52. array(1.2, '1.2'),
  53. array(fopen('php://memory', 'r'), 'resource(%d) of type (stream)'),
  54. array('1', "'1'"),
  55. 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. array("this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext",
  73. <<<EOF
  74. 'this
  75. is
  76. a
  77. very
  78. very
  79. very
  80. very
  81. very
  82. very
  83. long
  84. text'
  85. EOF
  86. ),
  87. array(new \stdClass, 'stdClass Object &%x ()'),
  88. 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
  97. is
  98. a
  99. very
  100. very
  101. very
  102. very
  103. very
  104. very
  105. long
  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. array(array(), 'Array &%d ()'),
  119. 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. array($obj3,
  133. <<<EOF
  134. stdClass Object &%x (
  135. 0 => 1
  136. 1 => 2
  137. 2 => 'Test\n'
  138. 3 => 4
  139. 4 => 5
  140. 5 => 6
  141. 6 => 7
  142. 7 => 8
  143. )
  144. EOF
  145. ),
  146. array(
  147. chr(0) . chr(1) . chr(2) . chr(3) . chr(4) . chr(5),
  148. 'Binary String: 0x000102030405'
  149. ),
  150. array(
  151. implode('', array_map('chr', range(0x0e, 0x1f))),
  152. 'Binary String: 0x0e0f101112131415161718191a1b1c1d1e1f'
  153. ),
  154. array(
  155. chr(0x00) . chr(0x09),
  156. 'Binary String: 0x0009'
  157. ),
  158. array(
  159. '',
  160. "''"
  161. ),
  162. );
  163. }
  164. /**
  165. * @dataProvider exportProvider
  166. */
  167. public function testExport($value, $expected)
  168. {
  169. $this->assertStringMatchesFormat(
  170. $expected,
  171. $this->trimNewline($this->exporter->export($value))
  172. );
  173. }
  174. public function testExport2()
  175. {
  176. if (PHP_VERSION === '5.3.3') {
  177. $this->markTestSkipped('Skipped due to "Nesting level too deep - recursive dependency?" fatal error');
  178. }
  179. $obj = new \stdClass;
  180. $obj->foo = 'bar';
  181. $array = array(
  182. 0 => 0,
  183. 'null' => null,
  184. 'boolean' => true,
  185. 'integer' => 1,
  186. 'double' => 1.2,
  187. 'string' => '1',
  188. 'text' => "this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext",
  189. 'object' => $obj,
  190. 'objectagain' => $obj,
  191. 'array' => array('foo' => 'bar'),
  192. );
  193. $array['self'] = &$array;
  194. $expected = <<<EOF
  195. Array &%d (
  196. 0 => 0
  197. 'null' => null
  198. 'boolean' => true
  199. 'integer' => 1
  200. 'double' => 1.2
  201. 'string' => '1'
  202. 'text' => 'this
  203. is
  204. a
  205. very
  206. very
  207. very
  208. very
  209. very
  210. very
  211. long
  212. text'
  213. 'object' => stdClass Object &%x (
  214. 'foo' => 'bar'
  215. )
  216. 'objectagain' => stdClass Object &%x
  217. 'array' => Array &%d (
  218. 'foo' => 'bar'
  219. )
  220. 'self' => Array &%d (
  221. 0 => 0
  222. 'null' => null
  223. 'boolean' => true
  224. 'integer' => 1
  225. 'double' => 1.2
  226. 'string' => '1'
  227. 'text' => 'this
  228. is
  229. a
  230. very
  231. very
  232. very
  233. very
  234. very
  235. very
  236. long
  237. text'
  238. 'object' => stdClass Object &%x
  239. 'objectagain' => stdClass Object &%x
  240. 'array' => Array &%d (
  241. 'foo' => 'bar'
  242. )
  243. 'self' => Array &%d
  244. )
  245. )
  246. EOF;
  247. $this->assertStringMatchesFormat(
  248. $expected,
  249. $this->trimNewline($this->exporter->export($array))
  250. );
  251. }
  252. public function shortenedExportProvider()
  253. {
  254. $obj = new \stdClass;
  255. $obj->foo = 'bar';
  256. $array = array(
  257. 'foo' => 'bar',
  258. );
  259. return array(
  260. array(null, 'null'),
  261. array(true, 'true'),
  262. array(1, '1'),
  263. array(1.0, '1.0'),
  264. array(1.2, '1.2'),
  265. array('1', "'1'"),
  266. // \n\r and \r is converted to \n
  267. array("this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext", "'this\\nis\\na\\nvery\\nvery\\nvery\\nvery...g\\ntext'"),
  268. array(new \stdClass, 'stdClass Object ()'),
  269. array($obj, 'stdClass Object (...)'),
  270. array(array(), 'Array ()'),
  271. array($array, 'Array (...)'),
  272. );
  273. }
  274. /**
  275. * @dataProvider shortenedExportProvider
  276. */
  277. public function testShortenedExport($value, $expected)
  278. {
  279. $this->assertSame(
  280. $expected,
  281. $this->trimNewline($this->exporter->shortenedExport($value))
  282. );
  283. }
  284. /**
  285. * @requires extension mbstring
  286. */
  287. public function testShortenedExportForMultibyteCharacters()
  288. {
  289. $oldMbLanguage = mb_language();
  290. mb_language('Japanese');
  291. $oldMbInternalEncoding = mb_internal_encoding();
  292. mb_internal_encoding('UTF-8');
  293. try {
  294. $this->assertSame(
  295. "'いろはにほへとちりぬるをわかよたれそつねならむうゐのおくや...しゑひもせす'",
  296. $this->trimNewline($this->exporter->shortenedExport('いろはにほへとちりぬるをわかよたれそつねならむうゐのおくやまけふこえてあさきゆめみしゑひもせす'))
  297. );
  298. } catch (\Exception $e) {
  299. mb_internal_encoding($oldMbInternalEncoding);
  300. mb_language($oldMbLanguage);
  301. throw $e;
  302. }
  303. mb_internal_encoding($oldMbInternalEncoding);
  304. mb_language($oldMbLanguage);
  305. }
  306. public function provideNonBinaryMultibyteStrings()
  307. {
  308. return array(
  309. array(implode('', array_map('chr', range(0x09, 0x0d))), 5),
  310. array(implode('', array_map('chr', range(0x20, 0x7f))), 96),
  311. array(implode('', array_map('chr', range(0x80, 0xff))), 128),
  312. );
  313. }
  314. /**
  315. * @dataProvider provideNonBinaryMultibyteStrings
  316. */
  317. public function testNonBinaryStringExport($value, $expectedLength)
  318. {
  319. $this->assertRegExp(
  320. "~'.{{$expectedLength}}'\$~s",
  321. $this->exporter->export($value)
  322. );
  323. }
  324. public function testNonObjectCanBeReturnedAsArray()
  325. {
  326. $this->assertEquals(array(true), $this->exporter->toArray(true));
  327. }
  328. private function trimNewline($string)
  329. {
  330. return preg_replace('/[ ]*\n/', "\n", $string);
  331. }
  332. }