Completed
Branch master (cb3538)
by Julian
02:11
created

Options::defaults()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

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