Xml_ParserTest.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. <?php
  2. namespace Test\Unit\Xml;
  3. require_once dirname(__DIR__) . '/Setup.php';
  4. use DateTime;
  5. use DateTimeZone;
  6. use Test\Setup;
  7. use Braintree;
  8. class ParserTest extends Setup
  9. {
  10. public function testTypeCastIntegers()
  11. {
  12. $array = Braintree\Xml::buildArrayFromXml('<root><foo type="integer">123</foo></root>');
  13. $this->assertEquals($array, ['root' => ['foo' => 123]]);
  14. }
  15. public function testDashesUnderscores()
  16. {
  17. $xml =<<<XML
  18. <root>
  19. <dash-es />
  20. <under_scores />
  21. </root>
  22. XML;
  23. $array = Braintree\Xml::buildArrayFromXml($xml);
  24. $this->assertEquals(['root' =>
  25. ['dashEs' => '', 'underScores' => '']], $array);
  26. }
  27. public function testCustomFieldsUnderscore()
  28. {
  29. $xml =<<<XML
  30. <root>
  31. <custom-fields>
  32. <with-dashes>convert to underscore</with-dashes>
  33. </custom-fields>
  34. </root>
  35. XML;
  36. $array = Braintree\Xml::buildArrayFromXml($xml);
  37. $this->assertEquals(['root' =>
  38. ['customFields' => ['with_dashes' => 'convert to underscore']]], $array);
  39. }
  40. public function testNullOrEmptyString()
  41. {
  42. $xml = <<<XML
  43. <root>
  44. <a_nil_value nil="true"></a_nil_value>
  45. <an_empty_string></an_empty_string>
  46. </root>
  47. XML;
  48. $array = Braintree\Xml::buildArrayFromXml($xml);
  49. $this->assertEquals(['root' =>
  50. ['aNilValue' => null, 'anEmptyString' => '']], $array);
  51. }
  52. public function testTypeCastsDatetimes()
  53. {
  54. $xml = <<<XML
  55. <root>
  56. <created-at type="datetime">2009-10-28T10:19:49Z</created-at>
  57. </root>
  58. XML;
  59. $array = Braintree\Xml::buildArrayFromXml($xml);
  60. date_default_timezone_set('UTC');
  61. $dateTime = new DateTime('2009-10-28T10:19:49', new DateTimeZone('UTC'));
  62. $this->assertEquals(['root' => ['createdAt' => $dateTime]], $array);
  63. $this->assertInstanceOf('DateTime', $array['root']['createdAt']);
  64. }
  65. public function testTypeCastsDates()
  66. {
  67. $xml = <<<XML
  68. <root>
  69. <some-date type="date">2009-10-28</some-date>
  70. </root>
  71. XML;
  72. $array = Braintree\Xml::buildArrayFromXml($xml);
  73. date_default_timezone_set('UTC');
  74. $dateTime = new DateTime('2009-10-28', new DateTimeZone('UTC'));
  75. $this->assertEquals(['root' => ['someDate' => $dateTime]], $array);
  76. }
  77. public function testBuildsArray()
  78. {
  79. $xml = <<<XML
  80. <root>
  81. <customers type="array">
  82. <customer><name>Adam</name></customer>
  83. <customer><name>Ben</name></customer>
  84. </customers>
  85. </root>
  86. XML;
  87. $array = Braintree\Xml::buildArrayFromXml($xml);
  88. $this->assertEquals(['root' =>
  89. ['customers' =>
  90. [['name' => 'Adam'],
  91. ['name' => 'Ben']]
  92. ]
  93. ], $array
  94. );
  95. }
  96. public function testReturnsBoolean()
  97. {
  98. $xml = <<<XML
  99. <root>
  100. <casted-true type="boolean">true</casted-true>
  101. <casted-one type="boolean">1</casted-one>
  102. <casted-false type="boolean">false</casted-false>
  103. <casted-anything type="boolean">anything</casted-anything>
  104. <uncasted-true>true</uncasted-true>
  105. </root>
  106. XML;
  107. $array = Braintree\Xml::buildArrayFromXml($xml);
  108. $this->assertEquals(
  109. ['root' =>
  110. ['castedTrue' => true,
  111. 'castedOne' => true,
  112. 'castedFalse' => false,
  113. 'castedAnything' => false,
  114. 'uncastedTrue' => 'true']
  115. ], $array);
  116. }
  117. public function testEmptyArrayAndNestedElements()
  118. {
  119. $xml = <<<XML
  120. <root>
  121. <nested-values>
  122. <value>1</value>
  123. </nested-values>
  124. <no-values type="array"/>
  125. </root>
  126. XML;
  127. $array = Braintree\Xml::buildArrayFromXml($xml);
  128. $this->assertEquals(
  129. ['root' => [
  130. 'noValues' => [],
  131. 'nestedValues' => [
  132. 'value' => 1
  133. ]
  134. ]
  135. ], $array);
  136. }
  137. public function testParsingNilEqualsTrueAfterArray()
  138. {
  139. $xml = <<<XML
  140. <root>
  141. <customer>
  142. <first-name>Dan</first-name>
  143. </customer>
  144. <blank nil="true" />
  145. </root>
  146. XML;
  147. $array = Braintree\Xml::buildArrayFromXml($xml);
  148. $this->assertEquals(null, $array['root']['blank']);
  149. }
  150. public function testTransactionParsingNil()
  151. {
  152. $xml = <<<XML
  153. <transaction>
  154. <id>8ysndw</id>
  155. <status>settled</status>
  156. <type>sale</type>
  157. <currency>USD</currency>
  158. <amount>1.00</amount>
  159. <merchant-account-id>default</merchant-account-id>
  160. <order-id nil="true"></order-id>
  161. <channel nil="true"></channel>
  162. <created-at type="datetime">2010-04-01T19:32:23Z</created-at>
  163. <updated-at type="datetime">2010-04-02T08:05:35Z</updated-at>
  164. <customer>
  165. <id nil="true"></id>
  166. <first-name>First</first-name>
  167. <last-name>Last</last-name>
  168. <company nil="true"></company>
  169. <email></email>
  170. <website nil="true"></website>
  171. <phone nil="true"></phone>
  172. <fax nil="true"></fax>
  173. </customer>
  174. <billing>
  175. <id nil="true"></id>
  176. <first-name nil="true"></first-name>
  177. <last-name nil="true"></last-name>
  178. <company>Widgets Inc</company>
  179. <street-address>1234 My Street</street-address>
  180. <extended-address>Apt 1</extended-address>
  181. <locality>Ottawa</locality>
  182. <region>ON</region>
  183. <postal-code>K1C2N6</postal-code>
  184. <country-name>Canada</country-name>
  185. </billing>
  186. <refund-id nil="true"></refund-id>
  187. <shipping>
  188. <id nil="true"></id>
  189. <first-name nil="true"></first-name>
  190. <last-name nil="true"></last-name>
  191. <company nil="true"></company>
  192. <street-address nil="true"></street-address>
  193. <extended-address nil="true"></extended-address>
  194. <locality nil="true"></locality>
  195. <region nil="true"></region>
  196. <postal-code nil="true"></postal-code>
  197. <country-name nil="true"></country-name>
  198. </shipping>
  199. <custom-fields>
  200. </custom-fields>
  201. <avs-error-response-code nil="true"></avs-error-response-code>
  202. <avs-postal-code-response-code>M</avs-postal-code-response-code>
  203. <avs-street-address-response-code>M</avs-street-address-response-code>
  204. <cvv-response-code>M</cvv-response-code>
  205. <processor-authorization-code>13390</processor-authorization-code>
  206. <processor-response-code>1000</processor-response-code>
  207. <processor-response-text>Approved</processor-response-text>
  208. <credit-card>
  209. <token nil="true"></token>
  210. <bin>510510</bin>
  211. <last-4>5100</last-4>
  212. <card-type>MasterCard</card-type>
  213. <expiration-month>09</expiration-month>
  214. <expiration-year>2011</expiration-year>
  215. <customer-location>US</customer-location>
  216. <cardholder-name nil="true"></cardholder-name>
  217. </credit-card>
  218. <status-history type="array">
  219. <status-event>
  220. <timestamp type="datetime">2010-04-01T19:32:24Z</timestamp>
  221. <status>authorized</status>
  222. <amount>1.00</amount>
  223. <user>dmanges-am</user>
  224. <transaction-source>API</transaction-source>
  225. </status-event>
  226. <status-event>
  227. <timestamp type="datetime">2010-04-01T19:32:25Z</timestamp>
  228. <status>submitted_for_settlement</status>
  229. <amount>1.00</amount>
  230. <user>dmanges-am</user>
  231. <transaction-source>API</transaction-source>
  232. </status-event>
  233. <status-event>
  234. <timestamp type="datetime">2010-04-02T08:05:36Z</timestamp>
  235. <status>settled</status>
  236. <amount>1.00</amount>
  237. <user nil="true"></user>
  238. <transaction-source></transaction-source>
  239. </status-event>
  240. </status-history>
  241. </transaction>
  242. XML;
  243. $array = Braintree\Xml::buildArrayFromXml($xml);
  244. $this->assertEquals(null, $array['transaction']['avsErrorResponseCode']);
  245. $this->assertEquals(null, $array['transaction']['refundId']);
  246. $this->assertEquals(null, $array['transaction']['orderId']);
  247. $this->assertEquals(null, $array['transaction']['channel']);
  248. $this->assertEquals(null, $array['transaction']['customer']['fax']);
  249. $this->assertEquals(null, $array['transaction']['creditCard']['token']);
  250. $this->assertEquals(null, $array['transaction']['creditCard']['cardholderName']);
  251. $this->assertEquals('First', $array['transaction']['customer']['firstName']);
  252. $this->assertEquals('Approved', $array['transaction']['processorResponseText']);
  253. }
  254. public function testParsingWithNodeHavingSameNameAsNodesDirectlyUnderCollection()
  255. {
  256. $xml = <<<END
  257. <foos type="collection">
  258. <page-size>50</page-size>
  259. <bar>
  260. <baz>one</baz>
  261. </bar>
  262. <bar>
  263. <baz>two</baz>
  264. <bar>bug was here</bar>
  265. </bar>
  266. </foos>
  267. END;
  268. $array = Braintree\Xml::buildArrayFromXml($xml);
  269. $this->assertEquals(['baz' => 'two', 'bar' => 'bug was here'], $array['foos']['bar'][1]);
  270. }
  271. public function testParsingCreditCardSearchResults()
  272. {
  273. $xml = <<<END
  274. <payment-methods type="collection">
  275. <current-page-number type="integer">1</current-page-number>
  276. <page-size type="integer">50</page-size>
  277. <total-items type="integer">8</total-items>
  278. <credit-card>
  279. <bin>411111</bin>
  280. <cardholder-name>John Doe</cardholder-name>
  281. <card-type>Visa</card-type>
  282. <created-at type="datetime">2010-07-02T15:50:51Z</created-at>
  283. <customer-id>589636</customer-id>
  284. <default type="boolean">true</default>
  285. <expiration-month>05</expiration-month>
  286. <expiration-year>2009</expiration-year>
  287. <expired type="boolean">true</expired>
  288. <customer-location>US</customer-location>
  289. <last-4>1111</last-4>
  290. <subscriptions type="array"/>
  291. <token>22pb</token>
  292. <updated-at type="datetime">2010-07-02T15:50:51Z</updated-at>
  293. </credit-card>
  294. <credit-card>
  295. <bin>411111</bin>
  296. <cardholder-name></cardholder-name>
  297. <card-type>Visa</card-type>
  298. <created-at type="datetime">2010-07-02T15:52:09Z</created-at>
  299. <customer-id>613603</customer-id>
  300. <default type="boolean">false</default>
  301. <expiration-month>05</expiration-month>
  302. <expiration-year>2009</expiration-year>
  303. <expired type="boolean">true</expired>
  304. <customer-location>US</customer-location>
  305. <last-4>1111</last-4>
  306. <subscriptions type="array">
  307. <subscription>
  308. <id>hzjh8b</id>
  309. <price>54.32</price>
  310. <plan-id>integration_trialless_plan</plan-id>
  311. <first-billing-date type="date">2010-07-02</first-billing-date>
  312. <next-billing-date type="date">2010-08-02</next-billing-date>
  313. <billing-period-start-date type="date">2010-07-02</billing-period-start-date>
  314. <billing-period-end-date type="date">2010-08-01</billing-period-end-date>
  315. <merchant-account-id>sandbox_credit_card</merchant-account-id>
  316. <trial-period type="boolean">false</trial-period>
  317. <status>Active</status>
  318. <failure-count type="integer">0</failure-count>
  319. <payment-method-token>3wx6</payment-method-token>
  320. <trial-duration nil="true"></trial-duration>
  321. <trial-duration-unit nil="true"></trial-duration-unit>
  322. <transactions type="array">
  323. <transaction>
  324. <id>2dpk76</id>
  325. <status>submitted_for_settlement</status>
  326. <type>sale</type>
  327. <currency-iso-code>USD</currency-iso-code>
  328. <amount>54.32</amount>
  329. <merchant-account-id>sandbox_credit_card</merchant-account-id>
  330. <order-id nil="true"></order-id>
  331. <channel nil="true"></channel>
  332. <created-at type="datetime">2010-07-02T15:52:09Z</created-at>
  333. <updated-at type="datetime">2010-07-02T15:52:09Z</updated-at>
  334. <customer>
  335. <id>613603</id>
  336. <first-name>Mike</first-name>
  337. <last-name>Jones</last-name>
  338. <company nil="true"></company>
  339. <email nil="true"></email>
  340. <website nil="true"></website>
  341. <phone nil="true"></phone>
  342. <fax nil="true"></fax>
  343. </customer>
  344. <billing>
  345. <id nil="true"></id>
  346. <first-name nil="true"></first-name>
  347. <last-name nil="true"></last-name>
  348. <company nil="true"></company>
  349. <street-address nil="true"></street-address>
  350. <extended-address nil="true"></extended-address>
  351. <locality nil="true"></locality>
  352. <region nil="true"></region>
  353. <postal-code nil="true"></postal-code>
  354. <country-name nil="true"></country-name>
  355. <country-code-alpha2 nil="true"></country-code-alpha2>
  356. <country-code-alpha3 nil="true"></country-code-alpha3>
  357. <country-code-numeric nil="true"></country-code-numeric>
  358. </billing>
  359. <refund-id nil="true"></refund-id>
  360. <refunded-transaction-id nil="true"></refunded-transaction-id>
  361. <shipping>
  362. <id nil="true"></id>
  363. <first-name nil="true"></first-name>
  364. <last-name nil="true"></last-name>
  365. <company nil="true"></company>
  366. <street-address nil="true"></street-address>
  367. <extended-address nil="true"></extended-address>
  368. <locality nil="true"></locality>
  369. <region nil="true"></region>
  370. <postal-code nil="true"></postal-code>
  371. <country-name nil="true"></country-name>
  372. <country-code-alpha2 nil="true"></country-code-alpha2>
  373. <country-code-alpha3 nil="true"></country-code-alpha3>
  374. <country-code-numeric nil="true"></country-code-numeric>
  375. </shipping>
  376. <custom-fields>
  377. </custom-fields>
  378. <avs-error-response-code nil="true"></avs-error-response-code>
  379. <avs-postal-code-response-code>I</avs-postal-code-response-code>
  380. <avs-street-address-response-code>I</avs-street-address-response-code>
  381. <cvv-response-code>I</cvv-response-code>
  382. <gateway-rejection-reason nil="true"></gateway-rejection-reason>
  383. <processor-authorization-code>9ZR5QB</processor-authorization-code>
  384. <processor-response-code>1000</processor-response-code>
  385. <processor-response-text>Approved</processor-response-text>
  386. <credit-card>
  387. <token>sb8w</token>
  388. <bin>411111</bin>
  389. <last-4>1111</last-4>
  390. <card-type>Visa</card-type>
  391. <expiration-month>05</expiration-month>
  392. <expiration-year>2010</expiration-year>
  393. <customer-location>US</customer-location>
  394. <cardholder-name></cardholder-name>
  395. </credit-card>
  396. <status-history type="array">
  397. <status-event>
  398. <timestamp type="datetime">2010-07-02T15:52:09Z</timestamp>
  399. <status>authorized</status>
  400. <amount>54.32</amount>
  401. <user>merchant</user>
  402. <transaction-source>Recurring</transaction-source>
  403. </status-event>
  404. <status-event>
  405. <timestamp type="datetime">2010-07-02T15:52:09Z</timestamp>
  406. <status>submitted_for_settlement</status>
  407. <amount>54.32</amount>
  408. <user>merchant</user>
  409. <transaction-source>Recurring</transaction-source>
  410. </status-event>
  411. </status-history>
  412. <subscription-id>hzjh8b</subscription-id>
  413. </transaction>
  414. </transactions>
  415. </subscription>
  416. </subscriptions>
  417. <token>3wx6</token>
  418. <updated-at type="datetime">2010-07-02T15:52:09Z</updated-at>
  419. </credit-card>
  420. </payment-methods>
  421. END;
  422. $array = Braintree\Xml::buildArrayFromXml($xml);
  423. $creditCards = $array['paymentMethods']['creditCard'];
  424. $creditCardWithSubscription = $creditCards[1];
  425. $transaction = $creditCardWithSubscription['subscriptions'][0]['transactions'][0];
  426. $this->assertEquals('411111', $transaction['creditCard']['bin']);
  427. $this->assertEquals('1111', $transaction['creditCard']['last4']);
  428. $this->assertEquals('Visa', $transaction['creditCard']['cardType']);
  429. }
  430. public function xmlAndBack($array)
  431. {
  432. $xml = Braintree\Xml::buildXmlFromArray($array);
  433. return Braintree\Xml::buildArrayFromXml($xml);
  434. }
  435. public function testSimpleCaseRoundtrip()
  436. {
  437. $array = ['root' => [
  438. 'foo' => 'fooValue',
  439. 'bar' => 'barValue']
  440. ];
  441. $array2 = $this->xmlAndBack($array);
  442. $this->assertEquals($array, $array2);
  443. }
  444. public function testArrayRoundtrip()
  445. {
  446. $array = ['root' => [
  447. 'items' => [
  448. ['name' => 'first'],
  449. ['name' => 'second'],
  450. ]
  451. ]];
  452. $array2 = $this->xmlAndBack($array);
  453. $this->assertEquals($array, $array2);
  454. }
  455. public function testBooleanRoundtrip()
  456. {
  457. $array = ['root' => [
  458. 'stringTrue' => true,
  459. 'boolTrue' => true,
  460. 'stringFalse' => false,
  461. 'boolFalse' => false,
  462. ]];
  463. $array2 = $this->xmlAndBack($array);
  464. $this->assertEquals($array, $array2);
  465. }
  466. public function testTimestampRoundtrip()
  467. {
  468. date_default_timezone_set('UTC');
  469. $array = ['root' => [
  470. 'aTimestamp' => date('D M d H:i:s e Y', mktime(1, 2, 3, 10, 28, 2009)),
  471. ]];
  472. $array2 = $this->xmlAndBack($array);
  473. $this->assertEquals($array, $array2);
  474. }
  475. public function testNullvsEmptyStringToXml()
  476. {
  477. $array = ['root' => [
  478. 'anEmptyString' => '',
  479. 'aNullValue' => null,
  480. ]];
  481. $xml = Braintree\Xml::buildXmlFromArray($array);
  482. $xml2 =<<<XML
  483. <?xml version="1.0" encoding="UTF-8"?>
  484. <root>
  485. <an-empty-string></an-empty-string>
  486. <a-null-value nil="true"></a-null-value>
  487. </root>
  488. XML;
  489. $this->assertEquals($xml, $xml2);
  490. }
  491. public function testIncludesTheEncodingRoundtrip()
  492. {
  493. $array = ['root' => [
  494. 'root' => 'bar',
  495. ]];
  496. $xml = Braintree\Xml::buildXmlFromArray($array);
  497. $this->assertRegExp('<\?xml version=\"1.0\" encoding=\"UTF-8\"\?>', $xml);
  498. }
  499. public function testRootNodeAndStringRoundtrip()
  500. {
  501. $array = ['id' => '123'];
  502. $array2 = $this->xmlAndBack($array);
  503. $this->assertEquals($array, $array2);
  504. }
  505. }