diff --git a/README.md b/README.md index 1072277..38d0ca9 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ For convenience, the API docs and examples can be found in the tables below |`GetUserPoints()`|Get a user's total hardcore and softcore points.|[docs](https://api-docs.retroachievements.org/v1/get-user-points.html) \| [example](examples/user/getuserpoints/getuserpoints.go)| |`GetUserProgress()`|Get a user's progress on a list of specified games.|[docs](https://api-docs.retroachievements.org/v1/get-user-progress.html) \| [example](examples/user/getuserprogress/getuserprogress.go)| |`GetUserRecentlyPlayedGames()`|Get a list of games a user has recently played.|[docs](https://api-docs.retroachievements.org/v1/get-user-recently-played-games.html) \| [example](examples/user/getuserrecentlyplayedgames/getuserrecentlyplayedgames.go)| +|`GetUserSummary()`|Get a user's profile metadata.|[docs](https://api-docs.retroachievements.org/v1/get-user-summary.html) \| [example](examples/user/getusersummary/getusersummary.go)|

Game

diff --git a/examples/user/getusersummary/getusersummary.go b/examples/user/getusersummary/getusersummary.go new file mode 100644 index 0000000..49cece9 --- /dev/null +++ b/examples/user/getusersummary/getusersummary.go @@ -0,0 +1,32 @@ +// Package getusersummary provides an example for a users summary info +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 getusersummary.go` +*/ +func main() { + secret := os.Getenv("RA_API_KEY") + + client := retroachievements.NewClient(secret) + + games := 10 + achievements := 10 + resp, err := client.GetUserSummary(models.GetUserSummaryParameters{ + Username: "jamiras", + GamesCount: &games, + AchievementsCount: &achievements, + }) + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", resp) +} diff --git a/http/request.go b/http/request.go index 3489d92..7118e5d 100644 --- a/http/request.go +++ b/http/request.go @@ -99,10 +99,10 @@ func IDs(ids []int) RequestDetail { }) } -// GameID adds a target game id to the query parameters -func GameID(gameId int) RequestDetail { +// Game adds a target game id to the query parameters +func Game(game int) RequestDetail { return requestDetailFn(func(r *Request) { - r.Params["g"] = strconv.Itoa(gameId) + r.Params["g"] = strconv.Itoa(game) }) } @@ -120,14 +120,14 @@ func Offset(offset int) RequestDetail { }) } -// AwardMetadata adds a target game id to the query parameters -func AwardMetadata(awardMetadata bool) RequestDetail { +// Achievement adds a achievement number query parameter +func Achievement(achievement int) RequestDetail { return requestDetailFn(func(r *Request) { - a := "0" - if awardMetadata { - a = "1" - } - r.Params["a"] = a + // a := "0" + // if awardMetadata { + // a = "1" + // } + r.Params["a"] = strconv.Itoa(achievement) }) } diff --git a/http/request_test.go b/http/request_test.go index 6ed30f5..350ca2a 100644 --- a/http/request_test.go +++ b/http/request_test.go @@ -25,8 +25,8 @@ func TestNewRequest(t *testing.T) { raHttp.To(later.Unix()), raHttp.Date(now), raHttp.IDs([]int{2837, 4535}), - raHttp.GameID(345), - raHttp.AwardMetadata(true), + raHttp.Game(345), + raHttp.Achievement(1), raHttp.Count(20), raHttp.Offset(34), ) diff --git a/models/achievements.go b/models/achievements.go deleted file mode 100644 index f716985..0000000 --- a/models/achievements.go +++ /dev/null @@ -1,71 +0,0 @@ -package models - -// UnlockedAchievement is a representation of achievements unlocked by a user -type UnlockedAchievement struct { - Achievement - // The date the achievement was unlocked - Date DateTime `json:"Date"` - - // Mode the achievement was unlocked in: 1 if in hardcore mode, 0 if not - HardcoreMode int `json:"HardcoreMode"` - - // The ID of the achievement - AchievementID int `json:"AchievementID"` - - // Name of the padge resource - BadgeName string `json:"BadgeName"` - - // Type of achievement (standard, missable, progression, win_condition) - Type string `json:"Type"` - - // Title of the game - GameTitle string `json:"GameTitle"` - - // URL resource of the game icon - GameIcon string `json:"GameIcon"` - - // ID of the game - GameID int `json:"GameID"` - - // Common name of the console - ConsoleName string `json:"ConsoleName"` - - // URL resource to the image used for the achievment badge - BadgeURL string `json:"BadgeURL"` - - // URL resource to the game page - GameURL string `json:"GameURL"` -} - -// GameAchievement is a representation of an achievement in a game -type GameAchievement struct { - Achievement - ID int `json:"ID"` - NumAwarded int `json:"NumAwarded"` - NumAwardedHardcore int `json:"NumAwardedHardcore"` - DateModified DateTime `json:"DateModified"` - DateCreated DateTime `json:"DateCreated"` - BadgeName string `json:"BadgeName"` - DisplayOrder int `json:"DisplayOrder"` - MemAddr string `json:"MemAddr"` - Type string `json:"type"` - DateEarnedHardcore *DateTime `json:"DateEarnedHardcore"` - DateEarned *DateTime `json:"DateEarned"` -} - -// Achievement is a common representation of an achievement -type Achievement struct { - // Title of the achievement - Title string `json:"Title"` - - // Description of the achievement - Description string `json:"Description"` - // Points awarded - Points int `json:"Points"` - - // Ratio of points the achievemnet is worth - TrueRatio int `json:"TrueRatio"` - - // Username of the author of the achievement - Author string `json:"Author"` -} diff --git a/models/awards.go b/models/awards.go deleted file mode 100644 index b58b59f..0000000 --- a/models/awards.go +++ /dev/null @@ -1,13 +0,0 @@ -package models - -type UserAwards struct { - TotalAwardsCount int `json:"TotalAwardsCount"` - HiddenAwardsCount int `json:"HiddenAwardsCount"` - MasteryAwardsCount int `json:"MasteryAwardsCount"` - CompletionAwardsCount int `json:"CompletionAwardsCount"` - BeatenHardcoreAwardsCount int `json:"BeatenHardcoreAwardsCount"` - BeatenSoftcoreAwardsCount int `json:"BeatenSoftcoreAwardsCount"` - EventAwardsCount int `json:"EventAwardsCount"` - SiteAwardsCount int `json:"SiteAwardsCount"` - VisibleUserAwards []Award `json:"VisibleUserAwards"` -} diff --git a/models/claims.go b/models/claims.go deleted file mode 100644 index 2579efe..0000000 --- a/models/claims.go +++ /dev/null @@ -1,10 +0,0 @@ -package models - -type Claim struct { - User string `json:"User"` - SetType int `json:"SetType"` - GameID int `json:"GameID"` - ClaimType int `json:"ClaimType"` - Created DateTime `json:"Created"` - Expiration DateTime `json:"Expiration"` -} diff --git a/models/old_game.go b/models/old_game.go deleted file mode 100644 index 2c48765..0000000 --- a/models/old_game.go +++ /dev/null @@ -1,58 +0,0 @@ -package models - -import "time" - -type Game struct { - Title string `json:"Title"` - ConsoleID int `json:"ConsoleID"` - ForumTopicID *int `json:"ForumTopicID"` - Flags *int `json:"Flags"` - ImageIcon string `json:"ImageIcon"` - ImageTitle string `json:"ImageTitle"` - ImageIngame string `json:"ImageIngame"` - ImageBoxArt string `json:"ImageBoxArt"` - Publisher string `json:"Publisher"` - Developer string `json:"Developer"` - Genre string `json:"Genre"` - Released LongMonthDate `json:"Released"` -} - -type GameInfo struct { - Game - GameTitle string `json:"GameTitle"` - ConsoleName string `json:"ConsoleName"` - Console string `json:"Console"` - GameIcon string `json:"GameIcon"` -} - -type ExtentedGameInfo struct { - Game - ID int `json:"ID"` - IsFinal int `json:"IsFinal"` - RichPresencePatch string `json:"RichPresencePatch"` - GuideURL *string `json:"GuideURL"` - Updated *time.Time `json:"Updated,omitempty"` - ConsoleName string `json:"ConsoleName"` - ParentGameID *int `json:"ParentGameID"` - NumDistinctPlayers int `json:"NumDistinctPlayers"` - NumAchievements int `json:"NumAchievements"` - Achievements map[int]GameAchievement `json:"Achievements"` - Claims []Claim `json:"Claims,omitempty"` - NumDistinctPlayersCasual int `json:"NumDistinctPlayersCasual"` - NumDistinctPlayersHardcore int `json:"NumDistinctPlayersHardcore"` -} - -type UserGameProgress struct { - ExtentedGameInfo - ReleasedAt *time.Time `json:"released_at"` - ReleasedAtGranularity *string `json:"released_at_granularity"` - PlayersTotal int `json:"players_total"` - AchievementsPublished int `json:"achievements_published"` - PointsTotal int `json:"points_total"` - NumAwardedToUser int `json:"NumAwardedToUser"` - NumAwardedToUserHardcore int `json:"NumAwardedToUserHardcore"` - UserCompletion string `json:"UserCompletion"` - UserCompletionHardcore string `json:"UserCompletionHardcore"` - HighestAwardKind *string `json:"HighestAwardKind"` - HighestAwardDate *RFC3339NumColonTZ `json:"HighestAwardDate"` -} diff --git a/models/profile.go b/models/profile.go deleted file mode 100644 index d9574be..0000000 --- a/models/profile.go +++ /dev/null @@ -1,20 +0,0 @@ -package models - -// Profile describes elements of a users profile -type Profile struct { - User string `json:"User"` - UserPic string `json:"UserPic"` - MemberSince DateTime `json:"MemberSince"` - RichPresenceMsg string `json:"RichPresenceMsg"` - LastGameID int `json:"LastGameID"` - ContribCount int `json:"ContribCount"` - ContribYield int `json:"ContribYield"` - TotalPoints int `json:"TotalPoints"` - TotalSoftcorePoints int `json:"TotalSoftcorePoints"` - TotalTruePoints int `json:"TotalTruePoints"` - Permissions int `json:"Permissions"` - Untracked int `json:"Untracked"` - ID int `json:"ID"` - UserWallActive bool `json:"UserWallActive"` - Motto string `json:"Motto"` -} diff --git a/models/user.go b/models/user.go index bd5850d..9249e21 100644 --- a/models/user.go +++ b/models/user.go @@ -465,3 +465,100 @@ type GetUserRecentlyPlayedGames struct { LastPlayed DateTime `json:"LastPlayed"` AchievementsTotal int `json:"AchievementsTotal"` } + +type GetUserSummaryParameters struct { + // The target username + Username string + + // [Optional] The number of recent games to return (default: 0). + GamesCount *int + + // [Optional] The number of recent achievements to return (default: 10) + AchievementsCount *int +} + +type GetUserSummary struct { + User string `json:"User"` + UserPic string `json:"UserPic"` + TotalRanked int `json:"TotalRanked"` + Status string `json:"Status"` + RichPresenceMsg string `json:"RichPresenceMsg"` + LastGameID int `json:"LastGameID"` + ContribCount int `json:"ContribCount"` + ContribYield int `json:"ContribYield"` + TotalPoints int `json:"TotalPoints"` + TotalSoftcorePoints int `json:"TotalSoftcorePoints"` + TotalTruePoints int `json:"TotalTruePoints"` + Permissions int `json:"Permissions"` + Untracked int `json:"Untracked"` + ID int `json:"ID"` + UserWallActive int `json:"UserWallActive"` + Motto string `json:"Motto"` + RecentlyPlayedCount int `json:"RecentlyPlayedCount"` + Rank *int `json:"Rank"` + MemberSince DateTime `json:"MemberSince"` + LastActivity GetUserSummaryLastActivity `json:"LastActivity"` + RecentlyPlayed []GetUserSummaryRecentlyPlayed `json:"RecentlyPlayed"` + Awarded map[string]GetUserSummaryAwarded `json:"Awarded"` + RecentAchievements map[string]map[string]GetUserSummaryRecentAchievements `json:"RecentAchievements"` + LastGame GetUserSummaryLastGame `json:"LastGame"` +} + +type GetUserSummaryLastActivity struct { + ID int `json:"ID"` + User string `json:"User"` +} + +type GetUserSummaryRecentlyPlayed struct { + GameID int `json:"GameID"` + ConsoleID int `json:"ConsoleID"` + ConsoleName string `json:"ConsoleName"` + Title string `json:"Title"` + ImageIcon string `json:"ImageIcon"` + ImageTitle string `json:"ImageTitle"` + ImageIngame string `json:"ImageIngame"` + ImageBoxArt string `json:"ImageBoxArt"` + LastPlayed DateTime `json:"LastPlayed"` + AchievementsTotal int `json:"AchievementsTotal"` +} + +type GetUserSummaryAwarded struct { + NumPossibleAchievements int `json:"NumPossibleAchievements"` + PossibleScore int `json:"PossibleScore"` + NumAchieved int `json:"NumAchieved"` + ScoreAchieved int `json:"ScoreAchieved"` + NumAchievedHardcore int `json:"NumAchievedHardcore"` + ScoreAchievedHardcore int `json:"ScoreAchievedHardcore"` +} + +type GetUserSummaryRecentAchievements struct { + ID int `json:"ID"` + GameID int `json:"GameID"` + GameTitle string `json:"GameTitle"` + Title string `json:"Title"` + Description string `json:"Description"` + Points int `json:"Points"` + Type *string `json:"Type"` + BadgeName string `json:"BadgeName"` + IsAwarded string `json:"IsAwarded"` + DateAwarded DateTime `json:"DateAwarded"` + HardcoreAchieved int `json:"HardcoreAchieved"` +} + +type GetUserSummaryLastGame struct { + ID int `json:"ID"` + Title string `json:"Title"` + ConsoleID int `json:"ConsoleID"` + ConsoleName string `json:"ConsoleName"` + ForumTopicID int `json:"ForumTopicID"` + Flags int `json:"Flags"` + ImageIcon string `json:"ImageIcon"` + ImageTitle string `json:"ImageTitle"` + ImageIngame string `json:"ImageIngame"` + ImageBoxArt string `json:"ImageBoxArt"` + Publisher string `json:"Publisher"` + Developer string `json:"Developer"` + Genre string `json:"Genre"` + Released LongMonthDate `json:"Released"` + IsFinal int `json:"IsFinal"` +} diff --git a/user.go b/user.go index b35768b..a5de24e 100644 --- a/user.go +++ b/user.go @@ -94,10 +94,10 @@ func (c *Client) GetGameInfoAndUserProgress(params models.GetGameInfoAndUserProg raHttp.Path("/API/API_GetGameInfoAndUserProgress.php"), raHttp.APIToken(c.Secret), raHttp.Username(params.Username), - raHttp.GameID(params.GameID), + raHttp.Game(params.GameID), } - if params.IncludeAwardMetadata != nil { - details = append(details, raHttp.AwardMetadata(*params.IncludeAwardMetadata)) + if params.IncludeAwardMetadata != nil && *params.IncludeAwardMetadata { + details = append(details, raHttp.Achievement(1)) } resp, err := c.do(details...) if err != nil { @@ -171,7 +171,7 @@ func (c *Client) GetUserGameRankAndScore(params models.GetUserGameRankAndScorePa raHttp.Path("/API/API_GetUserGameRankAndScore.php"), raHttp.APIToken(c.Secret), raHttp.Username(params.Username), - raHttp.GameID(params.GameID), + raHttp.Game(params.GameID), ) if err != nil { return nil, fmt.Errorf("calling endpoint: %w", err) @@ -244,3 +244,28 @@ func (c *Client) GetUserRecentlyPlayedGames(params models.GetUserRecentlyPlayedG } return recentlyPlayed, nil } + +// GetUserSummary get summary information about a given user. +func (c *Client) GetUserSummary(params models.GetUserSummaryParameters) (*models.GetUserSummary, error) { + details := []raHttp.RequestDetail{ + raHttp.Method(http.MethodGet), + raHttp.Path("/API/API_GetUserSummary.php"), + raHttp.APIToken(c.Secret), + raHttp.Username(params.Username), + } + if params.GamesCount != nil { + details = append(details, raHttp.Game(*params.GamesCount)) + } + if params.AchievementsCount != nil { + details = append(details, raHttp.Achievement(*params.AchievementsCount)) + } + resp, err := c.do(details...) + if err != nil { + return nil, fmt.Errorf("calling endpoint: %w", err) + } + recentlyPlayed, err := raHttp.ResponseObject[models.GetUserSummary](resp) + if err != nil { + return nil, fmt.Errorf("parsing response object: %w", err) + } + return recentlyPlayed, nil +} diff --git a/user_test.go b/user_test.go index aea0167..77f095a 100644 --- a/user_test.go +++ b/user_test.go @@ -1023,7 +1023,7 @@ func TestGetUserAwards(tt *testing.T) { params models.GetUserAwardsParameters modifyURL func(url string) string responseCode int - responseMessage models.UserAwards + responseMessage models.GetUserAwards responseError models.ErrorResponse response func(messageBytes []byte, errorBytes []byte) []byte assert func(t *testing.T, userAwards *models.GetUserAwards, err error) @@ -1091,7 +1091,7 @@ func TestGetUserAwards(tt *testing.T) { return url }, responseCode: http.StatusOK, - responseMessage: models.UserAwards{ + responseMessage: models.GetUserAwards{ TotalAwardsCount: 9, HiddenAwardsCount: 0, MasteryAwardsCount: 4, @@ -1932,3 +1932,291 @@ func TestGetUserRecentlyPlayedGames(tt *testing.T) { }) } } + +func TestGetUserSummary(tt *testing.T) { + gameCount := 10 + achievementCount := 5 + rank := 130 + memberSince, err := time.Parse(time.DateTime, "2017-06-18 18:49:00") + require.NoError(tt, err) + lastPlayed, err := time.Parse(time.DateTime, "2024-11-17 04:00:35") + require.NoError(tt, err) + releaseDate, err := time.Parse(models.LongMonthDateFormat, "September 27, 2011") + require.NoError(tt, err) + cheevoType := "progression" + tests := []struct { + name string + params models.GetUserSummaryParameters + modifyURL func(url string) string + responseCode int + responseMessage models.GetUserSummary + responseError models.ErrorResponse + response func(messageBytes []byte, errorBytes []byte) []byte + assert func(t *testing.T, resp *models.GetUserSummary, err error) + }{ + { + name: "fail to call endpoint", + params: models.GetUserSummaryParameters{ + Username: "Test", + GamesCount: &gameCount, + AchievementsCount: &achievementCount, + }, + modifyURL: func(url string) string { + return "" + }, + 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.GetUserSummary, err error) { + require.Nil(t, resp) + require.EqualError(t, err, "calling endpoint: Get \"/API/API_GetUserSummary.php?a=5&g=10&u=Test&y=some_secret\": unsupported protocol scheme \"\"") + }, + }, + { + name: "error response", + params: models.GetUserSummaryParameters{ + Username: "Test", + GamesCount: &gameCount, + AchievementsCount: &achievementCount, + }, + 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.GetUserSummary, err error) { + require.Nil(t, resp) + require.EqualError(t, err, "parsing response object: error responses: [401] Not Authorized") + }, + }, + { + name: "success", + params: models.GetUserSummaryParameters{ + Username: "Test", + GamesCount: &gameCount, + AchievementsCount: &achievementCount, + }, + modifyURL: func(url string) string { + return url + }, + responseCode: http.StatusOK, + responseMessage: models.GetUserSummary{ + User: "Jamiras", + RichPresenceMsg: "In Chapter 3: The Paladin Clan • 3h13 • Level 5 • 3 • 4918 Rings • 12/83", + LastGameID: 9404, + ContribCount: 179822, + ContribYield: 1208742, + TotalPoints: 116649, + TotalSoftcorePoints: 1350, + TotalTruePoints: 322472, + Permissions: 4, + Untracked: 0, + ID: 43495, + UserWallActive: 0, + Motto: "", + RecentlyPlayedCount: 1, + UserPic: "/UserPic/jamiras.png", + TotalRanked: 78332, + Status: "Offline", + Rank: &rank, + MemberSince: models.DateTime{ + Time: memberSince, + }, + LastActivity: models.GetUserSummaryLastActivity{ + ID: 0, + User: "jamiras", + }, + RecentlyPlayed: []models.GetUserSummaryRecentlyPlayed{ + { + GameID: 9404, + ConsoleID: 18, + ConsoleName: "Nintendo DS", + Title: "Solatorobo: Red the Hunter", + ImageIcon: "/Images/088320.png", + ImageTitle: "/Images/073286.png", + ImageIngame: "/Images/073287.png", + ImageBoxArt: "/Images/028653.png", + LastPlayed: models.DateTime{ + Time: lastPlayed, + }, + AchievementsTotal: 133, + }, + }, + Awarded: map[string]models.GetUserSummaryAwarded{ + "9404": { + NumPossibleAchievements: 133, + PossibleScore: 935, + NumAchieved: 16, + ScoreAchieved: 95, + NumAchievedHardcore: 16, + ScoreAchievedHardcore: 95, + }, + }, + RecentAchievements: map[string]map[string]models.GetUserSummaryRecentAchievements{ + "9404": { + "328833": { + ID: 328833, + GameID: 9404, + GameTitle: "Solatorobo: Red the Hunter", + Title: "Chapter 3: The Paladin Clan", + Description: "Complete the Chapter 3", + Points: 10, + Type: &cheevoType, + BadgeName: "368292", + IsAwarded: "1", + DateAwarded: models.DateTime{ + Time: lastPlayed, + }, + HardcoreAchieved: 1, + }, + }, + }, + LastGame: models.GetUserSummaryLastGame{ + ID: 9404, + Title: "Solatorobo: Red the Hunter", + ConsoleID: 18, + ConsoleName: "Nintendo DS", + ForumTopicID: 21569, + Flags: 0, + ImageIcon: "/Images/088320.png", + ImageTitle: "/Images/073286.png", + ImageIngame: "/Images/073287.png", + ImageBoxArt: "/Images/028653.png", + Publisher: "XSEED Games", + Developer: "CyberConnect2 | CyberConnect", + Genre: "Action RPG", + Released: models.LongMonthDate{ + Time: releaseDate, + }, + IsFinal: 0, + }, + }, + response: func(messageBytes []byte, errorBytes []byte) []byte { + return messageBytes + }, + assert: func(t *testing.T, resp *models.GetUserSummary, err error) { + require.NoError(t, err) + require.Equal(t, "Jamiras", resp.User) + require.Equal(t, "In Chapter 3: The Paladin Clan • 3h13 • Level 5 • 3 • 4918 Rings • 12/83", resp.RichPresenceMsg) + require.Equal(t, 9404, resp.LastGameID) + require.Equal(t, 179822, resp.ContribCount) + require.Equal(t, 1208742, resp.ContribYield) + require.Equal(t, 116649, resp.TotalPoints) + require.Equal(t, 1350, resp.TotalSoftcorePoints) + require.Equal(t, 322472, resp.TotalTruePoints) + require.Equal(t, 4, resp.Permissions) + require.Equal(t, 0, resp.Untracked) + require.Equal(t, 43495, resp.ID) + require.Equal(t, 0, resp.UserWallActive) + require.Equal(t, "", resp.Motto) + require.Equal(t, 1, resp.RecentlyPlayedCount) + require.Equal(t, "/UserPic/jamiras.png", resp.UserPic) + require.Equal(t, 78332, resp.TotalRanked) + require.Equal(t, "Offline", resp.Status) + require.NotNil(t, resp.Rank) + require.Equal(t, 130, *resp.Rank) + require.Equal(t, memberSince, resp.MemberSince.Time) + require.Equal(t, 0, resp.LastActivity.ID) + require.Equal(t, "jamiras", resp.LastActivity.User) + require.Len(t, resp.RecentlyPlayed, 1) + require.Equal(t, 9404, resp.RecentlyPlayed[0].GameID) + require.Equal(t, 18, resp.RecentlyPlayed[0].ConsoleID) + require.Equal(t, "Nintendo DS", resp.RecentlyPlayed[0].ConsoleName) + require.Equal(t, "Solatorobo: Red the Hunter", resp.RecentlyPlayed[0].Title) + require.Equal(t, "/Images/088320.png", resp.RecentlyPlayed[0].ImageIcon) + require.Equal(t, "/Images/073286.png", resp.RecentlyPlayed[0].ImageTitle) + require.Equal(t, "/Images/073287.png", resp.RecentlyPlayed[0].ImageIngame) + require.Equal(t, "/Images/028653.png", resp.RecentlyPlayed[0].ImageBoxArt) + require.Equal(t, 133, resp.RecentlyPlayed[0].AchievementsTotal) + require.Len(t, resp.Awarded, 1) + award, ok := resp.Awarded["9404"] + require.True(t, ok) + require.Equal(t, 133, award.NumPossibleAchievements) + require.Equal(t, 935, award.PossibleScore) + require.Equal(t, 16, award.NumAchieved) + require.Equal(t, 95, award.ScoreAchieved) + require.Equal(t, 16, award.NumAchievedHardcore) + require.Equal(t, 95, award.ScoreAchievedHardcore) + require.Len(t, resp.RecentAchievements, 1) + recent, ok := resp.RecentAchievements["9404"] + require.True(t, ok) + require.Len(t, recent, 1) + cheevo, ok := recent["328833"] + require.True(t, ok) + require.Equal(t, 328833, cheevo.ID) + require.Equal(t, 9404, cheevo.GameID) + require.Equal(t, "Solatorobo: Red the Hunter", cheevo.GameTitle) + require.Equal(t, "Chapter 3: The Paladin Clan", cheevo.Title) + require.Equal(t, "Complete the Chapter 3", cheevo.Description) + require.Equal(t, 10, cheevo.Points) + require.Equal(t, "368292", cheevo.BadgeName) + require.Equal(t, "1", cheevo.IsAwarded) + require.Equal(t, 1, cheevo.HardcoreAchieved) + require.NotNil(t, cheevo.Type) + require.Equal(t, cheevoType, *cheevo.Type) + require.Equal(t, lastPlayed, cheevo.DateAwarded.Time) + require.Equal(t, 9404, resp.LastGame.ID) + require.Equal(t, "Solatorobo: Red the Hunter", resp.LastGame.Title) + require.Equal(t, 18, resp.LastGame.ConsoleID) + require.Equal(t, "Nintendo DS", resp.LastGame.ConsoleName) + require.Equal(t, 21569, resp.LastGame.ForumTopicID) + require.Equal(t, 0, resp.LastGame.Flags) + require.Equal(t, "/Images/088320.png", resp.LastGame.ImageIcon) + require.Equal(t, "/Images/073286.png", resp.LastGame.ImageTitle) + require.Equal(t, "/Images/073287.png", resp.LastGame.ImageIngame) + require.Equal(t, "/Images/028653.png", resp.LastGame.ImageBoxArt) + require.Equal(t, "XSEED Games", resp.LastGame.Publisher) + require.Equal(t, "CyberConnect2 | CyberConnect", resp.LastGame.Developer) + require.Equal(t, "Action RPG", resp.LastGame.Genre) + require.Equal(t, releaseDate, resp.LastGame.Released.Time) + require.Equal(t, 0, resp.LastGame.IsFinal) + }, + }, + } + 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_GetUserSummary.php" + if r.URL.Path != expectedPath { + t.Errorf("Expected to request '%s', got: %s", expectedPath, r.URL.Path) + } + w.WriteHeader(test.responseCode) + responseMessage, err := json.Marshal(test.responseMessage) + require.NoError(t, err) + errBytes, err := json.Marshal(test.responseError) + require.NoError(t, err) + resp := test.response(responseMessage, 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.GetUserSummary(test.params) + test.assert(t, resp, err) + }) + } +}