updated plugin W3 Total Cache version 2.3.3

This commit is contained in:
2023-06-28 12:45:56 +00:00
committed by Gitium
parent 7d5eef77cf
commit aa3da0eb92
129 changed files with 17998 additions and 186 deletions

View File

@ -0,0 +1,213 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\AppendStream;
class AppendStreamTest extends BaseTest
{
public function testValidatesStreamsAreReadable()
{
$a = new AppendStream();
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isReadable'])
->getMockForAbstractClass();
$s->expects(self::once())
->method('isReadable')
->will(self::returnValue(false));
$this->expectExceptionGuzzle('InvalidArgumentException', 'Each stream must be readable');
$a->addStream($s);
}
public function testValidatesSeekType()
{
$a = new AppendStream();
$this->expectExceptionGuzzle('RuntimeException', 'The AppendStream can only seek with SEEK_SET');
$a->seek(100, SEEK_CUR);
}
public function testTriesToRewindOnSeek()
{
$a = new AppendStream();
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isReadable', 'rewind', 'isSeekable'])
->getMockForAbstractClass();
$s->expects(self::once())
->method('isReadable')
->will(self::returnValue(true));
$s->expects(self::once())
->method('isSeekable')
->will(self::returnValue(true));
$s->expects(self::once())
->method('rewind')
->will(self::throwException(new \RuntimeException()));
$a->addStream($s);
$this->expectExceptionGuzzle('RuntimeException', 'Unable to seek stream 0 of the AppendStream');
$a->seek(10);
}
public function testSeeksToPositionByReading()
{
$a = new AppendStream([
Psr7\Utils::streamFor('foo'),
Psr7\Utils::streamFor('bar'),
Psr7\Utils::streamFor('baz'),
]);
$a->seek(3);
self::assertSame(3, $a->tell());
self::assertSame('bar', $a->read(3));
$a->seek(6);
self::assertSame(6, $a->tell());
self::assertSame('baz', $a->read(3));
}
public function testDetachWithoutStreams()
{
$s = new AppendStream();
$s->detach();
self::assertSame(0, $s->getSize());
self::assertTrue($s->eof());
self::assertTrue($s->isReadable());
self::assertSame('', (string) $s);
self::assertTrue($s->isSeekable());
self::assertFalse($s->isWritable());
}
public function testDetachesEachStream()
{
$handle = fopen('php://temp', 'r');
$s1 = Psr7\Utils::streamFor($handle);
$s2 = Psr7\Utils::streamFor('bar');
$a = new AppendStream([$s1, $s2]);
$a->detach();
self::assertSame(0, $a->getSize());
self::assertTrue($a->eof());
self::assertTrue($a->isReadable());
self::assertSame('', (string) $a);
self::assertTrue($a->isSeekable());
self::assertFalse($a->isWritable());
self::assertNull($s1->detach());
$this->assertInternalTypeGuzzle('resource', $handle, 'resource is not closed when detaching');
fclose($handle);
}
public function testClosesEachStream()
{
$handle = fopen('php://temp', 'r');
$s1 = Psr7\Utils::streamFor($handle);
$s2 = Psr7\Utils::streamFor('bar');
$a = new AppendStream([$s1, $s2]);
$a->close();
self::assertSame(0, $a->getSize());
self::assertTrue($a->eof());
self::assertTrue($a->isReadable());
self::assertSame('', (string) $a);
self::assertTrue($a->isSeekable());
self::assertFalse($a->isWritable());
self::assertFalse(is_resource($handle));
}
public function testIsNotWritable()
{
$a = new AppendStream([Psr7\Utils::streamFor('foo')]);
self::assertFalse($a->isWritable());
self::assertTrue($a->isSeekable());
self::assertTrue($a->isReadable());
$this->expectExceptionGuzzle('RuntimeException', 'Cannot write to an AppendStream');
$a->write('foo');
}
public function testDoesNotNeedStreams()
{
$a = new AppendStream();
self::assertSame('', (string) $a);
}
public function testCanReadFromMultipleStreams()
{
$a = new AppendStream([
Psr7\Utils::streamFor('foo'),
Psr7\Utils::streamFor('bar'),
Psr7\Utils::streamFor('baz'),
]);
self::assertFalse($a->eof());
self::assertSame(0, $a->tell());
self::assertSame('foo', $a->read(3));
self::assertSame('bar', $a->read(3));
self::assertSame('baz', $a->read(3));
self::assertSame('', $a->read(1));
self::assertTrue($a->eof());
self::assertSame(9, $a->tell());
self::assertSame('foobarbaz', (string) $a);
}
public function testCanDetermineSizeFromMultipleStreams()
{
$a = new AppendStream([
Psr7\Utils::streamFor('foo'),
Psr7\Utils::streamFor('bar')
]);
self::assertSame(6, $a->getSize());
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isSeekable', 'isReadable'])
->getMockForAbstractClass();
$s->expects(self::once())
->method('isSeekable')
->will(self::returnValue(null));
$s->expects(self::once())
->method('isReadable')
->will(self::returnValue(true));
$a->addStream($s);
self::assertNull($a->getSize());
}
public function testCatchesExceptionsWhenCastingToString()
{
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isSeekable', 'read', 'isReadable', 'eof'])
->getMockForAbstractClass();
$s->expects(self::once())
->method('isSeekable')
->will(self::returnValue(true));
$s->expects(self::once())
->method('read')
->will(self::throwException(new \RuntimeException('foo')));
$s->expects(self::once())
->method('isReadable')
->will(self::returnValue(true));
$s->expects(self::any())
->method('eof')
->will(self::returnValue(false));
$a = new AppendStream([$s]);
self::assertFalse($a->eof());
self::assertSame('', (string) $a);
}
public function testReturnsEmptyMetadata()
{
$s = new AppendStream();
self::assertSame([], $s->getMetadata());
self::assertNull($s->getMetadata('foo'));
}
}

View File

