github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/float_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 "testing" 21 22 "github.com/stretchr/testify/assert" 23 24 "github.com/datastax/go-cassandra-native-protocol/datatype" 25 "github.com/datastax/go-cassandra-native-protocol/primitive" 26 ) 27 28 var ( 29 floatZeroBytes = encodeUint32(0x00000000) 30 floatOneBytes = encodeUint32(0x3f800000) 31 floatMinusOneBytes = encodeUint32(0xbf800000) 32 floatMaxFloat32Bytes = encodeUint32(0x7f7fffff) 33 ) 34 35 func Test_floatCodec_DataType(t *testing.T) { 36 assert.Equal(t, datatype.Float, Float.DataType()) 37 } 38 39 func Test_floatCodec_Encode(t *testing.T) { 40 for _, version := range primitive.SupportedProtocolVersions() { 41 t.Run(version.String(), func(t *testing.T) { 42 tests := []struct { 43 name string 44 source interface{} 45 expected []byte 46 err string 47 }{ 48 {"nil", nil, nil, ""}, 49 {"nil pointer", float32NilPtr(), nil, ""}, 50 {"non nil", 1.0, floatOneBytes, ""}, 51 {"conversion failed", int32(42), nil, fmt.Sprintf("cannot encode int32 as CQL float with %v: cannot convert from int32 to float32: conversion not supported", version)}, 52 } 53 for _, tt := range tests { 54 t.Run(tt.name, func(t *testing.T) { 55 actual, err := Float.Encode(tt.source, version) 56 assert.Equal(t, tt.expected, actual) 57 assertErrorMessage(t, tt.err, err) 58 }) 59 } 60 }) 61 } 62 } 63 64 func Test_floatCodec_Decode(t *testing.T) { 65 for _, version := range primitive.SupportedProtocolVersions() { 66 t.Run(version.String(), func(t *testing.T) { 67 tests := []struct { 68 name string 69 source []byte 70 dest interface{} 71 expected interface{} 72 wasNull bool 73 err string 74 }{ 75 {"null", nil, new(float32), new(float32), true, ""}, 76 {"non null", floatOneBytes, new(float32), float32Ptr(1), false, ""}, 77 {"non null interface", floatOneBytes, new(interface{}), interfacePtr(float32(1.0)), false, ""}, 78 {"read failed", []byte{1}, new(float32), new(float32), false, fmt.Sprintf("cannot decode CQL float as *float32 with %v: cannot read float32: expected 4 bytes but got: 1", version)}, 79 {"conversion failed", floatOneBytes, new(int64), new(int64), false, fmt.Sprintf("cannot decode CQL float as *int64 with %v: cannot convert from float32 to *int64: conversion not supported", version)}, 80 } 81 for _, tt := range tests { 82 t.Run(tt.name, func(t *testing.T) { 83 wasNull, err := Float.Decode(tt.source, tt.dest, version) 84 assert.Equal(t, tt.expected, tt.dest) 85 assert.Equal(t, tt.wasNull, wasNull) 86 assertErrorMessage(t, tt.err, err) 87 }) 88 } 89 }) 90 } 91 } 92 93 func Test_convertToFloat32(t *testing.T) { 94 tests := []struct { 95 name string 96 input interface{} 97 expected float32 98 wasNil bool 99 err string 100 }{ 101 {"from float64", float64(1), 1, false, ""}, 102 {"from float64 out of range", math.MaxFloat64, 0, false, "cannot convert from float64 to float32: value out of range: 1.7976931348623157e+308"}, 103 {"from *float64 non nil", float64Ptr(1), 1, false, ""}, 104 {"from *float64 nil", float64NilPtr(), 0, true, ""}, 105 {"from *float64 out of range", float64Ptr(math.MaxFloat64), 0, false, "cannot convert from *float64 to float32: value out of range: 1.7976931348623157e+308"}, 106 {"from float32", float32(1), 1, false, ""}, 107 {"from *float32 non nil", float32Ptr(1), 1, false, ""}, 108 {"from *float32 nil", float32NilPtr(), 0, true, ""}, 109 {"from untyped nil", nil, 0, true, ""}, 110 {"from unsupported value type", 42, 0, false, "cannot convert from int to float32: conversion not supported"}, 111 {"from unsupported pointer type", int32Ptr(42), 0, false, "cannot convert from *int32 to float32: conversion not supported"}, 112 } 113 for _, tt := range tests { 114 t.Run(tt.name, func(t *testing.T) { 115 dest, wasNil, err := convertToFloat32(tt.input) 116 assert.Equal(t, tt.expected, dest) 117 assert.Equal(t, tt.wasNil, wasNil) 118 assertErrorMessage(t, tt.err, err) 119 }) 120 } 121 } 122 123 func Test_convertFromFloat32(t *testing.T) { 124 tests := []struct { 125 name string 126 val float32 127 wasNull bool 128 dest interface{} 129 expected interface{} 130 err string 131 }{ 132 {"to *interface{} nil dest", 1, false, interfaceNilPtr(), interfaceNilPtr(), "cannot convert from float32 to *interface {}: destination is nil"}, 133 {"to *interface{} nil source", 0, true, new(interface{}), new(interface{}), ""}, 134 {"to *interface{} non nil", 1, false, new(interface{}), interfacePtr(float32(1)), ""}, 135 {"to *float64 nil dest", 1, false, float64NilPtr(), float64NilPtr(), "cannot convert from float32 to *float64: destination is nil"}, 136 {"to *float64 nil source", 0, true, new(float64), float64Ptr(0), ""}, 137 {"to *float64 non nil", 1, false, new(float64), float64Ptr(1), ""}, 138 {"to *float32 nil dest", 1, false, float32NilPtr(), float32NilPtr(), "cannot convert from float32 to *float32: destination is nil"}, 139 {"to *float32 nil source", 0, true, new(float32), float32Ptr(0), ""}, 140 {"to *float32 non nil", 1, false, new(float32), float32Ptr(1), ""}, 141 {"to untyped nil", 1, false, nil, nil, "cannot convert from float32 to <nil>: destination is nil"}, 142 {"to non pointer", 1, false, int64(0), int64(0), "cannot convert from float32 to int64: destination is not pointer"}, 143 {"to unsupported pointer type", 1, false, new(int64), new(int64), "cannot convert from float32 to *int64: conversion not supported"}, 144 } 145 for _, tt := range tests { 146 t.Run(tt.name, func(t *testing.T) { 147 err := convertFromFloat32(tt.val, tt.wasNull, tt.dest) 148 assert.Equal(t, tt.expected, tt.dest) 149 assertErrorMessage(t, tt.err, err) 150 }) 151 } 152 } 153 154 func Test_writeFloat32(t *testing.T) { 155 tests := []struct { 156 name string 157 val float32 158 expected []byte 159 }{ 160 {"zero", 0, floatZeroBytes}, 161 {"1", 1, floatOneBytes}, 162 {"-1", -1, floatMinusOneBytes}, 163 {"simple pos", 123.4, encodeUint32(0x42f6cccd)}, 164 {"simple neg", -123.4, encodeUint32(0xc2f6cccd)}, 165 {"max", math.MaxFloat32, floatMaxFloat32Bytes}, 166 } 167 for _, tt := range tests { 168 t.Run(tt.name, func(t *testing.T) { 169 actual := writeFloat32(tt.val) 170 assert.Equal(t, tt.expected, actual) 171 }) 172 } 173 } 174 175 func Test_readFloat32(t *testing.T) { 176 tests := []struct { 177 name string 178 source []byte 179 expected float32 180 wasNull bool 181 err string 182 }{ 183 {"nil", nil, 0, true, ""}, 184 {"empty", []byte{}, 0, true, ""}, 185 {"wrong length", []byte{1}, 0, false, "cannot read float32: expected 4 bytes but got: 1"}, 186 {"zero", floatZeroBytes, 0, false, ""}, 187 {"1", floatOneBytes, 1, false, ""}, 188 {"-1", floatMinusOneBytes, -1, false, ""}, 189 {"simple pos", encodeUint32(0x42f6cccd), 123.4, false, ""}, 190 {"simple neg", encodeUint32(0xc2f6cccd), -123.4, false, ""}, 191 {"max", floatMaxFloat32Bytes, math.MaxFloat32, false, ""}, 192 } 193 for _, tt := range tests { 194 t.Run(tt.name, func(t *testing.T) { 195 actual, wasNull, err := readFloat32(tt.source) 196 assert.Equal(t, tt.expected, actual) 197 assert.Equal(t, tt.wasNull, wasNull) 198 assertErrorMessage(t, tt.err, err) 199 }) 200 } 201 }