/
githubmirror
/
symfony
Обзор
Документация
Войти
/
githubmirror
/
symfony
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
8.2
src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php
395 строк
17 KB
Christian Flothmann
replace PHPUnit annotations with attributes
04 авг 2025, 10:05
04 авг 2025, 10:05
982f89c
Код
Авторство
О чём код?
<?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpClient\Tests; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\Attributes\TestWith; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpClient\Exception\InvalidArgumentException; use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpClient\HttpClientTrait; use Symfony\Contracts\HttpClient\HttpClientInterface; class HttpClientTraitTest extends TestCase { use HttpClientTrait; private const RFC3986_BASE = 'http://a/b/c/d;p?q'; #[DataProvider('providePrepareRequestUrl')] public function testPrepareRequestUrl(string $expected, string $url, array $query = []) { $defaults = [ 'base_uri' => 'http://example.com?c=c', 'query' => ['a' => 1, 'b' => 'b'], ]; [, $defaults] = self::prepareRequest(null, null, $defaults); [$url] = self::prepareRequest(null, $url, ['query' => $query], $defaults); $this->assertSame($expected, implode('', $url)); } public static function providePrepareRequestUrl(): iterable { yield ['http://example.com/', 'http://example.com/']; yield ['http://example.com/?a=1&b=b', '.']; yield ['http://example.com/?a=2&b=b', '.?a=2']; yield ['http://example.com/?a=3&b=b', '.', ['a' => 3]]; yield ['http://example.com/?a=3&b=b', '.?a=0', ['a' => 3]]; yield ['http://example.com/', 'http://example.com/', ['a' => null]]; yield ['http://example.com/?b=', 'http://example.com/', ['b' => '']]; yield ['http://example.com/?b=', 'http://example.com/', ['a' => null, 'b' => '']]; } public function testPrepareRequestWithBodyIsArray() { $defaults = [ 'base_uri' => 'http://example.com?c=c', 'query' => ['a' => 1, 'b' => 'b'], 'body' => [], ]; [, $defaults] = self::prepareRequest(null, null, $defaults); [,$options] = self::prepareRequest(null, 'http://example.com', [ 'body' => [1, 2], 'headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8', ], ], $defaults); $this->assertContains('Content-Type: application/x-www-form-urlencoded; charset=utf-8', $options['headers']); } public function testNormalizeBodyMultipart() { $file = fopen('php://memory', 'r+'); stream_context_set_option($file, 'http', 'filename', 'test.txt'); stream_context_set_option($file, 'http', 'content_type', 'text/plain'); fwrite($file, 'foobarbaz'); rewind($file); $headers = [ 'content-type' => ['Content-Type: multipart/form-data; boundary=ABCDEF'], ]; $body = [ 'foo[]' => 'bar', 'bar' => [ $file, ], ]; $body = self::normalizeBody($body, $headers); $result = ''; while ('' !== $data = $body(self::$CHUNK_SIZE)) { $result .= $data; } $expected = <<<'EOF' --ABCDEF Content-Disposition: form-data; name="foo[]" bar --ABCDEF Content-Disposition: form-data; name="bar[0]"; filename="test.txt" Content-Type: text/plain foobarbaz --ABCDEF-- EOF; $expected = str_replace("\n", "\r\n", $expected); $this->assertSame($expected, $result); } #[RequiresPhpExtension('openssl')] #[DataProvider('provideNormalizeBodyMultipartForwardStream')] #[Group('network')] public function testNormalizeBodyMultipartForwardStream($stream) { $body = [ 'logo' => $stream(), ]; $headers = []; $body = self::normalizeBody($body, $headers); $result = ''; while ('' !== $data = $body(self::$CHUNK_SIZE)) { $result .= $data; } $this->assertSame(1, preg_match('/^Content-Type: multipart\/form-data; boundary=(?<boundary>.+)$/', $headers['content-type'][0], $matches)); $this->assertSame('Content-Length: 3086', $headers['content-length'][0]); $this->assertSame(3086, \strlen($result)); $expected = <<<EOF --{$matches['boundary']} Content-Disposition: form-data; name="logo"; filename="1f44d.png" Content-Type: image/png %A --{$matches['boundary']}-- EOF; $expected = str_replace("\n", "\r\n", $expected); $this->assertStringMatchesFormat($expected, $result); } public static function provideNormalizeBodyMultipartForwardStream() { yield 'native' => [static fn () => fopen('https://github.githubassets.com/images/icons/emoji/unicode/1f44d.png', 'r')]; yield 'symfony' => [static fn () => HttpClient::create()->request('GET', 'https://github.githubassets.com/images/icons/emoji/unicode/1f44d.png')->toStream()]; } #[DataProvider('provideResolveUrl')] public function testResolveUrl(string $base, string $url, string $expected) { $this->assertSame($expected, implode('', self::resolveUrl(self::parseUrl($url), self::parseUrl($base)))); } /** * From https://github.com/guzzle/psr7/blob/master/tests/UriResoverTest.php. */ public static function provideResolveUrl(): array { return [ [self::RFC3986_BASE, 'g', 'http://a/b/c/g'], [self::RFC3986_BASE, './g', 'http://a/b/c/g'], [self::RFC3986_BASE, 'g/', 'http://a/b/c/g/'], [self::RFC3986_BASE, '/g', 'http://a/g'], [self::RFC3986_BASE, '//g', 'http://g/'], [self::RFC3986_BASE, '?y', 'http://a/b/c/d;p?y'], [self::RFC3986_BASE, '?y={"f":1}', 'http://a/b/c/d;p?y={%22f%22:1}'], [self::RFC3986_BASE, 'g{oof}y', 'http://a/b/c/g{oof}y'], [self::RFC3986_BASE, 'g?y', 'http://a/b/c/g?y'], [self::RFC3986_BASE, '#s', 'http://a/b/c/d;p?q#s'], [self::RFC3986_BASE, 'g#s', 'http://a/b/c/g#s'], [self::RFC3986_BASE, 'g?y#s', 'http://a/b/c/g?y#s'], [self::RFC3986_BASE, ';x', 'http://a/b/c/;x'], [self::RFC3986_BASE, 'g;x', 'http://a/b/c/g;x'], [self::RFC3986_BASE, 'g;x?y#s', 'http://a/b/c/g;x?y#s'], [self::RFC3986_BASE, '', self::RFC3986_BASE], [self::RFC3986_BASE, '.', 'http://a/b/c/'], [self::RFC3986_BASE, './', 'http://a/b/c/'], [self::RFC3986_BASE, '..', 'http://a/b/'], [self::RFC3986_BASE, '../', 'http://a/b/'], [self::RFC3986_BASE, '../g', 'http://a/b/g'], [self::RFC3986_BASE, '../..', 'http://a/'], [self::RFC3986_BASE, '../../', 'http://a/'], [self::RFC3986_BASE, '../../g', 'http://a/g'], [self::RFC3986_BASE, '../../../g', 'http://a/g'], [self::RFC3986_BASE, '../../../../g', 'http://a/g'], [self::RFC3986_BASE, '/./g', 'http://a/g'], [self::RFC3986_BASE, '/../g', 'http://a/g'], [self::RFC3986_BASE, 'g.', 'http://a/b/c/g.'], [self::RFC3986_BASE, '.g', 'http://a/b/c/.g'], [self::RFC3986_BASE, 'g..', 'http://a/b/c/g..'], [self::RFC3986_BASE, '..g', 'http://a/b/c/..g'], [self::RFC3986_BASE, './../g', 'http://a/b/g'], [self::RFC3986_BASE, 'foo////g', 'http://a/b/c/foo////g'], [self::RFC3986_BASE, './g/.', 'http://a/b/c/g/'], [self::RFC3986_BASE, 'g/./h', 'http://a/b/c/g/h'], [self::RFC3986_BASE, 'g/../h', 'http://a/b/c/h'], [self::RFC3986_BASE, 'g;x=1/./y', 'http://a/b/c/g;x=1/y'], [self::RFC3986_BASE, 'g;x=1/../y', 'http://a/b/c/y'], [self::RFC3986_BASE, 'g/h:123/i', 'http://a/b/c/g/h:123/i'], // dot-segments in the query or fragment [self::RFC3986_BASE, 'g?y/./x', 'http://a/b/c/g?y/./x'], [self::RFC3986_BASE, 'g?y/../x', 'http://a/b/c/g?y/../x'], [self::RFC3986_BASE, 'g#s/./x', 'http://a/b/c/g#s/./x'], [self::RFC3986_BASE, 'g#s/../x', 'http://a/b/c/g#s/../x'], [self::RFC3986_BASE, 'g#s/../x', 'http://a/b/c/g#s/../x'], [self::RFC3986_BASE, '?y#s', 'http://a/b/c/d;p?y#s'], // base with fragment ['http://a/b/c?q#s', '?y', 'http://a/b/c?y'], // base with user info ['http://u@a/b/c/d;p?q', '.', 'http://u@a/b/c/'], ['http://u:p@a/b/c/d;p?q', '.', 'http://u:p@a/b/c/'], // path ending with slash or no slash at all ['http://a/b/c/d/', 'e', 'http://a/b/c/d/e'], // falsey relative parts [self::RFC3986_BASE, '//0', 'http://0/'], [self::RFC3986_BASE, '0', 'http://a/b/c/0'], [self::RFC3986_BASE, '?0', 'http://a/b/c/d;p?0'], [self::RFC3986_BASE, '#0', 'http://a/b/c/d;p?q#0'], ]; } public function testResolveUrlWithoutScheme() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Unsupported scheme in "localhost:8080": "http" or "https" expected.'); self::resolveUrl(self::parseUrl('localhost:8080'), null); } public function testResolveBaseUrlWithoutScheme() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Unsupported scheme in "localhost:8081": "http" or "https" expected.'); self::resolveUrl(self::parseUrl('/foo'), self::parseUrl('localhost:8081')); } #[TestWith(['http://foo.com\bar'])] #[TestWith(['\\\foo.com/bar'])] #[TestWith(['a b'])] #[TestWith(['a b'])] #[TestWith(['a b'])] #[TestWith(['