github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/istructsmem/internal/utils/bytes_test.go (about) 1 /* 2 * Copyright (c) 2021-present Sigma-Soft, Ltd. 3 * @author: Nikolay Nikitin 4 */ 5 6 package utils 7 8 import ( 9 "bytes" 10 "io" 11 "reflect" 12 "strings" 13 "testing" 14 15 "github.com/stretchr/testify/require" 16 ) 17 18 func TestSafeWriteBuf(t *testing.T) { 19 type args struct { 20 buf []byte 21 data any 22 } 23 tests := []struct { 24 name string 25 args args 26 want []byte 27 }{ 28 { 29 name: "write nil", 30 args: args{data: nil}, 31 want: nil, 32 }, 33 { 34 name: "append nil", 35 args: args{buf: []byte{1, 2, 3}, data: nil}, 36 want: []byte{1, 2, 3}, 37 }, 38 { 39 name: "write fixed size data", 40 args: args{data: uint8(4)}, 41 want: []byte{4}, 42 }, 43 { 44 name: "append fixed size data", 45 args: args{buf: []byte{1, 2, 3}, data: uint8(4)}, 46 want: []byte{1, 2, 3, 4}, 47 }, 48 { 49 name: "write []byte", 50 args: args{data: []byte{4, 5, 6}}, 51 want: []byte{4, 5, 6}, 52 }, 53 { 54 name: "append []byte", 55 args: args{buf: []byte{1, 2, 3}, data: []byte{4, 5, 6}}, 56 want: []byte{1, 2, 3, 4, 5, 6}, 57 }, 58 { 59 name: "write string", 60 args: args{data: "AAA"}, 61 want: []byte{65, 65, 65}, 62 }, 63 { 64 name: "append string", 65 args: args{buf: []byte{1, 2, 3}, data: "AAA"}, 66 want: []byte{1, 2, 3, 65, 65, 65}, 67 }, 68 } 69 require := require.New(t) 70 for _, tt := range tests { 71 t.Run(tt.name, func(t *testing.T) { 72 b := bytes.NewBuffer(tt.args.buf) 73 SafeWriteBuf(b, tt.args.data) 74 require.EqualValues(tt.want, b.Bytes()) 75 }) 76 } 77 78 require.Panics(func() { 79 p := func() {} 80 SafeWriteBuf(bytes.NewBuffer(nil), p) 81 }, "must be panic if unknown data size") 82 } 83 84 func TestReadWriteShortString(t *testing.T) { 85 type args struct { 86 str string 87 } 88 tests := []struct { 89 name string 90 args args 91 }{ 92 { 93 name: "empty string", 94 args: args{str: ""}, 95 }, 96 { 97 name: "basic", 98 args: args{str: "AAA"}, 99 }, 100 } 101 require := require.New(t) 102 for _, tt := range tests { 103 t.Run(tt.name, func(t *testing.T) { 104 b := bytes.NewBuffer(nil) 105 WriteShortString(b, tt.args.str) 106 107 s, err := ReadShortString(b) 108 require.NoError(err) 109 require.EqualValues(tt.args.str, s) 110 }) 111 } 112 113 t.Run("must be truncated on write large (> 64K) string", func(t *testing.T) { 114 str := strings.Repeat("A", 0xFFFF+1) 115 116 b := bytes.NewBuffer(nil) 117 WriteShortString(b, str) 118 119 result, err := ReadShortString(b) 120 require.NoError(err) 121 require.EqualValues(strings.Repeat("A", 0xFFFF), result) 122 }) 123 124 t.Run("must be error read from EOF buffer", func(t *testing.T) { 125 b := bytes.NewBuffer(nil) 126 _, err := ReadShortString(b) 127 128 require.ErrorIs(err, io.ErrUnexpectedEOF) 129 }) 130 131 t.Run("must be error if not enough chars to read", func(t *testing.T) { 132 b := bytes.NewBuffer([]byte{0, 3, 65, 65}) 133 _, err := ReadShortString(b) 134 135 require.ErrorIs(err, io.ErrUnexpectedEOF) 136 require.ErrorContains(err, "expected 3 bytes, but only 2") 137 }) 138 } 139 140 func TestWriteXXX(t *testing.T) { 141 type s struct { 142 int8 143 byte 144 bool 145 int16 146 uint16 147 int32 148 uint32 149 int64 150 uint64 151 float32 152 float64 153 } 154 s1 := s{ 155 int8: -1, 156 byte: 1, 157 bool: true, 158 int16: -2222, 159 uint16: 3333, 160 int32: -444444, 161 uint32: 555555, 162 int64: -66666666666, 163 uint64: 77777777777, 164 float32: -8.888e8, 165 float64: 9.9999e99, 166 } 167 168 buf := new(bytes.Buffer) 169 SafeWriteBuf(buf, s1.int8) 170 SafeWriteBuf(buf, s1.byte) 171 SafeWriteBuf(buf, s1.bool) 172 SafeWriteBuf(buf, s1.int16) 173 SafeWriteBuf(buf, s1.uint16) 174 SafeWriteBuf(buf, s1.int32) 175 SafeWriteBuf(buf, s1.uint32) 176 SafeWriteBuf(buf, s1.int64) 177 SafeWriteBuf(buf, s1.uint64) 178 SafeWriteBuf(buf, s1.float32) 179 SafeWriteBuf(buf, s1.float64) 180 181 data := buf.Bytes() 182 183 t.Run("Write×××", func(t *testing.T) { 184 require := require.New(t) 185 186 buf := bytes.NewBuffer(nil) 187 WriteInt8(buf, s1.int8) 188 WriteByte(buf, s1.byte) 189 WriteBool(buf, s1.bool) 190 WriteInt16(buf, s1.int16) 191 WriteUint16(buf, s1.uint16) 192 WriteInt32(buf, s1.int32) 193 WriteUint32(buf, s1.uint32) 194 WriteInt64(buf, s1.int64) 195 WriteUint64(buf, s1.uint64) 196 WriteFloat32(buf, s1.float32) 197 WriteFloat64(buf, s1.float64) 198 199 require.EqualValues(data, buf.Bytes()) 200 }) 201 } 202 203 func TestReadWriteXXX(t *testing.T) { 204 type s struct { 205 int8 206 byte 207 bool 208 int16 209 uint16 210 int32 211 uint32 212 int64 213 uint64 214 float32 215 float64 216 string 217 } 218 s1 := s{ 219 int8: -1, 220 byte: 1, 221 bool: true, 222 int16: -2222, 223 uint16: 3333, 224 int32: -444444, 225 uint32: 555555, 226 int64: -66666666666, 227 uint64: 77777777777, 228 float32: -8.888e8, 229 float64: 9.9999e99, 230 string: "test 🧪 test", 231 } 232 233 var data []byte 234 235 require := require.New(t) 236 237 t.Run("Write×××", func(t *testing.T) { 238 buf := new(bytes.Buffer) 239 WriteInt8(buf, s1.int8) 240 WriteByte(buf, s1.byte) 241 WriteBool(buf, s1.bool) 242 WriteInt16(buf, s1.int16) 243 WriteUint16(buf, s1.uint16) 244 WriteInt32(buf, s1.int32) 245 WriteUint32(buf, s1.uint32) 246 WriteInt64(buf, s1.int64) 247 WriteUint64(buf, s1.uint64) 248 WriteFloat32(buf, s1.float32) 249 WriteFloat64(buf, s1.float64) 250 WriteShortString(buf, s1.string) 251 data = buf.Bytes() 252 253 require.NotEmpty(data) 254 }) 255 256 t.Run("Read×××", func(t *testing.T) { 257 258 s2 := s{} 259 buf := bytes.NewBuffer(data) 260 261 var e error 262 263 s2.int8, e = ReadInt8(buf) 264 require.NoError(e) 265 s2.byte, e = ReadByte(buf) 266 require.NoError(e) 267 s2.bool, e = ReadBool(buf) 268 require.NoError(e) 269 s2.int16, e = ReadInt16(buf) 270 require.NoError(e) 271 s2.uint16, e = ReadUInt16(buf) 272 require.NoError(e) 273 s2.int32, e = ReadInt32(buf) 274 require.NoError(e) 275 s2.uint32, e = ReadUInt32(buf) 276 require.NoError(e) 277 s2.int64, e = ReadInt64(buf) 278 require.NoError(e) 279 s2.uint64, e = ReadUInt64(buf) 280 require.NoError(e) 281 s2.float32, e = ReadFloat32(buf) 282 require.NoError(e) 283 s2.float64, e = ReadFloat64(buf) 284 require.NoError(e) 285 s2.string, e = ReadShortString(buf) 286 require.NoError(e) 287 288 require.EqualValues(s1, s2) 289 }) 290 } 291 292 func TestReadXXXerrors(t *testing.T) { 293 var e error 294 require := require.New(t) 295 296 b := bytes.NewBuffer([]byte{0}) 297 _ = b.Next(1) 298 299 _, e = ReadInt8(b) 300 require.ErrorIs(e, io.ErrUnexpectedEOF) 301 302 _, e = ReadByte(b) 303 require.ErrorIs(e, io.ErrUnexpectedEOF) 304 305 _, e = ReadBool(b) 306 require.ErrorIs(e, io.ErrUnexpectedEOF) 307 308 _, e = ReadInt16(b) 309 require.ErrorIs(e, io.ErrUnexpectedEOF) 310 311 _, e = ReadUInt16(b) 312 require.ErrorIs(e, io.ErrUnexpectedEOF) 313 314 _, e = ReadInt32(b) 315 require.ErrorIs(e, io.ErrUnexpectedEOF) 316 317 _, e = ReadUInt32(b) 318 require.ErrorIs(e, io.ErrUnexpectedEOF) 319 320 _, e = ReadInt64(b) 321 require.ErrorIs(e, io.ErrUnexpectedEOF) 322 323 _, e = ReadUInt64(b) 324 require.ErrorIs(e, io.ErrUnexpectedEOF) 325 326 _, e = ReadFloat32(b) 327 require.ErrorIs(e, io.ErrUnexpectedEOF) 328 329 _, e = ReadFloat64(b) 330 require.ErrorIs(e, io.ErrUnexpectedEOF) 331 } 332 333 func TestCopyBytes(t *testing.T) { 334 type args struct { 335 src []byte 336 } 337 tests := []struct { 338 name string 339 args args 340 want []byte 341 }{ 342 { 343 name: "basic test", 344 args: args{src: []byte{1, 2, 3}}, 345 want: []byte{1, 2, 3}, 346 }, 347 { 348 name: "must be ok to copy from nil", 349 args: args{src: nil}, 350 want: []byte{}, 351 }, 352 } 353 for _, tt := range tests { 354 t.Run(tt.name, func(t *testing.T) { 355 if got := CopyBytes(tt.args.src); !reflect.DeepEqual(got, tt.want) { 356 t.Errorf("CopyBytes() = %v, want %v", got, tt.want) 357 } 358 }) 359 } 360 } 361 362 type testInt uint16 363 364 func TestToBytes(t *testing.T) { 365 type args struct { 366 value []interface{} 367 } 368 tests := []struct { 369 name string 370 args args 371 want []byte 372 }{ 373 { 374 name: "fixed width", 375 args: args{value: []interface{}{uint16(20)}}, 376 want: []byte{0, 20}, 377 }, 378 { 379 name: "fixed width custom type", 380 args: args{value: []interface{}{testInt(1973)}}, 381 want: []byte{0x07, 0xb5}, 382 }, 383 { 384 name: "[]byte", 385 args: args{value: []interface{}{[]byte{1, 2, 3}}}, 386 want: []byte{1, 2, 3}, 387 }, 388 { 389 name: "string", 390 args: args{value: []interface{}{"AAA"}}, 391 want: []byte{65, 65, 65}, 392 }, 393 } 394 for _, tt := range tests { 395 t.Run(tt.name, func(t *testing.T) { 396 if got := ToBytes(tt.args.value...); !reflect.DeepEqual(got, tt.want) { 397 t.Errorf("ToBytes() = %v, want %v", got, tt.want) 398 } 399 }) 400 } 401 } 402 403 func TestFullBytes(t *testing.T) { 404 type args struct { 405 b []byte 406 } 407 tests := []struct { 408 name string 409 args args 410 want bool 411 }{ 412 { 413 name: "nil case", 414 args: args{b: nil}, 415 want: true, 416 }, 417 { 418 name: "null len case", 419 args: args{b: []byte{}}, 420 want: true, 421 }, 422 { 423 name: "full byte test", 424 args: args{b: []byte{0xFF}}, 425 want: true, 426 }, 427 { 428 name: "full word test", 429 args: args{b: []byte{0xFF, 0xFF}}, 430 want: true, 431 }, 432 { 433 name: "full long bytes test", 434 args: args{b: []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}, 435 want: true, 436 }, 437 { 438 name: "negative test", 439 args: args{b: []byte("bytes")}, 440 want: false, 441 }, 442 } 443 for _, tt := range tests { 444 t.Run(tt.name, func(t *testing.T) { 445 if got := FullBytes(tt.args.b); got != tt.want { 446 t.Errorf("fullBytes() = %v, want %v", got, tt.want) 447 } 448 }) 449 } 450 } 451 452 func TestIncBytes(t *testing.T) { 453 type args struct { 454 cc []byte 455 } 456 tests := []struct { 457 name string 458 args args 459 want []byte 460 }{ 461 { 462 name: "nil test", 463 args: args{cc: nil}, 464 want: nil, 465 }, 466 { 467 name: "null len test", 468 args: args{cc: []byte{}}, 469 want: nil, 470 }, 471 { 472 name: "full byte test", 473 args: args{cc: []byte{0xFF}}, 474 want: nil, 475 }, 476 { 477 name: "full word test", 478 args: args{cc: []byte{0xFF, 0xFF}}, 479 want: nil, 480 }, 481 { 482 name: "basic test", 483 args: args{cc: []byte{0x01, 0x02}}, 484 want: []byte{0x01, 0x03}, 485 }, 486 { 487 name: "full-end test", 488 args: args{cc: []byte{0x01, 0xFF}}, 489 want: []byte{0x02, 0x00}, 490 }, 491 } 492 for _, tt := range tests { 493 t.Run(tt.name, func(t *testing.T) { 494 if gotFinishCCols := IncBytes(tt.args.cc); !reflect.DeepEqual(gotFinishCCols, tt.want) { 495 t.Errorf("rangeCCols() = %v, want %v", gotFinishCCols, tt.want) 496 } 497 }) 498 } 499 }