Skip to content

Commit 866d1fc

Browse files
wip: add test to orderedmap
1 parent fdcf46e commit 866d1fc

File tree

2 files changed

+238
-1
lines changed

2 files changed

+238
-1
lines changed

Diff for: internal/orderedmap/orderedmap.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,18 @@ import (
2424
// Map is a map that keeps ordering insertion.
2525
type Map[K any, V any] interface {
2626
Get(K) V
27+
GetOk(key K) (V, bool)
2728
Set(K, V)
29+
Size() int
30+
ContainsKey(key K) bool
2831
Keys() []K
2932
Merge(...Map[K, V]) Map[K, V]
3033
SortKeys(f func(x, y K) int)
3134
SortStableKeys(f func(x, y K) int)
35+
Values() []V
36+
Clone() Map[K, V]
37+
Remove(key K)
38+
MarshalJSON() ([]byte, error)
3239
}
3340

3441
// NewWithConversionFunc creates a map using the given conversion function
@@ -43,7 +50,7 @@ func NewWithConversionFunc[K any, V any, C comparable](conv func(K) C) Map[K, V]
4350
}
4451

4552
// New creates a map
46-
func New[K comparable, V any]() *mapImpl[K, V, K] {
53+
func New[K comparable, V any]() Map[K, V] {
4754
return &mapImpl[K, V, K]{
4855
conv: func(in K) K { return in }, // identity
4956
kv: map[K]V{},

Diff for: internal/orderedmap/orderedmap_test.go

+230
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package orderedmap_test
17+
18+
import (
19+
"testing"
20+
21+
"github.com/arduino/arduino-cli/internal/orderedmap"
22+
"github.com/stretchr/testify/require"
23+
)
24+
25+
func TestGet(t *testing.T) {
26+
t.Run("the key is a string", func(t *testing.T) {
27+
m := orderedmap.New[string, int]()
28+
29+
require.Zero(t, m.Get("not-existing-key"))
30+
v, ok := m.GetOk("not-existing-key")
31+
require.Zero(t, v)
32+
require.False(t, ok)
33+
34+
m.Set("existing-key", 1)
35+
require.Equal(t, 1, m.Get("existing-key"))
36+
v, ok = m.GetOk("existing-key")
37+
require.Equal(t, 1, v)
38+
require.True(t, ok)
39+
40+
// test empty key
41+
m.Set("", 2)
42+
require.Equal(t, 2, m.Get(""))
43+
v, ok = m.GetOk("")
44+
require.Equal(t, 2, v)
45+
require.True(t, ok)
46+
})
47+
48+
t.Run("the key is int", func(t *testing.T) {
49+
m := orderedmap.New[int, int]()
50+
51+
require.Equal(t, 0, m.Get(1))
52+
v, ok := m.GetOk(1)
53+
require.Zero(t, v)
54+
require.False(t, ok)
55+
56+
m.Set(1, 1)
57+
require.Equal(t, 1, m.Get(1))
58+
v, ok = m.GetOk(1)
59+
require.Equal(t, 1, v)
60+
require.True(t, ok)
61+
62+
// test empty key
63+
m.Set(0, 2)
64+
require.Equal(t, 2, m.Get(0))
65+
v, ok = m.GetOk(0)
66+
require.Equal(t, 2, v)
67+
require.True(t, ok)
68+
})
69+
70+
t.Run("the key is a pointer", func(t *testing.T) {
71+
m := orderedmap.New[*string, int]()
72+
73+
notExistingKey := toPtr("not-existing-key")
74+
require.Equal(t, 0, m.Get(notExistingKey))
75+
v, ok := m.GetOk(notExistingKey)
76+
require.Zero(t, v)
77+
require.False(t, ok)
78+
79+
existingKey := toPtr("existing-key")
80+
m.Set(existingKey, 1)
81+
require.Equal(t, 1, m.Get(existingKey))
82+
v, ok = m.GetOk(existingKey)
83+
require.Equal(t, 1, v)
84+
require.True(t, ok)
85+
86+
// Using a different pointer with the same value returns no result
87+
require.Equal(t, 0, m.Get(toPtr("existing-key")))
88+
v, ok = m.GetOk(toPtr("existing-key"))
89+
require.Zero(t, v)
90+
require.False(t, ok)
91+
92+
// test empty key
93+
m.Set(nil, 2)
94+
require.Equal(t, 2, m.Get(nil))
95+
v, ok = m.GetOk(nil)
96+
require.Equal(t, 2, v)
97+
require.True(t, ok)
98+
})
99+
100+
t.Run("custom comparable key", func(t *testing.T) {
101+
type A struct {
102+
b []byte
103+
}
104+
m := orderedmap.NewWithConversionFunc[*A, int, string](
105+
func(a *A) string {
106+
if a == nil {
107+
return ""
108+
}
109+
return string(a.b)
110+
},
111+
)
112+
require.Zero(t, m.Get(&A{}))
113+
require.Zero(t, m.Get(nil))
114+
115+
// Here we're using the conversion function to set the key, using a different
116+
// pointer to retreive the value works.
117+
m.Set(&A{b: []byte{60, 61, 62}}, 1)
118+
require.Equal(t, 1, m.Get(&A{b: []byte{60, 61, 62}}))
119+
120+
m.Set(nil, 2)
121+
require.Equal(t, 2, m.Get(nil))
122+
})
123+
}
124+
125+
func TestSet(t *testing.T) {
126+
t.Run("insert 3 differnt keys", func(t *testing.T) {
127+
m := orderedmap.New[string, int]()
128+
m.Set("a", 1)
129+
m.Set("b", 2)
130+
m.Set("c", 3)
131+
require.Equal(t, 1, m.Get("a"))
132+
require.Equal(t, 2, m.Get("b"))
133+
require.Equal(t, 3, m.Get("c"))
134+
})
135+
t.Run("insert equal keys", func(t *testing.T) {
136+
m := orderedmap.New[string, int]()
137+
m.Set("a", 1)
138+
m.Set("a", 2)
139+
require.Equal(t, 2, m.Get("a"))
140+
})
141+
}
142+
143+
func TestSize(t *testing.T) {
144+
t.Run("empty map", func(t *testing.T) {
145+
m := orderedmap.New[string, bool]()
146+
require.Zero(t, m.Size())
147+
})
148+
t.Run("one element", func(t *testing.T) {
149+
m := orderedmap.New[string, bool]()
150+
m.Set("a", true)
151+
require.Equal(t, 1, m.Size())
152+
})
153+
t.Run("three elements", func(t *testing.T) {
154+
m := orderedmap.New[string, bool]()
155+
m.Set("a", true)
156+
m.Set("b", true)
157+
m.Set("c", true)
158+
require.Equal(t, 3, m.Size())
159+
})
160+
t.Run("insert same keys result in size 1", func(t *testing.T) {
161+
m := orderedmap.New[string, bool]()
162+
m.Set("a", true)
163+
m.Set("a", false)
164+
m.Set("a", true)
165+
require.Equal(t, 1, m.Size())
166+
})
167+
}
168+
169+
func TestKeys(t *testing.T) {
170+
t.Run("empty map", func(t *testing.T) {
171+
m := orderedmap.New[string, bool]()
172+
require.Empty(t, m.Keys())
173+
})
174+
t.Run("one element", func(t *testing.T) {
175+
m := orderedmap.New[string, bool]()
176+
m.Set("a", true)
177+
require.Len(t, m.Keys(), 1)
178+
})
179+
t.Run("keys respect order of insertion", func(t *testing.T) {
180+
m := orderedmap.New[string, bool]()
181+
m.Set("a", true)
182+
m.Set("b", true)
183+
m.Set("c", true)
184+
require.Equal(t, []string{"a", "b", "c"}, m.Keys())
185+
})
186+
t.Run("replacing a key changes the ordering", func(t *testing.T) {
187+
m := orderedmap.New[string, bool]()
188+
m.Set("a", true)
189+
m.Set("b", true)
190+
m.Set("a", false)
191+
require.Equal(t, []string{"b", "a"}, m.Keys())
192+
})
193+
t.Run("delete a key", func(t *testing.T) {
194+
m := orderedmap.New[string, bool]()
195+
m.Set("a", true)
196+
m.Set("b", true)
197+
m.Remove("a")
198+
require.Equal(t, []string{"b"}, m.Keys())
199+
})
200+
}
201+
202+
func TestRemove(t *testing.T) {
203+
t.Run("key doesn't exist", func(t *testing.T) {
204+
m := orderedmap.New[string, bool]()
205+
require.Zero(t, m.Get("not-existing-key"))
206+
m.Remove("not-existing-key")
207+
require.Zero(t, m.Get("not-existing-key"))
208+
})
209+
t.Run("key exist", func(t *testing.T) {
210+
m := orderedmap.New[string, bool]()
211+
m.Set("a", true)
212+
require.True(t, m.Get("a"))
213+
214+
m.Remove("a")
215+
require.False(t, m.Get("a"))
216+
})
217+
t.Run("key deletion doesn't affect other keys", func(t *testing.T) {
218+
m := orderedmap.New[string, bool]()
219+
m.Set("a", true)
220+
m.Set("b", true)
221+
m.Remove("a")
222+
require.True(t, m.Get("b"))
223+
_, ok := m.GetOk("a")
224+
require.False(t, ok)
225+
})
226+
}
227+
228+
func toPtr[V any](v V) *V {
229+
return &v
230+
}

0 commit comments

Comments
 (0)