FilesystemAdapterTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. <?php
  2. namespace Illuminate\Tests\Filesystem;
  3. use Carbon\Carbon;
  4. use GuzzleHttp\Psr7\Stream;
  5. use Illuminate\Contracts\Filesystem\FileExistsException;
  6. use Illuminate\Contracts\Filesystem\FileNotFoundException;
  7. use Illuminate\Filesystem\FilesystemAdapter;
  8. use Illuminate\Http\UploadedFile;
  9. use Illuminate\Testing\Assert;
  10. use InvalidArgumentException;
  11. use League\Flysystem\Adapter\Local;
  12. use League\Flysystem\Filesystem;
  13. use Mockery as m;
  14. use PHPUnit\Framework\TestCase;
  15. use Symfony\Component\HttpFoundation\StreamedResponse;
  16. class FilesystemAdapterTest extends TestCase
  17. {
  18. private $tempDir;
  19. private $filesystem;
  20. protected function setUp(): void
  21. {
  22. $this->tempDir = __DIR__.'/tmp';
  23. $this->filesystem = new Filesystem(new Local($this->tempDir));
  24. }
  25. protected function tearDown(): void
  26. {
  27. $filesystem = new Filesystem(new Local(dirname($this->tempDir)));
  28. $filesystem->deleteDir(basename($this->tempDir));
  29. m::close();
  30. }
  31. public function testResponse()
  32. {
  33. $this->filesystem->write('file.txt', 'Hello World');
  34. $files = new FilesystemAdapter($this->filesystem);
  35. $response = $files->response('file.txt');
  36. ob_start();
  37. $response->sendContent();
  38. $content = ob_get_clean();
  39. $this->assertInstanceOf(StreamedResponse::class, $response);
  40. $this->assertSame('Hello World', $content);
  41. $this->assertSame('inline; filename=file.txt', $response->headers->get('content-disposition'));
  42. }
  43. public function testDownload()
  44. {
  45. $this->filesystem->write('file.txt', 'Hello World');
  46. $files = new FilesystemAdapter($this->filesystem);
  47. $response = $files->download('file.txt', 'hello.txt');
  48. $this->assertInstanceOf(StreamedResponse::class, $response);
  49. $this->assertSame('attachment; filename=hello.txt', $response->headers->get('content-disposition'));
  50. }
  51. public function testDownloadNonAsciiFilename()
  52. {
  53. $this->filesystem->write('file.txt', 'Hello World');
  54. $files = new FilesystemAdapter($this->filesystem);
  55. $response = $files->download('file.txt', 'пиздюк.txt');
  56. $this->assertInstanceOf(StreamedResponse::class, $response);
  57. $this->assertSame("attachment; filename=pizdyuk.txt; filename*=utf-8''%D0%BF%D0%B8%D0%B7%D0%B4%D1%8E%D0%BA.txt", $response->headers->get('content-disposition'));
  58. }
  59. public function testDownloadNonAsciiEmptyFilename()
  60. {
  61. $this->filesystem->write('пиздюк.txt', 'Hello World');
  62. $files = new FilesystemAdapter($this->filesystem);
  63. $response = $files->download('пиздюк.txt');
  64. $this->assertInstanceOf(StreamedResponse::class, $response);
  65. $this->assertSame('attachment; filename=pizdyuk.txt; filename*=utf-8\'\'%D0%BF%D0%B8%D0%B7%D0%B4%D1%8E%D0%BA.txt', $response->headers->get('content-disposition'));
  66. }
  67. public function testDownloadPercentInFilename()
  68. {
  69. $this->filesystem->write('Hello%World.txt', 'Hello World');
  70. $files = new FilesystemAdapter($this->filesystem);
  71. $response = $files->download('Hello%World.txt', 'Hello%World.txt');
  72. $this->assertInstanceOf(StreamedResponse::class, $response);
  73. $this->assertSame('attachment; filename=HelloWorld.txt; filename*=utf-8\'\'Hello%25World.txt', $response->headers->get('content-disposition'));
  74. }
  75. public function testExists()
  76. {
  77. $this->filesystem->write('file.txt', 'Hello World');
  78. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  79. $this->assertTrue($filesystemAdapter->exists('file.txt'));
  80. }
  81. public function testMissing()
  82. {
  83. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  84. $this->assertTrue($filesystemAdapter->missing('file.txt'));
  85. }
  86. public function testPath()
  87. {
  88. $this->filesystem->write('file.txt', 'Hello World');
  89. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  90. $this->assertEquals($this->tempDir.DIRECTORY_SEPARATOR.'file.txt', $filesystemAdapter->path('file.txt'));
  91. }
  92. public function testGet()
  93. {
  94. $this->filesystem->write('file.txt', 'Hello World');
  95. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  96. $this->assertSame('Hello World', $filesystemAdapter->get('file.txt'));
  97. }
  98. public function testGetFileNotFound()
  99. {
  100. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  101. $this->expectException(FileNotFoundException::class);
  102. $filesystemAdapter->get('file.txt');
  103. }
  104. public function testPut()
  105. {
  106. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  107. $filesystemAdapter->put('file.txt', 'Something inside');
  108. $this->assertStringEqualsFile($this->tempDir.'/file.txt', 'Something inside');
  109. }
  110. public function testPrepend()
  111. {
  112. file_put_contents($this->tempDir.'/file.txt', 'World');
  113. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  114. $filesystemAdapter->prepend('file.txt', 'Hello ');
  115. $this->assertStringEqualsFile($this->tempDir.'/file.txt', 'Hello '.PHP_EOL.'World');
  116. }
  117. public function testAppend()
  118. {
  119. file_put_contents($this->tempDir.'/file.txt', 'Hello ');
  120. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  121. $filesystemAdapter->append('file.txt', 'Moon');
  122. $this->assertStringEqualsFile($this->tempDir.'/file.txt', 'Hello '.PHP_EOL.'Moon');
  123. }
  124. public function testDelete()
  125. {
  126. file_put_contents($this->tempDir.'/file.txt', 'Hello World');
  127. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  128. $this->assertTrue($filesystemAdapter->delete('file.txt'));
  129. Assert::assertFileDoesNotExist($this->tempDir.'/file.txt');
  130. }
  131. public function testDeleteReturnsFalseWhenFileNotFound()
  132. {
  133. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  134. $this->assertFalse($filesystemAdapter->delete('file.txt'));
  135. }
  136. public function testCopy()
  137. {
  138. $data = '33232';
  139. mkdir($this->tempDir.'/foo');
  140. file_put_contents($this->tempDir.'/foo/foo.txt', $data);
  141. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  142. $filesystemAdapter->copy('/foo/foo.txt', '/foo/foo2.txt');
  143. $this->assertFileExists($this->tempDir.'/foo/foo.txt');
  144. $this->assertEquals($data, file_get_contents($this->tempDir.'/foo/foo.txt'));
  145. $this->assertFileExists($this->tempDir.'/foo/foo2.txt');
  146. $this->assertEquals($data, file_get_contents($this->tempDir.'/foo/foo2.txt'));
  147. }
  148. public function testMove()
  149. {
  150. $data = '33232';
  151. mkdir($this->tempDir.'/foo');
  152. file_put_contents($this->tempDir.'/foo/foo.txt', $data);
  153. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  154. $filesystemAdapter->move('/foo/foo.txt', '/foo/foo2.txt');
  155. Assert::assertFileDoesNotExist($this->tempDir.'/foo/foo.txt');
  156. $this->assertFileExists($this->tempDir.'/foo/foo2.txt');
  157. $this->assertEquals($data, file_get_contents($this->tempDir.'/foo/foo2.txt'));
  158. }
  159. public function testStream()
  160. {
  161. $this->filesystem->write('file.txt', $original_content = 'Hello World');
  162. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  163. $readStream = $filesystemAdapter->readStream('file.txt');
  164. $filesystemAdapter->writeStream('copy.txt', $readStream);
  165. $this->assertEquals($original_content, $filesystemAdapter->get('copy.txt'));
  166. }
  167. public function testStreamBetweenFilesystems()
  168. {
  169. $secondFilesystem = new Filesystem(new Local($this->tempDir.'/second'));
  170. $this->filesystem->write('file.txt', $original_content = 'Hello World');
  171. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  172. $secondFilesystemAdapter = new FilesystemAdapter($secondFilesystem);
  173. $readStream = $filesystemAdapter->readStream('file.txt');
  174. $secondFilesystemAdapter->writeStream('copy.txt', $readStream);
  175. $this->assertEquals($original_content, $secondFilesystemAdapter->get('copy.txt'));
  176. }
  177. public function testStreamToExistingFileThrows()
  178. {
  179. $this->expectException(FileExistsException::class);
  180. $this->filesystem->write('file.txt', 'Hello World');
  181. $this->filesystem->write('existing.txt', 'Dear Kate');
  182. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  183. $readStream = $filesystemAdapter->readStream('file.txt');
  184. $filesystemAdapter->writeStream('existing.txt', $readStream);
  185. }
  186. public function testReadStreamNonExistentFileThrows()
  187. {
  188. $this->expectException(FileNotFoundException::class);
  189. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  190. $filesystemAdapter->readStream('nonexistent.txt');
  191. }
  192. public function testStreamInvalidResourceThrows()
  193. {
  194. $this->expectException(InvalidArgumentException::class);
  195. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  196. $filesystemAdapter->writeStream('file.txt', 'foo bar');
  197. }
  198. public function testPutWithStreamInterface()
  199. {
  200. file_put_contents($this->tempDir.'/foo.txt', 'some-data');
  201. $spy = m::spy($this->filesystem);
  202. $filesystemAdapter = new FilesystemAdapter($spy);
  203. $stream = fopen($this->tempDir.'/foo.txt', 'r');
  204. $guzzleStream = new Stream($stream);
  205. $filesystemAdapter->put('bar.txt', $guzzleStream);
  206. fclose($stream);
  207. $spy->shouldHaveReceived('putStream');
  208. $this->assertSame('some-data', $filesystemAdapter->get('bar.txt'));
  209. }
  210. public function testPutFileAs()
  211. {
  212. file_put_contents($filePath = $this->tempDir.'/foo.txt', 'uploaded file content');
  213. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  214. $uploadedFile = new UploadedFile($filePath, 'org.txt', null, null, true);
  215. $storagePath = $filesystemAdapter->putFileAs('/', $uploadedFile, 'new.txt');
  216. $this->assertSame('new.txt', $storagePath);
  217. $this->assertFileExists($filePath);
  218. $filesystemAdapter->assertExists($storagePath);
  219. $this->assertSame('uploaded file content', $filesystemAdapter->read($storagePath));
  220. $filesystemAdapter->assertExists(
  221. $storagePath,
  222. 'uploaded file content'
  223. );
  224. }
  225. public function testPutFileAsWithAbsoluteFilePath()
  226. {
  227. file_put_contents($filePath = $this->tempDir.'/foo.txt', 'normal file content');
  228. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  229. $storagePath = $filesystemAdapter->putFileAs('/', $filePath, 'new.txt');
  230. $this->assertSame('normal file content', $filesystemAdapter->read($storagePath));
  231. }
  232. public function testPutFile()
  233. {
  234. file_put_contents($filePath = $this->tempDir.'/foo.txt', 'uploaded file content');
  235. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  236. $uploadedFile = new UploadedFile($filePath, 'org.txt', null, null, true);
  237. $storagePath = $filesystemAdapter->putFile('/', $uploadedFile);
  238. $this->assertSame(44, strlen($storagePath)); // random 40 characters + ".txt"
  239. $this->assertFileExists($filePath);
  240. $filesystemAdapter->assertExists($storagePath);
  241. $filesystemAdapter->assertExists(
  242. $storagePath,
  243. 'uploaded file content'
  244. );
  245. }
  246. public function testPutFileWithAbsoluteFilePath()
  247. {
  248. file_put_contents($filePath = $this->tempDir.'/foo.txt', 'uploaded file content');
  249. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  250. $storagePath = $filesystemAdapter->putFile('/', $filePath);
  251. $this->assertSame(44, strlen($storagePath)); // random 40 characters + ".txt"
  252. $filesystemAdapter->assertExists($storagePath);
  253. $filesystemAdapter->assertExists(
  254. $storagePath,
  255. 'uploaded file content'
  256. );
  257. }
  258. public function testMacroable()
  259. {
  260. $this->filesystem->write('foo.txt', 'Hello World');
  261. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  262. $filesystemAdapter->macro('getFoo', function () {
  263. return $this->get('foo.txt');
  264. });
  265. $this->assertSame('Hello World', $filesystemAdapter->getFoo());
  266. }
  267. public function testTemporaryUrlWithCustomCallback()
  268. {
  269. $filesystemAdapter = new FilesystemAdapter($this->filesystem);
  270. $filesystemAdapter->buildTemporaryUrlsUsing(function ($path, Carbon $expiration, $options) {
  271. return $path.$expiration->toString().implode('', $options);
  272. });
  273. $path = 'foo';
  274. $expiration = Carbon::create(2021, 18, 12, 13);
  275. $options = ['bar' => 'baz'];
  276. $this->assertSame(
  277. $path.$expiration->toString().implode('', $options),
  278. $filesystemAdapter->temporaryUrl($path, $expiration, $options)
  279. );
  280. }
  281. }