feat: build Go-based SearXNG-compatible search service
Implement an API-first Go rewrite with local engine adapters, upstream fallback, and Nix-based tooling so searches can run without matching the original UI while preserving response compatibility. Made-with: Cursor
This commit is contained in:
parent
7783367c71
commit
dc44837219
32 changed files with 3330 additions and 0 deletions
80
internal/search/merge_test.go
Normal file
80
internal/search/merge_test.go
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package search
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ashie/gosearch/internal/contracts"
|
||||
)
|
||||
|
||||
func TestMergeResponses_DedupResultsAndSets(t *testing.T) {
|
||||
url1 := "https://example.com/a?x=1"
|
||||
uPtr := &url1
|
||||
|
||||
r1 := contracts.SearchResponse{
|
||||
Query: "q",
|
||||
NumberOfResults: 1,
|
||||
Results: []contracts.MainResult{
|
||||
{
|
||||
Template: "default.html",
|
||||
Title: "Title1",
|
||||
Content: "C1",
|
||||
URL: uPtr,
|
||||
Engine: "wikipedia",
|
||||
Score: 1.0,
|
||||
},
|
||||
},
|
||||
Answers: []map[string]any{{"title": "A1", "url": url1}},
|
||||
Corrections: []string{"corr1", "corr2"},
|
||||
Suggestions: []string{"s1", "s2"},
|
||||
Infoboxes: []map[string]any{},
|
||||
UnresponsiveEngines: [][2]string{},
|
||||
}
|
||||
|
||||
r2 := contracts.SearchResponse{
|
||||
Query: "q",
|
||||
NumberOfResults: 1,
|
||||
Results: []contracts.MainResult{
|
||||
{
|
||||
Template: "default.html",
|
||||
Title: "Title1",
|
||||
Content: "C2",
|
||||
URL: uPtr,
|
||||
Engine: "wikipedia",
|
||||
Score: 2.0,
|
||||
},
|
||||
},
|
||||
Answers: []map[string]any{{"title": "A1", "url": url1}},
|
||||
Corrections: []string{"corr2", "corr3"},
|
||||
Suggestions: []string{"s2", "s3"},
|
||||
Infoboxes: []map[string]any{},
|
||||
UnresponsiveEngines: [][2]string{},
|
||||
}
|
||||
|
||||
merged := MergeResponses([]contracts.SearchResponse{r1, r2})
|
||||
|
||||
if merged.Query != "q" {
|
||||
t.Fatalf("expected query q, got %q", merged.Query)
|
||||
}
|
||||
if merged.NumberOfResults != 1 {
|
||||
t.Fatalf("expected number_of_results max=1, got %d", merged.NumberOfResults)
|
||||
}
|
||||
if len(merged.Results) != 1 {
|
||||
t.Fatalf("expected 1 merged result, got %d", len(merged.Results))
|
||||
}
|
||||
|
||||
// Corrections/suggestions should be unioned.
|
||||
joinedCorr := strings.Join(merged.Corrections, ",")
|
||||
if !strings.Contains(joinedCorr, "corr1") || !strings.Contains(joinedCorr, "corr2") || !strings.Contains(joinedCorr, "corr3") {
|
||||
t.Fatalf("expected unioned corrections, got %v", merged.Corrections)
|
||||
}
|
||||
joinedSug := strings.Join(merged.Suggestions, ",")
|
||||
if !strings.Contains(joinedSug, "s1") || !strings.Contains(joinedSug, "s2") || !strings.Contains(joinedSug, "s3") {
|
||||
t.Fatalf("expected unioned suggestions, got %v", merged.Suggestions)
|
||||
}
|
||||
|
||||
if len(merged.Answers) != 1 {
|
||||
t.Fatalf("expected 1 merged answer, got %d", len(merged.Answers))
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue