From 2171b71e920d286a9527a4dddd05c00eceb6af83 Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Mon, 20 Dec 2021 14:37:31 +0100 Subject: ascii: Add sigsum ASCII-parser and tests --- pkg/ascii/ascii_test.go | 455 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 455 insertions(+) create mode 100644 pkg/ascii/ascii_test.go (limited to 'pkg/ascii/ascii_test.go') diff --git a/pkg/ascii/ascii_test.go b/pkg/ascii/ascii_test.go new file mode 100644 index 0000000..8aee70c --- /dev/null +++ b/pkg/ascii/ascii_test.go @@ -0,0 +1,455 @@ +package ascii + +import ( + "bytes" + "reflect" + "testing" +) + +type testStruct struct { + Num uint64 `ascii/test:"num"` + Struct testStructOther + Skip uint64 + skip uint64 +} + +type testStructOther struct { + Array testArray `ascii/test:"array"` + Slice []testArray `ascii/test:"slice"` + String string `ascii/test:"string"` +} + +type testArray [2]byte + +type testStructUnsupportedType struct { + ByteSlice []byte `ascii/test:"byte_slice"` +} + +func TestSerialize(t *testing.T) { + e := NewEncoding("ascii/test", "<--", ";;") + for _, table := range []struct { + desc string + want string + err bool + i interface{} + }{ + { + desc: "invalid: not pointer to struct", + err: true, + i: testStruct{}, + }, + { + desc: "invalid: struct with invalid key", + err: true, + i: &struct { + Num uint64 `ascii/test:"num<--nom"` + }{ + Num: 1, + }, + }, + { + desc: "invalid: struct with invalid type", + err: true, + i: &testStructUnsupportedType{ + ByteSlice: []byte("hellow"), + }, + }, + { + desc: "invalid: struct with invalid type and kind", + err: true, + i: &struct { + Struct testStructUnsupportedType + }{ + Struct: testStructUnsupportedType{ + ByteSlice: []byte("hellow"), + }, + }, + }, + { + desc: "valid", + want: "num<--1;;array<--01fe;;slice<--01fe;;slice<--00ff;;string<--hellow;;", + i: &testStruct{ + Num: 1, + Struct: testStructOther{ + Array: testArray{1, 254}, + Slice: []testArray{ + testArray{1, 254}, + testArray{0, 255}, + }, + String: "hellow", + }, + }, + }, + } { + b := bytes.NewBuffer(nil) + err := e.Serialize(b, table.i) + if got, want := err != nil, table.err; got != want { + t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.desc, err) + } + if err != nil { + continue + } + if got, want := string(b.Bytes()), table.want; got != want { + t.Errorf("got buf %s but wanted %s in test %q", got, want, table.desc) + } + } +} + +func TestWrite(t *testing.T) { + e := NewEncoding("ascii/test", "<--", ";;") + for _, table := range []struct { + desc string + want string + err bool + i interface{} + }{ + { + desc: "invalid: array with wrong type", + err: true, + i: [2]string{"first", "second"}, + }, + { + desc: "invalid: slice with wrong type", + err: true, + i: []string{"first", "second"}, + }, + { + desc: "invalid: empty slice with right type", + err: true, + i: make([][2]byte, 0), + }, + { + desc: "invalid: empty string", + err: true, + i: "", + }, + { + desc: "invalid: unsupported type and kind", + err: true, + i: int32(0), + }, + { + desc: "valid: uint64", + want: "some key<--1;;", + i: uint64(1), + }, + { + desc: "valid: byte array", + want: "some key<--01fe;;", + i: [2]byte{1, 254}, + }, + { + desc: "valid: slice array", + want: "some key<--01fe;;some key<--00ff;;", + i: [][2]byte{ + [2]byte{1, 254}, + [2]byte{0, 255}, + }, + }, + { + desc: "valid: slice uint64", + want: "some key<--1;;some key<--2;;", + i: []uint64{1, 2}, + }, + { + desc: "valid: string", + want: "some key<--some value;;", + i: "some value", + }, + } { + buf := bytes.NewBuffer(nil) + err := e.write(buf, "some key", reflect.ValueOf(table.i)) + if got, want := err != nil, table.err; got != want { + t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.desc, err) + } + if err != nil { + continue + } + if got, want := string(buf.Bytes()), table.want; got != want { + t.Errorf("got buf %s but wanted %s in test %q", got, want, table.desc) + } + } +} + +func TestWriteOne(t *testing.T) { + buf := bytes.NewBuffer(nil) + e := NewEncoding("ascii/test", "<--", ";;") + e.writeOne(buf, "some key", "some value") + want := "some key<--some value;;" + if got := string(buf.Bytes()); got != want { + t.Errorf("got buf %s but wanted %s", got, want) + } +} + +func TestDeserialize(t *testing.T) { + e := NewEncoding("ascii/test", "<--", ";;") + for _, table := range []struct { + desc string + buf string + want interface{} + err bool + }{ + { + desc: "invalid: interface must be pointer to struct", + buf: ";", + want: uint64(0), + err: true, + }, + { + desc: "invalid: buffer too small", + buf: ";", + want: testStruct{}, + err: true, + }, + { + desc: "invalid: buffer must end with endOfValue", + buf: "num<--1;;string<--hellow;;array<--01fe;;slice<--01fe;;slice<--00ff^^", + want: testStruct{}, + err: true, + }, + { + desc: "invalid: missing key num", + buf: "string<--hellow;;array<--01fe;;slice<--01fe;;slice<--00ff;;", + want: testStruct{}, + err: true, + }, + { + desc: "invalid: missing key-value pair on num line", + buf: "string<--hellow;;num;;array<--01fe;;slice<--01fe;;slice<--00ff;;", + want: testStruct{}, + err: true, + }, + { + desc: "invalid: missing value for key num", + buf: "num<--;;string<--hellow;;array<--01fe;;slice<--01fe;;slice<--00ff;;", + want: testStruct{}, + err: true, + }, + { + desc: "invalid: value for key num must be digits only", + buf: "num<--+1;;string<--hellow;;array<--01fe;;slice<--01fe;;slice<--00ff;;", + want: testStruct{}, + err: true, + }, + { + desc: "invalid: missing field for key num2", + buf: "num<--1;;string<--hellow;;num2<--2;;array<--01fe;;slice<--01fe;;slice<--00ff;;", + want: testStruct{}, + err: true, + }, + { + desc: "valid", + buf: "num<--1;;string<--hellow;;array<--01fe;;slice<--01fe;;slice<--00ff;;", + want: testStruct{ + Num: 1, + Struct: testStructOther{ + Array: testArray{1, 254}, + Slice: []testArray{ + testArray{1, 254}, + testArray{0, 255}, + }, + String: "hellow", + }, + }, + }, + } { + v := reflect.New(reflect.TypeOf(table.want)) + err := e.Deserialize(bytes.NewBuffer([]byte(table.buf)), v.Interface()) + if got, want := err != nil, table.err; got != want { + t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.desc, err) + } + if err != nil { + continue + } + + v = v.Elem() // have pointer to struct, get just struct as in table + if got, want := v.Interface(), table.want; !reflect.DeepEqual(got, want) { + t.Errorf("got interface %v but wanted %v in test %q", got, want, table.desc) + } + } + +} + +func TestMapKeys(t *testing.T) { + s := testStruct{} + m := make(map[string]*someValue) + e := NewEncoding("ascii/test", "<--", ";;") + if err := e.mapKeys(s, m); err == nil { + t.Errorf("expected mapping to fail without pointer") + } + if err := e.mapKeys(&s, m); err != nil { + t.Errorf("expected mapping to succeed") + return + } + + wantKeys := []string{"num", "array", "slice", "string"} + if got, want := len(m), len(wantKeys); got != want { + t.Errorf("got %d keys, wanted %d", got, want) + } + for _, key := range wantKeys { + if _, ok := m[key]; !ok { + t.Errorf("expected key %q in map", key) + } + } +} + +func TestSetKey(t *testing.T) { + for _, table := range []struct { + desc string + key string + value string + want interface{} + err bool + }{ + { + desc: "invalid: unsupported type and kind", + key: "num", + value: "1", + want: uint32(1), + err: true, + }, + // uint64 + { + desc: "invalid: uint64: underflow", + key: "num", + value: "-1", + want: uint64(0), + err: true, + }, + { + desc: "invalid: uint64: overflow", + key: "num", + value: "18446744073709551616", + want: uint64(0), + err: true, + }, + { + desc: "invalid: uint64: not a number", + key: "num", + value: "+1", + want: uint64(0), + err: true, + }, + { + desc: "invalid: uint64: number with white space", + key: "num", + value: "1 ", + want: uint64(0), + err: true, + }, + { + desc: "valid: uint64", + key: "num", + value: "1", + want: uint64(1), + }, + // string + { + desc: "invalid: string: empty", + key: "string", + value: "", + want: "", + err: true, + }, + { + desc: "valid: string", + key: "string", + value: "hellow", + want: "hellow", + }, + // array + { + desc: "invalid: array: bad hex", + key: "array", + value: "00fE", + want: [2]byte{}, + err: true, + }, + { + desc: "invalid: array: wrong size", + key: "array", + value: "01fe", + want: [3]byte{}, + err: true, + }, + { + desc: "valid: array", + key: "num", + value: "01fe", + want: [2]byte{1, 254}, + }, + // slice + { + desc: "invalid: slice: bad type", + key: "slice", + value: "01fe", + want: []string{ + "hello", + }, + err: true, + }, + { + desc: "invalid: bad hex", + key: "slice", + value: "01FE", + want: [][2]byte{ + [2]byte{1, 254}, + }, + err: true, + }, + { + desc: "valid: slice", + key: "slice", + value: "01fe", + want: [][2]byte{ + [2]byte{1, 254}, + }, + }, + { + desc: "valid: slice", + key: "slice", + value: "4711", + want: []uint64{4711}, + }, + } { + ref := &someValue{ + v: reflect.New(reflect.TypeOf(table.want)), + } + err := setKey(ref, table.key, table.value) + if got, want := err != nil, table.err; got != want { + t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.desc, err) + } + if err != nil { + continue + } + + ref.v = ref.v.Elem() // get same type as table + if got, want := ref.v.Interface(), table.want; !reflect.DeepEqual(got, want) { + t.Errorf("got interface %v but wanted %v in test %q", got, want, table.desc) + } + if got, want := ref.ok, true; got != want { + t.Errorf("got ok %v but wanted %v in test %q", got, want, table.desc) + } + } +} + +func TestDereferenceStructPointer(t *testing.T) { + var ts testStruct + if _, err := dereferenceStructPointer(ts); err == nil { + t.Errorf("should have failed dereferencing non-pointer") + } + + var tsp *testStruct + if _, err := dereferenceStructPointer(tsp); err == nil { + t.Errorf("should have failed dereferencing nil-pointer") + } + + var ta testArray + if _, err := dereferenceStructPointer(&ta); err == nil { + t.Errorf("should have failed dereferencing non-struct pointer") + } + + if _, err := dereferenceStructPointer(&ts); err != nil { + t.Errorf("should have succeeded dereferencing pointer to struct") + } +} -- cgit v1.2.3