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  }