github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/smallint_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  	smallintZeroBytes     = encodeUint16(0x0000)
    30  	smallintOneBytes      = encodeUint16(0x0001)
    31  	smallintMinusOneBytes = encodeUint16(0xffff)
    32  	smallintMaxInt16Bytes = encodeUint16(0x7fff)
    33  	smallintMinInt16Bytes = encodeUint16(0x8000)
    34  )
    35  
    36  func Test_smallintCodec_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", int16NilPtr(), nil, ""},
    47  				{"non nil", 1, smallintOneBytes, ""},
    48  				{"conversion failed", uint16(math.MaxUint16), nil, fmt.Sprintf("cannot encode uint16 as CQL smallint with %v: cannot convert from uint16 to int16: value out of range: 65535", version)},
    49  			}
    50  			for _, tt := range tests {
    51  				t.Run(tt.name, func(t *testing.T) {
    52  					actual, err := Smallint.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", int16NilPtr(), nil, "data type smallint not supported"},
    68  				{"non nil", 1, nil, "data type smallint not supported"},
    69  			}
    70  			for _, tt := range tests {
    71  				t.Run(tt.name, func(t *testing.T) {
    72  					actual, err := Smallint.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_smallintCodec_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(int16), new(int16), true, ""},
    93  				{"non null", smallintOneBytes, new(int16), int16Ptr(1), false, ""},
    94  				{"non null interface", smallintOneBytes, new(interface{}), interfacePtr(int16(1)), false, ""},
    95  				{"read failed", []byte{1}, new(int16), new(int16), false, fmt.Sprintf("cannot decode CQL smallint as *int16 with %v: cannot read int16: expected 2 bytes but got: 1", version)},
    96  				{"conversion failed", smallintOneBytes, new(float64), new(float64), false, fmt.Sprintf("cannot decode CQL smallint as *float64 with %v: cannot convert from int16 to *float64: conversion not supported", version)},
    97  			}
    98  			for _, tt := range tests {
    99  				t.Run(tt.name, func(t *testing.T) {
   100  					wasNull, err := Smallint.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(int16), new(int16), true, "data type smallint not supported"},
   119  				{"non null", smallintOneBytes, new(int16), new(int16), false, "data type smallint not supported"},
   120  			}
   121  			for _, tt := range tests {
   122  				t.Run(tt.name, func(t *testing.T) {
   123  					wasNull, err := Smallint.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_convertToInt16(t *testing.T) {
   134  	tests := []struct {
   135  		name     string
   136  		input    interface{}
   137  		expected int16
   138  		wasNil   bool
   139  		err      string
   140  	}{
   141  		{"from int", int(1), 1, false, ""},
   142  		{"from int out of range pos", int(math.MaxInt16 + 1), 0, false, "cannot convert from int to int16: value out of range: 32768"},
   143  		{"from int out of range neg", int(math.MinInt16 - 1), 0, false, "cannot convert from int to int16: value out of range: -32769"},
   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.MaxInt16 + 1), 0, false, "cannot convert from *int to int16: value out of range: 32768"},
   147  		{"from *int out of range neg", intPtr(math.MinInt16 - 1), 0, false, "cannot convert from *int to int16: value out of range: -32769"},
   148  		{"from int64", int64(1), 1, false, ""},
   149  		{"from int64 out of range pos", int64(math.MaxInt16 + 1), 0, false, "cannot convert from int64 to int16: value out of range: 32768"},
   150  		{"from int64 out of range neg", int64(math.MinInt16 - 1), 0, false, "cannot convert from int64 to int16: value out of range: -32769"},
   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.MaxInt16 + 1), 0, false, "cannot convert from *int64 to int16: value out of range: 32768"},
   154  		{"from *int64 out of range neg", int64Ptr(math.MinInt16 - 1), 0, false, "cannot convert from *int64 to int16: value out of range: -32769"},
   155  		{"from int32", int32(1), 1, false, ""},
   156  		{"from int32 out of range pos", int32(math.MaxInt16 + 1), 0, false, "cannot convert from int32 to int16: value out of range: 32768"},
   157  		{"from int32 out of range neg", int32(math.MinInt16 - 1), 0, false, "cannot convert from int32 to int16: value out of range: -32769"},
   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.MaxInt16 + 1), 0, false, "cannot convert from *int32 to int16: value out of range: 32768"},
   161  		{"from *int32 out of range neg", int32Ptr(math.MinInt16 - 1), 0, false, "cannot convert from *int32 to int16: value out of range: -32769"},
   162  		{"from int16", int16(1), 1, false, ""},
   163  		{"from *int16 non nil", int16Ptr(1), 1, false, ""},
   164  		{"from *int16 nil", int16NilPtr(), 0, true, ""},
   165  		{"from int8", int8(1), 1, false, ""},
   166  		{"from *int8 non nil", int8Ptr(1), 1, false, ""},
   167  		{"from *int8 nil", int8NilPtr(), 0, true, ""},
   168  		{"from uint", uint(1), 1, false, ""},
   169  		{"from uint out of range", uint(math.MaxInt16 + 1), 0, false, "cannot convert from uint to int16: value out of range: 32768"},
   170  		{"from *uint non nil", uintPtr(1), 1, false, ""},
   171  		{"from *uint nil", uintNilPtr(), 0, true, ""},
   172  		{"from *uint out of range", uintPtr(math.MaxInt16 + 1), 0, false, "cannot convert from *uint to int16: value out of range: 32768"},
   173  		{"from uint64", uint64(1), 1, false, ""},
   174  		{"from uint64 out of range", uint64(math.MaxInt16 + 1), 0, false, "cannot convert from uint64 to int16: value out of range: 32768"},
   175  		{"from *uint64 non nil", uint64Ptr(1), 1, false, ""},
   176  		{"from *uint64 nil", uint64NilPtr(), 0, true, ""},
   177  		{"from *uint64 out of range", uint64Ptr(math.MaxInt16 + 1), 0, false, "cannot convert from *uint64 to int16: value out of range: 32768"},
   178  		{"from uint32", uint32(1), 1, false, ""},
   179  		{"from uint32 out of range", uint32(math.MaxInt16 + 1), 0, false, "cannot convert from uint32 to int16: value out of range: 32768"},
   180  		{"from *uint32 non nil", uint32Ptr(1), 1, false, ""},
   181  		{"from *uint32 nil", uint32NilPtr(), 0, true, ""},
   182  		{"from *uint32 out of range", uint32Ptr(math.MaxInt16 + 1), 0, false, "cannot convert from *uint32 to int16: value out of range: 32768"},
   183  		{"from uint16", uint16(1), 1, false, ""},
   184  		{"from uint16 out of range", uint16(math.MaxInt16 + 1), 0, false, "cannot convert from uint16 to int16: value out of range: 32768"},
   185  		{"from *uint16 non nil", uint16Ptr(1), 1, false, ""},
   186  		{"from *uint16 nil", uint16NilPtr(), 0, true, ""},
   187  		{"from *uint16 out of range", uint16Ptr(math.MaxInt16 + 1), 0, false, "cannot convert from *uint16 to int16: value out of range: 32768"},
   188  		{"from uint8", uint8(1), 1, false, ""},
   189  		{"from *uint8 non nil", uint8Ptr(1), 1, false, ""},
   190  		{"from *uint8 nil", uint8NilPtr(), 0, true, ""},
   191  		{"from string", "1", 1, false, ""},
   192  		{"from string malformed", "not a number", 0, false, "cannot convert from string to int16: cannot parse 'not a number'"},
   193  		{"from string out of range", strconv.Itoa(math.MaxInt16 + 1), 0, false, "cannot convert from string to int16: cannot parse '32768'"},
   194  		{"from *string non nil", stringPtr("1"), 1, false, ""},
   195  		{"from *string malformed", stringPtr("not a number"), 0, false, "cannot convert from *string to int16: cannot parse 'not a number'"},
   196  		{"from *string out of range", stringPtr(strconv.Itoa(math.MaxInt16 + 1)), 0, false, "cannot convert from *string to int16: cannot parse '32768'"},
   197  		{"from *string nil", stringNilPtr(), 0, true, ""},
   198  		{"from untyped nil", nil, 0, true, ""},
   199  		{"from unsupported value type", 42.0, 0, false, "cannot convert from float64 to int16: conversion not supported"},
   200  		{"from unsupported pointer type", float64Ptr(42.0), 0, false, "cannot convert from *float64 to int16: conversion not supported"},
   201  	}
   202  	for _, tt := range tests {
   203  		t.Run(tt.name, func(t *testing.T) {
   204  			dest, wasNil, err := convertToInt16(tt.input)
   205  			assert.Equal(t, tt.expected, dest)
   206  			assert.Equal(t, tt.wasNil, wasNil)
   207  			assertErrorMessage(t, tt.err, err)
   208  		})
   209  	}
   210  }
   211  
   212  func Test_convertFromInt16(t *testing.T) {
   213  	tests := []struct {
   214  		name     string
   215  		val      int16
   216  		wasNull  bool
   217  		dest     interface{}
   218  		expected interface{}
   219  		err      string
   220  	}{
   221  		{"to *interface{} nil dest", 1, false, interfaceNilPtr(), interfaceNilPtr(), "cannot convert from int16 to *interface {}: destination is nil"},
   222  		{"to *interface{} nil source", 0, true, new(interface{}), new(interface{}), ""},
   223  		{"to *interface{} non nil", 1, false, new(interface{}), interfacePtr(int16(1)), ""},
   224  		{"to *int nil dest", 1, false, intNilPtr(), intNilPtr(), "cannot convert from int16 to *int: destination is nil"},
   225  		{"to *int nil source", 0, true, new(int), intPtr(0), ""},
   226  		{"to *int non nil", 1, false, new(int), intPtr(1), ""},
   227  		{"to *int64 nil dest", 1, false, int64NilPtr(), int64NilPtr(), "cannot convert from int16 to *int64: destination is nil"},
   228  		{"to *int64 nil source", 0, true, new(int64), int64Ptr(0), ""},
   229  		{"to *int64 non nil", 1, false, new(int64), int64Ptr(1), ""},
   230  		{"to *int32 nil dest", 1, false, int32NilPtr(), int32NilPtr(), "cannot convert from int16 to *int32: destination is nil"},
   231  		{"to *int32 nil source", 0, true, new(int32), int32Ptr(0), ""},
   232  		{"to *int32 non nil", 1, false, new(int32), int32Ptr(1), ""},
   233  		{"to *int16 nil dest", 1, false, int16NilPtr(), int16NilPtr(), "cannot convert from int16 to *int16: destination is nil"},
   234  		{"to *int16 nil source", 0, true, new(int16), int16Ptr(0), ""},
   235  		{"to *int16 non nil", 1, false, new(int16), int16Ptr(1), ""},
   236  		{"to *int8 nil dest", 1, false, int8NilPtr(), int8NilPtr(), "cannot convert from int16 to *int8: destination is nil"},
   237  		{"to *int8 nil source", 0, true, new(int8), int8Ptr(0), ""},
   238  		{"to *int8 non nil", 1, false, new(int8), int8Ptr(1), ""},
   239  		{"to *int8 out of range pos", math.MaxInt8 + 1, false, new(int8), int8Ptr(0), "cannot convert from int16 to *int8: value out of range: 128"},
   240  		{"to *int8 out of range neg", math.MinInt8 - 1, false, new(int8), int8Ptr(0), "cannot convert from int16 to *int8: value out of range: -129"},
   241  		{"to *uint nil dest", 1, false, uintNilPtr(), uintNilPtr(), "cannot convert from int16 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 int16 to *uint: value out of range: -1"},
   245  		{"to *uint64 nil dest", 1, false, uint64NilPtr(), uint64NilPtr(), "cannot convert from int16 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 int16 to *uint64: value out of range: -1"},
   249  		{"to *uint32 nil dest", 1, false, uint32NilPtr(), uint32NilPtr(), "cannot convert from int16 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 int16 to *uint32: value out of range: -1"},
   253  		{"to *uint16 nil dest", 1, false, uint16NilPtr(), uint16NilPtr(), "cannot convert from int16 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 int16 to *uint16: value out of range: -1"},
   257  		{"to *uint8 nil dest", 1, false, uint8NilPtr(), uint8NilPtr(), "cannot convert from int16 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 pos", math.MaxUint8 + 1, false, new(uint8), uint8Ptr(0), "cannot convert from int16 to *uint8: value out of range: 256"},
   261  		{"to *uint8 out of range neg", -1, false, new(uint8), uint8Ptr(0), "cannot convert from int16 to *uint8: value out of range: -1"},
   262  		{"to *string nil dest", 1, false, stringNilPtr(), stringNilPtr(), "cannot convert from int16 to *string: destination is nil"},
   263  		{"to *string nil source", 0, true, new(string), new(string), ""},
   264  		{"to *string non nil", 1, false, new(string), stringPtr("1"), ""},
   265  		{"to untyped nil", 1, false, nil, nil, "cannot convert from int16 to <nil>: destination is nil"},
   266  		{"to non pointer", 1, false, int16(0), int16(0), "cannot convert from int16 to int16: destination is not pointer"},
   267  		{"to unsupported pointer type", 1, false, new(float64), new(float64), "cannot convert from int16 to *float64: conversion not supported"},
   268  	}
   269  	for _, tt := range tests {
   270  		t.Run(tt.name, func(t *testing.T) {
   271  			err := convertFromInt16(tt.val, tt.wasNull, tt.dest)
   272  			assert.Equal(t, tt.expected, tt.dest)
   273  			assertErrorMessage(t, tt.err, err)
   274  		})
   275  	}
   276  }
   277  
   278  func Test_writeInt16(t *testing.T) {
   279  	tests := []struct {
   280  		name     string
   281  		val      int16
   282  		expected []byte
   283  	}{
   284  		{"zero", 0, smallintZeroBytes},
   285  		{"positive", 1, smallintOneBytes},
   286  		{"negative", -1, smallintMinusOneBytes},
   287  		{"max", math.MaxInt16, smallintMaxInt16Bytes},
   288  		{"min", math.MinInt16, smallintMinInt16Bytes},
   289  	}
   290  	for _, tt := range tests {
   291  		t.Run(tt.name, func(t *testing.T) {
   292  			actual := writeInt16(tt.val)
   293  			assert.Equal(t, tt.expected, actual)
   294  		})
   295  	}
   296  }
   297  
   298  func Test_readInt16(t *testing.T) {
   299  	tests := []struct {
   300  		name     string
   301  		source   []byte
   302  		expected int16
   303  		wasNull  bool
   304  		err      string
   305  	}{
   306  		{"nil", nil, 0, true, ""},
   307  		{"empty", []byte{}, 0, true, ""},
   308  		{"wrong length", []byte{1}, 0, false, "cannot read int16: expected 2 bytes but got: 1"},
   309  		{"zero", smallintZeroBytes, 0, false, ""},
   310  		{"positive", smallintOneBytes, 1, false, ""},
   311  		{"negative", smallintMinusOneBytes, -1, false, ""},
   312  		{"max", smallintMaxInt16Bytes, math.MaxInt16, false, ""},
   313  		{"min", smallintMinInt16Bytes, math.MinInt16, false, ""},
   314  	}
   315  	for _, tt := range tests {
   316  		t.Run(tt.name, func(t *testing.T) {
   317  			actual, wasNull, err := readInt16(tt.source)
   318  			assert.Equal(t, tt.expected, actual)
   319  			assert.Equal(t, tt.wasNull, wasNull)
   320  			assertErrorMessage(t, tt.err, err)
   321  		})
   322  	}
   323  }