"""Tests for `app.core.embeddings.HashEmbedder`.""" from __future__ import annotations import math import pytest from app.core.embeddings import HashEmbedder @pytest.mark.asyncio async def test_hash_embedder_returns_correct_dimension(): emb = HashEmbedder(dimension=128) vecs = await emb.embed(["hello world"]) assert len(vecs) == 1 assert len(vecs[0]) == 128 @pytest.mark.asyncio async def test_hash_embedder_empty_text_returns_zero_vector(): emb = HashEmbedder(dimension=64) vecs = await emb.embed([""]) assert vecs[0] == [0.0] * 64 @pytest.mark.asyncio async def test_hash_embedder_deterministic(): emb = HashEmbedder(dimension=64) v1 = (await emb.embed(["the quick brown fox"]))[0] v2 = (await emb.embed(["the quick brown fox"]))[0] assert v1 == v2 @pytest.mark.asyncio async def test_hash_embedder_normalized(): emb = HashEmbedder(dimension=64) v = (await emb.embed(["some text with multiple words for hashing"]))[0] norm = math.sqrt(sum(x * x for x in v)) assert abs(norm - 1.0) < 1e-6 @pytest.mark.asyncio async def test_hash_embedder_similar_texts_have_overlap(): """Texts sharing tokens should have non-zero cosine similarity.""" emb = HashEmbedder(dimension=256) v1 = (await emb.embed(["the dragon attacks the village"]))[0] v2 = (await emb.embed(["the dragon breathes fire"]))[0] v3 = (await emb.embed(["quantum mechanics equations"]))[0] # Cosine similarity (vectors are already normalized) sim_12 = sum(a * b for a, b in zip(v1, v2)) sim_13 = sum(a * b for a, b in zip(v1, v3)) # Shared-token texts should be more similar than disjoint ones assert sim_12 > sim_13 @pytest.mark.asyncio async def test_hash_embedder_batch(): emb = HashEmbedder(dimension=32) vecs = await emb.embed(["a", "b", "c"]) assert len(vecs) == 3 assert all(len(v) == 32 for v in vecs) def test_hash_embedder_invalid_dimension(): with pytest.raises(ValueError): HashEmbedder(dimension=0) with pytest.raises(ValueError): HashEmbedder(dimension=-1)