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