rainbow-dragon/Tests/ForgeOffloadTests/HashingTests.swift

82 lines
3 KiB
Swift

import XCTest
import Foundation
@testable import ForgeOffload
final class HashingTests: XCTestCase {
// xxHash64 official spec vectors (seed 0).
func testXXHash64SpecVectors() {
XCTAssertEqual(XXHash64.hash(Data()), 0xEF46_DB37_51D8_E999)
XCTAssertEqual(XXHash64.hash(Data([0x9E])), 0x4FCE_394C_C88952D8)
// "Nobody inspects the spammish repetition" widely published vector.
let spam = Data("Nobody inspects the spammish repetition".utf8)
XCTAssertEqual(XXHash64.hash(spam), 0xFBCE_A83C_8A378BF1)
}
// Known ASCII vector.
func testXXHash64Ascii() {
XCTAssertEqual(XXHash64.hash(Data("xxhash".utf8)), 0x32DD_38952C_4BC720)
}
// Streaming hash == whole-buffer hash for multi-MB input crossing block sizes.
func testStreamingMatchesWhole() {
var data = Data()
var seed: UInt64 = 0x12345678
for _ in 0..<(3 * 1024 * 1024 / 8) {
seed = seed &* 6364136223846793005 &+ 1442695040888963407
withUnsafeBytes(of: seed) { data.append(contentsOf: $0) }
}
let whole = XXHash64.hash(data)
var streamer = XXHash64()
// Uneven chunk sizes to exercise buffering.
var offset = 0
let chunks = [1, 31, 32, 33, 4096, 1_000_000]
var i = 0
while offset < data.count {
let size = min(chunks[i % chunks.count], data.count - offset)
streamer.update(data.subdata(in: offset..<offset + size))
offset += size
i += 1
}
XCTAssertEqual(streamer.finalize(), whole)
}
// Hex formatting: 16 lowercase hex chars, zero-padded.
func testHexFormat() {
let h = XXHash64.hexString(XXHash64.hash(Data("xxhash".utf8)))
XCTAssertEqual(h, "32dd38952c4bc720")
// Zero-padding for small values.
XCTAssertEqual(XXHash64.hexString(0xAB), "00000000000000ab")
}
// MD5 known vectors (RFC 1321).
func testMD5Vectors() {
XCTAssertEqual(MD5.hexString(Data()), "d41d8cd98f00b204e9800998ecf8427e")
XCTAssertEqual(MD5.hexString(Data("abc".utf8)), "900150983cd24fb0d6963f7d28e17f72")
XCTAssertEqual(
MD5.hexString(Data("message digest".utf8)),
"f96b697d7cb7938d525a2f31aaf161d0")
}
// File hashing: chunked reader over a temp file matches in-memory hash.
func testFileHashing() throws {
let path = NSTemporaryDirectory() + "forge-hash-\(UUID().uuidString).bin"
defer { try? FileManager.default.removeItem(atPath: path) }
var data = Data()
for i in 0..<100_000 {
data.append(UInt8(truncatingIfNeeded: i))
}
try data.write(to: URL(fileURLWithPath: path))
let fileHash = try FileHasher.xxh64(path: path)
XCTAssertEqual(fileHash, XXHash64.hexString(XXHash64.hash(data)))
let fileMD5 = try FileHasher.md5(path: path)
XCTAssertEqual(fileMD5, MD5.hexString(data))
}
func testMissingFileThrows() {
XCTAssertThrowsError(try FileHasher.xxh64(path: "/nonexistent/nope.bin"))
}
}