github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datatype/tuple_test.go (about) 1 // Copyright 2020 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 datatype 16 17 import ( 18 "bytes" 19 "errors" 20 "fmt" 21 "testing" 22 23 "github.com/stretchr/testify/assert" 24 "github.com/stretchr/testify/require" 25 26 "github.com/datastax/go-cassandra-native-protocol/primitive" 27 ) 28 29 func TestTupleType(t *testing.T) { 30 tupleType := NewTuple(Varchar, Int) 31 assert.Equal(t, primitive.DataTypeCodeTuple, tupleType.Code()) 32 assert.Equal(t, []DataType{Varchar, Int}, tupleType.FieldTypes) 33 } 34 35 func TestTupleTypeDeepCopy(t *testing.T) { 36 tt := NewTuple(Varchar, Int) 37 cloned := tt.DeepCopy() 38 assert.Equal(t, tt, cloned) 39 cloned.FieldTypes = []DataType{Int, Uuid, Float} 40 assert.NotEqual(t, tt, cloned) 41 assert.Equal(t, primitive.DataTypeCodeTuple, tt.Code()) 42 assert.Equal(t, []DataType{Varchar, Int}, tt.FieldTypes) 43 assert.Equal(t, primitive.DataTypeCodeTuple, cloned.Code()) 44 assert.Equal(t, []DataType{Int, Uuid, Float}, cloned.FieldTypes) 45 } 46 47 func TestTupleTypeDeepCopy_NilFieldTypesSlice(t *testing.T) { 48 tt := NewTuple(Varchar, Int) 49 tt.FieldTypes = nil 50 cloned := tt.DeepCopy() 51 assert.Equal(t, tt, cloned) 52 cloned.FieldTypes = []DataType{Int, Uuid, Float} 53 assert.NotEqual(t, tt, cloned) 54 assert.Equal(t, primitive.DataTypeCodeTuple, tt.Code()) 55 assert.Nil(t, tt.FieldTypes) 56 assert.Equal(t, primitive.DataTypeCodeTuple, cloned.Code()) 57 assert.Equal(t, []DataType{Int, Uuid, Float}, cloned.FieldTypes) 58 } 59 60 func TestTupleTypeDeepCopy_NilFieldType(t *testing.T) { 61 tt := NewTuple(nil, Int) 62 cloned := tt.DeepCopy() 63 assert.Equal(t, tt, cloned) 64 cloned.FieldTypes = []DataType{Int, Uuid, Float} 65 assert.NotEqual(t, tt, cloned) 66 assert.Equal(t, primitive.DataTypeCodeTuple, tt.Code()) 67 assert.Equal(t, []DataType{nil, Int}, tt.FieldTypes) 68 assert.Equal(t, primitive.DataTypeCodeTuple, cloned.Code()) 69 assert.Equal(t, []DataType{Int, Uuid, Float}, cloned.FieldTypes) 70 } 71 72 func TestTupleTypeDeepCopy_ComplexFieldTypes(t *testing.T) { 73 tt := NewTuple(NewList(NewTuple(Varchar)), Int) 74 cloned := tt.DeepCopy() 75 assert.Equal(t, tt, cloned) 76 cloned.FieldTypes[0].(*List).ElementType = NewTuple(Int) 77 assert.NotEqual(t, tt, cloned) 78 assert.Equal(t, primitive.DataTypeCodeTuple, tt.Code()) 79 assert.Equal(t, []DataType{NewList(NewTuple(Varchar)), Int}, tt.FieldTypes) 80 assert.Equal(t, primitive.DataTypeCodeTuple, cloned.Code()) 81 assert.Equal(t, []DataType{NewList(NewTuple(Int)), Int}, cloned.FieldTypes) 82 } 83 84 func TestWriteTupleType(t *testing.T) { 85 tests := []struct { 86 name string 87 input DataType 88 expected []byte 89 err error 90 }{ 91 { 92 "simple tuple", 93 NewTuple(Varchar, Int), 94 []byte{ 95 0, byte(primitive.DataTypeCodeTuple & 0xFF), 96 0, 2, // field count 97 0, byte(primitive.DataTypeCodeVarchar & 0xFF), 98 0, byte(primitive.DataTypeCodeInt & 0xFF), 99 }, 100 nil, 101 }, 102 { 103 "complex tuple", 104 NewTuple(NewTuple(Varchar, Int), NewTuple(Boolean, Float)), 105 []byte{ 106 0, byte(primitive.DataTypeCodeTuple & 0xFF), 107 0, 2, // field count 108 0, byte(primitive.DataTypeCodeTuple & 0xFF), 109 0, 2, // field count 110 0, byte(primitive.DataTypeCodeVarchar & 0xFF), 111 0, byte(primitive.DataTypeCodeInt & 0xFF), 112 0, byte(primitive.DataTypeCodeTuple & 0xFF), 113 0, 2, // field count 114 0, byte(primitive.DataTypeCodeBoolean & 0xFF), 115 0, byte(primitive.DataTypeCodeFloat & 0xFF), 116 }, 117 nil, 118 }, 119 {"nil tuple", nil, nil, errors.New("DataType can not be nil")}, 120 } 121 122 t.Run("versions_with_tuple_support", func(t *testing.T) { 123 for _, version := range primitive.SupportedProtocolVersionsGreaterThanOrEqualTo(primitive.ProtocolVersion3) { 124 t.Run(version.String(), func(t *testing.T) { 125 for _, test := range tests { 126 t.Run(test.name, func(t *testing.T) { 127 var dest = &bytes.Buffer{} 128 var err error 129 err = WriteDataType(test.input, dest, version) 130 actual := dest.Bytes() 131 assert.Equal(t, test.err, err) 132 assert.Equal(t, test.expected, actual) 133 }) 134 } 135 }) 136 } 137 }) 138 139 t.Run("versions_without_tuple_support", func(t *testing.T) { 140 for _, version := range primitive.SupportedProtocolVersionsLesserThan(primitive.ProtocolVersion3) { 141 t.Run(version.String(), func(t *testing.T) { 142 for _, test := range tests { 143 t.Run(test.name, func(t *testing.T) { 144 var dest = &bytes.Buffer{} 145 var err error 146 err = WriteDataType(test.input, dest, version) 147 actual := dest.Bytes() 148 require.NotNil(t, err) 149 if test.err != nil { 150 assert.Equal(t, test.err, err) 151 } else { 152 assert.Contains(t, err.Error(), 153 fmt.Sprintf("invalid data type code for %s: DataTypeCode Tuple", version)) 154 } 155 assert.Equal(t, 0, len(actual)) 156 }) 157 } 158 }) 159 } 160 }) 161 } 162 163 func TestLengthOfTupleType(t *testing.T) { 164 for _, version := range primitive.SupportedProtocolVersions() { 165 t.Run(version.String(), func(t *testing.T) { 166 tests := []struct { 167 name string 168 input DataType 169 expected int 170 err error 171 }{ 172 { 173 "simple tuple", 174 NewTuple(Varchar, Int), 175 primitive.LengthOfShort * 3, 176 nil, 177 }, 178 { 179 "complex tuple", 180 NewTuple(NewTuple(Varchar, Int), NewTuple(Boolean, Float)), 181 primitive.LengthOfShort * 9, 182 nil, 183 }, 184 {"nil tuple", nil, -1, errors.New("expected *Tuple, got <nil>")}, 185 } 186 for _, test := range tests { 187 t.Run(test.name, func(t *testing.T) { 188 var actual int 189 var err error 190 actual, err = lengthOfTupleType(test.input, version) 191 assert.Equal(t, test.expected, actual) 192 assert.Equal(t, test.err, err) 193 }) 194 } 195 }) 196 } 197 } 198 199 func TestReadTupleType(t *testing.T) { 200 tests := []struct { 201 name string 202 input []byte 203 expected DataType 204 err error 205 }{ 206 { 207 "simple tuple", 208 []byte{ 209 0, byte(primitive.DataTypeCodeTuple & 0xFF), 210 0, 2, // field count 211 0, byte(primitive.DataTypeCodeVarchar & 0xFF), 212 0, byte(primitive.DataTypeCodeInt & 0xFF), 213 }, 214 NewTuple(Varchar, Int), 215 nil, 216 }, 217 { 218 "complex tuple", 219 []byte{ 220 0, byte(primitive.DataTypeCodeTuple & 0xFF), 221 0, 2, // field count 222 0, byte(primitive.DataTypeCodeTuple & 0xFF), 223 0, 2, // field count 224 0, byte(primitive.DataTypeCodeVarchar & 0xFF), 225 0, byte(primitive.DataTypeCodeInt & 0xFF), 226 0, byte(primitive.DataTypeCodeTuple & 0xFF), 227 0, 2, // field count 228 0, byte(primitive.DataTypeCodeBoolean & 0xFF), 229 0, byte(primitive.DataTypeCodeFloat & 0xFF), 230 }, 231 NewTuple(NewTuple(Varchar, Int), NewTuple(Boolean, Float)), 232 nil, 233 }, 234 { 235 "cannot read tuple", 236 []byte{ 237 0, byte(primitive.DataTypeCodeTuple & 0xFF)}, 238 nil, 239 fmt.Errorf("cannot read tuple field count: %w", 240 fmt.Errorf("cannot read [short]: %w", 241 errors.New("EOF"))), 242 }, 243 } 244 245 t.Run("versions_with_tuple_support", func(t *testing.T) { 246 for _, version := range primitive.SupportedProtocolVersionsGreaterThanOrEqualTo(primitive.ProtocolVersion3) { 247 t.Run(version.String(), func(t *testing.T) { 248 249 for _, test := range tests { 250 t.Run(test.name, func(t *testing.T) { 251 var source = bytes.NewBuffer(test.input) 252 var actual DataType 253 var err error 254 actual, err = ReadDataType(source, version) 255 assert.Equal(t, test.expected, actual) 256 assert.Equal(t, test.err, err) 257 }) 258 } 259 }) 260 } 261 }) 262 263 t.Run("versions_without_tuple_support", func(t *testing.T) { 264 for _, version := range primitive.SupportedProtocolVersionsLesserThan(primitive.ProtocolVersion3) { 265 t.Run(version.String(), func(t *testing.T) { 266 for _, test := range tests { 267 t.Run(test.name, func(t *testing.T) { 268 var source = bytes.NewBuffer(test.input) 269 var actual DataType 270 var err error 271 actual, err = ReadDataType(source, version) 272 require.NotNil(t, err) 273 assert.Contains(t, err.Error(), 274 fmt.Sprintf("invalid data type code for %s: DataTypeCode Tuple", version)) 275 assert.Nil(t, actual) 276 }) 277 } 278 }) 279 } 280 }) 281 } 282 283 func Test_tupleType_String(t1 *testing.T) { 284 tests := []struct { 285 name string 286 fieldTypes []DataType 287 want string 288 }{ 289 {"empty", []DataType{}, "tuple<>"}, 290 {"simple", []DataType{Int, Varchar, Boolean}, "tuple<int,varchar,boolean>"}, 291 {"complex", []DataType{Int, NewTuple(Varchar, Boolean)}, "tuple<int,tuple<varchar,boolean>>"}, 292 } 293 for _, tt := range tests { 294 t1.Run(tt.name, func(t *testing.T) { 295 tuple := NewTuple(tt.fieldTypes...) 296 got := tuple.AsCql() 297 assert.Equal(t, tt.want, got) 298 }) 299 } 300 }