From aa5c7fc1f02db332a8235fcc467e3c2e2fa4b005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Wysoki=C5=84ski?= Date: Mon, 25 Mar 2024 07:29:27 +0100 Subject: [PATCH] refactor: new PrependSortString logic --- api/openapi3.yml | 8 +- internal/domain/ennoblement.go | 20 +- internal/domain/ennoblement_test.go | 134 +++++++++---- internal/domain/player.go | 28 +-- internal/domain/player_snapshot.go | 24 +-- internal/domain/player_snapshot_test.go | 130 +++++++++---- internal/domain/player_test.go | 153 +++++++++++---- internal/domain/server.go | 2 +- internal/domain/server_test.go | 13 +- internal/domain/tribe.go | 28 +-- internal/domain/tribe_change.go | 24 +-- internal/domain/tribe_change_test.go | 130 +++++++++---- internal/domain/tribe_snapshot.go | 24 +-- internal/domain/tribe_snapshot_test.go | 130 +++++++++---- internal/domain/tribe_test.go | 155 +++++++++++---- internal/domain/version.go | 2 +- internal/domain/version_test.go | 13 +- internal/domain/village.go | 2 +- internal/domain/village_test.go | 13 +- internal/port/handler_http_api_ennoblement.go | 87 +++++---- .../port/handler_http_api_ennoblement_test.go | 180 ++---------------- internal/port/handler_http_api_player.go | 29 ++- .../port/handler_http_api_player_snapshot.go | 27 ++- .../handler_http_api_player_snapshot_test.go | 45 +---- internal/port/handler_http_api_player_test.go | 4 +- internal/port/handler_http_api_tribe.go | 19 +- .../port/handler_http_api_tribe_change.go | 47 +++-- .../handler_http_api_tribe_change_test.go | 90 +-------- .../port/handler_http_api_tribe_snapshot.go | 27 ++- .../handler_http_api_tribe_snapshot_test.go | 45 +---- internal/port/handler_http_api_tribe_test.go | 2 +- 31 files changed, 872 insertions(+), 763 deletions(-) diff --git a/api/openapi3.yml b/api/openapi3.yml index d7fc623..f19c439 100644 --- a/api/openapi3.yml +++ b/api/openapi3.yml @@ -1737,7 +1737,7 @@ components: enum: - createdAt:ASC - createdAt:DESC - maxItems: 2 + maxItems: 1 TribeChangeSortQueryParam: name: sort in: query @@ -1751,7 +1751,7 @@ components: enum: - createdAt:ASC - createdAt:DESC - maxItems: 2 + maxItems: 1 TribeSnapshotSortQueryParam: name: sort in: query @@ -1765,7 +1765,7 @@ components: enum: - date:ASC - date:DESC - maxItems: 2 + maxItems: 1 PlayerSnapshotSortQueryParam: name: sort in: query @@ -1779,7 +1779,7 @@ components: enum: - date:ASC - date:DESC - maxItems: 2 + maxItems: 1 SinceQueryParam: name: since in: query diff --git a/internal/domain/ennoblement.go b/internal/domain/ennoblement.go index a56ee57..9348d51 100644 --- a/internal/domain/ennoblement.go +++ b/internal/domain/ennoblement.go @@ -485,7 +485,7 @@ func (params *ListEnnoblementsParams) Sort() []EnnoblementSort { } const ( - ennoblementSortMinLength = 1 + ennoblementSortMinLength = 0 ennoblementSortMaxLength = 3 ) @@ -503,12 +503,12 @@ func (params *ListEnnoblementsParams) SetSort(sort []EnnoblementSort) error { return nil } -func (params *ListEnnoblementsParams) PrependSortString(sort []string) error { - if err := validateSliceLen( - sort, - ennoblementSortMinLength, - max(ennoblementSortMaxLength-len(params.sort), 0), - ); err != nil { +func (params *ListEnnoblementsParams) PrependSortString(sort []string, allowed []EnnoblementSort, maxLength int) error { + if len(sort) == 0 { + return nil + } + + if err := validateSliceLen(sort, 0, max(min(ennoblementSortMaxLength-len(params.sort), maxLength), 0)); err != nil { return ValidationError{ Model: listEnnoblementsParamsModelName, Field: "sort", @@ -519,11 +519,7 @@ func (params *ListEnnoblementsParams) PrependSortString(sort []string) error { toPrepend := make([]EnnoblementSort, 0, len(sort)) for i, s := range sort { - converted, err := newSortFromString( - s, - EnnoblementSortCreatedAtASC, - EnnoblementSortCreatedAtDESC, - ) + converted, err := newSortFromString(s, allowed...) if err != nil { return SliceElementValidationError{ Model: listEnnoblementsParamsModelName, diff --git a/internal/domain/ennoblement_test.go b/internal/domain/ennoblement_test.go index bca0fb9..f9918c6 100644 --- a/internal/domain/ennoblement_test.go +++ b/internal/domain/ennoblement_test.go @@ -442,19 +442,10 @@ func TestListEnnoblementsParams_SetSort(t *testing.T) { }, }, { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListEnnoblementsParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, - }, - }, }, { name: "ERR: len(sort) > 3", @@ -470,7 +461,7 @@ func TestListEnnoblementsParams_SetSort(t *testing.T) { Model: "ListEnnoblementsParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 3, Current: 4, }, @@ -516,9 +507,20 @@ func TestListEnnoblementsParams_PrependSortString(t *testing.T) { t.Helper() return domain.ListEnnoblementsParams{} } + defaultAllowed := []domain.EnnoblementSort{ + domain.EnnoblementSortCreatedAtASC, + domain.EnnoblementSortCreatedAtDESC, + domain.EnnoblementSortIDASC, + domain.EnnoblementSortIDDESC, + domain.EnnoblementSortServerKeyASC, + domain.EnnoblementSortServerKeyDESC, + } + defaultMaxLength := 3 type args struct { - sort []string + sort []string + allowed []domain.EnnoblementSort + maxLength int } tests := []struct { @@ -529,44 +531,73 @@ func TestListEnnoblementsParams_PrependSortString(t *testing.T) { expectedErr error }{ { - name: "OK: [createdAt:ASC]", + name: "OK: [serverKey:ASC, createdAt:ASC, id:ASC]", + args: args{ + sort: []string{ + "serverKey:ASC", + "createdAt:ASC", + "id:ASC", + }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, + }, + expectedSort: []domain.EnnoblementSort{ + domain.EnnoblementSortServerKeyASC, + domain.EnnoblementSortCreatedAtASC, + domain.EnnoblementSortIDASC, + }, + }, + { + name: "OK: [serverKey:DESC, createdAt:DESC, id:DESC]", + args: args{ + sort: []string{ + "serverKey:DESC", + "createdAt:DESC", + "id:DESC", + }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, + }, + expectedSort: []domain.EnnoblementSort{ + domain.EnnoblementSortServerKeyDESC, + domain.EnnoblementSortCreatedAtDESC, + domain.EnnoblementSortIDDESC, + }, + }, + { + name: "OK: custom params", + newParams: func(t *testing.T) domain.ListEnnoblementsParams { + t.Helper() + params := domain.NewListEnnoblementsParams() + require.NoError(t, params.SetSort([]domain.EnnoblementSort{ + domain.EnnoblementSortIDASC, + domain.EnnoblementSortServerKeyASC, + })) + return params + }, args: args{ sort: []string{ "createdAt:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.EnnoblementSort{ domain.EnnoblementSortCreatedAtASC, + domain.EnnoblementSortIDASC, + domain.EnnoblementSortServerKeyASC, }, }, { - name: "OK: [createdAt:DESC]", + name: "OK: empty slice", args: args{ - sort: []string{ - "createdAt:DESC", - }, - }, - expectedSort: []domain.EnnoblementSort{ - domain.EnnoblementSortCreatedAtDESC, + sort: nil, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, }, { - name: "ERR: len(sort) < 1", - args: args{ - sort: nil, - }, - expectedErr: domain.ValidationError{ - Model: "ListEnnoblementsParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, - }, - }, - }, - { - name: "ERR: custom params + len(sort) > 1", + name: "ERR: custom params + len(sort) > sortMaxLength - len(sort)", newParams: func(t *testing.T) domain.ListEnnoblementsParams { t.Helper() params := domain.NewListEnnoblementsParams() @@ -581,12 +612,35 @@ func TestListEnnoblementsParams_PrependSortString(t *testing.T) { "createdAt:ASC", "createdAt:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListEnnoblementsParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, + Max: 1, + Current: 2, + }, + }, + }, + { + name: "ERR: len(sort) > maxLength", + newParams: defaultNewParams, + args: args{ + sort: []string{ + "serverKey:ASC", + "createdAt:ASC", + }, + allowed: defaultAllowed, + maxLength: 1, + }, + expectedErr: domain.ValidationError{ + Model: "ListEnnoblementsParams", + Field: "sort", + Err: domain.LenOutOfRangeError{ + Min: 0, Max: 1, Current: 2, }, @@ -599,6 +653,8 @@ func TestListEnnoblementsParams_PrependSortString(t *testing.T) { sort: []string{ "createdAt:", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.SliceElementValidationError{ Model: "ListEnnoblementsParams", @@ -616,6 +672,8 @@ func TestListEnnoblementsParams_PrependSortString(t *testing.T) { "createdAt:ASC", "createdAt:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListEnnoblementsParams", @@ -637,7 +695,7 @@ func TestListEnnoblementsParams_PrependSortString(t *testing.T) { } params := newParams(t) - require.ErrorIs(t, params.PrependSortString(tt.args.sort), tt.expectedErr) + require.ErrorIs(t, params.PrependSortString(tt.args.sort, tt.args.allowed, tt.args.maxLength), tt.expectedErr) if tt.expectedErr != nil { return } diff --git a/internal/domain/player.go b/internal/domain/player.go index de5baea..ecd6ec1 100644 --- a/internal/domain/player.go +++ b/internal/domain/player.go @@ -940,8 +940,8 @@ func (params *ListPlayersParams) Sort() []PlayerSort { } const ( - playerSortMinLength = 1 - playerSortMaxLength = 3 + playerSortMinLength = 0 + playerSortMaxLength = 4 ) func (params *ListPlayersParams) SetSort(sort []PlayerSort) error { @@ -958,8 +958,12 @@ func (params *ListPlayersParams) SetSort(sort []PlayerSort) error { return nil } -func (params *ListPlayersParams) PrependSortString(sort []string) error { - if err := validateSliceLen(sort, playerSortMinLength, max(playerSortMaxLength-len(params.sort), 0)); err != nil { +func (params *ListPlayersParams) PrependSortString(sort []string, allowed []PlayerSort, maxLength int) error { + if len(sort) == 0 { + return nil + } + + if err := validateSliceLen(sort, 0, max(min(playerSortMaxLength-len(params.sort), maxLength), 0)); err != nil { return ValidationError{ Model: listPlayersParamsModelName, Field: "sort", @@ -970,21 +974,7 @@ func (params *ListPlayersParams) PrependSortString(sort []string) error { toPrepend := make([]PlayerSort, 0, len(sort)) for i, s := range sort { - converted, err := newSortFromString( - s, - PlayerSortODScoreAttASC, - PlayerSortODScoreAttDESC, - PlayerSortODScoreDefASC, - PlayerSortODScoreDefDESC, - PlayerSortODScoreSupASC, - PlayerSortODScoreSupDESC, - PlayerSortODScoreTotalASC, - PlayerSortODScoreTotalDESC, - PlayerSortPointsASC, - PlayerSortPointsDESC, - PlayerSortDeletedAtASC, - PlayerSortDeletedAtDESC, - ) + converted, err := newSortFromString(s, allowed...) if err != nil { return SliceElementValidationError{ Model: listPlayersParamsModelName, diff --git a/internal/domain/player_snapshot.go b/internal/domain/player_snapshot.go index f037e4c..a872141 100644 --- a/internal/domain/player_snapshot.go +++ b/internal/domain/player_snapshot.go @@ -431,7 +431,7 @@ func (params *ListPlayerSnapshotsParams) Sort() []PlayerSnapshotSort { } const ( - playerSnapshotSortMinLength = 1 + playerSnapshotSortMinLength = 0 playerSnapshotSortMaxLength = 3 ) @@ -449,12 +449,16 @@ func (params *ListPlayerSnapshotsParams) SetSort(sort []PlayerSnapshotSort) erro return nil } -func (params *ListPlayerSnapshotsParams) PrependSortString(sort []string) error { - if err := validateSliceLen( - sort, - playerSnapshotSortMinLength, - max(playerSnapshotSortMaxLength-len(params.sort), 0), - ); err != nil { +func (params *ListPlayerSnapshotsParams) PrependSortString( + sort []string, + allowed []PlayerSnapshotSort, + maxLength int, +) error { + if len(sort) == 0 { + return nil + } + + if err := validateSliceLen(sort, 0, max(min(playerSnapshotSortMaxLength-len(params.sort), maxLength), 0)); err != nil { return ValidationError{ Model: listPlayerSnapshotsParamsModelName, Field: "sort", @@ -465,11 +469,7 @@ func (params *ListPlayerSnapshotsParams) PrependSortString(sort []string) error toPrepend := make([]PlayerSnapshotSort, 0, len(sort)) for i, s := range sort { - converted, err := newSortFromString( - s, - PlayerSnapshotSortDateASC, - PlayerSnapshotSortDateDESC, - ) + converted, err := newSortFromString(s, allowed...) if err != nil { return SliceElementValidationError{ Model: listPlayerSnapshotsParamsModelName, diff --git a/internal/domain/player_snapshot_test.go b/internal/domain/player_snapshot_test.go index c46c2e7..8df6f4a 100644 --- a/internal/domain/player_snapshot_test.go +++ b/internal/domain/player_snapshot_test.go @@ -327,19 +327,10 @@ func TestListPlayerSnapshotsParams_SetSort(t *testing.T) { }, }, { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListPlayerSnapshotsParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, - }, - }, }, { name: "ERR: len(sort) > 3", @@ -355,7 +346,7 @@ func TestListPlayerSnapshotsParams_SetSort(t *testing.T) { Model: "ListPlayerSnapshotsParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 3, Current: 4, }, @@ -401,9 +392,20 @@ func TestListPlayerSnapshotsParams_PrependSortString(t *testing.T) { t.Helper() return domain.ListPlayerSnapshotsParams{} } + defaultAllowed := []domain.PlayerSnapshotSort{ + domain.PlayerSnapshotSortDateASC, + domain.PlayerSnapshotSortDateDESC, + domain.PlayerSnapshotSortIDASC, + domain.PlayerSnapshotSortIDDESC, + domain.PlayerSnapshotSortServerKeyASC, + domain.PlayerSnapshotSortServerKeyDESC, + } + defaultMaxLength := 3 type args struct { - sort []string + sort []string + allowed []domain.PlayerSnapshotSort + maxLength int } tests := []struct { @@ -414,44 +416,71 @@ func TestListPlayerSnapshotsParams_PrependSortString(t *testing.T) { expectedErr error }{ { - name: "OK: [date:ASC]", + name: "OK: [id:ASC, date:ASC, serverKey:ASC]", + args: args{ + sort: []string{ + "id:ASC", + "date:ASC", + "serverKey:ASC", + }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, + }, + expectedSort: []domain.PlayerSnapshotSort{ + domain.PlayerSnapshotSortIDASC, + domain.PlayerSnapshotSortDateASC, + domain.PlayerSnapshotSortServerKeyASC, + }, + }, + { + name: "OK: [id:DESC, date:DESC, serverKey:DESC]", + args: args{ + sort: []string{ + "id:DESC", + "date:DESC", + "serverKey:DESC", + }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, + }, + expectedSort: []domain.PlayerSnapshotSort{ + domain.PlayerSnapshotSortIDDESC, + domain.PlayerSnapshotSortDateDESC, + domain.PlayerSnapshotSortServerKeyDESC, + }, + }, + { + name: "OK: custom params", + newParams: func(t *testing.T) domain.ListPlayerSnapshotsParams { + t.Helper() + params := domain.NewListPlayerSnapshotsParams() + require.NoError(t, params.SetSort([]domain.PlayerSnapshotSort{ + domain.PlayerSnapshotSortIDASC, + domain.PlayerSnapshotSortServerKeyASC, + })) + return params + }, args: args{ sort: []string{ "date:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.PlayerSnapshotSort{ domain.PlayerSnapshotSortDateASC, + domain.PlayerSnapshotSortIDASC, + domain.PlayerSnapshotSortServerKeyASC, }, }, { - name: "OK: [date:DESC]", - args: args{ - sort: []string{ - "date:DESC", - }, - }, - expectedSort: []domain.PlayerSnapshotSort{ - domain.PlayerSnapshotSortDateDESC, - }, - }, - { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListPlayerSnapshotsParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, - }, - }, }, { - name: "ERR: custom params + len(sort) > 1", + name: "ERR: custom params + len(sort) > sortMaxLength - len(sort)", newParams: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() @@ -466,12 +495,35 @@ func TestListPlayerSnapshotsParams_PrependSortString(t *testing.T) { "date:ASC", "date:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListPlayerSnapshotsParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, + Max: 1, + Current: 2, + }, + }, + }, + { + name: "ERR: len(sort) > maxLength", + newParams: defaultNewParams, + args: args{ + sort: []string{ + "serverKey:ASC", + "date:ASC", + }, + allowed: defaultAllowed, + maxLength: 1, + }, + expectedErr: domain.ValidationError{ + Model: "ListPlayerSnapshotsParams", + Field: "sort", + Err: domain.LenOutOfRangeError{ + Min: 0, Max: 1, Current: 2, }, @@ -484,6 +536,8 @@ func TestListPlayerSnapshotsParams_PrependSortString(t *testing.T) { sort: []string{ "date:", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.SliceElementValidationError{ Model: "ListPlayerSnapshotsParams", @@ -501,6 +555,8 @@ func TestListPlayerSnapshotsParams_PrependSortString(t *testing.T) { "date:ASC", "date:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListPlayerSnapshotsParams", @@ -522,7 +578,7 @@ func TestListPlayerSnapshotsParams_PrependSortString(t *testing.T) { } params := newParams(t) - require.ErrorIs(t, params.PrependSortString(tt.args.sort), tt.expectedErr) + require.ErrorIs(t, params.PrependSortString(tt.args.sort, tt.args.allowed, tt.args.maxLength), tt.expectedErr) if tt.expectedErr != nil { return } diff --git a/internal/domain/player_test.go b/internal/domain/player_test.go index 6ae5384..ce2f154 100644 --- a/internal/domain/player_test.go +++ b/internal/domain/player_test.go @@ -837,37 +837,29 @@ func TestListPlayersParams_SetSort(t *testing.T) { }, }, { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListPlayersParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, - }, - }, }, { - name: "ERR: len(sort) > 3", + name: "ERR: len(sort) > 4", args: args{ sort: []domain.PlayerSort{ domain.PlayerSortDeletedAtDESC, domain.PlayerSortPointsASC, domain.PlayerSortIDASC, domain.PlayerSortServerKeyASC, + domain.PlayerSortServerKeyASC, }, }, expectedErr: domain.ValidationError{ Model: "ListPlayersParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 4, + Min: 0, + Max: 4, + Current: 5, }, }, }, @@ -911,9 +903,30 @@ func TestListPlayersParams_PrependSortString(t *testing.T) { t.Helper() return domain.ListPlayersParams{} } + defaultAllowed := []domain.PlayerSort{ + domain.PlayerSortIDASC, + domain.PlayerSortIDDESC, + domain.PlayerSortServerKeyASC, + domain.PlayerSortServerKeyDESC, + domain.PlayerSortODScoreAttASC, + domain.PlayerSortODScoreAttDESC, + domain.PlayerSortODScoreDefASC, + domain.PlayerSortODScoreDefDESC, + domain.PlayerSortODScoreSupASC, + domain.PlayerSortODScoreSupDESC, + domain.PlayerSortODScoreTotalASC, + domain.PlayerSortODScoreTotalDESC, + domain.PlayerSortPointsASC, + domain.PlayerSortPointsDESC, + domain.PlayerSortDeletedAtASC, + domain.PlayerSortDeletedAtDESC, + } + defaultMaxLength := 4 type args struct { - sort []string + sort []string + allowed []domain.PlayerSort + maxLength int } tests := []struct { @@ -924,106 +937,145 @@ func TestListPlayersParams_PrependSortString(t *testing.T) { expectedErr error }{ { - name: "OK: [odScoreAtt:ASC, odScoreDef:ASC, odScoreTotal:ASC]", + name: "OK: [id:ASC, odScoreAtt:ASC, odScoreDef:ASC, odScoreTotal:ASC]", args: args{ sort: []string{ + "id:ASC", "odScoreAtt:ASC", "odScoreDef:ASC", "odScoreTotal:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.PlayerSort{ + domain.PlayerSortIDASC, domain.PlayerSortODScoreAttASC, domain.PlayerSortODScoreDefASC, domain.PlayerSortODScoreTotalASC, }, }, { - name: "OK: [odScoreAtt:DESC, odScoreDef:DESC, odScoreTotal:DESC]", + name: "OK: [id:DESC, odScoreAtt:DESC, odScoreDef:DESC, odScoreTotal:DESC]", args: args{ sort: []string{ + "id:DESC", "odScoreAtt:DESC", "odScoreDef:DESC", "odScoreTotal:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.PlayerSort{ + domain.PlayerSortIDDESC, domain.PlayerSortODScoreAttDESC, domain.PlayerSortODScoreDefDESC, domain.PlayerSortODScoreTotalDESC, }, }, { - name: "OK: [odScoreSup:ASC, points:ASC, deletedAt:ASC]", + name: "OK: [serverKey:ASC, odScoreSup:ASC, points:ASC, deletedAt:ASC]", args: args{ sort: []string{ + "serverKey:ASC", "odScoreSup:ASC", "points:ASC", "deletedAt:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.PlayerSort{ + domain.PlayerSortServerKeyASC, domain.PlayerSortODScoreSupASC, domain.PlayerSortPointsASC, domain.PlayerSortDeletedAtASC, }, }, { - name: "OK: [odScoreSup:DESC, points:DESC, deletedAt:DESC]", + name: "OK: [serverKey: DESC, odScoreSup:DESC, points:DESC, deletedAt:DESC]", args: args{ sort: []string{ + "serverKey:DESC", "odScoreSup:DESC", "points:DESC", "deletedAt:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.PlayerSort{ + domain.PlayerSortServerKeyDESC, domain.PlayerSortODScoreSupDESC, domain.PlayerSortPointsDESC, domain.PlayerSortDeletedAtDESC, }, }, { - name: "ERR: len(sort) < 1", - args: args{ - sort: nil, + name: "OK: custom params", + newParams: func(t *testing.T) domain.ListPlayersParams { + t.Helper() + params := domain.NewListPlayersParams() + require.NoError(t, params.SetSort([]domain.PlayerSort{ + domain.PlayerSortIDASC, + domain.PlayerSortServerKeyASC, + })) + return params }, - expectedErr: domain.ValidationError{ - Model: "ListPlayersParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, + args: args{ + sort: []string{ + "points:DESC", + "deletedAt:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, + }, + expectedSort: []domain.PlayerSort{ + domain.PlayerSortPointsDESC, + domain.PlayerSortDeletedAtDESC, + domain.PlayerSortIDASC, + domain.PlayerSortServerKeyASC, }, }, { - name: "ERR: len(sort) > 3", + name: "OK: empty slice", + args: args{ + sort: nil, + }, + }, + { + name: "ERR: len(sort) > 4", args: args{ sort: []string{ "odScoreAtt:ASC", "odScoreDef:ASC", "odScoreTotal:ASC", "points:ASC", + "points:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListPlayersParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 4, + Min: 0, + Max: 4, + Current: 5, }, }, }, { - name: "ERR: custom params + len(sort) > 2", + name: "ERR: custom params + len(sort) > sortMaxLength - len(sort)", newParams: func(t *testing.T) domain.ListPlayersParams { t.Helper() params := domain.NewListPlayersParams() - require.NoError(t, params.SetSort([]domain.PlayerSort{domain.PlayerSortIDASC})) + require.NoError(t, params.SetSort([]domain.PlayerSort{ + domain.PlayerSortIDASC, + domain.PlayerSortServerKeyASC, + })) return params }, args: args{ @@ -1032,17 +1084,40 @@ func TestListPlayersParams_PrependSortString(t *testing.T) { "odScoreDef:ASC", "odScoreTotal:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListPlayersParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 2, Current: 3, }, }, }, + { + name: "ERR: len(sort) > maxLength", + newParams: defaultNewParams, + args: args{ + sort: []string{ + "serverKey:ASC", + "odScoreAtt:ASC", + }, + allowed: defaultAllowed, + maxLength: 1, + }, + expectedErr: domain.ValidationError{ + Model: "ListPlayersParams", + Field: "sort", + Err: domain.LenOutOfRangeError{ + Min: 0, + Max: 1, + Current: 2, + }, + }, + }, { name: "ERR: unsupported sort string", newParams: defaultNewParams, @@ -1052,6 +1127,8 @@ func TestListPlayersParams_PrependSortString(t *testing.T) { "odScoreDef:ASC", "odScoreTotal:", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.SliceElementValidationError{ Model: "ListPlayersParams", @@ -1069,6 +1146,8 @@ func TestListPlayersParams_PrependSortString(t *testing.T) { "odScoreAtt:ASC", "odScoreAtt:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListPlayersParams", @@ -1090,7 +1169,7 @@ func TestListPlayersParams_PrependSortString(t *testing.T) { } params := newParams(t) - require.ErrorIs(t, params.PrependSortString(tt.args.sort), tt.expectedErr) + require.ErrorIs(t, params.PrependSortString(tt.args.sort, tt.args.allowed, tt.args.maxLength), tt.expectedErr) if tt.expectedErr != nil { return } diff --git a/internal/domain/server.go b/internal/domain/server.go index 263d20d..831468b 100644 --- a/internal/domain/server.go +++ b/internal/domain/server.go @@ -766,7 +766,7 @@ func (params *ListServersParams) Sort() []ServerSort { } const ( - serverSortMinLength = 1 + serverSortMinLength = 0 serverSortMaxLength = 2 ) diff --git a/internal/domain/server_test.go b/internal/domain/server_test.go index cf5374f..8a1199c 100644 --- a/internal/domain/server_test.go +++ b/internal/domain/server_test.go @@ -682,19 +682,10 @@ func TestListServersParams_SetSort(t *testing.T) { }, }, { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListServersParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 2, - Current: 0, - }, - }, }, { name: "ERR: len(sort) > 2", @@ -709,7 +700,7 @@ func TestListServersParams_SetSort(t *testing.T) { Model: "ListServersParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 2, Current: 3, }, diff --git a/internal/domain/tribe.go b/internal/domain/tribe.go index 4426cec..374101d 100644 --- a/internal/domain/tribe.go +++ b/internal/domain/tribe.go @@ -827,8 +827,8 @@ func (params *ListTribesParams) Sort() []TribeSort { } const ( - tribeSortMinLength = 1 - tribeSortMaxLength = 3 + tribeSortMinLength = 0 + tribeSortMaxLength = 4 ) func (params *ListTribesParams) SetSort(sort []TribeSort) error { @@ -845,8 +845,12 @@ func (params *ListTribesParams) SetSort(sort []TribeSort) error { return nil } -func (params *ListTribesParams) PrependSortString(sort []string) error { - if err := validateSliceLen(sort, tribeSortMinLength, max(tribeSortMaxLength-len(params.sort), 0)); err != nil { +func (params *ListTribesParams) PrependSortString(sort []string, allowed []TribeSort, maxLength int) error { + if len(sort) == 0 { + return nil + } + + if err := validateSliceLen(sort, 0, max(min(tribeSortMaxLength-len(params.sort), maxLength), 0)); err != nil { return ValidationError{ Model: listTribesParamsModelName, Field: "sort", @@ -857,21 +861,7 @@ func (params *ListTribesParams) PrependSortString(sort []string) error { toPrepend := make([]TribeSort, 0, len(sort)) for i, s := range sort { - converted, err := newSortFromString( - s, - TribeSortODScoreAttASC, - TribeSortODScoreAttDESC, - TribeSortODScoreDefASC, - TribeSortODScoreDefDESC, - TribeSortODScoreTotalASC, - TribeSortODScoreTotalDESC, - TribeSortPointsASC, - TribeSortPointsDESC, - TribeSortDominanceASC, - TribeSortDominanceDESC, - TribeSortDeletedAtASC, - TribeSortDeletedAtDESC, - ) + converted, err := newSortFromString(s, allowed...) if err != nil { return SliceElementValidationError{ Model: listTribesParamsModelName, diff --git a/internal/domain/tribe_change.go b/internal/domain/tribe_change.go index a0a358c..c9b432a 100644 --- a/internal/domain/tribe_change.go +++ b/internal/domain/tribe_change.go @@ -495,7 +495,7 @@ func (params *ListTribeChangesParams) Sort() []TribeChangeSort { } const ( - tribeChangeSortMinLength = 1 + tribeChangeSortMinLength = 0 tribeChangeSortMaxLength = 3 ) @@ -555,12 +555,16 @@ func (params *ListTribeChangesParams) SetLimit(limit int) error { return nil } -func (params *ListTribeChangesParams) PrependSortString(sort []string) error { - if err := validateSliceLen( - sort, - tribeChangeSortMinLength, - max(tribeChangeSortMaxLength-len(params.sort), 0), - ); err != nil { +func (params *ListTribeChangesParams) PrependSortString( + sort []string, + allowed []TribeChangeSort, + maxLength int, +) error { + if len(sort) == 0 { + return nil + } + + if err := validateSliceLen(sort, 0, max(min(tribeChangeSortMaxLength-len(params.sort), maxLength), 0)); err != nil { return ValidationError{ Model: listTribeChangesParamsModelName, Field: "sort", @@ -571,11 +575,7 @@ func (params *ListTribeChangesParams) PrependSortString(sort []string) error { toPrepend := make([]TribeChangeSort, 0, len(sort)) for i, s := range sort { - converted, err := newSortFromString( - s, - TribeChangeSortCreatedAtASC, - TribeChangeSortCreatedAtDESC, - ) + converted, err := newSortFromString(s, allowed...) if err != nil { return SliceElementValidationError{ Model: listTribeChangesParamsModelName, diff --git a/internal/domain/tribe_change_test.go b/internal/domain/tribe_change_test.go index 73c9e70..b01cc07 100644 --- a/internal/domain/tribe_change_test.go +++ b/internal/domain/tribe_change_test.go @@ -558,19 +558,10 @@ func TestListTribeChangesParams_SetSort(t *testing.T) { }, }, { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListTribeChangesParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, - }, - }, }, { name: "ERR: len(sort) > 3", @@ -586,7 +577,7 @@ func TestListTribeChangesParams_SetSort(t *testing.T) { Model: "ListTribeChangesParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 3, Current: 4, }, @@ -632,9 +623,20 @@ func TestListTribeChangesParams_PrependSortString(t *testing.T) { t.Helper() return domain.ListTribeChangesParams{} } + defaultAllowed := []domain.TribeChangeSort{ + domain.TribeChangeSortCreatedAtASC, + domain.TribeChangeSortCreatedAtDESC, + domain.TribeChangeSortIDASC, + domain.TribeChangeSortIDDESC, + domain.TribeChangeSortServerKeyASC, + domain.TribeChangeSortServerKeyDESC, + } + defaultMaxLength := 3 type args struct { - sort []string + sort []string + allowed []domain.TribeChangeSort + maxLength int } tests := []struct { @@ -645,44 +647,71 @@ func TestListTribeChangesParams_PrependSortString(t *testing.T) { expectedErr error }{ { - name: "OK: [createdAt:ASC]", + name: "OK: [id:ASC, createdAt:ASC, serverKey:ASC]", + args: args{ + sort: []string{ + "id:ASC", + "createdAt:ASC", + "serverKey:ASC", + }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, + }, + expectedSort: []domain.TribeChangeSort{ + domain.TribeChangeSortIDASC, + domain.TribeChangeSortCreatedAtASC, + domain.TribeChangeSortServerKeyASC, + }, + }, + { + name: "OK: [id:DESC, createdAt:DESC, serverKey:DESC]", + args: args{ + sort: []string{ + "id:DESC", + "createdAt:DESC", + "serverKey:DESC", + }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, + }, + expectedSort: []domain.TribeChangeSort{ + domain.TribeChangeSortIDDESC, + domain.TribeChangeSortCreatedAtDESC, + domain.TribeChangeSortServerKeyDESC, + }, + }, + { + name: "OK: custom params", + newParams: func(t *testing.T) domain.ListTribeChangesParams { + t.Helper() + params := domain.NewListTribeChangesParams() + require.NoError(t, params.SetSort([]domain.TribeChangeSort{ + domain.TribeChangeSortIDASC, + domain.TribeChangeSortServerKeyASC, + })) + return params + }, args: args{ sort: []string{ "createdAt:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.TribeChangeSort{ domain.TribeChangeSortCreatedAtASC, + domain.TribeChangeSortIDASC, + domain.TribeChangeSortServerKeyASC, }, }, { - name: "OK: [createdAt:DESC]", - args: args{ - sort: []string{ - "createdAt:DESC", - }, - }, - expectedSort: []domain.TribeChangeSort{ - domain.TribeChangeSortCreatedAtDESC, - }, - }, - { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListTribeChangesParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, - }, - }, }, { - name: "ERR: custom params + len(sort) > 1", + name: "ERR: custom params + len(sort) > sortMaxLength - len(sort)", newParams: func(t *testing.T) domain.ListTribeChangesParams { t.Helper() params := domain.NewListTribeChangesParams() @@ -697,12 +726,35 @@ func TestListTribeChangesParams_PrependSortString(t *testing.T) { "createdAt:ASC", "createdAt:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListTribeChangesParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, + Max: 1, + Current: 2, + }, + }, + }, + { + name: "ERR: len(sort) > maxLength", + newParams: defaultNewParams, + args: args{ + sort: []string{ + "serverKey:ASC", + "createdAt:ASC", + }, + allowed: defaultAllowed, + maxLength: 1, + }, + expectedErr: domain.ValidationError{ + Model: "ListTribeChangesParams", + Field: "sort", + Err: domain.LenOutOfRangeError{ + Min: 0, Max: 1, Current: 2, }, @@ -715,6 +767,8 @@ func TestListTribeChangesParams_PrependSortString(t *testing.T) { sort: []string{ "createdAt:", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.SliceElementValidationError{ Model: "ListTribeChangesParams", @@ -732,6 +786,8 @@ func TestListTribeChangesParams_PrependSortString(t *testing.T) { "createdAt:ASC", "createdAt:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListTribeChangesParams", @@ -753,7 +809,7 @@ func TestListTribeChangesParams_PrependSortString(t *testing.T) { } params := newParams(t) - require.ErrorIs(t, params.PrependSortString(tt.args.sort), tt.expectedErr) + require.ErrorIs(t, params.PrependSortString(tt.args.sort, tt.args.allowed, tt.args.maxLength), tt.expectedErr) if tt.expectedErr != nil { return } diff --git a/internal/domain/tribe_snapshot.go b/internal/domain/tribe_snapshot.go index 845240c..3c83db1 100644 --- a/internal/domain/tribe_snapshot.go +++ b/internal/domain/tribe_snapshot.go @@ -451,7 +451,7 @@ func (params *ListTribeSnapshotsParams) Sort() []TribeSnapshotSort { } const ( - tribeSnapshotSortMinLength = 1 + tribeSnapshotSortMinLength = 0 tribeSnapshotSortMaxLength = 3 ) @@ -469,12 +469,16 @@ func (params *ListTribeSnapshotsParams) SetSort(sort []TribeSnapshotSort) error return nil } -func (params *ListTribeSnapshotsParams) PrependSortString(sort []string) error { - if err := validateSliceLen( - sort, - tribeSnapshotSortMinLength, - max(tribeSnapshotSortMaxLength-len(params.sort), 0), - ); err != nil { +func (params *ListTribeSnapshotsParams) PrependSortString( + sort []string, + allowed []TribeSnapshotSort, + maxLength int, +) error { + if len(sort) == 0 { + return nil + } + + if err := validateSliceLen(sort, 0, max(min(tribeSnapshotSortMaxLength-len(params.sort), maxLength), 0)); err != nil { return ValidationError{ Model: listTribeSnapshotsParamsModelName, Field: "sort", @@ -485,11 +489,7 @@ func (params *ListTribeSnapshotsParams) PrependSortString(sort []string) error { toPrepend := make([]TribeSnapshotSort, 0, len(sort)) for i, s := range sort { - converted, err := newSortFromString( - s, - TribeSnapshotSortDateASC, - TribeSnapshotSortDateDESC, - ) + converted, err := newSortFromString(s, allowed...) if err != nil { return SliceElementValidationError{ Model: listTribeSnapshotsParamsModelName, diff --git a/internal/domain/tribe_snapshot_test.go b/internal/domain/tribe_snapshot_test.go index bfd95c0..92dc3a3 100644 --- a/internal/domain/tribe_snapshot_test.go +++ b/internal/domain/tribe_snapshot_test.go @@ -329,19 +329,10 @@ func TestListTribeSnapshotsParams_SetSort(t *testing.T) { }, }, { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListTribeSnapshotsParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, - }, - }, }, { name: "ERR: len(sort) > 3", @@ -357,7 +348,7 @@ func TestListTribeSnapshotsParams_SetSort(t *testing.T) { Model: "ListTribeSnapshotsParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 3, Current: 4, }, @@ -403,9 +394,20 @@ func TestListTribeSnapshotsParams_PrependSortString(t *testing.T) { t.Helper() return domain.ListTribeSnapshotsParams{} } + defaultAllowed := []domain.TribeSnapshotSort{ + domain.TribeSnapshotSortDateASC, + domain.TribeSnapshotSortDateDESC, + domain.TribeSnapshotSortIDASC, + domain.TribeSnapshotSortIDDESC, + domain.TribeSnapshotSortServerKeyASC, + domain.TribeSnapshotSortServerKeyDESC, + } + defaultMaxLength := 3 type args struct { - sort []string + sort []string + allowed []domain.TribeSnapshotSort + maxLength int } tests := []struct { @@ -416,44 +418,71 @@ func TestListTribeSnapshotsParams_PrependSortString(t *testing.T) { expectedErr error }{ { - name: "OK: [date:ASC]", + name: "OK: [id:ASC, date:ASC, serverKey:ASC]", + args: args{ + sort: []string{ + "id:ASC", + "date:ASC", + "serverKey:ASC", + }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, + }, + expectedSort: []domain.TribeSnapshotSort{ + domain.TribeSnapshotSortIDASC, + domain.TribeSnapshotSortDateASC, + domain.TribeSnapshotSortServerKeyASC, + }, + }, + { + name: "OK: [id:DESC, date:DESC, serverKey:DESC]", + args: args{ + sort: []string{ + "id:DESC", + "date:DESC", + "serverKey:DESC", + }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, + }, + expectedSort: []domain.TribeSnapshotSort{ + domain.TribeSnapshotSortIDDESC, + domain.TribeSnapshotSortDateDESC, + domain.TribeSnapshotSortServerKeyDESC, + }, + }, + { + name: "OK: custom params", + newParams: func(t *testing.T) domain.ListTribeSnapshotsParams { + t.Helper() + params := domain.NewListTribeSnapshotsParams() + require.NoError(t, params.SetSort([]domain.TribeSnapshotSort{ + domain.TribeSnapshotSortIDASC, + domain.TribeSnapshotSortServerKeyASC, + })) + return params + }, args: args{ sort: []string{ "date:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.TribeSnapshotSort{ domain.TribeSnapshotSortDateASC, + domain.TribeSnapshotSortIDASC, + domain.TribeSnapshotSortServerKeyASC, }, }, { - name: "OK: [date:DESC]", - args: args{ - sort: []string{ - "date:DESC", - }, - }, - expectedSort: []domain.TribeSnapshotSort{ - domain.TribeSnapshotSortDateDESC, - }, - }, - { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListTribeSnapshotsParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, - }, - }, }, { - name: "ERR: custom params + len(sort) > 1", + name: "ERR: custom params + len(sort) > sortMaxLength - len(sort)", newParams: func(t *testing.T) domain.ListTribeSnapshotsParams { t.Helper() params := domain.NewListTribeSnapshotsParams() @@ -468,12 +497,35 @@ func TestListTribeSnapshotsParams_PrependSortString(t *testing.T) { "date:ASC", "date:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListTribeSnapshotsParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, + Max: 1, + Current: 2, + }, + }, + }, + { + name: "ERR: len(sort) > maxLength", + newParams: defaultNewParams, + args: args{ + sort: []string{ + "serverKey:ASC", + "date:ASC", + }, + allowed: defaultAllowed, + maxLength: 1, + }, + expectedErr: domain.ValidationError{ + Model: "ListTribeSnapshotsParams", + Field: "sort", + Err: domain.LenOutOfRangeError{ + Min: 0, Max: 1, Current: 2, }, @@ -486,6 +538,8 @@ func TestListTribeSnapshotsParams_PrependSortString(t *testing.T) { sort: []string{ "date:", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.SliceElementValidationError{ Model: "ListTribeSnapshotsParams", @@ -503,6 +557,8 @@ func TestListTribeSnapshotsParams_PrependSortString(t *testing.T) { "date:ASC", "date:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListTribeSnapshotsParams", @@ -524,7 +580,7 @@ func TestListTribeSnapshotsParams_PrependSortString(t *testing.T) { } params := newParams(t) - require.ErrorIs(t, params.PrependSortString(tt.args.sort), tt.expectedErr) + require.ErrorIs(t, params.PrependSortString(tt.args.sort, tt.args.allowed, tt.args.maxLength), tt.expectedErr) if tt.expectedErr != nil { return } diff --git a/internal/domain/tribe_test.go b/internal/domain/tribe_test.go index 7da683c..f099d17 100644 --- a/internal/domain/tribe_test.go +++ b/internal/domain/tribe_test.go @@ -675,37 +675,29 @@ func TestListTribesParams_SetSort(t *testing.T) { }, }, { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListTribesParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, - }, - }, }, { - name: "ERR: len(sort) > 3", + name: "ERR: len(sort) > 4", args: args{ sort: []domain.TribeSort{ domain.TribeSortDominanceASC, domain.TribeSortPointsASC, domain.TribeSortIDASC, domain.TribeSortServerKeyASC, + domain.TribeSortServerKeyASC, }, }, expectedErr: domain.ValidationError{ Model: "ListTribesParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 4, + Min: 0, + Max: 4, + Current: 5, }, }, }, @@ -749,9 +741,30 @@ func TestListTribesParams_PrependSortString(t *testing.T) { t.Helper() return domain.ListTribesParams{} } + defaultAllowed := []domain.TribeSort{ + domain.TribeSortIDASC, + domain.TribeSortIDDESC, + domain.TribeSortServerKeyASC, + domain.TribeSortServerKeyDESC, + domain.TribeSortODScoreAttASC, + domain.TribeSortODScoreAttDESC, + domain.TribeSortODScoreDefASC, + domain.TribeSortODScoreDefDESC, + domain.TribeSortODScoreTotalASC, + domain.TribeSortODScoreTotalDESC, + domain.TribeSortPointsASC, + domain.TribeSortPointsDESC, + domain.TribeSortDominanceASC, + domain.TribeSortDominanceDESC, + domain.TribeSortDeletedAtASC, + domain.TribeSortDeletedAtDESC, + } + defaultMaxLength := 4 type args struct { - sort []string + sort []string + allowed []domain.TribeSort + maxLength int } tests := []struct { @@ -762,106 +775,147 @@ func TestListTribesParams_PrependSortString(t *testing.T) { expectedErr error }{ { - name: "OK: [odScoreAtt:ASC, odScoreDef:ASC, odScoreTotal:ASC]", + name: "OK: [id:ASC, odScoreAtt:ASC, odScoreDef:ASC, odScoreTotal:ASC]", args: args{ sort: []string{ + "id:ASC", "odScoreAtt:ASC", "odScoreDef:ASC", "odScoreTotal:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.TribeSort{ + domain.TribeSortIDASC, domain.TribeSortODScoreAttASC, domain.TribeSortODScoreDefASC, domain.TribeSortODScoreTotalASC, }, }, { - name: "OK: [odScoreAtt:DESC, odScoreDef:DESC, odScoreTotal:DESC]", + name: "OK: [id:DESC, odScoreAtt:DESC, odScoreDef:DESC, odScoreTotal:DESC]", args: args{ sort: []string{ + "id:DESC", "odScoreAtt:DESC", "odScoreDef:DESC", "odScoreTotal:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.TribeSort{ + domain.TribeSortIDDESC, domain.TribeSortODScoreAttDESC, domain.TribeSortODScoreDefDESC, domain.TribeSortODScoreTotalDESC, }, }, { - name: "OK: [points:ASC, dominance:ASC, deletedAt:ASC]", + name: "OK: [serverKey:ASC, points:ASC, dominance:ASC, deletedAt:ASC]", args: args{ sort: []string{ + "serverKey:ASC", "points:ASC", "dominance:ASC", "deletedAt:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.TribeSort{ + domain.TribeSortServerKeyASC, domain.TribeSortPointsASC, domain.TribeSortDominanceASC, domain.TribeSortDeletedAtASC, }, }, { - name: "OK: [points:DESC, dominance:DESC, deletedAt:DESC]", + name: "OK: [serverKey:DESC, points:DESC, dominance:DESC, deletedAt:DESC]", args: args{ sort: []string{ + "serverKey:DESC", "points:DESC", "dominance:DESC", "deletedAt:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedSort: []domain.TribeSort{ + domain.TribeSortServerKeyDESC, domain.TribeSortPointsDESC, domain.TribeSortDominanceDESC, domain.TribeSortDeletedAtDESC, }, }, { - name: "ERR: len(sort) < 1", - args: args{ - sort: nil, + name: "OK: custom params", + newParams: func(t *testing.T) domain.ListTribesParams { + t.Helper() + params := domain.NewListTribesParams() + require.NoError(t, params.SetSort([]domain.TribeSort{ + domain.TribeSortIDASC, + domain.TribeSortServerKeyASC, + })) + return params }, - expectedErr: domain.ValidationError{ - Model: "ListTribesParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 0, + args: args{ + sort: []string{ + "points:DESC", + "deletedAt:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, + }, + expectedSort: []domain.TribeSort{ + domain.TribeSortPointsDESC, + domain.TribeSortDeletedAtDESC, + domain.TribeSortIDASC, + domain.TribeSortServerKeyASC, }, }, { - name: "ERR: len(sort) > 3", + name: "OK: empty slice", + args: args{ + sort: nil, + allowed: defaultAllowed, + maxLength: defaultMaxLength, + }, + }, + { + name: "ERR: len(sort) > 4", args: args{ sort: []string{ "odScoreAtt:ASC", "odScoreDef:ASC", "odScoreTotal:ASC", "points:ASC", + "points:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListTribesParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 3, - Current: 4, + Min: 0, + Max: 4, + Current: 5, }, }, }, { - name: "ERR: custom params + len(sort) > 2", + name: "ERR: custom params + len(sort) > sortMaxLength - len(sort)", newParams: func(t *testing.T) domain.ListTribesParams { t.Helper() params := domain.NewListTribesParams() - require.NoError(t, params.SetSort([]domain.TribeSort{domain.TribeSortIDASC})) + require.NoError(t, params.SetSort([]domain.TribeSort{ + domain.TribeSortIDASC, + domain.TribeSortServerKeyASC, + })) return params }, args: args{ @@ -870,17 +924,40 @@ func TestListTribesParams_PrependSortString(t *testing.T) { "odScoreDef:ASC", "odScoreTotal:ASC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListTribesParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 2, Current: 3, }, }, }, + { + name: "ERR: len(sort) > maxLength", + newParams: defaultNewParams, + args: args{ + sort: []string{ + "odScoreAtt:ASC", + "odScoreDef:ASC", + }, + allowed: defaultAllowed, + maxLength: 1, + }, + expectedErr: domain.ValidationError{ + Model: "ListTribesParams", + Field: "sort", + Err: domain.LenOutOfRangeError{ + Min: 0, + Max: 1, + Current: 2, + }, + }, + }, { name: "ERR: unsupported sort string", newParams: defaultNewParams, @@ -890,6 +967,8 @@ func TestListTribesParams_PrependSortString(t *testing.T) { "odScoreDef:ASC", "odScoreTotal:", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.SliceElementValidationError{ Model: "ListTribesParams", @@ -907,6 +986,8 @@ func TestListTribesParams_PrependSortString(t *testing.T) { "odScoreAtt:ASC", "odScoreAtt:DESC", }, + allowed: defaultAllowed, + maxLength: defaultMaxLength, }, expectedErr: domain.ValidationError{ Model: "ListTribesParams", @@ -928,7 +1009,7 @@ func TestListTribesParams_PrependSortString(t *testing.T) { } params := newParams(t) - require.ErrorIs(t, params.PrependSortString(tt.args.sort), tt.expectedErr) + require.ErrorIs(t, params.PrependSortString(tt.args.sort, tt.args.allowed, tt.args.maxLength), tt.expectedErr) if tt.expectedErr != nil { return } diff --git a/internal/domain/version.go b/internal/domain/version.go index 907623e..c8bc69b 100644 --- a/internal/domain/version.go +++ b/internal/domain/version.go @@ -218,7 +218,7 @@ func (params *ListVersionsParams) SetCodes(codes []string) error { } const ( - versionSortMinLength = 1 + versionSortMinLength = 0 versionSortMaxLength = 1 ) diff --git a/internal/domain/version_test.go b/internal/domain/version_test.go index fe088dc..7ee2461 100644 --- a/internal/domain/version_test.go +++ b/internal/domain/version_test.go @@ -177,19 +177,10 @@ func TestListVersionsParams_SetSort(t *testing.T) { }, }, { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListVersionsParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 1, - Current: 0, - }, - }, }, { name: "ERR: len(sort) > 1", @@ -203,7 +194,7 @@ func TestListVersionsParams_SetSort(t *testing.T) { Model: "ListVersionsParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 1, Current: 2, }, diff --git a/internal/domain/village.go b/internal/domain/village.go index 3fcbcd1..435cf0a 100644 --- a/internal/domain/village.go +++ b/internal/domain/village.go @@ -664,7 +664,7 @@ func (params *ListVillagesParams) Sort() []VillageSort { } const ( - villageSortMinLength = 1 + villageSortMinLength = 0 villageSortMaxLength = 2 ) diff --git a/internal/domain/village_test.go b/internal/domain/village_test.go index 6d9ef4f..485f5d3 100644 --- a/internal/domain/village_test.go +++ b/internal/domain/village_test.go @@ -650,19 +650,10 @@ func TestListVillagesParams_SetSort(t *testing.T) { }, }, { - name: "ERR: len(sort) < 1", + name: "OK: empty slice", args: args{ sort: nil, }, - expectedErr: domain.ValidationError{ - Model: "ListVillagesParams", - Field: "sort", - Err: domain.LenOutOfRangeError{ - Min: 1, - Max: 2, - Current: 0, - }, - }, }, { name: "ERR: len(sort) > 2", @@ -677,7 +668,7 @@ func TestListVillagesParams_SetSort(t *testing.T) { Model: "ListVillagesParams", Field: "sort", Err: domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 2, Current: 3, }, diff --git a/internal/port/handler_http_api_ennoblement.go b/internal/port/handler_http_api_ennoblement.go index 86cad88..b82f500 100644 --- a/internal/port/handler_http_api_ennoblement.go +++ b/internal/port/handler_http_api_ennoblement.go @@ -8,6 +8,13 @@ import ( "gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel" ) +const apiEnnoblementSortMaxLength = 1 + +var apiEnnoblementSortAllowedValues = []domain.EnnoblementSort{ + domain.EnnoblementSortCreatedAtASC, + domain.EnnoblementSortCreatedAtDESC, +} + //nolint:gocyclo func (h *apiHTTPHandler) ListEnnoblements( w http.ResponseWriter, @@ -23,16 +30,18 @@ func (h *apiHTTPHandler) ListEnnoblements( return } + sort := []string{domain.EnnoblementSortCreatedAtASC.String()} if params.Sort != nil { - if err := domainParams.PrependSortString(*params.Sort); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) - return - } - } else { - if err := domainParams.PrependSortString([]string{domain.EnnoblementSortCreatedAtASC.String()}); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) - return - } + sort = *params.Sort + } + + if err := domainParams.PrependSortString( + sort, + apiEnnoblementSortAllowedValues, + apiEnnoblementSortMaxLength, + ); err != nil { + h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) + return } if err := domainParams.SetServerKeys([]string{serverKey}); err != nil { @@ -104,16 +113,18 @@ func (h *apiHTTPHandler) ListPlayerEnnoblements( return } + sort := []string{domain.EnnoblementSortCreatedAtASC.String()} if params.Sort != nil { - if err := domainParams.PrependSortString(*params.Sort); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) - return - } - } else { - if err := domainParams.PrependSortString([]string{domain.EnnoblementSortCreatedAtASC.String()}); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) - return - } + sort = *params.Sort + } + + if err := domainParams.PrependSortString( + sort, + apiEnnoblementSortAllowedValues, + apiEnnoblementSortMaxLength, + ); err != nil { + h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) + return } if err := domainParams.SetServerKeys([]string{serverKey}); err != nil { @@ -185,16 +196,18 @@ func (h *apiHTTPHandler) ListTribeEnnoblements( return } + sort := []string{domain.EnnoblementSortCreatedAtASC.String()} if params.Sort != nil { - if err := domainParams.PrependSortString(*params.Sort); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) - return - } - } else { - if err := domainParams.PrependSortString([]string{domain.EnnoblementSortCreatedAtASC.String()}); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) - return - } + sort = *params.Sort + } + + if err := domainParams.PrependSortString( + sort, + apiEnnoblementSortAllowedValues, + apiEnnoblementSortMaxLength, + ); err != nil { + h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) + return } if err := domainParams.SetServerKeys([]string{serverKey}); err != nil { @@ -266,16 +279,18 @@ func (h *apiHTTPHandler) ListVillageEnnoblements( return } + sort := []string{domain.EnnoblementSortCreatedAtASC.String()} if params.Sort != nil { - if err := domainParams.PrependSortString(*params.Sort); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) - return - } - } else { - if err := domainParams.PrependSortString([]string{domain.EnnoblementSortCreatedAtASC.String()}); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) - return - } + sort = *params.Sort + } + + if err := domainParams.PrependSortString( + sort, + apiEnnoblementSortAllowedValues, + apiEnnoblementSortMaxLength, + ); err != nil { + h.errorRenderer.withErrorPathFormatter(formatListEnnoblementsErrorPath).render(w, r, err) + return } if err := domainParams.SetServerKeys([]string{serverKey}); err != nil { diff --git a/internal/port/handler_http_api_ennoblement_test.go b/internal/port/handler_http_api_ennoblement_test.go index b9e2cb1..68f8499 100644 --- a/internal/port/handler_http_api_ennoblement_test.go +++ b/internal/port/handler_http_api_ennoblement_test.go @@ -414,13 +414,12 @@ func TestListEnnoblements(t *testing.T) { }, }, { - name: "ERR: len(sort) > 2", + name: "ERR: len(sort) > 1", reqModifier: func(t *testing.T, req *http.Request) { t.Helper() q := req.URL.Query() q.Add("sort", "createdAt:DESC") q.Add("sort", "createdAt:ASC") - q.Add("sort", "createdAt:ASC") req.URL.RawQuery = q.Encode() }, assertResp: func(t *testing.T, req *http.Request, resp *http.Response) { @@ -431,8 +430,8 @@ func TestListEnnoblements(t *testing.T) { // body body := decodeJSON[apimodel.ErrorResponse](t, resp.Body) domainErr := domain.LenOutOfRangeError{ - Min: 1, - Max: 2, + Min: 0, + Max: 1, Current: len(req.URL.Query()["sort"]), } assert.Equal(t, apimodel.ErrorResponse{ @@ -483,44 +482,6 @@ func TestListEnnoblements(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", "createdAt:DESC") - q.Add("sort", "createdAt:ASC") - 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: apimodel.ErrorCode(domainErr.Code()), - Message: domainErr.Error(), - Params: map[string]any{ - "sort": paramSort, - }, - Path: []string{"$query", "sort"}, - }, - }, - }, body) - }, - }, { name: "ERR: invalid since", reqModifier: func(t *testing.T, req *http.Request) { @@ -1061,13 +1022,12 @@ func TestListPlayerEnnoblements(t *testing.T) { }, }, { - name: "ERR: len(sort) > 2", + name: "ERR: len(sort) > 1", reqModifier: func(t *testing.T, req *http.Request) { t.Helper() q := req.URL.Query() q.Add("sort", "createdAt:DESC") q.Add("sort", "createdAt:ASC") - q.Add("sort", "createdAt:ASC") req.URL.RawQuery = q.Encode() }, assertResp: func(t *testing.T, req *http.Request, resp *http.Response) { @@ -1078,8 +1038,8 @@ func TestListPlayerEnnoblements(t *testing.T) { // body body := decodeJSON[apimodel.ErrorResponse](t, resp.Body) domainErr := domain.LenOutOfRangeError{ - Min: 1, - Max: 2, + Min: 0, + Max: 1, Current: len(req.URL.Query()["sort"]), } assert.Equal(t, apimodel.ErrorResponse{ @@ -1130,44 +1090,6 @@ func TestListPlayerEnnoblements(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", "createdAt:DESC") - q.Add("sort", "createdAt:ASC") - 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: apimodel.ErrorCode(domainErr.Code()), - Message: domainErr.Error(), - Params: map[string]any{ - "sort": paramSort, - }, - Path: []string{"$query", "sort"}, - }, - }, - }, body) - }, - }, { name: "ERR: invalid since", reqModifier: func(t *testing.T, req *http.Request) { @@ -1766,13 +1688,12 @@ func TestListTribeEnnoblements(t *testing.T) { }, }, { - name: "ERR: len(sort) > 2", + name: "ERR: len(sort) > 1", reqModifier: func(t *testing.T, req *http.Request) { t.Helper() q := req.URL.Query() q.Add("sort", "createdAt:DESC") q.Add("sort", "createdAt:ASC") - q.Add("sort", "createdAt:ASC") req.URL.RawQuery = q.Encode() }, assertResp: func(t *testing.T, req *http.Request, resp *http.Response) { @@ -1783,8 +1704,8 @@ func TestListTribeEnnoblements(t *testing.T) { // body body := decodeJSON[apimodel.ErrorResponse](t, resp.Body) domainErr := domain.LenOutOfRangeError{ - Min: 1, - Max: 2, + Min: 0, + Max: 1, Current: len(req.URL.Query()["sort"]), } assert.Equal(t, apimodel.ErrorResponse{ @@ -1835,44 +1756,6 @@ func TestListTribeEnnoblements(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", "createdAt:DESC") - q.Add("sort", "createdAt:ASC") - 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: apimodel.ErrorCode(domainErr.Code()), - Message: domainErr.Error(), - Params: map[string]any{ - "sort": paramSort, - }, - Path: []string{"$query", "sort"}, - }, - }, - }, body) - }, - }, { name: "ERR: invalid since", reqModifier: func(t *testing.T, req *http.Request) { @@ -2458,13 +2341,12 @@ func TestListVillageEnnoblements(t *testing.T) { }, }, { - name: "ERR: len(sort) > 2", + name: "ERR: len(sort) > 1", reqModifier: func(t *testing.T, req *http.Request) { t.Helper() q := req.URL.Query() q.Add("sort", "createdAt:DESC") q.Add("sort", "createdAt:ASC") - q.Add("sort", "createdAt:ASC") req.URL.RawQuery = q.Encode() }, assertResp: func(t *testing.T, req *http.Request, resp *http.Response) { @@ -2475,8 +2357,8 @@ func TestListVillageEnnoblements(t *testing.T) { // body body := decodeJSON[apimodel.ErrorResponse](t, resp.Body) domainErr := domain.LenOutOfRangeError{ - Min: 1, - Max: 2, + Min: 0, + Max: 1, Current: len(req.URL.Query()["sort"]), } assert.Equal(t, apimodel.ErrorResponse{ @@ -2527,44 +2409,6 @@ func TestListVillageEnnoblements(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", "createdAt:DESC") - q.Add("sort", "createdAt:ASC") - 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: apimodel.ErrorCode(domainErr.Code()), - Message: domainErr.Error(), - Params: map[string]any{ - "sort": paramSort, - }, - Path: []string{"$query", "sort"}, - }, - }, - }, body) - }, - }, { name: "ERR: invalid since", reqModifier: func(t *testing.T, req *http.Request) { diff --git a/internal/port/handler_http_api_player.go b/internal/port/handler_http_api_player.go index cc01369..d121e2d 100644 --- a/internal/port/handler_http_api_player.go +++ b/internal/port/handler_http_api_player.go @@ -11,6 +11,23 @@ import ( "github.com/go-chi/chi/v5" ) +const apiPlayerSortMaxLength = 2 + +var apiPlayerSortAllowedValues = []domain.PlayerSort{ + domain.PlayerSortODScoreAttASC, + domain.PlayerSortODScoreAttDESC, + domain.PlayerSortODScoreDefASC, + domain.PlayerSortODScoreDefDESC, + domain.PlayerSortODScoreSupASC, + domain.PlayerSortODScoreSupDESC, + domain.PlayerSortODScoreTotalASC, + domain.PlayerSortODScoreTotalDESC, + domain.PlayerSortPointsASC, + domain.PlayerSortPointsDESC, + domain.PlayerSortDeletedAtASC, + domain.PlayerSortDeletedAtDESC, +} + //nolint:gocyclo func (h *apiHTTPHandler) ListPlayers( w http.ResponseWriter, @@ -27,7 +44,11 @@ func (h *apiHTTPHandler) ListPlayers( } if params.Sort != nil { - if err := domainParams.PrependSortString(*params.Sort); err != nil { + if err := domainParams.PrependSortString( + *params.Sort, + apiPlayerSortAllowedValues, + apiPlayerSortMaxLength, + ); err != nil { h.errorRenderer.withErrorPathFormatter(formatListPlayersErrorPath).render(w, r, err) return } @@ -95,7 +116,11 @@ func (h *apiHTTPHandler) ListTribeMembers( } if params.Sort != nil { - if err := domainParams.PrependSortString(*params.Sort); err != nil { + if err := domainParams.PrependSortString( + *params.Sort, + apiPlayerSortAllowedValues, + apiPlayerSortMaxLength, + ); err != nil { h.errorRenderer.withErrorPathFormatter(formatListPlayersErrorPath).render(w, r, err) return } diff --git a/internal/port/handler_http_api_player_snapshot.go b/internal/port/handler_http_api_player_snapshot.go index e19f362..1871609 100644 --- a/internal/port/handler_http_api_player_snapshot.go +++ b/internal/port/handler_http_api_player_snapshot.go @@ -8,6 +8,13 @@ import ( "gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel" ) +const apiPlayerSnapshotSortMaxLength = 1 + +var apiPlayerSnapshotSortAllowedValues = []domain.PlayerSnapshotSort{ + domain.PlayerSnapshotSortDateASC, + domain.PlayerSnapshotSortDateDESC, +} + //nolint:gocyclo func (h *apiHTTPHandler) ListPlayerPlayerSnapshots( w http.ResponseWriter, @@ -29,16 +36,18 @@ func (h *apiHTTPHandler) ListPlayerPlayerSnapshots( return } + sort := []string{domain.PlayerSnapshotSortDateASC.String()} if params.Sort != nil { - if err := domainParams.PrependSortString(*params.Sort); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListPlayerSnapshotsErrorPath).render(w, r, err) - return - } - } else { - if err := domainParams.PrependSortString([]string{domain.PlayerSnapshotSortDateASC.String()}); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListPlayerSnapshotsErrorPath).render(w, r, err) - return - } + sort = *params.Sort + } + + if err := domainParams.PrependSortString( + sort, + apiPlayerSnapshotSortAllowedValues, + apiPlayerSnapshotSortMaxLength, + ); err != nil { + h.errorRenderer.withErrorPathFormatter(formatListPlayerSnapshotsErrorPath).render(w, r, err) + return } if err := domainParams.SetServerKeys([]string{serverKey}); err != nil { diff --git a/internal/port/handler_http_api_player_snapshot_test.go b/internal/port/handler_http_api_player_snapshot_test.go index 0553535..c192019 100644 --- a/internal/port/handler_http_api_player_snapshot_test.go +++ b/internal/port/handler_http_api_player_snapshot_test.go @@ -348,13 +348,12 @@ func TestListPlayerPlayerSnapshots(t *testing.T) { }, }, { - name: "ERR: len(sort) > 2", + name: "ERR: len(sort) > 1", reqModifier: func(t *testing.T, req *http.Request) { t.Helper() q := req.URL.Query() q.Add("sort", "date:DESC") q.Add("sort", "date:ASC") - q.Add("sort", "date:ASC") req.URL.RawQuery = q.Encode() }, assertResp: func(t *testing.T, req *http.Request, resp *http.Response) { @@ -365,8 +364,8 @@ func TestListPlayerPlayerSnapshots(t *testing.T) { // body body := decodeJSON[apimodel.ErrorResponse](t, resp.Body) domainErr := domain.LenOutOfRangeError{ - Min: 1, - Max: 2, + Min: 0, + Max: 1, Current: len(req.URL.Query()["sort"]), } assert.Equal(t, apimodel.ErrorResponse{ @@ -417,44 +416,6 @@ func TestListPlayerPlayerSnapshots(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", "date:DESC") - q.Add("sort", "date:ASC") - 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: apimodel.ErrorCode(domainErr.Code()), - Message: domainErr.Error(), - Params: map[string]any{ - "sort": paramSort, - }, - Path: []string{"$query", "sort"}, - }, - }, - }, body) - }, - }, { name: "ERR: version not found", reqModifier: func(t *testing.T, req *http.Request) { diff --git a/internal/port/handler_http_api_player_test.go b/internal/port/handler_http_api_player_test.go index 3926c3b..94907a2 100644 --- a/internal/port/handler_http_api_player_test.go +++ b/internal/port/handler_http_api_player_test.go @@ -474,7 +474,7 @@ func TestListPlayers(t *testing.T) { // body body := decodeJSON[apimodel.ErrorResponse](t, resp.Body) domainErr := domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 2, Current: len(req.URL.Query()["sort"]), } @@ -1133,7 +1133,7 @@ func TestListTribeMembers(t *testing.T) { // body body := decodeJSON[apimodel.ErrorResponse](t, resp.Body) domainErr := domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 2, Current: len(req.URL.Query()["sort"]), } diff --git a/internal/port/handler_http_api_tribe.go b/internal/port/handler_http_api_tribe.go index de9f6c9..dc2a693 100644 --- a/internal/port/handler_http_api_tribe.go +++ b/internal/port/handler_http_api_tribe.go @@ -11,6 +11,23 @@ import ( "github.com/go-chi/chi/v5" ) +const apiTribeSortMaxLength = 2 + +var apiTribeSortAllowedValues = []domain.TribeSort{ + domain.TribeSortODScoreAttASC, + domain.TribeSortODScoreAttDESC, + domain.TribeSortODScoreDefASC, + domain.TribeSortODScoreDefDESC, + domain.TribeSortODScoreTotalASC, + domain.TribeSortODScoreTotalDESC, + domain.TribeSortPointsASC, + domain.TribeSortPointsDESC, + domain.TribeSortDominanceASC, + domain.TribeSortDominanceDESC, + domain.TribeSortDeletedAtASC, + domain.TribeSortDeletedAtDESC, +} + //nolint:gocyclo func (h *apiHTTPHandler) ListTribes( w http.ResponseWriter, @@ -27,7 +44,7 @@ func (h *apiHTTPHandler) ListTribes( } if params.Sort != nil { - if err := domainParams.PrependSortString(*params.Sort); err != nil { + if err := domainParams.PrependSortString(*params.Sort, apiTribeSortAllowedValues, apiTribeSortMaxLength); err != nil { h.errorRenderer.withErrorPathFormatter(formatListTribesErrorPath).render(w, r, err) return } diff --git a/internal/port/handler_http_api_tribe_change.go b/internal/port/handler_http_api_tribe_change.go index a46cd8a..543d142 100644 --- a/internal/port/handler_http_api_tribe_change.go +++ b/internal/port/handler_http_api_tribe_change.go @@ -8,6 +8,13 @@ import ( "gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel" ) +const apiTribeChangeSortMaxLength = 1 + +var apiTribeChangeSortAllowedValues = []domain.TribeChangeSort{ + domain.TribeChangeSortCreatedAtASC, + domain.TribeChangeSortCreatedAtDESC, +} + //nolint:gocyclo func (h *apiHTTPHandler) ListPlayerTribeChanges( w http.ResponseWriter, @@ -29,16 +36,18 @@ func (h *apiHTTPHandler) ListPlayerTribeChanges( return } + sort := []string{domain.TribeChangeSortCreatedAtASC.String()} if params.Sort != nil { - if err := domainParams.PrependSortString(*params.Sort); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListTribeChangesErrorPath).render(w, r, err) - return - } - } else { - if err := domainParams.PrependSortString([]string{domain.TribeChangeSortCreatedAtASC.String()}); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListTribeChangesErrorPath).render(w, r, err) - return - } + sort = *params.Sort + } + + if err := domainParams.PrependSortString( + sort, + apiTribeChangeSortAllowedValues, + apiTribeChangeSortMaxLength, + ); err != nil { + h.errorRenderer.withErrorPathFormatter(formatListTribeChangesErrorPath).render(w, r, err) + return } if err := domainParams.SetServerKeys([]string{serverKey}); err != nil { @@ -110,16 +119,18 @@ func (h *apiHTTPHandler) ListTribeMemberChanges( return } + sort := []string{domain.TribeChangeSortCreatedAtASC.String()} if params.Sort != nil { - if err := domainParams.PrependSortString(*params.Sort); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListTribeChangesErrorPath).render(w, r, err) - return - } - } else { - if err := domainParams.PrependSortString([]string{domain.TribeChangeSortCreatedAtASC.String()}); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListTribeChangesErrorPath).render(w, r, err) - return - } + sort = *params.Sort + } + + if err := domainParams.PrependSortString( + sort, + apiTribeChangeSortAllowedValues, + apiTribeChangeSortMaxLength, + ); err != nil { + h.errorRenderer.withErrorPathFormatter(formatListTribeChangesErrorPath).render(w, r, err) + return } if err := domainParams.SetServerKeys([]string{serverKey}); err != nil { diff --git a/internal/port/handler_http_api_tribe_change_test.go b/internal/port/handler_http_api_tribe_change_test.go index a7321c5..a0e9381 100644 --- a/internal/port/handler_http_api_tribe_change_test.go +++ b/internal/port/handler_http_api_tribe_change_test.go @@ -429,13 +429,12 @@ func TestListPlayerTribeChanges(t *testing.T) { }, }, { - name: "ERR: len(sort) > 2", + name: "ERR: len(sort) > 1", reqModifier: func(t *testing.T, req *http.Request) { t.Helper() q := req.URL.Query() q.Add("sort", "createdAt:DESC") q.Add("sort", "createdAt:ASC") - q.Add("sort", "createdAt:ASC") req.URL.RawQuery = q.Encode() }, assertResp: func(t *testing.T, req *http.Request, resp *http.Response) { @@ -446,8 +445,8 @@ func TestListPlayerTribeChanges(t *testing.T) { // body body := decodeJSON[apimodel.ErrorResponse](t, resp.Body) domainErr := domain.LenOutOfRangeError{ - Min: 1, - Max: 2, + Min: 0, + Max: 1, Current: len(req.URL.Query()["sort"]), } assert.Equal(t, apimodel.ErrorResponse{ @@ -498,44 +497,6 @@ func TestListPlayerTribeChanges(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", "createdAt:DESC") - q.Add("sort", "createdAt:ASC") - 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: apimodel.ErrorCode(domainErr.Code()), - Message: domainErr.Error(), - Params: map[string]any{ - "sort": paramSort, - }, - Path: []string{"$query", "sort"}, - }, - }, - }, body) - }, - }, { name: "ERR: invalid since", reqModifier: func(t *testing.T, req *http.Request) { @@ -1160,13 +1121,12 @@ func TestListTribeMemberChanges(t *testing.T) { }, }, { - name: "ERR: len(sort) > 2", + name: "ERR: len(sort) > 1", reqModifier: func(t *testing.T, req *http.Request) { t.Helper() q := req.URL.Query() q.Add("sort", "createdAt:DESC") q.Add("sort", "createdAt:ASC") - q.Add("sort", "createdAt:ASC") req.URL.RawQuery = q.Encode() }, assertResp: func(t *testing.T, req *http.Request, resp *http.Response) { @@ -1177,8 +1137,8 @@ func TestListTribeMemberChanges(t *testing.T) { // body body := decodeJSON[apimodel.ErrorResponse](t, resp.Body) domainErr := domain.LenOutOfRangeError{ - Min: 1, - Max: 2, + Min: 0, + Max: 1, Current: len(req.URL.Query()["sort"]), } assert.Equal(t, apimodel.ErrorResponse{ @@ -1229,44 +1189,6 @@ func TestListTribeMemberChanges(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", "createdAt:DESC") - q.Add("sort", "createdAt:ASC") - 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: apimodel.ErrorCode(domainErr.Code()), - Message: domainErr.Error(), - Params: map[string]any{ - "sort": paramSort, - }, - Path: []string{"$query", "sort"}, - }, - }, - }, body) - }, - }, { name: "ERR: invalid since", reqModifier: func(t *testing.T, req *http.Request) { diff --git a/internal/port/handler_http_api_tribe_snapshot.go b/internal/port/handler_http_api_tribe_snapshot.go index a3868ec..412ea7c 100644 --- a/internal/port/handler_http_api_tribe_snapshot.go +++ b/internal/port/handler_http_api_tribe_snapshot.go @@ -8,6 +8,13 @@ import ( "gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel" ) +const apiTribeSnapshotSortMaxLength = 1 + +var apiTribeSnapshotSortAllowedValues = []domain.TribeSnapshotSort{ + domain.TribeSnapshotSortDateASC, + domain.TribeSnapshotSortDateDESC, +} + //nolint:gocyclo func (h *apiHTTPHandler) ListTribeTribeSnapshots( w http.ResponseWriter, @@ -29,16 +36,18 @@ func (h *apiHTTPHandler) ListTribeTribeSnapshots( return } + sort := []string{domain.TribeSnapshotSortDateASC.String()} if params.Sort != nil { - if err := domainParams.PrependSortString(*params.Sort); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListTribeSnapshotsErrorPath).render(w, r, err) - return - } - } else { - if err := domainParams.PrependSortString([]string{domain.TribeSnapshotSortDateASC.String()}); err != nil { - h.errorRenderer.withErrorPathFormatter(formatListTribeSnapshotsErrorPath).render(w, r, err) - return - } + sort = *params.Sort + } + + if err := domainParams.PrependSortString( + sort, + apiTribeSnapshotSortAllowedValues, + apiTribeSnapshotSortMaxLength, + ); err != nil { + h.errorRenderer.withErrorPathFormatter(formatListTribeSnapshotsErrorPath).render(w, r, err) + return } if err := domainParams.SetServerKeys([]string{serverKey}); err != nil { diff --git a/internal/port/handler_http_api_tribe_snapshot_test.go b/internal/port/handler_http_api_tribe_snapshot_test.go index cd447d7..e9a9617 100644 --- a/internal/port/handler_http_api_tribe_snapshot_test.go +++ b/internal/port/handler_http_api_tribe_snapshot_test.go @@ -348,13 +348,12 @@ func TestListTribeTribeSnapshots(t *testing.T) { }, }, { - name: "ERR: len(sort) > 2", + name: "ERR: len(sort) > 1", reqModifier: func(t *testing.T, req *http.Request) { t.Helper() q := req.URL.Query() q.Add("sort", "date:DESC") q.Add("sort", "date:ASC") - q.Add("sort", "date:ASC") req.URL.RawQuery = q.Encode() }, assertResp: func(t *testing.T, req *http.Request, resp *http.Response) { @@ -365,8 +364,8 @@ func TestListTribeTribeSnapshots(t *testing.T) { // body body := decodeJSON[apimodel.ErrorResponse](t, resp.Body) domainErr := domain.LenOutOfRangeError{ - Min: 1, - Max: 2, + Min: 0, + Max: 1, Current: len(req.URL.Query()["sort"]), } assert.Equal(t, apimodel.ErrorResponse{ @@ -417,44 +416,6 @@ func TestListTribeTribeSnapshots(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", "date:DESC") - q.Add("sort", "date:ASC") - 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: apimodel.ErrorCode(domainErr.Code()), - Message: domainErr.Error(), - Params: map[string]any{ - "sort": paramSort, - }, - Path: []string{"$query", "sort"}, - }, - }, - }, body) - }, - }, { name: "ERR: version not found", reqModifier: func(t *testing.T, req *http.Request) { diff --git a/internal/port/handler_http_api_tribe_test.go b/internal/port/handler_http_api_tribe_test.go index c8c8e89..88b3cd7 100644 --- a/internal/port/handler_http_api_tribe_test.go +++ b/internal/port/handler_http_api_tribe_test.go @@ -474,7 +474,7 @@ func TestListTribes(t *testing.T) { // body body := decodeJSON[apimodel.ErrorResponse](t, resp.Body) domainErr := domain.LenOutOfRangeError{ - Min: 1, + Min: 0, Max: 2, Current: len(req.URL.Query()["sort"]), } -- 2.45.1