Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176

This commit is contained in:
Pantheon Automation 2015-08-17 17:00:26 -07:00 committed by Greg Anderson
commit 9921556621
13277 changed files with 1459781 additions and 0 deletions

View file

@ -0,0 +1,58 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\BatchResults;
/**
* @covers \GuzzleHttp\BatchResults
*/
class BatchResultsTest extends \PHPUnit_Framework_TestCase
{
public function testExposesResults()
{
$a = new \stdClass();
$b = new \stdClass();
$c = new \stdClass();
$hash = new \SplObjectStorage();
$hash[$a] = '1';
$hash[$b] = '2';
$hash[$c] = new \Exception('foo');
$batch = new BatchResults($hash);
$this->assertCount(3, $batch);
$this->assertEquals([$a, $b, $c], $batch->getKeys());
$this->assertEquals([$hash[$c]], $batch->getFailures());
$this->assertEquals(['1', '2'], $batch->getSuccessful());
$this->assertEquals('1', $batch->getResult($a));
$this->assertNull($batch->getResult(new \stdClass()));
$this->assertTrue(isset($batch[0]));
$this->assertFalse(isset($batch[10]));
$this->assertEquals('1', $batch[0]);
$this->assertEquals('2', $batch[1]);
$this->assertNull($batch[100]);
$this->assertInstanceOf('Exception', $batch[2]);
$results = iterator_to_array($batch);
$this->assertEquals(['1', '2', $hash[$c]], $results);
}
/**
* @expectedException \RuntimeException
*/
public function testCannotSetByIndex()
{
$hash = new \SplObjectStorage();
$batch = new BatchResults($hash);
$batch[10] = 'foo';
}
/**
* @expectedException \RuntimeException
*/
public function testCannotUnsetByIndex()
{
$hash = new \SplObjectStorage();
$batch = new BatchResults($hash);
unset($batch[10]);
}
}

View file

@ -0,0 +1,624 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Client;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Event\ErrorEvent;
use GuzzleHttp\Message\MessageFactory;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Query;
use GuzzleHttp\Ring\Client\MockHandler;
use GuzzleHttp\Ring\Future\FutureArray;
use GuzzleHttp\Subscriber\History;
use GuzzleHttp\Subscriber\Mock;
use GuzzleHttp\Url;
use React\Promise\Deferred;
/**
* @covers GuzzleHttp\Client
*/
class ClientTest extends \PHPUnit_Framework_TestCase
{
/** @callable */
private $ma;
public function setup()
{
$this->ma = function () {
throw new \RuntimeException('Should not have been called.');
};
}
public function testProvidesDefaultUserAgent()
{
$ua = Client::getDefaultUserAgent();
$this->assertEquals(1, preg_match('#^Guzzle/.+ curl/.+ PHP/.+$#', $ua));
}
public function testUsesDefaultDefaultOptions()
{
$client = new Client();
$this->assertTrue($client->getDefaultOption('allow_redirects'));
$this->assertTrue($client->getDefaultOption('exceptions'));
$this->assertTrue($client->getDefaultOption('verify'));
}
public function testUsesProvidedDefaultOptions()
{
$client = new Client([
'defaults' => [
'allow_redirects' => false,
'query' => ['foo' => 'bar']
]
]);
$this->assertFalse($client->getDefaultOption('allow_redirects'));
$this->assertTrue($client->getDefaultOption('exceptions'));
$this->assertTrue($client->getDefaultOption('verify'));
$this->assertEquals(['foo' => 'bar'], $client->getDefaultOption('query'));
}
public function testCanSpecifyBaseUrl()
{
$this->assertSame('', (new Client())->getBaseUrl());
$this->assertEquals('http://foo', (new Client([
'base_url' => 'http://foo'
]))->getBaseUrl());
}
public function testCanSpecifyBaseUrlUriTemplate()
{
$client = new Client(['base_url' => ['http://foo.com/{var}/', ['var' => 'baz']]]);
$this->assertEquals('http://foo.com/baz/', $client->getBaseUrl());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesUriTemplateValue()
{
new Client(['base_url' => ['http://foo.com/']]);
}
/**
* @expectedException \Exception
* @expectedExceptionMessage Foo
*/
public function testCanSpecifyHandler()
{
$client = new Client(['handler' => function () {
throw new \Exception('Foo');
}]);
$client->get('http://httpbin.org');
}
/**
* @expectedException \Exception
* @expectedExceptionMessage Foo
*/
public function testCanSpecifyHandlerAsAdapter()
{
$client = new Client(['adapter' => function () {
throw new \Exception('Foo');
}]);
$client->get('http://httpbin.org');
}
/**
* @expectedException \Exception
* @expectedExceptionMessage Foo
*/
public function testCanSpecifyMessageFactory()
{
$factory = $this->getMockBuilder('GuzzleHttp\Message\MessageFactoryInterface')
->setMethods(['createRequest'])
->getMockForAbstractClass();
$factory->expects($this->once())
->method('createRequest')
->will($this->throwException(new \Exception('Foo')));
$client = new Client(['message_factory' => $factory]);
$client->get();
}
public function testCanSpecifyEmitter()
{
$emitter = $this->getMockBuilder('GuzzleHttp\Event\EmitterInterface')
->setMethods(['listeners'])
->getMockForAbstractClass();
$emitter->expects($this->once())
->method('listeners')
->will($this->returnValue('foo'));
$client = new Client(['emitter' => $emitter]);
$this->assertEquals('foo', $client->getEmitter()->listeners());
}
public function testAddsDefaultUserAgentHeaderWithDefaultOptions()
{
$client = new Client(['defaults' => ['allow_redirects' => false]]);
$this->assertFalse($client->getDefaultOption('allow_redirects'));
$this->assertEquals(
['User-Agent' => Client::getDefaultUserAgent()],
$client->getDefaultOption('headers')
);
}
public function testAddsDefaultUserAgentHeaderWithoutDefaultOptions()
{
$client = new Client();
$this->assertEquals(
['User-Agent' => Client::getDefaultUserAgent()],
$client->getDefaultOption('headers')
);
}
private function getRequestClient()
{
$client = $this->getMockBuilder('GuzzleHttp\Client')
->setMethods(['send'])
->getMock();
$client->expects($this->once())
->method('send')
->will($this->returnArgument(0));
return $client;
}
public function requestMethodProvider()
{
return [
['GET', false],
['HEAD', false],
['DELETE', false],
['OPTIONS', false],
['POST', 'foo'],
['PUT', 'foo'],
['PATCH', 'foo']
];
}
/**
* @dataProvider requestMethodProvider
*/
public function testClientProvidesMethodShortcut($method, $body)
{
$client = $this->getRequestClient();
if ($body) {
$request = $client->{$method}('http://foo.com', [
'headers' => ['X-Baz' => 'Bar'],
'body' => $body,
'query' => ['a' => 'b']
]);
} else {
$request = $client->{$method}('http://foo.com', [
'headers' => ['X-Baz' => 'Bar'],
'query' => ['a' => 'b']
]);
}
$this->assertEquals($method, $request->getMethod());
$this->assertEquals('Bar', $request->getHeader('X-Baz'));
$this->assertEquals('a=b', $request->getQuery());
if ($body) {
$this->assertEquals($body, $request->getBody());
}
}
public function testClientMergesDefaultOptionsWithRequestOptions()
{
$f = $this->getMockBuilder('GuzzleHttp\Message\MessageFactoryInterface')
->setMethods(array('createRequest'))
->getMockForAbstractClass();
$o = null;
// Intercept the creation
$f->expects($this->once())
->method('createRequest')
->will($this->returnCallback(
function ($method, $url, array $options = []) use (&$o) {
$o = $options;
return (new MessageFactory())->createRequest($method, $url, $options);
}
));
$client = new Client([
'message_factory' => $f,
'defaults' => [
'headers' => ['Foo' => 'Bar'],
'query' => ['baz' => 'bam'],
'exceptions' => false
]
]);
$request = $client->createRequest('GET', 'http://foo.com?a=b', [
'headers' => ['Hi' => 'there', '1' => 'one'],
'allow_redirects' => false,
'query' => ['t' => 1]
]);
$this->assertFalse($o['allow_redirects']);
$this->assertFalse($o['exceptions']);
$this->assertEquals('Bar', $request->getHeader('Foo'));
$this->assertEquals('there', $request->getHeader('Hi'));
$this->assertEquals('one', $request->getHeader('1'));
$this->assertEquals('a=b&baz=bam&t=1', $request->getQuery());
}
public function testClientMergesDefaultHeadersCaseInsensitively()
{
$client = new Client(['defaults' => ['headers' => ['Foo' => 'Bar']]]);
$request = $client->createRequest('GET', 'http://foo.com?a=b', [
'headers' => ['foo' => 'custom', 'user-agent' => 'test']
]);
$this->assertEquals('test', $request->getHeader('User-Agent'));
$this->assertEquals('custom', $request->getHeader('Foo'));
}
public function testCanOverrideDefaultOptionWithNull()
{
$client = new Client(['defaults' => ['proxy' => 'invalid!']]);
$request = $client->createRequest('GET', 'http://foo.com?a=b', [
'proxy' => null
]);
$this->assertFalse($request->getConfig()->hasKey('proxy'));
}
public function testDoesNotOverwriteExistingUA()
{
$client = new Client(['defaults' => [
'headers' => ['User-Agent' => 'test']
]]);
$this->assertEquals(
['User-Agent' => 'test'],
$client->getDefaultOption('headers')
);
}
public function testUsesBaseUrlWhenNoUrlIsSet()
{
$client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
$this->assertEquals(
'http://www.foo.com/baz?bam=bar',
$client->createRequest('GET')->getUrl()
);
}
public function testUsesBaseUrlCombinedWithProvidedUrl()
{
$client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
$this->assertEquals(
'http://www.foo.com/bar/bam',
$client->createRequest('GET', 'bar/bam')->getUrl()
);
}
public function testFalsyPathsAreCombinedWithBaseUrl()
{
$client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
$this->assertEquals(
'http://www.foo.com/0',
$client->createRequest('GET', '0')->getUrl()
);
}
public function testUsesBaseUrlCombinedWithProvidedUrlViaUriTemplate()
{
$client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
$this->assertEquals(
'http://www.foo.com/bar/123',
$client->createRequest('GET', ['bar/{bam}', ['bam' => '123']])->getUrl()
);
}
public function testSettingAbsoluteUrlOverridesBaseUrl()
{
$client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
$this->assertEquals(
'http://www.foo.com/foo',
$client->createRequest('GET', '/foo')->getUrl()
);
}
public function testSettingAbsoluteUriTemplateOverridesBaseUrl()
{
$client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
$this->assertEquals(
'http://goo.com/1',
$client->createRequest(
'GET',
['http://goo.com/{bar}', ['bar' => '1']]
)->getUrl()
);
}
public function testCanSetRelativeUrlStartingWithHttp()
{
$client = new Client(['base_url' => 'http://www.foo.com']);
$this->assertEquals(
'http://www.foo.com/httpfoo',
$client->createRequest('GET', 'httpfoo')->getUrl()
);
}
public function testClientSendsRequests()
{
$mock = new MockHandler(['status' => 200, 'headers' => []]);
$client = new Client(['handler' => $mock]);
$response = $client->get('http://test.com');
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('http://test.com', $response->getEffectiveUrl());
}
public function testSendingRequestCanBeIntercepted()
{
$response = new Response(200);
$client = new Client(['handler' => $this->ma]);
$client->getEmitter()->on(
'before',
function (BeforeEvent $e) use ($response) {
$e->intercept($response);
}
);
$this->assertSame($response, $client->get('http://test.com'));
$this->assertEquals('http://test.com', $response->getEffectiveUrl());
}
/**
* @expectedException \GuzzleHttp\Exception\RequestException
* @expectedExceptionMessage Argument 1 passed to GuzzleHttp\Message\FutureResponse::proxy() must implement interface GuzzleHttp\Ring\Future\FutureInterface
*/
public function testEnsuresResponseIsPresentAfterSending()
{
$handler = function () {};
$client = new Client(['handler' => $handler]);
$client->get('http://httpbin.org');
}
/**
* @expectedException \GuzzleHttp\Exception\RequestException
* @expectedExceptionMessage Waiting did not resolve future
*/
public function testEnsuresResponseIsPresentAfterDereferencing()
{
$deferred = new Deferred();
$handler = new MockHandler(function () use ($deferred) {
return new FutureArray(
$deferred->promise(),
function () {}
);
});
$client = new Client(['handler' => $handler]);
$response = $client->get('http://httpbin.org');
$response->wait();
}
public function testClientHandlesErrorsDuringBeforeSend()
{
$client = new Client();
$client->getEmitter()->on('before', function ($e) {
throw new \Exception('foo');
});
$client->getEmitter()->on('error', function (ErrorEvent $e) {
$e->intercept(new Response(200));
});
$this->assertEquals(
200,
$client->get('http://test.com')->getStatusCode()
);
}
/**
* @expectedException \GuzzleHttp\Exception\RequestException
* @expectedExceptionMessage foo
*/
public function testClientHandlesErrorsDuringBeforeSendAndThrowsIfUnhandled()
{
$client = new Client();
$client->getEmitter()->on('before', function (BeforeEvent $e) {
throw new RequestException('foo', $e->getRequest());
});
$client->get('http://httpbin.org');
}
/**
* @expectedException \GuzzleHttp\Exception\RequestException
* @expectedExceptionMessage foo
*/
public function testClientWrapsExceptions()
{
$client = new Client();
$client->getEmitter()->on('before', function (BeforeEvent $e) {
throw new \Exception('foo');
});
$client->get('http://httpbin.org');
}
public function testCanInjectResponseForFutureError()
{
$calledFuture = false;
$deferred = new Deferred();
$future = new FutureArray(
$deferred->promise(),
function () use ($deferred, &$calledFuture) {
$calledFuture = true;
$deferred->resolve(['error' => new \Exception('Noo!')]);
}
);
$mock = new MockHandler($future);
$client = new Client(['handler' => $mock]);
$called = 0;
$response = $client->get('http://localhost:123/foo', [
'future' => true,
'events' => [
'error' => function (ErrorEvent $e) use (&$called) {
$called++;
$e->intercept(new Response(200));
}
]
]);
$this->assertEquals(0, $called);
$this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $response);
$this->assertEquals(200, $response->getStatusCode());
$this->assertTrue($calledFuture);
$this->assertEquals(1, $called);
}
public function testCanReturnFutureResults()
{
$called = false;
$deferred = new Deferred();
$future = new FutureArray(
$deferred->promise(),
function () use ($deferred, &$called) {
$called = true;
$deferred->resolve(['status' => 201, 'headers' => []]);
}
);
$mock = new MockHandler($future);
$client = new Client(['handler' => $mock]);
$response = $client->get('http://localhost:123/foo', ['future' => true]);
$this->assertFalse($called);
$this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $response);
$this->assertEquals(201, $response->getStatusCode());
$this->assertTrue($called);
}
public function testThrowsExceptionsWhenDereferenced()
{
$calledFuture = false;
$deferred = new Deferred();
$future = new FutureArray(
$deferred->promise(),
function () use ($deferred, &$calledFuture) {
$calledFuture = true;
$deferred->resolve(['error' => new \Exception('Noop!')]);
}
);
$client = new Client(['handler' => new MockHandler($future)]);
try {
$res = $client->get('http://localhost:123/foo', ['future' => true]);
$res->wait();
$this->fail('Did not throw');
} catch (RequestException $e) {
$this->assertEquals(1, $calledFuture);
}
}
/**
* @expectedExceptionMessage Noo!
* @expectedException \GuzzleHttp\Exception\RequestException
*/
public function testThrowsExceptionsSynchronously()
{
$client = new Client([
'handler' => new MockHandler(['error' => new \Exception('Noo!')])
]);
$client->get('http://localhost:123/foo');
}
public function testCanSetDefaultValues()
{
$client = new Client(['foo' => 'bar']);
$client->setDefaultOption('headers/foo', 'bar');
$this->assertNull($client->getDefaultOption('foo'));
$this->assertEquals('bar', $client->getDefaultOption('headers/foo'));
}
public function testSendsAllInParallel()
{
$client = new Client();
$client->getEmitter()->attach(new Mock([
new Response(200),
new Response(201),
new Response(202),
]));
$history = new History();
$client->getEmitter()->attach($history);
$requests = [
$client->createRequest('GET', 'http://test.com'),
$client->createRequest('POST', 'http://test.com'),
$client->createRequest('PUT', 'http://test.com')
];
$client->sendAll($requests);
$requests = array_map(function($r) {
return $r->getMethod();
}, $history->getRequests());
$this->assertContains('GET', $requests);
$this->assertContains('POST', $requests);
$this->assertContains('PUT', $requests);
}
public function testCanDisableAuthPerRequest()
{
$client = new Client(['defaults' => ['auth' => 'foo']]);
$request = $client->createRequest('GET', 'http://test.com');
$this->assertEquals('foo', $request->getConfig()['auth']);
$request = $client->createRequest('GET', 'http://test.com', ['auth' => null]);
$this->assertFalse($request->getConfig()->hasKey('auth'));
}
public function testUsesProxyEnvironmentVariables()
{
$http = getenv('HTTP_PROXY');
$https = getenv('HTTPS_PROXY');
$client = new Client();
$this->assertNull($client->getDefaultOption('proxy'));
putenv('HTTP_PROXY=127.0.0.1');
$client = new Client();
$this->assertEquals(
['http' => '127.0.0.1'],
$client->getDefaultOption('proxy')
);
putenv('HTTPS_PROXY=127.0.0.2');
$client = new Client();
$this->assertEquals(
['http' => '127.0.0.1', 'https' => '127.0.0.2'],
$client->getDefaultOption('proxy')
);
putenv("HTTP_PROXY=$http");
putenv("HTTPS_PROXY=$https");
}
public function testReturnsFutureForErrorWhenRequested()
{
$client = new Client(['handler' => new MockHandler(['status' => 404])]);
$request = $client->createRequest('GET', 'http://localhost:123/foo', [
'future' => true
]);
$res = $client->send($request);
$this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $res);
try {
$res->wait();
$this->fail('did not throw');
} catch (RequestException $e) {
$this->assertContains('404', $e->getMessage());
}
}
public function testReturnsFutureForResponseWhenRequested()
{
$client = new Client(['handler' => new MockHandler(['status' => 200])]);
$request = $client->createRequest('GET', 'http://localhost:123/foo', [
'future' => true
]);
$res = $client->send($request);
$this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $res);
$this->assertEquals(200, $res->getStatusCode());
}
public function testCanUseUrlWithCustomQuery()
{
$client = new Client();
$url = Url::fromString('http://foo.com/bar');
$query = new Query(['baz' => '123%20']);
$query->setEncodingType(false);
$url->setQuery($query);
$r = $client->createRequest('GET', $url);
$this->assertEquals('http://foo.com/bar?baz=123%20', $r->getUrl());
}
}

View file

@ -0,0 +1,416 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Collection;
class CollectionTest extends \PHPUnit_Framework_TestCase
{
/** @var Collection */
protected $coll;
protected function setUp()
{
$this->coll = new Collection();
}
public function testConstructorCanBeCalledWithNoParams()
{
$this->coll = new Collection();
$p = $this->coll->toArray();
$this->assertEmpty($p, '-> Collection must be empty when no data is passed');
}
public function testConstructorCanBeCalledWithParams()
{
$testData = array(
'test' => 'value',
'test_2' => 'value2'
);
$this->coll = new Collection($testData);
$this->assertEquals($this->coll->toArray(), $testData);
$this->assertEquals($this->coll->toArray(), $this->coll->toArray());
}
public function testImplementsIteratorAggregate()
{
$this->coll->set('key', 'value');
$this->assertInstanceOf('ArrayIterator', $this->coll->getIterator());
$this->assertEquals(1, count($this->coll));
$total = 0;
foreach ($this->coll as $key => $value) {
$this->assertEquals('key', $key);
$this->assertEquals('value', $value);
$total++;
}
$this->assertEquals(1, $total);
}
public function testCanAddValuesToExistingKeysByUsingArray()
{
$this->coll->add('test', 'value1');
$this->assertEquals($this->coll->toArray(), array('test' => 'value1'));
$this->coll->add('test', 'value2');
$this->assertEquals($this->coll->toArray(), array('test' => array('value1', 'value2')));
$this->coll->add('test', 'value3');
$this->assertEquals($this->coll->toArray(), array('test' => array('value1', 'value2', 'value3')));
}
public function testHandlesMergingInDisparateDataSources()
{
$params = array(
'test' => 'value1',
'test2' => 'value2',
'test3' => array('value3', 'value4')
);
$this->coll->merge($params);
$this->assertEquals($this->coll->toArray(), $params);
$this->coll->merge(new Collection(['test4' => 'hi']));
$this->assertEquals(
$this->coll->toArray(),
$params + ['test4' => 'hi']
);
}
public function testCanClearAllDataOrSpecificKeys()
{
$this->coll->merge(array(
'test' => 'value1',
'test2' => 'value2'
));
// Clear a specific parameter by name
$this->coll->remove('test');
$this->assertEquals($this->coll->toArray(), array(
'test2' => 'value2'
));
// Clear all parameters
$this->coll->clear();
$this->assertEquals($this->coll->toArray(), array());
}
public function testProvidesKeys()
{
$this->assertEquals(array(), $this->coll->getKeys());
$this->coll->merge(array(
'test1' => 'value1',
'test2' => 'value2'
));
$this->assertEquals(array('test1', 'test2'), $this->coll->getKeys());
// Returns the cached array previously returned
$this->assertEquals(array('test1', 'test2'), $this->coll->getKeys());
$this->coll->remove('test1');
$this->assertEquals(array('test2'), $this->coll->getKeys());
$this->coll->add('test3', 'value3');
$this->assertEquals(array('test2', 'test3'), $this->coll->getKeys());
}
public function testChecksIfHasKey()
{
$this->assertFalse($this->coll->hasKey('test'));
$this->coll->add('test', 'value');
$this->assertEquals(true, $this->coll->hasKey('test'));
$this->coll->add('test2', 'value2');
$this->assertEquals(true, $this->coll->hasKey('test'));
$this->assertEquals(true, $this->coll->hasKey('test2'));
$this->assertFalse($this->coll->hasKey('testing'));
$this->assertEquals(false, $this->coll->hasKey('AB-C', 'junk'));
}
public function testChecksIfHasValue()
{
$this->assertFalse($this->coll->hasValue('value'));
$this->coll->add('test', 'value');
$this->assertEquals('test', $this->coll->hasValue('value'));
$this->coll->add('test2', 'value2');
$this->assertEquals('test', $this->coll->hasValue('value'));
$this->assertEquals('test2', $this->coll->hasValue('value2'));
$this->assertFalse($this->coll->hasValue('val'));
}
public function testImplementsCount()
{
$data = new Collection();
$this->assertEquals(0, $data->count());
$data->add('key', 'value');
$this->assertEquals(1, count($data));
$data->add('key', 'value2');
$this->assertEquals(1, count($data));
$data->add('key_2', 'value3');
$this->assertEquals(2, count($data));
}
public function testAddParamsByMerging()
{
$params = array(
'test' => 'value1',
'test2' => 'value2',
'test3' => array('value3', 'value4')
);
// Add some parameters
$this->coll->merge($params);
// Add more parameters by merging them in
$this->coll->merge(array(
'test' => 'another',
'different_key' => 'new value'
));
$this->assertEquals(array(
'test' => array('value1', 'another'),
'test2' => 'value2',
'test3' => array('value3', 'value4'),
'different_key' => 'new value'
), $this->coll->toArray());
}
public function testAllowsFunctionalFilter()
{
$this->coll->merge(array(
'fruit' => 'apple',
'number' => 'ten',
'prepositions' => array('about', 'above', 'across', 'after'),
'same_number' => 'ten'
));
$filtered = $this->coll->filter(function ($key, $value) {
return $value == 'ten';
});
$this->assertNotSame($filtered, $this->coll);
$this->assertEquals(array(
'number' => 'ten',
'same_number' => 'ten'
), $filtered->toArray());
}
public function testAllowsFunctionalMapping()
{
$this->coll->merge(array(
'number_1' => 1,
'number_2' => 2,
'number_3' => 3
));
$mapped = $this->coll->map(function ($key, $value) {
return $value * $value;
});
$this->assertNotSame($mapped, $this->coll);
$this->assertEquals(array(
'number_1' => 1,
'number_2' => 4,
'number_3' => 9
), $mapped->toArray());
}
public function testImplementsArrayAccess()
{
$this->coll->merge(array(
'k1' => 'v1',
'k2' => 'v2'
));
$this->assertTrue($this->coll->offsetExists('k1'));
$this->assertFalse($this->coll->offsetExists('Krull'));
$this->coll->offsetSet('k3', 'v3');
$this->assertEquals('v3', $this->coll->offsetGet('k3'));
$this->assertEquals('v3', $this->coll->get('k3'));
$this->coll->offsetUnset('k1');
$this->assertFalse($this->coll->offsetExists('k1'));
}
public function testCanReplaceAllData()
{
$this->coll->replace(array('a' => '123'));
$this->assertEquals(array('a' => '123'), $this->coll->toArray());
}
public function testPreparesFromConfig()
{
$c = Collection::fromConfig(array(
'a' => '123',
'base_url' => 'http://www.test.com/'
), array(
'a' => 'xyz',
'b' => 'lol'
), array('a'));
$this->assertInstanceOf('GuzzleHttp\Collection', $c);
$this->assertEquals(array(
'a' => '123',
'b' => 'lol',
'base_url' => 'http://www.test.com/'
), $c->toArray());
try {
$c = Collection::fromConfig(array(), array(), array('a'));
$this->fail('Exception not throw when missing config');
} catch (\InvalidArgumentException $e) {
}
}
function falseyDataProvider()
{
return array(
array(false, false),
array(null, null),
array('', ''),
array(array(), array()),
array(0, 0),
);
}
/**
* @dataProvider falseyDataProvider
*/
public function testReturnsCorrectData($a, $b)
{
$c = new Collection(array('value' => $a));
$this->assertSame($b, $c->get('value'));
}
public function testRetrievesNestedKeysUsingPath()
{
$data = array(
'foo' => 'bar',
'baz' => array(
'mesa' => array(
'jar' => 'jar'
)
)
);
$collection = new Collection($data);
$this->assertEquals('bar', $collection->getPath('foo'));
$this->assertEquals('jar', $collection->getPath('baz/mesa/jar'));
$this->assertNull($collection->getPath('wewewf'));
$this->assertNull($collection->getPath('baz/mesa/jar/jar'));
}
public function testFalseyKeysStillDescend()
{
$collection = new Collection(array(
'0' => array(
'a' => 'jar'
),
1 => 'other'
));
$this->assertEquals('jar', $collection->getPath('0/a'));
$this->assertEquals('other', $collection->getPath('1'));
}
public function getPathProvider()
{
$data = array(
'foo' => 'bar',
'baz' => array(
'mesa' => array(
'jar' => 'jar',
'array' => array('a', 'b', 'c')
),
'bar' => array(
'baz' => 'bam',
'array' => array('d', 'e', 'f')
)
),
'bam' => array(
array('foo' => 1),
array('foo' => 2),
array('array' => array('h', 'i'))
)
);
$c = new Collection($data);
return array(
// Simple path selectors
array($c, 'foo', 'bar'),
array($c, 'baz', $data['baz']),
array($c, 'bam', $data['bam']),
array($c, 'baz/mesa', $data['baz']['mesa']),
array($c, 'baz/mesa/jar', 'jar'),
// Does not barf on missing keys
array($c, 'fefwfw', null),
array($c, 'baz/mesa/array', $data['baz']['mesa']['array'])
);
}
/**
* @dataProvider getPathProvider
*/
public function testGetPath(Collection $c, $path, $expected, $separator = '/')
{
$this->assertEquals($expected, $c->getPath($path, $separator));
}
public function testOverridesSettings()
{
$c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3));
$c->overwriteWith(array('foo' => 10, 'bar' => 300));
$this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->toArray());
}
public function testOverwriteWithCollection()
{
$c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3));
$b = new Collection(array('foo' => 10, 'bar' => 300));
$c->overwriteWith($b);
$this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->toArray());
}
public function testOverwriteWithTraversable()
{
$c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3));
$b = new Collection(array('foo' => 10, 'bar' => 300));
$c->overwriteWith($b->getIterator());
$this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->toArray());
}
public function testCanSetNestedPathValueThatDoesNotExist()
{
$c = new Collection(array());
$c->setPath('foo/bar/baz/123', 'hi');
$this->assertEquals('hi', $c['foo']['bar']['baz']['123']);
}
public function testCanSetNestedPathValueThatExists()
{
$c = new Collection(array('foo' => array('bar' => 'test')));
$c->setPath('foo/bar', 'hi');
$this->assertEquals('hi', $c['foo']['bar']);
}
/**
* @expectedException \RuntimeException
*/
public function testVerifiesNestedPathIsValidAtExactLevel()
{
$c = new Collection(array('foo' => 'bar'));
$c->setPath('foo/bar', 'hi');
$this->assertEquals('hi', $c['foo']['bar']);
}
/**
* @expectedException \RuntimeException
*/
public function testVerifiesThatNestedPathIsValidAtAnyLevel()
{
$c = new Collection(array('foo' => 'bar'));
$c->setPath('foo/bar/baz', 'test');
}
public function testCanAppendToNestedPathValues()
{
$c = new Collection();
$c->setPath('foo/bar/[]', 'a');
$c->setPath('foo/bar/[]', 'b');
$this->assertEquals(['a', 'b'], $c['foo']['bar']);
}
}

