X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=vendor%2Fconsolidation%2Fannotated-command%2Ftests%2FtestAnnotatedCommandFactory.php;fp=vendor%2Fconsolidation%2Fannotated-command%2Ftests%2FtestAnnotatedCommandFactory.php;h=fa91517c267036f0443a0b74a73266acba438b28;hp=0000000000000000000000000000000000000000;hb=a2bd1bf0c2c1f1a17d188f4dc0726a45494cefae;hpb=57c063afa3f66b07c4bbddc2d6129a96d90f0aad diff --git a/vendor/consolidation/annotated-command/tests/testAnnotatedCommandFactory.php b/vendor/consolidation/annotated-command/tests/testAnnotatedCommandFactory.php new file mode 100644 index 000000000..fa91517c2 --- /dev/null +++ b/vendor/consolidation/annotated-command/tests/testAnnotatedCommandFactory.php @@ -0,0 +1,859 @@ +commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile; + $this->commandFactory = new AnnotatedCommandFactory(); + $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'defaultOptionOne'); + + $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance); + $this->assertEquals('default:option-one', $command->getName()); + $this->assertEquals('default:option-one [--foo [FOO]]', $command->getSynopsis()); + + $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command); + + $input = new StringInput('default:option-one'); + $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is 1'); + + $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'defaultOptionTwo'); + + $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance); + + $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance); + $this->assertEquals('default:option-two', $command->getName()); + $this->assertEquals('default:option-two [--foo [FOO]]', $command->getSynopsis()); + + $input = new StringInput('default:option-two'); + $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is 2'); + + $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'defaultOptionNone'); + + $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance); + + $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance); + $this->assertEquals('default:option-none', $command->getName()); + $this->assertEquals('default:option-none [--foo FOO]', $command->getSynopsis()); + + // Skip failing test until Symfony is fixed. + $this->markTestSkipped('Symfony Console 3.2.5 and 3.2.6 do not handle default options with required values correctly.'); + + $input = new StringInput('default:option-none --foo'); + $this->assertRunCommandViaApplicationContains($command, $input, ['The "--foo" option requires a value.'], 1); + } + + /** + * Test CommandInfo command caching. + * + * Sequence: + * - Create all of the command info objects from one class, caching them. + * - Change the method name of one of the items in the cache to a non-existent method + * - Restore all of the cached commandinfo objects + * - Ensure that the non-existent method cached commandinfo was not created + * - Ensure that the now-missing cached commandinfo was still created + * + * This tests both save/restore, plus adding a new command method to + * a class, and removing a command method from a class. + */ + function testAnnotatedCommandCache() + { + $testCacheStore = new \Consolidation\TestUtils\InMemoryCacheStore(); + + $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile; + $this->commandFactory = new AnnotatedCommandFactory(); + $this->commandFactory->setDataStore($testCacheStore); + + // Make commandInfo objects for every command in the test commandfile. + // These will also be stored in our cache. + $commandInfoList = $this->commandFactory->getCommandInfoListFromClass($this->commandFileInstance); + + $cachedClassName = get_class($this->commandFileInstance); + + $this->assertTrue($testCacheStore->has($cachedClassName)); + + $cachedData = $testCacheStore->get($cachedClassName); + $this->assertFalse(empty($cachedData)); + $this->assertTrue(array_key_exists('testArithmatic', $cachedData)); + + $alterCommandInfoCache = $cachedData['testArithmatic']; + unset($cachedData['testArithmatic']); + $alterCommandInfoCache['method_name'] = 'nonExistentMethod'; + $cachedData[$alterCommandInfoCache['method_name']] = $alterCommandInfoCache; + + $testCacheStore->set($cachedClassName, $cachedData); + + $restoredCommandInfoList = $this->commandFactory->getCommandInfoListFromClass($this->commandFileInstance); + + $rebuiltCachedData = $testCacheStore->get($cachedClassName); + + $this->assertFalse(empty($rebuiltCachedData)); + $this->assertTrue(array_key_exists('testArithmatic', $rebuiltCachedData)); + $this->assertFalse(array_key_exists('nonExistentMethod', $rebuiltCachedData)); + } + + /** + * 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] [--unused [UNUSED]] [--] []', $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] [--] []', $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 testJoinCommandHelp() + { + $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile; + $this->commandFactory = new AnnotatedCommandFactory(); + $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'myJoin'); + + $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance); + + $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command); + $this->assertEquals('my:join', $command->getName()); + $this->assertEquals('This is the my:join command', $command->getDescription()); + $this->assertEquals("This command will join its parameters together. It can also reverse and repeat its arguments.", $command->getHelp()); + $this->assertEquals('my:join [--flip] [--repeat [REPEAT]] [--] []...', $command->getSynopsis()); + + // Bug in parser: @usage with no parameters or options not passed to us correctly. + $actualUsages = implode(',', $command->getUsages()); + if ($actualUsages == 'my:join a b,my:join Example with no parameters or options') { + $this->markTestSkipped(); + } + $this->assertEquals('my:join a b,my:join', $actualUsages); + + $input = new StringInput('my:join bet alpha --flip --repeat=2'); + $this->assertRunCommandViaApplicationEquals($command, $input, 'alphabetalphabet'); + } + + 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 []', $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'); + + $input = new StringInput('help command:with-no-options something'); + $this->assertRunCommandViaApplicationContains( + $command, + $input, + [ + 'The first parameter.', + 'The other parameter.', + ] + ); + } + + 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 testRequiredArrayOption() + { + $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile; + $this->commandFactory = new AnnotatedCommandFactory(); + $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testRequiredArrayOption'); + + $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance); + $this->assertEquals('test:required-array-option [-a|--arr ARR]', $command->getSynopsis()); + + $input = new StringInput('test:required-array-option --arr=1 --arr=2 --arr=3'); + $this->assertRunCommandViaApplicationEquals($command, $input, '1 2 3'); + + $input = new StringInput('test:required-array-option -a 1 -a 2 -a 3'); + $this->assertRunCommandViaApplicationEquals($command, $input, '1 2 3'); + } + + function testArrayOption() + { + $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile; + $this->commandFactory = new AnnotatedCommandFactory(); + $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testArrayOption'); + + $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance); + $this->assertEquals('test:array-option [-a|--arr [ARR]]', $command->getSynopsis()); + + $input = new StringInput('test:array-option'); + $this->assertRunCommandViaApplicationEquals($command, $input, '1 2 3'); + + $input = new StringInput('test:array-option --arr=a --arr=b --arr=c'); + $this->assertRunCommandViaApplicationEquals($command, $input, 'a b c'); + + $input = new StringInput('test:array-option -a a'); + $this->assertRunCommandViaApplicationEquals($command, $input, 'a'); + } + + 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]>'); + + $input = new StringInput('list --raw'); + $this->assertRunCommandViaApplicationContains($command, $input, ['This command wraps its parameter in []; its alter hook then wraps the result in .']); + } + + function testReplaceCommandHook(){ + $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile(); + $this->commandFactory = new AnnotatedCommandFactory(); + + $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestReplaceCommandHook'); + + $this->assertTrue($hookInfo->hasAnnotation('hook')); + $this->assertEquals('replace-command test:replace-command', $hookInfo->getAnnotation('hook')); + + $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance); + + $hookCallback = $this->commandFactory->hookManager()->get('test:replace-command', [HookManager::REPLACE_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('hookTestReplaceCommandHook', $hookCallback[0][1]); + + $input = new StringInput('test:replace-command foo'); + $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testReplaceCommand'); + $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance); + $this->assertRunCommandViaApplicationEquals($command, $input, "bar", 0); + } + + 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 testDoubleDashWithVersion() + { + $this->commandFileInstance = new \Consolidation\TestUtils\ExampleHookAllCommandFile(); + $this->commandFactory = new AnnotatedCommandFactory(); + $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'doCat'); + $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance); + + $input = new ArgvInput(['placeholder', 'do:cat', 'one', '--', '--version']); + list($statusCode, $commandOutput) = $this->runCommandViaApplication($command, $input); + + if ($commandOutput == 'TestApplication version 0.0.0') { + $this->markTestSkipped('Symfony/Console 2.x does not respect -- with --version'); + } + $this->assertEquals('one--version', $commandOutput); + } + + 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,_path,_classname', 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 assertRunCommandViaApplicationContains($command, $input, $containsList, $expectedStatusCode = 0) + { + list($statusCode, $commandOutput) = $this->runCommandViaApplication($command, $input); + + foreach ($containsList as $contains) { + $this->assertContains($contains, $commandOutput); + } + $this->assertEquals($expectedStatusCode, $statusCode); + } + + function assertRunCommandViaApplicationEquals($command, $input, $expectedOutput, $expectedStatusCode = 0) + { + list($statusCode, $commandOutput) = $this->runCommandViaApplication($command, $input); + + $this->assertEquals($expectedOutput, $commandOutput); + $this->assertEquals($expectedStatusCode, $statusCode); + } + + function runCommandViaApplication($command, $input) + { + $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()); + + return [$statusCode, $commandOutput]; + } +}