package prices_test import ( "strings" "testing" "github.com/runescape-wiki/rsw/internal/prices" ) const osrsPriceBaseURL = "https://prices.runescape.wiki/api/v1/osrs" func osrsClient() *prices.Client { return prices.NewClient(osrsPriceBaseURL) } // --- OSRS Mapping Tests --- func TestOSRS_GetMapping_ReturnsItems(t *testing.T) { items, err := osrsClient().GetMapping() if err != nil { t.Fatalf("GetMapping failed: %v", err) } if len(items) < 100 { t.Fatalf("expected at least 100 items, got %d", len(items)) } } func TestOSRS_GetMapping_ContainsAbyssalWhip(t *testing.T) { items, err := osrsClient().GetMapping() if err != nil { t.Fatalf("GetMapping failed: %v", err) } found := false for _, item := range items { if strings.EqualFold(item.Name, "abyssal whip") { found = true if item.ID != 4151 { t.Errorf("expected Abyssal whip ID to be 4151, got %d", item.ID) } if !item.Members { t.Error("expected Abyssal whip to be members-only") } break } } if !found { t.Error("expected to find 'Abyssal whip' in mapping") } } // --- OSRS MappingCache Tests --- func TestOSRS_MappingCache_LookupByName(t *testing.T) { mc := prices.NewMappingCache(osrsClient(), "osrs") if err := mc.Load(); err != nil { t.Fatalf("Load failed: %v", err) } item := mc.LookupByName("Abyssal whip") if item == nil { t.Fatal("expected to find Abyssal whip") } if item.ID != 4151 { t.Errorf("expected ID 4151, got %d", item.ID) } } func TestOSRS_MappingCache_LookupByName_CaseInsensitive(t *testing.T) { mc := prices.NewMappingCache(osrsClient(), "osrs") if err := mc.Load(); err != nil { t.Fatalf("Load failed: %v", err) } item := mc.LookupByName("ABYSSAL WHIP") if item == nil { t.Fatal("expected case-insensitive lookup to find Abyssal whip") } } func TestOSRS_MappingCache_SearchByName(t *testing.T) { mc := prices.NewMappingCache(osrsClient(), "osrs") if err := mc.Load(); err != nil { t.Fatalf("Load failed: %v", err) } results := mc.SearchByName("dragon") if len(results) == 0 { t.Fatal("expected to find items containing 'dragon'") } for _, item := range results { if !strings.Contains(strings.ToLower(item.Name), "dragon") { t.Errorf("result %q does not contain 'dragon'", item.Name) } } } func TestOSRS_MappingCache_LookupByID(t *testing.T) { mc := prices.NewMappingCache(osrsClient(), "osrs") if err := mc.Load(); err != nil { t.Fatalf("Load failed: %v", err) } item := mc.LookupByID(4151) if item == nil { t.Fatal("expected to find item 4151") } if !strings.EqualFold(item.Name, "abyssal whip") { t.Errorf("expected 'Abyssal whip', got %q", item.Name) } } // --- OSRS Latest Price Tests --- func TestOSRS_GetLatestForItem_AbyssalWhip(t *testing.T) { latest, err := osrsClient().GetLatestForItem(4151) if err != nil { t.Fatalf("GetLatestForItem failed: %v", err) } if latest.High == nil && latest.Low == nil { t.Error("expected at least one of High or Low to be non-nil") } if latest.High != nil && *latest.High <= 0 { t.Errorf("expected positive high price, got %d", *latest.High) } if latest.Low != nil && *latest.Low <= 0 { t.Errorf("expected positive low price, got %d", *latest.Low) } } func TestOSRS_GetLatestForItem_Nonexistent(t *testing.T) { _, err := osrsClient().GetLatestForItem(999999999) if err == nil { t.Error("expected error for nonexistent item ID") } } // --- OSRS Timeseries Tests --- func TestOSRS_Get1Hour_AbyssalWhip(t *testing.T) { entry, err := osrsClient().Get1Hour(4151) if err != nil { t.Fatalf("Get1Hour failed: %v", err) } if entry.AvgHighPrice == nil { t.Error("expected AvgHighPrice to be non-nil for Abyssal whip") } else if *entry.AvgHighPrice <= 0 { t.Errorf("expected positive AvgHighPrice, got %d", *entry.AvgHighPrice) } if entry.AvgLowPrice == nil { t.Error("expected AvgLowPrice to be non-nil for Abyssal whip") } else if *entry.AvgLowPrice <= 0 { t.Errorf("expected positive AvgLowPrice, got %d", *entry.AvgLowPrice) } if entry.HighVolume <= 0 { t.Errorf("expected positive buy volume, got %d", entry.HighVolume) } if entry.LowVolume <= 0 { t.Errorf("expected positive sell volume, got %d", entry.LowVolume) } } func TestOSRS_Get5Min_AbyssalWhip(t *testing.T) { entry, err := osrsClient().Get5Min(4151) if err != nil { t.Fatalf("Get5Min failed: %v", err) } if entry.AvgHighPrice == nil { t.Error("expected AvgHighPrice to be non-nil for Abyssal whip") } else if *entry.AvgHighPrice <= 0 { t.Errorf("expected positive AvgHighPrice, got %d", *entry.AvgHighPrice) } if entry.AvgLowPrice == nil { t.Error("expected AvgLowPrice to be non-nil for Abyssal whip") } else if *entry.AvgLowPrice <= 0 { t.Errorf("expected positive AvgLowPrice, got %d", *entry.AvgLowPrice) } } // --- RS3 Client Tests --- func TestRS3_GetDetail_AbyssalWhip(t *testing.T) { c := prices.NewRS3Client() detail, err := c.GetDetail(4151) if err != nil { t.Fatalf("GetDetail failed: %v", err) } if detail.Name != "Abyssal whip" { t.Errorf("expected name 'Abyssal whip', got %q", detail.Name) } if detail.CurrentPrice == "" { t.Error("expected non-empty current price") } if detail.ID != 4151 { t.Errorf("expected ID 4151, got %d", detail.ID) } } func TestRS3_GetDetail_BluePartyhat(t *testing.T) { c := prices.NewRS3Client() detail, err := c.GetDetail(1042) if err != nil { t.Fatalf("GetDetail failed: %v", err) } if !strings.Contains(strings.ToLower(detail.Name), "partyhat") && !strings.Contains(strings.ToLower(detail.Name), "party hat") { t.Errorf("expected name to contain 'partyhat', got %q", detail.Name) } if detail.CurrentPrice == "" { t.Error("expected non-empty current price") } } func TestRS3_GetDetail_HasTrends(t *testing.T) { c := prices.NewRS3Client() detail, err := c.GetDetail(4151) if err != nil { t.Fatalf("GetDetail failed: %v", err) } if detail.Day30Change == "" { t.Error("expected non-empty 30-day change") } if detail.Day90Change == "" { t.Error("expected non-empty 90-day change") } if detail.Day180Change == "" { t.Error("expected non-empty 180-day change") } validTrends := map[string]bool{"positive": true, "negative": true, "neutral": true} if !validTrends[detail.Day30Trend] { t.Errorf("unexpected 30-day trend %q", detail.Day30Trend) } if !validTrends[detail.Day90Trend] { t.Errorf("unexpected 90-day trend %q", detail.Day90Trend) } } func TestRS3_GetDetail_Nonexistent(t *testing.T) { c := prices.NewRS3Client() _, err := c.GetDetail(999999999) if err == nil { t.Error("expected error for nonexistent RS3 item ID") } } // --- RS3 Exchange Module Tests (via wiki client) --- // These are in the wiki package test file, but we verify the RS3 price // client integrates correctly with real item IDs from exchange modules. func TestRS3_GetDetail_Members_Field(t *testing.T) { c := prices.NewRS3Client() detail, err := c.GetDetail(4151) if err != nil { t.Fatalf("GetDetail failed: %v", err) } if detail.Members != "true" { t.Errorf("expected Abyssal whip members='true', got %q", detail.Members) } }