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

Changed test typehint from AbstractTest to TestInterface. #173

Merged
merged 1 commit into from
Feb 19, 2016
Merged

Changed test typehint from AbstractTest to TestInterface. #173

merged 1 commit into from
Feb 19, 2016

Conversation

ezzatron
Copy link
Contributor

This PR is very simple, it allows Suite::runTest() to run any TestInterface implementation, instead of requiring tests to extend AbstractTest. It seems like the use of AbstractTest as a type hint was probably left over from a time before TestInterface existed.

What's more interesting, and what I can't figure out, is why this was only causing problems for me under PHP 7.

I have a pretty advanced use case. I am testing asynchronous code that uses Recoil, a generator-based coroutine library. I'm using Peridot's event system to wrap every test in my own implementation of TestInterface that runs the test under Recoil. My Peridot configuration looks like this:

// ... snip ...

class AsyncTestWrapper implements TestInterface
{
    public function __construct(TestInterface $test)
    {
        $this->test = $test;
    }

    public function run(TestResult $result)
    {
        return $this->test->run($result);
    }

    // ... snip ...

    public function getDefinition()
    {
        return function (...$arguments) {
            $definition = $this->test->getDefinition();
            $result = $definition(...$arguments);

            if ($result instanceof Generator) {
                $coroutine = $result;

                Recoil::run(function () use ($coroutine, &$result) {
                    $result = (yield $coroutine);
                });
            }

            return $result;
        };
    }

    // ... snip ...

    public function getDefinitionArguments()
    {
        return $this->test->getDefinitionArguments();
    }

    private $test;
}

return function (EventEmitterInterface $emitter) {
    $emitter->on(
        'suite.start',
        function (Suite $suite) {
            $suite->setTests(
                array_map(
                    function ($test) {
                        return new AsyncTestWrapper($test);
                    },
                    $suite->getTests()
                )
            );
        }
    );
};

This allows Peridot tests to become Recoil coroutines, and to use yield inside tests to perform asynchronous operations:

it('persists the document', function () {
    expect(yield $this->subject->persistDocument($this->id, $this->document))->to->be->true();

    $this->database->write->calledWith($this->id, $this->document, null);
});

This is working perfectly under PHP 5.6, but under PHP 7 I get:

Fatal error: Uncaught TypeError: Argument 1 passed to Peridot\Core\Suite::runTest() must be an instance of Peridot\Core\AbstractTest, instance of AsyncTestWrapper given, called in /path/to/project/vendor/peridot-php/peridot/src/Core/Suite.php on line 83 and defined in /path/to/project/vendor/peridot-php/peridot/src/Core/Suite.php:105
Stack trace:
#0 /path/to/project/vendor/peridot-php/peridot/src/Core/Suite.php(83): Peridot\Core\Suite->runTest(Object(AsyncTestWrapper), Object(Peridot\Core\TestResult))
#1 /path/to/project/vendor/peridot-php/peridot/src/Runner/Runner.php(59): Peridot\Core\Suite->run(Object(Peridot\Core\TestResult))
#2 /path/to/project/vendor/peridot-php/peridot/src/Console/Command.php(176): Peridot\Runner\Runner->run(Object(Peridot\Core\TestResult))
#3 /path/to/project/vendor/peridot-php/peridot/src/Console/Command.php(149): Peridot\Console\Command->getResult()
#4 /path/to/p in /path/to/project/vendor/peridot-php/peridot/src/Core/Suite.php on line 105

I have absolutely no idea how it could be working under 5.6 and not under 7, but there it is. Perhaps someone with a better understanding of Peridot could come up with a simpler, reproducible regression test for this issue.

In any case, this PR makes the problem go away.

@brianium
Copy link
Member

@ezzatron ah. good catch! merging - will likely push a new minor version as a result of this since the contract has changed.

brianium added a commit that referenced this pull request Feb 19, 2016
Changed test typehint from AbstractTest to TestInterface.
@brianium brianium merged commit 5431d3c into peridot-php:master Feb 19, 2016
@ezzatron
Copy link
Contributor Author

👍

@brianium
Copy link
Member

@ezzatron tagged a release of 1.17.0 with this change. thanks again!

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

Successfully merging this pull request may close these issues.

2 participants