Files

492 lines
23 KiB
Swift

// Copyright (c) 2026 Timofey Solomko
// Licensed under MIT License
//
// See LICENSE for license information
import XCTest
import SWCompression
class SevenZipTests: XCTestCase {
private static let testType: String = "7z"
func testBadFile_short() {
XCTAssertThrowsError(try SevenZipContainer.open(container: Data([0, 1, 2])))
}
func testBadFile_invalid() throws {
let testData = try Constants.data(forAnswer: "test6")
XCTAssertThrowsError(try SevenZipContainer.open(container: testData))
}
func testEmptyData() throws {
XCTAssertThrowsError(try SevenZipContainer.info(container: Data()))
XCTAssertThrowsError(try SevenZipContainer.open(container: Data()))
}
func test1() throws {
let testData = try Constants.data(forTest: "test1", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
let answerData = try Constants.data(forAnswer: "test1")
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "test1.answer")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, answerData.count)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, true)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertEqual(entries[0].info.crc, 0xB4E89E84)
XCTAssertEqual(entries[0].data, answerData)
}
func test2() throws {
let testData = try Constants.data(forTest: "test2", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 2)
let answer1Data = try Constants.data(forAnswer: "test1")
XCTAssertEqual(entries[0].info.name, "test1.answer")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, answer1Data.count)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, true)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertEqual(entries[0].info.crc, 0xB4E89E84)
XCTAssertEqual(entries[0].data, answer1Data)
let answer4Data = try Constants.data(forAnswer: "test4")
XCTAssertEqual(entries[1].info.name, "test4.answer")
XCTAssertEqual(entries[1].info.type, .regular)
XCTAssertEqual(entries[1].info.size, answer4Data.count)
XCTAssertEqual(entries[1].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[1].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[1].info.modificationTime)
XCTAssertNil(entries[1].info.accessTime)
XCTAssertNil(entries[1].info.creationTime)
XCTAssertEqual(entries[1].info.hasStream, true)
XCTAssertEqual(entries[1].info.isEmpty, false)
XCTAssertEqual(entries[1].info.isAnti, false)
XCTAssertEqual(entries[1].info.crc, 0xAEF524A3)
XCTAssertEqual(entries[1].data, answer4Data)
}
func test3() throws {
let testData = try Constants.data(forTest: "test3", withType: SevenZipTests.testType)
_ = try SevenZipContainer.info(container: testData)
_ = try SevenZipContainer.open(container: testData)
}
func testAntiFile() throws {
let testData = try Constants.data(forTest: "test_anti_file", withType: SevenZipTests.testType)
_ = try SevenZipContainer.info(container: testData)
let entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 6)
for entry in entries {
if entry.info.name == "test_create/test4.answer" {
XCTAssertEqual(entry.info.isAnti, true)
} else {
XCTAssertEqual(entry.info.isAnti, false)
}
}
}
func testMultiBlocks() throws {
// Container was created with "solid" options set to "off" (-ms=off).
let testData = try Constants.data(forTest: "test_multi_blocks", withType: SevenZipTests.testType)
_ = try SevenZipContainer.info(container: testData)
let entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 6)
}
func testAllTimestamps() throws {
// Container was created with "-mtc=on" and "-mta=on" options.
let testData = try Constants.data(forTest: "test_all_timestamps", withType: SevenZipTests.testType)
_ = try SevenZipContainer.info(container: testData)
let entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 6)
for entry in entries {
XCTAssertNotNil(entry.info.creationTime)
XCTAssertNotNil(entry.info.accessTime)
// Just in case...
XCTAssertNotNil(entry.info.modificationTime)
}
}
func testComplicatedCodingScheme() throws {
// Container was created with these options: "-mf=BCJ -m0=Copy -m1=Deflate -m2=Delta -m3=LZMA -m4=LZMA2"
let testData = try Constants.data(forTest: "test_complicated_coding_scheme", withType: SevenZipTests.testType)
// In these test case the most important thing is that information about entries must be read correctly.
_ = try SevenZipContainer.info(container: testData)
// It is expected for `open(container:) function to throw `SevenZipError.compressionNotSupported`,
// because of the coders used.
XCTAssertThrowsError(try SevenZipContainer.open(container: testData)) { error in
XCTAssertEqual(error as? SevenZipError, SevenZipError.compressionNotSupported)
}
}
func testEncryptedHeader() throws {
// Container was created with "-mhe=on".
let testData = try Constants.data(forTest: "test_encrypted_header", withType: SevenZipTests.testType)
XCTAssertThrowsError(try SevenZipContainer.info(container: testData)) { error in
XCTAssertEqual(error as? SevenZipError, SevenZipError.encryptionNotSupported)
}
// There is no point in testing `open(container:)` function, because we are unable to get even files' info.
}
func testSingleThread() throws {
// Container was created with disabled multithreading options.
// We check this just in case.
let testData = try Constants.data(forTest: "test_single_thread", withType: SevenZipTests.testType)
XCTAssertEqual(try SevenZipContainer.info(container: testData).count, 6)
XCTAssertEqual(try SevenZipContainer.open(container: testData).count, 6)
}
func testBigContainer() throws {
let testData = try Constants.data(forTest: "SWCompressionSourceCode", withType: SevenZipTests.testType)
_ = try SevenZipContainer.info(container: testData)
_ = try SevenZipContainer.open(container: testData)
}
func test7zBZip2() throws {
// File in container compressed with BZip2.
let testData = try Constants.data(forTest: "test_7z_bzip2", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
let answerData = try Constants.data(forAnswer: "test4")
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "test4.answer")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, answerData.count)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, true)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertEqual(entries[0].info.crc, 0xAEF524A3)
XCTAssertEqual(entries[0].data, answerData)
}
func test7zDeflate() throws {
// File in container compressed with Deflate.
let testData = try Constants.data(forTest: "test_7z_deflate", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
let answerData = try Constants.data(forAnswer: "test4")
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "test4.answer")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, answerData.count)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, true)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertEqual(entries[0].info.crc, 0xAEF524A3)
XCTAssertEqual(entries[0].data, answerData)
}
func test7zLZ4() throws {
// File in container compressed with LZ4.
let testData = try Constants.data(forTest: "test_7z_lz4", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
let answerData = try Constants.data(forAnswer: "test4")
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "test4.answer")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, answerData.count)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, true)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertEqual(entries[0].info.crc, 0xAEF524A3)
XCTAssertEqual(entries[0].data, answerData)
}
func test7zCopy() throws {
// File in container is explicitly uncompressed.
let testData = try Constants.data(forTest: "test_7z_copy", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
let answerData = try Constants.data(forAnswer: "test4")
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "test4.answer")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, answerData.count)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, true)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertEqual(entries[0].info.crc, 0xAEF524A3)
XCTAssertEqual(entries[0].data, answerData)
}
func testUnicode() throws {
let testData = try Constants.data(forTest: "test_unicode", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "текстовый файл.answer")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, true)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertEqual(entries[0].info.crc, 0xA139BCEE)
XCTAssertEqual(entries[0].data, Constants.текстовыйФайлData)
}
func testWinContainer() throws {
let testData = try Constants.data(forTest: "test_win", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 2)
XCTAssertEqual(entries[0].info.name, "dir")
XCTAssertEqual(entries[0].info.type, .directory)
XCTAssertEqual(entries[0].info.size, nil)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 0))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x10))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, false)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertNil(entries[0].info.crc)
XCTAssertEqual(entries[0].data, nil)
XCTAssertEqual(entries[1].info.name, "text_win.txt")
XCTAssertEqual(entries[1].info.type, .regular)
XCTAssertEqual(entries[1].info.size, 15)
XCTAssertEqual(entries[1].info.permissions, Permissions(rawValue: 0))
XCTAssertEqual(entries[1].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[1].info.modificationTime)
XCTAssertNil(entries[1].info.accessTime)
XCTAssertNil(entries[1].info.creationTime)
XCTAssertEqual(entries[1].info.hasStream, true)
XCTAssertEqual(entries[1].info.isEmpty, false)
XCTAssertEqual(entries[1].info.isAnti, false)
XCTAssertEqual(entries[1].info.crc, 0x1273FBD3)
XCTAssertEqual(entries[1].data, "Hello, Windows!".data(using: .utf8))
}
func test7z_LzmaBigDict() throws {
// Verifying the issue fixed by PR #61.
// Previously, there was a crash, if LZMA dictionary size was encoded using all 4 bytes.
let testData = try Constants.data(forTest: "test_lzma_big_dict", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "data")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, 16 * 1024 * 1024)
}
func testEmptyFile() throws {
let testData = try Constants.data(forTest: "test_empty_file", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "empty_file")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, 0)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, false)
XCTAssertEqual(entries[0].info.isEmpty, true)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertNil(entries[0].info.crc)
XCTAssertEqual(entries[0].data, Data())
}
func testEmptyDirectory() throws {
let testData = try Constants.data(forTest: "test_empty_dir", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "empty_dir")
XCTAssertEqual(entries[0].info.type, .directory)
XCTAssertEqual(entries[0].info.size, nil)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 493))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x10))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, false)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertNil(entries[0].info.crc)
XCTAssertEqual(entries[0].data, nil)
}
func testEmptyContainer() throws {
let testData = try Constants.data(forTest: "test_empty_cont", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.isEmpty, true)
}
func testDeltaFilter() throws {
let testData = try Constants.data(forTest: "test_delta_filter", withType: SevenZipTests.testType)
let entries = try SevenZipContainer.open(container: testData)
let answerData = try Constants.data(forAnswer: "test4")
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "test4.answer")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, answerData.count)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, true)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertEqual(entries[0].info.crc, 0xAEF524A3)
XCTAssertEqual(entries[0].data, answerData)
}
func testFormatMinorVersions() throws {
let answerData = try Constants.data(forAnswer: "test2")
var testData = try Constants.data(forTest: "test_minor_version_2", withType: SevenZipTests.testType)
var entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "test2.answer")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, answerData.count)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 0))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNil(entries[0].info.accessTime)
XCTAssertNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, true)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertEqual(entries[0].info.crc, 4168830779)
XCTAssertEqual(entries[0].data, answerData)
testData = try Constants.data(forTest: "test_minor_version_3", withType: SevenZipTests.testType)
entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "test2.answer")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, answerData.count)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNotNil(entries[0].info.accessTime)
XCTAssertNotNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, true)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertEqual(entries[0].info.crc, 4168830779)
XCTAssertEqual(entries[0].data, answerData)
testData = try Constants.data(forTest: "test_minor_version_4", withType: SevenZipTests.testType)
entries = try SevenZipContainer.open(container: testData)
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0].info.name, "test2.answer")
XCTAssertEqual(entries[0].info.type, .regular)
XCTAssertEqual(entries[0].info.size, answerData.count)
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
// Checking times' values is a bit difficult since they are extremely precise.
XCTAssertNotNil(entries[0].info.modificationTime)
XCTAssertNotNil(entries[0].info.accessTime)
XCTAssertNotNil(entries[0].info.creationTime)
XCTAssertEqual(entries[0].info.hasStream, true)
XCTAssertEqual(entries[0].info.isEmpty, false)
XCTAssertEqual(entries[0].info.isAnti, false)
XCTAssertEqual(entries[0].info.crc, 4168830779)
XCTAssertEqual(entries[0].data, answerData)
}
}