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