Passed
Pull Request — master (#56)
by
unknown
02:23
created

AssertRequestAgainstSchema::assertRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.584
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
namespace ByJG\ApiTools;
4
5
use ByJG\ApiTools\Base\Schema;
6
use ByJG\ApiTools\Exception\DefinitionNotFoundException;
7
use ByJG\ApiTools\Exception\GenericSwaggerException;
8
use ByJG\ApiTools\Exception\HttpMethodNotFoundException;
9
use ByJG\ApiTools\Exception\InvalidDefinitionException;
10
use ByJG\ApiTools\Exception\NotMatchedException;
11
use ByJG\ApiTools\Exception\PathNotFoundException;
12
use ByJG\ApiTools\Exception\StatusCodeNotMatchedException;
13
use PHPUnit\Framework\TestCase;
14
15
trait AssertRequestAgainstSchema
16
{
17
    /**
18
     * @var Schema
19
     */
20
    protected $schema;
21
22
    /**
23
     * configure the schema to use for requests
24
     *
25
     * When set, all requests without an own schema use this one instead.
26
     *
27
     * @param Schema|null $schema
28
     */
29
    public function setSchema($schema)
30
    {
31
        $this->schema = $schema;
32
    }
33
34
    /**
35
     * @param string $method The HTTP Method: GET, PUT, DELETE, POST, etc
36
     * @param string $path The REST path call
37
     * @param int $statusExpected
38
     * @param array|null $query
39
     * @param array|null $requestBody
40
     * @param array $requestHeader
41
     * @return mixed
42
     * @throws DefinitionNotFoundException
43
     * @throws GenericSwaggerException
44
     * @throws HttpMethodNotFoundException
45
     * @throws InvalidDefinitionException
46
     * @throws NotMatchedException
47
     * @throws PathNotFoundException
48
     * @throws StatusCodeNotMatchedException
49
     * @throws \GuzzleHttp\Exception\GuzzleException
50
     * @deprecated Use assertRequest instead
51
     */
52
    protected function makeRequest(
53
        $method,
54
        $path,
55
        $statusExpected = 200,
56
        $query = null,
57
        $requestBody = null,
58
        $requestHeader = []
59
    ) {
60
        assert($this instanceof TestCase);
61
62
        $this->checkSchema();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class PHPUnit\Framework\TestCase as the method checkSchema() does only exist in the following sub-classes of PHPUnit\Framework\TestCase: ByJG\ApiTools\ApiTestCase. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
63
        $requester = new ApiRequester();
64
        $body = $requester
65
            ->withSchema($this->schema)
0 ignored issues
show
Bug introduced by
The property schema does not seem to exist in PHPUnit\Framework\TestCase.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
66
            ->withMethod($method)
67
            ->withPath($path)
68
            ->withQuery($query)
0 ignored issues
show
Bug introduced by
It seems like $query defined by parameter $query on line 56 can also be of type null; however, ByJG\ApiTools\AbstractRequester::withQuery() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
69
            ->withRequestBody($requestBody)
0 ignored issues
show
Bug introduced by
It seems like $requestBody defined by parameter $requestBody on line 57 can also be of type array; however, ByJG\ApiTools\AbstractRequester::withRequestBody() does only seem to accept null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
70
            ->withRequestHeader($requestHeader)
71
            ->assertResponseCode($statusExpected)
72
            ->send();
73
74
        // Note:
75
        // This code is only reached if the send is successful and
76
        // all matches are satisfied. Otherwise an error is throwed before
77
        // reach this
78
        $this->assertTrue(true);
79
80
        return $body;
81
    }
82
83
    /**
84
     * @param AbstractRequester $request
85
     * @return mixed
86
     * @throws DefinitionNotFoundException
87
     * @throws GenericSwaggerException
88
     * @throws HttpMethodNotFoundException
89
     * @throws InvalidDefinitionException
90
     * @throws NotMatchedException
91
     * @throws PathNotFoundException
92
     * @throws StatusCodeNotMatchedException
93
     * @throws \GuzzleHttp\Exception\GuzzleException
94
     */
95
    public function assertRequest(AbstractRequester $request)
96
    {
97
        assert($this instanceof TestCase);
98
99
        // Add own schema if nothing is passed.
100
        if (!$request->hasSchema()) {
101
            $this->checkSchema();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class PHPUnit\Framework\TestCase as the method checkSchema() does only exist in the following sub-classes of PHPUnit\Framework\TestCase: ByJG\ApiTools\ApiTestCase. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
102
            $request->withSchema($this->schema);
0 ignored issues
show
Bug introduced by
The property schema does not seem to exist in PHPUnit\Framework\TestCase.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
103
        }
104
105
        // Request based on the Swagger Request definitios
106
        $body = $request->send();
107
108
        // Note:
109
        // This code is only reached if the send is successful and
110
        // all matches are satisfied. Otherwise an error is throwed before
111
        // reach this
112
        $this->assertTrue(true);
113
114
        return $body;
115
    }
116
117
    /**
118
     * @throws GenericSwaggerException
119
     */
120
    protected function checkSchema()
121
    {
122
        if (!$this->schema) {
123
            throw new GenericSwaggerException('You have to configure a schema for either the request or the testcase');
124
        }
125
    }
126
}
127