From 45ec30fefd63e919ceb74f61d48fdf30d2624a69 Mon Sep 17 00:00:00 2001 From: yoshikazu Date: Mon, 27 Jul 2026 15:44:24 +0000 Subject: [PATCH] Add dHash tests --- Tests/PhotochkTests/DHashTests.swift | 58 ++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Tests/PhotochkTests/DHashTests.swift diff --git a/Tests/PhotochkTests/DHashTests.swift b/Tests/PhotochkTests/DHashTests.swift new file mode 100644 index 0000000..006fb98 --- /dev/null +++ b/Tests/PhotochkTests/DHashTests.swift @@ -0,0 +1,58 @@ +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) + } +}