github.com/MetalBlockchain/metalgo@v1.11.9/utils/buffer/bounded_nonblocking_queue_test.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package buffer
     5  
     6  import (
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func TestNewBoundedQueue(t *testing.T) {
    13  	require := require.New(t)
    14  
    15  	// Case: maxSize < 1
    16  	_, err := NewBoundedQueue[bool](0, nil)
    17  	require.ErrorIs(err, errInvalidMaxSize)
    18  
    19  	// Case: maxSize == 1 and nil onEvict
    20  	b, err := NewBoundedQueue[bool](1, nil)
    21  	require.NoError(err)
    22  
    23  	// Put 2 elements to make sure we don't panic on evict
    24  	b.Push(true)
    25  	b.Push(true)
    26  }
    27  
    28  func TestBoundedQueue(t *testing.T) {
    29  	require := require.New(t)
    30  
    31  	maxSize := 3
    32  	evicted := []int{}
    33  	onEvict := func(elt int) {
    34  		evicted = append(evicted, elt)
    35  	}
    36  	b, err := NewBoundedQueue(maxSize, onEvict)
    37  	require.NoError(err)
    38  
    39  	require.Zero(b.Len())
    40  
    41  	// Fill the queue
    42  	for i := 0; i < maxSize; i++ {
    43  		b.Push(i)
    44  		require.Equal(i+1, b.Len())
    45  		got, ok := b.Peek()
    46  		require.True(ok)
    47  		require.Zero(got)
    48  		got, ok = b.Index(i)
    49  		require.True(ok)
    50  		require.Equal(i, got)
    51  		require.Len(b.List(), i+1)
    52  	}
    53  	require.Equal([]int{}, evicted)
    54  	require.Len(b.List(), maxSize)
    55  	// Queue is [0, 1, 2]
    56  
    57  	// Empty the queue
    58  	for i := 0; i < maxSize; i++ {
    59  		got, ok := b.Pop()
    60  		require.True(ok)
    61  		require.Equal(i, got)
    62  		require.Equal(maxSize-i-1, b.Len())
    63  		require.Len(b.List(), maxSize-i-1)
    64  	}
    65  
    66  	// Queue is empty
    67  
    68  	_, ok := b.Pop()
    69  	require.False(ok)
    70  	_, ok = b.Peek()
    71  	require.False(ok)
    72  	_, ok = b.Index(0)
    73  	require.False(ok)
    74  	require.Zero(b.Len())
    75  	require.Empty(b.List())
    76  
    77  	// Fill the queue again
    78  	for i := 0; i < maxSize; i++ {
    79  		b.Push(i)
    80  		require.Equal(i+1, b.Len())
    81  	}
    82  
    83  	// Queue is [0, 1, 2]
    84  
    85  	// Putting another element should evict the oldest.
    86  	b.Push(maxSize)
    87  
    88  	// Queue is [1, 2, 3]
    89  
    90  	require.Equal(maxSize, b.Len())
    91  	require.Len(b.List(), maxSize)
    92  	got, ok := b.Peek()
    93  	require.True(ok)
    94  	require.Equal(1, got)
    95  	got, ok = b.Index(0)
    96  	require.True(ok)
    97  	require.Equal(1, got)
    98  	got, ok = b.Index(maxSize - 1)
    99  	require.True(ok)
   100  	require.Equal(maxSize, got)
   101  	require.Equal([]int{0}, evicted)
   102  
   103  	// Put 2 more elements
   104  	b.Push(maxSize + 1)
   105  	b.Push(maxSize + 2)
   106  
   107  	// Queue is [3, 4, 5]
   108  
   109  	require.Equal(maxSize, b.Len())
   110  	require.Equal([]int{0, 1, 2}, evicted)
   111  	got, ok = b.Peek()
   112  	require.True(ok)
   113  	require.Equal(3, got)
   114  	require.Equal([]int{3, 4, 5}, b.List())
   115  
   116  	for i := maxSize; i < 2*maxSize; i++ {
   117  		got, ok := b.Index(i - maxSize)
   118  		require.True(ok)
   119  		require.Equal(i, got)
   120  	}
   121  
   122  	// Empty the queue
   123  	for i := 0; i < maxSize; i++ {
   124  		got, ok := b.Pop()
   125  		require.True(ok)
   126  		require.Equal(i+3, got)
   127  		require.Equal(maxSize-i-1, b.Len())
   128  		require.Len(b.List(), maxSize-i-1)
   129  	}
   130  
   131  	// Queue is empty
   132  
   133  	require.Empty(b.List())
   134  	require.Zero(b.Len())
   135  	require.Equal([]int{0, 1, 2}, evicted)
   136  	_, ok = b.Pop()
   137  	require.False(ok)
   138  	_, ok = b.Peek()
   139  	require.False(ok)
   140  	_, ok = b.Index(0)
   141  	require.False(ok)
   142  }