drupal-civicrm/vendor/consolidation/output-formatters/tests/testFormatters.php
2018-01-14 13:10:16 +00:00

1553 lines
45 KiB
PHP

<?php
namespace Consolidation\OutputFormatters;
use Consolidation\TestUtils\PropertyListWithCsvCells;
use Consolidation\TestUtils\RowsOfFieldsWithAlternatives;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\AssociativeList;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Consolidation\OutputFormatters\StructuredData\PropertyList;
use Consolidation\OutputFormatters\StructuredData\ListDataFromKeys;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
class FormattersTests extends \PHPUnit_Framework_TestCase
{
protected $formatterManager;
function setup() {
$this->formatterManager = new FormatterManager();
}
function assertFormattedOutputMatches($expected, $format, $data, FormatterOptions $options = null, $userOptions = []) {
if (!$options) {
$options = new FormatterOptions();
}
$options->setOptions($userOptions);
$output = new BufferedOutput();
$this->formatterManager->write($output, $format, $data, $options);
$actual = preg_replace('#[ \t]*$#sm', '', $output->fetch());
$this->assertEquals(rtrim($expected), rtrim($actual));
}
function testSimpleYaml()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = <<<EOT
one: a
two: b
three: c
EOT;
$this->assertFormattedOutputMatches($expected, 'yaml', $data);
$expected = <<<EOT
a
b
c
EOT;
$this->assertFormattedOutputMatches($expected, 'list', $data);
$data = new ListDataFromKeys($data);
$expected = <<<EOT
one: a
two: b
three: c
EOT;
$this->assertFormattedOutputMatches($expected, 'yaml', $data);
$expected = <<<EOT
one
two
three
EOT;
$this->assertFormattedOutputMatches($expected, 'list', $data);
}
function testNestedYaml()
{
$data = [
'one' => [
'i' => ['a', 'b', 'c'],
],
'two' => [
'ii' => ['q', 'r', 's'],
],
'three' => [
'iii' => ['t', 'u', 'v'],
],
];
$expected = <<<EOT
one:
i:
- a
- b
- c
two:
ii:
- q
- r
- s
three:
iii:
- t
- u
- v
EOT;
$this->assertFormattedOutputMatches($expected, 'yaml', $data);
}
function testSimpleJson()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = <<<EOT
{
"one": "a",
"two": "b",
"three": "c"
}
EOT;
$this->assertFormattedOutputMatches($expected, 'json', $data);
}
function testSerializeFormat()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = 'a:3:{s:3:"one";s:1:"a";s:3:"two";s:1:"b";s:5:"three";s:1:"c";}';
$this->assertFormattedOutputMatches($expected, 'php', $data);
}
function testNestedJson()
{
$data = [
'one' => [
'i' => ['a', 'b', 'c'],
],
'two' => [
'ii' => ['q', 'r', 's'],
],
'three' => [
'iii' => ['t', 'u', 'v'],
],
];
$expected = <<<EOT
{
"one": {
"i": [
"a",
"b",
"c"
]
},
"two": {
"ii": [
"q",
"r",
"s"
]
},
"three": {
"iii": [
"t",
"u",
"v"
]
}
}
EOT;
$this->assertFormattedOutputMatches($expected, 'json', $data);
}
function testSimplePrintR()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = <<<EOT
Array
(
[one] => a
[two] => b
[three] => c
)
EOT;
$this->assertFormattedOutputMatches($expected, 'print-r', $data);
}
function testNestedPrintR()
{
$data = [
'one' => [
'i' => ['a', 'b', 'c'],
],
'two' => [
'ii' => ['q', 'r', 's'],
],
'three' => [
'iii' => ['t', 'u', 'v'],
],
];
$expected = <<<EOT
Array
(
[one] => Array
(
[i] => Array
(
[0] => a
[1] => b
[2] => c
)
)
[two] => Array
(
[ii] => Array
(
[0] => q
[1] => r
[2] => s
)
)
[three] => Array
(
[iii] => Array
(
[0] => t
[1] => u
[2] => v
)
)
)
EOT;
$this->assertFormattedOutputMatches($expected, 'print-r', $data);
}
function testSimpleVarExport()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = <<<EOT
array (
'one' => 'a',
'two' => 'b',
'three' => 'c',
)
EOT;
$this->assertFormattedOutputMatches($expected, 'var_export', $data);
}
function testNestedVarExport()
{
$data = [
'one' => [
'i' => ['a', 'b', 'c'],
],
'two' => [
'ii' => ['q', 'r', 's'],
],
'three' => [
'iii' => ['t', 'u', 'v'],
],
];
$expected = <<<EOT
array (
'one' =>
array (
'i' =>
array (
0 => 'a',
1 => 'b',
2 => 'c',
),
),
'two' =>
array (
'ii' =>
array (
0 => 'q',
1 => 'r',
2 => 's',
),
),
'three' =>
array (
'iii' =>
array (
0 => 't',
1 => 'u',
2 => 'v',
),
),
)
EOT;
$this->assertFormattedOutputMatches($expected, 'var_export', $data);
}
function testList()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = <<<EOT
a
b
c
EOT;
$this->assertFormattedOutputMatches($expected, 'list', $data);
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\UnknownFormatException
* @expectedExceptionCode 1
* @expectedExceptionMessage The requested format, 'no-such-format', is not available.
*/
function testBadFormat()
{
$this->assertFormattedOutputMatches('Will fail, not return', 'no-such-format', ['a' => 'b']);
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\IncompatibleDataException
* @expectedExceptionCode 1
* @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.
*/
function testBadDataTypeForCsv()
{
$this->assertFormattedOutputMatches('Will fail, not return', 'csv', 'String cannot be converted to csv');
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\IncompatibleDataException
* @expectedExceptionCode 1
* @expectedExceptionMessage Data provided to Consolidation\OutputFormatters\Formatters\JsonFormatter must be an array. Instead, a string was provided.
*/
function testBadDataTypeForJson()
{
$this->assertFormattedOutputMatches('Will fail, not return', 'json', 'String cannot be converted to json');
}
function testNoFormatterSelected()
{
$data = 'Hello';
$expected = $data;
$this->assertFormattedOutputMatches($expected, '', $data);
}
function testRenderTableAsString()
{
$data = new RowsOfFields([['f1' => 'A', 'f2' => 'B', 'f3' => 'C'], ['f1' => 'x', 'f2' => 'y', 'f3' => 'z']]);
$expected = "A\tB\tC\nx\ty\tz";
$this->assertFormattedOutputMatches($expected, 'string', $data);
}
function testRenderTableAsStringWithSingleField()
{
$data = new RowsOfFields([['f1' => 'q', 'f2' => 'r', 'f3' => 's'], ['f1' => 'x', 'f2' => 'y', 'f3' => 'z']]);
$expected = "q\nx";
$options = new FormatterOptions([FormatterOptions::DEFAULT_STRING_FIELD => 'f1']);
$this->assertFormattedOutputMatches($expected, 'string', $data, $options);
}
function testRenderTableAsStringWithSingleFieldAndUserSelectedField()
{
$data = new RowsOfFields([['f1' => 'q', 'f2' => 'r', 'f3' => 's'], ['f1' => 'x', 'f2' => 'y', 'f3' => 'z']]);
$expected = "r\ny";
$options = new FormatterOptions([FormatterOptions::DEFAULT_STRING_FIELD => 'f1']);
$this->assertFormattedOutputMatches($expected, 'string', $data, $options, ['fields' => 'f2']);
}
function testSimpleCsv()
{
$data = ['a', 'b', 'c'];
$expected = "a,b,c";
$this->assertFormattedOutputMatches($expected, 'csv', $data);
}
function testLinesOfCsv()
{
$data = [['a', 'b', 'c'], ['x', 'y', 'z']];
$expected = "a,b,c\nx,y,z";
$this->assertFormattedOutputMatches($expected, 'csv', $data);
}
function testCsvWithEscapedValues()
{
$data = ["Red apple", "Yellow lemon"];
$expected = '"Red apple","Yellow lemon"';
$this->assertFormattedOutputMatches($expected, 'csv', $data);
}
function testCsvWithEmbeddedSingleQuote()
{
$data = ["John's book", "Mary's laptop"];
$expected = <<<EOT
"John's book","Mary's laptop"
EOT;
$this->assertFormattedOutputMatches($expected, 'csv', $data);
}
function testCsvWithEmbeddedDoubleQuote()
{
$data = ['The "best" solution'];
$expected = <<<EOT
"The ""best"" solution"
EOT;
$this->assertFormattedOutputMatches($expected, 'csv', $data);
}
function testCsvBothKindsOfQuotes()
{
$data = ["John's \"new\" book", "Mary's \"modified\" laptop"];
$expected = <<<EOT
"John's ""new"" book","Mary's ""modified"" laptop"
EOT;
$this->assertFormattedOutputMatches($expected, 'csv', $data);
}
function testSimpleTsv()
{
$data = ['a', 'b', 'c'];
$expected = "a\tb\tc";
$this->assertFormattedOutputMatches($expected, 'tsv', $data);
}
function testLinesOfTsv()
{
$data = [['a', 'b', 'c'], ['x', 'y', 'z']];
$expected = "a\tb\tc\nx\ty\tz";
$this->assertFormattedOutputMatches($expected, 'tsv', $data);
}
function testTsvBothKindsOfQuotes()
{
$data = ["John's \"new\" book", "Mary's \"modified\" laptop"];
$expected = "John's \"new\" book\tMary's \"modified\" laptop";
$this->assertFormattedOutputMatches($expected, 'tsv', $data);
}
function testTsvWithEscapedValues()
{
$data = ["Red apple", "Yellow lemon", "Embedded\ttab"];
$expected = "Red apple\tYellow lemon\tEmbedded\\ttab";
$this->assertFormattedOutputMatches($expected, 'tsv', $data);
}
protected function missingCellTableExampleData()
{
$data = [
[
'one' => 'a',
'two' => 'b',
'three' => 'c',
],
[
'one' => 'x',
'three' => 'z',
],
];
return new RowsOfFields($data);
}
function testTableWithMissingCell()
{
$data = $this->missingCellTableExampleData();
$expected = <<<EOT
----- ----- -------
One Two Three
----- ----- -------
a b c
x z
----- ----- -------
EOT;
$this->assertFormattedOutputMatches($expected, 'table', $data);
$expectedCsv = <<<EOT
One,Two,Three
a,b,c
x,,z
EOT;
$this->assertFormattedOutputMatches($expectedCsv, 'csv', $data);
$expectedTsv = <<<EOT
a\tb\tc
x\t\tz
EOT;
$this->assertFormattedOutputMatches($expectedTsv, 'tsv', $data);
$expectedTsvWithHeaders = <<<EOT
One\tTwo\tThree
a\tb\tc
x\t\tz
EOT;
$this->assertFormattedOutputMatches($expectedTsvWithHeaders, 'tsv', $data, new FormatterOptions(), ['include-field-labels' => true]);
}
function testTableWithWordWrapping()
{
$options = new FormatterOptions();
$data = [
[
'first' => 'This is a really long cell that contains a lot of data. When it is rendered, it should be wrapped across multiple lines.',
'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.',
]
];
$data = new RowsOfFields($data);
$expected = <<<EOT
------------------ --------------------
First Second
------------------ --------------------
This is a really This is the second
long cell that column of the same
contains a lot table. It is also
of data. When it very long, and
is rendered, it should be wrapped
should be across multiple
wrapped across lines, just like
multiple lines. the first column.
------------------ --------------------
EOT;
$options->setWidth(42);
$this->assertFormattedOutputMatches($expected, 'table', $data, $options);
$expected = <<<EOT
----------------------------------- ---------------------------------------
First Second
----------------------------------- ---------------------------------------
This is a really long cell that This is the second column of the same
contains a lot of data. When it table. It is also very long, and
is rendered, it should be wrapped should be wrapped across multiple
across multiple lines. lines, just like the first column.
----------------------------------- ---------------------------------------
EOT;
$options->setWidth(78);
$this->assertFormattedOutputMatches($expected, 'table', $data, $options);
}
function testWrappingLotsOfColumns()
{
$options = new FormatterOptions();
$data = [
[
'id' => '4d87b545-b4c3-4ece-9908-20c5c5e67e81',
'name' => '123456781234567812345678123456781234567812345678',
'service_level' => 'business',
'framework' => 'wordpress-network',
'owner' => '8558a08d-8059-45f6-9c4b-908299a025ee',
'created' => '2017-05-24 19:28:45',
'memberships' => 'b3a42ba5-755d-42ca-9109-21bde32809d0: Team,9bfaaf50-ece3-4460-acb8-dc1b8dd536e8: pantheon-engineering-canary-sites',
'frozen' => 'false',
],
[
'id' => '3d87b545-b4c3-4ece-9908-20c5c5e67e80',
'name' => 'build-tools-136',
'service_level' => 'free',
'framework' => 'drupal8',
'owner' => '7558a08d-8059-45f6-9c4b-908299a025ef',
'created' => '2017-05-24 19:28:45',
'memberships' => '5ae1fa30-8cc4-4894-8ca9-d50628dcba17: ci-for-drupal-8-composer',
'frozen' => 'false',
]
];
$data = new RowsOfFields($data);
$expected = <<<EOT
------------- ---------------- --------------- ----------- ------------- --------- ------------------------------------ --------
Id Name Service_level Framework Owner Created Memberships Frozen
------------- ---------------- --------------- ----------- ------------- --------- ------------------------------------ --------
4d87b545-b4 12345678123456 business wordp 8558a08d-80 2017-0 b3a42ba5-755d-42ca-9109-21bde32809 false
c3-4ece-990 78123456781234 ress- 59-45f6-9c4 5-24 d0:
8-20c5c5e67 56781234567812 netwo b-908299a02 19:28: Team,9bfaaf50-ece3-4460-acb8-dc1b8
e81 345678 rk 5ee 45 dd536e8:
pantheon-engineering-canary-sites
3d87b545-b4 build-tools-13 free drupa 7558a08d-80 2017-0 5ae1fa30-8cc4-4894-8ca9-d50628dcba false
c3-4ece-990 6 l8 59-45f6-9c4 5-24 17: ci-for-drupal-8-composer
8-20c5c5e67 b-908299a02 19:28:
e80 5ef 45
------------- ---------------- --------------- ----------- ------------- --------- ------------------------------------ --------
EOT;
$options->setWidth(125);
$this->assertFormattedOutputMatches($expected, 'table', $data, $options);
}
function testTableWithWordWrapping2()
{
$options = new FormatterOptions();
$data = [
[
'id' => 42,
'vid' => 321,
'description' => 'Life, the Universe and Everything.',
],
[
'id' => 13,
'vid' => 789,
'description' => 'Why is six afraid of seven?',
],
];
$data = new RowsOfFields($data);
$expected = <<<EOT
---- ----- -----------------------------
Id Vid Description
---- ----- -----------------------------
42 321 Life, the Universe and
Everything.
13 789 Why is six afraid of seven?
---- ----- -----------------------------
EOT;
$options->setWidth(42);
$this->assertFormattedOutputMatches($expected, 'table', $data, $options);
}
function testTableWithWordWrapping3()
{
$options = new FormatterOptions();
$data = [
'name' => 'Rex',
'species' => 'dog',
'food' => 'kibble',
'legs' => '4',
'description' => 'Rex is a very good dog, Brett. He likes kibble, and has four legs.',
];
$data = new PropertyList($data);
$expected = <<<EOT
------------- -------------------------
Name Rex
Species dog
Food kibble
Legs 4
Description Rex is a very good dog,
Brett. He likes kibble,
and has four legs.
------------- -------------------------
EOT;
$options->setWidth(42);
$this->assertFormattedOutputMatches($expected, 'table', $data, $options);
}
function testTableWithWordWrapping4()
{
$options = new FormatterOptions();
$data = [
'name' => ['label' => 'Name', 'sep' => ':', 'value' => 'Rex', ],
'species' => ['label' => 'Species', 'sep' => ':', 'value' => 'dog', ],
'food' => ['label' => 'Food', 'sep' => ':', 'value' => 'kibble', ],
'legs' => ['label' => 'Legs', 'sep' => ':', 'value' => '4', ],
'description' => ['label' => 'Description', 'sep' => ':', 'value' => 'Rex is a very good dog, Brett. He likes kibble, and has four legs.', ],
];
$data = new RowsOfFields($data);
$expected = <<<EOT
------------- ----- -----------------------------------------------------
Label Sep Value
------------- ----- -----------------------------------------------------
Name : Rex
Species : dog
Food : kibble
Legs : 4
Description : Rex is a very good dog, Brett. He likes kibble, and
has four legs.
------------- ----- -----------------------------------------------------
EOT;
$options->setWidth(78);
$this->assertFormattedOutputMatches($expected, 'table', $data, $options);
}
function testTableWithWordWrapping5()
{
$options = new FormatterOptions();
$data = [
'name' => ['Name', ':', 'Rex', ],
'species' => ['Species', ':', 'dog', ],
'food' => ['Food', ':', 'kibble', ],
'legs' => ['Legs', ':', '4', ],
'description' => ['Description', ':', 'Rex is a very good dog, Brett. He likes kibble, and has four legs.', ],
];
$data = new RowsOfFields($data);
$expected = <<<EOT
Name : Rex
Species : dog
Food : kibble
Legs : 4
Description : Rex is a very good dog, Brett. He likes kibble, and has
four legs.
EOT;
$options->setWidth(78);
$options->setIncludeFieldLables(false);
$options->setTableStyle('compact');
$this->assertFormattedOutputMatches($expected, 'table', $data, $options);
}
protected function simpleTableExampleData()
{
$data = [
'id-123' =>
[
'one' => 'a',
'two' => 'b',
'three' => 'c',
],
'id-456' =>
[
'one' => 'x',
'two' => 'y',
'three' => 'z',
],
];
return new RowsOfFields($data);
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\InvalidFormatException
* @expectedExceptionCode 1
* @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
*/
function testIncompatibleDataForTableFormatter()
{
$data = $this->simpleTableExampleData()->getArrayCopy();
$this->assertFormattedOutputMatches('Should throw an exception before comparing the table data', 'table', $data);
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\InvalidFormatException
* @expectedExceptionCode 1
* @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
*/
function testIncompatibleDataForSectionsFormatter()
{
$data = $this->simpleTableExampleData()->getArrayCopy();
$this->assertFormattedOutputMatches('Should throw an exception before comparing the table data', 'sections', $data);
}
function testSimpleTable()
{
$data = $this->simpleTableExampleData();
$expected = <<<EOT
----- ----- -------
One Two Three
----- ----- -------
a b c
x y z
----- ----- -------
EOT;
$this->assertFormattedOutputMatches($expected, 'table', $data);
$expectedBorderless = <<<EOT
===== ===== =======
One Two Three
===== ===== =======
a b c
x y z
===== ===== =======
EOT;
$this->assertFormattedOutputMatches($expectedBorderless, 'table', $data, new FormatterOptions(['table-style' => 'borderless']));
$expectedJson = <<<EOT
{
"id-123": {
"one": "a",
"two": "b",
"three": "c"
},
"id-456": {
"one": "x",
"two": "y",
"three": "z"
}
}
EOT;
$this->assertFormattedOutputMatches($expectedJson, 'json', $data);
$expectedCsv = <<<EOT
One,Two,Three
a,b,c
x,y,z
EOT;
$this->assertFormattedOutputMatches($expectedCsv, 'csv', $data);
$expectedList = <<<EOT
id-123
id-456
EOT;
$this->assertFormattedOutputMatches($expectedList, 'list', $data);
}
protected function tableWithAlternativesExampleData()
{
$data = [
'id-123' =>
[
'one' => 'a',
'two' => ['this', 'that', 'the other thing'],
'three' => 'c',
],
'id-456' =>
[
'one' => 'x',
'two' => 'y',
'three' => ['apples', 'oranges'],
],
];
return new RowsOfFieldsWithAlternatives($data);
}
function testTableWithAlternatives()
{
$data = $this->tableWithAlternativesExampleData();
$expected = <<<EOT
----- --------------------------- ----------------
One Two Three
----- --------------------------- ----------------
a this|that|the other thing c
x y apples|oranges
----- --------------------------- ----------------
EOT;
$this->assertFormattedOutputMatches($expected, 'table', $data);
$expectedBorderless = <<<EOT
===== =========================== ================
One Two Three
===== =========================== ================
a this|that|the other thing c
x y apples|oranges
===== =========================== ================
EOT;
$this->assertFormattedOutputMatches($expectedBorderless, 'table', $data, new FormatterOptions(['table-style' => 'borderless']));
$expectedJson = <<<EOT
{
"id-123": {
"one": "a",
"two": [
"this",
"that",
"the other thing"
],
"three": "c"
},
"id-456": {
"one": "x",
"two": "y",
"three": [
"apples",
"oranges"
]
}
}
EOT;
$this->assertFormattedOutputMatches($expectedJson, 'json', $data);
$expectedCsv = <<<EOT
One,Two,Three
a,"this|that|the other thing",c
x,y,apples|oranges
EOT;
$this->assertFormattedOutputMatches($expectedCsv, 'csv', $data);
$expectedList = <<<EOT
id-123
id-456
EOT;
$this->assertFormattedOutputMatches($expectedList, 'list', $data);
}
function testSimpleTableWithFieldLabels()
{
$data = $this->simpleTableExampleData();
$configurationData = new FormatterOptions(
[
'field-labels' => ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'],
'row-labels' => ['id-123' => 'Walrus', 'id-456' => 'Carpenter'],
]
);
$configurationDataAnnotationFormat = new FormatterOptions(
[
'field-labels' => "one: Uno\ntwo: Dos\nthree: Tres",
]
);
$expected = <<<EOT
------ ---- -----
Ichi Ni San
------ ---- -----
a b c
x y z
------ ---- -----
EOT;
$this->assertFormattedOutputMatches($expected, 'table', $data, $configurationData);
$expectedSidewaysTable = <<<EOT
------ --- ---
Ichi a x
Ni b y
San c z
------ --- ---
EOT;
$this->assertFormattedOutputMatches($expectedSidewaysTable, 'table', $data, $configurationData->override(['list-orientation' => true]));
$expectedAnnotationFormatConfigData = <<<EOT
----- ----- ------
Uno Dos Tres
----- ----- ------
a b c
x y z
----- ----- ------
EOT;
$this->assertFormattedOutputMatches($expectedAnnotationFormatConfigData, 'table', $data, $configurationDataAnnotationFormat);
$expectedWithNoFields = <<<EOT
--- --- ---
a b c
x y z
--- --- ---
EOT;
$this->assertFormattedOutputMatches($expectedWithNoFields, 'table', $data, $configurationData, ['include-field-labels' => false]);
$expectedWithReorderedFields = <<<EOT
----- ------
San Ichi
----- ------
c a
z x
----- ------
EOT;
$this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['three', 'one']]);
$this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['San', 'Ichi']]);
$this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => 'San,Ichi']);
$expectedWithRegexField = <<<EOT
------ -----
Ichi San
------ -----
a c
x z
------ -----
EOT;
$this->assertFormattedOutputMatches($expectedWithRegexField, 'table', $data, $configurationData, ['fields' => ['/e$/']]);
$this->assertFormattedOutputMatches($expectedWithRegexField, 'table', $data, $configurationData, ['fields' => ['*e']]);
$this->assertFormattedOutputMatches($expectedWithRegexField, 'table', $data, $configurationData, ['default-fields' => ['*e']]);
$expectedSections = <<<EOT
Walrus
One a
Two b
Three c
Carpenter
One x
Two y
Three z
EOT;
$this->assertFormattedOutputMatches($expectedSections, 'sections', $data, $configurationData);
$expectedJson = <<<EOT
{
"id-123": {
"three": "c",
"one": "a"
},
"id-456": {
"three": "z",
"one": "x"
}
}
EOT;
$this->assertFormattedOutputMatches($expectedJson, 'json', $data, $configurationData, ['fields' => ['San', 'Ichi']]);
$expectedSingleField = <<<EOT
-----
San
-----
c
z
-----
EOT;
$this->assertFormattedOutputMatches($expectedSingleField, 'table', $data, $configurationData, ['field' => 'San']);
$expectedEmptyColumn = <<<EOT
-----
San
-----
EOT;
$this->assertFormattedOutputMatches($expectedEmptyColumn, 'table', new RowsOfFields([]), $configurationData, ['field' => 'San']);
$this->assertFormattedOutputMatches('', '', new RowsOfFields([]), $configurationData, ['field' => 'San']);
$this->assertFormattedOutputMatches('[]', 'json', new RowsOfFields([]), $configurationData, ['field' => 'San']);
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\UnknownFieldException
* @expectedExceptionCode 1
* @expectedExceptionMessage The requested field, 'Shi', is not defined.
*/
function testNoSuchFieldException()
{
$configurationData = new FormatterOptions(
[
'field-labels' => ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'],
'row-labels' => ['id-123' => 'Walrus', 'id-456' => 'Carpenter'],
]
);
$data = $this->simpleTableExampleData();
$this->assertFormattedOutputMatches('Will throw before comparing', 'table', $data, $configurationData, ['field' => 'Shi']);
}
protected function simpleListExampleData()
{
$data = [
'one' => 'apple',
'two' => 'banana',
'three' => 'carrot',
];
return new PropertyList($data);
}
// Test with the deprecated data structure
protected function simpleListExampleDataUsingAssociativeList()
{
$data = [
'one' => 'apple',
'two' => 'banana',
'three' => 'carrot',
];
return new AssociativeList($data);
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\InvalidFormatException
* @expectedExceptionCode 1
* @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
*/
function testIncompatibleListDataForTableFormatter()
{
$data = $this->simpleListExampleData();
$this->assertFormattedOutputMatches('Should throw an exception before comparing the table data', 'table', $data->getArrayCopy());
}
function testEmptyList()
{
$data = new RowsOfFields([]);
$expected = <<<EOT
--- ---- -----
I II III
--- ---- -----
EOT;
// If we provide field labels, then the output will change to reflect that.
$formatterOptionsWithFieldLables = new FormatterOptions();
$formatterOptionsWithFieldLables
->setFieldLabels(['one' => 'I', 'two' => 'II', 'three' => 'III']);
$this->assertFormattedOutputMatches($expected, 'table', $data, $formatterOptionsWithFieldLables);
}
function testSimpleList()
{
$expected = <<<EOT
------- --------
One apple
Two banana
Three carrot
------- --------
EOT;
$data = $this->simpleListExampleDataUsingAssociativeList();
$this->assertFormattedOutputMatches($expected, 'table', $data);
$data = $this->simpleListExampleData();
$this->assertFormattedOutputMatches($expected, 'table', $data);
$expected = <<<EOT
----- --------
I apple
II banana
III carrot
----- --------
EOT;
// If we provide field labels, then the output will change to reflect that.
$formatterOptionsWithFieldLables = new FormatterOptions();
$formatterOptionsWithFieldLables
->setFieldLabels(['one' => 'I', 'two' => 'II', 'three' => 'III']);
$this->assertFormattedOutputMatches($expected, 'table', $data, $formatterOptionsWithFieldLables);
$expectedDrushStyleTable = <<<EOT
One : apple
Two : banana
Three : carrot
EOT;
// If we provide field labels, then the output will change to reflect that.
$formatterOptionsWithFieldLables = new FormatterOptions();
$formatterOptionsWithFieldLables
->setTableStyle('compact')
->setListDelimiter(':');
$this->assertFormattedOutputMatches($expectedDrushStyleTable, 'table', $data, $formatterOptionsWithFieldLables);
// Adding an extra field that does not exist in the data set should not change the output
$formatterOptionsWithExtraFieldLables = new FormatterOptions();
$formatterOptionsWithExtraFieldLables
->setFieldLabels(['one' => 'I', 'two' => 'II', 'three' => 'III', 'four' => 'IV']);
$this->assertFormattedOutputMatches($expected, 'table', $data, $formatterOptionsWithExtraFieldLables);
$expectedRotated = <<<EOT
------- -------- --------
One Two Three
------- -------- --------
apple banana carrot
------- -------- --------
EOT;
$this->assertFormattedOutputMatches($expectedRotated, 'table', $data, new FormatterOptions(['list-orientation' => false]));
$expectedList = <<< EOT
apple
banana
carrot
EOT;
$this->assertFormattedOutputMatches($expectedList, 'list', $data);
$expectedReorderedList = <<< EOT
carrot
apple
EOT;
$options = new FormatterOptions([FormatterOptions::FIELDS => 'three,one']);
$this->assertFormattedOutputMatches($expectedReorderedList, 'list', $data, $options);
$expectedCsv = <<< EOT
One,Two,Three
apple,banana,carrot
EOT;
$this->assertFormattedOutputMatches($expectedCsv, 'csv', $data);
$expectedCsvNoHeaders = 'apple,banana,carrot';
$this->assertFormattedOutputMatches($expectedCsvNoHeaders, 'csv', $data, new FormatterOptions(), ['include-field-labels' => false]);
// Next, configure the formatter options with 'include-field-labels',
// but set --include-field-labels to turn the option back on again.
$options = new FormatterOptions(['include-field-labels' => false]);
$input = new StringInput('test --include-field-labels');
$optionDefinitions = [
new InputArgument('unused', InputArgument::REQUIRED),
new InputOption('include-field-labels', null, InputOption::VALUE_NONE),
];
$definition = new InputDefinition($optionDefinitions);
$input->bind($definition);
$testValue = $input->getOption('include-field-labels');
$this->assertTrue($testValue);
$hasFieldLabels = $input->hasOption('include-field-labels');
$this->assertTrue($hasFieldLabels);
$this->assertFormattedOutputMatches($expectedCsvNoHeaders, 'csv', $data, $options);
$options->setInput($input);
$this->assertFormattedOutputMatches($expectedCsv, 'csv', $data, $options);
}
protected function associativeListWithRenderer()
{
$data = [
'one' => 'apple',
'two' => ['banana', 'plantain'],
'three' => 'carrot',
'four' => ['peaches', 'pumpkin pie'],
];
$list = new PropertyList($data);
$list->addRendererFunction(
function ($key, $cellData, FormatterOptions $options)
{
if (is_array($cellData)) {
return implode(',', $cellData);
}
return $cellData;
}
);
return $list;
}
protected function associativeListWithCsvCells()
{
$data = [
'one' => 'apple',
'two' => ['banana', 'plantain'],
'three' => 'carrot',
'four' => ['peaches', 'pumpkin pie'],
];
return new PropertyListWithCsvCells($data);
}
function testPropertyListWithCsvCells()
{
$this->doPropertyListWithCsvCells($this->associativeListWithRenderer());
$this->doPropertyListWithCsvCells($this->associativeListWithCsvCells());
}
function doPropertyListWithCsvCells($data)
{
$expected = <<<EOT
------- ---------------------
One apple
Two banana,plantain
Three carrot
Four peaches,pumpkin pie
------- ---------------------
EOT;
$this->assertFormattedOutputMatches($expected, 'table', $data);
$expectedList = <<< EOT
apple
banana,plantain
carrot
peaches,pumpkin pie
EOT;
$this->assertFormattedOutputMatches($expectedList, 'list', $data);
$expectedCsv = <<< EOT
One,Two,Three,Four
apple,"banana,plantain",carrot,"peaches,pumpkin pie"
EOT;
$this->assertFormattedOutputMatches($expectedCsv, 'csv', $data);
$expectedCsvNoHeaders = 'apple,"banana,plantain",carrot,"peaches,pumpkin pie"';
$this->assertFormattedOutputMatches($expectedCsvNoHeaders, 'csv', $data, new FormatterOptions(), ['include-field-labels' => false]);
$expectedTsv = <<< EOT
apple\tbanana,plantain\tcarrot\tpeaches,pumpkin pie
EOT;
$this->assertFormattedOutputMatches($expectedTsv, 'tsv', $data);
}
function testSimpleListWithFieldLabels()
{
$data = $this->simpleListExampleData();
$configurationData = new FormatterOptions(
[
'field-labels' => ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'],
]
);
$expected = <<<EOT
------ --------
Ichi apple
Ni banana
San carrot
------ --------
EOT;
$this->assertFormattedOutputMatches($expected, 'table', $data, $configurationData);
$expectedWithReorderedFields = <<<EOT
------ --------
San carrot
Ichi apple
------ --------
EOT;
$this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['three', 'one']]);
$this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['San', 'Ichi']]);
$expectedJson = <<<EOT
{
"three": "carrot",
"one": "apple"
}
EOT;
$this->assertFormattedOutputMatches($expectedJson, 'json', $data, $configurationData, ['fields' => ['San', 'Ichi']]);
}
function testSimpleXml()
{
$data = [
'name' => 'primary',
'description' => 'The primary colors of the color wheel.',
'colors' =>
[
'red',
'yellow',
'blue',
],
];
$expected = <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<document name="primary">
<description>The primary colors of the color wheel.</description>
<colors>
<color>red</color>
<color>yellow</color>
<color>blue</color>
</colors>
</document>
EOT;
$this->assertFormattedOutputMatches($expected, 'xml', $data);
}
function domDocumentData()
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$document = $dom->createElement('document');
$dom->appendChild($document);
$document->setAttribute('name', 'primary');
$description = $dom->createElement('description');
$document->appendChild($description);
$description->appendChild($dom->createTextNode('The primary colors of the color wheel.'));
$this->domCreateElements($dom, $document, 'color', ['red', 'yellow', 'blue']);
return $dom;
}
function domCreateElements($dom, $element, $name, $data)
{
$container = $dom->createElement("{$name}s");
$element->appendChild($container);
foreach ($data as $value) {
$child = $dom->createElement($name);
$container->appendChild($child);
$child->appendChild($dom->createTextNode($value));
}
}
function complexDomDocumentData()
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$document = $dom->createElement('document');
$dom->appendChild($document);
$document->setAttribute('name', 'widget-collection');
$description = $dom->createElement('description');
$document->appendChild($description);
$description->appendChild($dom->createTextNode('A couple of widgets.'));
$widgets = $dom->createElement('widgets');
$document->appendChild($widgets);
$widget = $dom->createElement('widget');
$widgets->appendChild($widget);
$widget->setAttribute('name', 'usual');
$this->domCreateElements($dom, $widget, 'color', ['red', 'yellow', 'blue']);
$this->domCreateElements($dom, $widget, 'shape', ['square', 'circle', 'triangle']);
$widget = $dom->createElement('widget');
$widgets->appendChild($widget);
$widget->setAttribute('name', 'unusual');
$this->domCreateElements($dom, $widget, 'color', ['muave', 'puce', 'umber']);
$this->domCreateElements($dom, $widget, 'shape', ['elipse', 'rhombus', 'trapazoid']);
return $dom;
}
function domDocumentTestValues()
{
$expectedXml = <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<document name="primary">
<description>The primary colors of the color wheel.</description>
<colors>
<color>red</color>
<color>yellow</color>
<color>blue</color>
</colors>
</document>
EOT;
$expectedJson = <<<EOT
{
"name": "primary",
"description": "The primary colors of the color wheel.",
"colors": [
"red",
"yellow",
"blue"
]
}
EOT;
$expectedComplexXml = <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<document name="widget-collection">
<description>A couple of widgets.</description>
<widgets>
<widget name="usual">
<colors>
<color>red</color>
<color>yellow</color>
<color>blue</color>
</colors>
<shapes>
<shape>square</shape>
<shape>circle</shape>
<shape>triangle</shape>
</shapes>
</widget>
<widget name="unusual">
<colors>
<color>muave</color>
<color>puce</color>
<color>umber</color>
</colors>
<shapes>
<shape>elipse</shape>
<shape>rhombus</shape>
<shape>trapazoid</shape>
</shapes>
</widget>
</widgets>
</document>
EOT;
$expectedComplexJson = <<<EOT
{
"name": "widget-collection",
"description": "A couple of widgets.",
"widgets": {
"usual": {
"name": "usual",
"colors": [
"red",
"yellow",
"blue"
],
"shapes": [
"square",
"circle",
"triangle"
]
},
"unusual": {
"name": "unusual",
"colors": [
"muave",
"puce",
"umber"
],
"shapes": [
"elipse",
"rhombus",
"trapazoid"
]
}
}
}
EOT;
return [
[
$this->domDocumentData(),
$expectedXml,
$expectedJson,
],
[
$this->complexDomDocumentData(),
$expectedComplexXml,
$expectedComplexJson,
],
];
}
/**
* @dataProvider domDocumentTestValues
*/
function testDomData($data, $expectedXml, $expectedJson)
{
$this->assertFormattedOutputMatches($expectedXml, 'xml', $data);
$this->assertFormattedOutputMatches($expectedJson, 'json', $data);
// Check to see if we get the same xml data if we convert from
// DOM -> array -> DOM.
$expectedJsonAsArray = (array)json_decode($expectedJson);
$this->assertFormattedOutputMatches($expectedXml, 'xml', $expectedJsonAsArray);
}
/**
* @expectedException \Exception
* @expectedExceptionCode 1
* @expectedExceptionMessage Data provided to Consolidation\OutputFormatters\Formatters\XmlFormatter must be either an instance of DOMDocument or an array. Instead, a string was provided.
*/
function testDataTypeForXmlFormatter()
{
$this->assertFormattedOutputMatches('Will fail, not return', 'xml', 'Strings cannot be converted to XML');
}
}