github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/int_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  	intZeroBytes     = encodeUint32(0x00000000)
    30  	intOneBytes      = encodeUint32(0x00000001)
    31  	intMinusOneBytes = encodeUint32(0xffffffff)
    32  	intMaxInt32Bytes = encodeUint32(0x7fffffff)
    33  	intMinInt32Bytes = encodeUint32(0x80000000)
    34  )
    35  
    36  func Test_intCodec_Encode(t *testing.T) {
    37  	for _, version := range primitive.SupportedProtocolVersions() {
    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", int32NilPtr(), nil, ""},
    47  				{"non nil", 1, intOneBytes, ""},
    48  				{"conversion failed", uint32(math.MaxUint32), nil, fmt.Sprintf("cannot encode uint32 as CQL int with %v: cannot convert from uint32 to int32: value out of range: 4294967295", version)},
    49  			}
    50  			for _, tt := range tests {
    51  				t.Run(tt.name, func(t *testing.T) {
    52  					actual, err := Int.Encode(tt.source, version)
    53  					assert.Equal(t, tt.expected, actual)
    54  					assertErrorMessage(t, tt.err, err)
    55  				})
    56  			}
    57  		})
    58  	}
    59  }
    60  
    61  func Test_intCodec_Decode(t *testing.T) {
    62  	for _, version := range primitive.SupportedProtocolVersions() {
    63  		t.Run(version.String(), func(t *testing.T) {
    64  			tests := []struct {
    65  				name     string
    66  				source   []byte
    67  				dest     interface{}
    68  				expected interface{}
    69  				wasNull  bool
    70  				err      string
    71  			}{
    72  				{"null", nil, new(int32), new(int32), true, ""},
    73  				{"non null", intOneBytes, new(int32), int32Ptr(1), false, ""},
    74  				{"non null interface", intOneBytes, new(interface{}), interfacePtr(int32(1)), false, ""},
    75  				{"read failed", []byte{1}, new(int32), new(int32), false, fmt.Sprintf("cannot decode CQL int as *int32 with %v: cannot read int32: expected 4 bytes but got: 1", version)},
    76  				{"conversion failed", intOneBytes, new(float64), new(float64), false, fmt.Sprintf("cannot decode CQL int as *float64 with %v: cannot convert from int32 to *float64: conversion not supported", version)},
    77  			}
    78  			for _, tt := range tests {
    79  				t.Run(tt.name, func(t *testing.T) {
    80  					wasNull, err := Int.Decode(tt.source, tt.dest, version)
    81  					assert.Equal(t, tt.expected, tt.dest)
    82  					assert.Equal(t, tt.wasNull, wasNull)
    83  					assertErrorMessage(t, tt.err, err)
    84  				})
    85  			}
    86  		})
    87  	}
    88  }
    89  
    90  func Test_convertToInt32(t *testing.T) {
    91  	tests := []struct {
    92  		name     string
    93  		input    interface{}
    94  		expected int32
    95  		wasNil   bool
    96  		err      string
    97  	}{
    98  		{"from int", int(1), 1, false, ""},
    99  		{"from int out of range pos", int(math.MaxInt32 + 1), 0, false, "cannot convert from int to int32: value out of range: 2147483648"},
   100  		{"from int out of range neg", int(math.MinInt32 - 1), 0, false, "cannot convert from int to int32: value out of range: -2147483649"},
   101  		{"from *int non nil", intPtr(1), 1, false, ""},
   102  		{"from *int nil", intNilPtr(), 0, true, ""},
   103  		{"from *int out of range pos", intPtr(math.MaxInt32 + 1), 0, false, "cannot convert from *int to int32: value out of range: 2147483648"},
   104  		{"from *int out of range neg", intPtr(math.MinInt32 - 1), 0, false, "cannot convert from *int to int32: value out of range: -2147483649"},
   105  		{"from int64", int64(1), 1, false, ""},
   106  		{"from int64 out of range pos", int64(math.MaxInt32 + 1), 0, false, "cannot convert from int64 to int32: value out of range: 2147483648"},
   107  		{"from int64 out of range neg", int64(math.MinInt32 - 1), 0, false, "cannot convert from int64 to int32: value out of range: -2147483649"},
   108  		{"from *int64 non nil", int64Ptr(1), 1, false, ""},
   109  		{"from *int64 nil", int64NilPtr(), 0, true, ""},
   110  		{"from *int64 out of range pos", int64Ptr(math.MaxInt32 + 1), 0, false, "cannot convert from *int64 to int32: value out of range: 2147483648"},
   111  		{"from *int64 out of range neg", int64Ptr(math.MinInt32 - 1), 0, false, "cannot convert from *int64 to int32: value out of range: -2147483649"},
   112  		{"from int32", int32(1), 1, false, ""},
   113  		{"from *int32 non nil", int32Ptr(1), 1, false, ""},
   114  		{"from *int32 nil", int32NilPtr(), 0, true, ""},
   115  		{"from int16", int16(1), 1, false, ""},
   116  		{"from *int16 non nil", int16Ptr(1), 1, false, ""},
   117  		{"from *int16 nil", int16NilPtr(), 0, true, ""},
   118  		{"from int8", int8(1), 1, false, ""},
   119  		{"from *int8 non nil", int8Ptr(1), 1, false, ""},
   120  		{"from *int8 nil", int8NilPtr(), 0, true, ""},
   121  		{"from uint", uint(1), 1, false, ""},
   122  		{"from uint out of range", uint(math.MaxInt32 + 1), 0, false, "cannot convert from uint to int32: value out of range: 2147483648"},
   123  		{"from *uint non nil", uintPtr(1), 1, false, ""},
   124  		{"from *uint nil", uintNilPtr(), 0, true, ""},
   125  		{"from *uint out of range", uintPtr(math.MaxInt32 + 1), 0, false, "cannot convert from *uint to int32: value out of range: 2147483648"},
   126  		{"from uint64", uint64(1), 1, false, ""},
   127  		{"from uint64 out of range", uint64(math.MaxInt32 + 1), 0, false, "cannot convert from uint64 to int32: value out of range: 2147483648"},
   128  		{"from *uint64 non nil", uint64Ptr(1), 1, false, ""},
   129  		{"from *uint64 nil", uint64NilPtr(), 0, true, ""},
   130  		{"from *uint64 out of range", uint64Ptr(math.MaxInt32 + 1), 0, false, "cannot convert from *uint64 to int32: value out of range: 2147483648"},
   131  		{"from uint32", uint32(1), 1, false, ""},
   132  		{"from uint32 out of range", uint32(math.MaxInt32 + 1), 0, false, "cannot convert from uint32 to int32: value out of range: 2147483648"},
   133  		{"from *uint32 non nil", uint32Ptr(1), 1, false, ""},
   134  		{"from *uint32 nil", uint32NilPtr(), 0, true, ""},
   135  		{"from *uint32 out of range", uint32Ptr(math.MaxInt32 + 1), 0, false, "cannot convert from *uint32 to int32: value out of range: 2147483648"},
   136  		{"from uint16", uint16(1), 1, false, ""},
   137  		{"from *uint16 non nil", uint16Ptr(1), 1, false, ""},
   138  		{"from *uint16 nil", uint16NilPtr(), 0, true, ""},
   139  		{"from uint8", uint8(1), 1, false, ""},
   140  		{"from *uint8 non nil", uint8Ptr(1), 1, false, ""},
   141  		{"from *uint8 nil", uint8NilPtr(), 0, true, ""},
   142  		{"from string", "1", 1, false, ""},
   143  		{"from string malformed", "not a number", 0, false, "cannot convert from string to int32: cannot parse 'not a number'"},
   144  		{"from string out of range", strconv.Itoa(math.MaxInt32 + 1), 0, false, "cannot convert from string to int32: cannot parse '2147483648'"},
   145  		{"from *string non nil", stringPtr("1"), 1, false, ""},
   146  		{"from *string malformed", stringPtr("not a number"), 0, false, "cannot convert from *string to int32: cannot parse 'not a number'"},
   147  		{"from *string out of range", stringPtr(strconv.Itoa(math.MaxInt32 + 1)), 0, false, "cannot convert from *string to int32: cannot parse '2147483648'"},
   148  		{"from *string nil", stringNilPtr(), 0, true, ""},
   149  		{"from untyped nil", nil, 0, true, ""},
   150  		{"from unsupported value type", 42.0, 0, false, "cannot convert from float64 to int32: conversion not supported"},
   151  		{"from unsupported pointer type", float64Ptr(42.0), 0, false, "cannot convert from *float64 to int32: conversion not supported"},
   152  	}
   153  	for _, tt := range tests {
   154  		t.Run(tt.name, func(t *testing.T) {
   155  			dest, wasNil, err := convertToInt32(tt.input)
   156  			assert.Equal(t, tt.expected, dest)
   157  			assert.Equal(t, tt.wasNil, wasNil)
   158  			assertErrorMessage(t, tt.err, err)
   159  		})
   160  	}
   161  }
   162  
   163  func Test_convertFromInt32(t *testing.T) {
   164  	tests := []struct {
   165  		name     string
   166  		val      int32
   167  		wasNull  bool
   168  		dest     interface{}
   169  		expected interface{}
   170  		err      string
   171  	}{
   172  		{"to *interface{} nil dest", 1, false, interfaceNilPtr(), interfaceNilPtr(), "cannot convert from int32 to *interface {}: destination is nil"},
   173  		{"to *interface{} nil source", 0, true, new(interface{}), new(interface{}), ""},
   174  		{"to *interface{} non nil", 1, false, new(interface{}), interfacePtr(int32(1)), ""},
   175  		{"to *int nil dest", 1, false, intNilPtr(), intNilPtr(), "cannot convert from int32 to *int: destination is nil"},
   176  		{"to *int nil source", 0, true, new(int), intPtr(0), ""},
   177  		{"to *int non nil", 1, false, new(int), intPtr(1), ""},
   178  		{"to *int64 nil dest", 1, false, int64NilPtr(), int64NilPtr(), "cannot convert from int32 to *int64: destination is nil"},
   179  		{"to *int64 nil source", 0, true, new(int64), int64Ptr(0), ""},
   180  		{"to *int64 non nil", 1, false, new(int64), int64Ptr(1), ""},
   181  		{"to *int32 nil dest", 1, false, int32NilPtr(), int32NilPtr(), "cannot convert from int32 to *int32: destination is nil"},
   182  		{"to *int32 nil source", 0, true, new(int32), int32Ptr(0), ""},
   183  		{"to *int32 non nil", 1, false, new(int32), int32Ptr(1), ""},
   184  		{"to *int16 nil dest", 1, false, int16NilPtr(), int16NilPtr(), "cannot convert from int32 to *int16: destination is nil"},
   185  		{"to *int16 nil source", 0, true, new(int16), int16Ptr(0), ""},
   186  		{"to *int16 non nil", 1, false, new(int16), int16Ptr(1), ""},
   187  		{"to *int16 out of range pos", math.MaxInt16 + 1, false, new(int16), int16Ptr(0), "cannot convert from int32 to *int16: value out of range: 32768"},
   188  		{"to *int16 out of range neg", math.MinInt16 - 1, false, new(int16), int16Ptr(0), "cannot convert from int32 to *int16: value out of range: -32769"},
   189  		{"to *int8 nil dest", 1, false, int8NilPtr(), int8NilPtr(), "cannot convert from int32 to *int8: destination is nil"},
   190  		{"to *int8 nil source", 0, true, new(int8), int8Ptr(0), ""},
   191  		{"to *int8 non nil", 1, false, new(int8), int8Ptr(1), ""},
   192  		{"to *int8 out of range pos", math.MaxInt8 + 1, false, new(int8), int8Ptr(0), "cannot convert from int32 to *int8: value out of range: 128"},
   193  		{"to *int8 out of range neg", math.MinInt8 - 1, false, new(int8), int8Ptr(0), "cannot convert from int32 to *int8: value out of range: -129"},
   194  		{"to *uint nil dest", 1, false, uintNilPtr(), uintNilPtr(), "cannot convert from int32 to *uint: destination is nil"},
   195  		{"to *uint nil source", 0, true, new(uint), uintPtr(0), ""},
   196  		{"to *uint non nil", 1, false, new(uint), uintPtr(1), ""},
   197  		{"to *uint out of range neg", -1, false, new(uint), new(uint), "cannot convert from int32 to *uint: value out of range: -1"},
   198  		{"to *uint64 nil dest", 1, false, uint64NilPtr(), uint64NilPtr(), "cannot convert from int32 to *uint64: destination is nil"},
   199  		{"to *uint64 nil source", 0, true, new(uint64), uint64Ptr(0), ""},
   200  		{"to *uint64 non nil", 1, false, new(uint64), uint64Ptr(1), ""},
   201  		{"to *uint64 out of range neg", -1, false, new(uint64), uint64Ptr(0), "cannot convert from int32 to *uint64: value out of range: -1"},
   202  		{"to *uint32 nil dest", 1, false, uint32NilPtr(), uint32NilPtr(), "cannot convert from int32 to *uint32: destination is nil"},
   203  		{"to *uint32 nil source", 0, true, new(uint32), uint32Ptr(0), ""},
   204  		{"to *uint32 non nil", 1, false, new(uint32), uint32Ptr(1), ""},
   205  		{"to *uint32 out of range neg", -1, false, new(uint32), uint32Ptr(0), "cannot convert from int32 to *uint32: value out of range: -1"},
   206  		{"to *uint16 nil dest", 1, false, uint16NilPtr(), uint16NilPtr(), "cannot convert from int32 to *uint16: destination is nil"},
   207  		{"to *uint16 nil source", 0, true, new(uint16), uint16Ptr(0), ""},
   208  		{"to *uint16 non nil", 1, false, new(uint16), uint16Ptr(1), ""},
   209  		{"to *uint16 out of range pos", math.MaxUint16 + 1, false, new(uint16), uint16Ptr(0), "cannot convert from int32 to *uint16: value out of range: 65536"},
   210  		{"to *uint16 out of range neg", -1, false, new(uint16), uint16Ptr(0), "cannot convert from int32 to *uint16: value out of range: -1"},
   211  		{"to *uint8 nil dest", 1, false, uint8NilPtr(), uint8NilPtr(), "cannot convert from int32 to *uint8: destination is nil"},
   212  		{"to *uint8 nil source", 0, true, new(uint8), uint8Ptr(0), ""},
   213  		{"to *uint8 non nil", 1, false, new(uint8), uint8Ptr(1), ""},
   214  		{"to *uint8 out of range pos", math.MaxUint8 + 1, false, new(uint8), uint8Ptr(0), "cannot convert from int32 to *uint8: value out of range: 256"},
   215  		{"to *uint8 out of range neg", -1, false, new(uint8), uint8Ptr(0), "cannot convert from int32 to *uint8: value out of range: -1"},
   216  		{"to *string nil dest", 1, false, stringNilPtr(), stringNilPtr(), "cannot convert from int32 to *string: destination is nil"},
   217  		{"to *string nil source", 0, true, new(string), new(string), ""},
   218  		{"to *string non nil", 1, false, new(string), stringPtr("1"), ""},
   219  		{"to untyped nil", 1, false, nil, nil, "cannot convert from int32 to <nil>: destination is nil"},
   220  		{"to non pointer", 1, false, int32(0), int32(0), "cannot convert from int32 to int32: destination is not pointer"},
   221  		{"to unsupported pointer type", 1, false, new(float64), new(float64), "cannot convert from int32 to *float64: conversion not supported"},
   222  	}
   223  	for _, tt := range tests {
   224  		t.Run(tt.name, func(t *testing.T) {
   225  			err := convertFromInt32(tt.val, tt.wasNull, tt.dest)
   226  			assert.Equal(t, tt.expected, tt.dest)
   227  			assertErrorMessage(t, tt.err, err)
   228  		})
   229  	}
   230  }
   231  
   232  func Test_writeInt32(t *testing.T) {
   233  	tests := []struct {
   234  		name     string
   235  		val      int32
   236  		expected []byte
   237  	}{
   238  		{"zero", 0, intZeroBytes},
   239  		{"positive", 1, intOneBytes},
   240  		{"negative", -1, intMinusOneBytes},
   241  		{"max", math.MaxInt32, intMaxInt32Bytes},
   242  		{"min", math.MinInt32, intMinInt32Bytes},
   243  	}
   244  	for _, tt := range tests {
   245  		t.Run(tt.name, func(t *testing.T) {
   246  			actual := writeInt32(tt.val)
   247  			assert.Equal(t, tt.expected, actual)
   248  		})
   249  	}
   250  }
   251  
   252  func Test_readInt32(t *testing.T) {
   253  	tests := []struct {
   254  		name     string
   255  		source   []byte
   256  		expected int32
   257  		wasNull  bool
   258  		err      string
   259  	}{
   260  		{"nil", nil, 0, true, ""},
   261  		{"empty", []byte{}, 0, true, ""},
   262  		{"wrong length", []byte{1}, 0, false, "cannot read int32: expected 4 bytes but got: 1"},
   263  		{"zero", intZeroBytes, 0, false, ""},
   264  		{"positive", intOneBytes, 1, false, ""},
   265  		{"negative", intMinusOneBytes, -1, false, ""},
   266  		{"max", intMaxInt32Bytes, math.MaxInt32, false, ""},
   267  		{"min", intMinInt32Bytes, math.MinInt32, false, ""},
   268  	}
   269  	for _, tt := range tests {
   270  		t.Run(tt.name, func(t *testing.T) {
   271  			actual, wasNull, err := readInt32(tt.source)
   272  			assert.Equal(t, tt.expected, actual)
   273  			assert.Equal(t, tt.wasNull, wasNull)
   274  			assertErrorMessage(t, tt.err, err)
   275  		})
   276  	}
   277  }