mirror of
https://github.com/luxfi/container.git
synced 2026-09-24 00:24:34 +00:00
223 lines
5.4 KiB
Go
223 lines
5.4 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package linked
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/luxfi/ids"
|
|
)
|
|
|
|
func TestHashmap(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
lh := NewHashmap[ids.ID, int]()
|
|
require.Zero(lh.Len(), "a new hashmap should be empty")
|
|
|
|
key0 := ids.GenerateTestID()
|
|
_, exists := lh.Get(key0)
|
|
require.False(exists, "shouldn't have found the value")
|
|
|
|
_, _, exists = lh.Oldest()
|
|
require.False(exists, "shouldn't have found a value")
|
|
|
|
_, _, exists = lh.Newest()
|
|
require.False(exists, "shouldn't have found a value")
|
|
|
|
lh.Put(key0, 0)
|
|
require.Equal(1, lh.Len(), "wrong hashmap length")
|
|
|
|
val0, exists := lh.Get(key0)
|
|
require.True(exists, "should have found the value")
|
|
require.Zero(val0, "wrong value")
|
|
|
|
rkey0, val0, exists := lh.Oldest()
|
|
require.True(exists, "should have found the value")
|
|
require.Equal(key0, rkey0, "wrong key")
|
|
require.Zero(val0, "wrong value")
|
|
|
|
rkey0, val0, exists = lh.Newest()
|
|
require.True(exists, "should have found the value")
|
|
require.Equal(key0, rkey0, "wrong key")
|
|
require.Zero(val0, "wrong value")
|
|
|
|
key1 := ids.GenerateTestID()
|
|
lh.Put(key1, 1)
|
|
require.Equal(2, lh.Len(), "wrong hashmap length")
|
|
|
|
val1, exists := lh.Get(key1)
|
|
require.True(exists, "should have found the value")
|
|
require.Equal(1, val1, "wrong value")
|
|
|
|
rkey0, val0, exists = lh.Oldest()
|
|
require.True(exists, "should have found the value")
|
|
require.Equal(key0, rkey0, "wrong key")
|
|
require.Zero(val0, "wrong value")
|
|
|
|
rkey1, val1, exists := lh.Newest()
|
|
require.True(exists, "should have found the value")
|
|
require.Equal(key1, rkey1, "wrong key")
|
|
require.Equal(1, val1, "wrong value")
|
|
|
|
require.True(lh.Delete(key0))
|
|
require.Equal(1, lh.Len(), "wrong hashmap length")
|
|
|
|
_, exists = lh.Get(key0)
|
|
require.False(exists, "shouldn't have found the value")
|
|
|
|
rkey1, val1, exists = lh.Oldest()
|
|
require.True(exists, "should have found the value")
|
|
require.Equal(rkey1, key1, "wrong key")
|
|
require.Equal(1, val1, "wrong value")
|
|
|
|
rkey1, val1, exists = lh.Newest()
|
|
require.True(exists, "should have found the value")
|
|
require.Equal(key1, rkey1, "wrong key")
|
|
require.Equal(1, val1, "wrong value")
|
|
|
|
lh.Put(key0, 0)
|
|
require.Equal(2, lh.Len(), "wrong hashmap length")
|
|
|
|
lh.Put(key1, 1)
|
|
require.Equal(2, lh.Len(), "wrong hashmap length")
|
|
|
|
rkey0, val0, exists = lh.Oldest()
|
|
require.True(exists, "should have found the value")
|
|
require.Equal(key0, rkey0, "wrong key")
|
|
require.Zero(val0, "wrong value")
|
|
|
|
rkey1, val1, exists = lh.Newest()
|
|
require.True(exists, "should have found the value")
|
|
require.Equal(key1, rkey1, "wrong key")
|
|
require.Equal(1, val1, "wrong value")
|
|
}
|
|
|
|
func TestHashmapClear(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
lh := NewHashmap[int, int]()
|
|
lh.Put(1, 1)
|
|
lh.Put(2, 2)
|
|
|
|
lh.Clear()
|
|
|
|
require.Empty(lh.entryMap)
|
|
require.Zero(lh.entryList.Len())
|
|
require.Len(lh.freeList, 2)
|
|
for _, e := range lh.freeList {
|
|
require.Zero(e.Value) // Make sure the value is cleared
|
|
}
|
|
}
|
|
|
|
func TestIterator(t *testing.T) {
|
|
require := require.New(t)
|
|
id1, id2, id3 := ids.GenerateTestID(), ids.GenerateTestID(), ids.GenerateTestID()
|
|
|
|
// Case: No elements
|
|
{
|
|
lh := NewHashmap[ids.ID, int]()
|
|
iter := lh.NewIterator()
|
|
require.NotNil(iter)
|
|
// Should immediately be exhausted
|
|
require.False(iter.Next())
|
|
require.False(iter.Next())
|
|
// Should be empty
|
|
require.Equal(ids.Empty, iter.Key())
|
|
require.Zero(iter.Value())
|
|
}
|
|
|
|
// Case: 1 element
|
|
{
|
|
lh := NewHashmap[ids.ID, int]()
|
|
iter := lh.NewIterator()
|
|
require.NotNil(iter)
|
|
lh.Put(id1, 1)
|
|
require.True(iter.Next())
|
|
require.Equal(id1, iter.Key())
|
|
require.Equal(1, iter.Value())
|
|
// Should be empty
|
|
require.False(iter.Next())
|
|
// Re-assign id1 --> 10
|
|
lh.Put(id1, 10)
|
|
iter = lh.NewIterator() // New iterator
|
|
require.True(iter.Next())
|
|
require.Equal(id1, iter.Key())
|
|
require.Equal(10, iter.Value())
|
|
// Should be empty
|
|
require.False(iter.Next())
|
|
// Delete id1
|
|
require.True(lh.Delete(id1))
|
|
iter = lh.NewIterator()
|
|
require.NotNil(iter)
|
|
// Should immediately be exhausted
|
|
require.False(iter.Next())
|
|
}
|
|
|
|
// Case: Multiple elements
|
|
{
|
|
lh := NewHashmap[ids.ID, int]()
|
|
lh.Put(id1, 1)
|
|
lh.Put(id2, 2)
|
|
lh.Put(id3, 3)
|
|
iter := lh.NewIterator()
|
|
// Should give back all 3 elements
|
|
require.True(iter.Next())
|
|
require.Equal(id1, iter.Key())
|
|
require.Equal(1, iter.Value())
|
|
require.True(iter.Next())
|
|
require.Equal(id2, iter.Key())
|
|
require.Equal(2, iter.Value())
|
|
require.True(iter.Next())
|
|
require.Equal(id3, iter.Key())
|
|
require.Equal(3, iter.Value())
|
|
// Should be exhausted
|
|
require.False(iter.Next())
|
|
}
|
|
|
|
// Case: Delete element that has been iterated over
|
|
{
|
|
lh := NewHashmap[ids.ID, int]()
|
|
lh.Put(id1, 1)
|
|
lh.Put(id2, 2)
|
|
lh.Put(id3, 3)
|
|
iter := lh.NewIterator()
|
|
require.True(iter.Next())
|
|
require.True(iter.Next())
|
|
require.True(lh.Delete(id1))
|
|
require.True(lh.Delete(id2))
|
|
require.True(iter.Next())
|
|
require.Equal(id3, iter.Key())
|
|
require.Equal(3, iter.Value())
|
|
// Should be exhausted
|
|
require.False(iter.Next())
|
|
}
|
|
}
|
|
|
|
func Benchmark_Hashmap_Put(b *testing.B) {
|
|
key := "hello"
|
|
value := "world"
|
|
|
|
lh := NewHashmap[string, string]()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
lh.Put(key, value)
|
|
}
|
|
}
|
|
|
|
func Benchmark_Hashmap_PutDelete(b *testing.B) {
|
|
key := "hello"
|
|
value := "world"
|
|
|
|
lh := NewHashmap[string, string]()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
lh.Put(key, value)
|
|
lh.Delete(key)
|
|
}
|
|
}
|