From d88f2bf5261ea29213143f8b378d504d02091377 Mon Sep 17 00:00:00 2001 From: Joshua Raphael Date: Tue, 19 Nov 2024 11:11:01 -0700 Subject: [PATCH] add GetAchievementCount endpoint --- README.md | 3 +- .../getachievementcount.go | 28 ++++ game.go | 18 +++ game_test.go | 136 ++++++++++++++++++ models/game.go | 10 ++ 5 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 examples/game/getachievementcount/getachievementcount.go diff --git a/README.md b/README.md index 534c073..55345cc 100644 --- a/README.md +++ b/README.md @@ -71,4 +71,5 @@ For convenience, the API docs and examples can be found in the tables below |-|-|-| |`GetGame()`|Get basic metadata about a game.|[docs](https://api-docs.retroachievements.org/v1/get-game.html) \| [example](examples/game/getgame/getgame.go)| |`GetGameExtended()`|Get extended metadata about a game.|[docs](https://api-docs.retroachievements.org/v1/get-game-extended.html) \| [example](examples/game/getgameextended/getgameextended.go)| -|`GetGameHashes()`|Get the hashes linked to a game.|[docs](https://api-docs.retroachievements.org/v1/get-game-hashes.html) \| [example](examples/game/getgamehashes/getgamehashes.go)| \ No newline at end of file +|`GetGameHashes()`|Get the hashes linked to a game.|[docs](https://api-docs.retroachievements.org/v1/get-game-hashes.html) \| [example](examples/game/getgamehashes/getgamehashes.go)| +|`GetAchievementCount()`|Get the list of achievement IDs for a game.|[docs](https://api-docs.retroachievements.org/v1/get-achievement-count.html) \| [example](examples/game/getachievementcount/getachievementcount.go)| \ No newline at end of file diff --git a/examples/game/getachievementcount/getachievementcount.go b/examples/game/getachievementcount/getachievementcount.go new file mode 100644 index 0000000..408ca33 --- /dev/null +++ b/examples/game/getachievementcount/getachievementcount.go @@ -0,0 +1,28 @@ +// Package getachievementcount provides an example for getting the list of achievement IDs for a game. +package main + +import ( + "fmt" + "os" + + "github.com/joshraphael/go-retroachievements" + "github.com/joshraphael/go-retroachievements/models" +) + +/* +Test script, add RA_API_KEY to your env and use `go run getachievementcount.go` +*/ +func main() { + secret := os.Getenv("RA_API_KEY") + + client := retroachievements.NewClient(secret) + + resp, err := client.GetAchievementCount(models.GetAchievementCountParameters{ + GameID: 515, + }) + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", resp) +} diff --git a/game.go b/game.go index 29e788e..03f026e 100644 --- a/game.go +++ b/game.go @@ -65,3 +65,21 @@ func (c *Client) GetGameHashes(params models.GetGameHashesParameters) (*models.G } return resp, nil } + +// GetAchievementCount the list of achievement IDs for a game. +func (c *Client) GetAchievementCount(params models.GetAchievementCountParameters) (*models.GetAchievementCount, error) { + r, err := c.do( + raHttp.Method(http.MethodGet), + raHttp.Path("/API/API_GetAchievementCount.php"), + raHttp.APIToken(c.Secret), + raHttp.IDs([]int{params.GameID}), + ) + if err != nil { + return nil, fmt.Errorf("calling endpoint: %w", err) + } + resp, err := raHttp.ResponseObject[models.GetAchievementCount](r) + if err != nil { + return nil, fmt.Errorf("parsing response object: %w", err) + } + return resp, nil +} diff --git a/game_test.go b/game_test.go index 23e16b9..9d3332c 100644 --- a/game_test.go +++ b/game_test.go @@ -528,3 +528,139 @@ func TestGetGameHashes(tt *testing.T) { }) } } + +func TestGetAchievementCount(tt *testing.T) { + tests := []struct { + name string + params models.GetAchievementCountParameters + modifyURL func(url string) string + responseCode int + responseMessage models.GetAchievementCount + responseError models.ErrorResponse + response func(messageBytes []byte, errorBytes []byte) []byte + assert func(t *testing.T, game *models.GetAchievementCount, err error) + }{ + { + name: "fail to call endpoint", + params: models.GetAchievementCountParameters{ + GameID: 14402, + }, + modifyURL: func(url string) string { + return "" + }, + responseCode: http.StatusOK, + response: func(messageBytes []byte, errorBytes []byte) []byte { + return messageBytes + }, + assert: func(t *testing.T, resp *models.GetAchievementCount, err error) { + require.Nil(t, resp) + require.EqualError(t, err, "calling endpoint: Get \"/API/API_GetAchievementCount.php?i=14402&y=some_secret\": unsupported protocol scheme \"\"") + }, + }, + { + name: "error response", + params: models.GetAchievementCountParameters{ + GameID: 14402, + }, + modifyURL: func(url string) string { + return url + }, + responseCode: http.StatusUnauthorized, + responseError: models.ErrorResponse{ + Message: "test", + Errors: []models.ErrorDetail{ + { + Status: http.StatusUnauthorized, + Code: "unauthorized", + Title: "Not Authorized", + }, + }, + }, + response: func(messageBytes []byte, errorBytes []byte) []byte { + return errorBytes + }, + assert: func(t *testing.T, resp *models.GetAchievementCount, err error) { + require.Nil(t, resp) + require.EqualError(t, err, "parsing response object: error responses: [401] Not Authorized") + }, + }, + { + name: "success", + params: models.GetAchievementCountParameters{ + GameID: 14402, + }, + modifyURL: func(url string) string { + return url + }, + responseCode: http.StatusOK, + responseMessage: models.GetAchievementCount{ + GameID: 14402, + AchievementIDs: []int{ + 79434, + 79435, + 79436, + 79437, + 79438, + 79439, + 79440, + 79441, + 79442, + 79443, + 79444, + 79445, + 325413, + 325414, + 325415, + }, + }, + response: func(messageBytes []byte, errorBytes []byte) []byte { + return messageBytes + }, + assert: func(t *testing.T, resp *models.GetAchievementCount, err error) { + require.NotNil(t, resp) + require.Equal(t, 14402, resp.GameID) + require.Len(t, resp.AchievementIDs, 15) + require.Equal(t, 79434, resp.AchievementIDs[0]) + require.Equal(t, 79435, resp.AchievementIDs[1]) + require.Equal(t, 79436, resp.AchievementIDs[2]) + require.Equal(t, 79437, resp.AchievementIDs[3]) + require.Equal(t, 79438, resp.AchievementIDs[4]) + require.Equal(t, 79439, resp.AchievementIDs[5]) + require.Equal(t, 79440, resp.AchievementIDs[6]) + require.Equal(t, 79441, resp.AchievementIDs[7]) + require.Equal(t, 79442, resp.AchievementIDs[8]) + require.Equal(t, 79443, resp.AchievementIDs[9]) + require.Equal(t, 79444, resp.AchievementIDs[10]) + require.Equal(t, 79445, resp.AchievementIDs[11]) + require.Equal(t, 325413, resp.AchievementIDs[12]) + require.Equal(t, 325414, resp.AchievementIDs[13]) + require.Equal(t, 325415, resp.AchievementIDs[14]) + require.NoError(t, err) + }, + }, + } + for _, test := range tests { + tt.Run(test.name, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + expectedPath := "/API/API_GetAchievementCount.php" + if r.URL.Path != expectedPath { + t.Errorf("Expected to request '%s', got: %s", expectedPath, r.URL.Path) + } + w.WriteHeader(test.responseCode) + messageBytes, err := json.Marshal(test.responseMessage) + require.NoError(t, err) + errBytes, err := json.Marshal(test.responseError) + require.NoError(t, err) + resp := test.response(messageBytes, errBytes) + num, err := w.Write(resp) + require.NoError(t, err) + require.Equal(t, num, len(resp)) + })) + defer server.Close() + + client := retroachievements.New(test.modifyURL(server.URL), "some_secret") + resp, err := client.GetAchievementCount(test.params) + test.assert(t, resp, err) + }) + } +} diff --git a/models/game.go b/models/game.go index 13c795f..b7c68bf 100644 --- a/models/game.go +++ b/models/game.go @@ -107,3 +107,13 @@ type GetGameHashesResult struct { Labels []string `json:"Labels"` PatchUrl *string `json:"PatchUrl"` } + +type GetAchievementCountParameters struct { + // The target game ID + GameID int +} + +type GetAchievementCount struct { + GameID int `json:"GameID"` + AchievementIDs []int `json:"AchievementIDs"` +}