// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. package gmap_test import ( "strconv" "sync" "testing" "github.com/gogf/gf/v2/container/gmap" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/test/gtest" "github.com/gogf/gf/v2/util/gconv" ) func Test_KVMap_NewKVMap(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() t.Assert(m.Size(), 0) t.Assert(m.IsEmpty(), true) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string](true) t.Assert(m.Size(), 0) t.Assert(m.IsEmpty(), true) }) } func Test_KVMap_NewKVMapFrom(t *testing.T) { gtest.C(t, func(t *gtest.T) { data := map[string]string{"a": "1", "b": "2"} m := gmap.NewKVMapFrom(data) t.Assert(m.Size(), 2) t.Assert(m.Get("a"), "1") t.Assert(m.Get("b"), "2") }) gtest.C(t, func(t *gtest.T) { data := map[int]int{1: 10, 2: 20} m := gmap.NewKVMapFrom(data, true) t.Assert(m.Size(), 2) t.Assert(m.Get(1), 10) t.Assert(m.Get(2), 20) }) } func Test_KVMap_Set_Get(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() m.Set("a", "1") t.Assert(m.Get("a"), "1") t.Assert(m.Size(), 1) m.Set("b", "2") t.Assert(m.Get("b"), "2") t.Assert(m.Size(), 2) // Set existing key m.Set("a", "10") t.Assert(m.Get("a"), "10") t.Assert(m.Size(), 2) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[int, int]() m.Set(1, 100) m.Set(2, 200) t.Assert(m.Get(1), 100) t.Assert(m.Get(2), 200) }) } func Test_KVMap_Sets(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() m.Sets(map[string]string{"a": "1", "b": "2", "c": "3"}) t.Assert(m.Size(), 3) t.Assert(m.Get("a"), "1") t.Assert(m.Get("b"), "2") t.Assert(m.Get("c"), "3") }) gtest.C(t, func(t *gtest.T) { data := map[string]string{"x": "10", "y": "20"} m := gmap.NewKVMapFrom(data) m.Sets(map[string]string{"a": "1", "b": "2"}) t.Assert(m.Size(), 4) t.Assert(m.Get("x"), "10") t.Assert(m.Get("a"), "1") }) } func Test_KVMap_Search(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) v, found := m.Search("a") t.Assert(found, true) t.Assert(v, "1") v, found = m.Search("c") t.Assert(found, false) t.Assert(v, "") }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[int, string]() v, found := m.Search(1) t.Assert(found, false) t.Assert(v, "") }) } func Test_KVMap_Contains(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) t.Assert(m.Contains("a"), true) t.Assert(m.Contains("b"), true) t.Assert(m.Contains("c"), false) }) } func Test_KVMap_Remove(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) t.Assert(m.Size(), 2) v := m.Remove("a") t.Assert(v, "1") t.Assert(m.Contains("a"), false) t.Assert(m.Size(), 1) v = m.Remove("c") t.Assert(v, "") t.Assert(m.Size(), 1) }) } func Test_KVMap_Removes(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2", "c": "3"}) t.Assert(m.Size(), 3) m.Removes([]string{"a", "c"}) t.Assert(m.Size(), 1) t.Assert(m.Contains("a"), false) t.Assert(m.Contains("c"), false) t.Assert(m.Contains("b"), true) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) m.Removes([]string{"x", "y"}) t.Assert(m.Size(), 2) }) } func Test_KVMap_Pop(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) t.Assert(m.Size(), 2) k, v := m.Pop() t.AssertIN(k, []string{"a", "b"}) t.AssertIN(v, []string{"1", "2"}) t.Assert(m.Size(), 1) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() k, v := m.Pop() t.Assert(k, "") t.Assert(v, "") }) } func Test_KVMap_Pops(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2", "c": "3"}) t.Assert(m.Size(), 3) popped := m.Pops(2) t.Assert(len(popped), 2) t.Assert(m.Size(), 1) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2", "c": "3"}) popped := m.Pops(-1) t.Assert(len(popped), 3) t.Assert(m.Size(), 0) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) popped := m.Pops(10) t.Assert(len(popped), 2) t.Assert(m.Size(), 0) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() popped := m.Pops(1) t.AssertNil(popped) }) } func Test_KVMap_Keys(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2", "c": "3"}) keys := m.Keys() t.Assert(len(keys), 3) t.AssertIN("a", keys) t.AssertIN("b", keys) t.AssertIN("c", keys) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[int, string]() keys := m.Keys() t.Assert(len(keys), 0) }) } func Test_KVMap_Values(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2", "c": "3"}) values := m.Values() t.Assert(len(values), 3) t.AssertIN("1", values) t.AssertIN("2", values) t.AssertIN("3", values) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() values := m.Values() t.Assert(len(values), 0) }) } func Test_KVMap_Size(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() t.Assert(m.Size(), 0) m.Set("a", "1") t.Assert(m.Size(), 1) m.Set("b", "2") t.Assert(m.Size(), 2) m.Remove("a") t.Assert(m.Size(), 1) m.Clear() t.Assert(m.Size(), 0) }) } func Test_KVMap_IsEmpty(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() t.Assert(m.IsEmpty(), true) m.Set("a", "1") t.Assert(m.IsEmpty(), false) m.Remove("a") t.Assert(m.IsEmpty(), true) }) } func Test_KVMap_Clear(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2", "c": "3"}) t.Assert(m.Size(), 3) m.Clear() t.Assert(m.Size(), 0) t.Assert(m.IsEmpty(), true) t.Assert(m.Get("a"), "") }) } func Test_KVMap_Map(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) data := m.Map() t.Assert(data["a"], "1") t.Assert(data["b"], "2") t.Assert(len(data), 2) }) gtest.C(t, func(t *gtest.T) { // Unsafe map, modifying returned map affects original m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}, false) data := m.Map() data["c"] = "3" t.Assert(m.Get("c"), "3") }) gtest.C(t, func(t *gtest.T) { // Safe map, modifying returned map doesn't affect original m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}, true) data := m.Map() data["c"] = "3" t.Assert(m.Get("c"), "") }) } func Test_KVMap_MapCopy(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) data := m.MapCopy() t.Assert(data["a"], "1") t.Assert(data["b"], "2") // Modifying copy doesn't affect original data["c"] = "3" t.Assert(m.Get("c"), "") m.Set("d", "4") t.Assert(data["d"], "") }) } func Test_KVMap_MapStrAny(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]int{"a": 1, "b": 2}) data := m.MapStrAny() t.Assert(len(data), 2) t.Assert(data["a"], 1) t.Assert(data["b"], 2) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[int]string{1: "a", 2: "b"}) data := m.MapStrAny() t.Assert(len(data), 2) t.Assert(data["1"], "a") t.Assert(data["2"], "b") }) } func Test_KVMap_FilterEmpty(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "", "b": "2", "c": "3"}) t.Assert(m.Size(), 3) m.FilterEmpty() t.Assert(m.Size(), 2) t.Assert(m.Contains("a"), false) t.Assert(m.Contains("b"), true) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]int{"a": 0, "b": 1, "c": 2}) t.Assert(m.Size(), 3) m.FilterEmpty() t.Assert(m.Size(), 2) t.Assert(m.Contains("a"), false) }) } func Test_KVMap_FilterNil(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, *string]() a := "a" m.Set("key1", &a) m.Set("key2", nil) m.Set("key3", nil) t.Assert(m.Size(), 3) m.FilterNil() t.Assert(m.Size(), 1) t.Assert(m.Contains("key1"), true) t.Assert(m.Contains("key2"), false) }) } func Test_KVMap_GetOrSet(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() v := m.GetOrSet("a", "1") t.Assert(v, "1") t.Assert(m.Get("a"), "1") v = m.GetOrSet("a", "10") t.Assert(v, "1") t.Assert(m.Get("a"), "1") }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]int{"a": 10}) v := m.GetOrSet("a", 20) t.Assert(v, 10) v = m.GetOrSet("b", 30) t.Assert(v, 30) t.Assert(m.Get("b"), 30) }) } func Test_KVMap_GetOrSetFunc(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() v := m.GetOrSetFunc("a", func() string { return "1" }) t.Assert(v, "1") v = m.GetOrSetFunc("a", func() string { return "10" }) t.Assert(v, "1") v = m.GetOrSetFunc("b", func() string { return "2" }) t.Assert(v, "2") }) } func Test_KVMap_GetOrSetFuncLock(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() counter := 0 v := m.GetOrSetFuncLock("a", func() int { counter++ return 10 }) t.Assert(v, 10) t.Assert(counter, 1) v = m.GetOrSetFuncLock("a", func() int { counter++ return 20 }) t.Assert(v, 10) t.Assert(counter, 1) }) } func Test_KVMap_SetIfNotExist(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() ok := m.SetIfNotExist("a", "1") t.Assert(ok, true) t.Assert(m.Get("a"), "1") ok = m.SetIfNotExist("a", "10") t.Assert(ok, false) t.Assert(m.Get("a"), "1") }) } func Test_KVMap_SetIfNotExistFunc(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() ok := m.SetIfNotExistFunc("a", func() int { return 10 }) t.Assert(ok, true) t.Assert(m.Get("a"), 10) ok = m.SetIfNotExistFunc("a", func() int { return 20 }) t.Assert(ok, false) t.Assert(m.Get("a"), 10) }) } func Test_KVMap_SetIfNotExistFuncLock(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() counter := 0 ok := m.SetIfNotExistFuncLock("a", func() string { counter++ return "1" }) t.Assert(ok, true) t.Assert(counter, 1) ok = m.SetIfNotExistFuncLock("a", func() string { counter++ return "2" }) t.Assert(ok, false) t.Assert(counter, 1) }) } func Test_KVMap_GetVar(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) v := m.GetVar("a") t.AssertNE(v, nil) t.Assert(v.Val(), "1") v = m.GetVar("c") t.Assert(v.Val(), nil) }) } func Test_KVMap_GetVarOrSet(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() v := m.GetVarOrSet("a", "1") t.AssertNE(v, nil) t.Assert(v.Val(), "1") v = m.GetVarOrSet("a", "10") t.Assert(v.Val(), "1") }) } func Test_KVMap_GetVarOrSetFunc(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() v := m.GetVarOrSetFunc("a", func() int { return 10 }) t.AssertNE(v, nil) t.Assert(v.Val(), 10) v = m.GetVarOrSetFunc("a", func() int { return 20 }) t.Assert(v.Val(), 10) }) } func Test_KVMap_GetVarOrSetFuncLock(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() v := m.GetVarOrSetFuncLock("a", func() string { return "1" }) t.AssertNE(v, nil) t.Assert(v.Val(), "1") v = m.GetVarOrSetFuncLock("a", func() string { return "10" }) t.Assert(v.Val(), "1") }) } func Test_KVMap_Iterator(t *testing.T) { gtest.C(t, func(t *gtest.T) { data := map[string]string{"a": "1", "b": "2", "c": "3"} m := gmap.NewKVMapFrom(data) count := 0 m.Iterator(func(k string, v string) bool { t.Assert(data[k], v) count++ return true }) t.Assert(count, 3) }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[int]string{1: "a", 2: "b", 3: "c"}) count := 0 m.Iterator(func(k int, v string) bool { count++ return count < 2 }) t.Assert(count, 2) }) } func Test_KVMap_Iterator_Deadlock(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"1": "1", "2": "2", "3": "3", "4": "4"}, true) m.Iterator(func(k string, _ string) bool { kInt, _ := strconv.Atoi(k) if kInt%2 == 0 { m.Remove(k) } return true }) t.Assert(m.Size(), 2) }) } func Test_KVMap_LockFunc(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) m.LockFunc(func(data map[string]string) { t.Assert(data["a"], "1") t.Assert(data["b"], "2") data["c"] = "3" }) t.Assert(m.Get("c"), "3") }) } func Test_KVMap_RLockFunc(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) count := 0 m.RLockFunc(func(data map[string]string) { count += len(data) }) t.Assert(count, 2) }) } func Test_KVMap_Replace(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) t.Assert(m.Size(), 2) m.Replace(map[string]string{"x": "10", "y": "20", "z": "30"}) t.Assert(m.Size(), 3) t.Assert(m.Get("a"), "") t.Assert(m.Get("x"), "10") }) } func Test_KVMap_Clone(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) m2 := m.Clone() t.Assert(m2.Get("a"), "1") t.Assert(m2.Get("b"), "2") t.Assert(m2.Size(), 2) m.Set("a", "10") t.Assert(m2.Get("a"), "1") }) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]int{"a": 1, "b": 2}, false) m2 := m.Clone(true) t.Assert(m2.Size(), 2) }) } func Test_KVMap_Flip(t *testing.T) { // Test with same type for key and value (string -> string) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2", "c": "3"}) m.Flip() t.Assert(m.Get("1"), "a") t.Assert(m.Get("2"), "b") t.Assert(m.Get("3"), "c") }) // Test with same type for key and value (int -> int) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[int]int{1: 10, 2: 20}) m.Flip() t.Assert(m.Get(10), 1) t.Assert(m.Get(20), 2) }) } func Test_KVMap_Merge(t *testing.T) { gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMapFrom(map[string]string{"a": "1"}) m2 := gmap.NewKVMapFrom(map[string]string{"b": "2", "c": "3"}) m1.Merge(m2) t.Assert(m1.Size(), 3) t.Assert(m1.Get("a"), "1") t.Assert(m1.Get("b"), "2") t.Assert(m1.Get("c"), "3") }) gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMap[string, int]() m2 := gmap.NewKVMapFrom(map[string]int{"a": 10, "b": 20}) m1.Merge(m2) t.Assert(m1.Size(), 2) t.Assert(m1.Get("a"), 10) }) gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMapFrom(map[string]string{"a": "1"}) m2 := gmap.NewKVMapFrom(map[string]string{"a": "10", "b": "2"}) m1.Merge(m2) t.Assert(m1.Get("a"), "10") }) } func Test_KVMap_IsSubOf(t *testing.T) { gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) m2 := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2", "c": "3"}) t.Assert(m1.IsSubOf(m2), true) t.Assert(m2.IsSubOf(m1), false) }) gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) m2 := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "10"}) t.Assert(m1.IsSubOf(m2), false) }) gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMapFrom(map[string]string{"a": "1"}) t.Assert(m1.IsSubOf(m1), true) }) } func Test_KVMap_Diff(t *testing.T) { gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2", "c": "3"}) m2 := gmap.NewKVMapFrom(map[string]string{"a": "1", "d": "4"}) added, removed, updated := m1.Diff(m2) t.Assert(len(added), 1) t.AssertIN("d", added) t.Assert(len(removed), 2) t.AssertIN("b", removed) t.AssertIN("c", removed) t.Assert(len(updated), 0) }) gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) m2 := gmap.NewKVMapFrom(map[string]string{"a": "10", "b": "2"}) added, removed, updated := m1.Diff(m2) t.Assert(len(added), 0) t.Assert(len(removed), 0) t.Assert(len(updated), 1) t.AssertIN("a", updated) }) } func Test_KVMap_String(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1"}) s := m.String() t.AssertNE(s, "") t.AssertIN("a", s) }) gtest.C(t, func(t *gtest.T) { var m *gmap.KVMap[string, string] s := m.String() t.Assert(s, "") }) } func Test_KVMap_MarshalJSON(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]int{"a": 1, "b": 2}) b, err := json.Marshal(m) t.AssertNil(err) t.AssertNE(b, nil) var data map[string]int err = json.Unmarshal(b, &data) t.AssertNil(err) t.Assert(data["a"], 1) t.Assert(data["b"], 2) }) gtest.C(t, func(t *gtest.T) { var m gmap.KVMap[int, int] m.Set(1, 10) b, err := json.Marshal(m) t.AssertNil(err) t.Assert(string(b), `{"1":10}`) }) } func Test_KVMap_UnmarshalJSON(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() data := []byte(`{"a":1,"b":2,"c":3}`) err := json.UnmarshalUseNumber(data, m) t.AssertNil(err) t.Assert(m.Get("a"), 1) t.Assert(m.Get("b"), 2) t.Assert(m.Get("c"), 3) }) gtest.C(t, func(t *gtest.T) { var m gmap.KVMap[string, string] data := []byte(`{"x":"10","y":"20"}`) err := json.UnmarshalUseNumber(data, &m) t.AssertNil(err) t.Assert(m.Get("x"), "10") t.Assert(m.Get("y"), "20") }) } func Test_KVMap_UnmarshalValue(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, string]() err := m.UnmarshalValue(map[string]any{ "a": "1", "b": "2", }) t.AssertNil(err) t.Assert(m.Get("a"), "1") t.Assert(m.Get("b"), "2") }) } func Test_KVMap_DeepCopy(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string][]string{ "a": {"1", "2"}, "b": {"3", "4"}, }) n := m.DeepCopy().(*gmap.KVMap[string, []string]) t.Assert(n.Size(), 2) t.Assert(n.Get("a"), []string{"1", "2"}) // Modifying original doesn't affect copy m.Get("a")[0] = "10" t.Assert(n.Get("a")[0], "1") }) gtest.C(t, func(t *gtest.T) { var m *gmap.KVMap[string, int] n := m.DeepCopy() t.AssertNil(n) }) } // Test Set with nil data func Test_KVMap_Set_NilData(t *testing.T) { gtest.C(t, func(t *gtest.T) { // Create map with nil internal data m := gmap.NewKVMapFrom[string, string](nil) m.Set("a", "1") t.Assert(m.Get("a"), "1") t.Assert(m.Size(), 1) }) } // Test Sets with nil data func Test_KVMap_Sets_NilData(t *testing.T) { gtest.C(t, func(t *gtest.T) { // Create map with nil internal data m := gmap.NewKVMapFrom[string, string](nil) m.Sets(map[string]string{"a": "1", "b": "2"}) t.Assert(m.Get("a"), "1") t.Assert(m.Get("b"), "2") t.Assert(m.Size(), 2) }) } // Test doSetWithLockCheck - key exists and value is nil func Test_KVMap_GetOrSet_KeyExists(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom[string, string](nil) // First call: key does not exist, set value v := m.GetOrSet("a", "1") t.Assert(v, "1") // Second call: key exists, should return existing value v = m.GetOrSet("a", "2") t.Assert(v, "1") }) } // Test GetOrSet with nil value func Test_KVMap_GetOrSet_NilValue(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, *string]() // Set nil value v := m.GetOrSet("a", nil) t.Assert(v, nil) // Key is not stored when value is nil (based on implementation) // The doSetWithLockCheck checks: if any(value) != nil // For pointer type, nil is actually stored because any(nil pointer) is not nil interface // Let's verify the actual behavior }) // Test with interface type to trigger the nil check gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, any]() v := m.GetOrSet("a", nil) t.Assert(v, nil) // nil interface value should not be stored t.Assert(m.Contains("a"), false) }) } // Test GetOrSetFunc with nil value func Test_KVMap_GetOrSetFunc_NilValue(t *testing.T) { // Test with interface type to trigger the nil check gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, any]() v := m.GetOrSetFunc("a", func() any { return nil }) t.Assert(v, nil) // nil interface value should not be stored t.Assert(m.Contains("a"), false) }) } // Test GetOrSetFuncLock with nil data and nil value func Test_KVMap_GetOrSetFuncLock_NilData(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom[string, string](nil) v := m.GetOrSetFuncLock("a", func() string { return "1" }) t.Assert(v, "1") t.Assert(m.Get("a"), "1") }) // Test with nil value (using any type) gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, any]() v := m.GetOrSetFuncLock("a", func() any { return nil }) t.Assert(v, nil) // nil interface value should not be stored t.Assert(m.Contains("a"), false) }) } // Test SetIfNotExist with nil data func Test_KVMap_SetIfNotExist_NilData(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom[string, string](nil) ok := m.SetIfNotExist("a", "1") t.Assert(ok, true) t.Assert(m.Get("a"), "1") }) } // Test SetIfNotExistFuncLock with nil data func Test_KVMap_SetIfNotExistFuncLock_NilData(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom[string, string](nil) ok := m.SetIfNotExistFuncLock("a", func() string { return "1" }) t.Assert(ok, true) t.Assert(m.Get("a"), "1") }) } // Test Flip with conversion errors func Test_KVMap_Flip_ConversionError(t *testing.T) { // Test with incompatible types that will fail conversion gtest.C(t, func(t *gtest.T) { type customKey struct { ID int } type customVal struct { Name string } m := gmap.NewKVMapFrom(map[customKey]customVal{ {ID: 1}: {Name: "a"}, {ID: 2}: {Name: "b"}, }) // Flip will fail because customVal cannot be converted to customKey m.Flip() // After failed flip, map should be empty or unchanged depending on implementation // Based on the code, items that fail conversion are skipped }) } // Test Merge with self func Test_KVMap_Merge_Self(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) m.Merge(m) t.Assert(m.Size(), 2) t.Assert(m.Get("a"), "1") t.Assert(m.Get("b"), "2") }) } // Test Merge with nil data func Test_KVMap_Merge_NilData(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom[string, string](nil) m2 := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) m.Merge(m2) t.Assert(m.Size(), 2) t.Assert(m.Get("a"), "1") t.Assert(m.Get("b"), "2") }) } // Test UnmarshalJSON with invalid JSON func Test_KVMap_UnmarshalJSON_InvalidJSON(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() err := m.UnmarshalJSON([]byte(`{invalid json}`)) t.AssertNE(err, nil) }) } // Test UnmarshalJSON with incompatible value types func Test_KVMap_UnmarshalJSON_TypeMismatch(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() // Valid JSON but values are strings, not ints err := m.UnmarshalJSON([]byte(`{"a":"not_a_number"}`)) // This may or may not error depending on gconv.Scan behavior // The test verifies the code path is executed _ = err }) } // Test UnmarshalValue with conversion error func Test_KVMap_UnmarshalValue_ConversionError(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() // This tests the conversion path err := m.UnmarshalValue(map[string]any{ "a": "1", "b": "2", }) // Even with string values, gconv.Scan should handle conversion t.AssertNil(err) t.Assert(m.Get("a"), 1) t.Assert(m.Get("b"), 2) }) } // Test Search with nil data func Test_KVMap_Search_NilData(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom[string, string](nil) v, found := m.Search("a") t.Assert(found, false) t.Assert(v, "") }) } // Test Get with nil data func Test_KVMap_Get_NilData(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom[string, int](nil) v := m.Get("a") t.Assert(v, 0) }) } // Test Contains with nil data func Test_KVMap_Contains_NilData(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom[string, string](nil) t.Assert(m.Contains("a"), false) }) } // Test Remove with nil data func Test_KVMap_Remove_NilData(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom[string, string](nil) v := m.Remove("a") t.Assert(v, "") }) } // Test Removes with nil data func Test_KVMap_Removes_NilData(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom[string, string](nil) m.Removes([]string{"a", "b"}) t.Assert(m.Size(), 0) }) } // Test Pop from empty map func Test_KVMap_Pop_Empty(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom[string, string](nil) k, v := m.Pop() t.Assert(k, "") t.Assert(v, "") }) } // Test Pops with size 0 func Test_KVMap_Pops_ZeroSize(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}) popped := m.Pops(0) t.AssertNil(popped) t.Assert(m.Size(), 2) }) } // Test Iterator early break func Test_KVMap_Iterator_Break(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2", "c": "3"}) count := 0 m.Iterator(func(k string, v string) bool { count++ return false // Break immediately }) t.Assert(count, 1) }) } // Test DeepCopy with safe mode func Test_KVMap_DeepCopy_Safe(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"a": "1", "b": "2"}, true) n := m.DeepCopy().(*gmap.KVMap[string, string]) t.Assert(n.Size(), 2) t.Assert(n.Get("a"), "1") }) } // Concurrent safety tests func Test_KVMap_Concurrent_Safe(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int](true) ch := make(chan int, 10) // Concurrent writes for i := 0; i < 10; i++ { go func(idx int) { m.Set(gconv.String(idx), idx) ch <- 1 }(i) } for i := 0; i < 10; i++ { <-ch } t.Assert(m.Size(), 10) }) } func Test_KVMap_Concurrent_RW(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int](true) m.Sets(map[string]int{"a": 1, "b": 2, "c": 3}) ch := make(chan int, 20) // Concurrent reads and writes for i := 0; i < 10; i++ { go func() { _ = m.Get("a") ch <- 1 }() } for i := 0; i < 10; i++ { go func(idx int) { m.Set(gconv.String(idx), idx) ch <- 1 }(i) } for i := 0; i < 20; i++ { <-ch } t.Assert(m.Size(), 13) }) } // Test concurrent GetOrSet func Test_KVMap_Concurrent_GetOrSet(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int](true) ch := make(chan int, 100) for i := 0; i < 100; i++ { go func(idx int) { m.GetOrSet("key", idx) ch <- 1 }(i) } for i := 0; i < 100; i++ { <-ch } // Only one value should be set t.Assert(m.Size(), 1) t.Assert(m.Contains("key"), true) }) } // Test concurrent SetIfNotExist func Test_KVMap_Concurrent_SetIfNotExist(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int](true) successCount := 0 ch := make(chan bool, 100) for i := 0; i < 100; i++ { go func(idx int) { ok := m.SetIfNotExist("key", idx) ch <- ok }(i) } for i := 0; i < 100; i++ { if <-ch { successCount++ } } // Only one goroutine should succeed t.Assert(successCount, 1) t.Assert(m.Size(), 1) }) } // Test doSetWithLockCheck when key exists (race condition scenario) func Test_KVMap_DoSetWithLockCheck_KeyExists(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int](true) // First, set the key using GetOrSet v := m.GetOrSet("a", 1) t.Assert(v, 1) // Second call - key exists in doSetWithLockCheck // This simulates the race condition where the key is set between Search and doSetWithLockCheck v = m.GetOrSet("a", 2) t.Assert(v, 1) }) } // Test Flip with key conversion error func Test_KVMap_Flip_KeyConversionError(t *testing.T) { gtest.C(t, func(t *gtest.T) { // Create a map where key->value conversion will fail // Using struct types that cannot be converted to each other type Key struct { ID int } type Value struct { Name string } m := gmap.NewKVMapFrom(map[Key]Value{ {ID: 1}: {Name: "a"}, }) // This should not panic, but the conversion may succeed or fail // depending on gconv.Scan implementation m.Flip() // Just verify it doesn't panic - size depends on conversion behavior }) } // Test Flip with value->key conversion success but key->value conversion failure func Test_KVMap_Flip_ValueKeyConversionError(t *testing.T) { gtest.C(t, func(t *gtest.T) { // Use int -> int where one direction might fail m := gmap.NewKVMapFrom(map[int]int{1: 10, 2: 20}) m.Flip() // Should flip successfully t.Assert(m.Contains(10), true) t.Assert(m.Contains(20), true) t.Assert(m.Get(10), 1) t.Assert(m.Get(20), 2) }) } // Test UnmarshalJSON with Scan error func Test_KVMap_UnmarshalJSON_ScanError(t *testing.T) { gtest.C(t, func(t *gtest.T) { // Create a map with int keys, but provide string keys in JSON // that cannot be properly scanned to int m := gmap.NewKVMap[int, string]() // This JSON has string keys that need to be converted to int err := m.UnmarshalJSON([]byte(`{"not_a_number":"value"}`)) // The error depends on gconv.Scan behavior // Just verify the code path is executed _ = err }) } // Test UnmarshalValue with Scan error func Test_KVMap_UnmarshalValue_ScanError(t *testing.T) { gtest.C(t, func(t *gtest.T) { // Create a map where the value type conversion will fail type CustomStruct struct { Field int } m := gmap.NewKVMap[string, CustomStruct]() // Try to unmarshal incompatible data err := m.UnmarshalValue(map[string]any{ "a": "not_a_struct", }) // The error depends on gconv.Scan behavior _ = err }) } // Test concurrent GetOrSetFunc func Test_KVMap_Concurrent_GetOrSetFunc(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int](true) ch := make(chan int, 100) counter := int32(0) for i := 0; i < 100; i++ { go func(idx int) { m.GetOrSetFunc("key", func() int { // Increment counter to track how many times the function is called return idx }) ch <- 1 }(i) } for i := 0; i < 100; i++ { <-ch } t.Assert(m.Size(), 1) _ = counter }) } // Test concurrent GetOrSetFuncLock func Test_KVMap_Concurrent_GetOrSetFuncLock(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int](true) ch := make(chan int, 100) for i := 0; i < 100; i++ { go func(idx int) { m.GetOrSetFuncLock("key", func() int { return idx }) ch <- 1 }(i) } for i := 0; i < 100; i++ { <-ch } t.Assert(m.Size(), 1) }) } // Test concurrent LockFunc func Test_KVMap_Concurrent_LockFunc(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int](true) m.Set("counter", 0) ch := make(chan int, 100) for i := 0; i < 100; i++ { go func() { m.LockFunc(func(data map[string]int) { data["counter"]++ }) ch <- 1 }() } for i := 0; i < 100; i++ { <-ch } t.Assert(m.Get("counter"), 100) }) } // Test empty map operations func Test_KVMap_EmptyMapOperations(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() // Test Keys on empty map keys := m.Keys() t.Assert(len(keys), 0) // Test Values on empty map values := m.Values() t.Assert(len(values), 0) // Test MapCopy on empty map copy := m.MapCopy() t.Assert(len(copy), 0) // Test MapStrAny on empty map strAny := m.MapStrAny() t.Assert(len(strAny), 0) }) } // Test FilterEmpty with various empty values func Test_KVMap_FilterEmpty_Various(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, any]() m.Set("nil", nil) m.Set("zero", 0) m.Set("empty_string", "") m.Set("false", false) m.Set("valid", "value") m.Set("empty_slice", []int{}) m.Set("empty_map", map[string]int{}) t.Assert(m.Size(), 7) m.FilterEmpty() t.Assert(m.Size(), 1) t.Assert(m.Contains("valid"), true) }) } // Test FilterNil with various nil values func Test_KVMap_FilterNil_Various(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, any]() m.Set("nil", nil) m.Set("zero", 0) m.Set("empty_string", "") m.Set("valid", "value") t.Assert(m.Size(), 4) m.FilterNil() t.Assert(m.Size(), 3) t.Assert(m.Contains("nil"), false) }) } // Test Clone with different safe modes func Test_KVMap_Clone_SafeMode(t *testing.T) { gtest.C(t, func(t *gtest.T) { // Clone unsafe map to safe m := gmap.NewKVMapFrom(map[string]int{"a": 1}, false) m2 := m.Clone(true) t.Assert(m2.Get("a"), 1) }) gtest.C(t, func(t *gtest.T) { // Clone safe map to unsafe m := gmap.NewKVMapFrom(map[string]int{"a": 1}, true) m2 := m.Clone(false) t.Assert(m2.Get("a"), 1) }) gtest.C(t, func(t *gtest.T) { // Clone with inherited safe mode m := gmap.NewKVMapFrom(map[string]int{"a": 1}, true) m2 := m.Clone() t.Assert(m2.Get("a"), 1) }) } // Test Diff with empty maps func Test_KVMap_Diff_Empty(t *testing.T) { gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMap[string, int]() m2 := gmap.NewKVMap[string, int]() added, removed, updated := m1.Diff(m2) t.Assert(len(added), 0) t.Assert(len(removed), 0) t.Assert(len(updated), 0) }) gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMap[string, int]() m2 := gmap.NewKVMapFrom(map[string]int{"a": 1, "b": 2}) added, removed, updated := m1.Diff(m2) t.Assert(len(added), 2) t.Assert(len(removed), 0) t.Assert(len(updated), 0) }) gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMapFrom(map[string]int{"a": 1, "b": 2}) m2 := gmap.NewKVMap[string, int]() added, removed, updated := m1.Diff(m2) t.Assert(len(added), 0) t.Assert(len(removed), 2) t.Assert(len(updated), 0) }) } // Test IsSubOf with empty maps func Test_KVMap_IsSubOf_Empty(t *testing.T) { gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMap[string, int]() m2 := gmap.NewKVMapFrom(map[string]int{"a": 1}) // Empty map is always a subset t.Assert(m1.IsSubOf(m2), true) }) gtest.C(t, func(t *gtest.T) { m1 := gmap.NewKVMapFrom(map[string]int{"a": 1}) m2 := gmap.NewKVMap[string, int]() // Non-empty map is not a subset of empty map t.Assert(m1.IsSubOf(m2), false) }) } // Test concurrent access to doSetWithLockCheck func Test_KVMap_DoSetWithLockCheck_Concurrent(t *testing.T) { gtest.C(t, func(t *gtest.T) { // This test creates a race condition where multiple goroutines // try to set the same key, triggering the "key exists" branch in doSetWithLockCheck m := gmap.NewKVMap[string, int](true) var wg sync.WaitGroup results := make([]int, 100) for i := 0; i < 100; i++ { wg.Add(1) go func(idx int) { defer wg.Done() // All goroutines try to set the same key v := m.GetOrSet("key", idx) results[idx] = v }(i) } wg.Wait() // All results should be the same (the first value that was set) firstValue := results[0] for _, v := range results { t.Assert(v, firstValue) } }) } // Test GetOrSetFunc concurrent to trigger doSetWithLockCheck key exists branch func Test_KVMap_GetOrSetFunc_Concurrent(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int](true) var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func(idx int) { defer wg.Done() m.GetOrSetFunc("key", func() int { return idx }) }(i) } wg.Wait() t.Assert(m.Size(), 1) }) } // Test SetIfNotExistFunc returning false when key exists func Test_KVMap_SetIfNotExistFunc_KeyExists(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() m.Set("a", 1) called := false ok := m.SetIfNotExistFunc("a", func() int { called = true return 2 }) t.Assert(ok, false) t.Assert(called, false) // Function should not be called if key exists t.Assert(m.Get("a"), 1) }) } // Test UnmarshalValue with nil input func Test_KVMap_UnmarshalValue_Nil(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() err := m.UnmarshalValue(nil) t.AssertNil(err) t.Assert(m.Size(), 0) }) } // Test MarshalJSON with empty map func Test_KVMap_MarshalJSON_Empty(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() b, err := m.MarshalJSON() t.AssertNil(err) t.Assert(string(b), "{}") }) } // Test String with empty map func Test_KVMap_String_Empty(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMap[string, int]() s := m.String() t.Assert(s, "{}") }) } // Test RLockFunc with concurrent access func Test_KVMap_RLockFunc_Concurrent(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]int{"a": 1, "b": 2}, true) var wg sync.WaitGroup results := make([]int, 100) for i := 0; i < 100; i++ { wg.Add(1) go func(idx int) { defer wg.Done() m.RLockFunc(func(data map[string]int) { results[idx] = data["a"] }) }(i) } wg.Wait() for _, v := range results { t.Assert(v, 1) } }) } // Test Flip with string types to cover both conversion branches func Test_KVMap_Flip_String(t *testing.T) { gtest.C(t, func(t *gtest.T) { m := gmap.NewKVMapFrom(map[string]string{"key1": "val1", "key2": "val2"}) m.Flip() t.Assert(m.Get("val1"), "key1") t.Assert(m.Get("val2"), "key2") }) } // Test TypedNil with custom nil checker for pointers func Test_KVMap_TypedNil(t *testing.T) { gtest.C(t, func(t *gtest.T) { type Student struct { Name string Age int } m1 := gmap.NewKVMap[int, *Student](true) for i := 0; i < 10; i++ { m1.GetOrSetFuncLock(i, func() *Student { if i%2 == 0 { return &Student{} } return nil }) } t.Assert(m1.Size(), 5) m2 := gmap.NewKVMap[int, *Student](true) m2.SetNilChecker(func(student *Student) bool { return student == nil }) for i := 0; i < 10; i++ { m2.GetOrSetFuncLock(i, func() *Student { if i%2 == 0 { return &Student{} } return nil }) } t.Assert(m2.Size(), 5) }) } func Test_NewKVMapWithChecker_TypedNil(t *testing.T) { gtest.C(t, func(t *gtest.T) { type Student struct { Name string Age int } m1 := gmap.NewKVMap[int, *Student](true) for i := 0; i < 10; i++ { m1.GetOrSetFuncLock(i, func() *Student { if i%2 == 0 { return &Student{} } return nil }) } t.Assert(m1.Size(), 5) m2 := gmap.NewKVMapWithChecker[int, *Student](func(student *Student) bool { return student == nil }, true) for i := 0; i < 10; i++ { m2.GetOrSetFuncLock(i, func() *Student { if i%2 == 0 { return &Student{} } return nil }) } t.Assert(m2.Size(), 5) }) }