LocatorProcessor   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 98
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 98
rs 10
wmc 14
lcom 0
cbo 6

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A configure() 0 12 1
C process() 0 57 12
1
<?php
2
3
namespace SilverStripe\BehatExtension\Console\Processor;
4
5
use Symfony\Component\DependencyInjection\ContainerInterface;
6
use Symfony\Component\Console\Command\Command;
7
use Symfony\Component\Console\Input\InputArgument;
8
use Symfony\Component\Console\Input\InputInterface;
9
use Symfony\Component\Console\Output\OutputInterface;
10
11
use Behat\Behat\Console\Processor\LocatorProcessor as BaseProcessor;
12
13
/**
14
 * Path locator processor.
15
 */
16
class LocatorProcessor extends BaseProcessor
17
{
18
    private $container;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
19
20
    /**
21
     * Constructs processor.
22
     *
23
     * @param ContainerInterface $container Container instance
24
     */
25
    public function __construct(ContainerInterface $container)
26
    {
27
        $this->container = $container;
28
    }
29
30
    /**
31
     * Configures command to be able to process it later.
32
     *
33
     * @param Command $command
34
     */
35
    public function configure(Command $command)
36
    {
37
        $command->addArgument(
38
            'features',
39
            InputArgument::OPTIONAL,
40
            "Feature(s) to run. Could be:".
41
            "\n- a dir (<comment>src/to/module/Features/</comment>), " .
42
            "\n- a feature (<comment>src/to/module/Features/*.feature</comment>), " .
43
            "\n- a scenario at specific line (<comment>src/to/module/Features/*.feature:10</comment>). " .
44
            "\n- Also, you can use short module notation (<comment>@moduleName/*.feature:10</comment>)"
45
        );
46
    }
47
48
    /**
49
     * Processes data from container and console input.
50
     *
51
     * @param InputInterface  $input
52
     * @param OutputInterface $output
53
     *
54
     * @throws \RuntimeException
55
     */
56
    public function process(InputInterface $input, OutputInterface $output)
57
    {
58
        $featuresPath = $input->getArgument('features');
59
        
60
        // Can't use 'behat.paths.base' since that's locked at this point to base folder (not module)
61
        $pathSuffix   = $this->container->getParameter('behat.silverstripe_extension.context.path_suffix');
62
63
        $currentModuleName = null;
0 ignored issues
show
Unused Code introduced by
$currentModuleName is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
64
        $modules = \SS_ClassLoader::instance()->getManifest()->getModules();
65
66
        // get module specified in behat.yml
67
        $currentModuleName = $this->container->getParameter('behat.silverstripe_extension.module');
68
69
        // get module from short notation if path starts from @
70
        if ($featuresPath && preg_match('/^\@([^\/\\\\]+)(.*)$/', $featuresPath, $matches)) {
71
            $currentModuleName = $matches[1];
72
            // TODO Replace with proper module loader once AJShort's changes are merged into core
73
            $currentModulePath = $modules[$currentModuleName];
74
            $featuresPath = str_replace(
75
                '@'.$currentModuleName,
76
                $currentModulePath.DIRECTORY_SEPARATOR.$pathSuffix,
77
                $featuresPath
78
            );
79
        // get module from provided features path
80
        } elseif (!$currentModuleName && $featuresPath) {
81
            $path = realpath(preg_replace('/\.feature\:.*$/', '.feature', $featuresPath));
82
            foreach ($modules as $moduleName => $modulePath) {
83
                if (false !== strpos($path, realpath($modulePath))) {
84
                    $currentModuleName = $moduleName;
85
                    $currentModulePath = realpath($modulePath);
86
                    break;
87
                }
88
            }
89
            $featuresPath = $currentModulePath.DIRECTORY_SEPARATOR.$pathSuffix.DIRECTORY_SEPARATOR.$featuresPath;
0 ignored issues
show
Bug introduced by
The variable $currentModulePath does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
90
        // if module is configured for profile and feature provided
91
        } elseif ($currentModuleName && $featuresPath) {
92
            $currentModulePath = $modules[$currentModuleName];
93
            $featuresPath = $currentModulePath.DIRECTORY_SEPARATOR.$pathSuffix.DIRECTORY_SEPARATOR.$featuresPath;
94
        }
95
96
        if ($input->getOption('namespace')) {
97
            $namespace = $input->getOption('namespace');
98
        } else {
99
            $namespace = ucfirst($currentModuleName);
100
        }
101
102
        if ($currentModuleName) {
103
            $this->container
104
                ->get('behat.silverstripe_extension.context.class_guesser')
105
                // TODO Improve once modules can declare their own namespaces consistently
106
                ->setNamespaceBase($namespace);
107
        }
108
109
        $this->container
110
            ->get('behat.console.command')
111
            ->setFeaturesPaths($featuresPath ? array($featuresPath) : array());
112
    }
113
}
114