Files
Maven/internal/memory/store_test.go
kami 880715fad4 maven: long-term memory vector-store interface (task 7)
- New internal/memory/ package: Store interface, InMemoryStore (cosine sim)
- Tests: insert→search roundtrip, topK truncation, empty store, cosine edges
- Wire into voice: memStore on reactiveHandler, insert note embedding after WriteNote
- Memory Insert is best-effort, log-and-continue on error

Co-Authored-By: opencode <opencode@anthropic.com>
2026-07-06 04:18:50 +04:00

81 lines
2.0 KiB
Go

package memory
import (
"context"
"math"
"testing"
)
func TestInsertAndSearch(t *testing.T) {
s := NewInMemoryStore()
ctx := context.Background()
// Insert a few vectors
s.Insert(ctx, "doc1", []float32{1, 0, 0}, nil)
s.Insert(ctx, "doc2", []float32{0, 1, 0}, nil)
s.Insert(ctx, "doc3", []float32{0, 0, 1}, map[string]string{"source": "note"})
// Search for something close to doc1
results, err := s.Search(ctx, []float32{0.9, 0.1, 0}, 5)
if err != nil {
t.Fatalf("Search: %v", err)
}
if len(results) != 3 {
t.Fatalf("expected 3 results, got %d", len(results))
}
if results[0].ID != "doc1" {
t.Errorf("nearest should be doc1, got %s", results[0].ID)
}
if math.Abs(results[0].Score-0.9) > 0.01 {
t.Errorf("doc1 score should be near 0.9, got %f", results[0].Score)
}
// Check metadata preserved
if results[2].Meta["source"] != "note" {
t.Errorf("doc3 meta.source = %q, want note", results[2].Meta["source"])
}
}
func TestTopKTruncation(t *testing.T) {
s := NewInMemoryStore()
ctx := context.Background()
for i := 0; i < 10; i++ {
s.Insert(ctx, "", []float32{float32(i) / 10, 0, 0}, nil)
}
results, err := s.Search(ctx, []float32{1, 0, 0}, 3)
if err != nil {
t.Fatalf("Search: %v", err)
}
if len(results) != 3 {
t.Fatalf("expected 3 results with topK=3, got %d", len(results))
}
}
func TestEmptyStore(t *testing.T) {
s := NewInMemoryStore()
results, err := s.Search(context.Background(), []float32{1, 0, 0}, 5)
if err != nil {
t.Fatalf("Search on empty store: %v", err)
}
if len(results) != 0 {
t.Fatalf("expected 0 results, got %d", len(results))
}
}
func TestCosineEdgeCases(t *testing.T) {
if c := cosine(nil, []float32{1}); c != 0 {
t.Errorf("nil first: expected 0, got %f", c)
}
if c := cosine([]float32{1}, nil); c != 0 {
t.Errorf("nil second: expected 0, got %f", c)
}
if c := cosine([]float32{}, []float32{}); c != 0 {
t.Errorf("empty: expected 0, got %f", c)
}
if c := cosine([]float32{1, 2}, []float32{1, 2}); math.Abs(c-5) > 0.001 {
t.Errorf("dot(1,2;1,2) = %f, want 5", c)
}
}