ZipDownloaderTest.php 13 KB

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