Closed vpassapera closed 7 years ago
Can you please use PNG insteaf of WebP for the screenshot? GitHub is not able to display that inline for some reason.
Are you able to see this one?
The otherone was PNG also. Not sure why it didn't display.
They all display properly on my chrome brower under linux and osx.
@derickr Xdebug issue?
I did also do an install with ansible on my build box where i first saw the issue (it's a continuous build so it could have updated xdebug), then i started seeing it on my vagrant box after a destroy and up and destroying compoer dir to try to replicate locally. Just adding a bit more info. The behavior is extremely bizarre.
@sebastianbergmann — Can't say without having the full source file.
What source file? The controller showing the lack of coverage?
On May 11, 2017 07:13, "Derick Rethans" notifications@github.com wrote:
@sebastianbergmann https://github.com/sebastianbergmann — Can't say without having the full source file.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/sebastianbergmann/php-code-coverage/issues/526#issuecomment-300802019, or mute the thread https://github.com/notifications/unsubscribe-auth/ABbK_lWlvc3fENarseXF6e6ZTsfAySySks5r4xd_gaJpZM4NXwfC .
Code:
<?php
namespace AppBundle\Controller;
use AppBundle\CommandBus\GetManifestYamlQuery;
use AppBundle\CommandBus\SendManifestNotificationCommand;
use AppBundle\Form\Type\ManifestNotificationType;
use AppBundle\Model\ManifestEmail;
use Doctrine\ORM\NoResultException;
use FOS\RestBundle\Controller\FOSRestController;
use JMS\Serializer\SerializationContext;
use League\Tactician\CommandBus;
use Nelmio\ApiDocBundle\Annotation as Nelmio;
use FOS\RestBundle\Controller\Annotations as FOS;
use JMS\DiExtraBundle\Annotation as DI;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Tdn\PhpTypes\Type\StringType;
/**
* Class ManifestController.
*/
class ManifestController extends FOSRestController
{
/**
* @var CommandBus
*
* @DI\Inject("tactician.commandbus")
*/
private $commandBus;
/**
* @param string $branch
*
* @FOS\Route("/manifests/{branch}.yml", name="get_manifest", requirements={"branch"="(.+)[^.yml]"})
*
* @Method({"GET"})
* @Nelmio\ApiDoc(
* resource=true,
* section="Manifests",
* description="Download a manifest for a specific branch in yaml format.",
* output="\Symfony\Component\HttpFoundation\Response",
* https=true
* )
*
* @return Response
*/
public function getManifestAction(string $branch)
{
try {
$yaml = $this->commandBus->handle(
new GetManifestYamlQuery(
$branch,
SerializationContext::create()->setGroups(['Manifest'])
)
);
$response = new Response($yaml);
$disposition = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
sprintf(
'manifest-%s.yml',
StringType::create($branch)->replace('/', '-')->toString()
)
);
$response->headers->set('Content-Type', 'text/yaml');
$response->headers->set('Content-Disposition', $disposition);
return $response;
} catch (NoResultException $e) {
// Throw below.
}
throw $this->createNotFoundException();
}
/**
* @Method({"POST"})
* @FOS\Route("/manifests/{branch}/actions/notify", defaults={"_format":"json"})
*
* @Nelmio\ApiDoc(
* resource=true,
* section="Manifests",
* description="Send release information to specified email addresses.",
* input="\AppBundle\Form\Type\ManifestNotificationType",
* output="\Symfony\Component\HttpFoundation\Response",
* https=true
* )
*
* @param Request $request
* @param string $branch
*
* @return Response
*/
public function postManifestNotificationAction(Request $request, string $branch)
{
try {
$result = $this->commandBus->handle(
new GetManifestYamlQuery(
$branch,
SerializationContext::create()->setGroups(ManifestEmail::SERIALIZATION_CONTEXT)
)
);
$command = new SendManifestNotificationCommand($result, $branch);
$form = $this->createForm(
ManifestNotificationType::class,
$command,
['method' => 'POST']
);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->commandBus->handle($command);
return new Response('', Response::HTTP_ACCEPTED);
}
return $this->handleView($this->view($form, Response::HTTP_BAD_REQUEST));
} catch (NoResultException $e) {
// Throw below.
}
throw $this->createNotFoundException();
}
}
Tests:
<?php
namespace Tests\AppBundle\Controller;
use AppBundle\Entity\Branch;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Yaml\Yaml;
use Tdn\PhpTypes\Type\StringType;
use Tests\AppBundle\FunctionalTestCase;
class ManifestControllerTest extends FunctionalTestCase
{
public function testGetManifestYamlNotFound()
{
$this->client->request('GET', '/manifests/noop.yml');
$response = $this->client->getResponse();
$this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode());
}
public function testGetManifestYaml()
{
$keys = [
'appName',
'version',
'buildNum',
'sourceRef',
];
/** @var Branch $branch */
$branch = $this->referenceRepository->getReference('release/COM170401.0');
$path = sprintf('/manifests/%s.yml', $branch->getFullName());
$this->client->request('GET', $path);
$response = $this->client->getResponse();
$this->isSuccessful($response);
$content = Yaml::parse($response->getContent());
$this->assertEquals(
'attachment; filename="manifest-release-COM170401.0.yml"',
$response->headers->get('Content-Disposition')
);
$this->assertEquals(
'text/yaml; charset=UTF-8',
$response->headers->get('Content-Type')
);
$this->assertArrayHasKey('artifacts', $content);
foreach ($content['artifacts'] as $artifact) {
$this->assertEquals($keys, array_keys($artifact));
}
}
public function testGetManifestYamlAlternateConvention()
{
$keys = [
'appName',
'version',
'buildNum',
'sourceRef',
];
/** @var Branch $branch */
$branch = $this->referenceRepository->getReference('release/COM170401.0');
$path = sprintf(
'/manifests/%s.yml',
StringType::create($branch->getFullName())->replace('/', '-')->toString()
);
$this->client->request('GET', $path);
$response = $this->client->getResponse();
$this->isSuccessful($response);
$content = Yaml::parse($response->getContent());
$this->assertEquals(
'attachment; filename="manifest-release-COM170401.0.yml"',
$response->headers->get('Content-Disposition')
);
$this->assertEquals(
'text/yaml; charset=UTF-8',
$response->headers->get('Content-Type')
);
$this->assertArrayHasKey('artifacts', $content);
foreach ($content['artifacts'] as $artifact) {
$this->assertEquals($keys, array_keys($artifact));
}
}
public function testPostManifestNotificationNotFound()
{
$this->client->request('POST', '/manifests/noop/actions/notify.json', ['emails' => []]);
$response = $this->client->getResponse();
$this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode());
}
public function testPostManifestNotificationBadRequest()
{
$payload = ['emails' => []];
/** @var Branch $branch */
$branch = $this->referenceRepository->getReference('release/COM170401.0');
$path = sprintf(
'/manifests/%s/actions/notify.json',
StringType::create($branch->getFullName())->replace('/', '-')->toString()
);
$this->client->request('POST', $path, $payload);
$response = $this->client->getResponse();
$content = json_decode($response->getContent(), true);
$this->assertEquals(Response::HTTP_BAD_REQUEST, $response->getStatusCode());
$this->assertCount(1, $content['errors']);
$this->assertEquals('You must specify at least one email address.', $content['errors'][0]);
}
public function testPostManifestNotificationBadRequestInvalidEmail()
{
$payload = ['emails' => [
'thisisnotanemail',
]];
/** @var Branch $branch */
$branch = $this->referenceRepository->getReference('release/COM170401.0');
$path = sprintf(
'/manifests/%s/actions/notify.json',
StringType::create($branch->getFullName())->replace('/', '-')->toString()
);
$this->client->request('POST', $path, $payload);
$response = $this->client->getResponse();
$content = json_decode($response->getContent(), true);
$this->assertEquals(Response::HTTP_BAD_REQUEST, $response->getStatusCode());
$this->assertCount(
1,
$content['children']['emails']['children'][0]['errors']
);
$this->assertEquals(
'Invalid email found in collection.',
$content['children']['emails']['children'][0]['errors'][0]
);
}
public function testPostManifestNotification()
{
$payload = ['emails' => [
'foo@bar.com',
]];
/** @var Branch $branch */
$branch = $this->referenceRepository->getReference('release/COM170401.0');
$path = sprintf(
'/manifests/%s/actions/notify.json',
StringType::create($branch->getFullName())->replace('/', '-')->toString()
);
$this->client->request('POST', $path, $payload);
$response = $this->client->getResponse();
$this->assertEquals(Response::HTTP_ACCEPTED, $response->getStatusCode());
}
}
Coverage report:
These are functional tests, and before were reporting 100% coverage across all metrics (as they should).
What makes less sense is that they are missing coverage on things like the second argument of a method. That's just odd.
PHP doesn't generate code on lines 55, 103 and 111, so I don't know what this can be:
filename: /tmp/foo.php
function name: getManifestAction
number of ops: 88
compiled vars: !0 = $branch, !1 = $yaml, !2 = $response, !3 = $disposition, !4 = $e
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
50 0 E > EXT_NOP
1 RECV !0
53 2 EXT_STMT
3 FETCH_OBJ_R $5 'commandBus'
4 INIT_METHOD_CALL $5, 'handle'
5 EXT_FCALL_BEGIN
54 6 NEW $5 :-3
7 EXT_FCALL_BEGIN
8 SEND_VAR_EX !0
56 9 INIT_STATIC_METHOD_CALL 'JMS%5CSerializer%5CSerializationContext', 'create'
10 EXT_FCALL_BEGIN
11 DO_FCALL 0 $6
12 EXT_FCALL_END
13 INIT_METHOD_CALL $6, 'setGroups'
14 EXT_FCALL_BEGIN
…
function name: postManifestNotificationAction
number of ops: 98
compiled vars: !0 = $request, !1 = $branch, !2 = $result, !3 = $command, !4 = $form, !5 = $e
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
98 0 E > EXT_NOP
1 RECV !0
2 RECV !1
101 3 EXT_STMT
4 FETCH_OBJ_R $6 'commandBus'
5 INIT_METHOD_CALL $6, 'handle'
6 EXT_FCALL_BEGIN
102 7 NEW $6 :-3
8 EXT_FCALL_BEGIN
9 SEND_VAR_EX !1
104 10 INIT_STATIC_METHOD_CALL 'JMS%5CSerializer%5CSerializationContext', 'create'
11 EXT_FCALL_BEGIN
12 DO_FCALL 0 $7
13 EXT_FCALL_END
14 INIT_METHOD_CALL $7, 'setGroups'
15 EXT_FCALL_BEGIN
16 FETCH_CONSTANT ~7 'AppBundle%5CModel%5CManifestEmail', 'SERIALIZATION_CONTEXT'
17 SEND_VAL_EX ~7
18 DO_FCALL 0 $7
19 EXT_FCALL_END
20 SEND_VAR_NO_REF 4 $7
21 DO_FCALL 0
22 EXT_FCALL_END
23 SEND_VAR_NO_REF 0 $6
24 DO_FCALL 0 $6
25 EXT_FCALL_END
26 ASSIGN !2, $6
108 27 EXT_STMT
28 NEW $6 :8
29 EXT_FCALL_BEGIN
30 SEND_VAR_EX !2
31 SEND_VAR_EX !1
32 DO_FCALL 0
33 EXT_FCALL_END
34 ASSIGN !3, $6
109 35 EXT_STMT
36 INIT_METHOD_CALL 'createForm'
37 EXT_FCALL_BEGIN
110 38 SEND_VAL_EX 'AppBundle%5CForm%5CType%5CManifestNotificationType'
39 SEND_VAR_EX !3
112 40 SEND_VAL_EX <array>
41 DO_FCALL 0 $6
42 EXT_FCALL_END
43 ASSIGN !4, $6
115 44 EXT_STMT
…
This is happening on a few tests.... always on parameters. The order seems random. I do see them listed above referenced though (e.g. !0 on line 12)
Any ideas?
The same issue. After update to Xdebug v2.5.3
Looks like this is not an issue with this component (or PHPUnit). Either the PHP compiler does not generated opcodes for the sourcecode lines in question or Xdebug does not recognize them.
This should be re-opened as per https://bugs.xdebug.org/view.php?id=1440
Not sure if it's possible for someone to test this on a version of PHP before 7.0.19 and see if something in that release broke it?
Alright, this is getting to be a major pain, almost detrimental in nature, due to the bad reporting coming in....
/**
* @FOS\Route("/releases/{release}", defaults={"_format":"json"}, requirements={"release"="(.+)[^[.json|.html]"})
*
* @Nelmio\ApiDoc(
* resource=true,
* section="Releases",
* description="Get a release.",
* https=true,
* output="\AppBundle\Response\ReleaseResponse"
* )
*
* @Method("GET")
* @FOS\View(
* templateVar="release",
* serializerGroups={"Default", "Detailed"}
* )
*
* @param string $release
*
* @return ReleaseResponse
*/
public function getReleaseAction(string $release): ReleaseResponse
{
try {
return $this->commandBus->handle(new GetReleaseQuery($release));
} catch (NoResultException $e) {
// Throw exception below.
}
throw $this->createNotFoundException();
}
With the following tests
<?php
namespace Tests\AppBundle\Controller;
use AppBundle\Entity\Release;
use Tests\AppBundle\FunctionalTestCase;
use Symfony\Component\HttpFoundation\Response;
use Tdn\PhpTypes\Type\StringType;
/**
* Class ReleaseControllerTest.
*/
class ReleaseControllerTest extends FunctionalTestCase
{
public function testGetReleaseNotFound()
{
$this->client->request('GET', '/releases/foo.json');
$response = $this->client->getResponse();
$this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode());
}
public function testGetAllReleasesJson()
{
/** @var Release[] $expected */
$expected = [
$this->referenceRepository->getReference('release-release/COM170701.0'),
$this->referenceRepository->getReference('release-hotfix/COM170301.2'),
$this->referenceRepository->getReference('release-release/COM170401.0'),
$this->referenceRepository->getReference('release-release/COM170501.0'),
];
$this->client->request('GET', '/releases.json');
$response = $this->client->getResponse();
$this->isSuccessful($response);
$response = json_decode($response->getContent(), true);
$this->assertEquals(count($expected), count($response['releases']));
foreach ($response['releases'] as $actualBranch) {
$currentExpected = array_shift($expected);
$this->assertEquals($currentExpected->getName(), $actualBranch['name']);
$this->assertEquals($currentExpected->getIaspec(), $actualBranch['iaSpec']);
$this->assertEquals($currentExpected->getType(), $actualBranch['type']);
$this->assertEquals($currentExpected->getCreatedAt()->format(DATE_ATOM), $actualBranch['createdAt']);
$this->assertEquals($currentExpected->getUpdatedAt()->format(DATE_ATOM), $actualBranch['updatedAt']);
}
}
public function testGetReleaseJson()
{
/** @var Release $expected */
$expected = $this->referenceRepository->getReference('release-hotfix/COM170301.2');
$path = sprintf(
'/releases/%s.json',
StringType::create($expected->getFullName())->replace('/', '-')->toString(),
$expected->getName()
);
$this->client->request('GET', $path);
$response = $this->client->getResponse();
$this->isSuccessful($response);
$response = json_decode($response->getContent(), true);
$this->assertEquals($expected->getName(), $response['name']);
$this->assertEquals($expected->getType(), $response['type']);
$this->assertEquals($expected->getIaspec(), $response['iaSpec']);
$this->assertEquals($expected->getStatus(), $response['status']);
$this->assertEquals($expected->getCreatedAt()->format(\DateTime::ATOM), $response['createdAt']);
$this->assertEquals($expected->getUpdatedAt()->format(\DateTime::ATOM), $response['updatedAt']);
$this->assertArrayHasKey('artifacts', $response);
$this->assertArrayHasKey('removedArtifacts', $response);
}
}
Says:
I literally cannot have code coverage guard turned on anywhere, cause it says it is not covered.... What can we do to get this fixed please?
Also please notice how
public function testGetReleaseNotFound()
{
$this->client->request('GET', '/releases/foo.json');
$response = $this->client->getResponse();
$this->assertEquals(Response::HTTP_NOT_FOUND, $response->getStatusCode());
}
Covers explicitly those lines. PHPUnit runs that tests.
[23:26:00] [vagrant@isengard] /vagrant [][feature/releases-view S:16 U:2 ✗] → ./bin/phpunit tests/AppBundle/Controller/ReleaseControllerTest.php
PHPUnit 6.1.4 by Sebastian Bergmann and contributors.
... 3 / 3 (100%)
Time: 40.82 seconds, Memory: 34.00MB
OK (3 tests, 32 assertions)
Generating code coverage report in Clover XML format ... done
Generating Crap4J report XML file ... done
Generating code coverage report in HTML format ... done
:(
Thank you for your report.
Please provide a minimal, self-contained, reproducing test case that shows the problem you are reporting. In your specific case this means that no framework code etc. is used/required that is affected by annotations.
Without such a minimal, self-contained, reproducing test case I will not be able to investigate this issue.
I think since 7.0 I started to see it very often. I found phpdbg
gives accurate results.
phpdbg -qrr ./vendor/bin/phpunit --coverage-text
It increased my coverage, but it still didn't fix the last outlined item.
Thanks @neomerx, this is better than nothing for now. (Coverage back up to 99.5%)
Basically it started reporting coverage for the item listed in the OP (not reporting in multi-line statements, and functions/methods and classes/traits reports 100%) that @derickr @sebastianbergmann said was fixed here:
https://bugs.xdebug.org/view.php?id=1440#c4349
It still however lacks coverage in the symfony framework functional test case. That may yet be a bug with this.
@vpassapera — There can be many reasons why a specific line is not covered. Each of them are likely a different issue. In order to be able to reproduce anything and not get bogged down with details, you need to provide the following in ONE new issue per case.
That means:
php -v
output.tar.gz
archive or a GitHub repository with a reproduce case. With one file that shows the problem and one test case file (with the exception that sometimes, you might need two source files to show a problem.This information should be file as one specific case per issue.
Understood.
I'll try to reproduce the symfony controller gaps in coverage in a public repo and link it here (I'll add some ansible provisioning and a vagrant file to ensure the same version runs on that example repo).
thanks for your time @derickr
While I switched the driver to phpdbg for coverage, I still use xdebug for actual debugging (e.g. phpstorm, etc) :)
Seems like this was fixed as my tests are now reporting 100% coverage.
Huzzah!
Glad I found this, I have the exact issue. What did you do exactly to fix the issue? I'm on PHP 7.1, PHP unit 5.x X. Not sure which version xdebug.
Should I upgrade PHP unit 6.x X and xdebug?
@wired00 it was fixed in Xdebug 2.5.5
, don't know if you need to update PhpUnit too or not.
Thanks @VasekPurchart I'll upgrade now. I'm currently on:
PHP 7.1.5
Xdebug 2.5.4
phpunit/php-code-coverage 4.0.8
Ok Great, for the benefit of others. I'm on OSX and fixed by going from xdebug 2.5.4
> 2.5.5
.
I simply ran brew update
> brew upgrade
now running 7.1.8 with Xdebug 2.5.5
and coverage is working perfectly.
@sebastianbergmann @filips123
I have same problem with PHP 7.2 and XDebug 2.6.
Q | A |
---|---|
php-code-coverage version | 6.1.3 |
PHP version | 7.2.11-3+ubuntu16.04.1+deb.sury.org+1 |
Driver | Xdebug |
Xdebug version | 2.6.1 |
Installation Method | Composer and PHAR |
Usage Method | PHPUnit |
PHPUnit version | 7.4.3 |
Source file:
<?php
namespace SunshineCMS\Services;
use Illuminate\Database\Capsule\Manager as IlluminateCapsule;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class DatabaseService implements ServiceProviderInterface
{
public function register(Container $container)
{
if (!isset($container['database'])) {
$container['database'] = function ($container) {
$settings = $container->get('settings')['database'];
$capsule = new IlluminateCapsule;
$capsule->addConnection($settings);
$capsule->setAsGlobal();
$capsule->bootEloquent();
return clone $capsule;
};
}
}
}
Test file:
<?php
namespace SunshineCMS\Tests\Unit\Services;
use PHPUnit\Framework\TestCase;
use SunshineCMS\Container;
use SunshineCMS\Services\DatabaseService;
class DatabaseServiceTest extends TestCase
{
/**
* @var array
*/
protected $settings;
public function setUp()
{
$this->settings = [
'siteURL' => 'https://sunshinecms.local/',
'siteDir' => dirname(dirname(__DIR__)),
'scriptName' => '/index.php',
];
}
/**
* @covers SunshineCMS\Services\DatabaseService::register()
*/
public function testServicesRegistration()
{
$container = new Container(['settings' => $this->settings]);
$service = new DatabaseService;
$service->register($container);
$this->assertTrue(isset($container->database));
$this->assertInstanceOf('\Illuminate\Database\Capsule\Manager', $container->database);
}
}
Coverage details:
If I run PHPUnit with phpdbg -qrr ./vendor/bin/phpunit
, coverage is normal (100%).
I am facing a similar problem, my configuration is as follows: OS: Mac OS 10.15.6 php: 7.3.11 xdebug: 2.7.0 Can someone please guide me? Generated by php-code-coverage 9.1.5 using PHP 7.3.11 with Xdebug 2.7.0 and PHPUnit 9.3.8 at Thu Sep 10 6:00:16 UTC 2020.
Today, after doing a composer update, my coverage guards broke, when phpunit started reporting that my coverage had dropped to 88% from 100%. (I started with phpunit version 5.6.x, and upgraded to phpunit 6.1 after I saw the bug, in hopes of it being fixed, seems to be present in all recent versions including the 5.x line)
Since no code had changed this seemed incorrect (only had done a composer update, no code changes).
Further investigation shows that PHPUnit is incorrectly reporting random arguments in methods and functions as not covered (even though they are).
Example:
In the example above, you can see that 4 tests actually cover that method, but it is saying that 1 argument is not covered. That seems impossible, since I have to call that method with those arguments. Especially since these tests are actually functional tests. Previously, these tests showed full coverage accross all metrics (Line, Functions and Methods, Classes and Traits), now, Lines show 100% but not Functions and Methods or Classes and Traits.
Example of one of the tests:
As you can see, this is fully a functional test that should cover all the lines. PHPUnit reports they are not covered?
This is causing all my reports and CI to break, since it uses phpunit to determine coverage thresholds.
My phpunit config
Relevant composer parts:
Xdebug Config
Seems that anywhere I use a mock (i use mockery), or symfony functional tests, phpunit is not honoring that coverage under the Methods & Functions | Classes metrics...it did not that long ago.
MOVED FROM https://github.com/sebastianbergmann/phpunit/issues/2676