github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/tinyint_test.go (about)

     1  // Copyright 2021 DataStax
     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 datacodec
    16  
    17  import (
    18  	"fmt"
    19  	"math"
    20  	"strconv"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  
    25  	"github.com/datastax/go-cassandra-native-protocol/primitive"
    26  )
    27  
    28  var (
    29  	tinyintZeroBytes     = []byte{0x00}
    30  	tinyintOneBytes      = []byte{0x01}
    31  	tinyintMinusOneBytes = []byte{0xff}
    32  	tinyintMaxInt8Bytes  = []byte{0x7f}
    33  	tinyintMinInt8Bytes  = []byte{0x80}
    34  )
    35  
    36  func Test_tinyintCodec_Encode(t *testing.T) {
    37  	for _, version := range primitive.SupportedProtocolVersionsGreaterThanOrEqualTo(primitive.ProtocolVersion4) {
    38  		t.Run(version.String(), func(t *testing.T) {
    39  			tests := []struct {
    40  				name     string
    41  				source   interface{}
    42  				expected []byte
    43  				err      string
    44  			}{
    45  				{"nil", nil, nil, ""},
    46  				{"nil pointer", int8NilPtr(), nil, ""},
    47  				{"non nil", 1, tinyintOneBytes, ""},
    48  				{"conversion failed", uint8(math.MaxUint8), nil, fmt.Sprintf("cannot encode uint8 as CQL tinyint with %v: cannot convert from uint8 to int8: value out of range: 255", version)},
    49  			}
    50  			for _, tt := range tests {
    51  				t.Run(tt.name, func(t *testing.T) {
    52  					actual, err := Tinyint.Encode(tt.source, version)
    53  					assert.Equal(t, tt.expected, actual)
    54  					assertErrorMessage(t, tt.err, err)
    55  				})
    56  			}
    57  		})
    58  	}
    59  	for _, version := range primitive.SupportedProtocolVersionsLesserThan(primitive.ProtocolVersion4) {
    60  		t.Run(version.String(), func(t *testing.T) {
    61  			tests := []struct {
    62  				name     string
    63  				source   interface{}
    64  				expected []byte
    65  				err      string
    66  			}{
    67  				{"nil", int8NilPtr(), nil, "data type tinyint not supported"},
    68  				{"non nil", 1, nil, "data type tinyint not supported"},
    69  			}
    70  			for _, tt := range tests {
    71  				t.Run(tt.name, func(t *testing.T) {
    72  					actual, err := Tinyint.Encode(tt.source, version)
    73  					assert.Equal(t, tt.expected, actual)
    74  					assertErrorMessage(t, tt.err, err)
    75  				})
    76  			}
    77  		})
    78  	}
    79  }
    80  
    81  func Test_tinyintCodec_Decode(t *testing.T) {
    82  	for _, version := range primitive.SupportedProtocolVersionsGreaterThanOrEqualTo(primitive.ProtocolVersion4) {
    83  		t.Run(version.String(), func(t *testing.T) {
    84  			tests := []struct {
    85  				name     string
    86  				source   []byte
    87  				dest     interface{}
    88  				expected interface{}
    89  				wasNull  bool
    90  				err      string
    91  			}{
    92  				{"null", nil, new(int8), new(int8), true, ""},
    93  				{"non null", tinyintOneBytes, new(int8), int8Ptr(1), false, ""},
    94  				{"non null interface", tinyintOneBytes, new(interface{}), interfacePtr(int8(1)), false, ""},
    95  				{"read failed", []byte{1, 2}, new(int8), new(int8), false, fmt.Sprintf("cannot decode CQL tinyint as *int8 with %v: cannot read int8: expected 1 bytes but got: 2", version)},
    96  				{"conversion failed", tinyintOneBytes, new(float64), new(float64), false, fmt.Sprintf("cannot decode CQL tinyint as *float64 with %v: cannot convert from int8 to *float64: conversion not supported", version)},
    97  			}
    98  			for _, tt := range tests {
    99  				t.Run(tt.name, func(t *testing.T) {
   100  					wasNull, err := Tinyint.Decode(tt.source, tt.dest, version)
   101  					assert.Equal(t, tt.expected, tt.dest)
   102  					assert.Equal(t, tt.wasNull, wasNull)
   103  					assertErrorMessage(t, tt.err, err)
   104  				})
   105  			}
   106  		})
   107  	}
   108  	for _, version := range primitive.SupportedProtocolVersionsLesserThan(primitive.ProtocolVersion4) {
   109  		t.Run(version.String(), func(t *testing.T) {
   110  			tests := []struct {
   111  				name     string
   112  				source   []byte
   113  				dest     interface{}
   114  				expected interface{}
   115  				wasNull  bool
   116  				err      string
   117  			}{
   118  				{"null", nil, new(int8), new(int8), true, "data type tinyint not supported"},
   119  				{"non null", tinyintOneBytes, new(int8), new(int8), false, "data type tinyint not supported"},
   120  			}
   121  			for _, tt := range tests {
   122  				t.Run(tt.name, func(t *testing.T) {
   123  					wasNull, err := Tinyint.Decode(tt.source, tt.dest, version)
   124  					assert.Equal(t, tt.expected, tt.dest)
   125  					assert.Equal(t, tt.wasNull, wasNull)
   126  					assertErrorMessage(t, tt.err, err)
   127  				})
   128  			}
   129  		})
   130  	}
   131  }
   132  
   133  func Test_convertToInt8(t *testing.T) {
   134  	tests := []struct {
   135  		name     string
   136  		input    interface{}
   137  		expected int8
   138  		wasNil   bool
   139  		err      string
   140  	}{
   141  		{"from int", int(1), 1, false, ""},
   142  		{"from int out of range pos", int(math.MaxInt8 + 1), 0, false, "cannot convert from int to int8: value out of range: 128"},
   143  		{"from int out of range neg", int(math.MinInt8 - 1), 0, false, "cannot convert from int to int8: value out of range: -129"},
   144  		{"from *int non nil", intPtr(1), 1, false, ""},
   145  		{"from *int nil", intNilPtr(), 0, true, ""},
   146  		{"from *int out of range pos", intPtr(math.MaxInt8 + 1), 0, false, "cannot convert from *int to int8: value out of range: 128"},
   147  		{"from *int out of range neg", intPtr(math.MinInt8 - 1), 0, false, "cannot convert from *int to int8: value out of range: -129"},
   148  		{"from int64", int64(1), 1, false, ""},
   149  		{"from int64 out of range pos", int64(math.MaxInt8 + 1), 0, false, "cannot convert from int64 to int8: value out of range: 128"},
   150  		{"from int64 out of range neg", int64(math.MinInt8 - 1), 0, false, "cannot convert from int64 to int8: value out of range: -129"},
   151  		{"from *int64 non nil", int64Ptr(1), 1, false, ""},
   152  		{"from *int64 nil", int64NilPtr(), 0, true, ""},
   153  		{"from *int64 out of range pos", int64Ptr(math.MaxInt8 + 1), 0, false, "cannot convert from *int64 to int8: value out of range: 128"},
   154  		{"from *int64 out of range neg", int64Ptr(math.MinInt8 - 1), 0, false, "cannot convert from *int64 to int8: value out of range: -129"},
   155  		{"from int32", int32(1), 1, false, ""},
   156  		{"from int32 out of range pos", int32(math.MaxInt8 + 1), 0, false, "cannot convert from int32 to int8: value out of range: 128"},
   157  		{"from int32 out of range neg", int32(math.MinInt8 - 1), 0, false, "cannot convert from int32 to int8: value out of range: -129"},
   158  		{"from *int32 non nil", int32Ptr(1), 1, false, ""},
   159  		{"from *int32 nil", int32NilPtr(), 0, true, ""},
   160  		{"from *int32 out of range pos", int32Ptr(math.MaxInt8 + 1), 0, false, "cannot convert from *int32 to int8: value out of range: 128"},
   161  		{"from *int32 out of range neg", int32Ptr(math.MinInt8 - 1), 0, false, "cannot convert from *int32 to int8: value out of range: -129"},
   162  		{"from int16", int16(1), 1, false, ""},
   163  		{"from *int16 non nil", int16Ptr(1), 1, false, ""},
   164  		{"from *int16 out of range pos", int16Ptr(math.MaxInt8 + 1), 0, false, "cannot convert from *int16 to int8: value out of range: 128"},
   165  		{"from *int16 out of range neg", int16Ptr(math.MinInt8 - 1), 0, false, "cannot convert from *int16 to int8: value out of range: -129"},
   166  		{"from *int16 nil", int16NilPtr(), 0, true, ""},
   167  		{"from int8", int8(1), 1, false, ""},
   168  		{"from *int8 non nil", int8Ptr(1), 1, false, ""},
   169  		{"from *int8 nil", int8NilPtr(), 0, true, ""},
   170  		{"from uint", uint(1), 1, false, ""},
   171  		{"from uint out of range", uint(math.MaxInt8 + 1), 0, false, "cannot convert from uint to int8: value out of range: 128"},
   172  		{"from *uint non nil", uintPtr(1), 1, false, ""},
   173  		{"from *uint nil", uintNilPtr(), 0, true, ""},
   174  		{"from *uint out of range", uintPtr(math.MaxInt8 + 1), 0, false, "cannot convert from *uint to int8: value out of range: 128"},
   175  		{"from uint64", uint64(1), 1, false, ""},
   176  		{"from uint64 out of range", uint64(math.MaxInt8 + 1), 0, false, "cannot convert from uint64 to int8: value out of range: 128"},
   177  		{"from *uint64 non nil", uint64Ptr(1), 1, false, ""},
   178  		{"from *uint64 nil", uint64NilPtr(), 0, true, ""},
   179  		{"from *uint64 out of range", uint64Ptr(math.MaxInt8 + 1), 0, false, "cannot convert from *uint64 to int8: value out of range: 128"},
   180  		{"from uint32", uint32(1), 1, false, ""},
   181  		{"from uint32 out of range", uint32(math.MaxInt8 + 1), 0, false, "cannot convert from uint32 to int8: value out of range: 128"},
   182  		{"from *uint32 non nil", uint32Ptr(1), 1, false, ""},
   183  		{"from *uint32 nil", uint32NilPtr(), 0, true, ""},
   184  		{"from *uint32 out of range", uint32Ptr(math.MaxInt8 + 1), 0, false, "cannot convert from *uint32 to int8: value out of range: 128"},
   185  		{"from uint16", uint16(1), 1, false, ""},
   186  		{"from uint16 out of range", uint16(math.MaxInt8 + 1), 0, false, "cannot convert from uint16 to int8: value out of range: 128"},
   187  		{"from *uint16 non nil", uint16Ptr(1), 1, false, ""},
   188  		{"from *uint16 nil", uint16NilPtr(), 0, true, ""},
   189  		{"from *uint16 out of range", uint16Ptr(math.MaxInt8 + 1), 0, false, "cannot convert from *uint16 to int8: value out of range: 128"},
   190  		{"from uint8", uint8(1), 1, false, ""},
   191  		{"from *uint8 non nil", uint8Ptr(1), 1, false, ""},
   192  		{"from *uint8 nil", uint8NilPtr(), 0, true, ""},
   193  		{"from string", "1", 1, false, ""},
   194  		{"from string malformed", "not a number", 0, false, "cannot convert from string to int8: cannot parse 'not a number'"},
   195  		{"from string out of range", strconv.Itoa(math.MaxInt8 + 1), 0, false, "cannot convert from string to int8: cannot parse '128'"},
   196  		{"from *string non nil", stringPtr("1"), 1, false, ""},
   197  		{"from *string malformed", stringPtr("not a number"), 0, false, "cannot convert from *string to int8: cannot parse 'not a number'"},
   198  		{"from *string out of range", stringPtr(strconv.Itoa(math.MaxInt8 + 1)), 0, false, "cannot convert from *string to int8: cannot parse '128'"},
   199  		{"from *string nil", stringNilPtr(), 0, true, ""},
   200  		{"from untyped nil", nil, 0, true, ""},
   201  		{"from unsupported value type", 42.0, 0, false, "cannot convert from float64 to int8: conversion not supported"},
   202  		{"from unsupported pointer type", float64Ptr(42.0), 0, false, "cannot convert from *float64 to int8: conversion not supported"},
   203  	}
   204  	for _, tt := range tests {
   205  		t.Run(tt.name, func(t *testing.T) {
   206  			dest, wasNil, err := convertToInt8(tt.input)
   207  			assert.Equal(t, tt.expected, dest)
   208  			assert.Equal(t, tt.wasNil, wasNil)
   209  			assertErrorMessage(t, tt.err, err)
   210  		})
   211  	}
   212  }
   213  
   214  func Test_convertFromInt8(t *testing.T) {
   215  	tests := []struct {
   216  		name     string
   217  		val      int8
   218  		wasNull  bool
   219  		dest     interface{}
   220  		expected interface{}
   221  		err      string
   222  	}{
   223  		{"to *interface{} nil dest", 1, false, interfaceNilPtr(), interfaceNilPtr(), "cannot convert from int8 to *interface {}: destination is nil"},
   224  		{"to *interface{} nil source", 0, true, new(interface{}), new(interface{}), ""},
   225  		{"to *interface{} non nil", 1, false, new(interface{}), interfacePtr(int8(1)), ""},
   226  		{"to *int nil dest", 1, false, intNilPtr(), intNilPtr(), "cannot convert from int8 to *int: destination is nil"},
   227  		{"to *int nil source", 0, true, new(int), intPtr(0), ""},
   228  		{"to *int non nil", 1, false, new(int), intPtr(1), ""},
   229  		{"to *int64 nil dest", 1, false, int64NilPtr(), int64NilPtr(), "cannot convert from int8 to *int64: destination is nil"},
   230  		{"to *int64 nil source", 0, true, new(int64), int64Ptr(0), ""},
   231  		{"to *int64 non nil", 1, false, new(int64), int64Ptr(1), ""},
   232  		{"to *int32 nil dest", 1, false, int32NilPtr(), int32NilPtr(), "cannot convert from int8 to *int32: destination is nil"},
   233  		{"to *int32 nil source", 0, true, new(int32), int32Ptr(0), ""},
   234  		{"to *int32 non nil", 1, false, new(int32), int32Ptr(1), ""},
   235  		{"to *int16 nil dest", 1, false, int16NilPtr(), int16NilPtr(), "cannot convert from int8 to *int16: destination is nil"},
   236  		{"to *int16 nil source", 0, true, new(int16), int16Ptr(0), ""},
   237  		{"to *int16 non nil", 1, false, new(int16), int16Ptr(1), ""},
   238  		{"to *int8 nil dest", 1, false, int8NilPtr(), int8NilPtr(), "cannot convert from int8 to *int8: destination is nil"},
   239  		{"to *int8 nil source", 0, true, new(int8), int8Ptr(0), ""},
   240  		{"to *int8 non nil", 1, false, new(int8), int8Ptr(1), ""},
   241  		{"to *uint nil dest", 1, false, uintNilPtr(), uintNilPtr(), "cannot convert from int8 to *uint: destination is nil"},
   242  		{"to *uint nil source", 0, true, new(uint), uintPtr(0), ""},
   243  		{"to *uint non nil", 1, false, new(uint), uintPtr(1), ""},
   244  		{"to *uint out of range neg", -1, false, new(uint), new(uint), "cannot convert from int8 to *uint: value out of range: -1"},
   245  		{"to *uint64 nil dest", 1, false, uint64NilPtr(), uint64NilPtr(), "cannot convert from int8 to *uint64: destination is nil"},
   246  		{"to *uint64 nil source", 0, true, new(uint64), uint64Ptr(0), ""},
   247  		{"to *uint64 non nil", 1, false, new(uint64), uint64Ptr(1), ""},
   248  		{"to *uint64 out of range neg", -1, false, new(uint64), uint64Ptr(0), "cannot convert from int8 to *uint64: value out of range: -1"},
   249  		{"to *uint32 nil dest", 1, false, uint32NilPtr(), uint32NilPtr(), "cannot convert from int8 to *uint32: destination is nil"},
   250  		{"to *uint32 nil source", 0, true, new(uint32), uint32Ptr(0), ""},
   251  		{"to *uint32 non nil", 1, false, new(uint32), uint32Ptr(1), ""},
   252  		{"to *uint32 out of range neg", -1, false, new(uint32), uint32Ptr(0), "cannot convert from int8 to *uint32: value out of range: -1"},
   253  		{"to *uint16 nil dest", 1, false, uint16NilPtr(), uint16NilPtr(), "cannot convert from int8 to *uint16: destination is nil"},
   254  		{"to *uint16 nil source", 0, true, new(uint16), uint16Ptr(0), ""},
   255  		{"to *uint16 non nil", 1, false, new(uint16), uint16Ptr(1), ""},
   256  		{"to *uint16 out of range neg", -1, false, new(uint16), uint16Ptr(0), "cannot convert from int8 to *uint16: value out of range: -1"},
   257  		{"to *uint8 nil dest", 1, false, uint8NilPtr(), uint8NilPtr(), "cannot convert from int8 to *uint8: destination is nil"},
   258  		{"to *uint8 nil source", 0, true, new(uint8), uint8Ptr(0), ""},
   259  		{"to *uint8 non nil", 1, false, new(uint8), uint8Ptr(1), ""},
   260  		{"to *uint8 out of range neg", -1, false, new(uint8), uint8Ptr(0), "cannot convert from int8 to *uint8: value out of range: -1"},
   261  		{"to *string nil dest", 1, false, stringNilPtr(), stringNilPtr(), "cannot convert from int8 to *string: destination is nil"},
   262  		{"to *string nil source", 0, true, new(string), new(string), ""},
   263  		{"to *string non nil", 1, false, new(string), stringPtr("1"), ""},
   264  		{"to untyped nil", 1, false, nil, nil, "cannot convert from int8 to <nil>: destination is nil"},
   265  		{"to non pointer", 1, false, int8(0), int8(0), "cannot convert from int8 to int8: destination is not pointer"},
   266  		{"to unsupported pointer type", 1, false, new(float64), new(float64), "cannot convert from int8 to *float64: conversion not supported"},
   267  	}
   268  	for _, tt := range tests {
   269  		t.Run(tt.name, func(t *testing.T) {
   270  			err := convertFromInt8(tt.val, tt.wasNull, tt.dest)
   271  			assert.Equal(t, tt.expected, tt.dest)
   272  			assertErrorMessage(t, tt.err, err)
   273  		})
   274  	}
   275  }
   276  
   277  func Test_writeInt8(t *testing.T) {
   278  	tests := []struct {
   279  		name     string
   280  		val      int8
   281  		expected []byte
   282  	}{
   283  		{"zero", 0, tinyintZeroBytes},
   284  		{"positive", 1, tinyintOneBytes},
   285  		{"negative", -1, tinyintMinusOneBytes},
   286  		{"max", math.MaxInt8, tinyintMaxInt8Bytes},
   287  		{"min", math.MinInt8, tinyintMinInt8Bytes},
   288  	}
   289  	for _, tt := range tests {
   290  		t.Run(tt.name, func(t *testing.T) {
   291  			actual := writeInt8(tt.val)
   292  			assert.Equal(t, tt.expected, actual)
   293  		})
   294  	}
   295  }
   296  
   297  func Test_readInt8(t *testing.T) {
   298  	tests := []struct {
   299  		name     string
   300  		source   []byte
   301  		expected int8
   302  		wasNull  bool
   303  		err      string
   304  	}{
   305  		{"nil", nil, 0, true, ""},
   306  		{"empty", []byte{}, 0, true, ""},
   307  		{"wrong length", []byte{1, 2}, 0, false, "cannot read int8: expected 1 bytes but got: 2"},
   308  		{"zero", tinyintZeroBytes, 0, false, ""},
   309  		{"positive", tinyintOneBytes, 1, false, ""},
   310  		{"negative", tinyintMinusOneBytes, -1, false, ""},
   311  		{"max", tinyintMaxInt8Bytes, math.MaxInt8, false, ""},
   312  		{"min", tinyintMinInt8Bytes, math.MinInt8, false, ""},
   313  	}
   314  	for _, tt := range tests {
   315  		t.Run(tt.name, func(t *testing.T) {
   316  			actual, wasNull, err := readInt8(tt.source)
   317  			assert.Equal(t, tt.expected, actual)
   318  			assert.Equal(t, tt.wasNull, wasNull)
   319  			assertErrorMessage(t, tt.err, err)
   320  		})
   321  	}
   322  }