Completed
Pull Request — master (#162)
by
unknown
02:07
created

FeatureNode   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 240
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 0

Test Coverage

Coverage 92.16%

Importance

Changes 0
Metric Value
wmc 20
lcom 3
cbo 0
dl 0
loc 240
ccs 47
cts 51
cp 0.9216
rs 10
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 21 1
A getNodeType() 0 4 1
A getTitle() 0 4 1
A hasDescription() 0 4 1
A getDescription() 0 4 1
A hasTag() 0 4 1
A hasTags() 0 4 1
A getTags() 0 4 1
A hasBackground() 0 4 1
A getBackground() 0 4 1
A hasScenarios() 0 4 1
A getScenarios() 0 18 5
A getKeyword() 0 4 1
A getLanguage() 0 4 1
A getFile() 0 4 1
A getLine() 0 4 1
1
<?php
2
3
/*
4
 * This file is part of the Behat Gherkin.
5
 * (c) Konstantin Kudryashov <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Behat\Gherkin\Node;
12
13
/**
14
 * Represents Gherkin Feature.
15
 *
16
 * @author Konstantin Kudryashov <[email protected]>
17
 */
18
class FeatureNode implements KeywordNodeInterface, TaggedNodeInterface
19
{
20
    /**
21
     * @var null|string
22
     */
23
    private $title;
24
    /**
25
     * @var null|string
26
     */
27
    private $description;
28
    /**
29
     * @var string[]
30
     */
31
    private $tags = array();
32
    /**
33
     * @var null|BackgroundNode
34
     */
35
    private $background;
36
    /**
37
     * @var ScenarioInterface[]
38
     */
39
    private $scenarios = array();
40
    /**
41
     * @var string
42
     */
43
    private $keyword;
44
    /**
45
     * @var string
46
     */
47
    private $language;
48
    /**
49
     * @var null|string
50
     */
51
    private $file;
52
    /**
53
     * @var integer
54
     */
55
    private $line;
56
57
    /**
58
     * Initializes feature.
59
     *
60
     * @param null|string         $title
61
     * @param null|string         $description
62
     * @param string[]            $tags
63
     * @param null|BackgroundNode $background
64
     * @param ScenarioInterface[] $scenarios
65
     * @param string              $keyword
66
     * @param string              $language
67
     * @param null|string         $file
68
     * @param integer             $line
69
     */
70 236
    public function __construct(
71
        $title,
72
        $description,
73
        array $tags,
74
        BackgroundNode $background = null,
75
        array $scenarios,
76
        $keyword,
77
        $language,
78
        $file,
79
        $line
80
    ) {
81 236
        $this->title = $title;
82 236
        $this->description = $description;
83 236
        $this->tags = $tags;
84 236
        $this->background = $background;
85 236
        $this->scenarios = $scenarios;
86 236
        $this->keyword = $keyword;
87 236
        $this->language = $language;
88 236
        $this->file = $file;
89 236
        $this->line = $line;
90 236
    }
91
92
    /**
93
     * Returns node type string
94
     *
95
     * @return string
96
     */
97 1
    public function getNodeType()
98
    {
99 1
        return 'Feature';
100
    }
101
102
    /**
103
     * Returns feature title.
104
     *
105
     * @return null|string
106
     */
107 13
    public function getTitle()
108
    {
109 13
        return $this->title;
110
    }
111
112
    /**
113
     * Checks if feature has a description.
114
     *
115
     * @return Boolean
116
     */
117
    public function hasDescription()
118
    {
119
        return !empty($this->description);
120
    }
121
122
    /**
123
     * Returns feature description.
124
     *
125
     * @return null|string
126
     */
127 13
    public function getDescription()
128
    {
129 13
        return $this->description;
130
    }
131
132
    /**
133
     * Checks if feature is tagged with tag.
134
     *
135
     * @param string $tag
136
     *
137
     * @return Boolean
138
     */
139
    public function hasTag($tag)
140
    {
141
        return in_array($tag, $this->tags);
142
    }
143
144
    /**
145
     * Checks if feature has tags.
146
     *
147
     * @return Boolean
148
     */
149 2
    public function hasTags()
150
    {
151 2
        return 0 < count($this->tags);
152
    }
153
154
    /**
155
     * Returns feature tags.
156
     *
157
     * @return string[]
158
     */
159 11
    public function getTags()
160
    {
161 11
        return $this->tags;
162
    }
163
164
    /**
165
     * Checks if feature has background.
166
     *
167
     * @return Boolean
168
     */
169 15
    public function hasBackground()
170
    {
171 15
        return null !== $this->background;
172
    }
173
174
    /**
175
     * Returns feature background.
176
     *
177
     * @return null|BackgroundNode
178
     */
179 11
    public function getBackground()
180
    {
181 11
        return $this->background;
182
    }
183
184
    /**
185
     * Checks if feature has scenarios.
186
     *
187
     * @return Boolean
188
     */
189 2
    public function hasScenarios()
190
    {
191 2
        return 0 < count($this->scenarios);
192
    }
193
194
    /**
195
     * Returns feature scenarios.
196
     *
197
     * @return ScenarioInterface[]
198
     */
199 14
    public function getScenarios()
200
    {
201 14
        if (!$this->hasBackground() || !$this->background->hasExamples()) {
202 12
            return $this->scenarios;
203
        }
204 2
        $scenarios = array();
205 2
        foreach ($this->scenarios as $scenario) {
206 2
            if ($scenario instanceof OutlineNode) {
207 2
                array_push($scenarios, $scenario);
208 2
                continue;
209
            }
210 1
            array_push(
211 1
                $scenarios,
212 1
                $scenario->getScenarioOutline($this->getBackground()->getExamples())
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Gherkin\Node\ScenarioInterface as the method getScenarioOutline() does only exist in the following implementations of said interface: Behat\Gherkin\Node\ScenarioNode.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
213
            );
214
        }
215 2
        return $scenarios;
216
    }
217
218
    /**
219
     * Returns feature keyword.
220
     *
221
     * @return string
222
     */
223 8
    public function getKeyword()
224
    {
225 8
        return $this->keyword;
226
    }
227
228
    /**
229
     * Returns feature language.
230
     *
231
     * @return string
232
     */
233 9
    public function getLanguage()
234
    {
235 9
        return $this->language;
236
    }
237
238
    /**
239
     * Returns feature file.
240
     *
241
     * @return null|string
242
     */
243 13
    public function getFile()
244
    {
245 13
        return $this->file;
246
    }
247
248
    /**
249
     * Returns feature declaration line number.
250
     *
251
     * @return integer
252
     */
253 16
    public function getLine()
254
    {
255 16
        return $this->line;
256
    }
257
}
258