1package goja
2
3import (
4	"hash/maphash"
5	"math"
6	"strconv"
7	"testing"
8)
9
10func testMapHashVal(v1, v2 Value, expected bool, t *testing.T) {
11	var h maphash.Hash
12	actual := v1.hash(&h) == v2.hash(&h)
13	if actual != expected {
14		t.Fatalf("testMapHashVal failed for %v, %v", v1, v2)
15	}
16}
17
18func TestMapHash(t *testing.T) {
19	testMapHashVal(_NaN, _NaN, true, t)
20	testMapHashVal(valueTrue, valueFalse, false, t)
21	testMapHashVal(valueTrue, valueTrue, true, t)
22	testMapHashVal(intToValue(0), _negativeZero, true, t)
23	testMapHashVal(asciiString("Test"), asciiString("Test"), true, t)
24	testMapHashVal(newStringValue("Тест"), newStringValue("Тест"), true, t)
25	testMapHashVal(floatToValue(1.2345), floatToValue(1.2345), true, t)
26	testMapHashVal(SymIterator, SymToStringTag, false, t)
27	testMapHashVal(SymIterator, SymIterator, true, t)
28
29	// The following tests introduce indeterministic behaviour
30	//testMapHashVal(asciiString("Test"), asciiString("Test1"), false, t)
31	//testMapHashVal(newStringValue("Тест"), asciiString("Test"), false, t)
32	//testMapHashVal(newStringValue("Тест"), newStringValue("Тест1"), false, t)
33}
34
35func TestOrderedMap(t *testing.T) {
36	m := newOrderedMap(&maphash.Hash{})
37	for i := int64(0); i < 50; i++ {
38		m.set(intToValue(i), asciiString(strconv.FormatInt(i, 10)))
39	}
40	if m.size != 50 {
41		t.Fatalf("Unexpected size: %d", m.size)
42	}
43
44	for i := int64(0); i < 50; i++ {
45		expected := asciiString(strconv.FormatInt(i, 10))
46		actual := m.get(intToValue(i))
47		if !expected.SameAs(actual) {
48			t.Fatalf("Wrong value for %d", i)
49		}
50	}
51
52	for i := int64(0); i < 50; i += 2 {
53		if !m.remove(intToValue(i)) {
54			t.Fatalf("remove(%d) return false", i)
55		}
56	}
57	if m.size != 25 {
58		t.Fatalf("Unexpected size: %d", m.size)
59	}
60
61	iter := m.newIter()
62	count := 0
63	for {
64		entry := iter.next()
65		if entry == nil {
66			break
67		}
68		m.remove(entry.key)
69		count++
70	}
71
72	if count != 25 {
73		t.Fatalf("Unexpected iter count: %d", count)
74	}
75
76	if m.size != 0 {
77		t.Fatalf("Unexpected size: %d", m.size)
78	}
79}
80
81func TestOrderedMapCollision(t *testing.T) {
82	m := newOrderedMap(&maphash.Hash{})
83	n1 := uint64(123456789)
84	n2 := math.Float64frombits(n1)
85	n1Key := intToValue(int64(n1))
86	n2Key := floatToValue(n2)
87	m.set(n1Key, asciiString("n1"))
88	m.set(n2Key, asciiString("n2"))
89	if m.size == len(m.hashTable) {
90		t.Fatal("Expected a collision but there wasn't one")
91	}
92	if n2Val := m.get(n2Key); !asciiString("n2").SameAs(n2Val) {
93		t.Fatalf("unexpected n2Val: %v", n2Val)
94	}
95	if n1Val := m.get(n1Key); !asciiString("n1").SameAs(n1Val) {
96		t.Fatalf("unexpected nVal: %v", n1Val)
97	}
98
99	if !m.remove(n1Key) {
100		t.Fatal("removing n1Key returned false")
101	}
102	if n2Val := m.get(n2Key); !asciiString("n2").SameAs(n2Val) {
103		t.Fatalf("2: unexpected n2Val: %v", n2Val)
104	}
105}
106
107func TestOrderedMapIter(t *testing.T) {
108	m := newOrderedMap(&maphash.Hash{})
109	iter := m.newIter()
110	ent := iter.next()
111	if ent != nil {
112		t.Fatal("entry should be nil")
113	}
114	iter1 := m.newIter()
115	m.set(intToValue(1), valueTrue)
116	ent = iter.next()
117	if ent != nil {
118		t.Fatal("2: entry should be nil")
119	}
120	ent = iter1.next()
121	if ent == nil {
122		t.Fatal("entry is nil")
123	}
124	if !intToValue(1).SameAs(ent.key) {
125		t.Fatal("unexpected key")
126	}
127	if !valueTrue.SameAs(ent.value) {
128		t.Fatal("unexpected value")
129	}
130}
131
132func TestOrderedMapIterVisitAfterReAdd(t *testing.T) {
133	m := newOrderedMap(&maphash.Hash{})
134	one := intToValue(1)
135	two := intToValue(2)
136
137	m.set(one, valueTrue)
138	m.set(two, valueTrue)
139	iter := m.newIter()
140	entry := iter.next()
141	if !one.SameAs(entry.key) {
142		t.Fatalf("1: unexpected key: %v", entry.key)
143	}
144	if !m.remove(one) {
145		t.Fatal("remove returned false")
146	}
147	entry = iter.next()
148	if !two.SameAs(entry.key) {
149		t.Fatalf("2: unexpected key: %v", entry.key)
150	}
151	m.set(one, valueTrue)
152	entry = iter.next()
153	if entry == nil {
154		t.Fatal("entry is nil")
155	}
156	if !one.SameAs(entry.key) {
157		t.Fatalf("3: unexpected key: %v", entry.key)
158	}
159}
160
161func TestOrderedMapIterAddAfterClear(t *testing.T) {
162	m := newOrderedMap(&maphash.Hash{})
163	one := intToValue(1)
164	m.set(one, valueTrue)
165	iter := m.newIter()
166	iter.next()
167	m.clear()
168	m.set(one, valueTrue)
169	entry := iter.next()
170	if entry == nil {
171		t.Fatal("entry is nil")
172	}
173	if entry.key != one {
174		t.Fatalf("unexpected key: %v", entry.key)
175	}
176	entry = iter.next()
177	if entry != nil {
178		t.Fatalf("entry is not nil: %v", entry)
179	}
180}
181
182func TestOrderedMapIterDeleteCurrent(t *testing.T) {
183	m := newOrderedMap(&maphash.Hash{})
184	one := intToValue(1)
185	two := intToValue(2)
186	iter := m.newIter()
187	m.set(one, valueTrue)
188	m.set(two, valueTrue)
189	entry := iter.next()
190	if entry.key != one {
191		t.Fatalf("unexpected key: %v", entry.key)
192	}
193	m.remove(one)
194	entry = iter.next()
195	if entry.key != two {
196		t.Fatalf("2: unexpected key: %v", entry.key)
197	}
198}
199