From 37645e37f71d0643a78d1239e8322617df7eb9ea Mon Sep 17 00:00:00 2001 From: Hamcha Date: Fri, 28 Jun 2019 17:24:47 +0200 Subject: [PATCH] Make HTTP server and URL customizable Tests now do not require internet access anymore Closes #4 --- mlp/booster.go | 6 +- mlp/booster_test.go | 1 - mlp/set.go | 8 +- mlp/set_test.go | 43 +++++++-- mlp/testdata/sets.go | 212 +++++++++++++++++++++++++++++++++++++++++++ mlp/utils.go | 2 +- 6 files changed, 261 insertions(+), 11 deletions(-) create mode 100644 mlp/testdata/sets.go diff --git a/mlp/booster.go b/mlp/booster.go index f2273fe..63d86e0 100644 --- a/mlp/booster.go +++ b/mlp/booster.go @@ -108,7 +108,7 @@ func (set *Set) PackSchema() draft.PackSchema { // ProviderByRarity returns a provider for a given rarity level from a given set func (set *Set) ProviderByRarity(rarity Rarity) draft.CardProvider { - var collection []draft.Card + collection := []draft.Card{} // RR flow is super easy, just pick one from our hardcoded list if rarity == RarityRoyalRare { rr, ok := royalRares[set.ID] @@ -126,6 +126,10 @@ func (set *Set) ProviderByRarity(rarity Rarity) draft.CardProvider { } return func(n int) []draft.Card { out := make([]draft.Card, n) + if len(collection) < 1 { + // Something really wrong happened here + return out + } for n := range out { // Pick a RR at random idx := rand.Intn(len(collection)) diff --git a/mlp/booster_test.go b/mlp/booster_test.go index 9bb2f4d..60b9ecb 100644 --- a/mlp/booster_test.go +++ b/mlp/booster_test.go @@ -9,7 +9,6 @@ import ( // TestAlternates tries to get alternates (SR/UR/RR) // This might require a while since it needs to generate MANY packs! -// This test *requires* an internet connection! func TestAlternates(t *testing.T) { // Load Premiere/CN as they have their own UR ratios prSet, err := mlp.LoadSetHTTP(mlp.SetPremiere) diff --git a/mlp/set.go b/mlp/set.go index ce98325..b6e56dc 100644 --- a/mlp/set.go +++ b/mlp/set.go @@ -89,6 +89,12 @@ func LoadSetBytes(id SetID, setdata []byte) (*Set, error) { return &set, err } +// HTTPClient is the HTTP client used in LoadSetHTTP +var HTTPClient = http.DefaultClient + +// HTTPSource is the base URL for fetching sets remotely via HTTP +var HTTPSource = "https://mcg.zyg.ovh/setdata/" + // LoadSetHTTP loads a set using MCG's remote server func LoadSetHTTP(id SetID) (*Set, error) { // Check if set is already loaded @@ -99,7 +105,7 @@ func LoadSetHTTP(id SetID) (*Set, error) { // Get SetID as string and make it lowercase setid := strings.ToLower(string(id)) - resp, err := http.Get("https://mcg.zyg.ovh/setdata/" + setid + ".json") + resp, err := HTTPClient.Get(HTTPSource + setid + ".json") if err != nil || resp.StatusCode != 200 { if err == nil { err = fmt.Errorf("server returned non-200 response code (%d)", resp.StatusCode) diff --git a/mlp/set_test.go b/mlp/set_test.go index d5296af..179a095 100644 --- a/mlp/set_test.go +++ b/mlp/set_test.go @@ -1,25 +1,29 @@ package mlp_test import ( + "fmt" + "net/http" + "net/http/httptest" + "os" "testing" "git.fromouter.space/mcg/draft" "git.fromouter.space/mcg/draft/mlp" + "git.fromouter.space/mcg/draft/mlp/testdata" ) // TestSet retrieves a set online and generates a couple packs with it -// This test *requires* an internet connection! func TestSet(t *testing.T) { // Clean all loaded sets mlp.CleanSetCache() - deSet, err := mlp.LoadSetHTTP(mlp.SetDefendersOfEquestria) + prSet, err := mlp.LoadSetHTTP(mlp.SetPremiere) if err != nil { t.Fatalf("Could not fetch set data: %s", err.Error()) } - pack1 := draft.MakePack(deSet) - pack2 := draft.MakePack(deSet) + pack1 := draft.MakePack(prSet) + pack2 := draft.MakePack(prSet) // Make sure both packs have the exact number of cards if len(pack1) != 12 { @@ -34,7 +38,6 @@ func TestSet(t *testing.T) { } // TestWrongSet tries to fetch a set that doesn't exist -// This test *requires* an internet connection! func TestWrongSet(t *testing.T) { _, err := mlp.LoadSetHTTP("nopenope") if err == nil { @@ -43,13 +46,12 @@ func TestWrongSet(t *testing.T) { } // TestAllLoads tests all the LoadSet* functions -// This test *requires* an internet connection! func TestAllLoads(t *testing.T) { // Clean all loaded sets mlp.CleanSetCache() // Test LoadSetHTTP - _, err := mlp.LoadSetHTTP(mlp.SetAbsoluteDiscord) + _, err := mlp.LoadSetHTTP(mlp.SetFriendsForever) if err != nil { t.Fatalf("[LoadSetHTTP] Could not fetch set data from the internet: %s", err.Error()) } @@ -157,4 +159,31 @@ func TestMalformedJSONLoad(t *testing.T) { if err == nil { t.Fatalf("LoadSetData with invalid data succeeded but shouldn't have") } + + _, err = mlp.LoadSetHTTP(mlp.SetID("broken")) + if err == nil { + t.Fatalf("LoadSetHTTP with invalid JSON succeded but shouldn't have") + } +} + +var testServer *httptest.Server + +func TestMain(m *testing.M) { + testServer = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + switch req.URL.Path { + case "/nopenope.json": + // 404 + http.Error(res, "Not found", http.StatusNotFound) + case "/broken.json": + // Broken response + fmt.Fprintf(res, "{{{{") + case "/pr.json": + fmt.Fprintf(res, testdata.SetPremiere) + default: + fmt.Fprintf(res, testdata.SetFriendForever) + } + })) + mlp.HTTPSource = testServer.URL + "/" + defer testServer.Close() + os.Exit(m.Run()) } diff --git a/mlp/testdata/sets.go b/mlp/testdata/sets.go new file mode 100644 index 0000000..1853e7c --- /dev/null +++ b/mlp/testdata/sets.go @@ -0,0 +1,212 @@ +package testdata + +// SetFriendForever is an excerpt from Friend Forever's JSON set data +const SetFriendForever = `{ + "Name": "Friends Forever", + "Cards": [ + { + "ID": "ff1", + "Name": "Gallus", + "Subname": "Full of Surprises", + "Element": [ + "Loyalty" + ], + "Keywords": [ + "Home Limit 3" + ], + "Traits": [ + "Griffon" + ], + "Power": 1, + "Type": "Mane Character", + "Text": "When you confront this card's Problem, turn this card over.", + "Rarity": "U" + }, + { + "ID": "ff3", + "Name": "Ocellus", + "Subname": "Knowledge is Power", + "Element": [ + "Generosity" + ], + "Keywords": [ + "Home Limit 3" + ], + "Traits": [ + "Changeling" + ], + "Power": 1, + "Type": "Mane Character", + "Text": "When you confront this card's Problem, turn this card over.", + "Rarity": "U" + }, + { + "ID": "ff4", + "Name": "Chipcutter", + "Subname": "Sculptor", + "Element": [ + "Loyalty" + ], + "Keywords": [ + "Swift" + ], + "Traits": [ + "Pegasus", + "Foal" + ], + "Cost": 3, + "Power": 2, + "Type": "Friend", + "Text": "", + "Rarity": "C" + }, + { + "ID": "ff5", + "Name": "Daybreaker", + "Subname": "Blinding Light", + "Element": [ + "Loyalty" + ], + "Keywords": [ + "Competitive 3" + ], + "Traits": [ + "Alicorn", + "Royalty" + ], + "Requirement": { + "Loyalty": 3 + }, + "Cost": 3, + "Power": 3, + "Type": "Friend", + "Text": "When you win a faceoff involving this card, score a point.", + "Rarity": "SR" + }, + { + "ID": "ff131", + "Name": "Silverstream", + "Subname": "Everything's New!", + "Element": [ + "Laughter" + ], + "Keywords": [ + "Home Limit 3" + ], + "Traits": [ + "Ally", + "Hippogriff" + ], + "Power": 1, + "Type": "Mane Character", + "Text": "Immediate: While this card is at a Problem with 2 or more other characters, turn this card over.", + "Rarity": "UR" + } + ] +}` + +// SetPremiere is an excerpt from Premiere's JSON set data +const SetPremiere = `{ + "Name": "Premiere", + "Cards": [ + { + "ID": "pr54", + "Name": "Comet Tail", + "Subname": "Hale Bopper", + "Element": [ + "Magic" + ], + "Keywords": [], + "Traits": [ + "Unicorn" + ], + "Cost": 1, + "Power": 1, + "Type": "Friend", + "Text": "", + "Rarity": "C" + }, + { + "ID": "pr55", + "Name": "Mint Jewelup", + "Subname": "A Cut Above", + "Element": [ + "Magic" + ], + "Keywords": [], + "Traits": [ + "Unicorn" + ], + "Requirement": { + "Magic": 2 + }, + "Cost": 2, + "Power": 1, + "Type": "Friend", + "Text": "Studious.", + "Rarity": "C" + }, + { + "ID": "pr56", + "Name": "Gyro", + "Subname": "Poindexter", + "Element": [ + "Magic" + ], + "Keywords": [], + "Traits": [ + "Earth Pony" + ], + "Requirement": { + "Magic": 3 + }, + "Cost": 1, + "Power": 1, + "Type": "Friend", + "Text": "When you play this card, you may search your deck for an Event, reveal it, put it into your hand, and shuffle your deck.", + "Rarity": "R" + }, + { + "ID": "pr77", + "Name": "Rarity", + "Subname": "Nest Weaver", + "Element": [ + "Generosity" + ], + "Keywords": [ + "Inspired" + ], + "Traits": [ + "Unicorn" + ], + "Requirement": { + "Generosity": 3 + }, + "Cost": 3, + "Power": 2, + "Type": "Friend", + "Text": "When you play this card, you may search your discard pile for a card and put it into your hand.", + "Rarity": "U" + }, + { + "ID": "pr211", + "Name": "Fluttershy", + "Subname": "Monster Tamer", + "Element": [ + "Kindness" + ], + "Keywords": [], + "Traits": [ + "Pegasus" + ], + "Requirement": { + "Kindness": 4 + }, + "Cost": 4, + "Power": 2, + "Type": "Friend", + "Text": "When you play this card to a Problem, you may banish a Troublemaker there. When this card leaves that Problem, put that banished Troublemaker into play at a Problem and uncover it.", + "Rarity": "UR" + } + ] +}` diff --git a/mlp/utils.go b/mlp/utils.go index 4017dd0..8ebab93 100644 --- a/mlp/utils.go +++ b/mlp/utils.go @@ -2,7 +2,7 @@ package mlp import "git.fromouter.space/mcg/draft" -// Converts multiple mlp.Card to draft.Card +// ToDraft converts multiple mlp.Card to draft.Card func ToDraft(cards []Card) []draft.Card { out := make([]draft.Card, len(cards)) for i, card := range cards {