github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/generics/list/list_test.go (about)

     1  // Copyright (c) 2019 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  // This implementation is a modification from Go's container/list source code.
    22  // Here is its license:
    23  
    24  // Copyright (c) 2009 The Go Authors. All rights reserved.
    25  
    26  // Redistribution and use in source and binary forms, with or without
    27  // modification, are permitted provided that the following conditions are
    28  // met:
    29  
    30  //    * Redistributions of source code must retain the above copyright
    31  // notice, this list of conditions and the following disclaimer.
    32  //    * Redistributions in binary form must reproduce the above
    33  // copyright notice, this list of conditions and the following disclaimer
    34  // in the documentation and/or other materials provided with the
    35  // distribution.
    36  //    * Neither the name of Google Inc. nor the names of its
    37  // contributors may be used to endorse or promote products derived from
    38  // this software without specific prior written permission.
    39  
    40  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    41  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    42  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    43  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    44  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    45  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    46  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    47  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    48  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    49  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    50  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    51  package list
    52  
    53  import (
    54  	"testing"
    55  )
    56  
    57  func checkListLen(t *testing.T, l *List, len int) bool {
    58  	if n := l.Len(); n != len {
    59  		t.Errorf("l.Len() = %d, want %d", n, len)
    60  		return false
    61  	}
    62  	return true
    63  }
    64  
    65  func checkListPointers(t *testing.T, l *List, es []*Element) {
    66  	root := &l.root
    67  
    68  	if !checkListLen(t, l, len(es)) {
    69  		return
    70  	}
    71  
    72  	// zero length lists must be the zero value or properly initialized (sentinel circle)
    73  	if len(es) == 0 {
    74  		if l.root.next != nil && l.root.next != root || l.root.prev != nil && l.root.prev != root {
    75  			t.Errorf("l.root.next = %p, l.root.prev = %p; both should both be nil or %p", l.root.next, l.root.prev, root)
    76  		}
    77  		return
    78  	}
    79  	// len(es) > 0
    80  
    81  	// check internal and external prev/next connections
    82  	for i, e := range es {
    83  		prev := root
    84  		Prev := (*Element)(nil)
    85  		if i > 0 {
    86  			prev = es[i-1]
    87  			Prev = prev
    88  		}
    89  		if p := e.prev; p != prev {
    90  			t.Errorf("elt[%d](%p).prev = %p, want %p", i, e, p, prev)
    91  		}
    92  		if p := e.Prev(); p != Prev {
    93  			t.Errorf("elt[%d](%p).Prev() = %p, want %p", i, e, p, Prev)
    94  		}
    95  
    96  		next := root
    97  		Next := (*Element)(nil)
    98  		if i < len(es)-1 {
    99  			next = es[i+1]
   100  			Next = next
   101  		}
   102  		if n := e.next; n != next {
   103  			t.Errorf("elt[%d](%p).next = %p, want %p", i, e, n, next)
   104  		}
   105  		if n := e.Next(); n != Next {
   106  			t.Errorf("elt[%d](%p).Next() = %p, want %p", i, e, n, Next)
   107  		}
   108  	}
   109  }
   110  
   111  func TestList(t *testing.T) {
   112  	l := newList(nil)
   113  	checkListPointers(t, l, []*Element{})
   114  
   115  	// Single element list
   116  	e := l.PushFront("a")
   117  	checkListPointers(t, l, []*Element{e})
   118  	l.MoveToFront(e)
   119  	checkListPointers(t, l, []*Element{e})
   120  	l.MoveToBack(e)
   121  	checkListPointers(t, l, []*Element{e})
   122  	l.Remove(e)
   123  	checkListPointers(t, l, []*Element{})
   124  
   125  	// Bigger list
   126  	e2 := l.PushFront(2)
   127  	e1 := l.PushFront(1)
   128  	e3 := l.PushBack(3)
   129  	e4 := l.PushBack("banana")
   130  	checkListPointers(t, l, []*Element{e1, e2, e3, e4})
   131  
   132  	l.Remove(e2)
   133  	checkListPointers(t, l, []*Element{e1, e3, e4})
   134  
   135  	l.MoveToFront(e3) // move from middle
   136  	checkListPointers(t, l, []*Element{e3, e1, e4})
   137  
   138  	l.MoveToFront(e1)
   139  	l.MoveToBack(e3) // move from middle
   140  	checkListPointers(t, l, []*Element{e1, e4, e3})
   141  
   142  	l.MoveToFront(e3) // move from back
   143  	checkListPointers(t, l, []*Element{e3, e1, e4})
   144  	l.MoveToFront(e3) // should be no-op
   145  	checkListPointers(t, l, []*Element{e3, e1, e4})
   146  
   147  	l.MoveToBack(e3) // move from front
   148  	checkListPointers(t, l, []*Element{e1, e4, e3})
   149  	l.MoveToBack(e3) // should be no-op
   150  	checkListPointers(t, l, []*Element{e1, e4, e3})
   151  
   152  	e2 = l.InsertBefore(2, e1) // insert before front
   153  	checkListPointers(t, l, []*Element{e2, e1, e4, e3})
   154  	l.Remove(e2)
   155  	e2 = l.InsertBefore(2, e4) // insert before middle
   156  	checkListPointers(t, l, []*Element{e1, e2, e4, e3})
   157  	l.Remove(e2)
   158  	e2 = l.InsertBefore(2, e3) // insert before back
   159  	checkListPointers(t, l, []*Element{e1, e4, e2, e3})
   160  	l.Remove(e2)
   161  
   162  	e2 = l.InsertAfter(2, e1) // insert after front
   163  	checkListPointers(t, l, []*Element{e1, e2, e4, e3})
   164  	l.Remove(e2)
   165  	e2 = l.InsertAfter(2, e4) // insert after middle
   166  	checkListPointers(t, l, []*Element{e1, e4, e2, e3})
   167  	l.Remove(e2)
   168  	e2 = l.InsertAfter(2, e3) // insert after back
   169  	checkListPointers(t, l, []*Element{e1, e4, e3, e2})
   170  	l.Remove(e2)
   171  
   172  	// Check standard iteration.
   173  	sum := 0
   174  	for e := l.Front(); e != nil; e = e.Next() {
   175  		if i, ok := e.Value.(int); ok {
   176  			sum += i
   177  		}
   178  	}
   179  	if sum != 4 {
   180  		t.Errorf("sum over l = %d, want 4", sum)
   181  	}
   182  
   183  	// Clear all elements by iterating
   184  	var next *Element
   185  	for e := l.Front(); e != nil; e = next {
   186  		next = e.Next()
   187  		l.Remove(e)
   188  	}
   189  	checkListPointers(t, l, []*Element{})
   190  }
   191  
   192  func checkList(t *testing.T, l *List, es []interface{}) {
   193  	if !checkListLen(t, l, len(es)) {
   194  		return
   195  	}
   196  
   197  	i := 0
   198  	for e := l.Front(); e != nil; e = e.Next() {
   199  		le := e.Value.(int)
   200  		if le != es[i] {
   201  			t.Errorf("elt[%d].Value = %v, want %v", i, le, es[i])
   202  		}
   203  		i++
   204  	}
   205  }
   206  
   207  func TestExtending(t *testing.T) {
   208  	l1 := newList(nil)
   209  	l2 := newList(nil)
   210  
   211  	l1.PushBack(1)
   212  	l1.PushBack(2)
   213  	l1.PushBack(3)
   214  
   215  	l2.PushBack(4)
   216  	l2.PushBack(5)
   217  
   218  	l3 := newList(nil)
   219  	l3.PushBackList(l1)
   220  	checkList(t, l3, []interface{}{1, 2, 3})
   221  	l3.PushBackList(l2)
   222  	checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
   223  
   224  	l3 = newList(nil)
   225  	l3.PushFrontList(l2)
   226  	checkList(t, l3, []interface{}{4, 5})
   227  	l3.PushFrontList(l1)
   228  	checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
   229  
   230  	checkList(t, l1, []interface{}{1, 2, 3})
   231  	checkList(t, l2, []interface{}{4, 5})
   232  
   233  	l3 = newList(nil)
   234  	l3.PushBackList(l1)
   235  	checkList(t, l3, []interface{}{1, 2, 3})
   236  	l3.PushBackList(l3)
   237  	checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
   238  
   239  	l3 = newList(nil)
   240  	l3.PushFrontList(l1)
   241  	checkList(t, l3, []interface{}{1, 2, 3})
   242  	l3.PushFrontList(l3)
   243  	checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
   244  
   245  	l3 = newList(nil)
   246  	l1.PushBackList(l3)
   247  	checkList(t, l1, []interface{}{1, 2, 3})
   248  	l1.PushFrontList(l3)
   249  	checkList(t, l1, []interface{}{1, 2, 3})
   250  }
   251  
   252  func TestRemove(t *testing.T) {
   253  	l := newList(nil)
   254  	e1 := l.PushBack(1)
   255  	e2 := l.PushBack(2)
   256  	checkListPointers(t, l, []*Element{e1, e2})
   257  	e := l.Front()
   258  	l.Remove(e)
   259  	checkListPointers(t, l, []*Element{e2})
   260  	l.Remove(e)
   261  	checkListPointers(t, l, []*Element{e2})
   262  }
   263  
   264  func TestIssue4103(t *testing.T) {
   265  	l1 := newList(nil)
   266  	l1.PushBack(1)
   267  	l1.PushBack(2)
   268  
   269  	l2 := newList(nil)
   270  	l2.PushBack(3)
   271  	l2.PushBack(4)
   272  
   273  	e := l1.Front()
   274  	l2.Remove(e) // l2 should not change because e is not an element of l2
   275  	if n := l2.Len(); n != 2 {
   276  		t.Errorf("l2.Len() = %d, want 2", n)
   277  	}
   278  
   279  	l1.InsertBefore(8, e)
   280  	if n := l1.Len(); n != 3 {
   281  		t.Errorf("l1.Len() = %d, want 3", n)
   282  	}
   283  }
   284  
   285  func TestIssue6349(t *testing.T) {
   286  	l := newList(nil)
   287  	l.PushBack(1)
   288  	l.PushBack(2)
   289  
   290  	e := l.Front()
   291  	l.Remove(e)
   292  	if e.Value != 1 {
   293  		t.Errorf("e.value = %d, want 1", e.Value)
   294  	}
   295  	if e.Next() != nil {
   296  		t.Errorf("e.Next() != nil")
   297  	}
   298  	if e.Prev() != nil {
   299  		t.Errorf("e.Prev() != nil")
   300  	}
   301  }
   302  
   303  func TestMove(t *testing.T) {
   304  	l := newList(nil)
   305  	e1 := l.PushBack(1)
   306  	e2 := l.PushBack(2)
   307  	e3 := l.PushBack(3)
   308  	e4 := l.PushBack(4)
   309  
   310  	l.MoveAfter(e3, e3)
   311  	checkListPointers(t, l, []*Element{e1, e2, e3, e4})
   312  	l.MoveBefore(e2, e2)
   313  	checkListPointers(t, l, []*Element{e1, e2, e3, e4})
   314  
   315  	l.MoveAfter(e3, e2)
   316  	checkListPointers(t, l, []*Element{e1, e2, e3, e4})
   317  	l.MoveBefore(e2, e3)
   318  	checkListPointers(t, l, []*Element{e1, e2, e3, e4})
   319  
   320  	l.MoveBefore(e2, e4)
   321  	checkListPointers(t, l, []*Element{e1, e3, e2, e4})
   322  	e2, e3 = e3, e2
   323  
   324  	l.MoveBefore(e4, e1)
   325  	checkListPointers(t, l, []*Element{e4, e1, e2, e3})
   326  	e1, e2, e3, e4 = e4, e1, e2, e3
   327  
   328  	l.MoveAfter(e4, e1)
   329  	checkListPointers(t, l, []*Element{e1, e4, e2, e3})
   330  	e2, e3, e4 = e4, e2, e3
   331  
   332  	l.MoveAfter(e2, e3)
   333  	checkListPointers(t, l, []*Element{e1, e3, e2, e4})
   334  	e2, e3 = e3, e2
   335  }
   336  
   337  // Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List
   338  func TestZeroList(t *testing.T) {
   339  	var l1 = new(List)
   340  	l1.PushFront(1)
   341  	checkList(t, l1, []interface{}{1})
   342  
   343  	var l2 = new(List)
   344  	l2.PushBack(1)
   345  	checkList(t, l2, []interface{}{1})
   346  
   347  	var l3 = new(List)
   348  	l3.PushFrontList(l1)
   349  	checkList(t, l3, []interface{}{1})
   350  
   351  	var l4 = new(List)
   352  	l4.PushBackList(l2)
   353  	checkList(t, l4, []interface{}{1})
   354  }
   355  
   356  // Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l.
   357  func TestInsertBeforeUnknownMark(t *testing.T) {
   358  	var l List
   359  	l.PushBack(1)
   360  	l.PushBack(2)
   361  	l.PushBack(3)
   362  	l.InsertBefore(1, new(Element))
   363  	checkList(t, &l, []interface{}{1, 2, 3})
   364  }
   365  
   366  // Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l.
   367  func TestInsertAfterUnknownMark(t *testing.T) {
   368  	var l List
   369  	l.PushBack(1)
   370  	l.PushBack(2)
   371  	l.PushBack(3)
   372  	l.InsertAfter(1, new(Element))
   373  	checkList(t, &l, []interface{}{1, 2, 3})
   374  }
   375  
   376  // Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
   377  func TestMoveUnknownMark(t *testing.T) {
   378  	var l1 List
   379  	e1 := l1.PushBack(1)
   380  
   381  	var l2 List
   382  	e2 := l2.PushBack(2)
   383  
   384  	l1.MoveAfter(e1, e2)
   385  	checkList(t, &l1, []interface{}{1})
   386  	checkList(t, &l2, []interface{}{2})
   387  
   388  	l1.MoveBefore(e1, e2)
   389  	checkList(t, &l1, []interface{}{1})
   390  	checkList(t, &l2, []interface{}{2})
   391  }
   392  
   393  func TestReset(t *testing.T) {
   394  	var l1 List
   395  	l1.Reset()
   396  	checkList(t, &l1, []interface{}{})
   397  
   398  	l1.PushBack(1)
   399  	checkList(t, &l1, []interface{}{1})
   400  	l1.Reset()
   401  	checkList(t, &l1, []interface{}{})
   402  
   403  	l1.PushBack(2)
   404  	l1.PushBack(3)
   405  	l1.PushBack(4)
   406  	l1.PushBack(5)
   407  	checkList(t, &l1, []interface{}{2, 3, 4, 5})
   408  	l1.Reset()
   409  	checkList(t, &l1, []interface{}{})
   410  }