Completed
Pull Request — master (#217)
by
unknown
03:02
created

Options   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 269
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 1

Test Coverage

Coverage 95%

Importance

Changes 12
Bugs 8 Features 3
Metric Value
wmc 29
c 12
b 8
f 3
lcom 2
cbo 1
dl 0
loc 269
ccs 95
cts 100
cp 0.95
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
D __construct() 0 38 9
A __get() 0 4 1
A defaults() 0 17 1
A phpunit() 0 16 3
A vendorDir() 0 9 2
A filterOptions() 0 22 2
A getConfigurationPath() 0 7 2
A getDefaultConfigurationForPath() 0 16 4
A initAnnotations() 0 9 3
A isFile() 0 4 2
1
<?php
2
namespace ParaTest\Runners\PHPUnit;
3
4
/**
5
 * Class Options
6
 *
7
 * An object containing all configurable information used
8
 * to run PHPUnit via ParaTest
9
 *
10
 * @package ParaTest\Runners\PHPUnit
11
 */
12
class Options
13
{
14
    /**
15
     * The number of processes to run at a time
16
     *
17
     * @var int
18
     */
19
    protected $processes;
20
21
    /**
22
     * The test path pointing to tests that will
23
     * be run
24
     *
25
     * @var string
26
     */
27
    protected $path;
28
29
    /**
30
     * The path to the PHPUnit binary that will be run
31
     *
32
     * @var string
33
     */
34
    protected $phpunit;
35
36
    /**
37
     * Determines whether or not ParaTest runs in
38
     * functional mode. If enabled, ParaTest will run
39
     * every test method in a separate process
40
     *
41
     * @var string
42
     */
43
    protected $functional;
44
45
    /**
46
     * Prevents starting new tests after a test has failed.
47
     *
48
     * @var boolean
49
     */
50
    protected $stopOnFailure;
51
52
    /**
53
     * A collection of post-processed option values. This is the collection
54
     * containing ParaTest specific options
55
     *
56
     * @var array
57
     */
58
    protected $filtered;
59
60
    /**
61
     * The number of times that a test needs to be repeated.
62
     *
63
     * @var int
64
     */
65
    protected $repeat;
66
67
    /**
68
     * A collection of option values directly corresponding
69
     * to certain annotations - i.e group
70
     *
71
     * @var array
72
     */
73
    protected $annotations = array();
74
75 42
    public function __construct($opts = array())
76
    {
77 42
        foreach (self::defaults() as $opt => $value) {
78 42
            $opts[$opt] = isset($opts[$opt]) ? $opts[$opt] : $value;
79 42
        }
80
81 42
        $this->processes = $opts['processes'];
82 42
        $this->path = $opts['path'];
83 42
        $this->phpunit = $opts['phpunit'];
84 42
        $this->functional = $opts['functional'];
85 42
        $this->stopOnFailure = $opts['stop-on-failure'];
86 42
        $this->runner = $opts['runner'];
0 ignored issues
show
Bug introduced by
The property runner does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
87 42
        $this->noTestTokens = $opts['no-test-tokens'];
0 ignored issues
show
Bug introduced by
The property noTestTokens does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
88 42
        $this->colors = $opts['colors'];
0 ignored issues
show
Bug introduced by
The property colors does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
89 42
        $this->testsuite = $opts['testsuite'];
0 ignored issues
show
Bug introduced by
The property testsuite does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
90 42
        $this->maxBatchSize = $opts['max-batch-size'];
0 ignored issues
show
Bug introduced by
The property maxBatchSize does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
91 42
        $this->filter = $opts['filter'];
0 ignored issues
show
Bug introduced by
The property filter does not seem to exist. Did you mean filtered?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
92 42
        $this->repeat = $opts['repeat'];
93
94
        // we need to register that options if they are blank but do not get them as
95
        // key with null value in $this->filtered as it will create problems for
96
        // phpunit command line generation (it will add them in command line with no value
97
        // and it's wrong because group and exclude-group options require value when passed
98
        // to phpunit)
99 42
        $this->groups = isset($opts['group']) && $opts['group'] !== ""
0 ignored issues
show
Bug introduced by
The property groups does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
100 42
                      ? explode(",", $opts['group'])
101 42
                      : array();
102 42
        $this->excludeGroups = isset($opts['exclude-group']) && $opts['exclude-group'] !== ""
0 ignored issues
show
Bug introduced by
The property excludeGroups does not seem to exist. Did you mean groups?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
103 42
                             ? explode(",", $opts['exclude-group'])
104 42
                             : array();
105
106 42
        if (strlen($opts['filter']) > 0 && !$this->functional) {
107
            throw new \RuntimeException("Option --filter is not implemented for non functional mode");
108
        }
109
110 42
        $this->filtered = $this->filterOptions($opts);
111 42
        $this->initAnnotations();
112 42
    }
113
114
    /**
115
     * Public read accessibility
116
     *
117
     * @param $var
118
     * @return mixed
119
     */
120 40
    public function __get($var)
121
    {
122 40
        return $this->$var;
123
    }
124
125
    /**
126
     * Returns a collection of ParaTest's default
127
     * option values
128
     *
129
     * @return array
130
     */
131 42
    protected static function defaults()
132
    {
133
        return array(
134 42
            'processes' => 5,
135 42
            'path' => '',
136 42
            'phpunit' => static::phpunit(),
137 42
            'functional' => false,
138 42
            'stop-on-failure' => false,
139 42
            'runner' => 'Runner',
140 42
            'no-test-tokens' => false,
141 42
            'colors' => false,
142 42
            'testsuite' => '',
143 42
            'max-batch-size' => 0,
144 42
            'filter' => null,
145
            'repeat' => 1
146 42
        );
147
    }
148
149
    /**
150
     * Get the path to phpunit
151
     * First checks if a Windows batch script is in the composer vendors directory.
152
     * Composer automatically handles creating a .bat file, so if on windows this should be the case.
153
     * Second look for the phpunit binary under nix
154
     * Defaults to phpunit on the users PATH
155
     * @return string $phpunit the path to phpunit
156
     */
157 42
    protected static function phpunit()
158
    {
159 42
        $vendor  = static::vendorDir();
160 42
        $phpunit = $vendor . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'phpunit';
161 42
        $batch = $phpunit . '.bat';
162
163 42
        if (file_exists($batch)) {
164
            return $batch;
165
        }
166
167 42
        if (file_exists($phpunit)) {
168 42
            return $phpunit;
169
        }
170
171
        return 'phpunit';
172
    }
173
174
    /**
175
     * Get the path to the vendor directory
176
     * First assumes vendor directory is accessible from src (i.e development)
177
     * Second assumes vendor directory is accessible within src
178
     */
179 42
    protected static function vendorDir()
180
    {
181 42
        $vendor = dirname(dirname(dirname(dirname(__DIR__)))) . DIRECTORY_SEPARATOR . 'vendor';
182 42
        if (!file_exists($vendor)) {
183
            $vendor = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__))))));