@ -0,0 +1,139 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use PHPUnit\Framework\TestCase;
abstract class BaseTest extends TestCase
{
/**
* @param string $exception
* @param string|null $message
*/
public function expectExceptionGuzzle($exception, $message = null)
{
if (method_exists($this, 'setExpectedException')) {
$this->setExpectedException($exception, $message);
} else {
$this->expectException($exception);
if (null !== $message) {
$this->expectExceptionMessage($message);
}
}
}
public function expectWarningGuzzle()
{
if (method_exists($this, 'expectWarning')) {
$this->expectWarning();
} elseif (class_exists('PHPUnit\Framework\Error\Warning')) {
$this->expectExceptionGuzzle('PHPUnit\Framework\Error\Warning');
} else {
$this->expectExceptionGuzzle('PHPUnit_Framework_Error_Warning');
}
}
/**
* @param string $type
* @param mixed $input
*/
public function assertInternalTypeGuzzle($type, $input)
{
switch ($type) {
case 'array':
if (method_exists($this, 'assertIsArray')) {
self::assertIsArray($input);
} else {
self::assertInternalType('array', $input);
}
break;
case 'bool':
case 'boolean':
if (method_exists($this, 'assertIsBool')) {
self::assertIsBool($input);
} else {
self::assertInternalType('bool', $input);
}
break;
case 'double':
case 'float':
case 'real':
if (method_exists($this, 'assertIsFloat')) {
self::assertIsFloat($input);
} else {
self::assertInternalType('float', $input);
}
break;
case 'int':
case 'integer':
if (method_exists($this, 'assertIsInt')) {
self::assertIsInt($input);
} else {
self::assertInternalType('int', $input);
}
break;
case 'numeric':
if (method_exists($this, 'assertIsNumeric')) {
self::assertIsNumeric($input);
} else {
self::assertInternalType('numeric', $input);
}
break;
case 'object':
if (method_exists($this, 'assertIsObject')) {
self::assertIsObject($input);
} else {
self::assertInternalType('object', $input);
}
break;
case 'resource':
if (method_exists($this, 'assertIsResource')) {
self::assertIsResource($input);
} else {
self::assertInternalType('resource', $input);
}
break;
case 'string':
if (method_exists($this, 'assertIsString')) {
self::assertIsString($input);
} else {
self::assertInternalType('string', $input);
}
break;
case 'scalar':
if (method_exists($this, 'assertIsScalar')) {
self::assertIsScalar($input);
} else {
self::assertInternalType('scalar', $input);
}
break;
case 'callable':
if (method_exists($this, 'assertIsCallable')) {
self::assertIsCallable($input);
} else {
self::assertInternalType('callable', $input);
}
break;
case 'iterable':
if (method_exists($this, 'assertIsIterable')) {
self::assertIsIterable($input);
} else {
self::assertInternalType('iterable', $input);
}
break;
}
}
/**
* @param string $needle
* @param string $haystack
*/
public function assertStringContainsStringGuzzle($needle, $haystack)
{
if (method_exists($this, 'assertStringContainsString')) {
self::assertStringContainsString($needle, $haystack);
} else {
self::assertContains($needle, $haystack);
}
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\BufferStream;
class BufferStreamTest extends BaseTest
{
public function testHasMetadata()
{
$b = new BufferStream(10);
self::assertTrue($b->isReadable());
self::assertTrue($b->isWritable());
self::assertFalse($b->isSeekable());
self::assertSame(null, $b->getMetadata('foo'));
self::assertSame(10, $b->getMetadata('hwm'));
self::assertSame([], $b->getMetadata());
}
public function testRemovesReadDataFromBuffer()
{
$b = new BufferStream();
self::assertSame(3, $b->write('foo'));
self::assertSame(3, $b->getSize());
self::assertFalse($b->eof());
self::assertSame('foo', $b->read(10));
self::assertTrue($b->eof());
self::assertSame('', $b->read(10));
}
public function testCanCastToStringOrGetContents()
{
$b = new BufferStream();
$b->write('foo');
$b->write('baz');
self::assertSame('foo', $b->read(3));
$b->write('bar');
self::assertSame('bazbar', (string) $b);
$this->expectExceptionGuzzle('RuntimeException', 'Cannot determine the position of a BufferStream');
$b->tell();
}
public function testDetachClearsBuffer()
{
$b = new BufferStream();
$b->write('foo');
$b->detach();
self::assertTrue($b->eof());
self::assertSame(3, $b->write('abc'));
self::assertSame('abc', $b->read(10));
}
public function testExceedingHighwaterMarkReturnsFalseButStillBuffers()
{
$b = new BufferStream(5);
self::assertSame(3, $b->write('hi '));
self::assertFalse($b->write('hello'));
self::assertSame('hi hello', (string) $b);
self::assertSame(4, $b->write('test'));
}
}

View File

@ -0,0 +1,212 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\CachingStream;
use GuzzleHttp\Psr7\Stream;
/**
* @covers GuzzleHttp\Psr7\CachingStream
*/
class CachingStreamTest extends BaseTest
{
/** @var CachingStream */
private $body;
/** @var Stream */
private $decorated;
/**
* @before
*/
public function setUpTest()
{
$this->decorated = Psr7\Utils::streamFor('testing');
$this->body = new CachingStream($this->decorated);
}
/**
* @after
*/
public function tearDownTest()
{
$this->decorated->close();
$this->body->close();
}
public function testUsesRemoteSizeIfAvailable()
{
$body = Psr7\Utils::streamFor('test');
$caching = new CachingStream($body);
self::assertSame(4, $caching->getSize());
}
public function testUsesRemoteSizeIfNotAvailable()
{
$body = new Psr7\PumpStream(function () {
return 'a';
});
$caching = new CachingStream($body);
self::assertNull($caching->getSize());
}
public function testReadsUntilCachedToByte()
{
$this->body->seek(5);
self::assertSame('n', $this->body->read(1));
$this->body->seek(0);
self::assertSame('t', $this->body->read(1));
}
public function testCanSeekNearEndWithSeekEnd()
{
$baseStream = Psr7\Utils::streamFor(implode('', range('a', 'z')));
$cached = new CachingStream($baseStream);
$cached->seek(-1, SEEK_END);
self::assertSame(25, $baseStream->tell());
self::assertSame('z', $cached->read(1));
self::assertSame(26, $cached->getSize());
}
public function testCanSeekToEndWithSeekEnd()
{
$baseStream = Psr7\Utils::streamFor(implode('', range('a', 'z')));
$cached = new CachingStream($baseStream);
$cached->seek(0, SEEK_END);
self::assertSame(26, $baseStream->tell());
self::assertSame('', $cached->read(1));
self::assertSame(26, $cached->getSize());
}
public function testCanUseSeekEndWithUnknownSize()
{
$baseStream = Psr7\Utils::streamFor('testing');
$decorated = Psr7\FnStream::decorate($baseStream, [
'getSize' => function () {
return null;
}
]);
$cached = new CachingStream($decorated);
$cached->seek(-1, SEEK_END);
self::assertSame('g', $cached->read(1));
}
public function testRewindUsesSeek()
{
$a = Psr7\Utils::streamFor('foo');
$d = $this->getMockBuilder('GuzzleHttp\Psr7\CachingStream')
->setMethods(['seek'])
->setConstructorArgs([$a])
->getMock();
$d->expects(self::once())
->method('seek')
->with(0)
->will(self::returnValue(true));
$d->seek(0);
}
public function testCanSeekToReadBytes()
{
self::assertSame('te', $this->body->read(2));
$this->body->seek(0);
self::assertSame('test', $this->body->read(4));
self::assertSame(4, $this->body->tell());
$this->body->seek(2);
self::assertSame(2, $this->body->tell());
$this->body->seek(2, SEEK_CUR);
self::assertSame(4, $this->body->tell());
self::assertSame('ing', $this->body->read(3));
}
public function testCanSeekToReadBytesWithPartialBodyReturned()
{
$stream = fopen('php://temp', 'r+');
fwrite($stream, 'testing');
fseek($stream, 0);
$this->decorated = $this->getMockBuilder('\GuzzleHttp\Psr7\Stream')
->setConstructorArgs([$stream])
->setMethods(['read'])
->getMock();
$this->decorated->expects(self::exactly(2))
->method('read')
->willReturnCallback(function ($length) use ($stream) {
return fread($stream, 2);
});
$this->body = new CachingStream($this->decorated);
self::assertSame(0, $this->body->tell());
$this->body->seek(4, SEEK_SET);
self::assertSame(4, $this->body->tell());
$this->body->seek(0);
self::assertSame('test', $this->body->read(4));
}
public function testWritesToBufferStream()
{
$this->body->read(2);
$this->body->write('hi');
$this->body->seek(0);
self::assertSame('tehiing', (string) $this->body);
}
public function testSkipsOverwrittenBytes()
{
$decorated = Psr7\Utils::streamFor(
implode("\n", array_map(function ($n) {
return str_pad($n, 4, '0', STR_PAD_LEFT);
}, range(0, 25)))
);
$body = new CachingStream($decorated);
self::assertSame("0000\n", Psr7\Utils::readLine($body));
self::assertSame("0001\n", Psr7\Utils::readLine($body));
// Write over part of the body yet to be read, so skip some bytes
self::assertSame(5, $body->write("TEST\n"));
self::assertSame(5, Helpers::readObjectAttribute($body, 'skipReadBytes'));
// Read, which skips bytes, then reads
self::assertSame("0003\n", Psr7\Utils::readLine($body));
self::assertSame(0, Helpers::readObjectAttribute($body, 'skipReadBytes'));
self::assertSame("0004\n", Psr7\Utils::readLine($body));
self::assertSame("0005\n", Psr7\Utils::readLine($body));
// Overwrite part of the cached body (so don't skip any bytes)
$body->seek(5);
self::assertSame(5, $body->write("ABCD\n"));
self::assertSame(0, Helpers::readObjectAttribute($body, 'skipReadBytes'));
self::assertSame("TEST\n", Psr7\Utils::readLine($body));
self::assertSame("0003\n", Psr7\Utils::readLine($body));
self::assertSame("0004\n", Psr7\Utils::readLine($body));
self::assertSame("0005\n", Psr7\Utils::readLine($body));
self::assertSame("0006\n", Psr7\Utils::readLine($body));
self::assertSame(5, $body->write("1234\n"));
self::assertSame(5, Helpers::readObjectAttribute($body, 'skipReadBytes'));
// Seek to 0 and ensure the overwritten bit is replaced
$body->seek(0);
self::assertSame("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", $body->read(50));
// Ensure that casting it to a string does not include the bit that was overwritten
$this->assertStringContainsStringGuzzle("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", (string) $body);
}
public function testClosesBothStreams()
{
$s = fopen('php://temp', 'r');
$a = Psr7\Utils::streamFor($s);
$d = new CachingStream($a);
$d->close();
self::assertFalse(is_resource($s));
}
public function testEnsuresValidWhence()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
$this->body->seek(10, -123456);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\BufferStream;
use GuzzleHttp\Psr7\DroppingStream;
class DroppingStreamTest extends BaseTest
{
public function testBeginsDroppingWhenSizeExceeded()
{
$stream = new BufferStream();
$drop = new DroppingStream($stream, 5);
self::assertSame(3, $drop->write('hel'));
self::assertSame(2, $drop->write('lo'));
self::assertSame(5, $drop->getSize());
self::assertSame('hello', $drop->read(5));
self::assertSame(0, $drop->getSize());
$drop->write('12345678910');
self::assertSame(5, $stream->getSize());
self::assertSame(5, $drop->getSize());
self::assertSame('12345', (string) $drop);
self::assertSame(0, $drop->getSize());
$drop->write('hello');
self::assertSame(0, $drop->write('test'));
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\FnStream;
/**
* @covers GuzzleHttp\Psr7\FnStream
*/
class FnStreamTest extends BaseTest
{
public function testThrowsWhenNotImplemented()
{
$this->expectExceptionGuzzle('BadMethodCallException', 'seek() is not implemented in the FnStream');
(new FnStream([]))->seek(1);
}
public function testProxiesToFunction()
{
$s = new FnStream([
'read' => function ($len) {
$this->assertSame(3, $len);
return 'foo';
}
]);
self::assertSame('foo', $s->read(3));
}
public function testCanCloseOnDestruct()
{
$called = false;
$s = new FnStream([
'close' => function () use (&$called) {
$called = true;
}
]);
unset($s);
self::assertTrue($called);
}
public function testDoesNotRequireClose()
{
$s = new FnStream([]);
unset($s);
self::assertTrue(true); // strict mode requires an assertion
}
public function testDecoratesStream()
{
$a = Psr7\Utils::streamFor('foo');
$b = FnStream::decorate($a, []);
self::assertSame(3, $b->getSize());
self::assertSame($b->isWritable(), true);
self::assertSame($b->isReadable(), true);
self::assertSame($b->isSeekable(), true);
self::assertSame($b->read(3), 'foo');
self::assertSame($b->tell(), 3);
self::assertSame($a->tell(), 3);
self::assertSame('', $a->read(1));
self::assertSame($b->eof(), true);
self::assertSame($a->eof(), true);
$b->seek(0);
self::assertSame('foo', (string) $b);
$b->seek(0);
self::assertSame('foo', $b->getContents());
self::assertSame($a->getMetadata(), $b->getMetadata());
$b->seek(0, SEEK_END);
$b->write('bar');
self::assertSame('foobar', (string) $b);
$this->assertInternalTypeGuzzle('resource', $b->detach());
$b->close();
}
public function testDecoratesWithCustomizations()
{
$called = false;
$a = Psr7\Utils::streamFor('foo');
$b = FnStream::decorate($a, [
'read' => function ($len) use (&$called, $a) {
$called = true;
return $a->read($len);
}
]);
self::assertSame('foo', $b->read(3));
self::assertTrue($called);
}
public function testDoNotAllowUnserialization()
{
$a = new FnStream([]);
$b = serialize($a);
$this->expectExceptionGuzzle('\LogicException', 'FnStream should never be unserialized');
unserialize($b);
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
class HasToString
{
public function __toString()
{
return 'foo';
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
class HeaderTest extends BaseTest
{
public function parseParamsProvider()
{
$res1 = [
[
'<http:/.../front.jpeg>',
'rel' => 'front',
'type' => 'image/jpeg',
],
[
'<http://.../back.jpeg>',
'rel' => 'back',
'type' => 'image/jpeg',
],
];
return [
[
'<http:/.../front.jpeg>; rel="front"; type="image/jpeg", <http://.../back.jpeg>; rel=back; type="image/jpeg"',
$res1,
],
[
'<http:/.../front.jpeg>; rel="front"; type="image/jpeg",<http://.../back.jpeg>; rel=back; type="image/jpeg"',
$res1,
],
[
'foo="baz"; bar=123, boo, test="123", foobar="foo;bar"',
[
['foo' => 'baz', 'bar' => '123'],
['boo'],
['test' => '123'],
['foobar' => 'foo;bar'],
],
],
[
'<http://.../side.jpeg?test=1>; rel="side"; type="image/jpeg",<http://.../side.jpeg?test=2>; rel=side; type="image/jpeg"',
[
['<http://.../side.jpeg?test=1>', 'rel' => 'side', 'type' => 'image/jpeg'],
['<http://.../side.jpeg?test=2>', 'rel' => 'side', 'type' => 'image/jpeg'],
],
],
[
'',
[],
],
];
}
/**
* @dataProvider parseParamsProvider
*/
public function testParseParams($header, $result)
{
self::assertSame($result, Psr7\Header::parse($header));
}
public function testParsesArrayHeaders()
{
$header = ['a, b', 'c', 'd, e'];
self::assertSame(['a', 'b', 'c', 'd', 'e'], Psr7\Header::normalize($header));
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
class Helpers
{
/**
* @param object $object
* @param string $attributeName
*/
public static function readObjectAttribute($object, $attributeName)
{
$reflector = new \ReflectionObject($object);
do {
try {
$attribute = $reflector->getProperty($attributeName);
if (!$attribute || $attribute->isPublic()) {
return $object->$attributeName;
}
$attribute->setAccessible(true);
return $attribute->getValue($object);
} catch (\ReflectionException $e) {
// do nothing
}
} while ($reflector = $reflector->getParentClass());
throw new \Exception(
sprintf('Attribute "%s" not found in object.', $attributeName)
);
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\InflateStream;
use GuzzleHttp\Psr7\NoSeekStream;
class InflateStreamTest extends BaseTest
{
public function testInflatesStreams()
{
$content = gzencode('test');
$a = Psr7\Utils::streamFor($content);
$b = new InflateStream($a);
self::assertSame('test', (string) $b);
}
public function testInflatesStreamsWithFilename()
{
$content = $this->getGzipStringWithFilename('test');
$a = Psr7\Utils::streamFor($content);
$b = new InflateStream($a);
self::assertSame('test', (string) $b);
}
public function testInflatesStreamsPreserveSeekable()
{
$content = $this->getGzipStringWithFilename('test');
$seekable = Psr7\Utils::streamFor($content);
$nonSeekable = new NoSeekStream(Psr7\Utils::streamFor($content));
self::assertTrue((new InflateStream($seekable))->isSeekable());
self::assertFalse((new InflateStream($nonSeekable))->isSeekable());
}
private function getGzipStringWithFilename($original_string)
{
$gzipped = bin2hex(gzencode($original_string));
$header = substr($gzipped, 0, 20);
// set FNAME flag
$header[6]=0;
$header[7]=8;
// make a dummy filename
$filename = '64756d6d7900';
$rest = substr($gzipped, 20);
return hex2bin($header . $filename . $rest);
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace GuzzleHttp\Tests\Psr7\Integration;
use GuzzleHttp\Tests\Psr7\BaseTest;
class ServerRequestFromGlobalsTest extends BaseTest
{
/**
* @before
*/
protected function setUpTest()
{
if (false === $this->getServerUri()) {
self::markTestSkipped();
}
parent::setUp();
}
public function testBodyExists()
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $this->getServerUri());
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, 'foobar');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($curl);
curl_close($curl);
self::assertNotFalse($response);
$data = json_decode($response, true);
self::assertIsArray($data);
self::assertArrayHasKey('method', $data);
self::assertArrayHasKey('uri', $data);
self::assertArrayHasKey('body', $data);
self::assertEquals('foobar', $data['body']);
}
private function getServerUri()
{
return isset($_SERVER['TEST_SERVER']) ? $_SERVER['TEST_SERVER'] : false;
}
}

View File

@ -0,0 +1,13 @@
<?php
require dirname(__DIR__, 2) . '/vendor/autoload.php';
$request = \GuzzleHttp\Psr7\ServerRequest::fromGlobals();
$output = [
'method' => $request->getMethod(),
'uri' => $request->getUri()->__toString(),
'body' => $request->getBody()->__toString(),
];
echo json_encode($output);

View File

@ -0,0 +1,71 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\LazyOpenStream;
class LazyOpenStreamTest extends BaseTest
{
private $fname;
/**
* @before
*/
public function setUpTest()
{
$this->fname = tempnam(sys_get_temp_dir(), 'tfile');
if (file_exists($this->fname)) {
unlink($this->fname);
}
}
/**
* @after
*/
public function tearDownTest()
{
if (file_exists($this->fname)) {
unlink($this->fname);
}
}
public function testOpensLazily()
{
$l = new LazyOpenStream($this->fname, 'w+');
$l->write('foo');
$this->assertInternalTypeGuzzle('array', $l->getMetadata());
self::assertFileExists($this->fname);
self::assertSame('foo', file_get_contents($this->fname));
self::assertSame('foo', (string) $l);
}
public function testProxiesToFile()
{
file_put_contents($this->fname, 'foo');
$l = new LazyOpenStream($this->fname, 'r');
self::assertSame('foo', $l->read(4));
self::assertTrue($l->eof());
self::assertSame(3, $l->tell());
self::assertTrue($l->isReadable());
self::assertTrue($l->isSeekable());
self::assertFalse($l->isWritable());
$l->seek(1);
self::assertSame('oo', $l->getContents());
self::assertSame('foo', (string) $l);
self::assertSame(3, $l->getSize());
$this->assertInternalTypeGuzzle('array', $l->getMetadata());
$l->close();
}
public function testDetachesUnderlyingStream()
{
file_put_contents($this->fname, 'foo');
$l = new LazyOpenStream($this->fname, 'r');
$r = $l->detach();
$this->assertInternalTypeGuzzle('resource', $r);
fseek($r, 0);
self::assertSame('foo', stream_get_contents($r));
fclose($r);
}
}

View File

@ -0,0 +1,166 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\FnStream;
use GuzzleHttp\Psr7\LimitStream;
use GuzzleHttp\Psr7\NoSeekStream;
use GuzzleHttp\Psr7\Stream;
/**
* @covers GuzzleHttp\Psr7\LimitStream
*/
class LimitStreamTest extends BaseTest
{
/** @var LimitStream */
private $body;
/** @var Stream */
private $decorated;
/**
* @before
*/
public function setUpTest()
{
$this->decorated = Psr7\Utils::streamFor(fopen(__FILE__, 'r'));
$this->body = new LimitStream($this->decorated, 10, 3);
}
public function testReturnsSubset()
{
$body = new LimitStream(Psr7\Utils::streamFor('foo'), -1, 1);
self::assertSame('oo', (string) $body);
self::assertTrue($body->eof());
$body->seek(0);
self::assertFalse($body->eof());
self::assertSame('oo', $body->read(100));
self::assertSame('', $body->read(1));
self::assertTrue($body->eof());
}
public function testReturnsSubsetWhenCastToString()
{
$body = Psr7\Utils::streamFor('foo_baz_bar');
$limited = new LimitStream($body, 3, 4);
self::assertSame('baz', (string) $limited);
}
public function testReturnsSubsetOfEmptyBodyWhenCastToString()
{
$body = Psr7\Utils::streamFor('01234567891234');
$limited = new LimitStream($body, 0, 10);
self::assertSame('', (string) $limited);
}
public function testReturnsSpecificSubsetOBodyWhenCastToString()
{
$body = Psr7\Utils::streamFor('0123456789abcdef');
$limited = new LimitStream($body, 3, 10);
self::assertSame('abc', (string) $limited);
}
public function testSeeksWhenConstructed()
{
self::assertSame(0, $this->body->tell());
self::assertSame(3, $this->decorated->tell());
}
public function testAllowsBoundedSeek()
{
$this->body->seek(100);
self::assertSame(10, $this->body->tell());
self::assertSame(13, $this->decorated->tell());
$this->body->seek(0);
self::assertSame(0, $this->body->tell());
self::assertSame(3, $this->decorated->tell());
try {
$this->body->seek(-10);
self::fail();
} catch (\RuntimeException $e) {
}
self::assertSame(0, $this->body->tell());
self::assertSame(3, $this->decorated->tell());
$this->body->seek(5);
self::assertSame(5, $this->body->tell());
self::assertSame(8, $this->decorated->tell());
// Fail
try {
$this->body->seek(1000, SEEK_END);
self::fail();
} catch (\RuntimeException $e) {
}
}
public function testReadsOnlySubsetOfData()
{
$data = $this->body->read(100);
self::assertSame(10, strlen($data));
self::assertSame('', $this->body->read(1000));
$this->body->setOffset(10);
$newData = $this->body->read(100);
self::assertSame(10, strlen($newData));
self::assertNotSame($data, $newData);
}
public function testThrowsWhenCurrentGreaterThanOffsetSeek()
{
$a = Psr7\Utils::streamFor('foo_bar');
$b = new NoSeekStream($a);
$c = new LimitStream($b);
$a->getContents();
$this->expectExceptionGuzzle('RuntimeException', 'Could not seek to stream offset 2');
$c->setOffset(2);
}
public function testCanGetContentsWithoutSeeking()
{
$a = Psr7\Utils::streamFor('foo_bar');
$b = new NoSeekStream($a);
$c = new LimitStream($b);
self::assertSame('foo_bar', $c->getContents());
}
public function testClaimsConsumedWhenReadLimitIsReached()
{
self::assertFalse($this->body->eof());
$this->body->read(1000);
self::assertTrue($this->body->eof());
}
public function testContentLengthIsBounded()
{
self::assertSame(10, $this->body->getSize());
}
public function testGetContentsIsBasedOnSubset()
{
$body = new LimitStream(Psr7\Utils::streamFor('foobazbar'), 3, 3);
self::assertSame('baz', $body->getContents());
}
public function testReturnsNullIfSizeCannotBeDetermined()
{
$a = new FnStream([
'getSize' => function () {
return null;
},
'tell' => function () {
return 0;
},
]);
$b = new LimitStream($a);
self::assertNull($b->getSize());
}
public function testLengthLessOffsetWhenNoLimitSize()
{
$a = Psr7\Utils::streamFor('foo_bar');
$b = new LimitStream($a, -1, 4);
self::assertSame(3, $b->getSize());
}
}

View File

@ -0,0 +1,266 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\FnStream;
class MessageTest extends BaseTest
{
public function testConvertsRequestsToStrings()
{
$request = new Psr7\Request('PUT', 'http://foo.com/hi?123', [
'Baz' => 'bar',
'Qux' => 'ipsum',
], 'hello', '1.0');
self::assertSame(
"PUT /hi?123 HTTP/1.0\r\nHost: foo.com\r\nBaz: bar\r\nQux: ipsum\r\n\r\nhello",
Psr7\Message::toString($request)
);
}
public function testConvertsResponsesToStrings()
{
$response = new Psr7\Response(200, [
'Baz' => 'bar',
'Qux' => 'ipsum',
], 'hello', '1.0', 'FOO');
self::assertSame(
"HTTP/1.0 200 FOO\r\nBaz: bar\r\nQux: ipsum\r\n\r\nhello",
Psr7\Message::toString($response)
);
}
public function testCorrectlyRendersSetCookieHeadersToString()
{
$response = new Psr7\Response(200, [
'Set-Cookie' => ['bar','baz','qux']
], 'hello', '1.0', 'FOO');
self::assertSame(
"HTTP/1.0 200 FOO\r\nSet-Cookie: bar\r\nSet-Cookie: baz\r\nSet-Cookie: qux\r\n\r\nhello",
Psr7\Message::toString($response)
);
}
public function testRewindsBody()
{
$body = Psr7\Utils::streamFor('abc');
$res = new Psr7\Response(200, [], $body);
Psr7\Message::rewindBody($res);
self::assertSame(0, $body->tell());
$body->rewind();
Psr7\Message::rewindBody($res);
self::assertSame(0, $body->tell());
}
public function testThrowsWhenBodyCannotBeRewound()
{
$body = Psr7\Utils::streamFor('abc');
$body->read(1);
$body = FnStream::decorate($body, [
'rewind' => function () {
throw new \RuntimeException('a');
},
]);
$res = new Psr7\Response(200, [], $body);
$this->expectExceptionGuzzle('RuntimeException');
Psr7\Message::rewindBody($res);
}
public function testParsesRequestMessages()
{
$req = "GET /abc HTTP/1.0\r\nHost: foo.com\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n\r\nTest";
$request = Psr7\Message::parseRequest($req);
self::assertSame('GET', $request->getMethod());
self::assertSame('/abc', $request->getRequestTarget());
self::assertSame('1.0', $request->getProtocolVersion());
self::assertSame('foo.com', $request->getHeaderLine('Host'));
self::assertSame('Bar', $request->getHeaderLine('Foo'));
self::assertSame('Bam, Qux', $request->getHeaderLine('Baz'));
self::assertSame('Test', (string)$request->getBody());
self::assertSame('http://foo.com/abc', (string)$request->getUri());
}
public function testParsesRequestMessagesWithHttpsScheme()
{
$req = "PUT /abc?baz=bar HTTP/1.1\r\nHost: foo.com:443\r\n\r\n";
$request = Psr7\Message::parseRequest($req);
self::assertSame('PUT', $request->getMethod());
self::assertSame('/abc?baz=bar', $request->getRequestTarget());
self::assertSame('1.1', $request->getProtocolVersion());
self::assertSame('foo.com:443', $request->getHeaderLine('Host'));
self::assertSame('', (string)$request->getBody());
self::assertSame('https://foo.com/abc?baz=bar', (string)$request->getUri());
}
public function testParsesRequestMessagesWithUriWhenHostIsNotFirst()
{
$req = "PUT / HTTP/1.1\r\nFoo: Bar\r\nHost: foo.com\r\n\r\n";
$request = Psr7\Message::parseRequest($req);
self::assertSame('PUT', $request->getMethod());
self::assertSame('/', $request->getRequestTarget());
self::assertSame('http://foo.com/', (string)$request->getUri());
}
public function testParsesRequestMessagesWithFullUri()
{
$req = "GET https://www.google.com:443/search?q=foobar HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
$request = Psr7\Message::parseRequest($req);
self::assertSame('GET', $request->getMethod());
self::assertSame('https://www.google.com:443/search?q=foobar', $request->getRequestTarget());
self::assertSame('1.1', $request->getProtocolVersion());
self::assertSame('www.google.com', $request->getHeaderLine('Host'));
self::assertSame('', (string)$request->getBody());
self::assertSame('https://www.google.com/search?q=foobar', (string)$request->getUri());
}
public function testParsesRequestMessagesWithCustomMethod()
{
$req = "GET_DATA / HTTP/1.1\r\nFoo: Bar\r\nHost: foo.com\r\n\r\n";
$request = Psr7\Message::parseRequest($req);
self::assertSame('GET_DATA', $request->getMethod());
}
public function testParsesRequestMessagesWithFoldedHeadersOnHttp10()
{
$req = "PUT / HTTP/1.0\r\nFoo: Bar\r\n Bam\r\n\r\n";
$request = Psr7\Message::parseRequest($req);
self::assertSame('PUT', $request->getMethod());
self::assertSame('/', $request->getRequestTarget());
self::assertSame('Bar Bam', $request->getHeaderLine('Foo'));
}
public function testRequestParsingFailsWithFoldedHeadersOnHttp11()
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'Invalid header syntax: Obsolete line folding');
Psr7\Message::parseResponse("GET_DATA / HTTP/1.1\r\nFoo: Bar\r\n Biz: Bam\r\n\r\n");
}
public function testParsesRequestMessagesWhenHeaderDelimiterIsOnlyALineFeed()
{
$req = "PUT / HTTP/1.0\nFoo: Bar\nBaz: Bam\n\n";
$request = Psr7\Message::parseRequest($req);
self::assertSame('PUT', $request->getMethod());
self::assertSame('/', $request->getRequestTarget());
self::assertSame('Bar', $request->getHeaderLine('Foo'));
self::assertSame('Bam', $request->getHeaderLine('Baz'));
}
public function testValidatesRequestMessages()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
Psr7\Message::parseRequest("HTTP/1.1 200 OK\r\n\r\n");
}
public function testParsesResponseMessages()
{
$res = "HTTP/1.0 200 OK\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n\r\nTest";
$response = Psr7\Message::parseResponse($res);
self::assertSame(200, $response->getStatusCode());
self::assertSame('OK', $response->getReasonPhrase());
self::assertSame('1.0', $response->getProtocolVersion());
self::assertSame('Bar', $response->getHeaderLine('Foo'));
self::assertSame('Bam, Qux', $response->getHeaderLine('Baz'));
self::assertSame('Test', (string)$response->getBody());
}
public function testParsesResponseWithoutReason()
{
$res = "HTTP/1.0 200\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n\r\nTest";
$response = Psr7\Message::parseResponse($res);
self::assertSame(200, $response->getStatusCode());
self::assertSame('OK', $response->getReasonPhrase());
self::assertSame('1.0', $response->getProtocolVersion());
self::assertSame('Bar', $response->getHeaderLine('Foo'));
self::assertSame('Bam, Qux', $response->getHeaderLine('Baz'));
self::assertSame('Test', (string)$response->getBody());
}
public function testParsesResponseWithLeadingDelimiter()
{
$res = "\r\nHTTP/1.0 200\r\nFoo: Bar\r\n\r\nTest";
$response = Psr7\Message::parseResponse($res);
self::assertSame(200, $response->getStatusCode());
self::assertSame('OK', $response->getReasonPhrase());
self::assertSame('1.0', $response->getProtocolVersion());
self::assertSame('Bar', $response->getHeaderLine('Foo'));
self::assertSame('Test', (string)$response->getBody());
}
public function testParsesResponseWithFoldedHeadersOnHttp10()
{
$res = "HTTP/1.0 200\r\nFoo: Bar\r\n Bam\r\n\r\nTest";
$response = Psr7\Message::parseResponse($res);
self::assertSame(200, $response->getStatusCode());
self::assertSame('OK', $response->getReasonPhrase());
self::assertSame('1.0', $response->getProtocolVersion());
self::assertSame('Bar Bam', $response->getHeaderLine('Foo'));
self::assertSame('Test', (string)$response->getBody());
}
public function testResponseParsingFailsWithFoldedHeadersOnHttp11()
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'Invalid header syntax: Obsolete line folding');
Psr7\Message::parseResponse("HTTP/1.1 200\r\nFoo: Bar\r\n Biz: Bam\r\nBaz: Qux\r\n\r\nTest");
}
public function testParsesResponseWhenHeaderDelimiterIsOnlyALineFeed()
{
$res = "HTTP/1.0 200\nFoo: Bar\nBaz: Bam\n\nTest\n\nOtherTest";
$response = Psr7\Message::parseResponse($res);
self::assertSame(200, $response->getStatusCode());
self::assertSame('OK', $response->getReasonPhrase());
self::assertSame('1.0', $response->getProtocolVersion());
self::assertSame('Bar', $response->getHeaderLine('Foo'));
self::assertSame('Bam', $response->getHeaderLine('Baz'));
self::assertSame("Test\n\nOtherTest", (string)$response->getBody());
}
public function testResponseParsingFailsWithoutHeaderDelimiter()
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'Invalid message: Missing header delimiter');
Psr7\Message::parseResponse("HTTP/1.0 200\r\nFoo: Bar\r\n Baz: Bam\r\nBaz: Qux\r\n");
}
public function testValidatesResponseMessages()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
Psr7\Message::parseResponse("GET / HTTP/1.1\r\n\r\n");
}
public function testMessageBodySummaryWithSmallBody()
{
$message = new Psr7\Response(200, [], 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
self::assertSame('Lorem ipsum dolor sit amet, consectetur adipiscing elit.', Psr7\Message::bodySummary($message));
}
public function testMessageBodySummaryWithLargeBody()
{
$message = new Psr7\Response(200, [], 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
self::assertSame('Lorem ipsu (truncated...)', Psr7\Message::bodySummary($message, 10));
}
public function testMessageBodySummaryWithSpecialUTF8Characters()
{
$message = new Psr7\Response(200, [], '’é€௵ဪ‱');
self::assertSame('’é€௵ဪ‱', Psr7\Message::bodySummary($message));
}
public function testMessageBodySummaryWithEmptyBody()
{
$message = new Psr7\Response(200, [], '');
self::assertNull(Psr7\Message::bodySummary($message));
}
public function testGetResponseBodySummaryOfNonReadableStream()
{
self::assertNull(Psr7\Message::bodySummary(new Psr7\Response(500, [], new ReadSeekOnlyStream())));
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
class MimeTypeTest extends BaseTest
{
public function testDetermineFromExtension()
{
self::assertNull(Psr7\MimeType::fromExtension('not-a-real-extension'));
self::assertSame('application/json', Psr7\MimeType::fromExtension('json'));
}
public function testDetermineFromFilename()
{
self::assertSame(
'image/jpeg',
Psr7\MimeType::fromFilename('/tmp/images/IMG034821.JPEG')
);
}
}

View File

@ -0,0 +1,245 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\MultipartStream;
class MultipartStreamTest extends BaseTest
{
public function testCreatesDefaultBoundary()
{
$b = new MultipartStream();
self::assertNotEmpty($b->getBoundary());
}
public function testCanProvideBoundary()
{
$b = new MultipartStream([], 'foo');
self::assertSame('foo', $b->getBoundary());
}
public function testIsNotWritable()
{
$b = new MultipartStream();
self::assertFalse($b->isWritable());
}
public function testCanCreateEmptyStream()
{
$b = new MultipartStream();
$boundary = $b->getBoundary();
self::assertSame("--{$boundary}--\r\n", $b->getContents());
self::assertSame(strlen($boundary) + 6, $b->getSize());
}
public function testValidatesFilesArrayElement()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
new MultipartStream([['foo' => 'bar']]);
}
public function testEnsuresFileHasName()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
new MultipartStream([['contents' => 'bar']]);
}
public function testSerializesFields()
{
$b = new MultipartStream([
[
'name' => 'foo',
'contents' => 'bar'
],
[
'name' => 'baz',
'contents' => 'bam'
]
], 'boundary');
self::assertSame(
"--boundary\r\nContent-Disposition: form-data; name=\"foo\"\r\nContent-Length: 3\r\n\r\n"
. "bar\r\n--boundary\r\nContent-Disposition: form-data; name=\"baz\"\r\nContent-Length: 3"
. "\r\n\r\nbam\r\n--boundary--\r\n",
(string) $b
);
}
public function testSerializesNonStringFields()
{
$b = new MultipartStream([
[
'name' => 'int',
'contents' => (int) 1
],
[
'name' => 'bool',
'contents' => (boolean) false
],
[
'name' => 'bool2',
'contents' => (boolean) true
],
[
'name' => 'float',
'contents' => (float) 1.1
]
], 'boundary');
self::assertSame(
"--boundary\r\nContent-Disposition: form-data; name=\"int\"\r\nContent-Length: 1\r\n\r\n"
. "1\r\n--boundary\r\nContent-Disposition: form-data; name=\"bool\"\r\n\r\n\r\n--boundary"
. "\r\nContent-Disposition: form-data; name=\"bool2\"\r\nContent-Length: 1\r\n\r\n"
. "1\r\n--boundary\r\nContent-Disposition: form-data; name=\"float\"\r\nContent-Length: 3"
. "\r\n\r\n1.1\r\n--boundary--\r\n",
(string) $b
);
}
public function testSerializesFiles()
{
$f1 = Psr7\FnStream::decorate(Psr7\Utils::streamFor('foo'), [
'getMetadata' => function () {
return '/foo/bar.txt';
}
]);
$f2 = Psr7\FnStream::decorate(Psr7\Utils::streamFor('baz'), [
'getMetadata' => function () {
return '/foo/baz.jpg';
}
]);
$f3 = Psr7\FnStream::decorate(Psr7\Utils::streamFor('bar'), [
'getMetadata' => function () {
return '/foo/bar.gif';
}
]);
$b = new MultipartStream([
[
'name' => 'foo',
'contents' => $f1
],
[
'name' => 'qux',
'contents' => $f2
],
[
'name' => 'qux',
'contents' => $f3
],
], 'boundary');
$expected = <<<EOT
--boundary
Content-Disposition: form-data; name="foo"; filename="bar.txt"
Content-Length: 3
Content-Type: text/plain
foo
--boundary
Content-Disposition: form-data; name="qux"; filename="baz.jpg"
Content-Length: 3
Content-Type: image/jpeg
baz
--boundary
Content-Disposition: form-data; name="qux"; filename="bar.gif"
Content-Length: 3
Content-Type: image/gif
bar
--boundary--
EOT;
self::assertSame($expected, str_replace("\r", '', $b));
}
public function testSerializesFilesWithCustomHeaders()
{
$f1 = Psr7\FnStream::decorate(Psr7\Utils::streamFor('foo'), [
'getMetadata' => function () {
return '/foo/bar.txt';
}
]);
$b = new MultipartStream([
[
'name' => 'foo',
'contents' => $f1,
'headers' => [
'x-foo' => 'bar',
'content-disposition' => 'custom'
]
]
], 'boundary');
$expected = <<<EOT
--boundary
x-foo: bar
content-disposition: custom
Content-Length: 3
Content-Type: text/plain
foo
--boundary--
EOT;
self::assertSame($expected, str_replace("\r", '', $b));
}
public function testSerializesFilesWithCustomHeadersAndMultipleValues()
{
$f1 = Psr7\FnStream::decorate(Psr7\Utils::streamFor('foo'), [
'getMetadata' => function () {
return '/foo/bar.txt';
}
]);
$f2 = Psr7\FnStream::decorate(Psr7\Utils::streamFor('baz'), [
'getMetadata' => function () {
return '/foo/baz.jpg';
}
]);
$b = new MultipartStream([
[
'name' => 'foo',
'contents' => $f1,
'headers' => [
'x-foo' => 'bar',
'content-disposition' => 'custom'
]
],
[
'name' => 'foo',
'contents' => $f2,
'headers' => ['cOntenT-Type' => 'custom'],
]
], 'boundary');
$expected = <<<EOT
--boundary
x-foo: bar
content-disposition: custom
Content-Length: 3
Content-Type: text/plain
foo
--boundary
cOntenT-Type: custom
Content-Disposition: form-data; name="foo"; filename="baz.jpg"
Content-Length: 3
baz
--boundary--
EOT;
self::assertSame($expected, str_replace("\r", '', $b));
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\NoSeekStream;
/**
* @covers GuzzleHttp\Psr7\NoSeekStream
* @covers GuzzleHttp\Psr7\StreamDecoratorTrait
*/
class NoSeekStreamTest extends BaseTest
{
public function testCannotSeek()
{
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isSeekable', 'seek'])
->getMockForAbstractClass();
$s->expects(self::never())->method('seek');
$s->expects(self::never())->method('isSeekable');
$wrapped = new NoSeekStream($s);
self::assertFalse($wrapped->isSeekable());
$this->expectExceptionGuzzle('RuntimeException', 'Cannot seek a NoSeekStream');
$wrapped->seek(2);
}
public function testToStringDoesNotSeek()
{
$s = \GuzzleHttp\Psr7\Utils::streamFor('foo');
$s->seek(1);
$wrapped = new NoSeekStream($s);
self::assertSame('oo', (string) $wrapped);
$wrapped->close();
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\LimitStream;
use GuzzleHttp\Psr7\PumpStream;
class PumpStreamTest extends BaseTest
{
public function testHasMetadataAndSize()
{
$p = new PumpStream(function () {
}, [
'metadata' => ['foo' => 'bar'],
'size' => 100
]);
self::assertSame('bar', $p->getMetadata('foo'));
self::assertSame(['foo' => 'bar'], $p->getMetadata());
self::assertSame(100, $p->getSize());
}
public function testCanReadFromCallable()
{
$p = Psr7\Utils::streamFor(function ($size) {
return 'a';
});
self::assertSame('a', $p->read(1));
self::assertSame(1, $p->tell());
self::assertSame('aaaaa', $p->read(5));
self::assertSame(6, $p->tell());
}
public function testStoresExcessDataInBuffer()
{
$called = [];
$p = Psr7\Utils::streamFor(function ($size) use (&$called) {
$called[] = $size;
return 'abcdef';
});
self::assertSame('a', $p->read(1));
self::assertSame('b', $p->read(1));
self::assertSame('cdef', $p->read(4));
self::assertSame('abcdefabc', $p->read(9));
self::assertSame([1, 9, 3], $called);
}
public function testInifiniteStreamWrappedInLimitStream()
{
$p = Psr7\Utils::streamFor(function () {
return 'a';
});
$s = new LimitStream($p, 5);
self::assertSame('aaaaa', (string) $s);
}
public function testDescribesCapabilities()
{
$p = Psr7\Utils::streamFor(function () {
});
self::assertTrue($p->isReadable());
self::assertFalse($p->isSeekable());
self::assertFalse($p->isWritable());
self::assertNull($p->getSize());
self::assertSame('', $p->getContents());
self::assertSame('', (string) $p);
$p->close();
self::assertSame('', $p->read(10));
self::assertTrue($p->eof());
try {
self::assertFalse($p->write('aa'));
self::fail();
} catch (\RuntimeException $e) {
}
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
class QueryTest extends BaseTest
{
public function parseQueryProvider()
{
return [
// Does not need to parse when the string is empty
['', []],
// Can parse mult-values items
['q=a&q=b', ['q' => ['a', 'b']]],
// Can parse multi-valued items that use numeric indices
['q[0]=a&q[1]=b', ['q[0]' => 'a', 'q[1]' => 'b']],
// Can parse duplicates and does not include numeric indices
['q[]=a&q[]=b', ['q[]' => ['a', 'b']]],
// Ensures that the value of "q" is an array even though one value
['q[]=a', ['q[]' => 'a']],
// Does not modify "." to "_" like PHP's parse_str()
['q.a=a&q.b=b', ['q.a' => 'a', 'q.b' => 'b']],
// Can decode %20 to " "
['q%20a=a%20b', ['q a' => 'a b']],
// Can parse funky strings with no values by assigning each to null
['q&a', ['q' => null, 'a' => null]],
// Does not strip trailing equal signs
['data=abc=', ['data' => 'abc=']],
// Can store duplicates without affecting other values
['foo=a&foo=b&?µ=c', ['foo' => ['a', 'b'], '?µ' => 'c']],
// Sets value to null when no "=" is present
['foo', ['foo' => null]],
// Preserves "0" keys.
['0', ['0' => null]],
// Sets the value to an empty string when "=" is present
['0=', ['0' => '']],
// Preserves falsey keys
['var=0', ['var' => '0']],
['a[b][c]=1&a[b][c]=2', ['a[b][c]' => ['1', '2']]],
['a[b]=c&a[d]=e', ['a[b]' => 'c', 'a[d]' => 'e']],
// Ensure it doesn't leave things behind with repeated values
// Can parse mult-values items
['q=a&q=b&q=c', ['q' => ['a', 'b', 'c']]],
];
}
/**
* @dataProvider parseQueryProvider
*/
public function testParsesQueries($input, $output)
{
$result = Psr7\Query::parse($input);
self::assertSame($output, $result);
}
public function testDoesNotDecode()
{
$str = 'foo%20=bar';
$data = Psr7\Query::parse($str, false);
self::assertSame(['foo%20' => 'bar'], $data);
}
/**
* @dataProvider parseQueryProvider
*/
public function testParsesAndBuildsQueries($input)
{
$result = Psr7\Query::parse($input, false);
self::assertSame($input, Psr7\Query::build($result, false));
}
public function testEncodesWithRfc1738()
{
$str = Psr7\Query::build(['foo bar' => 'baz+'], PHP_QUERY_RFC1738);
self::assertSame('foo+bar=baz%2B', $str);
}
public function testEncodesWithRfc3986()
{
$str = Psr7\Query::build(['foo bar' => 'baz+'], PHP_QUERY_RFC3986);
self::assertSame('foo%20bar=baz%2B', $str);
}
public function testDoesNotEncode()
{
$str = Psr7\Query::build(['foo bar' => 'baz+'], false);
self::assertSame('foo bar=baz+', $str);
}
public function testCanControlDecodingType()
{
$result = Psr7\Query::parse('var=foo+bar', PHP_QUERY_RFC3986);
self::assertSame('foo+bar', $result['var']);
$result = Psr7\Query::parse('var=foo+bar', PHP_QUERY_RFC1738);
self::assertSame('foo bar', $result['var']);
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\Stream;
final class ReadSeekOnlyStream extends Stream
{
public function __construct()
{
parent::__construct(fopen('php://memory', 'wb'));
}
public function isSeekable()
{
return true;
}
public function isReadable()
{
return false;
}
}

View File

@ -0,0 +1,298 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Uri;
/**
* @covers GuzzleHttp\Psr7\MessageTrait
* @covers GuzzleHttp\Psr7\Request
*/
class RequestTest extends BaseTest
{
public function testRequestUriMayBeString()
{
$r = new Request('GET', '/');
self::assertSame('/', (string) $r->getUri());
}
public function testRequestUriMayBeUri()
{
$uri = new Uri('/');
$r = new Request('GET', $uri);
self::assertSame($uri, $r->getUri());
}
public function testValidateRequestUri()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
new Request('GET', '///');
}
public function testCanConstructWithBody()
{
$r = new Request('GET', '/', [], 'baz');
self::assertInstanceOf('Psr\Http\Message\StreamInterface', $r->getBody());
self::assertSame('baz', (string) $r->getBody());
}
public function testNullBody()
{
$r = new Request('GET', '/', [], null);
self::assertInstanceOf('Psr\Http\Message\StreamInterface', $r->getBody());
self::assertSame('', (string) $r->getBody());
}
public function testFalseyBody()
{
$r = new Request('GET', '/', [], '0');
self::assertInstanceOf('Psr\Http\Message\StreamInterface', $r->getBody());
self::assertSame('0', (string) $r->getBody());
}
public function testConstructorDoesNotReadStreamBody()
{
$streamIsRead = false;
$body = Psr7\FnStream::decorate(Psr7\Utils::streamFor(''), [
'__toString' => function () use (&$streamIsRead) {
$streamIsRead = true;
return '';
}
]);
$r = new Request('GET', '/', [], $body);
self::assertFalse($streamIsRead);
self::assertSame($body, $r->getBody());
}
public function testCapitalizesMethod()
{
$r = new Request('get', '/');
self::assertSame('GET', $r->getMethod());
}
public function testCapitalizesWithMethod()
{
$r = new Request('GET', '/');
self::assertSame('PUT', $r->withMethod('put')->getMethod());
}
public function testWithUri()
{
$r1 = new Request('GET', '/');
$u1 = $r1->getUri();
$u2 = new Uri('http://www.example.com');
$r2 = $r1->withUri($u2);
self::assertNotSame($r1, $r2);
self::assertSame($u2, $r2->getUri());
self::assertSame($u1, $r1->getUri());
}
/**
* @dataProvider invalidMethodsProvider
*/
public function testConstructWithInvalidMethods($method)
{
$this->expectExceptionGuzzle('InvalidArgumentException');
new Request($method, '/');
}
/**
* @dataProvider invalidMethodsProvider
*/
public function testWithInvalidMethods($method)
{
$r = new Request('get', '/');
$this->expectExceptionGuzzle('InvalidArgumentException');
$r->withMethod($method);
}
public function invalidMethodsProvider()
{
return [
[null],
[false],
[['foo']],
[new \stdClass()],
];
}
public function testSameInstanceWhenSameUri()
{
$r1 = new Request('GET', 'http://foo.com');
$r2 = $r1->withUri($r1->getUri());
self::assertSame($r1, $r2);
}
public function testWithRequestTarget()
{
$r1 = new Request('GET', '/');
$r2 = $r1->withRequestTarget('*');
self::assertSame('*', $r2->getRequestTarget());
self::assertSame('/', $r1->getRequestTarget());
}
public function testRequestTargetDoesNotAllowSpaces()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
$r1 = new Request('GET', '/');
$r1->withRequestTarget('/foo bar');
}
public function testRequestTargetDefaultsToSlash()
{
$r1 = new Request('GET', '');
self::assertSame('/', $r1->getRequestTarget());
$r2 = new Request('GET', '*');
self::assertSame('*', $r2->getRequestTarget());
$r3 = new Request('GET', 'http://foo.com/bar baz/');
self::assertSame('/bar%20baz/', $r3->getRequestTarget());
}
public function testBuildsRequestTarget()
{
$r1 = new Request('GET', 'http://foo.com/baz?bar=bam');
self::assertSame('/baz?bar=bam', $r1->getRequestTarget());
}
public function testBuildsRequestTargetWithFalseyQuery()
{
$r1 = new Request('GET', 'http://foo.com/baz?0');
self::assertSame('/baz?0', $r1->getRequestTarget());
}
public function testHostIsAddedFirst()
{
$r = new Request('GET', 'http://foo.com/baz?bar=bam', ['Foo' => 'Bar']);
self::assertSame([
'Host' => ['foo.com'],
'Foo' => ['Bar']
], $r->getHeaders());
}
public function testHeaderValueWithWhitespace()
{
$r = new Request('GET', 'https://example.com/', [
'User-Agent' => 'Linux f0f489981e90 5.10.104-linuxkit 1 SMP Wed Mar 9 19:05:23 UTC 2022 x86_64'
]);
self::assertSame([
'Host' => ['example.com'],
'User-Agent' => ['Linux f0f489981e90 5.10.104-linuxkit 1 SMP Wed Mar 9 19:05:23 UTC 2022 x86_64']
], $r->getHeaders());
}
public function testCanGetHeaderAsCsv()
{
$r = new Request('GET', 'http://foo.com/baz?bar=bam', [
'Foo' => ['a', 'b', 'c']
]);
self::assertSame('a, b, c', $r->getHeaderLine('Foo'));
self::assertSame('', $r->getHeaderLine('Bar'));
}
public function testHostIsNotOverwrittenWhenPreservingHost()
{
$r = new Request('GET', 'http://foo.com/baz?bar=bam', ['Host' => 'a.com']);
self::assertSame(['Host' => ['a.com']], $r->getHeaders());
$r2 = $r->withUri(new Uri('http://www.foo.com/bar'), true);
self::assertSame('a.com', $r2->getHeaderLine('Host'));
}
public function testWithUriSetsHostIfNotSet()
{
$r = (new Request('GET', 'http://foo.com/baz?bar=bam'))->withoutHeader('Host');
self::assertSame([], $r->getHeaders());
$r2 = $r->withUri(new Uri('http://www.baz.com/bar'), true);
self::assertSame('www.baz.com', $r2->getHeaderLine('Host'));
}
public function testOverridesHostWithUri()
{
$r = new Request('GET', 'http://foo.com/baz?bar=bam');
self::assertSame(['Host' => ['foo.com']], $r->getHeaders());
$r2 = $r->withUri(new Uri('http://www.baz.com/bar'));
self::assertSame('www.baz.com', $r2->getHeaderLine('Host'));
}
public function testAggregatesHeaders()
{
$r = new Request('GET', '', [
'ZOO' => 'zoobar',
'zoo' => ['foobar', 'zoobar']
]);
self::assertSame(['ZOO' => ['zoobar', 'foobar', 'zoobar']], $r->getHeaders());
self::assertSame('zoobar, foobar, zoobar', $r->getHeaderLine('zoo'));
}
public function testAddsPortToHeader()
{
$r = new Request('GET', 'http://foo.com:8124/bar');
self::assertSame('foo.com:8124', $r->getHeaderLine('host'));
}
public function testAddsPortToHeaderAndReplacePreviousPort()
{
$r = new Request('GET', 'http://foo.com:8124/bar');
$r = $r->withUri(new Uri('http://foo.com:8125/bar'));
self::assertSame('foo.com:8125', $r->getHeaderLine('host'));
}
/**
* @dataProvider provideHeaderValuesContainingNotAllowedChars
*/
public function testContainsNotAllowedCharsOnHeaderValue($value)
{
$this->expectExceptionGuzzle('InvalidArgumentException', sprintf('"%s" is not valid header value', $value));
$r = new Request(
'GET',
'http://foo.com/baz?bar=bam',
[
'testing' => $value
]
);
}
/**
* @return iterable
*/
public function provideHeaderValuesContainingNotAllowedChars()
{
// Explicit tests for newlines as the most common exploit vector.
$tests = [
["new\nline"],
["new\r\nline"],
["new\rline"],
// Line folding is technically allowed, but deprecated.
// We don't support it.
["new\r\n line"],
["newline\n"],
["\nnewline"],
["newline\r\n"],
["\r\nnewline"],
];
for ($i = 0; $i <= 0xff; $i++) {
if (\chr($i) == "\t") {
continue;
}
if (\chr($i) == " ") {
continue;
}
if ($i >= 0x21 && $i <= 0x7e) {
continue;
}
if ($i >= 0x80) {
continue;
}
$tests[] = ["foo" . \chr($i) . "bar"];
$tests[] = ["foo" . \chr($i)];
}
return $tests;
}
}

View File

@ -0,0 +1,384 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\Response;
/**
* @covers GuzzleHttp\Psr7\MessageTrait
* @covers GuzzleHttp\Psr7\Response
*/
class ResponseTest extends BaseTest
{
public function testDefaultConstructor()
{
$r = new Response();
self::assertSame(200, $r->getStatusCode());
self::assertSame('1.1', $r->getProtocolVersion());
self::assertSame('OK', $r->getReasonPhrase());
self::assertSame([], $r->getHeaders());
self::assertInstanceOf('Psr\Http\Message\StreamInterface', $r->getBody());
self::assertSame('', (string) $r->getBody());
}
public function testCanConstructWithStatusCode()
{
$r = new Response(404);
self::assertSame(404, $r->getStatusCode());
self::assertSame('Not Found', $r->getReasonPhrase());
}
public function testConstructorDoesNotReadStreamBody()
{
$streamIsRead = false;
$body = Psr7\FnStream::decorate(Psr7\Utils::streamFor(''), [
'__toString' => function () use (&$streamIsRead) {
$streamIsRead = true;
return '';
}
]);
$r = new Response(200, [], $body);
self::assertFalse($streamIsRead);
self::assertSame($body, $r->getBody());
}
public function testStatusCanBeNumericString()
{
$r = new Response('404');
$r2 = $r->withStatus('201');
self::assertSame(404, $r->getStatusCode());
self::assertSame('Not Found', $r->getReasonPhrase());
self::assertSame(201, $r2->getStatusCode());
self::assertSame('Created', $r2->getReasonPhrase());
}
public function testCanConstructWithHeaders()
{
$r = new Response(200, ['Foo' => 'Bar']);
self::assertSame(['Foo' => ['Bar']], $r->getHeaders());
self::assertSame('Bar', $r->getHeaderLine('Foo'));
self::assertSame(['Bar'], $r->getHeader('Foo'));
}
public function testCanConstructWithHeadersAsArray()
{
$r = new Response(200, [
'Foo' => ['baz', 'bar']
]);
self::assertSame(['Foo' => ['baz', 'bar']], $r->getHeaders());
self::assertSame('baz, bar', $r->getHeaderLine('Foo'));
self::assertSame(['baz', 'bar'], $r->getHeader('Foo'));
}
public function testCanConstructWithBody()
{
$r = new Response(200, [], 'baz');
self::assertInstanceOf('Psr\Http\Message\StreamInterface', $r->getBody());
self::assertSame('baz', (string) $r->getBody());
}
public function testNullBody()
{
$r = new Response(200, [], null);
self::assertInstanceOf('Psr\Http\Message\StreamInterface', $r->getBody());
self::assertSame('', (string) $r->getBody());
}
public function testFalseyBody()
{
$r = new Response(200, [], '0');
self::assertInstanceOf('Psr\Http\Message\StreamInterface', $r->getBody());
self::assertSame('0', (string) $r->getBody());
}
public function testCanConstructWithReason()
{
$r = new Response(200, [], null, '1.1', 'bar');
self::assertSame('bar', $r->getReasonPhrase());
$r = new Response(200, [], null, '1.1', '0');
self::assertSame('0', $r->getReasonPhrase(), 'Falsey reason works');
}
public function testCanConstructWithProtocolVersion()
{
$r = new Response(200, [], null, '1000');
self::assertSame('1000', $r->getProtocolVersion());
}
public function testWithStatusCodeAndNoReason()
{
$r = (new Response())->withStatus(201);
self::assertSame(201, $r->getStatusCode());
self::assertSame('Created', $r->getReasonPhrase());
}
public function testWithStatusCodeAndReason()
{
$r = (new Response())->withStatus(201, 'Foo');
self::assertSame(201, $r->getStatusCode());
self::assertSame('Foo', $r->getReasonPhrase());
$r = (new Response())->withStatus(201, '0');
self::assertSame(201, $r->getStatusCode());
self::assertSame('0', $r->getReasonPhrase(), 'Falsey reason works');
}
public function testWithProtocolVersion()
{
$r = (new Response())->withProtocolVersion('1000');
self::assertSame('1000', $r->getProtocolVersion());
}
public function testSameInstanceWhenSameProtocol()
{
$r = new Response();
self::assertSame($r, $r->withProtocolVersion('1.1'));
}
public function testWithBody()
{
$b = Psr7\Utils::streamFor('0');
$r = (new Response())->withBody($b);
self::assertInstanceOf('Psr\Http\Message\StreamInterface', $r->getBody());
self::assertSame('0', (string) $r->getBody());
}
public function testSameInstanceWhenSameBody()
{
$r = new Response();
$b = $r->getBody();
self::assertSame($r, $r->withBody($b));
}
public function testWithHeader()
{
$r = new Response(200, ['Foo' => 'Bar']);
$r2 = $r->withHeader('baZ', 'Bam');
self::assertSame(['Foo' => ['Bar']], $r->getHeaders());
self::assertSame(['Foo' => ['Bar'], 'baZ' => ['Bam']], $r2->getHeaders());
self::assertSame('Bam', $r2->getHeaderLine('baz'));
self::assertSame(['Bam'], $r2->getHeader('baz'));
}
public function testNumericHeaderValue()
{
$r = (new Response())->withHeader('Api-Version', 1);
self::assertSame(['Api-Version' => ['1']], $r->getHeaders());
}
public function testWithHeaderAsArray()
{
$r = new Response(200, ['Foo' => 'Bar']);
$r2 = $r->withHeader('baZ', ['Bam', 'Bar']);
self::assertSame(['Foo' => ['Bar']], $r->getHeaders());
self::assertSame(['Foo' => ['Bar'], 'baZ' => ['Bam', 'Bar']], $r2->getHeaders());
self::assertSame('Bam, Bar', $r2->getHeaderLine('baz'));
self::assertSame(['Bam', 'Bar'], $r2->getHeader('baz'));
}
public function testWithHeaderReplacesDifferentCase()
{
$r = new Response(200, ['Foo' => 'Bar']);
$r2 = $r->withHeader('foO', 'Bam');
self::assertSame(['Foo' => ['Bar']], $r->getHeaders());
self::assertSame(['foO' => ['Bam']], $r2->getHeaders());
self::assertSame('Bam', $r2->getHeaderLine('foo'));
self::assertSame(['Bam'], $r2->getHeader('foo'));
}
public function testWithAddedHeader()
{
$r = new Response(200, ['Foo' => 'Bar']);
$r2 = $r->withAddedHeader('foO', 'Baz');
self::assertSame(['Foo' => ['Bar']], $r->getHeaders());
self::assertSame(['Foo' => ['Bar', 'Baz']], $r2->getHeaders());
self::assertSame('Bar, Baz', $r2->getHeaderLine('foo'));
self::assertSame(['Bar', 'Baz'], $r2->getHeader('foo'));
}
public function testWithAddedHeaderAsArray()
{
$r = new Response(200, ['Foo' => 'Bar']);
$r2 = $r->withAddedHeader('foO', ['Baz', 'Bam']);
self::assertSame(['Foo' => ['Bar']], $r->getHeaders());
self::assertSame(['Foo' => ['Bar', 'Baz', 'Bam']], $r2->getHeaders());
self::assertSame('Bar, Baz, Bam', $r2->getHeaderLine('foo'));
self::assertSame(['Bar', 'Baz', 'Bam'], $r2->getHeader('foo'));
}
public function testWithAddedHeaderThatDoesNotExist()
{
$r = new Response(200, ['Foo' => 'Bar']);
$r2 = $r->withAddedHeader('nEw', 'Baz');
self::assertSame(['Foo' => ['Bar']], $r->getHeaders());
self::assertSame(['Foo' => ['Bar'], 'nEw' => ['Baz']], $r2->getHeaders());
self::assertSame('Baz', $r2->getHeaderLine('new'));
self::assertSame(['Baz'], $r2->getHeader('new'));
}
public function testWithoutHeaderThatExists()
{
$r = new Response(200, ['Foo' => 'Bar', 'Baz' => 'Bam']);
$r2 = $r->withoutHeader('foO');
self::assertTrue($r->hasHeader('foo'));
self::assertSame(['Foo' => ['Bar'], 'Baz' => ['Bam']], $r->getHeaders());
self::assertFalse($r2->hasHeader('foo'));
self::assertSame(['Baz' => ['Bam']], $r2->getHeaders());
}
public function testWithoutHeaderThatDoesNotExist()
{
$r = new Response(200, ['Baz' => 'Bam']);
$r2 = $r->withoutHeader('foO');
self::assertSame($r, $r2);
self::assertFalse($r2->hasHeader('foo'));
self::assertSame(['Baz' => ['Bam']], $r2->getHeaders());
}
public function testSameInstanceWhenRemovingMissingHeader()
{
$r = new Response();
self::assertSame($r, $r->withoutHeader('foo'));
}
public function testPassNumericHeaderNameInConstructor()
{
$r = new Response(200, ['Location' => 'foo', '123' => 'bar']);
self::assertSame('bar', $r->getHeaderLine('123'));
}
/**
* @dataProvider invalidHeaderProvider
*/
public function testConstructResponseInvalidHeader($header, $headerValue, $expectedMessage)
{
$this->expectExceptionGuzzle('InvalidArgumentException', $expectedMessage);
new Response(200, [$header => $headerValue]);
}
public function invalidHeaderProvider()
{
return [
['foo', [], 'Header value can not be an empty array.'],
['', '', 'Header name can not be empty.'],
['foo', new \stdClass(), 'Header value must be scalar or null but stdClass provided.'],
];
}
/**
* @dataProvider invalidWithHeaderProvider
*/
public function testWithInvalidHeader($header, $headerValue, $expectedMessage)
{
$r = new Response();
$this->expectExceptionGuzzle('InvalidArgumentException', $expectedMessage);
$r->withHeader($header, $headerValue);
}
public function invalidWithHeaderProvider()
{
return array_merge($this->invalidHeaderProvider(), [
[[], 'foo', 'Header name must be a string but array provided.'],
[false, 'foo', 'Header name must be a string but boolean provided.'],
[new \stdClass(), 'foo', 'Header name must be a string but stdClass provided.'],
["", 'foo', "Header name can not be empty."],
["Content-Type\r\n\r\n", 'foo', "\"Content-Type\r\n\r\n\" is not valid header name."],
["Content-Type\r\n", 'foo', "\"Content-Type\r\n\" is not valid header name."],
["Content-Type\n", 'foo', "\"Content-Type\n\" is not valid header name."],
["\r\nContent-Type", 'foo', "\"\r\nContent-Type\" is not valid header name."],
["\nContent-Type", 'foo', "\"\nContent-Type\" is not valid header name."],
["\n", 'foo', "\"\n\" is not valid header name."],
["\r\n", 'foo', "\"\r\n\" is not valid header name."],
["\t", 'foo', "\"\t\" is not valid header name."],
]);
}
public function testHeaderValuesAreTrimmed()
{
$r1 = new Response(200, ['OWS' => " \t \tFoo\t \t "]);
$r2 = (new Response())->withHeader('OWS', " \t \tFoo\t \t ");
$r3 = (new Response())->withAddedHeader('OWS', " \t \tFoo\t \t ");
foreach ([$r1, $r2, $r3] as $r) {
self::assertSame(['OWS' => ['Foo']], $r->getHeaders());
self::assertSame('Foo', $r->getHeaderLine('OWS'));
self::assertSame(['Foo'], $r->getHeader('OWS'));
}
}
public function testWithAddedHeaderArrayValueAndKeys()
{
$message = (new Response())->withAddedHeader('list', ['foo' => 'one']);
$message = $message->withAddedHeader('list', ['foo' => 'two', 'bar' => 'three']);
$headerLine = $message->getHeaderLine('list');
self::assertSame('one, two, three', $headerLine);
}
/**
* @dataProvider nonIntegerStatusCodeProvider
*
* @param mixed $invalidValues
*/
public function testConstructResponseWithNonIntegerStatusCode($invalidValues)
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'Status code must be an integer value.');
new Response($invalidValues);
}
/**
* @dataProvider nonIntegerStatusCodeProvider
*
* @param mixed $invalidValues
*/
public function testResponseChangeStatusCodeWithNonInteger($invalidValues)
{
$response = new Response();
$this->expectExceptionGuzzle('InvalidArgumentException', 'Status code must be an integer value.');
$response->withStatus($invalidValues);
}
public function nonIntegerStatusCodeProvider()
{
return [
['whatever'],
['1.01'],
[1.01],
[new \stdClass()],
];
}
/**
* @dataProvider invalidStatusCodeRangeProvider
*
* @param mixed $invalidValues
*/
public function testConstructResponseWithInvalidRangeStatusCode($invalidValues)
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'Status code must be an integer value between 1xx and 5xx.');
new Response($invalidValues);
}
/**
* @dataProvider invalidStatusCodeRangeProvider
*
* @param mixed $invalidValues
*/
public function testResponseChangeStatusCodeWithWithInvalidRange($invalidValues)
{
$response = new Response();
$this->expectExceptionGuzzle('InvalidArgumentException', 'Status code must be an integer value between 1xx and 5xx.');
$response->withStatus($invalidValues);
}
public function invalidStatusCodeRangeProvider()
{
return [
[600],
[99],
];
}
}

View File

@ -0,0 +1,544 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\ServerRequest;
use GuzzleHttp\Psr7\UploadedFile;
use GuzzleHttp\Psr7\Uri;
/**
* @covers GuzzleHttp\Psr7\ServerRequest
*/
class ServerRequestTest extends BaseTest
{
public function dataNormalizeFiles()
{
return [
'Single file' => [
[
'file' => [
'name' => 'MyFile.txt',
'type' => 'text/plain',
'tmp_name' => '/tmp/php/php1h4j1o',
'error' => '0',
'size' => '123'
]
],
[
'file' => new UploadedFile(
'/tmp/php/php1h4j1o',
123,
UPLOAD_ERR_OK,
'MyFile.txt',
'text/plain'
)
]
],
'Empty file' => [
[
'image_file' => [
'name' => '',
'type' => '',
'tmp_name' => '',
'error' => '4',
'size' => '0'
]
],
[
'image_file' => new UploadedFile(
'',
0,
UPLOAD_ERR_NO_FILE,
'',
''
)
]
],
'Already Converted' => [
[
'file' => new UploadedFile(
'/tmp/php/php1h4j1o',
123,
UPLOAD_ERR_OK,
'MyFile.txt',
'text/plain'
)
],
[
'file' => new UploadedFile(
'/tmp/php/php1h4j1o',
123,
UPLOAD_ERR_OK,
'MyFile.txt',
'text/plain'
)
]
],
'Already Converted array' => [
[
'file' => [
new UploadedFile(
'/tmp/php/php1h4j1o',
123,
UPLOAD_ERR_OK,
'MyFile.txt',
'text/plain'
),
new UploadedFile(
'',
0,
UPLOAD_ERR_NO_FILE,
'',
''
)
],
],
[
'file' => [
new UploadedFile(
'/tmp/php/php1h4j1o',
123,
UPLOAD_ERR_OK,
'MyFile.txt',
'text/plain'
),
new UploadedFile(
'',
0,
UPLOAD_ERR_NO_FILE,
'',
''
)
],
]
],
'Multiple files' => [
[
'text_file' => [
'name' => 'MyFile.txt',
'type' => 'text/plain',
'tmp_name' => '/tmp/php/php1h4j1o',
'error' => '0',
'size' => '123'
],
'image_file' => [
'name' => '',
'type' => '',
'tmp_name' => '',
'error' => '4',
'size' => '0'
]
],
[
'text_file' => new UploadedFile(
'/tmp/php/php1h4j1o',
123,
UPLOAD_ERR_OK,
'MyFile.txt',
'text/plain'
),
'image_file' => new UploadedFile(
'',
0,
UPLOAD_ERR_NO_FILE,
'',
''
)
]
],
'Nested files' => [
[
'file' => [
'name' => [
0 => 'MyFile.txt',
1 => 'Image.png',
],
'type' => [
0 => 'text/plain',
1 => 'image/png',
],
'tmp_name' => [
0 => '/tmp/php/hp9hskjhf',
1 => '/tmp/php/php1h4j1o',
],
'error' => [
0 => '0',
1 => '0',
],
'size' => [
0 => '123',
1 => '7349',
],
],
'nested' => [
'name' => [
'other' => 'Flag.txt',
'test' => [
0 => 'Stuff.txt',
1 => '',
],
],
'type' => [
'other' => 'text/plain',
'test' => [
0 => 'text/plain',
1 => '',
],
],
'tmp_name' => [
'other' => '/tmp/php/hp9hskjhf',
'test' => [
0 => '/tmp/php/asifu2gp3',
1 => '',
],
],
'error' => [
'other' => '0',
'test' => [
0 => '0',
1 => '4',
],
],
'size' => [
'other' => '421',
'test' => [
0 => '32',
1 => '0',
]
]
],
],
[
'file' => [
0 => new UploadedFile(
'/tmp/php/hp9hskjhf',
123,
UPLOAD_ERR_OK,
'MyFile.txt',
'text/plain'
),
1 => new UploadedFile(
'/tmp/php/php1h4j1o',
7349,
UPLOAD_ERR_OK,
'Image.png',
'image/png'
),
],
'nested' => [
'other' => new UploadedFile(
'/tmp/php/hp9hskjhf',
421,
UPLOAD_ERR_OK,
'Flag.txt',
'text/plain'
),
'test' => [
0 => new UploadedFile(
'/tmp/php/asifu2gp3',
32,
UPLOAD_ERR_OK,
'Stuff.txt',
'text/plain'
),
1 => new UploadedFile(
'',
0,
UPLOAD_ERR_NO_FILE,
'',
''
),
]
]
]
]
];
}
/**
* @dataProvider dataNormalizeFiles
*/
public function testNormalizeFiles($files, $expected)
{
$result = ServerRequest::normalizeFiles($files);
self::assertEquals($expected, $result);
}
public function testNormalizeFilesRaisesException()
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'Invalid value in files specification');
ServerRequest::normalizeFiles(['test' => 'something']);
}
public function dataGetUriFromGlobals()
{
$server = [
'REQUEST_URI' => '/blog/article.php?id=10&user=foo',
'SERVER_PORT' => '443',
'SERVER_ADDR' => '217.112.82.20',
'SERVER_NAME' => 'www.example.org',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'REQUEST_METHOD' => 'POST',
'QUERY_STRING' => 'id=10&user=foo',
'DOCUMENT_ROOT' => '/path/to/your/server/root/',
'HTTP_HOST' => 'www.example.org',
'HTTPS' => 'on',
'REMOTE_ADDR' => '193.60.168.69',
'REMOTE_PORT' => '5390',
'SCRIPT_NAME' => '/blog/article.php',
'SCRIPT_FILENAME' => '/path/to/your/server/root/blog/article.php',
'PHP_SELF' => '/blog/article.php',
];
return [
'HTTPS request' => [
'https://www.example.org/blog/article.php?id=10&user=foo',
$server,
],
'HTTPS request with different on value' => [
'https://www.example.org/blog/article.php?id=10&user=foo',
array_merge($server, ['HTTPS' => '1']),
],
'HTTP request' => [
'http://www.example.org/blog/article.php?id=10&user=foo',
array_merge($server, ['HTTPS' => 'off', 'SERVER_PORT' => '80']),
],
'HTTP_HOST missing -> fallback to SERVER_NAME' => [
'https://www.example.org/blog/article.php?id=10&user=foo',
array_merge($server, ['HTTP_HOST' => null]),
],
'HTTP_HOST and SERVER_NAME missing -> fallback to SERVER_ADDR' => [
'https://217.112.82.20/blog/article.php?id=10&user=foo',
array_merge($server, ['HTTP_HOST' => null, 'SERVER_NAME' => null]),
],
'Query string with ?' => [
'https://www.example.org/path?continue=https://example.com/path?param=1',
array_merge($server, ['REQUEST_URI' => '/path?continue=https://example.com/path?param=1', 'QUERY_STRING' => '']),
],
'No query String' => [
'https://www.example.org/blog/article.php',
array_merge($server, ['REQUEST_URI' => '/blog/article.php', 'QUERY_STRING' => '']),
],
'Host header with port' => [
'https://www.example.org:8324/blog/article.php?id=10&user=foo',
array_merge($server, ['HTTP_HOST' => 'www.example.org:8324']),
],
'IPv6 local loopback address' => [
'https://[::1]:8000/blog/article.php?id=10&user=foo',
array_merge($server, ['HTTP_HOST' => '[::1]:8000']),
],
'Invalid host' => [
'https://localhost/blog/article.php?id=10&user=foo',
array_merge($server, ['HTTP_HOST' => 'a:b']),
],
'Different port with SERVER_PORT' => [
'https://www.example.org:8324/blog/article.php?id=10&user=foo',
array_merge($server, ['SERVER_PORT' => '8324']),
],
'REQUEST_URI missing query string' => [
'https://www.example.org/blog/article.php?id=10&user=foo',
array_merge($server, ['REQUEST_URI' => '/blog/article.php']),
],
'Empty server variable' => [
'http://localhost',
[],
],
];
}
/**
* @dataProvider dataGetUriFromGlobals
*/
public function testGetUriFromGlobals($expected, $serverParams)
{
$_SERVER = $serverParams;
self::assertEquals(new Uri($expected), ServerRequest::getUriFromGlobals());
}
public function testFromGlobals()
{
$_SERVER = [
'REQUEST_URI' => '/blog/article.php?id=10&user=foo',
'SERVER_PORT' => '443',
'SERVER_ADDR' => '217.112.82.20',
'SERVER_NAME' => 'www.example.org',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'REQUEST_METHOD' => 'POST',
'QUERY_STRING' => 'id=10&user=foo',
'DOCUMENT_ROOT' => '/path/to/your/server/root/',
'CONTENT_TYPE' => 'text/plain',
'HTTP_HOST' => 'www.example.org',
'HTTP_ACCEPT' => 'text/html',
'HTTP_REFERRER' => 'https://example.com',
'HTTP_USER_AGENT' => 'My User Agent',
'HTTPS' => 'on',
'REMOTE_ADDR' => '193.60.168.69',
'REMOTE_PORT' => '5390',
'SCRIPT_NAME' => '/blog/article.php',
'SCRIPT_FILENAME' => '/path/to/your/server/root/blog/article.php',
'PHP_SELF' => '/blog/article.php',
];
$_COOKIE = [
'logged-in' => 'yes!'
];
$_POST = [
'name' => 'Pesho',
'email' => 'pesho@example.com',
];
$_GET = [
'id' => 10,
'user' => 'foo',
];
$_FILES = [
'file' => [
'name' => 'MyFile.txt',
'type' => 'text/plain',
'tmp_name' => '/tmp/php/php1h4j1o',
'error' => UPLOAD_ERR_OK,
'size' => 123,
]
];
$server = ServerRequest::fromGlobals();
self::assertSame('POST', $server->getMethod());
self::assertEquals([
'Host' => ['www.example.org'],
'Content-Type' => ['text/plain'],
'Accept' => ['text/html'],
'Referrer' => ['https://example.com'],
'User-Agent' => ['My User Agent'],
], $server->getHeaders());
self::assertSame('', (string) $server->getBody());
self::assertSame('1.1', $server->getProtocolVersion());
self::assertSame($_COOKIE, $server->getCookieParams());
self::assertSame($_POST, $server->getParsedBody());
self::assertSame($_GET, $server->getQueryParams());
self::assertEquals(
new Uri('https://www.example.org/blog/article.php?id=10&user=foo'),
$server->getUri()
);
$expectedFiles = [
'file' => new UploadedFile(
'/tmp/php/php1h4j1o',
123,
UPLOAD_ERR_OK,
'MyFile.txt',
'text/plain'
),
];
self::assertEquals($expectedFiles, $server->getUploadedFiles());
}
public function testUploadedFiles()
{
$request1 = new ServerRequest('GET', '/');
$files = [
'file' => new UploadedFile('test', 123, UPLOAD_ERR_OK)
];
$request2 = $request1->withUploadedFiles($files);
self::assertNotSame($request2, $request1);
self::assertSame([], $request1->getUploadedFiles());
self::assertSame($files, $request2->getUploadedFiles());
}
public function testServerParams()
{
$params = ['name' => 'value'];
$request = new ServerRequest('GET', '/', [], null, '1.1', $params);
self::assertSame($params, $request->getServerParams());
}
public function testCookieParams()
{
$request1 = new ServerRequest('GET', '/');
$params = ['name' => 'value'];
$request2 = $request1->withCookieParams($params);
self::assertNotSame($request2, $request1);
self::assertEmpty($request1->getCookieParams());
self::assertSame($params, $request2->getCookieParams());
}
public function testQueryParams()
{
$request1 = new ServerRequest('GET', '/');
$params = ['name' => 'value'];
$request2 = $request1->withQueryParams($params);
self::assertNotSame($request2, $request1);
self::assertEmpty($request1->getQueryParams());
self::assertSame($params, $request2->getQueryParams());
}
public function testParsedBody()
{
$request1 = new ServerRequest('GET', '/');
$params = ['name' => 'value'];
$request2 = $request1->withParsedBody($params);
self::assertNotSame($request2, $request1);
self::assertEmpty($request1->getParsedBody());
self::assertSame($params, $request2->getParsedBody());
}
public function testAttributes()
{
$request1 = new ServerRequest('GET', '/');
$request2 = $request1->withAttribute('name', 'value');
$request3 = $request2->withAttribute('other', 'otherValue');
$request4 = $request3->withoutAttribute('other');
$request5 = $request3->withoutAttribute('unknown');
self::assertNotSame($request2, $request1);
self::assertNotSame($request3, $request2);
self::assertNotSame($request4, $request3);
self::assertSame($request5, $request3);
self::assertSame([], $request1->getAttributes());
self::assertNull($request1->getAttribute('name'));
self::assertSame(
'something',
$request1->getAttribute('name', 'something'),
'Should return the default value'
);
self::assertSame('value', $request2->getAttribute('name'));
self::assertSame(['name' => 'value'], $request2->getAttributes());
self::assertEquals(['name' => 'value', 'other' => 'otherValue'], $request3->getAttributes());
self::assertSame(['name' => 'value'], $request4->getAttributes());
}
public function testNullAttribute()
{
$request = (new ServerRequest('GET', '/'))->withAttribute('name', null);
self::assertSame(['name' => null], $request->getAttributes());
self::assertNull($request->getAttribute('name', 'different-default'));
$requestWithoutAttribute = $request->withoutAttribute('name');
self::assertSame([], $requestWithoutAttribute->getAttributes());
self::assertSame('different-default', $requestWithoutAttribute->getAttribute('name', 'different-default'));
}
}

View File

@ -0,0 +1,147 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\StreamDecoratorTrait;
use Psr\Http\Message\StreamInterface;
class Str implements StreamInterface
{
use StreamDecoratorTrait;
}
/**
* @covers GuzzleHttp\Psr7\StreamDecoratorTrait
*/
class StreamDecoratorTraitTest extends BaseTest
{
/** @var StreamInterface */
private $a;
/** @var StreamInterface */
private $b;
/** @var resource */
private $c;
/**
* @before
*/
public function setUpTest()
{
$this->c = fopen('php://temp', 'r+');
fwrite($this->c, 'foo');
fseek($this->c, 0);
$this->a = Psr7\Utils::streamFor($this->c);
$this->b = new Str($this->a);
}
public function testCatchesExceptionsWhenCastingToString()
{
$s = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['read'])
->getMockForAbstractClass();
$s->expects(self::once())
->method('read')
->will(self::throwException(new \Exception('foo')));
$msg = '';
set_error_handler(function ($errNo, $str) use (&$msg) {
$msg = $str;
});
echo new Str($s);
restore_error_handler();
$this->assertStringContainsStringGuzzle('foo', $msg);
}
public function testToString()
{
self::assertSame('foo', (string) $this->b);
}
public function testHasSize()
{
self::assertSame(3, $this->b->getSize());
}
public function testReads()
{
self::assertSame('foo', $this->b->read(10));
}
public function testCheckMethods()
{
self::assertSame($this->a->isReadable(), $this->b->isReadable());
self::assertSame($this->a->isWritable(), $this->b->isWritable());
self::assertSame($this->a->isSeekable(), $this->b->isSeekable());
}
public function testSeeksAndTells()
{
$this->b->seek(1);
self::assertSame(1, $this->a->tell());
self::assertSame(1, $this->b->tell());
$this->b->seek(0);
self::assertSame(0, $this->a->tell());
self::assertSame(0, $this->b->tell());
$this->b->seek(0, SEEK_END);
self::assertSame(3, $this->a->tell());
self::assertSame(3, $this->b->tell());
}
public function testGetsContents()
{
self::assertSame('foo', $this->b->getContents());
self::assertSame('', $this->b->getContents());
$this->b->seek(1);
self::assertSame('oo', $this->b->getContents());
}
public function testCloses()
{
$this->b->close();
self::assertFalse(is_resource($this->c));
}
public function testDetaches()
{
$this->b->detach();
self::assertFalse($this->b->isReadable());
}
public function testWrapsMetadata()
{
self::assertSame($this->b->getMetadata(), $this->a->getMetadata());
self::assertSame($this->b->getMetadata('uri'), $this->a->getMetadata('uri'));
}
public function testWrapsWrites()
{
$this->b->seek(0, SEEK_END);
$this->b->write('foo');
self::assertSame('foofoo', (string) $this->a);
}
public function testThrowsWithInvalidGetter()
{
$this->expectExceptionGuzzle('UnexpectedValueException');
$this->b->foo;
}
public function testThrowsWhenGetterNotImplemented()
{
$s = new BadStream();
$this->expectExceptionGuzzle('BadMethodCallException');
$s->stream;
}
}
class BadStream
{
use StreamDecoratorTrait;
public function __construct()
{
}
}

View File

@ -0,0 +1,403 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\Stream;
/**
* @covers GuzzleHttp\Psr7\Stream
*/
class StreamTest extends BaseTest
{
public static $isFReadError = false;
public function testConstructorThrowsExceptionOnInvalidArgument()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
new Stream(true);
}
public function testConstructorInitializesProperties()
{
$handle = fopen('php://temp', 'r+');
fwrite($handle, 'data');
$stream = new Stream($handle);
self::assertTrue($stream->isReadable());
self::assertTrue($stream->isWritable());
self::assertTrue($stream->isSeekable());
self::assertSame('php://temp', $stream->getMetadata('uri'));
$this->assertInternalTypeGuzzle('array', $stream->getMetadata());
self::assertSame(4, $stream->getSize());
self::assertFalse($stream->eof());
$stream->close();
}
public function testConstructorInitializesPropertiesWithRbPlus()
{
$handle = fopen('php://temp', 'rb+');
fwrite($handle, 'data');
$stream = new Stream($handle);
self::assertTrue($stream->isReadable());
self::assertTrue($stream->isWritable());
self::assertTrue($stream->isSeekable());
self::assertSame('php://temp', $stream->getMetadata('uri'));
$this->assertInternalTypeGuzzle('array', $stream->getMetadata());
self::assertSame(4, $stream->getSize());
self::assertFalse($stream->eof());
$stream->close();
}
public function testStreamClosesHandleOnDestruct()
{
$handle = fopen('php://temp', 'r');
$stream = new Stream($handle);
unset($stream);
self::assertFalse(is_resource($handle));
}
public function testConvertsToString()
{
$handle = fopen('php://temp', 'w+');
fwrite($handle, 'data');
$stream = new Stream($handle);
self::assertSame('data', (string) $stream);
self::assertSame('data', (string) $stream);
$stream->close();
}
public function testConvertsToStringNonSeekableStream()
{
if (defined('HHVM_VERSION')) {
self::markTestSkipped('This does not work on HHVM.');
}
$handle = popen('echo foo', 'r');
$stream = new Stream($handle);
self::assertFalse($stream->isSeekable());
self::assertSame('foo', trim((string) $stream));
}
public function testConvertsToStringNonSeekablePartiallyReadStream()
{
if (defined('HHVM_VERSION')) {
self::markTestSkipped('This does not work on HHVM.');
}
$handle = popen('echo bar', 'r');
$stream = new Stream($handle);
$firstLetter = $stream->read(1);
self::assertFalse($stream->isSeekable());
self::assertSame('b', $firstLetter);
self::assertSame('ar', trim((string) $stream));
}
public function testGetsContents()
{
$handle = fopen('php://temp', 'w+');
fwrite($handle, 'data');
$stream = new Stream($handle);
self::assertSame('', $stream->getContents());
$stream->seek(0);
self::assertSame('data', $stream->getContents());
self::assertSame('', $stream->getContents());
$stream->close();
}
public function testChecksEof()
{
$handle = fopen('php://temp', 'w+');
fwrite($handle, 'data');
$stream = new Stream($handle);
self::assertSame(4, $stream->tell(), 'Stream cursor already at the end');
self::assertFalse($stream->eof(), 'Stream still not eof');
self::assertSame('', $stream->read(1), 'Need to read one more byte to reach eof');
self::assertTrue($stream->eof());
$stream->close();
}
public function testGetSize()
{
$size = filesize(__FILE__);
$handle = fopen(__FILE__, 'r');
$stream = new Stream($handle);
self::assertSame($size, $stream->getSize());
// Load from cache
self::assertSame($size, $stream->getSize());
$stream->close();
}
public function testEnsuresSizeIsConsistent()
{
$h = fopen('php://temp', 'w+');
self::assertSame(3, fwrite($h, 'foo'));
$stream = new Stream($h);
self::assertSame(3, $stream->getSize());
self::assertSame(4, $stream->write('test'));
self::assertSame(7, $stream->getSize());
self::assertSame(7, $stream->getSize());
$stream->close();
}
public function testProvidesStreamPosition()
{
$handle = fopen('php://temp', 'w+');
$stream = new Stream($handle);
self::assertSame(0, $stream->tell());
$stream->write('foo');
self::assertSame(3, $stream->tell());
$stream->seek(1);
self::assertSame(1, $stream->tell());
self::assertSame(ftell($handle), $stream->tell());
$stream->close();
}
public function testDetachStreamAndClearProperties()
{
$handle = fopen('php://temp', 'r');
$stream = new Stream($handle);
self::assertSame($handle, $stream->detach());
$this->assertInternalTypeGuzzle('resource', $handle, 'Stream is not closed');
self::assertNull($stream->detach());
$this->assertStreamStateAfterClosedOrDetached($stream);
$stream->close();
}
public function testCloseResourceAndClearProperties()
{
$handle = fopen('php://temp', 'r');
$stream = new Stream($handle);
$stream->close();
self::assertFalse(is_resource($handle));
$this->assertStreamStateAfterClosedOrDetached($stream);
}
private function assertStreamStateAfterClosedOrDetached(Stream $stream)
{
self::assertFalse($stream->isReadable());
self::assertFalse($stream->isWritable());
self::assertFalse($stream->isSeekable());
self::assertNull($stream->getSize());
self::assertSame([], $stream->getMetadata());
self::assertNull($stream->getMetadata('foo'));
$throws = function (callable $fn) {
try {
$fn();
} catch (\Exception $e) {
$this->assertStringContainsStringGuzzle('Stream is detached', $e->getMessage());
return;
}
$this->fail('Exception should be thrown after the stream is detached.');
};
$throws(function () use ($stream) {
$stream->read(10);
});
$throws(function () use ($stream) {
$stream->write('bar');
});
$throws(function () use ($stream) {
$stream->seek(10);
});
$throws(function () use ($stream) {
$stream->tell();
});
$throws(function () use ($stream) {
$stream->eof();
});
$throws(function () use ($stream) {
$stream->getContents();
});
self::assertSame('', (string) $stream);
}
public function testStreamReadingWithZeroLength()
{
$r = fopen('php://temp', 'r');
$stream = new Stream($r);
self::assertSame('', $stream->read(0));
$stream->close();
}
public function testStreamReadingWithNegativeLength()
{
$r = fopen('php://temp', 'r');
$stream = new Stream($r);
$this->expectExceptionGuzzle('RuntimeException', 'Length parameter cannot be negative');
try {
$stream->read(-1);
} catch (\Exception $e) {
$stream->close();
throw $e;
}
$stream->close();
}
public function testStreamReadingFreadError()
{
self::$isFReadError = true;
$r = fopen('php://temp', 'r');
$stream = new Stream($r);
$this->expectExceptionGuzzle('RuntimeException', 'Unable to read from stream');
try {
$stream->read(1);
} catch (\Exception $e) {
self::$isFReadError = false;
$stream->close();
throw $e;
}
self::$isFReadError = false;
$stream->close();
}
/**
* @dataProvider gzipModeProvider
*
* @param string $mode
* @param bool $readable
* @param bool $writable
*/
public function testGzipStreamModes($mode, $readable, $writable)
{
if (defined('HHVM_VERSION')) {
self::markTestSkipped('This does not work on HHVM.');
}
$r = gzopen('php://temp', $mode);
$stream = new Stream($r);
self::assertSame($readable, $stream->isReadable());
self::assertSame($writable, $stream->isWritable());
$stream->close();
}
public function gzipModeProvider()
{
return [
['mode' => 'rb9', 'readable' => true, 'writable' => false],
['mode' => 'wb2', 'readable' => false, 'writable' => true],
];
}
/**
* @dataProvider readableModeProvider
*
* @param string $mode
*/
public function testReadableStream($mode)
{
$r = fopen('php://temp', $mode);
$stream = new Stream($r);
self::assertTrue($stream->isReadable());
$stream->close();
}
public function readableModeProvider()
{
return [
['r'],
['w+'],
['r+'],
['x+'],
['c+'],
['rb'],
['w+b'],
['r+b'],
['x+b'],
['c+b'],
['rt'],
['w+t'],
['r+t'],
['x+t'],
['c+t'],
['a+'],
['rb+'],
];
}
public function testWriteOnlyStreamIsNotReadable()
{
$r = fopen('php://output', 'w');
$stream = new Stream($r);
self::assertFalse($stream->isReadable());
$stream->close();
}
/**
* @dataProvider writableModeProvider
*
* @param string $mode
*/
public function testWritableStream($mode)
{
$r = fopen('php://temp', $mode);
$stream = new Stream($r);
self::assertTrue($stream->isWritable());
$stream->close();
}
public function writableModeProvider()
{
return [
['w'],
['w+'],
['rw'],
['r+'],
['x+'],
['c+'],
['wb'],
['w+b'],
['r+b'],
['rb+'],
['x+b'],
['c+b'],
['w+t'],
['r+t'],
['x+t'],
['c+t'],
['a'],
['a+'],
];
}
public function testReadOnlyStreamIsNotWritable()
{
$r = fopen('php://input', 'r');
$stream = new Stream($r);
self::assertFalse($stream->isWritable());
$stream->close();
}
}
namespace GuzzleHttp\Psr7;
use GuzzleHttp\Tests\Psr7\StreamTest;
function fread($handle, $length)
{
return StreamTest::$isFReadError ? false : \fread($handle, $length);
}

View File

@ -0,0 +1,200 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\StreamWrapper;
/**
* @covers GuzzleHttp\Psr7\StreamWrapper
*/
class StreamWrapperTest extends BaseTest
{
public function testResource()
{
$stream = Psr7\Utils::streamFor('foo');
$handle = StreamWrapper::getResource($stream);
self::assertSame('foo', fread($handle, 3));
self::assertSame(3, ftell($handle));
self::assertSame(3, fwrite($handle, 'bar'));
self::assertSame(0, fseek($handle, 0));
self::assertSame('foobar', fread($handle, 6));
self::assertSame('', fread($handle, 1));
self::assertTrue(feof($handle));
$stBlksize = defined('PHP_WINDOWS_VERSION_BUILD') ? -1 : 0;
// This fails on HHVM for some reason
if (!defined('HHVM_VERSION')) {
self::assertSame([
0 => 0,
1 => 0,
2 => 33206,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 6,
8 => 0,
9 => 0,
10 => 0,
11 => $stBlksize,
12 => $stBlksize,
'dev' => 0,
'ino' => 0,
'mode' => 33206,
'nlink' => 0,
'uid' => 0,
'gid' => 0,
'rdev' => 0,
'size' => 6,
'atime' => 0,
'mtime' => 0,
'ctime' => 0,
'blksize' => $stBlksize,
'blocks' => $stBlksize,
], fstat($handle));
}
self::assertTrue(fclose($handle));
self::assertSame('foobar', (string) $stream);
}
public function testStreamContext()
{
$stream = Psr7\Utils::streamFor('foo');
self::assertSame('foo', file_get_contents('guzzle://stream', false, StreamWrapper::createStreamContext($stream)));
}
public function testStreamCast()
{
$streams = [
StreamWrapper::getResource(Psr7\Utils::streamFor('foo')),
StreamWrapper::getResource(Psr7\Utils::streamFor('bar'))
];
$write = null;
$except = null;
$this->assertInternalTypeGuzzle('integer', stream_select($streams, $write, $except, 0));
}
public function testValidatesStream()
{
$stream = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isReadable', 'isWritable'])
->getMockForAbstractClass();
$stream->expects(self::once())
->method('isReadable')
->will(self::returnValue(false));
$stream->expects(self::once())
->method('isWritable')
->will(self::returnValue(false));
$this->expectExceptionGuzzle('InvalidArgumentException');
StreamWrapper::getResource($stream);
}
public function testReturnsFalseWhenStreamDoesNotExist()
{
$this->expectWarningGuzzle();
fopen('guzzle://foo', 'r');
}
public function testCanOpenReadonlyStream()
{
$stream = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->setMethods(['isReadable', 'isWritable'])
->getMockForAbstractClass();
$stream->expects(self::once())
->method('isReadable')
->will(self::returnValue(false));
$stream->expects(self::once())
->method('isWritable')
->will(self::returnValue(true));
$r = StreamWrapper::getResource($stream);
$this->assertInternalTypeGuzzle('resource', $r);
fclose($r);
}
public function testUrlStat()
{
StreamWrapper::register();
$stBlksize = defined('PHP_WINDOWS_VERSION_BUILD') ? -1 : 0;
self::assertSame([
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 0,
9 => 0,
10 => 0,
11 => $stBlksize,
12 => $stBlksize,
'dev' => 0,
'ino' => 0,
'mode' => 0,
'nlink' => 0,
'uid' => 0,
'gid' => 0,
'rdev' => 0,
'size' => 0,
'atime' => 0,
'mtime' => 0,
'ctime' => 0,
'blksize' => $stBlksize,
'blocks' => $stBlksize,
], stat('guzzle://stream'));
}
public function testXmlReaderWithStream()
{
if (!class_exists('XMLReader')) {
self::markTestSkipped('XML Reader is not available.');
}
if (defined('HHVM_VERSION')) {
self::markTestSkipped('This does not work on HHVM.');
}
$stream = Psr7\Utils::streamFor('<?xml version="1.0" encoding="utf-8"?><foo />');
StreamWrapper::register();
libxml_set_streams_context(StreamWrapper::createStreamContext($stream));
$reader = new \XMLReader();
self::assertTrue($reader->open('guzzle://stream'));
self::assertTrue($reader->read());
self::assertSame('foo', $reader->name);
}
public function testXmlWriterWithStream()
{
if (!class_exists('XMLWriter')) {
self::markTestSkipped('XML Writer is not available.');
}
if (defined('HHVM_VERSION')) {
self::markTestSkipped('This does not work on HHVM.');
}
$stream = Psr7\Utils::streamFor(fopen('php://memory', 'wb'));
StreamWrapper::register();
libxml_set_streams_context(StreamWrapper::createStreamContext($stream));
$writer = new \XMLWriter();
self::assertTrue($writer->openURI('guzzle://stream'));
self::assertTrue($writer->startDocument());
self::assertTrue($writer->writeElement('foo'));
self::assertTrue($writer->endDocument());
$stream->rewind();
self::assertXmlStringEqualsXmlString('<?xml version="1.0"?><foo />', (string) $stream);
}
}

View File

@ -0,0 +1,287 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\Stream;
use GuzzleHttp\Psr7\UploadedFile;
use ReflectionProperty;
/**
* @covers GuzzleHttp\Psr7\UploadedFile
*/
class UploadedFileTest extends BaseTest
{
private $cleanup;
/**
* @before
*/
public function setUpTest()
{
$this->cleanup = [];
}
/**
* @after
*/
public function tearDownTest()
{
foreach ($this->cleanup as $file) {
if (is_scalar($file) && file_exists($file)) {
unlink($file);
}
}
}
public function invalidStreams()
{
return [
'null' => [null],
'true' => [true],
'false' => [false],
'int' => [1],
'float' => [1.1],
'array' => [['filename']],
'object' => [(object) ['filename']],
];
}
/**
* @dataProvider invalidStreams
*/
public function testRaisesExceptionOnInvalidStreamOrFile($streamOrFile)
{
$this->expectExceptionGuzzle('InvalidArgumentException');
new UploadedFile($streamOrFile, 0, UPLOAD_ERR_OK);
}
public function invalidSizes()
{
return [
'null' => [null],
'float' => [1.1],
'array' => [[1]],
'object' => [(object) [1]],
];
}
/**
* @dataProvider invalidSizes
*/
public function testRaisesExceptionOnInvalidSize($size)
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'size');
new UploadedFile(fopen('php://temp', 'wb+'), $size, UPLOAD_ERR_OK);
}
public function invalidErrorStatuses()
{
return [
'null' => [null],
'true' => [true],
'false' => [false],
'float' => [1.1],
'string' => ['1'],
'array' => [[1]],
'object' => [(object) [1]],
'negative' => [-1],
'too-big' => [9],
];
}
/**
* @dataProvider invalidErrorStatuses
*/
public function testRaisesExceptionOnInvalidErrorStatus($status)
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'status');
new UploadedFile(fopen('php://temp', 'wb+'), 0, $status);
}
public function invalidFilenamesAndMediaTypes()
{
return [
'true' => [true],
'false' => [false],
'int' => [1],
'float' => [1.1],
'array' => [['string']],
'object' => [(object) ['string']],
];
}
/**
* @dataProvider invalidFilenamesAndMediaTypes
*/
public function testRaisesExceptionOnInvalidClientFilename($filename)
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'filename');
new UploadedFile(fopen('php://temp', 'wb+'), 0, UPLOAD_ERR_OK, $filename);
}
/**
* @dataProvider invalidFilenamesAndMediaTypes
*/
public function testRaisesExceptionOnInvalidClientMediaType($mediaType)
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'media type');
new UploadedFile(fopen('php://temp', 'wb+'), 0, UPLOAD_ERR_OK, 'foobar.baz', $mediaType);
}
public function testGetStreamReturnsOriginalStreamObject()
{
$stream = new Stream(fopen('php://temp', 'r'));
$upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK);
self::assertSame($stream, $upload->getStream());
}
public function testGetStreamReturnsWrappedPhpStream()
{
$stream = fopen('php://temp', 'wb+');
$upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK);
$uploadStream = $upload->getStream()->detach();
self::assertSame($stream, $uploadStream);
}
public function testGetStreamReturnsStreamForFile()
{
$this->cleanup[] = $stream = tempnam(sys_get_temp_dir(), 'stream_file');
$upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK);
$uploadStream = $upload->getStream();
$r = new ReflectionProperty($uploadStream, 'filename');
$r->setAccessible(true);
self::assertSame($stream, $r->getValue($uploadStream));
}
public function testSuccessful()
{
$stream = \GuzzleHttp\Psr7\Utils::streamFor('Foo bar!');
$upload = new UploadedFile($stream, $stream->getSize(), UPLOAD_ERR_OK, 'filename.txt', 'text/plain');
self::assertSame($stream->getSize(), $upload->getSize());
self::assertSame('filename.txt', $upload->getClientFilename());
self::assertSame('text/plain', $upload->getClientMediaType());
$this->cleanup[] = $to = tempnam(sys_get_temp_dir(), 'successful');
$upload->moveTo($to);
self::assertFileExists($to);
self::assertSame($stream->__toString(), file_get_contents($to));
}
public function invalidMovePaths()
{
return [
'null' => [null],
'true' => [true],
'false' => [false],
'int' => [1],
'float' => [1.1],
'empty' => [''],
'array' => [['filename']],
'object' => [(object) ['filename']],
];
}
/**
* @dataProvider invalidMovePaths
*/
public function testMoveRaisesExceptionForInvalidPath($path)
{
$stream = \GuzzleHttp\Psr7\Utils::streamFor('Foo bar!');
$upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK);
$this->cleanup[] = $path;
$this->expectExceptionGuzzle('InvalidArgumentException', 'path');
$upload->moveTo($path);
}
public function testMoveCannotBeCalledMoreThanOnce()
{
$stream = \GuzzleHttp\Psr7\Utils::streamFor('Foo bar!');
$upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK);
$this->cleanup[] = $to = tempnam(sys_get_temp_dir(), 'diac');
$upload->moveTo($to);
self::assertFileExists($to);
$this->expectExceptionGuzzle('RuntimeException', 'moved');
$upload->moveTo($to);
}
public function testCannotRetrieveStreamAfterMove()
{
$stream = \GuzzleHttp\Psr7\Utils::streamFor('Foo bar!');
$upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK);
$this->cleanup[] = $to = tempnam(sys_get_temp_dir(), 'diac');
$upload->moveTo($to);
self::assertFileExists($to);
$this->expectExceptionGuzzle('RuntimeException', 'moved');
$upload->getStream();
}
public function nonOkErrorStatus()
{
return [
'UPLOAD_ERR_INI_SIZE' => [ UPLOAD_ERR_INI_SIZE ],
'UPLOAD_ERR_FORM_SIZE' => [ UPLOAD_ERR_FORM_SIZE ],
'UPLOAD_ERR_PARTIAL' => [ UPLOAD_ERR_PARTIAL ],
'UPLOAD_ERR_NO_FILE' => [ UPLOAD_ERR_NO_FILE ],
'UPLOAD_ERR_NO_TMP_DIR' => [ UPLOAD_ERR_NO_TMP_DIR ],
'UPLOAD_ERR_CANT_WRITE' => [ UPLOAD_ERR_CANT_WRITE ],
'UPLOAD_ERR_EXTENSION' => [ UPLOAD_ERR_EXTENSION ],
];
}
/**
* @dataProvider nonOkErrorStatus
*/
public function testConstructorDoesNotRaiseExceptionForInvalidStreamWhenErrorStatusPresent($status)
{
$uploadedFile = new UploadedFile('not ok', 0, $status);
self::assertSame($status, $uploadedFile->getError());
}
/**
* @dataProvider nonOkErrorStatus
*/
public function testMoveToRaisesExceptionWhenErrorStatusPresent($status)
{
$uploadedFile = new UploadedFile('not ok', 0, $status);
$this->expectExceptionGuzzle('RuntimeException', 'upload error');
$uploadedFile->moveTo(__DIR__ . '/' . sha1(uniqid('', true)));
}
/**
* @dataProvider nonOkErrorStatus
*/
public function testGetStreamRaisesExceptionWhenErrorStatusPresent($status)
{
$uploadedFile = new UploadedFile('not ok', 0, $status);
$this->expectExceptionGuzzle('RuntimeException', 'upload error');
$uploadedFile->getStream();
}
public function testMoveToCreatesStreamIfOnlyAFilenameWasProvided()
{
$this->cleanup[] = $from = tempnam(sys_get_temp_dir(), 'copy_from');
$this->cleanup[] = $to = tempnam(sys_get_temp_dir(), 'copy_to');
copy(__FILE__, $from);
$uploadedFile = new UploadedFile($from, 100, UPLOAD_ERR_OK, basename($from), 'text/plain');
$uploadedFile->moveTo($to);
self::assertFileEquals(__FILE__, $to);
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Psr7\UriComparator;
/**
* @covers GuzzleHttp\Psr7\UriComparator
*/
class UriComparatorTest extends BaseTest
{
/**
* @dataProvider getCrossOriginExamples
*/
public function testIsCrossOrigin($originalUri, $modifiedUri, $expected)
{
self::assertSame($expected, UriComparator::isCrossOrigin(new Uri($originalUri), new Uri($modifiedUri)));
}
public function getCrossOriginExamples()
{
return [
['http://example.com/123', 'http://example.com/', false],
['http://example.com/123', 'http://example.com:80/', false],
['http://example.com:80/123', 'http://example.com/', false],
['http://example.com:80/123', 'http://example.com:80/', false],
['http://example.com/123', 'https://example.com/', true],
['http://example.com/123', 'http://www.example.com/', true],
['http://example.com/123', 'http://example.com:81/', true],
['http://example.com:80/123', 'http://example.com:81/', true],
['https://example.com/123', 'https://example.com/', false],
['https://example.com/123', 'https://example.com:443/', false],
['https://example.com:443/123', 'https://example.com/', false],
['https://example.com:443/123', 'https://example.com:443/', false],
['https://example.com/123', 'http://example.com/', true],
['https://example.com/123', 'https://www.example.com/', true],
['https://example.com/123', 'https://example.com:444/', true],
['https://example.com:443/123', 'https://example.com:444/', true],
];
}
}

View File

@ -0,0 +1,176 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Psr7\UriNormalizer;
/**
* @covers GuzzleHttp\Psr7\UriNormalizer
*/
class UriNormalizerTest extends BaseTest
{
public function testCapitalizePercentEncoding()
{
$actualEncoding = 'a%c2%7A%5eb%25%fa%fA%Fa';
$expectEncoding = 'a%C2%7A%5Eb%25%FA%FA%FA';
$uri = (new Uri())->withPath("/$actualEncoding")->withQuery($actualEncoding);
self::assertSame("/$actualEncoding?$actualEncoding", (string) $uri, 'Not normalized automatically beforehand');
$normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::CAPITALIZE_PERCENT_ENCODING);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $normalizedUri);
self::assertSame("/$expectEncoding?$expectEncoding", (string) $normalizedUri);
}
/**
* @dataProvider getUnreservedCharacters
*/
public function testDecodeUnreservedCharacters($char)
{
$percentEncoded = '%' . bin2hex($char);
// Add encoded reserved characters to test that those are not decoded and include the percent-encoded
// unreserved character both in lower and upper case to test the decoding is case-insensitive.
$encodedChars = $percentEncoded . '%2F%5B' . strtoupper($percentEncoded);
$uri = (new Uri())->withPath("/$encodedChars")->withQuery($encodedChars);
self::assertSame("/$encodedChars?$encodedChars", (string) $uri, 'Not normalized automatically beforehand');
$normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::DECODE_UNRESERVED_CHARACTERS);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $normalizedUri);
self::assertSame("/$char%2F%5B$char?$char%2F%5B$char", (string) $normalizedUri);
}
public function getUnreservedCharacters()
{
$unreservedChars = array_merge(range('a', 'z'), range('A', 'Z'), range('0', '9'), ['-', '.', '_', '~']);
return array_map(function ($char) {
return [$char];
}, $unreservedChars);
}
/**
* @dataProvider getEmptyPathTestCases
*/
public function testConvertEmptyPath($uri, $expected)
{
$normalizedUri = UriNormalizer::normalize(new Uri($uri), UriNormalizer::CONVERT_EMPTY_PATH);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $normalizedUri);
self::assertSame($expected, (string) $normalizedUri);
}
public function getEmptyPathTestCases()
{
return [
['http://example.org', 'http://example.org/'],
['https://example.org', 'https://example.org/'],
['urn://example.org', 'urn://example.org'],
];
}
public function testRemoveDefaultHost()
{
$uri = new Uri('file://localhost/myfile');
$normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DEFAULT_HOST);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $normalizedUri);
self::assertSame('file:///myfile', (string) $normalizedUri);
}
public function testRemoveDefaultPort()
{
$uri = $this->getMockBuilder('Psr\Http\Message\UriInterface')->getMock();
$uri->expects(self::any())->method('getScheme')->will(self::returnValue('http'));
$uri->expects(self::any())->method('getPort')->will(self::returnValue(80));
$uri->expects(self::once())->method('withPort')->with(null)->will(self::returnValue(new Uri('http://example.org')));
$normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DEFAULT_PORT);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $normalizedUri);
self::assertNull($normalizedUri->getPort());
}
public function testRemoveDotSegments()
{
$uri = new Uri('http://example.org/../a/b/../c/./d.html');
$normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DOT_SEGMENTS);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $normalizedUri);
self::assertSame('http://example.org/a/c/d.html', (string) $normalizedUri);
}
public function testRemoveDotSegmentsOfAbsolutePathReference()
{
$uri = new Uri('/../a/b/../c/./d.html');
$normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DOT_SEGMENTS);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $normalizedUri);
self::assertSame('/a/c/d.html', (string) $normalizedUri);
}
public function testRemoveDotSegmentsOfRelativePathReference()
{
$uri = new Uri('../c/./d.html');
$normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DOT_SEGMENTS);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $normalizedUri);
self::assertSame('../c/./d.html', (string) $normalizedUri);
}
public function testRemoveDuplicateSlashes()
{
$uri = new Uri('http://example.org//foo///bar/bam.html');
$normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DUPLICATE_SLASHES);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $normalizedUri);
self::assertSame('http://example.org/foo/bar/bam.html', (string) $normalizedUri);
}
public function testSortQueryParameters()
{
$uri = new Uri('?lang=en&article=fred');
$normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::SORT_QUERY_PARAMETERS);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $normalizedUri);
self::assertSame('?article=fred&lang=en', (string) $normalizedUri);
}
public function testSortQueryParametersWithSameKeys()
{
$uri = new Uri('?a=b&b=c&a=a&a&b=a&b=b&a=d&a=c');
$normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::SORT_QUERY_PARAMETERS);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $normalizedUri);
self::assertSame('?a&a=a&a=b&a=c&a=d&b=a&b=b&b=c', (string) $normalizedUri);
}
/**
* @dataProvider getEquivalentTestCases
*/
public function testIsEquivalent($uri1, $uri2, $expected)
{
$equivalent = UriNormalizer::isEquivalent(new Uri($uri1), new Uri($uri2));
self::assertSame($expected, $equivalent);
}
public function getEquivalentTestCases()
{
return [
['http://example.org', 'http://example.org', true],
['hTTp://eXaMpLe.org', 'http://example.org', true],
['http://example.org/path?#', 'http://example.org/path', true],
['http://example.org:80', 'http://example.org/', true],
['http://example.org/../a/.././p%61th?%7a=%5e', 'http://example.org/path?z=%5E', true],
['https://example.org/', 'http://example.org/', false],
['https://example.org/', '//example.org/', false],
['//example.org/', '//example.org/', true],
['file:/myfile', 'file:///myfile', true],
['file:///myfile', 'file://localhost/myfile', true],
];
}
}

