Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

129 lines
3.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package search
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRRFFuse(t *testing.T) {
textResults := []SearchResult{
{ID: "a", Score: 10},
{ID: "b", Score: 8},
{ID: "c", Score: 5},
}
vecIDs := []string{"b", "d", "a"}
results := rrfFuse(textResults, vecIDs, 60, 10)
require.GreaterOrEqual(t, len(results), 3)
// "a" and "b" appear in both lists → highest RRF scores.
// "b" is rank 1 in text, rank 0 in vec → should score high.
topIDs := make([]string, len(results))
for i, r := range results {
topIDs[i] = r.ID
}
assert.Contains(t, topIDs[:2], "a", "a should be in top 2 (in both lists)")
assert.Contains(t, topIDs[:2], "b", "b should be in top 2 (in both lists)")
// All results should have non-zero scores.
for _, r := range results {
assert.Greater(t, r.Score, float64(0))
}
}
func TestRRFFuse_EmptyVec(t *testing.T) {
textResults := []SearchResult{
{ID: "a", Score: 10},
{ID: "b", Score: 8},
}
results := rrfFuse(textResults, nil, 60, 10)
// With no vec results, only text results contribute.
assert.Len(t, results, 2)
assert.Equal(t, "a", results[0].ID)
}
func TestRRFFuse_Limit(t *testing.T) {
textResults := []SearchResult{
{ID: "a"}, {ID: "b"}, {ID: "c"}, {ID: "d"}, {ID: "e"},
}
vecIDs := []string{"f", "g", "h", "i", "j"}
results := rrfFuse(textResults, vecIDs, 60, 3)
assert.Len(t, results, 3)
}
// --- alphaFuse + auto-α coverage -------------------------------------
func TestAlphaFuse_SmallAlphaFavorsText(t *testing.T) {
// Text-only candidate "t" and vector-only candidate "v" at the
// same rank in their channels. With α=0.1 (BM25-heavy), "t" must
// outrank "v" — symbol queries are supposed to favor text.
textResults := []SearchResult{{ID: "t"}}
vecIDs := []string{"v"}
res := alphaFuse(textResults, vecIDs, 0.1, 60, 10)
require.Len(t, res, 2)
if res[0].ID != "t" {
t.Fatalf("with α=0.1 expected text-only hit first, got %v", res[0].ID)
}
}
func TestAlphaFuse_LargeAlphaFavorsVector(t *testing.T) {
textResults := []SearchResult{{ID: "t"}}
vecIDs := []string{"v"}
res := alphaFuse(textResults, vecIDs, 0.9, 60, 10)
require.Len(t, res, 2)
if res[0].ID != "v" {
t.Fatalf("with α=0.9 expected vector-only hit first, got %v", res[0].ID)
}
}
func TestAlphaFuse_ClampsAlpha(t *testing.T) {
// α below 0 → 0 (text-only); above 1 → 1 (vector-only). Out-of-
// range values must not break sort order.
textResults := []SearchResult{{ID: "t"}}
vecIDs := []string{"v"}
res := alphaFuse(textResults, vecIDs, -5.0, 60, 10)
require.Len(t, res, 2)
if res[0].ID != "t" {
t.Fatalf("α=-5 should clamp to 0 (text wins), got %v", res[0].ID)
}
res = alphaFuse(textResults, vecIDs, 5.0, 60, 10)
require.Len(t, res, 2)
if res[0].ID != "v" {
t.Fatalf("α=5 should clamp to 1 (vector wins), got %v", res[0].ID)
}
}
func TestAlphaFuse_DeterministicTieBreak(t *testing.T) {
textResults := []SearchResult{{ID: "alpha"}, {ID: "beta"}}
vecIDs := []string{"alpha", "gamma"}
for range 5 {
res := alphaFuse(textResults, vecIDs, 0.5, 60, 10)
require.GreaterOrEqual(t, len(res), 3)
if res[0].ID != "alpha" {
t.Fatalf("alphaFuse ordering not stable; got %v", res[0].ID)
}
}
}
func TestNewHybrid_AutoAlphaDefaultOn(t *testing.T) {
h := NewHybrid(nil, nil, nil)
if !h.AutoAlpha() {
t.Errorf("NewHybrid().AutoAlpha() = false, want true (auto-α default)")
}
h.SetAutoAlpha(false)
if h.AutoAlpha() {
t.Errorf("SetAutoAlpha(false) did not take effect")
}
h.SetAutoAlpha(true)
if !h.AutoAlpha() {
t.Errorf("SetAutoAlpha(true) did not take effect")
}
}