Drupal investigation

testFormatters.php 41KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481
  1. <?php
  2. namespace Consolidation\OutputFormatters;
  3. use Consolidation\TestUtils\PropertyListWithCsvCells;
  4. use Consolidation\TestUtils\RowsOfFieldsWithAlternatives;
  5. use Consolidation\OutputFormatters\Options\FormatterOptions;
  6. use Consolidation\OutputFormatters\StructuredData\AssociativeList;
  7. use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
  8. use Consolidation\OutputFormatters\StructuredData\PropertyList;
  9. use Symfony\Component\Console\Output\BufferedOutput;
  10. use Symfony\Component\Console\Output\OutputInterface;
  11. use Symfony\Component\Console\Input\InputInterface;
  12. use Symfony\Component\Console\Input\StringInput;
  13. use Symfony\Component\Console\Input\InputOption;
  14. use Symfony\Component\Console\Input\InputArgument;
  15. use Symfony\Component\Console\Input\InputDefinition;
  16. class FormattersTests extends \PHPUnit_Framework_TestCase
  17. {
  18. protected $formatterManager;
  19. function setup() {
  20. $this->formatterManager = new FormatterManager();
  21. }
  22. function assertFormattedOutputMatches($expected, $format, $data, FormatterOptions $options = null, $userOptions = []) {
  23. if (!$options) {
  24. $options = new FormatterOptions();
  25. }
  26. $options->setOptions($userOptions);
  27. $output = new BufferedOutput();
  28. $this->formatterManager->write($output, $format, $data, $options);
  29. $actual = preg_replace('#[ \t]*$#sm', '', $output->fetch());
  30. $this->assertEquals(rtrim($expected), rtrim($actual));
  31. }
  32. function testSimpleYaml()
  33. {
  34. $data = [
  35. 'one' => 'a',
  36. 'two' => 'b',
  37. 'three' => 'c',
  38. ];
  39. $expected = <<<EOT
  40. one: a
  41. two: b
  42. three: c
  43. EOT;
  44. $this->assertFormattedOutputMatches($expected, 'yaml', $data);
  45. }
  46. function testNestedYaml()
  47. {
  48. $data = [
  49. 'one' => [
  50. 'i' => ['a', 'b', 'c'],
  51. ],
  52. 'two' => [
  53. 'ii' => ['q', 'r', 's'],
  54. ],
  55. 'three' => [
  56. 'iii' => ['t', 'u', 'v'],
  57. ],
  58. ];
  59. $expected = <<<EOT
  60. one:
  61. i:
  62. - a
  63. - b
  64. - c
  65. two:
  66. ii:
  67. - q
  68. - r
  69. - s
  70. three:
  71. iii:
  72. - t
  73. - u
  74. - v
  75. EOT;
  76. $this->assertFormattedOutputMatches($expected, 'yaml', $data);
  77. }
  78. function testSimpleJson()
  79. {
  80. $data = [
  81. 'one' => 'a',
  82. 'two' => 'b',
  83. 'three' => 'c',
  84. ];
  85. $expected = <<<EOT
  86. {
  87. "one": "a",
  88. "two": "b",
  89. "three": "c"
  90. }
  91. EOT;
  92. $this->assertFormattedOutputMatches($expected, 'json', $data);
  93. }
  94. function testSerializeFormat()
  95. {
  96. $data = [
  97. 'one' => 'a',
  98. 'two' => 'b',
  99. 'three' => 'c',
  100. ];
  101. $expected = 'a:3:{s:3:"one";s:1:"a";s:3:"two";s:1:"b";s:5:"three";s:1:"c";}';
  102. $this->assertFormattedOutputMatches($expected, 'php', $data);
  103. }
  104. function testNestedJson()
  105. {
  106. $data = [
  107. 'one' => [
  108. 'i' => ['a', 'b', 'c'],
  109. ],
  110. 'two' => [
  111. 'ii' => ['q', 'r', 's'],
  112. ],
  113. 'three' => [
  114. 'iii' => ['t', 'u', 'v'],
  115. ],
  116. ];
  117. $expected = <<<EOT
  118. {
  119. "one": {
  120. "i": [
  121. "a",
  122. "b",
  123. "c"
  124. ]
  125. },
  126. "two": {
  127. "ii": [
  128. "q",
  129. "r",
  130. "s"
  131. ]
  132. },
  133. "three": {
  134. "iii": [
  135. "t",
  136. "u",
  137. "v"
  138. ]
  139. }
  140. }
  141. EOT;
  142. $this->assertFormattedOutputMatches($expected, 'json', $data);
  143. }
  144. function testSimplePrintR()
  145. {
  146. $data = [
  147. 'one' => 'a',
  148. 'two' => 'b',
  149. 'three' => 'c',
  150. ];
  151. $expected = <<<EOT
  152. Array
  153. (
  154. [one] => a
  155. [two] => b
  156. [three] => c
  157. )
  158. EOT;
  159. $this->assertFormattedOutputMatches($expected, 'print-r', $data);
  160. }
  161. function testNestedPrintR()
  162. {
  163. $data = [
  164. 'one' => [
  165. 'i' => ['a', 'b', 'c'],
  166. ],
  167. 'two' => [
  168. 'ii' => ['q', 'r', 's'],
  169. ],
  170. 'three' => [
  171. 'iii' => ['t', 'u', 'v'],
  172. ],
  173. ];
  174. $expected = <<<EOT
  175. Array
  176. (
  177. [one] => Array
  178. (
  179. [i] => Array
  180. (
  181. [0] => a
  182. [1] => b
  183. [2] => c
  184. )
  185. )
  186. [two] => Array
  187. (
  188. [ii] => Array
  189. (
  190. [0] => q
  191. [1] => r
  192. [2] => s
  193. )
  194. )
  195. [three] => Array
  196. (
  197. [iii] => Array
  198. (
  199. [0] => t
  200. [1] => u
  201. [2] => v
  202. )
  203. )
  204. )
  205. EOT;
  206. $this->assertFormattedOutputMatches($expected, 'print-r', $data);
  207. }
  208. function testSimpleVarExport()
  209. {
  210. $data = [
  211. 'one' => 'a',
  212. 'two' => 'b',
  213. 'three' => 'c',
  214. ];
  215. $expected = <<<EOT
  216. array (
  217. 'one' => 'a',
  218. 'two' => 'b',
  219. 'three' => 'c',
  220. )
  221. EOT;
  222. $this->assertFormattedOutputMatches($expected, 'var_export', $data);
  223. }
  224. function testNestedVarExport()
  225. {
  226. $data = [
  227. 'one' => [
  228. 'i' => ['a', 'b', 'c'],
  229. ],
  230. 'two' => [
  231. 'ii' => ['q', 'r', 's'],
  232. ],
  233. 'three' => [
  234. 'iii' => ['t', 'u', 'v'],
  235. ],
  236. ];
  237. $expected = <<<EOT
  238. array (
  239. 'one' =>
  240. array (
  241. 'i' =>
  242. array (
  243. 0 => 'a',
  244. 1 => 'b',
  245. 2 => 'c',
  246. ),
  247. ),
  248. 'two' =>
  249. array (
  250. 'ii' =>
  251. array (
  252. 0 => 'q',
  253. 1 => 'r',
  254. 2 => 's',
  255. ),
  256. ),
  257. 'three' =>
  258. array (
  259. 'iii' =>
  260. array (
  261. 0 => 't',
  262. 1 => 'u',
  263. 2 => 'v',
  264. ),
  265. ),
  266. )
  267. EOT;
  268. $this->assertFormattedOutputMatches($expected, 'var_export', $data);
  269. }
  270. function testList()
  271. {
  272. $data = [
  273. 'one' => 'a',
  274. 'two' => 'b',
  275. 'three' => 'c',
  276. ];
  277. $expected = <<<EOT
  278. a
  279. b
  280. c
  281. EOT;
  282. $this->assertFormattedOutputMatches($expected, 'list', $data);
  283. }
  284. /**
  285. * @expectedException \Consolidation\OutputFormatters\Exception\UnknownFormatException
  286. * @expectedExceptionCode 1
  287. * @expectedExceptionMessage The requested format, 'no-such-format', is not available.
  288. */
  289. function testBadFormat()
  290. {
  291. $this->assertFormattedOutputMatches('Will fail, not return', 'no-such-format', ['a' => 'b']);
  292. }
  293. /**
  294. * @expectedException \Consolidation\OutputFormatters\Exception\IncompatibleDataException
  295. * @expectedExceptionCode 1
  296. * @expectedExceptionMessage Data provided to Consolidation\OutputFormatters\Formatters\CsvFormatter must be one of an instance of Consolidation\OutputFormatters\StructuredData\RowsOfFields, an instance of Consolidation\OutputFormatters\StructuredData\PropertyList or an array. Instead, a string was provided.
  297. */
  298. function testBadDataTypeForCsv()
  299. {
  300. $this->assertFormattedOutputMatches('Will fail, not return', 'csv', 'String cannot be converted to csv');
  301. }
  302. /**
  303. * @expectedException \Consolidation\OutputFormatters\Exception\IncompatibleDataException
  304. * @expectedExceptionCode 1
  305. * @expectedExceptionMessage Data provided to Consolidation\OutputFormatters\Formatters\JsonFormatter must be an array. Instead, a string was provided.
  306. */
  307. function testBadDataTypeForJson()
  308. {
  309. $this->assertFormattedOutputMatches('Will fail, not return', 'json', 'String cannot be converted to json');
  310. }
  311. function testNoFormatterSelected()
  312. {
  313. $data = 'Hello';
  314. $expected = $data;
  315. $this->assertFormattedOutputMatches($expected, '', $data);
  316. }
  317. function testRenderTableAsString()
  318. {
  319. $data = new RowsOfFields([['f1' => 'A', 'f2' => 'B', 'f3' => 'C'], ['f1' => 'x', 'f2' => 'y', 'f3' => 'z']]);
  320. $expected = "A\tB\tC\nx\ty\tz";
  321. $this->assertFormattedOutputMatches($expected, 'string', $data);
  322. }
  323. function testRenderTableAsStringWithSingleField()
  324. {
  325. $data = new RowsOfFields([['f1' => 'q', 'f2' => 'r', 'f3' => 's'], ['f1' => 'x', 'f2' => 'y', 'f3' => 'z']]);
  326. $expected = "q\nx";
  327. $options = new FormatterOptions([FormatterOptions::DEFAULT_STRING_FIELD => 'f1']);
  328. $this->assertFormattedOutputMatches($expected, 'string', $data, $options);
  329. }
  330. function testRenderTableAsStringWithSingleFieldAndUserSelectedField()
  331. {
  332. $data = new RowsOfFields([['f1' => 'q', 'f2' => 'r', 'f3' => 's'], ['f1' => 'x', 'f2' => 'y', 'f3' => 'z']]);
  333. $expected = "r\ny";
  334. $options = new FormatterOptions([FormatterOptions::DEFAULT_STRING_FIELD => 'f1']);
  335. $this->assertFormattedOutputMatches($expected, 'string', $data, $options, ['fields' => 'f2']);
  336. }
  337. function testSimpleCsv()
  338. {
  339. $data = ['a', 'b', 'c'];
  340. $expected = "a,b,c";
  341. $this->assertFormattedOutputMatches($expected, 'csv', $data);
  342. }
  343. function testLinesOfCsv()
  344. {
  345. $data = [['a', 'b', 'c'], ['x', 'y', 'z']];
  346. $expected = "a,b,c\nx,y,z";
  347. $this->assertFormattedOutputMatches($expected, 'csv', $data);
  348. }
  349. function testCsvWithEscapedValues()
  350. {
  351. $data = ["Red apple", "Yellow lemon"];
  352. $expected = '"Red apple","Yellow lemon"';
  353. $this->assertFormattedOutputMatches($expected, 'csv', $data);
  354. }
  355. function testCsvWithEmbeddedSingleQuote()
  356. {
  357. $data = ["John's book", "Mary's laptop"];
  358. $expected = <<<EOT
  359. "John's book","Mary's laptop"
  360. EOT;
  361. $this->assertFormattedOutputMatches($expected, 'csv', $data);
  362. }
  363. function testCsvWithEmbeddedDoubleQuote()
  364. {
  365. $data = ['The "best" solution'];
  366. $expected = <<<EOT
  367. "The ""best"" solution"
  368. EOT;
  369. $this->assertFormattedOutputMatches($expected, 'csv', $data);
  370. }
  371. function testCsvBothKindsOfQuotes()
  372. {
  373. $data = ["John's \"new\" book", "Mary's \"modified\" laptop"];
  374. $expected = <<<EOT
  375. "John's ""new"" book","Mary's ""modified"" laptop"
  376. EOT;
  377. $this->assertFormattedOutputMatches($expected, 'csv', $data);
  378. }
  379. function testSimpleTsv()
  380. {
  381. $data = ['a', 'b', 'c'];
  382. $expected = "a\tb\tc";
  383. $this->assertFormattedOutputMatches($expected, 'tsv', $data);
  384. }
  385. function testLinesOfTsv()
  386. {
  387. $data = [['a', 'b', 'c'], ['x', 'y', 'z']];
  388. $expected = "a\tb\tc\nx\ty\tz";
  389. $this->assertFormattedOutputMatches($expected, 'tsv', $data);
  390. }
  391. function testTsvBothKindsOfQuotes()
  392. {
  393. $data = ["John's \"new\" book", "Mary's \"modified\" laptop"];
  394. $expected = "John's \"new\" book\tMary's \"modified\" laptop";
  395. $this->assertFormattedOutputMatches($expected, 'tsv', $data);
  396. }
  397. function testTsvWithEscapedValues()
  398. {
  399. $data = ["Red apple", "Yellow lemon", "Embedded\ttab"];
  400. $expected = "Red apple\tYellow lemon\tEmbedded\\ttab";
  401. $this->assertFormattedOutputMatches($expected, 'tsv', $data);
  402. }
  403. protected function missingCellTableExampleData()
  404. {
  405. $data = [
  406. [
  407. 'one' => 'a',
  408. 'two' => 'b',
  409. 'three' => 'c',
  410. ],
  411. [
  412. 'one' => 'x',
  413. 'three' => 'z',
  414. ],
  415. ];
  416. return new RowsOfFields($data);
  417. }
  418. function testTableWithMissingCell()
  419. {
  420. $data = $this->missingCellTableExampleData();
  421. $expected = <<<EOT
  422. ----- ----- -------
  423. One Two Three
  424. ----- ----- -------
  425. a b c
  426. x z
  427. ----- ----- -------
  428. EOT;
  429. $this->assertFormattedOutputMatches($expected, 'table', $data);
  430. $expectedCsv = <<<EOT
  431. One,Two,Three
  432. a,b,c
  433. x,,z
  434. EOT;
  435. $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data);
  436. $expectedTsv = <<<EOT
  437. a\tb\tc
  438. x\t\tz
  439. EOT;
  440. $this->assertFormattedOutputMatches($expectedTsv, 'tsv', $data);
  441. $expectedTsvWithHeaders = <<<EOT
  442. One\tTwo\tThree
  443. a\tb\tc
  444. x\t\tz
  445. EOT;
  446. $this->assertFormattedOutputMatches($expectedTsvWithHeaders, 'tsv', $data, new FormatterOptions(), ['include-field-labels' => true]);
  447. }
  448. function testTableWithWordWrapping()
  449. {
  450. $options = new FormatterOptions();
  451. $data = [
  452. [
  453. 'first' => 'This is a really long cell that contains a lot of data. When it is rendered, it should be wrapped across multiple lines.',
  454. 'second' => 'This is the second column of the same table. It is also very long, and should be wrapped across multiple lines, just like the first column.',
  455. ]
  456. ];
  457. $data = new RowsOfFields($data);
  458. $expected = <<<EOT
  459. ------------------ --------------------
  460. First Second
  461. ------------------ --------------------
  462. This is a really This is the second
  463. long cell that column of the same
  464. contains a lot table. It is also
  465. of data. When it very long, and
  466. is rendered, it should be wrapped
  467. should be across multiple
  468. wrapped across lines, just like
  469. multiple lines. the first column.
  470. ------------------ --------------------
  471. EOT;
  472. $options->setWidth(42);
  473. $this->assertFormattedOutputMatches($expected, 'table', $data, $options);
  474. $expected = <<<EOT
  475. ----------------------------------- ---------------------------------------
  476. First Second
  477. ----------------------------------- ---------------------------------------
  478. This is a really long cell that This is the second column of the same
  479. contains a lot of data. When it table. It is also very long, and
  480. is rendered, it should be wrapped should be wrapped across multiple
  481. across multiple lines. lines, just like the first column.
  482. ----------------------------------- ---------------------------------------
  483. EOT;
  484. $options->setWidth(78);
  485. $this->assertFormattedOutputMatches($expected, 'table', $data, $options);
  486. }
  487. function testTableWithWordWrapping2()
  488. {
  489. $options = new FormatterOptions();
  490. $data = [
  491. [
  492. 'id' => 42,
  493. 'vid' => 321,
  494. 'description' => 'Life, the Universe and Everything.',
  495. ],
  496. [
  497. 'id' => 13,
  498. 'vid' => 789,
  499. 'description' => 'Why is six afraid of seven?',
  500. ],
  501. ];
  502. $data = new RowsOfFields($data);
  503. $expected = <<<EOT
  504. ---- ----- -----------------------------
  505. Id Vid Description
  506. ---- ----- -----------------------------
  507. 42 321 Life, the Universe and
  508. Everything.
  509. 13 789 Why is six afraid of seven?
  510. ---- ----- -----------------------------
  511. EOT;
  512. $options->setWidth(42);
  513. $this->assertFormattedOutputMatches($expected, 'table', $data, $options);
  514. }
  515. function testTableWithWordWrapping3()
  516. {
  517. $options = new FormatterOptions();
  518. $data = [
  519. 'name' => 'Rex',
  520. 'species' => 'dog',
  521. 'food' => 'kibble',
  522. 'legs' => '4',
  523. 'description' => 'Rex is a very good dog, Brett. He likes kibble, and has four legs.',
  524. ];
  525. $data = new PropertyList($data);
  526. $expected = <<<EOT
  527. ------------- -------------------------
  528. Name Rex
  529. Species dog
  530. Food kibble
  531. Legs 4
  532. Description Rex is a very good dog,
  533. Brett. He likes kibble,
  534. and has four legs.
  535. ------------- -------------------------
  536. EOT;
  537. $options->setWidth(42);
  538. $this->assertFormattedOutputMatches($expected, 'table', $data, $options);
  539. }
  540. function testTableWithWordWrapping4()
  541. {
  542. $options = new FormatterOptions();
  543. $data = [
  544. 'name' => ['label' => 'Name', 'sep' => ':', 'value' => 'Rex', ],
  545. 'species' => ['label' => 'Species', 'sep' => ':', 'value' => 'dog', ],
  546. 'food' => ['label' => 'Food', 'sep' => ':', 'value' => 'kibble', ],
  547. 'legs' => ['label' => 'Legs', 'sep' => ':', 'value' => '4', ],
  548. 'description' => ['label' => 'Description', 'sep' => ':', 'value' => 'Rex is a very good dog, Brett. He likes kibble, and has four legs.', ],
  549. ];
  550. $data = new RowsOfFields($data);
  551. $expected = <<<EOT
  552. ------------- ----- -----------------------------------------------------
  553. Label Sep Value
  554. ------------- ----- -----------------------------------------------------
  555. Name : Rex
  556. Species : dog
  557. Food : kibble
  558. Legs : 4
  559. Description : Rex is a very good dog, Brett. He likes kibble, and
  560. has four legs.
  561. ------------- ----- -----------------------------------------------------
  562. EOT;
  563. $options->setWidth(78);
  564. $this->assertFormattedOutputMatches($expected, 'table', $data, $options);
  565. }
  566. function testTableWithWordWrapping5()
  567. {
  568. $options = new FormatterOptions();
  569. $data = [
  570. 'name' => ['Name', ':', 'Rex', ],
  571. 'species' => ['Species', ':', 'dog', ],
  572. 'food' => ['Food', ':', 'kibble', ],
  573. 'legs' => ['Legs', ':', '4', ],
  574. 'description' => ['Description', ':', 'Rex is a very good dog, Brett. He likes kibble, and has four legs.', ],
  575. ];
  576. $data = new RowsOfFields($data);
  577. $expected = <<<EOT
  578. Name : Rex
  579. Species : dog
  580. Food : kibble
  581. Legs : 4
  582. Description : Rex is a very good dog, Brett. He likes kibble, and has
  583. four legs.
  584. EOT;
  585. $options->setWidth(78);
  586. $options->setIncludeFieldLables(false);
  587. $options->setTableStyle('compact');
  588. $this->assertFormattedOutputMatches($expected, 'table', $data, $options);
  589. }
  590. protected function simpleTableExampleData()
  591. {
  592. $data = [
  593. 'id-123' =>
  594. [
  595. 'one' => 'a',
  596. 'two' => 'b',
  597. 'three' => 'c',
  598. ],
  599. 'id-456' =>
  600. [
  601. 'one' => 'x',
  602. 'two' => 'y',
  603. 'three' => 'z',
  604. ],
  605. ];
  606. return new RowsOfFields($data);
  607. }
  608. /**
  609. * @expectedException \Consolidation\OutputFormatters\Exception\InvalidFormatException
  610. * @expectedExceptionCode 1
  611. * @expectedExceptionMessage The format table cannot be used with the data produced by this command, which was an array. Valid formats are: csv,json,list,php,print-r,string,tsv,var_export,xml,yaml
  612. */
  613. function testIncompatibleDataForTableFormatter()
  614. {
  615. $data = $this->simpleTableExampleData()->getArrayCopy();
  616. $this->assertFormattedOutputMatches('Should throw an exception before comparing the table data', 'table', $data);
  617. }
  618. /**
  619. * @expectedException \Consolidation\OutputFormatters\Exception\InvalidFormatException
  620. * @expectedExceptionCode 1
  621. * @expectedExceptionMessage The format sections cannot be used with the data produced by this command, which was an array. Valid formats are: csv,json,list,php,print-r,string,tsv,var_export,xml,yaml
  622. */
  623. function testIncompatibleDataForSectionsFormatter()
  624. {
  625. $data = $this->simpleTableExampleData()->getArrayCopy();
  626. $this->assertFormattedOutputMatches('Should throw an exception before comparing the table data', 'sections', $data);
  627. }
  628. function testSimpleTable()
  629. {
  630. $data = $this->simpleTableExampleData();
  631. $expected = <<<EOT
  632. ----- ----- -------
  633. One Two Three
  634. ----- ----- -------
  635. a b c
  636. x y z
  637. ----- ----- -------
  638. EOT;
  639. $this->assertFormattedOutputMatches($expected, 'table', $data);
  640. $expectedBorderless = <<<EOT
  641. ===== ===== =======
  642. One Two Three
  643. ===== ===== =======
  644. a b c
  645. x y z
  646. ===== ===== =======
  647. EOT;
  648. $this->assertFormattedOutputMatches($expectedBorderless, 'table', $data, new FormatterOptions(['table-style' => 'borderless']));
  649. $expectedJson = <<<EOT
  650. {
  651. "id-123": {
  652. "one": "a",
  653. "two": "b",
  654. "three": "c"
  655. },
  656. "id-456": {
  657. "one": "x",
  658. "two": "y",
  659. "three": "z"
  660. }
  661. }
  662. EOT;
  663. $this->assertFormattedOutputMatches($expectedJson, 'json', $data);
  664. $expectedCsv = <<<EOT
  665. One,Two,Three
  666. a,b,c
  667. x,y,z
  668. EOT;
  669. $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data);
  670. $expectedList = <<<EOT
  671. id-123
  672. id-456
  673. EOT;
  674. $this->assertFormattedOutputMatches($expectedList, 'list', $data);
  675. }
  676. protected function tableWithAlternativesExampleData()
  677. {
  678. $data = [
  679. 'id-123' =>
  680. [
  681. 'one' => 'a',
  682. 'two' => ['this', 'that', 'the other thing'],
  683. 'three' => 'c',
  684. ],
  685. 'id-456' =>
  686. [
  687. 'one' => 'x',
  688. 'two' => 'y',
  689. 'three' => ['apples', 'oranges'],
  690. ],
  691. ];
  692. return new RowsOfFieldsWithAlternatives($data);
  693. }
  694. function testTableWithAlternatives()
  695. {
  696. $data = $this->tableWithAlternativesExampleData();
  697. $expected = <<<EOT
  698. ----- --------------------------- ----------------
  699. One Two Three
  700. ----- --------------------------- ----------------
  701. a this|that|the other thing c
  702. x y apples|oranges
  703. ----- --------------------------- ----------------
  704. EOT;
  705. $this->assertFormattedOutputMatches($expected, 'table', $data);
  706. $expectedBorderless = <<<EOT
  707. ===== =========================== ================
  708. One Two Three
  709. ===== =========================== ================
  710. a this|that|the other thing c
  711. x y apples|oranges
  712. ===== =========================== ================
  713. EOT;
  714. $this->assertFormattedOutputMatches($expectedBorderless, 'table', $data, new FormatterOptions(['table-style' => 'borderless']));
  715. $expectedJson = <<<EOT
  716. {
  717. "id-123": {
  718. "one": "a",
  719. "two": [
  720. "this",
  721. "that",
  722. "the other thing"
  723. ],
  724. "three": "c"
  725. },
  726. "id-456": {
  727. "one": "x",
  728. "two": "y",
  729. "three": [
  730. "apples",
  731. "oranges"
  732. ]
  733. }
  734. }
  735. EOT;
  736. $this->assertFormattedOutputMatches($expectedJson, 'json', $data);
  737. $expectedCsv = <<<EOT
  738. One,Two,Three
  739. a,"this|that|the other thing",c
  740. x,y,apples|oranges
  741. EOT;
  742. $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data);
  743. $expectedList = <<<EOT
  744. id-123
  745. id-456
  746. EOT;
  747. $this->assertFormattedOutputMatches($expectedList, 'list', $data);
  748. }
  749. function testSimpleTableWithFieldLabels()
  750. {
  751. $data = $this->simpleTableExampleData();
  752. $configurationData = new FormatterOptions(
  753. [
  754. 'field-labels' => ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'],
  755. 'row-labels' => ['id-123' => 'Walrus', 'id-456' => 'Carpenter'],
  756. ]
  757. );
  758. $configurationDataAnnotationFormat = new FormatterOptions(
  759. [
  760. 'field-labels' => "one: Uno\ntwo: Dos\nthree: Tres",
  761. ]
  762. );
  763. $expected = <<<EOT
  764. ------ ---- -----
  765. Ichi Ni San
  766. ------ ---- -----
  767. a b c
  768. x y z
  769. ------ ---- -----
  770. EOT;
  771. $this->assertFormattedOutputMatches($expected, 'table', $data, $configurationData);
  772. $expectedSidewaysTable = <<<EOT
  773. ------ --- ---
  774. Ichi a x
  775. Ni b y
  776. San c z
  777. ------ --- ---
  778. EOT;
  779. $this->assertFormattedOutputMatches($expectedSidewaysTable, 'table', $data, $configurationData->override(['list-orientation' => true]));
  780. $expectedAnnotationFormatConfigData = <<<EOT
  781. ----- ----- ------
  782. Uno Dos Tres
  783. ----- ----- ------
  784. a b c
  785. x y z
  786. ----- ----- ------
  787. EOT;
  788. $this->assertFormattedOutputMatches($expectedAnnotationFormatConfigData, 'table', $data, $configurationDataAnnotationFormat);
  789. $expectedWithNoFields = <<<EOT
  790. --- --- ---
  791. a b c
  792. x y z
  793. --- --- ---
  794. EOT;
  795. $this->assertFormattedOutputMatches($expectedWithNoFields, 'table', $data, $configurationData, ['include-field-labels' => false]);
  796. $expectedWithReorderedFields = <<<EOT
  797. ----- ------
  798. San Ichi
  799. ----- ------
  800. c a
  801. z x
  802. ----- ------
  803. EOT;
  804. $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['three', 'one']]);
  805. $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['San', 'Ichi']]);
  806. $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => 'San,Ichi']);
  807. $expectedWithRegexField = <<<EOT
  808. ------ -----
  809. Ichi San
  810. ------ -----
  811. a c
  812. x z
  813. ------ -----
  814. EOT;
  815. $this->assertFormattedOutputMatches($expectedWithRegexField, 'table', $data, $configurationData, ['fields' => ['/e$/']]);
  816. $this->assertFormattedOutputMatches($expectedWithRegexField, 'table', $data, $configurationData, ['fields' => ['*e']]);
  817. $this->assertFormattedOutputMatches($expectedWithRegexField, 'table', $data, $configurationData, ['default-fields' => ['*e']]);
  818. $expectedSections = <<<EOT
  819. Walrus
  820. One a
  821. Two b
  822. Three c
  823. Carpenter
  824. One x
  825. Two y
  826. Three z
  827. EOT;
  828. $this->assertFormattedOutputMatches($expectedSections, 'sections', $data, $configurationData);
  829. $expectedJson = <<<EOT
  830. {
  831. "id-123": {
  832. "three": "c",
  833. "one": "a"
  834. },
  835. "id-456": {
  836. "three": "z",
  837. "one": "x"
  838. }
  839. }
  840. EOT;
  841. $this->assertFormattedOutputMatches($expectedJson, 'json', $data, $configurationData, ['fields' => ['San', 'Ichi']]);
  842. $expectedSingleField = <<<EOT
  843. -----
  844. San
  845. -----
  846. c
  847. z
  848. -----
  849. EOT;
  850. $this->assertFormattedOutputMatches($expectedSingleField, 'table', $data, $configurationData, ['field' => 'San']);
  851. $expectedEmptyColumn = <<<EOT
  852. -----
  853. San
  854. -----
  855. EOT;
  856. $this->assertFormattedOutputMatches($expectedEmptyColumn, 'table', new RowsOfFields([]), $configurationData, ['field' => 'San']);
  857. $this->assertFormattedOutputMatches('', '', new RowsOfFields([]), $configurationData, ['field' => 'San']);
  858. $this->assertFormattedOutputMatches('[]', 'json', new RowsOfFields([]), $configurationData, ['field' => 'San']);
  859. }
  860. /**
  861. * @expectedException \Consolidation\OutputFormatters\Exception\UnknownFieldException
  862. * @expectedExceptionCode 1
  863. * @expectedExceptionMessage The requested field, 'Shi', is not defined.
  864. */
  865. function testNoSuchFieldException()
  866. {
  867. $configurationData = new FormatterOptions(
  868. [
  869. 'field-labels' => ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'],
  870. 'row-labels' => ['id-123' => 'Walrus', 'id-456' => 'Carpenter'],
  871. ]
  872. );
  873. $data = $this->simpleTableExampleData();
  874. $this->assertFormattedOutputMatches('Will throw before comparing', 'table', $data, $configurationData, ['field' => 'Shi']);
  875. }
  876. protected function simpleListExampleData()
  877. {
  878. $data = [
  879. 'one' => 'apple',
  880. 'two' => 'banana',
  881. 'three' => 'carrot',
  882. ];
  883. return new PropertyList($data);
  884. }
  885. // Test with the deprecated data structure
  886. protected function simpleListExampleDataUsingAssociativeList()
  887. {
  888. $data = [
  889. 'one' => 'apple',
  890. 'two' => 'banana',
  891. 'three' => 'carrot',
  892. ];
  893. return new AssociativeList($data);
  894. }
  895. /**
  896. * @expectedException \Consolidation\OutputFormatters\Exception\InvalidFormatException
  897. * @expectedExceptionCode 1
  898. * @expectedExceptionMessage The format table cannot be used with the data produced by this command, which was an array. Valid formats are: csv,json,list,php,print-r,string,tsv,var_export,xml,yaml
  899. */
  900. function testIncompatibleListDataForTableFormatter()
  901. {
  902. $data = $this->simpleListExampleData();
  903. $this->assertFormattedOutputMatches('Should throw an exception before comparing the table data', 'table', $data->getArrayCopy());
  904. }
  905. function testEmptyList()
  906. {
  907. $data = new RowsOfFields([]);
  908. $expected = <<<EOT
  909. --- ---- -----
  910. I II III
  911. --- ---- -----
  912. EOT;
  913. // If we provide field labels, then the output will change to reflect that.
  914. $formatterOptionsWithFieldLables = new FormatterOptions();
  915. $formatterOptionsWithFieldLables
  916. ->setFieldLabels(['one' => 'I', 'two' => 'II', 'three' => 'III']);
  917. $this->assertFormattedOutputMatches($expected, 'table', $data, $formatterOptionsWithFieldLables);
  918. }
  919. function testSimpleList()
  920. {
  921. $expected = <<<EOT
  922. ------- --------
  923. One apple
  924. Two banana
  925. Three carrot
  926. ------- --------
  927. EOT;
  928. $data = $this->simpleListExampleDataUsingAssociativeList();
  929. $this->assertFormattedOutputMatches($expected, 'table', $data);
  930. $data = $this->simpleListExampleData();
  931. $this->assertFormattedOutputMatches($expected, 'table', $data);
  932. $expected = <<<EOT
  933. ----- --------
  934. I apple
  935. II banana
  936. III carrot
  937. ----- --------
  938. EOT;
  939. // If we provide field labels, then the output will change to reflect that.
  940. $formatterOptionsWithFieldLables = new FormatterOptions();
  941. $formatterOptionsWithFieldLables
  942. ->setFieldLabels(['one' => 'I', 'two' => 'II', 'three' => 'III']);
  943. $this->assertFormattedOutputMatches($expected, 'table', $data, $formatterOptionsWithFieldLables);
  944. $expectedDrushStyleTable = <<<EOT
  945. One : apple
  946. Two : banana
  947. Three : carrot
  948. EOT;
  949. // If we provide field labels, then the output will change to reflect that.
  950. $formatterOptionsWithFieldLables = new FormatterOptions();
  951. $formatterOptionsWithFieldLables
  952. ->setTableStyle('compact')
  953. ->setListDelimiter(':');
  954. $this->assertFormattedOutputMatches($expectedDrushStyleTable, 'table', $data, $formatterOptionsWithFieldLables);
  955. // Adding an extra field that does not exist in the data set should not change the output
  956. $formatterOptionsWithExtraFieldLables = new FormatterOptions();
  957. $formatterOptionsWithExtraFieldLables
  958. ->setFieldLabels(['one' => 'I', 'two' => 'II', 'three' => 'III', 'four' => 'IV']);
  959. $this->assertFormattedOutputMatches($expected, 'table', $data, $formatterOptionsWithExtraFieldLables);
  960. $expectedRotated = <<<EOT
  961. ------- -------- --------
  962. One Two Three
  963. ------- -------- --------
  964. apple banana carrot
  965. ------- -------- --------
  966. EOT;
  967. $this->assertFormattedOutputMatches($expectedRotated, 'table', $data, new FormatterOptions(['list-orientation' => false]));
  968. $expectedList = <<< EOT
  969. apple
  970. banana
  971. carrot
  972. EOT;
  973. $this->assertFormattedOutputMatches($expectedList, 'list', $data);
  974. $expectedReorderedList = <<< EOT
  975. carrot
  976. apple
  977. EOT;
  978. $options = new FormatterOptions([FormatterOptions::FIELDS => 'three,one']);
  979. $this->assertFormattedOutputMatches($expectedReorderedList, 'list', $data, $options);
  980. $expectedCsv = <<< EOT
  981. One,Two,Three
  982. apple,banana,carrot
  983. EOT;
  984. $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data);
  985. $expectedCsvNoHeaders = 'apple,banana,carrot';
  986. $this->assertFormattedOutputMatches($expectedCsvNoHeaders, 'csv', $data, new FormatterOptions(), ['include-field-labels' => false]);
  987. // Next, configure the formatter options with 'include-field-labels',
  988. // but set --include-field-labels to turn the option back on again.
  989. $options = new FormatterOptions(['include-field-labels' => false]);
  990. $input = new StringInput('test --include-field-labels');
  991. $optionDefinitions = [
  992. new InputArgument('unused', InputArgument::REQUIRED),
  993. new InputOption('include-field-labels', null, InputOption::VALUE_NONE),
  994. ];
  995. $definition = new InputDefinition($optionDefinitions);
  996. $input->bind($definition);
  997. $testValue = $input->getOption('include-field-labels');
  998. $this->assertTrue($testValue);
  999. $hasFieldLabels = $input->hasOption('include-field-labels');
  1000. $this->assertTrue($hasFieldLabels);
  1001. $this->assertFormattedOutputMatches($expectedCsvNoHeaders, 'csv', $data, $options);
  1002. $options->setInput($input);
  1003. $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data, $options);
  1004. }
  1005. protected function associativeListWithRenderer()
  1006. {
  1007. $data = [
  1008. 'one' => 'apple',
  1009. 'two' => ['banana', 'plantain'],
  1010. 'three' => 'carrot',
  1011. 'four' => ['peaches', 'pumpkin pie'],
  1012. ];
  1013. $list = new PropertyList($data);
  1014. $list->addRendererFunction(
  1015. function ($key, $cellData, FormatterOptions $options)
  1016. {
  1017. if (is_array($cellData)) {
  1018. return implode(',', $cellData);
  1019. }
  1020. return $cellData;
  1021. }
  1022. );
  1023. return $list;
  1024. }
  1025. protected function associativeListWithCsvCells()
  1026. {
  1027. $data = [
  1028. 'one' => 'apple',
  1029. 'two' => ['banana', 'plantain'],
  1030. 'three' => 'carrot',
  1031. 'four' => ['peaches', 'pumpkin pie'],
  1032. ];
  1033. return new PropertyListWithCsvCells($data);
  1034. }
  1035. function testPropertyListWithCsvCells()
  1036. {
  1037. $this->doPropertyListWithCsvCells($this->associativeListWithRenderer());
  1038. $this->doPropertyListWithCsvCells($this->associativeListWithCsvCells());
  1039. }
  1040. function doPropertyListWithCsvCells($data)
  1041. {
  1042. $expected = <<<EOT
  1043. ------- ---------------------
  1044. One apple
  1045. Two banana,plantain
  1046. Three carrot
  1047. Four peaches,pumpkin pie
  1048. ------- ---------------------
  1049. EOT;
  1050. $this->assertFormattedOutputMatches($expected, 'table', $data);
  1051. $expectedList = <<< EOT
  1052. apple
  1053. banana,plantain
  1054. carrot
  1055. peaches,pumpkin pie
  1056. EOT;
  1057. $this->assertFormattedOutputMatches($expectedList, 'list', $data);
  1058. $expectedCsv = <<< EOT
  1059. One,Two,Three,Four
  1060. apple,"banana,plantain",carrot,"peaches,pumpkin pie"
  1061. EOT;
  1062. $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data);
  1063. $expectedCsvNoHeaders = 'apple,"banana,plantain",carrot,"peaches,pumpkin pie"';
  1064. $this->assertFormattedOutputMatches($expectedCsvNoHeaders, 'csv', $data, new FormatterOptions(), ['include-field-labels' => false]);
  1065. $expectedTsv = <<< EOT
  1066. apple\tbanana,plantain\tcarrot\tpeaches,pumpkin pie
  1067. EOT;
  1068. $this->assertFormattedOutputMatches($expectedTsv, 'tsv', $data);
  1069. }
  1070. function testSimpleListWithFieldLabels()
  1071. {
  1072. $data = $this->simpleListExampleData();
  1073. $configurationData = new FormatterOptions(
  1074. [
  1075. 'field-labels' => ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'],
  1076. ]
  1077. );
  1078. $expected = <<<EOT
  1079. ------ --------
  1080. Ichi apple
  1081. Ni banana
  1082. San carrot
  1083. ------ --------
  1084. EOT;
  1085. $this->assertFormattedOutputMatches($expected, 'table', $data, $configurationData);
  1086. $expectedWithReorderedFields = <<<EOT
  1087. ------ --------
  1088. San carrot
  1089. Ichi apple
  1090. ------ --------
  1091. EOT;
  1092. $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['three', 'one']]);
  1093. $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['San', 'Ichi']]);
  1094. $expectedJson = <<<EOT
  1095. {
  1096. "three": "carrot",
  1097. "one": "apple"
  1098. }
  1099. EOT;
  1100. $this->assertFormattedOutputMatches($expectedJson, 'json', $data, $configurationData, ['fields' => ['San', 'Ichi']]);
  1101. }
  1102. function testSimpleXml()
  1103. {
  1104. $data = [
  1105. 'name' => 'primary',
  1106. 'description' => 'The primary colors of the color wheel.',
  1107. 'colors' =>
  1108. [
  1109. 'red',
  1110. 'yellow',
  1111. 'blue',
  1112. ],
  1113. ];
  1114. $expected = <<<EOT
  1115. <?xml version="1.0" encoding="UTF-8"?>
  1116. <document name="primary">
  1117. <description>The primary colors of the color wheel.</description>
  1118. <colors>
  1119. <color>red</color>
  1120. <color>yellow</color>
  1121. <color>blue</color>
  1122. </colors>
  1123. </document>
  1124. EOT;
  1125. $this->assertFormattedOutputMatches($expected, 'xml', $data);
  1126. }
  1127. function domDocumentData()
  1128. {
  1129. $dom = new \DOMDocument('1.0', 'UTF-8');
  1130. $document = $dom->createElement('document');
  1131. $dom->appendChild($document);
  1132. $document->setAttribute('name', 'primary');
  1133. $description = $dom->createElement('description');
  1134. $document->appendChild($description);
  1135. $description->appendChild($dom->createTextNode('The primary colors of the color wheel.'));
  1136. $this->domCreateElements($dom, $document, 'color', ['red', 'yellow', 'blue']);
  1137. return $dom;
  1138. }
  1139. function domCreateElements($dom, $element, $name, $data)
  1140. {
  1141. $container = $dom->createElement("{$name}s");
  1142. $element->appendChild($container);
  1143. foreach ($data as $value) {
  1144. $child = $dom->createElement($name);
  1145. $container->appendChild($child);
  1146. $child->appendChild($dom->createTextNode($value));
  1147. }
  1148. }
  1149. function complexDomDocumentData()
  1150. {
  1151. $dom = new \DOMDocument('1.0', 'UTF-8');
  1152. $document = $dom->createElement('document');
  1153. $dom->appendChild($document);
  1154. $document->setAttribute('name', 'widget-collection');
  1155. $description = $dom->createElement('description');
  1156. $document->appendChild($description);
  1157. $description->appendChild($dom->createTextNode('A couple of widgets.'));
  1158. $widgets = $dom->createElement('widgets');
  1159. $document->appendChild($widgets);
  1160. $widget = $dom->createElement('widget');
  1161. $widgets->appendChild($widget);
  1162. $widget->setAttribute('name', 'usual');
  1163. $this->domCreateElements($dom, $widget, 'color', ['red', 'yellow', 'blue']);
  1164. $this->domCreateElements($dom, $widget, 'shape', ['square', 'circle', 'triangle']);
  1165. $widget = $dom->createElement('widget');
  1166. $widgets->appendChild($widget);
  1167. $widget->setAttribute('name', 'unusual');
  1168. $this->domCreateElements($dom, $widget, 'color', ['muave', 'puce', 'umber']);
  1169. $this->domCreateElements($dom, $widget, 'shape', ['elipse', 'rhombus', 'trapazoid']);
  1170. return $dom;
  1171. }
  1172. function domDocumentTestValues()
  1173. {
  1174. $expectedXml = <<<EOT
  1175. <?xml version="1.0" encoding="UTF-8"?>
  1176. <document name="primary">
  1177. <description>The primary colors of the color wheel.</description>
  1178. <colors>
  1179. <color>red</color>
  1180. <color>yellow</color>
  1181. <color>blue</color>
  1182. </colors>
  1183. </document>
  1184. EOT;
  1185. $expectedJson = <<<EOT
  1186. {
  1187. "name": "primary",
  1188. "description": "The primary colors of the color wheel.",
  1189. "colors": [
  1190. "red",
  1191. "yellow",
  1192. "blue"
  1193. ]
  1194. }
  1195. EOT;
  1196. $expectedComplexXml = <<<EOT
  1197. <?xml version="1.0" encoding="UTF-8"?>
  1198. <document name="widget-collection">
  1199. <description>A couple of widgets.</description>
  1200. <widgets>
  1201. <widget name="usual">
  1202. <colors>
  1203. <color>red</color>
  1204. <color>yellow</color>
  1205. <color>blue</color>
  1206. </colors>
  1207. <shapes>
  1208. <shape>square</shape>
  1209. <shape>circle</shape>
  1210. <shape>triangle</shape>
  1211. </shapes>
  1212. </widget>
  1213. <widget name="unusual">
  1214. <colors>
  1215. <color>muave</color>
  1216. <color>puce</color>
  1217. <color>umber</color>
  1218. </colors>
  1219. <shapes>
  1220. <shape>elipse</shape>
  1221. <shape>rhombus</shape>
  1222. <shape>trapazoid</shape>
  1223. </shapes>
  1224. </widget>
  1225. </widgets>
  1226. </document>
  1227. EOT;
  1228. $expectedComplexJson = <<<EOT
  1229. {
  1230. "name": "widget-collection",
  1231. "description": "A couple of widgets.",
  1232. "widgets": {
  1233. "usual": {
  1234. "name": "usual",
  1235. "colors": [
  1236. "red",
  1237. "yellow",
  1238. "blue"
  1239. ],
  1240. "shapes": [
  1241. "square",
  1242. "circle",
  1243. "triangle"
  1244. ]
  1245. },
  1246. "unusual": {
  1247. "name": "unusual",
  1248. "colors": [
  1249. "muave",
  1250. "puce",
  1251. "umber"
  1252. ],
  1253. "shapes": [
  1254. "elipse",
  1255. "rhombus",
  1256. "trapazoid"
  1257. ]
  1258. }
  1259. }
  1260. }
  1261. EOT;
  1262. return [
  1263. [
  1264. $this->domDocumentData(),
  1265. $expectedXml,
  1266. $expectedJson,
  1267. ],
  1268. [
  1269. $this->complexDomDocumentData(),
  1270. $expectedComplexXml,
  1271. $expectedComplexJson,
  1272. ],
  1273. ];
  1274. }
  1275. /**
  1276. * @dataProvider domDocumentTestValues
  1277. */
  1278. function testDomData($data, $expectedXml, $expectedJson)
  1279. {
  1280. $this->assertFormattedOutputMatches($expectedXml, 'xml', $data);
  1281. $this->assertFormattedOutputMatches($expectedJson, 'json', $data);
  1282. // Check to see if we get the same xml data if we convert from
  1283. // DOM -> array -> DOM.
  1284. $expectedJsonAsArray = (array)json_decode($expectedJson);
  1285. $this->assertFormattedOutputMatches($expectedXml, 'xml', $expectedJsonAsArray);
  1286. }
  1287. /**
  1288. * @expectedException \Exception
  1289. * @expectedExceptionCode 1
  1290. * @expectedExceptionMessage Data provided to Consolidation\OutputFormatters\Formatters\XmlFormatter must be either an instance of DOMDocument or an array. Instead, a string was provided.
  1291. */
  1292. function testDataTypeForXmlFormatter()
  1293. {
  1294. $this->assertFormattedOutputMatches('Will fail, not return', 'xml', 'Strings cannot be converted to XML');
  1295. }
  1296. }