diff --git a/internal/api/api.go b/internal/api/api.go index c86dc778..072ce0a5 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -10,7 +10,6 @@ import ( "os" "reflect" "sort" - "strconv" "strings" "sync" "time" @@ -36,58 +35,6 @@ func interfaceIsEmpty(i interface{}) bool { return reflect.ValueOf(i).Kind() != reflect.Ptr || reflect.ValueOf(i).IsNil() } -func paginate2(itemsPtr interface{}, itemsPerPage int, page int) int { - ritems := reflect.ValueOf(itemsPtr).Elem() - - itemsLen := ritems.Len() - if itemsLen == 0 { - return 0 - } - - pageCount := (itemsLen / itemsPerPage) - if (itemsLen % itemsPerPage) != 0 { - pageCount++ - } - - min := page * itemsPerPage - if min > itemsLen { - min = itemsLen - } - - max := (page + 1) * itemsPerPage - if max > itemsLen { - max = itemsLen - } - - ritems.Set(ritems.Slice(min, max)) - - return pageCount -} - -func paginate(itemsPtr interface{}, itemsPerPageStr string, pageStr string) (int, error) { - itemsPerPage := 100 - - if itemsPerPageStr != "" { - tmp, err := strconv.ParseUint(itemsPerPageStr, 10, 31) - if err != nil { - return 0, err - } - itemsPerPage = int(tmp) - } - - page := 0 - - if pageStr != "" { - tmp, err := strconv.ParseUint(pageStr, 10, 31) - if err != nil { - return 0, err - } - page = int(tmp) - } - - return paginate2(itemsPtr, itemsPerPage, page), nil -} - func sortedKeys(paths map[string]*conf.Path) []string { ret := make([]string, len(paths)) i := 0 diff --git a/internal/api/api_test.go b/internal/api/api_test.go index f34c307a..a88446aa 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -74,38 +74,6 @@ func checkError(t *testing.T, msg string, body io.Reader) { require.Equal(t, map[string]interface{}{"error": msg}, resErr) } -func TestPaginate(t *testing.T) { - items := make([]int, 5) - for i := 0; i < 5; i++ { - items[i] = i - } - - pageCount, err := paginate(&items, "1", "1") - require.NoError(t, err) - require.Equal(t, 5, pageCount) - require.Equal(t, []int{1}, items) - - items = make([]int, 5) - for i := 0; i < 5; i++ { - items[i] = i - } - - pageCount, err = paginate(&items, "3", "2") - require.NoError(t, err) - require.Equal(t, 2, pageCount) - require.Equal(t, []int{}, items) - - items = make([]int, 6) - for i := 0; i < 6; i++ { - items[i] = i - } - - pageCount, err = paginate(&items, "4", "1") - require.NoError(t, err) - require.Equal(t, 2, pageCount) - require.Equal(t, []int{4, 5}, items) -} - func TestConfigAuth(t *testing.T) { cnf := tempConf(t, "api: yes\n") diff --git a/internal/api/paginate.go b/internal/api/paginate.go new file mode 100644 index 00000000..8be72062 --- /dev/null +++ b/internal/api/paginate.go @@ -0,0 +1,63 @@ +package api + +import ( + "fmt" + "reflect" + "strconv" +) + +func paginate2(itemsPtr interface{}, itemsPerPage int, page int) int { + ritems := reflect.ValueOf(itemsPtr).Elem() + + itemsLen := ritems.Len() + if itemsLen == 0 { + return 0 + } + + pageCount := (itemsLen / itemsPerPage) + if (itemsLen % itemsPerPage) != 0 { + pageCount++ + } + + min := page * itemsPerPage + if min > itemsLen { + min = itemsLen + } + + max := (page + 1) * itemsPerPage + if max > itemsLen { + max = itemsLen + } + + ritems.Set(ritems.Slice(min, max)) + + return pageCount +} + +func paginate(itemsPtr interface{}, itemsPerPageStr string, pageStr string) (int, error) { + itemsPerPage := 100 + + if itemsPerPageStr != "" { + tmp, err := strconv.ParseUint(itemsPerPageStr, 10, 31) + if err != nil { + return 0, err + } + itemsPerPage = int(tmp) + + if itemsPerPage == 0 { + return 0, fmt.Errorf("invalid items per page") + } + } + + page := 0 + + if pageStr != "" { + tmp, err := strconv.ParseUint(pageStr, 10, 31) + if err != nil { + return 0, err + } + page = int(tmp) + } + + return paginate2(itemsPtr, itemsPerPage, page), nil +} diff --git a/internal/api/paginate_test.go b/internal/api/paginate_test.go new file mode 100644 index 00000000..cd5daea8 --- /dev/null +++ b/internal/api/paginate_test.go @@ -0,0 +1,65 @@ +package api + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPaginate(t *testing.T) { + func() { + items := make([]int, 5) + for i := 0; i < 5; i++ { + items[i] = i + } + + pageCount, err := paginate(&items, "1", "1") + require.NoError(t, err) + require.Equal(t, 5, pageCount) + require.Equal(t, []int{1}, items) + }() + + func() { + items := make([]int, 5) + for i := 0; i < 5; i++ { + items[i] = i + } + + pageCount, err := paginate(&items, "3", "2") + require.NoError(t, err) + require.Equal(t, 2, pageCount) + require.Equal(t, []int{}, items) + }() + + func() { + items := make([]int, 6) + for i := 0; i < 6; i++ { + items[i] = i + } + + pageCount, err := paginate(&items, "4", "1") + require.NoError(t, err) + require.Equal(t, 2, pageCount) + require.Equal(t, []int{4, 5}, items) + }() + + func() { + items := make([]int, 0) + + pageCount, err := paginate(&items, "1", "0") + require.NoError(t, err) + require.Equal(t, 0, pageCount) + require.Equal(t, []int{}, items) + }() +} + +func FuzzPaginate(f *testing.F) { + f.Fuzz(func(_ *testing.T, str1 string, str2 string) { + items := make([]int, 6) + for i := 0; i < 6; i++ { + items[i] = i + } + + paginate(&items, str1, str2) //nolint:errcheck + }) +} diff --git a/internal/api/testdata/fuzz/FuzzPaginate/23731da0f18d31d0 b/internal/api/testdata/fuzz/FuzzPaginate/23731da0f18d31d0 new file mode 100644 index 00000000..8e9f4e5e --- /dev/null +++ b/internal/api/testdata/fuzz/FuzzPaginate/23731da0f18d31d0 @@ -0,0 +1,3 @@ +go test fuzz v1 +string("A") +string("0") diff --git a/internal/api/testdata/fuzz/FuzzPaginate/34523a772174e26e b/internal/api/testdata/fuzz/FuzzPaginate/34523a772174e26e new file mode 100644 index 00000000..57b56556 --- /dev/null +++ b/internal/api/testdata/fuzz/FuzzPaginate/34523a772174e26e @@ -0,0 +1,3 @@ +go test fuzz v1 +string("1") +string("A") diff --git a/internal/api/testdata/fuzz/FuzzPaginate/85649d45641911d0 b/internal/api/testdata/fuzz/FuzzPaginate/85649d45641911d0 new file mode 100644 index 00000000..befd7df0 --- /dev/null +++ b/internal/api/testdata/fuzz/FuzzPaginate/85649d45641911d0 @@ -0,0 +1,3 @@ +go test fuzz v1 +string("0") +string("")