1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Process\Tests;
13
14use PHPUnit\Framework\TestCase;
15use Symfony\Component\Process\ProcessBuilder;
16
17/**
18 * @group legacy
19 */
20class ProcessBuilderTest extends TestCase
21{
22    public function testInheritEnvironmentVars()
23    {
24        $proc = ProcessBuilder::create()
25            ->add('foo')
26            ->getProcess();
27
28        $this->assertTrue($proc->areEnvironmentVariablesInherited());
29
30        $proc = ProcessBuilder::create()
31            ->add('foo')
32            ->inheritEnvironmentVariables(false)
33            ->getProcess();
34
35        $this->assertFalse($proc->areEnvironmentVariablesInherited());
36    }
37
38    public function testAddEnvironmentVariables()
39    {
40        $pb = new ProcessBuilder();
41        $env = [
42            'foo' => 'bar',
43            'foo2' => 'bar2',
44        ];
45        $proc = $pb
46            ->add('command')
47            ->setEnv('foo', 'bar2')
48            ->addEnvironmentVariables($env)
49            ->getProcess()
50        ;
51
52        $this->assertSame($env, $proc->getEnv());
53    }
54
55    public function testNegativeTimeoutFromSetter()
56    {
57        $this->expectException('Symfony\Component\Process\Exception\InvalidArgumentException');
58        $pb = new ProcessBuilder();
59        $pb->setTimeout(-1);
60    }
61
62    public function testNullTimeout()
63    {
64        $pb = new ProcessBuilder();
65        $pb->setTimeout(10);
66        $pb->setTimeout(null);
67
68        $r = new \ReflectionObject($pb);
69        $p = $r->getProperty('timeout');
70        $p->setAccessible(true);
71
72        $this->assertNull($p->getValue($pb));
73    }
74
75    public function testShouldSetArguments()
76    {
77        $pb = new ProcessBuilder(['initial']);
78        $pb->setArguments(['second']);
79
80        $proc = $pb->getProcess();
81
82        $this->assertStringContainsString('second', $proc->getCommandLine());
83    }
84
85    public function testPrefixIsPrependedToAllGeneratedProcess()
86    {
87        $pb = new ProcessBuilder();
88        $pb->setPrefix('/usr/bin/php');
89
90        $proc = $pb->setArguments(['-v'])->getProcess();
91        if ('\\' === \DIRECTORY_SEPARATOR) {
92            $this->assertEquals('"/usr/bin/php" -v', $proc->getCommandLine());
93        } else {
94            $this->assertEquals("'/usr/bin/php' '-v'", $proc->getCommandLine());
95        }
96
97        $proc = $pb->setArguments(['-i'])->getProcess();
98        if ('\\' === \DIRECTORY_SEPARATOR) {
99            $this->assertEquals('"/usr/bin/php" -i', $proc->getCommandLine());
100        } else {
101            $this->assertEquals("'/usr/bin/php' '-i'", $proc->getCommandLine());
102        }
103    }
104
105    public function testArrayPrefixesArePrependedToAllGeneratedProcess()
106    {
107        $pb = new ProcessBuilder();
108        $pb->setPrefix(['/usr/bin/php', 'composer.phar']);
109
110        $proc = $pb->setArguments(['-v'])->getProcess();
111        if ('\\' === \DIRECTORY_SEPARATOR) {
112            $this->assertEquals('"/usr/bin/php" composer.phar -v', $proc->getCommandLine());
113        } else {
114            $this->assertEquals("'/usr/bin/php' 'composer.phar' '-v'", $proc->getCommandLine());
115        }
116
117        $proc = $pb->setArguments(['-i'])->getProcess();
118        if ('\\' === \DIRECTORY_SEPARATOR) {
119            $this->assertEquals('"/usr/bin/php" composer.phar -i', $proc->getCommandLine());
120        } else {
121            $this->assertEquals("'/usr/bin/php' 'composer.phar' '-i'", $proc->getCommandLine());
122        }
123    }
124
125    public function testShouldEscapeArguments()
126    {
127        $pb = new ProcessBuilder(['%path%', 'foo " bar', '%baz%baz']);
128        $proc = $pb->getProcess();
129
130        if ('\\' === \DIRECTORY_SEPARATOR) {
131            $this->assertSame('""^%"path"^%"" "foo "" bar" ""^%"baz"^%"baz"', $proc->getCommandLine());
132        } else {
133            $this->assertSame("'%path%' 'foo \" bar' '%baz%baz'", $proc->getCommandLine());
134        }
135    }
136
137    public function testShouldEscapeArgumentsAndPrefix()
138    {
139        $pb = new ProcessBuilder(['arg']);
140        $pb->setPrefix('%prefix%');
141        $proc = $pb->getProcess();
142
143        if ('\\' === \DIRECTORY_SEPARATOR) {
144            $this->assertSame('""^%"prefix"^%"" arg', $proc->getCommandLine());
145        } else {
146            $this->assertSame("'%prefix%' 'arg'", $proc->getCommandLine());
147        }
148    }
149
150    public function testShouldThrowALogicExceptionIfNoPrefixAndNoArgument()
151    {
152        $this->expectException('Symfony\Component\Process\Exception\LogicException');
153        ProcessBuilder::create()->getProcess();
154    }
155
156    public function testShouldNotThrowALogicExceptionIfNoArgument()
157    {
158        $process = ProcessBuilder::create()
159            ->setPrefix('/usr/bin/php')
160            ->getProcess();
161
162        if ('\\' === \DIRECTORY_SEPARATOR) {
163            $this->assertEquals('"/usr/bin/php"', $process->getCommandLine());
164        } else {
165            $this->assertEquals("'/usr/bin/php'", $process->getCommandLine());
166        }
167    }
168
169    public function testShouldNotThrowALogicExceptionIfNoPrefix()
170    {
171        $process = ProcessBuilder::create(['/usr/bin/php'])
172            ->getProcess();
173
174        if ('\\' === \DIRECTORY_SEPARATOR) {
175            $this->assertEquals('"/usr/bin/php"', $process->getCommandLine());
176        } else {
177            $this->assertEquals("'/usr/bin/php'", $process->getCommandLine());
178        }
179    }
180
181    public function testShouldReturnProcessWithDisabledOutput()
182    {
183        $process = ProcessBuilder::create(['/usr/bin/php'])
184            ->disableOutput()
185            ->getProcess();
186
187        $this->assertTrue($process->isOutputDisabled());
188    }
189
190    public function testShouldReturnProcessWithEnabledOutput()
191    {
192        $process = ProcessBuilder::create(['/usr/bin/php'])
193            ->disableOutput()
194            ->enableOutput()
195            ->getProcess();
196
197        $this->assertFalse($process->isOutputDisabled());
198    }
199
200    public function testInvalidInput()
201    {
202        $this->expectException('Symfony\Component\Process\Exception\InvalidArgumentException');
203        $this->expectExceptionMessage('"Symfony\Component\Process\ProcessBuilder::setInput" only accepts strings, Traversable objects or stream resources.');
204        $builder = ProcessBuilder::create();
205        $builder->setInput([]);
206    }
207
208    public function testDoesNotPrefixExec()
209    {
210        if ('\\' === \DIRECTORY_SEPARATOR) {
211            $this->markTestSkipped('This test cannot run on Windows.');
212        }
213
214        $builder = ProcessBuilder::create(['command', '-v', 'ls']);
215        $process = $builder->getProcess();
216        $process->run();
217
218        $this->assertTrue($process->isSuccessful());
219    }
220}
221