ComposerRepositoryTest.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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\Repository;
  12. use Composer\IO\NullIO;
  13. use Composer\Repository\ComposerRepository;
  14. use Composer\Repository\RepositoryInterface;
  15. use Composer\Test\Mock\FactoryMock;
  16. use Composer\Test\TestCase;
  17. use Composer\Package\Loader\ArrayLoader;
  18. use Composer\Semver\VersionParser;
  19. class ComposerRepositoryTest extends TestCase
  20. {
  21. /**
  22. * @dataProvider loadDataProvider
  23. */
  24. public function testLoadData(array $expected, array $repoPackages)
  25. {
  26. $repoConfig = array(
  27. 'url' => 'http://example.org',
  28. );
  29. $repository = $this->getMockBuilder('Composer\Repository\ComposerRepository')
  30. ->setMethods(array('loadRootServerFile', 'createPackage'))
  31. ->setConstructorArgs(array(
  32. $repoConfig,
  33. new NullIO,
  34. FactoryMock::createConfig(),
  35. ))
  36. ->getMock();
  37. $repository
  38. ->expects($this->exactly(2))
  39. ->method('loadRootServerFile')
  40. ->will($this->returnValue($repoPackages));
  41. foreach ($expected as $at => $arg) {
  42. $stubPackage = $this->getPackage('stub/stub', '1.0.0');
  43. $repository
  44. ->expects($this->at($at + 2))
  45. ->method('createPackage')
  46. ->with($this->identicalTo($arg), $this->equalTo('Composer\Package\CompletePackage'))
  47. ->will($this->returnValue($stubPackage));
  48. }
  49. // Triggers initialization
  50. $packages = $repository->getPackages();
  51. // Final sanity check, ensure the correct number of packages were added.
  52. $this->assertCount(count($expected), $packages);
  53. }
  54. public function loadDataProvider()
  55. {
  56. return array(
  57. // Old repository format
  58. array(
  59. array(
  60. array('name' => 'foo/bar', 'version' => '1.0.0'),
  61. ),
  62. array('foo/bar' => array(
  63. 'name' => 'foo/bar',
  64. 'versions' => array(
  65. '1.0.0' => array('name' => 'foo/bar', 'version' => '1.0.0'),
  66. ),
  67. )),
  68. ),
  69. // New repository format
  70. array(
  71. array(
  72. array('name' => 'bar/foo', 'version' => '3.14'),
  73. array('name' => 'bar/foo', 'version' => '3.145'),
  74. ),
  75. array('packages' => array(
  76. 'bar/foo' => array(
  77. '3.14' => array('name' => 'bar/foo', 'version' => '3.14'),
  78. '3.145' => array('name' => 'bar/foo', 'version' => '3.145'),
  79. ),
  80. )),
  81. ),
  82. );
  83. }
  84. public function testWhatProvides()
  85. {
  86. $repo = $this->getMockBuilder('Composer\Repository\ComposerRepository')
  87. ->disableOriginalConstructor()
  88. ->setMethods(array('fetchFile'))
  89. ->getMock();
  90. $cache = $this->getMockBuilder('Composer\Cache')->disableOriginalConstructor()->getMock();
  91. $cache->expects($this->any())
  92. ->method('sha256')
  93. ->will($this->returnValue(false));
  94. $properties = array(
  95. 'cache' => $cache,
  96. 'loader' => new ArrayLoader(),
  97. 'providerListing' => array('a' => array('sha256' => 'xxx')),
  98. 'providersUrl' => 'https://dummy.test.link/to/%package%/file',
  99. );
  100. foreach ($properties as $property => $value) {
  101. $ref = new \ReflectionProperty($repo, $property);
  102. $ref->setAccessible(true);
  103. $ref->setValue($repo, $value);
  104. }
  105. $repo->expects($this->any())
  106. ->method('fetchFile')
  107. ->will($this->returnValue(array(
  108. 'packages' => array(
  109. array(array(
  110. 'uid' => 1,
  111. 'name' => 'a',
  112. 'version' => 'dev-master',
  113. 'extra' => array('branch-alias' => array('dev-master' => '1.0.x-dev')),
  114. )),
  115. array(array(
  116. 'uid' => 2,
  117. 'name' => 'a',
  118. 'version' => 'dev-develop',
  119. 'extra' => array('branch-alias' => array('dev-develop' => '1.1.x-dev')),
  120. )),
  121. array(array(
  122. 'uid' => 3,
  123. 'name' => 'a',
  124. 'version' => '0.6',
  125. )),
  126. ),
  127. )));
  128. $pool = $this->getMockBuilder('Composer\DependencyResolver\Pool')->getMock();
  129. $pool->expects($this->any())
  130. ->method('isPackageAcceptable')
  131. ->will($this->returnValue(true));
  132. $versionParser = new VersionParser();
  133. $repo->setRootAliases(array(
  134. 'a' => array(
  135. $versionParser->normalize('0.6') => array('alias' => 'dev-feature', 'alias_normalized' => $versionParser->normalize('dev-feature')),
  136. $versionParser->normalize('1.1.x-dev') => array('alias' => '1.0', 'alias_normalized' => $versionParser->normalize('1.0')),
  137. ),
  138. ));
  139. $packages = $repo->whatProvides($pool, 'a');
  140. $this->assertCount(7, $packages);
  141. $this->assertEquals(array('1', '1-alias', '2', '2-alias', '2-root', '3', '3-root'), array_keys($packages));
  142. $this->assertInstanceOf('Composer\Package\AliasPackage', $packages['2-root']);
  143. $this->assertSame($packages['2'], $packages['2-root']->getAliasOf());
  144. $this->assertSame($packages['2'], $packages['2-alias']->getAliasOf());
  145. }
  146. public function testSearchWithType()
  147. {
  148. $repoConfig = array(
  149. 'url' => 'http://example.org',
  150. );
  151. $result = array(
  152. 'results' => array(
  153. array(
  154. 'name' => 'foo',
  155. 'description' => null,
  156. ),
  157. ),
  158. );
  159. $rfs = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  160. ->disableOriginalConstructor()
  161. ->getMock();
  162. $rfs->expects($this->at(0))
  163. ->method('getContents')
  164. ->with('example.org', 'http://example.org/packages.json', false)
  165. ->willReturn(json_encode(array('search' => '/search.json?q=%query%&type=%type%')));
  166. $rfs->expects($this->at(1))
  167. ->method('getContents')
  168. ->with('example.org', 'http://example.org/search.json?q=foo&type=composer-plugin', false)
  169. ->willReturn(json_encode($result));
  170. $repository = new ComposerRepository($repoConfig, new NullIO, FactoryMock::createConfig(), null, $rfs);
  171. $this->assertSame(
  172. array(array('name' => 'foo', 'description' => null)),
  173. $repository->search('foo', RepositoryInterface::SEARCH_FULLTEXT, 'composer-plugin')
  174. );
  175. $this->assertEmpty(
  176. $repository->search('foo', RepositoryInterface::SEARCH_FULLTEXT, 'library')
  177. );
  178. }
  179. /**
  180. * @dataProvider canonicalizeUrlProvider
  181. *
  182. * @param string $expected
  183. * @param string $url
  184. * @param string $repositoryUrl
  185. */
  186. public function testCanonicalizeUrl($expected, $url, $repositoryUrl)
  187. {
  188. $repository = new ComposerRepository(
  189. array('url' => $repositoryUrl),
  190. new NullIO(),
  191. FactoryMock::createConfig()
  192. );
  193. $object = new \ReflectionObject($repository);
  194. $method = $object->getMethod('canonicalizeUrl');
  195. $method->setAccessible(true);
  196. // ComposerRepository::__construct ensures that the repository URL has a
  197. // protocol, so reset it here in order to test all cases.
  198. $property = $object->getProperty('url');
  199. $property->setAccessible(true);
  200. $property->setValue($repository, $repositoryUrl);
  201. $this->assertSame($expected, $method->invoke($repository, $url));
  202. }
  203. public function canonicalizeUrlProvider()
  204. {
  205. return array(
  206. array(
  207. 'https://example.org/path/to/file',
  208. '/path/to/file',
  209. 'https://example.org',
  210. ),
  211. array(
  212. 'https://example.org/canonic_url',
  213. 'https://example.org/canonic_url',
  214. 'https://should-not-see-me.test',
  215. ),
  216. array(
  217. 'file:///path/to/repository/file',
  218. '/path/to/repository/file',
  219. 'file:///path/to/repository',
  220. ),
  221. array(
  222. // Assert that the repository URL is returned unchanged if it is
  223. // not a URL.
  224. // (Backward compatibility test)
  225. 'invalid_repo_url',
  226. '/path/to/file',
  227. 'invalid_repo_url',
  228. ),
  229. array(
  230. // Assert that URLs can contain sequences resembling pattern
  231. // references as understood by preg_replace() without messing up
  232. // the result.
  233. // (Regression test)
  234. 'https://example.org/path/to/unusual_$0_filename',
  235. '/path/to/unusual_$0_filename',
  236. 'https://example.org',
  237. ),
  238. );
  239. }
  240. public function testGetProviderNamesWillReturnPartialPackageNames()
  241. {
  242. $rfs = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  243. ->disableOriginalConstructor()
  244. ->getMock();
  245. $rfs->expects($this->at(0))
  246. ->method('getContents')
  247. ->with('example.org', 'http://example.org/packages.json', false)
  248. ->willReturn(json_encode(array(
  249. 'providers-lazy-url' => '/foo/p/%package%.json',
  250. 'packages' => array('foo/bar' => array(
  251. 'dev-branch' => array(),
  252. 'v1.0.0' => array(),
  253. ))
  254. )));
  255. $repository = new ComposerRepository(
  256. array('url' => 'http://example.org/packages.json'),
  257. new NullIO(),
  258. FactoryMock::createConfig(),
  259. null,
  260. $rfs
  261. );
  262. $this->assertTrue($repository->hasProviders());
  263. $this->assertEquals(array('foo/bar'), $repository->getProviderNames());
  264. }
  265. }