first commit

This commit is contained in:
2025-10-11 19:53:28 +04:00
commit 0d53670ab7
18 changed files with 2413 additions and 0 deletions

38
maps/base.go Normal file
View File

@@ -0,0 +1,38 @@
package maps
import "maps"
// InitMap initializes a map pointer if it is nil.
// If the map is already initialized, this function does nothing.
//
// This is useful for ensuring a map is ready to use before adding entries,
// preventing nil pointer dereferences.
//
// Example:
//
// var m map[string]int
// InitMap(&m)
// m["key"] = 42 // safe to use
func InitMap[K comparable, V any, T ~map[K]V](m *T) {
if *m == nil {
*m = make(T)
}
}
// UpdateMap merges entries from the new map into the old map.
// If the old map is nil, it will be initialized first.
// Existing keys in the old map will be overwritten with values from the new map.
//
// This function modifies the old map in place by copying all key-value pairs
// from the new map into it.
//
// Example:
//
// old := map[string]int{"a": 1, "b": 2}
// new := map[string]int{"b": 3, "c": 4}
// UpdateMap(&old, new)
// // old is now: {"a": 1, "b": 3, "c": 4}
func UpdateMap[K comparable, V any, T ~map[K]V](oldMap *T, newMap T) {
InitMap(oldMap)
maps.Copy(*oldMap, newMap)
}

317
maps/base_test.go Normal file
View File