View file

@ -0,0 +1,339 @@
<?php
namespace GuzzleHttp\Tests\CookieJar;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Cookie\SetCookie;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
/**
* @covers GuzzleHttp\Cookie\CookieJar
*/
class CookieJarTest extends \PHPUnit_Framework_TestCase
{
/** @var CookieJar */
private $jar;
public function setUp()
{
$this->jar = new CookieJar();
}
protected function getTestCookies()
{
return [
new SetCookie(['Name' => 'foo', 'Value' => 'bar', 'Domain' => 'foo.com', 'Path' => '/', 'Discard' => true]),
new SetCookie(['Name' => 'test', 'Value' => '123', 'Domain' => 'baz.com', 'Path' => '/foo', 'Expires' => 2]),
new SetCookie(['Name' => 'you', 'Value' => '123', 'Domain' => 'bar.com', 'Path' => '/boo', 'Expires' => time() + 1000])
];
}
public function testQuotesBadCookieValues()
{
$this->assertEquals('foo', CookieJar::getCookieValue('foo'));
$this->assertEquals('"foo,bar"', CookieJar::getCookieValue('foo,bar'));
}
public function testCreatesFromArray()
{
$jar = CookieJar::fromArray([
'foo' => 'bar',
'baz' => 'bam'
], 'example.com');
$this->assertCount(2, $jar);
}
/**
* Provides test data for cookie cookieJar retrieval
*/
public function getCookiesDataProvider()
{
return [
[['foo', 'baz', 'test', 'muppet', 'googoo'], '', '', '', false],
[['foo', 'baz', 'muppet', 'googoo'], '', '', '', true],
[['googoo'], 'www.example.com', '', '', false],
[['muppet', 'googoo'], 'test.y.example.com', '', '', false],
[['foo', 'baz'], 'example.com', '', '', false],
[['muppet'], 'x.y.example.com', '/acme/', '', false],
[['muppet'], 'x.y.example.com', '/acme/test/', '', false],
[['googoo'], 'x.y.example.com', '/test/acme/test/', '', false],
[['foo', 'baz'], 'example.com', '', '', false],
[['baz'], 'example.com', '', 'baz', false],
];
}
public function testStoresAndRetrievesCookies()
{
$cookies = $this->getTestCookies();
foreach ($cookies as $cookie) {
$this->assertTrue($this->jar->setCookie($cookie));
}
$this->assertEquals(3, count($this->jar));
$this->assertEquals(3, count($this->jar->getIterator()));
$this->assertEquals($cookies, $this->jar->getIterator()->getArrayCopy());
}
public function testRemovesTemporaryCookies()
{
$cookies = $this->getTestCookies();
foreach ($this->getTestCookies() as $cookie) {
$this->jar->setCookie($cookie);
}
$this->jar->clearSessionCookies();
$this->assertEquals(
[$cookies[1], $cookies[2]],
$this->jar->getIterator()->getArrayCopy()
);
}
public function testRemovesSelectively()
{
foreach ($this->getTestCookies() as $cookie) {
$this->jar->setCookie($cookie);
}
// Remove foo.com cookies
$this->jar->clear('foo.com');
$this->assertEquals(2, count($this->jar));
// Try again, removing no further cookies
$this->jar->clear('foo.com');
$this->assertEquals(2, count($this->jar));
// Remove bar.com cookies with path of /boo
$this->jar->clear('bar.com', '/boo');
$this->assertEquals(1, count($this->jar));
// Remove cookie by name
$this->jar->clear(null, null, 'test');
$this->assertEquals(0, count($this->jar));
}
public function testDoesNotAddIncompleteCookies()
{
$this->assertEquals(false, $this->jar->setCookie(new SetCookie()));
$this->assertFalse($this->jar->setCookie(new SetCookie(array(
'Name' => 'foo'
))));
$this->assertFalse($this->jar->setCookie(new SetCookie(array(
'Name' => false
))));
$this->assertFalse($this->jar->setCookie(new SetCookie(array(
'Name' => true
))));
$this->assertFalse($this->jar->setCookie(new SetCookie(array(
'Name' => 'foo',
'Domain' => 'foo.com'
))));
}
public function testDoesAddValidCookies()
{
$this->assertTrue($this->jar->setCookie(new SetCookie(array(
'Name' => 'foo',
'Domain' => 'foo.com',
'Value' => 0
))));
$this->assertTrue($this->jar->setCookie(new SetCookie(array(
'Name' => 'foo',
'Domain' => 'foo.com',
'Value' => 0.0
))));
$this->assertTrue($this->jar->setCookie(new SetCookie(array(
'Name' => 'foo',
'Domain' => 'foo.com',
'Value' => '0'
))));
}
public function testOverwritesCookiesThatAreOlderOrDiscardable()
{
$t = time() + 1000;
$data = array(
'Name' => 'foo',
'Value' => 'bar',
'Domain' => '.example.com',
'Path' => '/',
'Max-Age' => '86400',
'Secure' => true,
'Discard' => true,
'Expires' => $t
);
// Make sure that the discard cookie is overridden with the non-discard
$this->assertTrue($this->jar->setCookie(new SetCookie($data)));
$this->assertEquals(1, count($this->jar));
$data['Discard'] = false;
$this->assertTrue($this->jar->setCookie(new SetCookie($data)));
$this->assertEquals(1, count($this->jar));
$c = $this->jar->getIterator()->getArrayCopy();
$this->assertEquals(false, $c[0]->getDiscard());
// Make sure it doesn't duplicate the cookie
$this->jar->setCookie(new SetCookie($data));
$this->assertEquals(1, count($this->jar));
// Make sure the more future-ful expiration date supersede the other
$data['Expires'] = time() + 2000;
$this->assertTrue($this->jar->setCookie(new SetCookie($data)));
$this->assertEquals(1, count($this->jar));
$c = $this->jar->getIterator()->getArrayCopy();
$this->assertNotEquals($t, $c[0]->getExpires());
}
public function testOverwritesCookiesThatHaveChanged()
{
$t = time() + 1000;
$data = array(
'Name' => 'foo',
'Value' => 'bar',
'Domain' => '.example.com',
'Path' => '/',
'Max-Age' => '86400',
'Secure' => true,
'Discard' => true,
'Expires' => $t
);
// Make sure that the discard cookie is overridden with the non-discard
$this->assertTrue($this->jar->setCookie(new SetCookie($data)));
$data['Value'] = 'boo';
$this->assertTrue($this->jar->setCookie(new SetCookie($data)));
$this->assertEquals(1, count($this->jar));
// Changing the value plus a parameter also must overwrite the existing one
$data['Value'] = 'zoo';
$data['Secure'] = false;
$this->assertTrue($this->jar->setCookie(new SetCookie($data)));
$this->assertEquals(1, count($this->jar));
$c = $this->jar->getIterator()->getArrayCopy();
$this->assertEquals('zoo', $c[0]->getValue());
}
public function testAddsCookiesFromResponseWithRequest()
{
$response = new Response(200, array(
'Set-Cookie' => "fpc=d=.Hm.yh4.1XmJWjJfs4orLQzKzPImxklQoxXSHOZATHUSEFciRueW_7704iYUtsXNEXq0M92Px2glMdWypmJ7HIQl6XIUvrZimWjQ3vIdeuRbI.FNQMAfcxu_XN1zSx7l.AcPdKL6guHc2V7hIQFhnjRW0rxm2oHY1P4bGQxFNz7f.tHm12ZD3DbdMDiDy7TBXsuP4DM-&v=2; expires=Fri, 02-Mar-2019 02:17:40 GMT;"
));
$request = new Request('GET', 'http://www.example.com');
$this->jar->extractCookies($request, $response);
$this->assertEquals(1, count($this->jar));
}
public function getMatchingCookiesDataProvider()
{
return array(
array('https://example.com', 'foo=bar; baz=foobar'),
array('http://example.com', ''),
array('https://example.com:8912', 'foo=bar; baz=foobar'),
array('https://foo.example.com', 'foo=bar; baz=foobar'),
array('http://foo.example.com/test/acme/', 'googoo=gaga')
);
}
/**
* @dataProvider getMatchingCookiesDataProvider
*/
public function testReturnsCookiesMatchingRequests($url, $cookies)
{
$bag = [
new SetCookie([
'Name' => 'foo',
'Value' => 'bar',
'Domain' => 'example.com',
'Path' => '/',
'Max-Age' => '86400',
'Secure' => true
]),
new SetCookie([
'Name' => 'baz',
'Value' => 'foobar',
'Domain' => 'example.com',
'Path' => '/',
'Max-Age' => '86400',
'Secure' => true
]),
new SetCookie([
'Name' => 'test',
'Value' => '123',
'Domain' => 'www.foobar.com',
'Path' => '/path/',
'Discard' => true
]),
new SetCookie([
'Name' => 'muppet',
'Value' => 'cookie_monster',
'Domain' => '.y.example.com',
'Path' => '/acme/',
'Expires' => time() + 86400
]),
new SetCookie([
'Name' => 'googoo',
'Value' => 'gaga',
'Domain' => '.example.com',
'Path' => '/test/acme/',
'Max-Age' => 1500
])
];
foreach ($bag as $cookie) {
$this->jar->setCookie($cookie);
}
$request = new Request('GET', $url);
$this->jar->addCookieHeader($request);
$this->assertEquals($cookies, $request->getHeader('Cookie'));
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Invalid cookie: Cookie name must not cannot invalid characters:
*/
public function testThrowsExceptionWithStrictMode()
{
$a = new CookieJar(true);
$a->setCookie(new SetCookie(['Name' => "abc\n", 'Value' => 'foo', 'Domain' => 'bar']));
}
public function testDeletesCookiesByName()
{
$cookies = $this->getTestCookies();
$cookies[] = new SetCookie([
'Name' => 'other',
'Value' => '123',
'Domain' => 'bar.com',
'Path' => '/boo',
'Expires' => time() + 1000
]);
$jar = new CookieJar();
foreach ($cookies as $cookie) {
$jar->setCookie($cookie);
}
$this->assertCount(4, $jar);
$jar->clear('bar.com', '/boo', 'other');
$this->assertCount(3, $jar);
$names = array_map(function (SetCookie $c) {
return $c->getName();
}, $jar->getIterator()->getArrayCopy());
$this->assertEquals(['foo', 'test', 'you'], $names);
}
public function testCanConvertToAndLoadFromArray()
{
$jar = new CookieJar(true);
foreach ($this->getTestCookies() as $cookie) {
$jar->setCookie($cookie);
}
$this->assertCount(3, $jar);
$arr = $jar->toArray();
$this->assertCount(3, $arr);
$newCookieJar = new CookieJar(false, $arr);
$this->assertCount(3, $newCookieJar);
$this->assertSame($jar->toArray(), $newCookieJar->toArray());
}
}

View file

@ -0,0 +1,71 @@
<?php
namespace GuzzleHttp\Tests\CookieJar;
use GuzzleHttp\Cookie\FileCookieJar;
use GuzzleHttp\Cookie\SetCookie;
/**
* @covers GuzzleHttp\Cookie\FileCookieJar
*/
class FileCookieJarTest extends \PHPUnit_Framework_TestCase
{
private $file;
public function setUp()
{
$this->file = tempnam('/tmp', 'file-cookies');
}
/**
* @expectedException \RuntimeException
*/
public function testValidatesCookieFile()
{
file_put_contents($this->file, 'true');
new FileCookieJar($this->file);
}
public function testLoadsFromFileFile()
{
$jar = new FileCookieJar($this->file);
$this->assertEquals([], $jar->getIterator()->getArrayCopy());
unlink($this->file);
}
public function testPersistsToFileFile()
{
$jar = new FileCookieJar($this->file);
$jar->setCookie(new SetCookie([
'Name' => 'foo',
'Value' => 'bar',
'Domain' => 'foo.com',
'Expires' => time() + 1000
]));
$jar->setCookie(new SetCookie([
'Name' => 'baz',
'Value' => 'bar',
'Domain' => 'foo.com',
'Expires' => time() + 1000
]));
$jar->setCookie(new SetCookie([
'Name' => 'boo',
'Value' => 'bar',
'Domain' => 'foo.com',
]));
$this->assertEquals(3, count($jar));
unset($jar);
// Make sure it wrote to the file
$contents = file_get_contents($this->file);
$this->assertNotEmpty($contents);
// Load the cookieJar from the file
$jar = new FileCookieJar($this->file);
// Weeds out temporary and session cookies
$this->assertEquals(2, count($jar));
unset($jar);
unlink($this->file);
}
}

View file

@ -0,0 +1,76 @@
<?php
namespace GuzzleHttp\Tests\CookieJar;
use GuzzleHttp\Cookie\SessionCookieJar;
use GuzzleHttp\Cookie\SetCookie;
/**
* @covers GuzzleHttp\Cookie\SessionCookieJar
*/
class SessionCookieJarTest extends \PHPUnit_Framework_TestCase
{
private $sessionVar;
public function setUp()
{
$this->sessionVar = 'sessionKey';
if (!isset($_SESSION)) {
$_SESSION = array();
}
}
/**
* @expectedException \RuntimeException
*/
public function testValidatesCookieSession()
{
$_SESSION[$this->sessionVar] = 'true';
new SessionCookieJar($this->sessionVar);
}
public function testLoadsFromSession()
{
$jar = new SessionCookieJar($this->sessionVar);
$this->assertEquals([], $jar->getIterator()->getArrayCopy());
unset($_SESSION[$this->sessionVar]);
}
public function testPersistsToSession()
{
$jar = new SessionCookieJar($this->sessionVar);
$jar->setCookie(new SetCookie([
'Name' => 'foo',
'Value' => 'bar',
'Domain' => 'foo.com',
'Expires' => time() + 1000
]));
$jar->setCookie(new SetCookie([
'Name' => 'baz',
'Value' => 'bar',
'Domain' => 'foo.com',
'Expires' => time() + 1000
]));
$jar->setCookie(new SetCookie([
'Name' => 'boo',
'Value' => 'bar',
'Domain' => 'foo.com',
]));
$this->assertEquals(3, count($jar));
unset($jar);
// Make sure it wrote to the sessionVar in $_SESSION
$contents = $_SESSION[$this->sessionVar];
$this->assertNotEmpty($contents);
// Load the cookieJar from the file
$jar = new SessionCookieJar($this->sessionVar);
// Weeds out temporary and session cookies
$this->assertEquals(2, count($jar));
unset($jar);
unset($_SESSION[$this->sessionVar]);
}
}

View file

@ -0,0 +1,364 @@
<?php
namespace GuzzleHttp\Tests\CookieJar;
use GuzzleHttp\Cookie\SetCookie;
/**
* @covers GuzzleHttp\Cookie\SetCookie
*/
class SetCookieTest extends \PHPUnit_Framework_TestCase
{
public function testInitializesDefaultValues()
{
$cookie = new SetCookie();
$this->assertEquals('/', $cookie->getPath());
}
public function testConvertsDateTimeMaxAgeToUnixTimestamp()
{
$cookie = new SetCookie(['Expires' => 'November 20, 1984']);
$this->assertInternalType('integer', $cookie->getExpires());
}
public function testAddsExpiresBasedOnMaxAge()
{
$t = time();
$cookie = new SetCookie(['Max-Age' => 100]);
$this->assertEquals($t + 100, $cookie->getExpires());
}
public function testHoldsValues()
{
$t = time();
$data = array(
'Name' => 'foo',
'Value' => 'baz',
'Path' => '/bar',
'Domain' => 'baz.com',
'Expires' => $t,
'Max-Age' => 100,
'Secure' => true,
'Discard' => true,
'HttpOnly' => true,
'foo' => 'baz',
'bar' => 'bam'
);
$cookie = new SetCookie($data);
$this->assertEquals($data, $cookie->toArray());
$this->assertEquals('foo', $cookie->getName());
$this->assertEquals('baz', $cookie->getValue());
$this->assertEquals('baz.com', $cookie->getDomain());
$this->assertEquals('/bar', $cookie->getPath());
$this->assertEquals($t, $cookie->getExpires());
$this->assertEquals(100, $cookie->getMaxAge());
$this->assertTrue($cookie->getSecure());
$this->assertTrue($cookie->getDiscard());
$this->assertTrue($cookie->getHttpOnly());
$this->assertEquals('baz', $cookie->toArray()['foo']);
$this->assertEquals('bam', $cookie->toArray()['bar']);
$cookie->setName('a');
$cookie->setValue('b');
$cookie->setPath('c');
$cookie->setDomain('bar.com');
$cookie->setExpires(10);
$cookie->setMaxAge(200);
$cookie->setSecure(false);
$cookie->setHttpOnly(false);
$cookie->setDiscard(false);
$this->assertEquals('a', $cookie->getName());
$this->assertEquals('b', $cookie->getValue());
$this->assertEquals('c', $cookie->getPath());
$this->assertEquals('bar.com', $cookie->getDomain());
$this->assertEquals(10, $cookie->getExpires());
$this->assertEquals(200, $cookie->getMaxAge());
$this->assertFalse($cookie->getSecure());
$this->assertFalse($cookie->getDiscard());
$this->assertFalse($cookie->getHttpOnly());
}
public function testDeterminesIfExpired()
{
$c = new SetCookie();
$c->setExpires(10);
$this->assertTrue($c->isExpired());
$c->setExpires(time() + 10000);
$this->assertFalse($c->isExpired());
}
public function testMatchesDomain()
{
$cookie = new SetCookie();
$this->assertTrue($cookie->matchesDomain('baz.com'));
$cookie->setDomain('baz.com');
$this->assertTrue($cookie->matchesDomain('baz.com'));
$this->assertFalse($cookie->matchesDomain('bar.com'));
$cookie->setDomain('.baz.com');
$this->assertTrue($cookie->matchesDomain('.baz.com'));
$this->assertTrue($cookie->matchesDomain('foo.baz.com'));
$this->assertFalse($cookie->matchesDomain('baz.bar.com'));
$this->assertTrue($cookie->matchesDomain('baz.com'));
$cookie->setDomain('.127.0.0.1');
$this->assertTrue($cookie->matchesDomain('127.0.0.1'));
$cookie->setDomain('127.0.0.1');
$this->assertTrue($cookie->matchesDomain('127.0.0.1'));
$cookie->setDomain('.com.');
$this->assertFalse($cookie->matchesDomain('baz.com'));
$cookie->setDomain('.local');
$this->assertTrue($cookie->matchesDomain('example.local'));
}
public function testMatchesPath()
{
$cookie = new SetCookie();
$this->assertTrue($cookie->matchesPath('/foo'));
$cookie->setPath('/foo');
$this->assertTrue($cookie->matchesPath('/foo'));
$this->assertTrue($cookie->matchesPath('/foo/bar'));
$this->assertFalse($cookie->matchesPath('/bar'));
}
public function cookieValidateProvider()
{
return array(
array('foo', 'baz', 'bar', true),
array('0', '0', '0', true),
array('', 'baz', 'bar', 'The cookie name must not be empty'),
array('foo', '', 'bar', 'The cookie value must not be empty'),
array('foo', 'baz', '', 'The cookie domain must not be empty'),
array("foo\r", 'baz', '0', 'Cookie name must not cannot invalid characters: =,; \t\r\n\013\014'),
);
}
/**
* @dataProvider cookieValidateProvider
*/
public function testValidatesCookies($name, $value, $domain, $result)
{
$cookie = new SetCookie(array(
'Name' => $name,
'Value' => $value,
'Domain' => $domain
));
$this->assertSame($result, $cookie->validate());
}
public function testDoesNotMatchIp()
{
$cookie = new SetCookie(['Domain' => '192.168.16.']);
$this->assertFalse($cookie->matchesDomain('192.168.16.121'));
}
public function testConvertsToString()
{
$t = 1382916008;
$cookie = new SetCookie([
'Name' => 'test',
'Value' => '123',
'Domain' => 'foo.com',
'Expires' => $t,
'Path' => '/abc',
'HttpOnly' => true,
'Secure' => true
]);
$this->assertEquals(
'test=123; Domain=foo.com; Path=/abc; Expires=Sun, 27 Oct 2013 23:20:08 GMT; Secure; HttpOnly',
(string) $cookie
);
}
/**
* Provides the parsed information from a cookie
*
* @return array
*/
public function cookieParserDataProvider()
{
return array(
array(
'ASIHTTPRequestTestCookie=This+is+the+value; expires=Sat, 26-Jul-2008 17:00:42 GMT; path=/tests; domain=allseeing-i.com; PHPSESSID=6c951590e7a9359bcedde25cda73e43c; path=/";',
array(
'Domain' => 'allseeing-i.com',
'Path' => '/',
'PHPSESSID' => '6c951590e7a9359bcedde25cda73e43c',
'Max-Age' => NULL,
'Expires' => 'Sat, 26-Jul-2008 17:00:42 GMT',
'Secure' => NULL,
'Discard' => NULL,
'Name' => 'ASIHTTPRequestTestCookie',
'Value' => 'This+is+the+value',
'HttpOnly' => false
)
),
array('', []),
array('foo', []),
// Test setting a blank value for a cookie
array(array(
'foo=', 'foo =', 'foo =;', 'foo= ;', 'foo =', 'foo= '),
array(
'Name' => 'foo',
'Value' => '',
'Discard' => null,
'Domain' => null,
'Expires' => null,
'Max-Age' => null,
'Path' => '/',
'Secure' => null,
'HttpOnly' => false
)
),
// Test setting a value and removing quotes
array(array(
'foo=1', 'foo =1', 'foo =1;', 'foo=1 ;', 'foo =1', 'foo= 1', 'foo = 1 ;', 'foo="1"', 'foo="1";', 'foo= "1";'),
array(
'Name' => 'foo',
'Value' => '1',
'Discard' => null,
'Domain' => null,
'Expires' => null,
'Max-Age' => null,
'Path' => '/',
'Secure' => null,
'HttpOnly' => false
)
),
// Some of the following tests are based on http://framework.zend.com/svn/framework/standard/trunk/tests/Zend/Http/CookieTest.php
array(
'justacookie=foo; domain=example.com',
array(
'Name' => 'justacookie',
'Value' => 'foo',
'Domain' => 'example.com',
'Discard' => null,
'Expires' => null,
'Max-Age' => null,
'Path' => '/',
'Secure' => null,
'HttpOnly' => false
)
),
array(
'expires=tomorrow; secure; path=/Space Out/; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=.example.com',
array(
'Name' => 'expires',
'Value' => 'tomorrow',
'Domain' => '.example.com',
'Path' => '/Space Out/',
'Expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
'Discard' => null,
'Secure' => true,
'Max-Age' => null,
'HttpOnly' => false
)
),
array(
'domain=unittests; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=example.com; path=/some value/',
array(
'Name' => 'domain',
'Value' => 'unittests',
'Domain' => 'example.com',
'Path' => '/some value/',
'Expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
'Secure' => false,
'Discard' => null,
'Max-Age' => null,
'HttpOnly' => false
)
),
array(
'path=indexAction; path=/; domain=.foo.com; expires=Tue, 21-Nov-2006 08:33:44 GMT',
array(
'Name' => 'path',
'Value' => 'indexAction',
'Domain' => '.foo.com',
'Path' => '/',
'Expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
'Secure' => false,
'Discard' => null,
'Max-Age' => null,
'HttpOnly' => false
)
),
array(
'secure=sha1; secure; SECURE; domain=some.really.deep.domain.com; version=1; Max-Age=86400',
array(
'Name' => 'secure',
'Value' => 'sha1',
'Domain' => 'some.really.deep.domain.com',
'Path' => '/',
'Secure' => true,
'Discard' => null,
'Expires' => time() + 86400,
'Max-Age' => 86400,
'HttpOnly' => false,
'version' => '1'
)
),
array(
'PHPSESSID=123456789+abcd%2Cef; secure; discard; domain=.localdomain; path=/foo/baz; expires=Tue, 21-Nov-2006 08:33:44 GMT;',
array(
'Name' => 'PHPSESSID',
'Value' => '123456789+abcd%2Cef',
'Domain' => '.localdomain',
'Path' => '/foo/baz',
'Expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
'Secure' => true,
'Discard' => true,
'Max-Age' => null,
'HttpOnly' => false
)
),
);
}
/**
* @dataProvider cookieParserDataProvider
*/
public function testParseCookie($cookie, $parsed)
{
foreach ((array) $cookie as $v) {
$c = SetCookie::fromString($v);
$p = $c->toArray();
if (isset($p['Expires'])) {
// Remove expires values from the assertion if they are relatively equal
if (abs($p['Expires'] != strtotime($parsed['Expires'])) < 40) {
unset($p['Expires']);
unset($parsed['Expires']);
}
}
if (!empty($parsed)) {
foreach ($parsed as $key => $value) {
$this->assertEquals($parsed[$key], $p[$key], 'Comparing ' . $key . ' ' . var_export($value, true) . ' : ' . var_export($parsed, true) . ' | ' . var_export($p, true));
}
foreach ($p as $key => $value) {
$this->assertEquals($p[$key], $parsed[$key], 'Comparing ' . $key . ' ' . var_export($value, true) . ' : ' . var_export($parsed, true) . ' | ' . var_export($p, true));
}
} else {
$this->assertEquals([
'Name' => null,
'Value' => null,
'Domain' => null,
'Path' => '/',
'Max-Age' => null,
'Expires' => null,
'Secure' => false,
'Discard' => false,
'HttpOnly' => false,
], $p);
}
}
}
}

View file

@ -0,0 +1,14 @@
<?php
namespace GuzzleHttp\Tests\Event;
class AbstractEventTest extends \PHPUnit_Framework_TestCase
{
public function testStopsPropagation()
{
$e = $this->getMockBuilder('GuzzleHttp\Event\AbstractEvent')
->getMockForAbstractClass();
$this->assertFalse($e->isPropagationStopped());
$e->stopPropagation();
$this->assertTrue($e->isPropagationStopped());
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Client;
use GuzzleHttp\Transaction;
use GuzzleHttp\Message\Request;
/**
* @covers GuzzleHttp\Event\AbstractRequestEvent
*/
class AbstractRequestEventTest extends \PHPUnit_Framework_TestCase
{
public function testHasTransactionMethods()
{
$t = new Transaction(new Client(), new Request('GET', '/'));
$e = $this->getMockBuilder('GuzzleHttp\Event\AbstractRequestEvent')
->setConstructorArgs([$t])
->getMockForAbstractClass();
$this->assertSame($t->client, $e->getClient());
$this->assertSame($t->request, $e->getRequest());
}
public function testHasTransaction()
{
$t = new Transaction(new Client(), new Request('GET', '/'));
$e = $this->getMockBuilder('GuzzleHttp\Event\AbstractRequestEvent')
->setConstructorArgs([$t])
->getMockForAbstractClass();
$r = new \ReflectionMethod($e, 'getTransaction');
$r->setAccessible(true);
$this->assertSame($t, $r->invoke($e));
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Client;
use GuzzleHttp\Transaction;
use GuzzleHttp\Message\Request;
/**
* @covers GuzzleHttp\Event\AbstractRetryableEvent
*/
class AbstractRetryableEventTest extends \PHPUnit_Framework_TestCase
{
public function testCanRetry()
{
$t = new Transaction(new Client(), new Request('GET', '/'));
$t->transferInfo = ['foo' => 'bar'];
$e = $this->getMockBuilder('GuzzleHttp\Event\AbstractRetryableEvent')
->setConstructorArgs([$t])
->getMockForAbstractClass();
$e->retry();
$this->assertTrue($e->isPropagationStopped());
$this->assertEquals('retry', $t->state);
}
public function testCanRetryAfterDelay()
{
$t = new Transaction(new Client(), new Request('GET', '/'));
$t->transferInfo = ['foo' => 'bar'];
$e = $this->getMockBuilder('GuzzleHttp\Event\AbstractRetryableEvent')
->setConstructorArgs([$t])
->getMockForAbstractClass();
$e->retry(10);
$this->assertTrue($e->isPropagationStopped());
$this->assertEquals('retry', $t->state);
$this->assertEquals(10, $t->request->getConfig()->get('delay'));
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Client;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Transaction;
use GuzzleHttp\Message\Request;
/**
* @covers GuzzleHttp\Event\AbstractTransferEvent
*/
class AbstractTransferEventTest extends \PHPUnit_Framework_TestCase
{
public function testHasStats()
{
$t = new Transaction(new Client(), new Request('GET', '/'));
$t->transferInfo = ['foo' => 'bar'];
$e = $this->getMockBuilder('GuzzleHttp\Event\AbstractTransferEvent')
->setConstructorArgs([$t])
->getMockForAbstractClass();
$this->assertNull($e->getTransferInfo('baz'));
$this->assertEquals('bar', $e->getTransferInfo('foo'));
$this->assertEquals($t->transferInfo, $e->getTransferInfo());
}
public function testHasResponse()
{
$t = new Transaction(new Client(), new Request('GET', '/'));
$t->response = new Response(200);
$e = $this->getMockBuilder('GuzzleHttp\Event\AbstractTransferEvent')
->setConstructorArgs([$t])
->getMockForAbstractClass();
$this->assertTrue($e->hasResponse());
$this->assertSame($t->response, $e->getResponse());
}
public function testCanInterceptWithResponse()
{
$t = new Transaction(new Client(), new Request('GET', '/'));
$r = new Response(200);
$e = $this->getMockBuilder('GuzzleHttp\Event\AbstractTransferEvent')
->setConstructorArgs([$t])
->getMockForAbstractClass();
$e->intercept($r);
$this->assertSame($t->response, $r);
$this->assertSame($t->response, $e->getResponse());
$this->assertTrue($e->isPropagationStopped());
}
public function testReturnsNumberOfRetries()
{
$t = new Transaction(new Client(), new Request('GET', '/'));
$t->retries = 2;
$e = $this->getMockBuilder('GuzzleHttp\Event\AbstractTransferEvent')
->setConstructorArgs([$t])
->getMockForAbstractClass();
$this->assertEquals(2, $e->getRetryCount());
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Transaction;
use GuzzleHttp\Client;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
/**
* @covers GuzzleHttp\Event\BeforeEvent
*/
class BeforeEventTest extends \PHPUnit_Framework_TestCase
{
public function testInterceptsWithEvent()
{
$t = new Transaction(new Client(), new Request('GET', '/'));
$t->exception = new \Exception('foo');
$e = new BeforeEvent($t);
$response = new Response(200);
$e->intercept($response);
$this->assertTrue($e->isPropagationStopped());
$this->assertSame($t->response, $response);
$this->assertNull($t->exception);
}
}

View file

@ -0,0 +1,363 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Event\Emitter;
use GuzzleHttp\Event\EventInterface;
use GuzzleHttp\Event\SubscriberInterface;
/**
* @link https://github.com/symfony/symfony/blob/master/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php Based on this test.
*/
class EmitterTest extends \PHPUnit_Framework_TestCase
{
/* Some pseudo events */
const preFoo = 'pre.foo';
const postFoo = 'post.foo';
const preBar = 'pre.bar';
const postBar = 'post.bar';
/** @var Emitter */
private $emitter;
private $listener;
protected function setUp()
{
$this->emitter = new Emitter();
$this->listener = new TestEventListener();
}
protected function tearDown()
{
$this->emitter = null;
$this->listener = null;
}
public function testInitialState()
{
$this->assertEquals(array(), $this->emitter->listeners());
}
public function testAddListener()
{
$this->emitter->on('pre.foo', array($this->listener, 'preFoo'));
$this->emitter->on('post.foo', array($this->listener, 'postFoo'));
$this->assertTrue($this->emitter->hasListeners(self::preFoo));
$this->assertTrue($this->emitter->hasListeners(self::preFoo));
$this->assertCount(1, $this->emitter->listeners(self::postFoo));
$this->assertCount(1, $this->emitter->listeners(self::postFoo));
$this->assertCount(2, $this->emitter->listeners());
}
public function testGetListenersSortsByPriority()
{
$listener1 = new TestEventListener();
$listener2 = new TestEventListener();
$listener3 = new TestEventListener();
$listener1->name = '1';
$listener2->name = '2';
$listener3->name = '3';
$this->emitter->on('pre.foo', array($listener1, 'preFoo'), -10);
$this->emitter->on('pre.foo', array($listener2, 'preFoo'), 10);
$this->emitter->on('pre.foo', array($listener3, 'preFoo'));
$expected = array(
array($listener2, 'preFoo'),
array($listener3, 'preFoo'),
array($listener1, 'preFoo'),
);
$this->assertSame($expected, $this->emitter->listeners('pre.foo'));
}
public function testGetAllListenersSortsByPriority()
{
$listener1 = new TestEventListener();
$listener2 = new TestEventListener();
$listener3 = new TestEventListener();
$listener4 = new TestEventListener();
$listener5 = new TestEventListener();
$listener6 = new TestEventListener();
$this->emitter->on('pre.foo', [$listener1, 'preFoo'], -10);
$this->emitter->on('pre.foo', [$listener2, 'preFoo']);
$this->emitter->on('pre.foo', [$listener3, 'preFoo'], 10);
$this->emitter->on('post.foo', [$listener4, 'preFoo'], -10);
$this->emitter->on('post.foo', [$listener5, 'preFoo']);
$this->emitter->on('post.foo', [$listener6, 'preFoo'], 10);
$expected = [
'pre.foo' => [[$listener3, 'preFoo'], [$listener2, 'preFoo'], [$listener1, 'preFoo']],
'post.foo' => [[$listener6, 'preFoo'], [$listener5, 'preFoo'], [$listener4, 'preFoo']],
];
$this->assertSame($expected, $this->emitter->listeners());
}
public function testDispatch()
{
$this->emitter->on('pre.foo', array($this->listener, 'preFoo'));
$this->emitter->on('post.foo', array($this->listener, 'postFoo'));
$this->emitter->emit(self::preFoo, $this->getEvent());
$this->assertTrue($this->listener->preFooInvoked);
$this->assertFalse($this->listener->postFooInvoked);
$this->assertInstanceOf('GuzzleHttp\Event\EventInterface', $this->emitter->emit(self::preFoo, $this->getEvent()));
$event = $this->getEvent();
$return = $this->emitter->emit(self::preFoo, $event);
$this->assertSame($event, $return);
}
public function testDispatchForClosure()
{
$invoked = 0;
$listener = function () use (&$invoked) {
$invoked++;
};
$this->emitter->on('pre.foo', $listener);
$this->emitter->on('post.foo', $listener);
$this->emitter->emit(self::preFoo, $this->getEvent());
$this->assertEquals(1, $invoked);
}
public function testStopEventPropagation()
{
$otherListener = new TestEventListener();
// postFoo() stops the propagation, so only one listener should
// be executed
// Manually set priority to enforce $this->listener to be called first
$this->emitter->on('post.foo', array($this->listener, 'postFoo'), 10);
$this->emitter->on('post.foo', array($otherListener, 'preFoo'));
$this->emitter->emit(self::postFoo, $this->getEvent());
$this->assertTrue($this->listener->postFooInvoked);
$this->assertFalse($otherListener->postFooInvoked);
}
public function testDispatchByPriority()
{
$invoked = array();
$listener1 = function () use (&$invoked) {
$invoked[] = '1';
};
$listener2 = function () use (&$invoked) {
$invoked[] = '2';
};
$listener3 = function () use (&$invoked) {
$invoked[] = '3';
};
$this->emitter->on('pre.foo', $listener1, -10);
$this->emitter->on('pre.foo', $listener2);
$this->emitter->on('pre.foo', $listener3, 10);
$this->emitter->emit(self::preFoo, $this->getEvent());
$this->assertEquals(array('3', '2', '1'), $invoked);
}
public function testRemoveListener()
{
$this->emitter->on('pre.bar', [$this->listener, 'preFoo']);
$this->assertNotEmpty($this->emitter->listeners(self::preBar));
$this->emitter->removeListener('pre.bar', [$this->listener, 'preFoo']);
$this->assertEmpty($this->emitter->listeners(self::preBar));
$this->emitter->removeListener('notExists', [$this->listener, 'preFoo']);
}
public function testAddSubscriber()
{
$eventSubscriber = new TestEventSubscriber();
$this->emitter->attach($eventSubscriber);
$this->assertNotEmpty($this->emitter->listeners(self::preFoo));
$this->assertNotEmpty($this->emitter->listeners(self::postFoo));
}
public function testAddSubscriberWithMultiple()
{
$eventSubscriber = new TestEventSubscriberWithMultiple();
$this->emitter->attach($eventSubscriber);
$listeners = $this->emitter->listeners('pre.foo');
$this->assertNotEmpty($this->emitter->listeners(self::preFoo));
$this->assertCount(2, $listeners);
}
public function testAddSubscriberWithPriorities()
{
$eventSubscriber = new TestEventSubscriber();
$this->emitter->attach($eventSubscriber);
$eventSubscriber = new TestEventSubscriberWithPriorities();
$this->emitter->attach($eventSubscriber);
$listeners = $this->emitter->listeners('pre.foo');
$this->assertNotEmpty($this->emitter->listeners(self::preFoo));
$this->assertCount(2, $listeners);
$this->assertInstanceOf('GuzzleHttp\Tests\Event\TestEventSubscriberWithPriorities', $listeners[0][0]);
}
public function testdetach()
{
$eventSubscriber = new TestEventSubscriber();
$this->emitter->attach($eventSubscriber);
$this->assertNotEmpty($this->emitter->listeners(self::preFoo));
$this->assertNotEmpty($this->emitter->listeners(self::postFoo));
$this->emitter->detach($eventSubscriber);
$this->assertEmpty($this->emitter->listeners(self::preFoo));
$this->assertEmpty($this->emitter->listeners(self::postFoo));
}
public function testdetachWithPriorities()
{
$eventSubscriber = new TestEventSubscriberWithPriorities();
$this->emitter->attach($eventSubscriber);
$this->assertNotEmpty($this->emitter->listeners(self::preFoo));
$this->assertNotEmpty($this->emitter->listeners(self::postFoo));
$this->emitter->detach($eventSubscriber);
$this->assertEmpty($this->emitter->listeners(self::preFoo));
$this->assertEmpty($this->emitter->listeners(self::postFoo));
}
public function testEventReceivesEventNameAsArgument()
{
$listener = new TestWithDispatcher();
$this->emitter->on('test', array($listener, 'foo'));
$this->assertNull($listener->name);
$this->emitter->emit('test', $this->getEvent());
$this->assertEquals('test', $listener->name);
}
/**
* @see https://bugs.php.net/bug.php?id=62976
*
* This bug affects:
* - The PHP 5.3 branch for versions < 5.3.18
* - The PHP 5.4 branch for versions < 5.4.8
* - The PHP 5.5 branch is not affected
*/
public function testWorkaroundForPhpBug62976()
{
$dispatcher = new Emitter();
$dispatcher->on('bug.62976', new CallableClass());
$dispatcher->removeListener('bug.62976', function () {});
$this->assertNotEmpty($dispatcher->listeners('bug.62976'));
}
public function testRegistersEventsOnce()
{
$this->emitter->once('pre.foo', array($this->listener, 'preFoo'));
$this->emitter->on('pre.foo', array($this->listener, 'preFoo'));
$this->assertCount(2, $this->emitter->listeners(self::preFoo));
$this->emitter->emit(self::preFoo, $this->getEvent());
$this->assertTrue($this->listener->preFooInvoked);
$this->assertCount(1, $this->emitter->listeners(self::preFoo));
}
public function testReturnsEmptyArrayForNonExistentEvent()
{
$this->assertEquals([], $this->emitter->listeners('doesnotexist'));
}
public function testCanAddFirstAndLastListeners()
{
$b = '';
$this->emitter->on('foo', function () use (&$b) { $b .= 'a'; }, 'first'); // 1
$this->emitter->on('foo', function () use (&$b) { $b .= 'b'; }, 'last'); // 0
$this->emitter->on('foo', function () use (&$b) { $b .= 'c'; }, 'first'); // 2
$this->emitter->on('foo', function () use (&$b) { $b .= 'd'; }, 'first'); // 3
$this->emitter->on('foo', function () use (&$b) { $b .= 'e'; }, 'first'); // 4
$this->emitter->on('foo', function () use (&$b) { $b .= 'f'; }); // 0
$this->emitter->emit('foo', $this->getEvent());
$this->assertEquals('edcabf', $b);
}
/**
* @return \GuzzleHttp\Event\EventInterface
*/
private function getEvent()
{
return $this->getMockBuilder('GuzzleHttp\Event\AbstractEvent')
->getMockForAbstractClass();
}
}
class CallableClass
{
public function __invoke()
{
}
}
class TestEventListener
{
public $preFooInvoked = false;
public $postFooInvoked = false;
/* Listener methods */
public function preFoo(EventInterface $e)
{
$this->preFooInvoked = true;
}
public function postFoo(EventInterface $e)
{
$this->postFooInvoked = true;
$e->stopPropagation();
}
/**
* @expectedException \PHPUnit_Framework_Error_Deprecated
*/
public function testHasDeprecatedAddListener()
{
$emitter = new Emitter();
$emitter->addListener('foo', function () {});
}
/**
* @expectedException \PHPUnit_Framework_Error_Deprecated
*/
public function testHasDeprecatedAddSubscriber()
{
$emitter = new Emitter();
$emitter->addSubscriber('foo', new TestEventSubscriber());
}
}
class TestWithDispatcher
{
public $name;
public function foo(EventInterface $e, $name)
{
$this->name = $name;
}
}
class TestEventSubscriber extends TestEventListener implements SubscriberInterface
{
public function getEvents()
{
return [
'pre.foo' => ['preFoo'],
'post.foo' => ['postFoo']
];
}
}
class TestEventSubscriberWithPriorities extends TestEventListener implements SubscriberInterface
{
public function getEvents()
{
return [
'pre.foo' => ['preFoo', 10],
'post.foo' => ['postFoo']
];
}
}
class TestEventSubscriberWithMultiple extends TestEventListener implements SubscriberInterface
{
public function getEvents()
{
return ['pre.foo' => [['preFoo', 10],['preFoo', 20]]];
}
}

View file

@ -0,0 +1,23 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Transaction;
use GuzzleHttp\Client;
use GuzzleHttp\Event\ErrorEvent;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\Request;
/**
* @covers GuzzleHttp\Event\ErrorEvent
*/
class ErrorEventTest extends \PHPUnit_Framework_TestCase
{
public function testInterceptsWithEvent()
{
$t = new Transaction(new Client(), new Request('GET', '/'));
$except = new RequestException('foo', $t->request);
$t->exception = $except;
$e = new ErrorEvent($t);
$this->assertSame($e->getException(), $t->exception);
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Event\HasEmitterInterface;
use GuzzleHttp\Event\HasEmitterTrait;
class AbstractHasEmitter implements HasEmitterInterface
{
use HasEmitterTrait;
}
/**
* @covers GuzzleHttp\Event\HasEmitterTrait
*/
class HasEmitterTraitTest extends \PHPUnit_Framework_TestCase
{
public function testHelperAttachesSubscribers()
{
$mock = $this->getMockBuilder('GuzzleHttp\Tests\Event\AbstractHasEmitter')
->getMockForAbstractClass();
$result = $mock->getEmitter();
$this->assertInstanceOf('GuzzleHttp\Event\EmitterInterface', $result);
$result2 = $mock->getEmitter();
$this->assertSame($result, $result2);
}
}

View file

@ -0,0 +1,92 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Event\HasEmitterInterface;
use GuzzleHttp\Event\HasEmitterTrait;
use GuzzleHttp\Event\ListenerAttacherTrait;
class ObjectWithEvents implements HasEmitterInterface
{
use HasEmitterTrait, ListenerAttacherTrait;
public $listeners = [];
public function __construct(array $args = [])
{
$this->listeners = $this->prepareListeners($args, ['foo', 'bar']);
$this->attachListeners($this, $this->listeners);
}
}
class ListenerAttacherTraitTest extends \PHPUnit_Framework_TestCase
{
public function testRegistersEvents()
{
$fn = function () {};
$o = new ObjectWithEvents([
'foo' => $fn,
'bar' => $fn,
]);
$this->assertEquals([
['name' => 'foo', 'fn' => $fn, 'priority' => 0, 'once' => false],
['name' => 'bar', 'fn' => $fn, 'priority' => 0, 'once' => false],
], $o->listeners);
$this->assertCount(1, $o->getEmitter()->listeners('foo'));
$this->assertCount(1, $o->getEmitter()->listeners('bar'));
}
public function testRegistersEventsWithPriorities()
{
$fn = function () {};
$o = new ObjectWithEvents([
'foo' => ['fn' => $fn, 'priority' => 99, 'once' => true],
'bar' => ['fn' => $fn, 'priority' => 50],
]);
$this->assertEquals([
['name' => 'foo', 'fn' => $fn, 'priority' => 99, 'once' => true],
['name' => 'bar', 'fn' => $fn, 'priority' => 50, 'once' => false],
], $o->listeners);
}
public function testRegistersMultipleEvents()
{
$fn = function () {};
$eventArray = [['fn' => $fn], ['fn' => $fn]];
$o = new ObjectWithEvents([
'foo' => $eventArray,
'bar' => $eventArray,
]);
$this->assertEquals([
['name' => 'foo', 'fn' => $fn, 'priority' => 0, 'once' => false],
['name' => 'foo', 'fn' => $fn, 'priority' => 0, 'once' => false],
['name' => 'bar', 'fn' => $fn, 'priority' => 0, 'once' => false],
['name' => 'bar', 'fn' => $fn, 'priority' => 0, 'once' => false],
], $o->listeners);
$this->assertCount(2, $o->getEmitter()->listeners('foo'));
$this->assertCount(2, $o->getEmitter()->listeners('bar'));
}
public function testRegistersEventsWithOnce()
{
$called = 0;
$fn = function () use (&$called) { $called++; };
$o = new ObjectWithEvents(['foo' => ['fn' => $fn, 'once' => true]]);
$ev = $this->getMock('GuzzleHttp\Event\EventInterface');
$o->getEmitter()->emit('foo', $ev);
$o->getEmitter()->emit('foo', $ev);
$this->assertEquals(1, $called);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesEvents()
{
$o = new ObjectWithEvents(['foo' => 'bar']);
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Client;
use GuzzleHttp\Event\ProgressEvent;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Transaction;
/**
* @covers GuzzleHttp\Event\ProgressEvent
*/
class ProgressEventTest extends \PHPUnit_Framework_TestCase
{
public function testContainsNumbers()
{
$t = new Transaction(new Client(), new Request('GET', 'http://a.com'));
$p = new ProgressEvent($t, 2, 1, 3, 0);
$this->assertSame($t->request, $p->getRequest());
$this->assertSame($t->client, $p->getClient());
$this->assertEquals(2, $p->downloadSize);
$this->assertEquals(1, $p->downloaded);
$this->assertEquals(3, $p->uploadSize);
$this->assertEquals(0, $p->uploaded);
}
}

View file

@ -0,0 +1,74 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Event\RequestEvents;
/**
* @covers GuzzleHttp\Event\RequestEvents
*/
class RequestEventsTest extends \PHPUnit_Framework_TestCase
{
public function prepareEventProvider()
{
$cb = function () {};
return [
[[], ['complete'], $cb, ['complete' => [$cb]]],
[
['complete' => $cb],
['complete'],
$cb,
['complete' => [$cb, $cb]]
],
[
['prepare' => []],
['error', 'foo'],
$cb,
[
'prepare' => [],
'error' => [$cb],
'foo' => [$cb]
]
],
[
['prepare' => []],
['prepare'],
$cb,
[
'prepare' => [$cb]
]
],
[
['prepare' => ['fn' => $cb]],
['prepare'], $cb,
[
'prepare' => [
['fn' => $cb],
$cb
]
]
],
];
}
/**
* @dataProvider prepareEventProvider
*/
public function testConvertsEventArrays(
array $in,
array $events,
$add,
array $out
) {
$result = RequestEvents::convertEventArray($in, $events, $add);
$this->assertEquals($out, $result);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesEventFormat()
{
RequestEvents::convertEventArray(['foo' => false], ['foo'], []);
}
}

View file

@ -0,0 +1,20 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Exception\ParseException;
use GuzzleHttp\Message\Response;
/**
* @covers GuzzleHttp\Exception\ParseException
*/
class ParseExceptionTest extends \PHPUnit_Framework_TestCase
{
public function testHasResponse()
{
$res = new Response(200);
$e = new ParseException('foo', $res);
$this->assertSame($res, $e->getResponse());
$this->assertEquals('foo', $e->getMessage());
}
}

View file

@ -0,0 +1,83 @@
<?php
namespace GuzzleHttp\Tests\Event;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Ring\Exception\ConnectException;
/**
* @covers GuzzleHttp\Exception\RequestException
*/
class RequestExceptionTest extends \PHPUnit_Framework_TestCase
{
public function testHasRequestAndResponse()
{
$req = new Request('GET', '/');
$res = new Response(200);
$e = new RequestException('foo', $req, $res);
$this->assertSame($req, $e->getRequest());
$this->assertSame($res, $e->getResponse());
$this->assertTrue($e->hasResponse());
$this->assertEquals('foo', $e->getMessage());
}
public function testCreatesGenerateException()
{
$e = RequestException::create(new Request('GET', '/'));
$this->assertEquals('Error completing request', $e->getMessage());
$this->assertInstanceOf('GuzzleHttp\Exception\RequestException', $e);
}
public function testCreatesClientErrorResponseException()
{
$e = RequestException::create(new Request('GET', '/'), new Response(400));
$this->assertEquals(
'Client error response [url] / [status code] 400 [reason phrase] Bad Request',
$e->getMessage()
);
$this->assertInstanceOf('GuzzleHttp\Exception\ClientException', $e);
}
public function testCreatesServerErrorResponseException()
{
$e = RequestException::create(new Request('GET', '/'), new Response(500));
$this->assertEquals(
'Server error response [url] / [status code] 500 [reason phrase] Internal Server Error',
$e->getMessage()
);
$this->assertInstanceOf('GuzzleHttp\Exception\ServerException', $e);
}
public function testCreatesGenericErrorResponseException()
{
$e = RequestException::create(new Request('GET', '/'), new Response(600));
$this->assertEquals(
'Unsuccessful response [url] / [status code] 600 [reason phrase] ',
$e->getMessage()
);
$this->assertInstanceOf('GuzzleHttp\Exception\RequestException', $e);
}
public function testHasStatusCodeAsExceptionCode() {
$e = RequestException::create(new Request('GET', '/'), new Response(442));
$this->assertEquals(442, $e->getCode());
}
public function testWrapsRequestExceptions()
{
$e = new \Exception('foo');
$r = new Request('GET', 'http://www.oo.com');
$ex = RequestException::wrapException($r, $e);
$this->assertInstanceOf('GuzzleHttp\Exception\RequestException', $ex);
$this->assertSame($e, $ex->getPrevious());
}
public function testWrapsConnectExceptions()
{
$e = new ConnectException('foo');
$r = new Request('GET', 'http://www.oo.com');
$ex = RequestException::wrapException($r, $e);
$this->assertInstanceOf('GuzzleHttp\Exception\ConnectException', $ex);
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace GuzzleHttp\tests\Exception;
use GuzzleHttp\Exception\XmlParseException;
/**
* @covers GuzzleHttp\Exception\XmlParseException
*/
class XmlParseExceptionTest extends \PHPUnit_Framework_TestCase
{
public function testHasError()
{
$error = new \LibXMLError();
$e = new XmlParseException('foo', null, null, $error);
$this->assertSame($error, $e->getError());
$this->assertEquals('foo', $e->getMessage());
}
}

View file

@ -0,0 +1,123 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Client;
use GuzzleHttp\Event\AbstractTransferEvent;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Event\EndEvent;
use GuzzleHttp\Event\ErrorEvent;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Pool;
class IntegrationTest extends \PHPUnit_Framework_TestCase
{
/**
* @issue https://github.com/guzzle/guzzle/issues/867
*/
public function testDoesNotFailInEventSystemForNetworkError()
{
$c = new Client();
$r = $c->createRequest(
'GET',
Server::$url,
[
'timeout' => 1,
'connect_timeout' => 1,
'proxy' => 'http://127.0.0.1:123/foo'
]
);
$events = [];
$fn = function(AbstractTransferEvent $event) use (&$events) {
$events[] = [
get_class($event),
$event->hasResponse(),
$event->getResponse()
];
};
$pool = new Pool($c, [$r], [
'error' => $fn,
'end' => $fn
]);
$pool->wait();
$this->assertCount(2, $events);
$this->assertEquals('GuzzleHttp\Event\ErrorEvent', $events[0][0]);
$this->assertFalse($events[0][1]);
$this->assertNull($events[0][2]);
$this->assertEquals('GuzzleHttp\Event\EndEvent', $events[1][0]);
$this->assertFalse($events[1][1]);
$this->assertNull($events[1][2]);
}
/**
* @issue https://github.com/guzzle/guzzle/issues/866
*/
public function testProperyGetsTransferStats()
{
$transfer = [];
Server::enqueue([new Response(200)]);
$c = new Client();
$response = $c->get(Server::$url . '/foo', [
'events' => [
'end' => function (EndEvent $e) use (&$transfer) {
$transfer = $e->getTransferInfo();
}
]
]);
$this->assertEquals(Server::$url . '/foo', $response->getEffectiveUrl());
$this->assertNotEmpty($transfer);
$this->assertArrayHasKey('url', $transfer);
}
public function testNestedFutureResponsesAreResolvedWhenSending()
{
$c = new Client();
$total = 3;
Server::enqueue([
new Response(200),
new Response(201),
new Response(202)
]);
$c->getEmitter()->on(
'complete',
function (CompleteEvent $e) use (&$total) {
if (--$total) {
$e->retry();
}
}
);
$response = $c->get(Server::$url);
$this->assertEquals(202, $response->getStatusCode());
$this->assertEquals('GuzzleHttp\Message\Response', get_class($response));
}
public function testNestedFutureErrorsAreResolvedWhenSending()
{
$c = new Client();
$total = 3;
Server::enqueue([
new Response(500),
new Response(501),
new Response(502)
]);
$c->getEmitter()->on(
'error',
function (ErrorEvent $e) use (&$total) {
if (--$total) {
$e->retry();
}
}
);
try {
$c->get(Server::$url);
$this->fail('Did not throw!');
} catch (RequestException $e) {
$this->assertEquals(502, $e->getResponse()->getStatusCode());
}
}
}

View file

@ -0,0 +1,269 @@
<?php
namespace GuzzleHttp\Tests\Message;
use GuzzleHttp\Message\AbstractMessage;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Stream\Stream;
/**
* @covers \GuzzleHttp\Message\AbstractMessage
*/
class AbstractMessageTest extends \PHPUnit_Framework_TestCase
{
public function testHasProtocolVersion()
{
$m = new Request('GET', '/');
$this->assertEquals(1.1, $m->getProtocolVersion());
}
public function testHasHeaders()
{
$m = new Request('GET', 'http://foo.com');
$this->assertFalse($m->hasHeader('foo'));
$m->addHeader('foo', 'bar');
$this->assertTrue($m->hasHeader('foo'));
}
public function testInitializesMessageWithProtocolVersionOption()
{
$m = new Request('GET', '/', [], null, [
'protocol_version' => '10'
]);
$this->assertEquals(10, $m->getProtocolVersion());
}
public function testHasBody()
{
$m = new Request('GET', 'http://foo.com');
$this->assertNull($m->getBody());
$s = Stream::factory('test');
$m->setBody($s);
$this->assertSame($s, $m->getBody());
$this->assertFalse($m->hasHeader('Content-Length'));
}
public function testCanRemoveBodyBySettingToNullAndRemovesCommonBodyHeaders()
{
$m = new Request('GET', 'http://foo.com');
$m->setBody(Stream::factory('foo'));
$m->setHeader('Content-Length', 3);
$m->setHeader('Transfer-Encoding', 'chunked');
$m->setBody(null);
$this->assertNull($m->getBody());
$this->assertFalse($m->hasHeader('Content-Length'));
$this->assertFalse($m->hasHeader('Transfer-Encoding'));
}
public function testCastsToString()
{
$m = new Request('GET', 'http://foo.com');
$m->setHeader('foo', 'bar');
$m->setBody(Stream::factory('baz'));
$this->assertEquals("GET / HTTP/1.1\r\nHost: foo.com\r\nfoo: bar\r\n\r\nbaz", (string) $m);
}
public function parseParamsProvider()
{
$res1 = array(
array(
'<http:/.../front.jpeg>',
'rel' => 'front',
'type' => 'image/jpeg',
),
array(
'<http://.../back.jpeg>',
'rel' => 'back',
'type' => 'image/jpeg',
),
);
return array(
array(
'<http:/.../front.jpeg>; rel="front"; type="image/jpeg", <http://.../back.jpeg>; rel=back; type="image/jpeg"',
$res1
),
array(
'<http:/.../front.jpeg>; rel="front"; type="image/jpeg",<http://.../back.jpeg>; rel=back; type="image/jpeg"',
$res1
),
array(
'foo="baz"; bar=123, boo, test="123", foobar="foo;bar"',
array(
array('foo' => 'baz', 'bar' => '123'),
array('boo'),
array('test' => '123'),
array('foobar' => 'foo;bar')
)
),
array(
'<http://.../side.jpeg?test=1>; rel="side"; type="image/jpeg",<http://.../side.jpeg?test=2>; rel=side; type="image/jpeg"',
array(
array('<http://.../side.jpeg?test=1>', 'rel' => 'side', 'type' => 'image/jpeg'),
array('<http://.../side.jpeg?test=2>', 'rel' => 'side', 'type' => 'image/jpeg')
)
),
array(
'',
array()
)
);
}
/**
* @dataProvider parseParamsProvider
*/
public function testParseParams($header, $result)
{
$request = new Request('GET', '/', ['foo' => $header]);
$this->assertEquals($result, Request::parseHeader($request, 'foo'));
}
public function testAddsHeadersWhenNotPresent()
{
$h = new Request('GET', 'http://foo.com');
$h->addHeader('foo', 'bar');
$this->assertInternalType('string', $h->getHeader('foo'));
$this->assertEquals('bar', $h->getHeader('foo'));
}
public function testAddsHeadersWhenPresentSameCase()
{
$h = new Request('GET', 'http://foo.com');
$h->addHeader('foo', 'bar');
$h->addHeader('foo', 'baz');
$this->assertEquals('bar, baz', $h->getHeader('foo'));
$this->assertEquals(['bar', 'baz'], $h->getHeaderAsArray('foo'));
}
public function testAddsMultipleHeaders()
{
$h = new Request('GET', 'http://foo.com');
$h->addHeaders([
'foo' => ' bar',
'baz' => [' bam ', 'boo']
]);
$this->assertEquals([
'foo' => ['bar'],
'baz' => ['bam', 'boo'],
'Host' => ['foo.com']
], $h->getHeaders());
}
public function testAddsHeadersWhenPresentDifferentCase()
{
$h = new Request('GET', 'http://foo.com');
$h->addHeader('Foo', 'bar');
$h->addHeader('fOO', 'baz');
$this->assertEquals('bar, baz', $h->getHeader('foo'));
}
public function testAddsHeadersWithArray()
{
$h = new Request('GET', 'http://foo.com');
$h->addHeader('Foo', ['bar', 'baz']);
$this->assertEquals('bar, baz', $h->getHeader('foo'));
}
public function testGetHeadersReturnsAnArrayOfOverTheWireHeaderValues()
{
$h = new Request('GET', 'http://foo.com');
$h->addHeader('foo', 'bar');
$h->addHeader('Foo', 'baz');
$h->addHeader('boO', 'test');
$result = $h->getHeaders();
$this->assertInternalType('array', $result);
$this->assertArrayHasKey('Foo', $result);
$this->assertArrayNotHasKey('foo', $result);
$this->assertArrayHasKey('boO', $result);
$this->assertEquals(['bar', 'baz'], $result['Foo']);
$this->assertEquals(['test'], $result['boO']);
}
public function testSetHeaderOverwritesExistingValues()
{
$h = new Request('GET', 'http://foo.com');
$h->setHeader('foo', 'bar');
$this->assertEquals('bar', $h->getHeader('foo'));
$h->setHeader('Foo', 'baz');
$this->assertEquals('baz', $h->getHeader('foo'));
$this->assertArrayHasKey('Foo', $h->getHeaders());
}
public function testSetHeaderOverwritesExistingValuesUsingHeaderArray()
{
$h = new Request('GET', 'http://foo.com');
$h->setHeader('foo', ['bar']);
$this->assertEquals('bar', $h->getHeader('foo'));
}
public function testSetHeaderOverwritesExistingValuesUsingArray()
{
$h = new Request('GET', 'http://foo.com');
$h->setHeader('foo', ['bar']);
$this->assertEquals('bar', $h->getHeader('foo'));
}
public function testSetHeadersOverwritesAllHeaders()
{
$h = new Request('GET', 'http://foo.com');
$h->setHeader('foo', 'bar');
$h->setHeaders(['foo' => 'a', 'boo' => 'b']);
$this->assertEquals(['foo' => ['a'], 'boo' => ['b']], $h->getHeaders());
}
public function testChecksIfCaseInsensitiveHeaderIsPresent()
{
$h = new Request('GET', 'http://foo.com');
$h->setHeader('foo', 'bar');
$this->assertTrue($h->hasHeader('foo'));
$this->assertTrue($h->hasHeader('Foo'));
$h->setHeader('fOo', 'bar');
$this->assertTrue($h->hasHeader('Foo'));
}
public function testRemovesHeaders()
{
$h = new Request('GET', 'http://foo.com');
$h->setHeader('foo', 'bar');
$h->removeHeader('foo');
$this->assertFalse($h->hasHeader('foo'));
$h->setHeader('Foo', 'bar');
$h->removeHeader('FOO');
$this->assertFalse($h->hasHeader('foo'));
}
public function testReturnsCorrectTypeWhenMissing()
{
$h = new Request('GET', 'http://foo.com');
$this->assertInternalType('string', $h->getHeader('foo'));
$this->assertInternalType('array', $h->getHeaderAsArray('foo'));
}
public function testSetsIntegersAndFloatsAsHeaders()
{
$h = new Request('GET', 'http://foo.com');
$h->setHeader('foo', 10);
$h->setHeader('bar', 10.5);
$h->addHeader('foo', 10);
$h->addHeader('bar', 10.5);
$this->assertSame('10, 10', $h->getHeader('foo'));
$this->assertSame('10.5, 10.5', $h->getHeader('bar'));
}
public function testGetsResponseStartLine()
{
$m = new Response(200);
$this->assertEquals('HTTP/1.1 200 OK', Response::getStartLine($m));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testThrowsWhenMessageIsUnknown()
{
$m = $this->getMockBuilder('GuzzleHttp\Message\AbstractMessage')
->getMockForAbstractClass();
AbstractMessage::getStartLine($m);
}
}

View file

@ -0,0 +1,160 @@
<?php
namespace GuzzleHttp\Tests\Message;
use GuzzleHttp\Message\FutureResponse;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Stream\Stream;
use React\Promise\Deferred;
use GuzzleHttp\Tests\Subscriber\MockTest;
class FutureResponseTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Class has no foo property
*/
public function testValidatesMagicMethod()
{
$f = MockTest::createFuture(function () {});
$f->foo;
}
public function testDoesTheSameAsResponseWhenDereferenced()
{
$str = Stream::factory('foo');
$response = new Response(200, ['Foo' => 'bar'], $str);
$future = MockTest::createFuture(function () use ($response) {
return $response;
});
$this->assertFalse($this->readAttribute($future, 'isRealized'));
$this->assertEquals(200, $future->getStatusCode());
$this->assertTrue($this->readAttribute($future, 'isRealized'));
// Deref again does nothing.
$future->wait();
$this->assertTrue($this->readAttribute($future, 'isRealized'));
$this->assertEquals('bar', $future->getHeader('Foo'));
$this->assertEquals(['bar'], $future->getHeaderAsarray('Foo'));
$this->assertSame($response->getHeaders(), $future->getHeaders());
$this->assertSame(
$response->getBody(),
$future->getBody()
);
$this->assertSame(
$response->getProtocolVersion(),
$future->getProtocolVersion()
);
$this->assertSame(
$response->getEffectiveUrl(),
$future->getEffectiveUrl()
);
$future->setEffectiveUrl('foo');
$this->assertEquals('foo', $response->getEffectiveUrl());
$this->assertSame(
$response->getReasonPhrase(),
$future->getReasonPhrase()
);
$this->assertTrue($future->hasHeader('foo'));
$future->removeHeader('Foo');
$this->assertFalse($future->hasHeader('foo'));
$this->assertFalse($response->hasHeader('foo'));
$future->setBody(Stream::factory('true'));
$this->assertEquals('true', (string) $response->getBody());
$this->assertTrue($future->json());
$this->assertSame((string) $response, (string) $future);
$future->setBody(Stream::factory('<a><b>c</b></a>'));
$this->assertEquals('c', (string) $future->xml()->b);
$future->addHeader('a', 'b');
$this->assertEquals('b', $future->getHeader('a'));
$future->addHeaders(['a' => '2']);
$this->assertEquals('b, 2', $future->getHeader('a'));
$future->setHeader('a', '2');
$this->assertEquals('2', $future->getHeader('a'));
$future->setHeaders(['a' => '3']);
$this->assertEquals(['a' => ['3']], $future->getHeaders());
}
public function testCanDereferenceManually()
{
$response = new Response(200, ['Foo' => 'bar']);
$future = MockTest::createFuture(function () use ($response) {
return $response;
});
$this->assertSame($response, $future->wait());
$this->assertTrue($this->readAttribute($future, 'isRealized'));
}
public function testCanCancel()
{
$c = false;
$deferred = new Deferred();
$future = new FutureResponse(
$deferred->promise(),
function () {},
function () use (&$c) {
$c = true;
return true;
}
);
$this->assertFalse($this->readAttribute($future, 'isRealized'));
$future->cancel();
$this->assertTrue($this->readAttribute($future, 'isRealized'));
$future->cancel();
}
public function testCanCancelButReturnsFalseForNoCancelFunction()
{
$future = MockTest::createFuture(function () {});
$future->cancel();
$this->assertTrue($this->readAttribute($future, 'isRealized'));
}
/**
* @expectedException \GuzzleHttp\Ring\Exception\CancelledFutureAccessException
*/
public function testAccessingCancelledResponseThrows()
{
$future = MockTest::createFuture(function () {});
$future->cancel();
$future->getStatusCode();
}
public function testExceptionInToStringTriggersError()
{
$future = MockTest::createFuture(function () {
throw new \Exception('foo');
});
$err = '';
set_error_handler(function () use (&$err) {
$err = func_get_args()[1];
});
echo $future;
restore_error_handler();
$this->assertContains('foo', $err);
}
public function testProxiesSetters()
{
$str = Stream::factory('foo');
$response = new Response(200, ['Foo' => 'bar'], $str);
$future = MockTest::createFuture(function () use ($response) {
return $response;
});
$future->setStatusCode(202);
$this->assertEquals(202, $future->getStatusCode());
$this->assertEquals(202, $response->getStatusCode());
$future->setReasonPhrase('foo');
$this->assertEquals('foo', $future->getReasonPhrase());
$this->assertEquals('foo', $response->getReasonPhrase());
}
}

View file

@ -0,0 +1,601 @@
<?php
namespace GuzzleHttp\Tests\Message;
use GuzzleHttp\Client;
use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Post\PostFile;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Message\MessageFactory;
use GuzzleHttp\Subscriber\Cookie;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Query;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Subscriber\History;
use GuzzleHttp\Subscriber\Mock;
/**
* @covers GuzzleHttp\Message\MessageFactory
*/
class MessageFactoryTest extends \PHPUnit_Framework_TestCase
{
public function testCreatesResponses()
{
$f = new MessageFactory();
$response = $f->createResponse(200, ['foo' => 'bar'], 'test', [
'protocol_version' => 1.0
]);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['foo' => ['bar']], $response->getHeaders());
$this->assertEquals('test', $response->getBody());
$this->assertEquals(1.0, $response->getProtocolVersion());
}
public function testCreatesRequestFromMessage()
{
$f = new MessageFactory();
$req = $f->fromMessage("GET / HTTP/1.1\r\nBaz: foo\r\n\r\n");
$this->assertEquals('GET', $req->getMethod());
$this->assertEquals('/', $req->getPath());
$this->assertEquals('foo', $req->getHeader('Baz'));
$this->assertNull($req->getBody());
}
public function testCreatesRequestFromMessageWithBody()
{
$req = (new MessageFactory())->fromMessage("GET / HTTP/1.1\r\nBaz: foo\r\n\r\ntest");
$this->assertEquals('test', $req->getBody());
}
public function testCreatesRequestWithPostBody()
{
$req = (new MessageFactory())->createRequest('GET', 'http://www.foo.com', ['body' => ['abc' => '123']]);
$this->assertEquals('abc=123', $req->getBody());
}
public function testCreatesRequestWithPostBodyScalars()
{
$req = (new MessageFactory())->createRequest(
'GET',
'http://www.foo.com',
['body' => [
'abc' => true,
'123' => false,
'foo' => null,
'baz' => 10,
'bam' => 1.5,
'boo' => [1]]
]
);
$this->assertEquals(
'abc=1&123=&foo&baz=10&bam=1.5&boo%5B0%5D=1',
(string) $req->getBody()
);
}
public function testCreatesRequestWithPostBodyAndPostFiles()
{
$pf = fopen(__FILE__, 'r');
$pfi = new PostFile('ghi', 'abc', __FILE__);
$req = (new MessageFactory())->createRequest('GET', 'http://www.foo.com', [
'body' => [
'abc' => '123',
'def' => $pf,
'ghi' => $pfi
]
]);
$this->assertInstanceOf('GuzzleHttp\Post\PostBody', $req->getBody());
$s = (string) $req;
$this->assertContains('testCreatesRequestWithPostBodyAndPostFiles', $s);
$this->assertContains('multipart/form-data', $s);
$this->assertTrue(in_array($pfi, $req->getBody()->getFiles(), true));
}
public function testCreatesResponseFromMessage()
{
$response = (new MessageFactory())->fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest");
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('OK', $response->getReasonPhrase());
$this->assertEquals('4', $response->getHeader('Content-Length'));
$this->assertEquals('test', $response->getBody(true));
}
public function testCanCreateHeadResponses()
{
$response = (new MessageFactory())->fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\n");
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('OK', $response->getReasonPhrase());
$this->assertEquals(null, $response->getBody());
$this->assertEquals('4', $response->getHeader('Content-Length'));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testFactoryRequiresMessageForRequest()
{
(new MessageFactory())->fromMessage('');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage foo
*/
public function testValidatesOptionsAreImplemented()
{
(new MessageFactory())->createRequest('GET', 'http://test.com', ['foo' => 'bar']);
}
public function testOptionsAddsRequestOptions()
{
$request = (new MessageFactory())->createRequest(
'GET', 'http://test.com', ['config' => ['baz' => 'bar']]
);
$this->assertEquals('bar', $request->getConfig()->get('baz'));
}
public function testCanDisableRedirects()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['allow_redirects' => false]);
$this->assertEmpty($request->getEmitter()->listeners('complete'));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesRedirects()
{
(new MessageFactory())->createRequest('GET', '/', ['allow_redirects' => 'foo']);
}
public function testCanEnableStrictRedirectsAndSpecifyMax()
{
$request = (new MessageFactory())->createRequest('GET', '/', [
'allow_redirects' => ['max' => 10, 'strict' => true]
]);
$this->assertTrue($request->getConfig()['redirect']['strict']);
$this->assertEquals(10, $request->getConfig()['redirect']['max']);
}
public function testCanAddCookiesFromHash()
{
$request = (new MessageFactory())->createRequest('GET', 'http://www.test.com/', [
'cookies' => ['Foo' => 'Bar']
]);
$cookies = null;
foreach ($request->getEmitter()->listeners('before') as $l) {
if ($l[0] instanceof Cookie) {
$cookies = $l[0];
break;
}
}
if (!$cookies) {
$this->fail('Did not add cookie listener');
} else {
$this->assertCount(1, $cookies->getCookieJar());
}
}
public function testAddsCookieUsingTrue()
{
$factory = new MessageFactory();
$request1 = $factory->createRequest('GET', '/', ['cookies' => true]);
$request2 = $factory->createRequest('GET', '/', ['cookies' => true]);
$listeners = function ($r) {
return array_filter($r->getEmitter()->listeners('before'), function ($l) {
return $l[0] instanceof Cookie;
});
};
$this->assertSame($listeners($request1), $listeners($request2));
}
public function testAddsCookieFromCookieJar()
{
$jar = new CookieJar();
$request = (new MessageFactory())->createRequest('GET', '/', ['cookies' => $jar]);
foreach ($request->getEmitter()->listeners('before') as $l) {
if ($l[0] instanceof Cookie) {
$this->assertSame($jar, $l[0]->getCookieJar());
}
}
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesCookies()
{
(new MessageFactory())->createRequest('GET', '/', ['cookies' => 'baz']);
}
public function testCanAddQuery()
{
$request = (new MessageFactory())->createRequest('GET', 'http://foo.com', [
'query' => ['Foo' => 'Bar']
]);
$this->assertEquals('Bar', $request->getQuery()->get('Foo'));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesQuery()
{
(new MessageFactory())->createRequest('GET', 'http://foo.com', [
'query' => 'foo'
]);
}
public function testCanSetDefaultQuery()
{
$request = (new MessageFactory())->createRequest('GET', 'http://foo.com?test=abc', [
'query' => ['Foo' => 'Bar', 'test' => 'def']
]);
$this->assertEquals('Bar', $request->getQuery()->get('Foo'));
$this->assertEquals('abc', $request->getQuery()->get('test'));
}
public function testCanSetDefaultQueryWithObject()
{
$request = (new MessageFactory)->createRequest(
'GET',
'http://foo.com?test=abc', [
'query' => new Query(['Foo' => 'Bar', 'test' => 'def'])
]
);
$this->assertEquals('Bar', $request->getQuery()->get('Foo'));
$this->assertEquals('abc', $request->getQuery()->get('test'));
}
public function testCanAddBasicAuth()
{
$request = (new MessageFactory())->createRequest('GET', 'http://foo.com', [
'auth' => ['michael', 'test']
]);
$this->assertTrue($request->hasHeader('Authorization'));
}
public function testCanAddDigestAuth()
{
$request = (new MessageFactory())->createRequest('GET', 'http://foo.com', [
'auth' => ['michael', 'test', 'digest']
]);
$this->assertEquals('michael:test', $request->getConfig()->getPath('curl/' . CURLOPT_USERPWD));
$this->assertEquals(CURLAUTH_DIGEST, $request->getConfig()->getPath('curl/' . CURLOPT_HTTPAUTH));
}
public function testCanDisableAuth()
{
$request = (new MessageFactory())->createRequest('GET', 'http://foo.com', [
'auth' => false
]);
$this->assertFalse($request->hasHeader('Authorization'));
}
public function testCanSetCustomAuth()
{
$request = (new MessageFactory())->createRequest('GET', 'http://foo.com', [
'auth' => 'foo'
]);
$this->assertEquals('foo', $request->getConfig()['auth']);
}
public function testCanAddEvents()
{
$foo = null;
$client = new Client();
$client->getEmitter()->attach(new Mock([new Response(200)]));
$client->get('http://test.com', [
'events' => [
'before' => function () use (&$foo) { $foo = true; }
]
]);
$this->assertTrue($foo);
}
public function testCanAddEventsWithPriority()
{
$foo = null;
$client = new Client();
$client->getEmitter()->attach(new Mock(array(new Response(200))));
$request = $client->createRequest('GET', 'http://test.com', [
'events' => [
'before' => [
'fn' => function () use (&$foo) { $foo = true; },
'priority' => 123
]
]
]);
$client->send($request);
$this->assertTrue($foo);
$l = $this->readAttribute($request->getEmitter(), 'listeners');
$this->assertArrayHasKey(123, $l['before']);
}
public function testCanAddEventsOnce()
{
$foo = 0;
$client = new Client();
$client->getEmitter()->attach(new Mock([
new Response(200),
new Response(200),
]));
$fn = function () use (&$foo) { ++$foo; };
$request = $client->createRequest('GET', 'http://test.com', [
'events' => ['before' => ['fn' => $fn, 'once' => true]]
]);
$client->send($request);
$this->assertEquals(1, $foo);
$client->send($request);
$this->assertEquals(1, $foo);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesEventContainsFn()
{
$client = new Client(['base_url' => 'http://test.com']);
$client->createRequest('GET', '/', ['events' => ['before' => ['foo' => 'bar']]]);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesEventIsArray()
{
$client = new Client(['base_url' => 'http://test.com']);
$client->createRequest('GET', '/', ['events' => ['before' => '123']]);
}
public function testCanAddSubscribers()
{
$mock = new Mock([new Response(200)]);
$client = new Client();
$client->getEmitter()->attach($mock);
$request = $client->get('http://test.com', ['subscribers' => [$mock]]);
}
public function testCanDisableExceptions()
{
$client = new Client();
$this->assertEquals(500, $client->get('http://test.com', [
'subscribers' => [new Mock([new Response(500)])],
'exceptions' => false
])->getStatusCode());
}
public function testCanChangeSaveToLocation()
{
$saveTo = Stream::factory();
$request = (new MessageFactory())->createRequest('GET', '/', ['save_to' => $saveTo]);
$this->assertSame($saveTo, $request->getConfig()->get('save_to'));
}
public function testCanSetProxy()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['proxy' => '192.168.16.121']);
$this->assertEquals('192.168.16.121', $request->getConfig()->get('proxy'));
}
public function testCanSetHeadersOption()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['headers' => ['Foo' => 'Bar']]);
$this->assertEquals('Bar', (string) $request->getHeader('Foo'));
}
public function testCanSetHeaders()
{
$request = (new MessageFactory())->createRequest('GET', '/', [
'headers' => ['Foo' => ['Baz', 'Bar'], 'Test' => '123']
]);
$this->assertEquals('Baz, Bar', $request->getHeader('Foo'));
$this->assertEquals('123', $request->getHeader('Test'));
}
public function testCanSetTimeoutOption()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['timeout' => 1.5]);
$this->assertEquals(1.5, $request->getConfig()->get('timeout'));
}
public function testCanSetConnectTimeoutOption()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['connect_timeout' => 1.5]);
$this->assertEquals(1.5, $request->getConfig()->get('connect_timeout'));
}
public function testCanSetDebug()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['debug' => true]);
$this->assertTrue($request->getConfig()->get('debug'));
}
public function testCanSetVerifyToOff()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['verify' => false]);
$this->assertFalse($request->getConfig()->get('verify'));
}
public function testCanSetVerifyToOn()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['verify' => true]);
$this->assertTrue($request->getConfig()->get('verify'));
}
public function testCanSetVerifyToPath()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['verify' => '/foo.pem']);
$this->assertEquals('/foo.pem', $request->getConfig()->get('verify'));
}
public function inputValidation()
{
return array_map(function ($option) { return array($option); }, array(
'headers', 'events', 'subscribers', 'params'
));
}
/**
* @dataProvider inputValidation
* @expectedException \InvalidArgumentException
*/
public function testValidatesInput($option)
{
(new MessageFactory())->createRequest('GET', '/', [$option => 'foo']);
}
public function testCanAddSslKey()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['ssl_key' => '/foo.pem']);
$this->assertEquals('/foo.pem', $request->getConfig()->get('ssl_key'));
}
public function testCanAddSslKeyPassword()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['ssl_key' => ['/foo.pem', 'bar']]);
$this->assertEquals(['/foo.pem', 'bar'], $request->getConfig()->get('ssl_key'));
}
public function testCanAddSslCert()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['cert' => '/foo.pem']);
$this->assertEquals('/foo.pem', $request->getConfig()->get('cert'));
}
public function testCanAddSslCertPassword()
{
$request = (new MessageFactory())->createRequest('GET', '/', ['cert' => ['/foo.pem', 'bar']]);
$this->assertEquals(['/foo.pem', 'bar'], $request->getConfig()->get('cert'));
}
public function testCreatesBodyWithoutZeroString()
{
$request = (new MessageFactory())->createRequest('PUT', 'http://test.com', ['body' => '0']);
$this->assertSame('0', (string) $request->getBody());
}
public function testCanSetProtocolVersion()
{
$request = (new MessageFactory())->createRequest('GET', 'http://t.com', ['version' => 1.0]);
$this->assertEquals(1.0, $request->getProtocolVersion());
}
public function testCanAddJsonData()
{
$request = (new MessageFactory())->createRequest('PUT', 'http://f.com', [
'json' => ['foo' => 'bar']
]);
$this->assertEquals(
'application/json',
$request->getHeader('Content-Type')
);
$this->assertEquals('{"foo":"bar"}', (string) $request->getBody());
}
public function testCanAddJsonDataToAPostRequest()
{
$request = (new MessageFactory())->createRequest('POST', 'http://f.com', [
'json' => ['foo' => 'bar']
]);
$this->assertEquals(
'application/json',
$request->getHeader('Content-Type')
);
$this->assertEquals('{"foo":"bar"}', (string) $request->getBody());
}
public function testCanAddJsonDataAndNotOverwriteContentType()
{
$request = (new MessageFactory())->createRequest('PUT', 'http://f.com', [
'headers' => ['Content-Type' => 'foo'],
'json' => null
]);
$this->assertEquals('foo', $request->getHeader('Content-Type'));
$this->assertEquals('null', (string) $request->getBody());
}
public function testCanUseCustomRequestOptions()
{
$c = false;
$f = new MessageFactory([
'foo' => function (RequestInterface $request, $value) use (&$c) {
$c = true;
$this->assertEquals('bar', $value);
}
]);
$f->createRequest('PUT', 'http://f.com', [
'headers' => ['Content-Type' => 'foo'],
'foo' => 'bar'
]);
$this->assertTrue($c);
}
/**
* @ticket https://github.com/guzzle/guzzle/issues/706
*/
public function testDoesNotApplyPostBodyRightAway()
{
$request = (new MessageFactory())->createRequest('POST', 'http://f.cn', [
'body' => ['foo' => ['bar', 'baz']]
]);
$this->assertEquals('', $request->getHeader('Content-Type'));
$this->assertEquals('', $request->getHeader('Content-Length'));
$request->getBody()->setAggregator(Query::duplicateAggregator());
$request->getBody()->applyRequestHeaders($request);
$this->assertEquals('foo=bar&foo=baz', $request->getBody());
}
public function testCanForceMultipartUploadWithContentType()
{
$client = new Client();
$client->getEmitter()->attach(new Mock([new Response(200)]));
$history = new History();
$client->getEmitter()->attach($history);
$client->post('http://foo.com', [
'headers' => ['Content-Type' => 'multipart/form-data'],
'body' => ['foo' => 'bar']
]);
$this->assertContains(
'multipart/form-data; boundary=',
$history->getLastRequest()->getHeader('Content-Type')
);
$this->assertContains(
"Content-Disposition: form-data; name=\"foo\"\r\n\r\nbar",
(string) $history->getLastRequest()->getBody()
);
}
public function testDecodeDoesNotForceAcceptHeader()
{
$request = (new MessageFactory())->createRequest('POST', 'http://f.cn', [
'decode_content' => true
]);
$this->assertEquals('', $request->getHeader('Accept-Encoding'));
$this->assertTrue($request->getConfig()->get('decode_content'));
}
public function testDecodeCanAddAcceptHeader()
{
$request = (new MessageFactory())->createRequest('POST', 'http://f.cn', [
'decode_content' => 'gzip'
]);
$this->assertEquals('gzip', $request->getHeader('Accept-Encoding'));
$this->assertTrue($request->getConfig()->get('decode_content'));
}
public function testCanDisableDecoding()
{
$request = (new MessageFactory())->createRequest('POST', 'http://f.cn', [
'decode_content' => false
]);
$this->assertEquals('', $request->getHeader('Accept-Encoding'));
$this->assertNull($request->getConfig()->get('decode_content'));
}
}
class ExtendedFactory extends MessageFactory
{
protected function add_foo() {}
}

