mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-03 20:26:36 +08:00
107 lines
2.8 KiB
Go
107 lines
2.8 KiB
Go
package reader
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
// 本文件:搜索范围的过滤逻辑(对应 legado SearchScope.getBookSourceParts)。
|
|
// 覆盖「只搜指定源」「空范围=全部」「范围失效退回全部」三种情形。
|
|
|
|
func scopeEchoSourceJSON(t *testing.T, name, serverURL string) string {
|
|
t.Helper()
|
|
src := map[string]any{
|
|
"bookSourceUrl": serverURL,
|
|
"bookSourceName": name,
|
|
"searchUrl": serverURL + "/search?q={{key}}",
|
|
"ruleSearch": map[string]any{
|
|
"bookList": "$.data",
|
|
"name": "$.book_name",
|
|
"author": "$.author",
|
|
"bookUrl": "$.book_url",
|
|
},
|
|
}
|
|
out, _ := json.Marshal(src)
|
|
return string(out)
|
|
}
|
|
|
|
func scopeEchoServer(t *testing.T, bookName string) *httptest.Server {
|
|
t.Helper()
|
|
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
payload := map[string]any{
|
|
"data": []map[string]string{{
|
|
"book_name": bookName,
|
|
"author": "作者",
|
|
"book_url": "/book/1",
|
|
}},
|
|
}
|
|
_ = json.NewEncoder(w).Encode(payload)
|
|
}))
|
|
}
|
|
|
|
func TestSearchRespectsSourceScope(t *testing.T) {
|
|
srvA := scopeEchoServer(t, "甲书")
|
|
defer srvA.Close()
|
|
srvB := scopeEchoServer(t, "乙书")
|
|
defer srvB.Close()
|
|
|
|
svc, _ := newLoginTestService(t)
|
|
for _, raw := range []string{
|
|
scopeEchoSourceJSON(t, "源A", srvA.URL),
|
|
scopeEchoSourceJSON(t, "源B", srvB.URL),
|
|
} {
|
|
if _, err := svc.ImportSources(t.Context(), raw); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
sources, err := svc.ListSources(t.Context())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
idByName := map[string]string{}
|
|
for _, s := range sources {
|
|
idByName[s.Name] = s.ID
|
|
}
|
|
|
|
names := func(books []SearchBook) map[string]bool {
|
|
out := map[string]bool{}
|
|
for _, b := range books {
|
|
out[b.Name] = true
|
|
}
|
|
return out
|
|
}
|
|
|
|
// 指定单个源:只应搜到该源的结果
|
|
books, skipped, err := svc.Search(t.Context(), "书", []string{idByName["源A"]})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(skipped) > 0 {
|
|
t.Fatalf("源A 不应失败: %+v", skipped)
|
|
}
|
|
if got := names(books); len(got) != 1 || !got["甲书"] {
|
|
t.Fatalf("只搜源A 应只返回甲书,实际 %+v", books)
|
|
}
|
|
|
|
// 空范围:默认全部启用书源,两个源都应命中
|
|
books, _, err = svc.Search(t.Context(), "书", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := names(books); len(got) != 2 || !got["甲书"] || !got["乙书"] {
|
|
t.Fatalf("空范围应搜到两个源的结果,实际 %+v", books)
|
|
}
|
|
|
|
// 范围里的源已不存在(删源/换设备)时退回全部启用,而不是搜不到
|
|
books, _, err = svc.Search(t.Context(), "书", []string{"not-a-real-source"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := names(books); len(got) != 2 {
|
|
t.Fatalf("失效范围应退回全部启用,实际 %+v", books)
|
|
}
|
|
}
|