You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

336 lines
6.1 KiB

  1. package clist
  2. import (
  3. "fmt"
  4. mrand "math/rand"
  5. "runtime"
  6. "testing"
  7. "time"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. func TestPanicOnMaxLength(t *testing.T) {
  11. maxLength := 1000
  12. l := newWithMax(maxLength)
  13. for i := 0; i < maxLength; i++ {
  14. l.PushBack(1)
  15. }
  16. assert.Panics(t, func() {
  17. l.PushBack(1)
  18. })
  19. }
  20. func TestSmall(t *testing.T) {
  21. l := New()
  22. el1 := l.PushBack(1)
  23. el2 := l.PushBack(2)
  24. el3 := l.PushBack(3)
  25. if l.Len() != 3 {
  26. t.Error("Expected len 3, got ", l.Len())
  27. }
  28. // fmt.Printf("%p %v\n", el1, el1)
  29. // fmt.Printf("%p %v\n", el2, el2)
  30. // fmt.Printf("%p %v\n", el3, el3)
  31. r1 := l.Remove(el1)
  32. // fmt.Printf("%p %v\n", el1, el1)
  33. // fmt.Printf("%p %v\n", el2, el2)
  34. // fmt.Printf("%p %v\n", el3, el3)
  35. r2 := l.Remove(el2)
  36. // fmt.Printf("%p %v\n", el1, el1)
  37. // fmt.Printf("%p %v\n", el2, el2)
  38. // fmt.Printf("%p %v\n", el3, el3)
  39. r3 := l.Remove(el3)
  40. if r1 != 1 {
  41. t.Error("Expected 1, got ", r1)
  42. }
  43. if r2 != 2 {
  44. t.Error("Expected 2, got ", r2)
  45. }
  46. if r3 != 3 {
  47. t.Error("Expected 3, got ", r3)
  48. }
  49. if l.Len() != 0 {
  50. t.Error("Expected len 0, got ", l.Len())
  51. }
  52. }
  53. func TestGCFifo(t *testing.T) {
  54. const numElements = 1000000
  55. l := New()
  56. gcCount := 0
  57. // SetFinalizer doesn't work well with circular structures,
  58. // so we construct a trivial non-circular structure to
  59. // track.
  60. type value struct {
  61. Int int
  62. }
  63. gcCh := make(chan struct{})
  64. for i := 0; i < numElements; i++ {
  65. v := new(value)
  66. v.Int = i
  67. l.PushBack(v)
  68. runtime.SetFinalizer(v, func(v *value) {
  69. gcCh <- struct{}{}
  70. })
  71. }
  72. for el := l.Front(); el != nil; {
  73. l.Remove(el)
  74. // oldEl := el
  75. el = el.Next()
  76. // oldEl.DetachPrev()
  77. // oldEl.DetachNext()
  78. }
  79. tickerQuitCh := make(chan struct{})
  80. tickerDoneCh := make(chan struct{})
  81. go func() {
  82. defer close(tickerDoneCh)
  83. ticker := time.NewTicker(time.Second)
  84. for {
  85. select {
  86. case <-ticker.C:
  87. runtime.GC()
  88. case <-tickerQuitCh:
  89. return
  90. }
  91. }
  92. }()
  93. for i := 0; i < numElements; i++ {
  94. <-gcCh
  95. gcCount++
  96. }
  97. close(tickerQuitCh)
  98. <-tickerDoneCh
  99. if gcCount != numElements {
  100. t.Errorf("expected gcCount to be %v, got %v", numElements,
  101. gcCount)
  102. }
  103. }
  104. func TestGCRandom(t *testing.T) {
  105. const numElements = 1000000
  106. l := New()
  107. gcCount := 0
  108. // SetFinalizer doesn't work well with circular structures,
  109. // so we construct a trivial non-circular structure to
  110. // track.
  111. type value struct {
  112. Int int
  113. }
  114. gcCh := make(chan struct{})
  115. for i := 0; i < numElements; i++ {
  116. v := new(value)
  117. v.Int = i
  118. l.PushBack(v)
  119. runtime.SetFinalizer(v, func(v *value) {
  120. gcCh <- struct{}{}
  121. })
  122. }
  123. els := make([]*CElement, 0, numElements)
  124. for el := l.Front(); el != nil; el = el.Next() {
  125. els = append(els, el)
  126. }
  127. for _, i := range mrand.Perm(numElements) {
  128. el := els[i]
  129. l.Remove(el)
  130. _ = el.Next()
  131. }
  132. tickerQuitCh := make(chan struct{})
  133. tickerDoneCh := make(chan struct{})
  134. go func() {
  135. defer close(tickerDoneCh)
  136. ticker := time.NewTicker(time.Second)
  137. for {
  138. select {
  139. case <-ticker.C:
  140. runtime.GC()
  141. case <-tickerQuitCh:
  142. return
  143. }
  144. }
  145. }()
  146. for i := 0; i < numElements; i++ {
  147. <-gcCh
  148. gcCount++
  149. }
  150. close(tickerQuitCh)
  151. <-tickerDoneCh
  152. if gcCount != numElements {
  153. t.Errorf("expected gcCount to be %v, got %v", numElements,
  154. gcCount)
  155. }
  156. }
  157. func TestScanRightDeleteRandom(t *testing.T) {
  158. const numElements = 1000
  159. const numTimes = 100
  160. const numScanners = 10
  161. l := New()
  162. stop := make(chan struct{})
  163. els := make([]*CElement, numElements)
  164. for i := 0; i < numElements; i++ {
  165. el := l.PushBack(i)
  166. els[i] = el
  167. }
  168. // Launch scanner routines that will rapidly iterate over elements.
  169. for i := 0; i < numScanners; i++ {
  170. go func(scannerID int) {
  171. var el *CElement
  172. restartCounter := 0
  173. counter := 0
  174. FOR_LOOP:
  175. for {
  176. select {
  177. case <-stop:
  178. fmt.Println("stopped")
  179. break FOR_LOOP
  180. default:
  181. }
  182. if el == nil {
  183. el = l.FrontWait()
  184. restartCounter++
  185. }
  186. el = el.Next()
  187. counter++
  188. }
  189. fmt.Printf("Scanner %v restartCounter: %v counter: %v\n", scannerID, restartCounter, counter)
  190. }(i)
  191. }
  192. // Remove an element, push back an element.
  193. for i := 0; i < numTimes; i++ {
  194. // Pick an element to remove
  195. rmElIdx := mrand.Intn(len(els))
  196. rmEl := els[rmElIdx]
  197. // Remove it
  198. l.Remove(rmEl)
  199. // fmt.Print(".")
  200. // Insert a new element
  201. newEl := l.PushBack(-1*i - 1)
  202. els[rmElIdx] = newEl
  203. if i%100000 == 0 {
  204. fmt.Printf("Pushed %vK elements so far...\n", i/1000)
  205. }
  206. }
  207. // Stop scanners
  208. close(stop)
  209. // time.Sleep(time.Second * 1)
  210. // And remove all the elements.
  211. for el := l.Front(); el != nil; el = el.Next() {
  212. l.Remove(el)
  213. }
  214. if l.Len() != 0 {
  215. t.Fatal("Failed to remove all elements from CList")
  216. }
  217. }
  218. func TestWaitChan(t *testing.T) {
  219. l := New()
  220. ch := l.WaitChan()
  221. // 1) add one element to an empty list
  222. go l.PushBack(1)
  223. <-ch
  224. // 2) and remove it
  225. el := l.Front()
  226. v := l.Remove(el)
  227. if v != 1 {
  228. t.Fatal("where is 1 coming from?")
  229. }
  230. // 3) test iterating forward and waiting for Next (NextWaitChan and Next)
  231. el = l.PushBack(0)
  232. done := make(chan struct{})
  233. pushed := 0
  234. go func() {
  235. for i := 1; i < 100; i++ {
  236. l.PushBack(i)
  237. pushed++
  238. time.Sleep(time.Duration(mrand.Intn(25)) * time.Millisecond)
  239. }
  240. // apply a deterministic pause so the counter has time to catch up
  241. time.Sleep(25 * time.Millisecond)
  242. close(done)
  243. }()
  244. next := el
  245. seen := 0
  246. FOR_LOOP:
  247. for {
  248. select {
  249. case <-next.NextWaitChan():
  250. next = next.Next()
  251. seen++
  252. if next == nil {
  253. t.Fatal("Next should not be nil when waiting on NextWaitChan")
  254. }
  255. case <-done:
  256. break FOR_LOOP
  257. case <-time.After(10 * time.Second):
  258. t.Fatal("max execution time")
  259. }
  260. }
  261. if pushed != seen {
  262. t.Fatalf("number of pushed items (%d) not equal to number of seen items (%d)", pushed, seen)
  263. }
  264. // 4) test iterating backwards (PrevWaitChan and Prev)
  265. prev := next
  266. seen = 0
  267. FOR_LOOP2:
  268. for {
  269. select {
  270. case <-prev.PrevWaitChan():
  271. prev = prev.Prev()
  272. seen++
  273. if prev == nil {
  274. t.Fatal("expected PrevWaitChan to block forever on nil when reached first elem")
  275. }
  276. case <-time.After(3 * time.Second):
  277. break FOR_LOOP2
  278. }
  279. }
  280. if pushed != seen {
  281. t.Fatalf("number of pushed items (%d) not equal to number of seen items (%d)", pushed, seen)
  282. }
  283. }