mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-02-26 16:57:08 +00:00
385 lines
8.5 KiB
Go
385 lines
8.5 KiB
Go
package orderedmap
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestBasicFeatures(t *testing.T) {
|
|
n := 100
|
|
om := New[int, int]()
|
|
|
|
// set(i, 2 * i)
|
|
for i := 0; i < n; i++ {
|
|
assertLenEqual(t, om, i)
|
|
oldValue, present := om.Set(i, 2*i)
|
|
assertLenEqual(t, om, i+1)
|
|
|
|
assert.Equal(t, 0, oldValue)
|
|
assert.False(t, present)
|
|
}
|
|
|
|
// get what we just set
|
|
for i := 0; i < n; i++ {
|
|
value, present := om.Get(i)
|
|
|
|
assert.Equal(t, 2*i, value)
|
|
assert.Equal(t, value, om.Value(i))
|
|
assert.True(t, present)
|
|
}
|
|
|
|
// get pairs of what we just set
|
|
for i := 0; i < n; i++ {
|
|
pair := om.GetPair(i)
|
|
|
|
assert.NotNil(t, pair)
|
|
assert.Equal(t, 2*i, pair.Value)
|
|
}
|
|
|
|
// forward iteration
|
|
i := 0
|
|
for pair := om.Oldest(); pair != nil; pair = pair.Next() {
|
|
assert.Equal(t, i, pair.Key)
|
|
assert.Equal(t, 2*i, pair.Value)
|
|
i++
|
|
}
|
|
// backward iteration
|
|
i = n - 1
|
|
for pair := om.Newest(); pair != nil; pair = pair.Prev() {
|
|
assert.Equal(t, i, pair.Key)
|
|
assert.Equal(t, 2*i, pair.Value)
|
|
i--
|
|
}
|
|
|
|
// forward iteration starting from known key
|
|
i = 42
|
|
for pair := om.GetPair(i); pair != nil; pair = pair.Next() {
|
|
assert.Equal(t, i, pair.Key)
|
|
assert.Equal(t, 2*i, pair.Value)
|
|
i++
|
|
}
|
|
|
|
// double values for pairs with even keys
|
|
for j := 0; j < n/2; j++ {
|
|
i = 2 * j
|
|
oldValue, present := om.Set(i, 4*i)
|
|
|
|
assert.Equal(t, 2*i, oldValue)
|
|
assert.True(t, present)
|
|
}
|
|
// and delete pairs with odd keys
|
|
for j := 0; j < n/2; j++ {
|
|
i = 2*j + 1
|
|
assertLenEqual(t, om, n-j)
|
|
value, present := om.Delete(i)
|
|
assertLenEqual(t, om, n-j-1)
|
|
|
|
assert.Equal(t, 2*i, value)
|
|
assert.True(t, present)
|
|
|
|
// deleting again shouldn't change anything
|
|
value, present = om.Delete(i)
|
|
assertLenEqual(t, om, n-j-1)
|
|
assert.Equal(t, 0, value)
|
|
assert.False(t, present)
|
|
}
|
|
|
|
// get the whole range
|
|
for j := 0; j < n/2; j++ {
|
|
i = 2 * j
|
|
value, present := om.Get(i)
|
|
assert.Equal(t, 4*i, value)
|
|
assert.Equal(t, value, om.Value(i))
|
|
assert.True(t, present)
|
|
|
|
i = 2*j + 1
|
|
value, present = om.Get(i)
|
|
assert.Equal(t, 0, value)
|
|
assert.Equal(t, value, om.Value(i))
|
|
assert.False(t, present)
|
|
}
|
|
|
|
// check iterations again
|
|
i = 0
|
|
for pair := om.Oldest(); pair != nil; pair = pair.Next() {
|
|
assert.Equal(t, i, pair.Key)
|
|
assert.Equal(t, 4*i, pair.Value)
|
|
i += 2
|
|
}
|
|
i = 2 * ((n - 1) / 2)
|
|
for pair := om.Newest(); pair != nil; pair = pair.Prev() {
|
|
assert.Equal(t, i, pair.Key)
|
|
assert.Equal(t, 4*i, pair.Value)
|
|
i -= 2
|
|
}
|
|
}
|
|
|
|
func TestUpdatingDoesntChangePairsOrder(t *testing.T) {
|
|
om := New[string, any]()
|
|
om.Set("foo", "bar")
|
|
om.Set("wk", 28)
|
|
om.Set("po", 100)
|
|
om.Set("bar", "baz")
|
|
|
|
oldValue, present := om.Set("po", 102)
|
|
assert.Equal(t, 100, oldValue)
|
|
assert.True(t, present)
|
|
|
|
assertOrderedPairsEqual(t, om,
|
|
[]string{"foo", "wk", "po", "bar"},
|
|
[]any{"bar", 28, 102, "baz"})
|
|
}
|
|
|
|
func TestDeletingAndReinsertingChangesPairsOrder(t *testing.T) {
|
|
om := New[string, any]()
|
|
om.Set("foo", "bar")
|
|
om.Set("wk", 28)
|
|
om.Set("po", 100)
|
|
om.Set("bar", "baz")
|
|
|
|
// delete a pair
|
|
oldValue, present := om.Delete("po")
|
|
assert.Equal(t, 100, oldValue)
|
|
assert.True(t, present)
|
|
|
|
// re-insert the same pair
|
|
oldValue, present = om.Set("po", 100)
|
|
assert.Nil(t, oldValue)
|
|
assert.False(t, present)
|
|
|
|
assertOrderedPairsEqual(t, om,
|
|
[]string{"foo", "wk", "bar", "po"},
|
|
[]any{"bar", 28, "baz", 100})
|
|
}
|
|
|
|
func TestEmptyMapOperations(t *testing.T) {
|
|
om := New[string, any]()
|
|
|
|
oldValue, present := om.Get("foo")
|
|
assert.Nil(t, oldValue)
|
|
assert.Nil(t, om.Value("foo"))
|
|
assert.False(t, present)
|
|
|
|
oldValue, present = om.Delete("bar")
|
|
assert.Nil(t, oldValue)
|
|
assert.False(t, present)
|
|
|
|
assertLenEqual(t, om, 0)
|
|
|
|
assert.Nil(t, om.Oldest())
|
|
assert.Nil(t, om.Newest())
|
|
}
|
|
|
|
type dummyTestStruct struct {
|
|
value string
|
|
}
|
|
|
|
func TestPackUnpackStructs(t *testing.T) {
|
|
om := New[string, dummyTestStruct]()
|
|
om.Set("foo", dummyTestStruct{"foo!"})
|
|
om.Set("bar", dummyTestStruct{"bar!"})
|
|
|
|
value, present := om.Get("foo")
|
|
assert.True(t, present)
|
|
assert.Equal(t, value, om.Value("foo"))
|
|
if assert.NotNil(t, value) {
|
|
assert.Equal(t, "foo!", value.value)
|
|
}
|
|
|
|
value, present = om.Set("bar", dummyTestStruct{"baz!"})
|
|
assert.True(t, present)
|
|
if assert.NotNil(t, value) {
|
|
assert.Equal(t, "bar!", value.value)
|
|
}
|
|
|
|
value, present = om.Get("bar")
|
|
assert.Equal(t, value, om.Value("bar"))
|
|
assert.True(t, present)
|
|
if assert.NotNil(t, value) {
|
|
assert.Equal(t, "baz!", value.value)
|
|
}
|
|
}
|
|
|
|
// shamelessly stolen from https://github.com/python/cpython/blob/e19a91e45fd54a56e39c2d12e6aaf4757030507f/Lib/test/test_ordered_dict.py#L55-L61
|
|
func TestShuffle(t *testing.T) {
|
|
ranLen := 100
|
|
|
|
for _, n := range []int{0, 10, 20, 100, 1000, 10000} {
|
|
t.Run(fmt.Sprintf("shuffle test with %d items", n), func(t *testing.T) {
|
|
om := New[string, string]()
|
|
|
|
keys := make([]string, n)
|
|
values := make([]string, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
// we prefix with the number to ensure that we don't get any duplicates
|
|
keys[i] = fmt.Sprintf("%d_%s", i, randomHexString(t, ranLen))
|
|
values[i] = randomHexString(t, ranLen)
|
|
|
|
value, present := om.Set(keys[i], values[i])
|
|
assert.Equal(t, "", value)
|
|
assert.False(t, present)
|
|
}
|
|
|
|
assertOrderedPairsEqual(t, om, keys, values)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMove(t *testing.T) {
|
|
om := New[int, any]()
|
|
om.Set(1, "bar")
|
|
om.Set(2, 28)
|
|
om.Set(3, 100)
|
|
om.Set(4, "baz")
|
|
om.Set(5, "28")
|
|
om.Set(6, "100")
|
|
om.Set(7, "baz")
|
|
om.Set(8, "baz")
|
|
|
|
err := om.MoveAfter(2, 3)
|
|
assert.Nil(t, err)
|
|
assertOrderedPairsEqual(t, om,
|
|
[]int{1, 3, 2, 4, 5, 6, 7, 8},
|
|
[]any{"bar", 100, 28, "baz", "28", "100", "baz", "baz"})
|
|
|
|
err = om.MoveBefore(6, 4)
|
|
assert.Nil(t, err)
|
|
assertOrderedPairsEqual(t, om,
|
|
[]int{1, 3, 2, 6, 4, 5, 7, 8},
|
|
[]any{"bar", 100, 28, "100", "baz", "28", "baz", "baz"})
|
|
|
|
err = om.MoveToBack(3)
|
|
assert.Nil(t, err)
|
|
assertOrderedPairsEqual(t, om,
|
|
[]int{1, 2, 6, 4, 5, 7, 8, 3},
|
|
[]any{"bar", 28, "100", "baz", "28", "baz", "baz", 100})
|
|
|
|
err = om.MoveToFront(5)
|
|
assert.Nil(t, err)
|
|
assertOrderedPairsEqual(t, om,
|
|
[]int{5, 1, 2, 6, 4, 7, 8, 3},
|
|
[]any{"28", "bar", 28, "100", "baz", "baz", "baz", 100})
|
|
|
|
err = om.MoveToFront(100)
|
|
assert.Equal(t, &KeyNotFoundError[int]{100}, err)
|
|
}
|
|
|
|
func TestGetAndMove(t *testing.T) {
|
|
om := New[int, any]()
|
|
om.Set(1, "bar")
|
|
om.Set(2, 28)
|
|
om.Set(3, 100)
|
|
om.Set(4, "baz")
|
|
om.Set(5, "28")
|
|
om.Set(6, "100")
|
|
om.Set(7, "baz")
|
|
om.Set(8, "baz")
|
|
|
|
value, err := om.GetAndMoveToBack(3)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 100, value)
|
|
assertOrderedPairsEqual(t, om,
|
|
[]int{1, 2, 4, 5, 6, 7, 8, 3},
|
|
[]any{"bar", 28, "baz", "28", "100", "baz", "baz", 100})
|
|
|
|
value, err = om.GetAndMoveToFront(5)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "28", value)
|
|
assertOrderedPairsEqual(t, om,
|
|
[]int{5, 1, 2, 4, 6, 7, 8, 3},
|
|
[]any{"28", "bar", 28, "baz", "100", "baz", "baz", 100})
|
|
|
|
value, err = om.GetAndMoveToBack(100)
|
|
assert.Equal(t, &KeyNotFoundError[int]{100}, err)
|
|
}
|
|
|
|
func TestAddPairs(t *testing.T) {
|
|
om := New[int, any]()
|
|
om.AddPairs(
|
|
Pair[int, any]{
|
|
Key: 28,
|
|
Value: "foo",
|
|
},
|
|
Pair[int, any]{
|
|
Key: 12,
|
|
Value: "bar",
|
|
},
|
|
Pair[int, any]{
|
|
Key: 28,
|
|
Value: "baz",
|
|
},
|
|
)
|
|
|
|
assertOrderedPairsEqual(t, om,
|
|
[]int{28, 12},
|
|
[]any{"baz", "bar"})
|
|
}
|
|
|
|
// sadly, we can't test the "actual" capacity here, see https://github.com/golang/go/issues/52157
|
|
func TestNewWithCapacity(t *testing.T) {
|
|
zero := New[int, string](0)
|
|
assert.Empty(t, zero.Len())
|
|
|
|
assert.PanicsWithValue(t, invalidOptionMessage, func() {
|
|
_ = New[int, string](1, 2)
|
|
})
|
|
assert.PanicsWithValue(t, invalidOptionMessage, func() {
|
|
_ = New[int, string](1, 2, 3)
|
|
})
|
|
|
|
om := New[int, string](-1)
|
|
om.Set(1337, "quarante-deux")
|
|
assert.Equal(t, 1, om.Len())
|
|
}
|
|
|
|
func TestNewWithOptions(t *testing.T) {
|
|
t.Run("wih capacity", func(t *testing.T) {
|
|
om := New[string, any](WithCapacity[string, any](98))
|
|
assert.Equal(t, 0, om.Len())
|
|
})
|
|
|
|
t.Run("with initial data", func(t *testing.T) {
|
|
om := New[string, int](WithInitialData(
|
|
Pair[string, int]{
|
|
Key: "a",
|
|
Value: 1,
|
|
},
|
|
Pair[string, int]{
|
|
Key: "b",
|
|
Value: 2,
|
|
},
|
|
Pair[string, int]{
|
|
Key: "c",
|
|
Value: 3,
|
|
},
|
|
))
|
|
|
|
assertOrderedPairsEqual(t, om,
|
|
[]string{"a", "b", "c"},
|
|
[]int{1, 2, 3})
|
|
})
|
|
|
|
t.Run("with an invalid option type", func(t *testing.T) {
|
|
assert.PanicsWithValue(t, invalidOptionMessage, func() {
|
|
_ = New[int, string]("foo")
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestNilMap(t *testing.T) {
|
|
// we want certain behaviors of a nil ordered map to be the same as they are for standard nil maps
|
|
var om *OrderedMap[int, any]
|
|
|
|
t.Run("len", func(t *testing.T) {
|
|
assert.Equal(t, 0, om.Len())
|
|
})
|
|
|
|
t.Run("iterating - akin to range", func(t *testing.T) {
|
|
assert.Nil(t, om.Oldest())
|
|
assert.Nil(t, om.Newest())
|
|
})
|
|
}
|