github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/container/queue/iterator_test.go (about)

     1  // Copyright 2022 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package queue
    15  
    16  import (
    17  	"math/rand"
    18  	"testing"
    19  
    20  	"github.com/edwingeng/deque"
    21  	"github.com/stretchr/testify/require"
    22  )
    23  
    24  const (
    25  	iterTestSize = 10007
    26  )
    27  
    28  func TestChunkQueueIteratorPrevNext(t *testing.T) {
    29  	t.Parallel()
    30  	q := NewChunkQueue[int]()
    31  	for i := 0; i < iterTestSize; i++ {
    32  		q.Push(i)
    33  	}
    34  
    35  	var it *ChunkQueueIterator[int]
    36  	i := 0
    37  	for it = q.First(); it.Valid(); it.Next() {
    38  		v := it.Value()
    39  		require.Equal(t, i, it.Index())
    40  		require.Equal(t, i, v)
    41  		i++
    42  	}
    43  	i--
    44  	for it = q.End(); it.Prev(); {
    45  		v := it.Value()
    46  		require.Equal(t, i, it.Index())
    47  		require.Equal(t, i, v)
    48  		i--
    49  	}
    50  
    51  	it = &ChunkQueueIterator[int]{0, nil}
    52  	require.False(t, it.Prev())
    53  	require.False(t, it.Next())
    54  }
    55  
    56  func BenchmarkIterate(b *testing.B) {
    57  	b.Run("Iterate-ChunkQueue-by-iterator", func(b *testing.B) {
    58  		q := NewChunkQueue[int]()
    59  		n := b.N
    60  		for i := 0; i < n; i++ {
    61  			q.Push(i)
    62  		}
    63  		b.ResetTimer()
    64  
    65  		i := 0
    66  		for it := q.First(); it.Valid(); it.Next() {
    67  			v := it.Value()
    68  			if v != i {
    69  				panic("not equal")
    70  			}
    71  			i++
    72  		}
    73  	})
    74  
    75  	b.Run("Iterate-ChunkQueue-by-Peek", func(b *testing.B) {
    76  		q := NewChunkQueue[int]()
    77  		n := b.N
    78  		for i := 0; i < n; i++ {
    79  			q.Push(i)
    80  		}
    81  		b.ResetTimer()
    82  
    83  		i := 0
    84  		for i = 0; i < q.Len(); i++ {
    85  			if q.Peek(i) != i {
    86  				panic(q.Peek(i))
    87  			}
    88  		}
    89  	})
    90  
    91  	b.Run("Iterate-ChunkQueue-by-Range", func(b *testing.B) {
    92  		q := NewChunkQueue[int]()
    93  		n := b.N
    94  		for i := 0; i < n; i++ {
    95  			q.Push(i)
    96  		}
    97  		b.ResetTimer()
    98  
    99  		q.RangeWithIndex(func(idx int, val int) bool {
   100  			if val != idx {
   101  				panic("not equal")
   102  			}
   103  			return true
   104  		})
   105  	})
   106  
   107  	b.Run("Iterate-Slice-byLoop", func(b *testing.B) {
   108  		n := b.N
   109  		q := make([]int, n)
   110  		for i := 0; i < n; i++ {
   111  			q[i] = i
   112  		}
   113  		b.ResetTimer()
   114  
   115  		for i := 0; i < len(q); i++ {
   116  			if q[i] != i {
   117  				panic("error")
   118  			}
   119  		}
   120  	})
   121  
   122  	b.Run("Iterate-3rdPartyDeque-byRange", func(b *testing.B) {
   123  		q := deque.NewDeque()
   124  		n := b.N
   125  
   126  		for i := 0; i < n; i++ {
   127  			q.Enqueue(i)
   128  		}
   129  		b.ResetTimer()
   130  
   131  		q.Range(func(idx int, val deque.Elem) bool {
   132  			if val.(int) != idx {
   133  				panic("not equal")
   134  			}
   135  			return true
   136  		})
   137  	})
   138  
   139  	b.Run("Iterate-3rdPartyDeque-byPeek", func(b *testing.B) {
   140  		q := deque.NewDeque()
   141  		n := b.N
   142  
   143  		for i := 0; i < n; i++ {
   144  			q.Enqueue(i)
   145  		}
   146  		b.ResetTimer()
   147  
   148  		for i := 0; i < n; i++ {
   149  			val := q.Peek(i)
   150  			if val != i {
   151  				panic("not equal")
   152  			}
   153  		}
   154  	})
   155  }
   156  
   157  func TestChunkQueueGetIterator(t *testing.T) {
   158  	t.Parallel()
   159  
   160  	q := NewChunkQueue[int]()
   161  	q.PushMany(0, 1)
   162  	var it *ChunkQueueIterator[int]
   163  	it = q.GetIterator(-1)
   164  	require.Nil(t, it)
   165  	it = q.GetIterator(2)
   166  	require.Nil(t, it)
   167  	oldIt := q.GetIterator(1)
   168  	q.PopMany(2)
   169  	require.False(t, oldIt.Valid(), oldIt.Prev())
   170  	require.True(t, q.Empty())
   171  
   172  	for i := 0; i < iterTestSize; i++ {
   173  		q.Push(i)
   174  	}
   175  	require.True(t, q.End().Index() < 0)
   176  	require.False(t, q.Begin().Prev())
   177  	require.Panics(t, func() {
   178  		q.End().Set(1)
   179  	})
   180  
   181  	require.NotPanics(t, func() {
   182  		for i := 0; i < iterTestSize; i++ {
   183  			it = q.GetIterator(i)
   184  			require.Equal(t, i, it.Index(), it.Value(), q.Peek(i))
   185  		}
   186  	})
   187  
   188  	cnt := 0
   189  	for !q.Empty() {
   190  		n := rand.Intn(q.Len())
   191  		if n == 0 {
   192  			n = testCaseSize/20 + 1
   193  		}
   194  		it := q.Begin()
   195  		require.True(t, it.Valid())
   196  
   197  		q.PopMany(n)
   198  		require.Equal(t, -1, it.Index())
   199  		require.False(t, it.Valid())
   200  
   201  		require.Nil(t, q.Begin().chunk.prev)
   202  		cnt += n
   203  		v := q.Begin().Value()
   204  		if cnt >= iterTestSize {
   205  			require.True(t, !it.Valid())
   206  		} else {
   207  			require.Equal(t, cnt, v)
   208  		}
   209  	}
   210  }