Completed
Branch master (cb3538)
by Julian
02:11
created

Runner::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
namespace ParaTest\Runners\PHPUnit;
3
4
use Habitat\Habitat;
5
6
class Runner extends BaseRunner
7
{
8
    /**
9
     * A collection of available tokens based on the number
10
     * of processes specified in $options
11
     *
12
     * @var array
13
     */
14
    protected $tokens = [];
15
16
17 8
    public function __construct($opts = [])
18
    {
19 8
        parent::__construct($opts);
20 8
        $this->initTokens();
21 8
    }
22
23
    /**
24
     * The money maker. Runs all ExecutableTest objects in separate processes.
25
     */
26 2
    public function run()
27
    {
28 2
        parent::run();
29
30 2
        while (count($this->running) || count($this->pending)) {
31 2
            foreach ($this->running as $key => $test) {
32 2
                if (!$this->testIsStillRunning($test)) {
33 2
                    unset($this->running[$key]);
34 2
                    $this->releaseToken($key);
35
                }
36
            }
37 2
            $this->fillRunQueue();
38 2
            usleep(10000);
39
        }
40 2
        $this->complete();
41 2
    }
42
43
    /**
44
     * Finalizes the run process. This method
45
     * prints all results, rewinds the log interpreter,
46
     * logs any results to JUnit, and cleans up temporary
47
     * files
48
     */
49 2
    private function complete()
50
    {
51 2
        $this->printer->printResults();
52 2
        $this->interpreter->rewind();
53 2
        $this->log();
54 2
        $this->logCoverage();
55 2
        $readers = $this->interpreter->getReaders();
56 2
        foreach ($readers as $reader) {
57 2
            $reader->removeLog();
58
        }
59 2
    }
60
61
    /**
62
     * This method removes ExecutableTest objects from the pending collection
63
     * and adds them to the running collection. It is also in charge of recycling and
64
     * acquiring available test tokens for use
65
     */
66 2
    private function fillRunQueue()
67
    {
68 2
        $opts = $this->options;
69 2
        while (sizeof($this->pending) && sizeof($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...
70 2
            $tokenData = $this->getNextAvailableToken();
71 2
            if ($tokenData !== false) {
72 2
                $this->acquireToken($tokenData['token']);
73 2
                $env = ['TEST_TOKEN' => $tokenData['token'], 'UNIQUE_TEST_TOKEN' => $tokenData['unique']] + Habitat::getAll();
74 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...
75
            }
76
        }
77 2
    }
78
79
    /**
80
     * Returns whether or not a test has finished being
81
     * executed. If it has, this method also halts a test process - optionally
82
     * throwing an exception if a fatal error has occurred -
83
     * prints feedback, and updates the overall exit code
84
     *
85
     * @param ExecutableTest $test
86
     * @return bool
87
     * @throws \Exception
88
     */
89 2
    private function testIsStillRunning($test)
90
    {
91 2
        if (!$test->isDoneRunning()) {
92 2
            return true;
93
        }
94 2
        $this->setExitCode($test);
95 2
        $test->stop();
96 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...
97
            $this->pending = [];
98
        }
99 2
        if (static::PHPUNIT_FATAL_ERROR === $test->getExitCode()) {
100
            $errorOutput = $test->getStderr();
101
            if (!$errorOutput) {
102
                $errorOutput = $test->getStdout();
103
            }
104
            throw new \Exception($errorOutput);
105
        }
106 2
        $this->printer->printFeedback($test);
107 2
        if ($this->hasCoverage()) {
108 2
            $this->addCoverage($test);
109
        }
110
111 2
        return false;
112
    }
113
114
    /**
115
     * If the provided test object has an exit code
116
     * higher than the currently set exit code, that exit
117
     * code will be set as the overall exit code
118
     *
119
     * @param ExecutableTest $test
120
     */
121 2
    private function setExitCode(ExecutableTest $test)
122
    {
123 2
        $exit = $test->getExitCode();
124 2
        if ($exit > $this->exitcode) {
125 2
            $this->exitcode = $exit;
126
        }
127 2
    }
128
129
    /**
130
     * Initialize the available test tokens based
131
     * on how many processes ParaTest will be run in
132
     */
133 8
    protected function initTokens()
134
    {
135 8
        $this->tokens = [];
136 8
        for ($i = 0; $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...
137 8
            $this->tokens[$i] = ['token' => $i, 'unique' => uniqid($i), 'available' => true];
138
        }
139 8
    }
140
141
    /**
142
     * Gets the next token that is available to be acquired
143
     * from a finished process
144
     *
145
     * @return bool|array
146
     */
147 4
    protected function getNextAvailableToken()
148
    {
149 4
        foreach ($this->tokens as $data) {
150 4
            if ($data['available']) {
151 3
                return $data;
152
            }
153
        }
154 1
        return false;
155
    }
156
157
    /**
158
     * Flag a token as available for use
159
     *
160
     * @param string $tokenIdentifier
161
     */
162 3
    protected function releaseToken($tokenIdentifier)
163
    {
164
        $filtered = array_filter($this->tokens, function ($val) use ($tokenIdentifier) {
165 3
            return ($val['token'] === $tokenIdentifier);
166 3
        });
167 3
        $keys = array_keys($filtered);
168 3
        $this->tokens[$keys[0]]['available'] = true;
169 3
    }
170
171
    /**
172
     * Flag a token as acquired and not available for use
173
     *
174
     * @param string $tokenIdentifier
175
     */
176
    protected function acquireToken($tokenIdentifier)
177
    {
178 2
        $filtered = array_filter($this->tokens, function ($val) use ($tokenIdentifier) {
179 2
            return ($val['token'] === $tokenIdentifier);
180 2
        });
181 2
        $keys = array_keys($filtered);
182 2
        $this->tokens[$keys[0]]['available'] = false;
183 2
    }
184
185
    /**
186
     * @param ExecutableTest $test
187
     */
188 2
    private function addCoverage(ExecutableTest $test)
189
    {
190 2
        $coverageFile = $test->getCoverageFileName();
191 2
        $this->getCoverage()->addCoverageFromFile($coverageFile);
192 2
    }
193
}
194