Skip to content

Commit

Permalink
Add PulseURL functions and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Henry-Sarabia committed Mar 1, 2019
1 parent fabe4df commit 73fd22d
Show file tree
Hide file tree
Showing 5 changed files with 359 additions and 0 deletions.
2 changes: 2 additions & 0 deletions igdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ type Client struct {
Pulses *PulseService
PulseGroups *PulseGroupService
PulseSources *PulseSourceService
PulseURLs *PulseURLService
ReleaseDates *ReleaseDateService
Screenshots *ScreenshotService
Themes *ThemeService
Expand Down Expand Up @@ -158,6 +159,7 @@ func NewClient(apiKey string, custom *http.Client) *Client {
c.Pulses = &PulseService{client: c, end: EndpointPulse}
c.PulseGroups = &PulseGroupService{client: c, end: EndpointPulseGroup}
c.PulseSources = &PulseSourceService{client: c, end: EndpointPulseSource}
c.PulseURLs = &PulseURLService{client: c, end: EndpointPulseURL}
c.ReleaseDates = &ReleaseDateService{client: c, end: EndpointReleaseDate}
c.Screenshots = &ScreenshotService{client: c, end: EndpointScreenshot}
c.Themes = &ThemeService{client: c, end: EndpointTheme}
Expand Down
118 changes: 118 additions & 0 deletions pulseurl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package igdb

import (
"github.com/Henry-Sarabia/sliceconv"
"github.com/pkg/errors"
"strconv"
)

//go:generate gomodifytags -file $GOFILE -struct PulseURL -add-tags json -w

// PulseURL represents a URL linking to an article.
// For more information visit: https://api-docs.igdb.com/#pulse-url
type PulseURL struct {
ID int `json:"id"`
Trusted bool `json:"trusted"`
URL string `json:"url"`
}

// PulseURLService handles all the API
// calls for the IGDB PulseURL endpoint.
type PulseURLService service

// Get returns a single PulseURL identified by the provided IGDB ID. Provide
// the SetFields functional option if you need to specify which fields to
// retrieve. If the ID does not match any PulseURLs, an error is returned.
func (ps *PulseURLService) Get(id int, opts ...Option) (*PulseURL, error) {
if id < 0 {
return nil, ErrNegativeID
}

var URL []*PulseURL

opts = append(opts, SetFilter("id", OpEquals, strconv.Itoa(id)))
err := ps.client.get(ps.end, &URL, opts...)
if err != nil {
return nil, errors.Wrapf(err, "cannot get PulseURL with ID %v", id)
}

return URL[0], nil
}

// List returns a list of PulseURLs identified by the provided list of IGDB IDs.
// Provide functional options to sort, filter, and paginate the results.
// Any ID that does not match a PulseURL is ignored. If none of the IDs
// match a PulseURL, an error is returned.
func (ps *PulseURLService) List(ids []int, opts ...Option) ([]*PulseURL, error) {
for len(ids) < 1 {
return nil, ErrEmptyIDs
}

for _, id := range ids {
if id < 0 {
return nil, ErrNegativeID
}
}

var URL []*PulseURL

opts = append(opts, SetFilter("id", OpContainsAtLeast, sliceconv.Itoa(ids)...))
err := ps.client.get(ps.end, &URL, opts...)
if err != nil {
return nil, errors.Wrapf(err, "cannot get PulseURLs with IDs %v", ids)
}

return URL, nil
}

// Index returns an index of PulseURLs based solely on the provided functional
// options used to sort, filter, and paginate the results. If no PulseURLs can
// be found using the provided options, an error is returned.
func (ps *PulseURLService) Index(opts ...Option) ([]*PulseURL, error) {
var URL []*PulseURL

err := ps.client.get(ps.end, &URL, opts...)
if err != nil {
return nil, errors.Wrap(err, "cannot get index of PulseURLs")
}

return URL, nil
}

// Search returns a list of PulseURLs found by searching the IGDB using the provided
// query. Provide functional options to sort, filter, and paginate the results. If
// no PulseURLs are found using the provided query, an error is returned.
func (ps *PulseURLService) Search(qry string, opts ...Option) ([]*PulseURL, error) {
var URL []*PulseURL

opts = append(opts, setSearch(qry))
err := ps.client.get(ps.end, &URL, opts...)
if err != nil {
return nil, errors.Wrapf(err, "cannot get PulseURL with query %s", qry)
}

return URL, nil
}

// Count returns the number of PulseURLs available in the IGDB.
// Provide the SetFilter functional option if you need to filter
// which PulseURLs to count.
func (ps *PulseURLService) Count(opts ...Option) (int, error) {
ct, err := ps.client.getCount(ps.end, opts...)
if err != nil {
return 0, errors.Wrap(err, "cannot count PulseURLs")
}

return ct, nil
}

// Fields returns the up-to-date list of fields in an
// IGDB PulseURL object.
func (ps *PulseURLService) Fields() ([]string, error) {
f, err := ps.client.getFields(ps.end)
if err != nil {
return nil, errors.Wrap(err, "cannot get PulseURL fields")
}

return f, nil
}
205 changes: 205 additions & 0 deletions pulseurl_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package igdb

import (
"encoding/json"
"github.com/pkg/errors"
"io/ioutil"
"net/http"
"reflect"
"testing"
)

const (
testPulseURLGet string = "test_data/pulseurl_get.json"
testPulseURLList string = "test_data/pulseurl_list.json"
)

func TestPulseURLService_Get(t *testing.T) {
f, err := ioutil.ReadFile(testPulseURLGet)
if err != nil {
t.Fatal(err)
}

init := make([]*PulseURL, 1)
json.Unmarshal(f, &init)

var tests = []struct {
name string
file string
id int
opts []Option
wantPulseURL *PulseURL
wantErr error
}{
{"Valid response", testPulseURLGet, 105759, []Option{SetFields("name")}, init[0], nil},
{"Invalid ID", testFileEmpty, -1, nil, nil, ErrNegativeID},
{"Empty response", testFileEmpty, 105759, nil, nil, errInvalidJSON},
{"Invalid option", testFileEmpty, 105759, []Option{SetOffset(-99999)}, nil, ErrOutOfRange},
{"No results", testFileEmptyArray, 0, nil, nil, ErrNoResults},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ts, c, err := testServerFile(http.StatusOK, test.file)
if err != nil {
t.Fatal(err)
}
defer ts.Close()

URL, err := c.PulseURLs.Get(test.id, test.opts...)
if errors.Cause(err) != test.wantErr {
t.Errorf("got: <%v>, want: <%v>", errors.Cause(err), test.wantErr)
}

if !reflect.DeepEqual(URL, test.wantPulseURL) {
t.Errorf("got: <%v>, \nwant: <%v>", URL, test.wantPulseURL)
}
})
}
}

