Completed
Push — master ( 36acf5...646be7 )
by Alfred
03:12
created

GherkinToDusk   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 321
Duplicated Lines 14.02 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 85.71%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 42
lcom 1
cbo 10
dl 45
loc 321
c 3
b 0
f 0
ccs 126
cts 147
cp 0.8571
rs 8.295

25 Methods

Rating   Name   Duplication   Size   Complexity  
A getWriteBrowserTest() 0 9 2
A setWriteBrowserTest() 0 9 2
B appendFeatures() 21 21 5
B initializeFeature() 24 24 5
A featureToBrowser() 0 10 1
A featureAppendToUnit() 0 8 1
A featureToUnit() 0 10 1
A isComponent() 0 4 1
A setComponent() 0 4 1
A getFeatureContent() 0 4 1
A setFeatureContent() 0 4 1
A loadFileContent() 0 5 1
A passThroughParser() 0 4 1
A getParsedFeature() 0 4 1
A setParsedFeature() 0 4 1
A breakIntoMethods() 0 4 1
A iterateOverScenariosAndBuildUpClassMethods() 0 16 2
A buildOutSteps() 0 11 2
A getDuskClassAndMethods() 0 4 1
A setDuskClassAndMethods() 0 4 1
A getWriteUnitTest() 0 9 2
A setWriteUnitTest() 0 9 2
A getAppendUnitTest() 0 9 2
A setAppendUnitTest() 0 9 2
A checkIfFileExists() 0 8 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like GherkinToDusk often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use GherkinToDusk, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace GD;
4
5
use Behat\Gherkin\Gherkin;
6
use Behat\Gherkin\Keywords\CucumberKeywords;
7
use Behat\Gherkin\Lexer;
8
use Behat\Gherkin\Loader\GherkinFileLoader;
9
use Behat\Gherkin\Loader\YamlFileLoader;
10
use Behat\Gherkin\Parser;
11
use GD\Exceptions\MustSetFileNameAndPath;
12
use GD\Helpers\AppendFile;
13
use GD\Helpers\BuildOutContent;
14
use GD\Helpers\WriteBrowserFile;
15
use GD\Helpers\WritePHPUnitFile;
16
use Illuminate\Filesystem\Filesystem;
17
use Illuminate\Support\Facades\App;
18
use Symfony\Component\Yaml\Yaml;
19
20
class GherkinToDusk extends BaseGherkinToDusk
21
{
22
    use BuildOutContent;
23
24
    protected $component = false;
25
26
    protected $string_contents = null;
27
28
    /**
29
     * Yml Content of a test yml
30
     * @var string
31
     */
32
    protected $feature_content;
33
34
    /**
35
     * @var \Behat\Gherkin\Node\FeatureNode
36
     */
37
    protected $parsed_feature;
38
39
    /**
40
     *
41
     */
42
    protected $dusk_class_and_methods;
43
44
45
    /**
46
     * @var WritePHPUnitFile
47
     */
48
    protected $write_unit_test;
49
50
    /**
51
     * @var AppendFile
52
     */
53
    protected $append_unit_test;
54
55
    /**
56
     * @var WriteBrowserFile
57
     */
58
    protected $write_browser_test;
59
    
60 12 View Code Duplication
    public function appendFeatures()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
61
    {
62 12
        $this->loadFileContent();
63 12
        $this->buildDuskTestName();
64 12
        $this->passThroughParser();
65 12
        $this->breakIntoMethods();
66
67 12
        switch ($this->context) {
68 12
            case 'unit':
69 12
            case 'domain':
70 12
                $this->featureAppendToUnit();
71 9
                break;
72
            case 'ui':
73
            case 'browser':
74
                //$this->featureToBrowser();
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
75
                break;
76
            default:
77
                //more coming soon
78
                break;
79 6
        }
80 9
    }
81
82 27 View Code Duplication
    public function initializeFeature()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
83
    {
84 27
        $this->loadFileContent();
85
86 27
        $this->buildDuskTestName();
87
88 27
        $this->passThroughParser();
89
90 27
        $this->breakIntoMethods();
91
92 27
        switch ($this->context) {
93 27
            case 'unit':
94 27
            case 'domain':
95 21
                $this->featureToUnit();
96 18
                break;
97 6
            case 'ui':
98 6
            case 'browser':
99 6
                $this->featureToBrowser();
100 6
                break;
101
            default:
102
                //more coming soon
103
                break;
104 16
        }
105 24
    }
106
107 6
    protected function featureToBrowser()
108
    {
109 6
        $this->checkIfFileExists();
110
111 6
        $this->getWriteBrowserTest()->writeTest(
112 6
            $this->getDestinationFolderRoot(),
113 6
            $this->getDuskTestName(),
114 6
            $this->getDuskClassAndMethods()
115 4
        );
116 6
    }
117
118 12
    protected function featureAppendToUnit()
119
    {
120 12
        $this->getAppendUnitTest()->writeTest(
121 12
            $this->getDestinationFolderRoot(),
122 12
            $this->getDuskTestName(),
123 12
            $this->getDuskClassAndMethods()
124 8
        );
125 9
    }
126
    
127 21
    protected function featureToUnit()
128
    {
129 21
        $this->checkIfFileExists();
130
131 18
        $this->getWriteUnitTest()->writeTest(
132 18
            $this->getDestinationFolderRoot(),
133 18
            $this->getDuskTestName(),
134 18
            $this->getDuskClassAndMethods()
135 12
        );
136 18
    }
137
138
139
    /**
140
     * @return boolean
141
     */
142
    public function isComponent()
143
    {
144
        return $this->component;
145
    }
146
147
    /**
148
     * @param boolean $component
149
     */
150
    public function setComponent($component)
151
    {
152
        $this->component = $component;
153
    }
154
155
    /**
156
     * @return mixed
157
     */
158 3
    public function getFeatureContent()
159
    {
160 3
        return $this->feature_content;
161
    }
162
163
    /**
164
     * @param mixed $feature_content
165
     */
166
    public function setFeatureContent($feature_content)
167
    {
168
        $this->feature_content = $feature_content;
169
    }
170
171 39
    private function loadFileContent()
172
    {
173 39
        $this->feature_content =
174 39
            $this->getFilesystem()->get($this->getFullPathToFileAndFileName());
175 39
    }
176
177 39
    private function passThroughParser()
178
    {
179 39
        $this->parsed_feature = $this->getParser()->parse($this->feature_content);
180 39
    }
181
182
    /**
183
     * @return \Behat\Gherkin\Node\FeatureNode
184
     */
185 3
    public function getParsedFeature()
186
    {
187 3
        return $this->parsed_feature;
188
    }
189
190
    /**
191
     * @param \Behat\Gherkin\Node\FeatureNode $parsed_feature
192
     */
193
    public function setParsedFeature($parsed_feature)
194
    {
195
        $this->parsed_feature = $parsed_feature;
196
    }
197
198 39
    private function breakIntoMethods()
199
    {
200 39
        $this->iterateOverScenariosAndBuildUpClassMethods();
201 39
    }
202
203 39
    private function iterateOverScenariosAndBuildUpClassMethods()
204
    {
205
        /** @var  $feature \Behat\Gherkin\Node\ScenarioNode */
206 39
        foreach ($this->parsed_feature->getScenarios() as $scenario_index => $scenario) {
207 39
            $parent_method_name = ucfirst(camel_case($scenario->getTitle()));
208
209 39
            $parent_method_name_camelized_and_prefix_test = sprintf('test%s', $parent_method_name);
210
211 39
            $this->dusk_class_and_methods[$scenario_index] = [
212 39
                'parent' => $parent_method_name_camelized_and_prefix_test,
213 39
                'parent_content' => $this->getParentLevelContent($parent_method_name_camelized_and_prefix_test)
214 26
            ];
215
216 39
            $this->buildOutSteps($scenario, $scenario_index);
217 26
        }
218 39
    }
219
220
    /**
221
     * @param $scenario \Behat\Gherkin\Node\ScenarioNode
222
     */
223 39
    protected function buildOutSteps($scenario, $scenario_index)
224
    {
225 39
        foreach ($scenario->getSteps() as $step_index => $step) {
226 39
            $method_name = camel_case(sprintf("%s %s", $step->getKeyword(), $step->getText()));
227 39
            $step_method_name_camalized = camel_case(sprintf("%s %s", $step->getKeyword(), $step->getText()));
228 39
            $this->dusk_class_and_methods[$scenario_index]['steps'][$step_index]['name'] =
229
                $method_name;
230 39
            $this->dusk_class_and_methods[$scenario_index]['steps'][$step_index] =
231 39
                $this->getStepLevelContent($step_method_name_camalized);
232 26
        }
233 39
    }
234
235
236
237
    /**
238
     * @return mixed
239
     */
240 36
    public function getDuskClassAndMethods()
241
    {
242 36
        return $this->dusk_class_and_methods;
243
    }
244
245
    /**
246
     * @param mixed $dusk_class_and_methods
247
     */
248
    public function setDuskClassAndMethods($dusk_class_and_methods)
249
    {
250
        $this->dusk_class_and_methods = $dusk_class_and_methods;
251
    }
252
253
254
255 6
    public function getWriteBrowserTest()
256
    {
257
258 6
        if (!$this->write_browser_test) {
259 6
            $this->setWriteBrowserTest();
260 4
        }
261
262 6
        return $this->write_browser_test;
263
    }
264
265
    /**
266
     * @param null $write_browser_test
267
     * @return GherkinToDusk
268
     * @internal param WritePHPUnitFile $write_unit_test
269
     */
270 6
    public function setWriteBrowserTest($write_browser_test = null)
271
    {
272 6
        if (!$write_browser_test) {
273 6
            $write_browser_test = new WriteBrowserFile();
274 4
        }
275
276 6
        $this->write_browser_test = $write_browser_test;
277 6
        return $this;
278
    }
279
280
281 18
    public function getWriteUnitTest()
282
    {
283
284 18
        if (!$this->write_unit_test) {
285 18
            $this->setWriteUnitTest();
286 12
        }
287
288 18
        return $this->write_unit_test;
289
    }
290
291
    /**
292
     * @param WritePHPUnitFile $write_unit_test
293
     * @return GherkinToDusk
294
     */
295 18
    public function setWriteUnitTest($write_unit_test = null)
296
    {
297 18
        if (!$write_unit_test) {
298 18
            $write_unit_test = new WritePHPUnitFile();
299 12
        }
300
301 18
        $this->write_unit_test = $write_unit_test;
302 18
        return $this;
303
    }
304
305
    /**
306
     * @return $append_unit_test AppendFile
0 ignored issues
show
Documentation introduced by
The doc-type $append_unit_test could not be parsed: Unknown type name "$append_unit_test" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
307
     */
308 12
    public function getAppendUnitTest()
309
    {
310
311 12
        if (!$this->append_unit_test) {
312 12
            $this->setAppendUnitTest();
313 8
        }
314
315 12
        return $this->append_unit_test;
316
    }
317
318
    /**
319
     * @param AppendFile $append_unit_test
320
     * @return GherkinToDusk
321
     */
322 12
    public function setAppendUnitTest($append_unit_test = null)
323
    {
324 12
        if (!$append_unit_test) {
325 12
            $append_unit_test = new AppendFile();
326 8
        }
327
328 12
        $this->append_unit_test = $append_unit_test;
329 12
        return $this;
330
    }
331
332 27
    private function checkIfFileExists()
333
    {
334 27
        if ($this->filesystem->exists($this->fullPathToDestinationFile())) {
335 3
            $path = $this->fullPathToDestinationFile();
336 3
            $message = sprintf("The test file exists already %s please use `append` command", $path);
337 3
            throw new \GD\Exceptions\TestFileExists($message);
338
        }
339 24
    }
340
}
341