package cmd import ( "strings" "testing" "github.com/yourorg/devour/internal/scraper" ) func TestDeriveSearchTerms(t *testing.T) { terms := deriveSearchTerms("go", "how to regex match http path") if len(terms) == 0 { t.Fatal("expected at least one derived search term") } joined := strings.Join(terms, ",") if !strings.Contains(joined, "regexp") { t.Fatalf("expected regexp term in %v", terms) } if !strings.Contains(joined, "net/http") { t.Fatalf("expected net/http term in %v", terms) } } func TestScoreDocument(t *testing.T) { query := "regex match in go" docTitleMatch := &scraper.Document{ Title: "Package regexp", Content: "Use MustCompile and MatchString to match values.", Type: "go-package", URL: "https://pkg.go.dev/regexp", } docNoMatch := &scraper.Document{ Title: "Package archive/tar", Content: "Read and write tar archives.", Type: "go-package", URL: "https://pkg.go.dev/archive/tar", } if scoreDocument(query, docTitleMatch) <= scoreDocument(query, docNoMatch) { t.Fatal("expected regex-related document to have a higher score") } } func TestExtractRecommendedAPI(t *testing.T) { docs := []rankedDoc{ { doc: &scraper.Document{ Title: "regexp.func MustCompile ΒΆ", URL: "https://pkg.go.dev/regexp", Content: "re := regexp.MustCompile(`\\\\d+`)\nif re.MatchString(input) { fmt.Println(\"ok\") }", }, }, } apis := extractRecommendedAPI(docs) if len(apis) == 0 { t.Fatal("expected API extraction to return at least one call") } } func TestExtractSnippet(t *testing.T) { content := "The regexp package implements regular expression search. Use MustCompile for fixed patterns." snippet := extractSnippet(content, []string{"regexp"}) if snippet == "" { t.Fatal("expected non-empty snippet") } if !strings.Contains(strings.ToLower(snippet), "regexp") { t.Fatalf("snippet should mention regexp, got: %q", snippet) } } func TestCandidateDocURLs_FrameworkFallbacks(t *testing.T) { next, err := candidateDocURLs("nextjs", "routing") if err != nil { t.Fatalf("candidateDocURLs(nextjs) error: %v", err) } if len(next) < 2 { t.Fatalf("expected fallback URLs for nextjs, got %v", next) } if next[0] != "https://nextjs.org/docs/app/building-your-application/routing" { t.Fatalf("unexpected primary nextjs URL: %q", next[0]) } remix, err := candidateDocURLs("remix", "routes") if err != nil { t.Fatalf("candidateDocURLs(remix) error: %v", err) } if len(remix) == 0 || remix[0] != "https://v2.remix.run/docs/file-conventions/routes" { t.Fatalf("unexpected remix candidate URLs: %v", remix) } solid, err := candidateDocURLs("solid", "router") if err != nil { t.Fatalf("candidateDocURLs(solid) error: %v", err) } if len(solid) == 0 || !strings.Contains(solid[0], "github.com/solidjs/solid-docs") { t.Fatalf("unexpected solid candidate URLs: %v", solid) } } func TestPrimaryQueryTokenSkipsQuestionWords(t *testing.T) { token := primaryQueryToken("what does routing do in remix") if token == "" { t.Fatal("expected non-empty token") } if token == "what" || token == "does" { t.Fatalf("expected informative token, got %q", token) } } func TestDeriveSearchTermsSolidRouting(t *testing.T) { terms := deriveSearchTerms("solid", "how to do routing in solid") joined := strings.Join(terms, ",") if !strings.Contains(joined, "solid-router") { t.Fatalf("expected solid-router term in %v", terms) } if strings.Contains(joined, "signals") { t.Fatalf("did not expect signals default for routing question, got %v", terms) } } func TestShouldFallbackToLive(t *testing.T) { strong := []rankedDoc{ { doc: &scraper.Document{Title: "Routing Guide", Content: "routing with file based routes", URL: "https://nextjs.org/docs/routing"}, score: 2.2, }, } if shouldFallbackToLive(strong, []string{"routing"}) { t.Fatal("expected strong local match to skip live fallback") } weak := []rankedDoc{ { doc: &scraper.Document{Title: "Misc", Content: "unrelated", URL: "https://example.com"}, score: 0.1, }, } if !shouldFallbackToLive(weak, []string{"routing"}) { t.Fatal("expected weak local match to trigger live fallback") } }