123 lines
5.1 KiB
Swift
123 lines
5.1 KiB
Swift
import XCTest
|
|
import Foundation
|
|
@testable import ForgeOffload
|
|
|
|
final class ChecksumBreadthTests: XCTestCase {
|
|
|
|
// XXH3-64 vectors verified against official xxhsum 0.8.2 (-H3, seed 0).
|
|
func testXXH3_64Vectors() {
|
|
XCTAssertEqual(XXH3.hash64(Data()), 0x2D06_800538D394C2)
|
|
XCTAssertEqual(XXH3.hash64(Data("xxhash".utf8)), 0xAA4C_2B42AE6B13DE)
|
|
XCTAssertEqual(
|
|
XXH3.hash64(Data("Nobody inspects the spammish repetition".utf8)),
|
|
0x6CB0_0603B5CC47E9)
|
|
}
|
|
|
|
// XXH3-128 vectors verified against official xxhsum 0.8.2 (-H128).
|
|
// Canonical hex = high64 then low64.
|
|
func testXXH3_128Vectors() {
|
|
let empty = XXH3.hash128(Data())
|
|
XCTAssertEqual(empty.hexString, "99aa06d3014798d86001c324468d497f")
|
|
let xx = XXH3.hash128(Data("xxhash".utf8))
|
|
XCTAssertEqual(xx.hexString, "9c8b437c78cac00a376072e24bfdf4d2")
|
|
}
|
|
|
|
// Streaming XXH3 == one-shot across chunk boundaries.
|
|
func testXXH3StreamingMatchesOneShot() {
|
|
var data = Data()
|
|
var seed: UInt64 = 0xABCDEF
|
|
for _ in 0..<(2 * 1024 * 1024 / 8) {
|
|
seed = seed &* 6364136223846793005 &+ 1442695040888963407
|
|
withUnsafeBytes(of: seed) { data.append(contentsOf: $0) }
|
|
}
|
|
let whole64 = XXH3.hash64(data)
|
|
let whole128 = XXH3.hash128(data)
|
|
|
|
let s64 = XXH3.Streaming(bits: .h64)
|
|
let s128 = XXH3.Streaming(bits: .h128)
|
|
var offset = 0
|
|
let chunks = [1, 63, 64, 65, 4096, 999_999]
|
|
var i = 0
|
|
while offset < data.count {
|
|
let size = min(chunks[i % chunks.count], data.count - offset)
|
|
let chunk = data.subdata(in: offset..<offset + size)
|
|
s64.update(chunk)
|
|
s128.update(chunk)
|
|
offset += size
|
|
i += 1
|
|
}
|
|
XCTAssertEqual(s64.digest64(), whole64)
|
|
let d128 = s128.digest128()
|
|
XCTAssertEqual(d128.low64, whole128.low64)
|
|
XCTAssertEqual(d128.high64, whole128.high64)
|
|
}
|
|
|
|
// SHA1 RFC 3174 vectors.
|
|
func testSHA1Vectors() {
|
|
XCTAssertEqual(SHA1.hexString(Data("abc".utf8)), "a9993e364706816aba3e25717850c26c9cd0d89d")
|
|
XCTAssertEqual(
|
|
SHA1.hexString(Data("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".utf8)),
|
|
"84983e441c3bd26ebaae4aa1f95129e5e54670f1")
|
|
XCTAssertEqual(SHA1.hexString(Data()), "da39a3ee5e6b4b0d3255bfef95601890afd80709")
|
|
}
|
|
|
|
// SHA1 streaming across block boundary.
|
|
func testSHA1Streaming() {
|
|
let text = String(repeating: "a", count: 1_000_000)
|
|
// RFC 3174 test: one million 'a' -> 34aa973cd4c4daa4f61eeb2bdbad27316534016f
|
|
var sha = SHA1()
|
|
let data = Data(text.utf8)
|
|
var offset = 0
|
|
while offset < data.count {
|
|
let size = min(77_777, data.count - offset)
|
|
sha.update(data.subdata(in: offset..<offset + size))
|
|
offset += size
|
|
}
|
|
let digest = sha.finalize()
|
|
XCTAssertEqual(digest.map { String(format: "%02x", $0) }.joined(),
|
|
"34aa973cd4c4daa4f61eeb2bdbad27316534016f")
|
|
}
|
|
|
|
// FileHasher algorithm dispatch: all algos over same temp file.
|
|
func testFileHasherAllAlgorithms() throws {
|
|
let path = NSTemporaryDirectory() + "forge-algo-\(UUID().uuidString).bin"
|
|
defer { try? FileManager.default.removeItem(atPath: path) }
|
|
var data = Data()
|
|
for i in 0..<50_000 { data.append(UInt8(truncatingIfNeeded: i)) }
|
|
try data.write(to: URL(fileURLWithPath: path))
|
|
|
|
for algo in HashAlgorithm.allCases {
|
|
let fileHash = try FileHasher.hash(path: path, algorithm: algo)
|
|
let memHash = HashAlgorithm.hashInMemory(data, algorithm: algo)
|
|
XCTAssertEqual(fileHash, memHash, "\(algo) file != memory")
|
|
XCTAssertFalse(fileHash.isEmpty)
|
|
}
|
|
}
|
|
|
|
// MHL element names per algorithm (ASC MHL v2 spec names).
|
|
func testMHLElementNames() {
|
|
XCTAssertEqual(HashAlgorithm.xxh64.mhlElement, "xxh64")
|
|
XCTAssertEqual(HashAlgorithm.xxh3.mhlElement, "xxh3")
|
|
XCTAssertEqual(HashAlgorithm.xxh128.mhlElement, "xxh128")
|
|
XCTAssertEqual(HashAlgorithm.md5.mhlElement, "md5")
|
|
XCTAssertEqual(HashAlgorithm.sha1.mhlElement, "sha1")
|
|
}
|
|
|
|
// MHL generate with alternate algorithm embeds right element + verifies.
|
|
func testMHLWithXXH3() throws {
|
|
let root = NSTemporaryDirectory() + "forge-mhl3-\(UUID().uuidString)"
|
|
defer { try? FileManager.default.removeItem(atPath: root) }
|
|
try FileManager.default.createDirectory(atPath: root, withIntermediateDirectories: true)
|
|
try Data("clip data".utf8).write(to: URL(fileURLWithPath: root + "/C1.mov"))
|
|
|
|
let xml = try MHL.generate(root: root, creator: "Forge", files: ["C1.mov"], algorithm: .xxh3)
|
|
XCTAssertTrue(xml.contains("<xxh3 action=\"original\""))
|
|
let result = try MHL.verify(manifest: xml, root: root)
|
|
XCTAssertTrue(result.passed)
|
|
|
|
// Tamper still caught with xxh3.
|
|
try Data("clip DATA".utf8).write(to: URL(fileURLWithPath: root + "/C1.mov"))
|
|
let bad = try MHL.verify(manifest: xml, root: root)
|
|
XCTAssertFalse(bad.passed)
|
|
}
|
|
}
|