Passed
Push — main ( e46995...8be666 )
by Siad
08:49
created

ExecTaskTest::testPropertySetReturnProperty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the LGPL. For more information please see
18
 * <http://phing.info>.
19
 */
20
21
namespace Phing\Test\Task\System;
22
23
use Exception;
24
use Phing\Exception\BuildException;
25
use Phing\Io\File;
26
use Phing\Io\FileSystem;
27
use Phing\Io\FileUtils;
28
use Phing\Project;
29
use Phing\Target;
30
use Phing\Task;
31
use Phing\Task\System\ExecTask;
32
use Phing\Test\Support\BuildFileTest;
33
use Phing\Type\Commandline;
34
use Phing\UnknownElement;
35
use ReflectionProperty;
36
37
/**
38
 * Tests the Exec Task.
39
 *
40
 * @author  Michiel Rook <[email protected]>
41
 *
42
 * @internal
43
 */
44
class ExecTaskTest extends BuildFileTest
45
{
46
    /**
47
     * Whether test is being run on windows.
48
     *
49
     * @var bool
50
     */
51
    protected $windows;
52
53
    public function setUp(): void
54
    {
55
        $this->configureProject(
56
            PHING_TEST_BASE . '/etc/tasks/system/ExecTest.xml'
57
        );
58
        $this->windows = 'WIN' === strtoupper(substr(PHP_OS, 0, 3));
59
    }
60
61
    public function testPropertySetCommandline(): void
62
    {
63
        $this->assertAttributeIsSetTo('commandline', new Commandline("echo 'foo'"));
64
    }
65
66
    public function testPropertySetDir(): void
67
    {
68
        $this->assertAttributeIsSetTo(
69
            'dir',
70
            new File(
71
                realpath(__DIR__ . '/../../../etc/tasks/system')
72
            )
73
        );
74
    }
75
76
    public function testPropertySetOs(): void
77
    {
78
        $this->assertAttributeIsSetTo('os', 'linux');
79
    }
80
81
    public function testPropertySetEscape(): void
82
    {
83
        $this->assertAttributeIsSetTo('escape', true);
84
    }
85
86
    public function testPropertySetLogoutput(): void
87
    {
88
        $this->assertAttributeIsSetTo('logoutput', true, 'logOutput');
89
    }
90
91
    public function testPropertySetPassthru(): void
92
    {
93
        $this->assertAttributeIsSetTo('passthru', true);
94
    }
95
96
    public function testPropertySetSpawn(): void
97
    {
98
        $this->assertAttributeIsSetTo('spawn', true);
99
    }
100
101
    public function testPropertySetReturnProperty(): void
102
    {
103
        $this->assertAttributeIsSetTo('returnProperty', 'retval');
104
    }
105
106
    public function testPropertySetOutputProperty(): void
107
    {
108
        $this->assertAttributeIsSetTo('outputProperty', 'outval');
109
    }
110
111
    public function testPropertySetCheckReturn(): void
112
    {
113
        $this->assertAttributeIsSetTo('checkreturn', true);
114
    }
115
116
    public function testPropertySetOutput(): void
117
    {
118
        $this->assertAttributeIsSetTo(
119
            'output',
120
            new File(
121
                realpath(__DIR__ . '/../../../etc/tasks/system')
122
                . '/outputfilename'
123
            )
124
        );
125
    }
126
127
    public function testPropertySetError(): void
128
    {
129
        $this->assertAttributeIsSetTo(
130
            'error',
131
            new File(
132
                realpath(__DIR__ . '/../../../etc/tasks/system')
133
                . '/errorfilename'
134
            )
135
        );
136
    }
137
138
    public function testPropertySetLevelError(): void
139
    {
140
        $this->assertAttributeIsSetTo('levelError', Project::MSG_ERR, 'logLevel');
141
    }
142
143
    public function testPropertySetLevelWarning(): void
144
    {
145
        $this->assertAttributeIsSetTo('levelWarning', Project::MSG_WARN, 'logLevel');
146
    }
147
148
    public function testPropertySetLevelInfo(): void
149
    {
150
        $this->assertAttributeIsSetTo('levelInfo', Project::MSG_INFO, 'logLevel');
151
    }
152
153
    public function testPropertySetLevelVerbose(): void
154
    {
155
        $this->assertAttributeIsSetTo('levelVerbose', Project::MSG_VERBOSE, 'logLevel');
156
    }
157
158
    public function testPropertySetLevelDebug(): void
159
    {
160
        $this->assertAttributeIsSetTo('levelDebug', Project::MSG_DEBUG, 'logLevel');
161
    }
162
163
    public function testPropertySetLevelUnknown(): void
164
    {
165
        $this->expectException(BuildException::class);
166
        $this->expectExceptionMessage('Unknown log level "unknown"');
167
168
        $this->getConfiguredTask('testPropertySetLevelUnknown', 'ExecTask');
169
    }
170
171
    public function testDoNotExecuteOnWrongOs(): void
172
    {
173
        $this->executeTarget(__FUNCTION__);
174
        $this->assertInLogs('not found in the specified list of valid OSes: unknownos');
175
        $this->assertStringNotContainsString(
176
            'this should not be executed',
177
            $this->getOutput()
178
        );
179
    }
180
181
    public function testDoNotExecuteOnWrongOsFamily(): void
182
    {
183
        $this->expectBuildException(__FUNCTION__, "Don't know how to detect os family 'unknownos'");
184
    }
185
186
    public function testExecuteOnCorrectOs(): void
187
    {
188
        $this->executeTarget(__FUNCTION__);
189
        $this->assertInLogs('this should be executed');
190
    }
191
192
    public function testExecuteOnCorrectOsFamily(): void
193
    {
194
        $this->executeTarget(__FUNCTION__);
195
        $this->assertInLogs('this should be executed');
196
    }
197
198
    public function testFailOnNonExistingDir(): void
199
    {
200
        $this->expectException(BuildException::class);
201
        $this->expectExceptionMessageMatches('/' . preg_quote(str_replace('/', DIRECTORY_SEPARATOR, "'/this/dir/does/not/exist' does not exist"), '/') . '/');
202
203
//        try {
204
//            $this->executeTarget(__FUNCTION__);
205
//            $this->fail('Expected BuildException was not thrown');
206
//        } catch (BuildException $e) {
207
//            $this->assertContains(
208
//                str_replace('/', DIRECTORY_SEPARATOR, "'/this/dir/does/not/exist' does not exist"),
209
//                $e->getMessage()
210
//            );
211
//        }
212
213
        $this->executeTarget(__FUNCTION__);
214
    }
215
216
    /**
217
     * @requires OS Linux|Darwin
218
     */
219
    public function testChangeToDir(): void
220
    {
221
        $this->executeTarget(__FUNCTION__);
222
        $this->assertInLogs('ExecTaskTest.php');
223
    }
224
225
    public function testCheckreturnTrue(): void
226
    {
227
        if (false === FileSystem::getFileSystem()->which('true')) {
0 ignored issues
show
introduced by
The condition false === Phing\Io\FileS...System()->which('true') is always false.
Loading history...
228
            $this->markTestSkipped("'true' not found.");
229
        }
230
        $this->executeTarget(__FUNCTION__);
231
        $this->assertTrue(true);
232
    }
233
234
    public function testCheckreturnFalse(): void
235
    {
236
        if (false === FileSystem::getFileSystem()->which('false')) {
0 ignored issues
show
introduced by
The condition false === Phing\Io\FileS...ystem()->which('false') is always false.
Loading history...
237
            $this->markTestSkipped("'false' not found.");
238
        }
239
240
        $this->expectException(BuildException::class);
241
        $this->expectExceptionMessage('exec returned: 1');
242
243
        $this->executeTarget(__FUNCTION__);
244
    }
245
246
    public function testOutputProperty(): void
247
    {
248
        $this->executeTarget(__FUNCTION__);
249
        $this->assertInLogs('The output property\'s value is: "foo"');
250
    }
251
252
    public function testReturnProperty(): void
253
    {
254
        $this->executeTarget(__FUNCTION__);
255
        $this->assertInLogs('The return property\'s value is: "1"');
256
    }
257
258
    public function testEscape(): void
259
    {
260
        $this->executeTarget(__FUNCTION__);
261
        $this->assertInLogs($this->windows ? '"foo" "|" "cat"' : 'foo | cat');
262
    }
263
264
    public function testPassthru(): void
265
    {
266
        ob_start();
267
        $this->executeTarget(__FUNCTION__);
268
        $out = ob_get_clean();
269
        $this->assertEquals('foo', rtrim($out, " \r\n"));
270
        //foo should not be in logs, except for the logged command
271
        $this->assertInLogs('echo foo');
272
        $this->assertNotContains('foo', $this->logBuffer);
273
    }
274
275
    public function testOutput(): void
276
    {
277
        $file = tempnam(FileUtils::getTempDir(), 'phing-exectest-');
278
        $this->project->setProperty('execTmpFile', $file);
279
        $this->executeTarget(__FUNCTION__);
280
        $this->assertStringContainsString('outfoo', file_get_contents($file));
281
        unlink($file);
282
    }
283
284
    public function testError(): void
285
    {
286
        $file = tempnam(FileUtils::getTempDir(), 'phing-exectest-');
287
        $this->project->setProperty('execTmpFile', $file);
288
        $this->executeTarget(__FUNCTION__);
289
        $this->assertStringContainsString('errfoo', file_get_contents($file));
290
        unlink($file);
291
    }
292
293
    public function testSpawn(): void
294
    {
295
        $start = time();
296
        $this->executeTarget(__FUNCTION__);
297
        $end = time();
298
        $this->assertLessThan(
299
            4,
300
            $end - $start,
301
            'Time between start and end should be lower than 4 seconds'
302
            . ' - otherwise it looks as spawning did not work'
303
        );
304
    }
305
306
    public function testNestedArg(): void
307
    {
308
        $this->executeTarget(__FUNCTION__);
309
        $this->assertInLogs($this->windows ? 'nested-arg "b  ar"' : 'nested-arg b  ar');
310
    }
311
312
    public function testMissingExecutableAndCommand(): void
313
    {
314
        $this->expectException(BuildException::class);
315
        $this->expectExceptionMessage('ExecTask: Please provide "executable"');
316
317
        $this->executeTarget(__FUNCTION__);
318
    }
319
320
    /**
321
     * Inspired by {@link http://www.phing.info/trac/ticket/833}.
322
     */
323
    public function testEscapedArg(): void
324
    {
325
        $this->executeTarget(__FUNCTION__);
326
        $this->assertPropertyEquals('outval', 'abc$b3!SB');
327
    }
328
329
    public function testEscapedArgWithoutWhitespace(): void
330
    {
331
        $this->executeTarget(__FUNCTION__);
332
        $this->assertInLogs($this->windows ? '"echo" "foo|bar" 2>&1' : '\'echo\' \'foo|bar\' 2>&1');
333
        $this->assertNotInLogs($this->windows ? 'echo " foo|bar " 2>&1' : 'echo \' foo|bar \' 2>&1');
334
    }
335
336
    public function testNestedEnv(): void
337
    {
338
        $this->executeTarget(__FUNCTION__);
339
        $this->assertStringStartsWith('phploc', $this->getProject()->getProperty('envtest'));
340
    }
341
342
    public function testEnvVar(): void
343
    {
344
        $this->expectPropertySet(__FUNCTION__, 'hello', 'world');
345
    }
346
347
    public function testMultipleEnvVars(): void
348
    {
349
        $this->expectPropertySet(__FUNCTION__, 'outputProperty', 'hello world');
350
    }
351
352
    protected function getTargetByName($name): Target
353
    {
354
        foreach ($this->project->getTargets() as $target) {
355
            if ($target->getName() == $name) {
356
                return $target;
357
            }
358
        }
359
360
        throw new Exception(sprintf('Target "%s" not found', $name));
361
    }
362
363
    protected function getTaskFromTarget($target, $taskname, $pos = 0): Task
364
    {
365
        $rchildren = new ReflectionProperty(get_class($target), 'children');
366
        $rchildren->setAccessible(true);
367
        $n = -1;
368
        foreach ($rchildren->getValue($target) as $child) {
369
            if ($child instanceof Task && ++$n == $pos) {
370
                return $child;
371
            }
372
        }
373
374
        throw new Exception(
375
            sprintf('%s #%d not found in task', $taskname, $pos)
376
        );
377
    }
378
379
    protected function getConfiguredTask($target, $task, $pos = 0): Task
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

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

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...
380
    {
381
        $target = $this->getTargetByName($target);
382
        $task = $this->getTaskFromTarget($target, $task);
383
        $task->maybeConfigure();
384
385
        return $task;
386
    }
387
388
    protected function assertAttributeIsSetTo($property, $value, $propertyName = null): void
389
    {
390
        $task = $this->getConfiguredTask(
391
            'testPropertySet' . ucfirst($property),
392
            'ExecTask'
393
        );
394
395
        if (null === $propertyName) {
396
            $propertyName = $property;
397
        }
398
399
        if ($task instanceof UnknownElement) {
400
            $task = $task->getRuntimeConfigurableWrapper()->getProxy();
401
        }
402
403
        $rprop = new ReflectionProperty(ExecTask::class, $propertyName);
404
        $rprop->setAccessible(true);
405
        $this->assertEquals($value, $rprop->getValue($task));
406
    }
407
408
    public function testSuggestion()
409
    {
410
        $this->executeTarget(__FUNCTION__);
411
        $hint = 'Consider using HttpRequestTask https://www.phing.info/guide/chunkhtml/HttpRequestTask.html';
412
        $this->assertInLogs($hint, Project::MSG_VERBOSE, 'ExecTask is not displaying suggestion');
413
    }
414
}
415