FunctionsTest.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. <?php
  2. namespace GuzzleHttp\Tests\Psr7;
  3. use GuzzleHttp\Psr7;
  4. use GuzzleHttp\Psr7\FnStream;
  5. use GuzzleHttp\Psr7\NoSeekStream;
  6. use GuzzleHttp\Psr7\Stream;
  7. class FunctionsTest extends BaseTest
  8. {
  9. public function testCopiesToString()
  10. {
  11. $s = Psr7\stream_for('foobaz');
  12. $this->assertEquals('foobaz', Psr7\copy_to_string($s));
  13. $s->seek(0);
  14. $this->assertEquals('foo', Psr7\copy_to_string($s, 3));
  15. $this->assertEquals('baz', Psr7\copy_to_string($s, 3));
  16. $this->assertEquals('', Psr7\copy_to_string($s));
  17. }
  18. public function testCopiesToStringStopsWhenReadFails()
  19. {
  20. $s1 = Psr7\stream_for('foobaz');
  21. $s1 = FnStream::decorate($s1, [
  22. 'read' => function () {
  23. return '';
  24. },
  25. ]);
  26. $result = Psr7\copy_to_string($s1);
  27. $this->assertEquals('', $result);
  28. }
  29. public function testCopiesToStream()
  30. {
  31. $s1 = Psr7\stream_for('foobaz');
  32. $s2 = Psr7\stream_for('');
  33. Psr7\copy_to_stream($s1, $s2);
  34. $this->assertEquals('foobaz', (string)$s2);
  35. $s2 = Psr7\stream_for('');
  36. $s1->seek(0);
  37. Psr7\copy_to_stream($s1, $s2, 3);
  38. $this->assertEquals('foo', (string)$s2);
  39. Psr7\copy_to_stream($s1, $s2, 3);
  40. $this->assertEquals('foobaz', (string)$s2);
  41. }
  42. public function testStopsCopyToStreamWhenWriteFails()
  43. {
  44. $s1 = Psr7\stream_for('foobaz');
  45. $s2 = Psr7\stream_for('');
  46. $s2 = FnStream::decorate($s2, [
  47. 'write' => function () {
  48. return 0;
  49. },
  50. ]);
  51. Psr7\copy_to_stream($s1, $s2);
  52. $this->assertEquals('', (string)$s2);
  53. }
  54. public function testStopsCopyToSteamWhenWriteFailsWithMaxLen()
  55. {
  56. $s1 = Psr7\stream_for('foobaz');
  57. $s2 = Psr7\stream_for('');
  58. $s2 = FnStream::decorate($s2, [
  59. 'write' => function () {
  60. return 0;
  61. },
  62. ]);
  63. Psr7\copy_to_stream($s1, $s2, 10);
  64. $this->assertEquals('', (string)$s2);
  65. }
  66. public function testCopyToStreamReadsInChunksInsteadOfAllInMemory()
  67. {
  68. $sizes = [];
  69. $s1 = new Psr7\FnStream([
  70. 'eof' => function () {
  71. return false;
  72. },
  73. 'read' => function ($size) use (&$sizes) {
  74. $sizes[] = $size;
  75. return str_repeat('.', $size);
  76. },
  77. ]);
  78. $s2 = Psr7\stream_for('');
  79. Psr7\copy_to_stream($s1, $s2, 16394);
  80. $s2->seek(0);
  81. $this->assertEquals(16394, strlen($s2->getContents()));
  82. $this->assertEquals(8192, $sizes[0]);
  83. $this->assertEquals(8192, $sizes[1]);
  84. $this->assertEquals(10, $sizes[2]);
  85. }
  86. public function testStopsCopyToSteamWhenReadFailsWithMaxLen()
  87. {
  88. $s1 = Psr7\stream_for('foobaz');
  89. $s1 = FnStream::decorate($s1, [
  90. 'read' => function () {
  91. return '';
  92. },
  93. ]);
  94. $s2 = Psr7\stream_for('');
  95. Psr7\copy_to_stream($s1, $s2, 10);
  96. $this->assertEquals('', (string)$s2);
  97. }
  98. public function testReadsLines()
  99. {
  100. $s = Psr7\stream_for("foo\nbaz\nbar");
  101. $this->assertEquals("foo\n", Psr7\readline($s));
  102. $this->assertEquals("baz\n", Psr7\readline($s));
  103. $this->assertEquals('bar', Psr7\readline($s));
  104. }
  105. public function testReadsLinesUpToMaxLength()
  106. {
  107. $s = Psr7\stream_for("12345\n");
  108. $this->assertEquals('123', Psr7\readline($s, 4));
  109. $this->assertEquals("45\n", Psr7\readline($s));
  110. }
  111. public function testReadLinesEof()
  112. {
  113. // Should return empty string on EOF
  114. $s = Psr7\stream_for("foo\nbar");
  115. while (!$s->eof()) {
  116. Psr7\readline($s);
  117. }
  118. $this->assertSame('', Psr7\readline($s));
  119. }
  120. public function testReadsLineUntilFalseReturnedFromRead()
  121. {
  122. $s = $this->getMockBuilder('GuzzleHttp\Psr7\Stream')
  123. ->setMethods(['read', 'eof'])
  124. ->disableOriginalConstructor()
  125. ->getMock();
  126. $s->expects($this->exactly(2))
  127. ->method('read')
  128. ->will($this->returnCallback(function () {
  129. static $c = false;
  130. if ($c) {
  131. return false;
  132. }
  133. $c = true;
  134. return 'h';
  135. }));
  136. $s->expects($this->exactly(2))
  137. ->method('eof')
  138. ->will($this->returnValue(false));
  139. $this->assertEquals('h', Psr7\readline($s));
  140. }
  141. public function testCalculatesHash()
  142. {
  143. $s = Psr7\stream_for('foobazbar');
  144. $this->assertEquals(md5('foobazbar'), Psr7\hash($s, 'md5'));
  145. }
  146. /**
  147. * @expectedException \RuntimeException
  148. */
  149. public function testCalculatesHashThrowsWhenSeekFails()
  150. {
  151. $s = new NoSeekStream(Psr7\stream_for('foobazbar'));
  152. $s->read(2);
  153. Psr7\hash($s, 'md5');
  154. }
  155. public function testCalculatesHashSeeksToOriginalPosition()
  156. {
  157. $s = Psr7\stream_for('foobazbar');
  158. $s->seek(4);
  159. $this->assertEquals(md5('foobazbar'), Psr7\hash($s, 'md5'));
  160. $this->assertEquals(4, $s->tell());
  161. }
  162. public function testOpensFilesSuccessfully()
  163. {
  164. $r = Psr7\try_fopen(__FILE__, 'r');
  165. $this->assertInternalType('resource', $r);
  166. fclose($r);
  167. }
  168. /**
  169. * @expectedException \RuntimeException
  170. * @expectedExceptionMessage Unable to open /path/to/does/not/exist using mode r
  171. */
  172. public function testThrowsExceptionNotWarning()
  173. {
  174. Psr7\try_fopen('/path/to/does/not/exist', 'r');
  175. }
  176. public function parseQueryProvider()
  177. {
  178. return [
  179. // Does not need to parse when the string is empty
  180. ['', []],
  181. // Can parse mult-values items
  182. ['q=a&q=b', ['q' => ['a', 'b']]],
  183. // Can parse multi-valued items that use numeric indices
  184. ['q[0]=a&q[1]=b', ['q[0]' => 'a', 'q[1]' => 'b']],
  185. // Can parse duplicates and does not include numeric indices
  186. ['q[]=a&q[]=b', ['q[]' => ['a', 'b']]],
  187. // Ensures that the value of "q" is an array even though one value
  188. ['q[]=a', ['q[]' => 'a']],
  189. // Does not modify "." to "_" like PHP's parse_str()
  190. ['q.a=a&q.b=b', ['q.a' => 'a', 'q.b' => 'b']],
  191. // Can decode %20 to " "
  192. ['q%20a=a%20b', ['q a' => 'a b']],
  193. // Can parse funky strings with no values by assigning each to null
  194. ['q&a', ['q' => null, 'a' => null]],
  195. // Does not strip trailing equal signs
  196. ['data=abc=', ['data' => 'abc=']],
  197. // Can store duplicates without affecting other values
  198. ['foo=a&foo=b&?µ=c', ['foo' => ['a', 'b'], '?µ' => 'c']],
  199. // Sets value to null when no "=" is present
  200. ['foo', ['foo' => null]],
  201. // Preserves "0" keys.
  202. ['0', ['0' => null]],
  203. // Sets the value to an empty string when "=" is present
  204. ['0=', ['0' => '']],
  205. // Preserves falsey keys
  206. ['var=0', ['var' => '0']],
  207. ['a[b][c]=1&a[b][c]=2', ['a[b][c]' => ['1', '2']]],
  208. ['a[b]=c&a[d]=e', ['a[b]' => 'c', 'a[d]' => 'e']],
  209. // Ensure it doesn't leave things behind with repeated values
  210. // Can parse mult-values items
  211. ['q=a&q=b&q=c', ['q' => ['a', 'b', 'c']]],
  212. ];
  213. }
  214. /**
  215. * @dataProvider parseQueryProvider
  216. */
  217. public function testParsesQueries($input, $output)
  218. {
  219. $result = Psr7\parse_query($input);
  220. $this->assertSame($output, $result);
  221. }
  222. public function testDoesNotDecode()
  223. {
  224. $str = 'foo%20=bar';
  225. $data = Psr7\parse_query($str, false);
  226. $this->assertEquals(['foo%20' => 'bar'], $data);
  227. }
  228. /**
  229. * @dataProvider parseQueryProvider
  230. */
  231. public function testParsesAndBuildsQueries($input)
  232. {
  233. $result = Psr7\parse_query($input, false);
  234. $this->assertSame($input, Psr7\build_query($result, false));
  235. }
  236. public function testEncodesWithRfc1738()
  237. {
  238. $str = Psr7\build_query(['foo bar' => 'baz+'], PHP_QUERY_RFC1738);
  239. $this->assertEquals('foo+bar=baz%2B', $str);
  240. }
  241. public function testEncodesWithRfc3986()
  242. {
  243. $str = Psr7\build_query(['foo bar' => 'baz+'], PHP_QUERY_RFC3986);
  244. $this->assertEquals('foo%20bar=baz%2B', $str);
  245. }
  246. public function testDoesNotEncode()
  247. {
  248. $str = Psr7\build_query(['foo bar' => 'baz+'], false);
  249. $this->assertEquals('foo bar=baz+', $str);
  250. }
  251. public function testCanControlDecodingType()
  252. {
  253. $result = Psr7\parse_query('var=foo+bar', PHP_QUERY_RFC3986);
  254. $this->assertEquals('foo+bar', $result['var']);
  255. $result = Psr7\parse_query('var=foo+bar', PHP_QUERY_RFC1738);
  256. $this->assertEquals('foo bar', $result['var']);
  257. }
  258. public function testParsesRequestMessages()
  259. {
  260. $req = "GET /abc HTTP/1.0\r\nHost: foo.com\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n\r\nTest";
  261. $request = Psr7\parse_request($req);
  262. $this->assertEquals('GET', $request->getMethod());
  263. $this->assertEquals('/abc', $request->getRequestTarget());
  264. $this->assertEquals('1.0', $request->getProtocolVersion());
  265. $this->assertEquals('foo.com', $request->getHeaderLine('Host'));
  266. $this->assertEquals('Bar', $request->getHeaderLine('Foo'));
  267. $this->assertEquals('Bam, Qux', $request->getHeaderLine('Baz'));
  268. $this->assertEquals('Test', (string)$request->getBody());
  269. $this->assertEquals('http://foo.com/abc', (string)$request->getUri());
  270. }
  271. public function testParsesRequestMessagesWithHttpsScheme()
  272. {
  273. $req = "PUT /abc?baz=bar HTTP/1.1\r\nHost: foo.com:443\r\n\r\n";
  274. $request = Psr7\parse_request($req);
  275. $this->assertEquals('PUT', $request->getMethod());
  276. $this->assertEquals('/abc?baz=bar', $request->getRequestTarget());
  277. $this->assertEquals('1.1', $request->getProtocolVersion());
  278. $this->assertEquals('foo.com:443', $request->getHeaderLine('Host'));
  279. $this->assertEquals('', (string)$request->getBody());
  280. $this->assertEquals('https://foo.com/abc?baz=bar', (string)$request->getUri());
  281. }
  282. public function testParsesRequestMessagesWithUriWhenHostIsNotFirst()
  283. {
  284. $req = "PUT / HTTP/1.1\r\nFoo: Bar\r\nHost: foo.com\r\n\r\n";
  285. $request = Psr7\parse_request($req);
  286. $this->assertEquals('PUT', $request->getMethod());
  287. $this->assertEquals('/', $request->getRequestTarget());
  288. $this->assertEquals('http://foo.com/', (string)$request->getUri());
  289. }
  290. public function testParsesRequestMessagesWithFullUri()
  291. {
  292. $req = "GET https://www.google.com:443/search?q=foobar HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
  293. $request = Psr7\parse_request($req);
  294. $this->assertEquals('GET', $request->getMethod());
  295. $this->assertEquals('https://www.google.com:443/search?q=foobar', $request->getRequestTarget());
  296. $this->assertEquals('1.1', $request->getProtocolVersion());
  297. $this->assertEquals('www.google.com', $request->getHeaderLine('Host'));
  298. $this->assertEquals('', (string)$request->getBody());
  299. $this->assertEquals('https://www.google.com/search?q=foobar', (string)$request->getUri());
  300. }
  301. public function testParsesRequestMessagesWithCustomMethod()
  302. {
  303. $req = "GET_DATA / HTTP/1.1\r\nFoo: Bar\r\nHost: foo.com\r\n\r\n";
  304. $request = Psr7\parse_request($req);
  305. $this->assertEquals('GET_DATA', $request->getMethod());
  306. }
  307. public function testParsesRequestMessagesWithFoldedHeadersOnHttp10()
  308. {
  309. $req = "PUT / HTTP/1.0\r\nFoo: Bar\r\n Bam\r\n\r\n";
  310. $request = Psr7\parse_request($req);
  311. $this->assertEquals('PUT', $request->getMethod());
  312. $this->assertEquals('/', $request->getRequestTarget());
  313. $this->assertEquals('Bar Bam', $request->getHeaderLine('Foo'));
  314. }
  315. /**
  316. * @expectedException \InvalidArgumentException
  317. * @expectedExceptionMessage Invalid header syntax: Obsolete line folding
  318. */
  319. public function testRequestParsingFailsWithFoldedHeadersOnHttp11()
  320. {
  321. Psr7\parse_response("GET_DATA / HTTP/1.1\r\nFoo: Bar\r\n Biz: Bam\r\n\r\n");
  322. }
  323. public function testParsesRequestMessagesWhenHeaderDelimiterIsOnlyALineFeed()
  324. {
  325. $req = "PUT / HTTP/1.0\nFoo: Bar\nBaz: Bam\n\n";
  326. $request = Psr7\parse_request($req);
  327. $this->assertEquals('PUT', $request->getMethod());
  328. $this->assertEquals('/', $request->getRequestTarget());
  329. $this->assertEquals('Bar', $request->getHeaderLine('Foo'));
  330. $this->assertEquals('Bam', $request->getHeaderLine('Baz'));
  331. }
  332. /**
  333. * @expectedException \InvalidArgumentException
  334. */
  335. public function testValidatesRequestMessages()
  336. {
  337. Psr7\parse_request("HTTP/1.1 200 OK\r\n\r\n");
  338. }
  339. public function testParsesResponseMessages()
  340. {
  341. $res = "HTTP/1.0 200 OK\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n\r\nTest";
  342. $response = Psr7\parse_response($res);
  343. $this->assertSame(200, $response->getStatusCode());
  344. $this->assertSame('OK', $response->getReasonPhrase());
  345. $this->assertSame('1.0', $response->getProtocolVersion());
  346. $this->assertSame('Bar', $response->getHeaderLine('Foo'));
  347. $this->assertSame('Bam, Qux', $response->getHeaderLine('Baz'));
  348. $this->assertSame('Test', (string)$response->getBody());
  349. }
  350. public function testParsesResponseWithoutReason()
  351. {
  352. $res = "HTTP/1.0 200\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n\r\nTest";
  353. $response = Psr7\parse_response($res);
  354. $this->assertSame(200, $response->getStatusCode());
  355. $this->assertSame('OK', $response->getReasonPhrase());
  356. $this->assertSame('1.0', $response->getProtocolVersion());
  357. $this->assertSame('Bar', $response->getHeaderLine('Foo'));
  358. $this->assertSame('Bam, Qux', $response->getHeaderLine('Baz'));
  359. $this->assertSame('Test', (string)$response->getBody());
  360. }
  361. public function testParsesResponseWithLeadingDelimiter()
  362. {
  363. $res = "\r\nHTTP/1.0 200\r\nFoo: Bar\r\n\r\nTest";
  364. $response = Psr7\parse_response($res);
  365. $this->assertSame(200, $response->getStatusCode());
  366. $this->assertSame('OK', $response->getReasonPhrase());
  367. $this->assertSame('1.0', $response->getProtocolVersion());
  368. $this->assertSame('Bar', $response->getHeaderLine('Foo'));
  369. $this->assertSame('Test', (string)$response->getBody());
  370. }
  371. public function testParsesResponseWithFoldedHeadersOnHttp10()
  372. {
  373. $res = "HTTP/1.0 200\r\nFoo: Bar\r\n Bam\r\n\r\nTest";
  374. $response = Psr7\parse_response($res);
  375. $this->assertSame(200, $response->getStatusCode());
  376. $this->assertSame('OK', $response->getReasonPhrase());
  377. $this->assertSame('1.0', $response->getProtocolVersion());
  378. $this->assertSame('Bar Bam', $response->getHeaderLine('Foo'));
  379. $this->assertSame('Test', (string)$response->getBody());
  380. }
  381. /**
  382. * @expectedException \InvalidArgumentException
  383. * @expectedExceptionMessage Invalid header syntax: Obsolete line folding
  384. */
  385. public function testResponseParsingFailsWithFoldedHeadersOnHttp11()
  386. {
  387. Psr7\parse_response("HTTP/1.1 200\r\nFoo: Bar\r\n Biz: Bam\r\nBaz: Qux\r\n\r\nTest");
  388. }
  389. public function testParsesResponseWhenHeaderDelimiterIsOnlyALineFeed()
  390. {
  391. $res = "HTTP/1.0 200\nFoo: Bar\nBaz: Bam\n\nTest\n\nOtherTest";
  392. $response = Psr7\parse_response($res);
  393. $this->assertSame(200, $response->getStatusCode());
  394. $this->assertSame('OK', $response->getReasonPhrase());
  395. $this->assertSame('1.0', $response->getProtocolVersion());
  396. $this->assertSame('Bar', $response->getHeaderLine('Foo'));
  397. $this->assertSame('Bam', $response->getHeaderLine('Baz'));
  398. $this->assertSame("Test\n\nOtherTest", (string)$response->getBody());
  399. }
  400. /**
  401. * @expectedException \InvalidArgumentException
  402. * @expectedExceptionMessage Invalid message: Missing header delimiter
  403. */
  404. public function testResponseParsingFailsWithoutHeaderDelimiter()
  405. {
  406. Psr7\parse_response("HTTP/1.0 200\r\nFoo: Bar\r\n Baz: Bam\r\nBaz: Qux\r\n");
  407. }
  408. /**
  409. * @expectedException \InvalidArgumentException
  410. */
  411. public function testValidatesResponseMessages()
  412. {
  413. Psr7\parse_response("GET / HTTP/1.1\r\n\r\n");
  414. }
  415. public function testDetermineMimetype()
  416. {
  417. $this->assertNull(Psr7\mimetype_from_extension('not-a-real-extension'));
  418. $this->assertEquals(
  419. 'application/json',
  420. Psr7\mimetype_from_extension('json')
  421. );
  422. $this->assertEquals(
  423. 'image/jpeg',
  424. Psr7\mimetype_from_filename('/tmp/images/IMG034821.JPEG')
  425. );
  426. }
  427. public function testCreatesUriForValue()
  428. {
  429. $this->assertInstanceOf('GuzzleHttp\Psr7\Uri', Psr7\uri_for('/foo'));
  430. $this->assertInstanceOf(
  431. 'GuzzleHttp\Psr7\Uri',
  432. Psr7\uri_for(new Psr7\Uri('/foo'))
  433. );
  434. }
  435. /**
  436. * @expectedException \InvalidArgumentException
  437. */
  438. public function testValidatesUri()
  439. {
  440. Psr7\uri_for([]);
  441. }
  442. public function testKeepsPositionOfResource()
  443. {
  444. $h = fopen(__FILE__, 'r');
  445. fseek($h, 10);
  446. $stream = Psr7\stream_for($h);
  447. $this->assertEquals(10, $stream->tell());
  448. $stream->close();
  449. }
  450. public function testCreatesWithFactory()
  451. {
  452. $stream = Psr7\stream_for('foo');
  453. $this->assertInstanceOf('GuzzleHttp\Psr7\Stream', $stream);
  454. $this->assertEquals('foo', $stream->getContents());
  455. $stream->close();
  456. }
  457. public function testFactoryCreatesFromEmptyString()
  458. {
  459. $s = Psr7\stream_for();
  460. $this->assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
  461. }
  462. public function testFactoryCreatesFromNull()
  463. {
  464. $s = Psr7\stream_for(null);
  465. $this->assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
  466. }
  467. public function testFactoryCreatesFromResource()
  468. {
  469. $r = fopen(__FILE__, 'r');
  470. $s = Psr7\stream_for($r);
  471. $this->assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
  472. $this->assertSame(file_get_contents(__FILE__), (string)$s);
  473. }
  474. public function testFactoryCreatesFromObjectWithToString()
  475. {
  476. $r = new HasToString();
  477. $s = Psr7\stream_for($r);
  478. $this->assertInstanceOf('GuzzleHttp\Psr7\Stream', $s);
  479. $this->assertEquals('foo', (string)$s);
  480. }
  481. public function testCreatePassesThrough()
  482. {
  483. $s = Psr7\stream_for('foo');
  484. $this->assertSame($s, Psr7\stream_for($s));
  485. }
  486. /**
  487. * @expectedException \InvalidArgumentException
  488. */
  489. public function testThrowsExceptionForUnknown()
  490. {
  491. Psr7\stream_for(new \stdClass());
  492. }
  493. public function testReturnsCustomMetadata()
  494. {
  495. $s = Psr7\stream_for('foo', ['metadata' => ['hwm' => 3]]);
  496. $this->assertEquals(3, $s->getMetadata('hwm'));
  497. $this->assertArrayHasKey('hwm', $s->getMetadata());
  498. }
  499. public function testCanSetSize()
  500. {
  501. $s = Psr7\stream_for('', ['size' => 10]);
  502. $this->assertEquals(10, $s->getSize());
  503. }
  504. public function testCanCreateIteratorBasedStream()
  505. {
  506. $a = new \ArrayIterator(['foo', 'bar', '123']);
  507. $p = Psr7\stream_for($a);
  508. $this->assertInstanceOf('GuzzleHttp\Psr7\PumpStream', $p);
  509. $this->assertEquals('foo', $p->read(3));
  510. $this->assertFalse($p->eof());
  511. $this->assertEquals('b', $p->read(1));
  512. $this->assertEquals('a', $p->read(1));
  513. $this->assertEquals('r12', $p->read(3));
  514. $this->assertFalse($p->eof());
  515. $this->assertEquals('3', $p->getContents());
  516. $this->assertTrue($p->eof());
  517. $this->assertEquals(9, $p->tell());
  518. }
  519. public function testConvertsRequestsToStrings()
  520. {
  521. $request = new Psr7\Request('PUT', 'http://foo.com/hi?123', [
  522. 'Baz' => 'bar',
  523. 'Qux' => 'ipsum',
  524. ], 'hello', '1.0');
  525. $this->assertEquals(
  526. "PUT /hi?123 HTTP/1.0\r\nHost: foo.com\r\nBaz: bar\r\nQux: ipsum\r\n\r\nhello",
  527. Psr7\str($request)
  528. );
  529. }
  530. public function testConvertsResponsesToStrings()
  531. {
  532. $response = new Psr7\Response(200, [
  533. 'Baz' => 'bar',
  534. 'Qux' => 'ipsum',
  535. ], 'hello', '1.0', 'FOO');
  536. $this->assertEquals(
  537. "HTTP/1.0 200 FOO\r\nBaz: bar\r\nQux: ipsum\r\n\r\nhello",
  538. Psr7\str($response)
  539. );
  540. }
  541. public function parseParamsProvider()
  542. {
  543. $res1 = [
  544. [
  545. '<http:/.../front.jpeg>',
  546. 'rel' => 'front',
  547. 'type' => 'image/jpeg',
  548. ],
  549. [
  550. '<http://.../back.jpeg>',
  551. 'rel' => 'back',
  552. 'type' => 'image/jpeg',
  553. ],
  554. ];
  555. return [
  556. [
  557. '<http:/.../front.jpeg>; rel="front"; type="image/jpeg", <http://.../back.jpeg>; rel=back; type="image/jpeg"',
  558. $res1,
  559. ],
  560. [
  561. '<http:/.../front.jpeg>; rel="front"; type="image/jpeg",<http://.../back.jpeg>; rel=back; type="image/jpeg"',
  562. $res1,
  563. ],
  564. [
  565. 'foo="baz"; bar=123, boo, test="123", foobar="foo;bar"',
  566. [
  567. ['foo' => 'baz', 'bar' => '123'],
  568. ['boo'],
  569. ['test' => '123'],
  570. ['foobar' => 'foo;bar'],
  571. ],
  572. ],
  573. [
  574. '<http://.../side.jpeg?test=1>; rel="side"; type="image/jpeg",<http://.../side.jpeg?test=2>; rel=side; type="image/jpeg"',
  575. [
  576. ['<http://.../side.jpeg?test=1>', 'rel' => 'side', 'type' => 'image/jpeg'],
  577. ['<http://.../side.jpeg?test=2>', 'rel' => 'side', 'type' => 'image/jpeg'],
  578. ],
  579. ],
  580. [
  581. '',
  582. [],
  583. ],
  584. ];
  585. }
  586. /**
  587. * @dataProvider parseParamsProvider
  588. */
  589. public function testParseParams($header, $result)
  590. {
  591. $this->assertEquals($result, Psr7\parse_header($header));
  592. }
  593. public function testParsesArrayHeaders()
  594. {
  595. $header = ['a, b', 'c', 'd, e'];
  596. $this->assertEquals(['a', 'b', 'c', 'd', 'e'], Psr7\normalize_header($header));
  597. }
  598. public function testRewindsBody()
  599. {
  600. $body = Psr7\stream_for('abc');
  601. $res = new Psr7\Response(200, [], $body);
  602. Psr7\rewind_body($res);
  603. $this->assertEquals(0, $body->tell());
  604. $body->rewind();
  605. Psr7\rewind_body($res);
  606. $this->assertEquals(0, $body->tell());
  607. }
  608. /**
  609. * @expectedException \RuntimeException
  610. */
  611. public function testThrowsWhenBodyCannotBeRewound()
  612. {
  613. $body = Psr7\stream_for('abc');
  614. $body->read(1);
  615. $body = FnStream::decorate($body, [
  616. 'rewind' => function () {
  617. throw new \RuntimeException('a');
  618. },
  619. ]);
  620. $res = new Psr7\Response(200, [], $body);
  621. Psr7\rewind_body($res);
  622. }
  623. public function testCanModifyRequestWithUri()
  624. {
  625. $r1 = new Psr7\Request('GET', 'http://foo.com');
  626. $r2 = Psr7\modify_request($r1, [
  627. 'uri' => new Psr7\Uri('http://www.foo.com'),
  628. ]);
  629. $this->assertEquals('http://www.foo.com', (string)$r2->getUri());
  630. $this->assertEquals('www.foo.com', (string)$r2->getHeaderLine('host'));
  631. }
  632. public function testCanModifyRequestWithUriAndPort()
  633. {
  634. $r1 = new Psr7\Request('GET', 'http://foo.com:8000');
  635. $r2 = Psr7\modify_request($r1, [
  636. 'uri' => new Psr7\Uri('http://www.foo.com:8000'),
  637. ]);
  638. $this->assertEquals('http://www.foo.com:8000', (string)$r2->getUri());
  639. $this->assertEquals('www.foo.com:8000', (string)$r2->getHeaderLine('host'));
  640. }
  641. public function testCanModifyRequestWithCaseInsensitiveHeader()
  642. {
  643. $r1 = new Psr7\Request('GET', 'http://foo.com', ['User-Agent' => 'foo']);
  644. $r2 = Psr7\modify_request($r1, ['set_headers' => ['User-agent' => 'bar']]);
  645. $this->assertEquals('bar', $r2->getHeaderLine('User-Agent'));
  646. $this->assertEquals('bar', $r2->getHeaderLine('User-agent'));
  647. }
  648. public function testReturnsAsIsWhenNoChanges()
  649. {
  650. $r1 = new Psr7\Request('GET', 'http://foo.com');
  651. $r2 = Psr7\modify_request($r1, []);
  652. $this->assertInstanceOf('GuzzleHttp\Psr7\Request', $r2);
  653. $r1 = new Psr7\ServerRequest('GET', 'http://foo.com');
  654. $r2 = Psr7\modify_request($r1, []);
  655. $this->assertInstanceOf('Psr\Http\Message\ServerRequestInterface', $r2);
  656. }
  657. public function testReturnsUriAsIsWhenNoChanges()
  658. {
  659. $r1 = new Psr7\Request('GET', 'http://foo.com');
  660. $r2 = Psr7\modify_request($r1, ['set_headers' => ['foo' => 'bar']]);
  661. $this->assertNotSame($r1, $r2);
  662. $this->assertEquals('bar', $r2->getHeaderLine('foo'));
  663. }
  664. public function testRemovesHeadersFromMessage()
  665. {
  666. $r1 = new Psr7\Request('GET', 'http://foo.com', ['foo' => 'bar']);
  667. $r2 = Psr7\modify_request($r1, ['remove_headers' => ['foo']]);
  668. $this->assertNotSame($r1, $r2);
  669. $this->assertFalse($r2->hasHeader('foo'));
  670. }
  671. public function testAddsQueryToUri()
  672. {
  673. $r1 = new Psr7\Request('GET', 'http://foo.com');
  674. $r2 = Psr7\modify_request($r1, ['query' => 'foo=bar']);
  675. $this->assertNotSame($r1, $r2);
  676. $this->assertEquals('foo=bar', $r2->getUri()->getQuery());
  677. }
  678. public function testModifyRequestKeepInstanceOfRequest()
  679. {
  680. $r1 = new Psr7\Request('GET', 'http://foo.com');
  681. $r2 = Psr7\modify_request($r1, ['remove_headers' => ['non-existent']]);
  682. $this->assertInstanceOf('GuzzleHttp\Psr7\Request', $r2);
  683. $r1 = new Psr7\ServerRequest('GET', 'http://foo.com');
  684. $r2 = Psr7\modify_request($r1, ['remove_headers' => ['non-existent']]);
  685. $this->assertInstanceOf('Psr\Http\Message\ServerRequestInterface', $r2);
  686. }
  687. public function testMessageBodySummaryWithSmallBody()
  688. {
  689. $message = new Psr7\Response(200, [], 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
  690. $this->assertEquals('Lorem ipsum dolor sit amet, consectetur adipiscing elit.', Psr7\get_message_body_summary($message));
  691. }
  692. public function testMessageBodySummaryWithLargeBody()
  693. {
  694. $message = new Psr7\Response(200, [], 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
  695. $this->assertEquals('Lorem ipsu (truncated...)', Psr7\get_message_body_summary($message, 10));
  696. }
  697. public function testMessageBodySummaryWithEmptyBody()
  698. {
  699. $message = new Psr7\Response(200, [], '');
  700. $this->assertNull(Psr7\get_message_body_summary($message));
  701. }
  702. public function testGetResponseBodySummaryOfNonReadableStream()
  703. {
  704. $this->assertNull(Psr7\get_message_body_summary(new Psr7\Response(500, [], new ReadSeekOnlyStream())));
  705. }
  706. public function testModifyServerRequestWithUploadedFiles()
  707. {
  708. $request = new Psr7\ServerRequest('GET', 'http://example.com/bla');
  709. $file = new Psr7\UploadedFile('Test', 100, \UPLOAD_ERR_OK);
  710. $request = $request->withUploadedFiles([$file]);
  711. /** @var Psr7\ServerRequest $modifiedRequest */
  712. $modifiedRequest = Psr7\modify_request($request, ['set_headers' => ['foo' => 'bar']]);
  713. $this->assertCount(1, $modifiedRequest->getUploadedFiles());
  714. $files = $modifiedRequest->getUploadedFiles();
  715. $this->assertInstanceOf('GuzzleHttp\Psr7\UploadedFile', $files[0]);
  716. }
  717. public function testModifyServerRequestWithCookies()
  718. {
  719. $request = (new Psr7\ServerRequest('GET', 'http://example.com/bla'))
  720. ->withCookieParams(['name' => 'value']);
  721. /** @var Psr7\ServerRequest $modifiedRequest */
  722. $modifiedRequest = Psr7\modify_request($request, ['set_headers' => ['foo' => 'bar']]);
  723. $this->assertEquals(['name' => 'value'], $modifiedRequest->getCookieParams());
  724. }
  725. public function testModifyServerRequestParsedBody()
  726. {
  727. $request = (new Psr7\ServerRequest('GET', 'http://example.com/bla'))
  728. ->withParsedBody(['name' => 'value']);
  729. /** @var Psr7\ServerRequest $modifiedRequest */
  730. $modifiedRequest = Psr7\modify_request($request, ['set_headers' => ['foo' => 'bar']]);
  731. $this->assertEquals(['name' => 'value'], $modifiedRequest->getParsedBody());
  732. }
  733. public function testModifyServerRequestQueryParams()
  734. {
  735. $request = (new Psr7\ServerRequest('GET', 'http://example.com/bla'))
  736. ->withQueryParams(['name' => 'value']);
  737. /** @var Psr7\ServerRequest $modifiedRequest */
  738. $modifiedRequest = Psr7\modify_request($request, ['set_headers' => ['foo' => 'bar']]);
  739. $this->assertEquals(['name' => 'value'], $modifiedRequest->getQueryParams());
  740. }
  741. }
  742. class HasToString
  743. {
  744. public function __toString()
  745. {
  746. return 'foo';
  747. }
  748. }
  749. /**
  750. * convert it to an anonymous class on PHP7
  751. */
  752. final class ReadSeekOnlyStream extends Stream
  753. {
  754. public function __construct()
  755. {
  756. parent::__construct(fopen('php://memory', 'wb'));
  757. }
  758. public function isSeekable()
  759. {
  760. return true;
  761. }
  762. public function isReadable()
  763. {
  764. return false;
  765. }
  766. }