Passed
Push — main ( 2c83d5...fb3f8a )
by Siad
05:21
created

ExecTaskTest   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 360
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 58
eloc 130
dl 0
loc 360
rs 4.5599
c 0
b 0
f 0

45 Methods

Rating   Name   Duplication   Size   Complexity  
A testPropertySetOutputProperty() 0 3 1
A testEscape() 0 4 2
A testPropertySetCommandline() 0 3 1
A testExecuteOnCorrectOs() 0 4 1
A testPropertySetLevelError() 0 3 1
A testPropertySetError() 0 7 1
A testReturnProperty() 0 4 1
A testMissingExecutableAndCommand() 0 6 1
A getTaskFromTarget() 0 12 4
A testOutput() 0 7 1
A testPropertySetLevelUnknown() 0 6 1
A testPropertySetPassthru() 0 3 1
A testEnvVar() 0 3 1
A testDoNotExecuteOnWrongOs() 0 7 1
A testExecuteOnCorrectOsFamily() 0 4 1
A testEscapedArgWithoutWhitespace() 0 6 3
A testPropertySetDir() 0 6 1
A testSpawn() 0 10 1
A testPropertySetOs() 0 3 1
A testPropertySetLevelDebug() 0 3 1
A testPropertySetEscape() 0 3 1
A testPassthru() 0 9 1
A testPropertySetLogoutput() 0 3 1
A testCheckreturnTrue() 0 7 2
A testCheckreturnFalse() 0 10 2
A testPropertySetReturnProperty() 0 3 1
A getConfiguredTask() 0 7 1
A getTargetByName() 0 8 3
A testChangeToDir() 0 4 1
A testPropertySetCheckReturn() 0 3 1
A testDoNotExecuteOnWrongOsFamily() 0 3 1
A testPropertySetLevelInfo() 0 3 1
A testPropertySetOutput() 0 7 1
A testNestedArg() 0 4 2
A testPropertySetSpawn() 0 3 1
A testOutputProperty() 0 4 1
A testError() 0 7 1
A testMultipleEnvVars() 0 3 1
A testFailOnNonExistingDir() 0 16 1
A testPropertySetLevelWarning() 0 3 1
A testEscapedArg() 0 4 1
A setUp() 0 6 1
A testPropertySetLevelVerbose() 0 3 1
A testNestedEnv() 0 4 1
A assertAttributeIsSetTo() 0 18 3

How to fix   Complexity   

Complex Class

Complex classes like ExecTaskTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ExecTaskTest, and based on these observations, apply Extract Interface, too.

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\Test\Task\System;
21
22
use Exception;
23
use Phing\Exception\BuildException;
24
use Phing\Io\File;
25
use Phing\Io\FileSystem;
26
use Phing\Io\FileUtils;
27
use Phing\Project;
28
use Phing\Task;
29
use Phing\Task\System\ExecTask;
30
use Phing\Test\Support\BuildFileTest;
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
 */
40
class ExecTaskTest extends BuildFileTest
41
{
42
    /**
43
     * Whether test is being run on windows
44
     * @var bool
45
     */
46
    protected $windows;
47
48
    public function setUp(): void
49
    {
50
        $this->configureProject(
51
            PHING_TEST_BASE . '/etc/tasks/system/ExecTest.xml'
52
        );
53
        $this->windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
54
    }
55
56
    protected function getTargetByName($name)
57
    {
58
        foreach ($this->project->getTargets() as $target) {
59
            if ($target->getName() == $name) {
60
                return $target;
61
            }
62
        }
63
        throw new Exception(sprintf('Target "%s" not found', $name));
64
    }
65
66
    protected function getTaskFromTarget($target, $taskname, $pos = 0)
67
    {
68
        $rchildren = new ReflectionProperty(get_class($target), 'children');
69
        $rchildren->setAccessible(true);
70
        $n = -1;
71
        foreach ($rchildren->getValue($target) as $child) {
72
            if ($child instanceof Task && ++$n == $pos) {
73
                return $child;
74
            }
75
        }
76
        throw new Exception(
77
            sprintf('%s #%d not found in task', $taskname, $pos)
78
        );
79
    }
80
81
    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

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