Skip to content

Commit

Permalink
Feature/bosskill (#4)
Browse files Browse the repository at this point in the history
* Add support for GuildBossKill api.

* Update readme to latest version

* Update json formatting on character
  • Loading branch information
tmaffia authored Aug 5, 2024
1 parent 1be1cce commit 3cfca64
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 12 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Wrapper for the raider.io API written in Go

### Include module in your go.mod
```
include github.com/tmaffia/raiderio v0.3.0
include github.com/tmaffia/raiderio v0.3.1
```

### Get a Character Profile
Expand Down
1 change: 1 addition & 0 deletions character.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Character struct {
ActiveRole string `json:"active_spec_role"`
Gender string `json:"gender"`
Faction string `json:"faction"`
Spec string `json:"spec"`
AchievementPoints int64 `json:"achievement_points"`
HonorableKills int64 `json:"honorable_kills"`
ThumbnailUrl string `json:"thumbnail_url"`
Expand Down
30 changes: 28 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (c *Client) GetGuild(ctx context.Context, gq *GuildQuery) (*Guild, error) {
// GetRaids retrieves a list of raids from the Raider.IO API
// It returns an error if the API returns a non-200 status code, or if the
// response body cannot be read or mapped to the Raids struct
// Takes an Expansion enum as a parameter
// Takes an Expansion enum as a parameter, in addition to context.Context
func (c *Client) GetRaids(ctx context.Context, e expansion.Expansion) (*Raids, error) {
reqUrl := c.ApiUrl + "/raiding/static-data?expansion_id=" + fmt.Sprintf("%d", e)
body, err := c.getAPIResponse(ctx, reqUrl)
Expand All @@ -106,7 +106,7 @@ func (c *Client) GetRaids(ctx context.Context, e expansion.Expansion) (*Raids, e
// GetRaidRankings retrieves a list of raid rankings from the Raider.IO API
// It returns an error if the API returns a non-200 status code, or if the
// response body cannot be read or mapped to the RaidRankings struct
// Takes a RaidQuery struct as a parameter
// Takes a RaidQuery struct as a parameter, in addition to context.Context
func (c *Client) GetRaidRankings(ctx context.Context, rq *RaidQuery) (*RaidRankings, error) {
err := validateRaidRankingsQuery(rq)
if err != nil {
Expand Down Expand Up @@ -141,3 +141,29 @@ func (c *Client) GetRaidRankings(ctx context.Context, rq *RaidQuery) (*RaidRanki

return &rankings, nil
}

// GetGuildBossKill returns a guild's first kill of a given boss
// Takes a context.Context object to facilitate timeout, and a GuildBossKillQuery
// GuildBossKillQuery has only required fields for this request
// returns a BossKill object
func (c *Client) GetGuildBossKill(ctx context.Context, q *GuildBossKillQuery) (*BossKill, error) {
err := validateGuildBossKillQuery(q)
if err != nil {
return nil, err
}
reqUrl := c.ApiUrl + "/guilds/boss-kill?raid=" + q.RaidSlug +
"&difficulty=" + string(q.Difficulty) + "&region=" + q.Region.Slug +
"&realm=" + q.Realm + "&guild=" + q.GuildName + "&boss=" + q.BossSlug

body, err := c.getAPIResponse(ctx, reqUrl)
if err != nil {
return nil, err
}

k, err := unmarshalGuildBossKill(body)
if err != nil {
return nil, err
}

return k, nil
}
106 changes: 97 additions & 9 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestGetCharacterProfile(t *testing.T) {
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(defaultCtx, time.Millisecond*10)
ctx, cancel = context.WithTimeout(defaultCtx, time.Millisecond*1)
defer cancel()
}

Expand Down Expand Up @@ -91,7 +91,7 @@ func TestGetCharacterWGear(t *testing.T) {
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*10)
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*1)
defer cancel()
}

Expand Down Expand Up @@ -153,7 +153,7 @@ func TestGetGuild(t *testing.T) {
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*10)
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*1)
defer cancel()
}

Expand Down Expand Up @@ -241,14 +241,15 @@ func TestGetGuildWRaidRankings(t *testing.T) {
{region: region.US, realm: "illidan", name: "warpath",
raidName: "aberrus-the-shadowed-crucible", expectedRank: 158},
{timeout: true, region: region.US, realm: "illidan", name: "warpath",
raidName: "aberrus-the-shadowed-crucible", expectedErrMsg: "raiderio api request timeout"},
raidName: "aberrus-the-shadowed-crucible",
expectedErrMsg: "raiderio api request timeout"},
}

for _, tc := range testCases {
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*10)
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*1)
defer cancel()
}

Expand All @@ -274,12 +275,90 @@ func TestGetGuildWRaidRankings(t *testing.T) {
}
}

