Completed
Pull Request — master (#248)
by
unknown
02:17
created

Options::__isset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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