Completed
Push — master ( 93f6e0...a7ea34 )
by Aydin
27:25 queued 18:55
created

ResponsesTest   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 548
Duplicated Lines 6.57 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 36
c 2
b 0
f 1
lcom 1
cbo 6
dl 36
loc 548
rs 8.8

29 Methods

Rating   Name   Duplication   Size   Complexity  
A testProtocolVersionGetSet() 17 17 1
A testBodyGetSet() 0 18 1
A testCodeGetSet() 19 19 1
A testStatusGetter() 0 7 1
A testHeadersGetter() 0 7 1
A testCookiesGetter() 0 7 1
A testPrepend() 0 7 1
A testAppend() 0 7 1
A testLockToggleAndGetters() 0 14 1
B testLockedNotModifiable() 0 42 6
A testSendHeaders() 0 10 1
A testSendHeadersInIsolateProcess() 0 4 1
A testSendCookies() 0 10 1
A testSendCookiesInIsolateProcess() 0 4 1
A testSendBody() 0 7 1
A testSend() 0 8 1
A testSendWhenAlreadySent() 0 9 1
A testSendCallsFastCGIFinishRequest() 0 10 1
A testChunk() 0 23 1
B testHeader() 0 25 3
A testCookie() 0 52 1
A testNoCache() 0 11 1
A testRedirect() 0 12 1
A testDump() 0 10 1
A testDumpArray() 0 11 1
B testFileSend() 0 32 1
B testFileSendLooseArgs() 0 27 1
B testJSON() 0 40 1
B testJSONWithPrefix() 0 35 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * Klein (klein.php) - A fast & flexible router for PHP
4
 *
5
 * @author      Chris O'Hara <[email protected]>
6
 * @author      Trevor Suarez (Rican7) (contributor and v2 refactorer)
7
 * @copyright   (c) Chris O'Hara
8
 * @link        https://github.com/chriso/klein.php
9
 * @license     MIT
10
 */
11
12
namespace Klein\Tests;
13
14
use Klein\DataCollection\HeaderDataCollection;
15
use Klein\DataCollection\ResponseCookieDataCollection;
16
use Klein\Exceptions\LockedResponseException;
17
use Klein\HttpStatus;
18
use Klein\Klein;
19
use Klein\Response;
20
use Klein\ResponseCookie;
21
use Klein\Tests\Mocks\MockRequestFactory;
22
23
/**
24
 * ResponsesTest 
25
 */
