github.com/maypok86/otter@v1.2.1/internal/expiry/queue_test.go (about)

     1  // Copyright (c) 2024 Alexey Mayshev. All rights reserved.
     2  // Copyright 2009 The Go Authors. All rights reserved.
     3  //
     4  // Copyright notice. Initial version of the following tests was based on
     5  // the following file from the Go Programming Language core repo:
     6  // https://cs.opensource.google/go/go/+/refs/tags/go1.21.5:src/container/list/list_test.go
     7  //
     8  // Use of this source code is governed by a BSD-style
     9  // license that can be found in the LICENSE file.
    10  // That can be found at https://cs.opensource.google/go/go/+/refs/tags/go1.21.5:LICENSE
    11  
    12  package expiry
    13  
    14  import (
    15  	"strconv"
    16  	"testing"
    17  
    18  	"github.com/maypok86/otter/internal/generated/node"
    19  )
    20  
    21  func checkQueueLen[K comparable, V any](t *testing.T, q *queue[K, V], length int) bool {
    22  	t.Helper()
    23  
    24  	if n := q.length(); n != length {
    25  		t.Errorf("q.length() = %d, want %d", n, length)
    26  		return false
    27  	}
    28  	return true
    29  }
    30  
    31  func checkQueuePointers[K comparable, V any](t *testing.T, q *queue[K, V], nodes []node.Node[K, V]) {
    32  	t.Helper()
    33  
    34  	if !checkQueueLen(t, q, len(nodes)) {
    35  		return
    36  	}
    37  
    38  	// zero length queues must be the zero value
    39  	if len(nodes) == 0 {
    40  		if !(node.Equals(q.head, nil) && node.Equals(q.tail, nil)) {
    41  			t.Errorf("q.head = %p, q.tail = %p; both should be nil", q.head, q.tail)
    42  		}
    43  		return
    44  	}
    45  
    46  	// check internal and external prev/next connections
    47  	for i, n := range nodes {
    48  		var prev node.Node[K, V]
    49  		if i > 0 {
    50  			prev = nodes[i-1]
    51  		}
    52  		if p := n.PrevExp(); !node.Equals(p, prev) {
    53  			t.Errorf("elt[%d](%p).prev = %p, want %p", i, n, p, prev)
    54  		}
    55  
    56  		var next node.Node[K, V]
    57  		if i < len(nodes)-1 {
    58  			next = nodes[i+1]
    59  		}
    60  		if nn := n.NextExp(); !node.Equals(nn, next) {
    61  			t.Errorf("nodes[%d](%p).next = %p, want %p", i, n, nn, next)
    62  		}
    63  	}
    64  }
    65  
    66  func newNode[K comparable](e K) node.Node[K, K] {
    67  	m := node.NewManager[K, K](node.Config{WithCost: true, WithExpiration: true})
    68  	return m.Create(e, e, 0, 0)
    69  }
    70  
    71  func TestQueue(t *testing.T) {
    72  	q := newQueue[string, string]()
    73  	checkQueuePointers(t, q, []node.Node[string, string]{})
    74  
    75  	// Single element queue
    76  	e := newNode("a")
    77  	q.push(e)
    78  	checkQueuePointers(t, q, []node.Node[string, string]{e})
    79  	q.remove(e)
    80  	q.push(e)
    81  	checkQueuePointers(t, q, []node.Node[string, string]{e})
    82  	q.remove(e)
    83  	checkQueuePointers(t, q, []node.Node[string, string]{})
    84  
    85  	// Bigger queue
    86  	e2 := newNode("2")
    87  	e1 := newNode("1")
    88  	e3 := newNode("3")
    89  	e4 := newNode("4")
    90  	q.push(e1)
    91  	q.push(e2)
    92  	q.push(e3)
    93  	q.push(e4)
    94  	checkQueuePointers(t, q, []node.Node[string, string]{e1, e2, e3, e4})
    95  
    96  	q.remove(e2)
    97  	checkQueuePointers(t, q, []node.Node[string, string]{e1, e3, e4})
    98  
    99  	// move from middle
   100  	q.remove(e3)
   101  	q.push(e3)
   102  	checkQueuePointers(t, q, []node.Node[string, string]{e1, e4, e3})
   103  
   104  	q.clear()
   105  	q.push(e3)
   106  	q.push(e1)
   107  	q.push(e4)
   108  	checkQueuePointers(t, q, []node.Node[string, string]{e3, e1, e4})
   109  
   110  	// should be no-op
   111  	q.remove(e3)
   112  	q.push(e3)
   113  	checkQueuePointers(t, q, []node.Node[string, string]{e1, e4, e3})
   114  
   115  	// Check standard iteration.
   116  	sum := 0
   117  	for e := q.head; !node.Equals(e, nil); e = e.NextExp() {
   118  		i, err := strconv.Atoi(e.Value())
   119  		if err != nil {
   120  			continue
   121  		}
   122  		sum += i
   123  	}
   124  	if sum != 8 {
   125  		t.Errorf("sum over l = %d, want 8", sum)
   126  	}
   127  
   128  	// Clear all elements by iterating
   129  	var next node.Node[string, string]
   130  	for e := q.head; !node.Equals(e, nil); e = next {
   131  		next = e.NextExp()
   132  		q.remove(e)
   133  	}
   134  	checkQueuePointers(t, q, []node.Node[string, string]{})
   135  }
   136  
   137  func TestQueue_Remove(t *testing.T) {
   138  	q := newQueue[int, int]()
   139  
   140  	e1 := newNode(1)
   141  	e2 := newNode(2)
   142  	q.push(e1)
   143  	q.push(e2)
   144  	checkQueuePointers(t, q, []node.Node[int, int]{e1, e2})
   145  	e := q.head
   146  	q.remove(e)
   147  	checkQueuePointers(t, q, []node.Node[int, int]{e2})
   148  	q.remove(e)
   149  	checkQueuePointers(t, q, []node.Node[int, int]{e2})
   150  }