View file

@ -0,0 +1,276 @@
<?php
namespace GuzzleHttp\Tests\Message;
use GuzzleHttp\Message\MessageParser;
/**
* @covers \GuzzleHttp\Message\MessageParser
*/
class MessageParserTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider requestProvider
*/
public function testParsesRequests($message, $parts)
{
$parser = new MessageParser();
$this->compareRequestResults($parts, $parser->parseRequest($message));
}
/**
* @dataProvider responseProvider
*/
public function testParsesResponses($message, $parts)
{
$parser = new MessageParser();
$this->compareResponseResults($parts, $parser->parseResponse($message));
}
public function testParsesRequestsWithMissingProtocol()
{
$parser = new MessageParser();
$parts = $parser->parseRequest("GET /\r\nHost: Foo.com\r\n\r\n");
$this->assertEquals('GET', $parts['method']);
$this->assertEquals('HTTP', $parts['protocol']);
$this->assertEquals('1.1', $parts['protocol_version']);
}
public function testParsesRequestsWithMissingVersion()
{
$parser = new MessageParser();
$parts = $parser->parseRequest("GET / HTTP\r\nHost: Foo.com\r\n\r\n");
$this->assertEquals('GET', $parts['method']);
$this->assertEquals('HTTP', $parts['protocol']);
$this->assertEquals('1.1', $parts['protocol_version']);
}
public function testParsesResponsesWithMissingReasonPhrase()
{
$parser = new MessageParser();
$parts = $parser->parseResponse("HTTP/1.1 200\r\n\r\n");
$this->assertEquals('200', $parts['code']);
$this->assertEquals('', $parts['reason_phrase']);
$this->assertEquals('HTTP', $parts['protocol']);
$this->assertEquals('1.1', $parts['protocol_version']);
}
public function requestProvider()
{
$auth = base64_encode('michael:foo');
return array(
// Empty request
array('', false),
// Converts casing of request. Does not require host header.
array("GET / HTTP/1.1\r\n\r\n", array(
'method' => 'GET',
'protocol' => 'HTTP',
'protocol_version' => '1.1',
'request_url' => array(
'scheme' => 'http',
'host' => '',
'port' => '',
'path' => '/',
'query' => ''
),
'headers' => array(),
'body' => ''
)),
// Path and query string, multiple header values per header and case sensitive storage
array("HEAD /path?query=foo HTTP/1.0\r\nHost: example.com\r\nX-Foo: foo\r\nx-foo: Bar\r\nX-Foo: foo\r\nX-Foo: Baz\r\n\r\n", array(
'method' => 'HEAD',
'protocol' => 'HTTP',
'protocol_version' => '1.0',
'request_url' => array(
'scheme' => 'http',
'host' => 'example.com',
'port' => '',
'path' => '/path',
'query' => 'query=foo'
),
'headers' => array(
'Host' => 'example.com',
'X-Foo' => array('foo', 'foo', 'Baz'),
'x-foo' => 'Bar'
),
'body' => ''
)),
// Includes a body
array("PUT / HTTP/1.0\r\nhost: example.com:443\r\nContent-Length: 4\r\n\r\ntest", array(
'method' => 'PUT',
'protocol' => 'HTTP',
'protocol_version' => '1.0',
'request_url' => array(
'scheme' => 'https',
'host' => 'example.com',
'port' => '443',
'path' => '/',
'query' => ''
),
'headers' => array(
'host' => 'example.com:443',
'Content-Length' => '4'
),
'body' => 'test'
)),
// Includes Authorization headers
array("GET / HTTP/1.1\r\nHost: example.com:8080\r\nAuthorization: Basic {$auth}\r\n\r\n", array(
'method' => 'GET',
'protocol' => 'HTTP',
'protocol_version' => '1.1',
'request_url' => array(
'scheme' => 'http',
'host' => 'example.com',
'port' => '8080',
'path' => '/',
'query' => ''
),
'headers' => array(
'Host' => 'example.com:8080',
'Authorization' => "Basic {$auth}"
),
'body' => ''
)),
// Include authorization header
array("GET / HTTP/1.1\r\nHost: example.com:8080\r\nauthorization: Basic {$auth}\r\n\r\n", array(
'method' => 'GET',
'protocol' => 'HTTP',
'protocol_version' => '1.1',
'request_url' => array(
'scheme' => 'http',
'host' => 'example.com',
'port' => '8080',
'path' => '/',
'query' => ''
),
'headers' => array(
'Host' => 'example.com:8080',
'authorization' => "Basic {$auth}"
),
'body' => ''
)),
);
}
public function responseProvider()
{
return array(
// Empty request
array('', false),
array("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", array(
'protocol' => 'HTTP',
'protocol_version' => '1.1',
'code' => '200',
'reason_phrase' => 'OK',
'headers' => array(
'Content-Length' => 0
),
'body' => ''
)),
array("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n", array(
'protocol' => 'HTTP',
'protocol_version' => '1.0',
'code' => '400',
'reason_phrase' => 'Bad Request',
'headers' => array(
'Content-Length' => 0
),
'body' => ''
)),
array("HTTP/1.0 100 Continue\r\n\r\n", array(
'protocol' => 'HTTP',
'protocol_version' => '1.0',
'code' => '100',
'reason_phrase' => 'Continue',
'headers' => array(),
'body' => ''
)),
array("HTTP/1.1 204 No Content\r\nX-Foo: foo\r\nx-foo: Bar\r\nX-Foo: foo\r\n\r\n", array(
'protocol' => 'HTTP',
'protocol_version' => '1.1',
'code' => '204',
'reason_phrase' => 'No Content',
'headers' => array(
'X-Foo' => array('foo', 'foo'),
'x-foo' => 'Bar'
),
'body' => ''
)),
array("HTTP/1.1 200 Ok that is great!\r\nContent-Length: 4\r\n\r\nTest", array(
'protocol' => 'HTTP',
'protocol_version' => '1.1',
'code' => '200',
'reason_phrase' => 'Ok that is great!',
'headers' => array(
'Content-Length' => 4
),
'body' => 'Test'
)),
);
}
public function compareRequestResults($result, $expected)
{
if (!$result) {
$this->assertFalse($expected);
return;
}
$this->assertEquals($result['method'], $expected['method']);
$this->assertEquals($result['protocol'], $expected['protocol']);
$this->assertEquals($result['protocol_version'], $expected['protocol_version']);
$this->assertEquals($result['request_url'], $expected['request_url']);
$this->assertEquals($result['body'], $expected['body']);
$this->compareHttpHeaders($result['headers'], $expected['headers']);
}
public function compareResponseResults($result, $expected)
{
if (!$result) {
$this->assertFalse($expected);
return;
}
$this->assertEquals($result['protocol'], $expected['protocol']);
$this->assertEquals($result['protocol_version'], $expected['protocol_version']);
$this->assertEquals($result['code'], $expected['code']);
$this->assertEquals($result['reason_phrase'], $expected['reason_phrase']);
$this->assertEquals($result['body'], $expected['body']);
$this->compareHttpHeaders($result['headers'], $expected['headers']);
}
protected function normalizeHeaders($headers)
{
$normalized = array();
foreach ($headers as $key => $value) {
$key = strtolower($key);
if (!isset($normalized[$key])) {
$normalized[$key] = $value;
} elseif (!is_array($normalized[$key])) {
$normalized[$key] = array($value);
} else {
$normalized[$key][] = $value;
}
}
foreach ($normalized as $key => &$value) {
if (is_array($value)) {
sort($value);
}
}
return $normalized;
}
public function compareHttpHeaders($result, $expected)
{
// Aggregate all headers case-insensitively
$result = $this->normalizeHeaders($result);
$expected = $this->normalizeHeaders($expected);
$this->assertEquals($result, $expected);
}
}

