XmlLocationTest.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. <?php
  2. namespace GuzzleHttp\Tests\Command\Guzzle\ResponseLocation;
  3. use GuzzleHttp\Command\Guzzle\Parameter;
  4. use GuzzleHttp\Command\Guzzle\ResponseLocation\XmlLocation;
  5. use GuzzleHttp\Command\Result;
  6. use GuzzleHttp\Psr7\Response;
  7. /**
  8. * @covers \GuzzleHttp\Command\Guzzle\ResponseLocation\XmlLocation
  9. */
  10. class XmlLocationTest extends \PHPUnit_Framework_TestCase
  11. {
  12. /**
  13. * @group ResponseLocation
  14. */
  15. public function testVisitsLocation()
  16. {
  17. $location = new XmlLocation();
  18. $parameter = new Parameter([
  19. 'name' => 'val',
  20. 'sentAs' => 'vim',
  21. 'filters' => ['strtoupper']
  22. ]);
  23. $model = new Parameter();
  24. $response = new Response(200, [], \GuzzleHttp\Psr7\stream_for('<w><vim>bar</vim></w>'));
  25. $result = new Result();
  26. $result = $location->before($result, $response, $model);
  27. $result = $location->visit($result, $response, $parameter);
  28. $result = $location->after($result, $response, $model);
  29. $this->assertEquals('BAR', $result['val']);
  30. }
  31. /**
  32. * @group ResponseLocation
  33. */
  34. public function testVisitsAdditionalProperties()
  35. {
  36. $location = new XmlLocation();
  37. $parameter = new Parameter();
  38. $model = new Parameter(['additionalProperties' => ['location' => 'xml']]);
  39. $response = new Response(200, [], \GuzzleHttp\Psr7\stream_for('<w><vim>bar</vim></w>'));
  40. $result = new Result();
  41. $result = $location->before($result, $response, $parameter);
  42. $result = $location->visit($result, $response, $parameter);
  43. $result = $location->after($result, $response, $model);
  44. $this->assertEquals('bar', $result['vim']);
  45. }
  46. /**
  47. * @group ResponseLocation
  48. */
  49. public function testEnsuresFlatArraysAreFlat()
  50. {
  51. $param = new Parameter([
  52. 'location' => 'xml',
  53. 'name' => 'foo',
  54. 'type' => 'array',
  55. 'items' => ['type' => 'string'],
  56. ]);
  57. $xml = '<xml><foo>bar</foo><foo>baz</foo></xml>';
  58. $this->xmlTest($param, $xml, ['foo' => ['bar', 'baz']]);
  59. $this->xmlTest($param, '<xml><foo>bar</foo></xml>', ['foo' => ['bar']]);
  60. }
  61. public function xmlDataProvider()
  62. {
  63. $param = new Parameter([
  64. 'location' => 'xml',
  65. 'name' => 'Items',
  66. 'type' => 'array',
  67. 'items' => [
  68. 'type' => 'object',
  69. 'name' => 'Item',
  70. 'properties' => [
  71. 'Bar' => ['type' => 'string'],
  72. 'Baz' => ['type' => 'string'],
  73. ],
  74. ],
  75. ]);
  76. return [
  77. [$param, '<Test><Items><Item><Bar>1</Bar></Item><Item><Bar>2</Bar></Item></Items></Test>', [
  78. 'Items' => [
  79. ['Bar' => 1],
  80. ['Bar' => 2],
  81. ],
  82. ]],
  83. [$param, '<Test><Items><Item><Bar>1</Bar></Item></Items></Test>', [
  84. 'Items' => [
  85. ['Bar' => 1],
  86. ]
  87. ]],
  88. [$param, '<Test><Items /></Test>', [
  89. 'Items' => [],
  90. ]]
  91. ];
  92. }
  93. /**
  94. * @dataProvider xmlDataProvider
  95. * @group ResponseLocation
  96. */
  97. public function testEnsuresWrappedArraysAreInCorrectLocations($param, $xml, $expected)
  98. {
  99. $location = new XmlLocation();
  100. $model = new Parameter();
  101. $response = new Response(200, [], \GuzzleHttp\Psr7\stream_for($xml));
  102. $result = new Result();
  103. $result = $location->before($result, $response, $param);
  104. $result = $location->visit($result, $response, $param);
  105. $result = $location->after($result, $response, $model);
  106. $this->assertEquals($expected, $result->toArray());
  107. }
  108. /**
  109. * @group ResponseLocation
  110. */
  111. public function testCanRenameValues()
  112. {
  113. $param = new Parameter([
  114. 'name' => 'TerminatingInstances',
  115. 'type' => 'array',
  116. 'location' => 'xml',
  117. 'sentAs' => 'instancesSet',
  118. 'items' => [
  119. 'name' => 'item',
  120. 'type' => 'object',
  121. 'sentAs' => 'item',
  122. 'properties' => [
  123. 'InstanceId' => [
  124. 'type' => 'string',
  125. 'sentAs' => 'instanceId',
  126. ],
  127. 'CurrentState' => [
  128. 'type' => 'object',
  129. 'sentAs' => 'currentState',
  130. 'properties' => [
  131. 'Code' => [
  132. 'type' => 'numeric',
  133. 'sentAs' => 'code',
  134. ],
  135. 'Name' => [
  136. 'type' => 'string',
  137. 'sentAs' => 'name',
  138. ],
  139. ],
  140. ],
  141. 'PreviousState' => [
  142. 'type' => 'object',
  143. 'sentAs' => 'previousState',
  144. 'properties' => [
  145. 'Code' => [
  146. 'type' => 'numeric',
  147. 'sentAs' => 'code',
  148. ],
  149. 'Name' => [
  150. 'type' => 'string',
  151. 'sentAs' => 'name',
  152. ],
  153. ],
  154. ],
  155. ],
  156. ]
  157. ]);
  158. $xml = '
  159. <xml>
  160. <instancesSet>
  161. <item>
  162. <instanceId>i-3ea74257</instanceId>
  163. <currentState>
  164. <code>32</code>
  165. <name>shutting-down</name>
  166. </currentState>
  167. <previousState>
  168. <code>16</code>
  169. <name>running</name>
  170. </previousState>
  171. </item>
  172. </instancesSet>
  173. </xml>
  174. ';
  175. $this->xmlTest($param, $xml, [
  176. 'TerminatingInstances' => [
  177. [
  178. 'InstanceId' => 'i-3ea74257',
  179. 'CurrentState' => [
  180. 'Code' => '32',
  181. 'Name' => 'shutting-down',
  182. ],
  183. 'PreviousState' => [
  184. 'Code' => '16',
  185. 'Name' => 'running',
  186. ],
  187. ],
  188. ],
  189. ]);
  190. }
  191. /**
  192. * @group ResponseLocation
  193. */
  194. public function testCanRenameAttributes()
  195. {
  196. $param = new Parameter([
  197. 'name' => 'RunningQueues',
  198. 'type' => 'array',
  199. 'location' => 'xml',
  200. 'items' => [
  201. 'type' => 'object',
  202. 'sentAs' => 'item',
  203. 'properties' => [
  204. 'QueueId' => [
  205. 'type' => 'string',
  206. 'sentAs' => 'queue_id',
  207. 'data' => [
  208. 'xmlAttribute' => true,
  209. ],
  210. ],
  211. 'CurrentState' => [
  212. 'type' => 'object',
  213. 'properties' => [
  214. 'Code' => [
  215. 'type' => 'numeric',
  216. 'sentAs' => 'code',
  217. 'data' => [
  218. 'xmlAttribute' => true,
  219. ],
  220. ],
  221. 'Name' => [
  222. 'sentAs' => 'name',
  223. 'data' => [
  224. 'xmlAttribute' => true,
  225. ],
  226. ],
  227. ],
  228. ],
  229. 'PreviousState' => [
  230. 'type' => 'object',
  231. 'properties' => [
  232. 'Code' => [
  233. 'type' => 'numeric',
  234. 'sentAs' => 'code',
  235. 'data' => [
  236. 'xmlAttribute' => true,
  237. ],
  238. ],
  239. 'Name' => [
  240. 'sentAs' => 'name',
  241. 'data' => [
  242. 'xmlAttribute' => true,
  243. ],
  244. ],
  245. ],
  246. ],
  247. ],
  248. ]
  249. ]);
  250. $xml = '
  251. <wrap>
  252. <RunningQueues>
  253. <item queue_id="q-3ea74257">
  254. <CurrentState code="32" name="processing" />
  255. <PreviousState code="16" name="wait" />
  256. </item>
  257. </RunningQueues>
  258. </wrap>';
  259. $this->xmlTest($param, $xml, [
  260. 'RunningQueues' => [
  261. [
  262. 'QueueId' => 'q-3ea74257',
  263. 'CurrentState' => [
  264. 'Code' => '32',
  265. 'Name' => 'processing',
  266. ],
  267. 'PreviousState' => [
  268. 'Code' => '16',
  269. 'Name' => 'wait',
  270. ],
  271. ],
  272. ],
  273. ]);
  274. }
  275. /**
  276. * @group ResponseLocation
  277. */
  278. public function testAddsEmptyArraysWhenValueIsMissing()
  279. {
  280. $param = new Parameter([
  281. 'name' => 'Foo',
  282. 'type' => 'array',
  283. 'location' => 'xml',
  284. 'items' => [
  285. 'type' => 'object',
  286. 'properties' => [
  287. 'Baz' => ['type' => 'array'],
  288. 'Bar' => [
  289. 'type' => 'object',
  290. 'properties' => [
  291. 'Baz' => ['type' => 'array'],
  292. ],
  293. ],
  294. ],
  295. ],
  296. ]);
  297. $xml = '<xml><Foo><Bar></Bar></Foo></xml>';
  298. $this->xmlTest($param, $xml, [
  299. 'Foo' => [
  300. [
  301. 'Bar' => [],
  302. ]
  303. ],
  304. ]);
  305. }
  306. /**
  307. * @group issue-399, ResponseLocation
  308. * @link https://github.com/guzzle/guzzle/issues/399
  309. */
  310. public function testDiscardingUnknownProperties()
  311. {
  312. $param = new Parameter([
  313. 'name' => 'foo',
  314. 'type' => 'object',
  315. 'additionalProperties' => false,
  316. 'properties' => [
  317. 'bar' => [
  318. 'type' => 'string',
  319. 'name' => 'bar',
  320. ],
  321. ],
  322. ]);
  323. $xml = '
  324. <xml>
  325. <foo>
  326. <bar>15</bar>
  327. <unknown>discard me</unknown>
  328. </foo>
  329. </xml>
  330. ';
  331. $this->xmlTest($param, $xml, [
  332. 'foo' => [
  333. 'bar' => 15
  334. ]
  335. ]);
  336. }
  337. /**
  338. * @group issue-399, ResponseLocation
  339. * @link https://github.com/guzzle/guzzle/issues/399
  340. */
  341. public function testDiscardingUnknownPropertiesWithAliasing()
  342. {
  343. $param = new Parameter([
  344. 'name' => 'foo',
  345. 'type' => 'object',
  346. 'additionalProperties' => false,
  347. 'properties' => [
  348. 'bar' => [
  349. 'name' => 'bar',
  350. 'sentAs' => 'baz',
  351. ],
  352. ],
  353. ]);
  354. $xml = '
  355. <xml>
  356. <foo>
  357. <baz>15</baz>
  358. <unknown>discard me</unknown>
  359. </foo>
  360. </xml>
  361. ';
  362. $this->xmlTest($param, $xml, [
  363. 'foo' => [
  364. 'bar' => 15,
  365. ],
  366. ]);
  367. }
  368. /**
  369. * @group ResponseLocation
  370. */
  371. public function testProcessingOfNestedAdditionalProperties()
  372. {
  373. $param = new Parameter([
  374. 'name' => 'foo',
  375. 'type' => 'object',
  376. 'additionalProperties' => true,
  377. 'properties' => [
  378. 'bar' => [
  379. 'name' => 'bar',
  380. 'sentAs' => 'baz',
  381. ],
  382. 'nestedNoAdditional' => [
  383. 'type' => 'object',
  384. 'additionalProperties' => false,
  385. 'properties' => [
  386. 'id' => [
  387. 'type' => 'integer',
  388. ],
  389. ],
  390. ],
  391. 'nestedWithAdditional' => [
  392. 'type' => 'object',
  393. 'additionalProperties' => true,
  394. ],
  395. 'nestedWithAdditionalSchema' => [
  396. 'type' => 'object',
  397. 'additionalProperties' => [
  398. 'type' => 'array',
  399. 'items' => [
  400. 'type' => 'string',
  401. ],
  402. ],
  403. ],
  404. ],
  405. ]);
  406. $xml = '
  407. <xml>
  408. <foo>
  409. <baz>15</baz>
  410. <additional>include me</additional>
  411. <nestedNoAdditional>
  412. <id>15</id>
  413. <unknown>discard me</unknown>
  414. </nestedNoAdditional>
  415. <nestedWithAdditional>
  416. <id>15</id>
  417. <additional>include me</additional>
  418. </nestedWithAdditional>
  419. <nestedWithAdditionalSchema>
  420. <arrayA>
  421. <item>1</item>
  422. <item>2</item>
  423. <item>3</item>
  424. </arrayA>
  425. <arrayB>
  426. <item>A</item>
  427. <item>B</item>
  428. <item>C</item>
  429. </arrayB>
  430. </nestedWithAdditionalSchema>
  431. </foo>
  432. </xml>
  433. ';
  434. $this->xmlTest($param, $xml, [
  435. 'foo' => [
  436. 'bar' => '15',
  437. 'additional' => 'include me',
  438. 'nestedNoAdditional' => [
  439. 'id' => '15',
  440. ],
  441. 'nestedWithAdditional' => [
  442. 'id' => '15',
  443. 'additional' => 'include me',
  444. ],
  445. 'nestedWithAdditionalSchema' => [
  446. 'arrayA' => ['1', '2', '3'],
  447. 'arrayB' => ['A', 'B', 'C'],
  448. ],
  449. ],
  450. ]);
  451. }
  452. /**
  453. * @group ResponseLocation
  454. */
  455. public function testConvertsMultipleAssociativeElementsToArray()
  456. {
  457. $param = new Parameter([
  458. 'name' => 'foo',
  459. 'type' => 'object',
  460. 'additionalProperties' => true,
  461. ]);
  462. $xml = '
  463. <xml>
  464. <foo>
  465. <baz>15</baz>
  466. <baz>25</baz>
  467. <bar>hi</bar>
  468. <bam>test</bam>
  469. <bam attr="hi" />
  470. </foo>
  471. </xml>
  472. ';
  473. $this->xmlTest($param, $xml, [
  474. 'foo' => [
  475. 'baz' => ['15', '25'],
  476. 'bar' => 'hi',
  477. 'bam' => [
  478. 'test',
  479. ['@attributes' => ['attr' => 'hi']]
  480. ]
  481. ]
  482. ]);
  483. }
  484. /**
  485. * @group ResponseLocation
  486. */
  487. public function testUnderstandsNamespaces()
  488. {
  489. $param = new Parameter([
  490. 'name' => 'nstest',
  491. 'type' => 'array',
  492. 'location' => 'xml',
  493. 'items' => [
  494. 'name' => 'item',
  495. 'type' => 'object',
  496. 'sentAs' => 'item',
  497. 'properties' => [
  498. 'id' => [
  499. 'type' => 'string',
  500. ],
  501. 'isbn:number' => [
  502. 'type' => 'string',
  503. ],
  504. 'meta' => [
  505. 'type' => 'object',
  506. 'sentAs' => 'abstract:meta',
  507. 'properties' => [
  508. 'foo' => [
  509. 'type' => 'numeric',
  510. ],
  511. 'bar' => [
  512. 'type' => 'object',
  513. 'properties' =>[
  514. 'attribute' => [
  515. 'type' => 'string',
  516. 'data' => [
  517. 'xmlAttribute' => true,
  518. 'xmlNs' => 'abstract',
  519. ],
  520. ],
  521. ],
  522. ],
  523. ],
  524. ],
  525. 'gamma' => [
  526. 'type' => 'object',
  527. 'data' => [
  528. 'xmlNs' => 'abstract',
  529. ],
  530. 'additionalProperties' => true,
  531. ],
  532. 'nonExistent' => [
  533. 'type' => 'object',
  534. 'data' => [
  535. 'xmlNs' => 'abstract',
  536. ],
  537. 'additionalProperties' => true,
  538. ],
  539. 'nonExistent2' => [
  540. 'type' => 'object',
  541. 'additionalProperties' => true,
  542. ],
  543. ],
  544. ],
  545. ]);
  546. $xml = '
  547. <xml>
  548. <nstest xmlns:isbn="urn:ISBN:0-395-36341-6" xmlns:abstract="urn:my.org:abstract">
  549. <item>
  550. <id>101</id>
  551. <isbn:number>1568491379</isbn:number>
  552. <abstract:meta>
  553. <foo>10</foo>
  554. <bar abstract:attribute="foo"></bar>
  555. </abstract:meta>
  556. <abstract:gamma>
  557. <foo>bar</foo>
  558. </abstract:gamma>
  559. </item>
  560. <item>
  561. <id>102</id>
  562. <isbn:number>1568491999</isbn:number>
  563. <abstract:meta>
  564. <foo>20</foo>
  565. <bar abstract:attribute="bar"></bar>
  566. </abstract:meta>
  567. <abstract:gamma>
  568. <foo>baz</foo>
  569. </abstract:gamma>
  570. </item>
  571. </nstest>
  572. </xml>
  573. ';
  574. $this->xmlTest($param, $xml, [
  575. 'nstest' => [
  576. [
  577. 'id' => '101',
  578. 'isbn:number' => 1568491379,
  579. 'meta' => [
  580. 'foo' => 10,
  581. 'bar' => [
  582. 'attribute' => 'foo',
  583. ],
  584. ],
  585. 'gamma' => [
  586. 'foo' => 'bar',
  587. ],
  588. ],
  589. [
  590. 'id' => '102',
  591. 'isbn:number' => 1568491999,
  592. 'meta' => [
  593. 'foo' => 20,
  594. 'bar' => [
  595. 'attribute' => 'bar'
  596. ],
  597. ],
  598. 'gamma' => [
  599. 'foo' => 'baz',
  600. ],
  601. ],
  602. ],
  603. ]);
  604. }
  605. /**
  606. * @group ResponseLocation
  607. */
  608. public function testCanWalkUndefinedPropertiesWithNamespace()
  609. {
  610. $param = new Parameter([
  611. 'name' => 'nstest',
  612. 'type' => 'array',
  613. 'location' => 'xml',
  614. 'items' => [
  615. 'name' => 'item',
  616. 'type' => 'object',
  617. 'sentAs' => 'item',
  618. 'additionalProperties' => [
  619. 'type' => 'object',
  620. 'data' => [
  621. 'xmlNs' => 'abstract'
  622. ],
  623. ],
  624. 'properties' => [
  625. 'id' => [
  626. 'type' => 'string',
  627. ],
  628. 'isbn:number' => [
  629. 'type' => 'string',
  630. ],
  631. ],
  632. ],
  633. ]);
  634. $xml = '
  635. <xml>
  636. <nstest xmlns:isbn="urn:ISBN:0-395-36341-6" xmlns:abstract="urn:my.org:abstract">
  637. <item>
  638. <id>101</id>
  639. <isbn:number>1568491379</isbn:number>
  640. <abstract:meta>
  641. <foo>10</foo>
  642. <bar>baz</bar>
  643. </abstract:meta>
  644. </item>
  645. <item>
  646. <id>102</id>
  647. <isbn:number>1568491999</isbn:number>
  648. <abstract:meta>
  649. <foo>20</foo>
  650. <bar>foo</bar>
  651. </abstract:meta>
  652. </item>
  653. </nstest>
  654. </xml>
  655. ';
  656. $this->xmlTest($param, $xml, [
  657. 'nstest' => [
  658. [
  659. 'id' => '101',
  660. 'isbn:number' => 1568491379,
  661. 'meta' => [
  662. 'foo' => 10,
  663. 'bar' => 'baz',
  664. ],
  665. ],
  666. [
  667. 'id' => '102',
  668. 'isbn:number' => 1568491999,
  669. 'meta' => [
  670. 'foo' => 20,
  671. 'bar' => 'foo',
  672. ],
  673. ],
  674. ]
  675. ]);
  676. }
  677. /**
  678. * @group ResponseLocation
  679. */
  680. public function testCanWalkSimpleArrayWithNamespace()
  681. {
  682. $param = new Parameter([
  683. 'name' => 'nstest',
  684. 'type' => 'array',
  685. 'location' => 'xml',
  686. 'items' => [
  687. 'type' => 'string',
  688. 'sentAs' => 'number',
  689. 'data' => [
  690. 'xmlNs' => 'isbn'
  691. ],
  692. ],
  693. ]);
  694. $xml = '
  695. <xml>
  696. <nstest xmlns:isbn="urn:ISBN:0-395-36341-6">
  697. <isbn:number>1568491379</isbn:number>
  698. <isbn:number>1568491999</isbn:number>
  699. <isbn:number>1568492999</isbn:number>
  700. </nstest>
  701. </xml>
  702. ';
  703. $this->xmlTest($param, $xml, [
  704. 'nstest' => [
  705. 1568491379,
  706. 1568491999,
  707. 1568492999,
  708. ],
  709. ]);
  710. }
  711. /**
  712. * @group ResponseLocation
  713. */
  714. public function testCanWalkSimpleArrayWithNamespace2()
  715. {
  716. $param = new Parameter([
  717. 'name' => 'nstest',
  718. 'type' => 'array',
  719. 'location' => 'xml',
  720. 'items' => [
  721. 'type' => 'string',
  722. 'sentAs' => 'isbn:number',
  723. ]
  724. ]);
  725. $xml = '
  726. <xml>
  727. <nstest xmlns:isbn="urn:ISBN:0-395-36341-6">
  728. <isbn:number>1568491379</isbn:number>
  729. <isbn:number>1568491999</isbn:number>
  730. <isbn:number>1568492999</isbn:number>
  731. </nstest>
  732. </xml>
  733. ';
  734. $this->xmlTest($param, $xml, [
  735. 'nstest' => [
  736. 1568491379,
  737. 1568491999,
  738. 1568492999,
  739. ],
  740. ]);
  741. }
  742. private function xmlTest(Parameter $param, $xml, $expected)
  743. {
  744. $location = new XmlLocation();
  745. $model = new Parameter();
  746. $response = new Response(200, [], \GuzzleHttp\Psr7\stream_for($xml));
  747. $result = new Result();
  748. $result = $location->before($result, $response, $param);
  749. $result = $location->visit($result, $response, $param);
  750. $result = $location->after($result, $response, $model);
  751. $this->assertEquals($expected, $result->toArray());
  752. }
  753. }