diff --git a/tests/unit/test_embeddings.py b/tests/unit/test_embeddings.py deleted file mode 100644 index f73d1faf..00000000 --- a/tests/unit/test_embeddings.py +++ /dev/null @@ -1,153 +0,0 @@ -"""Unit tests for timmy.memory.embeddings — embedding, similarity, and overlap.""" - -import math -from unittest.mock import MagicMock, patch - -import pytest - -import timmy.memory.embeddings as emb -from timmy.memory.embeddings import ( - _keyword_overlap, - _simple_hash_embedding, - cosine_similarity, - embed_text, -) - -# ── _simple_hash_embedding ────────────────────────────────────────────────── - - -class TestSimpleHashEmbedding: - def test_returns_list_of_floats(self): - vec = _simple_hash_embedding("hello world") - assert isinstance(vec, list) - assert all(isinstance(v, float) for v in vec) - - def test_dimension_is_128(self): - vec = _simple_hash_embedding("test sentence") - assert len(vec) == 128 - - def test_normalized_unit_vector(self): - vec = _simple_hash_embedding("some text here") - mag = math.sqrt(sum(x * x for x in vec)) - assert mag == pytest.approx(1.0, abs=1e-6) - - def test_deterministic(self): - a = _simple_hash_embedding("deterministic check") - b = _simple_hash_embedding("deterministic check") - assert a == b - - def test_different_texts_differ(self): - a = _simple_hash_embedding("alpha") - b = _simple_hash_embedding("beta") - assert a != b - - def test_empty_string(self): - vec = _simple_hash_embedding("") - assert len(vec) == 128 - # All zeros normalized → magnitude 0 guarded by `or 1.0` - assert all(v == 0.0 for v in vec) - - -# ── cosine_similarity ──────────────────────────────────────────────────────── - - -class TestCosineSimilarity: - def test_identical_vectors(self): - v = [1.0, 2.0, 3.0] - assert cosine_similarity(v, v) == pytest.approx(1.0) - - def test_orthogonal_vectors(self): - a = [1.0, 0.0] - b = [0.0, 1.0] - assert cosine_similarity(a, b) == pytest.approx(0.0) - - def test_opposite_vectors(self): - a = [1.0, 0.0] - b = [-1.0, 0.0] - assert cosine_similarity(a, b) == pytest.approx(-1.0) - - def test_zero_vector_returns_zero(self): - assert cosine_similarity([0.0, 0.0], [1.0, 2.0]) == 0.0 - assert cosine_similarity([1.0, 2.0], [0.0, 0.0]) == 0.0 - - def test_both_zero_returns_zero(self): - assert cosine_similarity([0.0], [0.0]) == 0.0 - - -# ── _keyword_overlap ───────────────────────────────────────────────────────── - - -class TestKeywordOverlap: - def test_full_overlap(self): - assert _keyword_overlap("hello world", "hello world") == pytest.approx(1.0) - - def test_partial_overlap(self): - assert _keyword_overlap("hello world", "hello there") == pytest.approx(0.5) - - def test_no_overlap(self): - assert _keyword_overlap("foo bar", "baz qux") == pytest.approx(0.0) - - def test_empty_query_returns_zero(self): - assert _keyword_overlap("", "some content") == 0.0 - - def test_case_insensitive(self): - assert _keyword_overlap("Hello WORLD", "hello world") == pytest.approx(1.0) - - -# ── _get_embedding_model ───────────────────────────────────────────────────── - - -class TestGetEmbeddingModel: - def setup_method(self): - # Reset global state before each test - emb.EMBEDDING_MODEL = None - - def teardown_method(self): - emb.EMBEDDING_MODEL = None - - def test_skip_embeddings_setting(self): - mock_settings = MagicMock() - mock_settings.timmy_skip_embeddings = True - with patch.dict("sys.modules", {"config": MagicMock(settings=mock_settings)}): - emb.EMBEDDING_MODEL = None - result = emb._get_embedding_model() - assert result is False - - def test_fallback_when_sentence_transformers_missing(self): - mock_settings = MagicMock() - mock_settings.timmy_skip_embeddings = False - with patch.dict("sys.modules", {"config": MagicMock(settings=mock_settings)}): - with patch.dict("sys.modules", {"sentence_transformers": None}): - emb.EMBEDDING_MODEL = None - result = emb._get_embedding_model() - assert result is False - - def test_caches_model(self): - sentinel = MagicMock() - emb.EMBEDDING_MODEL = sentinel - assert emb._get_embedding_model() is sentinel - - -# ── embed_text ─────────────────────────────────────────────────────────────── - - -class TestEmbedText: - def test_uses_fallback_when_model_false(self): - with patch.object(emb, "_get_embedding_model", return_value=False): - vec = embed_text("test") - assert len(vec) == 128 - - def test_uses_model_when_available(self): - import numpy as np - - mock_model = MagicMock() - mock_model.encode.return_value = np.array([0.1, 0.2, 0.3]) - with patch.object(emb, "_get_embedding_model", return_value=mock_model): - vec = embed_text("test") - assert vec == [0.1, 0.2, 0.3] - mock_model.encode.assert_called_once_with("test") - - def test_uses_fallback_when_model_none(self): - with patch.object(emb, "_get_embedding_model", return_value=None): - vec = embed_text("test") - assert len(vec) == 128