mirror of
https://github.com/lukaszraczylo/claude-mnemonic.git
synced 2026-06-06 23:13:50 +00:00
1ae8035470
- [x] Add golangci.yml configuration with fieldalignment linter - [x] Implement observation graph structure with edge detection - [x] Add LEANN-inspired hybrid vector storage with hub threshold - [x] Implement graph-aware search with selective recomputation - [x] Add auto-tuner for dynamic hub threshold adjustment - [x] Add graph and vector metrics tracking and reporting - [x] Extend configuration for graph parameters - [x] Add graph rebuild background service with periodic updates - [x] Add HTTP endpoints for graph stats and vector metrics - [x] Update UI with advanced metrics sidebar panel - [x] Implement AST-aware code chunking for Go, Python, TypeScript
187 lines
4.3 KiB
Go
187 lines
4.3 KiB
Go
package hybrid
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/lukaszraczylo/claude-mnemonic/internal/vector/sqlitevec"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestParseStrategy(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected VectorStorageStrategy
|
|
}{
|
|
{"hub_strategy", "hub", StorageHub},
|
|
{"on_demand_strategy", "on_demand", StorageOnDemand},
|
|
{"always_strategy", "always", StorageAlways},
|
|
{"invalid_defaults_to_hub", "invalid", StorageHub},
|
|
{"empty_defaults_to_hub", "", StorageHub},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := ParseStrategy(tt.input)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStrategyToString(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
expected string
|
|
input VectorStorageStrategy
|
|
}{
|
|
{"hub_to_string", "hub", StorageHub},
|
|
{"on_demand_to_string", "on_demand", StorageOnDemand},
|
|
{"always_to_string", "always", StorageAlways},
|
|
{"invalid_to_unknown", "unknown", VectorStorageStrategy(99)},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := strategyToString(tt.input)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCosineSimilarity(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
a []float32
|
|
b []float32
|
|
expected float32
|
|
}{
|
|
{
|
|
name: "identical_vectors",
|
|
a: []float32{1, 0, 0},
|
|
b: []float32{1, 0, 0},
|
|
expected: 1.0,
|
|
},
|
|
{
|
|
name: "orthogonal_vectors",
|
|
a: []float32{1, 0, 0},
|
|
b: []float32{0, 1, 0},
|
|
expected: 0.0,
|
|
},
|
|
{
|
|
name: "opposite_vectors",
|
|
a: []float32{1, 0, 0},
|
|
b: []float32{-1, 0, 0},
|
|
expected: -1.0,
|
|
},
|
|
{
|
|
name: "zero_vector",
|
|
a: []float32{0, 0, 0},
|
|
b: []float32{1, 1, 1},
|
|
expected: 0.0,
|
|
},
|
|
{
|
|
name: "parallel_vectors",
|
|
a: []float32{2, 0, 0},
|
|
b: []float32{4, 0, 0},
|
|
expected: 1.0,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := cosineSimilarity(tt.a, tt.b)
|
|
assert.InDelta(t, tt.expected, result, 0.001)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSortBySimilarity(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input []sqlitevec.QueryResult
|
|
expected []string // Expected order of IDs
|
|
}{
|
|
{
|
|
name: "already_sorted",
|
|
input: []sqlitevec.QueryResult{
|
|
{ID: "doc1", Similarity: 0.9},
|
|
{ID: "doc2", Similarity: 0.7},
|
|
{ID: "doc3", Similarity: 0.5},
|
|
},
|
|
expected: []string{"doc1", "doc2", "doc3"},
|
|
},
|
|
{
|
|
name: "reverse_sorted",
|
|
input: []sqlitevec.QueryResult{
|
|
{ID: "doc1", Similarity: 0.3},
|
|
{ID: "doc2", Similarity: 0.7},
|
|
{ID: "doc3", Similarity: 0.9},
|
|
},
|
|
expected: []string{"doc3", "doc2", "doc1"},
|
|
},
|
|
{
|
|
name: "random_order",
|
|
input: []sqlitevec.QueryResult{
|
|
{ID: "doc1", Similarity: 0.5},
|
|
{ID: "doc2", Similarity: 0.9},
|
|
{ID: "doc3", Similarity: 0.3},
|
|
{ID: "doc4", Similarity: 0.7},
|
|
},
|
|
expected: []string{"doc2", "doc4", "doc1", "doc3"},
|
|
},
|
|
{
|
|
name: "identical_similarities",
|
|
input: []sqlitevec.QueryResult{
|
|
{ID: "doc1", Similarity: 0.5},
|
|
{ID: "doc2", Similarity: 0.5},
|
|
{ID: "doc3", Similarity: 0.5},
|
|
},
|
|
expected: []string{"doc1", "doc2", "doc3"},
|
|
},
|
|
{
|
|
name: "empty_list",
|
|
input: []sqlitevec.QueryResult{},
|
|
expected: []string{},
|
|
},
|
|
{
|
|
name: "single_element",
|
|
input: []sqlitevec.QueryResult{
|
|
{ID: "doc1", Similarity: 0.5},
|
|
},
|
|
expected: []string{"doc1"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
sortBySimilarity(tt.input)
|
|
|
|
actual := make([]string, len(tt.input))
|
|
for i, r := range tt.input {
|
|
actual[i] = r.ID
|
|
}
|
|
|
|
assert.Equal(t, tt.expected, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSortBySimilarity_PreserveOtherFields(t *testing.T) {
|
|
input := []sqlitevec.QueryResult{
|
|
{ID: "doc1", Similarity: 0.3, Distance: 0.7, Metadata: map[string]any{"key": "val1"}},
|
|
{ID: "doc2", Similarity: 0.9, Distance: 0.1, Metadata: map[string]any{"key": "val2"}},
|
|
}
|
|
|
|
sortBySimilarity(input)
|
|
|
|
assert.Equal(t, "doc2", input[0].ID)
|
|
assert.InDelta(t, 0.9, input[0].Similarity, 0.001)
|
|
assert.InDelta(t, 0.1, input[0].Distance, 0.001)
|
|
assert.Equal(t, "val2", input[0].Metadata["key"])
|
|
|
|
assert.Equal(t, "doc1", input[1].ID)
|
|
assert.InDelta(t, 0.3, input[1].Similarity, 0.001)
|
|
assert.InDelta(t, 0.7, input[1].Distance, 0.001)
|
|
assert.Equal(t, "val1", input[1].Metadata["key"])
|
|
}
|