Completed
Push — master ( bd558f...6391f6 )
by WEBEWEB
02:19
created

testCallWithRequestTimeoutException()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.6666
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
/**
4
 * This file is part of the curl-library package.
5
 *
6
 * (c) 2017 WEBEWEB
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace WBW\Library\CURL\Tests\Request;
13
14
use Exception;
15
use WBW\Library\Core\Exception\Argument\StringArgumentException;
16
use WBW\Library\Core\Network\HTTP\HTTPHelper;
17
use WBW\Library\CURL\Exception\CURLRequestCallException;
18
use WBW\Library\CURL\Request\CURLGetRequest;
19
20
/**
21
 * cURL GET request test.
22
 *
23
 * @author webeweb <https://github.com/webeweb/>
24
 * @package WBW\Library\CURL\Tests\Request
25
 * @final
26
 */
27
final class CURLGetRequestTest extends AbstractCURLRequestTest {
28
29
    /**
30
     * Tests __construct() method.
31
     *
32
     * @return void
33
     */
34
    public function testConstruct() {
35
36
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
37
38
        $this->assertSame($this->configuration, $obj->getConfiguration());
39
        $this->assertEquals([], $obj->getHeaders());
40
        $this->assertEquals(CURLGetRequest::HTTP_METHOD_GET, $obj->getMethod());
41
        $this->assertEquals([], $obj->getPostData());
42
        $this->assertEquals([], $obj->getQueryData());
43
        $this->assertEquals("testCall.php", $obj->getResourcePath());
44
    }
45
46
    /**
47
     * Tests addHeader() method.
48
     *
49
     * @return void
50
     */
51
    public function testAddHeader() {
52
53
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
54
55
        // ===
56
        try {
57
58
            $obj->addHeader(1, "value");
59
        } catch (Exception $ex) {
60
61
            $this->assertInstanceOf(StringArgumentException::class, $ex);
62
            $this->assertEquals("The argument \"1\" is not a string", $ex->getMessage());
63
        }
64
65
        // ===
66
        $obj->addHeader("name", "value");
67
68
        $res = ["name" => "value"];
69
        $this->assertEquals($res, $obj->getHeaders());
70
    }
71
72
    /**
73
     * Tests addQueryData() method.
74
     *
75
     * @return void
76
     */
77
    public function testAddQueryData() {
78
79
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
80
81
        // ===
82
        try {
83
84
            $obj->addQueryData(1, "value");
85
        } catch (Exception $ex) {
86
87
            $this->assertInstanceOf(StringArgumentException::class, $ex);
88
            $this->assertEquals("The argument \"1\" is not a string", $ex->getMessage());
89
        }
90
91
        // ===
92
        $obj->addQueryData("name", "value");
93
94
        $res = ["name" => "value"];
95
        $this->assertEquals($res, $obj->getQueryData());
96
    }
97
98
    /**
99
     * Tests call() method.
100
     *
101
     * @return void
102
     */
103
    public function testCallWithAllowEncoding() {
104
105
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
106
107
        $obj->getConfiguration()->setAllowEncoding(true);
108
109
        $res = $obj->call();
110
111
        $this->assertEquals(CURLGetRequest::HTTP_METHOD_GET, json_decode($res->getResponseBody(), true)["method"]);
112
        $this->assertEquals(200, $res->getResponseInfo()["http_code"]);
113
    }
114
115
    /**
116
     * Tests call() method.
117
     *
118
     * @return void
119
     */
120
    public function testCallWithConnectTimeout() {
121
122
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
123
124
        $obj->getConfiguration()->setConnectTimeout(30);
125
126
        $res = $obj->call();
127
128
        $this->assertEquals(CURLGetRequest::HTTP_METHOD_GET, json_decode($res->getResponseBody(), true)["method"]);
129
        $this->assertEquals(200, $res->getResponseInfo()["http_code"]);
130
    }
131
132
    /**
133
     * Tests call() method.
134
     *
135
     * @return void
136
     */
137
    public function testCallWithDebug() {
138
139
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
140
141
        $obj->getConfiguration()->setDebug(true);
142
143
        $res = $obj->call();
144
145
        $this->assertEquals(CURLGetRequest::HTTP_METHOD_GET, json_decode($res->getResponseBody(), true)["method"]);
146
        $this->assertEquals(200, $res->getResponseInfo()["http_code"]);
147
    }
148
149
    /**
150
     * Tests call() method.
151
     *
152
     * @return void
153
     */
154
    public function testCallWithHeader() {
155
156
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
157
158
        $obj->addHeader("h", "v");
159
160
        // ===
161
        $resH = $obj->call();
162
163
        $this->assertContains("h: v", $resH->getRequestHeader());
164
        $this->assertEquals(CURLGetRequest::HTTP_METHOD_GET, json_decode($resH->getResponseBody(), true)["method"]);
165
        $this->assertEquals(200, $resH->getResponseInfo()["http_code"]);
166
167
        $obj->removeHeader("h");
168
169
        /* === JSON ======================================================== */
170
        $obj->addHeader("Content-Type", "application/json");
171
        $obj->addPostData("name", "value");
172
173
        $resJSON = $obj->call();
174
175
        $this->assertContains("Content-Type: application/json", $resJSON->getRequestHeader());
176
        $this->assertContains('{"name":"value"}', $resJSON->getRequestBody());
177
        $this->assertEquals(CURLGetRequest::HTTP_METHOD_GET, json_decode($resH->getResponseBody(), true)["method"]);
178
        $this->assertEquals(200, $resH->getResponseInfo()["http_code"]);
179
    }
180
181
    /**
182
     * Tests call() method.
183
     *
184
     * @return void
185
     */
186
    public function testCallWithRequestTimeout() {
187
188
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
189
190
        $obj->getConfiguration()->setRequestTimeout(30);
191
192
        $res = $obj->call();
193
194
        $this->assertEquals(CURLGetRequest::HTTP_METHOD_GET, json_decode($res->getResponseBody(), true)["method"]);
195
        $this->assertEquals(200, $res->getResponseInfo()["http_code"]);
196
    }
197
198
    /**
199
     * Tests call() method.
200
     *
201
     * @return void
202
     */
203
    public function testCallWithRequestTimeoutException() {
204
205
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
206
207
        $obj->getConfiguration()->setRequestTimeout(10);
208
        $obj->addQueryData("sleep", 60);
209
210
        // ===
211
        try {
212
213
            $obj->call();
214
        } catch (Exception $ex) {
215
216
            $this->assertInstanceOf(CURLRequestCallException::class, $ex);
217
            $this->assertContains("Call to ", $ex->getMessage());
218
            $this->assertEquals(0, $ex->getResponse()->getResponseInfo()["http_code"]);
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Exception as the method getResponse() does only exist in the following sub-classes of Exception: WBW\Library\CURL\Excepti...URLRequestCallException. 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...
219
        }
220
    }
221
222
    /**
223
     * Tests call() method.
224
     *
225
     * @return void
226
     */
227
    public function testCallWithSSLVerification() {
228
229
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
230
231
        $obj->getConfiguration()->setSslVerification(false);
232
233
        $res = $obj->call();
234
235
        $this->assertEquals(CURLGetRequest::HTTP_METHOD_GET, json_decode($res->getResponseBody(), true)["method"]);
236
        $this->assertEquals(200, $res->getResponseInfo()["http_code"]);
237
    }
238
239
    /**
240
     * Tests call() method.
241
     *
242
     * @return void
243
     */
244
    public function testCallWithVerbose() {
245
246
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
247
248
        $obj->getConfiguration()->setVerbose(true);
249
250
        $res = $obj->call();
251
252
        $this->assertEquals(CURLGetRequest::HTTP_METHOD_GET, json_decode($res->getResponseBody(), true)["method"]);
253
        $this->assertEquals(200, $res->getResponseInfo()["http_code"]);
254
    }
255
256
    /**
257
     * Tests call() method.
258
     *
259
     * @return void
260
     */
261
    public function testCallWithHTTPCodes() {
262
263
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
264
265
        foreach (HTTPHelper::getHTTPStatus() as $code) {
266
            try {
267
268
                $obj->addQueryData("code", $code);
269
270
                $rslt = $obj->call();
271
272
                $this->assertEquals($code, $rslt->getResponseInfo()["http_code"]);
273
                $this->assertGreaterThanOrEqual(200, $rslt->getResponseInfo()["http_code"]);
274
                $this->assertLessThanOrEqual(299, $rslt->getResponseInfo()["http_code"]);
275
            } catch (Exception $ex) {
276
277
                $this->assertInstanceOf(CURLRequestCallException::class, $ex);
278
                $this->assertEquals($code, $ex->getCode());
279
                $this->assertEquals($code, $ex->getResponse()->getResponseInfo()["http_code"]);
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Exception as the method getResponse() does only exist in the following sub-classes of Exception: WBW\Library\CURL\Excepti...URLRequestCallException. 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...
280
            }
281
        }
282
283
        /* ================================================================= */
284
    }
285
286
    /**
287
     * Tests the clearHeader() method.
288
     *
289
     * @return void
290
     */
291
    public function testClearHeaders() {
292
293
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
294
295
        $obj->addHeader("name", "value");
296
        $this->assertCount(1, $obj->getHeaders());
297
298
        $obj->clearHeaders();
299
        $this->assertCount(0, $obj->getHeaders());
300
    }
301
302
    /**
303
     * Tests the clearQueryData() method.
304
     *
305
     * @return void
306
     */
307
    public function testClearQueryData() {
308
309
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
310
311
        $obj->addQueryData("name", "value");
312
        $this->assertCount(1, $obj->getQueryData());
313
314
        $obj->clearQueryData();
315
        $this->assertCount(0, $obj->getQueryData());
316
    }
317
318
    /**
319
     * Tests removeHeader() method.
320
     *
321
     * @return void
322
     */
323
    public function testRemoveHeader() {
324
325
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
326
327
        $obj->addHeader("name", "value");
328
        $this->assertCount(1, $obj->getHeaders());
329
330
        $obj->removeHeader("Name");
331
        $this->assertCount(1, $obj->getHeaders());
332
333
        $obj->removeHeader("name");
334
        $this->assertCount(0, $obj->getHeaders());
335
    }
336
337
    /**
338
     * Tests removeQueryData() method.
339
     *
340
     * @return void
341
     */
342
    public function testRemoveQueryData() {
343
344
        $obj = new CURLGetRequest($this->configuration, self::RESOURCE_PATH);
345
346
        $obj->addQueryData("name", "value");
347
        $this->assertCount(1, $obj->getQueryData());
348
349
        $obj->removeQueryData("Name");
350
        $this->assertCount(1, $obj->getQueryData());
351
352
        $obj->removeQueryData("name");
353
        $this->assertCount(0, $obj->getQueryData());
354
    }
355
356
}
357