github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/clist/clist_test.go (about)

     1  package clist
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/gnolang/gno/tm2/pkg/random"
     9  	"github.com/stretchr/testify/assert"
    10  )
    11  
    12  func TestPanicOnMaxLength(t *testing.T) {
    13  	t.Parallel()
    14  
    15  	maxLength := 1000
    16  
    17  	l := newWithMax(maxLength)
    18  	for i := 0; i < maxLength; i++ {
    19  		l.PushBack(1)
    20  	}
    21  	assert.Panics(t, func() {
    22  		l.PushBack(1)
    23  	})
    24  }
    25  
    26  func TestSmall(t *testing.T) {
    27  	t.Parallel()
    28  
    29  	l := New()
    30  	el1 := l.PushBack(1)
    31  	el2 := l.PushBack(2)
    32  	el3 := l.PushBack(3)
    33  	if l.Len() != 3 {
    34  		t.Error("Expected len 3, got ", l.Len())
    35  	}
    36  
    37  	// fmt.Printf("%p %v\n", el1, el1)
    38  	// fmt.Printf("%p %v\n", el2, el2)
    39  	// fmt.Printf("%p %v\n", el3, el3)
    40  
    41  	r1 := l.Remove(el1)
    42  
    43  	// fmt.Printf("%p %v\n", el1, el1)
    44  	// fmt.Printf("%p %v\n", el2, el2)
    45  	// fmt.Printf("%p %v\n", el3, el3)
    46  
    47  	r2 := l.Remove(el2)
    48  
    49  	// fmt.Printf("%p %v\n", el1, el1)
    50  	// fmt.Printf("%p %v\n", el2, el2)
    51  	// fmt.Printf("%p %v\n", el3, el3)
    52  
    53  	r3 := l.Remove(el3)
    54  
    55  	if r1 != 1 {
    56  		t.Error("Expected 1, got ", r1)
    57  	}
    58  	if r2 != 2 {
    59  		t.Error("Expected 2, got ", r2)
    60  	}
    61  	if r3 != 3 {
    62  		t.Error("Expected 3, got ", r3)
    63  	}
    64  	if l.Len() != 0 {
    65  		t.Error("Expected len 0, got ", l.Len())
    66  	}
    67  }
    68  
    69  func TestScanRightDeleteRandom(t *testing.T) {
    70  	t.Parallel()
    71  
    72  	const numElements = 1000
    73  	const numTimes = 100
    74  	const numScanners = 10
    75  
    76  	l := New()
    77  	stop := make(chan struct{})
    78  
    79  	els := make([]*CElement, numElements)
    80  	for i := 0; i < numElements; i++ {
    81  		el := l.PushBack(i)
    82  		els[i] = el
    83  	}
    84  
    85  	// Launch scanner routines that will rapidly iterate over elements.
    86  	for i := 0; i < numScanners; i++ {
    87  		go func(scannerID int) {
    88  			var el *CElement
    89  			restartCounter := 0
    90  			counter := 0
    91  		FOR_LOOP:
    92  			for {
    93  				select {
    94  				case <-stop:
    95  					fmt.Println("stopped")
    96  					break FOR_LOOP
    97  				default:
    98  				}
    99  				if el == nil {
   100  					el = l.FrontWait()
   101  					restartCounter++
   102  				}
   103  				el = el.Next()
   104  				counter++
   105  			}
   106  			fmt.Printf("Scanner %v restartCounter: %v counter: %v\n", scannerID, restartCounter, counter)
   107  		}(i)
   108  	}
   109  
   110  	// Remove an element, push back an element.
   111  	for i := 0; i < numTimes; i++ {
   112  		// Pick an element to remove
   113  		rmElIdx := random.RandIntn(len(els))
   114  		rmEl := els[rmElIdx]
   115  
   116  		// Remove it
   117  		l.Remove(rmEl)
   118  		// fmt.Print(".")
   119  
   120  		// Insert a new element
   121  		newEl := l.PushBack(-1*i - 1)
   122  		els[rmElIdx] = newEl
   123  
   124  		if i%100000 == 0 {
   125  			fmt.Printf("Pushed %vK elements so far...\n", i/1000)
   126  		}
   127  	}
   128  
   129  	// Stop scanners
   130  	close(stop)
   131  	// time.Sleep(time.Second * 1)
   132  
   133  	// And remove all the elements.
   134  	for el := l.Front(); el != nil; el = el.Next() {
   135  		l.Remove(el)
   136  	}
   137  	if l.Len() != 0 {
   138  		t.Fatal("Failed to remove all elements from CList")
   139  	}
   140  }
   141  
   142  func TestWaitChan(t *testing.T) {
   143  	t.Parallel()
   144  
   145  	l := New()
   146  	ch := l.WaitChan()
   147  
   148  	// 1) add one element to an empty list
   149  	go l.PushBack(1)
   150  	<-ch
   151  
   152  	// 2) and remove it
   153  	el := l.Front()
   154  	v := l.Remove(el)
   155  	if v != 1 {
   156  		t.Fatal("where is 1 coming from?")
   157  	}
   158  
   159  	// 3) test iterating forward and waiting for Next (NextWaitChan and Next)
   160  	el = l.PushBack(0)
   161  
   162  	done := make(chan struct{})
   163  	pushed := 0
   164  	go func() {
   165  		for i := 1; i < 100; i++ {
   166  			l.PushBack(i)
   167  			pushed++
   168  			time.Sleep(time.Duration(random.RandIntn(25)) * time.Millisecond)
   169  		}
   170  		// apply a deterministic pause so the counter has time to catch up
   171  		time.Sleep(25 * time.Millisecond)
   172  		close(done)
   173  	}()
   174  
   175  	next := el
   176  	seen := 0
   177  FOR_LOOP:
   178  	for {
   179  		select {
   180  		case <-next.NextWaitChan():
   181  			next = next.Next()
   182  			seen++
   183  			if next == nil {
   184  				t.Fatal("Next should not be nil when waiting on NextWaitChan")
   185  			}
   186  		case <-done:
   187  			break FOR_LOOP
   188  		case <-time.After(10 * time.Second):
   189  			t.Fatal("max execution time")
   190  		}
   191  	}
   192  
   193  	if pushed != seen {
   194  		t.Fatalf("number of pushed items (%d) not equal to number of seen items (%d)", pushed, seen)
   195  	}
   196  
   197  	// 4) test iterating backwards (PrevWaitChan and Prev)
   198  	prev := next
   199  	seen = 0
   200  FOR_LOOP2:
   201  	for {
   202  		select {
   203  		case <-prev.PrevWaitChan():
   204  			prev = prev.Prev()
   205  			seen++
   206  			if prev == nil {
   207  				t.Fatal("expected PrevWaitChan to block forever on nil when reached first elem")
   208  			}
   209  		case <-time.After(3 * time.Second):
   210  			break FOR_LOOP2
   211  		}
   212  	}
   213  
   214  	if pushed != seen {
   215  		t.Fatalf("number of pushed items (%d) not equal to number of seen items (%d)", pushed, seen)
   216  	}
   217  }