1
2
3
4
5 package maps_test
6
7 import (
8 "bytes"
9 "encoding/binary"
10 "fmt"
11 "internal/runtime/maps"
12 "reflect"
13 "testing"
14 "unsafe"
15 )
16
17
18
19
20
21
22
23 type fuzzCommand struct {
24 Op fuzzOp
25
26
27 Key uint16
28
29
30 Elem uint32
31 }
32
33
34 var fuzzCommandSize = binary.Size(fuzzCommand{})
35
36 type fuzzOp uint8
37
38 const (
39 fuzzOpGet fuzzOp = iota
40 fuzzOpPut
41 fuzzOpDelete
42 )
43
44 func encode(fc []fuzzCommand) []byte {
45 var buf bytes.Buffer
46 if err := binary.Write(&buf, binary.LittleEndian, fc); err != nil {
47 panic(fmt.Sprintf("error writing %v: %v", fc, err))
48 }
49 return buf.Bytes()
50 }
51
52 func decode(b []byte) []fuzzCommand {
53
54
55 entries := len(b) / fuzzCommandSize
56 usefulSize := entries * fuzzCommandSize
57 b = b[:usefulSize]
58
59 fc := make([]fuzzCommand, entries)
60 buf := bytes.NewReader(b)
61 if err := binary.Read(buf, binary.LittleEndian, &fc); err != nil {
62 panic(fmt.Sprintf("error reading %v: %v", b, err))
63 }
64
65 return fc
66 }
67
68 func TestEncodeDecode(t *testing.T) {
69 fc := []fuzzCommand{
70 {
71 Op: fuzzOpPut,
72 Key: 123,
73 Elem: 456,
74 },
75 {
76 Op: fuzzOpGet,
77 Key: 123,
78 },
79 }
80
81 b := encode(fc)
82 got := decode(b)
83 if !reflect.DeepEqual(fc, got) {
84 t.Errorf("encode-decode roundtrip got %+v want %+v", got, fc)
85 }
86
87
88 b = append(b, 42)
89 got = decode(b)
90 if !reflect.DeepEqual(fc, got) {
91 t.Errorf("encode-decode (extra byte) roundtrip got %+v want %+v", got, fc)
92 }
93 }
94
95 func FuzzTable(f *testing.F) {
96
97 f.Add(encode([]fuzzCommand{
98 {
99 Op: fuzzOpPut,
100 Key: 123,
101 Elem: 456,
102 },
103 {
104 Op: fuzzOpDelete,
105 Key: 123,
106 },
107 {
108 Op: fuzzOpGet,
109 Key: 123,
110 },
111 }))
112
113
114 f.Add(encode([]fuzzCommand{
115 {
116 Op: fuzzOpPut,
117 Key: 1,
118 Elem: 101,
119 },
120 {
121 Op: fuzzOpPut,
122 Key: 2,
123 Elem: 102,
124 },
125 {
126 Op: fuzzOpPut,
127 Key: 3,
128 Elem: 103,
129 },
130 {
131 Op: fuzzOpPut,
132 Key: 4,
133 Elem: 104,
134 },
135 {
136 Op: fuzzOpPut,
137 Key: 5,
138 Elem: 105,
139 },
140 {
141 Op: fuzzOpPut,
142 Key: 6,
143 Elem: 106,
144 },
145 {
146 Op: fuzzOpPut,
147 Key: 7,
148 Elem: 107,
149 },
150 {
151 Op: fuzzOpPut,
152 Key: 8,
153 Elem: 108,
154 },
155 {
156 Op: fuzzOpGet,
157 Key: 1,
158 },
159 {
160 Op: fuzzOpDelete,
161 Key: 2,
162 },
163 {
164 Op: fuzzOpPut,
165 Key: 2,
166 Elem: 42,
167 },
168 {
169 Op: fuzzOpGet,
170 Key: 2,
171 },
172 }))
173
174 f.Fuzz(func(t *testing.T, in []byte) {
175 fc := decode(in)
176 if len(fc) == 0 {
177 return
178 }
179
180 m, typ := maps.NewTestMap[uint16, uint32](8)
181 ref := make(map[uint16]uint32)
182 for _, c := range fc {
183 switch c.Op {
184 case fuzzOpGet:
185 elemPtr, ok := m.Get(typ, unsafe.Pointer(&c.Key))
186 refElem, refOK := ref[c.Key]
187
188 if ok != refOK {
189 t.Errorf("Get(%d) got ok %v want ok %v", c.Key, ok, refOK)
190 }
191 if !ok {
192 continue
193 }
194 gotElem := *(*uint32)(elemPtr)
195 if gotElem != refElem {
196 t.Errorf("Get(%d) got %d want %d", c.Key, gotElem, refElem)
197 }
198 case fuzzOpPut:
199 m.Put(typ, unsafe.Pointer(&c.Key), unsafe.Pointer(&c.Elem))
200 ref[c.Key] = c.Elem
201 case fuzzOpDelete:
202 m.Delete(typ, unsafe.Pointer(&c.Key))
203 delete(ref, c.Key)
204 default:
205
206
207 continue
208 }
209 }
210 })
211 }
212
View as plain text