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	var result map[string]int
172	err = json.Unmarshal(data, &result)
173	assert.NoError(t, err)
174	assert.Equal(t, 2, len(result))
175	assert.Equal(t, 1, result["key1"])
176	assert.Equal(t, 2, result["key2"])
177}
178
179func TestMap_MarshalJSON_EmptyMap(t *testing.T) {
180	t.Parallel()
181
182	m := NewMap[string, int]()
183
184	data, err := json.Marshal(m)
185	assert.NoError(t, err)
186	assert.Equal(t, "{}", string(data))
187}
188
189func TestMap_UnmarshalJSON(t *testing.T) {
190	t.Parallel()
191
192	jsonData := `{"key1": 1, "key2": 2}`
193
194	m := NewMap[string, int]()
195	err := json.Unmarshal([]byte(jsonData), m)
196	assert.NoError(t, err)
197
198	assert.Equal(t, 2, m.Len())
199	value, ok := m.Get("key1")
200	assert.True(t, ok)
201	assert.Equal(t, 1, value)
202
203	value, ok = m.Get("key2")
204	assert.True(t, ok)
205	assert.Equal(t, 2, value)
206}
207
208func TestMap_UnmarshalJSON_EmptyJSON(t *testing.T) {
209	t.Parallel()
210
211	jsonData := `{}`
212
213	m := NewMap[string, int]()
214	err := json.Unmarshal([]byte(jsonData), m)
215	assert.NoError(t, err)
216	assert.Equal(t, 0, m.Len())
217}
218
219func TestMap_UnmarshalJSON_InvalidJSON(t *testing.T) {
220	t.Parallel()
221
222	jsonData := `{"key1": 1, "key2":}`
223
224	m := NewMap[string, int]()
225	err := json.Unmarshal([]byte(jsonData), m)
226	assert.Error(t, err)
227}
228
229func TestMap_UnmarshalJSON_OverwritesExistingData(t *testing.T) {
230	t.Parallel()
231
232	m := NewMap[string, int]()
233	m.Set("existing", 999)
234
235	jsonData := `{"key1": 1, "key2": 2}`
236	err := json.Unmarshal([]byte(jsonData), m)
237	assert.NoError(t, err)
238
239	assert.Equal(t, 2, m.Len())
240	_, ok := m.Get("existing")
241	assert.False(t, ok)
242
243	value, ok := m.Get("key1")
244	assert.True(t, ok)
245	assert.Equal(t, 1, value)
246}
247
248func TestMap_JSONRoundTrip(t *testing.T) {
249	t.Parallel()
250
251	original := NewMap[string, int]()
252	original.Set("key1", 1)
253	original.Set("key2", 2)
254	original.Set("key3", 3)
255
256	data, err := json.Marshal(original)
257	assert.NoError(t, err)
258
259	restored := NewMap[string, int]()
260	err = json.Unmarshal(data, restored)
261	assert.NoError(t, err)
262
263	assert.Equal(t, original.Len(), restored.Len())
264
265	for k, v := range original.Seq2() {
266		restoredValue, ok := restored.Get(k)
267		assert.True(t, ok)
268		assert.Equal(t, v, restoredValue)
269	}
270}
271
272func TestMap_ConcurrentAccess(t *testing.T) {
273	t.Parallel()
274
275	m := NewMap[int, int]()
276	const numGoroutines = 100
277	const numOperations = 100
278
279	var wg sync.WaitGroup
280	wg.Add(numGoroutines)
281
282	for i := range numGoroutines {
283		go func(id int) {
284			defer wg.Done()
285			for j := range numOperations {
286				key := id*numOperations + j
287				m.Set(key, key*2)
288				value, ok := m.Get(key)
289				assert.True(t, ok)
290				assert.Equal(t, key*2, value)
291			}
292		}(i)
293	}
294
295	wg.Wait()
296
297	assert.Equal(t, numGoroutines*numOperations, m.Len())
298}
299
300func TestMap_ConcurrentReadWrite(t *testing.T) {
301	t.Parallel()
302
303	m := NewMap[int, int]()
304	const numReaders = 50
305	const numWriters = 50
306	const numOperations = 100
307
308	for i := range 1000 {
309		m.Set(i, i)
310	}
311
312	var wg sync.WaitGroup
313	wg.Add(numReaders + numWriters)
314
315	for range numReaders {
316		go func() {
317			defer wg.Done()
318			for j := range numOperations {
319				key := j % 1000
320				value, ok := m.Get(key)
321				if ok {
322					assert.Equal(t, key, value)
323				}
324				_ = m.Len()
325			}
326		}()
327	}
328
329	for i := range numWriters {
330		go func(id int) {
331			defer wg.Done()
332			for j := range numOperations {
333				key := 1000 + id*numOperations + j
334				m.Set(key, key)
335				if j%10 == 0 {
336					m.Del(key)
337				}
338			}
339		}(i)
340	}
341
342	wg.Wait()
343}
344
345func TestMap_ConcurrentSeq2(t *testing.T) {
346	t.Parallel()
347
348	m := NewMap[int, int]()
349	for i := range 100 {
350		m.Set(i, i*2)
351	}
352
353	var wg sync.WaitGroup
354	const numIterators = 10
355
356	wg.Add(numIterators)
357	for range numIterators {
358		go func() {
359			defer wg.Done()
360			count := 0
361			for k, v := range m.Seq2() {
362				assert.Equal(t, k*2, v)
363				count++
364			}
365			assert.Equal(t, 100, count)
366		}()
367	}
368
369	wg.Wait()
370}
371
372func TestMap_TypeSafety(t *testing.T) {
373	t.Parallel()
374
375	stringIntMap := NewMap[string, int]()
376	stringIntMap.Set("key", 42)
377	value, ok := stringIntMap.Get("key")
378	assert.True(t, ok)
379	assert.Equal(t, 42, value)
380
381	intStringMap := NewMap[int, string]()
382	intStringMap.Set(42, "value")
383	strValue, ok := intStringMap.Get(42)
384	assert.True(t, ok)
385	assert.Equal(t, "value", strValue)
386
387	structMap := NewMap[string, struct{ Name string }]()
388	structMap.Set("key", struct{ Name string }{Name: "test"})
389	structValue, ok := structMap.Get("key")
390	assert.True(t, ok)
391	assert.Equal(t, "test", structValue.Name)
392}
393
394func TestMap_InterfaceCompliance(t *testing.T) {
395	t.Parallel()
396
397	var _ json.Marshaler = &Map[string, any]{}
398	var _ json.Unmarshaler = &Map[string, any]{}
399}
400
401func BenchmarkMap_Set(b *testing.B) {
402	m := NewMap[int, int]()
403
404	for i := 0; b.Loop(); i++ {
405		m.Set(i, i*2)
406	}
407}
408
409func BenchmarkMap_Get(b *testing.B) {
410	m := NewMap[int, int]()
411	for i := range 1000 {
412		m.Set(i, i*2)
413	}
414
415	for i := 0; b.Loop(); i++ {
416		m.Get(i % 1000)
417	}
418}
419
420func BenchmarkMap_Seq2(b *testing.B) {
421	m := NewMap[int, int]()
422	for i := range 1000 {
423		m.Set(i, i*2)
424	}
425
426	for b.Loop() {
427		for range m.Seq2() {
428		}
429	}
430}
431
432func BenchmarkMap_ConcurrentReadWrite(b *testing.B) {
433	m := NewMap[int, int]()
434	for i := range 1000 {
435		m.Set(i, i*2)
436	}
437
438	b.ResetTimer()
439	b.RunParallel(func(pb *testing.PB) {
440		i := 0
441		for pb.Next() {
442			if i%2 == 0 {
443				m.Get(i % 1000)
444			} else {
445				m.Set(i+1000, i*2)
446			}
447			i++
448		}
449	})
450}