184
        }
185
186 42
        return $vendor;
187
    }
188
189
    /**
190
     * Filter options to distinguish between paratest
191
     * internal options and any other options
192
     * @param  array $options
193
     * @return array
194
     */
195 42
    protected function filterOptions($options)
196
    {
197 42
        $filtered = array_diff_key($options, array(
198 42
            'processes' => $this->processes,
199 42
            'path' => $this->path,
200 42
            'phpunit' => $this->phpunit,
201 42
            'functional' => $this->functional,
202 42
            'stop-on-failure' => $this->stopOnFailure,
203 42
            'runner' => $this->runner,
204 42
            'no-test-tokens' => $this->noTestTokens,
205 42
            'colors' => $this->colors,
206 42
            'testsuite' => $this->testsuite,
207 42
            'max-batch-size' => $this->maxBatchSize,
208 42
            'filter' => $this->filter,
0 ignored issues
show
Bug introduced by
The property filter does not seem to exist. Did you mean filtered?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
209 42
            'repeat' => $this->repeat
210 42
        ));
211 42
        if ($configuration = $this->getConfigurationPath($filtered)) {
212 42
            $filtered['configuration'] = new Configuration($configuration);
213 42
        }
214
215 42
        return $filtered;
216
    }
217
218
    /**
219
     * Take an array of filtered options and return a
220
     * configuration path
221
     *
222
     * @param $filtered
223
     * @return string|null
224
     */
225 42
    protected function getConfigurationPath($filtered)
226
    {
227 42
        if (isset($filtered['configuration'])) {
228 18
            return $this->getDefaultConfigurationForPath($filtered['configuration'], $filtered['configuration']);
229
        }
230 28
        return $this->getDefaultConfigurationForPath();
231
    }
232
233
    /**
234
     * Retrieve the default configuration given a path (directory or file).
235
     * This will search into the directory, if a directory is specified
236
     *
237
     * @param string $path The path to search into
238
     * @param string $default The default value to give back
239
     * @return string|null
240
     */
241 42
    private function getDefaultConfigurationForPath($path = '.', $default = null)
242
    {
243 42
        if ($this->isFile($path)) {
244 15
            return realpath($path);
245
        }
246
247 28
        $path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
248 28
        $suffixes = array('phpunit.xml', 'phpunit.xml.dist');
249
250 28
        foreach ($suffixes as $suffix) {
251 28
            if ($this->isFile($path . $suffix)) {
252 28
                return realpath($path . $suffix);
253
            }
254 28
        }
255 4
        return $default;
256
    }
257
258
    /**
259
     * Load options that are represented by annotations
260
     * inside of tests i.e @group group1 = --group group1
261
     */
262 42
    protected function initAnnotations()
263
    {
264 42
        $annotatedOptions = array('group');
265 42
        foreach ($this->filtered as $key => $value) {
266 42
            if (array_search($key, $annotatedOptions) !== false) {
267 14
                $this->annotations[$key] = $value;
268 14
            }
269 42
        }
270 42
    }
271
272
    /**
273
     * @param $file
274
     * @return bool
275
     */
276 42
    private function isFile($file)
277
    {
278 42
        return file_exists($file) && !is_dir($file);
279
    }
280
}
281