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