"""Unit tests for cores.embedding — vector ops + cache.""" from __future__ import annotations import numpy as np from cores.embedding import ( normalize, cosine_similarity, euclidean_distance, batch_cosine_similarity, EmbeddingCache, ) class TestVectors: def test_normalize(self): v = np.array([3.0, 4.0]) n = normalize(v) assert np.linalg.norm(n) == pytest_approx(1.0) if (pytest := __import__("pytest")) else True def test_normalize_zero_vector(self): v = np.zeros(3) n = normalize(v) assert np.all(n == 0) def test_cosine_similarity_identical(self): v = np.array([1.0, 2.0, 3.0]) assert cosine_similarity(v, v) == 1.0 def test_euclidean_distance(self): a = np.array([0.0, 0.0]) b = np.array([3.0, 4.0]) assert euclidean_distance(a, b) == 5.0 def test_batch_cosine_similarity(self): query = np.array([1.0, 0.0]) matrix = np.array([ [1.0, 0.0], # identical [0.0, 1.0], # orthogonal [-1.0, 0.0], # opposite ]) sims = batch_cosine_similarity(query, matrix) assert len(sims) == 3 assert sims[0] == 1.0 assert sims[1] == 0.0 assert sims[2] == -1.0 class TestEmbeddingCache: def test_get_or_load_loads_once(self): cache = EmbeddingCache() call_count = [0] def loader(): call_count[0] += 1 return {"model": "fake"} m1 = cache.get_or_load("key1", loader) m2 = cache.get_or_load("key1", loader) assert m1 is m2 assert call_count[0] == 1 def test_is_loaded(self): cache = EmbeddingCache() assert not cache.is_loaded("x") cache.get_or_load("x", lambda: "model") assert cache.is_loaded("x") def test_evict(self): cache = EmbeddingCache() cache.get_or_load("x", lambda: "model") assert cache.evict("x") is True assert not cache.is_loaded("x") assert cache.evict("x") is False def test_clear(self): cache = EmbeddingCache() cache.get_or_load("a", lambda: 1) cache.get_or_load("b", lambda: 2) n = cache.clear() assert n == 2 assert cache.keys() == [] def test_keys(self): cache = EmbeddingCache() cache.get_or_load("a", lambda: 1) cache.get_or_load("b", lambda: 2) assert set(cache.keys()) == {"a", "b"} def pytest_approx(expected, rel=1e-6): """Tiny local approx since pytest.approx may not be in scope.""" class _Approx: def __init__(self, expected, rel): self.expected = expected self.rel = rel def __eq__(self, other): return abs(other - self.expected) <= self.rel * max(abs(self.expected), abs(other), 1.0) return _Approx(expected, rel)