View file

@ -0,0 +1,132 @@
<?php
namespace GuzzleHttp\Tests\Message;
use GuzzleHttp\Event\Emitter;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Query;
use GuzzleHttp\Stream\Stream;
/**
* @covers GuzzleHttp\Message\Request
*/
class RequestTest extends \PHPUnit_Framework_TestCase
{
public function testConstructorInitializesMessage()
{
$r = new Request('PUT', '/test', ['test' => '123'], Stream::factory('foo'));
$this->assertEquals('PUT', $r->getMethod());
$this->assertEquals('/test', $r->getUrl());
$this->assertEquals('123', $r->getHeader('test'));
$this->assertEquals('foo', $r->getBody());
}
public function testConstructorInitializesMessageWithProtocolVersion()
{
$r = new Request('GET', '', [], null, ['protocol_version' => 10]);
$this->assertEquals(10, $r->getProtocolVersion());
}
public function testConstructorInitializesMessageWithEmitter()
{
$e = new Emitter();
$r = new Request('GET', '', [], null, ['emitter' => $e]);
$this->assertSame($r->getEmitter(), $e);
}
public function testCloneIsDeep()
{
$r = new Request('GET', '/test', ['foo' => 'baz'], Stream::factory('foo'));
$r2 = clone $r;
$this->assertNotSame($r->getEmitter(), $r2->getEmitter());
$this->assertEquals('foo', $r2->getBody());
$r->getConfig()->set('test', 123);
$this->assertFalse($r2->getConfig()->hasKey('test'));
$r->setPath('/abc');
$this->assertEquals('/test', $r2->getPath());
}
public function testCastsToString()
{
$r = new Request('GET', 'http://test.com/test', ['foo' => 'baz'], Stream::factory('body'));
$s = explode("\r\n", (string) $r);
$this->assertEquals("GET /test HTTP/1.1", $s[0]);
$this->assertContains('Host: test.com', $s);
$this->assertContains('foo: baz', $s);
$this->assertContains('', $s);
$this->assertContains('body', $s);
}
public function testSettingUrlOverridesHostHeaders()
{
$r = new Request('GET', 'http://test.com/test');
$r->setUrl('https://baz.com/bar');
$this->assertEquals('baz.com', $r->getHost());
$this->assertEquals('baz.com', $r->getHeader('Host'));
$this->assertEquals('/bar', $r->getPath());
$this->assertEquals('https', $r->getScheme());
}
public function testQueryIsMutable()
{
$r = new Request('GET', 'http://www.foo.com?baz=bar');
$this->assertEquals('baz=bar', $r->getQuery());
$this->assertInstanceOf('GuzzleHttp\Query', $r->getQuery());
$r->getQuery()->set('hi', 'there');
$this->assertEquals('/?baz=bar&hi=there', $r->getResource());
}
public function testQueryCanChange()
{
$r = new Request('GET', 'http://www.foo.com?baz=bar');
$r->setQuery(new Query(['foo' => 'bar']));
$this->assertEquals('foo=bar', $r->getQuery());
}
public function testCanChangeMethod()
{
$r = new Request('GET', 'http://www.foo.com');
$r->setMethod('put');
$this->assertEquals('PUT', $r->getMethod());
}
public function testCanChangeSchemeWithPort()
{
$r = new Request('GET', 'http://www.foo.com:80');
$r->setScheme('https');
$this->assertEquals('https://www.foo.com', $r->getUrl());
}
public function testCanChangeScheme()
{
$r = new Request('GET', 'http://www.foo.com');
$r->setScheme('https');
$this->assertEquals('https://www.foo.com', $r->getUrl());
}
public function testCanChangeHost()
{
$r = new Request('GET', 'http://www.foo.com:222');
$r->setHost('goo');
$this->assertEquals('http://goo:222', $r->getUrl());
$this->assertEquals('goo:222', $r->getHeader('host'));
$r->setHost('goo:80');
$this->assertEquals('http://goo', $r->getUrl());
$this->assertEquals('goo', $r->getHeader('host'));
}
public function testCanChangePort()
{
$r = new Request('GET', 'http://www.foo.com:222');
$this->assertSame(222, $r->getPort());
$this->assertEquals('www.foo.com', $r->getHost());
$this->assertEquals('www.foo.com:222', $r->getHeader('host'));
$r->setPort(80);
$this->assertSame(80, $r->getPort());
$this->assertEquals('www.foo.com', $r->getHost());
$this->assertEquals('www.foo.com', $r->getHeader('host'));
}
}

