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  }