feat: sort validation improvements #14
|
@ -92,7 +92,7 @@ func (a listEnnoblementsParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuer
|
|||
case domain.EnnoblementSortServerKeyDESC:
|
||||
q = q.Order("ennoblement.server_key DESC")
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -211,7 +211,7 @@ func (a listPlayersParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
|||
case domain.PlayerSortDeletedAtDESC:
|
||||
q = q.OrderExpr("COALESCE(player.deleted_at, ?) DESC", time.Time{})
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,7 +306,7 @@ func (a listPlayersParamsApplier) applyCursor(q *bun.SelectQuery) *bun.SelectQue
|
|||
el.column = "COALESCE(player.deleted_at, '0001-01-01 00:00:00+00:00')"
|
||||
el.direction = sortDirectionDESC
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
|
||||
cursorApplier.data = append(cursorApplier.data, el)
|
||||
|
|
|
@ -97,7 +97,7 @@ func (a listPlayerSnapshotsParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQ
|
|||
case domain.PlayerSnapshotSortServerKeyDESC:
|
||||
q = q.Order("ps.server_key DESC")
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -228,7 +228,7 @@ func (a listServersParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
|||
case domain.ServerSortOpenDESC:
|
||||
q = q.Order("server.open DESC")
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,7 +272,7 @@ func (a listServersParamsApplier) applyCursor(q *bun.SelectQuery) *bun.SelectQue
|
|||
el.column = "server.open"
|
||||
el.direction = sortDirectionDESC
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
|
||||
cursorApplier.data = append(cursorApplier.data, el)
|
||||
|
|
|
@ -212,7 +212,7 @@ func (a listTribesParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
|||
case domain.TribeSortDeletedAtDESC:
|
||||
q = q.OrderExpr("COALESCE(tribe.deleted_at, ?) DESC", time.Time{})
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,7 +317,7 @@ func (a listTribesParamsApplier) applyCursor(q *bun.SelectQuery) *bun.SelectQuer
|
|||
el.column = "COALESCE(tribe.deleted_at, '0001-01-01 00:00:00+00:00')"
|
||||
el.direction = sortDirectionDESC
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
|
||||
cursorApplier.data = append(cursorApplier.data, el)
|
||||
|
|
|
@ -90,7 +90,7 @@ func (a listTribeChangesParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuer
|
|||
case domain.TribeChangeSortServerKeyDESC:
|
||||
q = q.Order("tc.server_key DESC")
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ func (a listTribeSnapshotsParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQu
|
|||
case domain.TribeSnapshotSortServerKeyDESC:
|
||||
q = q.Order("ts.server_key DESC")
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ func (a listVersionsParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
|||
case domain.VersionSortCodeDESC:
|
||||
q = q.Order("version.code DESC")
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ func (a listVersionsParamsApplier) applyCursor(q *bun.SelectQuery) *bun.SelectQu
|
|||
el.column = "version.code"
|
||||
el.direction = sortDirectionDESC
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
|
||||
cursorApplier.data = append(cursorApplier.data, el)
|
||||
|
|
|
@ -135,7 +135,7 @@ func (a listVillagesParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
|||
case domain.VillageSortServerKeyDESC:
|
||||
q = q.Order("village.server_key DESC")
|
||||
default:
|
||||
return q.Err(errInvalidSortValue)
|
||||
return q.Err(fmt.Errorf("%s: %w", s.String(), errInvalidSortValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package domain
|
|||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -165,6 +166,34 @@ const (
|
|||
EnnoblementSortServerKeyDESC
|
||||
)
|
||||
|
||||
// IsInConflict returns true if two sorts can't be used together (e.g. EnnoblementSortIDASC and EnnoblementSortIDDESC).
|
||||
func (s EnnoblementSort) IsInConflict(s2 EnnoblementSort) bool {
|
||||
ss := []EnnoblementSort{s, s2}
|
||||
slices.Sort(ss)
|
||||
// ASC is always an odd number, DESC is always an even number
|
||||
return (ss[0]%2 == 1 && ss[0] == ss[1]-1) || ss[0] == ss[1]
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (s EnnoblementSort) String() string {
|
||||
switch s {
|
||||
case EnnoblementSortCreatedAtASC:
|
||||
return "createdAt:ASC"
|
||||
case EnnoblementSortCreatedAtDESC:
|
||||
return "createdAt:DESC"
|
||||
case EnnoblementSortIDASC:
|
||||
return "id:ASC"
|
||||
case EnnoblementSortIDDESC:
|
||||
return "id:DESC"
|
||||
case EnnoblementSortServerKeyASC:
|
||||
return "serverKey:ASC"
|
||||
case EnnoblementSortServerKeyDESC:
|
||||
return "serverKey:DESC"
|
||||
default:
|
||||
return "unknown ennoblement sort"
|
||||
}
|
||||
}
|
||||
|
||||
type ListEnnoblementsParams struct {
|
||||
serverKeys []string
|
||||
sort []EnnoblementSort
|
||||
|
@ -207,7 +236,7 @@ const (
|
|||
)
|
||||
|
||||
func (params *ListEnnoblementsParams) SetSort(sort []EnnoblementSort) error {
|
||||
if err := validateSliceLen(sort, ennoblementSortMinLength, ennoblementSortMaxLength); err != nil {
|
||||
if err := validateSort(sort, ennoblementSortMinLength, ennoblementSortMaxLength); err != nil {
|
||||
return ValidationError{
|
||||
Model: listEnnoblementsParamsModelName,
|
||||
Field: "sort",
|
||||
|
|
|
@ -37,6 +37,71 @@ func TestNewCreateEnnoblementParams(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEnnoblementSort_IsInConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
sorts [2]domain.EnnoblementSort
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedRes bool
|
||||
}{
|
||||
{
|
||||
name: "OK: id:ASC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.EnnoblementSort{domain.EnnoblementSortIDASC, domain.EnnoblementSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.EnnoblementSort{domain.EnnoblementSortIDDESC, domain.EnnoblementSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.EnnoblementSort{domain.EnnoblementSortIDASC, domain.EnnoblementSortIDASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.EnnoblementSort{domain.EnnoblementSortIDDESC, domain.EnnoblementSortIDDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: createdAt:ASC createdAt:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.EnnoblementSort{domain.EnnoblementSortCreatedAtDESC, domain.EnnoblementSortCreatedAtDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: serverKey:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.EnnoblementSort{domain.EnnoblementSortServerKeyDESC, domain.EnnoblementSortServerKeyASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, tt.expectedRes, tt.args.sorts[0].IsInConflict(tt.args.sorts[1]))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListEnnoblementsParams_SetSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -94,6 +159,22 @@ func TestListEnnoblementsParams_SetSort(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: conflict",
|
||||
args: args{
|
||||
sort: []domain.EnnoblementSort{
|
||||
domain.EnnoblementSortIDASC,
|
||||
domain.EnnoblementSortIDDESC,
|
||||
},
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListEnnoblementsParams",
|
||||
Field: "sort",
|
||||
Err: domain.SortConflictError{
|
||||
Sort: [2]string{domain.EnnoblementSortIDASC.String(), domain.EnnoblementSortIDDESC.String()},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
@ -410,34 +410,73 @@ const (
|
|||
PlayerSortDeletedAtDESC
|
||||
)
|
||||
|
||||
// IsInConflict returns true if two sorts can't be used together (e.g. PlayerSortIDASC and PlayerSortIDDESC).
|
||||
func (s PlayerSort) IsInConflict(s2 PlayerSort) bool {
|
||||
ss := []PlayerSort{s, s2}
|
||||
slices.Sort(ss)
|
||||
// ASC is always an odd number, DESC is always an even number
|
||||
return (ss[0]%2 == 1 && ss[0] == ss[1]-1) || ss[0] == ss[1]
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func newPlayerSortFromString(s string) (PlayerSort, error) {
|
||||
switch strings.ToLower(s) {
|
||||
case "odscoreatt:asc":
|
||||
return PlayerSortODScoreAttASC, nil
|
||||
case "odscoreatt:desc":
|
||||
return PlayerSortODScoreAttDESC, nil
|
||||
case "odscoredef:asc":
|
||||
return PlayerSortODScoreDefASC, nil
|
||||
case "odscoredef:desc":
|
||||
return PlayerSortODScoreDefDESC, nil
|
||||
case "odscoretotal:asc":
|
||||
return PlayerSortODScoreTotalASC, nil
|
||||
case "odscoretotal:desc":
|
||||
return PlayerSortODScoreTotalDESC, nil
|
||||
case "points:asc":
|
||||
return PlayerSortPointsASC, nil
|
||||
case "points:desc":
|
||||
return PlayerSortPointsDESC, nil
|
||||
case "deletedat:asc":
|
||||
return PlayerSortDeletedAtASC, nil
|
||||
case "deletedat:desc":
|
||||
return PlayerSortDeletedAtDESC, nil
|
||||
func (s PlayerSort) String() string {
|
||||
switch s {
|
||||
case PlayerSortIDASC:
|
||||
return "id:ASC"
|
||||
case PlayerSortIDDESC:
|
||||
return "id:DESC"
|
||||
case PlayerSortServerKeyASC:
|
||||
return "serverKey:ASC"
|
||||
case PlayerSortServerKeyDESC:
|
||||
return "serverKey:DESC"
|
||||
case PlayerSortODScoreAttASC:
|
||||
return "odScoreAtt:ASC"
|
||||
case PlayerSortODScoreAttDESC:
|
||||
return "odScoreAtt:DESC"
|
||||
case PlayerSortODScoreDefASC:
|
||||
return "odScoreDef:ASC"
|
||||
case PlayerSortODScoreDefDESC:
|
||||
return "odScoreDef:DESC"
|
||||
case PlayerSortODScoreTotalASC:
|
||||
return "odScoreTotal:ASC"
|
||||
case PlayerSortODScoreTotalDESC:
|
||||
return "odScoreTotal:DESC"
|
||||
case PlayerSortPointsASC:
|
||||
return "points:ASC"
|
||||
case PlayerSortPointsDESC:
|
||||
return "points:DESC"
|
||||
case PlayerSortDeletedAtASC:
|
||||
return "deletedAt:ASC"
|
||||
case PlayerSortDeletedAtDESC:
|
||||
return "deletedAt:DESC"
|
||||
default:
|
||||
return 0, UnsupportedSortStringError{
|
||||
Sort: s,
|
||||
return "unknown player sort"
|
||||
}
|
||||
}
|
||||
|
||||
func newPlayerSortFromString(s string) (PlayerSort, error) {
|
||||
allowed := []PlayerSort{
|
||||
PlayerSortODScoreAttASC,
|
||||
PlayerSortODScoreAttDESC,
|
||||
PlayerSortODScoreDefASC,
|
||||
PlayerSortODScoreDefDESC,
|
||||
PlayerSortODScoreTotalASC,
|
||||
PlayerSortODScoreTotalDESC,
|
||||
PlayerSortPointsASC,
|
||||
PlayerSortPointsDESC,
|
||||
PlayerSortDeletedAtASC,
|
||||
PlayerSortDeletedAtDESC,
|
||||
}
|
||||
|
||||
for _, a := range allowed {
|
||||
if strings.EqualFold(a.String(), s) {
|
||||
return a, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, UnsupportedSortStringError{
|
||||
Sort: s,
|
||||
}
|
||||
}
|
||||
|
||||
type PlayerCursor struct {
|
||||
|
@ -734,7 +773,7 @@ const (
|
|||
)
|
||||
|
||||
func (params *ListPlayersParams) SetSort(sort []PlayerSort) error {
|
||||
if err := validateSliceLen(sort, playerSortMinLength, playerSortMaxLength); err != nil {
|
||||
if err := validateSort(sort, playerSortMinLength, playerSortMaxLength); err != nil {
|
||||
return ValidationError{
|
||||
Model: listPlayersParamsModelName,
|
||||
Field: "sort",
|
||||
|
@ -756,8 +795,10 @@ func (params *ListPlayersParams) PrependSortString(sort []string) error {
|
|||
}
|
||||
}
|
||||
|
||||
for i := len(sort) - 1; i >= 0; i-- {
|
||||
converted, err := newPlayerSortFromString(sort[i])
|
||||
toPrepend := make([]PlayerSort, 0, len(sort))
|
||||
|
||||
for i, s := range sort {
|
||||
converted, err := newPlayerSortFromString(s)
|
||||
if err != nil {
|
||||
return SliceElementValidationError{
|
||||
Model: listPlayersParamsModelName,
|
||||
|
@ -766,10 +807,10 @@ func (params *ListPlayersParams) PrependSortString(sort []string) error {
|
|||
Err: err,
|
||||
}
|
||||
}
|
||||
params.sort = append([]PlayerSort{converted}, params.sort...)
|
||||
toPrepend = append(toPrepend, converted)
|
||||
}
|
||||
|
||||
return nil
|
||||
return params.SetSort(append(toPrepend, params.sort...))
|
||||
}
|
||||
|
||||
func (params *ListPlayersParams) Cursor() PlayerCursor {
|
||||
|
|
|
@ -3,6 +3,7 @@ package domain
|
|||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -198,6 +199,35 @@ const (
|
|||
PlayerSnapshotSortServerKeyDESC
|
||||
)
|
||||
|
||||
// IsInConflict returns true if two sorts can't be used together
|
||||
// (e.g. PlayerSnapshotSortIDASC and PlayerSnapshotSortIDDESC).
|
||||
func (s PlayerSnapshotSort) IsInConflict(s2 PlayerSnapshotSort) bool {
|
||||
ss := []PlayerSnapshotSort{s, s2}
|
||||
slices.Sort(ss)
|
||||
// ASC is always an odd number, DESC is always an even number
|
||||
return (ss[0]%2 == 1 && ss[0] == ss[1]-1) || ss[0] == ss[1]
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (s PlayerSnapshotSort) String() string {
|
||||
switch s {
|
||||
case PlayerSnapshotSortDateASC:
|
||||
return "date:ASC"
|
||||
case PlayerSnapshotSortDateDESC:
|
||||
return "date:DESC"
|
||||
case PlayerSnapshotSortIDASC:
|
||||
return "id:ASC"
|
||||
case PlayerSnapshotSortIDDESC:
|
||||
return "id:DESC"
|
||||
case PlayerSnapshotSortServerKeyASC:
|
||||
return "serverKey:ASC"
|
||||
case PlayerSnapshotSortServerKeyDESC:
|
||||
return "serverKey:DESC"
|
||||
default:
|
||||
return "unknown player snapshot sort"
|
||||
}
|
||||
}
|
||||
|
||||
const PlayerSnapshotListMaxLimit = 200
|
||||
|
||||
type ListPlayerSnapshotsParams struct {
|
||||
|
@ -239,7 +269,7 @@ const (
|
|||
)
|
||||
|
||||
func (params *ListPlayerSnapshotsParams) SetSort(sort []PlayerSnapshotSort) error {
|
||||
if err := validateSliceLen(sort, playerSnapshotSortMinLength, playerSnapshotSortMaxLength); err != nil {
|
||||
if err := validateSort(sort, playerSnapshotSortMinLength, playerSnapshotSortMaxLength); err != nil {
|
||||
return ValidationError{
|
||||
Model: listPlayerSnapshotsParamsModelName,
|
||||
Field: "sort",
|
||||
|
|
|
@ -44,6 +44,71 @@ func TestNewCreatePlayerSnapshotParams(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPlayerSnapshotSort_IsInConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
sorts [2]domain.PlayerSnapshotSort
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedRes bool
|
||||
}{
|
||||
{
|
||||
name: "OK: id:ASC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSnapshotSort{domain.PlayerSnapshotSortIDASC, domain.PlayerSnapshotSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSnapshotSort{domain.PlayerSnapshotSortIDDESC, domain.PlayerSnapshotSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSnapshotSort{domain.PlayerSnapshotSortIDASC, domain.PlayerSnapshotSortIDASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSnapshotSort{domain.PlayerSnapshotSortIDASC, domain.PlayerSnapshotSortIDDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: date:ASC date:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSnapshotSort{domain.PlayerSnapshotSortDateASC, domain.PlayerSnapshotSortDateDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: serverKey:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSnapshotSort{domain.PlayerSnapshotSortServerKeyDESC, domain.PlayerSnapshotSortServerKeyASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, tt.expectedRes, tt.args.sorts[0].IsInConflict(tt.args.sorts[1]))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPlayerSnapshotsParams_SetSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -100,6 +165,22 @@ func TestListPlayerSnapshotsParams_SetSort(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: conflict",
|
||||
args: args{
|
||||
sort: []domain.PlayerSnapshotSort{
|
||||
domain.PlayerSnapshotSortIDASC,
|
||||
domain.PlayerSnapshotSortIDDESC,
|
||||
},
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListPlayerSnapshotsParams",
|
||||
Field: "sort",
|
||||
Err: domain.SortConflictError{
|
||||
Sort: [2]string{domain.PlayerSnapshotSortIDASC.String(), domain.PlayerSnapshotSortIDDESC.String()},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
@ -228,6 +228,99 @@ func TestNewCreatePlayerParams(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPlayerSort_IsInConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
sorts [2]domain.PlayerSort
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedRes bool
|
||||
}{
|
||||
{
|
||||
name: "OK: id:ASC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSort{domain.PlayerSortIDASC, domain.PlayerSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSort{domain.PlayerSortIDDESC, domain.PlayerSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSort{domain.PlayerSortIDASC, domain.PlayerSortIDASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSort{domain.PlayerSortIDASC, domain.PlayerSortIDDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: serverKey:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSort{domain.PlayerSortServerKeyDESC, domain.PlayerSortServerKeyASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: odScoreAtt:ASC odScoreAtt:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSort{domain.PlayerSortODScoreAttASC, domain.PlayerSortODScoreAttDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: odScoreDef:ASC odScoreDef:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSort{domain.PlayerSortODScoreDefASC, domain.PlayerSortODScoreDefDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: odScoreTotal:ASC odScoreTotal:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSort{domain.PlayerSortODScoreTotalASC, domain.PlayerSortODScoreTotalDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: points:ASC points:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSort{domain.PlayerSortPointsASC, domain.PlayerSortPointsDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: deletedAt:ASC deletedAt:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.PlayerSort{domain.PlayerSortDeletedAtASC, domain.PlayerSortDeletedAtDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, tt.expectedRes, tt.args.sorts[0].IsInConflict(tt.args.sorts[1]))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPlayerCursor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -649,6 +742,22 @@ func TestListPlayersParams_SetSort(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: conflict",
|
||||
args: args{
|
||||
sort: []domain.PlayerSort{
|
||||
domain.PlayerSortIDASC,
|
||||
domain.PlayerSortIDDESC,
|
||||
},
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListPlayersParams",
|
||||
Field: "sort",
|
||||
Err: domain.SortConflictError{
|
||||
Sort: [2]string{domain.PlayerSortIDASC.String(), domain.PlayerSortIDDESC.String()},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
@ -820,6 +929,22 @@ func TestListPlayersParams_PrependSortString(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: conflict",
|
||||
args: args{
|
||||
sort: []string{
|
||||
"odScoreAtt:ASC",
|
||||
"odScoreAtt:DESC",
|
||||
},
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListPlayersParams",
|
||||
Field: "sort",
|
||||
Err: domain.SortConflictError{
|
||||
Sort: [2]string{domain.PlayerSortODScoreAttASC.String(), domain.PlayerSortODScoreAttDESC.String()},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
@ -521,6 +521,29 @@ const (
|
|||
ServerSortOpenDESC
|
||||
)
|
||||
|
||||
// IsInConflict returns true if two sorts can't be used together (e.g. ServerSortKeyASC and ServerSortKeyDESC).
|
||||
func (s ServerSort) IsInConflict(s2 ServerSort) bool {
|
||||
ss := []ServerSort{s, s2}
|
||||
slices.Sort(ss)
|
||||
// ASC is always an odd number, DESC is always an even number
|
||||
return (ss[0]%2 == 1 && ss[0] == ss[1]-1) || ss[0] == ss[1]
|
||||
}
|
||||
|
||||
func (s ServerSort) String() string {
|
||||
switch s {
|
||||
case ServerSortKeyASC:
|
||||
return "key:ASC"
|
||||
case ServerSortKeyDESC:
|
||||
return "key:DESC"
|
||||
case ServerSortOpenASC:
|
||||
return "open:ASC"
|
||||
case ServerSortOpenDESC:
|
||||
return "open:DESC"
|
||||
default:
|
||||
return "unknown server sort"
|
||||
}
|
||||
}
|
||||
|
||||
type ServerCursor struct {
|
||||
key string
|
||||
open bool
|
||||
|
@ -703,7 +726,7 @@ const (
|
|||
)
|
||||
|
||||
func (params *ListServersParams) SetSort(sort []ServerSort) error {
|
||||
if err := validateSliceLen(sort, serverSortMinLength, serverSortMaxLength); err != nil {
|
||||
if err := validateSort(sort, serverSortMinLength, serverSortMaxLength); err != nil {
|
||||
return ValidationError{
|
||||
Model: listServersParamsModelName,
|
||||
Field: "sort",
|
||||
|
|
|
@ -498,6 +498,71 @@ func TestUpdateServerParams_SetNumBonusVillages(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestServerSort_IsInConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
sorts [2]domain.ServerSort
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedRes bool
|
||||
}{
|
||||
{
|
||||
name: "OK: key:ASC open:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.ServerSort{domain.ServerSortKeyASC, domain.ServerSortOpenASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: key:ASC open:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.ServerSort{domain.ServerSortKeyASC, domain.ServerSortOpenDESC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: key:DESC open:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.ServerSort{domain.ServerSortKeyDESC, domain.ServerSortOpenASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: key:ASC key:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.ServerSort{domain.ServerSortKeyASC, domain.ServerSortKeyDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: open:DESC open:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.ServerSort{domain.ServerSortOpenDESC, domain.ServerSortOpenASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: open:DESC open:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.ServerSort{domain.ServerSortOpenDESC, domain.ServerSortOpenDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, tt.expectedRes, tt.args.sorts[0].IsInConflict(tt.args.sorts[1]))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewServerCursor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -609,6 +674,22 @@ func TestListServersParams_SetSort(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: conflict",
|
||||
args: args{
|
||||
sort: []domain.ServerSort{
|
||||
domain.ServerSortKeyASC,
|
||||
domain.ServerSortKeyDESC,
|
||||
},
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListServersParams",
|
||||
Field: "sort",
|
||||
Err: domain.SortConflictError{
|
||||
Sort: [2]string{domain.ServerSortKeyASC.String(), domain.ServerSortKeyDESC.String()},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
@ -450,38 +450,79 @@ const (
|
|||
TribeSortDeletedAtDESC
|
||||
)
|
||||
|
||||
// IsInConflict returns true if two sorts can't be used together (e.g. TribeSortIDASC and TribeSortIDDESC).
|
||||
func (s TribeSort) IsInConflict(s2 TribeSort) bool {
|
||||
ss := []TribeSort{s, s2}
|
||||
slices.Sort(ss)
|
||||
// ASC is always an odd number, DESC is always an even number
|
||||
return (ss[0]%2 == 1 && ss[0] == ss[1]-1) || ss[0] == ss[1]
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func newTribeSortFromString(s string) (TribeSort, error) {
|
||||
switch strings.ToLower(s) {
|
||||
case "odscoreatt:asc":
|
||||
return TribeSortODScoreAttASC, nil
|
||||
case "odscoreatt:desc":
|
||||
return TribeSortODScoreAttDESC, nil
|
||||
case "odscoredef:asc":
|
||||
return TribeSortODScoreDefASC, nil
|
||||
case "odscoredef:desc":
|
||||
return TribeSortODScoreDefDESC, nil
|
||||
case "odscoretotal:asc":
|
||||
return TribeSortODScoreTotalASC, nil
|
||||
case "odscoretotal:desc":
|
||||
return TribeSortODScoreTotalDESC, nil
|
||||
case "points:asc":
|
||||
return TribeSortPointsASC, nil
|
||||
case "points:desc":
|
||||
return TribeSortPointsDESC, nil
|
||||
case "dominance:asc":
|
||||
return TribeSortDominanceASC, nil
|
||||
case "dominance:desc":
|
||||
return TribeSortDominanceDESC, nil
|
||||
case "deletedat:asc":
|
||||
return TribeSortDeletedAtASC, nil
|
||||
case "deletedat:desc":
|
||||
return TribeSortDeletedAtDESC, nil
|
||||
func (s TribeSort) String() string {
|
||||
switch s {
|
||||
case TribeSortIDASC:
|
||||
return "id:ASC"
|
||||
case TribeSortIDDESC:
|
||||
return "id:DESC"
|
||||
case TribeSortServerKeyASC:
|
||||
return "serverKey:ASC"
|
||||
case TribeSortServerKeyDESC:
|
||||
return "serverKey:DESC"
|
||||
case TribeSortODScoreAttASC:
|
||||
return "odScoreAtt:ASC"
|
||||
case TribeSortODScoreAttDESC:
|
||||
return "odScoreAtt:DESC"
|
||||
case TribeSortODScoreDefASC:
|
||||
return "odScoreDef:ASC"
|
||||
case TribeSortODScoreDefDESC:
|
||||
return "odScoreDef:DESC"
|
||||
case TribeSortODScoreTotalASC:
|
||||
return "odScoreTotal:ASC"
|
||||
case TribeSortODScoreTotalDESC:
|
||||
return "odScoreTotal:DESC"
|
||||
case TribeSortPointsASC:
|
||||
return "points:ASC"
|
||||
case TribeSortPointsDESC:
|
||||
return "points:DESC"
|
||||
case TribeSortDominanceASC:
|
||||
return "dominance:ASC"
|
||||
case TribeSortDominanceDESC:
|
||||
return "dominance:DESC"
|
||||
case TribeSortDeletedAtASC:
|
||||
return "deletedAt:ASC"
|
||||
case TribeSortDeletedAtDESC:
|
||||
return "deletedAt:DESC"
|
||||
default:
|
||||
return 0, UnsupportedSortStringError{
|
||||
Sort: s,
|
||||
return "unknown tribe sort"
|
||||
}
|
||||
}
|
||||
|
||||
func newTribeSortFromString(s string) (TribeSort, error) {
|
||||
allowed := []TribeSort{
|
||||
TribeSortODScoreAttASC,
|
||||
TribeSortODScoreAttDESC,
|
||||
TribeSortODScoreDefASC,
|
||||
TribeSortODScoreDefDESC,
|
||||
TribeSortODScoreTotalASC,
|
||||
TribeSortODScoreTotalDESC,
|
||||
TribeSortPointsASC,
|
||||
TribeSortPointsDESC,
|
||||
TribeSortDominanceASC,
|
||||
TribeSortDominanceDESC,
|
||||
TribeSortDeletedAtASC,
|
||||
TribeSortDeletedAtDESC,
|
||||
}
|
||||
|
||||
for _, a := range allowed {
|
||||
if strings.EqualFold(a.String(), s) {
|
||||
return a, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, UnsupportedSortStringError{
|
||||
Sort: s,
|
||||
}
|
||||
}
|
||||
|
||||
type TribeCursor struct {
|
||||
|
@ -735,7 +776,19 @@ func (params *ListTribesParams) ServerKeys() []string {
|
|||
}
|
||||
|
||||
func (params *ListTribesParams) SetServerKeys(serverKeys []string) error {
|
||||
for i, sk := range serverKeys {
|
||||
if err := validateServerKey(sk); err != nil {
|
||||
return SliceElementValidationError{
|
||||
Model: listTribesParamsModelName,
|
||||
Field: "serverKeys",
|
||||
Index: i,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params.serverKeys = serverKeys
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -781,7 +834,7 @@ const (
|
|||
)
|
||||
|
||||
func (params *ListTribesParams) SetSort(sort []TribeSort) error {
|
||||
if err := validateSliceLen(sort, tribeSortMinLength, tribeSortMaxLength); err != nil {
|
||||
if err := validateSort(sort, tribeSortMinLength, tribeSortMaxLength); err != nil {
|
||||
return ValidationError{
|
||||
Model: listTribesParamsModelName,
|
||||
Field: "sort",
|
||||
|
@ -803,8 +856,10 @@ func (params *ListTribesParams) PrependSortString(sort []string) error {
|
|||
}
|
||||
}
|
||||
|
||||
for i := len(sort) - 1; i >= 0; i-- {
|
||||
converted, err := newTribeSortFromString(sort[i])
|
||||
toPrepend := make([]TribeSort, 0, len(sort))
|
||||
|
||||
for i, s := range sort {
|
||||
converted, err := newTribeSortFromString(s)
|
||||
if err != nil {
|
||||
return SliceElementValidationError{
|
||||
Model: listTribesParamsModelName,
|
||||
|
@ -813,10 +868,10 @@ func (params *ListTribesParams) PrependSortString(sort []string) error {
|
|||
Err: err,
|
||||
}
|
||||
}
|
||||
params.sort = append([]TribeSort{converted}, params.sort...)
|
||||
toPrepend = append(toPrepend, converted)
|
||||
}
|
||||
|
||||
return nil
|
||||
return params.SetSort(append(toPrepend, params.sort...))
|
||||
}
|
||||
|
||||
func (params *ListTribesParams) Cursor() TribeCursor {
|
||||
|
|
|
@ -213,6 +213,34 @@ const (
|
|||
TribeChangeSortServerKeyDESC
|
||||
)
|
||||
|
||||
// IsInConflict returns true if two sorts can't be used together (e.g. TribeChangeSortIDASC and TribeChangeSortIDDESC).
|
||||
func (s TribeChangeSort) IsInConflict(s2 TribeChangeSort) bool {
|
||||
ss := []TribeChangeSort{s, s2}
|
||||
slices.Sort(ss)
|
||||
// ASC is always an odd number, DESC is always an even number
|
||||
return (ss[0]%2 == 1 && ss[0] == ss[1]-1) || ss[0] == ss[1]
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (s TribeChangeSort) String() string {
|
||||
switch s {
|
||||
case TribeChangeSortCreatedAtASC:
|
||||
return "createdAt:ASC"
|
||||
case TribeChangeSortCreatedAtDESC:
|
||||
return "createdAt:DESC"
|
||||
case TribeChangeSortIDASC:
|
||||
return "id:ASC"
|
||||
case TribeChangeSortIDDESC:
|
||||
return "id:DESC"
|
||||
case TribeChangeSortServerKeyASC:
|
||||
return "serverKey:ASC"
|
||||
case TribeChangeSortServerKeyDESC:
|
||||
return "serverKey:DESC"
|
||||
default:
|
||||
return "unknown tribe change sort"
|
||||
}
|
||||
}
|
||||
|
||||
type ListTribeChangesParams struct {
|
||||
serverKeys []string
|
||||
sort []TribeChangeSort
|
||||
|
@ -255,7 +283,7 @@ const (
|
|||
)
|
||||
|
||||
func (params *ListTribeChangesParams) SetSort(sort []TribeChangeSort) error {
|
||||
if err := validateSliceLen(sort, tribeChangeSortMinLength, tribeChangeSortMaxLength); err != nil {
|
||||
if err := validateSort(sort, tribeChangeSortMinLength, tribeChangeSortMaxLength); err != nil {
|
||||
return ValidationError{
|
||||
Model: listTribeChangesParamsModelName,
|
||||
Field: "sort",
|
||||
|
|
|
@ -214,6 +214,71 @@ func TestNewCreateTribeChangeParamsFromPlayers(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTribeChangeSort_IsInConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
sorts [2]domain.TribeChangeSort
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedRes bool
|
||||
}{
|
||||
{
|
||||
name: "OK: id:ASC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeChangeSort{domain.TribeChangeSortIDASC, domain.TribeChangeSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeChangeSort{domain.TribeChangeSortIDDESC, domain.TribeChangeSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeChangeSort{domain.TribeChangeSortIDASC, domain.TribeChangeSortIDASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeChangeSort{domain.TribeChangeSortIDDESC, domain.TribeChangeSortIDDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: createdAt:ASC createdAt:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeChangeSort{domain.TribeChangeSortCreatedAtDESC, domain.TribeChangeSortCreatedAtDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: serverKey:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeChangeSort{domain.TribeChangeSortServerKeyDESC, domain.TribeChangeSortServerKeyASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, tt.expectedRes, tt.args.sorts[0].IsInConflict(tt.args.sorts[1]))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListTribeChangesParams_SetSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -270,6 +335,22 @@ func TestListTribeChangesParams_SetSort(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: conflict",
|
||||
args: args{
|
||||
sort: []domain.TribeChangeSort{
|
||||
domain.TribeChangeSortIDASC,
|
||||
domain.TribeChangeSortIDDESC,
|
||||
},
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListTribeChangesParams",
|
||||
Field: "sort",
|
||||
Err: domain.SortConflictError{
|
||||
Sort: [2]string{domain.TribeChangeSortIDASC.String(), domain.TribeChangeSortIDDESC.String()},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
@ -3,6 +3,7 @@ package domain
|
|||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -224,6 +225,35 @@ const (
|
|||
TribeSnapshotSortServerKeyDESC
|
||||
)
|
||||
|
||||
// IsInConflict returns true if two sorts can't be used together
|
||||
// (e.g. TribeSnapshotSortIDASC and TribeSnapshotSortIDDESC).
|
||||
func (s TribeSnapshotSort) IsInConflict(s2 TribeSnapshotSort) bool {
|
||||
ss := []TribeSnapshotSort{s, s2}
|
||||
slices.Sort(ss)
|
||||
// ASC is always an odd number, DESC is always an even number
|
||||
return (ss[0]%2 == 1 && ss[0] == ss[1]-1) || ss[0] == ss[1]
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (s TribeSnapshotSort) String() string {
|
||||
switch s {
|
||||
case TribeSnapshotSortDateASC:
|
||||
return "date:ASC"
|
||||
case TribeSnapshotSortDateDESC:
|
||||
return "date:DESC"
|
||||
case TribeSnapshotSortIDASC:
|
||||
return "id:ASC"
|
||||
case TribeSnapshotSortIDDESC:
|
||||
return "id:DESC"
|
||||
case TribeSnapshotSortServerKeyASC:
|
||||
return "serverKey:ASC"
|
||||
case TribeSnapshotSortServerKeyDESC:
|
||||
return "serverKey:DESC"
|
||||
default:
|
||||
return "unknown tribe snapshot sort"
|
||||
}
|
||||
}
|
||||
|
||||
type ListTribeSnapshotsParams struct {
|
||||
serverKeys []string
|
||||
sort []TribeSnapshotSort
|
||||
|
@ -266,7 +296,7 @@ const (
|
|||
)
|
||||
|
||||
func (params *ListTribeSnapshotsParams) SetSort(sort []TribeSnapshotSort) error {
|
||||
if err := validateSliceLen(sort, tribeSnapshotSortMinLength, tribeSnapshotSortMaxLength); err != nil {
|
||||
if err := validateSort(sort, tribeSnapshotSortMinLength, tribeSnapshotSortMaxLength); err != nil {
|
||||
return ValidationError{
|
||||
Model: listTribeSnapshotsParamsModelName,
|
||||
Field: "sort",
|
||||
|
|
|
@ -46,6 +46,71 @@ func TestNewCreateTribeSnapshotParams(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTribeSnapshotSort_IsInConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
sorts [2]domain.TribeSnapshotSort
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedRes bool
|
||||
}{
|
||||
{
|
||||
name: "OK: id:ASC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSnapshotSort{domain.TribeSnapshotSortIDASC, domain.TribeSnapshotSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSnapshotSort{domain.TribeSnapshotSortIDDESC, domain.TribeSnapshotSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSnapshotSort{domain.TribeSnapshotSortIDASC, domain.TribeSnapshotSortIDASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSnapshotSort{domain.TribeSnapshotSortIDASC, domain.TribeSnapshotSortIDDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: date:ASC date:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSnapshotSort{domain.TribeSnapshotSortDateASC, domain.TribeSnapshotSortDateDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: serverKey:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSnapshotSort{domain.TribeSnapshotSortServerKeyDESC, domain.TribeSnapshotSortServerKeyASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, tt.expectedRes, tt.args.sorts[0].IsInConflict(tt.args.sorts[1]))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListTribeSnapshotsParams_SetSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -102,6 +167,22 @@ func TestListTribeSnapshotsParams_SetSort(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: conflict",
|
||||
args: args{
|
||||
sort: []domain.TribeSnapshotSort{
|
||||
domain.TribeSnapshotSortIDASC,
|
||||
domain.TribeSnapshotSortIDDESC,
|
||||
},
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListTribeSnapshotsParams",
|
||||
Field: "sort",
|
||||
Err: domain.SortConflictError{
|
||||
Sort: [2]string{domain.TribeSnapshotSortIDASC.String(), domain.TribeSnapshotSortIDDESC.String()},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
@ -180,6 +180,106 @@ func TestNewCreateTribeParams(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTribeSort_IsInConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
sorts [2]domain.TribeSort
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedRes bool
|
||||
}{
|
||||
{
|
||||
name: "OK: id:ASC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSort{domain.TribeSortIDASC, domain.TribeSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSort{domain.TribeSortIDDESC, domain.TribeSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSort{domain.TribeSortIDASC, domain.TribeSortIDASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSort{domain.TribeSortIDASC, domain.TribeSortIDDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: serverKey:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSort{domain.TribeSortServerKeyDESC, domain.TribeSortServerKeyASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: odScoreAtt:ASC odScoreAtt:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSort{domain.TribeSortODScoreAttASC, domain.TribeSortODScoreAttDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: odScoreDef:ASC odScoreDef:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSort{domain.TribeSortODScoreDefASC, domain.TribeSortODScoreDefDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: odScoreTotal:ASC odScoreTotal:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSort{domain.TribeSortODScoreTotalASC, domain.TribeSortODScoreTotalDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: points:ASC points:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSort{domain.TribeSortPointsASC, domain.TribeSortPointsDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: dominance:ASC dominance:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSort{domain.TribeSortDominanceASC, domain.TribeSortDominanceDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: deletedAt:ASC deletedAt:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.TribeSort{domain.TribeSortDeletedAtASC, domain.TribeSortDeletedAtDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, tt.expectedRes, tt.args.sorts[0].IsInConflict(tt.args.sorts[1]))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTribeCursor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -436,6 +536,60 @@ func TestListTribesParams_SetIDs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestListTribesParams_SetServerKeys(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
serverKeys []string
|
||||
}
|
||||
|
||||
type test struct {
|
||||
name string
|
||||
args args
|
||||
expectedErr error
|
||||
}
|
||||
|
||||
tests := []test{
|
||||
{
|
||||
name: "OK",
|
||||
args: args{
|
||||
serverKeys: []string{
|
||||
domaintest.RandServerKey(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, serverKeyTest := range newServerKeyValidationTests() {
|
||||
tests = append(tests, test{
|
||||
name: serverKeyTest.name,
|
||||
args: args{
|
||||
serverKeys: []string{serverKeyTest.key},
|
||||
},
|
||||
expectedErr: domain.SliceElementValidationError{
|
||||
Model: "ListTribesParams",
|
||||
Field: "serverKeys",
|
||||
Index: 0,
|
||||
Err: serverKeyTest.expectedErr,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params := domain.NewListTribesParams()
|
||||
|
||||
require.ErrorIs(t, params.SetServerKeys(tt.args.serverKeys), tt.expectedErr)
|
||||
if tt.expectedErr != nil {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, tt.args.serverKeys, params.ServerKeys())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListTribesParams_SetTags(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -570,6 +724,22 @@ func TestListTribesParams_SetSort(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: conflict",
|
||||
args: args{
|
||||
sort: []domain.TribeSort{
|
||||
domain.TribeSortIDASC,
|
||||
domain.TribeSortIDDESC,
|
||||
},
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListTribesParams",
|
||||
Field: "sort",
|
||||
Err: domain.SortConflictError{
|
||||
Sort: [2]string{domain.TribeSortIDASC.String(), domain.TribeSortIDDESC.String()},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
@ -745,6 +915,22 @@ func TestListTribesParams_PrependSortString(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: conflict",
|
||||
args: args{
|
||||
sort: []string{
|
||||
"odScoreAtt:ASC",
|
||||
"odScoreAtt:DESC",
|
||||
},
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListTribesParams",
|
||||
Field: "sort",
|
||||
Err: domain.SortConflictError{
|
||||
Sort: [2]string{domain.TribeSortODScoreAttASC.String(), domain.TribeSortODScoreAttDESC.String()},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
@ -244,6 +244,30 @@ func (e UnsupportedSortStringError) Params() map[string]any {
|
|||
}
|
||||
}
|
||||
|
||||
type SortConflictError struct {
|
||||
Sort [2]string
|
||||
}
|
||||
|
||||
var _ ErrorWithParams = SortConflictError{}
|
||||
|
||||
func (e SortConflictError) Error() string {
|
||||
return fmt.Sprintf("sort values %s are in conflict and can't be used together", e.Sort[0]+" and "+e.Sort[1])
|
||||
}
|
||||
|
||||
func (e SortConflictError) Type() ErrorType {
|
||||
return ErrorTypeIncorrectInput
|
||||
}
|
||||
|
||||
func (e SortConflictError) Code() string {
|
||||
return "sort-conflict"
|
||||
}
|
||||
|
||||
func (e SortConflictError) Params() map[string]any {
|
||||
return map[string]any{
|
||||
"Sort": e.Sort,
|
||||
}
|
||||
}
|
||||
|
||||
var ErrRequired error = simpleError{
|
||||
msg: "can't be blank",
|
||||
typ: ErrorTypeIncorrectInput,
|
||||
|
@ -322,3 +346,25 @@ func validateIntInRange(current, min, max int) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateSort[S ~[]E, E interface {
|
||||
IsInConflict(s E) bool
|
||||
String() string
|
||||
}](sort S, min, max int) error {
|
||||
if err := validateSliceLen(sort, min, max); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, s1 := range sort {
|
||||
for j := i + 1; j < len(sort); j++ {
|
||||
s2 := sort[j]
|
||||
if s1.IsInConflict(s2) {
|
||||
return SortConflictError{
|
||||
Sort: [2]string{s1.String(), s2.String()},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package domain
|
|||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type Version struct {
|
||||
|
@ -100,6 +101,25 @@ const (
|
|||
VersionSortCodeDESC
|
||||
)
|
||||
|
||||
// IsInConflict returns true if two sorts can't be used together (e.g. VersionSortCodeASC and VersionSortCodeDESC).
|
||||
func (s VersionSort) IsInConflict(s2 VersionSort) bool {
|
||||
ss := []VersionSort{s, s2}
|
||||
slices.Sort(ss)
|
||||
// ASC is always an odd number, DESC is always an even number
|
||||
return (ss[0]%2 == 1 && ss[0] == ss[1]-1) || ss[0] == ss[1]
|
||||
}
|
||||
|
||||
func (s VersionSort) String() string {
|
||||
switch s {
|
||||
case VersionSortCodeASC:
|
||||
return "code:ASC"
|
||||
case VersionSortCodeDESC:
|
||||
return "code:DESC"
|
||||
default:
|
||||
return "unknown version sort"
|
||||
}
|
||||
}
|
||||
|
||||
type VersionCursor struct {
|
||||
code string
|
||||
}
|
||||
|
@ -207,7 +227,7 @@ func (params *ListVersionsParams) Sort() []VersionSort {
|
|||
}
|
||||
|
||||
func (params *ListVersionsParams) SetSort(sort []VersionSort) error {
|
||||
if err := validateSliceLen(sort, versionSortMinLength, versionSortMaxLength); err != nil {
|
||||
if err := validateSort(sort, versionSortMinLength, versionSortMaxLength); err != nil {
|
||||
return ValidationError{
|
||||
Model: listVersionsParamsModelName,
|
||||
Field: "sort",
|
||||
|
|
|
@ -11,6 +11,43 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestVersionSort_IsInConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
sorts [2]domain.VersionSort
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedRes bool
|
||||
}{
|
||||
{
|
||||
name: "OK: code:ASC code:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.VersionSort{domain.VersionSortCodeASC, domain.VersionSortCodeASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: code:ASC code:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.VersionSort{domain.VersionSortCodeASC, domain.VersionSortCodeDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, tt.expectedRes, tt.args.sorts[0].IsInConflict(tt.args.sorts[1]))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewVersionCursor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -224,6 +224,30 @@ const (
|
|||
VillageSortServerKeyDESC
|
||||
)
|
||||
|
||||
// IsInConflict returns true if two sorts can't be used together (e.g. VillageSortIDASC and VillageSortIDDESC).
|
||||
func (s VillageSort) IsInConflict(s2 VillageSort) bool {
|
||||
ss := []VillageSort{s, s2}
|
||||
slices.Sort(ss)
|
||||
// ASC is always an odd number, DESC is always an even number
|
||||
return (ss[0]%2 == 1 && ss[0] == ss[1]-1) || ss[0] == ss[1]
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (s VillageSort) String() string {
|
||||
switch s {
|
||||
case VillageSortIDASC:
|
||||
return "id:ASC"
|
||||
case VillageSortIDDESC:
|
||||
return "id:DESC"
|
||||
case VillageSortServerKeyASC:
|
||||
return "serverKey:ASC"
|
||||
case VillageSortServerKeyDESC:
|
||||
return "serverKey:DESC"
|
||||
default:
|
||||
return "unknown village sort"
|
||||
}
|
||||
}
|
||||
|
||||
type ListVillagesParams struct {
|
||||
ids []int
|
||||
idGT NullInt
|
||||
|
@ -308,7 +332,7 @@ const (
|
|||
)
|
||||
|
||||
func (params *ListVillagesParams) SetSort(sort []VillageSort) error {
|
||||
if err := validateSliceLen(sort, villageSortMinLength, villageSortMaxLength); err != nil {
|
||||
if err := validateSort(sort, villageSortMinLength, villageSortMaxLength); err != nil {
|
||||
return ValidationError{
|
||||
Model: listVillagesParamsModelName,
|
||||
Field: "sort",
|
||||
|
|
|
@ -88,6 +88,64 @@ func TestNewCreateVillageParams(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestVillageSort_IsInConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
sorts [2]domain.VillageSort
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedRes bool
|
||||
}{
|
||||
{
|
||||
name: "OK: id:ASC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.VillageSort{domain.VillageSortIDASC, domain.VillageSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.VillageSort{domain.VillageSortIDDESC, domain.VillageSortServerKeyASC},
|
||||
},
|
||||
expectedRes: false,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.VillageSort{domain.VillageSortIDASC, domain.VillageSortIDASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: id:ASC id:DESC",
|
||||
args: args{
|
||||
sorts: [2]domain.VillageSort{domain.VillageSortIDASC, domain.VillageSortIDDESC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
{
|
||||
name: "OK: serverKey:DESC serverKey:ASC",
|
||||
args: args{
|
||||
sorts: [2]domain.VillageSort{domain.VillageSortServerKeyDESC, domain.VillageSortServerKeyASC},
|
||||
},
|
||||
expectedRes: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, tt.expectedRes, tt.args.sorts[0].IsInConflict(tt.args.sorts[1]))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListVillagesParams_SetIDs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -258,6 +316,22 @@ func TestListVillagesParams_SetSort(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: conflict",
|
||||
args: args{
|
||||
sort: []domain.VillageSort{
|
||||
domain.VillageSortIDASC,
|
||||
domain.VillageSortIDDESC,
|
||||
},
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListVillagesParams",
|
||||
Field: "sort",
|
||||
Err: domain.SortConflictError{
|
||||
Sort: [2]string{domain.VillageSortIDASC.String(), domain.VillageSortIDDESC.String()},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
@ -527,6 +527,44 @@ func TestListPlayers(t *testing.T) {
|
|||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: sort conflict",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Add("sort", "odScoreAtt:ASC")
|
||||
q.Add("sort", "odScoreAtt:DESC")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
q := req.URL.Query()
|
||||
domainErr := domain.SortConflictError{
|
||||
Sort: [2]string{q["sort"][0], q["sort"][1]},
|
||||
}
|
||||
paramSort := make([]any, len(domainErr.Sort))
|
||||
for i, s := range domainErr.Sort {
|
||||
paramSort[i] = s
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"sort": paramSort,
|
||||
},
|
||||
Path: []string{"$query", "sort"},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: len(name) > 100",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
|
|
|
@ -527,6 +527,44 @@ func TestListTribes(t *testing.T) {
|
|||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: sort conflict",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Add("sort", "odScoreAtt:ASC")
|
||||
q.Add("sort", "odScoreAtt:DESC")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
q := req.URL.Query()
|
||||
domainErr := domain.SortConflictError{
|
||||
Sort: [2]string{q["sort"][0], q["sort"][1]},
|
||||
}
|
||||
paramSort := make([]any, len(domainErr.Sort))
|
||||
for i, s := range domainErr.Sort {
|
||||
paramSort[i] = s
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"sort": paramSort,
|
||||
},
|
||||
Path: []string{"$query", "sort"},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: len(tag) > 100",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user