@@ -0,0 +1,317 @@
package maps
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestInitMap(t *testing.T) {
t.Run("initializes nil map", func(t *testing.T) {
var m map[string]int
require.Nil(t, m)
InitMap(&m)
assert.NotNil(t, m)
assert.Empty(t, m)
assert.Empty(t, m)
})
t.Run("does not reinitialize existing map", func(t *testing.T) {
m := map[string]int{"key": 42}
originalLen := len(m)
InitMap(&m)
assert.Len(t, m, originalLen)
assert.Equal(t, 42, m["key"])
})
t.Run("allows adding entries after initialization", func(t *testing.T) {
var m map[string]int
InitMap(&m)
m["test"] = 100
assert.Equal(t, 100, m["test"])
assert.Len(t, m, 1)
})
t.Run("works with empty initialized map", func(t *testing.T) {
m := make(map[string]int)
InitMap(&m)
assert.NotNil(t, m)
assert.Empty(t, m)
})
t.Run("works with different key types", func(t *testing.T) {
t.Run("int keys", func(t *testing.T) {
var m map[int]string
InitMap(&m)
assert.NotNil(t, m)
m[1] = "one"
assert.Equal(t, "one", m[1])
})
t.Run("struct keys", func(t *testing.T) {
type Key struct {
ID int
Name string
}
var m map[Key]bool
InitMap(&m)
assert.NotNil(t, m)
k := Key{ID: 1, Name: "test"}
m[k] = true
assert.True(t, m[k])
})
})
t.Run("works with different value types", func(t *testing.T) {
t.Run("string values", func(t *testing.T) {
var m map[string]string
InitMap(&m)
assert.NotNil(t, m)
m["key"] = "value"
assert.Equal(t, "value", m["key"])
})
t.Run("struct values", func(t *testing.T) {
type Value struct {
Count int
Name string
}
var m map[string]Value
InitMap(&m)
assert.NotNil(t, m)
m["test"] = Value{Count: 5, Name: "foo"}
assert.Equal(t, 5, m["test"].Count)
})
t.Run("slice values", func(t *testing.T) {
var m map[string][]int
InitMap(&m)
assert.NotNil(t, m)
m["numbers"] = []int{1, 2, 3}
assert.Equal(t, []int{1, 2, 3}, m["numbers"])
})
t.Run("pointer values", func(t *testing.T) {
var m map[string]*int
InitMap(&m)
assert.NotNil(t, m)
val := 42
m["ptr"] = &val
assert.Equal(t, 42, *m["ptr"])
})
})
t.Run("works with custom map types", func(t *testing.T) {
type CustomMap map[string]int
var m CustomMap
InitMap(&m)
assert.NotNil(t, m)
m["custom"] = 99
assert.Equal(t, 99, m["custom"])
})
}
func TestUpdateMap(t *testing.T) {
t.Run("merges new entries into existing map", func(t *testing.T) {
oldMap := map[string]int{"a": 1, "b": 2}
newMap := map[string]int{"c": 3, "d": 4}
UpdateMap(&oldMap, newMap)
assert.Len(t, oldMap, 4)
assert.Equal(t, 1, oldMap["a"])
assert.Equal(t, 2, oldMap["b"])
assert.Equal(t, 3, oldMap["c"])
assert.Equal(t, 4, oldMap["d"])
})
t.Run("overwrites existing keys", func(t *testing.T) {
oldMap := map[string]int{"a": 1, "b": 2}
newMap := map[string]int{"b": 3, "c": 4}
UpdateMap(&oldMap, newMap)
assert.Len(t, oldMap, 3)
assert.Equal(t, 1, oldMap["a"])
assert.Equal(t, 3, oldMap["b"], "existing key 'b' should be overwritten")
assert.Equal(t, 4, oldMap["c"])
})
t.Run("initializes nil map before merging", func(t *testing.T) {
var oldMap map[string]int
newMap := map[string]int{"a": 1, "b": 2}
require.Nil(t, oldMap)
UpdateMap(&oldMap, newMap)
assert.NotNil(t, oldMap)
assert.Len(t, oldMap, 2)
assert.Equal(t, 1, oldMap["a"])
assert.Equal(t, 2, oldMap["b"])
})
t.Run("handles empty new map", func(t *testing.T) {
oldMap := map[string]int{"a": 1}
newMap := map[string]int{}
UpdateMap(&oldMap, newMap)
assert.Len(t, oldMap, 1)
assert.Equal(t, 1, oldMap["a"])
})
t.Run("handles empty old map", func(t *testing.T) {
oldMap := map[string]int{}
newMap := map[string]int{"a": 1, "b": 2}
UpdateMap(&oldMap, newMap)
assert.Len(t, oldMap, 2)
assert.Equal(t, 1, oldMap["a"])
assert.Equal(t, 2, oldMap["b"])
})
t.Run("handles both empty maps", func(t *testing.T) {
oldMap := map[string]int{}
newMap := map[string]int{}
UpdateMap(&oldMap, newMap)
assert.NotNil(t, oldMap)
assert.Empty(t, oldMap)
})
t.Run("works with different types", func(t *testing.T) {
t.Run("string values", func(t *testing.T) {
oldMap := map[string]string{"key1": "value1"}
newMap := map[string]string{"key2": "value2"}
UpdateMap(&oldMap, newMap)
assert.Len(t, oldMap, 2)
assert.Equal(t, "value1", oldMap["key1"])
assert.Equal(t, "value2", oldMap["key2"])
})
t.Run("struct values", func(t *testing.T) {
type Person struct {
Name string
Age int
}
oldMap := map[string]Person{
"john": {Name: "John", Age: 30},
}
newMap := map[string]Person{
"jane": {Name: "Jane", Age: 25},
}
UpdateMap(&oldMap, newMap)
assert.Len(t, oldMap, 2)
assert.Equal(t, "John", oldMap["john"].Name)
assert.Equal(t, "Jane", oldMap["jane"].Name)
})
t.Run("int keys", func(t *testing.T) {
oldMap := map[int]string{1: "one"}
newMap := map[int]string{2: "two"}
UpdateMap(&oldMap, newMap)
assert.Len(t, oldMap, 2)
assert.Equal(t, "one", oldMap[1])
assert.Equal(t, "two", oldMap[2])
})
})
t.Run("modifies map in place", func(t *testing.T) {
oldMap := map[string]int{"a": 1}
originalMap := oldMap
newMap := map[string]int{"b": 2}
UpdateMap(&oldMap, newMap)
// Verify it's the same map (modified in place)
assert.Equal(t, 2, oldMap["b"])
// Note: originalMap is pointing to the same underlying map
// so it should also have the new value
assert.Equal(t, 2, originalMap["b"])
})
t.Run("does not modify new map", func(t *testing.T) {
oldMap := map[string]int{"a": 1}
newMap := map[string]int{"b": 2, "c": 3}
newLen := len(newMap)
UpdateMap(&oldMap, newMap)
assert.Len(t, newMap, newLen, "new map should not be modified")
assert.Equal(t, 2, newMap["b"])
assert.Equal(t, 3, newMap["c"])
_, hasA := newMap["a"]
assert.False(t, hasA, "new map should not contain keys from old map")
})
t.Run("works with custom map types", func(t *testing.T) {
type CustomMap map[string]int
oldMap := CustomMap{"a": 1}
newMap := CustomMap{"b": 2}
UpdateMap(&oldMap, newMap)
assert.Len(t, oldMap, 2)
assert.Equal(t, 1, oldMap["a"])
assert.Equal(t, 2, oldMap["b"])
})
t.Run("overwrites with zero values", func(t *testing.T) {
oldMap := map[string]int{"a": 10, "b": 20}
newMap := map[string]int{"a": 0}
UpdateMap(&oldMap, newMap)
assert.Len(t, oldMap, 2)
assert.Equal(t, 0, oldMap["a"], "should overwrite with zero value")
assert.Equal(t, 20, oldMap["b"])
})
t.Run("complex merge scenario", func(t *testing.T) {
oldMap := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
newMap := map[string]int{
"b": 20, // overwrite
"c": 30, // overwrite
"d": 40, // new
"e": 50, // new
}
UpdateMap(&oldMap, newMap)
expected := map[string]int{
"a": 1, // preserved
"b": 20, // overwritten
"c": 30, // overwritten
"d": 40, // new
"e": 50, // new
}
assert.Equal(t, expected, oldMap)
})
}