Security update for Core, with self-updated composer
[yaffs-website] / vendor / consolidation / annotated-command / tests / testAnnotatedCommandFactory.php
1 <?php
2 namespace Consolidation\AnnotatedCommand;
3
4 use Consolidation\AnnotatedCommand\AnnotationData;
5 use Consolidation\AnnotatedCommand\CommandData;
6 use Consolidation\AnnotatedCommand\Hooks\HookManager;
7 use Consolidation\AnnotatedCommand\Options\AlterOptionsCommandEvent;
8 use Consolidation\AnnotatedCommand\Parser\CommandInfo;
9 use Consolidation\TestUtils\ExampleCommandInfoAlterer;
10 use Symfony\Component\Console\Application;
11 use Symfony\Component\Console\Command\Command;
12 use Symfony\Component\Console\Input\InputInterface;
13 use Symfony\Component\Console\Input\ArgvInput;
14 use Symfony\Component\Console\Input\StringInput;
15 use Symfony\Component\Console\Output\BufferedOutput;
16 use Symfony\Component\Console\Output\OutputInterface;
17
18 class AnnotatedCommandFactoryTests extends \PHPUnit_Framework_TestCase
19 {
20     protected $commandFileInstance;
21     protected $commandFactory;
22
23     function testFibonacci()
24     {
25         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
26         $this->commandFactory = new AnnotatedCommandFactory();
27         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'fibonacci');
28
29         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
30         $this->assertEquals('fibonacci', $command->getName());
31         $this->assertEquals('fibonacci [--graphic] [--] <start> <steps>', $command->getSynopsis());
32         $this->assertEquals('Calculate the fibonacci sequence between two numbers.', $command->getDescription());
33         $this->assertEquals("Graphic output will look like
34 +----+---+-------------+
35 |    |   |             |
36 |    |-+-|             |
37 |----+-+-+             |
38 |        |             |
39 |        |             |
40 |        |             |
41 +--------+-------------+", $command->getHelp());
42
43         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
44
45         $input = new StringInput('help fibonacci');
46         $this->assertRunCommandViaApplicationContains($command, $input, ['Display the sequence graphically using cube representation']);
47     }
48
49     function testSniff()
50     {
51         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
52         $this->commandFactory = new AnnotatedCommandFactory();
53         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'sniff');
54
55         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
56         $this->assertEquals('sniff', $command->getName());
57         $this->assertEquals('sniff [--autofix] [--strict] [--] [<file>]', $command->getSynopsis());
58
59         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
60
61         $input = new StringInput('help sniff');
62         $this->assertRunCommandViaApplicationContains($command, $input, ['A file or directory to analyze.']);
63
64         $input = new StringInput('sniff --autofix --strict -- foo');
65         $this->assertRunCommandViaApplicationContains($command, $input, ["'autofix' => true",
66         "'strict' => true"]);
67     }
68
69     function testOptionDefaultValue()
70     {
71         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
72         $this->commandFactory = new AnnotatedCommandFactory();
73         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'defaultOptionOne');
74
75         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
76         $this->assertEquals('default:option-one', $command->getName());
77         $this->assertEquals('default:option-one [--foo [FOO]]', $command->getSynopsis());
78
79         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
80
81         $input = new StringInput('default:option-one');
82         $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is 1');
83
84         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'defaultOptionTwo');
85
86         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
87
88         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
89         $this->assertEquals('default:option-two', $command->getName());
90         $this->assertEquals('default:option-two [--foo [FOO]]', $command->getSynopsis());
91
92         $input = new StringInput('default:option-two');
93         $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is 2');
94
95         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'defaultOptionNone');
96
97         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
98
99         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
100         $this->assertEquals('default:option-none', $command->getName());
101         $this->assertEquals('default:option-none [--foo FOO]', $command->getSynopsis());
102
103         // Skip failing test until Symfony is fixed.
104         $this->markTestSkipped('Symfony Console 3.2.5 and 3.2.6 do not handle default options with required values correctly.');
105
106         $input = new StringInput('default:option-none --foo');
107         $this->assertRunCommandViaApplicationContains($command, $input, ['The "--foo" option requires a value.'], 1);
108     }
109
110     function testGlobalOptionsOnly()
111     {
112         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
113         $this->commandFactory = new AnnotatedCommandFactory();
114         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'globalOptionsOnly');
115
116         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
117
118         $input = new StringInput('global-options-only test');
119         $this->assertRunCommandViaApplicationEquals($command, $input, "Arg is test, options[help] is false");
120     }
121
122     function testOptionWithOptionalValue()
123     {
124         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
125         $this->commandFactory = new AnnotatedCommandFactory();
126
127         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'defaultOptionalValue');
128
129         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
130
131         // Test to see if we can differentiate between a missing option, and
132         // an option that has no value at all.
133         $input = new StringInput('default:optional-value --foo=bar');
134         $this->assertRunCommandViaApplicationEquals($command, $input, "Foo is 'bar'");
135
136         $input = new StringInput('default:optional-value --foo');
137         $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is true');
138
139         $input = new StringInput('default:optional-value');
140         $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is NULL');
141     }
142
143     function testOptionThatDefaultsToTrue()
144     {
145         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
146         $this->commandFactory = new AnnotatedCommandFactory();
147
148         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'defaultOptionDefaultsToTrue');
149
150         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
151
152         // Test to see if we can differentiate between a missing option, and
153         // an option that has no value at all.
154         $input = new StringInput('default:option-defaults-to-true --foo=bar');
155         $this->assertRunCommandViaApplicationEquals($command, $input, "Foo is 'bar'");
156
157         $input = new StringInput('default:option-defaults-to-true --foo');
158         $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is true');
159
160         $input = new StringInput('default:option-defaults-to-true');
161         $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is true');
162
163         $input = new StringInput('help default:option-defaults-to-true');
164         $this->assertRunCommandViaApplicationContains(
165             $command,
166             $input,
167             [
168                 '--no-foo',
169                 'Negate --foo option',
170             ]
171         );
172         $input = new ArgvInput(['cli.php', 'default:option-defaults-to-true', '--no-foo']);
173         $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is false');
174
175         // Do all of those things again, but with ArgvInput
176         $input = new ArgvInput(['cli.php', 'default:option-defaults-to-true', '--foo=bar']);
177         $this->assertRunCommandViaApplicationEquals($command, $input, "Foo is 'bar'");
178
179         $input = new ArgvInput(['cli.php', 'default:option-defaults-to-true', '--foo']);
180         $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is true');
181
182         $input = new ArgvInput(['cli.php', 'default:option-defaults-to-true']);
183         $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is true');
184
185         $input = new ArgvInput(['cli.php', 'default:option-defaults-to-true', '--no-foo']);
186         $this->assertRunCommandViaApplicationEquals($command, $input, 'Foo is false');
187     }
188     /**
189      * Test CommandInfo command caching.
190      *
191      * Sequence:
192      *  - Create all of the command info objects from one class, caching them.
193      *  - Change the method name of one of the items in the cache to a non-existent method
194      *  - Restore all of the cached commandinfo objects
195      *  - Ensure that the non-existent method cached commandinfo was not created
196      *  - Ensure that the now-missing cached commandinfo was still created
197      *
198      * This tests both save/restore, plus adding a new command method to
199      * a class, and removing a command method from a class.
200      */
201     function testAnnotatedCommandCache()
202     {
203         $testCacheStore = new \Consolidation\TestUtils\InMemoryCacheStore();
204
205         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
206         $this->commandFactory = new AnnotatedCommandFactory();
207         $this->commandFactory->setDataStore($testCacheStore);
208
209         // Make commandInfo objects for every command in the test commandfile.
210         // These will also be stored in our cache.
211         $commandInfoList = $this->commandFactory->getCommandInfoListFromClass($this->commandFileInstance);
212
213         $cachedClassName = get_class($this->commandFileInstance);
214
215         $this->assertTrue($testCacheStore->has($cachedClassName));
216
217         $cachedData = $testCacheStore->get($cachedClassName);
218         $this->assertFalse(empty($cachedData));
219         $this->assertTrue(array_key_exists('testArithmatic', $cachedData));
220
221         $alterCommandInfoCache = $cachedData['testArithmatic'];
222         unset($cachedData['testArithmatic']);
223         $alterCommandInfoCache['method_name'] = 'nonExistentMethod';
224         $cachedData[$alterCommandInfoCache['method_name']] = $alterCommandInfoCache;
225
226         $testCacheStore->set($cachedClassName, $cachedData);
227
228         $restoredCommandInfoList = $this->commandFactory->getCommandInfoListFromClass($this->commandFileInstance);
229
230         $rebuiltCachedData = $testCacheStore->get($cachedClassName);
231
232         $this->assertFalse(empty($rebuiltCachedData));
233         $this->assertTrue(array_key_exists('testArithmatic', $rebuiltCachedData));
234         $this->assertFalse(array_key_exists('nonExistentMethod', $rebuiltCachedData));
235     }
236
237     /**
238      * Test CommandInfo command annotation parsing.
239      */
240     function testAnnotatedCommandCreation()
241     {
242         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
243         $this->commandFactory = new AnnotatedCommandFactory();
244         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testArithmatic');
245
246         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
247
248         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
249         $this->assertEquals('test:arithmatic', $command->getName());
250         $this->assertEquals('This is the test:arithmatic command', $command->getDescription());
251         $this->assertEquals("This command will add one and two. If the --negate flag\nis provided, then the result is negated.", $command->getHelp());
252         $this->assertEquals('arithmatic', implode(',', $command->getAliases()));
253         $this->assertEquals('test:arithmatic [--negate] [--unused [UNUSED]] [--] <one> [<two>]', $command->getSynopsis());
254         $this->assertEquals('test:arithmatic 2 2 --negate', implode(',', $command->getUsages()));
255
256         $input = new StringInput('arithmatic 2 3 --negate');
257         $this->assertRunCommandViaApplicationEquals($command, $input, '-5');
258     }
259
260     /**
261      * Test CommandInfo command annotation altering.
262      */
263     function testAnnotatedCommandInfoAlteration()
264     {
265         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
266         $this->commandFactory = new AnnotatedCommandFactory();
267         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'myCat');
268
269         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
270
271         $annotationData = $command->getAnnotationData();
272         $this->assertTrue($annotationData->has('arbitrary'));
273         $this->assertFalse($annotationData->has('dynamic'));
274
275         $this->commandFactory->addCommandInfoAlterer(new ExampleCommandInfoAlterer());
276
277         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
278
279         $annotationData = $command->getAnnotationData();
280         $this->assertTrue($annotationData->has('arbitrary'));
281         $this->assertTrue($annotationData->has('dynamic'));
282     }
283
284     function testMyCatCommand()
285     {
286         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
287         $this->commandFactory = new AnnotatedCommandFactory();
288         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'myCat');
289
290         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
291
292         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
293         $this->assertEquals('my:cat', $command->getName());
294         $this->assertEquals('This is the my:cat command', $command->getDescription());
295         $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());
296         $this->assertEquals('c', implode(',', $command->getAliases()));
297         $this->assertEquals('my:cat [--flip] [--] <one> [<two>]', $command->getSynopsis());
298         $this->assertEquals('my:cat bet alpha --flip', implode(',', $command->getUsages()));
299
300         $input = new StringInput('my:cat bet alpha --flip');
301         $this->assertRunCommandViaApplicationEquals($command, $input, 'alphabet');
302     }
303
304     function testJoinCommandHelp()
305     {
306         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
307         $this->commandFactory = new AnnotatedCommandFactory();
308         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'myJoin');
309
310         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
311
312         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
313         $this->assertEquals('my:join', $command->getName());
314         $this->assertEquals('This is the my:join command', $command->getDescription());
315         $this->assertEquals("This command will join its parameters together. It can also reverse and repeat its arguments.", $command->getHelp());
316         $this->assertEquals('my:join [--flip] [--repeat [REPEAT]] [--] [<args>]...', $command->getSynopsis());
317
318         // TODO: Extra whitespace character if there are no options et. al. in the
319         // usage. This is uncommon, and the defect is invisible. Maybe find it someday.
320         $actualUsages = implode(',', $command->getUsages());
321         $this->assertEquals('my:join a b,my:join ', $actualUsages);
322
323         $input = new StringInput('my:join bet alpha --flip --repeat=2');
324         $this->assertRunCommandViaApplicationEquals($command, $input, 'alphabetalphabet');
325     }
326
327     function testDefaultsCommand()
328     {
329         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
330         $this->commandFactory = new AnnotatedCommandFactory();
331         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'defaults');
332
333         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
334
335         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
336         $this->assertEquals('defaults', $command->getName());
337         $this->assertEquals('Test default values in arguments', $command->getDescription());
338
339         $input = new StringInput('defaults');
340         $this->assertRunCommandViaApplicationEquals($command, $input, 'nothing provided');
341
342         $input = new StringInput('defaults ichi');
343         $this->assertRunCommandViaApplicationEquals($command, $input, 'only ichi');
344
345         $input = new StringInput('defaults I II');
346         $this->assertRunCommandViaApplicationEquals($command, $input, 'I and II');
347     }
348
349     function testCommandWithNoOptions()
350     {
351         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
352         $this->commandFactory = new AnnotatedCommandFactory();
353         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'commandWithNoOptions');
354
355         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
356
357         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
358         $this->assertEquals('command:with-no-options', $command->getName());
359         $this->assertEquals('This is a command with no options', $command->getDescription());
360         $this->assertEquals("This command will concatenate two parameters.", $command->getHelp());
361         $this->assertEquals('nope', implode(',', $command->getAliases()));
362         $this->assertEquals('command:with-no-options <one> [<two>]', $command->getSynopsis());
363         $this->assertEquals('command:with-no-options alpha bet', implode(',', $command->getUsages()));
364
365         $input = new StringInput('command:with-no-options something');
366         $this->assertRunCommandViaApplicationEquals($command, $input, 'somethingdefault');
367
368         $input = new StringInput('help command:with-no-options something');
369         $this->assertRunCommandViaApplicationContains(
370             $command,
371             $input,
372             [
373                 'The first parameter.',
374                 'The other parameter.',
375             ]
376         );
377     }
378
379     function testCommandWithIOParameters()
380     {
381         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
382         $this->commandFactory = new AnnotatedCommandFactory();
383         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'commandWithIOParameters');
384
385         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
386
387         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
388         $this->assertEquals('command:with-io-parameters', $command->getName());
389         $this->assertEquals("This command work with app's input and output", $command->getDescription());
390         $this->assertEquals('', $command->getHelp());
391         $this->assertEquals('command:with-io-parameters', $command->getSynopsis());
392
393         $input = new StringInput('command:with-io-parameters');
394         $this->assertRunCommandViaApplicationEquals($command, $input, 'command:with-io-parameters');
395     }
396
397     function testCommandWithNoArguments()
398     {
399         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
400         $this->commandFactory = new AnnotatedCommandFactory();
401         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'commandWithNoArguments');
402
403         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
404
405         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
406         $this->assertEquals('command:with-no-arguments', $command->getName());
407         $this->assertEquals('This command has no arguments--only options', $command->getDescription());
408         $this->assertEquals("Return a result only if not silent.", $command->getHelp());
409         $this->assertEquals('command:with-no-arguments [-s|--silent]', $command->getSynopsis());
410
411         $input = new StringInput('command:with-no-arguments');
412         $this->assertRunCommandViaApplicationEquals($command, $input, 'Hello, world');
413         $input = new StringInput('command:with-no-arguments -s');
414         $this->assertRunCommandViaApplicationEquals($command, $input, '');
415         $input = new StringInput('command:with-no-arguments --silent');
416         $this->assertRunCommandViaApplicationEquals($command, $input, '');
417     }
418
419     function testCommandWithShortcutOnAnnotation()
420     {
421         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
422         $this->commandFactory = new AnnotatedCommandFactory();
423         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'shortcutOnAnnotation');
424
425         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
426
427         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
428         $this->assertEquals('shortcut:on-annotation', $command->getName());
429         $this->assertEquals('Shortcut on annotation', $command->getDescription());
430         $this->assertEquals("This command defines the option shortcut on the annotation instead of in the options array.", $command->getHelp());
431         $this->assertEquals('shortcut:on-annotation [-s|--silent]', $command->getSynopsis());
432
433         $input = new StringInput('shortcut:on-annotation');
434         $this->assertRunCommandViaApplicationEquals($command, $input, 'Hello, world');
435         $input = new StringInput('shortcut:on-annotation -s');
436         $this->assertRunCommandViaApplicationEquals($command, $input, '');
437         $input = new StringInput('shortcut:on-annotation --silent');
438         $this->assertRunCommandViaApplicationEquals($command, $input, '');
439     }
440
441     function testState()
442     {
443         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile('secret secret');
444         $this->commandFactory = new AnnotatedCommandFactory();
445         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testState');
446
447         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
448
449         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
450         $this->assertEquals('test:state', $command->getName());
451
452         $input = new StringInput('test:state');
453         $this->assertRunCommandViaApplicationEquals($command, $input, 'secret secret');
454     }
455
456     function testPassthroughArray()
457     {
458         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
459         $this->commandFactory = new AnnotatedCommandFactory();
460         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testPassthrough');
461
462         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
463
464         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
465         $this->assertEquals('test:passthrough', $command->getName());
466
467         $input = new StringInput('test:passthrough a b c -- x y z');
468         $this->assertRunCommandViaApplicationEquals($command, $input, 'a,b,c,x,y,z');
469     }
470
471     function testPassThroughNonArray()
472     {
473         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
474         $this->commandFactory = new AnnotatedCommandFactory();
475         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'myJoin');
476
477         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
478
479         $input = new StringInput('my:join bet --flip -- x y z');
480         $this->assertRunCommandViaApplicationEquals($command, $input, 'zyxbet');
481         // Can't look at 'hasOption' until after the command initializes the
482         // option, because Symfony.
483         $this->assertTrue($input->hasOption('flip'));
484     }
485
486     function testPassThroughWithInputManipulation()
487     {
488         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
489         $this->commandFactory = new AnnotatedCommandFactory();
490         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'myJoin');
491
492         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
493
494         $input = new StringInput('my:join bet --repeat=2 -- x y z');
495         $this->assertRunCommandViaApplicationEquals($command, $input, 'betxyzbetxyz');
496         // Symfony does not allow us to manipulate the options via setOption until
497         // the definition from the command object has been set up.
498         $input->setOption('repeat', 3);
499         $this->assertEquals(3, $input->getOption('repeat'));
500         $input->setArgument(0, 'q');
501         // Manipulating $input does not work -- the changes are not effective.
502         // The end result here should be 'qx y yqx y yqx y y'
503         $this->assertRunCommandViaApplicationEquals($command, $input, 'betxyzbetxyz');
504     }
505
506     function testRequiredArrayOption()
507     {
508         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
509         $this->commandFactory = new AnnotatedCommandFactory();
510         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testRequiredArrayOption');
511
512         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
513         $this->assertEquals('test:required-array-option [-a|--arr ARR]', $command->getSynopsis());
514
515         $input = new StringInput('test:required-array-option --arr=1 --arr=2 --arr=3');
516         $this->assertRunCommandViaApplicationEquals($command, $input, '1 2 3');
517
518         $input = new StringInput('test:required-array-option -a 1 -a 2 -a 3');
519         $this->assertRunCommandViaApplicationEquals($command, $input, '1 2 3');
520     }
521
522     function testArrayOption()
523     {
524         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile;
525         $this->commandFactory = new AnnotatedCommandFactory();
526         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testArrayOption');
527
528         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
529         $this->assertEquals('test:array-option [-a|--arr [ARR]]', $command->getSynopsis());
530
531         $input = new StringInput('test:array-option');
532         $this->assertRunCommandViaApplicationEquals($command, $input, '1 2 3');
533
534         $input = new StringInput('test:array-option --arr=a --arr=b --arr=c');
535         $this->assertRunCommandViaApplicationEquals($command, $input, 'a b c');
536
537         $input = new StringInput('test:array-option -a a');
538         $this->assertRunCommandViaApplicationEquals($command, $input, 'a');
539     }
540
541     function testHookedCommand()
542     {
543         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
544         $this->commandFactory = new AnnotatedCommandFactory();
545
546         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestHook');
547
548         $this->assertTrue($hookInfo->hasAnnotation('hook'));
549         $this->assertEquals('alter test:hook', $hookInfo->getAnnotation('hook'));
550
551         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
552
553         $hookCallback = $this->commandFactory->hookManager()->get('test:hook', [HookManager::ALTER_RESULT]);
554         $this->assertTrue($hookCallback != null);
555         $this->assertEquals(1, count($hookCallback));
556         $this->assertEquals(2, count($hookCallback[0]));
557         $this->assertTrue(is_callable($hookCallback[0]));
558         $this->assertEquals('hookTestHook', $hookCallback[0][1]);
559
560         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testHook');
561         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
562
563         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
564         $this->assertEquals('test:hook', $command->getName());
565
566         $input = new StringInput('test:hook bar');
567         $this->assertRunCommandViaApplicationEquals($command, $input, '<[bar]>');
568
569         $input = new StringInput('list --raw');
570         $this->assertRunCommandViaApplicationContains($command, $input, ['This command wraps its parameter in []; its alter hook then wraps the result in .']);
571     }
572
573     function testReplaceCommandHook(){
574         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
575         $this->commandFactory = new AnnotatedCommandFactory();
576
577         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestReplaceCommandHook');
578
579         $this->assertTrue($hookInfo->hasAnnotation('hook'));
580         $this->assertEquals('replace-command test:replace-command', $hookInfo->getAnnotation('hook'));
581
582         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
583
584         $hookCallback = $this->commandFactory->hookManager()->get('test:replace-command', [HookManager::REPLACE_COMMAND_HOOK]);
585         $this->assertTrue($hookCallback != null);
586         $this->assertEquals(1, count($hookCallback));
587         $this->assertEquals(2, count($hookCallback[0]));
588         $this->assertTrue(is_callable($hookCallback[0]));
589         $this->assertEquals('hookTestReplaceCommandHook', $hookCallback[0][1]);
590
591         $input = new StringInput('test:replace-command foo');
592         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testReplaceCommand');
593         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
594         $this->assertRunCommandViaApplicationEquals($command, $input, "bar", 0);
595     }
596
597     function testPostCommandCalledAfterCommand()
598     {
599         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
600         $this->commandFactory = new AnnotatedCommandFactory();
601
602         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestPostCommandHook');
603
604         $this->assertTrue($hookInfo->hasAnnotation('hook'));
605         $this->assertEquals('post-command test:post-command', $hookInfo->getAnnotation('hook'));
606
607         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
608
609         $hookCallback = $this->commandFactory->hookManager()->get('test:post-command', [HookManager::POST_COMMAND_HOOK]);
610         $this->assertTrue($hookCallback != null);
611         $this->assertEquals(1, count($hookCallback));
612         $this->assertEquals(2, count($hookCallback[0]));
613         $this->assertTrue(is_callable($hookCallback[0]));
614         $this->assertEquals('hookTestPostCommandHook', $hookCallback[0][1]);
615
616         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestPreCommandHook');
617
618         $this->assertTrue($hookInfo->hasAnnotation('hook'));
619         $this->assertEquals('pre-command test:post-command', $hookInfo->getAnnotation('hook'));
620
621         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
622
623         $hookCallback = $this->commandFactory->hookManager()->get('test:post-command', [HookManager::PRE_COMMAND_HOOK]);
624         $this->assertTrue($hookCallback != null);
625         $this->assertEquals(1, count($hookCallback));
626         $this->assertEquals(2, count($hookCallback[0]));
627         $this->assertTrue(is_callable($hookCallback[0]));
628         $this->assertEquals('hookTestPreCommandHook', $hookCallback[0][1]);
629
630         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testPostCommand');
631         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
632
633         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
634         $this->assertEquals('test:post-command', $command->getName());
635
636         $input = new StringInput('test:post-command bar');
637         $this->assertRunCommandViaApplicationEquals($command, $input, "foo\nbar\nbaz", 0, $this->commandFileInstance);
638     }
639
640     function testHookAllCommands()
641     {
642         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleHookAllCommandFile();
643         $this->commandFactory = new AnnotatedCommandFactory();
644
645         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'alterAllCommands');
646
647         $this->assertTrue($hookInfo->hasAnnotation('hook'));
648         $this->assertEquals('alter', $hookInfo->getAnnotation('hook'));
649
650         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
651
652         $hookCallback = $this->commandFactory->hookManager()->get('Consolidation\TestUtils\ExampleHookAllCommandFile', [HookManager::ALTER_RESULT]);
653         $this->assertTrue($hookCallback != null);
654         $this->assertEquals(1, count($hookCallback));
655         $this->assertEquals(2, count($hookCallback[0]));
656         $this->assertTrue(is_callable($hookCallback[0]));
657         $this->assertEquals('alterAllCommands', $hookCallback[0][1]);
658
659         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'doCat');
660         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
661
662         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
663         $this->assertEquals('do:cat', $command->getName());
664
665         $input = new StringInput('do:cat bar');
666         $this->assertRunCommandViaApplicationEquals($command, $input, '*** bar ***');
667     }
668
669     function testDoubleDashWithVersion()
670     {
671         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleHookAllCommandFile();
672         $this->commandFactory = new AnnotatedCommandFactory();
673         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'doCat');
674         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
675
676         $input = new ArgvInput(['placeholder', 'do:cat', 'one', '--', '--version']);
677         list($statusCode, $commandOutput) = $this->runCommandViaApplication($command, $input);
678
679         if ($commandOutput == 'TestApplication version 0.0.0') {
680             $this->markTestSkipped('Symfony/Console 2.x does not respect -- with --version');
681         }
682         $this->assertEquals('one--version', $commandOutput);
683     }
684
685     function testAnnotatedHookedCommand()
686     {
687         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
688         $this->commandFactory = new AnnotatedCommandFactory();
689
690         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestAnnotatedHook');
691
692         $this->assertTrue($hookInfo->hasAnnotation('hook'));
693         $this->assertEquals('alter @hookme', $hookInfo->getAnnotation('hook'));
694
695         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
696         $hookCallback = $this->commandFactory->hookManager()->get('@hookme', [HookManager::ALTER_RESULT]);
697         $this->assertTrue($hookCallback != null);
698         $this->assertEquals(1, count($hookCallback));
699         $this->assertEquals(2, count($hookCallback[0]));
700         $this->assertTrue(is_callable($hookCallback[0]));
701         $this->assertEquals('hookTestAnnotatedHook', $hookCallback[0][1]);
702
703         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testAnnotationHook');
704         $annotationData = $commandInfo->getRawAnnotations();
705         $this->assertEquals('hookme,before,after', implode(',', $annotationData->keys()));
706         $this->assertEquals('@hookme,@before,@after', implode(',', array_map(function ($item) { return "@$item"; }, $annotationData->keys())));
707
708         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
709
710         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
711         $this->assertEquals('test:annotation-hook', $command->getName());
712
713         $input = new StringInput('test:annotation-hook baz');
714         $this->assertRunCommandViaApplicationEquals($command, $input, '>(baz)<');
715     }
716
717     function testHookHasCommandAnnotation()
718     {
719         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
720         $this->commandFactory = new AnnotatedCommandFactory();
721
722         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookAddCommandName');
723
724         $this->assertTrue($hookInfo->hasAnnotation('hook'));
725         $this->assertEquals('alter @addmycommandname', $hookInfo->getAnnotation('hook'));
726
727         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
728         $hookCallback = $this->commandFactory->hookManager()->get('@addmycommandname', [HookManager::ALTER_RESULT]);
729         $this->assertTrue($hookCallback != null);
730         $this->assertEquals(1, count($hookCallback));
731         $this->assertEquals(2, count($hookCallback[0]));
732         $this->assertTrue(is_callable($hookCallback[0]));
733         $this->assertEquals('hookAddCommandName', $hookCallback[0][1]);
734
735         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'alterMe');
736         $annotationData = $commandInfo->getRawAnnotations();
737         $this->assertEquals('command,addmycommandname', implode(',', $annotationData->keys()));
738
739         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
740
741         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
742         $this->assertEquals('alter-me', $command->getName());
743
744         $input = new StringInput('alter-me');
745         $this->assertRunCommandViaApplicationEquals($command, $input, 'splendiferous from alter-me');
746
747         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'alterMeToo');
748         $annotationData = $commandInfo->getRawAnnotations();
749         $this->assertEquals('addmycommandname', implode(',', $annotationData->keys()));
750         $annotationData = $commandInfo->getAnnotations();
751         $this->assertEquals('addmycommandname,command,_path,_classname', implode(',', $annotationData->keys()));
752
753         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
754
755         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
756         $this->assertEquals('alter:me-too', $command->getName());
757
758         $input = new StringInput('alter:me-too');
759         $this->assertRunCommandViaApplicationEquals($command, $input, 'fantabulous from alter:me-too');
760     }
761
762     function testHookedCommandWithHookAddedLater()
763     {
764         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
765         $this->commandFactory = new AnnotatedCommandFactory();
766         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testHook');
767
768         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
769
770         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
771         $this->assertEquals('test:hook', $command->getName());
772
773         // Run the command once without the hook
774         $input = new StringInput('test:hook foo');
775         $this->assertRunCommandViaApplicationEquals($command, $input, '[foo]');
776
777         // Register the hook and run the command again
778         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'hookTestHook');
779
780         $this->assertTrue($hookInfo->hasAnnotation('hook'));
781         $this->assertEquals('alter test:hook', $hookInfo->getAnnotation('hook'));
782
783         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
784         $hookCallback = $this->commandFactory->hookManager()->get('test:hook', [HookManager::ALTER_RESULT]);;
785         $this->assertTrue($hookCallback != null);
786         $this->assertEquals(1, count($hookCallback));
787         $this->assertEquals(2, count($hookCallback[0]));
788         $this->assertTrue(is_callable($hookCallback[0]));
789         $this->assertEquals('hookTestHook', $hookCallback[0][1]);
790
791         $input = new StringInput('test:hook bar');
792         $this->assertRunCommandViaApplicationEquals($command, $input, '<[bar]>');
793     }
794
795     function testInitializeHook()
796     {
797         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
798         $this->commandFactory = new AnnotatedCommandFactory();
799
800         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'initializeTestHello');
801
802         $this->assertTrue($hookInfo->hasAnnotation('hook'));
803         $this->assertEquals($hookInfo->getAnnotation('hook'), 'init test:hello');
804
805         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
806
807         $hookCallback = $this->commandFactory->hookManager()->get('test:hello', [HookManager::INITIALIZE]);
808         $this->assertTrue($hookCallback != null);
809         $this->assertEquals(1, count($hookCallback));
810         $this->assertEquals(2, count($hookCallback[0]));
811         $this->assertTrue(is_callable($hookCallback[0]));
812         $this->assertEquals('initializeTestHello', $hookCallback[0][1]);
813
814         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testHello');
815         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
816
817         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
818         $this->assertEquals('test:hello', $command->getName());
819         $commandGetNames = $this->callProtected($command, 'getNames');
820         $this->assertEquals('test:hello,Consolidation\TestUtils\ExampleCommandFile', implode(',', $commandGetNames));
821
822         $hookCallback = $command->commandProcessor()->hookManager()->get('test:hello', 'init');
823         $this->assertTrue($hookCallback != null);
824         $this->assertEquals('initializeTestHello', $hookCallback[0][1]);
825
826         $input = new StringInput('test:hello');
827         $this->assertRunCommandViaApplicationEquals($command, $input, "Hello, Huey.");
828     }
829
830     function testCommandEventHook()
831     {
832         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
833         $this->commandFactory = new AnnotatedCommandFactory();
834
835         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'commandEventTestHello');
836
837         $this->assertTrue($hookInfo->hasAnnotation('hook'));
838         $this->assertEquals($hookInfo->getAnnotation('hook'), 'command-event test:hello');
839
840         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
841
842         $hookCallback = $this->commandFactory->hookManager()->get('test:hello', [HookManager::COMMAND_EVENT]);
843         $this->assertTrue($hookCallback != null);
844         $this->assertEquals(1, count($hookCallback));
845         $this->assertEquals(2, count($hookCallback[0]));
846         $this->assertTrue(is_callable($hookCallback[0]));
847         $this->assertEquals('commandEventTestHello', $hookCallback[0][1]);
848
849         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testHello');
850         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
851
852         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
853         $this->assertEquals('test:hello', $command->getName());
854         $commandGetNames = $this->callProtected($command, 'getNames');
855         $this->assertEquals('test:hello,Consolidation\TestUtils\ExampleCommandFile', implode(',', $commandGetNames));
856
857         $hookCallback = $command->commandProcessor()->hookManager()->get('test:hello', 'command-event');
858         $this->assertTrue($hookCallback != null);
859         $this->assertEquals('commandEventTestHello', $hookCallback[0][1]);
860
861         $input = new StringInput('test:hello Pluto');
862         $this->assertRunCommandViaApplicationEquals($command, $input, "Here comes Pluto!\nHello, Pluto.");
863     }
864
865
866     function testInteractAndValidate()
867     {
868         $this->commandFileInstance = new \Consolidation\TestUtils\ExampleCommandFile();
869         $this->commandFactory = new AnnotatedCommandFactory();
870
871         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'interactTestHello');
872
873         $this->assertTrue($hookInfo->hasAnnotation('hook'));
874         $this->assertEquals($hookInfo->getAnnotation('hook'), 'interact test:hello');
875
876         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
877
878         $hookInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'validateTestHello');
879
880         $this->assertTrue($hookInfo->hasAnnotation('hook'));
881         $this->assertEquals($hookInfo->getAnnotation('hook'), 'validate test:hello');
882
883         $this->commandFactory->registerCommandHook($hookInfo, $this->commandFileInstance);
884
885         $hookCallback = $this->commandFactory->hookManager()->get('test:hello', [HookManager::ARGUMENT_VALIDATOR]);
886         $this->assertTrue($hookCallback != null);
887         $this->assertEquals(1, count($hookCallback));
888         $this->assertEquals(2, count($hookCallback[0]));
889         $this->assertTrue(is_callable($hookCallback[0]));
890         $this->assertEquals('validateTestHello', $hookCallback[0][1]);
891
892         $hookCallback = $this->commandFactory->hookManager()->get('test:hello', [HookManager::INTERACT]);
893         $this->assertTrue($hookCallback != null);
894         $this->assertEquals(1, count($hookCallback));
895         $this->assertEquals(2, count($hookCallback[0]));
896         $this->assertTrue(is_callable($hookCallback[0]));
897         $this->assertEquals('interactTestHello', $hookCallback[0][1]);
898
899         $commandInfo = $this->commandFactory->createCommandInfo($this->commandFileInstance, 'testHello');
900         $command = $this->commandFactory->createCommand($commandInfo, $this->commandFileInstance);
901
902         $this->assertInstanceOf('\Symfony\Component\Console\Command\Command', $command);
903         $this->assertEquals('test:hello', $command->getName());
904         $commandGetNames = $this->callProtected($command, 'getNames');
905         $this->assertEquals('test:hello,Consolidation\TestUtils\ExampleCommandFile', implode(',', $commandGetNames));
906
907         $testInteractInput = new StringInput('test:hello');
908         $definition = new \Symfony\Component\Console\Input\InputDefinition(
909             [
910                 new \Symfony\Component\Console\Input\InputArgument('application', \Symfony\Component\Console\Input\InputArgument::REQUIRED),
911                 new \Symfony\Component\Console\Input\InputArgument('who', \Symfony\Component\Console\Input\InputArgument::REQUIRED),
912             ]
913         );
914         $testInteractInput->bind($definition);
915         $testInteractOutput = new BufferedOutput();
916         $command->commandProcessor()->interact(
917             $testInteractInput,
918             $testInteractOutput,
919             $commandGetNames,
920             $command->getAnnotationData()
921         );
922         $this->assertEquals('Goofey', $testInteractInput->getArgument('who'));
923
924         $hookCallback = $command->commandProcessor()->hookManager()->get('test:hello', 'interact');
925         $this->assertTrue($hookCallback != null);
926         $this->assertEquals('interactTestHello', $hookCallback[0][1]);
927
928         $input = new StringInput('test:hello "Mickey Mouse"');
929         $this->assertRunCommandViaApplicationEquals($command, $input, 'Hello, Mickey Mouse.');
930
931         $input = new StringInput('test:hello');
932         $this->assertRunCommandViaApplicationEquals($command, $input, 'Hello, Goofey.');
933
934         $input = new StringInput('test:hello "Donald Duck"');
935         $this->assertRunCommandViaApplicationEquals($command, $input, "I won't say hello to Donald Duck.", 1);
936
937         $input = new StringInput('test:hello "Drumph"');
938         $this->assertRunCommandViaApplicationEquals($command, $input, "Irrational value error.", 1);
939
940         // Try the last test again with a display error function installed.
941         $this->commandFactory->commandProcessor()->setDisplayErrorFunction(
942             function ($output, $message) {
943                 $output->writeln("*** $message ****");
944             }
945         );
946
947         $input = new StringInput('test:hello "Drumph"');
948         $this->assertRunCommandViaApplicationEquals($command, $input, "*** Irrational value error. ****", 1);
949     }
950
951     function callProtected($object, $method, $args = [])
952     {
953         $r = new \ReflectionMethod($object, $method);
954         $r->setAccessible(true);
955         return $r->invokeArgs($object, $args);
956     }
957
958     function assertRunCommandViaApplicationContains($command, $input, $containsList, $expectedStatusCode = 0)
959     {
960         list($statusCode, $commandOutput) = $this->runCommandViaApplication($command, $input);
961
962         foreach ($containsList as $contains) {
963             $this->assertContains($contains, $commandOutput);
964         }
965         $this->assertEquals($expectedStatusCode, $statusCode);
966     }
967
968     function assertRunCommandViaApplicationEquals($command, $input, $expectedOutput, $expectedStatusCode = 0)
969     {
970         list($statusCode, $commandOutput) = $this->runCommandViaApplication($command, $input);
971
972         $this->assertEquals($expectedOutput, $commandOutput);
973         $this->assertEquals($expectedStatusCode, $statusCode);
974     }
975
976     function runCommandViaApplication($command, $input)
977     {
978         $output = new BufferedOutput();
979         if ($this->commandFileInstance && method_exists($this->commandFileInstance, 'setOutput')) {
980             $this->commandFileInstance->setOutput($output);
981         }
982
983         $application = new Application('TestApplication', '0.0.0');
984         $alterOptionsEventManager = new AlterOptionsCommandEvent($application);
985
986         $eventDispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();
987         $eventDispatcher->addSubscriber($this->commandFactory->commandProcessor()->hookManager());
988         $this->commandFactory->commandProcessor()->hookManager()->addCommandEvent($alterOptionsEventManager);
989         $application->setDispatcher($eventDispatcher);
990
991         $application->setAutoExit(false);
992         $application->add($command);
993
994         $statusCode = $application->run($input, $output);
995         $commandOutput = trim(str_replace("\r", '', $output->fetch()));
996
997         return [$statusCode, $commandOutput];
998     }
999 }