1<?php
2/**
3 * PHP_CodeCoverage
4 *
5 * Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 *   * Redistributions of source code must retain the above copyright
13 *     notice, this list of conditions and the following disclaimer.
14 *
15 *   * Redistributions in binary form must reproduce the above copyright
16 *     notice, this list of conditions and the following disclaimer in
17 *     the documentation and/or other materials provided with the
18 *     distribution.
19 *
20 *   * Neither the name of Sebastian Bergmann nor the names of his
21 *     contributors may be used to endorse or promote products derived
22 *     from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 * @category   PHP
38 * @package    CodeCoverage
39 * @subpackage Tests
40 * @author     Sebastian Bergmann <sebastian@phpunit.de>
41 * @copyright  2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
42 * @license    http://www.opensource.org/licenses/BSD-3-Clause  The BSD 3-Clause License
43 * @link       http://github.com/sebastianbergmann/php-code-coverage
44 * @since      File available since Release 1.0.0
45 */
46
47if (!defined('TEST_FILES_PATH')) {
48    define(
49      'TEST_FILES_PATH',
50      dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR .
51      '_files' . DIRECTORY_SEPARATOR
52    );
53}
54
55require_once TEST_FILES_PATH . '../TestCase.php';
56
57require_once TEST_FILES_PATH . 'BankAccount.php';
58require_once TEST_FILES_PATH . 'BankAccountTest.php';
59
60/**
61 * Tests for the PHP_CodeCoverage class.
62 *
63 * @category   PHP
64 * @package    CodeCoverage
65 * @subpackage Tests
66 * @author     Sebastian Bergmann <sebastian@phpunit.de>
67 * @copyright  2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
68 * @license    http://www.opensource.org/licenses/BSD-3-Clause  The BSD 3-Clause License
69 * @link       http://github.com/sebastianbergmann/php-code-coverage
70 * @since      Class available since Release 1.0.0
71 */
72class PHP_CodeCoverageTest extends PHP_CodeCoverage_TestCase
73{
74    protected $coverage;
75    protected $getLinesToBeCovered;
76
77    protected function setUp()
78    {
79        $this->coverage = new PHP_CodeCoverage;
80
81        $this->getLinesToBeCovered = new ReflectionMethod(
82          'PHP_CodeCoverage', 'getLinesToBeCovered'
83        );
84
85        $this->getLinesToBeCovered->setAccessible(TRUE);
86    }
87
88    /**
89     * @covers PHP_CodeCoverage::__construct
90     * @covers PHP_CodeCoverage::filter
91     */
92    public function testConstructor()
93    {
94        $this->assertAttributeInstanceOf(
95          'PHP_CodeCoverage_Driver_Xdebug', 'driver', $this->coverage
96        );
97
98        $this->assertAttributeInstanceOf(
99          'PHP_CodeCoverage_Filter', 'filter', $this->coverage
100        );
101    }
102
103    /**
104     * @covers PHP_CodeCoverage::__construct
105     * @covers PHP_CodeCoverage::filter
106     */
107    public function testConstructor2()
108    {
109        $filter   = new PHP_CodeCoverage_Filter;
110        $coverage = new PHP_CodeCoverage(NULL, $filter);
111
112        $this->assertAttributeInstanceOf(
113          'PHP_CodeCoverage_Driver_Xdebug', 'driver', $coverage
114        );
115
116        $this->assertSame($filter, $coverage->filter());
117    }
118
119    /**
120     * @covers            PHP_CodeCoverage::start
121     * @expectedException PHP_CodeCoverage_Exception
122     */
123    public function testStartThrowsExceptionForInvalidArgument()
124    {
125        $this->coverage->start(NULL, array(), NULL);
126    }
127
128    /**
129     * @covers            PHP_CodeCoverage::stop
130     * @expectedException PHP_CodeCoverage_Exception
131     */
132    public function testStopThrowsExceptionForInvalidArgument()
133    {
134        $this->coverage->stop(NULL);
135    }
136
137    /**
138     * @covers            PHP_CodeCoverage::append
139     * @expectedException PHP_CodeCoverage_Exception
140     */
141    public function testAppendThrowsExceptionForInvalidArgument()
142    {
143        $this->coverage->append(array(), NULL);
144    }
145
146    /**
147     * @covers            PHP_CodeCoverage::setCacheTokens
148     * @expectedException PHP_CodeCoverage_Exception
149     */
150    public function testSetCacheTokensThrowsExceptionForInvalidArgument()
151    {
152        $this->coverage->setCacheTokens(NULL);
153    }
154
155    /**
156     * @covers PHP_CodeCoverage::setCacheTokens
157     */
158    public function testSetCacheTokens()
159    {
160        $this->coverage->setCacheTokens(TRUE);
161        $this->assertAttributeEquals(TRUE, 'cacheTokens', $this->coverage);
162    }
163
164    /**
165     * @covers            PHP_CodeCoverage::setForceCoversAnnotation
166     * @expectedException PHP_CodeCoverage_Exception
167     */
168    public function testSetForceCoversAnnotationThrowsExceptionForInvalidArgument()
169    {
170        $this->coverage->setForceCoversAnnotation(NULL);
171    }
172
173    /**
174     * @covers PHP_CodeCoverage::setForceCoversAnnotation
175     */
176    public function testSetForceCoversAnnotation()
177    {
178        $this->coverage->setForceCoversAnnotation(TRUE);
179        $this->assertAttributeEquals(
180          TRUE, 'forceCoversAnnotation', $this->coverage
181        );
182    }
183
184    /**
185     * @covers            PHP_CodeCoverage::setProcessUncoveredFilesFromWhitelist
186     * @expectedException PHP_CodeCoverage_Exception
187     */
188    public function testSetProcessUncoveredFilesFromWhitelistThrowsExceptionForInvalidArgument()
189    {
190        $this->coverage->setProcessUncoveredFilesFromWhitelist(NULL);
191    }
192
193    /**
194     * @covers PHP_CodeCoverage::setProcessUncoveredFilesFromWhitelist
195     */
196    public function testSetProcessUncoveredFilesFromWhitelist()
197    {
198        $this->coverage->setProcessUncoveredFilesFromWhitelist(TRUE);
199        $this->assertAttributeEquals(
200          TRUE, 'processUncoveredFilesFromWhitelist', $this->coverage
201        );
202    }
203
204    /**
205     * @covers PHP_CodeCoverage::setMapTestClassNameToCoveredClassName
206     */
207    public function testSetMapTestClassNameToCoveredClassName()
208    {
209        $this->coverage->setMapTestClassNameToCoveredClassName(TRUE);
210        $this->assertAttributeEquals(
211          TRUE, 'mapTestClassNameToCoveredClassName', $this->coverage
212        );
213    }
214
215    /**
216     * @covers            PHP_CodeCoverage::setMapTestClassNameToCoveredClassName
217     * @expectedException PHP_CodeCoverage_Exception
218     */
219    public function testSetMapTestClassNameToCoveredClassNameThrowsExceptionForInvalidArgument()
220    {
221        $this->coverage->setMapTestClassNameToCoveredClassName(NULL);
222    }
223
224    /**
225     * @covers PHP_CodeCoverage::clear
226     */
227    public function testClear()
228    {
229        $this->coverage->clear();
230
231        $this->assertAttributeEquals(NULL, 'currentId', $this->coverage);
232        $this->assertAttributeEquals(array(), 'data', $this->coverage);
233        $this->assertAttributeEquals(array(), 'tests', $this->coverage);
234    }
235
236    /**
237     * @covers PHP_CodeCoverage::start
238     * @covers PHP_CodeCoverage::stop
239     * @covers PHP_CodeCoverage::append
240     * @covers PHP_CodeCoverage::applyListsFilter
241     * @covers PHP_CodeCoverage::initializeFilesThatAreSeenTheFirstTime
242     * @covers PHP_CodeCoverage::applyCoversAnnotationFilter
243     * @covers PHP_CodeCoverage::getTests
244     */
245    public function testCollect()
246    {
247        $coverage = $this->getCoverageForBankAccount();
248
249        $this->assertEquals(
250          $this->getExpectedDataArrayForBankAccount(), $coverage->getData()
251        );
252
253        $this->assertEquals(
254          array(
255            'BankAccountTest::testBalanceIsInitiallyZero' => NULL,
256            'BankAccountTest::testBalanceCannotBecomeNegative' => NULL,
257            'BankAccountTest::testBalanceCannotBecomeNegative2' => NULL,
258            'BankAccountTest::testDepositWithdrawMoney' => NULL
259          ),
260          $coverage->getTests()
261        );
262    }
263
264    /**
265     * @covers PHP_CodeCoverage::getData
266     * @covers PHP_CodeCoverage::merge
267     */
268    public function testMerge()
269    {
270        $coverage = $this->getCoverageForBankAccountForFirstTwoTests();
271        $coverage->merge($this->getCoverageForBankAccountForLastTwoTests());
272
273        $this->assertEquals(
274          $this->getExpectedDataArrayForBankAccount(), $coverage->getData()
275        );
276    }
277
278    /**
279     * @covers PHP_CodeCoverage::getData
280     * @covers PHP_CodeCoverage::merge
281     */
282    public function testMerge2()
283    {
284        $coverage = new PHP_CodeCoverage(
285          $this->getMock('PHP_CodeCoverage_Driver_Xdebug'),
286          new PHP_CodeCoverage_Filter
287        );
288
289        $coverage->merge($this->getCoverageForBankAccount());
290
291        $this->assertEquals(
292          $this->getExpectedDataArrayForBankAccount(), $coverage->getData()
293        );
294    }
295
296    /**
297     * @covers       PHP_CodeCoverage::getLinesToBeCovered
298     * @covers       PHP_CodeCoverage::resolveCoversToReflectionObjects
299     * @dataProvider getLinesToBeCoveredProvider
300     */
301    public function testGetLinesToBeCovered($test, $lines)
302    {
303        if (strpos($test, 'Namespace') === 0) {
304            $expected = array(
305              TEST_FILES_PATH . 'NamespaceCoveredClass.php' => $lines
306            );
307        }
308
309        else if ($test === 'CoverageNoneTest') {
310            $expected = array();
311        }
312
313        else if ($test === 'CoverageNothingTest') {
314            $expected = false;
315        }
316
317        else if ($test === 'CoverageFunctionTest') {
318            $expected = array(
319              TEST_FILES_PATH . 'CoveredFunction.php' => $lines
320            );
321        }
322
323        else {
324            $expected = array(TEST_FILES_PATH . 'CoveredClass.php' => $lines);
325        }
326
327        $this->assertEquals(
328          $expected,
329          $this->getLinesToBeCovered->invoke(
330            $this->coverage, $test, 'testSomething'
331          )
332        );
333    }
334
335    /**
336     * @covers            PHP_CodeCoverage::getLinesToBeCovered
337     * @covers            PHP_CodeCoverage::resolveCoversToReflectionObjects
338     * @expectedException PHP_CodeCoverage_Exception
339     */
340    public function testGetLinesToBeCovered2()
341    {
342        $this->getLinesToBeCovered->invoke(
343          $this->coverage, 'NotExistingCoveredElementTest', 'testOne'
344        );
345    }
346
347    /**
348     * @covers            PHP_CodeCoverage::getLinesToBeCovered
349     * @covers            PHP_CodeCoverage::resolveCoversToReflectionObjects
350     * @expectedException PHP_CodeCoverage_Exception
351     */
352    public function testGetLinesToBeCovered3()
353    {
354        $this->getLinesToBeCovered->invoke(
355          $this->coverage, 'NotExistingCoveredElementTest', 'testTwo'
356        );
357    }
358
359    /**
360     * @covers            PHP_CodeCoverage::getLinesToBeCovered
361     * @covers            PHP_CodeCoverage::resolveCoversToReflectionObjects
362     * @expectedException PHP_CodeCoverage_Exception
363     */
364    public function testGetLinesToBeCovered4()
365    {
366        $this->getLinesToBeCovered->invoke(
367          $this->coverage, 'NotExistingCoveredElementTest', 'testThree'
368        );
369    }
370
371    /**
372     * @covers PHP_CodeCoverage::getLinesToBeCovered
373     */
374    public function testGetLinesToBeCoveredSkipsNonExistantMethods()
375    {
376        $this->assertSame(
377          array(),
378          $this->getLinesToBeCovered->invoke(
379            $this->coverage,
380            'NotExistingCoveredElementTest',
381            'methodDoesNotExist'
382          )
383        );
384    }
385
386    /**
387     * @covers PHP_CodeCoverage::getLinesToBeCovered
388     * @expectedException PHP_CodeCoverage_Exception
389     */
390    public function testTwoCoversDefaultClassAnnoationsAreNotAllowed()
391    {
392        $this->getLinesToBeCovered->invoke(
393          $this->coverage,
394          'CoverageTwoDefaultClassAnnotations',
395          'testSomething'
396        );
397    }
398
399    /**
400     * @covers PHP_CodeCoverage::getLinesToBeCovered
401     */
402    public function testFunctionParenthesesAreAllowed()
403    {
404        $this->assertSame(
405          array(TEST_FILES_PATH . 'CoveredFunction.php' => range(2, 4)),
406          $this->getLinesToBeCovered->invoke(
407            $this->coverage,
408            'CoverageFunctionParenthesesTest',
409            'testSomething'
410          )
411        );
412    }
413
414    /**
415     * @covers PHP_CodeCoverage::getLinesToBeCovered
416     */
417    public function testFunctionParenthesesAreAllowedWithWhitespace()
418    {
419        $this->assertSame(
420          array(TEST_FILES_PATH . 'CoveredFunction.php' => range(2, 4)),
421          $this->getLinesToBeCovered->invoke(
422            $this->coverage,
423            'CoverageFunctionParenthesesWhitespaceTest',
424            'testSomething'
425          )
426        );
427    }
428
429    /**
430     * @covers PHP_CodeCoverage::getLinesToBeCovered
431     */
432    public function testMethodParenthesesAreAllowed()
433    {
434        $this->assertSame(
435          array(TEST_FILES_PATH . 'CoveredClass.php' => range(31, 35)),
436          $this->getLinesToBeCovered->invoke(
437            $this->coverage,
438            'CoverageMethodParenthesesTest',
439            'testSomething'
440          )
441        );
442    }
443
444    /**
445     * @covers PHP_CodeCoverage::getLinesToBeCovered
446     */
447    public function testMethodParenthesesAreAllowedWithWhitespace()
448    {
449        $this->assertSame(
450          array(TEST_FILES_PATH . 'CoveredClass.php' => range(31, 35)),
451          $this->getLinesToBeCovered->invoke(
452            $this->coverage,
453            'CoverageMethodParenthesesWhitespaceTest',
454            'testSomething'
455          )
456        );
457    }
458
459    public function getLinesToBeCoveredProvider()
460    {
461        return array(
462          array(
463            'CoverageNoneTest',
464            array()
465          ),
466          array(
467            'CoverageClassExtendedTest',
468            array_merge(range(19, 36), range(2, 17))
469          ),
470          array(
471            'CoverageClassTest',
472            range(19, 36)
473          ),
474          array(
475            'CoverageMethodTest',
476            range(31, 35)
477          ),
478          array(
479            'CoverageMethodOneLineAnnotationTest',
480            range(31, 35)
481          ),
482          array(
483            'CoverageNotPrivateTest',
484            array_merge(range(25, 29), range(31, 35))
485          ),
486          array(
487            'CoverageNotProtectedTest',
488            array_merge(range(21, 23), range(31, 35))
489          ),
490          array(
491            'CoverageNotPublicTest',
492            array_merge(range(21, 23), range(25, 29))
493          ),
494          array(
495            'CoveragePrivateTest',
496            range(21, 23)
497          ),
498          array(
499            'CoverageProtectedTest',
500            range(25, 29)
501          ),
502          array(
503            'CoveragePublicTest',
504            range(31, 35)
505          ),
506          array(
507            'CoverageFunctionTest',
508            range(2, 4)
509          ),
510          array(
511            'NamespaceCoverageClassExtendedTest',
512            array_merge(range(21, 38), range(4, 19))
513          ),
514          array(
515            'NamespaceCoverageClassTest',
516            range(21, 38)
517          ),
518          array(
519            'NamespaceCoverageMethodTest',
520            range(33, 37)
521          ),
522          array(
523            'NamespaceCoverageNotPrivateTest',
524            array_merge(range(27, 31), range(33, 37))
525          ),
526          array(
527            'NamespaceCoverageNotProtectedTest',
528            array_merge(range(23, 25), range(33, 37))
529          ),
530          array(
531            'NamespaceCoverageNotPublicTest',
532            array_merge(range(23, 25), range(27, 31))
533          ),
534          array(
535            'NamespaceCoveragePrivateTest',
536            range(23, 25)
537          ),
538          array(
539            'NamespaceCoverageProtectedTest',
540            range(27, 31)
541          ),
542          array(
543            'NamespaceCoveragePublicTest',
544            range(33, 37)
545          ),
546          array(
547            'NamespaceCoverageCoversClassTest',
548            array_merge(range(23, 25), range(27, 31), range(33, 37), range(6, 8), range(10, 13), range(15, 18))
549          ),
550          array(
551            'NamespaceCoverageCoversClassPublicTest',
552            range(33, 37)
553          ),
554          array(
555            'CoverageNothingTest',
556            false
557          )
558        );
559    }
560}
561