diff options
Diffstat (limited to 'pkg/binary/binary_test.go')
-rw-r--r-- | pkg/binary/binary_test.go | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/pkg/binary/binary_test.go b/pkg/binary/binary_test.go new file mode 100644 index 000000000..4d609a438 --- /dev/null +++ b/pkg/binary/binary_test.go @@ -0,0 +1,266 @@ +// Copyright 2018 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package binary + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "reflect" + "strings" + "testing" +) + +func newInt32(i int32) *int32 { + return &i +} + +func TestSize(t *testing.T) { + if got, want := Size(uint32(10)), uintptr(4); got != want { + t.Errorf("Got = %d, want = %d", got, want) + } +} + +func TestPanic(t *testing.T) { + tests := []struct { + name string + f func([]byte, binary.ByteOrder, interface{}) + data interface{} + want string + }{ + {"Unmarshal int", Unmarshal, 5, "invalid type: int"}, + {"Unmarshal []int", Unmarshal, []int{5}, "invalid type: int"}, + {"Marshal int", func(_ []byte, bo binary.ByteOrder, d interface{}) { Marshal(nil, bo, d) }, 5, "invalid type: int"}, + {"Marshal int[]", func(_ []byte, bo binary.ByteOrder, d interface{}) { Marshal(nil, bo, d) }, []int{5}, "invalid type: int"}, + {"Unmarshal short buffer", Unmarshal, newInt32(5), "runtime error: index out of range"}, + {"Unmarshal long buffer", func(_ []byte, bo binary.ByteOrder, d interface{}) { Unmarshal(make([]byte, 50), bo, d) }, newInt32(5), "buffer too long by 46 bytes"}, + {"marshal int", func(_ []byte, bo binary.ByteOrder, d interface{}) { marshal(nil, bo, reflect.ValueOf(d)) }, 5, "invalid type: int"}, + {"Size int", func(_ []byte, _ binary.ByteOrder, d interface{}) { Size(d) }, 5, "invalid type: int"}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + defer func() { + r := recover() + if got := fmt.Sprint(r); !strings.HasPrefix(got, test.want) { + t.Errorf("Got recover() = %q, want prefix = %q", got, test.want) + } + }() + + test.f(nil, LittleEndian, test.data) + }) + } +} + +type inner struct { + Field int32 +} + +type outer struct { + Int8 int8 + Int16 int16 + Int32 int32 + Int64 int64 + Uint8 uint8 + Uint16 uint16 + Uint32 uint32 + Uint64 uint64 + + Slice []int32 + Array [5]int32 + Struct inner +} + +func TestMarshalUnmarshal(t *testing.T) { + want := outer{ + 1, 2, 3, 4, 5, 6, 7, 8, + []int32{9, 10, 11}, + [5]int32{12, 13, 14, 15, 16}, + inner{17}, + } + buf := Marshal(nil, LittleEndian, want) + got := outer{Slice: []int32{0, 0, 0}} + Unmarshal(buf, LittleEndian, &got) + if !reflect.DeepEqual(&got, &want) { + t.Errorf("Got = %#v, want = %#v", got, want) + } +} + +type outerBenchmark struct { + Int8 int8 + Int16 int16 + Int32 int32 + Int64 int64 + Uint8 uint8 + Uint16 uint16 + Uint32 uint32 + Uint64 uint64 + + Array [5]int32 + Struct inner +} + +func BenchmarkMarshalUnmarshal(b *testing.B) { + b.ReportAllocs() + + in := outerBenchmark{ + 1, 2, 3, 4, 5, 6, 7, 8, + [5]int32{9, 10, 11, 12, 13}, + inner{14}, + } + buf := make([]byte, Size(&in)) + out := outerBenchmark{} + + for i := 0; i < b.N; i++ { + buf := Marshal(buf[:0], LittleEndian, &in) + Unmarshal(buf, LittleEndian, &out) + } +} + +func BenchmarkReadWrite(b *testing.B) { + b.ReportAllocs() + + in := outerBenchmark{ + 1, 2, 3, 4, 5, 6, 7, 8, + [5]int32{9, 10, 11, 12, 13}, + inner{14}, + } + buf := bytes.NewBuffer(make([]byte, binary.Size(&in))) + out := outerBenchmark{} + + for i := 0; i < b.N; i++ { + buf.Reset() + if err := binary.Write(buf, LittleEndian, &in); err != nil { + b.Error("Write:", err) + } + if err := binary.Read(buf, LittleEndian, &out); err != nil { + b.Error("Read:", err) + } + } +} + +type outerPadding struct { + _ int8 + _ int16 + _ int32 + _ int64 + _ uint8 + _ uint16 + _ uint32 + _ uint64 + + _ []int32 + _ [5]int32 + _ inner +} + +func TestMarshalUnmarshalPadding(t *testing.T) { + var want outerPadding + buf := Marshal(nil, LittleEndian, want) + var got outerPadding + Unmarshal(buf, LittleEndian, &got) + if !reflect.DeepEqual(&got, &want) { + t.Errorf("Got = %#v, want = %#v", got, want) + } +} + +// Numbers with bits in every byte that distinguishable in big and little endian. +const ( + want16 = 64<<8 | 128 + want32 = 16<<24 | 32<<16 | want16 + want64 = 1<<56 | 2<<48 | 4<<40 | 8<<32 | want32 +) + +func TestReadWriteUint16(t *testing.T) { + const want = uint16(want16) + var buf bytes.Buffer + if err := WriteUint16(&buf, LittleEndian, want); err != nil { + t.Error("WriteUint16:", err) + } + got, err := ReadUint16(&buf, LittleEndian) + if err != nil { + t.Error("ReadUint16:", err) + } + if got != want { + t.Errorf("got = %d, want = %d", got, want) + } +} + +func TestReadWriteUint32(t *testing.T) { + const want = uint32(want32) + var buf bytes.Buffer + if err := WriteUint32(&buf, LittleEndian, want); err != nil { + t.Error("WriteUint32:", err) + } + got, err := ReadUint32(&buf, LittleEndian) + if err != nil { + t.Error("ReadUint32:", err) + } + if got != want { + t.Errorf("got = %d, want = %d", got, want) + } +} + +func TestReadWriteUint64(t *testing.T) { + const want = uint64(want64) + var buf bytes.Buffer + if err := WriteUint64(&buf, LittleEndian, want); err != nil { + t.Error("WriteUint64:", err) + } + got, err := ReadUint64(&buf, LittleEndian) + if err != nil { + t.Error("ReadUint64:", err) + } + if got != want { + t.Errorf("got = %d, want = %d", got, want) + } +} + +type readWriter struct { + err error +} + +func (rw *readWriter) Write([]byte) (int, error) { + return 0, rw.err +} + +func (rw *readWriter) Read([]byte) (int, error) { + return 0, rw.err +} + +func TestReadWriteError(t *testing.T) { + tests := []struct { + name string + f func(rw io.ReadWriter) error + }{ + {"WriteUint16", func(rw io.ReadWriter) error { return WriteUint16(rw, LittleEndian, 0) }}, + {"ReadUint16", func(rw io.ReadWriter) error { _, err := ReadUint16(rw, LittleEndian); return err }}, + {"WriteUint32", func(rw io.ReadWriter) error { return WriteUint32(rw, LittleEndian, 0) }}, + {"ReadUint32", func(rw io.ReadWriter) error { _, err := ReadUint32(rw, LittleEndian); return err }}, + {"WriteUint64", func(rw io.ReadWriter) error { return WriteUint64(rw, LittleEndian, 0) }}, + {"ReadUint64", func(rw io.ReadWriter) error { _, err := ReadUint64(rw, LittleEndian); return err }}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + want := errors.New("want") + if got := test.f(&readWriter{want}); got != want { + t.Errorf("got = %v, want = %v", got, want) + } + }) + } +} |