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

willReturnCallback() does not pass unknown named variadic arguments to callback #5455

Closed
stefanfisk opened this issue Aug 1, 2023 · 1 comment
Labels
feature/test-doubles Stubs and Mock Objects type/change-in-php-requires-adaptation A change in PHP requires a change in PHPUnit

Comments

@stefanfisk
Copy link

Q A
PHPUnit version 10.2.6
PHP version 8.2.8
Installation Method Composer

Summary

Mocks for methods that accept var args do not passed unknown named variadic arguments to the callback in willReturnCallback(). AFAIK this should be supported since PHP 8.0.0.

I believe the issue exists because the mocks use func_*() for getting the passed arguments, but those functions no longer return all arguments. See func_get_args() for details.

Current behavior

Only indexed arguments are passed.

How to reproduce

Here's two passing tests for unmocked cases and a failing test that uses a mock.

tests/Support/VarArger.php

<?php

namespace Tests\Support;

class VarArger
{
    public function fn(mixed ...$args): mixed
    {
        return [$foo, ...$args];
    }
}

tests/WithReturnCallbackTest.php

<?php

namespace Tests;

use PHPUnit\Framework\TestCase;
use Tests\Support\VarArger;
use stdClass;

class WithReturnCallbackTest extends TestCase
{
    public function testRealInstance(): void
    {
        $real = new VarArger();

        $args = ['foo', 'bar', 'baz' => 'qux'];

        $this->assertSame(
            $args,
            $real->fn(...$args),
        );
    }

    public function testCallback(): void
    {
        $callback = fn ($foo, ...$args) => [$foo, ...$args];

        $args = ['foo', 'bar', 'baz' => 'qux'];

        $this->assertSame(
            $args,
            $callback(...$args),
        );
    }

    public function testMock(): void
    {
        $mock = $this->createMock(VarArger::class);
        $mock
            ->expects($this->once())
            ->method('fn')
            ->withAnyParameters()
            ->willReturnCallback(fn ($foo, ...$args) => [$foo, ...$args]);

        $args = ['foo', 'bar', 'baz' => 'qux'];

        $this->assertSame(
            $args,
            $mock->fn(...$args),
        );
    }
}

The mock class looks like this:

<?php

class Mock_VarArger_343a613f extends Tests\Support\VarArger implements PHPUnit\Framework\MockObject\MockObject
{
    use \PHPUnit\Framework\MockObject\Api;
    use \PHPUnit\Framework\MockObject\Method;
    use \PHPUnit\Framework\MockObject\MockedCloneMethod;

    public function fn(string $foo, mixed ...$args): mixed
    {
        $__phpunit_arguments = [$foo];
        $__phpunit_count     = func_num_args();

        if ($__phpunit_count > 1) {
            $__phpunit_arguments_tmp = func_get_args();

            for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) {
                $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i];
            }
        }

        $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke(
            new \PHPUnit\Framework\MockObject\Invocation(
                'Tests\Support\VarArger', 'fn', $__phpunit_arguments, 'mixed', $this, false
            )
        );

        return $__phpunit_result;
    }
}

Expected behavior

All arguments should be passed to the callback.

@stefanfisk stefanfisk added type/change-in-php-requires-adaptation A change in PHP requires a change in PHPUnit version/10 Something affects PHPUnit 10 labels Aug 1, 2023
@sebastianbergmann sebastianbergmann added feature/test-doubles Stubs and Mock Objects and removed version/10 Something affects PHPUnit 10 labels Aug 1, 2023
@sebastianbergmann sebastianbergmann changed the title willReturnCallback() does not pass unknown named variadic arguments to callback willReturnCallback() does not pass unknown named variadic arguments to callback Jan 12, 2024
@sebastianbergmann
Copy link
Owner

Fixed by #5648.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature/test-doubles Stubs and Mock Objects type/change-in-php-requires-adaptation A change in PHP requires a change in PHPUnit
Projects
None yet
Development

No branches or pull requests

2 participants