1package csync
  2
  3import (
  4	"encoding/json"
  5	"maps"
  6	"sync"
  7	"testing"
  8
  9	"github.com/stretchr/testify/assert"
 10)
 11
 12func TestNewMap(t *testing.T) {
 13	t.Parallel()
 14
 15	m := NewMap[string, int]()
 16	assert.NotNil(t, m)
 17	assert.NotNil(t, m.inner)
 18	assert.Equal(t, 0, m.Len())
 19}
 20
 21func TestNewMapFrom(t *testing.T) {
 22	t.Parallel()
 23
 24	original := map[string]int{
 25		"key1": 1,
 26		"key2": 2,
 27	}
 28
 29	m := NewMapFrom(original)
 30	assert.NotNil(t, m)
 31	assert.Equal(t, original, m.inner)
 32	assert.Equal(t, 2, m.Len())
 33
 34	value, ok := m.Get("key1")
 35	assert.True(t, ok)
 36	assert.Equal(t, 1, value)
 37}
 38
 39func TestMap_Set(t *testing.T) {
 40	t.Parallel()
 41
 42	m := NewMap[string, int]()
 43
 44	m.Set("key1", 42)
 45	value, ok := m.Get("key1")
 46	assert.True(t, ok)
 47	assert.Equal(t, 42, value)
 48	assert.Equal(t, 1, m.Len())
 49
 50	m.Set("key1", 100)
 51	value, ok = m.Get("key1")
 52	assert.True(t, ok)
 53	assert.Equal(t, 100, value)
 54	assert.Equal(t, 1, m.Len())
 55}
 56
 57func TestMap_Get(t *testing.T) {
 58	t.Parallel()
 59
 60	m := NewMap[string, int]()
 61
 62	value, ok := m.Get("nonexistent")
 63	assert.False(t, ok)
 64	assert.Equal(t, 0, value)
 65
 66	m.Set("key1", 42)
 67	value, ok = m.Get("key1")
 68	assert.True(t, ok)
 69	assert.Equal(t, 42, value)
 70}
 71
 72func TestMap_Del(t *testing.T) {
 73	t.Parallel()
 74
 75	m := NewMap[string, int]()
 76	m.Set("key1", 42)
 77	m.Set("key2", 100)
 78
 79	assert.Equal(t, 2, m.Len())
 80
 81	m.Del("key1")
 82	_, ok := m.Get("key1")
 83	assert.False(t, ok)
 84	assert.Equal(t, 1, m.Len())
 85
 86	value, ok := m.Get("key2")
 87	assert.True(t, ok)
 88	assert.Equal(t, 100, value)
 89
 90	m.Del("nonexistent")
 91	assert.Equal(t, 1, m.Len())
 92}
 93
 94func TestMap_Len(t *testing.T) {
 95	t.Parallel()
 96
 97	m := NewMap[string, int]()
 98	assert.Equal(t, 0, m.Len())
 99
100	m.Set("key1", 1)
101	assert.Equal(t, 1, m.Len())
102
103	m.Set("key2", 2)
104	assert.Equal(t, 2, m.Len())
105
106	m.Del("key1")
107	assert.Equal(t, 1, m.Len())
108
109	m.Del("key2")
110	assert.Equal(t, 0, m.Len())
111}
112
113func TestMap_Seq2(t *testing.T) {
114	t.Parallel()
115
116	m := NewMap[string, int]()
117	m.Set("key1", 1)
118	m.Set("key2", 2)
119	m.Set("key3", 3)
120
121	collected := maps.Collect(m.Seq2())
122
123	assert.Equal(t, 3, len(collected))
124	assert.Equal(t, 1, collected["key1"])
125	assert.Equal(t, 2, collected["key2"])
126	assert.Equal(t, 3, collected["key3"])
127}
128
129func TestMap_Seq2_EarlyReturn(t *testing.T) {
130	t.Parallel()
131
132	m := NewMap[string, int]()
133	m.Set("key1", 1)
134	m.Set("key2", 2)
135	m.Set("key3", 3)
136
137	count := 0
138	for range m.Seq2() {
139		count++
140		if count == 2 {
141			break
142		}
143	}
144
145	assert.Equal(t, 2, count)
146}
147
148func TestMap_Seq2_EmptyMap(t *testing.T) {
149	t.Parallel()
150
151	m := NewMap[string, int]()
152
153	count := 0
154	for range m.Seq2() {
155		count++
156	}
157
158	assert.Equal(t, 0, count)
159}
160
161func TestMap_MarshalJSON(t *testing.T) {
162	t.Parallel()
163
164	m := NewMap[string, int]()
165	m.Set("key1", 1)
166	m.Set("key2", 2)
167
168	data, err := json.Marshal(m)
169	assert.NoError(t, err)
170
171	result := &Map[string, int]{}
172	err = json.Unmarshal(data, result)
173	assert.NoError(t, err)
174	assert.Equal(t, 2, result.Len())
175	v1, _ := result.Get("key1")
176	v2, _ := result.Get("key2")
177	assert.Equal(t, 1, v1)
178	assert.Equal(t, 2, v2)
179}
180
181func TestMap_MarshalJSON_EmptyMap(t *testing.T) {
182	t.Parallel()
183
184	m := NewMap[string, int]()
185
186	data, err := json.Marshal(m)
187	assert.NoError(t, err)
188	assert.Equal(t, "{}", string(data))
189}
190
191func TestMap_UnmarshalJSON(t *testing.T) {
192	t.Parallel()
193
194	jsonData := `{"key1": 1, "key2": 2}`
195
196	m := NewMap[string, int]()
197	err := json.Unmarshal([]byte(jsonData), m)
198	assert.NoError(t, err)
199
200	assert.Equal(t, 2, m.Len())
201	value, ok := m.Get("key1")
202	assert.True(t, ok)
203	assert.Equal(t, 1, value)
204
205	value, ok = m.Get("key2")
206	assert.True(t, ok)
207	assert.Equal(t, 2, value)
208}
209
210func TestMap_UnmarshalJSON_EmptyJSON(t *testing.T) {
211	t.Parallel()
212
213	jsonData := `{}`
214
215	m := NewMap[string, int]()
216	err := json.Unmarshal([]byte(jsonData), m)
217	assert.NoError(t, err)
218	assert.Equal(t, 0, m.Len())
219}
220
221func TestMap_UnmarshalJSON_InvalidJSON(t *testing.T) {
222	t.Parallel()
223
224	jsonData := `{"key1": 1, "key2":}`
225
226	m := NewMap[string, int]()
227	err := json.Unmarshal([]byte(jsonData), m)
228	assert.Error(t, err)
229}
230
231func TestMap_UnmarshalJSON_OverwritesExistingData(t *testing.T) {
232	t.Parallel()
233
234	m := NewMap[string, int]()
235	m.Set("existing", 999)
236
237	jsonData := `{"key1": 1, "key2": 2}`
238	err := json.Unmarshal([]byte(jsonData), m)
239	assert.NoError(t, err)
240
241	assert.Equal(t, 2, m.Len())
242	_, ok := m.Get("existing")
243	assert.False(t, ok)
244
245	value, ok := m.Get("key1")
246	assert.True(t, ok)
247	assert.Equal(t, 1, value)
248}
249
250func TestMap_JSONRoundTrip(t *testing.T) {
251	t.Parallel()
252
253	original := NewMap[string, int]()
254	original.Set("key1", 1)
255	original.Set("key2", 2)
256	original.Set("key3", 3)
257
258	data, err := json.Marshal(original)
259	assert.NoError(t, err)
260
261	restored := NewMap[string, int]()
262	err = json.Unmarshal(data, restored)
263	assert.NoError(t, err)
264
265	assert.Equal(t, original.Len(), restored.Len())
266
267	for k, v := range original.Seq2() {
268		restoredValue, ok := restored.Get(k)
269		assert.True(t, ok)
270		assert.Equal(t, v, restoredValue)
271	}
272}
273
274func TestMap_ConcurrentAccess(t *testing.T) {
275	t.Parallel()
276
277	m := NewMap[int, int]()
278	const numGoroutines = 100
279	const numOperations = 100
280
281	var wg sync.WaitGroup
282	wg.Add(numGoroutines)
283
284	for i := range numGoroutines {
285		go func(id int) {
286			defer wg.Done()
287			for j := range numOperations {
288				key := id*numOperations + j
289				m.Set(key, key*2)
290				value, ok := m.Get(key)
291				assert.True(t, ok)
292				assert.Equal(t, key*2, value)
293			}
294		}(i)
295	}
296
297	wg.Wait()
298
299	assert.Equal(t, numGoroutines*numOperations, m.Len())
300}
301
302func TestMap_ConcurrentReadWrite(t *testing.T) {
303	t.Parallel()
304
305	m := NewMap[int, int]()
306	const numReaders = 50
307	const numWriters = 50
308	const numOperations = 100
309
310	for i := range 1000 {
311		m.Set(i, i)
312	}
313
314	var wg sync.WaitGroup
315	wg.Add(numReaders + numWriters)
316
317	for range numReaders {
318		go func() {
319			defer wg.Done()
320			for j := range numOperations {
321				key := j % 1000
322				value, ok := m.Get(key)
323				if ok {
324					assert.Equal(t, key, value)
325				}
326				_ = m.Len()
327			}
328		}()
329	}
330
331	for i := range numWriters {
332		go func(id int) {
333			defer wg.Done()
334			for j := range numOperations {
335				key := 1000 + id*numOperations + j
336				m.Set(key, key)
337				if j%10 == 0 {
338					m.Del(key)
339				}
340			}
341		}(i)
342	}
343
344	wg.Wait()
345}
346
347func TestMap_ConcurrentSeq2(t *testing.T) {
348	t.Parallel()
349
350	m := NewMap[int, int]()
351	for i := range 100 {
352		m.Set(i, i*2)
353	}
354
355	var wg sync.WaitGroup
356	const numIterators = 10
357
358	wg.Add(numIterators)
359	for range numIterators {
360		go func() {
361			defer wg.Done()
362			count := 0
363			for k, v := range m.Seq2() {
364				assert.Equal(t, k*2, v)
365				count++
366			}
367			assert.Equal(t, 100, count)
368		}()
369	}
370
371	wg.Wait()
372}
373
374func TestMap_TypeSafety(t *testing.T) {
375	t.Parallel()
376
377	stringIntMap := NewMap[string, int]()
378	stringIntMap.Set("key", 42)
379	value, ok := stringIntMap.Get("key")
380	assert.True(t, ok)
381	assert.Equal(t, 42, value)
382
383	intStringMap := NewMap[int, string]()
384	intStringMap.Set(42, "value")
385	strValue, ok := intStringMap.Get(42)
386	assert.True(t, ok)
387	assert.Equal(t, "value", strValue)
388
389	structMap := NewMap[string, struct{ Name string }]()
390	structMap.Set("key", struct{ Name string }{Name: "test"})
391	structValue, ok := structMap.Get("key")
392	assert.True(t, ok)
393	assert.Equal(t, "test", structValue.Name)
394}
395
396func TestMap_InterfaceCompliance(t *testing.T) {
397	t.Parallel()
398
399	var _ json.Marshaler = &Map[string, any]{}
400	var _ json.Unmarshaler = &Map[string, any]{}
401}
402
403func BenchmarkMap_Set(b *testing.B) {
404	m := NewMap[int, int]()
405
406	for i := 0; b.Loop(); i++ {
407		m.Set(i, i*2)
408	}
409}
410
411func BenchmarkMap_Get(b *testing.B) {
412	m := NewMap[int, int]()
413	for i := range 1000 {
414		m.Set(i, i*2)
415	}
416
417	for i := 0; b.Loop(); i++ {
418		m.Get(i % 1000)
419	}
420}
421
422func BenchmarkMap_Seq2(b *testing.B) {
423	m := NewMap[int, int]()
424	for i := range 1000 {
425		m.Set(i, i*2)
426	}
427
428	for b.Loop() {
429		for range m.Seq2() {
430		}
431	}
432}
433
434func BenchmarkMap_ConcurrentReadWrite(b *testing.B) {
435	m := NewMap[int, int]()
436	for i := range 1000 {
437		m.Set(i, i*2)
438	}
439
440	b.ResetTimer()
441	b.RunParallel(func(pb *testing.PB) {
442		i := 0
443		for pb.Next() {
444			if i%2 == 0 {
445				m.Get(i % 1000)
446			} else {
447				m.Set(i+1000, i*2)
448			}
449			i++
450		}
451	})
452}