ZipDownloaderTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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\Downloader;
  12. use Composer\Downloader\ZipDownloader;
  13. use Composer\Package\PackageInterface;
  14. use Composer\Test\TestCase;
  15. use Composer\Util\Filesystem;
  16. class ZipDownloaderTest extends TestCase
  17. {
  18. /**
  19. * @var string
  20. */
  21. private $testDir;
  22. private $prophet;
  23. private $io;
  24. private $config;
  25. public function setUp()
  26. {
  27. $this->testDir = $this->getUniqueTmpDirectory();
  28. $this->io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
  29. $this->config = $this->getMockBuilder('Composer\Config')->getMock();
  30. }
  31. public function tearDown()
  32. {
  33. $fs = new Filesystem;
  34. $fs->removeDirectory($this->testDir);
  35. $this->setPrivateProperty('hasSystemUnzip', null);
  36. $this->setPrivateProperty('hasZipArchive', null);
  37. }
  38. public function setPrivateProperty($name, $value, $obj = null)
  39. {
  40. $reflectionClass = new \ReflectionClass('Composer\Downloader\ZipDownloader');
  41. $reflectedProperty = $reflectionClass->getProperty($name);
  42. $reflectedProperty->setAccessible(true);
  43. if ($obj === null) {
  44. $reflectedProperty->setValue($value);
  45. } else {
  46. $reflectedProperty->setValue($obj, $value);
  47. }
  48. }
  49. /**
  50. * @group only
  51. */
  52. public function testErrorMessages()
  53. {
  54. if (!class_exists('ZipArchive')) {
  55. $this->markTestSkipped('zip extension missing');
  56. }
  57. $this->config->expects($this->at(0))
  58. ->method('get')
  59. ->with('disable-tls')
  60. ->will($this->returnValue(false));
  61. $this->config->expects($this->at(1))
  62. ->method('get')
  63. ->with('cafile')
  64. ->will($this->returnValue(null));
  65. $this->config->expects($this->at(2))
  66. ->method('get')
  67. ->with('capath')
  68. ->will($this->returnValue(null));
  69. $this->config->expects($this->at(3))
  70. ->method('get')
  71. ->with('vendor-dir')
  72. ->will($this->returnValue($this->testDir));
  73. $packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock();
  74. $packageMock->expects($this->any())
  75. ->method('getDistUrl')
  76. ->will($this->returnValue($distUrl = 'file://'.__FILE__))
  77. ;
  78. $packageMock->expects($this->any())
  79. ->method('getDistUrls')
  80. ->will($this->returnValue(array($distUrl)))
  81. ;
  82. $packageMock->expects($this->atLeastOnce())
  83. ->method('getTransportOptions')
  84. ->will($this->returnValue(array()))
  85. ;
  86. $downloader = new ZipDownloader($this->io, $this->config);
  87. $this->setPrivateProperty('hasSystemUnzip', false);
  88. try {
  89. $downloader->download($packageMock, sys_get_temp_dir().'/composer-zip-test');
  90. $this->fail('Download of invalid zip files should throw an exception');
  91. } catch (\Exception $e) {
  92. $this->assertContains('is not a zip archive', $e->getMessage());
  93. }
  94. }
  95. /**
  96. * @expectedException \RuntimeException
  97. * @expectedExceptionMessage There was an error extracting the ZIP file
  98. */
  99. public function testZipArchiveOnlyFailed()
  100. {
  101. if (!class_exists('ZipArchive')) {
  102. $this->markTestSkipped('zip extension missing');
  103. }
  104. $this->setPrivateProperty('hasSystemUnzip', false);
  105. $this->setPrivateProperty('hasZipArchive', true);
  106. $downloader = new MockedZipDownloader($this->io, $this->config);
  107. $zipArchive = $this->getMockBuilder('ZipArchive')->getMock();
  108. $zipArchive->expects($this->at(0))
  109. ->method('open')
  110. ->will($this->returnValue(true));
  111. $zipArchive->expects($this->at(1))
  112. ->method('extractTo')
  113. ->will($this->returnValue(false));
  114. $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
  115. $downloader->extract('testfile.zip', 'vendor/dir');
  116. }
  117. /**
  118. * @expectedException \RuntimeException
  119. * @expectedExceptionMessage The archive may contain identical file names with different capitalization (which fails on case insensitive filesystems): Not a directory
  120. */
  121. public function testZipArchiveExtractOnlyFailed()
  122. {
  123. if (!class_exists('ZipArchive')) {
  124. $this->markTestSkipped('zip extension missing');
  125. }
  126. $this->setPrivateProperty('hasSystemUnzip', false);
  127. $this->setPrivateProperty('hasZipArchive', true);
  128. $downloader = new MockedZipDownloader($this->io, $this->config);
  129. $zipArchive = $this->getMockBuilder('ZipArchive')->getMock();
  130. $zipArchive->expects($this->at(0))
  131. ->method('open')
  132. ->will($this->returnValue(true));
  133. $zipArchive->expects($this->at(1))
  134. ->method('extractTo')
  135. ->will($this->throwException(new \ErrorException('Not a directory')));
  136. $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
  137. $downloader->extract('testfile.zip', 'vendor/dir');
  138. }
  139. /**
  140. * @group only
  141. */
  142. public function testZipArchiveOnlyGood()
  143. {
  144. if (!class_exists('ZipArchive')) {
  145. $this->markTestSkipped('zip extension missing');
  146. }
  147. $this->setPrivateProperty('hasSystemUnzip', false);
  148. $this->setPrivateProperty('hasZipArchive', true);
  149. $downloader = new MockedZipDownloader($this->io, $this->config);
  150. $zipArchive = $this->getMockBuilder('ZipArchive')->getMock();
  151. $zipArchive->expects($this->at(0))
  152. ->method('open')
  153. ->will($this->returnValue(true));
  154. $zipArchive->expects($this->at(1))
  155. ->method('extractTo')
  156. ->will($this->returnValue(true));
  157. $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
  158. $downloader->extract('testfile.zip', 'vendor/dir');
  159. }
  160. /**
  161. * @expectedException \Exception
  162. * @expectedExceptionMessage Failed to execute unzip
  163. */
  164. public function testSystemUnzipOnlyFailed()
  165. {
  166. if (!class_exists('ZipArchive')) {
  167. $this->markTestSkipped('zip extension missing');
  168. }
  169. $this->setPrivateProperty('hasSystemUnzip', true);
  170. $this->setPrivateProperty('hasZipArchive', false);
  171. $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
  172. $processExecutor->expects($this->at(0))
  173. ->method('execute')
  174. ->will($this->returnValue(1));
  175. $downloader = new MockedZipDownloader($this->io, $this->config, null, null, $processExecutor);
  176. $downloader->extract('testfile.zip', 'vendor/dir');
  177. }
  178. public function testSystemUnzipOnlyGood()
  179. {
  180. if (!class_exists('ZipArchive')) {
  181. $this->markTestSkipped('zip extension missing');
  182. }
  183. $this->setPrivateProperty('hasSystemUnzip', true);
  184. $this->setPrivateProperty('hasZipArchive', false);
  185. $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
  186. $processExecutor->expects($this->at(0))
  187. ->method('execute')
  188. ->will($this->returnValue(0));
  189. $downloader = new MockedZipDownloader($this->io, $this->config, null, null, $processExecutor);
  190. $downloader->extract('testfile.zip', 'vendor/dir');
  191. }
  192. public function testNonWindowsFallbackGood()
  193. {
  194. if (!class_exists('ZipArchive')) {
  195. $this->markTestSkipped('zip extension missing');
  196. }
  197. $this->setPrivateProperty('isWindows', false);
  198. $this->setPrivateProperty('hasSystemUnzip', true);
  199. $this->setPrivateProperty('hasZipArchive', true);
  200. $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
  201. $processExecutor->expects($this->at(0))
  202. ->method('execute')
  203. ->will($this->returnValue(1));
  204. $zipArchive = $this->getMockBuilder('ZipArchive')->getMock();
  205. $zipArchive->expects($this->at(0))
  206. ->method('open')
  207. ->will($this->returnValue(true));
  208. $zipArchive->expects($this->at(1))
  209. ->method('extractTo')
  210. ->will($this->returnValue(true));
  211. $downloader = new MockedZipDownloader($this->io, $this->config, null, null, $processExecutor);
  212. $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
  213. $downloader->extract('testfile.zip', 'vendor/dir');
  214. }
  215. /**
  216. * @expectedException \Exception
  217. * @expectedExceptionMessage There was an error extracting the ZIP file
  218. */
  219. public function testNonWindowsFallbackFailed()
  220. {
  221. if (!class_exists('ZipArchive')) {
  222. $this->markTestSkipped('zip extension missing');
  223. }
  224. $this->setPrivateProperty('isWindows', false);
  225. $this->setPrivateProperty('hasSystemUnzip', true);
  226. $this->setPrivateProperty('hasZipArchive', true);
  227. $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
  228. $processExecutor->expects($this->at(0))
  229. ->method('execute')
  230. ->will($this->returnValue(1));
  231. $zipArchive = $this->getMockBuilder('ZipArchive')->getMock();
  232. $zipArchive->expects($this->at(0))
  233. ->method('open')
  234. ->will($this->returnValue(true));
  235. $zipArchive->expects($this->at(1))
  236. ->method('extractTo')
  237. ->will($this->returnValue(false));
  238. $downloader = new MockedZipDownloader($this->io, $this->config, null, null, $processExecutor);
  239. $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
  240. $downloader->extract('testfile.zip', 'vendor/dir');
  241. }
  242. public function testWindowsFallbackGood()
  243. {
  244. if (!class_exists('ZipArchive')) {
  245. $this->markTestSkipped('zip extension missing');
  246. }
  247. $this->setPrivateProperty('isWindows', true);
  248. $this->setPrivateProperty('hasSystemUnzip', true);
  249. $this->setPrivateProperty('hasZipArchive', true);
  250. $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
  251. $processExecutor->expects($this->atLeastOnce())
  252. ->method('execute')
  253. ->will($this->returnValue(0));
  254. $zipArchive = $this->getMockBuilder('ZipArchive')->getMock();
  255. $zipArchive->expects($this->at(0))
  256. ->method('open')
  257. ->will($this->returnValue(true));
  258. $zipArchive->expects($this->at(1))
  259. ->method('extractTo')
  260. ->will($this->returnValue(false));
  261. $downloader = new MockedZipDownloader($this->io, $this->config, null, null, $processExecutor);
  262. $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
  263. $downloader->extract('testfile.zip', 'vendor/dir');
  264. }
  265. /**
  266. * @expectedException \Exception
  267. * @expectedExceptionMessage Failed to execute unzip
  268. */
  269. public function testWindowsFallbackFailed()
  270. {
  271. if (!class_exists('ZipArchive')) {
  272. $this->markTestSkipped('zip extension missing');
  273. }
  274. $this->setPrivateProperty('isWindows', true);
  275. $this->setPrivateProperty('hasSystemUnzip', true);
  276. $this->setPrivateProperty('hasZipArchive', true);
  277. $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
  278. $processExecutor->expects($this->atLeastOnce())
  279. ->method('execute')
  280. ->will($this->returnValue(1));
  281. $zipArchive = $this->getMockBuilder('ZipArchive')->getMock();
  282. $zipArchive->expects($this->at(0))
  283. ->method('open')
  284. ->will($this->returnValue(true));
  285. $zipArchive->expects($this->at(1))
  286. ->method('extractTo')
  287. ->will($this->returnValue(false));
  288. $downloader = new MockedZipDownloader($this->io, $this->config, null, null, $processExecutor);
  289. $this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
  290. $downloader->extract('testfile.zip', 'vendor/dir');
  291. }
  292. }
  293. class MockedZipDownloader extends ZipDownloader
  294. {
  295. public function download(PackageInterface $package, $path, $output = true)
  296. {
  297. return;
  298. }
  299. public function extract($file, $path)
  300. {
  301. parent::extract($file, $path);
  302. }
  303. }