View File

@ -0,0 +1,204 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Psr7\UriResolver;
/**
* @covers GuzzleHttp\Psr7\UriResolver
*/
class UriResolverTest extends BaseTest
{
const RFC3986_BASE = 'http://a/b/c/d;p?q';
/**
* @dataProvider getResolveTestCases
*/
public function testResolveUri($base, $rel, $expectedTarget)
{
$baseUri = new Uri($base);
$targetUri = UriResolver::resolve($baseUri, new Uri($rel));
self::assertInstanceOf('Psr\Http\Message\UriInterface', $targetUri);
self::assertSame($expectedTarget, (string) $targetUri);
// This ensures there are no test cases that only work in the resolve() direction but not the
// opposite via relativize(). This can happen when both base and rel URI are relative-path
// references resulting in another relative-path URI.
self::assertSame($expectedTarget, (string) UriResolver::resolve($baseUri, $targetUri));
}
/**
* @dataProvider getResolveTestCases
*/
public function testRelativizeUri($base, $expectedRelativeReference, $target)
{
$baseUri = new Uri($base);
$relativeUri = UriResolver::relativize($baseUri, new Uri($target));
self::assertInstanceOf('Psr\Http\Message\UriInterface', $relativeUri);
// There are test-cases with too many dot-segments and relative references that are equal like "." == "./".
// So apart from the same-as condition, this alternative success condition is necessary.
self::assertTrue(
$expectedRelativeReference === (string) $relativeUri
|| $target === (string) UriResolver::resolve($baseUri, $relativeUri),
sprintf(
'"%s" is not the correct relative reference as it does not resolve to the target URI from the base URI',
(string) $relativeUri
)
);
}
/**
* @dataProvider getRelativizeTestCases
*/
public function testRelativizeUriWithUniqueTests($base, $target, $expectedRelativeReference)
{
$baseUri = new Uri($base);
$targetUri = new Uri($target);
$relativeUri = UriResolver::relativize($baseUri, $targetUri);
self::assertInstanceOf('Psr\Http\Message\UriInterface', $relativeUri);
self::assertSame($expectedRelativeReference, (string) $relativeUri);
self::assertSame((string) UriResolver::resolve($baseUri, $targetUri), (string) UriResolver::resolve($baseUri, $relativeUri));
}
public function getResolveTestCases()
{
return [
[self::RFC3986_BASE, 'g:h', 'g:h'],
[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, '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'],
// 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'],
['urn:no-slash', 'e', 'urn: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'],
// absolute path base URI
['/a/b/', '', '/a/b/'],
['/a/b', '', '/a/b'],
['/', 'a', '/a'],
['/', 'a/b', '/a/b'],
['/a/b', 'g', '/a/g'],
['/a/b/c', './', '/a/b/'],
['/a/b/', '../', '/a/'],
['/a/b/c', '../', '/a/'],
['/a/b/', '../../x/y/z/', '/x/y/z/'],
['/a/b/c/d/e', '../../../c/d', '/a/c/d'],
['/a/b/c//', '../', '/a/b/c/'],
['/a/b/c/', './/', '/a/b/c//'],
['/a/b/c', '../../../../a', '/a'],
['/a/b/c', '../../../..', '/'],
// not actually a dot-segment
['/a/b/c', '..a/b..', '/a/b/..a/b..'],
// '' cannot be used as relative reference as it would inherit the base query component
['/a/b?q', 'b', '/a/b'],
['/a/b/?q', './', '/a/b/'],
// path with colon: "with:colon" would be the wrong relative reference
['/a/', './with:colon', '/a/with:colon'],
['/a/', 'b/with:colon', '/a/b/with:colon'],
['/a/', './:b/', '/a/:b/'],
// relative path references
['a', 'a/b', 'a/b'],
['', '', ''],
['', '..', ''],
['/', '..', '/'],
['urn:a/b', '..//a/b', 'urn:/a/b'],
// network path references
// empty base path and relative-path reference
['//example.com', 'a', '//example.com/a'],
// path starting with two slashes
['//example.com//two-slashes', './', '//example.com//'],
['//example.com', './/', '//example.com//'],
['//example.com/', './/', '//example.com//'],
// base URI has less components than relative URI
['/', '//a/b?q#h', '//a/b?q#h'],
['/', 'urn:/', 'urn:/'],
];
}
/**
* Some additional tests to getResolveTestCases() that only make sense for relativize.
*/
public function getRelativizeTestCases()
{
return [
// targets that are relative-path references are returned as-is
['a/b', 'b/c', 'b/c'],
['a/b/c', '../b/c', '../b/c'],
['a', '', ''],
['a', './', './'],
['a', 'a/..', 'a/..'],
['/a/b/?q', '?q#h', '?q#h'],
['/a/b/?q', '#h', '#h'],
['/a/b/?q', 'c#h', 'c#h'],
// If the base URI has a query but the target has none, we cannot return an empty path reference as it would
// inherit the base query component when resolving.
['/a/b/?q', '/a/b/#h', './#h'],
['/', '/#h', '#h'],
['/', '/', ''],
['http://a', 'http://a/', './'],
['urn:a/b?q', 'urn:x/y?q', '../x/y?q'],
['urn:', 'urn:/', './/'],
['urn:a/b?q', 'urn:', '../'],
// target URI has less components than base URI
['http://a/b/', '//a/b/c', 'c'],
['http://a/b/', '/b/c', 'c'],
['http://a/b/', '/x/y', '../x/y'],
['http://a/b/', '/', '../'],
// absolute target URI without authority but base URI has one
['urn://a/b/', 'urn:/b/', 'urn:/b/'],
];
}
}

