import Foundation import Testing @testable import Photochk @Suite("dHash") struct DHashTests { @Test("同じ値のハミング距離は 0") func identical() { #expect(DHash.hammingDistance(0xDEAD_BEEF_1234_5678, 0xDEAD_BEEF_1234_5678) == 0) } @Test("違うビットの数がそのまま距離になる") func differingBits() { #expect(DHash.hammingDistance(0, 0b1011) == 3) #expect(DHash.hammingDistance(.max, 0) == 64) #expect(DHash.hammingDistance(0b1100, 0b0110) == 2) } @Test("生成した画像から 64bit のハッシュが取れる") func computesFromImage() throws { let directory = try TestImages.makeTemporaryDirectory() defer { try? FileManager.default.removeItem(at: directory) } let url = directory.appendingPathComponent("base.jpg") try TestImages.writeJPEG(TestImages.pattern(seed: 1), to: url, quality: 0.9) let basics = try #require(DHash.compute(for: url)) #expect(basics.pixelWidth == TestImages.width) #expect(basics.pixelHeight == TestImages.height) // 同じファイルからは必ず同じ値が出る let again = try #require(DHash.compute(for: url)) #expect(basics.dHash == again.dHash) } @Test("リサイズしてもハッシュはほとんど変わらず、別の絵柄とは大きく離れる") func robustToResize() throws { let directory = try TestImages.makeTemporaryDirectory() defer { try? FileManager.default.removeItem(at: directory) } let base = directory.appendingPathComponent("base.jpg") let small = directory.appendingPathComponent("small.jpg") let other = directory.appendingPathComponent("other.jpg") let pattern = TestImages.pattern(seed: 7) try TestImages.writeJPEG(pattern, to: base, quality: 0.9) try TestImages.writeJPEG(TestImages.scaled(pattern, factor: 0.5), to: small, quality: 0.8) try TestImages.writeJPEG(TestImages.pattern(seed: 99), to: other, quality: 0.9) let baseHash = try #require(DHash.compute(for: base)).dHash let smallHash = try #require(DHash.compute(for: small)).dHash let otherHash = try #require(DHash.compute(for: other)).dHash #expect(DHash.hammingDistance(baseHash, smallHash) <= 12) #expect(DHash.hammingDistance(baseHash, otherHash) > 12) } }