82 lines
3 KiB
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"))
|
|
}
|
|
}
|