Passed
Push — master ( 972120...1c77fc )
by Michiel
08:19
created

ExecTaskTest::testPassthru()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19
20
namespace Phing\Tasks\System;
21
22
use Exception;
23
use Phing\Exception\BuildException;
24
use Phing\Io\FileSystem;
25
use Phing\Io\FileUtils;
26
use Phing\Io\File;
27
use Phing\Project;
28
use Phing\Support\BuildFileTest;
29
use Phing\Task;
30
use Phing\Tasks\System\ExecTask;
31
use Phing\Type\Commandline;
32
use Phing\UnknownElement;
33
use ReflectionProperty;
34
35
/**
36
 * Tests the Exec Task
37
 *
38
 * @author  Michiel Rook <[email protected]>
39
 * @package phing.tasks.system
40
 */
41
class ExecTaskTest extends BuildFileTest
42
{
43
    /**
44
     * Whether test is being run on windows
45
     * @var bool
46
     */
47
    protected $windows;
48
49
    public function setUp(): void
50
    {
51
        $this->configureProject(
52
            PHING_TEST_BASE . '/etc/tasks/system/ExecTest.xml'
53
        );
54
        $this->windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
55
    }
56
57
    protected function getTargetByName($name)
58
    {
59
        foreach ($this->project->getTargets() as $target) {
60
            if ($target->getName() == $name) {
61
                return $target;
62
            }
63
        }
64
        throw new Exception(sprintf('Target "%s" not found', $name));
65
    }
66
67
    protected function getTaskFromTarget($target, $taskname, $pos = 0)
68
    {
69
        $rchildren = new ReflectionProperty(get_class($target), 'children');
70
        $rchildren->setAccessible(true);
71
        $n = -1;
72
        foreach ($rchildren->getValue($target) as $child) {
73
            if ($child instanceof Task && ++$n == $pos) {
74
                return $child;
75
            }
76
        }
77
        throw new Exception(
78
            sprintf('%s #%d not found in task', $taskname, $pos)
79
        );
80
    }
81
82
    protected function getConfiguredTask($target, $task, $pos = 0)
0 ignored issues
show
Unused Code introduced by
The parameter $pos is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

82
    protected function getConfiguredTask($target, $task, /** @scrutinizer ignore-unused */ $pos = 0)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
83
    {
84
        $target = $this->getTargetByName($target);
85
        $task = $this->getTaskFromTarget($target, $task);
86
        $task->maybeConfigure();
87
88
        return $task;
89
    }
90
91
    protected function assertAttributeIsSetTo($property, $value, $propertyName = null)
92
    {
93
        $task = $this->getConfiguredTask(
94
            'testPropertySet' . ucfirst($property),
95
            'ExecTask'
96
        );
97
98
        if ($propertyName === null) {
99
            $propertyName = $property;
100
        }
101
102
        if ($task instanceof UnknownElement) {
103
            $task = $task->getRuntimeConfigurableWrapper()->getProxy();
104
        }
105
106
        $rprop = new ReflectionProperty(ExecTask::class, $propertyName);
107
        $rprop->setAccessible(true);
108
        $this->assertEquals($value, $rprop->getValue($task));
109
    }
110
111
    public function testPropertySetCommandline()
112
    {
113
        $this->assertAttributeIsSetTo('commandline', new Commandline("echo 'foo'"));
114
    }
115
116
    public function testPropertySetDir()
117
    {
118
        $this->assertAttributeIsSetTo(
119
            'dir',
120
            new File(
121
                realpath(__DIR__ . '/../../../etc/tasks/system')
122
            )
123
        );
124
    }
125
126
    public function testPropertySetOs()
127
    {
128
        $this->assertAttributeIsSetTo('os', "linux");
129
    }
130
131
    public function testPropertySetEscape()
132
    {
133
        $this->assertAttributeIsSetTo('escape', true);
134
    }
135
136
    public function testPropertySetLogoutput()
137
    {
138
        $this->assertAttributeIsSetTo('logoutput', true, 'logOutput');
139
    }
140
141
    public function testPropertySetPassthru()
142
    {
143
        $this->assertAttributeIsSetTo('passthru', true);
144
    }
145
146
    public function testPropertySetSpawn()
147
    {
148
        $this->assertAttributeIsSetTo('spawn', true);
149
    }
150
151
    public function testPropertySetReturnProperty()
152
    {
153
        $this->assertAttributeIsSetTo('returnProperty', 'retval');
154
    }
155
156
    public function testPropertySetOutputProperty()
157
    {
158
        $this->assertAttributeIsSetTo('outputProperty', 'outval');
159
    }
160
161
    public function testPropertySetCheckReturn()
162
    {
163
        $this->assertAttributeIsSetTo('checkreturn', true);
164
    }
165
166
    public function testPropertySetOutput()
167
    {
168
        $this->assertAttributeIsSetTo(
169
            'output',
170
            new File(
171
                realpath(__DIR__ . '/../../../etc/tasks/system')
172
                . '/outputfilename'
173
            )
174
        );
175
    }
176
177
    public function testPropertySetError()
178
    {
179
        $this->assertAttributeIsSetTo(
180
            'error',
181
            new File(
182
                realpath(__DIR__ . '/../../../etc/tasks/system')
183
                . '/errorfilename'
184
            )
185
        );
186
    }
187
188
    public function testPropertySetLevelError()
189
    {
190
        $this->assertAttributeIsSetTo('levelError', Project::MSG_ERR, 'logLevel');
191
    }
192
193
    public function testPropertySetLevelWarning()
194
    {
195
        $this->assertAttributeIsSetTo('levelWarning', Project::MSG_WARN, 'logLevel');
196
    }
197
198
    public function testPropertySetLevelInfo()
199
    {
200
        $this->assertAttributeIsSetTo('levelInfo', Project::MSG_INFO, 'logLevel');
201
    }
202
203
    public function testPropertySetLevelVerbose()
204
    {
205
        $this->assertAttributeIsSetTo('levelVerbose', Project::MSG_VERBOSE, 'logLevel');
206
    }
207
208
    public function testPropertySetLevelDebug()
209
    {
210
        $this->assertAttributeIsSetTo('levelDebug', Project::MSG_DEBUG, 'logLevel');
211
    }
212
213
    public function testPropertySetLevelUnknown()
214
    {
215
        $this->expectException(BuildException::class);
216
        $this->expectExceptionMessage('Unknown log level "unknown"');
217
218
        $this->getConfiguredTask('testPropertySetLevelUnknown', 'ExecTask');
219
    }
220
221
    public function testDoNotExecuteOnWrongOs()
222
    {
223
        $this->executeTarget(__FUNCTION__);
224
        $this->assertInLogs('not found in the specified list of valid OSes: unknownos');
225
        $this->assertStringNotContainsString(
226
            'this should not be executed',
227
            $this->getOutput()
228
        );
229
    }
230
231
    public function testDoNotExecuteOnWrongOsFamily()
232
    {
233
        $this->expectBuildException(__FUNCTION__, "Don't know how to detect os family 'unknownos'");
234
    }
235
236
    public function testExecuteOnCorrectOs()
237
    {
238
        $this->executeTarget(__FUNCTION__);
239
        $this->assertInLogs('this should be executed');
240
    }
241
242
    public function testExecuteOnCorrectOsFamily()
243
    {
244
        $this->executeTarget(__FUNCTION__);
245
        $this->assertInLogs('this should be executed');
246
    }
247
248
    public function testFailOnNonExistingDir()
249
    {
250
        $this->expectException(BuildException::class);
251
        $this->expectExceptionMessageMatches('/' . preg_quote(str_replace('/', DIRECTORY_SEPARATOR, "'/this/dir/does/not/exist' does not exist"), '/') . '/');
252
253
//        try {
254
//            $this->executeTarget(__FUNCTION__);
255
//            $this->fail('Expected BuildException was not thrown');
256
//        } catch (BuildException $e) {
257
//            $this->assertContains(
258
//                str_replace('/', DIRECTORY_SEPARATOR, "'/this/dir/does/not/exist' does not exist"),
259
//                $e->getMessage()
260
//            );
261
//        }
262
263
        $this->executeTarget(__FUNCTION__);
264
    }
265
266
    /**
267
     * @requires OS Linux|Darwin
268
     */
269
    public function testChangeToDir()
270
    {
271
        $this->executeTarget(__FUNCTION__);
272
        $this->assertInLogs('ExecTaskTest.php');
273
    }
274
275
    public function testCheckreturnTrue()
276
    {
277
        if (FileSystem::getFileSystem()->which('true') === false) {
0 ignored issues
show
introduced by
The condition Phing\Io\FileSystem::get...which('true') === false is always false.
Loading history...
278
            $this->markTestSkipped("'true' not found.");
279
        }
280
        $this->executeTarget(__FUNCTION__);
281
        $this->assertTrue(true);
282
    }
283
284
    public function testCheckreturnFalse()
285
    {
286
        if (FileSystem::getFileSystem()->which('false') === false) {
0 ignored issues
show
introduced by
The condition Phing\Io\FileSystem::get...hich('false') === false is always false.
Loading history...
287
            $this->markTestSkipped("'false' not found.");
288
        }
289
290
        $this->expectException(BuildException::class);
291
        $this->expectExceptionMessage('exec returned: 1');
292
293
        $this->executeTarget(__FUNCTION__);
294
    }
295
296
    public function testOutputProperty()
297
    {
298
        $this->executeTarget(__FUNCTION__);
299
        $this->assertInLogs('The output property\'s value is: "foo"');
300
    }
301
302
    public function testReturnProperty()
303
    {
304
        $this->executeTarget(__FUNCTION__);
305
        $this->assertInLogs('The return property\'s value is: "1"');
306
    }
307
308
    public function testEscape()
309
    {
310
        $this->executeTarget(__FUNCTION__);
311
        $this->assertInLogs($this->windows ? '"foo" "|" "cat"' : 'foo | cat');
312
    }
313
314
    public function testPassthru()
315
    {
316
        ob_start();
317
        $this->executeTarget(__FUNCTION__);
318
        $out = ob_get_clean();
319
        $this->assertEquals("foo", rtrim($out, " \r\n"));
320
        //foo should not be in logs, except for the logged command
321
        $this->assertInLogs('echo foo');
322
        $this->assertNotContains('foo', $this->logBuffer);
323
    }
324
325
    public function testOutput()
326
    {
327
        $file = tempnam(FileUtils::getTempDir(), 'phing-exectest-');
328
        $this->project->setProperty('execTmpFile', $file);
329
        $this->executeTarget(__FUNCTION__);
330
        $this->assertStringContainsString('outfoo', file_get_contents($file));
331
        unlink($file);
332
    }
333
334
    public function testError()
335
    {
336
        $file = tempnam(FileUtils::getTempDir(), 'phing-exectest-');
337
        $this->project->setProperty('execTmpFile', $file);
338
        $this->executeTarget(__FUNCTION__);
339
        $this->assertStringContainsString('errfoo', file_get_contents($file));
340
        unlink($file);
341
    }
342
343
    public function testSpawn()
344
    {
345
        $start = time();
346
        $this->executeTarget(__FUNCTION__);
347
        $end = time();
348
        $this->assertLessThan(
349
            4,
350
            $end - $start,
351
            'Time between start and end should be lower than 4 seconds'
352
            . ' - otherwise it looks as spawning did not work'
353
        );
354
    }
355
356
    public function testNestedArg()
357
    {
358
        $this->executeTarget(__FUNCTION__);
359
        $this->assertInLogs($this->windows ? 'nested-arg "b  ar"' : 'nested-arg b  ar');
360
    }
361
362
    public function testMissingExecutableAndCommand()
363
    {
364
        $this->expectException(BuildException::class);
365
        $this->expectExceptionMessage('ExecTask: Please provide "executable"');
366
367
        $this->executeTarget(__FUNCTION__);
368
    }
369
370
    /**
371
     * Inspired by {@link http://www.phing.info/trac/ticket/833}
372
     */
373
    public function testEscapedArg()
374
    {
375
        $this->executeTarget(__FUNCTION__);
376
        $this->assertPropertyEquals('outval', 'abc$b3!SB');
377
    }
378
379
    public function testEscapedArgWithoutWhitespace()
380
    {
381
        $arg = 'foo|bar';
0 ignored issues
show
Unused Code introduced by
The assignment to $arg is dead and can be removed.
Loading history...
382
        $this->executeTarget(__FUNCTION__);
383
        $this->assertInLogs($this->windows ? '"echo" "foo|bar" 2>&1' : '\'echo\' \'foo|bar\' 2>&1');
384
        $this->assertNotInLogs($this->windows ? 'echo " foo|bar " 2>&1' : 'echo \' foo|bar \' 2>&1');
385
    }
386
387
    public function testNestedEnv()
388
    {
389
        $this->executeTarget(__FUNCTION__);
390
        $this->assertStringStartsWith('phploc', $this->getProject()->getProperty('envtest'));
391
    }
392
393
    public function testEnvVar(): void
394
    {
395
        $this->expectPropertySet(__FUNCTION__, 'hello', 'world');
396
    }
397
398
    public function testMultipleEnvVars(): void
399
    {
400
        $this->expectPropertySet(__FUNCTION__, 'outputProperty', 'hello world');
401
    }
402
}
403