ARM-software/golang-utils

View on GitHub
utils/collection/pagination/testing.go

Summary

Maintainability
A
3 hrs
Test Coverage
/*
 * Copyright (C) 2020-2022 Arm Limited or its affiliates and Contributors. All rights reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

package pagination

import (
    "context"
    "fmt"
    "math/rand"
    "time"

    "github.com/bxcodec/faker/v3"

    "github.com/ARM-software/golang-utils/utils/commonerrors"
    "github.com/ARM-software/golang-utils/utils/parallelisation"
)

type MockItem struct {
    Index  int
    ID     string
    Value1 string
    Value2 string
}

func GenerateMockItem() *MockItem {
    return &MockItem{
        ID:     faker.UUIDHyphenated(),
        Value1: faker.Name(),
        Value2: faker.Sentence(),
    }
}

type MockPageIterator struct {
    elements     []MockItem
    currentIndex int
}

func (m *MockPageIterator) HasNext() bool {
    return m.currentIndex < len(m.elements)
}

func (m *MockPageIterator) GetNext() (item interface{}, err error) {
    if m.currentIndex < 0 {
        err = fmt.Errorf("%w: incorrect element index", commonerrors.ErrInvalid)
        return
    }
    if !m.HasNext() {
        err = fmt.Errorf("%w: there is no more items", commonerrors.ErrNotFound)
        return
    }
    element := m.elements[m.currentIndex]
    item = &element
    m.currentIndex++
    return
}

func NewMockPageIterator(page *MockPage) (IIterator, error) {
    if page == nil {
        return nil, commonerrors.ErrUndefined
    }
    return &MockPageIterator{
        elements:     page.elements,
        currentIndex: 0,
    }, nil
}

type MockPage struct {
    elements   []MockItem
    nextPage   IStream
    futurePage IStream
}

func (m *MockPage) HasNext() bool {
    return m.nextPage != nil
}

func (m *MockPage) GetNext(ctx context.Context) (page IPage, err error) {
    err = parallelisation.DetermineContextError(ctx)
    if err != nil {
        return
    }
    if !m.HasNext() {
        err = fmt.Errorf("%w: there is no more pages", commonerrors.ErrNotFound)
    }
    page = m.nextPage
    return
}

func (m *MockPage) GetItemIterator() (IIterator, error) {
    return NewMockPageIterator(m)
}

func (m *MockPage) AppendItem(i *MockItem) error {
    if i == nil {
        return commonerrors.ErrUndefined
    }
    m.elements = append(m.elements, *i)
    return nil
}

func (m *MockPage) SetNext(next IStream) error {
    if next == nil {
        return commonerrors.ErrUndefined
    }
    m.nextPage = next
    return nil
}

func (m *MockPage) SetFuture(future IStream) error {
    if future == nil {
        return commonerrors.ErrUndefined
    }
    m.futurePage = future
    return nil
}

func (m *MockPage) SetIndexes(firstIndex int) {
    for i := 0; i < len(m.elements); i++ {
        m.elements[i].Index = i + firstIndex
    }
    if m.nextPage != nil {
        nPage := m.nextPage.(*MockPage)
        nPage.SetIndexes(firstIndex + len(m.elements))
    }
    if m.futurePage != nil {
        fPage := m.futurePage.(*MockPage)
        fPage.SetIndexes(firstIndex + len(m.elements))
    }
}

func (m *MockPage) GetItemCount() (int64, error) {
    return int64(len(m.elements)), nil
}

func (m *MockPage) HasFuture() bool {
    return m.futurePage != nil
}

func (m *MockPage) GetFuture(ctx context.Context) (future IStream, err error) {
    err = parallelisation.DetermineContextError(ctx)
    if err != nil {
        return
    }
    if !m.HasFuture() {
        err = fmt.Errorf("%w: there is no future page", commonerrors.ErrNotFound)
    }
    future = m.futurePage
    return
}

func GenerateEmptyPage() IStream {
    return &MockPage{}
}

func GenerateMockPage() (IStream, error) {
    random := rand.New(rand.NewSource(time.Now().Unix())) //nolint:gosec //causes G404: Use of weak random number generator (math/rand instead of crypto/rand) (gosec), So disable gosec as this is just for testing
    page := GenerateEmptyPage().(*MockPage)
    n := random.Intn(50) //nolint:gosec //causes G404: Use of weak random number generator (math/rand instead of crypto/rand) (gosec), So disable gosec as this is just for testing
    for i := 0; i < n; i++ {
        err := page.AppendItem(GenerateMockItem())
        if err != nil {
            return nil, err
        }
    }
    return page, nil
}

func GenerateMockCollection() (firstPage IStream, itemTotal int64, err error) {
    random := rand.New(rand.NewSource(time.Now().Unix())) //nolint:gosec //causes G404: Use of weak random number generator (math/rand instead of crypto/rand) (gosec), So disable gosec as this is just for testing
    n := random.Intn(50)                                  //nolint:gosec //causes G404: Use of weak random number generator (math/rand instead of crypto/rand) (gosec), So disable gosec as this is just for testing
    var next IStream
    for i := 0; i < n; i++ {
        currentPage, subErr := GenerateMockPage()
        if subErr != nil {
            err = subErr
            return
        }
        currentCount, subErr := currentPage.GetItemCount()
        if subErr != nil {
            err = subErr
            return
        }
        itemTotal += currentCount

        if next != nil {
            mockP := currentPage.(*MockPage)
            subErr = mockP.SetNext(next)
            if subErr != nil {
                err = subErr
                return
            }

        }
        firstPage = currentPage
        next = firstPage
    }
    if firstPage == nil {
        return
    }
    mockP := firstPage.(*MockPage)
    mockP.SetIndexes(0)
    return
}

func GenerateMockStream() (firstPage IStream, itemTotal int64, err error) {
    random := rand.New(rand.NewSource(time.Now().Unix())) //nolint:gosec //causes G404: Use of weak random number generator (math/rand instead of crypto/rand) (gosec), So disable gosec as this is just for testing
    n := random.Intn(50)                                  //nolint:gosec //causes G404: Use of weak random number generator (math/rand instead of crypto/rand) (gosec), So disable gosec as this is just for testing
    var future IStream
    for i := 0; i < n; i++ {
        currentPage, subErr := GenerateMockPage()
        if subErr != nil {
            err = subErr
            return
        }
        currentCount, subErr := currentPage.GetItemCount()
        if subErr != nil {
            err = subErr
            return
        }
        itemTotal += currentCount

        mockP := currentPage.(*MockPage)
        if future == nil {
            subErr = mockP.SetFuture(GenerateEmptyPage())
        } else {
            subErr = mockP.SetFuture(future)
        }
        if subErr != nil {
            err = subErr
            return
        }

        firstPage = currentPage
        future = firstPage
    }
    if firstPage == nil {
        return
    }
    mockP := firstPage.(*MockPage)
    mockP.SetIndexes(0)
    return
}