Completed
Pull Request — master (#204)
by
unknown
02:26
created

WrapperRunner::streamsOf()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6
Metric Value
dl 0
loc 8
ccs 0
cts 6
cp 0
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
crap 6
1
<?php
2
namespace ParaTest\Runners\PHPUnit;
3
4
class WrapperRunner extends BaseRunner
5
{
6
    const PHPUNIT_FAILURES = 1;
7
    const PHPUNIT_ERRORS = 2;
8
9
    /**
10
     * @var array
11
     */
12
    protected $streams;
13
14
    /**
15
     * @var Worker[]
16
     */
17
    protected $workers;
18
19
    /**
20
     * @var array
21
     */
22
    protected $modified;
23
24
25
    public function run()
26
    {
27
        parent::run();
28
29
        $this->startWorkers();
30
        $this->assignAllPendingTests();
31
        $this->sendStopMessages();
32
        $this->waitForAllToFinish();
33
        $this->complete();
34
    }
35
36
    protected function load()
37
    {
38
        if ($this->options->functional) {
0 ignored issues
show
Documentation introduced by
The property $functional 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...
39
            throw new \RuntimeException("The `functional` option is not supported yet in the WrapperRunner. Only full classes can be run due to the current PHPUnit commands causing classloading issues.");
40
        }
41
        parent::load();
42
    }
43
44
    private function startWorkers()
45
    {
46
        $wrapper = realpath(__DIR__ . '/../../../../bin/phpunit-wrapper');
47
        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...
48
            $worker = new Worker();
49
            if ($this->options->noTestTokens) {
50
                $token = null;
51
                $uniqueToken = null;
52
            } else {
53
                $token = $i;
54
                $uniqueToken = uniqid();
55
            }
56
            $worker->start($wrapper, $token, $uniqueToken);
57
            $this->streams[] = $worker->stdout();
58
            $this->workers[] = $worker;
59
        }
60
    }
61
62
    private function assignAllPendingTests()
63
    {
64
        $phpunit = $this->options->phpunit;
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...
65
        $phpunitOptions = $this->options->filtered;
0 ignored issues
show
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...
66
        $phpunitOptions['no-globals-backup'] = null;
67
        while (count($this->pending)) {
68
            $this->waitForStreamsToChange($this->streams);
69
            foreach ($this->progressedWorkers() as $worker) {
70
                if ($worker->isFree()) {
71
                    $this->flushWorker($worker);
72
                    $pending = array_shift($this->pending);
73
                    if ($pending) {
74
                        $worker->assign($pending, $phpunit, $phpunitOptions);
75
                    }
76
                }
77
            }
78
        }
79
    }
80
81
    private function sendStopMessages()
82
    {
83
        foreach ($this->workers as $worker) {
84
            $worker->stop();
85
        }
86
    }
87
88
    private function waitForAllToFinish()
89
    {
90
        $toStop = $this->workers;
91
        while (count($toStop) > 0) {
92
            $toCheck = $this->streamsOf($toStop);
93
            $new = $this->waitForStreamsToChange($toCheck);
0 ignored issues
show
Unused Code introduced by
$new is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
94
            foreach ($this->progressedWorkers() as $index => $worker) {
95
                if (!$worker->isRunning()) {
96
                    $this->flushWorker($worker);
97
                    unset($toStop[$index]);
98
                }
99
            }
100
        }
101
    }
102
103
    // put on WorkersPool
104
    private function waitForStreamsToChange($modified)
105
    {
106
        $write = array();
107
        $except = array();
108
        $result = stream_select($modified, $write, $except, 1);
109
        if ($result === false) {
110
            throw new \RuntimeException("stream_select() returned an error while waiting for all workers to finish.");
111
        }
112
        $this->modified = $modified;
113
        return $result;
114
    }
115
116
    /**
117
     * put on WorkersPool
118
     * @return Worker[]
119
     */
120
    private function progressedWorkers()
121
    {
122
        $result = array();
123
        foreach ($this->modified as $modifiedStream) {
124
            $found = null;
125
            foreach ($this->streams as $index => $stream) {
126
                if ($modifiedStream == $stream) {
127
                    $found = $index;
128
                    break;
129
                }
130
            }
131
            $result[$found] = $this->workers[$found];
132
        }
133
        $this->modified = array();
134
        return $result;
135
    }
136
137
    /**
138
     * Returns the output streams of a subset of workers.
139
     * @param array    keys are positions in $this->workers
140
     * @return array
141
     */
142
    private function streamsOf($workers)
143
    {
144
        $streams = array();
145
        foreach (array_keys($workers) as $index) {
146
            $streams[$index] = $this->streams[$index];
147
        }
148
        return $streams;
149
    }
150
151
    private function complete()
152
    {
153
        $this->setExitCode();
154
        $this->printer->printResults();
155
        $this->interpreter->rewind();
156
        $this->log();
157
        $this->logCoverage();
158
        $readers = $this->interpreter->getReaders();
159
        foreach ($readers as $reader) {
160
            $reader->removeLog();
161
        }
162
    }
163
164
165
    private function setExitCode()
166
    {
167
        if ($this->interpreter->getTotalErrors()) {
0 ignored issues
show
Documentation Bug introduced by
The method getTotalErrors does not exist on object<ParaTest\Logging\LogInterpreter>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
168
            $this->exitcode = self::PHPUNIT_ERRORS;
169
        } elseif ($this->interpreter->getTotalFailures()) {
0 ignored issues
show
Documentation Bug introduced by
The method getTotalFailures does not exist on object<ParaTest\Logging\LogInterpreter>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
170
            $this->exitcode = self::PHPUNIT_FAILURES;
171
        } else {
172
            $this->exitcode = 0;
173
        }
174
    }
175
176
    private function flushWorker($worker)
177
    {
178
        if ($this->hasCoverage()) {
179
            $this->addCoverageFromFile($worker->getCoverageFileName());
180
        }
181
        $worker->printFeedback($this->printer);
182
        $worker->reset();
183
    }
184
185
  /**
186
    private function testIsStillRunning($test)
187
    {
188
        if(!$test->isDoneRunning()) return true;
189
        $this->setExitCode($test);
190
        $test->stop();
191
        if (static::PHPUNIT_FATAL_ERROR === $test->getExitCode())
192
            throw new \Exception($test->getStderr(), $test->getExitCode());
193
        return false;
194
    }
195
     */
196
}
197