func TestGetGuildBossKill(t *testing.T) {
testCases := []struct {
region *region.Region
realm string
guildName string
raidSlug string
bossSlug string
difficulty raiderio.RaidDifficulty
expectedDefeatedAt string
expectedCharacterName string
expectedErrMsg string
timeout bool
}{
{region: region.US, realm: "illidan", guildName: "warpath",
raidSlug: "vault-of-the-incarnates", bossSlug: "terros",
difficulty: raiderio.MythicRaid, expectedCharacterName: "Drbananaphd"},
{region: nil, difficulty: raiderio.MythicRaid, realm: "illidan",
guildName: "warpath", raidSlug: "vault-of-the-incarnates",
bossSlug: "terros", expectedErrMsg: "invalid region"},
{region: region.US, difficulty: raiderio.MythicRaid,
realm: "invalid-realm", guildName: "warpath", raidSlug: "vault-of-the-incarnates",
bossSlug: "terros", expectedErrMsg: "invalid realm"},
{region: region.US, difficulty: raiderio.MythicRaid,
guildName: "warpath", raidSlug: "vault-of-the-incarnates",
bossSlug: "terros", expectedErrMsg: "invalid realm"},
{region: region.US, difficulty: raiderio.MythicRaid, realm: "illidan",
guildName: "impossible-guild_name", raidSlug: "vault-of-the-incarnates",
bossSlug: "terros", expectedErrMsg: "guild not found"},
{region: region.US, difficulty: raiderio.MythicRaid, realm: "illidan",
raidSlug: "vault-of-the-incarnates", bossSlug: "terros",
expectedErrMsg: "invalid guild name"},
{region: region.US, difficulty: raiderio.MythicRaid, realm: "illidan",
guildName: "warpath", raidSlug: "invalid-raid-slug", bossSlug: "terros",
expectedErrMsg: "invalid raid"},
{region: region.US, difficulty: raiderio.MythicRaid, realm: "illidan",
guildName: "warpath", bossSlug: "terros",
expectedErrMsg: "invalid raid name"},
{region: region.US, difficulty: raiderio.MythicRaid, realm: "illidan",
guildName: "warpath", raidSlug: "vault-of-the-incarnates",
bossSlug: "invalid-boss-slug", expectedErrMsg: "invalid boss"},
{region: region.US, difficulty: raiderio.MythicRaid, realm: "illidan",
guildName: "warpath", raidSlug: "vault-of-the-incarnates",
expectedErrMsg: "invalid boss"},
{region: region.US, realm: "illidan", guildName: "warpath",
raidSlug: "vault-of-the-incarnates", bossSlug: "terros",
expectedErrMsg: "invalid raid difficulty"},
{timeout: true, region: region.US, realm: "illidan", guildName: "warpath",
raidSlug: "vault-of-the-incarnates", bossSlug: "terros",
difficulty: raiderio.MythicRaid,
expectedErrMsg: "raiderio api request timeout"},
}

for _, tc := range testCases {
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*1)
defer cancel()
}

k, err := c.GetGuildBossKill(ctx, &raiderio.GuildBossKillQuery{
Region: tc.region,
Realm: tc.realm,
GuildName: tc.guildName,
RaidSlug: tc.raidSlug,
BossSlug: tc.bossSlug,
Difficulty: tc.difficulty,
})

if err != nil && err.Error() != tc.expectedErrMsg {
t.Fatalf("error message got: %v, expected: %v", err.Error(), tc.expectedErrMsg)
}

if err == nil && !killIncludesCharacter(k, tc.expectedCharacterName) {
t.Fatalf("boss kill character name expected: %v", tc.expectedCharacterName)
}
}
}

func TestGetRaids(t *testing.T) {
testCases := []struct {
timeout bool
expansion expansion.Expansion
raidName string
raidDifficulty string
expectedRaidName string
expectedErrMsg string
}{
Expand All @@ -292,7 +371,7 @@ func TestGetRaids(t *testing.T) {
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*10)
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*1)
defer cancel()
}

Expand All @@ -312,7 +391,6 @@ func TestGetRaids(t *testing.T) {
}

func TestGetRaidRankings(t *testing.T) {
c := raiderio.NewClient()
testCases := []struct {
timeout bool
slug string
Expand Down Expand Up @@ -344,7 +422,7 @@ func TestGetRaidRankings(t *testing.T) {
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*10)
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*1)
defer cancel()
}

Expand Down Expand Up @@ -372,3 +450,13 @@ func TestGetRaidRankings(t *testing.T) {
}
}
}

// Tests if character is a part of the particular boss kill
func killIncludesCharacter(k *raiderio.BossKill, c string) bool {
for _, v := range k.Roster {
if v.Name == c {
return true
}
}
return false
}
10 changes: 10 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ var (
ErrUnsupportedExpac = errors.New("unsupported expansion")
ErrLimitOutOfBounds = errors.New("limit must be a positive int")
ErrPageOutOfBounds = errors.New("page must be a positive int")
ErrInvalidBoss = errors.New("invalid boss")
ErrInvalidQuery = errors.New("invalid query")
ErrApiTimeout = errors.New("raiderio api request timeout")
ErrUnexpected = errors.New("unexpected error")
)
Expand All @@ -34,6 +36,14 @@ func wrapApiError(responseBody *apiErrorResponse) error {
return ErrInvalidRealm
}

if strings.Contains(responseBody.Message, "Failed to find raid") {
return ErrInvalidRaid
}

if strings.Contains(responseBody.Message, "Failed to find boss") {
return ErrInvalidBoss
}

if strings.Contains(responseBody.Message, "Could not find requested character") {
return ErrCharacterNotFound
}
Expand Down
Loading

0 comments on commit 3cfca64

Please sign in to comment.