1<?php 2/* 3 * This file is part of the php-code-coverage package. 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 11namespace SebastianBergmann\CodeCoverage; 12 13use SebastianBergmann\CodeCoverage\Driver\PHPDBG; 14use SebastianBergmann\CodeCoverage\Driver\Xdebug; 15 16/** 17 * @covers SebastianBergmann\CodeCoverage\CodeCoverage 18 */ 19class CodeCoverageTest extends TestCase 20{ 21 /** 22 * @var CodeCoverage 23 */ 24 private $coverage; 25 26 protected function setUp() 27 { 28 $this->coverage = new CodeCoverage; 29 } 30 31 public function testCanBeConstructedForXdebugWithoutGivenFilterObject() 32 { 33 if (PHP_SAPI == 'phpdbg') { 34 $this->markTestSkipped('Requires PHP CLI and Xdebug'); 35 } 36 37 $this->assertAttributeInstanceOf( 38 Xdebug::class, 39 'driver', 40 $this->coverage 41 ); 42 43 $this->assertAttributeInstanceOf( 44 Filter::class, 45 'filter', 46 $this->coverage 47 ); 48 } 49 50 public function testCanBeConstructedForXdebugWithGivenFilterObject() 51 { 52 if (PHP_SAPI == 'phpdbg') { 53 $this->markTestSkipped('Requires PHP CLI and Xdebug'); 54 } 55 56 $filter = new Filter; 57 $coverage = new CodeCoverage(null, $filter); 58 59 $this->assertAttributeInstanceOf( 60 Xdebug::class, 61 'driver', 62 $coverage 63 ); 64 65 $this->assertSame($filter, $coverage->filter()); 66 } 67 68 public function testCanBeConstructedForPhpdbgWithoutGivenFilterObject() 69 { 70 if (PHP_SAPI != 'phpdbg') { 71 $this->markTestSkipped('Requires PHPDBG'); 72 } 73 74 $this->assertAttributeInstanceOf( 75 PHPDBG::class, 76 'driver', 77 $this->coverage 78 ); 79 80 $this->assertAttributeInstanceOf( 81 Filter::class, 82 'filter', 83 $this->coverage 84 ); 85 } 86 87 public function testCanBeConstructedForPhpdbgWithGivenFilterObject() 88 { 89 if (PHP_SAPI != 'phpdbg') { 90 $this->markTestSkipped('Requires PHPDBG'); 91 } 92 93 $filter = new Filter; 94 $coverage = new CodeCoverage(null, $filter); 95 96 $this->assertAttributeInstanceOf( 97 PHPDBG::class, 98 'driver', 99 $coverage 100 ); 101 102 $this->assertSame($filter, $coverage->filter()); 103 } 104 105 /** 106 * @expectedException SebastianBergmann\CodeCoverage\Exception 107 */ 108 public function testCannotStartWithInvalidArgument() 109 { 110 $this->coverage->start(null, null); 111 } 112 113 /** 114 * @expectedException SebastianBergmann\CodeCoverage\Exception 115 */ 116 public function testCannotStopWithInvalidFirstArgument() 117 { 118 $this->coverage->stop(null); 119 } 120 121 /** 122 * @expectedException SebastianBergmann\CodeCoverage\Exception 123 */ 124 public function testCannotStopWithInvalidSecondArgument() 125 { 126 $this->coverage->stop(true, null); 127 } 128 129 /** 130 * @expectedException SebastianBergmann\CodeCoverage\Exception 131 */ 132 public function testCannotAppendWithInvalidArgument() 133 { 134 $this->coverage->append([], null); 135 } 136 137 /** 138 * @expectedException SebastianBergmann\CodeCoverage\Exception 139 */ 140 public function testSetCacheTokensThrowsExceptionForInvalidArgument() 141 { 142 $this->coverage->setCacheTokens(null); 143 } 144 145 public function testSetCacheTokens() 146 { 147 $this->coverage->setCacheTokens(true); 148 $this->assertAttributeEquals(true, 'cacheTokens', $this->coverage); 149 } 150 151 /** 152 * @expectedException SebastianBergmann\CodeCoverage\Exception 153 */ 154 public function testSetCheckForUnintentionallyCoveredCodeThrowsExceptionForInvalidArgument() 155 { 156 $this->coverage->setCheckForUnintentionallyCoveredCode(null); 157 } 158 159 public function testSetCheckForUnintentionallyCoveredCode() 160 { 161 $this->coverage->setCheckForUnintentionallyCoveredCode(true); 162 $this->assertAttributeEquals( 163 true, 164 'checkForUnintentionallyCoveredCode', 165 $this->coverage 166 ); 167 } 168 169 /** 170 * @expectedException SebastianBergmann\CodeCoverage\Exception 171 */ 172 public function testSetForceCoversAnnotationThrowsExceptionForInvalidArgument() 173 { 174 $this->coverage->setForceCoversAnnotation(null); 175 } 176 177 public function testSetCheckForMissingCoversAnnotation() 178 { 179 $this->coverage->setCheckForMissingCoversAnnotation(true); 180 $this->assertAttributeEquals( 181 true, 182 'checkForMissingCoversAnnotation', 183 $this->coverage 184 ); 185 } 186 187 /** 188 * @expectedException SebastianBergmann\CodeCoverage\Exception 189 */ 190 public function testSetCheckForMissingCoversAnnotationThrowsExceptionForInvalidArgument() 191 { 192 $this->coverage->setCheckForMissingCoversAnnotation(null); 193 } 194 195 public function testSetForceCoversAnnotation() 196 { 197 $this->coverage->setForceCoversAnnotation(true); 198 $this->assertAttributeEquals( 199 true, 200 'forceCoversAnnotation', 201 $this->coverage 202 ); 203 } 204 205 /** 206 * @expectedException SebastianBergmann\CodeCoverage\Exception 207 */ 208 public function testSetCheckForUnexecutedCoveredCodeThrowsExceptionForInvalidArgument() 209 { 210 $this->coverage->setCheckForUnexecutedCoveredCode(null); 211 } 212 213 public function testSetCheckForUnexecutedCoveredCode() 214 { 215 $this->coverage->setCheckForUnexecutedCoveredCode(true); 216 $this->assertAttributeEquals( 217 true, 218 'checkForUnexecutedCoveredCode', 219 $this->coverage 220 ); 221 } 222 223 /** 224 * @expectedException SebastianBergmann\CodeCoverage\Exception 225 */ 226 public function testSetAddUncoveredFilesFromWhitelistThrowsExceptionForInvalidArgument() 227 { 228 $this->coverage->setAddUncoveredFilesFromWhitelist(null); 229 } 230 231 public function testSetAddUncoveredFilesFromWhitelist() 232 { 233 $this->coverage->setAddUncoveredFilesFromWhitelist(true); 234 $this->assertAttributeEquals( 235 true, 236 'addUncoveredFilesFromWhitelist', 237 $this->coverage 238 ); 239 } 240 241 /** 242 * @expectedException SebastianBergmann\CodeCoverage\Exception 243 */ 244 public function testSetProcessUncoveredFilesFromWhitelistThrowsExceptionForInvalidArgument() 245 { 246 $this->coverage->setProcessUncoveredFilesFromWhitelist(null); 247 } 248 249 public function testSetProcessUncoveredFilesFromWhitelist() 250 { 251 $this->coverage->setProcessUncoveredFilesFromWhitelist(true); 252 $this->assertAttributeEquals( 253 true, 254 'processUncoveredFilesFromWhitelist', 255 $this->coverage 256 ); 257 } 258 259 public function testSetIgnoreDeprecatedCode() 260 { 261 $this->coverage->setIgnoreDeprecatedCode(true); 262 $this->assertAttributeEquals( 263 true, 264 'ignoreDeprecatedCode', 265 $this->coverage 266 ); 267 } 268 269 /** 270 * @expectedException SebastianBergmann\CodeCoverage\Exception 271 */ 272 public function testSetIgnoreDeprecatedCodeThrowsExceptionForInvalidArgument() 273 { 274 $this->coverage->setIgnoreDeprecatedCode(null); 275 } 276 277 public function testClear() 278 { 279 $this->coverage->clear(); 280 281 $this->assertAttributeEquals(null, 'currentId', $this->coverage); 282 $this->assertAttributeEquals([], 'data', $this->coverage); 283 $this->assertAttributeEquals([], 'tests', $this->coverage); 284 } 285 286 public function testCollect() 287 { 288 $coverage = $this->getCoverageForBankAccount(); 289 290 $this->assertEquals( 291 $this->getExpectedDataArrayForBankAccount(), 292 $coverage->getData() 293 ); 294 295 if (version_compare(\PHPUnit_Runner_Version::id(), '4.7', '>=')) { 296 $size = 'unknown'; 297 } else { 298 $size = 'small'; 299 } 300 301 $this->assertEquals( 302 [ 303 'BankAccountTest::testBalanceIsInitiallyZero' => ['size' => $size, 'status' => null], 304 'BankAccountTest::testBalanceCannotBecomeNegative' => ['size' => $size, 'status' => null], 305 'BankAccountTest::testBalanceCannotBecomeNegative2' => ['size' => $size, 'status' => null], 306 'BankAccountTest::testDepositWithdrawMoney' => ['size' => $size, 'status' => null] 307 ], 308 $coverage->getTests() 309 ); 310 } 311 312 public function testMerge() 313 { 314 $coverage = $this->getCoverageForBankAccountForFirstTwoTests(); 315 $coverage->merge($this->getCoverageForBankAccountForLastTwoTests()); 316 317 $this->assertEquals( 318 $this->getExpectedDataArrayForBankAccount(), 319 $coverage->getData() 320 ); 321 } 322 323 public function testMerge2() 324 { 325 $coverage = new CodeCoverage( 326 $this->createMock(Xdebug::class), 327 new Filter 328 ); 329 330 $coverage->merge($this->getCoverageForBankAccount()); 331 332 $this->assertEquals( 333 $this->getExpectedDataArrayForBankAccount(), 334 $coverage->getData() 335 ); 336 } 337 338 public function testGetLinesToBeIgnored() 339 { 340 $this->assertEquals( 341 [ 342 1, 343 3, 344 4, 345 5, 346 7, 347 8, 348 9, 349 10, 350 11, 351 12, 352 13, 353 14, 354 15, 355 16, 356 17, 357 18, 358 19, 359 20, 360 21, 361 22, 362 23, 363 24, 364 25, 365 26, 366 27, 367 28, 368 30, 369 32, 370 33, 371 34, 372 35, 373 36, 374 37, 375 38 376 ], 377 $this->getLinesToBeIgnored()->invoke( 378 $this->coverage, 379 TEST_FILES_PATH . 'source_with_ignore.php' 380 ) 381 ); 382 } 383 384 public function testGetLinesToBeIgnored2() 385 { 386 $this->assertEquals( 387 [1, 5], 388 $this->getLinesToBeIgnored()->invoke( 389 $this->coverage, 390 TEST_FILES_PATH . 'source_without_ignore.php' 391 ) 392 ); 393 } 394 395 public function testGetLinesToBeIgnored3() 396 { 397 $this->assertEquals( 398 [ 399 1, 400 2, 401 3, 402 4, 403 5, 404 8, 405 11, 406 15, 407 16, 408 19, 409 20 410 ], 411 $this->getLinesToBeIgnored()->invoke( 412 $this->coverage, 413 TEST_FILES_PATH . 'source_with_class_and_anonymous_function.php' 414 ) 415 ); 416 } 417 418 public function testGetLinesToBeIgnoredOneLineAnnotations() 419 { 420 $this->assertEquals( 421 [ 422 1, 423 2, 424 3, 425 4, 426 5, 427 6, 428 7, 429 8, 430 9, 431 10, 432 11, 433 12, 434 13, 435 14, 436 15, 437 16, 438 18, 439 20, 440 21, 441 23, 442 24, 443 25, 444 27, 445 28, 446 29, 447 30, 448 31, 449 32, 450 33, 451 34, 452 37 453 ], 454 $this->getLinesToBeIgnored()->invoke( 455 $this->coverage, 456 TEST_FILES_PATH . 'source_with_oneline_annotations.php' 457 ) 458 ); 459 } 460 461 /** 462 * @return \ReflectionMethod 463 */ 464 private function getLinesToBeIgnored() 465 { 466 $getLinesToBeIgnored = new \ReflectionMethod( 467 'SebastianBergmann\CodeCoverage\CodeCoverage', 468 'getLinesToBeIgnored' 469 ); 470 471 $getLinesToBeIgnored->setAccessible(true); 472 473 return $getLinesToBeIgnored; 474 } 475 476 public function testGetLinesToBeIgnoredWhenIgnoreIsDisabled() 477 { 478 $this->coverage->setDisableIgnoredLines(true); 479 480 $this->assertEquals( 481 [], 482 $this->getLinesToBeIgnored()->invoke( 483 $this->coverage, 484 TEST_FILES_PATH . 'source_with_ignore.php' 485 ) 486 ); 487 } 488 489 /** 490 * @expectedException SebastianBergmann\CodeCoverage\CoveredCodeNotExecutedException 491 */ 492 public function testAppendThrowsExceptionIfCoveredCodeWasNotExecuted() 493 { 494 $this->coverage->filter()->addDirectoryToWhitelist(TEST_FILES_PATH); 495 $this->coverage->setCheckForUnexecutedCoveredCode(true); 496 497 $data = [ 498 TEST_FILES_PATH . 'BankAccount.php' => [ 499 29 => -1, 500 31 => -1 501 ] 502 ]; 503 504 $linesToBeCovered = [ 505 TEST_FILES_PATH . 'BankAccount.php' => [ 506 22, 507 24 508 ] 509 ]; 510 511 $linesToBeUsed = []; 512 513 $this->coverage->append($data, 'File1.php', true, $linesToBeCovered, $linesToBeUsed); 514 } 515 516 /** 517 * @expectedException SebastianBergmann\CodeCoverage\CoveredCodeNotExecutedException 518 */ 519 public function testAppendThrowsExceptionIfUsedCodeWasNotExecuted() 520 { 521 $this->coverage->filter()->addDirectoryToWhitelist(TEST_FILES_PATH); 522 $this->coverage->setCheckForUnexecutedCoveredCode(true); 523 524 $data = [ 525 TEST_FILES_PATH . 'BankAccount.php' => [ 526 29 => -1, 527 31 => -1 528 ] 529 ]; 530 531 $linesToBeCovered = [ 532 TEST_FILES_PATH . 'BankAccount.php' => [ 533 29, 534 31 535 ] 536 ]; 537 538 $linesToBeUsed = [ 539 TEST_FILES_PATH . 'BankAccount.php' => [ 540 22, 541 24 542 ] 543 ]; 544 545 $this->coverage->append($data, 'File1.php', true, $linesToBeCovered, $linesToBeUsed); 546 } 547} 548