RSTSpecificationLocator   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 48
c 1
b 0
f 0
dl 0
loc 131
rs 10
wmc 17

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getSuitePaths() 0 13 2
A locateSpecifications() 0 20 4
A findAbsolutePath() 0 17 6
A findFeatureFiles() 0 27 3
A __construct() 0 4 1
A getLocatorExamples() 0 5 1
1
<?php
2
3
namespace Bex\Behat\BehatRSTSpecificationLocatorExtension\Gherkin\Specification\Locator;
4
5
use Behat\Behat\Gherkin\Specification\LazyFeatureIterator;
6
use Behat\Gherkin\Filter\PathsFilter;
7
use Behat\Gherkin\Gherkin;
8
use Behat\Testwork\Specification\Locator\SpecificationLocator;
9
use Behat\Testwork\Specification\NoSpecificationsIterator;
10
use Behat\Testwork\Suite\Exception\SuiteConfigurationException;
11
use Behat\Testwork\Suite\Suite;
12
use RecursiveDirectoryIterator;
13
use RecursiveIteratorIterator;
14
use RegexIterator;
15
16
/**
17
 * Notes:
18
 *
19
 *   The whole class is copy pasted from \Behat\Behat\Gherkin\Specification\Locator\FilesystemFeatureLocator
20
 *
21
 *   Changes compared to the FilesystemFeatureLocator:
22
 *     - getLocatorExamples method content
23
 *     - 1 line change in findFeatureFiles method to look for rst files
24
 *
25
 *    Copy paste was required because the required change was in a private method.
26
 *
27
 *  @TODO Create a BaseFilesystemFeatureLocator and contribute it back to Behat to avoid copy pasting
28
 */
29
class RSTSpecificationLocator implements SpecificationLocator
30
{
31
    /** @var Gherkin */
32
    private $gherkin;
33
34
    /** @var string */
35
    private $basePath;
36
37
    public function __construct(Gherkin $gherkin, $basePath)
38
    {
39
        $this->gherkin = $gherkin;
40
        $this->basePath = $basePath;
41
    }
42
43
    public function getLocatorExamples()
44
    {
45
        return [
46
            'a dir <comment>(features/)</comment>',
47
            'a reStructuredText document <comment>(*.rst)</comment>.'
48
        ];
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function locateSpecifications(Suite $suite, $locator)
55
    {
56
        if (!$suite->hasSetting('paths')) {
57
            return new NoSpecificationsIterator($suite);
58
        }
59
60
        $suiteLocators = $this->getSuitePaths($suite);
61
62
        if ($locator) {
63
            $filters = array(new PathsFilter($suiteLocators));
64
65
            return new LazyFeatureIterator($suite, $this->gherkin, $this->findFeatureFiles($locator), $filters);
66
        }
67
68
        $featurePaths = array();
69
        foreach ($suiteLocators as $suiteLocator) {
70
            $featurePaths = array_merge($featurePaths, $this->findFeatureFiles($suiteLocator));
71
        }
72
73
        return new LazyFeatureIterator($suite, $this->gherkin, $featurePaths);
74
    }
75
76
    /**
77
     * Returns array of feature paths configured for the provided suite.
78
     *
79
     * @param Suite $suite
80
     *
81
     * @return string[]
82
     *
83
     * @throws SuiteConfigurationException If `paths` setting is not an array
84
     */
85
    private function getSuitePaths(Suite $suite)
86
    {
87
        if (!is_array($suite->getSetting('paths'))) {
88
            throw new SuiteConfigurationException(
89
                sprintf('`paths` setting of the "%s" suite is expected to be an array, %s given.',
90
                        $suite->getName(),
91
                        gettype($suite->getSetting('paths'))
92
                ),
93
                $suite->getName()
94
            );
95
        }
96
97
        return $suite->getSetting('paths');
98
    }
99
100
    /**
101
     * Loads feature files paths from provided path.
102
     *
103
     * @param string $path
104
     *
105
     * @return string[]
106
     */
107
    private function findFeatureFiles($path)
108
    {
109
        $absolutePath = $this->findAbsolutePath($path);
110
111
        if (!$absolutePath) {
112
            return array($path);
113
        }
114
115
        if (is_file($absolutePath)) {
116
            return array($absolutePath);
117
        }
118
119
        $iterator = new RegexIterator(
120
            new RecursiveIteratorIterator(
121
                new RecursiveDirectoryIterator(
122
                    $absolutePath,
123
                    RecursiveDirectoryIterator::FOLLOW_SYMLINKS | RecursiveDirectoryIterator::SKIP_DOTS
124
                )
125
            ),
126
            '/^.+\.rst/i',
127
            RegexIterator::MATCH
128
        );
129
130
        $paths = array_map('strval', iterator_to_array($iterator));
131
        uasort($paths, 'strnatcasecmp');
132
133
        return $paths;
134
    }
135
136
    /**
137
     * Finds absolute path for provided relative (relative to base features path).
138
     *
139
     * @param string $path Relative path
140
     *
141
     * @return string
142
     */
143
    private function findAbsolutePath($path)
144
    {
145
        if (is_file($path) || is_dir($path)) {
146
            return realpath($path);
147
        }
148
149
        if (null === $this->basePath) {
150
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
151
        }
152
153
        if (is_file($this->basePath . DIRECTORY_SEPARATOR . $path)
154
            || is_dir($this->basePath . DIRECTORY_SEPARATOR . $path)
155
        ) {
156
            return realpath($this->basePath . DIRECTORY_SEPARATOR . $path);
157
        }
158
159
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
160
    }
161
}