github.com/go-playground/pkg/v5@v5.29.1/container/list/doubly_linked_test.go (about) 1 //go:build go1.18 2 // +build go1.18 3 4 package listext 5 6 import ( 7 "container/list" 8 . "github.com/go-playground/assert/v2" 9 "testing" 10 ) 11 12 func TestLinkedListInserts(t *testing.T) { 13 l := NewDoublyLinked[int]() 14 Equal(t, l.IsEmpty(), true) 15 Equal(t, l.Len(), 0) 16 17 node1 := l.PushFront(1) 18 node2 := l.PushFront(2) 19 node3 := l.PushFront(3) 20 21 l.Remove(node2) 22 l.InsertAtFront(node2) 23 Equal(t, l.Front().Value, node2.Value) 24 25 l.Remove(node2) 26 l.InsertAtBack(node2) 27 Equal(t, l.Back().Value, node2.Value) 28 29 l.Remove(node2) 30 l.InsertBefore(node3, node2) 31 Equal(t, l.Front().Value, node2.Value) 32 33 l.Remove(node2) 34 l.InsertAfter(node1, node2) 35 Equal(t, l.Back().Value, node2.Value) 36 } 37 38 func TestSingleEntryPopBack(t *testing.T) { 39 40 l := NewDoublyLinked[int]() 41 Equal(t, l.IsEmpty(), true) 42 Equal(t, l.Len(), 0) 43 44 // push some data and then re-check 45 zeroNode := l.PushFront(0) 46 Equal(t, zeroNode.Value, 0) 47 Equal(t, l.IsEmpty(), false) 48 Equal(t, l.Len(), 1) 49 Equal(t, zeroNode.Prev(), nil) 50 Equal(t, zeroNode.Next(), nil) 51 52 // test popping where one node is both head and tail 53 back := l.PopBack() 54 Equal(t, back.Value, 0) 55 Equal(t, back.Next(), nil) 56 Equal(t, back.Prev(), nil) 57 Equal(t, l.IsEmpty(), true) 58 Equal(t, l.Len(), 0) 59 60 front := l.PopFront() 61 Equal(t, front, nil) 62 } 63 64 func TestSingleEntryPopFront(t *testing.T) { 65 66 l := NewDoublyLinked[int]() 67 Equal(t, l.IsEmpty(), true) 68 Equal(t, l.Len(), 0) 69 70 // push some data and then re-check 71 zeroNode := l.PushFront(0) 72 Equal(t, zeroNode.Value, 0) 73 Equal(t, l.IsEmpty(), false) 74 Equal(t, l.Len(), 1) 75 Equal(t, zeroNode.Prev(), nil) 76 Equal(t, zeroNode.Next(), nil) 77 78 // test popping where one node is both head and tail 79 front := l.PopFront() 80 Equal(t, front.Value, 0) 81 Equal(t, front.Next(), nil) 82 Equal(t, front.Prev(), nil) 83 Equal(t, l.IsEmpty(), true) 84 Equal(t, l.Len(), 0) 85 86 back := l.PopBack() 87 Equal(t, back, nil) 88 89 } 90 91 func TestDoubleEntryPopBack(t *testing.T) { 92 93 l := NewDoublyLinked[int]() 94 Equal(t, l.IsEmpty(), true) 95 Equal(t, l.Len(), 0) 96 97 // push some data and then re-check 98 zeroNode := l.PushFront(0) 99 oneNode := l.PushFront(1) 100 Equal(t, l.IsEmpty(), false) 101 Equal(t, l.Len(), 2) 102 Equal(t, zeroNode.Value, 0) 103 Equal(t, oneNode.Value, 1) 104 Equal(t, zeroNode.Prev().Value, 1) 105 Equal(t, zeroNode.Next(), nil) 106 Equal(t, oneNode.Prev(), nil) 107 Equal(t, oneNode.Next().Value, 0) 108 109 back := l.PopBack() 110 Equal(t, l.IsEmpty(), false) 111 Equal(t, l.Len(), 1) 112 Equal(t, back.Value, 0) 113 Equal(t, back.Next(), nil) 114 Equal(t, back.Prev(), nil) 115 Equal(t, l.Front().Value, 1) 116 Equal(t, l.Back().Value, 1) 117 118 back2 := l.PopBack() 119 Equal(t, l.IsEmpty(), true) 120 Equal(t, l.Len(), 0) 121 Equal(t, back2.Value, 1) 122 Equal(t, back2.Next(), nil) 123 Equal(t, back2.Prev(), nil) 124 Equal(t, l.Front(), nil) 125 Equal(t, l.Back(), nil) 126 } 127 128 func TestTripleEntryPopBack(t *testing.T) { 129 130 l := NewDoublyLinked[int]() 131 Equal(t, l.IsEmpty(), true) 132 Equal(t, l.Len(), 0) 133 134 // push some data and then re-check 135 zeroNode := l.PushFront(0) 136 oneNode := l.PushFront(1) 137 twoNode := l.PushFront(2) 138 Equal(t, l.IsEmpty(), false) 139 Equal(t, l.Len(), 3) 140 Equal(t, zeroNode.Value, 0) 141 Equal(t, oneNode.Value, 1) 142 Equal(t, twoNode.Value, 2) 143 Equal(t, zeroNode.Next(), nil) 144 Equal(t, zeroNode.Prev().Value, 1) 145 Equal(t, zeroNode.Prev().Prev().Value, 2) 146 Equal(t, zeroNode.Prev().Prev().Prev(), nil) 147 Equal(t, oneNode.Next().Value, 0) 148 Equal(t, oneNode.Next().Next(), nil) 149 Equal(t, oneNode.Prev().Value, 2) 150 Equal(t, oneNode.Prev().Prev(), nil) 151 Equal(t, twoNode.Prev(), nil) 152 Equal(t, twoNode.Next().Value, 1) 153 Equal(t, twoNode.Next().Next().Value, 0) 154 Equal(t, twoNode.Next().Next().Next(), nil) 155 156 // remove front 157 l.Remove(twoNode) 158 159 // remove back 160 l.Remove(zeroNode) 161 } 162 163 func TestLinkedListPushFront(t *testing.T) { 164 165 l := NewDoublyLinked[int]() 166 Equal(t, l.IsEmpty(), true) 167 Equal(t, l.Len(), 0) 168 169 // push some data and then re-check 170 zeroNode := l.PushFront(0) 171 oneNode := l.PushFront(1) 172 twoNode := l.PushFront(2) 173 Equal(t, l.IsEmpty(), false) 174 Equal(t, l.Len(), 3) 175 176 // test next logic 177 Equal(t, zeroNode.Value, 0) 178 Equal(t, zeroNode.Next(), nil) 179 Equal(t, zeroNode.Prev().Value, 1) 180 Equal(t, zeroNode.Prev().Prev().Value, 2) 181 Equal(t, zeroNode.Prev().Prev().Prev(), nil) 182 Equal(t, oneNode.Value, 1) 183 Equal(t, oneNode.Next().Value, 0) 184 Equal(t, oneNode.Next().Next(), nil) 185 Equal(t, oneNode.Prev().Value, 2) 186 Equal(t, oneNode.Prev().Prev(), nil) 187 Equal(t, twoNode.Value, 2) 188 Equal(t, twoNode.Prev(), nil) 189 Equal(t, twoNode.Next().Value, 1) 190 Equal(t, twoNode.Next().Next().Value, 0) 191 Equal(t, twoNode.Next().Next().Next(), nil) 192 193 // remove middle node and test again 194 l.Remove(oneNode) 195 Equal(t, oneNode.Value, 1) 196 Equal(t, oneNode.Prev(), nil) 197 Equal(t, oneNode.Next(), nil) 198 199 // move to front 200 l.MoveToFront(zeroNode) 201 Equal(t, l.Front().Value, 0) 202 Equal(t, l.Back().Value, 2) 203 204 // move to back 205 l.MoveToBack(zeroNode) 206 Equal(t, l.Front().Value, 2) 207 Equal(t, l.Back().Value, 0) 208 209 // test clearing 210 l.Clear() 211 Equal(t, l.IsEmpty(), true) 212 Equal(t, l.Len(), 0) 213 } 214 215 func TestLinkedListPushBack(t *testing.T) { 216 217 l := NewDoublyLinked[int]() 218 Equal(t, l.IsEmpty(), true) 219 Equal(t, l.Len(), 0) 220 221 // push some data and then re-check 222 zeroNode := l.PushBack(0) 223 oneNode := l.PushBack(1) 224 twoNode := l.PushBack(2) 225 Equal(t, l.IsEmpty(), false) 226 Equal(t, l.Len(), 3) 227 228 // test next logic 229 Equal(t, zeroNode.Value, 0) 230 Equal(t, zeroNode.Next().Value, 1) 231 Equal(t, zeroNode.Next().Next().Value, 2) 232 Equal(t, zeroNode.Next().Next().Next(), nil) 233 Equal(t, zeroNode.Prev(), nil) 234 Equal(t, oneNode.Value, 1) 235 Equal(t, oneNode.Next().Value, 2) 236 Equal(t, oneNode.Next().Next(), nil) 237 Equal(t, oneNode.Prev().Value, 0) 238 Equal(t, oneNode.Prev().Prev(), nil) 239 Equal(t, twoNode.Value, 2) 240 Equal(t, twoNode.Prev().Value, 1) 241 Equal(t, twoNode.Prev().Prev().Value, 0) 242 Equal(t, twoNode.Prev().Prev().Prev(), nil) 243 Equal(t, twoNode.Next(), nil) 244 245 // remove middle node and test again 246 l.Remove(oneNode) 247 Equal(t, oneNode.Value, 1) 248 Equal(t, oneNode.Prev(), nil) 249 Equal(t, oneNode.Next(), nil) 250 251 // move to front 252 l.MoveToBack(zeroNode) 253 Equal(t, l.Front().Value, 2) 254 Equal(t, l.Back().Value, 0) 255 256 // move to back 257 l.MoveToFront(zeroNode) 258 Equal(t, l.Front().Value, 0) 259 Equal(t, l.Back().Value, 2) 260 261 // test clearing 262 l.Clear() 263 Equal(t, l.IsEmpty(), true) 264 Equal(t, l.Len(), 0) 265 } 266 267 func TestLinkedListMoving(t *testing.T) { 268 269 l := NewDoublyLinked[int]() 270 Equal(t, l.IsEmpty(), true) 271 Equal(t, l.Len(), 0) 272 273 // test pushing after with one node 274 node1 := l.PushFront(0) 275 node2 := l.PushAfter(node1, 1) 276 Equal(t, l.IsEmpty(), false) 277 Equal(t, l.Len(), 2) 278 Equal(t, l.Front().Value, node1.Value) 279 Equal(t, l.Back().Value, node2.Value) 280 281 // test moving after with two nodes 282 l.MoveAfter(node2, node1) 283 Equal(t, l.IsEmpty(), false) 284 Equal(t, l.Len(), 2) 285 Equal(t, l.Front().Value, node2.Value) 286 Equal(t, l.Back().Value, node1.Value) 287 288 // test clearing 289 l.Clear() 290 Equal(t, l.IsEmpty(), true) 291 Equal(t, l.Len(), 0) 292 293 // test pushing before with one node 294 node1 = l.PushFront(0) 295 node2 = l.PushBefore(node1, 1) 296 Equal(t, l.IsEmpty(), false) 297 Equal(t, l.Len(), 2) 298 Equal(t, l.Front().Value, node2.Value) 299 Equal(t, l.Back().Value, node1.Value) 300 301 // test moving before with two nodes 302 l.MoveBefore(node2, node1) 303 Equal(t, l.IsEmpty(), false) 304 Equal(t, l.Len(), 2) 305 Equal(t, l.Front().Value, node1.Value) 306 Equal(t, l.Back().Value, node2.Value) 307 308 // test clearing 309 l.Clear() 310 Equal(t, l.IsEmpty(), true) 311 Equal(t, l.Len(), 0) 312 313 // testing the same as above BUT with 3 nodes attached 314 node1 = l.PushFront(0) 315 node2 = l.PushAfter(node1, 1) 316 node3 := l.PushAfter(node2, 2) 317 Equal(t, l.IsEmpty(), false) 318 Equal(t, l.Len(), 3) 319 Equal(t, l.Front().Value, node1.Value) 320 Equal(t, l.Front().Next().Value, node2.Value) 321 Equal(t, l.Back().Value, node3.Value) 322 Equal(t, l.Back().Prev().Value, node2.Value) 323 324 l.MoveBefore(node2, node3) 325 Equal(t, l.IsEmpty(), false) 326 Equal(t, l.Len(), 3) 327 Equal(t, l.Front().Value, node1.Value) 328 Equal(t, l.Front().Next().Value, node3.Value) 329 Equal(t, l.Back().Value, node2.Value) 330 Equal(t, l.Back().Prev().Value, node3.Value) 331 332 l.MoveAfter(node3, node1) 333 Equal(t, l.IsEmpty(), false) 334 Equal(t, l.Len(), 3) 335 Equal(t, l.Front().Value, node3.Value) 336 Equal(t, l.Front().Next().Value, node1.Value) 337 Equal(t, l.Back().Value, node2.Value) 338 Equal(t, l.Back().Prev().Value, node1.Value) 339 340 // test clearing 341 l.Clear() 342 Equal(t, l.IsEmpty(), true) 343 Equal(t, l.Len(), 0) 344 345 // testing the same as above BUT with 4 nodes attached moving the middle nodes back and forth 346 node1 = l.PushFront(0) 347 node2 = l.PushAfter(node1, 1) 348 node3 = l.PushAfter(node2, 2) 349 node4 := l.PushAfter(node3, 3) 350 Equal(t, l.IsEmpty(), false) 351 Equal(t, l.Len(), 4) 352 Equal(t, l.Front().Value, node1.Value) 353 Equal(t, l.Front().Next().Value, node2.Value) 354 Equal(t, l.Front().Next().Next().Value, node3.Value) 355 Equal(t, l.Front().Next().Next().Next().Value, node4.Value) 356 Equal(t, l.Front().Next().Next().Next().Next(), nil) 357 Equal(t, l.Back().Value, node4.Value) 358 Equal(t, l.Back().Prev().Value, node3.Value) 359 Equal(t, l.Back().Prev().Prev().Value, node2.Value) 360 Equal(t, l.Back().Prev().Prev().Prev().Value, node1.Value) 361 Equal(t, l.Back().Prev().Prev().Prev().Prev(), nil) 362 363 l.MoveAfter(node3, node2) 364 Equal(t, l.IsEmpty(), false) 365 Equal(t, l.Len(), 4) 366 Equal(t, l.Front().Value, node1.Value) 367 Equal(t, l.Front().Next().Value, node3.Value) 368 Equal(t, l.Front().Next().Next().Value, node2.Value) 369 Equal(t, l.Front().Next().Next().Next().Value, node4.Value) 370 Equal(t, l.Front().Next().Next().Next().Next(), nil) 371 Equal(t, l.Back().Value, node4.Value) 372 Equal(t, l.Back().Prev().Value, node2.Value) 373 Equal(t, l.Back().Prev().Prev().Value, node3.Value) 374 Equal(t, l.Back().Prev().Prev().Prev().Value, node1.Value) 375 Equal(t, l.Back().Prev().Prev().Prev().Prev(), nil) 376 377 l.MoveAfter(node2, node3) 378 Equal(t, l.IsEmpty(), false) 379 Equal(t, l.Len(), 4) 380 Equal(t, l.Front().Value, node1.Value) 381 Equal(t, l.Front().Next().Value, node2.Value) 382 Equal(t, l.Front().Next().Next().Value, node3.Value) 383 Equal(t, l.Front().Next().Next().Next().Value, node4.Value) 384 Equal(t, l.Front().Next().Next().Next().Next(), nil) 385 Equal(t, l.Back().Value, node4.Value) 386 Equal(t, l.Back().Prev().Value, node3.Value) 387 Equal(t, l.Back().Prev().Prev().Value, node2.Value) 388 Equal(t, l.Back().Prev().Prev().Prev().Value, node1.Value) 389 Equal(t, l.Back().Prev().Prev().Prev().Prev(), nil) 390 391 // test clearing 392 l.Clear() 393 Equal(t, l.IsEmpty(), true) 394 Equal(t, l.Len(), 0) 395 } 396 397 func TestLinkedListRemoveSingleEntry(t *testing.T) { 398 399 l := NewDoublyLinked[int]() 400 Equal(t, l.IsEmpty(), true) 401 Equal(t, l.Len(), 0) 402 403 // test pushing after with one node 404 node := l.PushFront(0) 405 Equal(t, l.IsEmpty(), false) 406 Equal(t, l.Len(), 1) 407 Equal(t, l.Front().Value, node.Value) 408 Equal(t, l.Back().Value, node.Value) 409 410 l.Remove(node) 411 Equal(t, l.IsEmpty(), true) 412 Equal(t, l.Len(), 0) 413 } 414 415 func BenchmarkDoublyLinkedList(b *testing.B) { 416 for i := 0; i < b.N; i++ { 417 l := NewDoublyLinked[int]() 418 node := l.PushBack(0) 419 l.Remove(node) 420 _ = node.Value 421 } 422 } 423 424 func BenchmarkDoublyLinkedList_STD(b *testing.B) { 425 for i := 0; i < b.N; i++ { 426 l := list.New() 427 node := l.PushBack(0) 428 _ = l.Remove(node) 429 } 430 }