Runner   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 190
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 93.75%

Importance

Changes 0
Metric Value
wmc 29
lcom 1
cbo 7
dl 0
loc 190
ccs 75
cts 80
cp 0.9375
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
B run() 0 16 5
A complete() 0 11 2
A fillRunQueue() 0 12 4
C testIsStillRunning() 0 24 7
A setExitCode() 0 7 2
A addCoverage() 0 5 1
A getNextAvailableToken() 0 10 3
A releaseToken() 0 8 1
A acquireToken() 0 8 1
A initTokens() 0 7 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ParaTest\Runners\PHPUnit;
6
7
use Habitat\Habitat;
8
9
class Runner extends BaseRunner
10
{
11
    /**
12
     * A collection of available tokens based on the number
13
     * of processes specified in $options.
14
     *
15
     * @var array
16
     */
17
    protected $tokens = [];
18
19 8
    public function __construct(array $opts = [])
20
    {
21 8
        parent::__construct($opts);
22 8
        $this->initTokens();
23 8
    }
24
25
    /**
26
     * The money maker. Runs all ExecutableTest objects in separate processes.
27
     */
28 2
    public function run()
29
    {
30 2
        parent::run();
31
32 2
        while (count($this->running) || count($this->pending)) {
33 2
            foreach ($this->running as $key => $test) {
34 2
                if (!$this->testIsStillRunning($test)) {
35 2
                    unset($this->running[$key]);
36 2
                    $this->releaseToken($key);
37
                }
38
            }
39 2
            $this->fillRunQueue();
40 2
            usleep(10000);
41
        }
42 2
        $this->complete();
43 2
    }
44
45
    /**
46
     * Finalizes the run process. This method
47
     * prints all results, rewinds the log interpreter,
48
     * logs any results to JUnit, and cleans up temporary
49
     * files.
50
     */
51 2
    private function complete()
52
    {
53 2
        $this->printer->printResults();
54 2
        $this->interpreter->rewind();
55 2
        $this->log();
56 2
        $this->logCoverage();
57 2
        $readers = $this->interpreter->getReaders();
58 2
        foreach ($readers as $reader) {
59 2
            $reader->removeLog();
60
        }
61 2
    }
62
63
    /**
64
     * This method removes ExecutableTest objects from the pending collection
65
     * and adds them to the running collection. It is also in charge of recycling and
66
     * acquiring available test tokens for use.
67
     */
68 2
    private function fillRunQueue()
69
    {
70 2
        $opts = $this->options;
71 2
        while (count($this->pending) && count($this->running) < $opts->processes) {
0 ignored issues
show
Documentation introduced by
The property $processes is declared protected in ParaTest\Runners\PHPUnit\Options. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
72 2
            $tokenData = $this->getNextAvailableToken();
73 2
            if ($tokenData !== false) {
74 2
                $this->acquireToken($tokenData['token']);
75 2
                $env = ['TEST_TOKEN' => $tokenData['token'], 'UNIQUE_TEST_TOKEN' => $tokenData['unique']] + Habitat::getAll();
76 2
                $this->running[$tokenData['token']] = array_shift($this->pending)->run($opts->phpunit, $opts->filtered, $env);
0 ignored issues
show
Documentation introduced by
The property $phpunit is declared protected in ParaTest\Runners\PHPUnit\Options. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation introduced by
The property $filtered is declared protected in ParaTest\Runners\PHPUnit\Options. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
77
            }
78
        }
79 2
    }
80
81
    /**
82
     * Returns whether or not a test has finished being
83
     * executed. If it has, this method also halts a test process - optionally
84
     * throwing an exception if a fatal error has occurred -
85
     * prints feedback, and updates the overall exit code.
86
     *
87
     * @param ExecutableTest $test
88
     *
89
     * @throws \Exception
90
     *
91
     * @return bool
92
     */
93 2
    private function testIsStillRunning(ExecutableTest $test): bool
94
    {
95 2
        if (!$test->isDoneRunning()) {
96 2
            return true;
97
        }
98 2
        $this->setExitCode($test);
99 2
        $test->stop();
100 2
        if ($this->options->stopOnFailure && $test->getExitCode() > 0) {
0 ignored issues
show
Documentation introduced by
The property $stopOnFailure is declared protected in ParaTest\Runners\PHPUnit\Options. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
101
            $this->pending = [];
102
        }
103 2
        if (static::PHPUNIT_FATAL_ERROR === $test->getExitCode()) {
104
            $errorOutput = $test->getStderr();
105
            if (!$errorOutput) {
106
                $errorOutput = $test->getStdout();
107
            }
108
            throw new \Exception($errorOutput);
109
        }
110 2
        $this->printer->printFeedback($test);
111 2
        if ($this->hasCoverage()) {
112 2
            $this->addCoverage($test);
113
        }
114
115 2
        return false;
116
    }
117
118
    /**
119
     * If the provided test object has an exit code
120
     * higher than the currently set exit code, that exit
121
     * code will be set as the overall exit code.
122
     *
123
     * @param ExecutableTest $test
124
     */
125 2
    private function setExitCode(ExecutableTest $test)
126
    {
127 2
        $exit = $test->getExitCode();
128 2
        if ($exit > $this->exitcode) {
129 2
            $this->exitcode = $exit;
130
        }
131 2
    }
132
133
    /**
134
     * Initialize the available test tokens based
135
     * on how many processes ParaTest will be run in.
136
     */
137 8
    protected function initTokens()
138
    {
139 8
        $this->tokens = [];
140 8
        for ($i = 1; $i <= $this->options->processes; ++$i) {
0 ignored issues
show
Documentation introduced by
The property $processes is declared protected in ParaTest\Runners\PHPUnit\Options. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
141 8
            $this->tokens[$i] = ['token' => $i, 'unique' => uniqid(sprintf('%s_', $i)), 'available' => true];
142
        }
143 8
    }
144
145
    /**
146
     * Gets the next token that is available to be acquired
147
     * from a finished process.
148
     *
149
     * @return bool|array
150
     */
151 4
    protected function getNextAvailableToken()
152
    {
153 4
        foreach ($this->tokens as $data) {
154 4
            if ($data['available']) {
155 4
                return $data;
156
            }
157
        }
158
159 1
        return false;
160
    }
161
162
    /**
163
     * Flag a token as available for use.
164
     *
165
     * @param string $tokenIdentifier
166
     */
167
    protected function releaseToken($tokenIdentifier)
168
    {
169 3
        $filtered = array_filter($this->tokens, function ($val) use ($tokenIdentifier) {
170 3
            return $val['token'] === $tokenIdentifier;
171 3
        });
172 3
        $keys = array_keys($filtered);
173 3
        $this->tokens[$keys[0]]['available'] = true;
174 3
    }
175
176
    /**
177
     * Flag a token as acquired and not available for use.
178
     *
179
     * @param string $tokenIdentifier
180
     */
181
    protected function acquireToken($tokenIdentifier)
182
    {
183 2
        $filtered = array_filter($this->tokens, function ($val) use ($tokenIdentifier) {
184 2
            return $val['token'] === $tokenIdentifier;
185 2
        });
186 2
        $keys = array_keys($filtered);
187 2
        $this->tokens[$keys[0]]['available'] = false;
188 2
    }
189
190
    /**
191
     * @param ExecutableTest $test
192
     */
193 2
    private function addCoverage(ExecutableTest $test)
194
    {
195 2
        $coverageFile = $test->getCoverageFileName();
196 2
        $this->getCoverage()->addCoverageFromFile($coverageFile);
197 2
    }
198
}
199