Passed
Push — main ( 1152fc...a2dce0 )
by Siad
07:08
created

tests/Phing/Task/System/ApplyTaskTest.php (3 issues)

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\Io\File;
25
use Phing\Io\FileUtils;
26
use Phing\Target;
27
use Phing\Task;
28
use Phing\Task\System\ApplyTask;
29
use Phing\Test\Support\BuildFileTest;
30
use Phing\UnknownElement;
31
use ReflectionException;
32
use ReflectionProperty;
33
34
/**
35
 * Tests the Apply Task.
36
 *
37
 * @author  Utsav Handa <handautsav at hotmail dot com>
38
 */
39
class ApplyTaskTest extends BuildFileTest
40
{
41
    /**
42
     * Whether test is being run on windows.
43
     *
44
     * @var bool
45
     */
46
    protected $windows;
47
48
    /**
49
     * Setup the test.
50
     */
51
    public function setUp(): void
52
    {
53
        // Tests definitions
54
        $this->configureProject(PHING_TEST_BASE . '/etc/tasks/system/ApplyTest.xml');
55
56
        // Identifying the running environment
57
        $this->windows = 'WIN' === strtoupper(substr(PHP_OS, 0, 3));
58
    }
59
60
    // T E S T S
61
62
    /**
63
     * Tests the OS configuration setting.
64
     */
65
    public function testPropertySetOs()
66
    {
67
        $this->assertAttributeIsSetTo('os', 'linux');
68
    }
69
70
    /**
71
     * Tests the dir configuration setting.
72
     */
73
    public function testPropertySetDir()
74
    {
75
        $this->assertAttributeIsSetTo('dir', new File($this->project->getProperty('php.tmpdir')));
76
    }
77
78
    /**
79
     * Tests the escape configuration setting.
80
     */
81
    public function testPropertySetEscape()
82
    {
83
        $this->assertAttributeIsSetTo('escape', true);
84
    }
85
86
    /**
87
     * Tests the pass-thru configuration setting.
88
     */
89
    public function testPropertySetPassthru()
90
    {
91
        $this->assertAttributeIsSetTo('passthru', true);
92
    }
93
94
    /**
95
     * Tests the spawn configuration setting.
96
     */
97
    public function testPropertySetSpawn()
98
    {
99
        $this->assertAttributeIsSetTo('spawn', true);
100
    }
101
102
    /**
103
     * Tests the returnProperty configuration setting.
104
     */
105
    public function testPropertySetReturnProperty()
106
    {
107
        $this->assertAttributeIsSetTo('returnProperty', 'retval');
108
    }
109
110
    /**
111
     * Tests the outputProperty configuration setting.
112
     */
113
    public function testPropertySetOutputProperty()
114
    {
115
        $this->assertAttributeIsSetTo('outputProperty', 'outval');
116
    }
117
118
    /**
119
     * Tests the checkReturn/failonerror configuration setting.
120
     */
121
    public function testPropertySetCheckReturn()
122
    {
123
        $this->assertAttributeIsSetTo('checkreturn', true);
124
    }
125
126
    /**
127
     * Tests the output configuration setting.
128
     */
129
    public function testPropertySetOutput()
130
    {
131
        $this->assertAttributeIsSetTo(
132
            'output',
133
            new File($this->project->getProperty('php.tmpdir') . '/outputfilename')
134
        );
135
    }
136
137
    /**
138
     * Tests the error configuration setting.
139
     */
140
    public function testPropertySetError()
141
    {
142
        $this->assertAttributeIsSetTo(
143
            'error',
144
            new File($this->project->getProperty('php.tmpdir') . '/errorfilename')
145
        );
146
    }
147
148
    /**
149
     * Tests the append configuration setting.
150
     */
151
    public function testPropertySetAppend()
152
    {
153
        $this->assertAttributeIsSetTo('append', true, 'appendoutput');
154
    }
155
156
    /**
157
     * Tests the parallel configuration setting.
158
     */
159
    public function testPropertySetParallel()
160
    {
161
        $this->assertAttributeIsSetTo('parallel', false);
162
    }
163
164
    /**
165
     * Tests the addsourcefile configuration setting.
166
     */
167
    public function testPropertySetAddsourcefile()
168
    {
169
        $this->assertAttributeIsSetTo('addsourcefile', false);
170
    }
171
172
    /**
173
     * Tests the relative configuration setting.
174
     */
175
    public function testPropertySetRelative()
176
    {
177
        $this->assertAttributeIsSetTo('relative', false);
178
    }
179
180
    /**
181
     * Tests the forwardslash configuration setting.
182
     */
183
    public function testPropertySetForwardslash()
184
    {
185
        $this->assertAttributeIsSetTo('forwardslash', true);
186
    }
187
188
    /**
189
     * Tests the maxparallel configuration setting.
190
     */
191
    public function testPropertySetMaxparallel()
192
    {
193
        $this->assertAttributeIsSetTo('maxparallel', 10);
194
    }
195
196
    /**
197
     * Tests the OS execution for the unspecified OS.
198
     */
199
    public function testDoNotExecuteOnWrongOs()
200
    {
201
        // Process
202
        $this->executeTarget(__FUNCTION__);
203
        $this->assertInLogs('was not found in the specified list of valid OSes: unknownos');
204
205
        $this->assertStringNotContainsString('this should not be executed', $this->getOutput());
206
    }
207
208
    /**
209
     * Tests the OS execution for the specified OS list.
210
     */
211
    public function testExecuteOnCorrectOs()
212
    {
213
        $this->executeTarget(__FUNCTION__);
214
        $this->assertInLogs('this should be executed');
215
    }
216
217
    /**
218
     * Tests the dir changing on a non-existent directory.
219
     */
220
    public function testFailOnNonExistingDir()
221
    {
222
        $nonExistentDir = $this->project->getProperty('php.tmpdir') . DIRECTORY_SEPARATOR
223
            . 'non' . DIRECTORY_SEPARATOR
224
            . 'existent' . DIRECTORY_SEPARATOR
225
            . 'dir';
226
227
        return $this->expectBuildExceptionContaining(
0 ignored issues
show
Are you sure the usage of $this->expectBuildExcept...not a valid directory') targeting Phing\Test\Support\Build...ldExceptionContaining() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
228
            __FUNCTION__,
229
            __FUNCTION__,
230
            "'{$nonExistentDir}' is not a valid directory"
231
        );
232
    }
233
234
    /**
235
     * Tests the dir changing on an existent directory.
236
     *
237
     * @requires OS ^(?:(?!Win).)*$
238
     */
239
    public function testChangeToDir()
240
    {
241
        $this->executeTarget(__FUNCTION__);
242
        $this->assertInLogs('Working directory change successful');
243
    }
244
245
    /**
246
     * Tests the failonerror/checkreturn value for 'true'.
247
     *
248
     * @requires OS ^(?:(?!Win).)*$
249
     */
250
    public function testCheckreturnTrue()
251
    {
252
        $this->executeTarget(__FUNCTION__);
253
        $this->assertTrue(true);
254
    }
255
256
    /**
257
     * Tests the failonerror/checkreturn value for 'false'.
258
     *
259
     * @requires OS ^(?:(?!Win).)*$
260
     */
261
    public function testCheckreturnFalse()
262
    {
263
        return $this->expectBuildExceptionContaining(__FUNCTION__, __FUNCTION__, 'Task exited with code (1)');
0 ignored issues
show
Are you sure the usage of $this->expectBuildExcept... exited with code (1)') targeting Phing\Test\Support\Build...ldExceptionContaining() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
264
    }
265
266
    /**
267
     * Tests the outputProperty setting.
268
     */
269
    public function testOutputProperty()
270
    {
271
        $this->executeTarget(__FUNCTION__);
272
        $this->assertInLogs('The output property\'s value is: "foo"');
273
    }
274
275
    /**
276
     * Tests the returnProperty setting.
277
     */
278
    public function testReturnProperty()
279
    {
280
        $this->executeTarget(__FUNCTION__);
281
        $this->assertInLogs('The return property\'s value is: "1"');
282
    }
283
284
    /**
285
     * Tests the command escaping for execution.
286
     */
287
    public function testEscape()
288
    {
289
        $this->executeTarget(__FUNCTION__);
290
        $this->assertInLogs(
291
            $this->windows
292
                ? (escapeshellarg('echo') . ' ' . escapeshellarg('foo') . ' ' . escapeshellarg('|') . ' ' . escapeshellarg('cat'))
293
                : ("'echo' 'foo' '|' 'cat'")
294
        );
295
    }
296
297
    /**
298
     * Tests the command execution with 'passthru' function.
299
     */
300
    public function testPassThru()
301
    {
302
        $this->executeTarget(__FUNCTION__);
303
        $this->assertInLogs('Executing command:');
304
    }
305
306
    /**
307
     * Tests the output file functionality.
308
     */
309
    public function testOutput()
310
    {
311
        // Getting a temp. file
312
        $tempfile = tempnam(FileUtils::getTempDir(), 'phing-exectest-');
313
314
        // Setting the property
315
        $this->project->setProperty('execTmpFile', $tempfile);
316
        $this->executeTarget(__FUNCTION__);
317
318
        // Validating the output
319
        $output = @file_get_contents($tempfile);
320
        @unlink($tempfile);
321
        $this->assertEquals('outfoo', rtrim($output));
322
    }
323
324
    /**
325
     * Tests the error file functionality.
326
     *
327
     * @requires OS ^(?:(?!Win).)*$
328
     */
329
    public function testError()
330
    {
331
        // Getting a temp. file
332
        $tempfile = tempnam(FileUtils::getTempDir(), 'phing-exectest-');
333
334
        $scriptFile = getcwd() . '/error_output.sh';
335
        file_put_contents($scriptFile, 'echo errfoo 1>&2');
336
        chmod($scriptFile, 0744);
337
338
        // Setting the property
339
        $this->project->setProperty('executable', $scriptFile);
340
        $this->project->setProperty('execTmpFile', $tempfile);
341
        $this->executeTarget(__FUNCTION__);
342
343
        // Validating the output
344
        $output = @file_get_contents($tempfile);
345
        @unlink($tempfile);
346
        @unlink($scriptFile);
347
        $this->assertEquals('errfoo', rtrim($output));
348
    }
349
350
    /**
351
     * Tests the execution with the background process spawning.
352
     *
353
     * @requires OS ^(?:(?!Win).)*$
354
     */
355
    public function testSpawn()
356
    {
357
        // Process
358
        $start = time();
359
        $this->executeTarget(__FUNCTION__);
360
        $end = time();
361
        $this->assertLessThan(
362
            4,
363
            ($end - $start),
364
            'Execution time should be lower than 4 seconds, otherwise spawning did not work'
365
        );
366
    }
367
368
    /**
369
     * Tests the nested arguments specified for the execution.
370
     */
371
    public function testNestedArgs()
372
    {
373
        $this->executeTarget(__FUNCTION__);
374
        $this->assertInLogs('echo Hello World');
375
    }
376
377
    /**
378
     * Tests the missing/unspecified executable information.
379
     */
380
    public function testMissingExecutable()
381
    {
382
        $this->expectBuildExceptionContaining(__FUNCTION__, __FUNCTION__, 'Please provide "executable" information');
383
    }
384
385
    /**
386
     * Tests the escape functionality for special characters in argument.
387
     */
388
    public function testEscapedArg()
389
    {
390
        $this->executeTarget(__FUNCTION__);
391
        $this->assertPropertyEquals('outval', $this->windows ? 'abc$b3 SB' : 'abc$b3!SB');
392
    }
393
394
    /**
395
     * Tests the relative source filenames functionality.
396
     *
397
     * @requires OS ^(?:(?!Win).)*$
398
     */
399
    public function testRelativeSourceFilenames()
400
    {
401
        $this->executeTarget(__FUNCTION__);
402
        $this->assertNotInLogs('/etc/');
403
    }
404
405
    /**
406
     * Tests the source filename addition functionality.
407
     *
408
     * @requires OS ^(?:(?!Win).)*$
409
     */
410
    public function testSourceFilename()
411
    {
412
        $this->executeTarget(__FUNCTION__);
413
        // As the addsourcefilename is 'off', only the executable should be processed in the execution
414
        $this->assertInLogs('Executing command: ls');
415
    }
416
417
    /**
418
     * Tests the output file append functionality.
419
     */
420
    public function testOutputAppend()
421
    {
422
        // Getting a temp. file
423
        $tempfile = tempnam(FileUtils::getTempDir(), 'phing-exectest-');
424
425
        // Setting the property
426
        $this->project->setProperty('execTmpFile', $tempfile);
427
        $this->executeTarget(__FUNCTION__);
428
429
        // Validating the output
430
        $output = @file_get_contents($tempfile);
431
        @unlink($tempfile);
432
        $this->assertEquals($this->windows ? "Append OK \r\nAppend OK" : "Append OK\nAppend OK", rtrim($output));
433
    }
434
435
    /**
436
     * Tests the parallel configuration.
437
     */
438
    public function testParallel()
439
    {
440
        $this->executeTarget(__FUNCTION__);
441
        $messages = [];
442
        foreach ($this->logBuffer as $log) {
443
            $messages[] = $log['message'];
444
        }
445
        $this->assertEquals(1, substr_count(implode("\n", $messages), 'Executing command:'));
446
    }
447
448
    public function testMapperSupport()
449
    {
450
        // Getting a temp. file
451
        $tempfile = tempnam(FileUtils::getTempDir(), 'phing-exectest-');
452
453
        // Setting the property
454
        $this->project->setProperty('execTmpFile', $tempfile);
455
456
        $this->executeTarget(__FUNCTION__);
457
        $messages = [];
458
        foreach ($this->logBuffer as $log) {
459
            $messages[] = $log['message'];
460
        }
461
        $this->assertContains('Applied echo to 4 files and 0 directories.', $messages);
462
    }
463
464
    // H E L P E R  M E T H O D S
465
466
    /**
467
     * @param string $name
468
     *
469
     * @return Target
470
     * @throws Exception
471
     */
472
    protected function getTargetByName(string $name): Target
473
    {
474
        foreach ($this->project->getTargets() as $target) {
475
            if ($target->getName() == $name) {
476
                return $target;
477
            }
478
        }
479
480
        throw new Exception(sprintf('Target "%s" not found', $name));
481
    }
482
483
    /**
484
     * @param $target
485
     * @param string $taskName
486
     * @param int $pos
487
     *
488
     * @return Task
489
     * @throws Exception
490
     */
491
    protected function getTaskFromTarget($target, string $taskName, $pos = 0): Task
492
    {
493
        $rchildren = new ReflectionProperty(get_class($target), 'children');
494
        $rchildren->setAccessible(true);
495
        $n = -1;
496
        foreach ($rchildren->getValue($target) as $child) {
497
            if ($child instanceof Task && ++$n == $pos) {
498
                return $child;
499
            }
500
        }
501
502
        throw new Exception(sprintf('%s #%d not found in task', $taskName, $pos));
503
    }
504
505
    /**
506
     * @param string $target
507
     * @param string $task
508
     *
509
     * @return Task
510
     * @throws Exception
511
     */
512
    protected function getConfiguredTask(string $target, string $task): Task
513
    {
514
        $target = $this->getTargetByName($target);
515
        $task = $this->getTaskFromTarget($target, $task);
516
        $task->maybeConfigure();
517
518
        if ($task instanceof UnknownElement) {
519
            return $task->getRuntimeConfigurableWrapper()->getProxy();
520
        }
521
522
        return $task;
523
    }
524
525
    /**
526
     * @param string $property
527
     * @param mixed $value
528
     * @param null $propertyName
529
     * @throws ReflectionException
530
     */
531
    protected function assertAttributeIsSetTo(string $property, $value, $propertyName = null)
532
    {
533
        $task = $this->getConfiguredTask('testPropertySet' . ucfirst($property), ApplyTask::class);
534
535
        $propertyName = (null === $propertyName) ? $property : $propertyName;
0 ignored issues
show
The condition null === $propertyName is always true.
Loading history...
536
        $rprop = new ReflectionProperty(ApplyTask::class, $propertyName);
537
        $rprop->setAccessible(true);
538
        $this->assertEquals($value, $rprop->getValue($task));
539
    }
540
}
541