View file

@ -0,0 +1,120 @@
<?php
namespace GuzzleHttp\Tests\Message;
use GuzzleHttp\Exception\XmlParseException;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Stream\Stream;
/**
* @covers GuzzleHttp\Message\Response
*/
class ResponseTest extends \PHPUnit_Framework_TestCase
{
public function testCanProvideCustomStatusCodeAndReasonPhrase()
{
$response = new Response(999, [], null, ['reason_phrase' => 'hi!']);
$this->assertEquals(999, $response->getStatusCode());
$this->assertEquals('hi!', $response->getReasonPhrase());
}
public function testConvertsToString()
{
$response = new Response(200);
$this->assertEquals("HTTP/1.1 200 OK\r\n\r\n", (string) $response);
// Add another header
$response = new Response(200, ['X-Test' => 'Guzzle']);
$this->assertEquals("HTTP/1.1 200 OK\r\nX-Test: Guzzle\r\n\r\n", (string) $response);
$response = new Response(200, ['Content-Length' => 4], Stream::factory('test'));
$this->assertEquals("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest", (string) $response);
}
public function testConvertsToStringAndSeeksToByteZero()
{
$response = new Response(200);
$s = Stream::factory('foo');
$s->read(1);
$response->setBody($s);
$this->assertEquals("HTTP/1.1 200 OK\r\n\r\nfoo", (string) $response);
}
public function testParsesJsonResponses()
{
$json = '{"foo": "bar"}';
$response = new Response(200, [], Stream::factory($json));
$this->assertEquals(['foo' => 'bar'], $response->json());
$this->assertEquals(json_decode($json), $response->json(['object' => true]));
$response = new Response(200);
$this->assertEquals(null, $response->json());
}
/**
* @expectedException \GuzzleHttp\Exception\ParseException
* @expectedExceptionMessage Unable to parse JSON data: JSON_ERROR_SYNTAX - Syntax error, malformed JSON
*/
public function testThrowsExceptionWhenFailsToParseJsonResponse()
{
$response = new Response(200, [], Stream::factory('{"foo": "'));
$response->json();
}
public function testParsesXmlResponses()
{
$response = new Response(200, [], Stream::factory('<abc><foo>bar</foo></abc>'));
$this->assertEquals('bar', (string) $response->xml()->foo);
// Always return a SimpleXMLElement from the xml method
$response = new Response(200);
$this->assertEmpty((string) $response->xml()->foo);
}
/**
* @expectedException \GuzzleHttp\Exception\XmlParseException
* @expectedExceptionMessage Unable to parse response body into XML: String could not be parsed as XML
*/
public function testThrowsExceptionWhenFailsToParseXmlResponse()
{
$response = new Response(200, [], Stream::factory('<abc'));
try {
$response->xml();
} catch (XmlParseException $e) {
$xmlParseError = $e->getError();
$this->assertInstanceOf('\LibXMLError', $xmlParseError);
$this->assertContains("Couldn't find end of Start Tag abc line 1", $xmlParseError->message);
throw $e;
}
}
public function testHasEffectiveUrl()
{
$r = new Response(200);
$this->assertNull($r->getEffectiveUrl());
$r->setEffectiveUrl('http://www.test.com');
$this->assertEquals('http://www.test.com', $r->getEffectiveUrl());
}
public function testPreventsComplexExternalEntities()
{
$xml = '<?xml version="1.0"?><!DOCTYPE scan[<!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=ResponseTest.php">]><scan>&test;</scan>';
$response = new Response(200, [], Stream::factory($xml));
$oldCwd = getcwd();
chdir(__DIR__);
try {
$xml = $response->xml();
chdir($oldCwd);
$this->markTestIncomplete('Did not throw the expected exception! XML resolved as: ' . $xml->asXML());
} catch (\Exception $e) {
chdir($oldCwd);
}
}
public function testStatusAndReasonAreMutable()
{
$response = new Response(200);
$response->setStatusCode(201);
$this->assertEquals(201, $response->getStatusCode());
$response->setReasonPhrase('Foo');
$this->assertEquals('Foo', $response->getReasonPhrase());
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Mimetypes;
/**
* @covers GuzzleHttp\Mimetypes
*/
class MimetypesTest extends \PHPUnit_Framework_TestCase
{
public function testGetsFromExtension()
{
$this->assertEquals('text/x-php', Mimetypes::getInstance()->fromExtension('php'));
}
public function testGetsFromFilename()
{
$this->assertEquals('text/x-php', Mimetypes::getInstance()->fromFilename(__FILE__));
}
public function testGetsFromCaseInsensitiveFilename()
{
$this->assertEquals('text/x-php', Mimetypes::getInstance()->fromFilename(strtoupper(__FILE__)));
}
public function testReturnsNullWhenNoMatchFound()
{
$this->assertNull(Mimetypes::getInstance()->fromExtension('foobar'));
}
}

View file

@ -0,0 +1,319 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Client;
use GuzzleHttp\Event\RequestEvents;
use GuzzleHttp\Pool;
use GuzzleHttp\Ring\Client\MockHandler;
use GuzzleHttp\Ring\Future\FutureArray;
use GuzzleHttp\Subscriber\History;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Event\ErrorEvent;
use GuzzleHttp\Event\EndEvent;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Subscriber\Mock;
use React\Promise\Deferred;
class PoolTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesIterable()
{
new Pool(new Client(), 'foo');
}
public function testCanControlPoolSizeAndClient()
{
$c = new Client();
$p = new Pool($c, [], ['pool_size' => 10]);
$this->assertSame($c, $this->readAttribute($p, 'client'));
$this->assertEquals(10, $this->readAttribute($p, 'poolSize'));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesEachElement()
{
$c = new Client();
$requests = ['foo'];
$p = new Pool($c, new \ArrayIterator($requests));
$p->wait();
}
public function testSendsAndRealizesFuture()
{
$c = $this->getClient();
$p = new Pool($c, [$c->createRequest('GET', 'http://foo.com')]);
$this->assertTrue($p->wait());
$this->assertFalse($p->wait());
$this->assertTrue($this->readAttribute($p, 'isRealized'));
$this->assertFalse($p->cancel());
}
public function testSendsManyRequestsInCappedPool()
{
$c = $this->getClient();
$p = new Pool($c, [$c->createRequest('GET', 'http://foo.com')]);
$this->assertTrue($p->wait());
$this->assertFalse($p->wait());
}
public function testSendsRequestsThatHaveNotBeenRealized()
{
$c = $this->getClient();
$p = new Pool($c, [$c->createRequest('GET', 'http://foo.com')]);
$this->assertTrue($p->wait());
$this->assertFalse($p->wait());
$this->assertFalse($p->cancel());
}
public function testCancelsInFlightRequests()
{
$c = $this->getClient();
$h = new History();
$c->getEmitter()->attach($h);
$p = new Pool($c, [
$c->createRequest('GET', 'http://foo.com'),
$c->createRequest('GET', 'http://foo.com', [
'events' => [
'before' => [
'fn' => function () use (&$p) {
$this->assertTrue($p->cancel());
},
'priority' => RequestEvents::EARLY
]
]
])
]);
ob_start();
$p->wait();
$contents = ob_get_clean();
$this->assertEquals(1, count($h));
$this->assertEquals('Cancelling', $contents);
}
private function getClient()
{
$deferred = new Deferred();
$future = new FutureArray(
$deferred->promise(),
function() use ($deferred) {
$deferred->resolve(['status' => 200, 'headers' => []]);
}, function () {
echo 'Cancelling';
}
);
return new Client(['handler' => new MockHandler($future)]);
}
public function testBatchesRequests()
{
$client = new Client(['handler' => function () {
throw new \RuntimeException('No network access');
}]);
$responses = [
new Response(301, ['Location' => 'http://foo.com/bar']),
new Response(200),
new Response(200),
new Response(404)
];
$client->getEmitter()->attach(new Mock($responses));
$requests = [
$client->createRequest('GET', 'http://foo.com/baz'),
$client->createRequest('HEAD', 'http://httpbin.org/get'),
$client->createRequest('PUT', 'http://httpbin.org/put'),
];
$a = $b = $c = $d = 0;
$result = Pool::batch($client, $requests, [
'before' => function (BeforeEvent $e) use (&$a) { $a++; },
'complete' => function (CompleteEvent $e) use (&$b) { $b++; },
'error' => function (ErrorEvent $e) use (&$c) { $c++; },
'end' => function (EndEvent $e) use (&$d) { $d++; }
]);
$this->assertEquals(4, $a);
$this->assertEquals(2, $b);
$this->assertEquals(1, $c);
$this->assertEquals(3, $d);
$this->assertCount(3, $result);
$this->assertInstanceOf('GuzzleHttp\BatchResults', $result);
// The first result is actually the second (redirect) response.
$this->assertSame($responses[1], $result[0]);
// The second result is a 1:1 request:response map
$this->assertSame($responses[2], $result[1]);
// The third entry is the 404 RequestException
$this->assertSame($responses[3], $result[2]->getResponse());
}
public function testBatchesRequestsWithDynamicPoolSize()
{
$client = new Client(['handler' => function () {
throw new \RuntimeException('No network access');
}]);
$responses = [
new Response(301, ['Location' => 'http://foo.com/bar']),
new Response(200),
new Response(200),
new Response(404)
];
$client->getEmitter()->attach(new Mock($responses));
$requests = [
$client->createRequest('GET', 'http://foo.com/baz'),
$client->createRequest('HEAD', 'http://httpbin.org/get'),
$client->createRequest('PUT', 'http://httpbin.org/put'),
];
$a = $b = $c = $d = 0;
$result = Pool::batch($client, $requests, [
'before' => function (BeforeEvent $e) use (&$a) { $a++; },
'complete' => function (CompleteEvent $e) use (&$b) { $b++; },
'error' => function (ErrorEvent $e) use (&$c) { $c++; },
'end' => function (EndEvent $e) use (&$d) { $d++; },
'pool_size' => function ($queueSize) {
static $options = [1, 2, 1];
static $queued = 0;
$this->assertEquals(
$queued,
$queueSize,
'The number of queued requests should be equal to the sum of pool sizes so far.'
);
$next = array_shift($options);
$queued += $next;
return $next;
}
]);
$this->assertEquals(4, $a);
$this->assertEquals(2, $b);
$this->assertEquals(1, $c);
$this->assertEquals(3, $d);
$this->assertCount(3, $result);
$this->assertInstanceOf('GuzzleHttp\BatchResults', $result);
// The first result is actually the second (redirect) response.
$this->assertSame($responses[1], $result[0]);
// The second result is a 1:1 request:response map
$this->assertSame($responses[2], $result[1]);
// The third entry is the 404 RequestException
$this->assertSame($responses[3], $result[2]->getResponse());
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Each event listener must be a callable or
*/
public function testBatchValidatesTheEventFormat()
{
$client = new Client();
$requests = [$client->createRequest('GET', 'http://foo.com/baz')];
Pool::batch($client, $requests, ['complete' => 'foo']);
}
public function testEmitsProgress()
{
$client = new Client(['handler' => function () {
throw new \RuntimeException('No network access');
}]);
$responses = [new Response(200), new Response(404)];
$client->getEmitter()->attach(new Mock($responses));
$requests = [
$client->createRequest('GET', 'http://foo.com/baz'),
$client->createRequest('HEAD', 'http://httpbin.org/get')
];
$pool = new Pool($client, $requests);
$count = 0;
$thenned = null;
$pool->then(
function ($value) use (&$thenned) {
$thenned = $value;
},
null,
function ($result) use (&$count, $requests) {
$this->assertSame($requests[$count], $result['request']);
if ($count == 0) {
$this->assertNull($result['error']);
$this->assertEquals(200, $result['response']->getStatusCode());
} else {
$this->assertInstanceOf(
'GuzzleHttp\Exception\ClientException',
$result['error']
);
}
$count++;
}
);
$pool->wait();
$this->assertEquals(2, $count);
$this->assertEquals(true, $thenned);
}
public function testDoesNotThrowInErrorEvent()
{
$client = new Client();
$responses = [new Response(404)];
$client->getEmitter()->attach(new Mock($responses));
$requests = [$client->createRequest('GET', 'http://foo.com/baz')];
$result = Pool::batch($client, $requests);
$this->assertCount(1, $result);
$this->assertInstanceOf('GuzzleHttp\Exception\ClientException', $result[0]);
}
public function testHasSendMethod()
{
$client = new Client();
$responses = [new Response(404)];
$history = new History();
$client->getEmitter()->attach($history);
$client->getEmitter()->attach(new Mock($responses));
$requests = [$client->createRequest('GET', 'http://foo.com/baz')];
Pool::send($client, $requests);
$this->assertCount(1, $history);
}
public function testDoesNotInfinitelyRecurse()
{
$client = new Client(['handler' => function () {
throw new \RuntimeException('No network access');
}]);
$last = null;
$client->getEmitter()->on(
'before',
function (BeforeEvent $e) use (&$last) {
$e->intercept(new Response(200));
if (function_exists('xdebug_get_stack_depth')) {
if ($last) {
$this->assertEquals($last, xdebug_get_stack_depth());
} else {
$last = xdebug_get_stack_depth();
}
}
}
);
$requests = [];
for ($i = 0; $i < 100; $i++) {
$requests[] = $client->createRequest('GET', 'http://foo.com');
}
$pool = new Pool($client, $requests);
$pool->wait();
}
}

View file

@ -0,0 +1,120 @@
<?php
namespace GuzzleHttp\Tests\Post;
use GuzzleHttp\Post\MultipartBody;
use GuzzleHttp\Post\PostFile;
/**
* @covers GuzzleHttp\Post\MultipartBody
*/
class MultipartBodyTest extends \PHPUnit_Framework_TestCase
{
protected function getTestBody()
{
return new MultipartBody(['foo' => 'bar'], [
new PostFile('foo', 'abc', 'foo.txt')
], 'abcdef');
}
public function testConstructorAddsFieldsAndFiles()
{
$b = $this->getTestBody();
$this->assertEquals('abcdef', $b->getBoundary());
$c = (string) $b;
$this->assertContains("--abcdef\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n", $c);
$this->assertContains("--abcdef\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"foo.txt\"\r\n"
. "Content-Type: text/plain\r\n\r\nabc\r\n--abcdef--", $c);
}
public function testDoesNotModifyFieldFormat()
{
$m = new MultipartBody(['foo+baz' => 'bar+bam %20 boo'], [
new PostFile('foo+bar', 'abc %20 123', 'foo.txt')
], 'abcdef');
$this->assertContains('name="foo+baz"', (string) $m);
$this->assertContains('name="foo+bar"', (string) $m);
$this->assertContains('bar+bam %20 boo', (string) $m);
$this->assertContains('abc %20 123', (string) $m);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testConstructorValidatesFiles()
{
new MultipartBody([], ['bar']);
}
public function testConstructorCanCreateBoundary()
{
$b = new MultipartBody();
$this->assertNotNull($b->getBoundary());
}
public function testWrapsStreamMethods()
{
$b = $this->getTestBody();
$this->assertFalse($b->write('foo'));
$this->assertFalse($b->isWritable());
$this->assertTrue($b->isReadable());
$this->assertTrue($b->isSeekable());
$this->assertEquals(0, $b->tell());
}
public function testCanDetachFieldsAndFiles()
{
$b = $this->getTestBody();
$b->detach();
$b->close();
$this->assertEquals('', (string) $b);
}
public function testIsSeekableReturnsTrueIfAllAreSeekable()
{
$s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
->setMethods(['isSeekable', 'isReadable'])
->getMockForAbstractClass();
$s->expects($this->once())
->method('isSeekable')
->will($this->returnValue(false));
$s->expects($this->once())
->method('isReadable')
->will($this->returnValue(true));
$p = new PostFile('foo', $s, 'foo.php');
$b = new MultipartBody([], [$p]);
$this->assertFalse($b->isSeekable());
$this->assertFalse($b->seek(10));
}
public function testReadsFromBuffer()
{
$b = $this->getTestBody();
$c = $b->read(1);
$c .= $b->read(1);
$c .= $b->read(1);
$c .= $b->read(1);
$c .= $b->read(1);
$this->assertEquals('--abc', $c);
}
public function testCalculatesSize()
{
$b = $this->getTestBody();
$this->assertEquals(strlen($b), $b->getSize());
}
public function testCalculatesSizeAndReturnsNullForUnknown()
{
$s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
->setMethods(['getSize', 'isReadable'])
->getMockForAbstractClass();
$s->expects($this->once())
->method('getSize')
->will($this->returnValue(null));
$s->expects($this->once())
->method('isReadable')
->will($this->returnValue(true));
$b = new MultipartBody([], [new PostFile('foo', $s, 'foo.php')]);
$this->assertNull($b->getSize());
}
}

View file

@ -0,0 +1,255 @@
<?php
namespace GuzzleHttp\Tests\Post;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Post\PostBody;
use GuzzleHttp\Post\PostFile;
use GuzzleHttp\Query;
/**
* @covers GuzzleHttp\Post\PostBody
*/
class PostBodyTest extends \PHPUnit_Framework_TestCase
{
public function testWrapsBasicStreamFunctionality()
{
$b = new PostBody();
$this->assertTrue($b->isSeekable());
$this->assertTrue($b->isReadable());
$this->assertFalse($b->isWritable());
$this->assertFalse($b->write('foo'));
}
public function testApplyingWithNothingDoesNothing()
{
$b = new PostBody();
$m = new Request('POST', '/');
$b->applyRequestHeaders($m);
$this->assertFalse($m->hasHeader('Content-Length'));
$this->assertFalse($m->hasHeader('Content-Type'));
}
public function testCanForceMultipartUploadsWhenApplying()
{
$b = new PostBody();
$b->forceMultipartUpload(true);
$m = new Request('POST', '/');
$b->applyRequestHeaders($m);
$this->assertContains(
'multipart/form-data',
$m->getHeader('Content-Type')
);
}
public function testApplyingWithFilesAddsMultipartUpload()
{
$b = new PostBody();
$p = new PostFile('foo', fopen(__FILE__, 'r'));
$b->addFile($p);
$this->assertEquals([$p], $b->getFiles());
$this->assertNull($b->getFile('missing'));
$this->assertSame($p, $b->getFile('foo'));
$m = new Request('POST', '/');
$b->applyRequestHeaders($m);
$this->assertContains(
'multipart/form-data',
$m->getHeader('Content-Type')
);
$this->assertTrue($m->hasHeader('Content-Length'));
}
public function testApplyingWithFieldsAddsMultipartUpload()
{
$b = new PostBody();
$b->setField('foo', 'bar');
$this->assertEquals(['foo' => 'bar'], $b->getFields());
$m = new Request('POST', '/');
$b->applyRequestHeaders($m);
$this->assertContains(
'application/x-www-form',
$m->getHeader('Content-Type')
);
$this->assertTrue($m->hasHeader('Content-Length'));
}
public function testMultipartWithNestedFields()
{
$b = new PostBody();
$b->setField('foo', ['bar' => 'baz']);
$b->forceMultipartUpload(true);
$this->assertEquals(['foo' => ['bar' => 'baz']], $b->getFields());
$m = new Request('POST', '/');
$b->applyRequestHeaders($m);
$this->assertContains(
'multipart/form-data',
$m->getHeader('Content-Type')
);
$this->assertTrue($m->hasHeader('Content-Length'));
$contents = $b->getContents();
$this->assertContains('name="foo[bar]"', $contents);
$this->assertNotContains('name="foo"', $contents);
}
public function testCountProvidesFieldsAndFiles()
{
$b = new PostBody();
$b->setField('foo', 'bar');
$b->addFile(new PostFile('foo', fopen(__FILE__, 'r')));
$this->assertEquals(2, count($b));
$b->clearFiles();
$b->removeField('foo');
$this->assertEquals(0, count($b));
$this->assertEquals([], $b->getFiles());
$this->assertEquals([], $b->getFields());
}
public function testHasFields()
{
$b = new PostBody();
$b->setField('foo', 'bar');
$b->setField('baz', '123');
$this->assertEquals('bar', $b->getField('foo'));
$this->assertEquals('123', $b->getField('baz'));
$this->assertNull($b->getField('ahh'));
$this->assertTrue($b->hasField('foo'));
$this->assertFalse($b->hasField('test'));
$b->replaceFields(['abc' => '123']);
$this->assertFalse($b->hasField('foo'));
$this->assertTrue($b->hasField('abc'));
}
public function testConvertsFieldsToQueryStyleBody()
{
$b = new PostBody();
$b->setField('foo', 'bar');
$b->setField('baz', '123');
$this->assertEquals('foo=bar&baz=123', $b);
$this->assertEquals(15, $b->getSize());
$b->seek(0);
$this->assertEquals('foo=bar&baz=123', $b->getContents());
$b->seek(0);
$this->assertEquals('foo=bar&baz=123', $b->read(1000));
$this->assertEquals(15, $b->tell());
}
public function testCanSpecifyQueryAggregator()
{
$b = new PostBody();
$b->setField('foo', ['baz', 'bar']);
$this->assertEquals('foo%5B0%5D=baz&foo%5B1%5D=bar', (string) $b);
$b = new PostBody();
$b->setField('foo', ['baz', 'bar']);
$agg = Query::duplicateAggregator();
$b->setAggregator($agg);
$this->assertEquals('foo=baz&foo=bar', (string) $b);
}
public function testDetachesAndCloses()
{
$b = new PostBody();
$b->setField('foo', 'bar');
$b->detach();
$b->close();
$this->assertEquals('', $b->read(10));
}
public function testDetachesWhenBodyIsPresent()
{
$b = new PostBody();
$b->setField('foo', 'bar');
$b->getContents();
$b->detach();
}
public function testFlushAndMetadataPlaceholders()
{
$b = new PostBody();
$this->assertEquals([], $b->getMetadata());
$this->assertNull($b->getMetadata('foo'));
}
public function testCreatesMultipartUploadWithMultiFields()
{
$b = new PostBody();
$b->setField('testing', ['baz', 'bar']);
$b->setField('other', 'hi');
$b->setField('third', 'there');
$b->addFile(new PostFile('foo', fopen(__FILE__, 'r')));
$s = (string) $b;
$this->assertContains(file_get_contents(__FILE__), $s);
$this->assertContains('testing=bar', $s);
$this->assertContains(
'Content-Disposition: form-data; name="third"',
$s
);
$this->assertContains(
'Content-Disposition: form-data; name="other"',
$s
);
}
public function testMultipartWithBase64Fields()
{
$b = new PostBody();
$b->setField('foo64', '/xA2JhWEqPcgyLRDdir9WSRi/khpb2Lh3ooqv+5VYoc=');
$b->forceMultipartUpload(true);
$this->assertEquals(
['foo64' => '/xA2JhWEqPcgyLRDdir9WSRi/khpb2Lh3ooqv+5VYoc='],
$b->getFields()
);
$m = new Request('POST', '/');
$b->applyRequestHeaders($m);
$this->assertContains(
'multipart/form-data',
$m->getHeader('Content-Type')
);
$this->assertTrue($m->hasHeader('Content-Length'));
$contents = $b->getContents();
$this->assertContains('name="foo64"', $contents);
$this->assertContains(
'/xA2JhWEqPcgyLRDdir9WSRi/khpb2Lh3ooqv+5VYoc=',
$contents
);
}
public function testMultipartWithAmpersandInValue()
{
$b = new PostBody();
$b->setField('a', 'b&c=d');
$b->forceMultipartUpload(true);
$this->assertEquals(['a' => 'b&c=d'], $b->getFields());
$m = new Request('POST', '/');
$b->applyRequestHeaders($m);
$this->assertContains(
'multipart/form-data',
$m->getHeader('Content-Type')
);
$this->assertTrue($m->hasHeader('Content-Length'));
$contents = $b->getContents();
$this->assertContains('name="a"', $contents);
$this->assertContains('b&c=d', $contents);
}
/**
* @expectedException \GuzzleHttp\Stream\Exception\CannotAttachException
*/
public function testCannotAttach()
{
$b = new PostBody();
$b->attach('foo');
}
public function testDoesNotOverwriteExistingHeaderForUrlencoded()
{
$m = new Request('POST', 'http://foo.com', [
'content-type' => 'application/x-www-form-urlencoded; charset=utf-8'
]);
$b = new PostBody();
$b->setField('foo', 'bar');
$b->applyRequestHeaders($m);
$this->assertEquals(
'application/x-www-form-urlencoded; charset=utf-8',
$m->getHeader('Content-Type')
);
}
}

View file

@ -0,0 +1,61 @@
<?php
namespace GuzzleHttp\Tests\Post;
use GuzzleHttp\Post\MultipartBody;
use GuzzleHttp\Post\PostFile;
use GuzzleHttp\Stream\Stream;
/**
* @covers GuzzleHttp\Post\PostFile
*/
class PostFileTest extends \PHPUnit_Framework_TestCase
{
public function testCreatesFromString()
{
$p = new PostFile('foo', 'hi', '/path/to/test.php');
$this->assertInstanceOf('GuzzleHttp\Post\PostFileInterface', $p);
$this->assertEquals('hi', $p->getContent());
$this->assertEquals('foo', $p->getName());
$this->assertEquals('/path/to/test.php', $p->getFilename());
$this->assertEquals(
'form-data; name="foo"; filename="test.php"',
$p->getHeaders()['Content-Disposition']
);
}
public function testGetsFilenameFromMetadata()
{
$p = new PostFile('foo', fopen(__FILE__, 'r'));
$this->assertEquals(__FILE__, $p->getFilename());
}
public function testDefaultsToNameWhenNoFilenameExists()
{
$p = new PostFile('foo', 'bar');
$this->assertEquals('foo', $p->getFilename());
}
public function testCreatesFromMultipartFormData()
{
$mp = new MultipartBody([], [], 'baz');
$p = new PostFile('foo', $mp);
$this->assertEquals(
'form-data; name="foo"',
$p->getHeaders()['Content-Disposition']
);
$this->assertEquals(
'multipart/form-data; boundary=baz',
$p->getHeaders()['Content-Type']
);
}
public function testCanAddHeaders()
{
$p = new PostFile('foo', Stream::factory('hi'), 'test.php', [
'X-Foo' => '123',
'Content-Disposition' => 'bar'
]);
$this->assertEquals('bar', $p->getHeaders()['Content-Disposition']);
$this->assertEquals('123', $p->getHeaders()['X-Foo']);
}
}

View file

@ -0,0 +1,80 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Query;
use GuzzleHttp\QueryParser;
class QueryParserTest extends \PHPUnit_Framework_TestCase
{
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' => ['a', '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']],
// Can deeply nest and store duplicate PHP values
['a[b][c]=1&a[b][c]=2', [
'a' => ['b' => ['c' => ['1', '2']]]
]],
// Can parse PHP style arrays
['a[b]=c&a[d]=e', ['a' => ['b' => 'c', '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)
{
$query = Query::fromString($input);
$this->assertEquals($output, $query->toArray());
// Normalize the input and output
$query->setEncodingType(false);
$this->assertEquals(rawurldecode($input), (string) $query);
}
public function testConvertsPlusSymbolsToSpacesByDefault()
{
$query = Query::fromString('var=foo+bar', true);
$this->assertEquals('foo bar', $query->get('var'));
}
public function testCanControlDecodingType()
{
$qp = new QueryParser();
$q = new Query();
$qp->parseInto($q, 'var=foo+bar', Query::RFC3986);
$this->assertEquals('foo+bar', $q->get('var'));
$qp->parseInto($q, 'var=foo+bar', Query::RFC1738);
$this->assertEquals('foo bar', $q->get('var'));
}
}

View file

@ -0,0 +1,171 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Query;
class QueryTest extends \PHPUnit_Framework_TestCase
{
public function testCanCastToString()
{
$q = new Query(['foo' => 'baz', 'bar' => 'bam boozle']);
$this->assertEquals('foo=baz&bar=bam%20boozle', (string) $q);
}
public function testCanDisableUrlEncoding()
{
$q = new Query(['bar' => 'bam boozle']);
$q->setEncodingType(false);
$this->assertEquals('bar=bam boozle', (string) $q);
}
public function testCanSpecifyRfc1783UrlEncodingType()
{
$q = new Query(['bar abc' => 'bam boozle']);
$q->setEncodingType(Query::RFC1738);
$this->assertEquals('bar+abc=bam+boozle', (string) $q);
}
public function testCanSpecifyRfc3986UrlEncodingType()
{
$q = new Query(['bar abc' => 'bam boozle', 'ሴ' => 'hi']);
$q->setEncodingType(Query::RFC3986);
$this->assertEquals('bar%20abc=bam%20boozle&%E1%88%B4=hi', (string) $q);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesEncodingType()
{
(new Query(['bar' => 'bam boozle']))->setEncodingType('foo');
}
public function testAggregatesMultipleValues()
{
$q = new Query(['foo' => ['bar', 'baz']]);
$this->assertEquals('foo%5B0%5D=bar&foo%5B1%5D=baz', (string) $q);
}
public function testCanSetAggregator()
{
$q = new Query(['foo' => ['bar', 'baz']]);
$q->setAggregator(function (array $data) {
return ['foo' => ['barANDbaz']];
});
$this->assertEquals('foo=barANDbaz', (string) $q);
}
public function testAllowsMultipleValuesPerKey()
{
$q = new Query();
$q->add('facet', 'size');
$q->add('facet', 'width');
$q->add('facet.field', 'foo');
// Use the duplicate aggregator
$q->setAggregator($q::duplicateAggregator());
$this->assertEquals('facet=size&facet=width&facet.field=foo', (string) $q);
}
public function testAllowsZeroValues()
{
$query = new Query(array(
'foo' => 0,
'baz' => '0',
'bar' => null,
'boo' => false
));
$this->assertEquals('foo=0&baz=0&bar&boo=', (string) $query);
}
private $encodeData = [
't' => [
'v1' => ['a', '1'],
'v2' => 'b',
'v3' => ['v4' => 'c', 'v5' => 'd']
]
];
public function testEncodesDuplicateAggregator()
{
$agg = Query::duplicateAggregator();
$result = $agg($this->encodeData);
$this->assertEquals(array(
't[v1]' => ['a', '1'],
't[v2]' => ['b'],
't[v3][v4]' => ['c'],
't[v3][v5]' => ['d'],
), $result);
}
public function testDuplicateEncodesNoNumericIndices()
{
$agg = Query::duplicateAggregator();
$result = $agg($this->encodeData);
$this->assertEquals(array(
't[v1]' => ['a', '1'],
't[v2]' => ['b'],
't[v3][v4]' => ['c'],
't[v3][v5]' => ['d'],
), $result);
}
public function testEncodesPhpAggregator()
{
$agg = Query::phpAggregator();
$result = $agg($this->encodeData);
$this->assertEquals(array(
't[v1][0]' => ['a'],
't[v1][1]' => ['1'],
't[v2]' => ['b'],
't[v3][v4]' => ['c'],
't[v3][v5]' => ['d'],
), $result);
}
public function testPhpEncodesNoNumericIndices()
{
$agg = Query::phpAggregator(false);
$result = $agg($this->encodeData);
$this->assertEquals(array(
't[v1][]' => ['a', '1'],
't[v2]' => ['b'],
't[v3][v4]' => ['c'],
't[v3][v5]' => ['d'],
), $result);
}
public function testCanDisableUrlEncodingDecoding()
{
$q = Query::fromString('foo=bar+baz boo%20', false);
$this->assertEquals('bar+baz boo%20', $q['foo']);
$this->assertEquals('foo=bar+baz boo%20', (string) $q);
}
public function testCanChangeUrlEncodingDecodingToRfc1738()
{
$q = Query::fromString('foo=bar+baz', Query::RFC1738);
$this->assertEquals('bar baz', $q['foo']);
$this->assertEquals('foo=bar+baz', (string) $q);
}
public function testCanChangeUrlEncodingDecodingToRfc3986()
{
$q = Query::fromString('foo=bar%20baz', Query::RFC3986);
$this->assertEquals('bar baz', $q['foo']);
$this->assertEquals('foo=bar%20baz', (string) $q);
}
public function testQueryStringsAllowSlashButDoesNotDecodeWhenDisable()
{
$q = Query::fromString('foo=bar%2Fbaz&bam=boo%20boo', Query::RFC3986);
$q->setEncodingType(false);
$this->assertEquals('foo=bar/baz&bam=boo boo', (string) $q);
}
public function testQueryStringsAllowDecodingEncodingCompletelyDisabled()
{
$q = Query::fromString('foo=bar%2Fbaz&bam=boo boo!', false);
$this->assertEquals('foo=bar%2Fbaz&bam=boo boo!', (string) $q);
}
}

View file

@ -0,0 +1,187 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\MessageFactory;
use GuzzleHttp\Message\Response;
use GuzzleHttp\RequestFsm;
use GuzzleHttp\Ring\Future\CompletedFutureArray;
use GuzzleHttp\Subscriber\Mock;
use GuzzleHttp\Transaction;
use GuzzleHttp\Client;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Event\ErrorEvent;
use GuzzleHttp\Event\EndEvent;
use GuzzleHttp\Message\FutureResponse;
use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Event\RequestEvents;
use React\Promise\Deferred;
class RequestFsmTest extends \PHPUnit_Framework_TestCase
{
private $mf;
public function setup()
{
$this->mf = new MessageFactory();
}
public function testEmitsBeforeEventInTransition()
{
$fsm = new RequestFsm(function () {
return new CompletedFutureArray(['status' => 200]);
}, $this->mf);
$t = new Transaction(new Client(), new Request('GET', 'http://foo.com'));
$c = false;
$t->request->getEmitter()->on('before', function (BeforeEvent $e) use (&$c) {
$c = true;
});
$fsm($t);
$this->assertTrue($c);
}
public function testEmitsCompleteEventInTransition()
{
$fsm = new RequestFsm(function () {
return new CompletedFutureArray(['status' => 200]);
}, $this->mf);
$t = new Transaction(new Client(), new Request('GET', 'http://foo.com'));
$t->response = new Response(200);
$t->state = 'complete';
$c = false;
$t->request->getEmitter()->on('complete', function (CompleteEvent $e) use (&$c) {
$c = true;
});
$fsm($t);
$this->assertTrue($c);
}
public function testDoesNotEmitCompleteForFuture()
{
$fsm = new RequestFsm(function () {
return new CompletedFutureArray(['status' => 200]);
}, $this->mf);
$t = new Transaction(new Client(), new Request('GET', 'http://foo.com'));
$deferred = new Deferred();
$t->response = new FutureResponse($deferred->promise());
$t->state = 'complete';
$c = false;
$t->request->getEmitter()->on('complete', function (CompleteEvent $e) use (&$c) {
$c = true;
});
$fsm($t);
$this->assertFalse($c);
}
public function testTransitionsThroughSuccessfulTransfer()
{
$client = new Client();
$client->getEmitter()->attach(new Mock([new Response(200)]));
$request = $client->createRequest('GET', 'http://ewfewwef.com');
$this->addListeners($request, $calls);
$client->send($request);
$this->assertEquals(['before', 'complete', 'end'], $calls);
}
public function testTransitionsThroughErrorsInBefore()
{
$fsm = new RequestFsm(function () {
return new CompletedFutureArray(['status' => 200]);
}, $this->mf);
$client = new Client();
$request = $client->createRequest('GET', 'http://ewfewwef.com');
$t = new Transaction($client, $request);
$calls = [];
$this->addListeners($t->request, $calls);
$t->request->getEmitter()->on('before', function (BeforeEvent $e) {
throw new \Exception('foo');
});
try {
$fsm($t);
$this->fail('did not throw');
} catch (RequestException $e) {
$this->assertContains('foo', $t->exception->getMessage());
$this->assertEquals(['before', 'error', 'end'], $calls);
}
}
public function testTransitionsThroughErrorsInComplete()
{
$client = new Client();
$client->getEmitter()->attach(new Mock([new Response(200)]));
$request = $client->createRequest('GET', 'http://ewfewwef.com');
$this->addListeners($request, $calls);
$request->getEmitter()->once('complete', function (CompleteEvent $e) {
throw new \Exception('foo');
});
try {
$client->send($request);
$this->fail('did not throw');
} catch (RequestException $e) {
$this->assertContains('foo', $e->getMessage());
$this->assertEquals(['before', 'complete', 'error', 'end'], $calls);
}
}
public function testTransitionsThroughErrorInterception()
{
$fsm = new RequestFsm(function () {
return new CompletedFutureArray(['status' => 404]);
}, $this->mf);
$client = new Client();
$request = $client->createRequest('GET', 'http://ewfewwef.com');
$t = new Transaction($client, $request);
$calls = [];
$this->addListeners($t->request, $calls);
$t->request->getEmitter()->on('error', function (ErrorEvent $e) {
$e->intercept(new Response(200));
});
$fsm($t);
$this->assertEquals(200, $t->response->getStatusCode());
$this->assertNull($t->exception);
$this->assertEquals(['before', 'complete', 'error', 'complete', 'end'], $calls);
}
private function addListeners(RequestInterface $request, &$calls)
{
$request->getEmitter()->on('before', function (BeforeEvent $e) use (&$calls) {
$calls[] = 'before';
}, RequestEvents::EARLY);
$request->getEmitter()->on('complete', function (CompleteEvent $e) use (&$calls) {
$calls[] = 'complete';
}, RequestEvents::EARLY);
$request->getEmitter()->on('error', function (ErrorEvent $e) use (&$calls) {
$calls[] = 'error';
}, RequestEvents::EARLY);
$request->getEmitter()->on('end', function (EndEvent $e) use (&$calls) {
$calls[] = 'end';
}, RequestEvents::EARLY);
}
/**
* @expectedException \GuzzleHttp\Exception\RequestException
* @expectedExceptionMessage Too many state transitions
*/
public function testDetectsInfiniteLoops()
{
$client = new Client([
'fsm' => $fsm = new RequestFsm(
function () {
return new CompletedFutureArray(['status' => 200]);
},
new MessageFactory(),
3
)
]);
$request = $client->createRequest('GET', 'http://foo.com:123');
$request->getEmitter()->on('before', function () {
throw new \Exception('foo');
});
$request->getEmitter()->on('error', function ($e) {
$e->retry();
});
$client->send($request);
}
}

View file

@ -0,0 +1,195 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Client;
use GuzzleHttp\Event\ProgressEvent;
use GuzzleHttp\Message\MessageFactory;
use GuzzleHttp\RingBridge;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Transaction;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Ring\Client\MockHandler;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Event\ErrorEvent;
use GuzzleHttp\RequestFsm;
class RingBridgeTest extends \PHPUnit_Framework_TestCase
{
public function testCreatesRingRequests()
{
$stream = Stream::factory('test');
$request = new Request('GET', 'http://httpbin.org/get?a=b', [
'test' => 'hello'
], $stream);
$request->getConfig()->set('foo', 'bar');
$trans = new Transaction(new Client(), $request);
$factory = new MessageFactory();
$fsm = new RequestFsm(function () {}, new MessageFactory());
$r = RingBridge::prepareRingRequest($trans, $factory, $fsm);
$this->assertEquals('http', $r['scheme']);
$this->assertEquals('1.1', $r['version']);
$this->assertEquals('GET', $r['http_method']);
$this->assertEquals('http://httpbin.org/get?a=b', $r['url']);
$this->assertEquals('/get', $r['uri']);
$this->assertEquals('a=b', $r['query_string']);
$this->assertEquals([
'Host' => ['httpbin.org'],
'test' => ['hello']
], $r['headers']);
$this->assertSame($stream, $r['body']);
$this->assertEquals(['foo' => 'bar'], $r['client']);
$this->assertFalse($r['future']);
}
public function testCreatesRingRequestsWithNullQueryString()
{
$request = new Request('GET', 'http://httpbin.org');
$trans = new Transaction(new Client(), $request);
$factory = new MessageFactory();
$fsm = new RequestFsm(function () {}, new MessageFactory());
$r = RingBridge::prepareRingRequest($trans, $factory, $fsm);
$this->assertNull($r['query_string']);
$this->assertEquals('/', $r['uri']);
$this->assertEquals(['Host' => ['httpbin.org']], $r['headers']);
$this->assertNull($r['body']);
$this->assertEquals([], $r['client']);
}
public function testAddsProgress()
{
Server::enqueue([new Response(200)]);
$client = new Client(['base_url' => Server::$url]);
$request = $client->createRequest('GET');
$called = false;
$request->getEmitter()->on(
'progress',
function (ProgressEvent $e) use (&$called) {
$called = true;
}
);
$this->assertEquals(200, $client->send($request)->getStatusCode());
$this->assertTrue($called);
}
public function testGetsResponseProtocolVersionAndEffectiveUrlAndReason()
{
$client = new Client([
'handler' => new MockHandler([
'status' => 200,
'reason' => 'test',
'headers' => [],
'version' => '1.0',
'effective_url' => 'http://foo.com'
])
]);
$request = $client->createRequest('GET', 'http://foo.com');
$response = $client->send($request);
$this->assertEquals('1.0', $response->getProtocolVersion());
$this->assertEquals('http://foo.com', $response->getEffectiveUrl());
$this->assertEquals('test', $response->getReasonPhrase());
}
public function testGetsStreamFromResponse()
{
$res = fopen('php://temp', 'r+');
fwrite($res, 'foo');
rewind($res);
$client = new Client([
'handler' => new MockHandler([
'status' => 200,
'headers' => [],
'body' => $res
])
]);
$request = $client->createRequest('GET', 'http://foo.com');
$response = $client->send($request);
$this->assertEquals('foo', (string) $response->getBody());
}
public function testEmitsErrorEventOnError()
{
$client = new Client(['base_url' => 'http://127.0.0.1:123']);
$request = $client->createRequest('GET');
$called = false;
$request->getEmitter()->on('error', function () use (&$called) {
$called = true;
});
$request->getConfig()['timeout'] = 0.001;
$request->getConfig()['connect_timeout'] = 0.001;
try {
$client->send($request);
$this->fail('did not throw');
} catch (RequestException $e) {
$this->assertSame($request, $e->getRequest());
$this->assertContains('cURL error', $e->getMessage());
$this->assertTrue($called);
}
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesRingRequest()
{
RingBridge::fromRingRequest([]);
}
public function testCreatesRequestFromRing()
{
$request = RingBridge::fromRingRequest([
'http_method' => 'GET',
'uri' => '/',
'headers' => [
'foo' => ['bar'],
'host' => ['foo.com']
],
'body' => 'test',
'version' => '1.0'
]);
$this->assertEquals('GET', $request->getMethod());
$this->assertEquals('http://foo.com/', $request->getUrl());
$this->assertEquals('1.0', $request->getProtocolVersion());
$this->assertEquals('test', (string) $request->getBody());
$this->assertEquals('bar', $request->getHeader('foo'));
}
public function testCanInterceptException()
{
$client = new Client(['base_url' => 'http://127.0.0.1:123']);
$request = $client->createRequest('GET');
$called = false;
$request->getEmitter()->on(
'error',
function (ErrorEvent $e) use (&$called) {
$called = true;
$e->intercept(new Response(200));
}
);
$request->getConfig()['timeout'] = 0.001;
$request->getConfig()['connect_timeout'] = 0.001;
$this->assertEquals(200, $client->send($request)->getStatusCode());
$this->assertTrue($called);
}
public function testCreatesLongException()
{
$r = new Request('GET', 'http://www.google.com');
$e = RingBridge::getNoRingResponseException($r);
$this->assertInstanceOf('GuzzleHttp\Exception\RequestException', $e);
$this->assertSame($r, $e->getRequest());
}
public function testEnsuresResponseOrExceptionWhenCompletingResponse()
{
$trans = new Transaction(new Client(), new Request('GET', 'http://f.co'));
$f = new MessageFactory();
$fsm = new RequestFsm(function () {}, new MessageFactory());
try {
RingBridge::completeRingResponse($trans, [], $f, $fsm);
} catch (RequestException $e) {
$this->assertSame($trans->request, $e->getRequest());
$this->assertContains('RingPHP', $e->getMessage());
}
}
}

View file

@ -0,0 +1,107 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Client;
use GuzzleHttp\Message\MessageFactory;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Message\ResponseInterface;
use GuzzleHttp\RingBridge;
use GuzzleHttp\Tests\Ring\Client\Server as TestServer;
/**
* Placeholder for the RingPHP-Client server that makes it easier to use.
*/
class Server
{
public static $url = 'http://127.0.0.1:8125/';
public static $port = 8125;
/**
* Queue an array of responses or a single response on the server.
*
* Any currently queued responses will be overwritten. Subsequent requests
* on the server will return queued responses in FIFO order.
*
* @param array $responses Responses to queue.
* @throws \Exception
*/
public static function enqueue(array $responses)
{
static $factory;
if (!$factory) {
$factory = new MessageFactory();
}
$data = [];
foreach ($responses as $response) {
// Create the response object from a string
if (is_string($response)) {
$response = $factory->fromMessage($response);
} elseif (!($response instanceof ResponseInterface)) {
throw new \Exception('Responses must be strings or Responses');
}
$data[] = self::convertResponse($response);
}
TestServer::enqueue($data);
}
/**
* Get all of the received requests
*
* @param bool $hydrate Set to TRUE to turn the messages into
* actual {@see RequestInterface} objects. If $hydrate is FALSE,
* requests will be returned as strings.
*
* @return array
* @throws \RuntimeException
*/
public static function received($hydrate = false)
{
$response = TestServer::received();
if ($hydrate) {
$c = new Client();
$factory = new MessageFactory();
$response = array_map(function($message) use ($factory, $c) {
return RingBridge::fromRingRequest($message);
}, $response);
}
return $response;
}
public static function flush()
{
TestServer::flush();
}
public static function stop()
{
TestServer::stop();
}
public static function wait($maxTries = 5)
{
TestServer::wait($maxTries);
}
public static function start()
{
TestServer::start();
}
private static function convertResponse(Response $response)
{
$headers = array_map(function ($h) {
return implode(', ', $h);
}, $response->getHeaders());
return [
'status' => $response->getStatusCode(),
'reason' => $response->getReasonPhrase(),
'headers' => $headers,
'body' => base64_encode((string) $response->getBody())
];
}
}

View file

@ -0,0 +1,74 @@
<?php
namespace GuzzleHttp\Tests\Subscriber;
use GuzzleHttp\Transaction;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Subscriber\Cookie;
use GuzzleHttp\Subscriber\History;
use GuzzleHttp\Subscriber\Mock;
/**
* @covers GuzzleHttp\Subscriber\Cookie
*/
class CookieTest extends \PHPUnit_Framework_TestCase
{
public function testExtractsAndStoresCookies()
{
$request = new Request('GET', '/');
$response = new Response(200);
$mock = $this->getMockBuilder('GuzzleHttp\Cookie\CookieJar')
->setMethods(array('extractCookies'))
->getMock();
$mock->expects($this->exactly(1))
->method('extractCookies')
->with($request, $response);
$plugin = new Cookie($mock);
$t = new Transaction(new Client(), $request);
$t->response = $response;
$plugin->onComplete(new CompleteEvent($t));
}
public function testProvidesCookieJar()
{
$jar = new CookieJar();
$plugin = new Cookie($jar);
$this->assertSame($jar, $plugin->getCookieJar());
}
public function testCookiesAreExtractedFromRedirectResponses()
{
$jar = new CookieJar();
$cookie = new Cookie($jar);
$history = new History();
$mock = new Mock([
"HTTP/1.1 302 Moved Temporarily\r\n" .
"Set-Cookie: test=583551; Domain=www.foo.com; Expires=Wednesday, 23-Mar-2050 19:49:45 GMT; Path=/\r\n" .
"Location: /redirect\r\n\r\n",
"HTTP/1.1 200 OK\r\n" .
"Content-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\n" .
"Content-Length: 0\r\n\r\n"
]);
$client = new Client(['base_url' => 'http://www.foo.com']);
$client->getEmitter()->attach($cookie);
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($history);
$client->get();
$request = $client->createRequest('GET', '/');
$client->send($request);
$this->assertEquals('test=583551', $request->getHeader('Cookie'));
$requests = $history->getRequests();
// Confirm subsequent requests have the cookie.
$this->assertEquals('test=583551', $requests[2]->getHeader('Cookie'));
// Confirm the redirected request has the cookie.
$this->assertEquals('test=583551', $requests[1]->getHeader('Cookie'));
}
}

View file

@ -0,0 +1,140 @@
<?php
namespace GuzzleHttp\Tests\Subscriber;
use GuzzleHttp\Transaction;
use GuzzleHttp\Client;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Event\ErrorEvent;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Subscriber\History;
use GuzzleHttp\Subscriber\Mock;
/**
* @covers GuzzleHttp\Subscriber\History
*/
class HistoryTest extends \PHPUnit_Framework_TestCase
{
public function testAddsForErrorEvent()
{
$request = new Request('GET', '/');
$response = new Response(400);
$t = new Transaction(new Client(), $request);
$t->response = $response;
$e = new RequestException('foo', $request, $response);
$ev = new ErrorEvent($t, $e);
$h = new History(2);
$h->onError($ev);
// Only tracks when no response is present
$this->assertEquals([], $h->getRequests());
}
public function testLogsConnectionErrors()
{
$request = new Request('GET', '/');
$t = new Transaction(new Client(), $request);
$e = new RequestException('foo', $request);
$ev = new ErrorEvent($t, $e);
$h = new History();
$h->onError($ev);
$this->assertEquals([$request], $h->getRequests());
}
public function testMaintainsLimitValue()
{
$request = new Request('GET', '/');
$response = new Response(200);
$t = new Transaction(new Client(), $request);
$t->response = $response;
$ev = new CompleteEvent($t);
$h = new History(2);
$h->onComplete($ev);
$h->onComplete($ev);
$h->onComplete($ev);
$this->assertEquals(2, count($h));
$this->assertSame($request, $h->getLastRequest());
$this->assertSame($response, $h->getLastResponse());
foreach ($h as $trans) {
$this->assertInstanceOf('GuzzleHttp\Message\RequestInterface', $trans['request']);
$this->assertInstanceOf('GuzzleHttp\Message\ResponseInterface', $trans['response']);
}
return $h;
}
/**
* @depends testMaintainsLimitValue
*/
public function testClearsHistory($h)
{
$this->assertEquals(2, count($h));
$h->clear();
$this->assertEquals(0, count($h));
}
public function testWorksWithMock()
{
$client = new Client(['base_url' => 'http://localhost/']);
$h = new History();
$client->getEmitter()->attach($h);
$mock = new Mock([new Response(200), new Response(201), new Response(202)]);
$client->getEmitter()->attach($mock);
$request = $client->createRequest('GET', '/');
$client->send($request);
$request->setMethod('PUT');
$client->send($request);
$request->setMethod('POST');
$client->send($request);
$this->assertEquals(3, count($h));
$result = implode("\n", array_map(function ($line) {
return strpos($line, 'User-Agent') === 0
? 'User-Agent:'
: trim($line);
}, explode("\n", $h)));
$this->assertEquals("> GET / HTTP/1.1
Host: localhost
User-Agent:
< HTTP/1.1 200 OK
> PUT / HTTP/1.1
Host: localhost
User-Agent:
< HTTP/1.1 201 Created
> POST / HTTP/1.1
Host: localhost
User-Agent:
< HTTP/1.1 202 Accepted
", $result);
}
public function testCanCastToString()
{
$client = new Client(['base_url' => 'http://localhost/']);
$h = new History();
$client->getEmitter()->attach($h);
$mock = new Mock(array(
new Response(301, array('Location' => '/redirect1', 'Content-Length' => 0)),
new Response(307, array('Location' => '/redirect2', 'Content-Length' => 0)),
new Response(200, array('Content-Length' => '2'), Stream::factory('HI'))
));
$client->getEmitter()->attach($mock);
$request = $client->createRequest('GET', '/');
$client->send($request);
$this->assertEquals(3, count($h));
$h = str_replace("\r", '', $h);
$this->assertContains("> GET / HTTP/1.1\nHost: localhost\nUser-Agent:", $h);
$this->assertContains("< HTTP/1.1 301 Moved Permanently\nLocation: /redirect1", $h);
$this->assertContains("< HTTP/1.1 307 Temporary Redirect\nLocation: /redirect2", $h);
$this->assertContains("< HTTP/1.1 200 OK\nContent-Length: 2\n\nHI", $h);
}
}

View file

@ -0,0 +1,60 @@
<?php
namespace GuzzleHttp\Tests\Message;
use GuzzleHttp\Client;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Subscriber\HttpError;
use GuzzleHttp\Transaction;
use GuzzleHttp\Subscriber\Mock;
/**
* @covers GuzzleHttp\Subscriber\HttpError
*/
class HttpErrorTest extends \PHPUnit_Framework_TestCase
{
public function testIgnoreSuccessfulRequests()
{
$event = $this->getEvent();
$event->intercept(new Response(200));
(new HttpError())->onComplete($event);
}
/**
* @expectedException \GuzzleHttp\Exception\ClientException
*/
public function testThrowsClientExceptionOnFailure()
{
$event = $this->getEvent();
$event->intercept(new Response(403));
(new HttpError())->onComplete($event);
}
/**
* @expectedException \GuzzleHttp\Exception\ServerException
*/
public function testThrowsServerExceptionOnFailure()
{
$event = $this->getEvent();
$event->intercept(new Response(500));
(new HttpError())->onComplete($event);
}
private function getEvent()
{
return new CompleteEvent(new Transaction(new Client(), new Request('PUT', '/')));
}
/**
* @expectedException \GuzzleHttp\Exception\ClientException
*/
public function testFullTransaction()
{
$client = new Client();
$client->getEmitter()->attach(new Mock([
new Response(403)
]));
$client->get('http://httpbin.org');
}
}

View file

@ -0,0 +1,192 @@
<?php
namespace GuzzleHttp\Tests\Subscriber;
use GuzzleHttp\Client;
use GuzzleHttp\Subscriber\Mock;
use GuzzleHttp\Message\FutureResponse;
use GuzzleHttp\Transaction;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\MessageFactory;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Stream\Stream;
use React\Promise\Deferred;
/**
* @covers GuzzleHttp\Subscriber\Mock
*/
class MockTest extends \PHPUnit_Framework_TestCase
{
public static function createFuture(
callable $wait,
callable $cancel = null
) {
$deferred = new Deferred();
return new FutureResponse(
$deferred->promise(),
function () use ($deferred, $wait) {
$deferred->resolve($wait());
},
$cancel
);
}
public function testDescribesSubscribedEvents()
{
$mock = new Mock();
$this->assertInternalType('array', $mock->getEvents());
}
public function testIsCountable()
{
$plugin = new Mock();
$plugin->addResponse((new MessageFactory())->fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
$this->assertEquals(1, count($plugin));
}
public function testCanClearQueue()
{
$plugin = new Mock();
$plugin->addResponse((new MessageFactory())->fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
$plugin->clearQueue();
$this->assertEquals(0, count($plugin));
}
public function testRetrievesResponsesFromFiles()
{
$tmp = tempnam('/tmp', 'tfile');
file_put_contents($tmp, "HTTP/1.1 201 OK\r\nContent-Length: 0\r\n\r\n");
$plugin = new Mock();
$plugin->addResponse($tmp);
unlink($tmp);
$this->assertEquals(1, count($plugin));
$q = $this->readAttribute($plugin, 'queue');
$this->assertEquals(201, $q[0]->getStatusCode());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testThrowsExceptionWhenInvalidResponse()
{
(new Mock())->addResponse(false);
}
public function testAddsMockResponseToRequestFromClient()
{
$response = new Response(200);
$t = new Transaction(new Client(), new Request('GET', '/'));
$m = new Mock([$response]);
$ev = new BeforeEvent($t);
$m->onBefore($ev);
$this->assertSame($response, $t->response);
}
/**
* @expectedException \OutOfBoundsException
*/
public function testUpdateThrowsExceptionWhenEmpty()
{
$p = new Mock();
$ev = new BeforeEvent(new Transaction(new Client(), new Request('GET', '/')));
$p->onBefore($ev);
}
public function testReadsBodiesFromMockedRequests()
{
$m = new Mock([new Response(200)]);
$client = new Client(['base_url' => 'http://test.com']);
$client->getEmitter()->attach($m);
$body = Stream::factory('foo');
$client->put('/', ['body' => $body]);
$this->assertEquals(3, $body->tell());
}
public function testCanMockBadRequestExceptions()
{
$client = new Client(['base_url' => 'http://test.com']);
$request = $client->createRequest('GET', '/');
$ex = new RequestException('foo', $request);
$mock = new Mock([$ex]);
$this->assertCount(1, $mock);
$request->getEmitter()->attach($mock);
try {
$client->send($request);
$this->fail('Did not dequeue an exception');
} catch (RequestException $e) {
$this->assertSame($e, $ex);
$this->assertSame($request, $ex->getRequest());
}
}
public function testCanMockFutureResponses()
{
$client = new Client(['base_url' => 'http://test.com']);
$request = $client->createRequest('GET', '/', ['future' => true]);
$response = new Response(200);
$future = self::createFuture(function () use ($response) {
return $response;
});
$mock = new Mock([$future]);
$this->assertCount(1, $mock);
$request->getEmitter()->attach($mock);
$res = $client->send($request);
$this->assertSame($future, $res);
$this->assertFalse($this->readAttribute($res, 'isRealized'));
$this->assertSame($response, $res->wait());
}
public function testCanMockExceptionFutureResponses()
{
$client = new Client(['base_url' => 'http://test.com']);
$request = $client->createRequest('GET', '/', ['future' => true]);
$future = self::createFuture(function () use ($request) {
throw new RequestException('foo', $request);
});
$mock = new Mock([$future]);
$request->getEmitter()->attach($mock);
$response = $client->send($request);
$this->assertSame($future, $response);
$this->assertFalse($this->readAttribute($response, 'isRealized'));
try {
$response->wait();
$this->fail('Did not throw');
} catch (RequestException $e) {
$this->assertContains('foo', $e->getMessage());
}
}
public function testCanMockFailedFutureResponses()
{
$client = new Client(['base_url' => 'http://test.com']);
$request = $client->createRequest('GET', '/', ['future' => true]);
// The first mock will be a mocked future response.
$future = self::createFuture(function () use ($client) {
// When dereferenced, we will set a mocked response and send
// another request.
$client->get('http://httpbin.org', ['events' => [
'before' => function (BeforeEvent $e) {
$e->intercept(new Response(404));
}
]]);
});
$mock = new Mock([$future]);
$request->getEmitter()->attach($mock);
$response = $client->send($request);
$this->assertSame($future, $response);
$this->assertFalse($this->readAttribute($response, 'isRealized'));
try {
$response->wait();
$this->fail('Did not throw');
} catch (RequestException $e) {
$this->assertEquals(404, $e->getResponse()->getStatusCode());
}
}
}

View file

@ -0,0 +1,213 @@
<?php
namespace GuzzleHttp\Tests\Message;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Tests\Server;
use GuzzleHttp\Transaction;
use GuzzleHttp\Client;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Stream\NoSeekStream;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Subscriber\Prepare;
/**
* @covers GuzzleHttp\Subscriber\Prepare
*/
class PrepareTest extends \PHPUnit_Framework_TestCase
{
public function testIgnoresRequestsWithNoBody()
{
$s = new Prepare();
$t = $this->getTrans();
$s->onBefore(new BeforeEvent($t));
$this->assertFalse($t->request->hasHeader('Expect'));
}
public function testAppliesPostBody()
{
$s = new Prepare();
$t = $this->getTrans();
$p = $this->getMockBuilder('GuzzleHttp\Post\PostBody')
->setMethods(['applyRequestHeaders'])
->getMockForAbstractClass();
$p->expects($this->once())
->method('applyRequestHeaders');
$t->request->setBody($p);
$s->onBefore(new BeforeEvent($t));
}
public function testAddsExpectHeaderWithTrue()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->getConfig()->set('expect', true);
$t->request->setBody(Stream::factory('foo'));
$s->onBefore(new BeforeEvent($t));
$this->assertEquals('100-Continue', $t->request->getHeader('Expect'));
}
public function testAddsExpectHeaderBySize()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->getConfig()->set('expect', 2);
$t->request->setBody(Stream::factory('foo'));
$s->onBefore(new BeforeEvent($t));
$this->assertTrue($t->request->hasHeader('Expect'));
}
public function testDoesNotModifyExpectHeaderIfPresent()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setHeader('Expect', 'foo');
$t->request->setBody(Stream::factory('foo'));
$s->onBefore(new BeforeEvent($t));
$this->assertEquals('foo', $t->request->getHeader('Expect'));
}
public function testDoesAddExpectHeaderWhenSetToFalse()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->getConfig()->set('expect', false);
$t->request->setBody(Stream::factory('foo'));
$s->onBefore(new BeforeEvent($t));
$this->assertFalse($t->request->hasHeader('Expect'));
}
public function testDoesNotAddExpectHeaderBySize()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->getConfig()->set('expect', 10);
$t->request->setBody(Stream::factory('foo'));
$s->onBefore(new BeforeEvent($t));
$this->assertFalse($t->request->hasHeader('Expect'));
}
public function testAddsExpectHeaderForNonSeekable()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setBody(new NoSeekStream(Stream::factory('foo')));
$s->onBefore(new BeforeEvent($t));
$this->assertTrue($t->request->hasHeader('Expect'));
}
public function testRemovesContentLengthWhenSendingWithChunked()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setBody(Stream::factory('foo'));
$t->request->setHeader('Transfer-Encoding', 'chunked');
$s->onBefore(new BeforeEvent($t));
$this->assertFalse($t->request->hasHeader('Content-Length'));
}
public function testUsesProvidedContentLengthAndRemovesXferEncoding()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setBody(Stream::factory('foo'));
$t->request->setHeader('Content-Length', '3');
$t->request->setHeader('Transfer-Encoding', 'chunked');
$s->onBefore(new BeforeEvent($t));
$this->assertEquals(3, $t->request->getHeader('Content-Length'));
$this->assertFalse($t->request->hasHeader('Transfer-Encoding'));
}
public function testSetsContentTypeIfPossibleFromStream()
{
$body = $this->getMockBody();
$sub = new Prepare();
$t = $this->getTrans();
$t->request->setBody($body);
$sub->onBefore(new BeforeEvent($t));
$this->assertEquals(
'image/jpeg',
$t->request->getHeader('Content-Type')
);
$this->assertEquals(4, $t->request->getHeader('Content-Length'));
}
public function testDoesNotOverwriteExistingContentType()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setBody($this->getMockBody());
$t->request->setHeader('Content-Type', 'foo/baz');
$s->onBefore(new BeforeEvent($t));
$this->assertEquals(
'foo/baz',
$t->request->getHeader('Content-Type')
);
}
public function testSetsContentLengthIfPossible()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setBody($this->getMockBody());
$s->onBefore(new BeforeEvent($t));
$this->assertEquals(4, $t->request->getHeader('Content-Length'));
}
public function testSetsTransferEncodingChunkedIfNeeded()
{
$r = new Request('PUT', '/');
$s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
->setMethods(['getSize'])
->getMockForAbstractClass();
$s->expects($this->exactly(2))
->method('getSize')
->will($this->returnValue(null));
$r->setBody($s);
$t = $this->getTrans($r);
$s = new Prepare();
$s->onBefore(new BeforeEvent($t));
$this->assertEquals('chunked', $r->getHeader('Transfer-Encoding'));
}
public function testContentLengthIntegrationTest()
{
Server::flush();
Server::enqueue([new Response(200)]);
$client = new Client(['base_url' => Server::$url]);
$this->assertEquals(200, $client->put('/', [
'body' => 'test'
])->getStatusCode());
$request = Server::received(true)[0];
$this->assertEquals('PUT', $request->getMethod());
$this->assertEquals('4', $request->getHeader('Content-Length'));
$this->assertEquals('test', (string) $request->getBody());
}
private function getTrans($request = null)
{
return new Transaction(
new Client(),
$request ?: new Request('PUT', '/')
);
}
/**
* @return \GuzzleHttp\Stream\StreamInterface
*/
private function getMockBody()
{
$s = $this->getMockBuilder('GuzzleHttp\Stream\MetadataStreamInterface')
->setMethods(['getMetadata', 'getSize'])
->getMockForAbstractClass();
$s->expects($this->any())
->method('getMetadata')
->with('uri')
->will($this->returnValue('/foo/baz/bar.jpg'));
$s->expects($this->exactly(2))
->method('getSize')
->will($this->returnValue(4));
return $s;
}
}

View file

@ -0,0 +1,288 @@
<?php
namespace GuzzleHttp\Tests\Plugin\Redirect;
use GuzzleHttp\Client;
use GuzzleHttp\Subscriber\History;
use GuzzleHttp\Subscriber\Mock;
/**
* @covers GuzzleHttp\Subscriber\Redirect
*/
class RedirectTest extends \PHPUnit_Framework_TestCase
{
public function testRedirectsRequests()
{
$mock = new Mock();
$history = new History();
$mock->addMultiple([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client(['base_url' => 'http://test.com']);
$client->getEmitter()->attach($history);
$client->getEmitter()->attach($mock);
$request = $client->createRequest('GET', '/foo');
// Ensure "end" is called only once
$called = 0;
$request->getEmitter()->on('end', function () use (&$called) {
$called++;
});
$response = $client->send($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertContains('/redirect2', $response->getEffectiveUrl());
// Ensure that two requests were sent
$requests = $history->getRequests(true);
$this->assertEquals('/foo', $requests[0]->getPath());
$this->assertEquals('GET', $requests[0]->getMethod());
$this->assertEquals('/redirect1', $requests[1]->getPath());
$this->assertEquals('GET', $requests[1]->getMethod());
$this->assertEquals('/redirect2', $requests[2]->getPath());
$this->assertEquals('GET', $requests[2]->getMethod());
$this->assertEquals(1, $called);
}
/**
* @expectedException \GuzzleHttp\Exception\TooManyRedirectsException
* @expectedExceptionMessage Will not follow more than
*/
public function testCanLimitNumberOfRedirects()
{
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect3\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect4\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect5\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect6\r\nContent-Length: 0\r\n\r\n"
]);
$client = new Client();
$client->getEmitter()->attach($mock);
$client->get('http://www.example.com/foo');
}
public function testDefaultBehaviorIsToRedirectWithGetForEntityEnclosingRequests()
{
$h = new History();
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client();
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($h);
$client->post('http://test.com/foo', [
'headers' => ['X-Baz' => 'bar'],
'body' => 'testing'
]);
$requests = $h->getRequests(true);
$this->assertEquals('POST', $requests[0]->getMethod());
$this->assertEquals('GET', $requests[1]->getMethod());
$this->assertEquals('bar', (string) $requests[1]->getHeader('X-Baz'));
$this->assertEquals('GET', $requests[2]->getMethod());
}
public function testCanRedirectWithStrictRfcCompliance()
{
$h = new History();
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client(['base_url' => 'http://test.com']);
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($h);
$client->post('/foo', [
'headers' => ['X-Baz' => 'bar'],
'body' => 'testing',
'allow_redirects' => ['max' => 10, 'strict' => true]
]);
$requests = $h->getRequests(true);
$this->assertEquals('POST', $requests[0]->getMethod());
$this->assertEquals('POST', $requests[1]->getMethod());
$this->assertEquals('bar', (string) $requests[1]->getHeader('X-Baz'));
$this->assertEquals('POST', $requests[2]->getMethod());
}
public function testRewindsStreamWhenRedirectingIfNeeded()
{
$h = new History();
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client(['base_url' => 'http://test.com']);
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($h);
$body = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
->setMethods(['seek', 'read', 'eof', 'tell'])
->getMockForAbstractClass();
$body->expects($this->once())->method('tell')->will($this->returnValue(1));
$body->expects($this->once())->method('seek')->will($this->returnValue(true));
$body->expects($this->any())->method('eof')->will($this->returnValue(true));
$body->expects($this->any())->method('read')->will($this->returnValue('foo'));
$client->post('/foo', [
'body' => $body,
'allow_redirects' => ['max' => 5, 'strict' => true]
]);
}
/**
* @expectedException \GuzzleHttp\Exception\CouldNotRewindStreamException
* @expectedExceptionMessage Unable to rewind the non-seekable request body after redirecting
*/
public function testThrowsExceptionWhenStreamCannotBeRewound()
{
$h = new History();
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client();
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($h);
$body = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
->setMethods(['seek', 'read', 'eof', 'tell'])
->getMockForAbstractClass();
$body->expects($this->once())->method('tell')->will($this->returnValue(1));
$body->expects($this->once())->method('seek')->will($this->returnValue(false));
$body->expects($this->any())->method('eof')->will($this->returnValue(true));
$body->expects($this->any())->method('read')->will($this->returnValue('foo'));
$client->post('http://example.com/foo', [
'body' => $body,
'allow_redirects' => ['max' => 10, 'strict' => true]
]);
}
public function testRedirectsCanBeDisabledPerRequest()
{
$client = new Client(['base_url' => 'http://test.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]));
$response = $client->put('/', ['body' => 'test', 'allow_redirects' => false]);
$this->assertEquals(301, $response->getStatusCode());
}
public function testCanRedirectWithNoLeadingSlashAndQuery()
{
$h = new History();
$client = new Client(['base_url' => 'http://www.foo.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect?foo=bar\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]));
$client->getEmitter()->attach($h);
$client->get('?foo=bar');
$requests = $h->getRequests(true);
$this->assertEquals('http://www.foo.com?foo=bar', $requests[0]->getUrl());
$this->assertEquals('http://www.foo.com/redirect?foo=bar', $requests[1]->getUrl());
}
public function testHandlesRedirectsWithSpacesProperly()
{
$client = new Client(['base_url' => 'http://www.foo.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect 1\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
]));
$h = new History();
$client->getEmitter()->attach($h);
$client->get('/foo');
$reqs = $h->getRequests(true);
$this->assertEquals('/redirect%201', $reqs[1]->getResource());
}
public function testAddsRefererWhenPossible()
{
$client = new Client(['base_url' => 'http://www.foo.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /bar\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
]));
$h = new History();
$client->getEmitter()->attach($h);
$client->get('/foo', ['allow_redirects' => ['max' => 5, 'referer' => true]]);
$reqs = $h->getRequests(true);
$this->assertEquals('http://www.foo.com/foo', $reqs[1]->getHeader('Referer'));
}
public function testDoesNotAddRefererWhenChangingProtocols()
{
$client = new Client(['base_url' => 'https://www.foo.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\n"
. "Location: http://www.foo.com/foo\r\n"
. "Content-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
]));
$h = new History();
$client->getEmitter()->attach($h);
$client->get('/foo', ['allow_redirects' => ['max' => 5, 'referer' => true]]);
$reqs = $h->getRequests(true);
$this->assertFalse($reqs[1]->hasHeader('Referer'));
}
public function testRedirectsWithGetOn303()
{
$h = new History();
$mock = new Mock([
"HTTP/1.1 303 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client();
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($h);
$client->post('http://test.com/foo', ['body' => 'testing']);
$requests = $h->getRequests(true);
$this->assertEquals('POST', $requests[0]->getMethod());
$this->assertEquals('GET', $requests[1]->getMethod());
}
public function testRelativeLinkBasedLatestRequest()
{
$client = new Client(['base_url' => 'http://www.foo.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: http://www.bar.com\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
]));
$response = $client->get('/');
$this->assertEquals(
'http://www.bar.com/redirect',
$response->getEffectiveUrl()
);
}
/**
* @expectedException \GuzzleHttp\Exception\BadResponseException
* @expectedExceptionMessage Redirect URL, https://foo.com/redirect2, does not use one of the allowed redirect protocols: http
*/
public function testThrowsWhenRedirectingToInvalidUrlProtocol()
{
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: https://foo.com/redirect2\r\nContent-Length: 0\r\n\r\n"
]);
$client = new Client();
$client->getEmitter()->attach($mock);
$client->get('http://www.example.com/foo', [
'allow_redirects' => [
'protocols' => ['http']
]
]);
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Client;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Transaction;
class TransactionTest extends \PHPUnit_Framework_TestCase
{
public function testHoldsData()
{
$client = new Client();
$request = new Request('GET', 'http://www.foo.com');
$t = new Transaction($client, $request);
$this->assertSame($client, $t->client);
$this->assertSame($request, $t->request);
$response = new Response(200);
$t->response = $response;
$this->assertSame($response, $t->response);
}
}

View file

@ -0,0 +1,202 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\UriTemplate;
/**
* @covers GuzzleHttp\UriTemplate
*/
class UriTemplateTest extends \PHPUnit_Framework_TestCase
{
/**
* @return array
*/
public function templateProvider()
{
$params = array(
'var' => 'value',
'hello' => 'Hello World!',
'empty' => '',
'path' => '/foo/bar',
'x' => '1024',
'y' => '768',
'null' => null,
'list' => array('red', 'green', 'blue'),
'keys' => array(
"semi" => ';',
"dot" => '.',
"comma" => ','
),
'empty_keys' => array(),
);
return array_map(function ($t) use ($params) {
$t[] = $params;
return $t;
}, array(
array('foo', 'foo'),
array('{var}', 'value'),
array('{hello}', 'Hello%20World%21'),
array('{+var}', 'value'),
array('{+hello}', 'Hello%20World!'),
array('{+path}/here', '/foo/bar/here'),
array('here?ref={+path}', 'here?ref=/foo/bar'),
array('X{#var}', 'X#value'),
array('X{#hello}', 'X#Hello%20World!'),
array('map?{x,y}', 'map?1024,768'),
array('{x,hello,y}', '1024,Hello%20World%21,768'),
array('{+x,hello,y}', '1024,Hello%20World!,768'),
array('{+path,x}/here', '/foo/bar,1024/here'),
array('{#x,hello,y}', '#1024,Hello%20World!,768'),
array('{#path,x}/here', '#/foo/bar,1024/here'),
array('X{.var}', 'X.value'),
array('X{.x,y}', 'X.1024.768'),
array('{/var}', '/value'),
array('{/var,x}/here', '/value/1024/here'),
array('{;x,y}', ';x=1024;y=768'),
array('{;x,y,empty}', ';x=1024;y=768;empty'),
array('{?x,y}', '?x=1024&y=768'),
array('{?x,y,empty}', '?x=1024&y=768&empty='),
array('?fixed=yes{&x}', '?fixed=yes&x=1024'),
array('{&x,y,empty}', '&x=1024&y=768&empty='),
array('{var:3}', 'val'),
array('{var:30}', 'value'),
array('{list}', 'red,green,blue'),
array('{list*}', 'red,green,blue'),
array('{keys}', 'semi,%3B,dot,.,comma,%2C'),
array('{keys*}', 'semi=%3B,dot=.,comma=%2C'),
array('{+path:6}/here', '/foo/b/here'),
array('{+list}', 'red,green,blue'),
array('{+list*}', 'red,green,blue'),
array('{+keys}', 'semi,;,dot,.,comma,,'),
array('{+keys*}', 'semi=;,dot=.,comma=,'),
array('{#path:6}/here', '#/foo/b/here'),
array('{#list}', '#red,green,blue'),
array('{#list*}', '#red,green,blue'),
array('{#keys}', '#semi,;,dot,.,comma,,'),
array('{#keys*}', '#semi=;,dot=.,comma=,'),
array('X{.var:3}', 'X.val'),
array('X{.list}', 'X.red,green,blue'),
array('X{.list*}', 'X.red.green.blue'),
array('X{.keys}', 'X.semi,%3B,dot,.,comma,%2C'),
array('X{.keys*}', 'X.semi=%3B.dot=..comma=%2C'),
array('{/var:1,var}', '/v/value'),
array('{/list}', '/red,green,blue'),
array('{/list*}', '/red/green/blue'),
array('{/list*,path:4}', '/red/green/blue/%2Ffoo'),
array('{/keys}', '/semi,%3B,dot,.,comma,%2C'),
array('{/keys*}', '/semi=%3B/dot=./comma=%2C'),
array('{;hello:5}', ';hello=Hello'),
array('{;list}', ';list=red,green,blue'),
array('{;list*}', ';list=red;list=green;list=blue'),
array('{;keys}', ';keys=semi,%3B,dot,.,comma,%2C'),
array('{;keys*}', ';semi=%3B;dot=.;comma=%2C'),
array('{?var:3}', '?var=val'),
array('{?list}', '?list=red,green,blue'),
array('{?list*}', '?list=red&list=green&list=blue'),
array('{?keys}', '?keys=semi,%3B,dot,.,comma,%2C'),
array('{?keys*}', '?semi=%3B&dot=.&comma=%2C'),
array('{&var:3}', '&var=val'),
array('{&list}', '&list=red,green,blue'),
array('{&list*}', '&list=red&list=green&list=blue'),
array('{&keys}', '&keys=semi,%3B,dot,.,comma,%2C'),
array('{&keys*}', '&semi=%3B&dot=.&comma=%2C'),
array('{.null}', ''),
array('{.null,var}', '.value'),
array('X{.empty_keys*}', 'X'),
array('X{.empty_keys}', 'X'),
// Test that missing expansions are skipped
array('test{&missing*}', 'test'),
// Test that multiple expansions can be set
array('http://{var}/{var:2}{?keys*}', 'http://value/va?semi=%3B&dot=.&comma=%2C'),
// Test more complex query string stuff
array('http://www.test.com{+path}{?var,keys*}', 'http://www.test.com/foo/bar?var=value&semi=%3B&dot=.&comma=%2C')
));
}
/**
* @dataProvider templateProvider
*/
public function testExpandsUriTemplates($template, $expansion, $params)
{
$uri = new UriTemplate($template);
$this->assertEquals($expansion, $uri->expand($template, $params));
}
public function expressionProvider()
{
return array(
array(
'{+var*}', array(
'operator' => '+',
'values' => array(
array('value' => 'var', 'modifier' => '*')
)
),
),
array(
'{?keys,var,val}', array(
'operator' => '?',
'values' => array(
array('value' => 'keys', 'modifier' => ''),
array('value' => 'var', 'modifier' => ''),
array('value' => 'val', 'modifier' => '')
)
),
),
array(
'{+x,hello,y}', array(
'operator' => '+',
'values' => array(
array('value' => 'x', 'modifier' => ''),
array('value' => 'hello', 'modifier' => ''),
array('value' => 'y', 'modifier' => '')
)
)
)
);
}
/**
* @dataProvider expressionProvider
*/
public function testParsesExpressions($exp, $data)
{
$template = new UriTemplate($exp);
// Access the config object
$class = new \ReflectionClass($template);
$method = $class->getMethod('parseExpression');
$method->setAccessible(true);
$exp = substr($exp, 1, -1);
$this->assertEquals($data, $method->invokeArgs($template, array($exp)));
}
/**
* @ticket https://github.com/guzzle/guzzle/issues/90
*/
public function testAllowsNestedArrayExpansion()
{
$template = new UriTemplate();
$result = $template->expand('http://example.com{+path}{/segments}{?query,data*,foo*}', array(
'path' => '/foo/bar',
'segments' => array('one', 'two'),
'query' => 'test',
'data' => array(
'more' => array('fun', 'ice cream')
),
'foo' => array(
'baz' => array(
'bar' => 'fizz',
'test' => 'buzz'
),
'bam' => 'boo'
)
));
$this->assertEquals('http://example.com/foo/bar/one,two?query=test&more%5B0%5D=fun&more%5B1%5D=ice%20cream&baz%5Bbar%5D=fizz&baz%5Btest%5D=buzz&bam=boo', $result);
}
}

View file

@ -0,0 +1,356 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Query;
use GuzzleHttp\Url;
/**
* @covers GuzzleHttp\Url
*/
class UrlTest extends \PHPUnit_Framework_TestCase
{
const RFC3986_BASE = "http://a/b/c/d;p?q";
public function testEmptyUrl()
{
$url = Url::fromString('');
$this->assertEquals('', (string) $url);
}
public function testPortIsDeterminedFromScheme()
{
$this->assertEquals(80, Url::fromString('http://www.test.com/')->getPort());
$this->assertEquals(443, Url::fromString('https://www.test.com/')->getPort());
$this->assertEquals(21, Url::fromString('ftp://www.test.com/')->getPort());
$this->assertEquals(8192, Url::fromString('http://www.test.com:8192/')->getPort());
$this->assertEquals(null, Url::fromString('foo://www.test.com/')->getPort());
}
public function testRemovesDefaultPortWhenSettingScheme()
{
$url = Url::fromString('http://www.test.com/');
$url->setPort(80);
$url->setScheme('https');
$this->assertEquals(443, $url->getPort());
}
public function testCloneCreatesNewInternalObjects()
{
$u1 = Url::fromString('http://www.test.com/');
$u2 = clone $u1;
$this->assertNotSame($u1->getQuery(), $u2->getQuery());
}
public function testValidatesUrlPartsInFactory()
{
$url = Url::fromString('/index.php');
$this->assertEquals('/index.php', (string) $url);
$this->assertFalse($url->isAbsolute());
$url = 'http://michael:test@test.com:80/path/123?q=abc#test';
$u = Url::fromString($url);
$this->assertEquals('http://michael:test@test.com/path/123?q=abc#test', (string) $u);
$this->assertTrue($u->isAbsolute());
}
public function testAllowsFalsyUrlParts()
{
$url = Url::fromString('http://a:50/0?0#0');
$this->assertSame('a', $url->getHost());
$this->assertEquals(50, $url->getPort());
$this->assertSame('/0', $url->getPath());
$this->assertEquals('0', (string) $url->getQuery());
$this->assertSame('0', $url->getFragment());
$this->assertEquals('http://a:50/0?0#0', (string) $url);
$url = Url::fromString('');
$this->assertSame('', (string) $url);
$url = Url::fromString('0');
$this->assertSame('0', (string) $url);
}
public function testBuildsRelativeUrlsWithFalsyParts()
{
$url = Url::buildUrl(['path' => '/0']);
$this->assertSame('/0', $url);
$url = Url::buildUrl(['path' => '0']);
$this->assertSame('0', $url);
$url = Url::buildUrl(['host' => '', 'path' => '0']);
$this->assertSame('0', $url);
}
public function testUrlStoresParts()
{
$url = Url::fromString('http://test:pass@www.test.com:8081/path/path2/?a=1&b=2#fragment');
$this->assertEquals('http', $url->getScheme());
$this->assertEquals('test', $url->getUsername());
$this->assertEquals('pass', $url->getPassword());
$this->assertEquals('www.test.com', $url->getHost());
$this->assertEquals(8081, $url->getPort());
$this->assertEquals('/path/path2/', $url->getPath());
$this->assertEquals('fragment', $url->getFragment());
$this->assertEquals('a=1&b=2', (string) $url->getQuery());
$this->assertEquals(array(
'fragment' => 'fragment',
'host' => 'www.test.com',
'pass' => 'pass',
'path' => '/path/path2/',
'port' => 8081,
'query' => 'a=1&b=2',
'scheme' => 'http',
'user' => 'test'
), $url->getParts());
}
public function testHandlesPathsCorrectly()
{
$url = Url::fromString('http://www.test.com');
$this->assertEquals('', $url->getPath());
$url->setPath('test');
$this->assertEquals('test', $url->getPath());
$url->setPath('/test/123/abc');
$this->assertEquals(array('', 'test', '123', 'abc'), $url->getPathSegments());
$parts = parse_url('http://www.test.com/test');
$parts['path'] = '';
$this->assertEquals('http://www.test.com', Url::buildUrl($parts));
$parts['path'] = 'test';
$this->assertEquals('http://www.test.com/test', Url::buildUrl($parts));
}
public function testAddsQueryIfPresent()
{
$this->assertEquals('?foo=bar', Url::buildUrl(array(
'query' => 'foo=bar'
)));
}
public function testAddsToPath()
{
// Does nothing here
$url = Url::fromString('http://e.com/base?a=1');
$url->addPath(false);
$this->assertEquals('http://e.com/base?a=1', $url);
$url = Url::fromString('http://e.com/base?a=1');
$url->addPath('');
$this->assertEquals('http://e.com/base?a=1', $url);
$url = Url::fromString('http://e.com/base?a=1');
$url->addPath('/');
$this->assertEquals('http://e.com/base?a=1', $url);
$url = Url::fromString('http://e.com/base');
$url->addPath('0');
$this->assertEquals('http://e.com/base/0', $url);
$url = Url::fromString('http://e.com/base?a=1');
$url->addPath('relative');
$this->assertEquals('http://e.com/base/relative?a=1', $url);
$url = Url::fromString('http://e.com/base?a=1');
$url->addPath('/relative');
$this->assertEquals('http://e.com/base/relative?a=1', $url);
}
/**
* URL combination data provider
*
* @return array
*/
public function urlCombineDataProvider()
{
return [
// Specific test cases
['http://www.example.com/', 'http://www.example.com/', 'http://www.example.com/'],
['http://www.example.com/path', '/absolute', 'http://www.example.com/absolute'],
['http://www.example.com/path', '/absolute?q=2', 'http://www.example.com/absolute?q=2'],
['http://www.example.com/', '?q=1', 'http://www.example.com/?q=1'],
['http://www.example.com/path', 'http://test.com', 'http://test.com'],
['http://www.example.com:8080/path', 'http://test.com', 'http://test.com'],
['http://www.example.com:8080/path', '?q=2#abc', 'http://www.example.com:8080/path?q=2#abc'],
['http://www.example.com/path', 'http://u:a@www.example.com/', 'http://u:a@www.example.com/'],
['/path?q=2', 'http://www.test.com/', 'http://www.test.com/path?q=2'],
['http://api.flickr.com/services/', 'http://www.flickr.com/services/oauth/access_token', 'http://www.flickr.com/services/oauth/access_token'],
['https://www.example.com/path', '//foo.com/abc', 'https://foo.com/abc'],
['https://www.example.com/0/', 'relative/foo', 'https://www.example.com/0/relative/foo'],
['', '0', '0'],
// RFC 3986 test cases
[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'],
[self::RFC3986_BASE, 'http:g', 'http:g'],
];
}
/**
* @dataProvider urlCombineDataProvider
*/
public function testCombinesUrls($a, $b, $c)
{
$this->assertEquals($c, (string) Url::fromString($a)->combine($b));
}
public function testHasGettersAndSetters()
{
$url = Url::fromString('http://www.test.com/');
$url->setHost('example.com');
$this->assertEquals('example.com', $url->getHost());
$url->setPort(8080);
$this->assertEquals('8080', $url->getPort());
$url->setPath('/foo/bar');
$this->assertEquals('/foo/bar', $url->getPath());
$url->setPassword('a');
$this->assertEquals('a', $url->getPassword());
$url->setUsername('b');
$this->assertEquals('b', $url->getUsername());
$url->setFragment('abc');
$this->assertEquals('abc', $url->getFragment());
$url->setScheme('https');
$this->assertEquals('https', $url->getScheme());
$url->setQuery('a=123');
$this->assertEquals('a=123', (string) $url->getQuery());
$this->assertEquals(
'https://b:a@example.com:8080/foo/bar?a=123#abc',
(string) $url
);
$url->setQuery(new Query(['b' => 'boo']));
$this->assertEquals('b=boo', $url->getQuery());
$this->assertEquals(
'https://b:a@example.com:8080/foo/bar?b=boo#abc',
(string) $url
);
$url->setQuery('a%20=bar!', true);
$this->assertEquals(
'https://b:a@example.com:8080/foo/bar?a%20=bar!#abc',
(string) $url
);
}
public function testSetQueryAcceptsArray()
{
$url = Url::fromString('http://www.test.com');
$url->setQuery(array('a' => 'b'));
$this->assertEquals('http://www.test.com?a=b', (string) $url);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testQueryMustBeValid()
{
$url = Url::fromString('http://www.test.com');
$url->setQuery(false);
}
public function testDefersParsingAndEncodingQueryUntilNecessary()
{
$url = Url::fromString('http://www.test.com');
// Note that invalid characters are encoded.
$url->setQuery('foo#bar/', true);
$this->assertEquals('http://www.test.com?foo%23bar/', (string) $url);
$this->assertInternalType('string', $this->readAttribute($url, 'query'));
$this->assertEquals('foo%23bar%2F', (string) $url->getQuery());
$this->assertInstanceOf('GuzzleHttp\Query', $this->readAttribute($url, 'query'));
}
public function urlProvider()
{
return array(
array('/foo/..', '/'),
array('//foo//..', '//foo/'),
array('/foo//', '/foo//'),
array('/foo/../..', '/'),
array('/foo/../.', '/'),
array('/./foo/..', '/'),
array('/./foo', '/foo'),
array('/./foo/', '/foo/'),
array('*', '*'),
array('/foo', '/foo'),
array('/abc/123/../foo/', '/abc/foo/'),
array('/a/b/c/./../../g', '/a/g'),
array('/b/c/./../../g', '/g'),
array('/b/c/./../../g', '/g'),
array('/c/./../../g', '/g'),
array('/./../../g', '/g'),
array('foo', 'foo'),
);
}
/**
* @dataProvider urlProvider
*/
public function testRemoveDotSegments($path, $result)
{
$url = Url::fromString('http://www.example.com');
$url->setPath($path);
$url->removeDotSegments();
$this->assertEquals($result, $url->getPath());
}
public function testSettingHostWithPortModifiesPort()
{
$url = Url::fromString('http://www.example.com');
$url->setHost('foo:8983');
$this->assertEquals('foo', $url->getHost());
$this->assertEquals(8983, $url->getPort());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testValidatesUrlCanBeParsed()
{
Url::fromString('foo:////');
}
public function testConvertsSpecialCharsInPathWhenCastingToString()
{
$url = Url::fromString('http://foo.com/baz bar?a=b');
$url->addPath('?');
$this->assertEquals('http://foo.com/baz%20bar/%3F?a=b', (string) $url);
}
public function testCorrectlyEncodesPathWithoutDoubleEncoding()
{
$url = Url::fromString('http://foo.com/baz%20 bar:boo/baz!');
$this->assertEquals('/baz%20%20bar:boo/baz!', $url->getPath());
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace GuzzleHttp\Tests;
use GuzzleHttp\Utils;
class UtilsTest extends \PHPUnit_Framework_TestCase
{
public function testExpandsTemplate()
{
$this->assertEquals(
'foo/123',
Utils::uriTemplate('foo/{bar}', ['bar' => '123'])
);
}
public function noBodyProvider()
{
return [['get'], ['head'], ['delete']];
}
public function testJsonDecodes()
{
$this->assertTrue(Utils::jsonDecode('true'));
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Unable to parse JSON data: JSON_ERROR_SYNTAX - Syntax error, malformed JSON
*/
public function testJsonDecodesWithErrorMessages()
{
Utils::jsonDecode('!narf!');
}
}

View file

@ -0,0 +1,11 @@
<?php
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../vendor/guzzlehttp/ringphp/tests/Client/Server.php';
use GuzzleHttp\Tests\Server;
Server::start();
register_shutdown_function(function () {
Server::stop();
});

View file

@ -0,0 +1,61 @@
<?php
/*
* Runs a performance test against the node.js server for both serial and
* parallel requests. Requires PHP 5.5 or greater.
*
* # Basic usage
* make perf
* # With custom options
* REQUESTS=100 PARALLEL=5000 make perf
*/
require __DIR__ . '/bootstrap.php';
use GuzzleHttp\Client;
use GuzzleHttp\Tests\Server;
use GuzzleHttp\Ring\Client\CurlMultiHandler;
use GuzzleHttp\Pool;
// Wait until the server is responding
Server::wait();
// Get custom make variables
$total = isset($_SERVER['REQUESTS']) ? $_SERVER['REQUESTS'] : 1000;
$parallel = isset($_SERVER['PARALLEL']) ? $_SERVER['PARALLEL'] : 100;
$client = new Client(['base_url' => Server::$url]);
$t = microtime(true);
for ($i = 0; $i < $total; $i++) {
$client->get('/guzzle-server/perf');
}
$totalTime = microtime(true) - $t;
$perRequest = ($totalTime / $total) * 1000;
printf("Serial: %f (%f ms / request) %d total\n",
$totalTime, $perRequest, $total);
// Create a generator used to yield batches of requests
$reqs = function () use ($client, $total) {
for ($i = 0; $i < $total; $i++) {
yield $client->createRequest('GET', '/guzzle-server/perf');
}
};
$t = microtime(true);
Pool::send($client, $reqs(), ['parallel' => $parallel]);
$totalTime = microtime(true) - $t;
$perRequest = ($totalTime / $total) * 1000;
printf("Batch: %f (%f ms / request) %d total with %d in parallel\n",
$totalTime, $perRequest, $total, $parallel);
$handler = new CurlMultiHandler(['max_handles' => $parallel]);
$client = new Client(['handler' => $handler, 'base_url' => Server::$url]);
$t = microtime(true);
for ($i = 0; $i < $total; $i++) {
$client->get('/guzzle-server/perf');
}
unset($client);
$totalTime = microtime(true) - $t;
$perRequest = ($totalTime / $total) * 1000;
printf("Future: %f (%f ms / request) %d total\n",
$totalTime, $perRequest, $total);