You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

416 lines
14 KiB

<?php
include_once dirname(__FILE__).'/../szipinfo.php';
/**
* Test case for SzipInfo.
*
* @group szip
*/
class SzipInfoTest extends PHPUnit_Framework_TestCase
{
protected $fixturesDir;
/**
* This method is called before each test is executed.
*/
protected function setUp()
{
$this->fixturesDir = realpath(dirname(__FILE__).'/fixtures/szip');
}
/**
* 7z files consist of headers at the archive start and end, with the blocks
* of packed data streams between. We should be abe to report an accurate list
* of all headers in summmary form.
*
* @dataProvider providerTestFixtures
* @param string $filename sample 7z filename
* @param string $headers expected list of valid headers
*/
public function testStoresListOfAllValidHeaders($filename, $headers)
{
$szip = new SzipInfo;
$szip->open($filename, true);
$this->assertEmpty($szip->error, $szip->error);
$headerList = $szip->getHeaders(true);
$this->assertEquals(count($headers), count($headerList));
$this->assertEquals($headers, $headerList);
}
/**
* Provides test data from sample files.
*/
public function providerTestFixtures()
{
$ds = DIRECTORY_SEPARATOR;
$fixturesDir = realpath(dirname(__FILE__).'/fixtures/szip');
$fixtures = array();
foreach (glob($fixturesDir.$ds.'*.{7z,001,002}', GLOB_BRACE) as $szipfile) {
$fname = pathinfo($szipfile, PATHINFO_BASENAME).'.headers';
$fpath = $fixturesDir.$ds.$fname;
if (file_exists($fpath)) {
$headers = include $fpath;
$fixtures[] = array('filename' => $szipfile, 'headers' => $headers);
}
}
return $fixtures;
}
/**
* We should be able to report on the contents of the 7z archive, with some
* simple processing of the raw headers to make them human-readable. It's
* especially helpful to know if we're dealing with files stored in solid
* archives and/or compressed substreams.
*/
public function testListsAllArchiveFiles()
{
$szip = new SzipInfo;
// Without substreams
$szip->open($this->fixturesDir.'/store_method.7z');
$this->assertEmpty($szip->error);
$this->assertFalse($szip->isSolid);
$this->assertSame(2, $szip->blockCount);
$files = $szip->getFileList();
$this->assertCount(2, $files);
$file = $files[0];
$this->assertSame('7zFormat.txt', $file['name']);
$this->assertSame(7573, $file['size']);
$this->assertSame(1284641836, $file['date']);
$this->assertSame(0, $file['pass']);
$this->assertSame(0, $file['compressed']);
$this->assertSame(0, $file['block']);
$this->assertSame('32-7604', $file['range']);
$this->assertSame('3f8ccf66', $file['crc32']);
$this->assertArrayNotHasKey('is_dir', $file);
$file = $files[1];
$this->assertSame('foo.txt', $file['name']);
$this->assertSame(15, $file['size']);
$this->assertSame(1373228890, $file['date']);
$this->assertSame(0, $file['pass']);
$this->assertSame(0, $file['compressed']);
$this->assertSame(1, $file['block']);
$this->assertSame('7605-7619', $file['range']);
$this->assertSame('1a92d0b1', $file['crc32']);
$this->assertArrayNotHasKey('is_dir', $file);
// With compressed substreams
$szip->open($this->fixturesDir.'/solid_lzma_multi.7z');
$this->assertEmpty($szip->error);
$this->assertTrue($szip->isSolid);
$this->assertSame(1, $szip->blockCount);
$files = $szip->getFileList();
$this->assertCount(3, $files);
$file = $files[0];
$this->assertSame('7zFormat.txt', $file['name']);
$this->assertSame(7573, $file['size']);
$this->assertSame(1, $file['compressed']);
$this->assertSame(0, $file['block']);
$this->assertSame('32-2087', $file['range']);
$this->assertSame('3f8ccf66', $file['crc32']);
$file = $files[1];
$this->assertSame('bar.txt', $file['name']);
$this->assertSame(15, $file['size']);
$this->assertSame(1, $file['compressed']);
$this->assertSame(0, $file['block']);
$this->assertSame('32-2087', $file['range']);
$this->assertSame('71afb453', $file['crc32']);
$file = $files[2];
$this->assertSame('foo.txt', $file['name']);
$this->assertSame(15, $file['size']);
$this->assertSame(1, $file['compressed']);
$this->assertSame(0, $file['block']);
$this->assertSame('32-2087', $file['range']);
$this->assertSame('1a92d0b1', $file['crc32']);
// With directories/empty streams
$szip->open($this->fixturesDir.'/store_with_empty.7z');
$this->assertEmpty($szip->error);
$this->assertSame(2, $szip->blockCount);
$files = $szip->getFileList();
$this->assertCount(4, $files);
$file = $files[0];
$this->assertSame('testdir3/7zFormat.txt', $file['name']);
$this->assertSame(7573, $file['size']);
$this->assertSame(0, $file['block']);
$file = $files[1];
$this->assertSame('testdir3/foo.txt', $file['name']);
$this->assertSame(15, $file['size']);
$this->assertSame(1, $file['block']);
$file = $files[2];
$this->assertSame('testdir3/empty.txt', $file['name']);
$this->assertSame(0, $file['size']);
$this->assertArrayNotHasKey('block', $file);
$this->assertArrayNotHasKey('range', $file);
$this->assertArrayNotHasKey('crc32', $file);
$this->assertArrayNotHasKey('is_dir', $file);
$file = $files[3];
$this->assertSame('testdir3', $file['name']);
$this->assertSame(0, $file['size']);
$this->assertSame(1, $file['is_dir']);
$this->assertArrayNotHasKey('block', $file);
$this->assertArrayNotHasKey('crc32', $file);
$this->assertArrayNotHasKey('range', $file);
}
/**
* File ranges should reflect the file data actually available in the current
* source, even if only partial and/or the Start header is missing or skipped.
* If no file data is available, ranges should not be included in the file info.
*/
public function testListsPackedRangesWithPartialData()
{
$szip = new SzipInfo;
// Without start header (multi-volume)
$file = $this->fixturesDir.'/multi_volume.7z.002';
$end = filesize($file) - 1;
$szip->open($file, true, array(2, $end));
$files = $szip->getFileList();
$this->assertSame('2-3508', $files[0]['range']);
$this->assertSame('3509-3523', $files[1]['range']);
$szip->open($file, true, array(3508, $end));
$files = $szip->getFileList();
$this->assertSame('3508-3508', $files[0]['range']);
$this->assertSame('3509-3523', $files[1]['range']);
$szip->open($file, true, array(3510, $end));
$files = $szip->getFileList();
$this->assertArrayNotHasKey('range', $files[0]);
$this->assertSame('3510-3523', $files[1]['range']);
// With start header (skipped)
$file = $this->fixturesDir.'/store_with_directories.7z';;
$end = filesize($file) - 1;
$szip->open($file, true, array(2, $end));
$files = $szip->getFileList();
$this->assertSame('32-7604', $files[0]['range']);
$this->assertSame('7605-7619', $files[1]['range']);
$szip->open($file, true, array(7604, $end));
$files = $szip->getFileList();
$this->assertSame('7604-7604', $files[0]['range']);
$this->assertSame('7605-7619', $files[1]['range']);
$this->assertSame('7635-7649', $files[3]['range']);
$szip->open($file, true, array(7605, $end));
$files = $szip->getFileList();
$this->assertArrayNotHasKey('range', $files[0]);
$this->assertSame('7605-7619', $files[1]['range']);
$this->assertSame('7635-7649', $files[3]['range']);
$szip->open($file, true, array(7640, $end));
$files = $szip->getFileList();
$this->assertArrayNotHasKey('range', $files[0]);
$this->assertArrayNotHasKey('range', $files[1]);
$this->assertArrayNotHasKey('range', $files[2]);
$this->assertSame('7640-7649', $files[3]['range']);
}
/**
* If the archive files aren't compressed, we should just be able to extract
* the file data and use it as is.
*
* @depends testListsPackedRangesWithPartialData
*/
public function testExtractsUncompressedFileData()
{
$szip = new SzipInfo;
// With all data available
$szip->open($this->fixturesDir.'/store_method.7z');
$this->assertEmpty($szip->error);
$files = $szip->getFileList();
$this->assertCount(2, $files);
$this->assertSame('7zFormat.txt', $files[0]['name']);
$this->assertSame(0, $files[0]['compressed']);
$data = $szip->getFileData($files[0]['name']);
$this->assertSame($files[0]['size'], strlen($data));
$this->assertSame($files[0]['crc32'], dechex(crc32($data)));
$this->assertStringStartsWith('7z Format description', $data);
$this->assertStringEndsWith("End of document\r\n", $data);
$this->assertSame('foo.txt', $files[1]['name']);
$this->assertSame(0, $files[1]['compressed']);
$data = $szip->getFileData($files[1]['name']);
$this->assertSame($files[1]['size'], strlen($data));
$this->assertSame($files[1]['crc32'], dechex(crc32($data)));
$this->assertSame('sample foo text', $data);
// With partial data available
$szip->open($this->fixturesDir.'/multi_volume.7z.002', true);
$this->assertEmpty($szip->error);
$files = $szip->getFileList();
$this->assertCount(2, $files);
$this->assertSame('7zFormat.txt', $files[0]['name']);
$this->assertSame(0, $files[0]['compressed']);
$data = $szip->getFileData($files[0]['name']);
$this->assertNotSame($files[0]['size'], strlen($data));
$this->assertStringStartsWith('odecIdSize', $data);
$this->assertStringEndsWith("End of document\r\n", $data);
}
/**
* Provides the path to the external client executable, or false if it
* doesn't exist in the given directory.
*
* @return string|boolean the absolute path to the executable, or false
*/
protected function getUnzipPath()
{
$unzip = DIRECTORY_SEPARATOR === '\\'
? dirname(__FILE__).'\bin\7z\7za.exe'
: dirname(__FILE__).'/bin/7z/7za';
if (file_exists($unzip))
return $unzip;
return false;
}
/**
* Decompression and/or decryption of archive contents should be possible by
* using an external client to read the current file, or temporary files for
* data sources. The test should be skipped if no external client is available.
*
* @group external
*/
public function testExtractsFilesWithExternalClient()
{
if (!($unzip = $this->getUnzipPath())) {
$this->markTestSkipped();
}
$szip = new SzipInfo;
// Compressed files
$szfile = $this->fixturesDir.'/solid_lzma_multi.7z';
$szip->open($szfile);
$this->assertEmpty($szip->error);
$files = $szip->getFileList();
$file = $files[0];
$this->assertSame('7zFormat.txt', $file['name']);
$this->assertSame(1, $file['compressed']);
$data = $szip->extractFile($file['name']);
$this->assertNotEmpty($szip->error);
$this->assertContains('external client', $szip->error);
$szip->setExternalClient($unzip);
$data = $szip->extractFile($file['name']);
$this->assertEmpty($szip->error);
$this->assertSame(strlen($data), $file['size']);
$this->assertSame($file['crc32'], dechex(crc32($data)));
$this->assertStringStartsWith('7z Format description', $data);
$this->assertStringEndsWith("End of document\r\n", $data);
// Encrypted files
$szfile = $this->fixturesDir.'/multi_substreams_encrypted.7z';
$szip->open($szfile);
$this->assertEmpty($szip->error);
$files = $szip->getFileList();
$file = $files[2];
$this->assertSame('7zFormat.txt', $file['name']);
$this->assertSame(1, $file['pass']);
$data = $szip->extractFile($file['name']);
$this->assertNotEmpty($szip->error);
$this->assertContains('passworded', $szip->error);
$data = $szip->extractFile($file['name'], null, 'password');
$this->assertEmpty($szip->error, $szip->error);
$this->assertSame(strlen($data), $file['size']);
$this->assertSame($file['crc32'], dechex(crc32($data)));
$this->assertStringStartsWith('7z Format description', $data);
$this->assertStringEndsWith("End of document\r\n", $data);
// From a data source (via temp file)
$szip->setData(file_get_contents($szfile));
$this->assertEmpty($szip->error);
$summary = $szip->getSummary(true);
$this->assertSame(filesize($szfile), $summary['data_size']);
$data = $szip->extractFile($file['name'], null, 'password');
$this->assertEmpty($szip->error);
$this->assertSame($file['size'], strlen($data));
$this->assertSame($file['crc32'], dechex(crc32($data)));
}
/**
* Headers can be compressed or encrypted, and we should be able to use an
* external client to extract these before further parsing.
*
* @depends testExtractsFilesWithExternalClient
* @group external
*/
public function testExtractsEncodedHeadersWithExternalClient()
{
if (!($unzip = $this->getUnzipPath())) {
$this->markTestSkipped();
}
$szip = new SzipInfo;
// Compressed headers
$file = $this->fixturesDir.'/store_method_enc_headers.7z';
$szip->open($file);
$this->assertEmpty($szip->error);
$this->assertSame(1, $szip->blockCount);
$this->assertEmpty($szip->getFileList());
$szip->setExternalClient($unzip);
$szip->open($file);
$this->assertEmpty($szip->error);
$this->assertSame(2, $szip->blockCount);
$files = $szip->getFileList();
$this->assertCount(2, $files);
$file = $files[0];
$this->assertSame('7zFormat.txt', $file['name']);
$this->assertSame('32-7604', $file['range']);
$file = $files[1];
$this->assertSame('foo.txt', $file['name']);
$this->assertSame('7605-7619', $file['range']);
// Encrypted headers
$file = $this->fixturesDir.'/encrypted_headers.7z';
$szip->open($file);
$this->assertNotEmpty($szip->error);
$this->assertContains('password needed', $szip->error);
$this->assertTrue($szip->isEncrypted);
$this->assertSame(1, $szip->blockCount);
$this->assertEmpty($szip->getFileList());
$szip->setPassword('password');
$szip->open($file);
$this->assertEmpty($szip->error);
$this->assertSame(1, $szip->blockCount);
$files = $szip->getFilelist();
$this->assertCount(1, $files);
$file = $files[0];
$this->assertSame('7zFormat.txt', $file['name']);
$this->assertSame(7573, $file['size']);
$this->assertSame('32-7615', $file['range']);
$this->assertSame(1, $file['pass']);
$this->assertSame(0, $file['compressed']);
}
} // End SzipInfoTest