Chris@13
|
1 <?php
|
Chris@13
|
2
|
Chris@13
|
3 /*
|
Chris@13
|
4 * This file is part of Psy Shell.
|
Chris@13
|
5 *
|
Chris@13
|
6 * (c) 2012-2018 Justin Hileman
|
Chris@13
|
7 *
|
Chris@13
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@13
|
9 * file that was distributed with this source code.
|
Chris@13
|
10 */
|
Chris@13
|
11
|
Chris@13
|
12 namespace Psy\Test\Input;
|
Chris@13
|
13
|
Chris@13
|
14 use Psy\Input\CodeArgument;
|
Chris@13
|
15 use Psy\Input\ShellInput;
|
Chris@13
|
16 use Symfony\Component\Console\Input\InputArgument;
|
Chris@13
|
17 use Symfony\Component\Console\Input\InputDefinition;
|
Chris@13
|
18 use Symfony\Component\Console\Input\InputOption;
|
Chris@13
|
19
|
Chris@13
|
20 class ShellInputTest extends \PHPUnit\Framework\TestCase
|
Chris@13
|
21 {
|
Chris@13
|
22 /**
|
Chris@16
|
23 * @expectedException \InvalidArgumentException
|
Chris@16
|
24 * @expectedExceptionMessage Unexpected CodeArgument before the final position: a
|
Chris@13
|
25 */
|
Chris@16
|
26 public function testThrowsWhenCodeArgumentNotInFinalPosition()
|
Chris@13
|
27 {
|
Chris@16
|
28 $definition = new InputDefinition([
|
Chris@16
|
29 new CodeArgument('a', null, CodeArgument::REQUIRED),
|
Chris@16
|
30 new InputArgument('b', null, InputArgument::REQUIRED),
|
Chris@16
|
31 ]);
|
Chris@16
|
32
|
Chris@16
|
33 $input = new ShellInput('foo bar');
|
Chris@16
|
34 $input->bind($definition);
|
Chris@13
|
35 }
|
Chris@13
|
36
|
Chris@13
|
37 public function testInputOptionWithGivenString()
|
Chris@13
|
38 {
|
Chris@13
|
39 $definition = new InputDefinition([
|
Chris@13
|
40 new InputOption('foo', null, InputOption::VALUE_REQUIRED),
|
Chris@13
|
41 new CodeArgument('code', null, CodeArgument::REQUIRED),
|
Chris@13
|
42 ]);
|
Chris@13
|
43
|
Chris@13
|
44 $input = new ShellInput('--foo=bar echo "baz\\\\n";');
|
Chris@13
|
45 $input->bind($definition);
|
Chris@13
|
46 $this->assertSame('bar', $input->getOption('foo'));
|
Chris@13
|
47 $this->assertSame('echo "baz\n";', $input->getArgument('code'));
|
Chris@13
|
48 }
|
Chris@13
|
49
|
Chris@13
|
50 public function testInputOptionWithoutCodeArguments()
|
Chris@13
|
51 {
|
Chris@13
|
52 $definition = new InputDefinition([
|
Chris@13
|
53 new InputOption('foo', null, InputOption::VALUE_REQUIRED),
|
Chris@16
|
54 new InputOption('qux', 'q', InputOption::VALUE_REQUIRED),
|
Chris@13
|
55 new InputArgument('bar', null, InputArgument::REQUIRED),
|
Chris@13
|
56 new InputArgument('baz', null, InputArgument::REQUIRED),
|
Chris@13
|
57 ]);
|
Chris@13
|
58
|
Chris@16
|
59 $input = new ShellInput('--foo=foo -q qux bar "baz\\\\n"');
|
Chris@13
|
60 $input->bind($definition);
|
Chris@13
|
61 $this->assertSame('foo', $input->getOption('foo'));
|
Chris@16
|
62 $this->assertSame('qux', $input->getOption('qux'));
|
Chris@13
|
63 $this->assertSame('bar', $input->getArgument('bar'));
|
Chris@13
|
64 $this->assertSame('baz\\n', $input->getArgument('baz'));
|
Chris@13
|
65 }
|
Chris@13
|
66
|
Chris@16
|
67 public function testInputWithDashDash()
|
Chris@16
|
68 {
|
Chris@16
|
69 $definition = new InputDefinition([
|
Chris@16
|
70 new InputOption('foo', null, InputOption::VALUE_REQUIRED),
|
Chris@16
|
71 new CodeArgument('code', null, CodeArgument::REQUIRED),
|
Chris@16
|
72 ]);
|
Chris@16
|
73
|
Chris@16
|
74 $input = new ShellInput('-- echo --foo::$bar');
|
Chris@16
|
75 $input->bind($definition);
|
Chris@16
|
76 $this->assertNull($input->getOption('foo'));
|
Chris@16
|
77 $this->assertSame('echo --foo::$bar', $input->getArgument('code'));
|
Chris@16
|
78 }
|
Chris@16
|
79
|
Chris@16
|
80 public function testInputWithEmptyString()
|
Chris@16
|
81 {
|
Chris@16
|
82 $definition = new InputDefinition([
|
Chris@16
|
83 new InputOption('foo', null, InputOption::VALUE_REQUIRED),
|
Chris@16
|
84 new CodeArgument('code', null, CodeArgument::REQUIRED),
|
Chris@16
|
85 ]);
|
Chris@16
|
86
|
Chris@16
|
87 $input = new ShellInput('"" --foo bar');
|
Chris@16
|
88 $input->bind($definition);
|
Chris@16
|
89 $this->assertSame('"" --foo bar', $input->getArgument('code'));
|
Chris@16
|
90 }
|
Chris@16
|
91
|
Chris@16
|
92 /**
|
Chris@16
|
93 * @dataProvider getTokenizeData
|
Chris@16
|
94 */
|
Chris@16
|
95 public function testTokenize($input, $tokens, $message)
|
Chris@16
|
96 {
|
Chris@16
|
97 $input = new ShellInput($input);
|
Chris@16
|
98 $r = new \ReflectionClass('Psy\Input\ShellInput');
|
Chris@16
|
99 $p = $r->getProperty('tokenPairs');
|
Chris@16
|
100 $p->setAccessible(true);
|
Chris@16
|
101 $this->assertSame($tokens, $p->getValue($input), $message);
|
Chris@16
|
102 }
|
Chris@16
|
103
|
Chris@13
|
104 public function getTokenizeData()
|
Chris@13
|
105 {
|
Chris@13
|
106 // Test all the cases from StringInput test, ensuring they have an appropriate $rest token.
|
Chris@13
|
107 return [
|
Chris@13
|
108 [
|
Chris@13
|
109 '',
|
Chris@13
|
110 [],
|
Chris@13
|
111 '->tokenize() parses an empty string',
|
Chris@13
|
112 ],
|
Chris@13
|
113 [
|
Chris@13
|
114 'foo',
|
Chris@13
|
115 [['foo', 'foo']],
|
Chris@13
|
116 '->tokenize() parses arguments',
|
Chris@13
|
117 ],
|
Chris@13
|
118 [
|
Chris@13
|
119 ' foo bar ',
|
Chris@13
|
120 [['foo', 'foo bar '], ['bar', 'bar ']],
|
Chris@13
|
121 '->tokenize() ignores whitespaces between arguments',
|
Chris@13
|
122 ],
|
Chris@13
|
123 [
|
Chris@13
|
124 '"quoted"',
|
Chris@13
|
125 [['quoted', '"quoted"']],
|
Chris@13
|
126 '->tokenize() parses quoted arguments',
|
Chris@13
|
127 ],
|
Chris@13
|
128 [
|
Chris@13
|
129 "'quoted'",
|
Chris@13
|
130 [['quoted', "'quoted'"]],
|
Chris@13
|
131 '->tokenize() parses quoted arguments',
|
Chris@13
|
132 ],
|
Chris@13
|
133 [
|
Chris@13
|
134 "'a\rb\nc\td'",
|
Chris@13
|
135 [["a\rb\nc\td", "'a\rb\nc\td'"]],
|
Chris@13
|
136 '->tokenize() parses whitespace chars in strings',
|
Chris@13
|
137 ],
|
Chris@13
|
138 [
|
Chris@13
|
139 "'a'\r'b'\n'c'\t'd'",
|
Chris@13
|
140 [
|
Chris@13
|
141 ['a', "'a'\r'b'\n'c'\t'd'"],
|
Chris@13
|
142 ['b', "'b'\n'c'\t'd'"],
|
Chris@13
|
143 ['c', "'c'\t'd'"],
|
Chris@13
|
144 ['d', "'d'"],
|
Chris@13
|
145 ],
|
Chris@13
|
146 '->tokenize() parses whitespace chars between args as spaces',
|
Chris@13
|
147 ],
|
Chris@13
|
148
|
Chris@13
|
149 /*
|
Chris@13
|
150 * These don't play nice with unescaping input, but the end result
|
Chris@13
|
151 * is correct, so disable the tests for now.
|
Chris@13
|
152 *
|
Chris@13
|
153 * @todo Sort this out and re-enable these test cases.
|
Chris@13
|
154 */
|
Chris@13
|
155 // [
|
Chris@13
|
156 // '\"quoted\"',
|
Chris@13
|
157 // [['"quoted"', '\"quoted\"']],
|
Chris@13
|
158 // '->tokenize() parses escaped-quoted arguments',
|
Chris@13
|
159 // ],
|
Chris@13
|
160 // [
|
Chris@13
|
161 // "\'quoted\'",
|
Chris@13
|
162 // [['\'quoted\'', "\'quoted\'"]],
|
Chris@13
|
163 // '->tokenize() parses escaped-quoted arguments',
|
Chris@13
|
164 // ],
|
Chris@13
|
165
|
Chris@13
|
166 [
|
Chris@13
|
167 '-a',
|
Chris@13
|
168 [['-a', '-a']],
|
Chris@13
|
169 '->tokenize() parses short options',
|
Chris@13
|
170 ],
|
Chris@13
|
171 [
|
Chris@13
|
172 '-azc',
|
Chris@13
|
173 [['-azc', '-azc']],
|
Chris@13
|
174 '->tokenize() parses aggregated short options',
|
Chris@13
|
175 ],
|
Chris@13
|
176 [
|
Chris@13
|
177 '-awithavalue',
|
Chris@13
|
178 [['-awithavalue', '-awithavalue']],
|
Chris@13
|
179 '->tokenize() parses short options with a value',
|
Chris@13
|
180 ],
|
Chris@13
|
181 [
|
Chris@13
|
182 '-a"foo bar"',
|
Chris@13
|
183 [['-afoo bar', '-a"foo bar"']],
|
Chris@13
|
184 '->tokenize() parses short options with a value',
|
Chris@13
|
185 ],
|
Chris@13
|
186 [
|
Chris@13
|
187 '-a"foo bar""foo bar"',
|
Chris@13
|
188 [['-afoo barfoo bar', '-a"foo bar""foo bar"']],
|
Chris@13
|
189 '->tokenize() parses short options with a value',
|
Chris@13
|
190 ],
|
Chris@13
|
191 [
|
Chris@13
|
192 '-a\'foo bar\'',
|
Chris@13
|
193 [['-afoo bar', '-a\'foo bar\'']],
|
Chris@13
|
194 '->tokenize() parses short options with a value',
|
Chris@13
|
195 ],
|
Chris@13
|
196 [
|
Chris@13
|
197 '-a\'foo bar\'\'foo bar\'',
|
Chris@13
|
198 [['-afoo barfoo bar', '-a\'foo bar\'\'foo bar\'']],
|
Chris@13
|
199 '->tokenize() parses short options with a value',
|
Chris@13
|
200 ],
|
Chris@13
|
201 [
|
Chris@13
|
202 '-a\'foo bar\'"foo bar"',
|
Chris@13
|
203 [['-afoo barfoo bar', '-a\'foo bar\'"foo bar"']],
|
Chris@13
|
204 '->tokenize() parses short options with a value',
|
Chris@13
|
205 ],
|
Chris@13
|
206 [
|
Chris@13
|
207 '--long-option',
|
Chris@13
|
208 [['--long-option', '--long-option']],
|
Chris@13
|
209 '->tokenize() parses long options',
|
Chris@13
|
210 ],
|
Chris@13
|
211 [
|
Chris@13
|
212 '--long-option=foo',
|
Chris@13
|
213 [['--long-option=foo', '--long-option=foo']],
|
Chris@13
|
214 '->tokenize() parses long options with a value',
|
Chris@13
|
215 ],
|
Chris@13
|
216 [
|
Chris@13
|
217 '--long-option="foo bar"',
|
Chris@13
|
218 [['--long-option=foo bar', '--long-option="foo bar"']],
|
Chris@13
|
219 '->tokenize() parses long options with a value',
|
Chris@13
|
220 ],
|
Chris@13
|
221 [
|
Chris@13
|
222 '--long-option="foo bar""another"',
|
Chris@13
|
223 [['--long-option=foo baranother', '--long-option="foo bar""another"']],
|
Chris@13
|
224 '->tokenize() parses long options with a value',
|
Chris@13
|
225 ],
|
Chris@13
|
226 [
|
Chris@13
|
227 '--long-option=\'foo bar\'',
|
Chris@13
|
228 [['--long-option=foo bar', '--long-option=\'foo bar\'']],
|
Chris@13
|
229 '->tokenize() parses long options with a value',
|
Chris@13
|
230 ],
|
Chris@13
|
231 [
|
Chris@13
|
232 "--long-option='foo bar''another'",
|
Chris@13
|
233 [['--long-option=foo baranother', "--long-option='foo bar''another'"]],
|
Chris@13
|
234 '->tokenize() parses long options with a value',
|
Chris@13
|
235 ],
|
Chris@13
|
236 [
|
Chris@13
|
237 "--long-option='foo bar'\"another\"",
|
Chris@13
|
238 [['--long-option=foo baranother', "--long-option='foo bar'\"another\""]],
|
Chris@13
|
239 '->tokenize() parses long options with a value',
|
Chris@13
|
240 ],
|
Chris@13
|
241 [
|
Chris@13
|
242 'foo -a -ffoo --long bar',
|
Chris@13
|
243 [
|
Chris@13
|
244 ['foo', 'foo -a -ffoo --long bar'],
|
Chris@13
|
245 ['-a', '-a -ffoo --long bar'],
|
Chris@13
|
246 ['-ffoo', '-ffoo --long bar'],
|
Chris@13
|
247 ['--long', '--long bar'],
|
Chris@13
|
248 ['bar', 'bar'],
|
Chris@13
|
249 ],
|
Chris@13
|
250 '->tokenize() parses when several arguments and options',
|
Chris@13
|
251 ],
|
Chris@13
|
252 ];
|
Chris@13
|
253 }
|
Chris@13
|
254 }
|