github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/tuple_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 "errors" 19 "testing" 20 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/mock" 23 24 "github.com/datastax/go-cassandra-native-protocol/datatype" 25 "github.com/datastax/go-cassandra-native-protocol/primitive" 26 ) 27 28 type ( 29 SimpleTuple struct { 30 Int int 31 Bool bool 32 String *string 33 } 34 partialTuple struct { 35 Int int 36 Bool bool 37 } 38 excessTuple struct { 39 Int int 40 Bool bool 41 String *string 42 Float float64 43 } 44 complexTuple struct { 45 SimpleTuple 46 Element2 *excessTuple 47 } 48 ) 49 50 var ( 51 tupleCodecEmpty, _ = NewTuple(datatype.NewTuple()) 52 tupleCodecSimple, _ = NewTuple(datatype.NewTuple(datatype.Int, datatype.Boolean, datatype.Varchar)) 53 tupleCodecInts, _ = NewTuple(datatype.NewTuple(datatype.Int, datatype.Int, datatype.Int)) // can be mapped to []int 54 tupleCodecComplex, _ = NewTuple(datatype.NewTuple(tupleCodecSimple.DataType(), tupleCodecSimple.DataType())) 55 ) 56 57 var ( 58 tupleNullsBytes = []byte{ 59 255, 255, 255, 255, // nil int 60 255, 255, 255, 255, // nil boolean 61 255, 255, 255, 255, // nil string 62 } 63 tupleOneTwoThreeTrueAbcBytes = []byte{ 64 0, 0, 0, 4, // length of int 65 0, 0, 0, 123, // int 66 0, 0, 0, 1, // length of boolean 67 1, // boolean 68 0, 0, 0, 3, // length of string 69 a, b, c, // string 70 } 71 tupleOneTwoThreeFalseNilBytes = []byte{ 72 0, 0, 0, 4, // length of int 73 0, 0, 0, 123, // int 74 0, 0, 0, 1, // length of boolean 75 0, // boolean 76 255, 255, 255, 255, // nil string 77 } 78 tupleZeroFalseNilBytes = []byte{ 79 0, 0, 0, 4, // length of int 80 0, 0, 0, 0, // int 81 0, 0, 0, 1, // length of boolean 82 0, // boolean 83 255, 255, 255, 255, // nil string 84 } 85 tupleComplexBytes = []byte{ 86 0, 0, 0, 20, // length of element 1 87 // element 1 88 0, 0, 0, 4, // length of int 89 0, 0, 0, 12, // int 90 0, 0, 0, 1, // length of boolean 91 0, // boolean 92 0, 0, 0, 3, // length of string 93 a, b, c, // string 94 0, 0, 0, 20, // length of element 2 95 // element 2 96 0, 0, 0, 4, // length of int 97 0, 0, 0, 34, // int 98 0, 0, 0, 1, // length of boolean 99 1, // boolean 100 0, 0, 0, 3, // length of string 101 d, e, f, // string 102 } 103 tupleComplexWithNullsBytes = []byte{ 104 0, 0, 0, 20, // length of element 1 105 // element 1 106 0, 0, 0, 4, // length of int 107 0, 0, 0, 12, // int 108 0, 0, 0, 1, // length of boolean 109 0, // boolean 110 0, 0, 0, 3, // length of string 111 a, b, c, // string 112 0, 0, 0, 17, // length of element 2 113 // element 2 114 0, 0, 0, 4, // length of int 115 0, 0, 0, 34, // int 116 0, 0, 0, 1, // length of boolean 117 1, // boolean 118 255, 255, 255, 255, // nil string 119 } 120 tupleComplexWithNulls2Bytes = []byte{ 121 0, 0, 0, 20, // length of element 1 122 // element 1 123 0, 0, 0, 4, // length of int 124 0, 0, 0, 12, // int 125 0, 0, 0, 1, // length of boolean 126 0, // boolean 127 0, 0, 0, 3, // length of string 128 a, b, c, // string 129 255, 255, 255, 255, // nil element 2 130 } 131 tupleOneTwoThreeBytes = []byte{ 132 0, 0, 0, 4, // length of int 133 0, 0, 0, 1, // int 134 0, 0, 0, 4, // length of int 135 0, 0, 0, 2, // int 136 0, 0, 0, 4, // length of int 137 0, 0, 0, 3, // int 138 } 139 tupleOneTwoNilBytes = []byte{ 140 0, 0, 0, 4, // length of int 141 0, 0, 0, 1, // int 142 0, 0, 0, 4, // length of int 143 0, 0, 0, 2, // int 144 255, 255, 255, 255, // nil int 145 } 146 tupleOneNilNilBytes = []byte{ 147 0, 0, 0, 4, // length of int 148 0, 0, 0, 1, // int 149 255, 255, 255, 255, // nil int 150 255, 255, 255, 255, // nil int 151 } 152 tupleMissingBytes = []byte{ 153 0, 0, 0, 4, // length of int 154 0, 0, 0, 123, // int 155 0, 0, 0, 1, // length of boolean 156 1, // boolean 157 0, 0, 0, 3, // length of string 158 // missing string 159 } 160 tupleIntMissingBytes = []byte{ 161 0, 0, 0, 4, // length of int 162 0, 0, 0, 1, // int 163 0, 0, 0, 4, // length of int 164 0, 0, 0, 2, // int 165 0, 0, 0, 4, // length of int 166 // missing int 167 } 168 ) 169 170 func TestNewTupleCodec(t *testing.T) { 171 tests := []struct { 172 name string 173 dataType *datatype.Tuple 174 expected Codec 175 err string 176 }{ 177 { 178 "simple", 179 datatype.NewTuple(datatype.Int, datatype.Varchar), 180 &tupleCodec{ 181 dataType: datatype.NewTuple(datatype.Int, datatype.Varchar), 182 elementCodecs: []Codec{Int, Varchar}, 183 }, 184 "", 185 }, 186 { 187 "complex", 188 datatype.NewTuple(datatype.Int, datatype.NewTuple(datatype.Int, datatype.Varchar)), 189 &tupleCodec{ 190 dataType: datatype.NewTuple(datatype.Int, datatype.NewTuple(datatype.Int, datatype.Varchar)), 191 elementCodecs: []Codec{Int, &tupleCodec{ 192 dataType: datatype.NewTuple(datatype.Int, datatype.Varchar), 193 elementCodecs: []Codec{Int, Varchar}, 194 }}, 195 }, 196 "", 197 }, 198 { 199 "empty", 200 datatype.NewTuple(), 201 &tupleCodec{ 202 dataType: datatype.NewTuple(), 203 elementCodecs: []Codec{}, 204 }, 205 "", 206 }, 207 { 208 "wrong child", 209 datatype.NewTuple(wrongDataType{}), 210 nil, 211 "cannot create codec for tuple element 0: cannot create data codec for CQL type 666", 212 }, 213 { 214 "nil", 215 nil, 216 nil, 217 "data type is nil", 218 }, 219 } 220 for _, tt := range tests { 221 t.Run(tt.name, func(t *testing.T) { 222 actual, err := NewTuple(tt.dataType) 223 assert.Equal(t, tt.expected, actual) 224 assertErrorMessage(t, tt.err, err) 225 }) 226 } 227 } 228 229 func Test_tupleCodec_Encode(t *testing.T) { 230 for _, version := range primitive.SupportedProtocolVersionsGreaterThanOrEqualTo(primitive.ProtocolVersion3) { 231 t.Run(version.String(), func(t *testing.T) { 232 t.Run("[]interface{}", func(t *testing.T) { 233 tests := []struct { 234 name string 235 codec Codec 236 input *[]interface{} 237 expected []byte 238 err string 239 }{ 240 {"nil", tupleCodecEmpty, nil, nil, ""}, 241 {"empty", tupleCodecSimple, &[]interface{}{nil, nil, nil}, tupleNullsBytes, ""}, 242 {"simple", tupleCodecSimple, &[]interface{}{123, true, "abc"}, tupleOneTwoThreeTrueAbcBytes, ""}, 243 {"simple with pointers", tupleCodecSimple, &[]interface{}{intPtr(123), boolPtr(true), stringPtr("abc")}, tupleOneTwoThreeTrueAbcBytes, ""}, 244 {"nil element", tupleCodecSimple, &[]interface{}{123, false, nil}, tupleOneTwoThreeFalseNilBytes, ""}, 245 {"not enough elements", tupleCodecSimple, &[]interface{}{123}, nil, "slice index out of range: 1"}, 246 {"too many elements", tupleCodecSimple, &[]interface{}{123, true, "abc", "extra"}, tupleOneTwoThreeTrueAbcBytes, ""}, 247 {"complex", tupleCodecComplex, &[]interface{}{[]interface{}{12, false, "abc"}, []interface{}{34, true, "def"}}, tupleComplexBytes, ""}, 248 } 249 for _, tt := range tests { 250 t.Run(tt.name, func(t *testing.T) { 251 if tt.input != nil { 252 t.Run("value", func(t *testing.T) { 253 dest, err := tt.codec.Encode(*tt.input, version) 254 assert.Equal(t, tt.expected, dest) 255 assertErrorMessage(t, tt.err, err) 256 }) 257 } 258 t.Run("pointer", func(t *testing.T) { 259 dest, err := tt.codec.Encode(tt.input, version) 260 assert.Equal(t, tt.expected, dest) 261 assertErrorMessage(t, tt.err, err) 262 }) 263 }) 264 } 265 }) 266 t.Run("struct simple", func(t *testing.T) { 267 tests := []struct { 268 name string 269 codec Codec 270 input *SimpleTuple 271 expected []byte 272 }{ 273 {"nil", tupleCodecEmpty, nil, nil}, 274 {"empty", tupleCodecSimple, &SimpleTuple{}, tupleZeroFalseNilBytes}, 275 {"simple", tupleCodecSimple, &SimpleTuple{123, true, stringPtr("abc")}, tupleOneTwoThreeTrueAbcBytes}, 276 {"nil element", tupleCodecSimple, &SimpleTuple{123, false, nil}, tupleOneTwoThreeFalseNilBytes}, 277 } 278 for _, tt := range tests { 279 t.Run(tt.name, func(t *testing.T) { 280 if tt.input != nil { 281 t.Run("value", func(t *testing.T) { 282 dest, err := tt.codec.Encode(*tt.input, version) 283 assert.Equal(t, tt.expected, dest) 284 assert.NoError(t, err) 285 286 }) 287 } 288 t.Run("pointer", func(t *testing.T) { 289 dest, err := tt.codec.Encode(tt.input, version) 290 assert.Equal(t, tt.expected, dest) 291 assert.NoError(t, err) 292 }) 293 }) 294 } 295 }) 296 t.Run("struct partial", func(t *testing.T) { 297 tests := []struct { 298 name string 299 codec Codec 300 input *partialTuple 301 expected []byte 302 err string 303 }{ 304 {"simple", tupleCodecSimple, &partialTuple{123, false}, nil, "no accessible field with index 2 found"}, 305 } 306 for _, tt := range tests { 307 t.Run(tt.name, func(t *testing.T) { 308 if tt.input != nil { 309 t.Run("value", func(t *testing.T) { 310 dest, err := tt.codec.Encode(*tt.input, version) 311 assert.Equal(t, tt.expected, dest) 312 assertErrorMessage(t, tt.err, err) 313 }) 314 } 315 t.Run("pointer", func(t *testing.T) { 316 dest, err := tt.codec.Encode(tt.input, version) 317 assert.Equal(t, tt.expected, dest) 318 assertErrorMessage(t, tt.err, err) 319 }) 320 }) 321 } 322 }) 323 t.Run("struct excess", func(t *testing.T) { 324 tests := []struct { 325 name string 326 codec Codec 327 input *excessTuple 328 expected []byte 329 }{ 330 {"nil", tupleCodecEmpty, nil, nil}, 331 {"empty", tupleCodecSimple, &excessTuple{}, tupleZeroFalseNilBytes}, 332 {"simple", tupleCodecSimple, &excessTuple{123, true, stringPtr("abc"), 42.0}, tupleOneTwoThreeTrueAbcBytes}, 333 } 334 for _, tt := range tests { 335 t.Run(tt.name, func(t *testing.T) { 336 if tt.input != nil { 337 t.Run("value", func(t *testing.T) { 338 dest, err := tt.codec.Encode(*tt.input, version) 339 assert.Equal(t, tt.expected, dest) 340 assert.NoError(t, err) 341 }) 342 } 343 t.Run("pointer", func(t *testing.T) { 344 dest, err := tt.codec.Encode(tt.input, version) 345 assert.Equal(t, tt.expected, dest) 346 assert.NoError(t, err) 347 }) 348 }) 349 } 350 }) 351 t.Run("struct complex", func(t *testing.T) { 352 tests := []struct { 353 name string 354 codec Codec 355 input *complexTuple 356 expected []byte 357 }{ 358 {"nil", tupleCodecEmpty, nil, nil}, 359 {"empty", tupleCodecEmpty, &complexTuple{}, nil}, 360 {"complex", tupleCodecComplex, &complexTuple{ 361 SimpleTuple{12, false, stringPtr("abc")}, 362 &excessTuple{34, true, nil, 0.0}, 363 }, []byte{ 364 0, 0, 0, 20, // length of element 1 365 // element 1 366 0, 0, 0, 4, // length of int 367 0, 0, 0, 12, // int 368 0, 0, 0, 1, // length of boolean 369 0, // boolean 370 0, 0, 0, 3, // length of string 371 a, b, c, // string 372 0, 0, 0, 17, // length of element 2 373 // element 2 374 0, 0, 0, 4, // length of int 375 0, 0, 0, 34, // int 376 0, 0, 0, 1, // length of boolean 377 1, // boolean 378 255, 255, 255, 255, // nil string 379 }}, 380 {"nil element", tupleCodecComplex, &complexTuple{ 381 SimpleTuple{12, false, stringPtr("abc")}, 382 nil, 383 }, []byte{ 384 0, 0, 0, 20, // length of element 1 385 // element 1 386 0, 0, 0, 4, // length of int 387 0, 0, 0, 12, // int 388 0, 0, 0, 1, // length of boolean 389 0, // boolean 390 0, 0, 0, 3, // length of string 391 a, b, c, // string 392 255, 255, 255, 255, // nil element 2 393 }}, 394 } 395 for _, tt := range tests { 396 t.Run(tt.name, func(t *testing.T) { 397 if tt.input != nil { 398 t.Run("value", func(t *testing.T) { 399 dest, err := tt.codec.Encode(*tt.input, version) 400 assert.Equal(t, tt.expected, dest) 401 assert.NoError(t, err) 402 }) 403 } 404 t.Run("pointer", func(t *testing.T) { 405 dest, err := tt.codec.Encode(tt.input, version) 406 assert.Equal(t, tt.expected, dest) 407 assert.NoError(t, err) 408 }) 409 }) 410 } 411 }) 412 t.Run("[3]int", func(t *testing.T) { 413 tests := []struct { 414 name string 415 codec Codec 416 input *[3]int 417 expected []byte 418 }{ 419 {"nil", tupleCodecInts, nil, nil}, 420 {"non nil", tupleCodecInts, &[3]int{1, 2, 3}, tupleOneTwoThreeBytes}, 421 } 422 for _, tt := range tests { 423 t.Run(tt.name, func(t *testing.T) { 424 if tt.input != nil { 425 t.Run("value", func(t *testing.T) { 426 dest, err := tt.codec.Encode(*tt.input, version) 427 assert.Equal(t, tt.expected, dest) 428 assert.NoError(t, err) 429 }) 430 } 431 t.Run("pointer", func(t *testing.T) { 432 dest, err := tt.codec.Encode(tt.input, version) 433 assert.Equal(t, tt.expected, dest) 434 assert.NoError(t, err) 435 }) 436 }) 437 } 438 }) 439 t.Run("[3]*int", func(t *testing.T) { 440 tests := []struct { 441 name string 442 codec Codec 443 input *[3]*int 444 expected []byte 445 }{ 446 {"nil", tupleCodecInts, nil, nil}, 447 {"nil element", tupleCodecInts, &[3]*int{intPtr(1), nil, nil}, tupleOneNilNilBytes}, 448 } 449 for _, tt := range tests { 450 t.Run(tt.name, func(t *testing.T) { 451 if tt.input != nil { 452 t.Run("value", func(t *testing.T) { 453 dest, err := tt.codec.Encode(*tt.input, version) 454 assert.Equal(t, tt.expected, dest) 455 assert.NoError(t, err) 456 }) 457 } 458 t.Run("pointer", func(t *testing.T) { 459 dest, err := tt.codec.Encode(tt.input, version) 460 assert.Equal(t, tt.expected, dest) 461 assert.NoError(t, err) 462 }) 463 }) 464 } 465 }) 466 t.Run("[]int", func(t *testing.T) { 467 tests := []struct { 468 name string 469 codec Codec 470 input *[]int 471 expected []byte 472 err string 473 }{ 474 {"nil", tupleCodecInts, nil, nil, ""}, 475 {"non nil", tupleCodecInts, &[]int{1, 2, 3}, tupleOneTwoThreeBytes, ""}, 476 {"not enough elements", tupleCodecInts, &[]int{1}, nil, "slice index out of range: 1"}, 477 {"too many elements", tupleCodecInts, &[]int{1, 2, 3, 4, 5}, tupleOneTwoThreeBytes, ""}, 478 } 479 for _, tt := range tests { 480 t.Run(tt.name, func(t *testing.T) { 481 if tt.input != nil { 482 t.Run("value", func(t *testing.T) { 483 dest, err := tt.codec.Encode(*tt.input, version) 484 assert.Equal(t, tt.expected, dest) 485 assertErrorMessage(t, tt.err, err) 486 }) 487 } 488 t.Run("pointer", func(t *testing.T) { 489 dest, err := tt.codec.Encode(tt.input, version) 490 assert.Equal(t, tt.expected, dest) 491 assertErrorMessage(t, tt.err, err) 492 }) 493 }) 494 } 495 }) 496 t.Run("[]*int", func(t *testing.T) { 497 tests := []struct { 498 name string 499 codec Codec 500 input *[]*int 501 expected []byte 502 err string 503 }{ 504 {"nil", tupleCodecInts, nil, nil, ""}, 505 {"nil element", tupleCodecInts, &[]*int{intPtr(1), intPtr(2), nil}, tupleOneTwoNilBytes, ""}, 506 {"not enough elements", tupleCodecInts, &[]*int{intPtr(1)}, nil, "slice index out of range: 1"}, 507 {"too many elements", tupleCodecInts, &[]*int{intPtr(1), intPtr(2), nil, intPtr(4)}, tupleOneTwoNilBytes, ""}, 508 } 509 for _, tt := range tests { 510 t.Run(tt.name, func(t *testing.T) { 511 if tt.input != nil { 512 t.Run("value", func(t *testing.T) { 513 dest, err := tt.codec.Encode(*tt.input, version) 514 assert.Equal(t, tt.expected, dest) 515 assertErrorMessage(t, tt.err, err) 516 }) 517 } 518 t.Run("pointer", func(t *testing.T) { 519 dest, err := tt.codec.Encode(tt.input, version) 520 assert.Equal(t, tt.expected, dest) 521 assertErrorMessage(t, tt.err, err) 522 }) 523 }) 524 } 525 }) 526 }) 527 } 528 for _, version := range primitive.SupportedProtocolVersionsLesserThan(primitive.ProtocolVersion3) { 529 t.Run(version.String(), func(t *testing.T) { 530 codec, _ := NewTuple(datatype.NewTuple(datatype.Int)) 531 dest, err := codec.Encode(nil, version) 532 assert.Nil(t, dest) 533 assertErrorMessage(t, "data type tuple<int> not supported in "+version.String(), err) 534 }) 535 } 536 t.Run("invalid types", func(t *testing.T) { 537 dest, err := tupleCodecSimple.Encode(123, primitive.ProtocolVersion5) 538 assert.Nil(t, dest) 539 assert.EqualError(t, err, "cannot encode int as CQL tuple<int,boolean,varchar> with ProtocolVersion OSS 5: source type not supported") 540 }) 541 } 542 543 func Test_tupleCodec_Decode(t *testing.T) { 544 for _, version := range primitive.SupportedProtocolVersionsGreaterThanOrEqualTo(primitive.ProtocolVersion3) { 545 t.Run(version.String(), func(t *testing.T) { 546 t.Run("*interface{}", func(t *testing.T) { 547 tests := []struct { 548 name string 549 codec Codec 550 input []byte 551 dest *interface{} 552 expected *interface{} 553 err string 554 wasNull bool 555 }{ 556 {"nil input", tupleCodecSimple, nil, new(interface{}), new(interface{}), "", true}, 557 {"nil elements map to zero values", tupleCodecSimple, tupleNullsBytes, new(interface{}), interfacePtr([]interface{}{nil, nil, nil}), "", false}, 558 {"simple", tupleCodecSimple, tupleOneTwoThreeTrueAbcBytes, new(interface{}), interfacePtr([]interface{}{int32(123), true, "abc"}), "", false}, 559 {"complex", tupleCodecComplex, tupleComplexBytes, new(interface{}), interfacePtr([]interface{}{ 560 []interface{}{int32(12), false, "abc"}, 561 []interface{}{int32(34), true, "def"}, 562 }), "", false}, 563 {"nil dest", tupleCodecSimple, tupleOneTwoThreeTrueAbcBytes, nil, nil, "destination is nil", false}, 564 {"not enough bytes", tupleCodecSimple, tupleMissingBytes, new(interface{}), interfacePtr([]interface{}{int32(123), true, nil}), "cannot read element 2", false}, 565 {"slice length too large", tupleCodecSimple, tupleOneTwoThreeTrueAbcBytes, interfacePtr([]interface{}{nil, nil, nil, 42.0}), interfacePtr([]interface{}{int32(123), true, "abc"}), "", false}, 566 } 567 for _, tt := range tests { 568 t.Run(tt.name, func(t *testing.T) { 569 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 570 assert.Equal(t, tt.expected, tt.dest) 571 assert.Equal(t, tt.wasNull, wasNull) 572 assertErrorMessage(t, tt.err, err) 573 }) 574 } 575 }) 576 t.Run("*[]interface{}", func(t *testing.T) { 577 tests := []struct { 578 name string 579 codec Codec 580 input []byte 581 dest *[]interface{} 582 expected *[]interface{} 583 err string 584 wasNull bool 585 }{ 586 {name: "nil input", codec: tupleCodecSimple, dest: new([]interface{}), expected: new([]interface{}), wasNull: true}, 587 {"nil elements map to zero values", tupleCodecSimple, tupleNullsBytes, new([]interface{}), &[]interface{}{nil, nil, nil}, "", false}, 588 {"simple", tupleCodecSimple, tupleOneTwoThreeTrueAbcBytes, new([]interface{}), &[]interface{}{int32(123), true, "abc"}, "", false}, 589 {"complex", tupleCodecComplex, tupleComplexBytes, new([]interface{}), &[]interface{}{ 590 []interface{}{int32(12), false, "abc"}, 591 []interface{}{int32(34), true, "def"}, 592 }, "", false}, 593 {"nil dest", tupleCodecSimple, tupleOneTwoThreeTrueAbcBytes, nil, nil, "destination is nil", false}, 594 {"not enough bytes", tupleCodecSimple, tupleMissingBytes, new([]interface{}), &[]interface{}{int32(123), true, nil}, "cannot read element 2", false}, 595 {"slice length too large", tupleCodecSimple, tupleOneTwoThreeTrueAbcBytes, &[]interface{}{nil, nil, nil, 42.0}, &[]interface{}{int32(123), true, "abc"}, "", false}, 596 } 597 for _, tt := range tests { 598 t.Run(tt.name, func(t *testing.T) { 599 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 600 assert.Equal(t, tt.expected, tt.dest) 601 assert.Equal(t, tt.wasNull, wasNull) 602 assertErrorMessage(t, tt.err, err) 603 }) 604 } 605 }) 606 t.Run("struct simple", func(t *testing.T) { 607 tests := []struct { 608 name string 609 codec Codec 610 input []byte 611 dest *SimpleTuple 612 expected *SimpleTuple 613 err string 614 wasNull bool 615 }{ 616 {"nil input", tupleCodecSimple, nil, &SimpleTuple{}, &SimpleTuple{}, "", true}, 617 {"empty input", tupleCodecSimple, []byte{}, &SimpleTuple{}, &SimpleTuple{}, "", true}, 618 {"nil elements", tupleCodecSimple, tupleNullsBytes, &SimpleTuple{}, &SimpleTuple{Int: 0, Bool: false, String: nil}, "", false}, 619 {"simple", tupleCodecSimple, tupleOneTwoThreeTrueAbcBytes, &SimpleTuple{}, &SimpleTuple{Int: 123, Bool: true, String: stringPtr("abc")}, "", false}, 620 {"nil dest", tupleCodecSimple, tupleMissingBytes, nil, nil, "destination is nil", false}, 621 } 622 for _, tt := range tests { 623 t.Run(tt.name, func(t *testing.T) { 624 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 625 if tt.expected != nil && tt.dest != nil { 626 assert.Equal(t, *tt.expected, *tt.dest) 627 } 628 assert.Equal(t, tt.wasNull, wasNull) 629 assertErrorMessage(t, tt.err, err) 630 }) 631 } 632 }) 633 t.Run("struct partial", func(t *testing.T) { 634 tests := []struct { 635 name string 636 codec Codec 637 input []byte 638 dest *partialTuple 639 expected *partialTuple 640 err string 641 wasNull bool 642 }{ 643 {"simple", tupleCodecSimple, tupleOneTwoThreeTrueAbcBytes, &partialTuple{}, &partialTuple{Int: 123, Bool: true}, "no accessible field with index 2 found", false}, 644 } 645 for _, tt := range tests { 646 t.Run(tt.name, func(t *testing.T) { 647 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 648 if tt.expected != nil && tt.dest != nil { 649 assert.Equal(t, *tt.expected, *tt.dest) 650 } 651 assert.Equal(t, tt.wasNull, wasNull) 652 assertErrorMessage(t, tt.err, err) 653 }) 654 } 655 }) 656 t.Run("struct excess", func(t *testing.T) { 657 tests := []struct { 658 name string 659 codec Codec 660 input []byte 661 dest *excessTuple 662 expected *excessTuple 663 err string 664 wasNull bool 665 }{ 666 {"nil input", tupleCodecSimple, nil, &excessTuple{}, &excessTuple{}, "", true}, 667 {"empty input", tupleCodecSimple, []byte{}, &excessTuple{}, &excessTuple{}, "", true}, 668 {"nil elements", tupleCodecSimple, tupleNullsBytes, &excessTuple{}, &excessTuple{}, "", false}, 669 {"simple", tupleCodecSimple, tupleOneTwoThreeTrueAbcBytes, &excessTuple{}, &excessTuple{Int: 123, Bool: true, String: stringPtr("abc")}, "", false}, 670 {"nil dest", tupleCodecSimple, tupleMissingBytes, nil, nil, "destination is nil", false}, 671 } 672 for _, tt := range tests { 673 t.Run(tt.name, func(t *testing.T) { 674 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 675 if tt.expected != nil && tt.dest != nil { 676 assert.Equal(t, *tt.expected, *tt.dest) 677 } 678 assert.Equal(t, tt.wasNull, wasNull) 679 assertErrorMessage(t, tt.err, err) 680 }) 681 } 682 }) 683 t.Run("struct complex", func(t *testing.T) { 684 tests := []struct { 685 name string 686 codec Codec 687 input []byte 688 dest *complexTuple 689 expected *complexTuple 690 err string 691 wasNull bool 692 }{ 693 {"nil", tupleCodecComplex, nil, &complexTuple{}, &complexTuple{}, "", true}, 694 {"empty", tupleCodecComplex, []byte{}, &complexTuple{}, &complexTuple{}, "", true}, 695 {"complex", tupleCodecComplex, tupleComplexWithNullsBytes, &complexTuple{}, &complexTuple{ 696 SimpleTuple{12, false, stringPtr("abc")}, 697 &excessTuple{34, true, nil, 0.0}, 698 }, "", false}, 699 {"nil element", tupleCodecComplex, tupleComplexWithNulls2Bytes, &complexTuple{}, &complexTuple{ 700 SimpleTuple{12, false, stringPtr("abc")}, 701 nil, 702 }, "", false}, 703 } 704 for _, tt := range tests { 705 t.Run(tt.name, func(t *testing.T) { 706 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 707 assert.Equal(t, *tt.expected, *tt.dest) 708 assert.Equal(t, tt.wasNull, wasNull) 709 assertErrorMessage(t, tt.err, err) 710 }) 711 } 712 }) 713 t.Run("[3]int", func(t *testing.T) { 714 tests := []struct { 715 name string 716 codec Codec 717 input []byte 718 expected *[3]int 719 dest *[3]int 720 err string 721 wasNull bool 722 }{ 723 {"nil", tupleCodecInts, nil, new([3]int), new([3]int), "", true}, 724 {"non nil", tupleCodecInts, tupleOneTwoThreeBytes, &[3]int{1, 2, 3}, new([3]int), "", false}, 725 {"nil dest", tupleCodecInts, tupleOneTwoThreeBytes, nil, nil, "destination is nil", false}, 726 } 727 for _, tt := range tests { 728 t.Run(tt.name, func(t *testing.T) { 729 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 730 assert.Equal(t, tt.expected, tt.dest) 731 assert.Equal(t, tt.wasNull, wasNull) 732 assertErrorMessage(t, tt.err, err) 733 }) 734 } 735 }) 736 t.Run("[3]*int", func(t *testing.T) { 737 tests := []struct { 738 name string 739 codec Codec 740 input []byte 741 expected *[3]*int 742 dest *[3]*int 743 err string 744 wasNull bool 745 }{ 746 {"nil", tupleCodecInts, nil, new([3]*int), new([3]*int), "", true}, 747 {"non nil", tupleCodecInts, tupleOneTwoThreeBytes, &[3]*int{intPtr(1), intPtr(2), intPtr(3)}, new([3]*int), "", false}, 748 {"nil dest", tupleCodecInts, tupleOneTwoThreeBytes, nil, nil, "destination is nil", false}, 749 } 750 for _, tt := range tests { 751 t.Run(tt.name, func(t *testing.T) { 752 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 753 assert.Equal(t, tt.expected, tt.dest) 754 assert.Equal(t, tt.wasNull, wasNull) 755 assertErrorMessage(t, tt.err, err) 756 }) 757 } 758 }) 759 t.Run("[4]int", func(t *testing.T) { 760 tests := []struct { 761 name string 762 codec Codec 763 input []byte 764 expected *[4]int 765 dest *[4]int 766 err string 767 wasNull bool 768 }{ 769 {"nil", tupleCodecInts, nil, new([4]int), new([4]int), "", true}, 770 {"non nil", tupleCodecInts, tupleOneTwoThreeBytes, &[4]int{1, 2, 3, 0}, new([4]int), "", false}, 771 {"nil dest", tupleCodecInts, tupleOneTwoThreeBytes, nil, nil, "destination is nil", false}, 772 } 773 for _, tt := range tests { 774 t.Run(tt.name, func(t *testing.T) { 775 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 776 assert.Equal(t, tt.expected, tt.dest) 777 assert.Equal(t, tt.wasNull, wasNull) 778 assertErrorMessage(t, tt.err, err) 779 }) 780 } 781 }) 782 t.Run("[2]int", func(t *testing.T) { 783 tests := []struct { 784 name string 785 codec Codec 786 input []byte 787 expected *[2]int 788 dest *[2]int 789 err string 790 wasNull bool 791 }{ 792 {"non nil", tupleCodecInts, tupleOneTwoThreeBytes, &[2]int{1, 2}, new([2]int), "array index out of range: 2", false}, 793 } 794 for _, tt := range tests { 795 t.Run(tt.name, func(t *testing.T) { 796 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 797 assert.Equal(t, tt.expected, tt.dest) 798 assert.Equal(t, tt.wasNull, wasNull) 799 assertErrorMessage(t, tt.err, err) 800 }) 801 } 802 }) 803 t.Run("[]int", func(t *testing.T) { 804 tests := []struct { 805 name string 806 codec Codec 807 input []byte 808 expected *[]int 809 dest *[]int 810 err string 811 wasNull bool 812 }{ 813 {"nil", tupleCodecInts, nil, new([]int), new([]int), "", true}, 814 {"non nil", tupleCodecInts, tupleOneTwoThreeBytes, &[]int{1, 2, 3}, new([]int), "", false}, 815 {"not enough elements", tupleCodecInts, tupleIntMissingBytes, &[]int{1, 2, 0}, new([]int), "cannot read element 2", false}, 816 {"slice length too small", tupleCodecInts, tupleOneTwoThreeBytes, &[]int{1, 2, 3}, new([]int), "", false}, 817 {"slice length too large", tupleCodecInts, tupleOneTwoThreeBytes, &[]int{1, 2, 3}, &[]int{0, 0, 0, 0}, "", false}, 818 {"nil dest", tupleCodecInts, tupleOneTwoThreeBytes, nil, nil, "destination is nil", false}, 819 } 820 for _, tt := range tests { 821 t.Run(tt.name, func(t *testing.T) { 822 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 823 assert.Equal(t, tt.expected, tt.dest) 824 assert.Equal(t, tt.wasNull, wasNull) 825 assertErrorMessage(t, tt.err, err) 826 }) 827 } 828 }) 829 t.Run("[]*int", func(t *testing.T) { 830 tests := []struct { 831 name string 832 codec Codec 833 input []byte 834 expected *[]*int 835 dest *[]*int 836 err string 837 wasNull bool 838 }{ 839 {"nil", tupleCodecInts, nil, new([]*int), new([]*int), "", true}, 840 {"non nil", tupleCodecInts, tupleOneTwoThreeBytes, &[]*int{intPtr(1), intPtr(2), intPtr(3)}, new([]*int), "", false}, 841 {"nil dest", tupleCodecInts, tupleOneTwoThreeBytes, nil, nil, "destination is nil", false}, 842 {"slice length too small", tupleCodecInts, tupleOneTwoThreeBytes, &[]*int{intPtr(1), intPtr(2), intPtr(3)}, &[]*int{intPtr(1), nil}, "", false}, 843 {"slice length too large", tupleCodecInts, tupleOneTwoThreeBytes, &[]*int{intPtr(1), intPtr(2), intPtr(3)}, &[]*int{intPtr(0), intPtr(0), intPtr(0), intPtr(0)}, "", false}, 844 } 845 for _, tt := range tests { 846 t.Run(tt.name, func(t *testing.T) { 847 wasNull, err := tt.codec.Decode(tt.input, tt.dest, version) 848 assert.Equal(t, tt.expected, tt.dest) 849 assert.Equal(t, tt.wasNull, wasNull) 850 assertErrorMessage(t, tt.err, err) 851 }) 852 } 853 }) 854 }) 855 } 856 for _, version := range primitive.SupportedProtocolVersionsLesserThan(primitive.ProtocolVersion3) { 857 t.Run(version.String(), func(t *testing.T) { 858 codec, _ := NewTuple(datatype.NewTuple(datatype.Int)) 859 _, err := codec.Decode(nil, nil, version) 860 assertErrorMessage(t, "data type tuple<int> not supported in "+version.String(), err) 861 }) 862 } 863 t.Run("invalid types", func(t *testing.T) { 864 wasNull, err := tupleCodecSimple.Decode([]byte{1, 2, 3}, new(int), primitive.ProtocolVersion5) 865 assert.False(t, wasNull) 866 assert.EqualError(t, err, "cannot decode CQL tuple<int,boolean,varchar> as *int with ProtocolVersion OSS 5: destination type not supported") 867 }) 868 } 869 870 func Test_writeTuple(t *testing.T) { 871 type args struct { 872 ext extractor 873 elementCodecs []Codec 874 version primitive.ProtocolVersion 875 } 876 tests := []struct { 877 name string 878 args args 879 want []byte 880 wantErr string 881 }{ 882 { 883 "cannot extract elem", 884 args{ 885 func() extractor { 886 ext := &mockExtractor{} 887 ext.On("getElem", 0, 0).Return(nil, errSliceIndexOutOfRange(true, 0)) 888 return ext 889 }(), 890 []Codec{nil}, 891 primitive.ProtocolVersion5, 892 }, 893 nil, 894 "cannot extract element 0: slice index out of range: 0", 895 }, 896 { 897 "cannot encode", 898 args{ 899 func() extractor { 900 ext := &mockExtractor{} 901 ext.On("getElem", 0, 0).Return(123, nil) 902 return ext 903 }(), 904 func() []Codec { 905 codec := &mockCodec{} 906 codec.On("Encode", 123, primitive.ProtocolVersion5).Return(nil, errors.New("write failed")) 907 return []Codec{codec} 908 }(), 909 primitive.ProtocolVersion5, 910 }, 911 nil, 912 "cannot encode element 0: write failed", 913 }, 914 {"success", args{ 915 func() extractor { 916 ext := &mockExtractor{} 917 ext.On("getElem", 0, 0).Return(123, nil) 918 ext.On("getElem", 1, 1).Return("abc", nil) 919 ext.On("getElem", 2, 2).Return(true, nil) 920 return ext 921 }(), 922 func() []Codec { 923 codec1 := &mockCodec{} 924 codec1.On("Encode", 123, primitive.ProtocolVersion5).Return([]byte{1}, nil) 925 codec2 := &mockCodec{} 926 codec2.On("Encode", "abc", primitive.ProtocolVersion5).Return([]byte{2}, nil) 927 codec3 := &mockCodec{} 928 codec3.On("Encode", true, primitive.ProtocolVersion5).Return(nil, nil) 929 return []Codec{codec1, codec2, codec3} 930 }(), 931 primitive.ProtocolVersion5, 932 }, []byte{ 933 0, 0, 0, 1, // elem 1 934 1, 935 0, 0, 0, 1, // elem 2 936 2, 937 255, 255, 255, 255, // elem 3 (nil) 938 }, ""}, 939 } 940 for _, tt := range tests { 941 t.Run(tt.name, func(t *testing.T) { 942 got, gotErr := writeTuple(tt.args.ext, tt.args.elementCodecs, tt.args.version) 943 assert.Equal(t, tt.want, got) 944 assertErrorMessage(t, tt.wantErr, gotErr) 945 }) 946 } 947 } 948 949 func Test_readTuple(t *testing.T) { 950 type args struct { 951 source []byte 952 inj injector 953 elementCodecs []Codec 954 version primitive.ProtocolVersion 955 } 956 tests := []struct { 957 name string 958 args args 959 wantErr string 960 }{ 961 { 962 "cannot read element", 963 args{ 964 []byte{ 965 0, // wrong [bytes] 966 }, 967 nil, 968 []Codec{nil}, 969 primitive.ProtocolVersion5, 970 }, 971 "cannot read element 0: cannot read [bytes] length: cannot read [int]: unexpected EOF", 972 }, 973 { 974 "cannot create element", 975 args{ 976 []byte{ 977 0, 0, 0, 1, 123, // [bytes] 978 }, 979 func() injector { 980 inj := &mockInjector{} 981 inj.On("zeroElem", 0, 0).Return(nil, errors.New("wrong data type")) 982 return inj 983 }(), 984 func() []Codec { 985 codec := &mockCodec{} 986 codec.On("DataType").Return(datatype.Int) 987 return []Codec{codec} 988 }(), 989 primitive.ProtocolVersion5, 990 }, 991 "cannot create zero element 0: wrong data type", 992 }, 993 { 994 "cannot decode element", 995 args{ 996 []byte{ 997 0, 0, 0, 1, 123, // [bytes] 998 }, 999 func() injector { 1000 inj := &mockInjector{} 1001 inj.On("zeroElem", 0, 0).Return(new(int), nil) 1002 return inj 1003 }(), 1004 func() []Codec { 1005 codec := &mockCodec{} 1006 codec.On("DataType").Return(datatype.Int) 1007 codec.On("Decode", []byte{123}, new(int), primitive.ProtocolVersion5).Return(false, errors.New("decode failed")) 1008 return []Codec{codec} 1009 }(), 1010 primitive.ProtocolVersion5, 1011 }, 1012 "cannot decode element 0: decode failed", 1013 }, 1014 { 1015 "cannot set element", 1016 args{ 1017 []byte{ 1018 0, 0, 0, 1, 123, // [bytes] 1019 }, 1020 func() injector { 1021 inj := &mockInjector{} 1022 inj.On("zeroElem", 0, 0).Return(new(int), nil) 1023 inj.On("setElem", 0, 0, intPtr(123), false, false).Return(errors.New("cannot set elem")) 1024 return inj 1025 }(), 1026 func() []Codec { 1027 codec := &mockCodec{} 1028 codec.On("DataType").Return(datatype.Int) 1029 codec.On("Decode", []byte{123}, new(int), primitive.ProtocolVersion5).Run(func(args mock.Arguments) { 1030 decodedElement := args.Get(1).(*int) 1031 *decodedElement = 123 1032 }).Return(false, nil) 1033 return []Codec{codec} 1034 }(), 1035 primitive.ProtocolVersion5, 1036 }, 1037 "cannot inject element 0: cannot set elem", 1038 }, 1039 { 1040 "bytes remaining", 1041 args{ 1042 []byte{ 1043 0, 0, 0, 1, 123, // [bytes] 1044 1, // trailing bytes 1045 }, 1046 func() injector { 1047 inj := &mockInjector{} 1048 inj.On("zeroElem", 0, 0).Return(new(int), nil) 1049 inj.On("setElem", 0, 0, intPtr(123), false, false).Return(nil) 1050 return inj 1051 }(), 1052 func() []Codec { 1053 codec := &mockCodec{} 1054 codec.On("DataType").Return(datatype.Int) 1055 codec.On("Decode", []byte{123}, new(int), primitive.ProtocolVersion5).Run(func(args mock.Arguments) { 1056 decodedElement := args.Get(1).(*int) 1057 *decodedElement = 123 1058 }).Return(false, nil) 1059 return []Codec{codec} 1060 }(), 1061 primitive.ProtocolVersion5, 1062 }, 1063 "source was not fully read: bytes total: 6, read: 5, remaining: 1", 1064 }, 1065 { 1066 "success", 1067 args{ 1068 []byte{ 1069 0, 0, 0, 1, 123, // 1st elem 1070 0, 0, 0, 3, a, b, c, // 2nd elem 1071 255, 255, 255, 255, // 3rd elem (nil) 1072 }, 1073 func() injector { 1074 inj := &mockInjector{} 1075 inj.On("zeroElem", 0, 0).Return(new(int), nil) 1076 inj.On("zeroElem", 1, 1).Return(new(string), nil) 1077 inj.On("zeroElem", 2, 2).Return(new(bool), nil) 1078 inj.On("setElem", 0, 0, intPtr(123), false, false).Return(nil) 1079 inj.On("setElem", 1, 1, stringPtr("abc"), false, false).Return(nil) 1080 inj.On("setElem", 2, 2, new(bool), false, true).Return(nil) 1081 return inj 1082 }(), 1083 func() []Codec { 1084 codec1 := &mockCodec{} 1085 codec1.On("DataType").Return(datatype.Int) 1086 codec1.On("Decode", []byte{123}, new(int), primitive.ProtocolVersion5).Run(func(args mock.Arguments) { 1087 decodedElement := args.Get(1).(*int) 1088 *decodedElement = 123 1089 }).Return(false, nil) 1090 codec2 := &mockCodec{} 1091 codec2.On("DataType").Return(datatype.Varchar) 1092 codec2.On("Decode", []byte{a, b, c}, new(string), primitive.ProtocolVersion5).Run(func(args mock.Arguments) { 1093 decodedElement := args.Get(1).(*string) 1094 *decodedElement = "abc" 1095 }).Return(false, nil) 1096 codec3 := &mockCodec{} 1097 codec3.On("DataType").Return(datatype.Boolean) 1098 codec3.On("Decode", []byte(nil), new(bool), primitive.ProtocolVersion5).Return(true, nil) 1099 return []Codec{codec1, codec2, codec3} 1100 }(), 1101 primitive.ProtocolVersion5, 1102 }, 1103 "", 1104 }, 1105 } 1106 for _, tt := range tests { 1107 t.Run(tt.name, func(t *testing.T) { 1108 gotErr := readTuple(tt.args.source, tt.args.inj, tt.args.elementCodecs, tt.args.version) 1109 assertErrorMessage(t, tt.wantErr, gotErr) 1110 }) 1111 } 1112 }