| | |
| | |
| | |
| |
|
| | package maps_test |
| |
|
| | import ( |
| | "bytes" |
| | "encoding/binary" |
| | "fmt" |
| | "internal/runtime/maps" |
| | "reflect" |
| | "testing" |
| | "unsafe" |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | type fuzzCommand struct { |
| | Op fuzzOp |
| |
|
| | |
| | Key uint16 |
| |
|
| | |
| | Elem uint32 |
| | } |
| |
|
| | |
| | var fuzzCommandSize = binary.Size(fuzzCommand{}) |
| |
|
| | type fuzzOp uint8 |
| |
|
| | const ( |
| | fuzzOpGet fuzzOp = iota |
| | fuzzOpPut |
| | fuzzOpDelete |
| | ) |
| |
|
| | func encode(fc []fuzzCommand) []byte { |
| | var buf bytes.Buffer |
| | if err := binary.Write(&buf, binary.LittleEndian, fc); err != nil { |
| | panic(fmt.Sprintf("error writing %v: %v", fc, err)) |
| | } |
| | return buf.Bytes() |
| | } |
| |
|
| | func decode(b []byte) []fuzzCommand { |
| | |
| | |
| | entries := len(b) / fuzzCommandSize |
| | usefulSize := entries * fuzzCommandSize |
| | b = b[:usefulSize] |
| |
|
| | fc := make([]fuzzCommand, entries) |
| | buf := bytes.NewReader(b) |
| | if err := binary.Read(buf, binary.LittleEndian, &fc); err != nil { |
| | panic(fmt.Sprintf("error reading %v: %v", b, err)) |
| | } |
| |
|
| | return fc |
| | } |
| |
|
| | func TestEncodeDecode(t *testing.T) { |
| | fc := []fuzzCommand{ |
| | { |
| | Op: fuzzOpPut, |
| | Key: 123, |
| | Elem: 456, |
| | }, |
| | { |
| | Op: fuzzOpGet, |
| | Key: 123, |
| | }, |
| | } |
| |
|
| | b := encode(fc) |
| | got := decode(b) |
| | if !reflect.DeepEqual(fc, got) { |
| | t.Errorf("encode-decode roundtrip got %+v want %+v", got, fc) |
| | } |
| |
|
| | |
| | b = append(b, 42) |
| | got = decode(b) |
| | if !reflect.DeepEqual(fc, got) { |
| | t.Errorf("encode-decode (extra byte) roundtrip got %+v want %+v", got, fc) |
| | } |
| | } |
| |
|
| | func FuzzTable(f *testing.F) { |
| | |
| | f.Add(encode([]fuzzCommand{ |
| | { |
| | Op: fuzzOpPut, |
| | Key: 123, |
| | Elem: 456, |
| | }, |
| | { |
| | Op: fuzzOpDelete, |
| | Key: 123, |
| | }, |
| | { |
| | Op: fuzzOpGet, |
| | Key: 123, |
| | }, |
| | })) |
| |
|
| | |
| | f.Add(encode([]fuzzCommand{ |
| | { |
| | Op: fuzzOpPut, |
| | Key: 1, |
| | Elem: 101, |
| | }, |
| | { |
| | Op: fuzzOpPut, |
| | Key: 2, |
| | Elem: 102, |
| | }, |
| | { |
| | Op: fuzzOpPut, |
| | Key: 3, |
| | Elem: 103, |
| | }, |
| | { |
| | Op: fuzzOpPut, |
| | Key: 4, |
| | Elem: 104, |
| | }, |
| | { |
| | Op: fuzzOpPut, |
| | Key: 5, |
| | Elem: 105, |
| | }, |
| | { |
| | Op: fuzzOpPut, |
| | Key: 6, |
| | Elem: 106, |
| | }, |
| | { |
| | Op: fuzzOpPut, |
| | Key: 7, |
| | Elem: 107, |
| | }, |
| | { |
| | Op: fuzzOpPut, |
| | Key: 8, |
| | Elem: 108, |
| | }, |
| | { |
| | Op: fuzzOpGet, |
| | Key: 1, |
| | }, |
| | { |
| | Op: fuzzOpDelete, |
| | Key: 2, |
| | }, |
| | { |
| | Op: fuzzOpPut, |
| | Key: 2, |
| | Elem: 42, |
| | }, |
| | { |
| | Op: fuzzOpGet, |
| | Key: 2, |
| | }, |
| | })) |
| |
|
| | f.Fuzz(func(t *testing.T, in []byte) { |
| | fc := decode(in) |
| | if len(fc) == 0 { |
| | return |
| | } |
| |
|
| | m, typ := maps.NewTestMap[uint16, uint32](8) |
| | ref := make(map[uint16]uint32) |
| | for _, c := range fc { |
| | switch c.Op { |
| | case fuzzOpGet: |
| | elemPtr, ok := m.Get(typ, unsafe.Pointer(&c.Key)) |
| | refElem, refOK := ref[c.Key] |
| |
|
| | if ok != refOK { |
| | t.Errorf("Get(%d) got ok %v want ok %v", c.Key, ok, refOK) |
| | } |
| | if !ok { |
| | continue |
| | } |
| | gotElem := *(*uint32)(elemPtr) |
| | if gotElem != refElem { |
| | t.Errorf("Get(%d) got %d want %d", c.Key, gotElem, refElem) |
| | } |
| | case fuzzOpPut: |
| | m.Put(typ, unsafe.Pointer(&c.Key), unsafe.Pointer(&c.Elem)) |
| | ref[c.Key] = c.Elem |
| | case fuzzOpDelete: |
| | m.Delete(typ, unsafe.Pointer(&c.Key)) |
| | delete(ref, c.Key) |
| | default: |
| | |
| | |
| | continue |
| | } |
| | } |
| | }) |
| | } |
| |
|