Completed
Pull Request — master (#218)
by
unknown
03:00
created

Options::__construct()   D

Complexity

Conditions 9
Paths 96

Size

Total Lines 39
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 9.0036

Importance

Changes 10
Bugs 6 Features 5
Metric Value
c 10
b 6
f 5
dl 0
loc 39
ccs 27
cts 28
cp 0.9643
rs 4.909
cc 9
eloc 26
nc 96
nop 1
crap 9.0036
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
     * Whether or not should repeat only the failing tests.
69
     *
70
     * @var int
71
     */
72
    protected $only_repeat_failed;
73
74
    /**
75
     * A collection of option values directly corresponding
76
     * to certain annotations - i.e group
77
     *
78
     * @var array
79
     */
80
    protected $annotations = array();
81
82 42
    public function __construct($opts = array())
83
    {
84 42
        foreach (self::defaults() as $opt => $value) {
85 42
            $opts[$opt] = isset($opts[$opt]) ? $opts[$opt] : $value;
86 42
        }
87
88 42
        $this->processes = $opts['processes'];
89 42
        $this->path = $opts['path'];
90 42
        $this->phpunit = $opts['phpunit'];
91 42
        $this->functional = $opts['functional'];
92 42
        $this->stopOnFailure = $opts['stop-on-failure'];
93 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...
94 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...
95 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...
96 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...
97 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...
98 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...
99 42
        $this->repeat = $opts['repeat'];
100 42
        $this->only_repeat_failed = $opts['only-repeat-failed'];
101
102
        // we need to register that options if they are blank but do not get them as
103
        // key with null value in $this->filtered as it will create problems for
104
        // phpunit command line generation (it will add them in command line with no value
105
        // and it's wrong because group and exclude-group options require value when passed
106
        // to phpunit)
107 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...
108 42
                      ? explode(",", $opts['group'])
109 42
                      : array();
110 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...
111 42
                             ? explode(",", $opts['exclude-group'])
112 42
                             : array();
113
114 42
        if (strlen($opts['filter']) > 0 && !$this->functional) {
115
            throw new \RuntimeException("Option --filter is not implemented for non functional mode");
116
        }
117
118 42
        $this->filtered = $this->filterOptions($opts);
119 42
        $this->initAnnotations();
120 42
    }
121
122
    /**
123
     * Public read accessibility
124
     *
125
     * @param $var
126
     * @return mixed
127
     */
128 40
    public function __get($var)
129
    {
130 40
        return $this->$var;
131
    }
132
133
    /**
134
     * Returns a collection of ParaTest's default
135
     * option values
136
     *
137
     * @return array
138
     */
139 42
    protected static function defaults()
140
    {
141
        return array(
142 42
            'processes' => 5,
143 42
            'path' => '',
144 42
            'phpunit' => static::phpunit(),
145 42
            'functional' => false,
146 42
            'stop-on-failure' => false,
147 42
            'runner' => 'Runner',
148 42
            'no-test-tokens' => false,
149 42
            'colors' => false,
150 42
            'testsuite' => '',
151 42
            'max-batch-size' => 0,
152 42
            'filter' => null,
153 42
            'repeat' => 1,
154 42
            'only-repeat-failed' => 0,
155 42
        );
156
    }
157
158
    /**
159
     * Get the path to phpunit
160
     * First checks if a Windows batch script is in the composer vendors directory.
161
     * Composer automatically handles creating a .bat file, so if on windows this should be the case.
162
     * Second look for the phpunit binary under nix
163
     * Defaults to phpunit on the users PATH
164
     * @return string $phpunit the path to phpunit
165
     */
166 42
    protected static function phpunit()
167
    {
168 42
        $vendor  = static::vendorDir();
169 42
        $phpunit = $vendor . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'phpunit';
170 42
        $batch = $phpunit . '.bat';
171
172 42
        if (file_exists($batch)) {
173
            return $batch;
174
        }
175
176 42
        if (file_exists($phpunit)) {
177 42
            return $phpunit;
178
        }
179
180
        return 'phpunit';
181
    }
182
183
    /**
184
     * Get the path to the vendor directory
185
     * First assumes vendor directory is accessible from src (i.e development)
186
     * Second assumes vendor directory is accessible within src
187
     */
188 42
    protected static function vendorDir()
189
    {
190 42
        $vendor = dirname(dirname(dirname(dirname(__DIR__)))) . DIRECTORY_SEPARATOR . 'vendor';
191 42
        if (!file_exists($vendor)) {
192
            $vendor = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__))))));
193
        }
194
195 42
        return $vendor;
196
    }
197
198
    /**
199
     * Filter options to distinguish between paratest
200
     * internal options and any other options
201
     * @param  array $options
202
     * @return array
203
     */
204 42
    protected function filterOptions($options)
205
    {
206 42
        $filtered = array_diff_key($options, array(
207 42
            'processes' => $this->processes,
208 42
            'path' => $this->path,
209 42
            'phpunit' => $this->phpunit,
210 42
            'functional' => $this->functional,
211 42
            'stop-on-failure' => $this->stopOnFailure,
212 42
            'runner' => $this->runner,
213 42
            'no-test-tokens' => $this->noTestTokens,
214 42
            'colors' => $this->colors,
215 42
            'testsuite' => $this->testsuite,
216 42
            'max-batch-size' => $this->maxBatchSize,
217 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...
218 42
            'repeat' => $this->repeat,
219 42
            'only-repeat-failed' => $this->only_repeat_failed,
220 42
        ));
221 42
        if ($configuration = $this->getConfigurationPath($filtered)) {
222 42
            $filtered['configuration'] = new Configuration($configuration);
223 42
        }
224
225 42
        return $filtered;
226
    }
227
228
    /**
229
     * Take an array of filtered options and return a
230
     * configuration path
231
     *
232
     * @param $filtered
233
     * @return string|null
234
     */
235 42
    protected function getConfigurationPath($filtered)
236
    {
237 42
        if (isset($filtered['configuration'])) {
238 18
            return $this->getDefaultConfigurationForPath($filtered['configuration'], $filtered['configuration']);
239
        }
240 28
        return $this->getDefaultConfigurationForPath();
241
    }
242
243
    /**
244
     * Retrieve the default configuration given a path (directory or file).
245
     * This will search into the directory, if a directory is specified
246
     *
247
     * @param string $path The path to search into
248
     * @param string $default The default value to give back
249
     * @return string|null
250
     */
251 42
    private function getDefaultConfigurationForPath($path = '.', $default = null)
252
    {
253 42
        if ($this->isFile($path)) {
254 15
            return realpath($path);
255
        }
256
257 28
        $path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
258 28
        $suffixes = array('phpunit.xml', 'phpunit.xml.dist');
259
260 28
        foreach ($suffixes as $suffix) {
261 28
            if ($this->isFile($path . $suffix)) {
262 28
                return realpath($path . $suffix);
263
            }
264 28
        }
265 4
        return $default;
266
    }
267
268
    /**
269
     * Load options that are represented by annotations
270
     * inside of tests i.e @group group1 = --group group1
271
     */
272 42
    protected function initAnnotations()
273
    {
274 42
        $annotatedOptions = array('group');
275 42
        foreach ($this->filtered as $key => $value) {
276 42
            if (array_search($key, $annotatedOptions) !== false) {
277 14
                $this->annotations[$key] = $value;
278 14
            }
279 42
        }
280 42
    }
281
282
    /**
283
     * @param $file
284
     * @return bool
285
     */
286 42
    private function isFile($file)
287
    {
288 42
        return file_exists($file) && !is_dir($file);
289
    }
290
}
291