package clist import ( "fmt" "math/rand" "runtime" "sync/atomic" "testing" "time" ) func TestSmall(t *testing.T) { l := New() el1 := l.PushBack(1) el2 := l.PushBack(2) el3 := l.PushBack(3) if l.Len() != 3 { t.Error("Expected len 3, got ", l.Len()) } //fmt.Printf("%p %v\n", el1, el1) //fmt.Printf("%p %v\n", el2, el2) //fmt.Printf("%p %v\n", el3, el3) r1 := l.Remove(el1) //fmt.Printf("%p %v\n", el1, el1) //fmt.Printf("%p %v\n", el2, el2) //fmt.Printf("%p %v\n", el3, el3) r2 := l.Remove(el2) //fmt.Printf("%p %v\n", el1, el1) //fmt.Printf("%p %v\n", el2, el2) //fmt.Printf("%p %v\n", el3, el3) r3 := l.Remove(el3) if r1 != 1 { t.Error("Expected 1, got ", r1) } if r2 != 2 { t.Error("Expected 2, got ", r2) } if r3 != 3 { t.Error("Expected 3, got ", r3) } if l.Len() != 0 { t.Error("Expected len 0, got ", l.Len()) } } /* This test is quite hacky because it relies on SetFinalizer which isn't guaranteed to run at all. */ func _TestGCFifo(t *testing.T) { const numElements = 1000000 l := New() gcCount := new(uint64) // SetFinalizer doesn't work well with circular structures, // so we construct a trivial non-circular structure to // track. type value struct { Int int } done := make(chan struct{}) for i := 0; i < numElements; i++ { v := new(value) v.Int = i l.PushBack(v) runtime.SetFinalizer(v, func(v *value) { atomic.AddUint64(gcCount, 1) }) } for el := l.Front(); el != nil; { l.Remove(el) //oldEl := el el = el.Next() //oldEl.DetachPrev() //oldEl.DetachNext() } runtime.GC() time.Sleep(time.Second * 3) runtime.GC() time.Sleep(time.Second * 3) _ = done if *gcCount != numElements { t.Errorf("Expected gcCount to be %v, got %v", numElements, *gcCount) } } /* This test is quite hacky because it relies on SetFinalizer which isn't guaranteed to run at all. */ func _TestGCRandom(t *testing.T) { const numElements = 1000000 l := New() gcCount := 0 // SetFinalizer doesn't work well with circular structures, // so we construct a trivial non-circular structure to // track. type value struct { Int int } for i := 0; i < numElements; i++ { v := new(value) v.Int = i l.PushBack(v) runtime.SetFinalizer(v, func(v *value) { gcCount += 1 }) } els := make([]*CElement, 0, numElements) for el := l.Front(); el != nil; el = el.Next() { els = append(els, el) } for _, i := range rand.Perm(numElements) { el := els[i] l.Remove(el) el = el.Next() } runtime.GC() time.Sleep(time.Second * 3) if gcCount != numElements { t.Errorf("Expected gcCount to be %v, got %v", numElements, gcCount) } } func TestScanRightDeleteRandom(t *testing.T) { const numElements = 10000 const numTimes = 100000 const numScanners = 10 l := New() stop := make(chan struct{}) els := make([]*CElement, numElements, numElements) for i := 0; i < numElements; i++ { el := l.PushBack(i) els[i] = el } // Launch scanner routines that will rapidly iterate over elements. for i := 0; i < numScanners; i++ { go func(scannerID int) { var el *CElement restartCounter := 0 counter := 0 FOR_LOOP: for { select { case <-stop: fmt.Println("stopped") break FOR_LOOP default: } if el == nil { el = l.FrontWait() restartCounter += 1 } el = el.Next() counter += 1 } fmt.Printf("Scanner %v restartCounter: %v counter: %v\n", scannerID, restartCounter, counter) }(i) } // Remove an element, push back an element. for i := 0; i < numTimes; i++ { // Pick an element to remove rmElIdx := rand.Intn(len(els)) rmEl := els[rmElIdx] // Remove it l.Remove(rmEl) //fmt.Print(".") // Insert a new element newEl := l.PushBack(-1*i - 1) els[rmElIdx] = newEl if i%100000 == 0 { fmt.Printf("Pushed %vK elements so far...\n", i/1000) } } // Stop scanners close(stop) time.Sleep(time.Second * 1) // And remove all the elements. for el := l.Front(); el != nil; el = el.Next() { l.Remove(el) } if l.Len() != 0 { t.Fatal("Failed to remove all elements from CList") } }