Add vagrant machine, new test and travis-ci config

This commit is contained in:
Gamonoid
2016-11-25 13:53:36 +01:00
parent 21c5d09bac
commit 9348be0acd
2417 changed files with 228307 additions and 246 deletions

View File

@@ -0,0 +1,26 @@
<?php
namespace Consolidation\TestUtils;
use Symfony\Component\Console\Application;
class ApplicationWithTerminalWidth extends Application
{
protected $width = 0;
protected $height = 0;
public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
{
parent::__construct($name, $version);
}
public function setWidthAndHeight($width, $height)
{
$this->width = $width;
$this->height = $height;
}
public function getTerminalDimensions()
{
return [ $this->width, $this->height ];
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Consolidation\TestUtils;
use Consolidation\AnnotatedCommand\AnnotatedCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Test file used in the Annotation Factory tests. It is also
* discovered in the testCommandDiscovery() test.
*
* The testCommandDiscovery test search base is the 'src' directory;
* any command files located immediately inside the search base are
* eligible for discovery, and will be included in the search results.
*/
class ExampleAnnotatedCommand extends AnnotatedCommand
{
/**
* Do the main function of the my:cat command.
*/
public function myCat($one, $two = '', $flip = false)
{
if ($flip) {
return "{$two}{$one}";
}
return "{$one}{$two}";
}
/**
* This is the my:cat command implemented as an AnnotatedCommand subclass.
*
* This command will concatenate two parameters. If the --flip flag
* is provided, then the result is the concatenation of two and one.
*
* @command my:cat
* @arg string $one The first parameter.
* @arg string $two The other parameter.
* @default $two ''
* @option boolean $flip Whether or not the second parameter should come first in the result.
* @aliases c
* @usage bet alpha --flip
* Concatenate "alpha" and "bet".
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$one = $input->getArgument('one');
$two = $input->getArgument('two');
$flip = $input->getOption('flip');
$result = $this->myCat($one, $two, $flip);
// We could also just use $output->writeln($result) here,
// but calling processResults enables the use of output
// formatters. Note also that if you use processResults, you
// should correctly inject the command processor into your
// annotated command via AnnotatedCommand::setCommandProcessor().
return $this->processResults($input, $output, $result);
}
}

View File

@@ -0,0 +1,351 @@
<?php
namespace Consolidation\TestUtils;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\AnnotationData;
use Consolidation\AnnotatedCommand\CommandError;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Test file used in the Annotation Factory tests. It is also
* discovered in the testCommandDiscovery() test.
*
* The testCommandDiscovery test search base is the 'src' directory;
* any command files located immediately inside the search base are
* eligible for discovery, and will be included in the search results.
*/
class ExampleCommandFile
{
protected $state;
protected $output;
public function __construct($state = '')
{
$this->state = $state;
}
public function setOutput($output)
{
$this->output = $output;
}
/**
* This is the my:cat command
*
* This command will concatenate two parameters. If the --flip flag
* is provided, then the result is the concatenation of two and one.
*
* @param string $one The first parameter.
* @param string $two The other parameter.
* @option boolean $flip Whether or not the second parameter should come first in the result.
* @aliases c
* @usage bet alpha --flip
* Concatenate "alpha" and "bet".
* @arbitrary This annotation is here merely as a marker used in testing.
*/
public function myCat($one, $two = '', $options = ['flip' => false])
{
if ($options['flip']) {
return "{$two}{$one}";
}
return "{$one}{$two}";
}
/**
* @command my:repeat
*/
public function myRepeat($one, $two = '', $options = ['repeat' => 1])
{
return str_repeat("{$one}{$two}", $options['repeat']);
}
/**
* @command my:join
*/
public function myJoin(array $args, $options = ['flip' => false, 'repeat' => 1])
{
if ($options['flip']) {
$args = array_reverse($args);
}
$result = implode('', $args);
return str_repeat($result, $options['repeat']);
}
/**
* This is a command with no options
*
* This command will concatenate two parameters.
*
* @param $one The first parameter.
* @param $two The other parameter.
* @aliases nope
* @usage alpha bet
* Concatenate "alpha" and "bet".
*/
public function commandWithNoOptions($one, $two = 'default')
{
return "{$one}{$two}";
}
/**
* This command has no arguments--only options
*
* Return a result only if not silent.
*
* @option silent Supress output.
*/
public function commandWithNoArguments($opts = ['silent|s' => false])
{
if (!$opts['silent']) {
return "Hello, world";
}
}
/**
* Shortcut on annotation
*
* This command defines the option shortcut on the annotation instead of in the options array.
*
* @param $opts The options
* @option silent|s Supress output.
*/
public function shortcutOnAnnotation($opts = ['silent' => false])
{
if (!$opts['silent']) {
return "Hello, world";
}
}
/**
* This is the test:arithmatic command
*
* This command will add one and two. If the --negate flag
* is provided, then the result is negated.
*
* @command test:arithmatic
* @param integer $one The first number to add.
* @param integer $two The other number to add.
* @option negate Whether or not the result should be negated.
* @aliases arithmatic
* @usage 2 2 --negate
* Add two plus two and then negate.
* @custom
*/
public function testArithmatic($one, $two, $options = ['negate' => false])
{
$result = $one + $two;
if ($options['negate']) {
$result = -$result;
}
// Integer return codes are exit codes (errors), so
// return a the result as a string so that it will be printed.
return "$result";
}
/**
* This is the test:state command
*
* This command tests to see if the state of the Commandfile instance
*/
public function testState()
{
return $this->state;
}
/**
* This is the test:passthrough command
*
* This command takes a variable number of parameters as
* an array and returns them as a csv.
*/
public function testPassthrough(array $params)
{
return implode(',', $params);
}
/**
* This command wraps its parameter in []; its alter hook
* then wraps the result in <>.
*/
public function testHook($parameter)
{
return "[$parameter]";
}
/**
* Wrap the results of test:hook in <>.
*
* @hook alter test:hook
*/
public function hookTestHook($result)
{
return "<$result>";
}
/**
* This test is very similar to the preceding test, except
* it uses an annotation hook instead of a named-function hook.
*
* @hookme
* @before >
* @after <
*/
public function testAnnotationHook($parameter)
{
return "($parameter)";
}
/**
* Wrap the results of test:hook in whatever the @before and @after
* annotations contain.
*
* @hook alter @hookme
*/
public function hookTestAnnotatedHook($result, CommandData $commandData)
{
$before = $commandData->annotationData()->get('before', '-');
$after = $commandData->annotationData()->get('after', '-');
return "$before$result$after";
}
/**
* Alter the results of the hook with its command name.
*
* @hook alter @addmycommandname
*/
public function hookAddCommandName($result, CommandData $commandData)
{
$annotationData = $commandData->annotationData();
return "$result from " . $annotationData['command'];
}
/**
* Here is a hook with an explicit command annotation that we will alter
* with the preceeding hook
*
* @command alter-me
* @addmycommandname
*/
public function alterMe()
{
return "splendiferous";
}
/**
* Here is another hook that has no command annotation that should be
* altered with the default value for the command name
*
* @addmycommandname
*/
public function alterMeToo()
{
return "fantabulous";
}
/**
* @hook pre-command test:post-command
*/
public function hookTestPreCommandHook(CommandData $commandData)
{
// Use 'writeln' to detect order that hooks are called
$this->output->writeln("foo");
}
/**
* @command test:post-command
*/
public function testPostCommand($value)
{
$this->output->writeln($value);
}
/**
* @hook post-command test:post-command
*/
public function hookTestPostCommandHook($result, CommandData $commandData)
{
// Use 'writeln' to detect order that hooks are called
$this->output->writeln("baz");
}
public function testHello($who)
{
return "Hello, $who.";
}
public function testException($what)
{
throw new \Exception($what);
}
/**
* @hook init test:hello
*/
public function initializeTestHello($input, AnnotationData $annotationData)
{
$who = $input->getArgument('who');
if (!$who) {
$input->setArgument('who', 'Huey');
}
}
/**
* @hook command-event test:hello
*/
public function commandEventTestHello(ConsoleCommandEvent $event)
{
// Note that Symfony Console will not allow us to alter the
// input from this hook, so we'll just print something to
// show that this hook was executed.
$input = $event->getInput();
$who = $input->getArgument('who');
$this->output->writeln("Here comes $who!");
}
/**
* @hook interact test:hello
*/
public function interactTestHello($input, $output)
{
$who = $input->getArgument('who');
if (!$who) {
$input->setArgument('who', 'Goofey');
}
}
/**
* @hook validate test:hello
*/
public function validateTestHello($commandData)
{
$args = $commandData->arguments();
if ($args['who'] == 'Donald Duck') {
return new CommandError("I won't say hello to Donald Duck.");
}
if ($args['who'] == 'Drumph') {
throw new \Exception('Irrational value error.');
}
}
/**
* Test default values in arguments
*
* @param string|null $one
* @param string|null $two
* @return string
*/
public function defaults($one = null, $two = null)
{
if ($one && $two) {
return "$one and $two";
}
if ($one) {
return "only $one";
}
return "nothing provided";
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Consolidation\TestUtils;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Consolidation\AnnotatedCommand\CommandInfoAltererInterface;
class ExampleCommandInfoAlterer implements CommandInfoAltererInterface
{
public function alterCommandInfo(CommandInfo $commandInfo, $commandFileInstance)
{
if ($commandInfo->hasAnnotation('arbitrary')) {
$commandInfo->addAnnotation('dynamic', "This annotation was dynamically added by ExampleCommandInfoAlterer");
}
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace Consolidation\TestUtils;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Consolidation\AnnotatedCommand\CommandError;
use Consolidation\AnnotatedCommand\AnnotationData;
/**
*
*/
class ExampleHookAllCommandFile
{
public function doCat($one, $two = '', $options = ['flip' => false])
{
if ($options['flip']) {
return "{$two}{$one}";
}
return "{$one}{$two}";
}
public function doRepeat($one, $two = '', $options = ['repeat' => 1])
{
return str_repeat("{$one}{$two}", $options['repeat']);
}
/**
* This hook function does not specify which command or annotation
* it is hooking; that makes it apply to every command in the same class.
*
* @hook alter
*/
public function alterAllCommands($result)
{
if (is_string($result)) {
$result = "*** $result ***";
}
return $result;
}
}

View File

@@ -0,0 +1,243 @@
<?php
namespace Consolidation\TestUtils\alpha;
use Consolidation\AnnotatedCommand\CommandError;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Consolidation\OutputFormatters\StructuredData\AssociativeList;
use Consolidation\AnnotatedCommand\AnnotationData;
use Symfony\Component\Console\Input\InputOption;
use Consolidation\AnnotatedCommand\CommandData;
/**
* Test file used in the testCommandDiscovery() test.
*
* This commandfile is found by the test. The test search base is the
* 'src' directory, and 'alpha' is one of the search directories available
* for searching.
*/
class AlphaCommandFile
{
/**
* @command always:fail
*/
public function alwaysFail()
{
return new CommandError('This command always fails.', 13);
}
/**
* @command simulated:status
*/
public function simulatedStatus()
{
return ['status-code' => 42];
}
/**
* @command example:output
*/
public function exampleOutput()
{
return 'Hello, World.';
}
/**
* @command example:cat
*/
public function exampleCat($one, $two = '', $options = ['flip' => false])
{
if ($options['flip']) {
return "{$two}{$one}";
}
return "{$one}{$two}";
}
/**
* @command example:echo
*/
public function exampleEcho(array $args)
{
return ['item-list' => $args];
}
/**
* @command example:message
*/
public function exampleMessage()
{
return ['message' => 'Shipwrecked; send bananas.'];
}
/**
* Test command with formatters
*
* @command example:table
* @field-labels
* first: I
* second: II
* third: III
* @usage example:table --format=yaml
* @usage example:table --format=csv
* @usage example:table --fields=first,third
* @usage example:table --fields=III,II
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
*/
public function exampleTable($options = ['format' => 'table', 'fields' => ''])
{
$outputData = [
[ 'first' => 'One', 'second' => 'Two', 'third' => 'Three' ],
[ 'first' => 'Eins', 'second' => 'Zwei', 'third' => 'Drei' ],
[ 'first' => 'Ichi', 'second' => 'Ni', 'third' => 'San' ],
[ 'first' => 'Uno', 'second' => 'Dos', 'third' => 'Tres' ],
];
return new RowsOfFields($outputData);
}
/**
* Test word wrapping
*
* @command example:wrap
* @field-labels
* first: First
* second: Second
*
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
*/
public function exampleWrap()
{
$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.',
]
];
return new RowsOfFields($data);
}
/**
* @hook option example:table
*/
public function additionalOptionForExampleTable($command, $annotationData)
{
$command->addOption(
'dynamic',
'',
InputOption::VALUE_NONE,
'Option added by @hook option example:table'
);
}
/**
* Demonstrate an alter hook with an option
*
* @hook alter example:table
* @option french Add a row with French numbers.
* @usage example:table --french
*/
public function alterFormatters($result, CommandData $commandData)
{
if ($commandData->input()->getOption('french')) {
$result[] = [ 'first' => 'Un', 'second' => 'Deux', 'third' => 'Trois' ];
}
return $result;
}
/**
* Test command with formatters using an associative list
*
* @command example:list
* @field-labels
* sftp_command: SFTP Command
* sftp_username: SFTP Username
* sftp_host: SFTP Host
* sftp_password: SFTP Password
* sftp_url: SFTP URL
* git_command: Git Command
* git_username: Git Username
* git_host: Git Host
* git_port: Git Port
* git_url: Git URL
* mysql_command: MySQL Command
* mysql_username: MySQL Username
* mysql_host: MySQL Host
* mysql_password: MySQL Password
* mysql_url: MySQL URL
* mysql_port: MySQL Port
* mysql_database: MySQL Database
* redis_command: Redis Command
* redis_port: Redis Port
* redis_url: Redis URL
* redis_password: Redis Password
* @default-fields *_command
* @return \Consolidation\OutputFormatters\StructuredData\AssociativeList
*/
public function exampleAssociativeList()
{
$outputData = [
'sftp_command' => 'sftp -o Port=2222 dev@appserver.dev.drush.in',
'sftp_username' => 'dev',
'sftp_host' => 'appserver.dev.drush.in',
'sftp_password' => 'Use your account password',
'sftp_url' => 'sftp://dev@appserver.dev.drush.in:2222',
'git_command' => 'git clone ssh://codeserver.dev@codeserver.dev.drush.in:2222/~/repository.git wp-update',
'git_username' => 'codeserver.dev',
'git_host' => 'codeserver.dev.drush.in',
'git_port' => 2222,
'git_url' => 'ssh://codeserver.dev@codeserver.dev.drush.in:2222/~/repository.git',
'mysql_command' => 'mysql -u pantheon -p4b33cb -h dbserver.dev.drush.in -P 16191 pantheon',
'mysql_username' => 'pantheon',
'mysql_host' => 'dbserver.dev.drush.in',
'mysql_password' => '4b33cb',
'mysql_url' => 'mysql://pantheon:4b33cb@dbserver.dev.drush.in:16191/pantheon',
'mysql_port' => 16191,
'mysql_database' => 'pantheon',
];
return new AssociativeList($outputData);
}
/**
* This command has no annotations; this means that it will not be
* found when createCommandsFromClass() is called with
* '$includeAllPublicMethods' set to false.
*/
public function withoutAnnotations()
{
return 'ok';
}
/**
* @command command:with-one-optional-argument
*
* This command has just one optional argument.
*
* Return a result only if not silent.
*
* @option silent Supress output.
*/
public function commandWithOneOptionalArgument($who = 'world', $opts = ['silent|s' => false])
{
if (!$opts['silent']) {
return "Hello, $who";
}
}
/**
* This should be a command, because it is annotated like one.
*
* @command get:serious
*/
public function getSerious()
{
return 'very serious';
}
/**
* This should not be a command, because it looks like an accessor and
* has no @command annotation.
*/
public function getLost()
{
return 'very lost';
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Consolidation\TestUtils\alpha\Exclude;
/**
* Test file used in the testCommandDiscovery() test.
*
* This commandfile is NOT found by the test. It is in a searched
* location (@see Consolidation\TestUtils\alpha\Exclude\IncludedCommandFile),
* but it is in a folder named 'Exclude', which is excluded form search.
*/
class ExcludedCommandFile
{
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Consolidation\TestUtils\alpha\Inclusive;
/**
* Test file used in the testCommandDiscovery() test.
*
* This commandfile is found by the test. The test search base is the
* 'src' directory, and 'alpha' is one of the search directories available
* for searching. Directories such as this in the search locations list
* are searched deeply (to a depth of two), so command files may be
* organized into sub-namespaces, if desired.
*/
class IncludedCommandFile
{
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Consolidation\TestUtils\beta;
use Consolidation\AnnotatedCommand\AnnotationData;
use Consolidation\AnnotatedCommand\CommandData;
/**
* Test file used in the testCommandDiscovery() test.
*
* This commandfile is not found by the test. The test search base is the
* 'src' directory, but 'beta' is NOT one of the search directories available
* for searching, so nothing in this folder will be examined.
*/
class BetaCommandFile
{
public function unavailableCommand()
{
return 'This command is not available, because this commandfile is not in a location that is searched by the tests.';
}
/**
* Demonstrate an alter hook with an option
*
* @hook alter example:table
* @option chinese Add a row with Chinese numbers.
* @usage example:table --chinese
*/
public function alterFormattersChinese($result, CommandData $commandData)
{
if ($commandData->input()->getOption('chinese')) {
$result[] = [ 'first' => '壹', 'second' => '貳', 'third' => '叁' ];
}
return $result;
}
/**
* Demonstrate an alter hook with an option
*
* @hook alter *
* @option kanji Add a row with Kanji numbers.
* @usage example:table --kanji
*/
public function alterFormattersKanji($result, CommandData $commandData)
{
if ($commandData->input()->getOption('kanji')) {
$result[] = [ 'first' => '一', 'second' => '二', 'third' => '三' ];
}
return $result;
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Consolidation\AnnotatedCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Application;
class AnnotatedCommandTests extends \PHPUnit_Framework_TestCase
{
function testMyCatCommand()
{
$command = new \Consolidation\TestUtils\ExampleAnnotatedCommand();
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('my:cat', $command->getName());
$this->assertEquals('This is the my:cat command implemented as an AnnotatedCommand subclass.', $command->getDescription());
$this->assertEquals("This command will concatenate two parameters. If the --flip flag\nis provided, then the result is the concatenation of two and one.", $command->getHelp());
$this->assertEquals('c', implode(',', $command->getAliases()));
// Symfony Console composes the synopsis; perhaps we should not test it. Remove if this gives false failures.
$this->assertEquals('my:cat [--flip] [--] <one> [<two>]', $command->getSynopsis());
$this->assertEquals('my:cat bet alpha --flip', implode(',', $command->getUsages()));
$input = new StringInput('my:cat bet alpha --flip');
$this->assertRunCommandViaApplicationEquals($command, $input, 'alphabet');
}
// TODO: Make a base test class to hold this.
function assertRunCommandViaApplicationEquals($command, $input, $expectedOutput, $expectedStatusCode = 0)
{
$output = new BufferedOutput();
$application = new Application('TestApplication', '0.0.0');
$application->setAutoExit(false);
$application->add($command);
$statusCode = $application->run($input, $output);
$commandOutput = trim($output->fetch());
$this->assertEquals($expectedOutput, $commandOutput);
$this->assertEquals($expectedStatusCode, $statusCode);
}
}

View File

@@ -0,0 +1,639 @@
<?php
namespace Consolidation\AnnotatedCommand;
use Consolidation\AnnotatedCommand\AnnotationData;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\Hooks\HookManager;
use Consolidation\AnnotatedCommand\Options\AlterOptionsCommandEvent;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Consolidation\TestUtils\ExampleCommandInfoAlterer;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
class AnnotatedCommandFactoryTests extends \PHPUnit_Framework_TestCase
{
protected $commandFileInstance;
protected $commandFactory;
/**
* Test CommandInfo command annotation parsing.
*/
function testAnnotatedCommandCreation()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testArithmatic');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('test:arithmatic', $command->getName());
$this->assertEquals('This is the test:arithmatic command', $command->getDescription());
$this->assertEquals("This command will add one and two. If the --negate flag\nis provided, then the result is negated.", $command->getHelp());
$this->assertEquals('arithmatic', implode(',', $command->getAliases()));
$this->assertEquals('test:arithmatic [--negate] [--] <one> <two>', $command->getSynopsis());
$this->assertEquals('test:arithmatic 2 2 --negate', implode(',', $command->getUsages()));
$input = new StringInput('arithmatic 2 3 --negate');
$this->assertRunCommandViaApplicationEquals($command, $input, '-5');
}
/**
* Test CommandInfo command annotation altering.
*/
function testAnnotatedCommandInfoAlteration()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'myCat');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$annotationData = $command->getAnnotationData();
$this->assertTrue($annotationData->has('arbitrary'));
$this->assertFalse($annotationData->has('dynamic'));
$this->commandFactory->addCommandInfoAlterer(new ExampleCommandInfoAlterer());
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$annotationData = $command->getAnnotationData();
$this->assertTrue($annotationData->has('arbitrary'));
$this->assertTrue($annotationData->has('dynamic'));
}
function testMyCatCommand()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'myCat');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('my:cat', $command->getName());
$this->assertEquals('This is the my:cat command', $command->getDescription());
$this->assertEquals("This command will concatenate two parameters. If the --flip flag\nis provided, then the result is the concatenation of two and one.", $command->getHelp());
$this->assertEquals('c', implode(',', $command->getAliases()));
$this->assertEquals('my:cat [--flip] [--] <one> [<two>]', $command->getSynopsis());
$this->assertEquals('my:cat bet alpha --flip', implode(',', $command->getUsages()));
$input = new StringInput('my:cat bet alpha --flip');
$this->assertRunCommandViaApplicationEquals($command, $input, 'alphabet');
}
function testDefaultsCommand()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'defaults');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('defaults', $command->getName());
$this->assertEquals('Test default values in arguments', $command->getDescription());
$input = new StringInput('defaults');
$this->assertRunCommandViaApplicationEquals($command, $input, 'nothing provided');
$input = new StringInput('defaults ichi');
$this->assertRunCommandViaApplicationEquals($command, $input, 'only ichi');
$input = new StringInput('defaults I II');
$this->assertRunCommandViaApplicationEquals($command, $input, 'I and II');
}
function testCommandWithNoOptions()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'commandWithNoOptions');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('command:with-no-options', $command->getName());
$this->assertEquals('This is a command with no options', $command->getDescription());
$this->assertEquals("This command will concatenate two parameters.", $command->getHelp());
$this->assertEquals('nope', implode(',', $command->getAliases()));
$this->assertEquals('command:with-no-options <one> [<two>]', $command->getSynopsis());
$this->assertEquals('command:with-no-options alpha bet', implode(',', $command->getUsages()));
$input = new StringInput('command:with-no-options something');
$this->assertRunCommandViaApplicationEquals($command, $input, 'somethingdefault');
}
function testCommandWithNoArguments()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'commandWithNoArguments');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('command:with-no-arguments', $command->getName());
$this->assertEquals('This command has no arguments--only options', $command->getDescription());
$this->assertEquals("Return a result only if not silent.", $command->getHelp());
$this->assertEquals('command:with-no-arguments [-s|--silent]', $command->getSynopsis());
$input = new StringInput('command:with-no-arguments');
$this->assertRunCommandViaApplicationEquals($command, $input, 'Hello, world');
$input = new StringInput('command:with-no-arguments -s');
$this->assertRunCommandViaApplicationEquals($command, $input, '');
$input = new StringInput('command:with-no-arguments --silent');
$this->assertRunCommandViaApplicationEquals($command, $input, '');
}
function testCommandWithShortcutOnAnnotation()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'shortcutOnAnnotation');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('shortcut:on-annotation', $command->getName());
$this->assertEquals('Shortcut on annotation', $command->getDescription());
$this->assertEquals("This command defines the option shortcut on the annotation instead of in the options array.", $command->getHelp());
$this->assertEquals('shortcut:on-annotation [-s|--silent]', $command->getSynopsis());
$input = new StringInput('shortcut:on-annotation');
$this->assertRunCommandViaApplicationEquals($command, $input, 'Hello, world');
$input = new StringInput('shortcut:on-annotation -s');
$this->assertRunCommandViaApplicationEquals($command, $input, '');
$input = new StringInput('shortcut:on-annotation --silent');
$this->assertRunCommandViaApplicationEquals($command, $input, '');
}
function testState()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile('secret secret');
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testState');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('test:state', $command->getName());
$input = new StringInput('test:state');
$this->assertRunCommandViaApplicationEquals($command, $input, 'secret secret');
}
function testPassthroughArray()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testPassthrough');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('test:passthrough', $command->getName());
$input = new StringInput('test:passthrough a b c -- x y z');
$this->assertRunCommandViaApplicationEquals($command, $input, 'a,b,c,x,y,z');
}
function testPassThroughNonArray()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'myJoin');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$input = new StringInput('my:join bet --flip -- x y z');
$this->assertRunCommandViaApplicationEquals($command, $input, 'zyxbet');
// Can't look at 'hasOption' until after the command initializes the
// option, because Symfony.
$this->assertTrue($input->hasOption('flip'));
}
function testPassThroughWithInputManipulation()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'myJoin');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$input = new StringInput('my:join bet --repeat=2 -- x y z');
$this->assertRunCommandViaApplicationEquals($command, $input, 'betxyzbetxyz');
// Symfony does not allow us to manipulate the options via setOption until
// the definition from the command object has been set up.
$input->setOption('repeat', 3);
$this->assertEquals(3, $input->getOption('repeat'));
$input->setArgument(0, 'q');
// Manipulating $input does not work -- the changes are not effective.
// The end result here should be 'qx y yqx y yqx y y'
$this->assertRunCommandViaApplicationEquals($command, $input, 'betxyzbetxyz');
}
function testHookedCommand()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
$this->commandFactory = new AnnotatedCommandFactory();
$hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestHook');
$this->assertTrue($hookInfo->hasAnnotation('hook'));
$this->assertEquals('alter test:hook', $hookInfo->getAnnotation('hook'));
$this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
$hookCallback = $this->commandFactory->hookManager()->get('test:hook', [HookManager::ALTER_RESULT]);
$this->assertTrue($hookCallback != null);
$this->assertEquals(1, count($hookCallback));
$this->assertEquals(2, count($hookCallback[0]));
$this->assertTrue(is_callable($hookCallback[0]));
$this->assertEquals('hookTestHook', $hookCallback[0][1]);
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testHook');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('test:hook', $command->getName());
$input = new StringInput('test:hook bar');
$this->assertRunCommandViaApplicationEquals($command, $input, '<[bar]>');
}
function testPostCommandCalledAfterCommand()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
$this->commandFactory = new AnnotatedCommandFactory();
$hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestPostCommandHook');
$this->assertTrue($hookInfo->hasAnnotation('hook'));
$this->assertEquals('post-command test:post-command', $hookInfo->getAnnotation('hook'));
$this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
$hookCallback = $this->commandFactory->hookManager()->get('test:post-command', [HookManager::POST_COMMAND_HOOK]);
$this->assertTrue($hookCallback != null);
$this->assertEquals(1, count($hookCallback));
$this->assertEquals(2, count($hookCallback[0]));
$this->assertTrue(is_callable($hookCallback[0]));
$this->assertEquals('hookTestPostCommandHook', $hookCallback[0][1]);
$hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestPreCommandHook');
$this->assertTrue($hookInfo->hasAnnotation('hook'));
$this->assertEquals('pre-command test:post-command', $hookInfo->getAnnotation('hook'));
$this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
$hookCallback = $this->commandFactory->hookManager()->get('test:post-command', [HookManager::PRE_COMMAND_HOOK]);
$this->assertTrue($hookCallback != null);
$this->assertEquals(1, count($hookCallback));
$this->assertEquals(2, count($hookCallback[0]));
$this->assertTrue(is_callable($hookCallback[0]));
$this->assertEquals('hookTestPreCommandHook', $hookCallback[0][1]);
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testPostCommand');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('test:post-command', $command->getName());
$input = new StringInput('test:post-command bar');
$this->assertRunCommandViaApplicationEquals($command, $input, "foo\nbar\nbaz", 0, $this->commandFileInstance);
}
function testHookAllCommands()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleHookAllCommandFile();
$this->commandFactory = new AnnotatedCommandFactory();
$hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'alterAllCommands');
$this->assertTrue($hookInfo->hasAnnotation('hook'));
$this->assertEquals('alter', $hookInfo->getAnnotation('hook'));
$this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
$hookCallback = $this->commandFactory->hookManager()->get('Consolidation\TestUtils\ExampleHookAllCommandFile', [HookManager::ALTER_RESULT]);
$this->assertTrue($hookCallback != null);
$this->assertEquals(1, count($hookCallback));
$this->assertEquals(2, count($hookCallback[0]));
$this->assertTrue(is_callable($hookCallback[0]));
$this->assertEquals('alterAllCommands', $hookCallback[0][1]);
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'doCat');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('do:cat', $command->getName());
$input = new StringInput('do:cat bar');
$this->assertRunCommandViaApplicationEquals($command, $input, '*** bar ***');
}
function testAnnotatedHookedCommand()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
$this->commandFactory = new AnnotatedCommandFactory();
$hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestAnnotatedHook');
$this->assertTrue($hookInfo->hasAnnotation('hook'));
$this->assertEquals('alter @hookme', $hookInfo->getAnnotation('hook'));
$this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
$hookCallback = $this->commandFactory->hookManager()->get('@hookme', [HookManager::ALTER_RESULT]);
$this->assertTrue($hookCallback != null);
$this->assertEquals(1, count($hookCallback));
$this->assertEquals(2, count($hookCallback[0]));
$this->assertTrue(is_callable($hookCallback[0]));
$this->assertEquals('hookTestAnnotatedHook', $hookCallback[0][1]);
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testAnnotationHook');
$annotationData = $commandInfo->getRawAnnotations();
$this->assertEquals('hookme,before,after', implode(',', $annotationData->keys()));
$this->assertEquals('@hookme,@before,@after', implode(',', array_map(function ($item) { return "@$item"; }, $annotationData->keys())));
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('test:annotation-hook', $command->getName());
$input = new StringInput('test:annotation-hook baz');
$this->assertRunCommandViaApplicationEquals($command, $input, '>(baz)<');
}
function testHookHasCommandAnnotation()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
$this->commandFactory = new AnnotatedCommandFactory();
$hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookAddCommandName');
$this->assertTrue($hookInfo->hasAnnotation('hook'));
$this->assertEquals('alter @addmycommandname', $hookInfo->getAnnotation('hook'));
$this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
$hookCallback = $this->commandFactory->hookManager()->get('@addmycommandname', [HookManager::ALTER_RESULT]);
$this->assertTrue($hookCallback != null);
$this->assertEquals(1, count($hookCallback));
$this->assertEquals(2, count($hookCallback[0]));
$this->assertTrue(is_callable($hookCallback[0]));
$this->assertEquals('hookAddCommandName', $hookCallback[0][1]);
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'alterMe');
$annotationData = $commandInfo->getRawAnnotations();
$this->assertEquals('command,addmycommandname', implode(',', $annotationData->keys()));
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('alter-me', $command->getName());
$input = new StringInput('alter-me');
$this->assertRunCommandViaApplicationEquals($command, $input, 'splendiferous from alter-me');
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'alterMeToo');
$annotationData = $commandInfo->getRawAnnotations();
$this->assertEquals('addmycommandname', implode(',', $annotationData->keys()));
$annotationData = $commandInfo->getAnnotations();
$this->assertEquals('addmycommandname,command', implode(',', $annotationData->keys()));
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('alter:me-too', $command->getName());
$input = new StringInput('alter:me-too');
$this->assertRunCommandViaApplicationEquals($command, $input, 'fantabulous from alter:me-too');
}
function testHookedCommandWithHookAddedLater()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
$this->commandFactory = new AnnotatedCommandFactory();
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testHook');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('test:hook', $command->getName());
// Run the command once without the hook
$input = new StringInput('test:hook foo');
$this->assertRunCommandViaApplicationEquals($command, $input, '[foo]');
// Register the hook and run the command again
$hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestHook');
$this->assertTrue($hookInfo->hasAnnotation('hook'));
$this->assertEquals('alter test:hook', $hookInfo->getAnnotation('hook'));
$this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
$hookCallback = $this->commandFactory->hookManager()->get('test:hook', [HookManager::ALTER_RESULT]);;
$this->assertTrue($hookCallback != null);
$this->assertEquals(1, count($hookCallback));
$this->assertEquals(2, count($hookCallback[0]));
$this->assertTrue(is_callable($hookCallback[0]));
$this->assertEquals('hookTestHook', $hookCallback[0][1]);
$input = new StringInput('test:hook bar');
$this->assertRunCommandViaApplicationEquals($command, $input, '<[bar]>');
}
function testInitializeHook()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
$this->commandFactory = new AnnotatedCommandFactory();
$hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'initializeTestHello');
$this->assertTrue($hookInfo->hasAnnotation('hook'));
$this->assertEquals($hookInfo->getAnnotation('hook'), 'init test:hello');
$this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
$hookCallback = $this->commandFactory->hookManager()->get('test:hello', [HookManager::INITIALIZE]);
$this->assertTrue($hookCallback != null);
$this->assertEquals(1, count($hookCallback));
$this->assertEquals(2, count($hookCallback[0]));
$this->assertTrue(is_callable($hookCallback[0]));
$this->assertEquals('initializeTestHello', $hookCallback[0][1]);
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testHello');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('test:hello', $command->getName());
$commandGetNames = $this->callProtected($command, 'getNames');
$this->assertEquals('test:hello,Consolidation\TestUtils\ExampleCommandFile', implode(',', $commandGetNames));
$hookCallback = $command->commandProcessor()->hookManager()->get('test:hello', 'init');
$this->assertTrue($hookCallback != null);
$this->assertEquals('initializeTestHello', $hookCallback[0][1]);
$input = new StringInput('test:hello');
$this->assertRunCommandViaApplicationEquals($command, $input, "Hello, Huey.");
}
function testCommandEventHook()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
$this->commandFactory = new AnnotatedCommandFactory();
$hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'commandEventTestHello');
$this->assertTrue($hookInfo->hasAnnotation('hook'));
$this->assertEquals($hookInfo->getAnnotation('hook'), 'command-event test:hello');
$this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
$hookCallback = $this->commandFactory->hookManager()->get('test:hello', [HookManager::COMMAND_EVENT]);
$this->assertTrue($hookCallback != null);
$this->assertEquals(1, count($hookCallback));
$this->assertEquals(2, count($hookCallback[0]));
$this->assertTrue(is_callable($hookCallback[0]));
$this->assertEquals('commandEventTestHello', $hookCallback[0][1]);
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testHello');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('test:hello', $command->getName());
$commandGetNames = $this->callProtected($command, 'getNames');
$this->assertEquals('test:hello,Consolidation\TestUtils\ExampleCommandFile', implode(',', $commandGetNames));
$hookCallback = $command->commandProcessor()->hookManager()->get('test:hello', 'command-event');
$this->assertTrue($hookCallback != null);
$this->assertEquals('commandEventTestHello', $hookCallback[0][1]);
$input = new StringInput('test:hello Pluto');
$this->assertRunCommandViaApplicationEquals($command, $input, "Here comes Pluto!\nHello, Pluto.");
}
function testInteractAndValidate()
{
$this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
$this->commandFactory = new AnnotatedCommandFactory();
$hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'interactTestHello');
$this->assertTrue($hookInfo->hasAnnotation('hook'));
$this->assertEquals($hookInfo->getAnnotation('hook'), 'interact test:hello');
$this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
$hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'validateTestHello');
$this->assertTrue($hookInfo->hasAnnotation('hook'));
$this->assertEquals($hookInfo->getAnnotation('hook'), 'validate test:hello');
$this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
$hookCallback = $this->commandFactory->hookManager()->get('test:hello', [HookManager::ARGUMENT_VALIDATOR]);
$this->assertTrue($hookCallback != null);
$this->assertEquals(1, count($hookCallback));
$this->assertEquals(2, count($hookCallback[0]));
$this->assertTrue(is_callable($hookCallback[0]));
$this->assertEquals('validateTestHello', $hookCallback[0][1]);
$hookCallback = $this->commandFactory->hookManager()->get('test:hello', [HookManager::INTERACT]);
$this->assertTrue($hookCallback != null);
$this->assertEquals(1, count($hookCallback));
$this->assertEquals(2, count($hookCallback[0]));
$this->assertTrue(is_callable($hookCallback[0]));
$this->assertEquals('interactTestHello', $hookCallback[0][1]);
$commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testHello');
$command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
$this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
$this->assertEquals('test:hello', $command->getName());
$commandGetNames = $this->callProtected($command, 'getNames');
$this->assertEquals('test:hello,Consolidation\TestUtils\ExampleCommandFile', implode(',', $commandGetNames));
$testInteractInput = new StringInput('test:hello');
$definition = new \Symfony\Component\Console\Input\InputDefinition(
[
new \Symfony\Component\Console\Input\InputArgument('application', \Symfony\Component\Console\Input\InputArgument::REQUIRED),
new \Symfony\Component\Console\Input\InputArgument('who', \Symfony\Component\Console\Input\InputArgument::REQUIRED),
]
);
$testInteractInput->bind($definition);
$testInteractOutput = new BufferedOutput();
$command->commandProcessor()->interact(
$testInteractInput,
$testInteractOutput,
$commandGetNames,
$command->getAnnotationData()
);
$this->assertEquals('Goofey', $testInteractInput->getArgument('who'));
$hookCallback = $command->commandProcessor()->hookManager()->get('test:hello', 'interact');
$this->assertTrue($hookCallback != null);
$this->assertEquals('interactTestHello', $hookCallback[0][1]);
$input = new StringInput('test:hello "Mickey Mouse"');
$this->assertRunCommandViaApplicationEquals($command, $input, 'Hello, Mickey Mouse.');
$input = new StringInput('test:hello');
$this->assertRunCommandViaApplicationEquals($command, $input, 'Hello, Goofey.');
$input = new StringInput('test:hello "Donald Duck"');
$this->assertRunCommandViaApplicationEquals($command, $input, "I won't say hello to Donald Duck.", 1);
$input = new StringInput('test:hello "Drumph"');
$this->assertRunCommandViaApplicationEquals($command, $input, "Irrational value error.", 1);
// Try the last test again with a display error function installed.
$this->commandFactory->commandProcessor()->setDisplayErrorFunction(
function ($output, $message) {
$output->writeln("*** $message ****");
}
);
$input = new StringInput('test:hello "Drumph"');
$this->assertRunCommandViaApplicationEquals($command, $input, "*** Irrational value error. ****", 1);
}
function callProtected($object, $method, $args = [])
{
$r = new \ReflectionMethod($object, $method);
$r->setAccessible(true);
return $r->invokeArgs($object, $args);
}
function assertRunCommandViaApplicationEquals($command, $input, $expectedOutput, $expectedStatusCode = 0)
{
$output = new BufferedOutput();
if ($this->commandFileInstance && method_exists($this->commandFileInstance, 'setOutput')) {
$this->commandFileInstance->setOutput($output);
}
$application = new Application('TestApplication', '0.0.0');
$alterOptionsEventManager = new AlterOptionsCommandEvent($application);
$eventDispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();
$eventDispatcher->addSubscriber($this->commandFactory->commandProcessor()->hookManager());
$eventDispatcher->addSubscriber($alterOptionsEventManager);
$application->setDispatcher($eventDispatcher);
$application->setAutoExit(false);
$application->add($command);
$statusCode = $application->run($input, $output);
$commandOutput = trim($output->fetch());
$this->assertEquals($expectedOutput, $commandOutput);
$this->assertEquals($expectedStatusCode, $statusCode);
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace Consolidation\AnnotatedCommand;
class CommandFileDiscoveryTests extends \PHPUnit_Framework_TestCase
{
function testCommandDiscovery()
{
$discovery = new CommandFileDiscovery();
$discovery
->setSearchPattern('*CommandFile.php')
->setSearchLocations(['alpha']);
chdir(__DIR__);
$commandFiles = $discovery->discover('.', '\Consolidation\TestUtils');
$commandFilePaths = array_keys($commandFiles);
$commandFileNamespaces = array_values($commandFiles);
// Ensure that the command files that we expected to
// find were all found. We don't find anything in
// 'beta' because only 'alpha' is in the search path.
$this->assertContains('./src/ExampleCommandFile.php', $commandFilePaths);
$this->assertContains('./src/ExampleHookAllCommandFile.php', $commandFilePaths);
$this->assertContains('./src/alpha/AlphaCommandFile.php', $commandFilePaths);
$this->assertContains('./src/alpha/Inclusive/IncludedCommandFile.php', $commandFilePaths);
// Make sure that there are no additional items found.
$this->assertEquals(4, count($commandFilePaths));
// Ensure that the command file namespaces that we expected
// to be generated all match.
$this->assertContains('\Consolidation\TestUtils\ExampleCommandFile', $commandFileNamespaces);
$this->assertContains('\Consolidation\TestUtils\ExampleHookAllCommandFile', $commandFileNamespaces);
$this->assertContains('\Consolidation\TestUtils\alpha\AlphaCommandFile', $commandFileNamespaces);
$this->assertContains('\Consolidation\TestUtils\alpha\Inclusive\IncludedCommandFile', $commandFileNamespaces);
// We do not need to test for additional namespace items, because we
// know that the length of the array_keys must be the same as the
// length of the array_values.
}
function testDeepCommandDiscovery()
{
$discovery = new CommandFileDiscovery();
$discovery
->setSearchPattern('*CommandFile.php')
->setSearchDepth(1)
->setSearchLocations([]);
chdir(__DIR__);
$commandFiles = $discovery->discover('.', '\Consolidation\TestUtils');
$commandFilePaths = array_keys($commandFiles);
$commandFileNamespaces = array_values($commandFiles);
// Ensure that the command files that we expected to
// find were all found. We find both 'alpha' and 'beta'
// items because the search locations is empty, which
// causes the search at the base directory to be deep.
// We do not find alpha/Inclusive, though, as the search
// depth is only 2, which excludes directories that are
// three levels deep.
$this->assertContains('./src/ExampleCommandFile.php', $commandFilePaths);
$this->assertContains('./src/ExampleHookAllCommandFile.php', $commandFilePaths);
$this->assertContains('./src/alpha/AlphaCommandFile.php', $commandFilePaths);
$this->assertContains('./src/beta/BetaCommandFile.php', $commandFilePaths);
// Make sure that there are no additional items found.
$this->assertEquals(4, count($commandFilePaths));
// Ensure that the command file namespaces that we expected
// to be generated all match.
$this->assertContains('\Consolidation\TestUtils\ExampleCommandFile', $commandFileNamespaces);
$this->assertContains('\Consolidation\TestUtils\ExampleHookAllCommandFile', $commandFileNamespaces);
$this->assertContains('\Consolidation\TestUtils\alpha\AlphaCommandFile', $commandFileNamespaces);
$this->assertContains('\Consolidation\TestUtils\beta\BetaCommandFile', $commandFileNamespaces);
// We do not need to test for additional namespace items, because we
// know that the length of the array_keys must be the same as the
// length of the array_values.
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Consolidation\AnnotatedCommand;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
class CommandInfoTests extends \PHPUnit_Framework_TestCase
{
function flattenArray($actualValue)
{
$result = [];
foreach ($actualValue as $key => $value) {
if (!is_string($value)) {
$value = var_export($value, true);
}
$result[] = "{$key}=>{$value}";
}
return implode("\n", $result);
}
/**
* Test CommandInfo command annotation parsing.
*/
function testParsing()
{
$commandInfo = new CommandInfo('\Consolidation\TestUtils\ExampleCommandFile', 'testArithmatic');
$this->assertEquals('test:arithmatic', $commandInfo->getName());
$this->assertEquals(
'This is the test:arithmatic command',
$commandInfo->getDescription()
);
$this->assertEquals(
"This command will add one and two. If the --negate flag\nis provided, then the result is negated.",
$commandInfo->getHelp()
);
$this->assertEquals('arithmatic', implode(',', $commandInfo->getAliases()));
$this->assertEquals(
'2 2 --negate=>Add two plus two and then negate.',
$this->flattenArray($commandInfo->getExampleUsages())
);
$this->assertEquals(
'The first number to add.',
$commandInfo->arguments()->getDescription('one')
);
$this->assertEquals(
'The other number to add.',
$commandInfo->arguments()->getDescription('two')
);
$this->assertEquals(
'Whether or not the result should be negated.',
$commandInfo->options()->getDescription('negate')
);
}
function testReturnValue()
{
$commandInfo = new CommandInfo('\Consolidation\TestUtils\alpha\AlphaCommandFile', 'exampleTable');
$this->assertEquals('example:table', $commandInfo->getName());
$this->assertEquals('\Consolidation\OutputFormatters\StructuredData\RowsOfFields', $commandInfo->getReturnType());
}
}

View File

@@ -0,0 +1,508 @@
<?php
namespace Consolidation\AnnotatedCommand;
use Consolidation\AnnotatedCommand\AnnotationData;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandProcessor;
use Consolidation\AnnotatedCommand\Hooks\AlterResultInterface;
use Consolidation\AnnotatedCommand\Hooks\ExtractOutputInterface;
use Consolidation\AnnotatedCommand\Hooks\HookManager;
use Consolidation\AnnotatedCommand\Hooks\ProcessResultInterface;
use Consolidation\AnnotatedCommand\Hooks\StatusDeterminerInterface;
use Consolidation\AnnotatedCommand\Hooks\ValidatorInterface;
use Consolidation\AnnotatedCommand\Options\AlterOptionsCommandEvent;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Consolidation\OutputFormatters\FormatterManager;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Consolidation\TestUtils\ApplicationWithTerminalWidth;
use Consolidation\AnnotatedCommand\Options\PrepareTerminalWidthOption;
/**
* Do a test of all of the classes in this project, top-to-bottom.
*/
class FullStackTests extends \PHPUnit_Framework_TestCase
{
protected $application;
protected $commandFactory;
function setup() {
$this->application = new ApplicationWithTerminalWidth('TestApplication', '0.0.0');
$this->commandFactory = new AnnotatedCommandFactory();
$alterOptionsEventManager = new AlterOptionsCommandEvent($this->application);
$eventDispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();
$eventDispatcher->addSubscriber($this->commandFactory->commandProcessor()->hookManager());
$eventDispatcher->addSubscriber($alterOptionsEventManager);
$this->application->setDispatcher($eventDispatcher);
$this->application->setAutoExit(false);
}
function testValidFormats()
{
$formatter = new FormatterManager();
$formatter->addDefaultFormatters();
$formatter->addDefaultSimplifiers();
$commandInfo = new CommandInfo('\Consolidation\TestUtils\alpha\AlphaCommandFile', 'exampleTable');
$this->assertEquals('example:table', $commandInfo->getName());
$this->assertEquals('\Consolidation\OutputFormatters\StructuredData\RowsOfFields', $commandInfo->getReturnType());
}
function testAutomaticOptions()
{
$commandFileInstance = new \Consolidation\TestUtils\alpha\AlphaCommandFile;
$formatter = new FormatterManager();
$formatter->addDefaultFormatters();
$formatter->addDefaultSimplifiers();
$this->commandFactory->commandProcessor()->setFormatterManager($formatter);
$commandInfo = $this->commandFactory->createCommandInfo($commandFileInstance, 'exampleTable');
$command = $this->commandFactory->createCommand($commandInfo, $commandFileInstance);
$this->application->add($command);
$containsList =
[
'--format[=FORMAT] Format the result data. Available formats: csv,json,list,php,print-r,sections,string,table,tsv,var_export,xml,yaml [default: "table"]',
'--fields[=FIELDS] Available fields: I (first), II (second), III (third) [default: ""]',
];
$this->assertRunCommandViaApplicationContains('help example:table', $containsList);
}
function testCommandsAndHooks()
{
// First, search for commandfiles in the 'alpha'
// directory. Note that this same functionality
// is tested more thoroughly in isolation in
// testCommandFileDiscovery.php
$discovery = new CommandFileDiscovery();
$discovery
->setSearchPattern('*CommandFile.php')
->setIncludeFilesAtBase(false)
->setSearchLocations(['alpha']);
chdir(__DIR__);
$commandFiles = $discovery->discover('.', '\Consolidation\TestUtils');
$formatter = new FormatterManager();
$formatter->addDefaultFormatters();
$formatter->addDefaultSimplifiers();
$hookManager = new HookManager();
$terminalWidthOption = new PrepareTerminalWidthOption();
$terminalWidthOption->setApplication($this->application);
$commandProcessor = new CommandProcessor($hookManager);
$commandProcessor->setFormatterManager($formatter);
$commandProcessor->addPrepareFormatter($terminalWidthOption);
// Create a new factory, and load all of the files
// discovered above. The command factory class is
// tested in isolation in testAnnotatedCommandFactory.php,
// but this is the only place where
$factory = new AnnotatedCommandFactory();
$factory->setCommandProcessor($commandProcessor);
// $factory->addListener(...);
$factory->setIncludeAllPublicMethods(false);
$this->addDiscoveredCommands($factory, $commandFiles);
$this->assertRunCommandViaApplicationContains('list', ['example:table'], ['additional:option', 'without:annotations']);
$this->assertTrue($this->application->has('example:table'));
$this->assertFalse($this->application->has('without:annotations'));
// Fetch a reference to the 'example:table' command and test its valid format types
$exampleTableCommand = $this->application->find('example:table');
$returnType = $exampleTableCommand->getReturnType();
$this->assertEquals('\Consolidation\OutputFormatters\StructuredData\RowsOfFields', $returnType);
$validFormats = $formatter->validFormats($returnType);
$this->assertEquals('csv,json,list,php,print-r,sections,string,table,tsv,var_export,xml,yaml', implode(',', $validFormats));
// Control: run commands without hooks.
$this->assertRunCommandViaApplicationEquals('always:fail', 'This command always fails.', 13);
$this->assertRunCommandViaApplicationEquals('simulated:status', '42');
$this->assertRunCommandViaApplicationEquals('example:output', 'Hello, World.');
$this->assertRunCommandViaApplicationEquals('example:cat bet alpha --flip', 'alphabet');
$this->assertRunCommandViaApplicationEquals('example:echo a b c', "a\tb\tc");
$this->assertRunCommandViaApplicationEquals('example:message', 'Shipwrecked; send bananas.');
$this->assertRunCommandViaApplicationEquals('command:with-one-optional-argument', 'Hello, world');
$this->assertRunCommandViaApplicationEquals('command:with-one-optional-argument Joe', 'Hello, Joe');
// Add some hooks.
$factory->hookManager()->addValidator(new ExampleValidator());
$factory->hookManager()->addResultProcessor(new ExampleResultProcessor());
$factory->hookManager()->addAlterResult(new ExampleResultAlterer());
$factory->hookManager()->addStatusDeterminer(new ExampleStatusDeterminer());
$factory->hookManager()->addOutputExtractor(new ExampleOutputExtractor());
// Run the same commands as before, and confirm that results
// are different now that the hooks are in place.
$this->assertRunCommandViaApplicationEquals('simulated:status', '', 42);
$this->assertRunCommandViaApplicationEquals('example:output', 'Hello, World!');
$this->assertRunCommandViaApplicationEquals('example:cat bet alpha --flip', 'alphareplaced');
$this->assertRunCommandViaApplicationEquals('example:echo a b c', 'a,b,c');
$this->assertRunCommandViaApplicationEquals('example:message', 'Shipwrecked; send bananas.');
$expected = <<<EOT
------ ------ -------
I II III
------ ------ -------
One Two Three
Eins Zwei Drei
Ichi Ni San
Uno Dos Tres
------ ------ -------
EOT;
$this->assertRunCommandViaApplicationEquals('example:table', $expected);
$expected = <<<EOT
------- ------
III II
------- ------
Three Two
Drei Zwei
San Ni
Tres Dos
------- ------
EOT;
$this->assertRunCommandViaApplicationEquals('example:table --fields=III,II', $expected);
$expectedSingleField = <<<EOT
Two
Zwei
Ni
Dos
EOT;
// When --field is specified (instead of --fields), then the format
// is forced to 'string'.
$this->assertRunCommandViaApplicationEquals('example:table --field=II', $expectedSingleField);
// Check the help for the example table command and see if the options
// from the alter hook were added. We expect that we should not see
// any of the information from the alter hook in the 'beta' folder yet.
$this->assertRunCommandViaApplicationContains('help example:table',
[
'Option added by @hook option example:table',
'example:table --french',
'Add a row with French numbers.'
],
[
'chinese',
'kanji',
]
);
$expectedOutputWithFrench = <<<EOT
------ ------ -------
I II III
------ ------ -------
One Two Three
Eins Zwei Drei
Ichi Ni San
Uno Dos Tres
Un Deux Trois
------ ------ -------
EOT;
$this->assertRunCommandViaApplicationEquals('example:table --french', $expectedOutputWithFrench);
$expectedAssociativeListTable = <<<EOT
--------------- ----------------------------------------------------------------------------------------
SFTP Command sftp -o Port=2222 dev@appserver.dev.drush.in
Git Command git clone ssh://codeserver.dev@codeserver.dev.drush.in:2222/~/repository.git wp-update
MySQL Command mysql -u pantheon -p4b33cb -h dbserver.dev.drush.in -P 16191 pantheon
--------------- ----------------------------------------------------------------------------------------
EOT;
$this->assertRunCommandViaApplicationEquals('example:list', $expectedAssociativeListTable);
$this->assertRunCommandViaApplicationEquals('example:list --field=sftp_command', 'sftp -o Port=2222 dev@appserver.dev.drush.in');
$this->assertRunCommandViaApplicationEquals('get:serious', 'very serious');
$this->assertRunCommandViaApplicationContains('get:lost', 'Command "get:lost" is not defined.', [], 1);
$this->assertRunCommandViaApplicationContains('help example:wrap',
[
'Test word wrapping',
'[default: "table"]',
]
);
$expectedUnwrappedOutput = <<<EOT
-------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------
First Second
-------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------
This is a really long cell that contains a lot of data. When it is rendered, it should be wrapped across multiple lines. 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.
-------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------
EOT;
$this->application->setWidthAndHeight(0, 0);
$this->assertRunCommandViaApplicationEquals('example:wrap', $expectedUnwrappedOutput);
$expectedWrappedOutput = <<<EOT
------------------- --------------------
First Second
------------------- --------------------
This is a really This is the second
long cell that column of the same
contains a lot of table. It is also
data. When it is very long, and
rendered, it should be wrapped
should be wrapped across multiple
across multiple lines, just like
lines. the first column.
------------------- --------------------
EOT;
$this->application->setWidthAndHeight(42, 24);
$this->assertRunCommandViaApplicationEquals('example:wrap', $expectedWrappedOutput);
}
function testCommandsAndHooksIncludeAllPublicMethods()
{
// First, search for commandfiles in the 'alpha'
// directory. Note that this same functionality
// is tested more thoroughly in isolation in
// testCommandFileDiscovery.php
$discovery = new CommandFileDiscovery();
$discovery
->setSearchPattern('*CommandFile.php')
->setIncludeFilesAtBase(false)
->setSearchLocations(['alpha']);
chdir(__DIR__);
$commandFiles = $discovery->discover('.', '\Consolidation\TestUtils');
$formatter = new FormatterManager();
$formatter->addDefaultFormatters();
$formatter->addDefaultSimplifiers();
$hookManager = new HookManager();
$commandProcessor = new CommandProcessor($hookManager);
$commandProcessor->setFormatterManager($formatter);
// Create a new factory, and load all of the files
// discovered above. The command factory class is
// tested in isolation in testAnnotatedCommandFactory.php,
// but this is the only place where
$factory = new AnnotatedCommandFactory();
$factory->setCommandProcessor($commandProcessor);
// $factory->addListener(...);
// Now we will once again add all commands, this time including all
// public methods. The command 'withoutAnnotations' should now be found.
$factory->setIncludeAllPublicMethods(true);
$this->addDiscoveredCommands($factory, $commandFiles);
$this->assertTrue($this->application->has('without:annotations'));
$this->assertRunCommandViaApplicationContains('list', ['example:table', 'without:annotations'], ['alter:formatters']);
$this->assertRunCommandViaApplicationEquals('get:serious', 'very serious');
$this->assertRunCommandViaApplicationContains('get:lost', 'Command "get:lost" is not defined.', [], 1);
}
function testCommandsAndHooksWithBetaFolder()
{
// First, search for commandfiles in the 'alpha'
// directory. Note that this same functionality
// is tested more thoroughly in isolation in
// testCommandFileDiscovery.php
$discovery = new CommandFileDiscovery();
$discovery
->setSearchPattern('*CommandFile.php')
->setIncludeFilesAtBase(false)
->setSearchLocations(['alpha', 'beta']);
chdir(__DIR__);
$commandFiles = $discovery->discover('.', '\Consolidation\TestUtils');
$formatter = new FormatterManager();
$formatter->addDefaultFormatters();
$formatter->addDefaultSimplifiers();
$hookManager = new HookManager();
$commandProcessor = new CommandProcessor($hookManager);
$commandProcessor->setFormatterManager($formatter);
// Create a new factory, and load all of the files
// discovered above. The command factory class is
// tested in isolation in testAnnotatedCommandFactory.php,
// but this is the only place where
$factory = new AnnotatedCommandFactory();
$factory->setCommandProcessor($commandProcessor);
// $factory->addListener(...);
$factory->setIncludeAllPublicMethods(true);
$this->addDiscoveredCommands($factory, $commandFiles);
// A few asserts, to make sure that our hooks all get registered.
$allRegisteredHooks = $hookManager->getAllHooks();
$registeredHookNames = array_keys($allRegisteredHooks);
sort($registeredHookNames);
$this->assertEquals('*,example:table', implode(',', $registeredHookNames));
$allHooksForExampleTable = $allRegisteredHooks['example:table'];
$allHookPhasesForExampleTable = array_keys($allHooksForExampleTable);
sort($allHookPhasesForExampleTable);
$this->assertEquals('alter,option', implode(',', $allHookPhasesForExampleTable));
$this->assertContains('alterFormattersChinese', var_export($allHooksForExampleTable, true));
$alterHooksForExampleTable = $this->callProtected($hookManager, 'getHooks', [['example:table'], 'alter']);
$this->assertContains('alterFormattersKanji', var_export($alterHooksForExampleTable, true));
$allHooksForAnyCommand = $allRegisteredHooks['*'];
$allHookPhasesForAnyCommand = array_keys($allHooksForAnyCommand);
sort($allHookPhasesForAnyCommand);
$this->assertEquals('alter', implode(',', $allHookPhasesForAnyCommand));
$this->assertContains('alterFormattersKanji', var_export($allHooksForAnyCommand, true));
// Help should have the information from the hooks in the 'beta' folder
$this->assertRunCommandViaApplicationContains('help example:table',
[
'Option added by @hook option example:table',
'example:table --french',
'Add a row with French numbers.',
'chinese',
'kanji',
]
);
// Confirm that the "unavailable" command is now available
$this->assertTrue($this->application->has('unavailable:command'));
$expectedOutputWithChinese = <<<EOT
------ ------ -------
I II III
------ ------ -------
One Two Three
Eins Zwei Drei
Ichi Ni San
Uno Dos Tres
壹 貳 叁
------ ------ -------
EOT;
$this->assertRunCommandViaApplicationEquals('example:table --chinese', $expectedOutputWithChinese);
$expectedOutputWithKanji = <<<EOT
------ ------ -------
I II III
------ ------ -------
One Two Three
Eins Zwei Drei
Ichi Ni San
Uno Dos Tres
一 二 三
------ ------ -------
EOT;
$this->assertRunCommandViaApplicationEquals('example:table --kanji', $expectedOutputWithKanji);
}
public function addDiscoveredCommands($factory, $commandFiles) {
foreach ($commandFiles as $path => $commandClass) {
$this->assertFileExists($path);
if (!class_exists($commandClass)) {
include $path;
}
$commandInstance = new $commandClass();
$commandList = $factory->createCommandsFromClass($commandInstance);
foreach ($commandList as $command) {
$this->application->add($command);
}
}
}
function assertRunCommandViaApplicationEquals($cmd, $expectedOutput, $expectedStatusCode = 0)
{
$input = new StringInput($cmd);
$output = new BufferedOutput();
$statusCode = $this->application->run($input, $output);
$commandOutput = trim($output->fetch());
$expectedOutput = $this->simplifyWhitespace($expectedOutput);
$commandOutput = $this->simplifyWhitespace($commandOutput);
$this->assertEquals($expectedOutput, $commandOutput);
$this->assertEquals($expectedStatusCode, $statusCode);
}
function assertRunCommandViaApplicationContains($cmd, $containsList, $doesNotContainList = [], $expectedStatusCode = 0)
{
$input = new StringInput($cmd);
$output = new BufferedOutput();
$containsList = (array) $containsList;
$statusCode = $this->application->run($input, $output);
$commandOutput = trim($output->fetch());
$commandOutput = $this->simplifyWhitespace($commandOutput);
foreach ($containsList as $expectedToContain) {
$this->assertContains($this->simplifyWhitespace($expectedToContain), $commandOutput);
}
foreach ($doesNotContainList as $expectedToNotContain) {
$this->assertNotContains($this->simplifyWhitespace($expectedToNotContain), $commandOutput);
}
$this->assertEquals($expectedStatusCode, $statusCode);
}
function simplifyWhitespace($data)
{
return trim(preg_replace('#[ \t]+$#m', '', $data));
}
function callProtected($object, $method, $args = [])
{
$r = new \ReflectionMethod($object, $method);
$r->setAccessible(true);
return $r->invokeArgs($object, $args);
}
}
class ExampleValidator implements ValidatorInterface
{
public function validate(CommandData $commandData)
{
$args = $commandData->arguments();
if (isset($args['one']) && ($args['one'] == 'bet')) {
$commandData->input()->setArgument('one', 'replaced');
return $args;
}
}
}
class ExampleResultProcessor implements ProcessResultInterface
{
public function process($result, CommandData $commandData)
{
if (is_array($result) && array_key_exists('item-list', $result)) {
return implode(',', $result['item-list']);
}
}
}
class ExampleResultAlterer implements AlterResultInterface
{
public function process($result, CommandData $commandData)
{
if (is_string($result) && ($result == 'Hello, World.')) {
return 'Hello, World!';
}
}
}
class ExampleStatusDeterminer implements StatusDeterminerInterface
{
public function determineStatusCode($result)
{
if (is_array($result) && array_key_exists('status-code', $result)) {
return $result['status-code'];
}
}
}
class ExampleOutputExtractor implements ExtractOutputInterface
{
public function extractOutput($result)
{
if (is_array($result) && array_key_exists('message', $result)) {
return $result['message'];
}
}
}