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

BuildFileTest   F

Complexity

Total Complexity 74

Size/Duplication

Total Lines 498
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 74
eloc 177
dl 0
loc 498
rs 2.48
c 0
b 0
f 0

28 Methods

Rating   Name   Duplication   Size   Complexity  
A getOutput() 0 3 1
A cleanBuffer() 0 23 5
A assertPropertyUnset() 0 3 1
A expectBuildException() 0 3 1
A expectBuildExceptionContaining() 0 26 5
A expectOutputAndError() 0 7 1
A assertFileSizeAtLeast() 0 9 2
B getRelativeDate() 0 48 11
A getResource() 0 3 1
A assertNotInLogs() 0 16 4
B rmdir() 0 18 7
A configureProject() 0 10 1
A expectSpecificBuildException() 0 18 4
A expectPropertyUnset() 0 3 1
A getBuildException() 0 3 1
A assertPropertyEquals() 0 4 1
A expectOutput() 0 5 1
A executeTarget() 0 11 2
A expectLog() 0 4 1
A expectLogContaining() 0 4 1
A getProjectDir() 0 3 1
A assertPropertySet() 0 3 1
A expectDebuglog() 0 4 1
A getProject() 0 3 1
A getError() 0 3 1
B assertLogLineContaining() 0 26 8
A expectPropertySet() 0 4 1
B assertInLogs() 0 23 8

How to fix   Complexity   

Complex Class

Complex classes like BuildFileTest 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 BuildFileTest, 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\Support;
21
22
use Phing\Exception\BuildException;
23
use Phing\Io\File;
24
use Phing\Parser\ProjectConfigurator;
25
use Phing\Project;
26
use PHPUnit\Framework\TestCase;
27
28
/**
29
 * A BuildFileTest is a TestCase which executes targets from a Phing buildfile
30
 * for testing.
31
 *
32
 * This class provides a number of utility methods for particular build file
33
 * tests which extend this class.
34
 *
35
 * @author Nico Seessle <[email protected]>
36
 * @author Conor MacNeill
37
 * @author Victor Farazdagi <[email protected]>
38
 */
