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 $this->assertEquals( 296 [ 297 'BankAccountTest::testBalanceIsInitiallyZero' => ['size' => 'unknown', 'status' => null], 298 'BankAccountTest::testBalanceCannotBecomeNegative' => ['size' => 'unknown', 'status' => null], 299 'BankAccountTest::testBalanceCannotBecomeNegative2' => ['size' => 'unknown', 'status' => null], 300 'BankAccountTest::testDepositWithdrawMoney' => ['size' => 'unknown', 'status' => null] 301 ], 302 $coverage->getTests() 303 ); 304 } 305 306 public function testMerge() 307 { 308 $coverage = $this->getCoverageForBankAccountForFirstTwoTests(); 309 $coverage->merge($this->getCoverageForBankAccountForLastTwoTests()); 310 311 $this->assertEquals( 312 $this->getExpectedDataArrayForBankAccount(), 313 $coverage->getData() 314 ); 315 } 316 317 public function testMerge2() 318 { 319 $coverage = new CodeCoverage( 320 $this->createMock(Xdebug::class), 321 new Filter 322 ); 323 324 $coverage->merge($this->getCoverageForBankAccount()); 325 326 $this->assertEquals( 327 $this->getExpectedDataArrayForBankAccount(), 328 $coverage->getData() 329 ); 330 } 331 332 public function testGetLinesToBeIgnored() 333 { 334 $this->assertEquals( 335 [ 336 1, 337 3, 338 4, 339 5, 340 7, 341 8, 342 9, 343 10, 344 11, 345 12, 346 13, 347 14, 348 15, 349 16, 350 17, 351 18, 352 19, 353 20, 354 21, 355 22, 356 23, 357 24, 358 25, 359 26, 360 27, 361 28, 362 30, 363 32, 364 33, 365 34, 366 35, 367 36, 368 37, 369 38 370 ], 371 $this->getLinesToBeIgnored()->invoke( 372 $this->coverage, 373 TEST_FILES_PATH . 'source_with_ignore.php' 374 ) 375 ); 376 } 377 378 public function testGetLinesToBeIgnored2() 379 { 380 $this->assertEquals( 381 [1, 5], 382 $this->getLinesToBeIgnored()->invoke( 383 $this->coverage, 384 TEST_FILES_PATH . 'source_without_ignore.php' 385 ) 386 ); 387 } 388 389 public function testGetLinesToBeIgnored3() 390 { 391 $this->assertEquals( 392 [ 393 1, 394 2, 395 3, 396 4, 397 5, 398 8, 399 11, 400 15, 401 16, 402 19, 403 20 404 ], 405 $this->getLinesToBeIgnored()->invoke( 406 $this->coverage, 407 TEST_FILES_PATH . 'source_with_class_and_anonymous_function.php' 408 ) 409 ); 410 } 411 412 public function testGetLinesToBeIgnoredOneLineAnnotations() 413 { 414 $this->assertEquals( 415 [ 416 1, 417 2, 418 3, 419 4, 420 5, 421 6, 422 7, 423 8, 424 9, 425 10, 426 11, 427 12, 428 13, 429 14, 430 15, 431 16, 432 18, 433 20, 434 21, 435 23, 436 24, 437 25, 438 27, 439 28, 440 29, 441 30, 442 31, 443 32, 444 33, 445 34, 446 37 447 ], 448 $this->getLinesToBeIgnored()->invoke( 449 $this->coverage, 450 TEST_FILES_PATH . 'source_with_oneline_annotations.php' 451 ) 452 ); 453 } 454 455 /** 456 * @return \ReflectionMethod 457 */ 458 private function getLinesToBeIgnored() 459 { 460 $getLinesToBeIgnored = new \ReflectionMethod( 461 'SebastianBergmann\CodeCoverage\CodeCoverage', 462 'getLinesToBeIgnored' 463 ); 464 465 $getLinesToBeIgnored->setAccessible(true); 466 467 return $getLinesToBeIgnored; 468 } 469 470 public function testGetLinesToBeIgnoredWhenIgnoreIsDisabled() 471 { 472 $this->coverage->setDisableIgnoredLines(true); 473 474 $this->assertEquals( 475 [], 476 $this->getLinesToBeIgnored()->invoke( 477 $this->coverage, 478 TEST_FILES_PATH . 'source_with_ignore.php' 479 ) 480 ); 481 } 482 483 /** 484 * @expectedException SebastianBergmann\CodeCoverage\CoveredCodeNotExecutedException 485 */ 486 public function testAppendThrowsExceptionIfCoveredCodeWasNotExecuted() 487 { 488 $this->coverage->filter()->addDirectoryToWhitelist(TEST_FILES_PATH); 489 $this->coverage->setCheckForUnexecutedCoveredCode(true); 490 491 $data = [ 492 TEST_FILES_PATH . 'BankAccount.php' => [ 493 29 => -1, 494 31 => -1 495 ] 496 ]; 497 498 $linesToBeCovered = [ 499 TEST_FILES_PATH . 'BankAccount.php' => [ 500 22, 501 24 502 ] 503 ]; 504 505 $linesToBeUsed = []; 506 507 $this->coverage->append($data, 'File1.php', true, $linesToBeCovered, $linesToBeUsed); 508 } 509 510 /** 511 * @expectedException SebastianBergmann\CodeCoverage\CoveredCodeNotExecutedException 512 */ 513 public function testAppendThrowsExceptionIfUsedCodeWasNotExecuted() 514 { 515 $this->coverage->filter()->addDirectoryToWhitelist(TEST_FILES_PATH); 516 $this->coverage->setCheckForUnexecutedCoveredCode(true); 517 518 $data = [ 519 TEST_FILES_PATH . 'BankAccount.php' => [ 520 29 => -1, 521 31 => -1 522 ] 523 ]; 524 525 $linesToBeCovered = [ 526 TEST_FILES_PATH . 'BankAccount.php' => [ 527 29, 528 31 529 ] 530 ]; 531 532 $linesToBeUsed = [ 533 TEST_FILES_PATH . 'BankAccount.php' => [ 534 22, 535 24 536 ] 537 ]; 538 539 $this->coverage->append($data, 'File1.php', true, $linesToBeCovered, $linesToBeUsed); 540 } 541} 542