mirror of
https://github.com/tsolomko/SWCompression.git
synced 2026-06-23 14:56:41 +00:00
366 lines
16 KiB
Swift
366 lines
16 KiB
Swift
// Copyright (c) 2026 Timofey Solomko
|
|
// Licensed under MIT License
|
|
//
|
|
// See LICENSE for license information
|
|
|
|
import XCTest
|
|
import SWCompression
|
|
|
|
class TarTests: XCTestCase {
|
|
|
|
private static let testType: String = "tar"
|
|
|
|
func testBadFile_short() {
|
|
XCTAssertThrowsError(try TarContainer.open(container: Data([0, 1, 2])))
|
|
}
|
|
|
|
func testBadFile_invalid() throws {
|
|
// This is potentially a misleading test, since there is no way to guarantee that a file is not a TAR container.
|
|
// We use randomly generated data, since the 0-filled data is processed as an empty container.
|
|
let testData = try Constants.data(forAnswer: "test7")
|
|
XCTAssertThrowsError(try TarContainer.open(container: testData))
|
|
}
|
|
|
|
func test() throws {
|
|
let testData = try Constants.data(forTest: "test", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .ustar)
|
|
|
|
let entries = try TarContainer.open(container: testData)
|
|
|
|
XCTAssertEqual(entries.count, 1)
|
|
XCTAssertEqual(entries[0].info.name, "test5.answer")
|
|
XCTAssertEqual(entries[0].info.size, 0)
|
|
XCTAssertEqual(entries[0].info.type, .regular)
|
|
XCTAssertEqual(entries[0].info.ownerID, 501)
|
|
XCTAssertEqual(entries[0].info.groupID, 20)
|
|
XCTAssertEqual(entries[0].info.ownerUserName, "timofeysolomko")
|
|
XCTAssertEqual(entries[0].info.ownerGroupName, "staff")
|
|
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
|
|
XCTAssertNil(entries[0].info.comment)
|
|
XCTAssertEqual(entries[0].data, Data())
|
|
}
|
|
|
|
func testPax() throws {
|
|
let testData = try Constants.data(forTest: "full_test", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .pax)
|
|
|
|
let entries = try TarContainer.open(container: testData)
|
|
|
|
XCTAssertEqual(entries.count, 5)
|
|
|
|
for entry in entries {
|
|
let name = entry.info.name.components(separatedBy: ".")[0]
|
|
let answerData = try Constants.data(forAnswer: name)
|
|
|
|
XCTAssertEqual(entry.data, answerData)
|
|
XCTAssertEqual(entry.info.type, .regular)
|
|
XCTAssertEqual(entry.info.ownerUserName, "tsolomko")
|
|
XCTAssertEqual(entry.info.ownerGroupName, "tsolomko")
|
|
XCTAssertEqual(entry.info.ownerID, 1001)
|
|
XCTAssertEqual(entry.info.groupID, 1001)
|
|
XCTAssertEqual(entry.info.permissions, Permissions(rawValue: 436))
|
|
XCTAssertNil(entry.info.comment)
|
|
// Checking times' values is a bit difficult since they are extremely precise.
|
|
XCTAssertNotNil(entry.info.modificationTime)
|
|
XCTAssertNotNil(entry.info.accessTime)
|
|
XCTAssertNotNil(entry.info.creationTime)
|
|
}
|
|
}
|
|
|
|
func testPaxRecordNewline() throws {
|
|
// In this test we check the handling of a PAX header record with a newline character inside a record value.
|
|
let testData = try Constants.data(forTest: "test_pax_record_newline", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .pax)
|
|
|
|
let entries = try TarContainer.open(container: testData)
|
|
|
|
XCTAssertEqual(entries.count, 1)
|
|
XCTAssertEqual(entries.first?.info.name, "test_file")
|
|
XCTAssertEqual(entries.first?.data, Data("Hello, weird pax record value!".utf8))
|
|
XCTAssertEqual(entries.first?.info.type, .regular)
|
|
XCTAssertEqual(entries.first?.info.size, 30)
|
|
XCTAssertNil(entries.first?.info.accessTime)
|
|
XCTAssertNil(entries.first?.info.creationTime)
|
|
XCTAssertEqual(entries.first?.info.modificationTime, Date(timeIntervalSince1970: 1666443016))
|
|
XCTAssertEqual(entries.first?.info.permissions, Permissions(rawValue: 420))
|
|
XCTAssertEqual(entries.first?.info.ownerID, 501)
|
|
XCTAssertEqual(entries.first?.info.groupID, 20)
|
|
XCTAssertEqual(entries.first?.info.ownerUserName, "tsolomko")
|
|
XCTAssertEqual(entries.first?.info.ownerGroupName, "staff")
|
|
XCTAssertEqual(entries.first?.info.deviceMajorNumber, 0)
|
|
XCTAssertEqual(entries.first?.info.deviceMinorNumber, 0)
|
|
XCTAssertNil(entries.first?.info.charset)
|
|
XCTAssertNil(entries.first?.info.comment)
|
|
XCTAssertEqual(entries.first?.info.linkName, "")
|
|
XCTAssertEqual(entries.first?.info.unknownExtendedHeaderRecords?.count, 3)
|
|
XCTAssertEqual(entries.first?.info.unknownExtendedHeaderRecords?["normal1"], "test_record_value1")
|
|
XCTAssertEqual(entries.first?.info.unknownExtendedHeaderRecords?["newline"], "test1\ntest2")
|
|
XCTAssertEqual(entries.first?.info.unknownExtendedHeaderRecords?["normal2"], "test_record_value2")
|
|
}
|
|
|
|
func testFormats() throws {
|
|
let formatTestNames = ["test_gnu", "test_oldgnu", "test_pax", "test_ustar", "test_v7"]
|
|
|
|
let answerData = try Constants.data(forAnswer: "test1")
|
|
|
|
for testName in formatTestNames {
|
|
let testData = try Constants.data(forTest: testName, withType: TarTests.testType)
|
|
|
|
if testName == "test_gnu" {
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .gnu)
|
|
} else if testName == "test_oldgnu" {
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .gnu)
|
|
} else if testName == "test_pax" {
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .pax)
|
|
} else if testName == "test_ustar" {
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .ustar)
|
|
} else if testName == "test_v7" {
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .prePosix)
|
|
}
|
|
|
|
let entries = try TarContainer.open(container: testData)
|
|
|
|
XCTAssertEqual(entries.count, 1)
|
|
XCTAssertEqual(entries[0].info.name, "test1.answer")
|
|
XCTAssertEqual(entries[0].info.size, 14)
|
|
XCTAssertEqual(entries[0].info.type, .regular)
|
|
XCTAssertEqual(entries[0].data, answerData)
|
|
}
|
|
}
|
|
|
|
func testLongNames() throws {
|
|
let formatTestNames = ["long_test_gnu", "long_test_oldgnu", "long_test_pax"]
|
|
|
|
for testName in formatTestNames {
|
|
let testData = try Constants.data(forTest: testName, withType: TarTests.testType)
|
|
|
|
if testName == "long_test_gnu" {
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .gnu)
|
|
} else if testName == "long_test_oldgnu" {
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .gnu)
|
|
} else if testName == "long_test_pax" {
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .pax)
|
|
}
|
|
|
|
let entries = try TarContainer.open(container: testData)
|
|
|
|
XCTAssertEqual(entries.count, 6)
|
|
}
|
|
}
|
|
|
|
func testWinContainer() throws {
|
|
let testData = try Constants.data(forTest: "test_win", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .ustar)
|
|
|
|
let entries = try TarContainer.open(container: testData)
|
|
|
|
XCTAssertEqual(entries.count, 2)
|
|
|
|
XCTAssertEqual(entries[0].info.name, "dir/")
|
|
XCTAssertEqual(entries[0].info.type, .directory)
|
|
XCTAssertEqual(entries[0].info.size, 0)
|
|
XCTAssertEqual(entries[0].info.ownerUserName, "")
|
|
XCTAssertEqual(entries[0].info.ownerGroupName, "")
|
|
XCTAssertEqual(entries[0].info.ownerID, 0)
|
|
XCTAssertEqual(entries[0].info.groupID, 0)
|
|
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 511))
|
|
XCTAssertNil(entries[0].info.comment)
|
|
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.ownerUserName, "")
|
|
XCTAssertEqual(entries[1].info.ownerGroupName, "")
|
|
XCTAssertEqual(entries[1].info.ownerID, 0)
|
|
XCTAssertEqual(entries[1].info.groupID, 0)
|
|
XCTAssertEqual(entries[1].info.permissions, Permissions(rawValue: 511))
|
|
XCTAssertNil(entries[1].info.comment)
|
|
XCTAssertEqual(entries[1].data, "Hello, Windows!".data(using: .utf8))
|
|
}
|
|
|
|
func testEmptyFile() throws {
|
|
let testData = try Constants.data(forTest: "test_empty_file", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .ustar)
|
|
|
|
let entries = try TarContainer.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.ownerID, 501)
|
|
XCTAssertEqual(entries[0].info.groupID, 20)
|
|
XCTAssertEqual(entries[0].info.ownerUserName, "timofeysolomko")
|
|
XCTAssertEqual(entries[0].info.ownerGroupName, "staff")
|
|
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
|
|
XCTAssertNil(entries[0].info.comment)
|
|
XCTAssertEqual(entries[0].data, Data())
|
|
}
|
|
|
|
func testEmptyDirectory() throws {
|
|
let testData = try Constants.data(forTest: "test_empty_dir", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .ustar)
|
|
|
|
let entries = try TarContainer.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, 0)
|
|
XCTAssertEqual(entries[0].info.ownerID, 501)
|
|
XCTAssertEqual(entries[0].info.groupID, 20)
|
|
XCTAssertEqual(entries[0].info.ownerUserName, "timofeysolomko")
|
|
XCTAssertEqual(entries[0].info.ownerGroupName, "staff")
|
|
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 493))
|
|
XCTAssertNil(entries[0].info.comment)
|
|
XCTAssertEqual(entries[0].data, nil)
|
|
}
|
|
|
|
func testOnlyDirectoryHeader() throws {
|
|
// This tests the correct handling of the situation when there is nothing in the container but one basic header,
|
|
// even no EOF marker (two blocks of zeros).
|
|
let testData = try Constants.data(forTest: "test_only_dir_header", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .ustar)
|
|
|
|
let entries = try TarContainer.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, 0)
|
|
XCTAssertEqual(entries[0].info.ownerID, 501)
|
|
XCTAssertEqual(entries[0].info.groupID, 20)
|
|
XCTAssertEqual(entries[0].info.ownerUserName, "timofeysolomko")
|
|
XCTAssertEqual(entries[0].info.ownerGroupName, "staff")
|
|
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 493))
|
|
XCTAssertNil(entries[0].info.comment)
|
|
XCTAssertNil(entries[0].data)
|
|
}
|
|
|
|
func testEmptyContainer() throws {
|
|
let testData = try Constants.data(forTest: "test_empty_cont", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .prePosix)
|
|
|
|
let entries = try TarContainer.open(container: testData)
|
|
|
|
XCTAssertEqual(entries.isEmpty, true)
|
|
}
|
|
|
|
func testBigContainer() throws {
|
|
let testData = try Constants.data(forTest: "SWCompressionSourceCode", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .ustar)
|
|
|
|
_ = try TarContainer.info(container: testData)
|
|
_ = try TarContainer.open(container: testData)
|
|
}
|
|
|
|
func testUnicodeUstar() throws {
|
|
let testData = try Constants.data(forTest: "test_unicode_ustar", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .ustar)
|
|
|
|
let entries = try TarContainer.open(container: testData)
|
|
|
|
XCTAssertEqual(entries.count, 1)
|
|
XCTAssertEqual(entries[0].info.name, "текстовый файл.answer")
|
|
XCTAssertEqual(entries[0].info.type, .regular)
|
|
XCTAssertEqual(entries[0].info.ownerID, 501)
|
|
XCTAssertEqual(entries[0].info.groupID, 20)
|
|
XCTAssertEqual(entries[0].info.ownerUserName, "timofeysolomko")
|
|
XCTAssertEqual(entries[0].info.ownerGroupName, "staff")
|
|
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
|
|
XCTAssertNil(entries[0].info.comment)
|
|
XCTAssertEqual(entries[0].data, Constants.текстовыйФайлData)
|
|
}
|
|
|
|
func testUnicodePax() throws {
|
|
let testData = try Constants.data(forTest: "test_unicode_pax", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .pax)
|
|
|
|
let entries = try TarContainer.open(container: testData)
|
|
|
|
XCTAssertEqual(entries.count, 1)
|
|
XCTAssertEqual(entries[0].info.name, "текстовый файл.answer")
|
|
XCTAssertEqual(entries[0].info.type, .regular)
|
|
XCTAssertEqual(entries[0].info.ownerID, 501)
|
|
XCTAssertEqual(entries[0].info.groupID, 20)
|
|
XCTAssertEqual(entries[0].info.ownerUserName, "timofeysolomko")
|
|
XCTAssertEqual(entries[0].info.ownerGroupName, "staff")
|
|
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
|
|
XCTAssertNil(entries[0].info.comment)
|
|
XCTAssertEqual(entries[0].data, Constants.текстовыйФайлData)
|
|
}
|
|
|
|
func testGnuIncrementalFormat() throws {
|
|
let testData = try Constants.data(forTest: "test_gnu_inc_format", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .gnu)
|
|
|
|
let entries = try TarContainer.open(container: testData)
|
|
|
|
XCTAssertEqual(entries.count, 3)
|
|
|
|
for entry in entries {
|
|
XCTAssertEqual(entry.info.ownerID, 501)
|
|
XCTAssertEqual(entry.info.groupID, 20)
|
|
XCTAssertEqual(entry.info.ownerUserName, "timofeysolomko")
|
|
XCTAssertEqual(entry.info.ownerGroupName, "staff")
|
|
XCTAssertNotNil(entry.info.accessTime)
|
|
XCTAssertNotNil(entry.info.creationTime)
|
|
}
|
|
}
|
|
|
|
func testBigNumField() throws {
|
|
// This file is truncated because of its size (8.6 GB): it doesn't contain any actual file data.
|
|
let testData = try Constants.data(forTest: "test_big_num_field", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .gnu)
|
|
|
|
let entries = try TarContainer.info(container: testData)
|
|
|
|
XCTAssertEqual(entries.count, 1)
|
|
XCTAssertEqual(entries[0].name, "rands")
|
|
XCTAssertEqual(entries[0].type, .regular)
|
|
XCTAssertEqual(entries[0].size, 8600000000)
|
|
XCTAssertEqual(entries[0].ownerUserName, "timofeysolomko")
|
|
XCTAssertEqual(entries[0].ownerGroupName, "staff")
|
|
XCTAssertEqual(entries[0].ownerID, 501)
|
|
XCTAssertEqual(entries[0].groupID, 20)
|
|
XCTAssertEqual(entries[0].permissions, Permissions(rawValue: 420))
|
|
XCTAssertNil(entries[0].comment)
|
|
}
|
|
|
|
func testNegativeMtime() throws {
|
|
let testData = try Constants.data(forTest: "test_negative_mtime", withType: TarTests.testType)
|
|
|
|
XCTAssertEqual(try TarContainer.formatOf(container: testData), .gnu)
|
|
|
|
let entries = try TarContainer.open(container: testData)
|
|
|
|
XCTAssertEqual(entries.count, 1)
|
|
XCTAssertEqual(entries[0].info.name, "file")
|
|
XCTAssertEqual(entries[0].info.type, .regular)
|
|
XCTAssertEqual(entries[0].info.size, 27)
|
|
XCTAssertEqual(entries[0].info.ownerID, 501)
|
|
XCTAssertEqual(entries[0].info.groupID, 20)
|
|
XCTAssertEqual(entries[0].info.ownerUserName, "timofeysolomko")
|
|
XCTAssertEqual(entries[0].info.ownerGroupName, "staff")
|
|
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
|
|
XCTAssertEqual(entries[0].info.modificationTime, Date(timeIntervalSince1970: -313006414))
|
|
XCTAssertNil(entries[0].info.comment)
|
|
XCTAssertEqual(entries[0].data, "File with negative mtime.\n\n".data(using: .utf8))
|
|
}
|
|
|
|
}
|