diff options
-rw-r--r-- | composer.json | 6 | ||||
-rw-r--r-- | tests/AddFileTest.php | 67 | ||||
-rw-r--r-- | tests/ArchiveTest.php | 89 | ||||
-rw-r--r-- | tests/BaseTestCase.php | 49 | ||||
-rw-r--r-- | tests/LargeFileTest.php | 35 | ||||
-rw-r--r-- | tests/PathTest.php | 83 |
6 files changed, 329 insertions, 0 deletions
diff --git a/composer.json b/composer.json index 67e2d06..3d078a8 100644 --- a/composer.json +++ b/composer.json @@ -29,5 +29,11 @@ "psr-4": { "Pablotron\\ZipStream\\Tests\\": "tests/" } + }, + + "scripts": { + "test": [ + "phpunit --bootstrap vendor/autoload.php tests" + ] } } diff --git a/tests/AddFileTest.php b/tests/AddFileTest.php new file mode 100644 index 0000000..3ea65e0 --- /dev/null +++ b/tests/AddFileTest.php @@ -0,0 +1,67 @@ +<?php +declare(strict_types = 1); + +namespace Pablotron\ZipStream\Tests; + +use \PHPUnit\Framework\TestCase; +use \Pablotron\ZipStream\ZipStream; + +final class AddFileTest extends BaseTestCase { + public function testCreateFile() : void { + $this->with_temp_zip(function(ZipStream &$zip) { + $zip->add_file('hello.txt', 'hello!'); + }, function(string $path) { + $zip = $this->open_archive($path); + + $this->assertEquals( + 'hello!', + $zip->getFromName('hello.txt') + ); + }); + } + + public function testCreateFileWithComment() : void { + $comment = 'test comment'; + $this->with_temp_zip(function(ZipStream &$zip) use ($comment) { + $zip->add_file('hello.txt', 'hello!', [ + 'comment' => $comment, + ]); + }, function(string $path) use ($comment) { + $zip = $this->open_archive($path); + + $this->assertEquals( + $comment, + $zip->getCommentName('hello.txt') + ); + }); + } + + public function testCreateFileWithUnknownMethod() : void { + $this->expectException(\Pablotron\ZipStream\UnknownMethodError::class); + + $this->with_temp_zip(function(ZipStream &$zip) { + $zip->add_file('hello.txt', 'hello!', [ + 'method' => -20, + ]); + }); + } + + public function testCreateFileTimestamp() : void { + # get timezone offset + # $ofs = \DateTimeZone::getOffset(\DateTime::getTimezone()); + $ofs = 4 * 3600; # hard-coded to EDT for now + + # get time from 2 hours ago (round to even number of seconds) + $time = ((time() - (2 * 3600)) >> 1) << 1; + + $this->with_temp_zip(function(ZipStream &$zip) use ($time) { + $zip->add_file('hello.txt', 'hello!', [ + 'time' => $time, + ]); + }, function($zip_path) use ($time, $ofs) { + $zip = $this->open_archive($zip_path); + $st = $zip->statName('hello.txt'); + $this->assertEquals($time, $st['mtime'] - $ofs); + }); + } +}; diff --git a/tests/ArchiveTest.php b/tests/ArchiveTest.php new file mode 100644 index 0000000..cbac0f1 --- /dev/null +++ b/tests/ArchiveTest.php @@ -0,0 +1,89 @@ +<?php +declare(strict_types = 1); + +namespace Pablotron\ZipStream\Tests; + +use PHPUnit\Framework\TestCase; +use Pablotron\ZipStream\ZipStream; +use Pablotron\ZipStream\FileWriter; +use Pablotron\ZipStream\StreamWriter; + +final class ArchiveTest extends BaseTestCase { + public function testCreate() : void { + $zip = new ZipStream('test.zip'); + + $this->assertInstanceOf( + ZipStream::class, + $zip + ); + } + + public function testFileWriter() { + $this->with_temp_file(function(string $dst_path) { + ZipStream::send($dst_path, function(ZipStream &$zip) { + $zip->add_file('hello.txt', 'hello!'); + }, [ + 'output' => new FileWriter(), + ]); + + # open archive + $zip = $this->open_archive($dst_path); + + # read hello.txt, check text + $this->assertEquals( + 'hello!', + $zip->getFromName('hello.txt') + ); + }); + } + + public function testStreamWriter() { + $this->with_temp_file(function(string $dst_path) { + $fh = fopen($dst_path, 'wb'); + if ($fh === false) { + throw new Exception("fopen() failed"); + } + + ZipStream::send($dst_path, function(ZipStream &$zip) { + $zip->add_file('hello.txt', 'hello!'); + }, [ + 'output' => new StreamWriter($fh), + ]); + + # close stream + fclose($fh); + + # open archive + $zip = $this->open_archive($dst_path); + + # read hello.txt, check text + $this->assertEquals( + 'hello!', + $zip->getFromName('hello.txt') + ); + }); + } + + public function testArchiveComment() : void { + $this->with_temp_file(function($dst_path) { + $comment = 'test archive comment'; + + # write archive + ZipStream::send($dst_path, function(ZipStream &$zip) { + $zip->add_file('hello.txt', 'hello!'); + }, [ + 'comment' => $comment, + 'output' => new FileWriter(), + ]); + + # open archive + $zip = $this->open_archive($dst_path); + + # read hello.txt, check text + $this->assertEquals( + $comment, + $zip->getArchiveComment() + ); + }); + } +}; diff --git a/tests/BaseTestCase.php b/tests/BaseTestCase.php new file mode 100644 index 0000000..8934e96 --- /dev/null +++ b/tests/BaseTestCase.php @@ -0,0 +1,49 @@ +<?php +declare(strict_types = 1); + +namespace Pablotron\ZipStream\Tests; + +use PHPUnit\Framework\TestCase; +use \Pablotron\ZipStream\ZipStream; +use \Pablotron\ZipStream\FileWriter; + +class BaseTestCase extends TestCase { + protected function open_archive(string $path) { + # open archive, check for error + $zip = new \ZipArchive(); + if ($zip->open($path) !== true) { + throw new Exception("ZipArchive#open() failed: $dst_name"); + } + + # return archive + return $zip; + } + + protected function with_temp_file(callable $cb) : void { + # build path to temp file + $path = tempnam('/tmp', 'zipstream-test'); + try { + # pass to test + $cb($path); + } finally { + if (file_exists($path)) { + # remove temp file if it exists + unlink($path); + } + } + } + + protected function with_temp_zip(callable $zip_cb, callable $test_cb = null) { + $this->with_temp_file(function(string $dst_path) use ($zip_cb, $test_cb) { + # create zip, pass to zip callback + ZipStream::send($dst_path, $zip_cb, [ + 'output' => new FileWriter(), + ]); + + if ($test_cb) { + # pass to test callback + $test_cb($dst_path); + } + }); + } +}; diff --git a/tests/LargeFileTest.php b/tests/LargeFileTest.php new file mode 100644 index 0000000..c271b47 --- /dev/null +++ b/tests/LargeFileTest.php @@ -0,0 +1,35 @@ +<?php +declare(strict_types = 1); + +namespace Pablotron\ZipStream\Tests; + +use \PHPUnit\Framework\TestCase; +use \Pablotron\ZipStream\ZipStream; + +final class LargeFileTest extends BaseTestCase { + public function testCreateLargeFile() : void { + # build 4M string + $chunk_size = (1 << 22); + $num_chunks = 1025; + + # calculate expected size + $expected_size = $chunk_size * $num_chunks; + + $this->with_temp_zip(function(ZipStream &$zip) use ($chunk_size, $num_chunks) { + $zip->add('hello.txt', function($e) use ($chunk_size, $num_chunks) { + # build chunk + $data = str_repeat('x', $chunk_size); + + # repeatedly write chunk + foreach (range(0, $num_chunks - 1) as $i) { + $e->write($data); + } + }); + }, function($zip_path) use ($expected_size) { + $zip = $this->open_archive($zip_path); + $st = $zip->statName('hello.txt'); + + $this->assertEquals($expected_size, $st['size']); + }); + } +}; diff --git a/tests/PathTest.php b/tests/PathTest.php new file mode 100644 index 0000000..a71be8d --- /dev/null +++ b/tests/PathTest.php @@ -0,0 +1,83 @@ +<?php +declare(strict_types = 1); + +namespace Pablotron\ZipStream\Tests; + +use \PHPUnit\Framework\TestCase; +use \Pablotron\ZipStream\ZipStream; + +final class PathTest extends BaseTestCase { + public function testAddEmptyPath() : void { + $this->expectException(\Pablotron\ZipStream\PathError::class); + + $this->with_temp_zip(function(ZipStream &$zip) { + $zip->add_file('', 'empty test'); + }); + } + + public function testAddLongPath() : void { + $this->expectException(\Pablotron\ZipStream\PathError::class); + + $this->with_temp_zip(function(ZipStream &$zip) { + $long_path = str_repeat('x', 65535); + $zip->add_file($long_path, 'long path test'); + }); + } + + public function testAddPathWithLeadingSlash() : void { + $this->expectException(\Pablotron\ZipStream\PathError::class); + + $this->with_temp_zip(function(ZipStream &$zip) { + $zip->add_file('/foo', 'leading slash path test'); + }); + } + + public function testAddPathWithTrailingSlash() : void { + $this->expectException(\Pablotron\ZipStream\PathError::class); + + $this->with_temp_zip(function(ZipStream &$zip) { + $zip->add_file('foo/', 'trailing slash path test'); + }); + } + + public function testAddPathWithDoubleSlashes() : void { + $this->expectException(\Pablotron\ZipStream\PathError::class); + + $this->with_temp_zip(function(ZipStream &$zip) { + $zip->add_file('foo//bar', 'double slash path test'); + }); + } + + public function testAddPathWithBackslashes() : void { + $this->expectException(\Pablotron\ZipStream\PathError::class); + + $this->with_temp_zip(function(ZipStream &$zip) { + $zip->add_file('foo\\bar', 'backslash path test'); + }); + } + + public function testLeadingRelativePath() : void { + $this->expectException(\Pablotron\ZipStream\PathError::class); + + $this->with_temp_zip(function(ZipStream &$zip) { + $zip->add_file('../bar', 'leading relative path test'); + }); + } + + public function testMiddleRelativePath() : void { + $this->expectException(\Pablotron\ZipStream\PathError::class); + + $this->with_temp_zip(function(ZipStream &$zip) { + $zip->add_file('foo/../bar', 'middle relative path test'); + }); + } + + public function testTrailingRelativePath() : void { + $this->expectException(\Pablotron\ZipStream\PathError::class); + + $this->with_temp_zip(function(ZipStream &$zip) { + $zip->add_file('foo/../bar', 'trailing relative path test'); + }); + } + +}; |