View File

@ -0,0 +1,710 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\Uri;
/**
* @covers GuzzleHttp\Psr7\Uri
*/
class UriTest extends BaseTest
{
public function testParsesProvidedUri()
{
$uri = new Uri('https://user:pass@example.com:8080/path/123?q=abc#test');
self::assertSame('https', $uri->getScheme());
self::assertSame('user:pass@example.com:8080', $uri->getAuthority());
self::assertSame('user:pass', $uri->getUserInfo());
self::assertSame('example.com', $uri->getHost());
self::assertSame(8080, $uri->getPort());
self::assertSame('/path/123', $uri->getPath());
self::assertSame('q=abc', $uri->getQuery());
self::assertSame('test', $uri->getFragment());
self::assertSame('https://user:pass@example.com:8080/path/123?q=abc#test', (string) $uri);
}
public function testCanTransformAndRetrievePartsIndividually()
{
$uri = (new Uri())
->withScheme('https')
->withUserInfo('user', 'pass')
->withHost('example.com')
->withPort(8080)
->withPath('/path/123')
->withQuery('q=abc')
->withFragment('test');
self::assertSame('https', $uri->getScheme());
self::assertSame('user:pass@example.com:8080', $uri->getAuthority());
self::assertSame('user:pass', $uri->getUserInfo());
self::assertSame('example.com', $uri->getHost());
self::assertSame(8080, $uri->getPort());
self::assertSame('/path/123', $uri->getPath());
self::assertSame('q=abc', $uri->getQuery());
self::assertSame('test', $uri->getFragment());
self::assertSame('https://user:pass@example.com:8080/path/123?q=abc#test', (string) $uri);
}
/**
* @dataProvider getValidUris
*/
public function testValidUrisStayValid($input)
{
$uri = new Uri($input);
self::assertSame($input, (string) $uri);
}
/**
* @dataProvider getValidUris
*/
public function testFromParts($input)
{
$uri = Uri::fromParts(parse_url($input));
self::assertSame($input, (string) $uri);
}
public function getValidUris()
{
return [
['urn:path-rootless'],
['urn:path:with:colon'],
['urn:/path-absolute'],
['urn:/'],
// only scheme with empty path
['urn:'],
// only path
['/'],
['relative/'],
['0'],
// same document reference
[''],
// network path without scheme
['//example.org'],
['//example.org/'],
['//example.org?q#h'],
// only query
['?q'],
['?q=abc&foo=bar'],
// only fragment
['#fragment'],
// dot segments are not removed automatically
['./foo/../bar'],
];
}
/**
* @dataProvider getInvalidUris
*/
public function testInvalidUrisThrowException($invalidUri)
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'Unable to parse URI');
new Uri($invalidUri);
}
public function getInvalidUris()
{
return [
// parse_url() requires the host component which makes sense for http(s)
// but not when the scheme is not known or different. So '//' or '///' is
// currently invalid as well but should not according to RFC 3986.
['http://'],
['urn://host:with:colon'], // host cannot contain ":"
];
}
public function testPortMustBeValid()
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'Must be between 0 and 65535');
(new Uri())->withPort(100000);
}
public function testWithPortCannotBeNegative()
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'Invalid port: -1. Must be between 0 and 65535');
(new Uri())->withPort(-1);
}
public function testParseUriPortCannotBeNegative()
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'Unable to parse URI');
new Uri('//example.com:-1');
}
public function testSchemeMustHaveCorrectType()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
(new Uri())->withScheme([]);
}
public function testHostMustHaveCorrectType()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
(new Uri())->withHost([]);
}
public function testPathMustHaveCorrectType()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
(new Uri())->withPath([]);
}
public function testQueryMustHaveCorrectType()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
(new Uri())->withQuery([]);
}
public function testFragmentMustHaveCorrectType()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
(new Uri())->withFragment([]);
}
public function testCanParseFalseyUriParts()
{
$uri = new Uri('0://0:0@0/0?0#0');
self::assertSame('0', $uri->getScheme());
self::assertSame('0:0@0', $uri->getAuthority());
self::assertSame('0:0', $uri->getUserInfo());
self::assertSame('0', $uri->getHost());
self::assertSame('/0', $uri->getPath());
self::assertSame('0', $uri->getQuery());
self::assertSame('0', $uri->getFragment());
self::assertSame('0://0:0@0/0?0#0', (string) $uri);
}
public function testCanConstructFalseyUriParts()
{
$uri = (new Uri())
->withScheme('0')
->withUserInfo('0', '0')
->withHost('0')
->withPath('/0')
->withQuery('0')
->withFragment('0');
self::assertSame('0', $uri->getScheme());
self::assertSame('0:0@0', $uri->getAuthority());
self::assertSame('0:0', $uri->getUserInfo());
self::assertSame('0', $uri->getHost());
self::assertSame('/0', $uri->getPath());
self::assertSame('0', $uri->getQuery());
self::assertSame('0', $uri->getFragment());
self::assertSame('0://0:0@0/0?0#0', (string) $uri);
}
/**
* @dataProvider getPortTestCases
*/
public function testIsDefaultPort($scheme, $port, $isDefaultPort)
{
$uri = $this->getMockBuilder('Psr\Http\Message\UriInterface')->getMock();
$uri->expects(self::any())->method('getScheme')->will(self::returnValue($scheme));
$uri->expects(self::any())->method('getPort')->will(self::returnValue($port));
self::assertSame($isDefaultPort, Uri::isDefaultPort($uri));
}
public function getPortTestCases()
{
return [
['http', null, true],
['http', 80, true],
['http', 8080, false],
['https', null, true],
['https', 443, true],
['https', 444, false],
['ftp', 21, true],
['gopher', 70, true],
['nntp', 119, true],
['news', 119, true],
['telnet', 23, true],
['tn3270', 23, true],
['imap', 143, true],
['pop', 110, true],
['ldap', 389, true],
];
}
public function testIsAbsolute()
{
self::assertTrue(Uri::isAbsolute(new Uri('http://example.org')));
self::assertFalse(Uri::isAbsolute(new Uri('//example.org')));
self::assertFalse(Uri::isAbsolute(new Uri('/abs-path')));
self::assertFalse(Uri::isAbsolute(new Uri('rel-path')));
}
public function testIsNetworkPathReference()
{
self::assertFalse(Uri::isNetworkPathReference(new Uri('http://example.org')));
self::assertTrue(Uri::isNetworkPathReference(new Uri('//example.org')));
self::assertFalse(Uri::isNetworkPathReference(new Uri('/abs-path')));
self::assertFalse(Uri::isNetworkPathReference(new Uri('rel-path')));
}
public function testIsAbsolutePathReference()
{
self::assertFalse(Uri::isAbsolutePathReference(new Uri('http://example.org')));
self::assertFalse(Uri::isAbsolutePathReference(new Uri('//example.org')));
self::assertTrue(Uri::isAbsolutePathReference(new Uri('/abs-path')));
self::assertTrue(Uri::isAbsolutePathReference(new Uri('/')));
self::assertFalse(Uri::isAbsolutePathReference(new Uri('rel-path')));
}
public function testIsRelativePathReference()
{
self::assertFalse(Uri::isRelativePathReference(new Uri('http://example.org')));
self::assertFalse(Uri::isRelativePathReference(new Uri('//example.org')));
self::assertFalse(Uri::isRelativePathReference(new Uri('/abs-path')));
self::assertTrue(Uri::isRelativePathReference(new Uri('rel-path')));
self::assertTrue(Uri::isRelativePathReference(new Uri('')));
}
public function testIsSameDocumentReference()
{
self::assertFalse(Uri::isSameDocumentReference(new Uri('http://example.org')));
self::assertFalse(Uri::isSameDocumentReference(new Uri('//example.org')));
self::assertFalse(Uri::isSameDocumentReference(new Uri('/abs-path')));
self::assertFalse(Uri::isSameDocumentReference(new Uri('rel-path')));
self::assertFalse(Uri::isSameDocumentReference(new Uri('?query')));
self::assertTrue(Uri::isSameDocumentReference(new Uri('')));
self::assertTrue(Uri::isSameDocumentReference(new Uri('#fragment')));
$baseUri = new Uri('http://example.org/path?foo=bar');
self::assertTrue(Uri::isSameDocumentReference(new Uri('#fragment'), $baseUri));
self::assertTrue(Uri::isSameDocumentReference(new Uri('?foo=bar#fragment'), $baseUri));
self::assertTrue(Uri::isSameDocumentReference(new Uri('/path?foo=bar#fragment'), $baseUri));
self::assertTrue(Uri::isSameDocumentReference(new Uri('path?foo=bar#fragment'), $baseUri));
self::assertTrue(Uri::isSameDocumentReference(new Uri('//example.org/path?foo=bar#fragment'), $baseUri));
self::assertTrue(Uri::isSameDocumentReference(new Uri('http://example.org/path?foo=bar#fragment'), $baseUri));
self::assertFalse(Uri::isSameDocumentReference(new Uri('https://example.org/path?foo=bar'), $baseUri));
self::assertFalse(Uri::isSameDocumentReference(new Uri('http://example.com/path?foo=bar'), $baseUri));
self::assertFalse(Uri::isSameDocumentReference(new Uri('http://example.org/'), $baseUri));
self::assertFalse(Uri::isSameDocumentReference(new Uri('http://example.org'), $baseUri));
self::assertFalse(Uri::isSameDocumentReference(new Uri('urn:/path'), new Uri('urn://example.com/path')));
}
public function testAddAndRemoveQueryValues()
{
$uri = new Uri();
$uri = Uri::withQueryValue($uri, 'a', 'b');
$uri = Uri::withQueryValue($uri, 'c', 'd');
$uri = Uri::withQueryValue($uri, 'e', null);
self::assertSame('a=b&c=d&e', $uri->getQuery());
$uri = Uri::withoutQueryValue($uri, 'c');
self::assertSame('a=b&e', $uri->getQuery());
$uri = Uri::withoutQueryValue($uri, 'e');
self::assertSame('a=b', $uri->getQuery());
$uri = Uri::withoutQueryValue($uri, 'a');
self::assertSame('', $uri->getQuery());
}
public function testNumericQueryValue()
{
$uri = Uri::withQueryValue(new Uri(), 'version', 1);
self::assertSame('version=1', $uri->getQuery());
}
public function testWithQueryValues()
{
$uri = new Uri();
$uri = Uri::withQueryValues($uri, [
'key1' => 'value1',
'key2' => 'value2'
]);
self::assertSame('key1=value1&key2=value2', $uri->getQuery());
}
public function testWithQueryValuesReplacesSameKeys()
{
$uri = new Uri();
$uri = Uri::withQueryValues($uri, [
'key1' => 'value1',
'key2' => 'value2'
]);
$uri = Uri::withQueryValues($uri, [
'key2' => 'newvalue'
]);
self::assertSame('key1=value1&key2=newvalue', $uri->getQuery());
}
public function testWithQueryValueReplacesSameKeys()
{
$uri = new Uri();
$uri = Uri::withQueryValue($uri, 'a', 'b');
$uri = Uri::withQueryValue($uri, 'c', 'd');
$uri = Uri::withQueryValue($uri, 'a', 'e');
self::assertSame('c=d&a=e', $uri->getQuery());
}
public function testWithoutQueryValueRemovesAllSameKeys()
{
$uri = (new Uri())->withQuery('a=b&c=d&a=e');
$uri = Uri::withoutQueryValue($uri, 'a');
self::assertSame('c=d', $uri->getQuery());
}
public function testRemoveNonExistingQueryValue()
{
$uri = new Uri();
$uri = Uri::withQueryValue($uri, 'a', 'b');
$uri = Uri::withoutQueryValue($uri, 'c');
self::assertSame('a=b', $uri->getQuery());
}
public function testWithQueryValueHandlesEncoding()
{
$uri = new Uri();
$uri = Uri::withQueryValue($uri, 'E=mc^2', 'ein&stein');
self::assertSame('E%3Dmc%5E2=ein%26stein', $uri->getQuery(), 'Decoded key/value get encoded');
$uri = new Uri();
$uri = Uri::withQueryValue($uri, 'E%3Dmc%5e2', 'ein%26stein');
self::assertSame('E%3Dmc%5e2=ein%26stein', $uri->getQuery(), 'Encoded key/value do not get double-encoded');
}
public function testWithoutQueryValueHandlesEncoding()
{
// It also tests that the case of the percent-encoding does not matter,
// i.e. both lowercase "%3d" and uppercase "%5E" can be removed.
$uri = (new Uri())->withQuery('E%3dmc%5E2=einstein&foo=bar');
$uri = Uri::withoutQueryValue($uri, 'E=mc^2');
self::assertSame('foo=bar', $uri->getQuery(), 'Handles key in decoded form');
$uri = (new Uri())->withQuery('E%3dmc%5E2=einstein&foo=bar');
$uri = Uri::withoutQueryValue($uri, 'E%3Dmc%5e2');
self::assertSame('foo=bar', $uri->getQuery(), 'Handles key in encoded form');
}
public function testSchemeIsNormalizedToLowercase()
{
$uri = new Uri('HTTP://example.com');
self::assertSame('http', $uri->getScheme());
self::assertSame('http://example.com', (string) $uri);
$uri = (new Uri('//example.com'))->withScheme('HTTP');
self::assertSame('http', $uri->getScheme());
self::assertSame('http://example.com', (string) $uri);
}
public function testHostIsNormalizedToLowercase()
{
$uri = new Uri('//eXaMpLe.CoM');
self::assertSame('example.com', $uri->getHost());
self::assertSame('//example.com', (string) $uri);
$uri = (new Uri())->withHost('eXaMpLe.CoM');
self::assertSame('example.com', $uri->getHost());
self::assertSame('//example.com', (string) $uri);
}
public function testPortIsNullIfStandardPortForScheme()
{
// HTTPS standard port
$uri = new Uri('https://example.com:443');
self::assertNull($uri->getPort());
self::assertSame('example.com', $uri->getAuthority());
$uri = (new Uri('https://example.com'))->withPort(443);
self::assertNull($uri->getPort());
self::assertSame('example.com', $uri->getAuthority());
// HTTP standard port
$uri = new Uri('http://example.com:80');
self::assertNull($uri->getPort());
self::assertSame('example.com', $uri->getAuthority());
$uri = (new Uri('http://example.com'))->withPort(80);
self::assertNull($uri->getPort());
self::assertSame('example.com', $uri->getAuthority());
}
public function testPortIsReturnedIfSchemeUnknown()
{
$uri = (new Uri('//example.com'))->withPort(80);
self::assertSame(80, $uri->getPort());
self::assertSame('example.com:80', $uri->getAuthority());
}
public function testStandardPortIsNullIfSchemeChanges()
{
$uri = new Uri('http://example.com:443');
self::assertSame('http', $uri->getScheme());
self::assertSame(443, $uri->getPort());
$uri = $uri->withScheme('https');
self::assertNull($uri->getPort());
}
public function testPortPassedAsStringIsCastedToInt()
{
$uri = (new Uri('//example.com'))->withPort('8080');
self::assertSame(8080, $uri->getPort(), 'Port is returned as integer');
self::assertSame('example.com:8080', $uri->getAuthority());
}
public function testPortCanBeRemoved()
{
$uri = (new Uri('http://example.com:8080'))->withPort(null);
self::assertNull($uri->getPort());
self::assertSame('http://example.com', (string) $uri);
}
/**
* In RFC 8986 the host is optional and the authority can only
* consist of the user info and port.
*/
public function testAuthorityWithUserInfoOrPortButWithoutHost()
{
$uri = (new Uri())->withUserInfo('user', 'pass');
self::assertSame('user:pass', $uri->getUserInfo());
self::assertSame('user:pass@', $uri->getAuthority());
$uri = $uri->withPort(8080);
self::assertSame(8080, $uri->getPort());
self::assertSame('user:pass@:8080', $uri->getAuthority());
self::assertSame('//user:pass@:8080', (string) $uri);
$uri = $uri->withUserInfo('');
self::assertSame(':8080', $uri->getAuthority());
}
public function testHostInHttpUriDefaultsToLocalhost()
{
$uri = (new Uri())->withScheme('http');
self::assertSame('localhost', $uri->getHost());
self::assertSame('localhost', $uri->getAuthority());
self::assertSame('http://localhost', (string) $uri);
}
public function testHostInHttpsUriDefaultsToLocalhost()
{
$uri = (new Uri())->withScheme('https');
self::assertSame('localhost', $uri->getHost());
self::assertSame('localhost', $uri->getAuthority());
self::assertSame('https://localhost', (string) $uri);
}
public function testFileSchemeWithEmptyHostReconstruction()
{
$uri = new Uri('file:///tmp/filename.ext');
self::assertSame('', $uri->getHost());
self::assertSame('', $uri->getAuthority());
self::assertSame('file:///tmp/filename.ext', (string) $uri);
}
public function uriComponentsEncodingProvider()
{
$unreserved = 'a-zA-Z0-9.-_~!$&\'()*+,;=:@';
return [
// Percent encode spaces
['/pa th?q=va lue#frag ment', '/pa%20th', 'q=va%20lue', 'frag%20ment', '/pa%20th?q=va%20lue#frag%20ment'],
// Percent encode multibyte
['/€?€#€', '/%E2%82%AC', '%E2%82%AC', '%E2%82%AC', '/%E2%82%AC?%E2%82%AC#%E2%82%AC'],
// Don't encode something that's already encoded
['/pa%20th?q=va%20lue#frag%20ment', '/pa%20th', 'q=va%20lue', 'frag%20ment', '/pa%20th?q=va%20lue#frag%20ment'],
// Percent encode invalid percent encodings
['/pa%2-th?q=va%2-lue#frag%2-ment', '/pa%252-th', 'q=va%252-lue', 'frag%252-ment', '/pa%252-th?q=va%252-lue#frag%252-ment'],
// Don't encode path segments
['/pa/th//two?q=va/lue#frag/ment', '/pa/th//two', 'q=va/lue', 'frag/ment', '/pa/th//two?q=va/lue#frag/ment'],
// Don't encode unreserved chars or sub-delimiters
["/$unreserved?$unreserved#$unreserved", "/$unreserved", $unreserved, $unreserved, "/$unreserved?$unreserved#$unreserved"],
// Encoded unreserved chars are not decoded
['/p%61th?q=v%61lue#fr%61gment', '/p%61th', 'q=v%61lue', 'fr%61gment', '/p%61th?q=v%61lue#fr%61gment'],
];
}
/**
* @dataProvider uriComponentsEncodingProvider
*/
public function testUriComponentsGetEncodedProperly($input, $path, $query, $fragment, $output)
{
$uri = new Uri($input);
self::assertSame($path, $uri->getPath());
self::assertSame($query, $uri->getQuery());
self::assertSame($fragment, $uri->getFragment());
self::assertSame($output, (string) $uri);
}
public function testWithPathEncodesProperly()
{
$uri = (new Uri())->withPath('/baz?#€/b%61r');
// Query and fragment delimiters and multibyte chars are encoded.
self::assertSame('/baz%3F%23%E2%82%AC/b%61r', $uri->getPath());
self::assertSame('/baz%3F%23%E2%82%AC/b%61r', (string) $uri);
}
public function testWithQueryEncodesProperly()
{
$uri = (new Uri())->withQuery('?=#&€=/&b%61r');
// A query starting with a "?" is valid and must not be magically removed. Otherwise it would be impossible to
// construct such an URI. Also the "?" and "/" does not need to be encoded in the query.
self::assertSame('?=%23&%E2%82%AC=/&b%61r', $uri->getQuery());
self::assertSame('??=%23&%E2%82%AC=/&b%61r', (string) $uri);
}
public function testWithFragmentEncodesProperly()
{
$uri = (new Uri())->withFragment('#€?/b%61r');
// A fragment starting with a "#" is valid and must not be magically removed. Otherwise it would be impossible to
// construct such an URI. Also the "?" and "/" does not need to be encoded in the fragment.
self::assertSame('%23%E2%82%AC?/b%61r', $uri->getFragment());
self::assertSame('#%23%E2%82%AC?/b%61r', (string) $uri);
}
public function testAllowsForRelativeUri()
{
$uri = (new Uri)->withPath('foo');
self::assertSame('foo', $uri->getPath());
self::assertSame('foo', (string) $uri);
}
public function testRelativePathAndAuhorityIsAutomagicallyFixed()
{
// concatenating a relative path with a host doesn't work: "//example.comfoo" would be wrong
$uri = (new Uri)->withPath('foo')->withHost('example.com');
self::assertSame('/foo', $uri->getPath());
self::assertSame('//example.com/foo', (string) $uri);
}
public function testPathStartingWithTwoSlashesAndNoAuthorityIsInvalid()
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'The path of a URI without an authority must not start with two slashes "//"');
// URI "//foo" would be interpreted as network reference and thus change the original path to the host
(new Uri)->withPath('//foo');
}
public function testPathStartingWithTwoSlashes()
{
$uri = new Uri('http://example.org//path-not-host.com');
self::assertSame('//path-not-host.com', $uri->getPath());
$uri = $uri->withScheme('');
self::assertSame('//example.org//path-not-host.com', (string) $uri); // This is still valid
$this->expectExceptionGuzzle('\InvalidArgumentException');
$uri->withHost(''); // Now it becomes invalid
}
public function testRelativeUriWithPathBeginngWithColonSegmentIsInvalid()
{
$this->expectExceptionGuzzle('InvalidArgumentException', 'A relative URI must not have a path beginning with a segment containing a colon');
(new Uri)->withPath('mailto:foo');
}
public function testRelativeUriWithPathHavingColonSegment()
{
$uri = (new Uri('urn:/mailto:foo'))->withScheme('');
self::assertSame('/mailto:foo', $uri->getPath());
$this->expectExceptionGuzzle('\InvalidArgumentException');
(new Uri('urn:mailto:foo'))->withScheme('');
}
public function testDefaultReturnValuesOfGetters()
{
$uri = new Uri();
self::assertSame('', $uri->getScheme());
self::assertSame('', $uri->getAuthority());
self::assertSame('', $uri->getUserInfo());
self::assertSame('', $uri->getHost());
self::assertNull($uri->getPort());
self::assertSame('', $uri->getPath());
self::assertSame('', $uri->getQuery());
self::assertSame('', $uri->getFragment());
}
public function testImmutability()
{
$uri = new Uri();
self::assertNotSame($uri, $uri->withScheme('https'));
self::assertNotSame($uri, $uri->withUserInfo('user', 'pass'));
self::assertNotSame($uri, $uri->withHost('example.com'));
self::assertNotSame($uri, $uri->withPort(8080));
self::assertNotSame($uri, $uri->withPath('/path/123'));
self::assertNotSame($uri, $uri->withQuery('q=abc'));
self::assertNotSame($uri, $uri->withFragment('test'));
}
public function testExtendingClassesInstantiates()
{
// The non-standard port triggers a cascade of private methods which
// should not use late static binding to access private static members.
// If they do, this will fatal.
self::assertInstanceOf(
'GuzzleHttp\Tests\Psr7\ExtendedUriTest',
new ExtendedUriTest('http://h:9/')
);
}
public function testSpecialCharsOfUserInfo()
{
// The `userInfo` must always be URL-encoded.
$uri = (new Uri)->withUserInfo('foo@bar.com', 'pass#word');
self::assertSame('foo%40bar.com:pass%23word', $uri->getUserInfo());
// The `userInfo` can already be URL-encoded: it should not be encoded twice.
$uri = (new Uri)->withUserInfo('foo%40bar.com', 'pass%23word');
self::assertSame('foo%40bar.com:pass%23word', $uri->getUserInfo());
}
public function testInternationalizedDomainName()
{
$uri = new Uri('https://яндекс.рф');
self::assertSame('яндекс.рф', $uri->getHost());
$uri = new Uri('https://яндекAс.рф');
self::assertSame('яндекaс.рф', $uri->getHost());
}
public function testIPv6Host()
{
$uri = new Uri('https://[2a00:f48:1008::212:183:10]');
self::assertSame('[2a00:f48:1008::212:183:10]', $uri->getHost());
$uri = new Uri('http://[2a00:f48:1008::212:183:10]:56?foo=bar');
self::assertSame('[2a00:f48:1008::212:183:10]', $uri->getHost());
self::assertSame(56, $uri->getPort());
self::assertSame('foo=bar', $uri->getQuery());
}
}
class ExtendedUriTest extends Uri
{
}

