JsonManipulatorTest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\Test\Json;
  12. use Composer\Json\JsonManipulator;
  13. class JsonManipulatorTest extends \PHPUnit_Framework_TestCase
  14. {
  15. /**
  16. * @dataProvider linkProvider
  17. */
  18. public function testAddLink($json, $type, $package, $constraint, $expected)
  19. {
  20. $manipulator = new JsonManipulator($json);
  21. $this->assertTrue($manipulator->addLink($type, $package, $constraint));
  22. $this->assertEquals($expected, $manipulator->getContents());
  23. }
  24. public function linkProvider()
  25. {
  26. return array(
  27. array(
  28. '{}',
  29. 'require',
  30. 'vendor/baz',
  31. 'qux',
  32. '{
  33. "require": {
  34. "vendor/baz": "qux"
  35. }
  36. }
  37. '
  38. ),
  39. array(
  40. '{
  41. "foo": "bar"
  42. }',
  43. 'require',
  44. 'vendor/baz',
  45. 'qux',
  46. '{
  47. "foo": "bar",
  48. "require": {
  49. "vendor/baz": "qux"
  50. }
  51. }
  52. '
  53. ),
  54. array(
  55. '{
  56. "require": {
  57. }
  58. }',
  59. 'require',
  60. 'vendor/baz',
  61. 'qux',
  62. '{
  63. "require": {
  64. "vendor/baz": "qux"
  65. }
  66. }
  67. '
  68. ),
  69. array(
  70. '{
  71. "require": {
  72. "foo": "bar"
  73. }
  74. }',
  75. 'require',
  76. 'vendor/baz',
  77. 'qux',
  78. '{
  79. "require": {
  80. "foo": "bar",
  81. "vendor/baz": "qux"
  82. }
  83. }
  84. '
  85. ),
  86. array(
  87. '{
  88. "require":
  89. {
  90. "foo": "bar",
  91. "vendor/baz": "baz"
  92. }
  93. }',
  94. 'require',
  95. 'vendor/baz',
  96. 'qux',
  97. '{
  98. "require":
  99. {
  100. "foo": "bar",
  101. "vendor/baz": "qux"
  102. }
  103. }
  104. '
  105. ),
  106. array(
  107. '{
  108. "require":
  109. {
  110. "foo": "bar",
  111. "vendor\/baz": "baz"
  112. }
  113. }',
  114. 'require',
  115. 'vendor/baz',
  116. 'qux',
  117. '{
  118. "require":
  119. {
  120. "foo": "bar",
  121. "vendor/baz": "qux"
  122. }
  123. }
  124. '
  125. ),
  126. array(
  127. '{
  128. "require": {
  129. "foo": "bar"
  130. },
  131. "repositories": [{
  132. "type": "package",
  133. "package": {
  134. "require": {
  135. "foo": "bar"
  136. }
  137. }
  138. }]
  139. }',
  140. 'require',
  141. 'foo',
  142. 'qux',
  143. '{
  144. "require": {
  145. "foo": "qux"
  146. },
  147. "repositories": [{
  148. "type": "package",
  149. "package": {
  150. "require": {
  151. "foo": "bar"
  152. }
  153. }
  154. }]
  155. }
  156. '
  157. ),
  158. array(
  159. '{
  160. "repositories": [{
  161. "type": "package",
  162. "package": {
  163. "require": {
  164. "foo": "bar"
  165. }
  166. }
  167. }]
  168. }',
  169. 'require',
  170. 'foo',
  171. 'qux',
  172. '{
  173. "repositories": [{
  174. "type": "package",
  175. "package": {
  176. "require": {
  177. "foo": "bar"
  178. }
  179. }
  180. }],
  181. "require": {
  182. "foo": "qux"
  183. }
  184. }
  185. '
  186. ),
  187. array(
  188. '{
  189. "require": {
  190. "php": "5.*"
  191. }
  192. }',
  193. 'require-dev',
  194. 'foo',
  195. 'qux',
  196. '{
  197. "require": {
  198. "php": "5.*"
  199. },
  200. "require-dev": {
  201. "foo": "qux"
  202. }
  203. }
  204. '
  205. ),
  206. array(
  207. '{
  208. "require": {
  209. "php": "5.*"
  210. },
  211. "require-dev": {
  212. "foo": "bar"
  213. }
  214. }',
  215. 'require-dev',
  216. 'foo',
  217. 'qux',
  218. '{
  219. "require": {
  220. "php": "5.*"
  221. },
  222. "require-dev": {
  223. "foo": "qux"
  224. }
  225. }
  226. '
  227. ),
  228. array(
  229. '{
  230. "repositories": [{
  231. "type": "package",
  232. "package": {
  233. "bar": "ba[z",
  234. "dist": {
  235. "url": "http...",
  236. "type": "zip"
  237. },
  238. "autoload": {
  239. "classmap": [ "foo/bar" ]
  240. }
  241. }
  242. }],
  243. "require": {
  244. "php": "5.*"
  245. },
  246. "require-dev": {
  247. "foo": "bar"
  248. }
  249. }',
  250. 'require-dev',
  251. 'foo',
  252. 'qux',
  253. '{
  254. "repositories": [{
  255. "type": "package",
  256. "package": {
  257. "bar": "ba[z",
  258. "dist": {
  259. "url": "http...",
  260. "type": "zip"
  261. },
  262. "autoload": {
  263. "classmap": [ "foo/bar" ]
  264. }
  265. }
  266. }],
  267. "require": {
  268. "php": "5.*"
  269. },
  270. "require-dev": {
  271. "foo": "qux"
  272. }
  273. }
  274. '
  275. ),
  276. );
  277. }
  278. /**
  279. * @dataProvider removeSubNodeProvider
  280. */
  281. public function testRemoveSubNode($json, $name, $expected, $expectedContent = null)
  282. {
  283. $manipulator = new JsonManipulator($json);
  284. $this->assertEquals($expected, $manipulator->removeSubNode('repositories', $name));
  285. if (null !== $expectedContent) {
  286. $this->assertEquals($expectedContent, $manipulator->getContents());
  287. }
  288. }
  289. public function removeSubNodeProvider()
  290. {
  291. return array(
  292. 'works on simple ones first' => array(
  293. '{
  294. "repositories": {
  295. "foo": {
  296. "foo": "bar",
  297. "bar": "baz"
  298. },
  299. "bar": {
  300. "foo": "bar",
  301. "bar": "baz"
  302. }
  303. }
  304. }',
  305. 'foo',
  306. true,
  307. '{
  308. "repositories": {
  309. "bar": {
  310. "foo": "bar",
  311. "bar": "baz"
  312. }
  313. }
  314. }
  315. '
  316. ),
  317. 'works on simple ones last' => array(
  318. '{
  319. "repositories": {
  320. "foo": {
  321. "foo": "bar",
  322. "bar": "baz"
  323. },
  324. "bar": {
  325. "foo": "bar",
  326. "bar": "baz"
  327. }
  328. }
  329. }',
  330. 'bar',
  331. true,
  332. '{
  333. "repositories": {
  334. "foo": {
  335. "foo": "bar",
  336. "bar": "baz"
  337. }
  338. }
  339. }
  340. '
  341. ),
  342. 'works on simple ones unique' => array(
  343. '{
  344. "repositories": {
  345. "foo": {
  346. "foo": "bar",
  347. "bar": "baz"
  348. }
  349. }
  350. }',
  351. 'foo',
  352. true,
  353. '{
  354. "repositories": {
  355. }
  356. }
  357. '
  358. ),
  359. 'works on simple ones middle' => array(
  360. '{
  361. "repositories": {
  362. "foo": {
  363. "foo": "bar",
  364. "bar": "baz"
  365. },
  366. "bar": {
  367. "foo": "bar",
  368. "bar": "baz"
  369. },
  370. "baz": {
  371. "foo": "bar",
  372. "bar": "baz"
  373. }
  374. }
  375. }',
  376. 'bar',
  377. true,
  378. '{
  379. "repositories": {
  380. "foo": {
  381. "foo": "bar",
  382. "bar": "baz"
  383. },
  384. "baz": {
  385. "foo": "bar",
  386. "bar": "baz"
  387. }
  388. }
  389. }
  390. '
  391. ),
  392. 'works on undefined ones' => array(
  393. '{
  394. "repositories": {
  395. "main": {
  396. "foo": "bar",
  397. "bar": "baz"
  398. }
  399. }
  400. }',
  401. 'removenotthere',
  402. true,
  403. '{
  404. "repositories": {
  405. "main": {
  406. "foo": "bar",
  407. "bar": "baz"
  408. }
  409. }
  410. }
  411. '
  412. ),
  413. 'works on child having unmatched name' => array(
  414. '{
  415. "repositories": {
  416. "baz": {
  417. "foo": "bar",
  418. "bar": "baz"
  419. }
  420. }
  421. }',
  422. 'bar',
  423. true,
  424. '{
  425. "repositories": {
  426. "baz": {
  427. "foo": "bar",
  428. "bar": "baz"
  429. }
  430. }
  431. }
  432. '
  433. ),
  434. 'works on child having duplicate name' => array(
  435. '{
  436. "repositories": {
  437. "foo": {
  438. "baz": "qux"
  439. },
  440. "baz": {
  441. "foo": "bar",
  442. "bar": "baz"
  443. }
  444. }
  445. }',
  446. 'baz',
  447. true,
  448. '{
  449. "repositories": {
  450. "foo": {
  451. "baz": "qux"
  452. }
  453. }
  454. }
  455. '
  456. ),
  457. 'works on empty repos' => array(
  458. '{
  459. "repositories": {
  460. }
  461. }',
  462. 'bar',
  463. true
  464. ),
  465. 'works on empty repos2' => array(
  466. '{
  467. "repositories": {}
  468. }',
  469. 'bar',
  470. true
  471. ),
  472. 'works on missing repos' => array(
  473. "{\n}",
  474. 'bar',
  475. true
  476. ),
  477. 'works on deep repos' => array(
  478. '{
  479. "repositories": {
  480. "foo": {
  481. "package": { "bar": "baz" }
  482. }
  483. }
  484. }',
  485. 'foo',
  486. true,
  487. '{
  488. "repositories": {
  489. }
  490. }
  491. '
  492. ),
  493. 'fails on deep repos with borked texts' => array(
  494. '{
  495. "repositories": {
  496. "foo": {
  497. "package": { "bar": "ba{z" }
  498. }
  499. }
  500. }',
  501. 'bar',
  502. false
  503. ),
  504. 'fails on deep repos with borked texts2' => array(
  505. '{
  506. "repositories": {
  507. "foo": {
  508. "package": { "bar": "ba}z" }
  509. }
  510. }
  511. }',
  512. 'bar',
  513. false
  514. ),
  515. 'fails on deep arrays with borked texts' => array(
  516. '{
  517. "repositories": [{
  518. "package": { "bar": "ba[z" }
  519. }]
  520. }',
  521. 'bar',
  522. false
  523. ),
  524. 'fails on deep arrays with borked texts2' => array(
  525. '{
  526. "repositories": [{
  527. "package": { "bar": "ba]z" }
  528. }]
  529. }',
  530. 'bar',
  531. false
  532. ),
  533. );
  534. }
  535. public function testAddRepositoryCanInitializeEmptyRepositories()
  536. {
  537. $manipulator = new JsonManipulator('{
  538. "repositories": {
  539. }
  540. }');
  541. $this->assertTrue($manipulator->addRepository('bar', array('type' => 'composer')));
  542. $this->assertEquals('{
  543. "repositories": {
  544. "bar": {
  545. "type": "composer"
  546. }
  547. }
  548. }
  549. ', $manipulator->getContents());
  550. }
  551. public function testAddRepositoryCanInitializeFromScratch()
  552. {
  553. $manipulator = new JsonManipulator("{
  554. \t\"a\": \"b\"
  555. }");
  556. $this->assertTrue($manipulator->addRepository('bar2', array('type' => 'composer')));
  557. $this->assertEquals("{
  558. \t\"a\": \"b\",
  559. \t\"repositories\": {
  560. \t\t\"bar2\": {
  561. \t\t\t\"type\": \"composer\"
  562. \t\t}
  563. \t}
  564. }
  565. ", $manipulator->getContents());
  566. }
  567. public function testAddRepositoryCanAdd()
  568. {
  569. $manipulator = new JsonManipulator('{
  570. "repositories": {
  571. "foo": {
  572. "type": "vcs",
  573. "url": "lala"
  574. }
  575. }
  576. }');
  577. $this->assertTrue($manipulator->addRepository('bar', array('type' => 'composer')));
  578. $this->assertEquals('{
  579. "repositories": {
  580. "foo": {
  581. "type": "vcs",
  582. "url": "lala"
  583. },
  584. "bar": {
  585. "type": "composer"
  586. }
  587. }
  588. }
  589. ', $manipulator->getContents());
  590. }
  591. public function testAddRepositoryCanOverrideDeepRepos()
  592. {
  593. $manipulator = new JsonManipulator('{
  594. "repositories": {
  595. "baz": {
  596. "type": "package",
  597. "package": {}
  598. }
  599. }
  600. }');
  601. $this->assertTrue($manipulator->addRepository('baz', array('type' => 'composer')));
  602. $this->assertEquals('{
  603. "repositories": {
  604. "baz": {
  605. "type": "composer"
  606. }
  607. }
  608. }
  609. ', $manipulator->getContents());
  610. }
  611. public function testAddConfigSettingEscapes()
  612. {
  613. $manipulator = new JsonManipulator('{
  614. "config": {
  615. }
  616. }');
  617. $this->assertTrue($manipulator->addConfigSetting('test', 'a\b'));
  618. $this->assertTrue($manipulator->addConfigSetting('test2', "a\nb\fa"));
  619. $this->assertEquals('{
  620. "config": {
  621. "test": "a\\\\b",
  622. "test2": "a\nb\fa"
  623. }
  624. }
  625. ', $manipulator->getContents());
  626. }
  627. public function testAddConfigSettingCanAdd()
  628. {
  629. $manipulator = new JsonManipulator('{
  630. "config": {
  631. "foo": "bar"
  632. }
  633. }');
  634. $this->assertTrue($manipulator->addConfigSetting('bar', 'baz'));
  635. $this->assertEquals('{
  636. "config": {
  637. "foo": "bar",
  638. "bar": "baz"
  639. }
  640. }
  641. ', $manipulator->getContents());
  642. }
  643. public function testAddConfigSettingCanOverwrite()
  644. {
  645. $manipulator = new JsonManipulator('{
  646. "config": {
  647. "foo": "bar",
  648. "bar": "baz"
  649. }
  650. }');
  651. $this->assertTrue($manipulator->addConfigSetting('foo', 'zomg'));
  652. $this->assertEquals('{
  653. "config": {
  654. "foo": "zomg",
  655. "bar": "baz"
  656. }
  657. }
  658. ', $manipulator->getContents());
  659. }
  660. public function testAddConfigSettingCanOverwriteNumbers()
  661. {
  662. $manipulator = new JsonManipulator('{
  663. "config": {
  664. "foo": 500
  665. }
  666. }');
  667. $this->assertTrue($manipulator->addConfigSetting('foo', 50));
  668. $this->assertEquals('{
  669. "config": {
  670. "foo": 50
  671. }
  672. }
  673. ', $manipulator->getContents());
  674. }
  675. public function testAddConfigSettingCanOverwriteArrays()
  676. {
  677. $manipulator = new JsonManipulator('{
  678. "config": {
  679. "github-oauth": {
  680. "github.com": "foo"
  681. },
  682. "github-protocols": ["https"]
  683. }
  684. }');
  685. $this->assertTrue($manipulator->addConfigSetting('github-protocols', array('https', 'http')));
  686. $this->assertEquals('{
  687. "config": {
  688. "github-oauth": {
  689. "github.com": "foo"
  690. },
  691. "github-protocols": ["https", "http"]
  692. }
  693. }
  694. ', $manipulator->getContents());
  695. $this->assertTrue($manipulator->addConfigSetting('github-oauth', array('github.com' => 'bar', 'alt.example.org' => 'baz')));
  696. $this->assertEquals('{
  697. "config": {
  698. "github-oauth": {
  699. "github.com": "bar",
  700. "alt.example.org": "baz"
  701. },
  702. "github-protocols": ["https", "http"]
  703. }
  704. }
  705. ', $manipulator->getContents());
  706. }
  707. public function testAddConfigSettingCanAddSubKeyInEmptyConfig()
  708. {
  709. $manipulator = new JsonManipulator('{
  710. "config": {
  711. }
  712. }');
  713. $this->assertTrue($manipulator->addConfigSetting('github-oauth.bar', 'baz'));
  714. $this->assertEquals('{
  715. "config": {
  716. "github-oauth": {
  717. "bar": "baz"
  718. }
  719. }
  720. }
  721. ', $manipulator->getContents());
  722. }
  723. public function testAddConfigSettingCanAddSubKeyInEmptyVal()
  724. {
  725. $manipulator = new JsonManipulator('{
  726. "config": {
  727. "github-oauth": {},
  728. "github-oauth2": {
  729. }
  730. }
  731. }');
  732. $this->assertTrue($manipulator->addConfigSetting('github-oauth.bar', 'baz'));
  733. $this->assertTrue($manipulator->addConfigSetting('github-oauth2.a.bar', 'baz2'));
  734. $this->assertTrue($manipulator->addConfigSetting('github-oauth3.b', 'c'));
  735. $this->assertEquals('{
  736. "config": {
  737. "github-oauth": {
  738. "bar": "baz"
  739. },
  740. "github-oauth2": {
  741. "a.bar": "baz2"
  742. },
  743. "github-oauth3": {
  744. "b": "c"
  745. }
  746. }
  747. }
  748. ', $manipulator->getContents());
  749. }
  750. public function testAddConfigSettingCanAddSubKeyInHash()
  751. {
  752. $manipulator = new JsonManipulator('{
  753. "config": {
  754. "github-oauth": {
  755. "github.com": "foo"
  756. }
  757. }
  758. }');
  759. $this->assertTrue($manipulator->addConfigSetting('github-oauth.bar', 'baz'));
  760. $this->assertEquals('{
  761. "config": {
  762. "github-oauth": {
  763. "github.com": "foo",
  764. "bar": "baz"
  765. }
  766. }
  767. }
  768. ', $manipulator->getContents());
  769. }
  770. public function testAddRootSettingDoesNotBreakDots()
  771. {
  772. $manipulator = new JsonManipulator('{
  773. "github-oauth": {
  774. "github.com": "foo"
  775. }
  776. }');
  777. $this->assertTrue($manipulator->addSubNode('github-oauth', 'bar', 'baz'));
  778. $this->assertEquals('{
  779. "github-oauth": {
  780. "github.com": "foo",
  781. "bar": "baz"
  782. }
  783. }
  784. ', $manipulator->getContents());
  785. }
  786. public function testRemoveConfigSettingCanRemoveSubKeyInHash()
  787. {
  788. $manipulator = new JsonManipulator('{
  789. "config": {
  790. "github-oauth": {
  791. "github.com": "foo",
  792. "bar": "baz"
  793. }
  794. }
  795. }');
  796. $this->assertTrue($manipulator->removeConfigSetting('github-oauth.bar'));
  797. $this->assertEquals('{
  798. "config": {
  799. "github-oauth": {
  800. "github.com": "foo"
  801. }
  802. }
  803. }
  804. ', $manipulator->getContents());
  805. }
  806. public function testRemoveConfigSettingCanRemoveSubKeyInHashWithSiblings()
  807. {
  808. $manipulator = new JsonManipulator('{
  809. "config": {
  810. "foo": "bar",
  811. "github-oauth": {
  812. "github.com": "foo",
  813. "bar": "baz"
  814. }
  815. }
  816. }');
  817. $this->assertTrue($manipulator->removeConfigSetting('github-oauth.bar'));
  818. $this->assertEquals('{
  819. "config": {
  820. "foo": "bar",
  821. "github-oauth": {
  822. "github.com": "foo"
  823. }
  824. }
  825. }
  826. ', $manipulator->getContents());
  827. }
  828. public function testAddMainKey()
  829. {
  830. $manipulator = new JsonManipulator('{
  831. "foo": "bar"
  832. }');
  833. $this->assertTrue($manipulator->addMainKey('bar', 'baz'));
  834. $this->assertEquals('{
  835. "foo": "bar",
  836. "bar": "baz"
  837. }
  838. ', $manipulator->getContents());
  839. }
  840. public function testUpdateMainKey()
  841. {
  842. $manipulator = new JsonManipulator('{
  843. "foo": "bar"
  844. }');
  845. $this->assertTrue($manipulator->addMainKey('foo', 'baz'));
  846. $this->assertEquals('{
  847. "foo": "baz"
  848. }
  849. ', $manipulator->getContents());
  850. }
  851. public function testUpdateMainKey2()
  852. {
  853. $manipulator = new JsonManipulator('{
  854. "a": {
  855. "foo": "bar",
  856. "baz": "qux"
  857. },
  858. "foo": "bar",
  859. "baz": "bar"
  860. }');
  861. $this->assertTrue($manipulator->addMainKey('foo', 'baz'));
  862. $this->assertTrue($manipulator->addMainKey('baz', 'quux'));
  863. $this->assertEquals('{
  864. "a": {
  865. "foo": "bar",
  866. "baz": "qux"
  867. },
  868. "foo": "baz",
  869. "baz": "quux"
  870. }
  871. ', $manipulator->getContents());
  872. }
  873. public function testUpdateMainKey3()
  874. {
  875. $manipulator = new JsonManipulator('{
  876. "require": {
  877. "php": "5.*"
  878. },
  879. "require-dev": {
  880. "foo": "bar"
  881. }
  882. }');
  883. $this->assertTrue($manipulator->addMainKey('require-dev', array('foo' => 'qux')));
  884. $this->assertEquals('{
  885. "require": {
  886. "php": "5.*"
  887. },
  888. "require-dev": {
  889. "foo": "qux"
  890. }
  891. }
  892. ', $manipulator->getContents());
  893. }
  894. }