diff --git a/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php b/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php index 7f3d35d803..52587cc7c7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php @@ -29,7 +29,7 @@ use Symfony\Component\Routing\RouteCollectionBuilder; * @author Fabien Potencier * * @method void configureRoutes(RoutingConfigurator $routes) - * @method void configureContainer(ContainerConfigurator $c) + * @method void configureContainer(ContainerConfigurator $container) */ trait MicroKernelTrait { diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php index 87f6095d8f..d2bc1152a2 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php @@ -280,15 +280,26 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass return; } + if ('mixed' === $type) { + return; + } + if (is_a($class, $type, true)) { return; } - $checkFunction = sprintf('is_%s', $type); - - if (!$reflectionType->isBuiltin() || !$checkFunction($value)) { - throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? $class : get_debug_type($value), $parameter); + if ('false' === $type) { + if (false === $value) { + return; + } + } elseif ($reflectionType->isBuiltin()) { + $checkFunction = sprintf('is_%s', $type); + if ($checkFunction($value)) { + return; + } } + + throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? $class : get_debug_type($value), $parameter); } private function getExpressionLanguage(): ExpressionLanguage diff --git a/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php b/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php index 461c50cce6..2a11626fe2 100644 --- a/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php +++ b/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php @@ -25,6 +25,11 @@ class InvalidParameterTypeException extends InvalidArgumentException $acceptedType = $acceptedType instanceof \ReflectionNamedType ? $acceptedType->getName() : (string) $acceptedType; $this->code = $type; - parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s::%s()" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName(), $acceptedType, $type)); + $function = $parameter->getDeclaringFunction(); + $functionName = $function instanceof \ReflectionMethod + ? sprintf('%s::%s', $function->getDeclaringClass()->getName(), $function->getName()) + : $function->getName(); + + parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s()" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $functionName, $acceptedType, $type)); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php index ca7aecf9e7..d331c648d1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php @@ -836,6 +836,22 @@ class CheckTypeDeclarationsPassTest extends TestCase $this->addToAssertionCount(1); } + /** + * @requires PHP 8 + */ + public function testUnionTypePassesWithFalse() + { + $container = new ContainerBuilder(); + + $container->register('union', UnionConstructor::class) + ->setFactory([UnionConstructor::class, 'create']) + ->setArguments([false]); + + (new CheckTypeDeclarationsPass(true))->process($container); + + $this->addToAssertionCount(1); + } + /** * @requires PHP 8 */ @@ -851,8 +867,6 @@ class CheckTypeDeclarationsPassTest extends TestCase $this->expectExceptionMessage('Invalid definition for service "union": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\UnionConstructor::__construct()" accepts "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo|int", "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Waldo" passed.'); (new CheckTypeDeclarationsPass(true))->process($container); - - $this->addToAssertionCount(1); } /** @@ -869,6 +883,57 @@ class CheckTypeDeclarationsPassTest extends TestCase $this->expectExceptionMessage('Invalid definition for service "union": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\UnionConstructor::__construct()" accepts "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo|int", "array" passed.'); (new CheckTypeDeclarationsPass(true))->process($container); + } + + /** + * @requires PHP 8 + */ + public function testUnionTypeWithFalseFailsWithReference() + { + $container = new ContainerBuilder(); + + $container->register('waldo', Waldo::class); + $container->register('union', UnionConstructor::class) + ->setFactory([UnionConstructor::class, 'create']) + ->setArguments([new Reference('waldo')]); + + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "union": argument 1 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\UnionConstructor::create()" accepts "array|false", "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Waldo" passed.'); + + (new CheckTypeDeclarationsPass(true))->process($container); + } + + /** + * @requires PHP 8 + */ + public function testUnionTypeWithFalseFailsWithTrue() + { + $container = new ContainerBuilder(); + + $container->register('waldo', Waldo::class); + $container->register('union', UnionConstructor::class) + ->setFactory([UnionConstructor::class, 'create']) + ->setArguments([true]); + + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "union": argument 1 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\UnionConstructor::create()" accepts "array|false", "boolean" passed.'); + + (new CheckTypeDeclarationsPass(true))->process($container); + } + + /** + * @requires PHP 8 + */ + public function testReferencePassesMixed() + { + $container = new ContainerBuilder(); + + $container->register('waldo', Waldo::class); + $container->register('union', UnionConstructor::class) + ->setFactory([UnionConstructor::class, 'make']) + ->setArguments([new Reference('waldo')]); + + (new CheckTypeDeclarationsPass(true))->process($container); $this->addToAssertionCount(1); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Exception/InvalidParameterTypeExceptionTest.php b/src/Symfony/Component/DependencyInjection/Tests/Exception/InvalidParameterTypeExceptionTest.php new file mode 100644 index 0000000000..d61388ea2d --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Exception/InvalidParameterTypeExceptionTest.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Exception; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Exception\InvalidParameterTypeException; + +final class InvalidParameterTypeExceptionTest extends TestCase +{ + /** + * @dataProvider provideReflectionParameters + */ + public function testExceptionMessage(\ReflectionParameter $parameter, string $expectedMessage) + { + $exception = new InvalidParameterTypeException('my_service', 'int', $parameter); + + self::assertSame($expectedMessage, $exception->getMessage()); + } + + public function provideReflectionParameters(): iterable + { + yield 'static method' => [ + new \ReflectionParameter([MyClass::class, 'doSomething'], 0), + 'Invalid definition for service "my_service": argument 1 of "Symfony\Component\DependencyInjection\Tests\Exception\MyClass::doSomething()" accepts "array", "int" passed.', + ]; + + yield 'function' => [ + new \ReflectionParameter(__NAMESPACE__.'\\myFunction', 0), + 'Invalid definition for service "my_service": argument 1 of "Symfony\Component\DependencyInjection\Tests\Exception\myFunction()" accepts "array", "int" passed.', + ]; + } +} + +class MyClass +{ + public static function doSomething(array $arguments): void + { + } +} + +function myFunction(array $arguments): void +{ +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/UnionConstructor.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/UnionConstructor.php index 5ba5972863..144480a978 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/UnionConstructor.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/UnionConstructor.php @@ -7,4 +7,14 @@ class UnionConstructor public function __construct(Foo|int $arg) { } + + public static function create(array|false $arg): static + { + return new static(0); + } + + public static function make(mixed $arg): static + { + return new static(0); + } } diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/README.md b/src/Symfony/Component/Notifier/Bridge/GoogleChat/README.md index 8a4b55c7e8..53da1e8060 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/README.md +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/README.md @@ -14,7 +14,7 @@ where: - `ACCESS_KEY` is your Google Chat access key - `ACCESS_TOKEN` is your Google Chat access token - `SPACE` is the Google Chat space - - `THREAD_KEY` is the the Google Chat message thread to group messages into a single thread (optional) + - `THREAD_KEY` is the Google Chat message thread to group messages into a single thread (optional) Resources --------- diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatOptionsTest.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatOptionsTest.php index aa763bcd0f..691958c46a 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatOptionsTest.php +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatOptionsTest.php @@ -14,7 +14,7 @@ namespace Symfony\Component\Notifier\Bridge\GoogleChat\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Notifier\Bridge\GoogleChat\GoogleChatOptions; -class GoogleChatOptionsTest extends TestCase +final class GoogleChatOptionsTest extends TestCase { public function testToArray() { diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportFactoryTest.php index 01a8d263f2..0840a3476a 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportFactoryTest.php @@ -11,65 +11,46 @@ namespace Symfony\Component\Notifier\Bridge\GoogleChat\Tests; -use PHPUnit\Framework\TestCase; use Symfony\Component\Notifier\Bridge\GoogleChat\GoogleChatTransportFactory; -use Symfony\Component\Notifier\Exception\IncompleteDsnException; -use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; -use Symfony\Component\Notifier\Transport\Dsn; +use Symfony\Component\Notifier\Tests\TransportFactoryTestCase; +use Symfony\Component\Notifier\Transport\TransportFactoryInterface; -final class GoogleChatTransportFactoryTest extends TestCase +final class GoogleChatTransportFactoryTest extends TransportFactoryTestCase { - public function testCreateWithDsn() - { - $factory = $this->createFactory(); - - $transport = $factory->create(Dsn::fromString('googlechat://abcde-fghij:kl_mnopqrstwxyz%3D@chat.googleapis.com/AAAAA_YYYYY')); - - $this->assertSame('googlechat://chat.googleapis.com/AAAAA_YYYYY', (string) $transport); - } - - public function testCreateWithThreadKeyInDsn() - { - $factory = $this->createFactory(); - - $transport = $factory->create(Dsn::fromString('googlechat://abcde-fghij:kl_mnopqrstwxyz%3D@chat.googleapis.com/AAAAA_YYYYY?threadKey=abcdefg')); - - $this->assertSame('googlechat://chat.googleapis.com/AAAAA_YYYYY?threadKey=abcdefg', (string) $transport); - } - - public function testCreateRequiresCredentials() - { - $factory = $this->createFactory(); - - $this->expectException(IncompleteDsnException::class); - - $factory->create(Dsn::fromString('googlechat://chat.googleapis.com/v1/spaces/AAAAA_YYYYY/messages')); - } - - public function testSupportsReturnsTrueWithSupportedScheme() - { - $factory = $this->createFactory(); - - $this->assertTrue($factory->supports(Dsn::fromString('googlechat://host/path'))); - } - - public function testSupportsReturnsFalseWithUnsupportedScheme() - { - $factory = $this->createFactory(); - - $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://host/path'))); - } - - public function testUnsupportedSchemeThrowsUnsupportedSchemeException() - { - $factory = $this->createFactory(); - - $this->expectException(UnsupportedSchemeException::class); - $factory->create(Dsn::fromString('somethingElse://host/path')); - } - - private function createFactory(): GoogleChatTransportFactory + /** + * @return GoogleChatTransportFactory + */ + public function createFactory(): TransportFactoryInterface { return new GoogleChatTransportFactory(); } + + public function createProvider(): iterable + { + yield [ + 'googlechat://chat.googleapis.com/AAAAA_YYYYY', + 'googlechat://abcde-fghij:kl_mnopqrstwxyz%3D@chat.googleapis.com/AAAAA_YYYYY', + ]; + + yield [ + 'googlechat://chat.googleapis.com/AAAAA_YYYYY?threadKey=abcdefg', + 'googlechat://abcde-fghij:kl_mnopqrstwxyz%3D@chat.googleapis.com/AAAAA_YYYYY?threadKey=abcdefg', + ]; + } + + public function supportsProvider(): iterable + { + yield [true, 'googlechat://host/path']; + yield [false, 'somethingElse://host/path']; + } + + public function incompleteDsnProvider(): iterable + { + yield 'missing credentials' => ['googlechat://chat.googleapis.com/v1/spaces/AAAAA_YYYYY/messages']; + } + + public function unsupportedSchemeProvider(): iterable + { + yield ['somethingElse://host/path']; + } } diff --git a/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php index 7c4a9d2143..98c40c73d9 100644 --- a/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php @@ -11,41 +11,37 @@ namespace Symfony\Component\Notifier\Bridge\Infobip\Tests; -use PHPUnit\Framework\TestCase; use Symfony\Component\Notifier\Bridge\Infobip\InfobipTransport; -use Symfony\Component\Notifier\Exception\LogicException; +use Symfony\Component\Notifier\Message\ChatMessage; use Symfony\Component\Notifier\Message\MessageInterface; use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Component\Notifier\Tests\TransportTestCase; +use Symfony\Component\Notifier\Transport\TransportInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; -final class InfobipTransportTest extends TestCase +final class InfobipTransportTest extends TransportTestCase { - public function testToStringContainsProperties() + /** + * @return InfobipTransport + */ + public function createTransport(?HttpClientInterface $client = null): TransportInterface { - $transport = $this->createTransport(); - - $this->assertSame('infobip://host.test?from=0611223344', (string) $transport); + return (new InfobipTransport('authtoken', '0611223344', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } - public function testSupportsMessageInterface() + public function toStringProvider(): iterable { - $transport = $this->createTransport(); - - $this->assertTrue($transport->supports(new SmsMessage('0611223344', 'Hello!'))); - $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); + yield ['infobip://host.test?from=0611223344', $this->createTransport()]; } - public function testSendNonSmsMessageThrowsLogicException() + public function supportedMessagesProvider(): iterable { - $transport = $this->createTransport(); - - $this->expectException(LogicException::class); - - $transport->send($this->createMock(MessageInterface::class)); + yield [new SmsMessage('0611223344', 'Hello!')]; } - private function createTransport(): InfobipTransport + public function unsupportedMessagesProvider(): iterable { - return (new InfobipTransport('authtoken', '0611223344', $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + yield [new ChatMessage('Hello!')]; + yield [$this->createMock(MessageInterface::class)]; } } diff --git a/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportFactoryTest.php index 51dd961963..76ddaeb753 100644 --- a/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportFactoryTest.php @@ -2,55 +2,41 @@ namespace Symfony\Component\Notifier\Bridge\LinkedIn\Tests; -use PHPUnit\Framework\TestCase; use Symfony\Component\Notifier\Bridge\LinkedIn\LinkedInTransportFactory; -use Symfony\Component\Notifier\Exception\IncompleteDsnException; -use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; -use Symfony\Component\Notifier\Transport\Dsn; +use Symfony\Component\Notifier\Tests\TransportFactoryTestCase; +use Symfony\Component\Notifier\Transport\TransportFactoryInterface; -final class LinkedInTransportFactoryTest extends TestCase +final class LinkedInTransportFactoryTest extends TransportFactoryTestCase { - public function testCreateWithDsn() - { - $factory = $this->createFactory(); - - $transport = $factory->create(Dsn::fromString('linkedin://accessToken:UserId@host.test')); - - $this->assertSame('linkedin://host.test', (string) $transport); - } - - public function testCreateWithOnlyAccessTokenOrUserIdThrowsIncompleteDsnException() - { - $factory = $this->createFactory(); - - $this->expectException(IncompleteDsnException::class); - $factory->create(Dsn::fromString('linkedin://AccessTokenOrUserId@default')); - } - - public function testSupportsReturnsTrueWithSupportedScheme() - { - $factory = $this->createFactory(); - - $this->assertTrue($factory->supports(Dsn::fromString('linkedin://host/path'))); - } - - public function testSupportsReturnsFalseWithUnsupportedScheme() - { - $factory = $this->createFactory(); - - $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://host/path'))); - } - - public function testUnsupportedSchemeThrowsUnsupportedSchemeException() - { - $factory = $this->createFactory(); - - $this->expectException(UnsupportedSchemeException::class); - $factory->create(Dsn::fromString('somethingElse://accessToken:UserId@default')); - } - - private function createFactory(): LinkedInTransportFactory + /** + * @return LinkedInTransportFactory + */ + public function createFactory(): TransportFactoryInterface { return new LinkedInTransportFactory(); } + + public function createProvider(): iterable + { + yield [ + 'linkedin://host.test', + 'linkedin://accessToken:UserId@host.test', + ]; + } + + public function supportsProvider(): iterable + { + yield [true, 'linkedin://host']; + yield [false, 'somethingElse://host']; + } + + public function incompleteDsnProvider(): iterable + { + yield 'missing account or user_id' => ['linkedin://AccessTokenOrUserId@default']; + } + + public function unsupportedSchemeProvider(): iterable + { + yield ['somethingElse://accessToken:UserId@default']; + } } diff --git a/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytTransportFactoryTest.php new file mode 100644 index 0000000000..1001dff8d0 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytTransportFactoryTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Mobyt\Tests; + +use Symfony\Component\Notifier\Bridge\Mobyt\MobytTransportFactory; +use Symfony\Component\Notifier\Tests\TransportFactoryTestCase; +use Symfony\Component\Notifier\Transport\TransportFactoryInterface; + +/** + * @author Oskar Stark + */ +final class MobytTransportFactoryTest extends TransportFactoryTestCase +{ + /** + * @return MobytTransportFactory + */ + public function createFactory(): TransportFactoryInterface + { + return new MobytTransportFactory(); + } + + public function createProvider(): iterable + { + yield [ + 'mobyt://host.test?from=FROM&type_quality=LL', + 'mobyt://accountSid:authToken@host.test?from=FROM', + ]; + + yield [ + 'mobyt://host.test?from=FROM&type_quality=N', + 'mobyt://accountSid:authToken@host.test?from=FROM&type_quality=N', + ]; + } + + public function supportsProvider(): iterable + { + yield [true, 'mobyt://accountSid:authToken@host.test?from=FROM']; + yield [false, 'somethingElse://accountSid:authToken@host.test?from=FROM']; + } + + public function incompleteDsnProvider(): iterable + { + yield 'missing token' => ['mobyt://host.test?from=FROM']; + yield 'missing option: from' => ['mobyt://accountSid:authToken@host']; + } + + public function unsupportedSchemeProvider(): iterable + { + yield ['somethingElse://accountSid:authToken@host.test?from=FROM']; + yield ['somethingElse://accountSid:authToken@host.test']; // missing "from" option + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytTransportTest.php new file mode 100644 index 0000000000..906ecebcf4 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytTransportTest.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Mobyt\Tests; + +use Symfony\Component\Notifier\Bridge\Mobyt\MobytOptions; +use Symfony\Component\Notifier\Bridge\Mobyt\MobytTransport; +use Symfony\Component\Notifier\Message\ChatMessage; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Component\Notifier\Tests\TransportTestCase; +use Symfony\Component\Notifier\Transport\TransportInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Oskar Stark + */ +final class MobytTransportTest extends TransportTestCase +{ + /** + * @return MobytTransport + */ + public function createTransport(?HttpClientInterface $client = null, string $messageType = MobytOptions::MESSAGE_TYPE_QUALITY_LOW): TransportInterface + { + return (new MobytTransport('accountSid', 'authToken', 'from', $messageType, $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + } + + public function toStringProvider(): iterable + { + yield ['mobyt://host.test?from=from&type_quality=LL', $this->createTransport()]; + yield ['mobyt://host.test?from=from&type_quality=N', $this->createTransport(null, MobytOptions::MESSAGE_TYPE_QUALITY_HIGH)]; + } + + public function supportedMessagesProvider(): iterable + { + yield [new SmsMessage('0611223344', 'Hello!')]; + } + + public function unsupportedMessagesProvider(): iterable + { + yield [new ChatMessage('Hello!')]; + yield [$this->createMock(MessageInterface::class)]; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransport.php b/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransport.php index f078d6411d..b25db1ebc7 100644 --- a/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransport.php @@ -47,6 +47,10 @@ final class SlackTransport extends AbstractTransport public function __toString(): string { + if (null === $this->chatChannel) { + return sprintf('slack://%s', $this->getEndpoint()); + } + return sprintf('slack://%s?channel=%s', $this->getEndpoint(), urlencode($this->chatChannel)); } diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php index 1aed295e36..24d6730fe4 100644 --- a/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php @@ -11,40 +11,37 @@ namespace Symfony\Component\Notifier\Bridge\Smsapi\Tests; -use PHPUnit\Framework\TestCase; use Symfony\Component\Notifier\Bridge\Smsapi\SmsapiTransport; -use Symfony\Component\Notifier\Exception\LogicException; +use Symfony\Component\Notifier\Message\ChatMessage; use Symfony\Component\Notifier\Message\MessageInterface; use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Component\Notifier\Tests\TransportTestCase; +use Symfony\Component\Notifier\Transport\TransportInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; -final class SmsapiTransportTest extends TestCase +final class SmsapiTransportTest extends TransportTestCase { - public function testToStringContainsProperties() + /** + * @return SmsapiTransport + */ + public function createTransport(?HttpClientInterface $client = null): TransportInterface { - $transport = $this->createTransport(); - - $this->assertSame('smsapi://test.host?from=testFrom', (string) $transport); + return (new SmsapiTransport('testToken', 'testFrom', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('test.host'); } - public function testSupportsMessageInterface() + public function toStringProvider(): iterable { - $transport = $this->createTransport(); - - $this->assertTrue($transport->supports(new SmsMessage('0611223344', 'Hello!'))); - $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); + yield ['smsapi://test.host?from=testFrom', $this->createTransport()]; } - public function testSendNonChatMessageThrows() + public function supportedMessagesProvider(): iterable { - $transport = $this->createTransport(); - - $this->expectException(LogicException::class); - $transport->send($this->createMock(MessageInterface::class)); + yield [new SmsMessage('0611223344', 'Hello!')]; } - private function createTransport(): SmsapiTransport + public function unsupportedMessagesProvider(): iterable { - return (new SmsapiTransport('testToken', 'testFrom', $this->createMock(HttpClientInterface::class)))->setHost('test.host'); + yield [new ChatMessage('Hello!')]; + yield [$this->createMock(MessageInterface::class)]; } } diff --git a/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php index d02adb010b..eeed3b5024 100644 --- a/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php @@ -50,7 +50,7 @@ final class TelegramTransportTest extends TransportTestCase yield [$this->createMock(MessageInterface::class)]; } - public function testSendWithErrorResponseThrows() + public function testSendWithErrorResponseThrowsTransportException() { $this->expectException(TransportException::class); $this->expectExceptionMessageMatches('/testDescription.+testErrorCode/'); diff --git a/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php index 1af5b06eca..422a04d118 100644 --- a/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php @@ -11,40 +11,37 @@ namespace Symfony\Component\Notifier\Bridge\Zulip\Tests; -use PHPUnit\Framework\TestCase; use Symfony\Component\Notifier\Bridge\Zulip\ZulipTransport; -use Symfony\Component\Notifier\Exception\LogicException; use Symfony\Component\Notifier\Message\ChatMessage; use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Component\Notifier\Tests\TransportTestCase; +use Symfony\Component\Notifier\Transport\TransportInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; -final class ZulipTransportTest extends TestCase +final class ZulipTransportTest extends TransportTestCase { - public function testToStringContainsProperties() + /** + * @return ZulipTransport + */ + public function createTransport(?HttpClientInterface $client = null): TransportInterface { - $transport = $this->createTransport(); - - $this->assertSame('zulip://test.host?channel=testChannel', (string) $transport); + return (new ZulipTransport('testEmail', 'testToken', 'testChannel', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('test.host'); } - public function testSupportsChatMessage() + public function toStringProvider(): iterable { - $transport = $this->createTransport(); - - $this->assertTrue($transport->supports(new ChatMessage('testChatMessage'))); - $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); + yield ['zulip://test.host?channel=testChannel', $this->createTransport()]; } - public function testSendNonChatMessageThrows() + public function supportedMessagesProvider(): iterable { - $transport = $this->createTransport(); - - $this->expectException(LogicException::class); - $transport->send($this->createMock(MessageInterface::class)); + yield [new ChatMessage('Hello!')]; } - private function createTransport(): ZulipTransport + public function unsupportedMessagesProvider(): iterable { - return (new ZulipTransport('testEmail', 'testToken', 'testChannel', $this->createMock(HttpClientInterface::class)))->setHost('test.host'); + yield [new SmsMessage('0611223344', 'Hello!')]; + yield [$this->createMock(MessageInterface::class)]; } } diff --git a/src/Symfony/Component/Notifier/CHANGELOG.md b/src/Symfony/Component/Notifier/CHANGELOG.md index 55144822a3..88403dba51 100644 --- a/src/Symfony/Component/Notifier/CHANGELOG.md +++ b/src/Symfony/Component/Notifier/CHANGELOG.md @@ -12,7 +12,6 @@ CHANGELOG ----- * [BC BREAK] The `TransportInterface::send()` and `AbstractTransport::doSend()` methods changed to return a `?SentMessage` instance instead of `void`. - * Added the Zulip notifier bridge * The `EmailRecipientInterface` and `RecipientInterface` were introduced. * Added `email` and `phone` properties to `Recipient`. * [BC BREAK] Changed the type-hint of the `$recipient` argument in the `as*Message()` method @@ -30,7 +29,6 @@ CHANGELOG 5.1.0 ----- - * Added the Mattermost notifier bridge * [BC BREAK] The `ChatMessage::fromNotification()` method's `$recipient` and `$transport` arguments were removed. * [BC BREAK] The `EmailMessage::fromNotification()` and `SmsMessage::fromNotification()` diff --git a/src/Symfony/Component/VarDumper/Cloner/Data.php b/src/Symfony/Component/VarDumper/Cloner/Data.php index 74f8f945db..c695a11aef 100644 --- a/src/Symfony/Component/VarDumper/Cloner/Data.php +++ b/src/Symfony/Component/VarDumper/Cloner/Data.php @@ -331,7 +331,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate } $cursor->hardRefTo = $refs[$r]; $cursor->hardRefHandle = $this->useRefHandles & $item->handle; - $cursor->hardRefCount = $item->refCount; + $cursor->hardRefCount = 0 < $item->handle ? $item->refCount : 0; } $cursor->attr = $item->attr; $type = $item->class ?: \gettype($item->value); diff --git a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php index 08588fc339..c1e67bb2bf 100644 --- a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php @@ -143,13 +143,19 @@ class VarCloner extends AbstractCloner if (Stub::ARRAY_ASSOC === $stub->class) { // Copies of $GLOBALS have very strange behavior, // let's detect them with some black magic - $a[$gid] = true; - - // Happens with copies of $GLOBALS - if (isset($v[$gid])) { + if (\PHP_VERSION_ID < 80100 && ($a[$gid] = true) && isset($v[$gid])) { unset($v[$gid]); $a = []; foreach ($v as $gk => &$gv) { + if ($v === $gv) { + unset($v); + $v = new Stub(); + $v->value = [$v->cut = \count($gv), Stub::TYPE_ARRAY => 0]; + $v->handle = -1; + $gv = &$hardRefs[spl_object_id($v)]; + $gv = $v; + } + $a[$gk] = &$gv; } unset($gv); diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php index e5e29166ce..1d1f99ec42 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php @@ -411,6 +411,7 @@ EOTXT /** * @runInSeparateProcess * @preserveGlobalState disabled + * @requires PHP < 8.1 */ public function testSpecialVars56() { @@ -425,11 +426,11 @@ array:3 [ ] ] 1 => array:1 [ - "GLOBALS" => &2 array:1 [ - "GLOBALS" => &2 array:1 [&2] - ] + "GLOBALS" => & array:1 [ …1] + ] + 2 => &3 array:1 [ + "GLOBALS" => &3 array:1 [&3] ] - 2 => &2 array:1 [&2] ] EOTXT , @@ -440,6 +441,7 @@ EOTXT /** * @runInSeparateProcess * @preserveGlobalState disabled + * @requires PHP < 8.1 */ public function testGlobals() { @@ -462,11 +464,11 @@ EOTXT <<<'EOTXT' array:2 [ 1 => array:1 [ - "GLOBALS" => &1 array:1 [ - "GLOBALS" => &1 array:1 [&1] - ] + "GLOBALS" => & array:1 [ …1] + ] + 2 => &2 array:1 [ + "GLOBALS" => &2 array:1 [&2] ] - 2 => &1 array:1 [&1] ] EOTXT @@ -556,6 +558,6 @@ EOTXT return $var; }; - return [$var(), $GLOBALS, &$GLOBALS]; + return eval('return [$var(), $GLOBALS, &$GLOBALS];'); } }