Yaffs site version 1.1
[yaffs-website] / vendor / psy / psysh / test / Psy / Test / ShellTest.php
1 <?php
2
3 /*
4  * This file is part of Psy Shell.
5  *
6  * (c) 2012-2017 Justin Hileman
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Psy\Test;
13
14 use Psy\Configuration;
15 use Psy\Exception\ErrorException;
16 use Psy\Exception\ParseErrorException;
17 use Psy\Shell;
18 use Psy\TabCompletion\Matcher\ClassMethodsMatcher;
19 use Symfony\Component\Console\Output\StreamOutput;
20
21 class ShellTest extends \PHPUnit_Framework_TestCase
22 {
23     private $streams = array();
24
25     public function tearDown()
26     {
27         foreach ($this->streams as $stream) {
28             fclose($stream);
29         }
30     }
31
32     public function testScopeVariables()
33     {
34         $one       = 'banana';
35         $two       = 123;
36         $three     = new \StdClass();
37         $__psysh__ = 'ignore this';
38         $_         = 'ignore this';
39         $_e        = 'ignore this';
40
41         $shell = new Shell($this->getConfig());
42         $shell->setScopeVariables(compact('one', 'two', 'three', '__psysh__', '_', '_e', 'this'));
43
44         $this->assertNotContains('__psysh__', $shell->getScopeVariableNames());
45         $this->assertEquals(array('one', 'two', 'three', '_'), $shell->getScopeVariableNames());
46         $this->assertEquals('banana', $shell->getScopeVariable('one'));
47         $this->assertEquals(123, $shell->getScopeVariable('two'));
48         $this->assertSame($three, $shell->getScopeVariable('three'));
49         $this->assertNull($shell->getScopeVariable('_'));
50
51         $shell->setScopeVariables(array());
52         $this->assertEquals(array('_'), $shell->getScopeVariableNames());
53
54         $shell->setBoundObject($this);
55         $this->assertEquals(array('_', 'this'), $shell->getScopeVariableNames());
56         $this->assertSame($this, $shell->getScopeVariable('this'));
57         $this->assertEquals(array('_' => null), $shell->getScopeVariables(false));
58         $this->assertEquals(array('_' => null, 'this' => $this), $shell->getScopeVariables());
59     }
60
61     /**
62      * @expectedException \InvalidArgumentException
63      */
64     public function testUnknownScopeVariablesThrowExceptions()
65     {
66         $shell = new Shell($this->getConfig());
67         $shell->setScopeVariables(array('foo' => 'FOO', 'bar' => 1));
68         $shell->getScopeVariable('baz');
69     }
70
71     public function testIncludes()
72     {
73         $config = $this->getConfig(array('configFile' => __DIR__ . '/../../fixtures/empty.php'));
74
75         $shell = new Shell($config);
76         $this->assertEmpty($shell->getIncludes());
77         $shell->setIncludes(array('foo', 'bar', 'baz'));
78         $this->assertEquals(array('foo', 'bar', 'baz'), $shell->getIncludes());
79     }
80
81     public function testIncludesConfig()
82     {
83         $config = $this->getConfig(array(
84             'defaultIncludes' => array('/file.php'),
85             'configFile'      => __DIR__ . '/../../fixtures/empty.php',
86         ));
87
88         $shell = new Shell($config);
89
90         $includes = $shell->getIncludes();
91         $this->assertEquals('/file.php', $includes[0]);
92     }
93
94     public function testAddMatchersViaConfig()
95     {
96         $config = $this->getConfig(array(
97             'tabCompletionMatchers' => array(
98                 new ClassMethodsMatcher(),
99             ),
100         ));
101
102         $matchers = $config->getTabCompletionMatchers();
103
104         $this->assertTrue(array_pop($matchers) instanceof ClassMethodsMatcher);
105     }
106
107     public function testRenderingExceptions()
108     {
109         $shell  = new Shell($this->getConfig());
110         $output = $this->getOutput();
111         $stream = $output->getStream();
112         $e      = new ParseErrorException('message', 13);
113
114         $shell->setOutput($output);
115         $shell->addCode('code');
116         $this->assertTrue($shell->hasCode());
117         $this->assertNotEmpty($shell->getCodeBuffer());
118
119         $shell->writeException($e);
120
121         $this->assertSame($e, $shell->getScopeVariable('_e'));
122         $this->assertFalse($shell->hasCode());
123         $this->assertEmpty($shell->getCodeBuffer());
124
125         rewind($stream);
126         $streamContents = stream_get_contents($stream);
127
128         $this->assertContains('PHP Parse error', $streamContents);
129         $this->assertContains('message', $streamContents);
130         $this->assertContains('line 13', $streamContents);
131     }
132
133     public function testHandlingErrors()
134     {
135         $shell  = new Shell($this->getConfig());
136         $output = $this->getOutput();
137         $stream = $output->getStream();
138         $shell->setOutput($output);
139
140         $oldLevel = error_reporting();
141         error_reporting($oldLevel & ~E_USER_NOTICE);
142
143         try {
144             $shell->handleError(E_USER_NOTICE, 'wheee', null, 13);
145         } catch (ErrorException $e) {
146             error_reporting($oldLevel);
147             $this->fail('Unexpected error exception');
148         }
149         error_reporting($oldLevel);
150
151         rewind($stream);
152         $streamContents = stream_get_contents($stream);
153
154         $this->assertContains('PHP error:', $streamContents);
155         $this->assertContains('wheee',      $streamContents);
156         $this->assertContains('line 13',    $streamContents);
157     }
158
159     /**
160      * @expectedException \Psy\Exception\ErrorException
161      */
162     public function testNotHandlingErrors()
163     {
164         $shell    = new Shell($this->getConfig());
165         $oldLevel = error_reporting();
166         error_reporting($oldLevel | E_USER_NOTICE);
167
168         try {
169             $shell->handleError(E_USER_NOTICE, 'wheee', null, 13);
170         } catch (ErrorException $e) {
171             error_reporting($oldLevel);
172             throw $e;
173         }
174     }
175
176     public function testVersion()
177     {
178         $shell = new Shell($this->getConfig());
179
180         $this->assertInstanceOf('Symfony\Component\Console\Application', $shell);
181         $this->assertContains(Shell::VERSION, $shell->getVersion());
182         $this->assertContains(phpversion(), $shell->getVersion());
183         $this->assertContains(php_sapi_name(), $shell->getVersion());
184     }
185
186     public function testCodeBuffer()
187     {
188         $shell = new Shell($this->getConfig());
189
190         $shell->addCode('class');
191         $this->assertNull($shell->flushCode());
192         $this->assertTrue($shell->hasCode());
193
194         $shell->addCode('a');
195         $this->assertNull($shell->flushCode());
196         $this->assertTrue($shell->hasCode());
197
198         $shell->addCode('{}');
199         $code = $shell->flushCode();
200         $this->assertFalse($shell->hasCode());
201         $code = preg_replace('/\s+/', ' ', $code);
202         $this->assertNotNull($code);
203         $this->assertEquals('class a { } return new \\Psy\\CodeCleaner\\NoReturnValue();', $code);
204     }
205
206     public function testKeepCodeBufferOpen()
207     {
208         $shell = new Shell($this->getConfig());
209
210         $shell->addCode('1 \\');
211         $this->assertNull($shell->flushCode());
212         $this->assertTrue($shell->hasCode());
213
214         $shell->addCode('+ 1 \\');
215         $this->assertNull($shell->flushCode());
216         $this->assertTrue($shell->hasCode());
217
218         $shell->addCode('+ 1');
219         $code = $shell->flushCode();
220         $this->assertFalse($shell->hasCode());
221         $code = preg_replace('/\s+/', ' ', $code);
222         $this->assertNotNull($code);
223         $this->assertEquals('return 1 + 1 + 1;', $code);
224     }
225
226     /**
227      * @expectedException \Psy\Exception\ParseErrorException
228      */
229     public function testCodeBufferThrowsParseExceptions()
230     {
231         $shell = new Shell($this->getConfig());
232         $shell->addCode('this is not valid');
233         $shell->flushCode();
234     }
235
236     public function testClosuresSupport()
237     {
238         $shell = new Shell($this->getConfig());
239         $code = '$test = function () {}';
240         $shell->addCode($code);
241         $shell->flushCode();
242         $code = '$test()';
243         $shell->addCode($code);
244         $shell->flushCode();
245     }
246
247     public function testWriteStdout()
248     {
249         $output = $this->getOutput();
250         $stream = $output->getStream();
251         $shell  = new Shell($this->getConfig());
252         $shell->setOutput($output);
253
254         $shell->writeStdout("{{stdout}}\n");
255
256         rewind($stream);
257         $streamContents = stream_get_contents($stream);
258
259         $this->assertEquals('{{stdout}}' . PHP_EOL, $streamContents);
260     }
261
262     public function testWriteStdoutWithoutNewline()
263     {
264         $output = $this->getOutput();
265         $stream = $output->getStream();
266         $shell  = new Shell($this->getConfig());
267         $shell->setOutput($output);
268
269         $shell->writeStdout('{{stdout}}');
270
271         rewind($stream);
272         $streamContents = stream_get_contents($stream);
273
274         $this->assertEquals('{{stdout}}<aside>⏎</aside>' . PHP_EOL, $streamContents);
275     }
276
277     /**
278      * @dataProvider getReturnValues
279      */
280     public function testWriteReturnValue($input, $expected)
281     {
282         $output = $this->getOutput();
283         $stream = $output->getStream();
284         $shell  = new Shell($this->getConfig());
285         $shell->setOutput($output);
286
287         $shell->writeReturnValue($input);
288         rewind($stream);
289         $this->assertEquals($expected, stream_get_contents($stream));
290     }
291
292     public function getReturnValues()
293     {
294         return array(
295             array('{{return value}}', "=> \"\033[32m{{return value}}\033[39m\"" . PHP_EOL),
296             array(1, "=> \033[35m1\033[39m" . PHP_EOL),
297         );
298     }
299
300     /**
301      * @dataProvider getRenderedExceptions
302      */
303     public function testWriteException($exception, $expected)
304     {
305         $output = $this->getOutput();
306         $stream = $output->getStream();
307         $shell  = new Shell($this->getConfig());
308         $shell->setOutput($output);
309
310         $shell->writeException($exception);
311         rewind($stream);
312         $this->assertEquals($expected, stream_get_contents($stream));
313     }
314
315     public function getRenderedExceptions()
316     {
317         return array(
318             array(new \Exception('{{message}}'), "Exception with message '{{message}}'" . PHP_EOL),
319         );
320     }
321
322     private function getOutput()
323     {
324         $stream = fopen('php://memory', 'w+');
325         $this->streams[] = $stream;
326
327         $output = new StreamOutput($stream, StreamOutput::VERBOSITY_NORMAL, false);
328
329         return $output;
330     }
331
332     private function getConfig(array $config = array())
333     {
334         // Mebbe there's a better way than this?
335         $dir = tempnam(sys_get_temp_dir(), 'psysh_shell_test_');
336         unlink($dir);
337
338         $defaults = array(
339             'configDir'  => $dir,
340             'dataDir'    => $dir,
341             'runtimeDir' => $dir,
342         );
343
344         return new Configuration(array_merge($defaults, $config));
345     }
346 }