Completed
Push — develop ( a98fd2...49ed8e )
by Jaap
09:10
created

ApiContext::gatherContexts()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 6
rs 9.4285
1
<?php
2
/**
3
 * This file is part of phpDocumentor.
4
 *
5
 *  For the full copyright and license information, please view the LICENSE
6
 *  file that was distributed with this source code.
7
 *
8
 * @copyright 2010-2017 Mike van Riel<[email protected]>
9
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
10
 * @link      http://phpdoc.org
11
 */
12
13
namespace phpDocumentor\Behat\Contexts\Ast;
14
15
use Behat\Behat\Context\Context;
16
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
17
use Behat\Gherkin\Node\PyStringNode;
18
use phpDocumentor\Behat\Contexts\EnvironmentContext;
19
use phpDocumentor\Descriptor\ClassDescriptor;
20
use phpDocumentor\Descriptor\Collection;
21
use phpDocumentor\Descriptor\DescriptorAbstract;
22
use phpDocumentor\Descriptor\FileDescriptor;
23
use phpDocumentor\Descriptor\ProjectDescriptor;
24
use phpDocumentor\Descriptor\Tag\VersionDescriptor;
25
use phpDocumentor\Reflection\DocBlock\Tag\SeeTag;
26
use PHPUnit\Framework\Assert;
27
28
class ApiContext extends BaseContext implements Context
29
{
30
    /**
31
     * @Then /^the AST has a class named "([^"]*)" in file "([^"]*)"$/
32
     * @throws \Exception
33
     */
34
    public function theASTHasAclassNamedInFile($class, $file)
35
    {
36
        $ast = $this->getAst();
37
38
        /** @var FileDescriptor $fileDescriptor */
39
        $fileDescriptor = $ast->getFiles()->get($file);
40
41
        /** @var ClassDescriptor $classDescriptor */
42
        foreach ($fileDescriptor->getClasses() as $classDescriptor) {
43
            if ($classDescriptor->getName() === $class) {
44
                return;
45
            }
46
        }
47
48
        throw new \Exception(sprintf('Didn\'t find expected class "%s" in "%s"', $class, $file));
49
    }
50
51
    /**
52
     * @Then /^the class named "([^"]*)" is in the default package$/
53
     * @throws \Exception
54
     */
55
    public function theASTHasAClassInDefaultPackage($class)
56
    {
57
        $class = $this->findClassByName($class);
58
59
        Assert::assertEquals('Default', $class->getPackage()->getName());
60
    }
61
62
    /**
63
     * @param $class
64
     * @param $expectedContent
65
     * @Then the class named ":class" has docblock with content:
66
     */
67
    public function classHasDocblockWithContent($class, PyStringNode $expectedContent)
68
    {
69
        $class = $this->findClassByName($class);
70
71
        Assert::assertEquals($expectedContent->getRaw(), $class->getDescription());
72
    }
73
74
    /**
75
     * @param $classFqsen
76
     * @param $docElement
77
     * @param $value
78
     * @Then class ":classFqsen" has :docElement:
79
     * @throws \Exception
80
     */
81
    public function classHasDocblockContent($classFqsen, $docElement, PyStringNode $value)
82
    {
83
        $class = $this->findClassByFqsen($classFqsen);
84
85
        $method = 'get' . $docElement;
86
87
        Assert::assertEquals($value->getRaw(), $class->$method());
88
    }
89
90
    /**
91
     * @param $classFqsen
92
     * @param $elementType
93
     * @param $elementName
94
     * @param $docElement
95
     * @param PyStringNode $value
96
     * @Then class ":classFqsen" has :elementType :elementName with :docElement:
97
     */
98
    public function classHasElementWithDocblockContent($classFqsen, $elementType, $elementName, $docElement, PyStringNode $value)
99
    {
100
        $class = $this->findClassByFqsen($classFqsen);
101
102
        switch ($elementType) {
103
            case 'method':
104
            case 'constant':
105
                $method = $method = 'get' . $elementType . 's';
106
                break;
107
            case 'property':
108
                $method = 'getProperties';
109
                break;
110
            default:
111
                $method = 'get' . $elementType;
112
                break;
113
        }
114
115
        $element = $class-> $method()->get($elementName);
116
117
        $method = 'get' . $docElement;
118
        $actual = $element->$method();
119
120
        Assert::assertEquals($value->getRaw(), $actual);
121
    }
122
123
    /**
124
     * @param $classFqsen
125
     * @param $value
126
     * @Then class ":classFqsen" has version :value
127
     */
128
    public function classHasVersion($classFqsen, $value)
129
    {
130
        $class = $this->findClassByFqsen($classFqsen);
131
132
        /** @var VersionDescriptor $tag */
133
        foreach ($class->getVersion() as $tag) {
134
            if ($tag->getVersion() === $value) {
135
                return;
136
            }
137
        }
138
139
        Assert::fail(sprintf('Didn\'t find expected version "%s"', $value));
140
    }
141
142
    /**
143
     * @param $classFqsen
144
     * @param $tagName
145
     * @Then class ":classFqsen" without tag :tagName
146
     */
147
    public function classWithoutTag($classFqsen, $tagName)
148
    {
149
        $this->classHasTag($classFqsen, $tagName, 0);
150
    }
151
152
    /**
153
     * @param string $classFqsen
154
     * @param string $tagName
155
     * @param int $expectedNumber
156
     * @Then class ":classFqsen" has exactly :expectedNumber tag :tagName
157
     */
158
    public function classHasTag($classFqsen, $tagName, $expectedNumber)
159
    {
160
        $class = $this->findClassByFqsen($classFqsen);
161
        static::AssertTagCount($class, $tagName, $expectedNumber);
0 ignored issues
show
Bug introduced by
Since AssertTagCount() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of AssertTagCount() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
162
    }
163
164
    /**
165
     * @param string $classFqsen
166
     * @param string $tagName
167
     * @param string $method
168
     * @Then class ":classFqsen" has a method named :method without tag :tagName
169
     */
170
    public function classHasMethodWithoutTag($classFqsen, $tagName, $method)
171
    {
172
        $this->classHasMethodWithExpectedCountTag($classFqsen, $tagName, $method, 0);
173
    }
174
175
    /**
176
     * @param string $classFqsen
177
     * @param string $tagName
178
     * @param string $methodName
179
     * @Then class ":classFqsen" has a method named :method with exactly :expected tag :tagName
180
     */
181
    public function classHasMethodWithExpectedCountTag($classFqsen, $tagName, $methodName, $expectedCount)
182
    {
183
        $class = $this->findClassByFqsen($classFqsen);
184
        $method = $class->getMethods()->get($methodName);
185
186
        static::AssertTagCount($method, $tagName, $expectedCount);
0 ignored issues
show
Bug introduced by
Since AssertTagCount() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of AssertTagCount() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
187
    }
188
189
    /**
190
     * @param string $className
191
     * @return ClassDescriptor
192
     * @throws \Exception
193
     */
194
    private function findClassByName($className)
195
    {
196
        $ast = $this->getAst();
197
        foreach ($ast->getFiles() as $file) {
198
            foreach ($file->getClasses() as $classDescriptor) {
199
                if ($classDescriptor->getName() === $className) {
200
                    return $classDescriptor;
201
                }
202
            }
203
        }
204
205
        throw new \Exception(sprintf('Didn\'t find expected class "%s"', $className));
206
    }
207
208
    /**
209
     * @param string $tagName
210
     * @param int $expectedNumber
211
     * @param DescriptorAbstract $element
212
     */
213
    private static function AssertTagCount($element, $tagName, $expectedNumber)
0 ignored issues
show
Coding Style introduced by
Method name "ApiContext::AssertTagCount" is not in camel caps format
Loading history...
214
    {
215
        /** @var Collection $tagCollection */
216
        $tagCollection = $element->getTags()->get($tagName, new Collection());
217
218
        Assert::assertEquals((int)$expectedNumber, $tagCollection->count());
219
        if ($expectedNumber > 0) {
220
            Assert::assertEquals($tagName, $tagCollection[0]->getName());
221
        }
222
    }
223
}
224