Completed
Pull Request — master (#203)
by
unknown
02:55
created

Options::__construct()   D

Complexity

Conditions 9
Paths 96

Size

Total Lines 37
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 9.0046

Importance

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