39
abstract class BuildFileTest extends TestCase
40
{
41
    /** @var Project */
42
    protected $project;
43
44
    /**
45
     * @var array Array of log BuildEvent objects.
46
     */
47
    public $logBuffer = [];
48
49
    /**
50
     * @var array
51
     */
52
    private $outBuffer;
53
54
    /**
55
     * @var array
56
     */
57
    private $errBuffer;
58
59
    /**
60
     * @var BuildException
61
     */
62
    private $buildException;
63
64
    /**
65
     * Asserts that the log buffer contains specified message at specified priority.
66
     * @param string $expected Message subsctring
67
     * @param int $priority Message priority (default: any)
68
     * @param string $errormsg The error message to display.
69
     */
70
    protected function assertInLogs($expected, $priority = null, $errormsg = "Expected to find '%s' in logs: %s")
71
    {
72
        $found = false;
73
        foreach ($this->logBuffer as $log) {
74
            if (false !== stripos($log['message'], $expected)) {
75
                $this->assertEquals(1, 1); // increase number of positive assertions
76
                if ($priority === null) {
77
                    return;
78
                } elseif ($priority !== null) {
79
                    if ($priority >= $log['priority']) {
80
                        $found = true;
81
                    }
82
                }
83
            }
84
            if ($found) {
85
                return;
86
            }
87
        }
88
        $representation = [];
89
        foreach ($this->logBuffer as $log) {
90
            $representation[] = "[msg=\"{$log['message']}\",priority={$log['priority']}]";
91
        }
92
        $this->fail(sprintf($errormsg, $expected, var_export($representation, true)));
93
    }
94
95
    /**
96
     * Asserts that the log buffer contains specified message at specified priority.
97
     * @param string $expected Message subsctring
98
     * @param int $priority Message priority (default: any)
99
     * @param string $errormsg The error message to display.
100
     */
101
    protected function assertLogLineContaining(
102
        $expected,
103
        $priority = null,
104
        $errormsg = "Expected to find a log line that starts with '%s': %s"
105
    ) {
106
        $found = false;
107
        foreach ($this->logBuffer as $log) {
108
            if (false !== strpos($log['message'], $expected)) {
109
                $this->assertEquals(1, 1); // increase number of positive assertions
110
                if ($priority === null) {
111
                    return;
112
                } elseif ($priority !== null) {
113
                    if ($priority >= $log['priority']) {
114
                        $found = true;
115
                    }
116
                }
117
            }
118
            if ($found) {
119
                return;
120
            }
121
        }
122
        $representation = [];
123
        foreach ($this->logBuffer as $log) {
124
            $representation[] = "[msg=\"{$log['message']}\",priority={$log['priority']}]";
125
        }
126
        $this->fail(sprintf($errormsg, $expected, var_export($representation, true)));
127
    }
128
129
    /**
130
     * Asserts that the log buffer does NOT contain specified message at specified priority.
131
     * @param string $message Message subsctring
132
     * @param int $priority Message priority (default: any)
133
     * @param string $errormsg The error message to display.
134
     */
135
    protected function assertNotInLogs(
136
        $message,
137
        $priority = null,
0 ignored issues
show
Unused Code introduced by
The parameter $priority 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

137
        /** @scrutinizer ignore-unused */ $priority = null,

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...
138
        $errormsg = "Unexpected string '%s' found in logs: %s"
139
    ) {
140
        foreach ($this->logBuffer as $log) {
141
            if (false !== stripos($log['message'], $message)) {
142
                $representation = [];
143
                foreach ($this->logBuffer as $log) {
0 ignored issues
show
Comprehensibility Bug introduced by
$log is overwriting a variable from outer foreach loop.
Loading history...
144
                    $representation[] = "[msg=\"{$log['message']}\",priority={$log['priority']}]";
145
                }
146
                $this->fail(sprintf($errormsg, $message, var_export($representation, true)));
147
            }
148
        }
149
150
        $this->assertEquals(1, 1); // increase number of positive assertions
151
    }
152
153
    /**
154
     *  run a target, expect for any build exception
155
     *
156
     * @param string $target target to run
157
     * @param string $cause information string to reader of report
158
     */
159
    protected function expectBuildException($target, $cause)
160
    {
161
        $this->expectSpecificBuildException($target, $cause, null);
162
    }
163
164
    /**
165
     * Assert that only the given message has been logged with a
166
     * priority &gt;= INFO when running the given target.
167
     */
168
    protected function expectLog($target, $log)
169
    {
170
        $this->executeTarget($target);
171
        $this->assertInLogs($log);
172
    }
173
174
    /**
175
     * Assert that the given message has been logged with a priority
176
     * &gt;= INFO when running the given target.
177
     */
178
    protected function expectLogContaining($target, $log)
179
    {
180
        $this->executeTarget($target);
181
        $this->assertInLogs($log);
182
    }
183
184
    /**
185
     * Assert that the given message has been logged with a priority
186
     * &gt;= DEBUG when running the given target.
187
     */
188
    protected function expectDebuglog($target, $log)
189
    {
190
        $this->executeTarget($target);
191
        $this->assertInLogs($log, Project::MSG_DEBUG);
192
    }
193
194
    /**
195
     *  execute the target, verify output matches expectations
196
     *
197
     * @param string $target target to execute
198
     * @param string $output output to look for
199
     */
200
    protected function expectOutput($target, $output)
201
    {
202
        $this->executeTarget($target);
203
        $realOutput = $this->getOutput();
204
        $this->assertEquals($output, $realOutput);
205
    }
206
207
    /**
208
     *  execute the target, verify output matches expectations
209
     *  and that we got the named error at the end
210
     * @param string $target target to execute
211
     * @param string $output output to look for
212
     * @param string $error Description of Parameter
213
     */
214
215
    protected function expectOutputAndError($target, $output, $error)
216
    {
217
        $this->executeTarget($target);
218
        $realOutput = $this->getOutput();
219
        $this->assertEquals($output, $realOutput);
220
        $realError = $this->getError();
221
        $this->assertEquals($error, $realError);
222
    }
223
224
    protected function getOutput()
225
    {
226
        return $this->cleanBuffer($this->outBuffer);
227
    }
228
229
    protected function getError()
230
    {
231
        return $this->cleanBuffer($this->errBuffer);
232
    }
233
234
    protected function getBuildException()
235
    {
236
        return $this->buildException;
237
    }
238
239
    private function cleanBuffer($buffer)
240
    {
241
        $cleanedBuffer = "";
242
        $cr = false;
243
        for ($i = 0, $bufflen = strlen($buffer); $i < $bufflen; $i++) {
244
            $ch = $buffer[$i];
245
            if ($ch == "\r") {
246
                $cr = true;
247
                continue;
248
            }
249
250
            if (!$cr) {
251
                $cleanedBuffer .= $ch;
252
            } else {
253
                if ($ch == "\n") {
254
                    $cleanedBuffer .= $ch;
255
                } else {
256
                    $cleanedBuffer .= "\r" . $ch;
257
                }
258
            }
259
        }
260
261
        return $cleanedBuffer;
262
    }
263
264
    /**
265
     *  set up to run the named project
266
     *
267
     * @param string $filename name of project file to run
268
     * @throws BuildException
269
     */
270
    protected function configureProject($filename)
271
    {
272
        $this->logBuffer = [];
273
        $this->project = new Project();
274
        $this->project->init();
275
        $f = new File($filename);
276
        $this->project->setUserProperty("phing.file", $f->getAbsolutePath());
277
        $this->project->setUserProperty("phing.dir", dirname($f->getAbsolutePath()));
278
        $this->project->addBuildListener(new PhingTestListener($this));
279
        ProjectConfigurator::configureProject($this->project, new File($filename));
280
    }
281
282
    /**
283
     *  execute a target we have set up
284
     * @pre configureProject has been called
285
     * @param string $targetName target to run
286
     */
287
    protected function executeTarget($targetName)
288
    {
289
        if (empty($this->project)) {
290
            return;
291
        }
292
293
        $this->outBuffer = "";
0 ignored issues
show
Documentation Bug introduced by
It seems like '' of type string is incompatible with the declared type array of property $outBuffer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
294
        $this->errBuffer = "";
0 ignored issues
show
Documentation Bug introduced by
It seems like '' of type string is incompatible with the declared type array of property $errBuffer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
295
        $this->logBuffer = [];
296
        $this->buildException = null;
297
        $this->project->executeTarget($targetName);
298
    }
299
300
    /**
301
     * Get the project which has been configured for a test.
302
     *
303
     * @return Project the Project instance for this test.
304
     */
305
    protected function getProject()
306
    {
307
        return $this->project;
308
    }
309
310
    /**
311
     * get the directory of the project
312
     * @return File the base dir of the project
313
     */
314
    protected function getProjectDir()
315
    {
316
        return $this->project->getBasedir();
317
    }
318
319
    /**
320
     *  run a target, wait for a build exception
321
     *
322
     * @param string $target target to run
323
     * @param string $cause information string to reader of report
324
     * @param string $msg the message value of the build exception we are waiting for
325
     * set to null for any build exception to be valid
326
     */
327
    protected function expectSpecificBuildException($target, $cause, $msg)
328
    {
329
        try {
330
            $this->executeTarget($target);
331
        } catch (BuildException $ex) {
332
            $this->buildException = $ex;
333
            if (($msg !== null) && ($ex->getMessage() != $msg)) {
334
                $this->fail(
335
                    "Should throw BuildException because '" . $cause
336
                    . "' with message '" . $msg
337
                    . "' (actual message '" . $ex->getMessage() . "' instead)"
338
                );
339
            }
340
            $this->assertEquals(1, 1); // increase number of positive assertions
341
342
            return;
343
        }
344
        $this->fail("Should throw BuildException because: " . $cause);
345
    }
346
347
    /**
348
     *  run a target, expect an exception string
349
     *  containing the substring we look for (case sensitive match)
350
     *
351
     * @param string $target target to run
352
     * @param string $cause information string to reader of report
353
     * @param string $contains substring of the build exception to look for
354
     */
355
    protected function expectBuildExceptionContaining($target, $cause, $contains)
356
    {
357
        try {
358
            $this->executeTarget($target);
359
        } catch (BuildException $ex) {
360
            $this->buildException = $ex;
361
            $found = false;
362
            while ($ex) {
363
                $msg = $ex->getMessage();
364
                if (false !== strpos($ex->getMessage(), $contains)) {
365
                    $found = true;
366
                }
367
                $ex = $ex->getPrevious();
368
            };
369
370
            if (!$found) {
371
                $this->fail(
372
                    "Should throw BuildException because '" . $cause . "' with message containing '" . $contains
373
                    . "' (actual message '" . $msg . "' instead)"
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $msg does not seem to be defined for all execution paths leading up to this point.
Loading history...
374
                );
375
            }
376
377
            $this->assertEquals(1, 1); // increase number of positive assertions
378
            return;
379
        }
380
        $this->fail("Should throw BuildException because: " . $cause);
381
    }
382
383
    /**
384
     * call a target, verify property is as expected
385
     *
386
     * @param string $target build file target
387
     * @param string $property property name
388
     * @param string $value expected value
389
     */
390
391
    protected function expectPropertySet($target, $property, $value = "true")
392
    {
393
        $this->executeTarget($target);
394
        $this->assertPropertyEquals($property, $value);
395
    }
396
397
    /**
398
     * assert that a property equals a value; comparison is case sensitive.
399
     * @param string $property property name
400
     * @param string $value expected value
401
     */
402
    protected function assertPropertyEquals($property, $value)
403
    {
404
        $result = $this->project->getProperty($property);
405
        $this->assertEquals($value, $result, "property " . $property);
406
    }
407
408
    /**
409
     * assert that a property equals &quot;true&quot;
410
     * @param string $property property name
411
     */
412
    protected function assertPropertySet($property)
413
    {
414
        $this->assertPropertyEquals($property, "true");
415
    }
416
417
    /**
418
     * assert that a property is null
419
     * @param string $property property name
420
     */
421
    protected function assertPropertyUnset($property)
422
    {
423
        $this->assertPropertyEquals($property, null);
424
    }
425
426
    /**
427
     * call a target, verify property is null
428
     * @param string $target build file target
429
     * @param string $property property name
430
     */
431
    protected function expectPropertyUnset($target, $property)
432
    {
433
        $this->expectPropertySet($target, $property, null);
434
    }
435
436
    /**
437
     * Retrieve a resource from the caller classloader to avoid
438
     * assuming a vm working directory. The resource path must be
439
     * relative to the package name or absolute from the root path.
440
     * @param resource $resource the resource to retrieve its url.
441
     * @throws BuildException if resource is not found.
442
     */
443
    protected function getResource($resource)
0 ignored issues
show
Unused Code introduced by
The parameter $resource 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

443
    protected function getResource(/** @scrutinizer ignore-unused */ $resource)

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...
444
    {
445
        throw new BuildException("getResource() not yet implemented");
446
        //$url = ggetClass().getResource(resource);
447
        //assertNotNull("Could not find resource :" + resource, url);
448
        //return url;
449
    }
450
451
    protected function rmdir($dir)
452
    {
453
        if (!file_exists($dir)) {
454
            return true;
455
        }
456
        if (!is_dir($dir)) {
457
            return unlink($dir);
458
        }
459
        foreach (scandir($dir) as $item) {
460
            if ($item === '.' || $item === '..') {
461
                continue;
462
            }
463
            if (!$this->rmdir($dir . DIRECTORY_SEPARATOR . $item)) {
464
                return false;
465
            }
466
        }
467
468
        return rmdir($dir);
469
    }
470
471
    /**
472
     * Get relative date
473
     *
474
     * @param int $timestamp Timestamp to us as pin-point
475
     * @param string $type Whether 'fulldate' or 'time'
476
     * @return string
477
     */
478
    protected function getRelativeDate($timestamp, $type = 'fulldate')
0 ignored issues
show
Unused Code introduced by
The parameter $type 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

478
    protected function getRelativeDate($timestamp, /** @scrutinizer ignore-unused */ $type = 'fulldate')

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...
479
    {
480
        // calculate the diffrence
481
        $timediff = time() - $timestamp;
482
483
        if ($timediff < 3600) {
484
            if ($timediff < 120) {
485
                $returndate = "1 minute ago";
486
            } else {
487
                $returndate = ceil($timediff / 60) . " minutes ago";
488
            }
489
        } else {
490
            if ($timediff < 7200) {
491
                $returndate = "1 hour ago.";
492
            } else {
493
                if ($timediff < 86400) {
494
                    $returndate = ceil($timediff / 3600) . " hours ago";
495
                } else {
496
                    if ($timediff < 172800) {
497
                        $returndate = "1 day ago.";
498
                    } else {
499
                        if ($timediff < 604800) {
500
                            $returndate = ceil($timediff / 86400) . " days ago";
501
                        } else {
502
                            if ($timediff < 1209600) {
503
                                $returndate = ceil($timediff / 86400) . " days ago";
504
                            } else {
505
                                if ($timediff < 2629744) {
506
                                    $returndate = ceil($timediff / 86400) . " days ago";
507
                                } else {
508
                                    if ($timediff < 3024000) {
509
                                        $returndate = ceil($timediff / 604900) . " weeks ago";
510
                                    } else {
511
                                        if ($timediff > 5259486) {
512
                                            $returndate = ceil($timediff / 2629744) . " months ago";
513
                                        } else {
514
                                            $returndate = ceil($timediff / 604900) . " weeks ago";
515
                                        }
516
                                    }
517
                                }
518
                            }
519
                        }
520
                    }
521
                }
522
            }
523
        }
524
525
        return $returndate;
526
    }
527
528
    public function assertFileSizeAtLeast(string $filepath, int $bytes)
529
    {
530
        $actualSize = filesize($filepath);
531
532
        if (!is_int($actualSize)) {
0 ignored issues
show
introduced by
The condition is_int($actualSize) is always true.
Loading history...
533
            $this->fail("Error while reading file '$filepath'");
534
        }
535
536
        $this->assertGreaterThanOrEqual($bytes, $actualSize);
537
    }
538
}
539