rainbow-dragon/Tests/ForgeOffloadTests/ChecksumBreadthTests.swift

124 lines
5.1 KiB
Swift
Raw Normal View History

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)
}
}