func TestPulseURLService_List(t *testing.T) {
f, err := ioutil.ReadFile(testPulseURLList)
if err != nil {
t.Fatal(err)
}

init := make([]*PulseURL, 0)
json.Unmarshal(f, &init)

var tests = []struct {
name string
file string
ids []int
opts []Option
wantPulseURLs []*PulseURL
wantErr error
}{
{"Valid response", testPulseURLList, []int{105784, 105904, 105984, 92066, 70576}, []Option{SetLimit(5)}, init, nil},
{"Zero IDs", testFileEmpty, nil, nil, nil, ErrEmptyIDs},
{"Invalid ID", testFileEmpty, []int{-500}, nil, nil, ErrNegativeID},
{"Empty response", testFileEmpty, []int{105784, 105904, 105984, 92066, 70576}, nil, nil, errInvalidJSON},
{"Invalid option", testFileEmpty, []int{105784, 105904, 105984, 92066, 70576}, []Option{SetOffset(-99999)}, nil, ErrOutOfRange},
{"No results", testFileEmptyArray, []int{0, 9999999}, nil, nil, ErrNoResults},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ts, c, err := testServerFile(http.StatusOK, test.file)
if err != nil {
t.Fatal(err)
}
defer ts.Close()

URL, err := c.PulseURLs.List(test.ids, test.opts...)
if errors.Cause(err) != test.wantErr {
t.Errorf("got: <%v>, want: <%v>", errors.Cause(err), test.wantErr)
}

if !reflect.DeepEqual(URL, test.wantPulseURLs) {
t.Errorf("got: <%v>, \nwant: <%v>", URL, test.wantPulseURLs)
}
})
}
}

