refactor(tw): improve test quality & refactor ParseError
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Dawid Wysokiński 2023-02-26 08:42:02 +01:00
parent 419c23673d
commit 56dc421bd0
Signed by: Kichiyaki
GPG Key ID: B5445E357FB8B892
4 changed files with 684 additions and 508 deletions

View File

@ -126,7 +126,7 @@ func (c *Client) GetServerConfig(ctx context.Context, baseURLRaw string) (Server
var cfg ServerConfig
if err := c.getXML(ctx, buildURLWithQuery(baseURL, endpointInterface, queryConfig), &cfg); err != nil {
if err = c.getXML(ctx, buildURLWithQuery(baseURL, endpointInterface, queryConfig), &cfg); err != nil {
return ServerConfig{}, err
}
@ -141,7 +141,7 @@ func (c *Client) GetBuildingInfo(ctx context.Context, baseURLRaw string) (Buildi
var info BuildingInfo
if err := c.getXML(ctx, buildURLWithQuery(baseURL, endpointInterface, queryBuildingInfo), &info); err != nil {
if err = c.getXML(ctx, buildURLWithQuery(baseURL, endpointInterface, queryBuildingInfo), &info); err != nil {
return BuildingInfo{}, err
}
@ -156,7 +156,7 @@ func (c *Client) GetUnitInfo(ctx context.Context, baseURLRaw string) (UnitInfo,
var info UnitInfo
if err := c.getXML(ctx, buildURLWithQuery(baseURL, endpointInterface, queryUnitInfo), &info); err != nil {
if err = c.getXML(ctx, buildURLWithQuery(baseURL, endpointInterface, queryUnitInfo), &info); err != nil {
return UnitInfo{}, err
}
@ -373,10 +373,12 @@ func (t tribeCSVParser) parse() ([]Tribe, error) {
if err != nil {
return nil, err
}
tribe, err := t.parseRecord(rec)
if err != nil {
return nil, err
}
tribes = append(tribes, tribe)
}
@ -393,42 +395,42 @@ func (t tribeCSVParser) parseRecord(record []string) (Tribe, error) {
tribe.ID, err = strconv.ParseInt(record[0], 10, 64)
if err != nil {
return Tribe{}, NewParseError(err, record, "tribe.ID")
return Tribe{}, ParseError{Err: err, Str: record[0], Field: "Tribe.ID"}
}
tribe.Name, err = urlpkg.QueryUnescape(record[1])
if err != nil {
return Tribe{}, NewParseError(err, record, "tribe.Name")
return Tribe{}, ParseError{Err: err, Str: record[1], Field: "Tribe.Name"}
}
tribe.Tag, err = urlpkg.QueryUnescape(record[2])
if err != nil {
return Tribe{}, NewParseError(err, record, "tribe.Tag")
return Tribe{}, ParseError{Err: err, Str: record[2], Field: "Tribe.Tag"}
}
tribe.NumMembers, err = strconv.ParseInt(record[3], 10, 64)
if err != nil {
return Tribe{}, NewParseError(err, record, "tribe.NumMembers")
return Tribe{}, ParseError{Err: err, Str: record[3], Field: "Tribe.NumMembers"}
}
tribe.NumVillages, err = strconv.ParseInt(record[4], 10, 64)
if err != nil {
return Tribe{}, NewParseError(err, record, "tribe.NumVillages")
return Tribe{}, ParseError{Err: err, Str: record[4], Field: "Tribe.NumVillages"}
}
tribe.Points, err = strconv.ParseInt(record[5], 10, 64)
if err != nil {
return Tribe{}, NewParseError(err, record, "tribe.Points")
return Tribe{}, ParseError{Err: err, Str: record[5], Field: "Tribe.Points"}
}
tribe.AllPoints, err = strconv.ParseInt(record[6], 10, 64)
if err != nil {
return Tribe{}, NewParseError(err, record, "tribe.AllPoints")
return Tribe{}, ParseError{Err: err, Str: record[6], Field: "Tribe.AllPoints"}
}
tribe.Rank, err = strconv.ParseInt(record[7], 10, 64)
if err != nil {
return Tribe{}, NewParseError(err, record, "tribe.Rank")
return Tribe{}, ParseError{Err: err, Str: record[7], Field: "Tribe.Rank"}
}
tribe.OpponentsDefeated = t.od[tribe.ID]
@ -456,10 +458,12 @@ func (p playerCSVParser) parse() ([]Player, error) {
if err != nil {
return nil, err
}
player, err := p.parseRecord(rec)
if err != nil {
return nil, err
}
players = append(players, player)
}
@ -476,32 +480,32 @@ func (p playerCSVParser) parseRecord(record []string) (Player, error) {
player.ID, err = strconv.ParseInt(record[0], 10, 64)
if err != nil {
return Player{}, NewParseError(err, record, "player.ID")
return Player{}, ParseError{Err: err, Str: record[0], Field: "Player.ID"}
}
player.Name, err = urlpkg.QueryUnescape(record[1])
if err != nil {
return Player{}, NewParseError(err, record, "player.Name")
return Player{}, ParseError{Err: err, Str: record[1], Field: "Player.Name"}
}
player.TribeID, err = strconv.ParseInt(record[2], 10, 64)
if err != nil {
return Player{}, NewParseError(err, record, "player.TribeID")
return Player{}, ParseError{Err: err, Str: record[2], Field: "Player.TribeID"}
}
player.NumVillages, err = strconv.ParseInt(record[3], 10, 64)
if err != nil {
return Player{}, NewParseError(err, record, "player.NumVillages")
return Player{}, ParseError{Err: err, Str: record[3], Field: "Player.NumVillages"}
}
player.Points, err = strconv.ParseInt(record[4], 10, 64)
if err != nil {
return Player{}, NewParseError(err, record, "player.Points")
return Player{}, ParseError{Err: err, Str: record[4], Field: "Player.Points"}
}
player.Rank, err = strconv.ParseInt(record[5], 10, 64)
if err != nil {
return Player{}, NewParseError(err, record, "player.Rank")
return Player{}, ParseError{Err: err, Str: record[5], Field: "Player.Rank"}
}
player.OpponentsDefeated = p.od[player.ID]
@ -548,37 +552,37 @@ func (v villageCSVParser) parseRecord(record []string) (Village, error) {
village.ID, err = strconv.ParseInt(record[0], 10, 64)
if err != nil {
return Village{}, NewParseError(err, record, "village.ID")
return Village{}, ParseError{Err: err, Str: record[0], Field: "Village.ID"}
}
village.Name, err = urlpkg.QueryUnescape(record[1])
if err != nil {
return Village{}, NewParseError(err, record, "village.Name")
return Village{}, ParseError{Err: err, Str: record[1], Field: "Village.Name"}
}
village.X, err = strconv.ParseInt(record[2], 10, 64)
if err != nil {
return Village{}, NewParseError(err, record, "village.X")
return Village{}, ParseError{Err: err, Str: record[2], Field: "Village.X"}
}
village.Y, err = strconv.ParseInt(record[3], 10, 64)
if err != nil {
return Village{}, NewParseError(err, record, "village.Y")
return Village{}, ParseError{Err: err, Str: record[3], Field: "Village.Y"}
}
village.PlayerID, err = strconv.ParseInt(record[4], 10, 64)
if err != nil {
return Village{}, NewParseError(err, record, "village.PlayerID")
return Village{}, ParseError{Err: err, Str: record[4], Field: "Village.PlayerID"}
}
village.Points, err = strconv.ParseInt(record[5], 10, 64)
if err != nil {
return Village{}, NewParseError(err, record, "village.Points")
return Village{}, ParseError{Err: err, Str: record[5], Field: "Village.Points"}
}
village.Bonus, err = strconv.ParseInt(record[6], 10, 64)
if err != nil {
return Village{}, NewParseError(err, record, "village.Bonus")
return Village{}, ParseError{Err: err, Str: record[6], Field: "Village.Bonus"}
}
village.Continent = "K" + string(record[3][0]) + string(record[2][0])
@ -610,10 +614,12 @@ func (o odCSVParser) parse() ([]odRecord, error) {
if err != nil {
return nil, err
}
od, err := o.parseRecord(rec)
if err != nil {
return nil, err
}
odRecords = append(odRecords, od)
}
@ -626,17 +632,17 @@ func (o odCSVParser) parseRecord(record []string) (odRecord, error) {
rec.Rank, err = strconv.ParseInt(record[0], 10, 64)
if err != nil {
return odRecord{}, NewParseError(err, record, "odRecord.Rank")
return odRecord{}, ParseError{Err: err, Str: record[0], Field: "odRecord.Rank"}
}
rec.ID, err = strconv.ParseInt(record[1], 10, 64)
if err != nil {
return odRecord{}, NewParseError(err, record, "odRecord.ID")
return odRecord{}, ParseError{Err: err, Str: record[1], Field: "odRecord.ID"}
}
rec.Score, err = strconv.ParseInt(record[2], 10, 64)
if err != nil {
return odRecord{}, NewParseError(err, record, "odRecord.Score")
return odRecord{}, ParseError{Err: err, Str: record[2], Field: "odRecord.Score"}
}
return rec, nil
@ -664,9 +670,11 @@ func (e ennoblementCSVParser) parse() ([]Ennoblement, error) {
if err != nil {
return nil, err
}
if ennoblement.CreatedAt.Before(e.since) {
continue
}
ennoblements = append(ennoblements, ennoblement)
}
@ -683,37 +691,37 @@ func (e ennoblementCSVParser) parseRecord(record []string) (Ennoblement, error)
ennoblement.VillageID, err = strconv.ParseInt(record[0], 10, 64)
if err != nil {
return Ennoblement{}, NewParseError(err, record, "ennoblement.VillageID")
return Ennoblement{}, ParseError{Err: err, Str: record[0], Field: "Ennoblement.VillageID"}
}
ennoblement.CreatedAt, err = e.parseTimestamp(record[1])
if err != nil {
return Ennoblement{}, NewParseError(err, record, "ennoblement.CreatedAt")
return Ennoblement{}, ParseError{Err: err, Str: record[1], Field: "Ennoblement.CreatedAt"}
}
ennoblement.NewOwnerID, err = strconv.ParseInt(record[2], 10, 64)
if err != nil {
return Ennoblement{}, NewParseError(err, record, "ennoblement.NewOwnerID")
return Ennoblement{}, ParseError{Err: err, Str: record[2], Field: "Ennoblement.NewOwnerID"}
}
ennoblement.OldOwnerID, err = strconv.ParseInt(record[3], 10, 64)
if err != nil {
return Ennoblement{}, NewParseError(err, record, "ennoblement.OldOwnerID")
return Ennoblement{}, ParseError{Err: err, Str: record[3], Field: "Ennoblement.OldOwnerID"}
}
ennoblement.OldTribeID, err = strconv.ParseInt(record[4], 10, 64)
if err != nil {
return Ennoblement{}, NewParseError(err, record, "ennoblement.OldTribeID")
return Ennoblement{}, ParseError{Err: err, Str: record[4], Field: "Ennoblement.OldTribeID"}
}
ennoblement.NewTribeID, err = strconv.ParseInt(record[5], 10, 64)
if err != nil {
return Ennoblement{}, NewParseError(err, record, "ennoblement.NewTribeID")
return Ennoblement{}, ParseError{Err: err, Str: record[5], Field: "Ennoblement.NewTribeID"}
}
ennoblement.Points, err = strconv.ParseInt(record[6], 10, 64)
if err != nil {
return Ennoblement{}, NewParseError(err, record, "ennoblement.Points")
return Ennoblement{}, ParseError{Err: err, Str: record[6], Field: "Ennoblement.Points"}
}
return ennoblement, nil

View File

@ -12,8 +12,6 @@ import (
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/require"
"gitea.dwysokinski.me/twhelp/core/internal/tw"
@ -561,7 +559,7 @@ func TestClient_GetTribes(t *testing.T) {
respODA string
respODD string
checkErr func(err error) bool
expectedTribes []tw.Tribe
expectedTribes func(url string) []tw.Tribe
}{
{
name: "OK",
@ -569,11 +567,13 @@ func TestClient_GetTribes(t *testing.T) {
respOD: "1,1,1\n2,2,2\n3,3,3",
respODA: "1,1,1\n2,2,2\n3,3,3",
respODD: "1,1,1\n2,2,2\n3,3,3",
expectedTribes: []tw.Tribe{
expectedTribes: func(url string) []tw.Tribe {
return []tw.Tribe{
{
ID: 1,
Name: "name 1",
Tag: "tag 1",
ProfileURL: url + "/game.php?screen=info_ally&id=1",
NumMembers: 100,
NumVillages: 101,
Points: 102,
@ -594,6 +594,7 @@ func TestClient_GetTribes(t *testing.T) {
ID: 2,
Name: "name2",
Tag: "tag2",
ProfileURL: url + "/game.php?screen=info_ally&id=2",
NumMembers: 200,
NumVillages: 202,
Points: 202,
@ -614,6 +615,7 @@ func TestClient_GetTribes(t *testing.T) {
ID: 3,
Name: "name3",
Tag: "tag3",
ProfileURL: url + "/game.php?screen=info_ally&id=3",
NumMembers: 300,
NumVillages: 303,
Points: 302,
@ -634,6 +636,7 @@ func TestClient_GetTribes(t *testing.T) {
ID: 4,
Name: "name4",
Tag: "tag4",
ProfileURL: url + "/game.php?screen=info_ally&id=4",
NumMembers: 400,
NumVillages: 404,
Points: 402,
@ -641,140 +644,141 @@ func TestClient_GetTribes(t *testing.T) {
Rank: 404,
OpponentsDefeated: tw.OpponentsDefeated{},
},
}
},
},
{
name: "ERR: invalid value - OD.Rank",
name: "ERR: OD.Rank can't be converted to int64",
respOD: "test,1,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - OD.ID",
name: "ERR: OD.ID -can't be converted to int64",
respOD: "1,test,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - OD.Score",
name: "ERR: OD.Score can't be converted to int64",
respOD: "1,1,test",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODA.Rank",
name: "ERR: ODA.Rank can't be converted to int64",
respODA: "test,1,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODA.ID",
name: "ERR: ODA.ID can't be converted to int64",
respODA: "1,test,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODA.Score",
name: "ERR: ODA.Score can't be converted to int64",
respODA: "1,1,test",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODD.Rank",
name: "ERR: ODD.Rank can't be converted to int64",
respODD: "test,1,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODD.ID",
name: "ERR: ODD.ID can't be converted to int64",
respODD: "1,test,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODD.Score",
name: "ERR: ODD.Score can't be converted to int64",
respODD: "1,1,test",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: incorrect number of fields 1",
name: "ERR: too few fields",
respTribe: "1,name%201,tag%201,100,101,102,103",
checkErr: func(err error) bool {
return errors.Is(err, csv.ErrFieldCount)
},
},
{
name: "ERR: incorrect number of fields 2",
name: "ERR: too many fields",
respTribe: "1,name%201,tag%201,100,101,102,103,104,105",
checkErr: func(err error) bool {
return errors.Is(err, csv.ErrFieldCount)
},
},
{
name: "ERR: invalid value - Tribe.ID",
name: "ERR: Tribe.ID can't be converted to int64",
respTribe: "1.23,name1,tag1,100,101,102,103,104",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "tribe.ID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Tribe.ID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Tribe.NumMembers",
name: "ERR: Tribe.NumMembers can't be converted to int64",
respTribe: "1,name1,tag1,100.23,101,102,103,104",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "tribe.NumMembers" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Tribe.NumMembers" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Tribe.NumVillages",
name: "ERR: Tribe.NumVillages can't be converted to int64",
respTribe: "1,name1,tag1,100,101.23,102,103,104",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "tribe.NumVillages" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Tribe.NumVillages" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Tribe.Points",
name: "ERR: Tribe.Points can't be converted to int64",
respTribe: "1,name1,tag1,100,101,102.23,103,104",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "tribe.Points" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Tribe.Points" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Tribe.AllPoints",
name: "ERR: Tribe.AllPoints can't be converted to int64",
respTribe: "1,name1,tag1,100,101,102,103.23,104",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "tribe.AllPoints" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Tribe.AllPoints" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Tribe.Rank",
name: "ERR: Tribe.Rank can't be converted to int64",
respTribe: "1,name1,tag1,100,101,102,103,104.23",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "tribe.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Tribe.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
}
@ -797,25 +801,21 @@ func TestClient_GetTribes(t *testing.T) {
tribes, err := newTestClient(srv.Client()).GetTribes(context.Background(), srv.URL)
checkErr := func(err error) bool {
return err == nil
return errors.Is(err, nil)
}
if tt.checkErr != nil {
checkErr = tt.checkErr
}
var expectedTribes []tw.Tribe
if tt.expectedTribes != nil {
expectedTribes = tt.expectedTribes(srv.URL)
}
assert.True(t, checkErr(err))
require.Len(t, tribes, len(tt.expectedTribes))
require.Len(t, tribes, len(expectedTribes))
for i, tribe := range tribes {
assert.Empty(t, cmp.Diff(
tt.expectedTribes[i],
tribe,
cmpopts.IgnoreFields(tw.Tribe{}, "ProfileURL"),
))
assert.Equal(
t,
fmt.Sprintf("%s/game.php?screen=info_ally&id=%d", srv.URL, tribe.ID),
tribe.ProfileURL,
)
assert.Equal(t, expectedTribes[i], tribe)
}
})
}
@ -832,7 +832,7 @@ func TestClient_GetPlayers(t *testing.T) {
respODD string
respODS string
checkErr func(err error) bool
expectedPlayers []tw.Player
expectedPlayers func(url string) []tw.Player
}{
{
name: "OK",
@ -841,10 +841,12 @@ func TestClient_GetPlayers(t *testing.T) {
respODA: "1,1,1000\n2,2,253\n3,3,100",
respODD: "1,1,1002\n2,2,251\n3,3,155",
respODS: "1,1,1003\n2,2,250\n3,3,166",
expectedPlayers: []tw.Player{
expectedPlayers: func(url string) []tw.Player {
return []tw.Player{
{
ID: 1,
Name: "name 1",
ProfileURL: url + "/game.php?screen=info_player&id=1",
TribeID: 123,
NumVillages: 124,
Points: 125,
@ -863,6 +865,7 @@ func TestClient_GetPlayers(t *testing.T) {
{
ID: 2,
Name: "name2",
ProfileURL: url + "/game.php?screen=info_player&id=2",
TribeID: 256,
NumVillages: 257,
Points: 258,
@ -881,6 +884,7 @@ func TestClient_GetPlayers(t *testing.T) {
{
ID: 3,
Name: "name3",
ProfileURL: url + "/game.php?screen=info_player&id=3",
TribeID: 356,
NumVillages: 357,
Points: 358,
@ -899,162 +903,164 @@ func TestClient_GetPlayers(t *testing.T) {
{
ID: 4,
Name: "name4",
ProfileURL: url + "/game.php?screen=info_player&id=4",
TribeID: 456,
NumVillages: 457,
Points: 458,
Rank: 459,
OpponentsDefeated: tw.OpponentsDefeated{},
},
}
},
},
{
name: "ERR: invalid value - OD.Rank",
name: "ERR: OD.Rank can't be converted to int64",
respOD: "test,1,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - OD.ID",
name: "ERR: OD.ID can't be converted to int64",
respOD: "1,test,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - OD.Score",
name: "ERR: OD.Score can't be converted to int64",
respOD: "1,1,test",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODA.Rank",
name: "ERR: ODA.Rank can't be converted to int64",
respODA: "test,1,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODA.ID",
name: "ERR: ODA.ID can't be converted to int64",
respODA: "1,test,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODA.Score",
name: "ERR: ODA.Score can't be converted to int64",
respODA: "1,1,test",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODD.Rank",
name: "ERR: ODD.Rank can't be converted to int64",
respODD: "test,1,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODD.ID",
name: "ERR: ODD.ID can't be converted to int64",
respODD: "1,test,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODD.Score",
name: "ERR: ODD.Score can't be converted to int64",
respODD: "1,1,test",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODS.Rank",
name: "ERR: ODS.Rank can't be converted to int64",
respODS: "test,1,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODS.ID",
name: "ERR: ODS.ID can't be converted to int64",
respODS: "1,test,1001",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.ID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - ODS.Score",
name: "ERR: ODS.Score can't be converted to int64",
respODS: "1,1,test",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "odRecord.Score" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: incorrect number of fields 1",
name: "ERR: too few fields",
respPlayer: "1,name%201,123,124,125",
checkErr: func(err error) bool {
return errors.Is(err, csv.ErrFieldCount)
},
},
{
name: "ERR: incorrect number of fields 2",
name: "ERR: too many fields",
respPlayer: "1,name%201,123,124,125,126,127",
checkErr: func(err error) bool {
return errors.Is(err, csv.ErrFieldCount)
},
},
{
name: "ERR: invalid value - Player.ID",
name: "ERR: Player.ID can't be converted to int64",
respPlayer: "1.25,name,123,124,125,126",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "player.ID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Player.ID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Player.TribeID",
name: "ERR: Player.TribeID can't be converted to int64",
respPlayer: "1,name,1.23,124,125,126",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "player.TribeID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Player.TribeID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Player.NumVillages",
name: "ERR: Player.NumVillages can't be converted to int64",
respPlayer: "1,name,123,1.24,125,126",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "player.NumVillages" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Player.NumVillages" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Player.Points",
name: "ERR: Player.Points can't be converted to int64",
respPlayer: "1,name,123,124,1.25,126",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "player.Points" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Player.Points" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Player.Rank",
name: "ERR: Player.Rank can't be converted to int64",
respPlayer: "1,name,123,124,125,1.26",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "player.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Player.Rank" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
}
@ -1078,25 +1084,21 @@ func TestClient_GetPlayers(t *testing.T) {
players, err := newTestClient(srv.Client()).GetPlayers(context.Background(), srv.URL)
checkErr := func(err error) bool {
return err == nil
return errors.Is(err, nil)
}
if tt.checkErr != nil {
checkErr = tt.checkErr
}
var expectedPlayers []tw.Player
if tt.expectedPlayers != nil {
expectedPlayers = tt.expectedPlayers(srv.URL)
}
assert.True(t, checkErr(err))
require.Len(t, players, len(tt.expectedPlayers))
require.Len(t, players, len(expectedPlayers))
for i, player := range players {
assert.Empty(t, cmp.Diff(
tt.expectedPlayers[i],
player,
cmpopts.IgnoreFields(tw.Player{}, "ProfileURL"),
))
assert.Equal(
t,
fmt.Sprintf("%s/game.php?screen=info_player&id=%d", srv.URL, player.ID),
player.ProfileURL,
)
assert.Equal(t, expectedPlayers[i], player)
}
})
}
@ -1109,15 +1111,17 @@ func TestClient_GetVillages(t *testing.T) {
name string
resp string
checkErr func(err error) bool
expectedVillages []tw.Village
expectedVillages func(url string) []tw.Village
}{
{
name: "OK",
resp: "123,village%201,500,501,502,503,504\n124,village 2,100,201,102,103,104",
expectedVillages: []tw.Village{
expectedVillages: func(url string) []tw.Village {
return []tw.Village{
{
ID: 123,
Name: "village 1",
ProfileURL: url + "/game.php?screen=info_village&id=123",
X: 500,
Y: 501,
Continent: "K55",
@ -1128,6 +1132,7 @@ func TestClient_GetVillages(t *testing.T) {
{
ID: 124,
Name: "village 2",
ProfileURL: url + "/game.php?screen=info_village&id=124",
X: 100,
Y: 201,
Continent: "K21",
@ -1135,68 +1140,69 @@ func TestClient_GetVillages(t *testing.T) {
Points: 103,
Bonus: 104,
},
}
},
},
{
name: "ERR: incorrect number of fields 1",
name: "ERR: too few fields",
resp: "123,village 1,500,501,502,503",
checkErr: func(err error) bool {
return errors.Is(err, csv.ErrFieldCount)
},
},
{
name: "ERR: incorrect number of fields 2",
name: "ERR: too many fields",
resp: "123,village 1,500,501,502,503,504,505",
checkErr: func(err error) bool {
return errors.Is(err, csv.ErrFieldCount)
},
},
{
name: "ERR: invalid value - Village.ID",
name: "ERR: Village.ID can't be converted to int64",
resp: "123.23,village 1,500,501,502,503,504",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "village.ID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Village.ID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Village.X",
name: "ERR: Village.X can't be converted to int64",
resp: "123,village 1,123.23,501,502,503,504",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "village.X" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Village.X" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Village.Y",
name: "ERR: Village.Y can't be converted to int64",
resp: "123,village 1,500,123.23,502,503,504",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "village.Y" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Village.Y" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Village.PlayerID",
name: "ERR: Village.PlayerID can't be converted to int64",
resp: "123,village 1,500,501,123.23,503,504",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "village.PlayerID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Village.PlayerID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Village.Points",
name: "ERR: Village.Points can't be converted to int64",
resp: "123,village 1,500,501,502,123.23,504",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "village.Points" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Village.Points" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Village.Bonus",
name: "ERR: Village.Bonus can't be converted to int64",
resp: "123,village 1,500,501,502,503,123.23",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "village.Bonus" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Village.Bonus" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
}
@ -1216,25 +1222,21 @@ func TestClient_GetVillages(t *testing.T) {
villages, err := newTestClient(srv.Client()).GetVillages(context.Background(), srv.URL)
checkErr := func(err error) bool {
return err == nil
return errors.Is(err, nil)
}
if tt.checkErr != nil {
checkErr = tt.checkErr
}
var expectedVillages []tw.Village
if tt.expectedVillages != nil {
expectedVillages = tt.expectedVillages(srv.URL)
}
assert.True(t, checkErr(err))
require.Len(t, villages, len(tt.expectedVillages))
require.Len(t, villages, len(expectedVillages))
for i, village := range villages {
assert.Empty(t, cmp.Diff(
tt.expectedVillages[i],
village,
cmpopts.IgnoreFields(tw.Village{}, "ProfileURL"),
))
assert.Equal(
t,
fmt.Sprintf("%s/game.php?screen=info_village&id=%d", srv.URL, village.ID),
village.ProfileURL,
)
assert.Equal(t, expectedVillages[i], village)
}
})
}
@ -1243,7 +1245,9 @@ func TestClient_GetVillages(t *testing.T) {
func TestClient_GetEnnoblements(t *testing.T) {
t.Parallel()
now := time.Now()
t.Run("map/conquer_extended.txt", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
since time.Time
@ -1252,7 +1256,7 @@ func TestClient_GetEnnoblements(t *testing.T) {
expectedEnnoblements []tw.Ennoblement
}{
{
name: "OK: /map/conquer_extended.txt",
name: "OK",
since: time.Unix(1657842401, 0),
//nolint:lll
resp: "1424,1657842406,698953084,699589674,0,122,380\n3150,1657882879,6461674,0,0,179,111\n1025,1657947400,9157005,698942601,0,52,461\n1025,1657842400,9157005,698942601,0,52,461",
@ -1288,7 +1292,121 @@ func TestClient_GetEnnoblements(t *testing.T) {
},
},
{
name: "OK: /interface.php?func=get_conquer_extended",
name: "ERR: too few fields",
resp: "1424,1657842406,698953084,699589674,0,122",
checkErr: func(err error) bool {
return errors.Is(err, csv.ErrFieldCount)
},
},
{
name: "ERR: too many fields",
resp: "1424,1657842406,698953084,699589674,0,122,380,0",
checkErr: func(err error) bool {
return errors.Is(err, csv.ErrFieldCount)
},
},
{
name: "ERR: Ennoblement.VillageID can't be converted to int64",
resp: "asd,1657842406,698953084,699589674,0,122,380",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.VillageID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: Ennoblement.VillageID can't be converted to int64",
resp: "1424,asd,698953084,699589674,0,122,380",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.CreatedAt" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: Ennoblement.NewOwnerID can't be converted to int64",
resp: "1424,1657842406,asd,699589674,0,122,380",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.NewOwnerID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: Ennoblement.OldOwnerID can't be converted to int64",
resp: "1424,1657842406,698953084,asd,0,122,380",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.OldOwnerID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: Ennoblement.OldTribeID can't be converted to int64",
resp: "1424,1657842406,698953084,699589674,asd,122,380",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.OldTribeID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: Ennoblement.NewTribeID can't be converted to int64",
resp: "1424,1657842406,698953084,699589674,0,asd,380",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.NewTribeID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: Ennoblement.Points can't be converted to int64",
resp: "1424,1657842406,698953084,699589674,0,122,asd",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.Points" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
mux := http.NewServeMux()
mux.HandleFunc("/map/conquer_extended.txt", newPlainTextHandlerString(tt.resp))
srv := httptest.NewTLSServer(mux)
t.Cleanup(srv.Close)
ennoblements, err := newTestClient(srv.Client()).GetEnnoblements(context.Background(), srv.URL, tt.since)
checkErr := func(err error) bool {
return errors.Is(err, nil)
}
if tt.checkErr != nil {
checkErr = tt.checkErr
}
assert.True(t, checkErr(err))
require.Len(t, ennoblements, len(tt.expectedEnnoblements))
for i, ennoblement := range ennoblements {
assert.Equal(t, tt.expectedEnnoblements[i], ennoblement)
}
})
}
})
t.Run("interface.php?func=get_conquer_extended", func(t *testing.T) {
t.Parallel()
now := time.Now()
tests := []struct {
name string
since time.Time
resp string
checkErr func(err error) bool
clientOpts []tw.ClientOption
expectedEnnoblements []tw.Ennoblement
}{
{
name: "OK: without custom ennoblementsUseInterfaceFunc",
since: now.Add(-22 * time.Hour),
resp: fmt.Sprintf(
"1424,%d,698953084,699589674,0,122,380\n3150,%d,6461674,0,0,179,111\n1025,%d,9157005,698942601,0,52,461",
@ -1328,73 +1446,127 @@ func TestClient_GetEnnoblements(t *testing.T) {
},
},
{
name: "ERR: incorrect number of fields 1",
resp: "1424,1657842406,698953084,699589674,0,122",
name: "OK: with custom ennoblementsUseInterfaceFunc",
since: now.Add(-47 * time.Hour),
resp: fmt.Sprintf(
"1424,%d,698953084,699589674,0,122,380\n3150,%d,6461674,0,0,179,111\n1025,%d,9157005,698942601,0,52,461",
now.Add(-44*time.Hour).Unix(),
now.Add(-40*time.Minute).Unix(),
now.Add(-40*time.Second).Unix(),
),
checkErr: nil,
clientOpts: []tw.ClientOption{
tw.WithEnnoblementsUseInterfaceFunc(func(since time.Time) bool {
return since.After(time.Now().Add(-48 * time.Hour))
}),
},
expectedEnnoblements: []tw.Ennoblement{
{
VillageID: 1424,
NewOwnerID: 698953084,
NewTribeID: 122,
OldOwnerID: 699589674,
OldTribeID: 0,
Points: 380,
CreatedAt: time.Unix(now.Add(-44*time.Hour).Unix(), 0),
},
{
VillageID: 3150,
NewOwnerID: 6461674,
NewTribeID: 179,
OldOwnerID: 0,
OldTribeID: 0,
Points: 111,
CreatedAt: time.Unix(now.Add(-40*time.Minute).Unix(), 0),
},
{
VillageID: 1025,
NewOwnerID: 9157005,
NewTribeID: 52,
OldOwnerID: 698942601,
OldTribeID: 0,
Points: 461,
CreatedAt: time.Unix(now.Add(-40*time.Second).Unix(), 0),
},
},
},
{
name: "ERR: too few fields",
since: now.Add(-22 * time.Hour),
resp: fmt.Sprintf("1424,%d,698953084,699589674,0,122", now.Add(-21*time.Hour).Unix()),
checkErr: func(err error) bool {
return errors.Is(err, csv.ErrFieldCount)
},
},
{
name: "ERR: incorrect number of fields 2",
resp: "1424,1657842406,698953084,699589674,0,122,380,0",
name: "ERR: too many fields",
since: now.Add(-22 * time.Hour),
resp: fmt.Sprintf("1424,%d,698953084,699589674,0,122,380,0", now.Add(-21*time.Hour).Unix()),
checkErr: func(err error) bool {
return errors.Is(err, csv.ErrFieldCount)
},
},
{
name: "ERR: invalid value - Ennoblement.VillageID",
resp: "asd,1657842406,698953084,699589674,0,122,380",
name: "ERR: Ennoblement.VillageID can't be converted to int64",
since: now.Add(-22 * time.Hour),
resp: fmt.Sprintf("asd,%d,698953084,699589674,0,122,380", now.Add(-21*time.Hour).Unix()),
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "ennoblement.VillageID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.VillageID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Ennoblement.VillageID",
name: "ERR: Ennoblement.CreatedAt can't be converted to int64",
since: now.Add(-22 * time.Hour),
resp: "1424,asd,698953084,699589674,0,122,380",
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "ennoblement.CreatedAt" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.CreatedAt" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Ennoblement.NewOwnerID",
resp: "1424,1657842406,asd,699589674,0,122,380",
name: "ERR: Ennoblement.NewOwnerID can't be converted to int64",
since: now.Add(-22 * time.Hour),
resp: fmt.Sprintf("1424,%d,asd,699589674,0,122,380", now.Add(-21*time.Hour).Unix()),
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "ennoblement.NewOwnerID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.NewOwnerID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Ennoblement.OldOwnerID",
resp: "1424,1657842406,698953084,asd,0,122,380",
name: "ERR: Ennoblement.OldOwnerID can't be converted to int64",
since: now.Add(-22 * time.Hour),
resp: fmt.Sprintf("1424,%d,698953084,asd,0,122,380", now.Add(-21*time.Hour).Unix()),
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "ennoblement.OldOwnerID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.OldOwnerID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Ennoblement.OldTribeID",
resp: "1424,1657842406,698953084,699589674,asd,122,380",
name: "ERR: Ennoblement.OldTribeID can't be converted to int64",
since: now.Add(-22 * time.Hour),
resp: fmt.Sprintf("1424,%d,698953084,699589674,asd,122,380", now.Add(-21*time.Hour).Unix()),
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "ennoblement.OldTribeID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.OldTribeID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Ennoblement.NewTribeID",
resp: "1424,1657842406,698953084,699589674,0,asd,380",
name: "ERR: Ennoblement.NewTribeID can't be converted to int64",
since: now.Add(-22 * time.Hour),
resp: fmt.Sprintf("1424,%d,698953084,699589674,0,asd,380", now.Add(-21*time.Hour).Unix()),
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "ennoblement.NewTribeID" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.NewTribeID" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
{
name: "ERR: invalid value - Ennoblement.Points",
resp: "1424,1657842406,698953084,699589674,0,122,asd",
name: "ERR: Ennoblement.Points can't be converted to int64",
since: now.Add(-22 * time.Hour),
resp: fmt.Sprintf("1424,%d,698953084,699589674,0,122,asd", now.Add(-21*time.Hour).Unix()),
checkErr: func(err error) bool {
var parseErr tw.ParseError
return errors.As(err, &parseErr) && parseErr.Field() == "ennoblement.Points" && errors.Is(parseErr, strconv.ErrSyntax)
return errors.As(err, &parseErr) && parseErr.Field == "Ennoblement.Points" && errors.Is(parseErr, strconv.ErrSyntax)
},
},
}
@ -1407,12 +1579,11 @@ func TestClient_GetEnnoblements(t *testing.T) {
mux := http.NewServeMux()
mux.HandleFunc("/interface.php", newInterfacePlainTextHandlerString("get_conquer_extended", tt.resp))
mux.HandleFunc("/map/conquer_extended.txt", newPlainTextHandlerString(tt.resp))
srv := httptest.NewTLSServer(mux)
t.Cleanup(srv.Close)
ennoblements, err := newTestClient(srv.Client()).GetEnnoblements(context.Background(), srv.URL, tt.since)
ennoblements, err := newTestClient(srv.Client(), tt.clientOpts...).GetEnnoblements(context.Background(), srv.URL, tt.since)
checkErr := func(err error) bool {
return errors.Is(err, nil)
@ -1428,10 +1599,12 @@ func TestClient_GetEnnoblements(t *testing.T) {
}
})
}
})
}
func newTestClient(hc *http.Client) *tw.Client {
return tw.NewClient(tw.WithHTTPClient(hc), tw.WithUserAgent(testUserAgent))
// user agent and http client can't be overridden via opts
func newTestClient(hc *http.Client, opts ...tw.ClientOption) *tw.Client {
return tw.NewClient(append(opts, tw.WithHTTPClient(hc), tw.WithUserAgent(testUserAgent))...)
}
func newInterfaceXMLHandler(funcName string, result []byte) func(w http.ResponseWriter, r *http.Request) {

View File

@ -1,42 +1,15 @@
package tw
import (
"strings"
)
const (
recordLenLimit = 100
)
type ParseError struct {
record []string
field string
err error
Field string
Str string
Err error
}
func NewParseError(err error, record []string, field string) ParseError {
return ParseError{
err: err,
record: record,
field: field,
}
}
func (e ParseError) Error() string {
recordStr := strings.Join(e.record, ",")
if len(recordStr) > recordLenLimit {
recordStr = recordStr[0:recordLenLimit-3] + "..."
}
return "parse error (field=" + e.field + " record=" + recordStr + "): " + e.err.Error()
}
func (e ParseError) Field() string {
return e.field
}
func (e ParseError) Record() []string {
return e.record
return e.Field + ": parsing \"" + e.Str + "\": " + e.Err.Error()
}
func (e ParseError) Unwrap() error {
return e.err
return e.Err
}

View File

@ -0,0 +1,22 @@
package tw_test
import (
"errors"
"fmt"
"testing"
"gitea.dwysokinski.me/twhelp/core/internal/tw"
"github.com/stretchr/testify/assert"
)
func TestParseError(t *testing.T) {
t.Parallel()
err := tw.ParseError{
Field: "test",
Str: "anything",
Err: errors.New("err"),
}
assert.Equal(t, fmt.Sprintf("%s: parsing \"%s\": %s", err.Field, err.Str, err.Err.Error()), err.Error())
assert.ErrorIs(t, err, err.Err)
}