1<?php
2/*
3 * This file is part of PHPUnit.
4 *
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'NoArgTestCaseTest.php';
12require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Singleton.php';
13require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Mockable.php';
14
15$GLOBALS['a']  = 'a';
16$_ENV['b']     = 'b';
17$_POST['c']    = 'c';
18$_GET['d']     = 'd';
19$_COOKIE['e']  = 'e';
20$_SERVER['f']  = 'f';
21$_FILES['g']   = 'g';
22$_REQUEST['h'] = 'h';
23$GLOBALS['i']  = 'i';
24
25class Framework_TestCaseTest extends PHPUnit_Framework_TestCase
26{
27    protected $backupGlobalsBlacklist = ['i', 'singleton'];
28
29    /**
30     * Used be testStaticAttributesBackupPre
31     */
32    protected static $testStatic = 0;
33
34    public function testCaseToString()
35    {
36        $this->assertEquals(
37            'Framework_TestCaseTest::testCaseToString',
38            $this->toString()
39        );
40    }
41
42    public function testSuccess()
43    {
44        $test   = new Success;
45        $result = $test->run();
46
47        $this->assertEquals(PHPUnit_Runner_BaseTestRunner::STATUS_PASSED, $test->getStatus());
48        $this->assertEquals(0, $result->errorCount());
49        $this->assertEquals(0, $result->failureCount());
50        $this->assertEquals(0, $result->skippedCount());
51        $this->assertCount(1, $result);
52    }
53
54    public function testFailure()
55    {
56        $test   = new Failure;
57        $result = $test->run();
58
59        $this->assertEquals(PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE, $test->getStatus());
60        $this->assertEquals(0, $result->errorCount());
61        $this->assertEquals(1, $result->failureCount());
62        $this->assertEquals(0, $result->skippedCount());
63        $this->assertCount(1, $result);
64    }
65
66    public function testError()
67    {
68        $test   = new TestError;
69        $result = $test->run();
70
71        $this->assertEquals(PHPUnit_Runner_BaseTestRunner::STATUS_ERROR, $test->getStatus());
72        $this->assertEquals(1, $result->errorCount());
73        $this->assertEquals(0, $result->failureCount());
74        $this->assertEquals(0, $result->skippedCount());
75        $this->assertCount(1, $result);
76    }
77
78    public function testSkipped()
79    {
80        $test   = new TestSkipped();
81        $result = $test->run();
82
83        $this->assertEquals(PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED, $test->getStatus());
84        $this->assertEquals('Skipped test', $test->getStatusMessage());
85        $this->assertEquals(0, $result->errorCount());
86        $this->assertEquals(0, $result->failureCount());
87        $this->assertEquals(1, $result->skippedCount());
88        $this->assertCount(1, $result);
89    }
90
91    public function testIncomplete()
92    {
93        $test   = new TestIncomplete();
94        $result = $test->run();
95
96        $this->assertEquals(PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE, $test->getStatus());
97        $this->assertEquals('Incomplete test', $test->getStatusMessage());
98        $this->assertEquals(0, $result->errorCount());
99        $this->assertEquals(0, $result->failureCount());
100        $this->assertEquals(0, $result->skippedCount());
101        $this->assertCount(1, $result);
102    }
103
104    public function testExceptionInSetUp()
105    {
106        $test   = new ExceptionInSetUpTest('testSomething');
107        $result = $test->run();
108
109        $this->assertTrue($test->setUp);
110        $this->assertFalse($test->assertPreConditions);
111        $this->assertFalse($test->testSomething);
112        $this->assertFalse($test->assertPostConditions);
113        $this->assertTrue($test->tearDown);
114    }
115
116    public function testExceptionInAssertPreConditions()
117    {
118        $test   = new ExceptionInAssertPreConditionsTest('testSomething');
119        $result = $test->run();
120
121        $this->assertTrue($test->setUp);
122        $this->assertTrue($test->assertPreConditions);
123        $this->assertFalse($test->testSomething);
124        $this->assertFalse($test->assertPostConditions);
125        $this->assertTrue($test->tearDown);
126    }
127
128    public function testExceptionInTest()
129    {
130        $test   = new ExceptionInTest('testSomething');
131        $result = $test->run();
132
133        $this->assertTrue($test->setUp);
134        $this->assertTrue($test->assertPreConditions);
135        $this->assertTrue($test->testSomething);
136        $this->assertFalse($test->assertPostConditions);
137        $this->assertTrue($test->tearDown);
138    }
139
140    public function testExceptionInAssertPostConditions()
141    {
142        $test   = new ExceptionInAssertPostConditionsTest('testSomething');
143        $result = $test->run();
144
145        $this->assertTrue($test->setUp);
146        $this->assertTrue($test->assertPreConditions);
147        $this->assertTrue($test->testSomething);
148        $this->assertTrue($test->assertPostConditions);
149        $this->assertTrue($test->tearDown);
150    }
151
152    public function testExceptionInTearDown()
153    {
154        $test   = new ExceptionInTearDownTest('testSomething');
155        $result = $test->run();
156
157        $this->assertTrue($test->setUp);
158        $this->assertTrue($test->assertPreConditions);
159        $this->assertTrue($test->testSomething);
160        $this->assertTrue($test->assertPostConditions);
161        $this->assertTrue($test->tearDown);
162        $this->assertEquals(PHPUnit_Runner_BaseTestRunner::STATUS_ERROR, $test->getStatus());
163    }
164
165    public function testNoArgTestCasePasses()
166    {
167        $result = new PHPUnit_Framework_TestResult;
168        $t      = new PHPUnit_Framework_TestSuite('NoArgTestCaseTest');
169
170        $t->run($result);
171
172        $this->assertCount(1, $result);
173        $this->assertEquals(0, $result->failureCount());
174        $this->assertEquals(0, $result->errorCount());
175    }
176
177    public function testWasRun()
178    {
179        $test = new WasRun;
180        $test->run();
181
182        $this->assertTrue($test->wasRun);
183    }
184
185    public function testException()
186    {
187        $test = new ThrowExceptionTestCase('test');
188        $test->expectException(RuntimeException::class);
189
190        $result = $test->run();
191
192        $this->assertCount(1, $result);
193        $this->assertTrue($result->wasSuccessful());
194    }
195
196    public function testExceptionWithEmptyMessage()
197    {
198        $test = new ThrowExceptionTestCase('test');
199        $test->expectException(RuntimeException::class, '');
200
201        $result = $test->run();
202
203        $this->assertCount(1, $result);
204        $this->assertTrue($result->wasSuccessful());
205    }
206
207    public function testExceptionWithNullMessage()
208    {
209        $test = new ThrowExceptionTestCase('test');
210        $test->expectException(RuntimeException::class, null);
211
212        $result = $test->run();
213
214        $this->assertCount(1, $result);
215        $this->assertTrue($result->wasSuccessful());
216    }
217
218    public function testExceptionWithMessage()
219    {
220        $test = new ThrowExceptionTestCase('test');
221        $test->expectException(RuntimeException::class);
222        $test->expectExceptionMessage('A runtime error occurred');
223
224        $result = $test->run();
225
226        $this->assertCount(1, $result);
227        $this->assertTrue($result->wasSuccessful());
228    }
229
230    public function testExceptionWithWrongMessage()
231    {
232        $test = new ThrowExceptionTestCase('test');
233        $test->expectException(RuntimeException::class);
234        $test->expectExceptionMessage('A logic error occurred');
235
236        $result = $test->run();
237
238        $this->assertEquals(1, $result->failureCount());
239        $this->assertCount(1, $result);
240        $this->assertEquals(
241            "Failed asserting that exception message 'A runtime error occurred' contains 'A logic error occurred'.",
242            $test->getStatusMessage()
243        );
244    }
245
246    public function testExceptionWithRegexpMessage()
247    {
248        $test = new ThrowExceptionTestCase('test');
249        $test->expectException(RuntimeException::class);
250        $test->expectExceptionMessageRegExp('/runtime .*? occurred/');
251
252        $result = $test->run();
253
254        $this->assertCount(1, $result);
255        $this->assertTrue($result->wasSuccessful());
256    }
257
258    public function testExceptionWithWrongRegexpMessage()
259    {
260        $test = new ThrowExceptionTestCase('test');
261        $test->expectException(RuntimeException::class);
262        $test->expectExceptionMessageRegExp('/logic .*? occurred/');
263
264        $result = $test->run();
265
266        $this->assertEquals(1, $result->failureCount());
267        $this->assertCount(1, $result);
268        $this->assertEquals(
269            "Failed asserting that exception message 'A runtime error occurred' matches '/logic .*? occurred/'.",
270            $test->getStatusMessage()
271        );
272    }
273
274    public function testExceptionWithInvalidRegexpMessage()
275    {
276        $test = new ThrowExceptionTestCase('test');
277        $test->expectException(RuntimeException::class);
278        $test->expectExceptionMessageRegExp('#runtime .*? occurred/');
279
280        $test->run();
281
282        $this->assertEquals(
283            "Invalid expected exception message regex given: '#runtime .*? occurred/'",
284            $test->getStatusMessage()
285        );
286    }
287
288    public function testNoException()
289    {
290        $test = new ThrowNoExceptionTestCase('test');
291        $test->expectException(RuntimeException::class);
292
293        $result = $test->run();
294
295        $this->assertEquals(1, $result->failureCount());
296        $this->assertCount(1, $result);
297    }
298
299    public function testWrongException()
300    {
301        $test = new ThrowExceptionTestCase('test');
302        $test->expectException(InvalidArgumentException::class);
303
304        $result = $test->run();
305
306        $this->assertEquals(1, $result->failureCount());
307        $this->assertCount(1, $result);
308    }
309
310    /**
311     * @backupGlobals enabled
312     */
313    public function testGlobalsBackupPre()
314    {
315        global $a;
316        global $i;
317
318        $this->assertEquals('a', $a);
319        $this->assertEquals('a', $GLOBALS['a']);
320        $this->assertEquals('b', $_ENV['b']);
321        $this->assertEquals('c', $_POST['c']);
322        $this->assertEquals('d', $_GET['d']);
323        $this->assertEquals('e', $_COOKIE['e']);
324        $this->assertEquals('f', $_SERVER['f']);
325        $this->assertEquals('g', $_FILES['g']);
326        $this->assertEquals('h', $_REQUEST['h']);
327        $this->assertEquals('i', $i);
328        $this->assertEquals('i', $GLOBALS['i']);
329
330        $GLOBALS['a']   = 'aa';
331        $GLOBALS['foo'] = 'bar';
332        $_ENV['b']      = 'bb';
333        $_POST['c']     = 'cc';
334        $_GET['d']      = 'dd';
335        $_COOKIE['e']   = 'ee';
336        $_SERVER['f']   = 'ff';
337        $_FILES['g']    = 'gg';
338        $_REQUEST['h']  = 'hh';
339        $GLOBALS['i']   = 'ii';
340
341        $this->assertEquals('aa', $a);
342        $this->assertEquals('aa', $GLOBALS['a']);
343        $this->assertEquals('bar', $GLOBALS['foo']);
344        $this->assertEquals('bb', $_ENV['b']);
345        $this->assertEquals('cc', $_POST['c']);
346        $this->assertEquals('dd', $_GET['d']);
347        $this->assertEquals('ee', $_COOKIE['e']);
348        $this->assertEquals('ff', $_SERVER['f']);
349        $this->assertEquals('gg', $_FILES['g']);
350        $this->assertEquals('hh', $_REQUEST['h']);
351        $this->assertEquals('ii', $i);
352        $this->assertEquals('ii', $GLOBALS['i']);
353    }
354
355    public function testGlobalsBackupPost()
356    {
357        global $a;
358        global $i;
359
360        $this->assertEquals('a', $a);
361        $this->assertEquals('a', $GLOBALS['a']);
362        $this->assertEquals('b', $_ENV['b']);
363        $this->assertEquals('c', $_POST['c']);
364        $this->assertEquals('d', $_GET['d']);
365        $this->assertEquals('e', $_COOKIE['e']);
366        $this->assertEquals('f', $_SERVER['f']);
367        $this->assertEquals('g', $_FILES['g']);
368        $this->assertEquals('h', $_REQUEST['h']);
369        $this->assertEquals('ii', $i);
370        $this->assertEquals('ii', $GLOBALS['i']);
371
372        $this->assertArrayNotHasKey('foo', $GLOBALS);
373    }
374
375    /**
376     * @backupGlobals enabled
377     * @backupStaticAttributes enabled
378     */
379    public function testStaticAttributesBackupPre()
380    {
381        $GLOBALS['singleton'] = Singleton::getInstance();
382        self::$testStatic     = 123;
383    }
384
385    /**
386     * @depends testStaticAttributesBackupPre
387     */
388    public function testStaticAttributesBackupPost()
389    {
390        $this->assertNotSame($GLOBALS['singleton'], Singleton::getInstance());
391        $this->assertSame(0, self::$testStatic);
392    }
393
394    public function testIsInIsolationReturnsFalse()
395    {
396        $test   = new IsolationTest('testIsInIsolationReturnsFalse');
397        $result = $test->run();
398
399        $this->assertCount(1, $result);
400        $this->assertTrue($result->wasSuccessful());
401    }
402
403    public function testIsInIsolationReturnsTrue()
404    {
405        $test   = new IsolationTest('testIsInIsolationReturnsTrue');
406        $test->setRunTestInSeparateProcess(true);
407        $result = $test->run();
408
409        $this->assertCount(1, $result);
410        $this->assertTrue($result->wasSuccessful());
411    }
412
413    public function testExpectOutputStringFooActualFoo()
414    {
415        $test   = new OutputTestCase('testExpectOutputStringFooActualFoo');
416        $result = $test->run();
417
418        $this->assertCount(1, $result);
419        $this->assertTrue($result->wasSuccessful());
420    }
421
422    public function testExpectOutputStringFooActualBar()
423    {
424        $test   = new OutputTestCase('testExpectOutputStringFooActualBar');
425        $result = $test->run();
426
427        $this->assertCount(1, $result);
428        $this->assertFalse($result->wasSuccessful());
429    }
430
431    public function testExpectOutputRegexFooActualFoo()
432    {
433        $test   = new OutputTestCase('testExpectOutputRegexFooActualFoo');
434        $result = $test->run();
435
436        $this->assertCount(1, $result);
437        $this->assertTrue($result->wasSuccessful());
438    }
439
440    public function testExpectOutputRegexFooActualBar()
441    {
442        $test   = new OutputTestCase('testExpectOutputRegexFooActualBar');
443        $result = $test->run();
444
445        $this->assertCount(1, $result);
446        $this->assertFalse($result->wasSuccessful());
447    }
448
449    public function testSkipsIfRequiresHigherVersionOfPHPUnit()
450    {
451        $test   = new RequirementsTest('testAlwaysSkip');
452        $result = $test->run();
453
454        $this->assertEquals(1, $result->skippedCount());
455        $this->assertEquals(
456            'PHPUnit >= 1111111 is required.',
457            $test->getStatusMessage()
458        );
459    }
460
461    public function testSkipsIfRequiresHigherVersionOfPHP()
462    {
463        $test   = new RequirementsTest('testAlwaysSkip2');
464        $result = $test->run();
465
466        $this->assertEquals(1, $result->skippedCount());
467        $this->assertEquals(
468            'PHP >= 9999999 is required.',
469            $test->getStatusMessage()
470        );
471    }
472
473    public function testSkipsIfRequiresNonExistingOs()
474    {
475        $test   = new RequirementsTest('testAlwaysSkip3');
476        $result = $test->run();
477
478        $this->assertEquals(1, $result->skippedCount());
479        $this->assertEquals(
480            'Operating system matching /DOESNOTEXIST/i is required.',
481            $test->getStatusMessage()
482        );
483    }
484
485    public function testSkipsIfRequiresNonExistingFunction()
486    {
487        $test   = new RequirementsTest('testNine');
488        $result = $test->run();
489
490        $this->assertEquals(1, $result->skippedCount());
491        $this->assertEquals(
492            'Function testFunc is required.',
493            $test->getStatusMessage()
494        );
495    }
496
497    public function testSkipsIfRequiresNonExistingExtension()
498    {
499        $test   = new RequirementsTest('testTen');
500        $result = $test->run();
501
502        $this->assertEquals(
503            'Extension testExt is required.',
504            $test->getStatusMessage()
505        );
506    }
507
508    public function testSkipsIfRequiresExtensionWithAMinimumVersion()
509    {
510        $test   = new RequirementsTest('testSpecificExtensionVersion');
511        $result = $test->run();
512
513        $this->assertEquals(
514            'Extension testExt >= 1.8.0 is required.',
515            $test->getStatusMessage()
516        );
517    }
518
519    public function testSkipsProvidesMessagesForAllSkippingReasons()
520    {
521        $test   = new RequirementsTest('testAllPossibleRequirements');
522        $result = $test->run();
523
524        $this->assertEquals(
525            'PHP >= 99-dev is required.' . PHP_EOL .
526            'PHPUnit >= 9-dev is required.' . PHP_EOL .
527            'Operating system matching /DOESNOTEXIST/i is required.' . PHP_EOL .
528            'Function testFuncOne is required.' . PHP_EOL .
529            'Function testFuncTwo is required.' . PHP_EOL .
530            'Extension testExtOne is required.' . PHP_EOL .
531            'Extension testExtTwo is required.' . PHP_EOL .
532            'Extension testExtThree >= 2.0 is required.',
533            $test->getStatusMessage()
534        );
535    }
536
537    public function testRequiringAnExistingMethodDoesNotSkip()
538    {
539        $test   = new RequirementsTest('testExistingMethod');
540        $result = $test->run();
541        $this->assertEquals(0, $result->skippedCount());
542    }
543
544    public function testRequiringAnExistingFunctionDoesNotSkip()
545    {
546        $test   = new RequirementsTest('testExistingFunction');
547        $result = $test->run();
548        $this->assertEquals(0, $result->skippedCount());
549    }
550
551    public function testRequiringAnExistingExtensionDoesNotSkip()
552    {
553        $test   = new RequirementsTest('testExistingExtension');
554        $result = $test->run();
555        $this->assertEquals(0, $result->skippedCount());
556    }
557
558    public function testRequiringAnExistingOsDoesNotSkip()
559    {
560        $test   = new RequirementsTest('testExistingOs');
561        $result = $test->run();
562        $this->assertEquals(0, $result->skippedCount());
563    }
564
565    public function testCurrentWorkingDirectoryIsRestored()
566    {
567        $expectedCwd = getcwd();
568
569        $test = new ChangeCurrentWorkingDirectoryTest('testSomethingThatChangesTheCwd');
570        $test->run();
571
572        $this->assertSame($expectedCwd, getcwd());
573    }
574
575    /**
576     * @requires PHP 7
577     * @expectedException TypeError
578     */
579    public function testTypeErrorCanBeExpected()
580    {
581        $o = new ClassWithScalarTypeDeclarations;
582        $o->foo(null, null);
583    }
584
585    public function testCreateMockFromClassName()
586    {
587        $mock = $this->createMock(Mockable::class);
588
589        $this->assertInstanceOf(Mockable::class, $mock);
590        $this->assertInstanceOf(PHPUnit_Framework_MockObject_MockObject::class, $mock);
591    }
592
593    public function testCreateMockMocksAllMethods()
594    {
595        /** @var Mockable $mock */
596        $mock = $this->createMock(Mockable::class);
597
598        $this->assertNull($mock->foo());
599        $this->assertNull($mock->bar());
600    }
601
602    public function testCreatePartialMockDoesNotMockAllMethods()
603    {
604        /** @var Mockable $mock */
605        $mock = $this->createPartialMock(Mockable::class, ['foo']);
606
607        $this->assertNull($mock->foo());
608        $this->assertTrue($mock->bar());
609    }
610
611    public function testCreatePartialMockCanMockNoMethods()
612    {
613        /** @var Mockable $mock */
614        $mock = $this->createPartialMock(Mockable::class, []);
615
616        $this->assertTrue($mock->foo());
617        $this->assertTrue($mock->bar());
618    }
619
620    public function testCreateMockSkipsConstructor()
621    {
622        /** @var Mockable $mock */
623        $mock = $this->createMock(Mockable::class);
624
625        $this->assertFalse($mock->constructorCalled);
626    }
627
628    public function testCreateMockDisablesOriginalClone()
629    {
630        /** @var Mockable $mock */
631        $mock = $this->createMock(Mockable::class);
632
633        $cloned = clone $mock;
634        $this->assertFalse($cloned->cloned);
635    }
636
637    public function testConfiguredMockCanBeCreated()
638    {
639        /** @var Mockable $mock */
640        $mock = $this->createConfiguredMock(
641            Mockable::class,
642            [
643                'foo' => false
644            ]
645        );
646
647        $this->assertFalse($mock->foo());
648        $this->assertNull($mock->bar());
649    }
650
651    public function testProvidingOfAutoreferencedArray()
652    {
653        $test = new \TestAutoreferenced('testJsonEncodeException', $this->getAutoreferencedArray());
654        $test->runBare();
655
656        $this->assertInternalType('array', $test->myTestData);
657        $this->assertArrayHasKey('data', $test->myTestData);
658        $this->assertEquals($test->myTestData['data'][0], $test->myTestData['data']);
659    }
660
661    /**
662     * @return array
663     */
664    private function getAutoreferencedArray()
665    {
666        $recursionData   = [];
667        $recursionData[] = &$recursionData;
668
669        return [
670            'RECURSION' => [
671                'data' => $recursionData
672            ]
673        ];
674    }
675
676    public function testProvidingArrayThatMixesObjectsAndScalars()
677    {
678        $data = [
679            [123],
680            ['foo'],
681            [$this->createMock(Mockable::class)],
682        ];
683
684        $test = new \TestAutoreferenced('testJsonEncodeException', [$data]);
685        $test->runBare();
686
687        $this->assertInternalType('array', $test->myTestData);
688        $this->assertSame($data, $test->myTestData);
689    }
690}
691