ollama/internal/orderedmap/orderedmap_test.go

272 lines
5.5 KiB
Go

package orderedmap
import (
"encoding/json"
"slices"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMap_BasicOperations(t *testing.T) {
m := New[string, int]()
// Test empty map
assert.Equal(t, 0, m.Len())
v, ok := m.Get("a")
assert.False(t, ok)
assert.Equal(t, 0, v)
// Test Set and Get
m.Set("a", 1)
m.Set("b", 2)
m.Set("c", 3)
assert.Equal(t, 3, m.Len())
v, ok = m.Get("a")
assert.True(t, ok)
assert.Equal(t, 1, v)
v, ok = m.Get("b")
assert.True(t, ok)
assert.Equal(t, 2, v)
v, ok = m.Get("c")
assert.True(t, ok)
assert.Equal(t, 3, v)
// Test updating existing key preserves position
m.Set("a", 10)
v, ok = m.Get("a")
assert.True(t, ok)
assert.Equal(t, 10, v)
assert.Equal(t, 3, m.Len()) // Length unchanged
}
func TestMap_InsertionOrderPreserved(t *testing.T) {
m := New[string, int]()
// Insert in non-alphabetical order
m.Set("z", 1)
m.Set("a", 2)
m.Set("m", 3)
m.Set("b", 4)
// Verify iteration order matches insertion order
var keys []string
var values []int
for k, v := range m.All() {
keys = append(keys, k)
values = append(values, v)
}
assert.Equal(t, []string{"z", "a", "m", "b"}, keys)
assert.Equal(t, []int{1, 2, 3, 4}, values)
}
func TestMap_UpdatePreservesPosition(t *testing.T) {
m := New[string, int]()
m.Set("first", 1)
m.Set("second", 2)
m.Set("third", 3)
// Update middle element
m.Set("second", 20)
var keys []string
for k := range m.All() {
keys = append(keys, k)
}
// Order should still be first, second, third
assert.Equal(t, []string{"first", "second", "third"}, keys)
}
func TestMap_MarshalJSON_PreservesOrder(t *testing.T) {
m := New[string, int]()
// Insert in non-alphabetical order
m.Set("z", 1)
m.Set("a", 2)
m.Set("m", 3)
data, err := json.Marshal(m)
require.NoError(t, err)
// JSON should preserve insertion order, not alphabetical
assert.Equal(t, `{"z":1,"a":2,"m":3}`, string(data))
}
func TestMap_UnmarshalJSON_PreservesOrder(t *testing.T) {
// JSON with non-alphabetical key order
jsonData := `{"z":1,"a":2,"m":3}`
m := New[string, int]()
err := json.Unmarshal([]byte(jsonData), m)
require.NoError(t, err)
// Verify iteration order matches JSON order
var keys []string
for k := range m.All() {
keys = append(keys, k)
}
assert.Equal(t, []string{"z", "a", "m"}, keys)
}
func TestMap_JSONRoundTrip(t *testing.T) {
// Test that unmarshal -> marshal produces identical JSON
original := `{"zebra":"z","apple":"a","mango":"m","banana":"b"}`
m := New[string, string]()
err := json.Unmarshal([]byte(original), m)
require.NoError(t, err)
data, err := json.Marshal(m)
require.NoError(t, err)
assert.Equal(t, original, string(data))
}
func TestMap_ToMap(t *testing.T) {
m := New[string, int]()
m.Set("a", 1)
m.Set("b", 2)
regular := m.ToMap()
assert.Equal(t, 2, len(regular))
assert.Equal(t, 1, regular["a"])
assert.Equal(t, 2, regular["b"])
}
func TestMap_NilSafety(t *testing.T) {
var m *Map[string, int]
// All operations should be safe on nil
assert.Equal(t, 0, m.Len())
v, ok := m.Get("a")
assert.False(t, ok)
assert.Equal(t, 0, v)
// Set on nil is a no-op
m.Set("a", 1)
assert.Equal(t, 0, m.Len())
// All returns empty iterator
var keys []string
for k := range m.All() {
keys = append(keys, k)
}
assert.Empty(t, keys)
// ToMap returns nil
assert.Nil(t, m.ToMap())
// MarshalJSON returns null
data, err := json.Marshal(m)
require.NoError(t, err)
assert.Equal(t, "null", string(data))
}
func TestMap_EmptyMapMarshal(t *testing.T) {
m := New[string, int]()
data, err := json.Marshal(m)
require.NoError(t, err)
assert.Equal(t, "{}", string(data))
}
func TestMap_NestedValues(t *testing.T) {
m := New[string, any]()
m.Set("string", "hello")
m.Set("number", 42)
m.Set("bool", true)
m.Set("nested", map[string]int{"x": 1})
data, err := json.Marshal(m)
require.NoError(t, err)
expected := `{"string":"hello","number":42,"bool":true,"nested":{"x":1}}`
assert.Equal(t, expected, string(data))
}
func TestMap_AllIteratorEarlyExit(t *testing.T) {
m := New[string, int]()
m.Set("a", 1)
m.Set("b", 2)
m.Set("c", 3)
m.Set("d", 4)
// Collect only first 2
var keys []string
for k := range m.All() {
keys = append(keys, k)
if len(keys) == 2 {
break
}
}
assert.Equal(t, []string{"a", "b"}, keys)
}
func TestMap_IntegerKeys(t *testing.T) {
m := New[int, string]()
m.Set(3, "three")
m.Set(1, "one")
m.Set(2, "two")
var keys []int
for k := range m.All() {
keys = append(keys, k)
}
// Should preserve insertion order, not numerical order
assert.Equal(t, []int{3, 1, 2}, keys)
}
func TestMap_UnmarshalIntoExisting(t *testing.T) {
m := New[string, int]()
m.Set("existing", 999)
// Unmarshal should replace contents
err := json.Unmarshal([]byte(`{"new":1}`), m)
require.NoError(t, err)
_, ok := m.Get("existing")
assert.False(t, ok, "existing key should be gone after unmarshal")
v, ok := m.Get("new")
assert.True(t, ok)
assert.Equal(t, 1, v)
}
func TestMap_LargeOrderPreservation(t *testing.T) {
m := New[string, int]()
// Create many keys in specific order
keys := make([]string, 100)
for i := range 100 {
keys[i] = string(rune('a' + (99 - i))) // reverse order: 'd', 'c', 'b', 'a' (extended)
if i >= 26 {
keys[i] = string(rune('A'+i-26)) + string(rune('a'+i%26))
}
}
for i, k := range keys {
m.Set(k, i)
}
// Verify order preserved
var resultKeys []string
for k := range m.All() {
resultKeys = append(resultKeys, k)
}
assert.True(t, slices.Equal(keys, resultKeys), "large map should preserve insertion order")
}