func TestPulseURLService_Index(t *testing.T) {
f, err := ioutil.ReadFile(testPulseURLList)
if err != nil {
t.Fatal(err)
}

init := make([]*PulseURL, 0)
json.Unmarshal(f, &init)

tests := []struct {
name string
file string
opts []Option
wantPulseURLs []*PulseURL
wantErr error
}{
{"Valid response", testPulseURLList, []Option{SetLimit(5)}, init, nil},
{"Empty response", testFileEmpty, nil, nil, errInvalidJSON},
{"Invalid option", testFileEmpty, []Option{SetOffset(-99999)}, nil, ErrOutOfRange},
{"No results", testFileEmptyArray, nil, nil, ErrNoResults},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ts, c, err := testServerFile(http.StatusOK, test.file)
if err != nil {
t.Fatal(err)
}
defer ts.Close()

URL, err := c.PulseURLs.Index(test.opts...)
if errors.Cause(err) != test.wantErr {
t.Errorf("got: <%v>, want: <%v>", errors.Cause(err), test.wantErr)
}

if !reflect.DeepEqual(URL, test.wantPulseURLs) {
t.Errorf("got: <%v>, \nwant: <%v>", URL, test.wantPulseURLs)
}
})
}
}

func TestPulseURLService_Count(t *testing.T) {
var tests = []struct {
name string
resp string
opts []Option
wantCount int
wantErr error
}{
{"Happy path", `{"count": 100}`, []Option{SetFilter("popularity", OpGreaterThan, "75")}, 100, nil},
{"Empty response", "", nil, 0, errInvalidJSON},
{"Invalid option", "", []Option{SetLimit(-100)}, 0, ErrOutOfRange},
{"No results", "[]", nil, 0, ErrNoResults},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ts, c := testServerString(http.StatusOK, test.resp)
defer ts.Close()

count, err := c.PulseURLs.Count(test.opts...)
if errors.Cause(err) != test.wantErr {
t.Errorf("got: <%v>, want: <%v>", errors.Cause(err), test.wantErr)
}

if count != test.wantCount {
t.Fatalf("got: <%v>, want: <%v>", count, test.wantCount)
}
})
}
}

func TestPulseURLService_Fields(t *testing.T) {
var tests = []struct {
name string
resp string
wantFields []string
wantErr error
}{
{"Happy path", `["name", "slug", "url"]`, []string{"url", "slug", "name"}, nil},
{"Dot operator", `["logo.url", "background.id"]`, []string{"background.id", "logo.url"}, nil},
{"Asterisk", `["*"]`, []string{"*"}, nil},
{"Empty response", "", nil, errInvalidJSON},
{"No results", "[]", nil, nil},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ts, c := testServerString(http.StatusOK, test.resp)
defer ts.Close()

fields, err := c.PulseURLs.Fields()
if errors.Cause(err) != test.wantErr {
t.Errorf("got: <%v>, want: <%v>", errors.Cause(err), test.wantErr)
}

if !equalSlice(fields, test.wantFields) {
t.Fatalf("Expected fields '%v', got '%v'", test.wantFields, fields)
}
})
}
}
7 changes: 7 additions & 0 deletions test_data/pulseurl_get.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"id": 105759,
"trusted": false,
"url": "http://shoryuken.com/2017/10/30/the-latest-beta-version-of-fightcade-goes-live-for-accounts-from-2015-and-older/"
}
]
27 changes: 27 additions & 0 deletions test_data/pulseurl_list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[
{
"id": 105784,
"trusted": false,
"url": "http://www.criticalhit.net/gaming/you-can-play-the-whole-of-far-cry-5-in-co-op/"
},
{
"id": 105904,
"trusted": false,
"url": "http://www.pcgamer.com/the-elder-scrolls-legends-is-getting-a-clockwork-city-expansion"
},
{
"id": 105984,
"trusted": false,
"url": "http://shoryuken.com/2017/10/31/dante-shows-some-bold-moves-in-this-new-marvel-vs-capcom-infinite-combo-video/"
},
{
"id": 92066,
"trusted": false,
"url": "http://gamingbolt.com/saints-row-the-third-is-now-playable-on-xbox-one-via-backward-compatibility"
},
{
"id": 70576,
"trusted": false,
"url": "http://www.gamepur.com/news/27082-zelda-master-trials.html"
}
]

0 comments on commit 73fd22d

Please sign in to comment.