View File

@ -0,0 +1,469 @@
<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\FnStream;
use GuzzleHttp\Psr7\NoSeekStream;
class UtilsTest extends BaseTest
{
public function testCopiesToString()
{
$s = Psr7\Utils::streamFor('foobaz');
self::assertSame('foobaz', Psr7\Utils::copyToString($s));
$s->seek(0);
self::assertSame('foo', Psr7\Utils::copyToString($s, 3));
self::assertSame('baz', Psr7\Utils::copyToString($s, 3));
self::assertSame('', Psr7\Utils::copyToString($s));
}
public function testCopiesToStringStopsWhenReadFails()
{
$s1 = Psr7\Utils::streamFor('foobaz');
$s1 = FnStream::decorate($s1, [
'read' => function () {
return '';
},
]);
$result = Psr7\Utils::copyToString($s1);
self::assertSame('', $result);
}
public function testCopiesToStream()
{
$s1 = Psr7\Utils::streamFor('foobaz');
$s2 = Psr7\Utils::streamFor('');
Psr7\Utils::copyToStream($s1, $s2);
self::assertSame('foobaz', (string)$s2);
$s2 = Psr7\Utils::streamFor('');
$s1->seek(0);
Psr7\Utils::copyToStream($s1, $s2, 3);
self::assertSame('foo', (string)$s2);
Psr7\Utils::copyToStream($s1, $s2, 3);
self::assertSame('foobaz', (string)$s2);
}
public function testStopsCopyToStreamWhenWriteFails()
{
$s1 = Psr7\Utils::streamFor('foobaz');
$s2 = Psr7\Utils::streamFor('');
$s2 = FnStream::decorate($s2, [
'write' => function () {
return 0;
},
]);
Psr7\Utils::copyToStream($s1, $s2);
self::assertSame('', (string)$s2);
}
public function testStopsCopyToSteamWhenWriteFailsWithMaxLen()
{
$s1 = Psr7\Utils::streamFor('foobaz');
$s2 = Psr7\Utils::streamFor('');
$s2 = FnStream::decorate($s2, [
'write' => function () {
return 0;
},
]);
Psr7\Utils::copyToStream($s1, $s2, 10);
self::assertSame('', (string)$s2);
}
public function testCopyToStreamReadsInChunksInsteadOfAllInMemory()
{
$sizes = [];
$s1 = new Psr7\FnStream([
'eof' => function () {
return false;
},
'read' => function ($size) use (&$sizes) {
$sizes[] = $size;
return str_repeat('.', $size);
},
]);
$s2 = Psr7\Utils::streamFor('');
Psr7\Utils::copyToStream($s1, $s2, 16394);
$s2->seek(0);
self::assertSame(16394, strlen($s2->getContents()));
self::assertSame(8192, $sizes[0]);
self::assertSame(8192, $sizes[1]);
self::assertSame(10, $sizes[2]);
}
public function testStopsCopyToSteamWhenReadFailsWithMaxLen()
{
$s1 = Psr7\Utils::streamFor('foobaz');
$s1 = FnStream::decorate($s1, [
'read' => function () {
return '';
},
]);
$s2 = Psr7\Utils::streamFor('');
Psr7\Utils::copyToStream($s1, $s2, 10);
self::assertSame('', (string)$s2);
}
public function testReadsLines()
{
$s = Psr7\Utils::streamFor("foo\nbaz\nbar");
self::assertSame("foo\n", Psr7\Utils::readLine($s));
self::assertSame("baz\n", Psr7\Utils::readLine($s));
self::assertSame('bar', Psr7\Utils::readLine($s));
}
public function testReadsLinesUpToMaxLength()
{
$s = Psr7\Utils::streamFor("12345\n");
self::assertSame('123', Psr7\Utils::readLine($s, 4));
self::assertSame("45\n", Psr7\Utils::readLine($s));
}
public function testReadLinesEof()
{
// Should return empty string on EOF
$s = Psr7\Utils::streamFor("foo\nbar");
while (!$s->eof()) {
Psr7\Utils::readLine($s);
}
self::assertSame('', Psr7\Utils::readLine($s));
}
public function testReadsLineUntilFalseReturnedFromRead()
{
$s = $this->getMockBuilder('GuzzleHttp\Psr7\Stream')
->setMethods(['read', 'eof'])
->disableOriginalConstructor()
->getMock();
$s->expects(self::exactly(2))
->method('read')
->will(self::returnCallback(function () {
static $c = false;
if ($c) {
return false;
}
$c = true;
return 'h';
}));
$s->expects(self::exactly(2))
->method('eof')
->will(self::returnValue(false));
self::assertSame('h', Psr7\Utils::readLine($s));
}
public function testCalculatesHash()
{
$s = Psr7\Utils::streamFor('foobazbar');
self::assertSame(md5('foobazbar'), Psr7\Utils::hash($s, 'md5'));
}
public function testCalculatesHashThrowsWhenSeekFails()
{
$s = new NoSeekStream(Psr7\Utils::streamFor('foobazbar'));
$s->read(2);
$this->expectExceptionGuzzle('RuntimeException');
Psr7\Utils::hash($s, 'md5');
}
public function testCalculatesHashSeeksToOriginalPosition()
{
$s = Psr7\Utils::streamFor('foobazbar');
$s->seek(4);
self::assertSame(md5('foobazbar'), Psr7\Utils::hash($s, 'md5'));
self::assertSame(4, $s->tell());
}
public function testOpensFilesSuccessfully()
{
$r = Psr7\Utils::tryFopen(__FILE__, 'r');
$this->assertInternalTypeGuzzle('resource', $r);
fclose($r);
}
public function testThrowsExceptionNotWarning()
{
$this->expectExceptionGuzzle('RuntimeException', 'Unable to open "/path/to/does/not/exist" using mode "r"');
Psr7\Utils::tryFopen('/path/to/does/not/exist', 'r');
}
public function testThrowsExceptionNotValueError()
{
$this->expectExceptionGuzzle('RuntimeException', 'Unable to open "" using mode "r"');
Psr7\Utils::tryFopen('', 'r');
}
public function testCreatesUriForValue()
{
self::assertInstanceOf('GuzzleHttp\Psr7\Uri', Psr7\Utils::uriFor('/foo'));
self::assertInstanceOf(
'GuzzleHttp\Psr7\Uri',
Psr7\Utils::uriFor(new Psr7\Uri('/foo'))
);
}
public function testValidatesUri()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
Psr7\Utils::uriFor([]);
}
public function testKeepsPositionOfResource()
{
$h = fopen(__FILE__, 'r');
fseek($h, 10);
$stream = Psr7\Utils::streamFor($h);
self::assertSame(10, $stream->tell());
$stream->close();
}
public function testCreatesWithFactory()
{
$stream = Psr7\Utils::streamFor('foo');
self::assertInstanceOf('GuzzleHttp\Psr7\Stream', $stream);
self::assertSame('foo', $stream->getContents());
$stream->close();
}
public function testFactoryCreatesFromEmptyString()
{
$s = Psr7\Utils::streamFor();
self::assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
}
public function testFactoryCreatesFromNull()
{
$s = Psr7\Utils::streamFor(null);
self::assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
}
public function testFactoryCreatesFromResource()
{
$r = fopen(__FILE__, 'r');
$s = Psr7\Utils::streamFor($r);
self::assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
self::assertSame(file_get_contents(__FILE__), (string)$s);
}
public function testFactoryCreatesFromObjectWithToString()
{
$r = new HasToString();
$s = Psr7\Utils::streamFor($r);
self::assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
self::assertSame('foo', (string)$s);
}
public function testCreatePassesThrough()
{
$s = Psr7\Utils::streamFor('foo');
self::assertSame($s, Psr7\Utils::streamFor($s));
}
public function testThrowsExceptionForUnknown()
{
$this->expectExceptionGuzzle('InvalidArgumentException');
Psr7\Utils::streamFor(new \stdClass());
}
public function testReturnsCustomMetadata()
{
$s = Psr7\Utils::streamFor('foo', ['metadata' => ['hwm' => 3]]);
self::assertSame(3, $s->getMetadata('hwm'));
self::assertArrayHasKey('hwm', $s->getMetadata());
}
public function testCanSetSize()
{
$s = Psr7\Utils::streamFor('', ['size' => 10]);
self::assertSame(10, $s->getSize());
}
public function testCanCreateIteratorBasedStream()
{
$a = new \ArrayIterator(['foo', 'bar', '123']);
$p = Psr7\Utils::streamFor($a);
self::assertInstanceOf('GuzzleHttp\Psr7\PumpStream', $p);
self::assertSame('foo', $p->read(3));
self::assertFalse($p->eof());
self::assertSame('b', $p->read(1));
self::assertSame('a', $p->read(1));
self::assertSame('r12', $p->read(3));
self::assertFalse($p->eof());
self::assertSame('3', $p->getContents());
self::assertTrue($p->eof());
self::assertSame(9, $p->tell());
}
public function testConvertsRequestsToStrings()
{
$request = new Psr7\Request('PUT', 'http://foo.com/hi?123', [
'Baz' => 'bar',
'Qux' => 'ipsum',
], 'hello', '1.0');
self::assertSame(
"PUT /hi?123 HTTP/1.0\r\nHost: foo.com\r\nBaz: bar\r\nQux: ipsum\r\n\r\nhello",
Psr7\Message::toString($request)
);
}
public function testConvertsResponsesToStrings()
{
$response = new Psr7\Response(200, [
'Baz' => 'bar',
'Qux' => 'ipsum',
], 'hello', '1.0', 'FOO');
self::assertSame(
"HTTP/1.0 200 FOO\r\nBaz: bar\r\nQux: ipsum\r\n\r\nhello",
Psr7\Message::toString($response)
);
}
public function testCorrectlyRendersSetCookieHeadersToString()
{
$response = new Psr7\Response(200, [
'Set-Cookie' => ['bar','baz','qux']
], 'hello', '1.0', 'FOO');
self::assertSame(
"HTTP/1.0 200 FOO\r\nSet-Cookie: bar\r\nSet-Cookie: baz\r\nSet-Cookie: qux\r\n\r\nhello",
Psr7\Message::toString($response)
);
}
public function testCanModifyRequestWithUri()
{
$r1 = new Psr7\Request('GET', 'http://foo.com');
$r2 = Psr7\Utils::modifyRequest($r1, [
'uri' => new Psr7\Uri('http://www.foo.com'),
]);
self::assertSame('http://www.foo.com', (string)$r2->getUri());
self::assertSame('www.foo.com', (string)$r2->getHeaderLine('host'));
}
public function testCanModifyRequestWithUriAndPort()
{
$r1 = new Psr7\Request('GET', 'http://foo.com:8000');
$r2 = Psr7\Utils::modifyRequest($r1, [
'uri' => new Psr7\Uri('http://www.foo.com:8000'),
]);
self::assertSame('http://www.foo.com:8000', (string)$r2->getUri());
self::assertSame('www.foo.com:8000', (string)$r2->getHeaderLine('host'));
}
public function testCanModifyRequestWithCaseInsensitiveHeader()
{
$r1 = new Psr7\Request('GET', 'http://foo.com', ['User-Agent' => 'foo']);
$r2 = Psr7\Utils::modifyRequest($r1, ['set_headers' => ['User-agent' => 'bar']]);
self::assertSame('bar', $r2->getHeaderLine('User-Agent'));
self::assertSame('bar', $r2->getHeaderLine('User-agent'));
}
public function testReturnsAsIsWhenNoChanges()
{
$r1 = new Psr7\Request('GET', 'http://foo.com');
$r2 = Psr7\Utils::modifyRequest($r1, []);
self::assertInstanceOf('GuzzleHttp\Psr7\Request', $r2);
$r1 = new Psr7\ServerRequest('GET', 'http://foo.com');
$r2 = Psr7\Utils::modifyRequest($r1, []);
self::assertInstanceOf('Psr\Http\Message\ServerRequestInterface', $r2);
}
public function testReturnsUriAsIsWhenNoChanges()
{
$r1 = new Psr7\Request('GET', 'http://foo.com');
$r2 = Psr7\Utils::modifyRequest($r1, ['set_headers' => ['foo' => 'bar']]);
self::assertNotSame($r1, $r2);
self::assertSame('bar', $r2->getHeaderLine('foo'));
}
public function testRemovesHeadersFromMessage()
{
$r1 = new Psr7\Request('GET', 'http://foo.com', ['foo' => 'bar']);
$r2 = Psr7\Utils::modifyRequest($r1, ['remove_headers' => ['foo']]);
self::assertNotSame($r1, $r2);
self::assertFalse($r2->hasHeader('foo'));
}
public function testAddsQueryToUri()
{
$r1 = new Psr7\Request('GET', 'http://foo.com');
$r2 = Psr7\Utils::modifyRequest($r1, ['query' => 'foo=bar']);
self::assertNotSame($r1, $r2);
self::assertSame('foo=bar', $r2->getUri()->getQuery());
}
public function testModifyRequestKeepInstanceOfRequest()
{
$r1 = new Psr7\Request('GET', 'http://foo.com');
$r2 = Psr7\Utils::modifyRequest($r1, ['remove_headers' => ['non-existent']]);
self::assertInstanceOf('GuzzleHttp\Psr7\Request', $r2);
$r1 = new Psr7\ServerRequest('GET', 'http://foo.com');
$r2 = Psr7\Utils::modifyRequest($r1, ['remove_headers' => ['non-existent']]);
self::assertInstanceOf('Psr\Http\Message\ServerRequestInterface', $r2);
}
public function testModifyServerRequestWithUploadedFiles()
{
$request = new Psr7\ServerRequest('GET', 'http://example.com/bla');
$file = new Psr7\UploadedFile('Test', 100, \UPLOAD_ERR_OK);
$request = $request->withUploadedFiles([$file]);
/** @var Psr7\ServerRequest $modifiedRequest */
$modifiedRequest = Psr7\Utils::modifyRequest($request, ['set_headers' => ['foo' => 'bar']]);
self::assertCount(1, $modifiedRequest->getUploadedFiles());
$files = $modifiedRequest->getUploadedFiles();
self::assertInstanceOf('GuzzleHttp\Psr7\UploadedFile', $files[0]);
}
public function testModifyServerRequestWithCookies()
{
$request = (new Psr7\ServerRequest('GET', 'http://example.com/bla'))
->withCookieParams(['name' => 'value']);
/** @var Psr7\ServerRequest $modifiedRequest */
$modifiedRequest = Psr7\Utils::modifyRequest($request, ['set_headers' => ['foo' => 'bar']]);
self::assertSame(['name' => 'value'], $modifiedRequest->getCookieParams());
}
public function testModifyServerRequestParsedBody()
{
$request = (new Psr7\ServerRequest('GET', 'http://example.com/bla'))
->withParsedBody(['name' => 'value']);
/** @var Psr7\ServerRequest $modifiedRequest */
$modifiedRequest = Psr7\Utils::modifyRequest($request, ['set_headers' => ['foo' => 'bar']]);
self::assertSame(['name' => 'value'], $modifiedRequest->getParsedBody());
}
public function testModifyServerRequestQueryParams()
{
$request = (new Psr7\ServerRequest('GET', 'http://example.com/bla'))
->withQueryParams(['name' => 'value']);
/** @var Psr7\ServerRequest $modifiedRequest */
$modifiedRequest = Psr7\Utils::modifyRequest($request, ['set_headers' => ['foo' => 'bar']]);
self::assertSame(['name' => 'value'], $modifiedRequest->getQueryParams());
}
public function testModifyServerRequestRetainsAttributes()
{
$request = (new Psr7\ServerRequest('GET', 'http://example.com/bla'))
->withAttribute('foo', 'bar');
/** @var Psr7\ServerRequest $modifiedRequest */
$modifiedRequest = Psr7\Utils::modifyRequest($request, []);
self::assertSame(['foo' => 'bar'], $modifiedRequest->getAttributes());
}
}