26
class ResponsesTest extends AbstractKleinTest
27
{
28
29 View Code Duplication
    public function testProtocolVersionGetSet()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
30
    {
31
        $version_reg_ex = '/^[0-9]\.[0-9]$/';
32
33
        // Empty constructor
34
        $response = new Response();
35
36
        $this->assertNotNull($response->protocolVersion());
37
        $this->assertInternalType('string', $response->protocolVersion());
38
        $this->assertRegExp($version_reg_ex, $response->protocolVersion());
39
40
        // Set in method
41
        $response = new Response();
42
        $response->protocolVersion('2.0');
43
44
        $this->assertSame('2.0', $response->protocolVersion());
45
    }
46
47
    public function testBodyGetSet()
48
    {
49
        // Empty constructor
50
        $response = new Response();
51
52
        $this->assertEmpty($response->body());
53
54
        // Body set in constructor
55
        $response = new Response('dog');
56
57
        $this->assertSame('dog', $response->body());
58
59
        // Body set in method
60
        $response = new Response();
61
        $response->body('testing');
62
63
        $this->assertSame('testing', $response->body());
64
    }
65
66 View Code Duplication
    public function testCodeGetSet()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
67
    {
68
        // Empty constructor
69
        $response = new Response();
70
71
        $this->assertNotNull($response->code());
72
        $this->assertInternalType('int', $response->code());
73
74
        // Code set in constructor
75
        $response = new Response(null, 503);
76
77
        $this->assertSame(503, $response->code());
78
79
        // Code set in method
80
        $response = new Response();
81
        $response->code(204);
82
83
        $this->assertSame(204, $response->code());
84
    }
85
86
    public function testStatusGetter()
87
    {
88
        $response = new Response();
89
90
        $this->assertInternalType('object', $response->status());
91
        $this->assertTrue($response->status() instanceof HttpStatus);
92
    }
93
94
    public function testHeadersGetter()
95
    {
96
        $response = new Response();
97
98
        $this->assertInternalType('object', $response->headers());
99
        $this->assertTrue($response->headers() instanceof HeaderDataCollection);
100
    }
101
102
    public function testCookiesGetter()
103
    {
104
        $response = new Response();
105
106
        $this->assertInternalType('object', $response->cookies());
107
        $this->assertTrue($response->cookies() instanceof ResponseCookieDataCollection);
108
    }
109
110
    public function testPrepend()
111
    {
112
        $response = new Response('ein');
113
        $response->prepend('Kl');
114
115
        $this->assertSame('Klein', $response->body());
116
    }
117
118
    public function testAppend()
119
    {
120
        $response = new Response('Kl');
121
        $response->append('ein');
122
123
        $this->assertSame('Klein', $response->body());
124
    }
125
126
    public function testLockToggleAndGetters()
127
    {
128
        $response = new Response();
129
130
        $this->assertFalse($response->isLocked());
131
132
        $response->lock();
133
134
        $this->assertTrue($response->isLocked());
135
136
        $response->unlock();
137
138
        $this->assertFalse($response->isLocked());
139
    }
140
141
    public function testLockedNotModifiable()
142
    {
143
        $response = new Response();
144
        $response->lock();
145
146
        // Get initial values
147
        $protocol_version = $response->protocolVersion();
148
        $body = $response->body();
149
        $code = $response->code();
150
151
        // Attempt to modify
152
        try {
153
            $response->protocolVersion('2.0');
154
        } catch (LockedResponseException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
155
        }
156
157
        try {
158
            $response->body('WOOT!');
159
        } catch (LockedResponseException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
160
        }
161
162
        try {
163
            $response->code(204);
164
        } catch (LockedResponseException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
165
        }
166
167
        try {
168
            $response->prepend('cat');
169
        } catch (LockedResponseException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
170
        }
171
172
        try {
173
            $response->append('dog');
174
        } catch (LockedResponseException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
175
        }
176
177
178
        // Assert nothing has changed
179
        $this->assertSame($protocol_version, $response->protocolVersion());
180
        $this->assertSame($body, $response->body());
181
        $this->assertSame($code, $response->code());
182
    }
183
184
    /**
185
     * Testing headers is a pain in the ass. ;)
186
     *
187
     * Technically... we can't. So, yea.
188
     *
189
     * Attempt to run in a separate process so we can
190
     * at least call our internal methods
191
     */
192
    public function testSendHeaders()
193
    {
194
        $response = new Response('woot!');
195
        $response->headers()->set('test', 'sure');
196
        $response->headers()->set('Authorization', 'Basic asdasd');
197
198
        $response->sendHeaders();
199
200
        $this->expectOutputString(null);
201
    }
202
203
    /**
204
     * @runInSeparateProcess
205
     */
206
    public function testSendHeadersInIsolateProcess()
207
    {
208
        $this->testSendHeaders();
209
    }
210
211
    /**
212
     * Testing cookies is exactly like testing headers
213
     * ... So, yea.
214
     */
215
    public function testSendCookies()
216
    {
217
        $response = new Response();
218
        $response->cookies()->set('test', 'woot!');
219
        $response->cookies()->set('Cookie-name', 'wtf?');
220
221
        $response->sendCookies();
222
223
        $this->expectOutputString(null);
224
    }
225
226
    /**
227
     * @runInSeparateProcess
228
     */
229
    public function testSendCookiesInIsolateProcess()
230
    {
231
        $this->testSendCookies();
232
    }
233
234
    public function testSendBody()
235
    {
236
        $response = new Response('woot!');
237
        $response->sendBody();
238
239
        $this->expectOutputString('woot!');
240
    }
241
242
    public function testSend()
243
    {
244
        $response = new Response('woot!');
245
        $response->send();
246
247
        $this->expectOutputString('woot!');
248
        $this->assertTrue($response->isLocked());
249
    }
250
251
    /**
252
     * @expectedException \Klein\Exceptions\ResponseAlreadySentException
253
     */
254
    public function testSendWhenAlreadySent()
255
    {
256
        $response = new Response();
257
        $response->send();
258
259
        $this->assertTrue($response->isLocked());
260
261
        $response->send();
262
    }
263
264
    /**
265
     * This uses some crazy exploitation to make sure that the
266
     * `fastcgi_finish_request()` function gets called.
267
     * Because of this, this MUST be run in a separate process
268
     *
269
     * @runInSeparateProcess
270
     */
271
    public function testSendCallsFastCGIFinishRequest()
272
    {
273
        // Custom fastcgi function
274
        implement_custom_fastcgi_function();
275
276
        $response = new Response();
277
        $response->send();
278
279
        $this->expectOutputString('fastcgi_finish_request');
280
    }
281
282
    public function testChunk()
283
    {
284
        $content = array(
285
            'initial content',
286
            'more',
287
            'content',
288
        );
289
290
        $response = new Response($content[0]);
291
292
        $response->chunk();
293
        $response->chunk($content[1]);
294
        $response->chunk($content[2]);
295
296
        $this->expectOutputString(
297
            dechex(strlen($content[0]))."\r\n"
298
            ."$content[0]\r\n"
299
            .dechex(strlen($content[1]))."\r\n"
300
            ."$content[1]\r\n"
301
            .dechex(strlen($content[2]))."\r\n"
302
            ."$content[2]\r\n"
303
        );
304
    }
305
306
    public function testHeader()
307
    {
308
        $headers = array(
309
            'test' => 'woot!',
310
            'test' => 'sure',
311
            'okay' => 'yup',
312
        );
313
314
        $response = new Response();
315
316
        // Make sure the headers are initially empty
317
        $this->assertEmpty($response->headers()->all());
318
319
        // Set the headers
320
        foreach ($headers as $name => $value) {
321
            $response->header($name, $value);
322
        }
323
324
        $this->assertNotEmpty($response->headers()->all());
325
326
        // Set the headers
327
        foreach ($headers as $name => $value) {
328
            $this->assertSame($value, $response->headers()->get($name));
329
        }
330
    }
331
332
    /**
333
     * @group testCookie
334
     */
335
    public function testCookie()
336
    {
337
        $test_cookie_data = array(
338
            'name'      => 'name',
339
            'value'    => 'value',
340
            'expiry'   => null,
341
            'path'     => '/path',
342
            'domain'   => 'whatever.com',
343
            'secure'   => true,
344
            'httponly' => true
345
        );
346
347
        $test_cookie = new ResponseCookie(
0 ignored issues
show
Unused Code introduced by
$test_cookie 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...
348
            $test_cookie_data['name'],
349
            $test_cookie_data['value'],
350
            $test_cookie_data['expiry'],
351
            $test_cookie_data['path'],
352
            $test_cookie_data['domain'],
353
            $test_cookie_data['secure'],
354
            $test_cookie_data['httponly']
355
        );
356
357
        $response = new Response();
358
359
        // Make sure the cookies are initially empty
360
        $this->assertEmpty($response->cookies()->all());
361
362
        // Set a cookies
363
        $response->cookie(
364
            $test_cookie_data['name'],
365
            $test_cookie_data['value'],
366
            $test_cookie_data['expiry'],
367
            $test_cookie_data['path'],
368
            $test_cookie_data['domain'],
369
            $test_cookie_data['secure'],
370
            $test_cookie_data['httponly']
371
        );
372
373
        $this->assertNotEmpty($response->cookies()->all());
374
375
        $the_cookie = $response->cookies()->get($test_cookie_data['name']);
376
377
        $this->assertNotNull($the_cookie);
378
        $this->assertTrue($the_cookie instanceof ResponseCookie);
379
        $this->assertSame($test_cookie_data['name'], $the_cookie->getName());
380
        $this->assertSame($test_cookie_data['value'], $the_cookie->getValue());
381
        $this->assertSame($test_cookie_data['path'], $the_cookie->getPath());
382
        $this->assertSame($test_cookie_data['domain'], $the_cookie->getDomain());
383
        $this->assertSame($test_cookie_data['secure'], $the_cookie->getSecure());
384
        $this->assertSame($test_cookie_data['httponly'], $the_cookie->getHttpOnly());
385
        $this->assertNotNull($the_cookie->getExpire());
386
    }
387
388
    public function testNoCache()
389
    {
390
        $response = new Response();
391
392
        // Make sure the headers are initially empty
393
        $this->assertEmpty($response->headers()->all());
394
395
        $response->noCache();
396
397
        $this->assertContains('no-cache', $response->headers()->all());
398
    }
399
400
    public function testRedirect()
401
    {
402
        $url = 'http://google.com/';
403
        $code = 302;
404
405
        $response = new Response();
406
        $response->redirect($url, $code);
407
408
        $this->assertSame($code, $response->code());
409
        $this->assertSame($url, $response->headers()->get('location'));
410
        $this->assertTrue($response->isLocked());
411
    }
412
413
    public function testDump()
414
    {
415
        $response = new Response();
416
417
        $this->assertEmpty($response->body());
418
419
        $response->dump('test');
420
421
        $this->assertContains('test', $response->body());
422
    }
423
424
    public function testDumpArray()
425
    {
426
        $response = new Response();
427
428
        $this->assertEmpty($response->body());
429
430
        $response->dump(array('sure', 1, 10, 17, 'ok' => 'no'));
431
432
        $this->assertNotEmpty($response->body());
433
        $this->assertNotEquals('<pre></pre>', $response->body());
434
    }
435
436
    public function testFileSend()
437
    {
438
        $file_name = 'testing';
439
        $file_mime = 'text/plain';
440
441
        $this->klein_app->respond(
442
            function ($request, $response, $service) use ($file_name, $file_mime) {
0 ignored issues
show
Unused Code introduced by
The parameter $service is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
443
                $response->file(__FILE__, $file_name, $file_mime);
444
            }
445
        );
446
447
        $this->klein_app->dispatch();
448
449
        // Expect our output to match our json encoded test object
450
        $this->expectOutputString(
451
            file_get_contents(__FILE__)
452
        );
453
454
        // Assert headers were passed
455
        $this->assertEquals(
456
            $file_mime,
457
            $this->klein_app->response()->headers()->get('Content-Type')
458
        );
459
        $this->assertEquals(
460
            filesize(__FILE__),
461
            $this->klein_app->response()->headers()->get('Content-Length')
462
        );
463
        $this->assertContains(
464
            $file_name,
465
            $this->klein_app->response()->headers()->get('Content-Disposition')
466
        );
467
    }
468
469
    public function testFileSendLooseArgs()
470
    {
471
        $this->klein_app->respond(
472
            function ($request, $response, $service) {
0 ignored issues
show
Unused Code introduced by
The parameter $service is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
473
                $response->file(__FILE__);
474
            }
475
        );
476
477
        $this->klein_app->dispatch();
478
479
        // Expect our output to match our json encoded test object
480
        $this->expectOutputString(
481
            file_get_contents(__FILE__)
482
        );
483
484
        // Assert headers were passed
485
        $this->assertEquals(
486
            filesize(__FILE__),
487
            $this->klein_app->response()->headers()->get('Content-Length')
488
        );
489
        $this->assertNotNull(
490
            $this->klein_app->response()->headers()->get('Content-Type')
491
        );
492
        $this->assertNotNull(
493
            $this->klein_app->response()->headers()->get('Content-Disposition')
494
        );
495
    }
496
497
    public function testJSON()
498
    {
499
        // Create a test object to be JSON encoded/decoded
500
        $test_object = (object) array(
501
            'cheese',
502
            'dog' => 'bacon',
503
            1.5 => 'should be 1 (thanks PHP casting...)',
504
            'integer' => 1,
505
            'double' => 1.5,
506
            '_weird' => true,
507
            'uniqid' => uniqid(),
508
        );
509
510
        $this->klein_app->respond(
511
            function ($request, $response, $service) use ($test_object) {
0 ignored issues
show
Unused Code introduced by
The parameter $service is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
512
                $response->json($test_object);
513
            }
514
        );
515
516
        $this->klein_app->dispatch();
517
518
        // Expect our output to match our json encoded test object
519
        $this->expectOutputString(
520
            json_encode($test_object)
521
        );
522
523
        // Assert headers were passed
524
        $this->assertEquals(
525
            'no-cache',
526
            $this->klein_app->response()->headers()->get('Pragma')
527
        );
528
        $this->assertEquals(
529
            'no-store, no-cache',
530
            $this->klein_app->response()->headers()->get('Cache-Control')
531
        );
532
        $this->assertEquals(
533
            'application/json',
534
            $this->klein_app->response()->headers()->get('Content-Type')
535
        );
536
    }
537
538
    public function testJSONWithPrefix()
539
    {
540
        // Create a test object to be JSON encoded/decoded
541
        $test_object = array(
542
            'cheese',
543
        );
544
        $prefix = 'dogma';
545
546
        $this->klein_app->respond(
547
            function ($request, $response, $service) use ($test_object, $prefix) {
0 ignored issues
show
Unused Code introduced by
The parameter $service is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
548
                $response->json($test_object, $prefix);
549
            }
550
        );
551
552
        $this->klein_app->dispatch();
553
554
        // Expect our output to match our json encoded test object
555
        $this->expectOutputString(
556
            'dogma('. json_encode($test_object) .');'
557
        );
558
559
        // Assert headers were passed
560
        $this->assertEquals(
561
            'no-cache',
562
            $this->klein_app->response()->headers()->get('Pragma')
563
        );
564
        $this->assertEquals(
565
            'no-store, no-cache',
566
            $this->klein_app->response()->headers()->get('Cache-Control')
567
        );
568
        $this->assertEquals(
569
            'text/javascript',
570
            $this->klein_app->response()->headers()->get('Content-Type')
571
        );
572
    }
573
}
574