From 9cbbbca2e338face465a1fc8ec4cd30fb3369065 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 6 Mar 2026 01:37:17 +0000 Subject: [PATCH] test: add integration tests for OSRS and RS3 wiki searches and page fetches --- scripts/rsw/internal/wiki/integration_test.go | 518 ++++++++++++++++++ 1 file changed, 518 insertions(+) create mode 100644 scripts/rsw/internal/wiki/integration_test.go diff --git a/scripts/rsw/internal/wiki/integration_test.go b/scripts/rsw/internal/wiki/integration_test.go new file mode 100644 index 0000000..15f1cb5 --- /dev/null +++ b/scripts/rsw/internal/wiki/integration_test.go @@ -0,0 +1,518 @@ +package wiki_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/runescape-wiki/rsw/internal/wiki" +) + +const ( + osrsAPIURL = "https://oldschool.runescape.wiki/api.php" + rs3APIURL = "https://runescape.wiki/api.php" +) + +func osrsClient() *wiki.Client { + return wiki.NewClient(osrsAPIURL) +} + +func rs3Client() *wiki.Client { + return wiki.NewClient(rs3APIURL) +} + +func containsKeyword(t *testing.T, text, keyword string) { + t.Helper() + if !strings.Contains(strings.ToLower(text), strings.ToLower(keyword)) { + t.Errorf("expected to find keyword %q in text, but it was not found.\nText (first 500 chars): %.500s", keyword, text) + } +} + +func containsAnyKeyword(t *testing.T, text string, keywords []string) { + t.Helper() + lower := strings.ToLower(text) + for _, kw := range keywords { + if strings.Contains(lower, strings.ToLower(kw)) { + return + } + } + t.Errorf("expected to find one of %v in text, but none were found.\nText (first 500 chars): %.500s", keywords, text) +} + +// --- OSRS Search Tests --- + +func TestOSRS_Search_DragonScimitar(t *testing.T) { + results, err := osrsClient().Search("dragon scimitar", 5) + if err != nil { + t.Fatalf("Search failed: %v", err) + } + if len(results) == 0 { + t.Fatal("expected results, got none") + } + + found := false + for _, r := range results { + if strings.Contains(strings.ToLower(r.Title), "dragon scimitar") { + found = true + break + } + } + if !found { + t.Errorf("expected to find 'Dragon scimitar' in results, got: %v", titlesOf(results)) + } +} + +func TestOSRS_Search_AbyssalWhip(t *testing.T) { + results, err := osrsClient().Search("abyssal whip", 5) + if err != nil { + t.Fatalf("Search failed: %v", err) + } + if len(results) == 0 { + t.Fatal("expected results, got none") + } + + found := false + for _, r := range results { + if strings.Contains(strings.ToLower(r.Title), "abyssal whip") { + found = true + break + } + } + if !found { + t.Errorf("expected to find 'Abyssal whip' in results, got: %v", titlesOf(results)) + } +} + +func TestOSRS_Search_MonkeyMadness(t *testing.T) { + results, err := osrsClient().Search("Monkey Madness", 5) + if err != nil { + t.Fatalf("Search failed: %v", err) + } + if len(results) == 0 { + t.Fatal("expected results, got none") + } + + found := false + for _, r := range results { + if strings.Contains(strings.ToLower(r.Title), "monkey madness") { + found = true + break + } + } + if !found { + t.Errorf("expected to find 'Monkey Madness' in results, got: %v", titlesOf(results)) + } +} + +func TestOSRS_Search_MiningTraining(t *testing.T) { + results, err := osrsClient().Search("mining training", 5) + if err != nil { + t.Fatalf("Search failed: %v", err) + } + if len(results) == 0 { + t.Fatal("expected results, got none") + } + + found := false + for _, r := range results { + lower := strings.ToLower(r.Title) + if strings.Contains(lower, "mining") { + found = true + break + } + } + if !found { + t.Errorf("expected to find mining-related result, got: %v", titlesOf(results)) + } +} + +func TestOSRS_Search_Snippet_ContainsKeywords(t *testing.T) { + results, err := osrsClient().Search("dragon scimitar", 5) + if err != nil { + t.Fatalf("Search failed: %v", err) + } + if len(results) == 0 { + t.Fatal("expected results, got none") + } + + allText := collectSnippets(results) + containsAnyKeyword(t, allText, []string{"dragon", "scimitar", "weapon", "sword"}) +} + +// --- RS3 Search Tests --- + +func TestRS3_Search_DragonBones(t *testing.T) { + results, err := rs3Client().Search("dragon bones", 5) + if err != nil { + t.Fatalf("Search failed: %v", err) + } + if len(results) == 0 { + t.Fatal("expected results, got none") + } + + found := false + for _, r := range results { + if strings.Contains(strings.ToLower(r.Title), "dragon bones") { + found = true + break + } + } + if !found { + t.Errorf("expected to find 'Dragon bones' in results, got: %v", titlesOf(results)) + } +} + +func TestRS3_Search_PlaguessEnd(t *testing.T) { + results, err := rs3Client().Search("Plague's End", 5) + if err != nil { + t.Fatalf("Search failed: %v", err) + } + if len(results) == 0 { + t.Fatal("expected results, got none") + } + + found := false + for _, r := range results { + if strings.Contains(strings.ToLower(r.Title), "plague") { + found = true + break + } + } + if !found { + t.Errorf("expected to find plague-related result, got: %v", titlesOf(results)) + } +} + +func TestRS3_Search_BluePartyhat(t *testing.T) { + results, err := rs3Client().Search("blue partyhat", 5) + if err != nil { + t.Fatalf("Search failed: %v", err) + } + if len(results) == 0 { + t.Fatal("expected results, got none") + } + + found := false + for _, r := range results { + lower := strings.ToLower(r.Title) + if strings.Contains(lower, "partyhat") || strings.Contains(lower, "party hat") { + found = true + break + } + } + if !found { + t.Errorf("expected to find 'Blue partyhat' in results, got: %v", titlesOf(results)) + } +} + +func TestRS3_Search_PrayerTraining(t *testing.T) { + results, err := rs3Client().Search("prayer training", 5) + if err != nil { + t.Fatalf("Search failed: %v", err) + } + if len(results) == 0 { + t.Fatal("expected results, got none") + } + + found := false + for _, r := range results { + lower := strings.ToLower(r.Title) + if strings.Contains(lower, "prayer") { + found = true + break + } + } + if !found { + t.Errorf("expected to find prayer-related result, got: %v", titlesOf(results)) + } +} + +// --- OSRS Page Tests --- + +func TestOSRS_GetPage_DragonScimitar_ContainsKeyInfo(t *testing.T) { + page, err := osrsClient().GetPage("Dragon scimitar") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + if page.Wikitext == "" { + t.Fatal("expected non-empty wikitext") + } + + containsKeyword(t, page.Wikitext, "scimitar") + containsAnyKeyword(t, page.Wikitext, []string{"members", "Members"}) + containsAnyKeyword(t, page.Wikitext, []string{"attack", "Attack", "slash", "Slash"}) +} + +func TestOSRS_GetPage_AbyssalWhip_ContainsKeyInfo(t *testing.T) { + page, err := osrsClient().GetPage("Abyssal whip") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + containsKeyword(t, page.Wikitext, "whip") + containsAnyKeyword(t, page.Wikitext, []string{"slayer", "Slayer"}) + containsAnyKeyword(t, page.Wikitext, []string{"abyssal", "Abyssal"}) +} + +func TestOSRS_GetPage_HasSections(t *testing.T) { + page, err := osrsClient().GetPage("Dragon scimitar") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + if len(page.Sections) == 0 { + t.Error("expected page to have sections") + } +} + +func TestOSRS_GetPage_MonkeyMadness_Quest(t *testing.T) { + page, err := osrsClient().GetPage("Monkey Madness I") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + containsKeyword(t, page.Wikitext, "quest") + containsAnyKeyword(t, page.Wikitext, []string{"gnome", "Gnome", "monkey", "Monkey"}) + containsAnyKeyword(t, page.Wikitext, []string{"requirements", "Requirements"}) +} + +// --- RS3 Page Tests --- + +func TestRS3_GetPage_DragonBones_ContainsKeyInfo(t *testing.T) { + page, err := rs3Client().GetPage("Dragon bones") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + containsKeyword(t, page.Wikitext, "prayer") + containsAnyKeyword(t, page.Wikitext, []string{"dragon", "Dragon"}) + containsAnyKeyword(t, page.Wikitext, []string{"bone", "Bone", "bones", "Bones"}) +} + +func TestRS3_GetPage_PlaguessEnd_Quest(t *testing.T) { + page, err := rs3Client().GetPage("Plague's End") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + containsKeyword(t, page.Wikitext, "quest") + containsAnyKeyword(t, page.Wikitext, []string{"elf", "Elf", "elven", "Elven"}) + containsAnyKeyword(t, page.Wikitext, []string{"requirements", "Requirements"}) +} + +// --- Section Tests --- + +func TestOSRS_GetPage_Sections_DragonScimitar(t *testing.T) { + page, err := osrsClient().GetPage("Dragon scimitar") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + if len(page.Sections) == 0 { + t.Fatal("expected at least one section") + } + + sectionNames := make([]string, len(page.Sections)) + for i, s := range page.Sections { + sectionNames[i] = strings.ToLower(s.Line) + } + + allSections := strings.Join(sectionNames, " ") + containsAnyKeyword(t, allSections, []string{"combat", "stats", "bonuses", "item", "creation", "drop"}) +} + +func TestOSRS_GetPageSection_DragonScimitar_FirstSection(t *testing.T) { + page, err := osrsClient().GetPage("Dragon scimitar") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + idx := findSectionContaining(page.Sections, []string{"combat", "bonuses", "stats", "creation", "special"}) + if idx < 0 { + if len(page.Sections) == 0 { + t.Skip("no sections found") + } + idx = parseFirstSectionIndex(page.Sections) + if idx < 0 { + t.Skip("could not parse any section index") + } + } + + section, err := osrsClient().GetPageSection("Dragon scimitar", idx) + if err != nil { + t.Fatalf("GetPageSection failed: %v", err) + } + if section.Wikitext == "" { + t.Error("expected non-empty section wikitext") + } +} + +func TestOSRS_GetPage_MiningTraining_Sections(t *testing.T) { + page, err := osrsClient().GetPage("Mining training") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + containsKeyword(t, page.Wikitext, "mining") + containsAnyKeyword(t, page.Wikitext, []string{"experience", "xp", "level"}) + + if len(page.Sections) == 0 { + t.Error("expected mining training page to have sections") + } +} + +func TestOSRS_GetPageSection_MiningTraining_FirstSection(t *testing.T) { + page, err := osrsClient().GetPage("Mining training") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + idx := parseFirstSectionIndex(page.Sections) + if idx < 0 { + t.Skip("no sections with valid index found") + } + + section, err := osrsClient().GetPageSection("Mining training", idx) + if err != nil { + t.Fatalf("GetPageSection failed: %v", err) + } + if section.Wikitext == "" { + t.Error("expected non-empty wikitext for section") + } + containsAnyKeyword(t, section.Wikitext, []string{"mining", "xp", "experience", "level", "ore"}) +} + +func TestRS3_GetPage_PrayerTraining_Sections(t *testing.T) { + page, err := rs3Client().GetPage("Prayer training") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + containsKeyword(t, page.Wikitext, "prayer") + containsAnyKeyword(t, page.Wikitext, []string{"experience", "xp", "level", "bones"}) + + if len(page.Sections) == 0 { + t.Error("expected prayer training page to have sections") + } +} + +func TestRS3_GetPageSection_PrayerTraining_BonesSection(t *testing.T) { + page, err := rs3Client().GetPage("Prayer training") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + idx := findSectionContaining(page.Sections, []string{"bones", "altars", "bury", "offering"}) + if idx < 0 { + t.Skip("no bones/altars section found") + } + + section, err := rs3Client().GetPageSection("Prayer training", idx) + if err != nil { + t.Fatalf("GetPageSection failed: %v", err) + } + containsAnyKeyword(t, section.Wikitext, []string{"prayer", "bone", "xp", "experience"}) +} + +func TestRS3_GetPage_Slayer_Sections(t *testing.T) { + page, err := rs3Client().GetPage("Slayer") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + containsKeyword(t, page.Wikitext, "slayer") + if len(page.Sections) == 0 { + t.Error("expected slayer page to have sections") + } +} + +func TestRS3_GetPageSection_Slayer_MastersSection(t *testing.T) { + page, err := rs3Client().GetPage("Slayer") + if err != nil { + t.Fatalf("GetPage failed: %v", err) + } + + idx := findSectionContaining(page.Sections, []string{"master", "masters", "tutor"}) + if idx < 0 { + t.Skip("no masters section found") + } + + section, err := rs3Client().GetPageSection("Slayer", idx) + if err != nil { + t.Fatalf("GetPageSection failed: %v", err) + } + containsAnyKeyword(t, section.Wikitext, []string{"slayer", "master", "task"}) +} + +// --- FindSectionIndex Tests --- + +func TestFindSectionIndex_Found(t *testing.T) { + sections := []wiki.Section{ + {Index: "1", Line: "Overview"}, + {Index: "2", Line: "Combat styles"}, + {Index: "3", Line: "Rewards"}, + } + idx := wiki.FindSectionIndex(sections, "Combat styles") + if idx != 2 { + t.Errorf("expected index 2, got %d", idx) + } +} + +func TestFindSectionIndex_NotFound(t *testing.T) { + sections := []wiki.Section{ + {Index: "1", Line: "Overview"}, + } + idx := wiki.FindSectionIndex(sections, "NonExistent") + if idx != -1 { + t.Errorf("expected -1, got %d", idx) + } +} + +func TestFindSectionIndex_Empty(t *testing.T) { + idx := wiki.FindSectionIndex(nil, "anything") + if idx != -1 { + t.Errorf("expected -1 for nil sections, got %d", idx) + } +} + +// --- Helpers --- + +func titlesOf(results []wiki.SearchResult) []string { + titles := make([]string, len(results)) + for i, r := range results { + titles[i] = r.Title + } + return titles +} + +func collectSnippets(results []wiki.SearchResult) string { + var parts []string + for _, r := range results { + parts = append(parts, r.Snippet) + } + return strings.Join(parts, " ") +} + +func findSectionContaining(sections []wiki.Section, keywords []string) int { + for _, s := range sections { + lower := strings.ToLower(s.Line) + for _, kw := range keywords { + if strings.Contains(lower, strings.ToLower(kw)) { + var idx int + if _, err := fmt.Sscanf(s.Index, "%d", &idx); err == nil && idx > 0 { + return idx + } + } + } + } + return -1 +} + +func parseFirstSectionIndex(sections []wiki.Section) int { + for _, s := range sections { + var idx int + if _, err := fmt.Sscanf(s.Index, "%d", &idx); err == nil && idx > 0 { + return idx + } + } + return -1 +}