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