github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/varint_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 "testing" 22 23 "github.com/stretchr/testify/assert" 24 25 "github.com/datastax/go-cassandra-native-protocol/datatype" 26 "github.com/datastax/go-cassandra-native-protocol/primitive" 27 ) 28 29 var ( 30 hugeBigIntPos = new(big.Int).Add(new(big.Int).SetUint64(math.MaxUint64), oneBigInt) 31 hugeBigIntNeg = new(big.Int).Sub(big.NewInt(math.MinInt64), oneBigInt) 32 ) 33 34 func Test_varintCodec_DataType(t *testing.T) { 35 assert.Equal(t, datatype.Varint, Varint.DataType()) 36 } 37 38 func Test_varintCodec_Encode(t *testing.T) { 39 for _, version := range primitive.SupportedProtocolVersions() { 40 t.Run(version.String(), func(t *testing.T) { 41 tests := []struct { 42 name string 43 source interface{} 44 expected []byte 45 err string 46 }{ 47 {"nil", nil, nil, ""}, 48 {"nil pointer", bigIntNilPtr(), nil, ""}, 49 {"non nil", oneBigInt, []byte{1}, ""}, 50 {"conversion failed", float64(0), nil, fmt.Sprintf("cannot encode float64 as CQL varint with %v: cannot convert from float64 to *big.Int: conversion not supported", version)}, 51 } 52 for _, tt := range tests { 53 t.Run(tt.name, func(t *testing.T) { 54 actual, err := Varint.Encode(tt.source, version) 55 assert.Equal(t, tt.expected, actual) 56 assertErrorMessage(t, tt.err, err) 57 }) 58 } 59 }) 60 } 61 } 62 63 func Test_varintCodec_Decode(t *testing.T) { 64 for _, version := range primitive.SupportedProtocolVersions() { 65 t.Run(version.String(), func(t *testing.T) { 66 tests := []struct { 67 name string 68 source []byte 69 dest interface{} 70 expected interface{} 71 wasNull bool 72 err string 73 }{ 74 {"null", nil, new(big.Int), new(big.Int), true, ""}, 75 {"non null", []byte{1}, new(big.Int), oneBigInt, false, ""}, 76 {"non null interface", []byte{1}, new(interface{}), interfacePtr(oneBigInt), false, ""}, 77 {"conversion failed", []byte{1}, new(float64), new(float64), false, fmt.Sprintf("cannot decode CQL varint as *float64 with %v: cannot convert from *big.Int to *float64: conversion not supported", version)}, 78 } 79 for _, tt := range tests { 80 t.Run(tt.name, func(t *testing.T) { 81 wasNull, err := Varint.Decode(tt.source, tt.dest, version) 82 assert.Equal(t, tt.expected, tt.dest) 83 assert.Equal(t, tt.wasNull, wasNull) 84 assertErrorMessage(t, tt.err, err) 85 }) 86 } 87 }) 88 } 89 } 90 91 func Test_convertToBigInt(t *testing.T) { 92 tests := []struct { 93 name string 94 input interface{} 95 expected *big.Int 96 err string 97 }{ 98 {"from *big.Int non nil", oneBigInt, oneBigInt, ""}, 99 {"from *big.Int nil", bigIntNilPtr(), nil, ""}, 100 {"from int", int(1), oneBigInt, ""}, 101 {"from *int non nil", intPtr(1), oneBigInt, ""}, 102 {"from *int nil", intNilPtr(), nil, ""}, 103 {"from int64", int64(1), oneBigInt, ""}, 104 {"from *int64 non nil", int64Ptr(1), oneBigInt, ""}, 105 {"from *int64 nil", int64NilPtr(), nil, ""}, 106 {"from int32", int32(1), oneBigInt, ""}, 107 {"from *int32 non nil", int32Ptr(1), oneBigInt, ""}, 108 {"from *int32 nil", int32NilPtr(), nil, ""}, 109 {"from int16", int16(1), oneBigInt, ""}, 110 {"from *int16 non nil", int16Ptr(1), oneBigInt, ""}, 111 {"from *int16 nil", int16NilPtr(), nil, ""}, 112 {"from int8", int8(1), oneBigInt, ""}, 113 {"from *int8 non nil", int8Ptr(1), oneBigInt, ""}, 114 {"from *int8 nil", int8NilPtr(), nil, ""}, 115 {"from uint", uint(1), oneBigInt, ""}, 116 {"from *uint non nil", uintPtr(1), oneBigInt, ""}, 117 {"from *uint nil", uintNilPtr(), nil, ""}, 118 {"from uint64", uint64(1), oneBigInt, ""}, 119 {"from *uint64 non nil", uint64Ptr(1), oneBigInt, ""}, 120 {"from *uint64 nil", uint64NilPtr(), nil, ""}, 121 {"from uint32", uint32(1), oneBigInt, ""}, 122 {"from *uint32 non nil", uint32Ptr(1), oneBigInt, ""}, 123 {"from *uint32 nil", uint32NilPtr(), nil, ""}, 124 {"from uint16", uint16(1), oneBigInt, ""}, 125 {"from *uint16 non nil", uint16Ptr(1), oneBigInt, ""}, 126 {"from *uint16 nil", uint16NilPtr(), nil, ""}, 127 {"from uint8", uint8(1), oneBigInt, ""}, 128 {"from *uint8 non nil", uint8Ptr(1), oneBigInt, ""}, 129 {"from *uint8 nil", uint8NilPtr(), nil, ""}, 130 {"from string", "1", oneBigInt, ""}, 131 {"from string malformed", "not a number", nil, "cannot convert from string to *big.Int: cannot parse 'not a number'"}, 132 {"from *string non nil", stringPtr("1"), oneBigInt, ""}, 133 {"from *string malformed", stringPtr("not a number"), nil, "cannot convert from *string to *big.Int: cannot parse 'not a number'"}, 134 {"from *string nil", stringNilPtr(), nil, ""}, 135 {"from untyped nil", nil, nil, ""}, 136 {"from unsupported value type", 42.0, nil, "cannot convert from float64 to *big.Int: conversion not supported"}, 137 {"from unsupported pointer type", float64Ptr(42.0), nil, "cannot convert from *float64 to *big.Int: conversion not supported"}, 138 } 139 for _, tt := range tests { 140 t.Run(tt.name, func(t *testing.T) { 141 dest, err := convertToBigInt(tt.input) 142 assert.Equal(t, tt.expected, dest) 143 assertErrorMessage(t, tt.err, err) 144 }) 145 } 146 } 147 148 func Test_convertFromBigInt(t *testing.T) { 149 tests := []struct { 150 name string 151 val *big.Int 152 wasNull bool 153 dest interface{} 154 expected interface{} 155 err string 156 }{ 157 {"to *interface{} nil dest", oneBigInt, false, interfaceNilPtr(), interfaceNilPtr(), "cannot convert from *big.Int to *interface {}: destination is nil"}, 158 {"to *interface{} nil source", nil, true, new(interface{}), new(interface{}), ""}, 159 {"to *interface{} non nil", oneBigInt, false, new(interface{}), interfacePtr(oneBigInt), ""}, 160 {"to *big.Int nil dest", oneBigInt, false, bigIntNilPtr(), bigIntNilPtr(), "cannot convert from *big.Int to *big.Int: destination is nil"}, 161 {"to *big.Int nil source", nil, true, new(big.Int), new(big.Int), ""}, 162 {"to *big.Int non nil", oneBigInt, false, big.NewInt(1), big.NewInt(1), ""}, 163 {"to *int nil dest", oneBigInt, false, intNilPtr(), intNilPtr(), "cannot convert from *big.Int to *int: destination is nil"}, 164 {"to *int nil source", nil, true, new(int), intPtr(0), ""}, 165 {"to *int non nil", oneBigInt, false, new(int), intPtr(1), ""}, 166 {"to *int out of range pos", hugeBigIntPos, false, new(int), new(int), "cannot convert from *big.Int to *int: value out of range: 18446744073709551616"}, 167 {"to *int out of range neg", hugeBigIntNeg, false, new(int), new(int), "cannot convert from *big.Int to *int: value out of range: -9223372036854775809"}, 168 {"to *int64 nil dest", oneBigInt, false, int64NilPtr(), int64NilPtr(), "cannot convert from *big.Int to *int64: destination is nil"}, 169 {"to *int64 nil source", nil, true, new(int64), int64Ptr(0), ""}, 170 {"to *int64 non nil", oneBigInt, false, new(int64), int64Ptr(1), ""}, 171 {"to *int64 out of range pos", hugeBigIntPos, false, new(int64), new(int64), "cannot convert from *big.Int to *int64: value out of range: 18446744073709551616"}, 172 {"to *int64 out of range neg", hugeBigIntNeg, false, new(int64), new(int64), "cannot convert from *big.Int to *int64: value out of range: -9223372036854775809"}, 173 {"to *int32 nil dest", oneBigInt, false, int32NilPtr(), int32NilPtr(), "cannot convert from *big.Int to *int32: destination is nil"}, 174 {"to *int32 nil source", nil, true, new(int32), int32Ptr(0), ""}, 175 {"to *int32 non nil", oneBigInt, false, new(int32), int32Ptr(1), ""}, 176 {"to *int32 out of range pos", hugeBigIntPos, false, new(int32), new(int32), "cannot convert from *big.Int to *int32: value out of range: 18446744073709551616"}, 177 {"to *int32 out of range neg", hugeBigIntNeg, false, new(int32), new(int32), "cannot convert from *big.Int to *int32: value out of range: -9223372036854775809"}, 178 {"to *int16 nil dest", oneBigInt, false, int16NilPtr(), int16NilPtr(), "cannot convert from *big.Int to *int16: destination is nil"}, 179 {"to *int16 nil source", nil, true, new(int16), int16Ptr(0), ""}, 180 {"to *int16 non nil", oneBigInt, false, new(int16), int16Ptr(1), ""}, 181 {"to *int16 out of range pos", hugeBigIntPos, false, new(int16), new(int16), "cannot convert from *big.Int to *int16: value out of range: 18446744073709551616"}, 182 {"to *int16 out of range neg", hugeBigIntNeg, false, new(int16), new(int16), "cannot convert from *big.Int to *int16: value out of range: -9223372036854775809"}, 183 {"to *int8 nil dest", oneBigInt, false, int8NilPtr(), int8NilPtr(), "cannot convert from *big.Int to *int8: destination is nil"}, 184 {"to *int8 nil source", nil, true, new(int8), int8Ptr(0), ""}, 185 {"to *int8 non nil", oneBigInt, false, new(int8), int8Ptr(1), ""}, 186 {"to *int8 out of range pos", hugeBigIntPos, false, new(int8), new(int8), "cannot convert from *big.Int to *int8: value out of range: 18446744073709551616"}, 187 {"to *int8 out of range neg", hugeBigIntNeg, false, new(int8), new(int8), "cannot convert from *big.Int to *int8: value out of range: -9223372036854775809"}, 188 {"to *uint nil dest", oneBigInt, false, uintNilPtr(), uintNilPtr(), "cannot convert from *big.Int to *uint: destination is nil"}, 189 {"to *uint nil source", nil, true, new(uint), uintPtr(0), ""}, 190 {"to *uint non nil", oneBigInt, false, new(uint), uintPtr(1), ""}, 191 {"to *uint out of range pos", hugeBigIntPos, false, new(uint), new(uint), "cannot convert from *big.Int to *uint: value out of range: 18446744073709551616"}, 192 {"to *uint out of range neg", hugeBigIntNeg, false, new(uint), new(uint), "cannot convert from *big.Int to *uint: value out of range: -9223372036854775809"}, 193 {"to *uint64 nil dest", oneBigInt, false, uint64NilPtr(), uint64NilPtr(), "cannot convert from *big.Int to *uint64: destination is nil"}, 194 {"to *uint64 nil source", nil, true, new(uint64), uint64Ptr(0), ""}, 195 {"to *uint64 non nil", oneBigInt, false, new(uint64), uint64Ptr(1), ""}, 196 {"to *uint64 out of range pos", hugeBigIntPos, false, new(uint64), new(uint64), "cannot convert from *big.Int to *uint64: value out of range: 18446744073709551616"}, 197 {"to *uint64 out of range neg", hugeBigIntNeg, false, new(uint64), new(uint64), "cannot convert from *big.Int to *uint64: value out of range: -9223372036854775809"}, 198 {"to *uint32 nil dest", oneBigInt, false, uint32NilPtr(), uint32NilPtr(), "cannot convert from *big.Int to *uint32: destination is nil"}, 199 {"to *uint32 nil source", nil, true, new(uint32), uint32Ptr(0), ""}, 200 {"to *uint32 non nil", oneBigInt, false, new(uint32), uint32Ptr(1), ""}, 201 {"to *uint32 out of range pos", hugeBigIntPos, false, new(uint32), new(uint32), "cannot convert from *big.Int to *uint32: value out of range: 18446744073709551616"}, 202 {"to *uint32 out of range neg", hugeBigIntNeg, false, new(uint32), new(uint32), "cannot convert from *big.Int to *uint32: value out of range: -9223372036854775809"}, 203 {"to *uint16 nil dest", oneBigInt, false, uint16NilPtr(), uint16NilPtr(), "cannot convert from *big.Int to *uint16: destination is nil"}, 204 {"to *uint16 nil source", nil, true, new(uint16), uint16Ptr(0), ""}, 205 {"to *uint16 non nil", oneBigInt, false, new(uint16), uint16Ptr(1), ""}, 206 {"to *uint16 out of range pos", hugeBigIntPos, false, new(uint16), new(uint16), "cannot convert from *big.Int to *uint16: value out of range: 18446744073709551616"}, 207 {"to *uint16 out of range neg", hugeBigIntNeg, false, new(uint16), new(uint16), "cannot convert from *big.Int to *uint16: value out of range: -9223372036854775809"}, 208 {"to *uint8 nil dest", oneBigInt, false, uint8NilPtr(), uint8NilPtr(), "cannot convert from *big.Int to *uint8: destination is nil"}, 209 {"to *uint8 nil source", nil, true, new(uint8), uint8Ptr(0), ""}, 210 {"to *uint8 non nil", oneBigInt, false, new(uint8), uint8Ptr(1), ""}, 211 {"to *uint8 out of range pos", hugeBigIntPos, false, new(uint8), new(uint8), "cannot convert from *big.Int to *uint8: value out of range: 18446744073709551616"}, 212 {"to *uint8 out of range neg", hugeBigIntNeg, false, new(uint8), new(uint8), "cannot convert from *big.Int to *uint8: value out of range: -9223372036854775809"}, 213 {"to *string nil dest", oneBigInt, false, stringNilPtr(), stringNilPtr(), "cannot convert from *big.Int to *string: destination is nil"}, 214 {"to *string nil source", nil, true, new(string), new(string), ""}, 215 {"to *string non nil", oneBigInt, false, new(string), stringPtr("1"), ""}, 216 {"to untyped nil", oneBigInt, false, nil, nil, "cannot convert from *big.Int to <nil>: destination is nil"}, 217 {"to non pointer", oneBigInt, false, int64(0), int64(0), "cannot convert from *big.Int to int64: destination is not pointer"}, 218 {"to unsupported pointer type", oneBigInt, false, new(float64), new(float64), "cannot convert from *big.Int to *float64: conversion not supported"}, 219 } 220 for _, tt := range tests { 221 t.Run(tt.name, func(t *testing.T) { 222 err := convertFromBigInt(tt.val, tt.wasNull, tt.dest) 223 assert.Equal(t, tt.expected, tt.dest) 224 assertErrorMessage(t, tt.err, err) 225 }) 226 } 227 } 228 229 func Test_writeBigInt(t *testing.T) { 230 hugeNeg, ok := new(big.Int).SetString("-1042342234234123423435647768234", 10) 231 assert.True(t, ok) 232 tests := []struct { 233 name string 234 val *big.Int 235 expected []byte 236 }{ 237 {"nil", nil, nil}, 238 {"zero", zeroBigInt, []byte{0}}, 239 {"1", oneBigInt, []byte{1}}, 240 {"-1", big.NewInt(-1), []byte{0xff}}, 241 {"100", big.NewInt(100), []byte{0x64}}, 242 {"-100", big.NewInt(-100), []byte{0x9c}}, 243 {"128", big.NewInt(128), []byte{0x00, 0x80}}, 244 {"255", big.NewInt(255), []byte{0x00, 0xff}}, 245 {"MinInt32", big.NewInt(math.MinInt32), []byte{0x80, 0x00, 0x00, 0x00}}, 246 {"MaxInt32", big.NewInt(math.MaxInt32), []byte{0x7f, 0xff, 0xff, 0xff}}, 247 {"huge neg", hugeNeg, []byte{0xf2, 0xd8, 0x02, 0xb6, 0x52, 0x7f, 0x99, 0xee, 0x98, 0x23, 0x99, 0xa9, 0x56}}, 248 {"huge pos", new(big.Int).SetUint64(math.MaxUint64), []byte{0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, 249 } 250 for _, tt := range tests { 251 t.Run(tt.name, func(t *testing.T) { 252 actual := writeBigInt(tt.val) 253 assert.Equal(t, tt.expected, actual) 254 }) 255 } 256 } 257 258 func Test_readBigInt(t *testing.T) { 259 hugeNeg, ok := new(big.Int).SetString("-1042342234234123423435647768234", 10) 260 assert.True(t, ok) 261 tests := []struct { 262 name string 263 source []byte 264 expected *big.Int 265 }{ 266 {"nil", nil, nil}, 267 {"empty", []byte{}, nil}, 268 {"zero", []byte{0}, zeroBigInt}, 269 {"-1", []byte{0xff}, big.NewInt(-1)}, 270 {"100", []byte{0x64}, big.NewInt(100)}, 271 {"-100", []byte{0x9c}, big.NewInt(-100)}, 272 {"128", []byte{0x00, 0x80}, big.NewInt(128)}, 273 {"255", []byte{0x00, 0xff}, big.NewInt(255)}, 274 {"huge neg", []byte{0xf2, 0xd8, 0x02, 0xb6, 0x52, 0x7f, 0x99, 0xee, 0x98, 0x23, 0x99, 0xa9, 0x56}, hugeNeg}, 275 {"huge pos", []byte{0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, new(big.Int).SetUint64(math.MaxUint64)}, 276 } 277 for _, tt := range tests { 278 t.Run(tt.name, func(t *testing.T) { 279 actual := readBigInt(tt.source) 280 assert.Zero(t, tt.expected.Cmp(actual)) 281 }) 282 } 283 }