Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does not recognize prophecies from wrapper methods #121

Closed
func0der opened this issue Feb 13, 2020 · 5 comments · Fixed by #165
Closed

Does not recognize prophecies from wrapper methods #121

func0der opened this issue Feb 13, 2020 · 5 comments · Fixed by #165
Assignees

Comments

@func0der
Copy link

func0der commented Feb 13, 2020

Hey there,

I encountered a problem where your extension does not recognize prophecies that were not build directly inline, but in getters.

Code example:

class FooText extends TestCase {
    /**
     * @test
     * @doesNotPerformAssertions
     */
    public function itCanBeConstructedValid(): void
    {
        new ComposerPublisher(
            $this->prophesize(Nexus::class)->reveal()
        );
    }
   
    /**
     * @test
     * @doesNotPerformAssertions
     */
    public function itCanBeConstructedPhpStanInvalid(): void
    {
        new ComposerPublisher(
            $this->getNexus()->reveal()
        );
    }

    private function getNexus(): ObjectProphecy
    {
        return $this->prophesize(Nexus::class);
    }
}

Scanning itCanBeConstructedPhpStanInvalid PHPStan reports:

Parameter #1 $nexus of class
         NexusPublisher\Publisher\ComposerPublisher constructor expects
         NexusPublisher\Target\Nexus, object given.```

I and maybe others use getters to not duplicate the prophesize() for one and a the same class over and over again. There might be more to the prophecy construction like return object X on every call Y on the prophecy we are building:

private function getNexus(string $path): ObjectProphecy{
    $instance = $this->prophesize(Nexus::class);
    $instance->getPath()->willReturn($path);
    return $instance
}

So i do not think this setup is not THAT unusual.

The notice about the invalid parameter happens at a minimum of level 7.

I hope it is possible to solve this without introducing a PHPDoc like ObjectProphecy<NexusPublisher\Target\Nexus>.

If you need anything else, let me know :)

@localheinz localheinz self-assigned this Feb 18, 2020
@AnnaDamm
Copy link

AnnaDamm commented Feb 26, 2020

I am having a similar (the same?) problem. I tried to use intersection return type or as generic (code in wrapper function is the same as in the first post)

/** @return ObjectProphecy&ClientInterface */
// throws:
 Method
        SsoClientTest::getHttpClient()
         should return
         GuzzleHttp\ClientInterface&Prophecy\Prophecy\ObjectProphecy but
         returns Prophecy\Prophecy\ObjectProphecy<GuzzleHttp\ClientInterface>

But when using the generic version from the error message:

/** @return ObjectProphecy<GuzzleHttp\ClientInterface> */
// throws:
PHPDoc tag @return contains generic type
         Prophecy\Prophecy\ObjectProphecy<GuzzleHttp\ClientInterface> but
         class Prophecy\Prophecy\ObjectProphecy is not generic.

@localheinz
Copy link
Contributor

@ondrejmirtes

Perhaps you have an idea how I can solve this problem?

@ondrejmirtes
Copy link
Contributor

Well, using ObjectProphecyType for this scenario is a workaround from pre-generic days. Today, we could make Prophecy\Prophecy\ObjectProphecy generic using a custom stub file and annotating reveal in appropriate way.

If the developer then annotates:

    /**
     * @return ObjectProphecy<Nexus>
     */
    private function getNexus(): ObjectProphecy
    {
        return $this->prophesize(Nexus::class);
    }

Then it will work as expected. Please note that without the ObjectProphecy<Nexus> part, PHPStan will complain about this code on level 6 and up by default :)

To construct generic ObjectProphecy in some kind of PHPStan extension, you need this code:

new GenericObjectType(\Prophecy\Prophecy\ObjectProphecy::class, [new ObjectType('ProphesizedClass')]);

@localheinz
Copy link
Contributor

Thank you for your quick feedback, @ondrejmirtes!

👍

@ondrejmirtes
Copy link
Contributor

Let me know if you need any more help :) I've been meaning to write some documentation around stubFiles but the gist is here:

It's like a source code, but PHPStan only reads PHPDocs from it. Create a file that looks like one of these: https://github.com/phpstan/phpstan-src/tree/master/stubs

And add it to "stubFiles" PHPStan config option in your phpstan.neon, like this: https://github.com/phpstan/phpstan-src/blob/7cd1d70dcfbfb57a41f6043b15761b4050365c7b/conf/config.neon#L65-L70

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants