gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/binary/binary_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package binary 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "errors" 21 "fmt" 22 "io" 23 "reflect" 24 "strings" 25 "testing" 26 ) 27 28 func newInt32(i int32) *int32 { 29 return &i 30 } 31 32 func TestSize(t *testing.T) { 33 if got, want := Size(uint32(10)), uintptr(4); got != want { 34 t.Errorf("Got = %d, want = %d", got, want) 35 } 36 } 37 38 func TestPanic(t *testing.T) { 39 tests := []struct { 40 name string 41 f func([]byte, binary.ByteOrder, any) 42 data any 43 want string 44 }{ 45 {"Unmarshal int", Unmarshal, 5, "invalid type: int"}, 46 {"Unmarshal []int", Unmarshal, []int{5}, "invalid type: int"}, 47 {"Marshal int", func(_ []byte, bo binary.ByteOrder, d any) { Marshal(nil, bo, d) }, 5, "invalid type: int"}, 48 {"Marshal int[]", func(_ []byte, bo binary.ByteOrder, d any) { Marshal(nil, bo, d) }, []int{5}, "invalid type: int"}, 49 {"Unmarshal short buffer", Unmarshal, newInt32(5), "runtime error: index out of range"}, 50 {"Unmarshal long buffer", func(_ []byte, bo binary.ByteOrder, d any) { Unmarshal(make([]byte, 50), bo, d) }, newInt32(5), "buffer too long by 46 bytes"}, 51 {"marshal int", func(_ []byte, bo binary.ByteOrder, d any) { marshal(nil, bo, reflect.ValueOf(d)) }, 5, "invalid type: int"}, 52 {"Size int", func(_ []byte, _ binary.ByteOrder, d any) { Size(d) }, 5, "invalid type: int"}, 53 } 54 55 for _, test := range tests { 56 t.Run(test.name, func(t *testing.T) { 57 defer func() { 58 r := recover() 59 if got := fmt.Sprint(r); !strings.HasPrefix(got, test.want) { 60 t.Errorf("Got recover() = %q, want prefix = %q", got, test.want) 61 } 62 }() 63 64 test.f(nil, LittleEndian, test.data) 65 }) 66 } 67 } 68 69 type inner struct { 70 Field int32 71 } 72 73 type outer struct { 74 Int8 int8 75 Int16 int16 76 Int32 int32 77 Int64 int64 78 Uint8 uint8 79 Uint16 uint16 80 Uint32 uint32 81 Uint64 uint64 82 83 Slice []int32 84 Array [5]int32 85 Struct inner 86 } 87 88 func TestMarshalUnmarshal(t *testing.T) { 89 want := outer{ 90 1, 2, 3, 4, 5, 6, 7, 8, 91 []int32{9, 10, 11}, 92 [5]int32{12, 13, 14, 15, 16}, 93 inner{17}, 94 } 95 buf := Marshal(nil, LittleEndian, want) 96 got := outer{Slice: []int32{0, 0, 0}} 97 Unmarshal(buf, LittleEndian, &got) 98 if !reflect.DeepEqual(&got, &want) { 99 t.Errorf("Got = %#v, want = %#v", got, want) 100 } 101 } 102 103 type outerBenchmark struct { 104 Int8 int8 105 Int16 int16 106 Int32 int32 107 Int64 int64 108 Uint8 uint8 109 Uint16 uint16 110 Uint32 uint32 111 Uint64 uint64 112 113 Array [5]int32 114 Struct inner 115 } 116 117 func BenchmarkMarshalUnmarshal(b *testing.B) { 118 b.ReportAllocs() 119 120 in := outerBenchmark{ 121 1, 2, 3, 4, 5, 6, 7, 8, 122 [5]int32{9, 10, 11, 12, 13}, 123 inner{14}, 124 } 125 buf := make([]byte, Size(&in)) 126 out := outerBenchmark{} 127 128 for i := 0; i < b.N; i++ { 129 buf := Marshal(buf[:0], LittleEndian, &in) 130 Unmarshal(buf, LittleEndian, &out) 131 } 132 } 133 134 func BenchmarkReadWrite(b *testing.B) { 135 b.ReportAllocs() 136 137 in := outerBenchmark{ 138 1, 2, 3, 4, 5, 6, 7, 8, 139 [5]int32{9, 10, 11, 12, 13}, 140 inner{14}, 141 } 142 buf := bytes.NewBuffer(make([]byte, binary.Size(&in))) 143 out := outerBenchmark{} 144 145 for i := 0; i < b.N; i++ { 146 buf.Reset() 147 if err := binary.Write(buf, LittleEndian, &in); err != nil { 148 b.Error("Write:", err) 149 } 150 if err := binary.Read(buf, LittleEndian, &out); err != nil { 151 b.Error("Read:", err) 152 } 153 } 154 } 155 156 type outerPadding struct { 157 _ int8 158 _ int16 159 _ int32 160 _ int64 161 _ uint8 162 _ uint16 163 _ uint32 164 _ uint64 165 166 _ []int32 167 _ [5]int32 168 _ inner 169 } 170 171 func TestMarshalUnmarshalPadding(t *testing.T) { 172 var want outerPadding 173 buf := Marshal(nil, LittleEndian, want) 174 var got outerPadding 175 Unmarshal(buf, LittleEndian, &got) 176 if !reflect.DeepEqual(&got, &want) { 177 t.Errorf("Got = %#v, want = %#v", got, want) 178 } 179 } 180 181 // Numbers with bits in every byte that distinguishable in big and little endian. 182 const ( 183 want16 = 64<<8 | 128 184 want32 = 16<<24 | 32<<16 | want16 185 want64 = 1<<56 | 2<<48 | 4<<40 | 8<<32 | want32 186 ) 187 188 func TestReadWriteUint16(t *testing.T) { 189 const want = uint16(want16) 190 var buf bytes.Buffer 191 if err := WriteUint16(&buf, LittleEndian, want); err != nil { 192 t.Error("WriteUint16:", err) 193 } 194 got, err := ReadUint16(&buf, LittleEndian) 195 if err != nil { 196 t.Error("ReadUint16:", err) 197 } 198 if got != want { 199 t.Errorf("got = %d, want = %d", got, want) 200 } 201 } 202 203 func TestReadWriteUint32(t *testing.T) { 204 const want = uint32(want32) 205 var buf bytes.Buffer 206 if err := WriteUint32(&buf, LittleEndian, want); err != nil { 207 t.Error("WriteUint32:", err) 208 } 209 got, err := ReadUint32(&buf, LittleEndian) 210 if err != nil { 211 t.Error("ReadUint32:", err) 212 } 213 if got != want { 214 t.Errorf("got = %d, want = %d", got, want) 215 } 216 } 217 218 func TestReadWriteUint64(t *testing.T) { 219 const want = uint64(want64) 220 var buf bytes.Buffer 221 if err := WriteUint64(&buf, LittleEndian, want); err != nil { 222 t.Error("WriteUint64:", err) 223 } 224 got, err := ReadUint64(&buf, LittleEndian) 225 if err != nil { 226 t.Error("ReadUint64:", err) 227 } 228 if got != want { 229 t.Errorf("got = %d, want = %d", got, want) 230 } 231 } 232 233 type readWriter struct { 234 err error 235 } 236 237 func (rw *readWriter) Write([]byte) (int, error) { 238 return 0, rw.err 239 } 240 241 func (rw *readWriter) Read([]byte) (int, error) { 242 return 0, rw.err 243 } 244 245 func TestReadWriteError(t *testing.T) { 246 tests := []struct { 247 name string 248 f func(rw io.ReadWriter) error 249 }{ 250 {"WriteUint16", func(rw io.ReadWriter) error { return WriteUint16(rw, LittleEndian, 0) }}, 251 {"ReadUint16", func(rw io.ReadWriter) error { _, err := ReadUint16(rw, LittleEndian); return err }}, 252 {"WriteUint32", func(rw io.ReadWriter) error { return WriteUint32(rw, LittleEndian, 0) }}, 253 {"ReadUint32", func(rw io.ReadWriter) error { _, err := ReadUint32(rw, LittleEndian); return err }}, 254 {"WriteUint64", func(rw io.ReadWriter) error { return WriteUint64(rw, LittleEndian, 0) }}, 255 {"ReadUint64", func(rw io.ReadWriter) error { _, err := ReadUint64(rw, LittleEndian); return err }}, 256 } 257 258 for _, test := range tests { 259 t.Run(test.name, func(t *testing.T) { 260 want := errors.New("want") 261 if got := test.f(&readWriter{want}); got != want { 262 t.Errorf("got = %v, want = %v", got, want) 263 } 264 }) 265 } 266 }