1/* 2Copyright 2017 Google LLC 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package spanner 18 19import ( 20 "math" 21 "reflect" 22 "testing" 23 "time" 24 25 "cloud.google.com/go/civil" 26 proto3 "github.com/golang/protobuf/ptypes/struct" 27 sppb "google.golang.org/genproto/googleapis/spanner/v1" 28) 29 30var ( 31 t1 = mustParseTime("2016-11-15T15:04:05.999999999Z") 32 // Boundaries 33 t2 = mustParseTime("0000-01-01T00:00:00.000000000Z") 34 t3 = mustParseTime("9999-12-31T23:59:59.999999999Z") 35 // Local timezone 36 t4 = time.Now() 37 d1 = mustParseDate("2016-11-15") 38 d2 = mustParseDate("1678-01-01") 39) 40 41func mustParseTime(s string) time.Time { 42 t, err := time.Parse(time.RFC3339Nano, s) 43 if err != nil { 44 panic(err) 45 } 46 return t 47} 48 49func mustParseDate(s string) civil.Date { 50 d, err := civil.ParseDate(s) 51 if err != nil { 52 panic(err) 53 } 54 return d 55} 56 57// Test encoding Values. 58func TestEncodeValue(t *testing.T) { 59 var ( 60 tString = stringType() 61 tInt = intType() 62 tBool = boolType() 63 tFloat = floatType() 64 tBytes = bytesType() 65 tTime = timeType() 66 tDate = dateType() 67 ) 68 for i, test := range []struct { 69 in interface{} 70 want *proto3.Value 71 wantType *sppb.Type 72 }{ 73 // STRING / STRING ARRAY 74 {"abc", stringProto("abc"), tString}, 75 {NullString{"abc", true}, stringProto("abc"), tString}, 76 {NullString{"abc", false}, nullProto(), tString}, 77 {[]string(nil), nullProto(), listType(tString)}, 78 {[]string{"abc", "bcd"}, listProto(stringProto("abc"), stringProto("bcd")), listType(tString)}, 79 {[]NullString{{"abcd", true}, {"xyz", false}}, listProto(stringProto("abcd"), nullProto()), listType(tString)}, 80 // BYTES / BYTES ARRAY 81 {[]byte("foo"), bytesProto([]byte("foo")), tBytes}, 82 {[]byte(nil), nullProto(), tBytes}, 83 {[][]byte{nil, []byte("ab")}, listProto(nullProto(), bytesProto([]byte("ab"))), listType(tBytes)}, 84 {[][]byte(nil), nullProto(), listType(tBytes)}, 85 // INT64 / INT64 ARRAY 86 {7, intProto(7), tInt}, 87 {[]int(nil), nullProto(), listType(tInt)}, 88 {[]int{31, 127}, listProto(intProto(31), intProto(127)), listType(tInt)}, 89 {int64(81), intProto(81), tInt}, 90 {[]int64(nil), nullProto(), listType(tInt)}, 91 {[]int64{33, 129}, listProto(intProto(33), intProto(129)), listType(tInt)}, 92 {NullInt64{11, true}, intProto(11), tInt}, 93 {NullInt64{11, false}, nullProto(), tInt}, 94 {[]NullInt64{{35, true}, {131, false}}, listProto(intProto(35), nullProto()), listType(tInt)}, 95 // BOOL / BOOL ARRAY 96 {true, boolProto(true), tBool}, 97 {NullBool{true, true}, boolProto(true), tBool}, 98 {NullBool{true, false}, nullProto(), tBool}, 99 {[]bool{true, false}, listProto(boolProto(true), boolProto(false)), listType(tBool)}, 100 {[]NullBool{{true, true}, {true, false}}, listProto(boolProto(true), nullProto()), listType(tBool)}, 101 // FLOAT64 / FLOAT64 ARRAY 102 {3.14, floatProto(3.14), tFloat}, 103 {NullFloat64{3.1415, true}, floatProto(3.1415), tFloat}, 104 {NullFloat64{math.Inf(1), true}, floatProto(math.Inf(1)), tFloat}, 105 {NullFloat64{3.14159, false}, nullProto(), tFloat}, 106 {[]float64(nil), nullProto(), listType(tFloat)}, 107 {[]float64{3.141, 0.618, math.Inf(-1)}, listProto(floatProto(3.141), floatProto(0.618), floatProto(math.Inf(-1))), listType(tFloat)}, 108 {[]NullFloat64{{3.141, true}, {0.618, false}}, listProto(floatProto(3.141), nullProto()), listType(tFloat)}, 109 // TIMESTAMP / TIMESTAMP ARRAY 110 {t1, timeProto(t1), tTime}, 111 {NullTime{t1, true}, timeProto(t1), tTime}, 112 {NullTime{t1, false}, nullProto(), tTime}, 113 {[]time.Time(nil), nullProto(), listType(tTime)}, 114 {[]time.Time{t1, t2, t3, t4}, listProto(timeProto(t1), timeProto(t2), timeProto(t3), timeProto(t4)), listType(tTime)}, 115 {[]NullTime{{t1, true}, {t1, false}}, listProto(timeProto(t1), nullProto()), listType(tTime)}, 116 // DATE / DATE ARRAY 117 {d1, dateProto(d1), tDate}, 118 {NullDate{d1, true}, dateProto(d1), tDate}, 119 {NullDate{civil.Date{}, false}, nullProto(), tDate}, 120 {[]civil.Date(nil), nullProto(), listType(tDate)}, 121 {[]civil.Date{d1, d2}, listProto(dateProto(d1), dateProto(d2)), listType(tDate)}, 122 {[]NullDate{{d1, true}, {civil.Date{}, false}}, listProto(dateProto(d1), nullProto()), listType(tDate)}, 123 // GenericColumnValue 124 {GenericColumnValue{tString, stringProto("abc")}, stringProto("abc"), tString}, 125 {GenericColumnValue{tString, nullProto()}, nullProto(), tString}, 126 // not actually valid (stringProto inside int list), but demonstrates pass-through. 127 { 128 GenericColumnValue{ 129 Type: listType(tInt), 130 Value: listProto(intProto(5), nullProto(), stringProto("bcd")), 131 }, 132 listProto(intProto(5), nullProto(), stringProto("bcd")), 133 listType(tInt), 134 }, 135 // placeholder 136 {CommitTimestamp, stringProto(commitTimestampPlaceholderString), tTime}, 137 } { 138 got, gotType, err := encodeValue(test.in) 139 if err != nil { 140 t.Fatalf("#%d: got error during encoding: %v, want nil", i, err) 141 } 142 if !testEqual(got, test.want) { 143 t.Errorf("#%d: got encode result: %v, want %v", i, got, test.want) 144 } 145 if !testEqual(gotType, test.wantType) { 146 t.Errorf("#%d: got encode type: %v, want %v", i, gotType, test.wantType) 147 } 148 } 149} 150 151type encodeTest struct { 152 desc string 153 in interface{} 154 want *proto3.Value 155 wantType *sppb.Type 156} 157 158func checkStructEncoding(desc string, got *proto3.Value, gotType *sppb.Type, 159 want *proto3.Value, wantType *sppb.Type, t *testing.T) { 160 if !testEqual(got, want) { 161 t.Errorf("Test %s: got encode result: %v, want %v", desc, got, want) 162 } 163 if !testEqual(gotType, wantType) { 164 t.Errorf("Test %s: got encode type: %v, want %v", desc, gotType, wantType) 165 } 166} 167 168// Testcase code 169func encodeStructValue(test encodeTest, t *testing.T) { 170 got, gotType, err := encodeValue(test.in) 171 if err != nil { 172 t.Fatalf("Test %s: got error during encoding: %v, want nil", test.desc, err) 173 } 174 checkStructEncoding(test.desc, got, gotType, test.want, test.wantType, t) 175} 176 177func TestEncodeStructValuePointers(t *testing.T) { 178 type structf struct { 179 F int `spanner:"ff2"` 180 } 181 nestedStructProto := structType(mkField("ff2", intType())) 182 183 type testType struct { 184 Stringf string 185 Structf *structf 186 ArrStructf []*structf 187 } 188 testTypeProto := structType( 189 mkField("Stringf", stringType()), 190 mkField("Structf", nestedStructProto), 191 mkField("ArrStructf", listType(nestedStructProto))) 192 193 for _, test := range []encodeTest{ 194 { 195 "Pointer to Go struct with pointers-to-(array)-struct fields.", 196 &testType{"hello", &structf{50}, []*structf{&structf{30}, &structf{40}}}, 197 listProto( 198 stringProto("hello"), 199 listProto(intProto(50)), 200 listProto( 201 listProto(intProto(30)), 202 listProto(intProto(40)))), 203 testTypeProto, 204 }, 205 { 206 "Nil pointer to Go struct representing a NULL struct value.", 207 (*testType)(nil), 208 nullProto(), 209 testTypeProto, 210 }, 211 { 212 "Slice of pointers to Go structs with NULL and non-NULL elements.", 213 []*testType{ 214 (*testType)(nil), 215 &testType{"hello", nil, []*structf{nil, &structf{40}}}, 216 &testType{"world", &structf{70}, nil}, 217 }, 218 listProto( 219 nullProto(), 220 listProto( 221 stringProto("hello"), 222 nullProto(), 223 listProto(nullProto(), listProto(intProto(40)))), 224 listProto( 225 stringProto("world"), 226 listProto(intProto(70)), 227 nullProto())), 228 listType(testTypeProto), 229 }, 230 { 231 "Nil slice of pointers to structs representing a NULL array of structs.", 232 []*testType(nil), 233 nullProto(), 234 listType(testTypeProto), 235 }, 236 { 237 "Empty slice of pointers to structs representing an empty array of structs.", 238 []*testType{}, 239 listProto(), 240 listType(testTypeProto), 241 }, 242 } { 243 encodeStructValue(test, t) 244 } 245} 246 247func TestEncodeStructValueErrors(t *testing.T) { 248 type Embedded struct { 249 A int 250 } 251 type embedded struct { 252 B bool 253 } 254 x := 0 255 256 for _, test := range []struct { 257 desc string 258 in interface{} 259 wantErr error 260 }{ 261 { 262 "Unsupported embedded fields.", 263 struct{ Embedded }{Embedded{10}}, 264 errUnsupportedEmbeddedStructFields("Embedded"), 265 }, 266 { 267 "Unsupported pointer to embedded fields.", 268 struct{ *Embedded }{&Embedded{10}}, 269 errUnsupportedEmbeddedStructFields("Embedded"), 270 }, 271 { 272 "Unsupported embedded + unexported fields.", 273 struct { 274 int 275 *bool 276 embedded 277 }{10, nil, embedded{false}}, 278 errUnsupportedEmbeddedStructFields("int"), 279 }, 280 { 281 "Unsupported type.", 282 (**struct{})(nil), 283 errEncoderUnsupportedType((**struct{})(nil)), 284 }, 285 { 286 "Unsupported type.", 287 3, 288 errEncoderUnsupportedType(3), 289 }, 290 { 291 "Unsupported type.", 292 &x, 293 errEncoderUnsupportedType(&x), 294 }, 295 } { 296 _, _, got := encodeStruct(test.in) 297 if got == nil || !testEqual(test.wantErr, got) { 298 t.Errorf("Test: %s, expected error %v during decoding, got %v", test.desc, test.wantErr, got) 299 } 300 } 301} 302 303func TestEncodeStructValueArrayStructFields(t *testing.T) { 304 type structf struct { 305 Intff int 306 } 307 308 structfType := structType(mkField("Intff", intType())) 309 for _, test := range []encodeTest{ 310 { 311 "Unnamed array-of-struct-typed field.", 312 struct { 313 Intf int 314 ArrStructf []structf `spanner:""` 315 }{10, []structf{structf{1}, structf{2}}}, 316 listProto( 317 intProto(10), 318 listProto( 319 listProto(intProto(1)), 320 listProto(intProto(2)))), 321 structType( 322 mkField("Intf", intType()), 323 mkField("", listType(structfType))), 324 }, 325 { 326 "Null array-of-struct-typed field.", 327 struct { 328 Intf int 329 ArrStructf []structf 330 }{10, []structf(nil)}, 331 listProto(intProto(10), nullProto()), 332 structType( 333 mkField("Intf", intType()), 334 mkField("ArrStructf", listType(structfType))), 335 }, 336 { 337 "Array-of-struct-typed field representing empty array.", 338 struct { 339 Intf int 340 ArrStructf []structf 341 }{10, []structf{}}, 342 listProto(intProto(10), listProto([]*proto3.Value{}...)), 343 structType( 344 mkField("Intf", intType()), 345 mkField("ArrStructf", listType(structfType))), 346 }, 347 { 348 "Array-of-struct-typed field with nullable struct elements.", 349 struct { 350 Intf int 351 ArrStructf []*structf 352 }{ 353 10, 354 []*structf{(*structf)(nil), &structf{1}}, 355 }, 356 listProto( 357 intProto(10), 358 listProto( 359 nullProto(), 360 listProto(intProto(1)))), 361 structType( 362 mkField("Intf", intType()), 363 mkField("ArrStructf", listType(structfType))), 364 }, 365 } { 366 encodeStructValue(test, t) 367 } 368} 369 370func TestEncodeStructValueStructFields(t *testing.T) { 371 type structf struct { 372 Intff int 373 } 374 structfType := structType(mkField("Intff", intType())) 375 for _, test := range []encodeTest{ 376 { 377 "Named struct-type field.", 378 struct { 379 Intf int 380 Structf structf 381 }{10, structf{10}}, 382 listProto(intProto(10), listProto(intProto(10))), 383 structType( 384 mkField("Intf", intType()), 385 mkField("Structf", structfType)), 386 }, 387 { 388 "Unnamed struct-type field.", 389 struct { 390 Intf int 391 Structf structf `spanner:""` 392 }{10, structf{10}}, 393 listProto(intProto(10), listProto(intProto(10))), 394 structType( 395 mkField("Intf", intType()), 396 mkField("", structfType)), 397 }, 398 { 399 "Duplicate struct-typed field.", 400 struct { 401 Structf1 structf `spanner:""` 402 Structf2 structf `spanner:""` 403 }{structf{10}, structf{20}}, 404 listProto(listProto(intProto(10)), listProto(intProto(20))), 405 structType( 406 mkField("", structfType), 407 mkField("", structfType)), 408 }, 409 { 410 "Null struct-typed field.", 411 struct { 412 Intf int 413 Structf *structf 414 }{10, nil}, 415 listProto(intProto(10), nullProto()), 416 structType( 417 mkField("Intf", intType()), 418 mkField("Structf", structfType)), 419 }, 420 { 421 "Empty struct-typed field.", 422 struct { 423 Intf int 424 Structf struct{} 425 }{10, struct{}{}}, 426 listProto(intProto(10), listProto([]*proto3.Value{}...)), 427 structType( 428 mkField("Intf", intType()), 429 mkField("Structf", structType([]*sppb.StructType_Field{}...))), 430 }, 431 } { 432 encodeStructValue(test, t) 433 } 434} 435 436func TestEncodeStructValueFieldNames(t *testing.T) { 437 type embedded struct { 438 B bool 439 } 440 441 for _, test := range []encodeTest{ 442 { 443 "Duplicate fields.", 444 struct { 445 Field1 int `spanner:"field"` 446 DupField1 int `spanner:"field"` 447 }{10, 20}, 448 listProto(intProto(10), intProto(20)), 449 structType( 450 mkField("field", intType()), 451 mkField("field", intType())), 452 }, 453 { 454 "Duplicate Fields (different types).", 455 struct { 456 IntField int `spanner:"field"` 457 StringField string `spanner:"field"` 458 }{10, "abc"}, 459 listProto(intProto(10), stringProto("abc")), 460 structType( 461 mkField("field", intType()), 462 mkField("field", stringType())), 463 }, 464 { 465 "Duplicate unnamed fields.", 466 struct { 467 Dup int `spanner:""` 468 Dup1 int `spanner:""` 469 }{10, 20}, 470 listProto(intProto(10), intProto(20)), 471 structType( 472 mkField("", intType()), 473 mkField("", intType())), 474 }, 475 { 476 "Named and unnamed fields.", 477 struct { 478 Field string 479 Field1 int `spanner:""` 480 Field2 string `spanner:"field"` 481 }{"abc", 10, "def"}, 482 listProto(stringProto("abc"), intProto(10), stringProto("def")), 483 structType( 484 mkField("Field", stringType()), 485 mkField("", intType()), 486 mkField("field", stringType())), 487 }, 488 { 489 "Ignored unexported fields.", 490 struct { 491 Field int 492 field bool 493 Field1 string `spanner:"field"` 494 }{10, false, "abc"}, 495 listProto(intProto(10), stringProto("abc")), 496 structType( 497 mkField("Field", intType()), 498 mkField("field", stringType())), 499 }, 500 { 501 "Ignored unexported struct/slice fields.", 502 struct { 503 a []*embedded 504 b []embedded 505 c embedded 506 d *embedded 507 Field1 string `spanner:"field"` 508 }{nil, nil, embedded{}, nil, "def"}, 509 listProto(stringProto("def")), 510 structType( 511 mkField("field", stringType())), 512 }, 513 } { 514 encodeStructValue(test, t) 515 } 516} 517 518func TestEncodeStructValueBasicFields(t *testing.T) { 519 StructTypeProto := structType( 520 mkField("Stringf", stringType()), 521 mkField("Intf", intType()), 522 mkField("Boolf", boolType()), 523 mkField("Floatf", floatType()), 524 mkField("Bytef", bytesType()), 525 mkField("Timef", timeType()), 526 mkField("Datef", dateType())) 527 528 for _, test := range []encodeTest{ 529 { 530 "Basic types.", 531 struct { 532 Stringf string 533 Intf int 534 Boolf bool 535 Floatf float64 536 Bytef []byte 537 Timef time.Time 538 Datef civil.Date 539 }{"abc", 300, false, 3.45, []byte("foo"), t1, d1}, 540 listProto( 541 stringProto("abc"), 542 intProto(300), 543 boolProto(false), 544 floatProto(3.45), 545 bytesProto([]byte("foo")), 546 timeProto(t1), 547 dateProto(d1)), 548 StructTypeProto, 549 }, 550 { 551 "Basic types null values.", 552 struct { 553 Stringf NullString 554 Intf NullInt64 555 Boolf NullBool 556 Floatf NullFloat64 557 Bytef []byte 558 Timef NullTime 559 Datef NullDate 560 }{ 561 NullString{"abc", false}, 562 NullInt64{4, false}, 563 NullBool{false, false}, 564 NullFloat64{5.6, false}, 565 nil, 566 NullTime{t1, false}, 567 NullDate{d1, false}, 568 }, 569 listProto( 570 nullProto(), 571 nullProto(), 572 nullProto(), 573 nullProto(), 574 nullProto(), 575 nullProto(), 576 nullProto()), 577 StructTypeProto, 578 }, 579 } { 580 encodeStructValue(test, t) 581 } 582} 583 584func TestEncodeStructValueArrayFields(t *testing.T) { 585 StructTypeProto := structType( 586 mkField("Stringf", listType(stringType())), 587 mkField("Intf", listType(intType())), 588 mkField("Int64f", listType(intType())), 589 mkField("Boolf", listType(boolType())), 590 mkField("Floatf", listType(floatType())), 591 mkField("Bytef", listType(bytesType())), 592 mkField("Timef", listType(timeType())), 593 mkField("Datef", listType(dateType()))) 594 595 for _, test := range []encodeTest{ 596 { 597 "Arrays of basic types with non-nullable elements", 598 struct { 599 Stringf []string 600 Intf []int 601 Int64f []int64 602 Boolf []bool 603 Floatf []float64 604 Bytef [][]byte 605 Timef []time.Time 606 Datef []civil.Date 607 }{ 608 []string{"abc", "def"}, 609 []int{4, 67}, 610 []int64{5, 68}, 611 []bool{false, true}, 612 []float64{3.45, 0.93}, 613 [][]byte{[]byte("foo"), nil}, 614 []time.Time{t1, t2}, 615 []civil.Date{d1, d2}, 616 }, 617 listProto( 618 listProto(stringProto("abc"), stringProto("def")), 619 listProto(intProto(4), intProto(67)), 620 listProto(intProto(5), intProto(68)), 621 listProto(boolProto(false), boolProto(true)), 622 listProto(floatProto(3.45), floatProto(0.93)), 623 listProto(bytesProto([]byte("foo")), nullProto()), 624 listProto(timeProto(t1), timeProto(t2)), 625 listProto(dateProto(d1), dateProto(d2))), 626 StructTypeProto, 627 }, 628 { 629 "Arrays of basic types with nullable elements.", 630 struct { 631 Stringf []NullString 632 Intf []NullInt64 633 Int64f []NullInt64 634 Boolf []NullBool 635 Floatf []NullFloat64 636 Bytef [][]byte 637 Timef []NullTime 638 Datef []NullDate 639 }{ 640 []NullString{NullString{"abc", false}, NullString{"def", true}}, 641 []NullInt64{NullInt64{4, false}, NullInt64{67, true}}, 642 []NullInt64{NullInt64{5, false}, NullInt64{68, true}}, 643 []NullBool{NullBool{true, false}, NullBool{false, true}}, 644 []NullFloat64{NullFloat64{3.45, false}, NullFloat64{0.93, true}}, 645 [][]byte{[]byte("foo"), nil}, 646 []NullTime{NullTime{t1, false}, NullTime{t2, true}}, 647 []NullDate{NullDate{d1, false}, NullDate{d2, true}}, 648 }, 649 listProto( 650 listProto(nullProto(), stringProto("def")), 651 listProto(nullProto(), intProto(67)), 652 listProto(nullProto(), intProto(68)), 653 listProto(nullProto(), boolProto(false)), 654 listProto(nullProto(), floatProto(0.93)), 655 listProto(bytesProto([]byte("foo")), nullProto()), 656 listProto(nullProto(), timeProto(t2)), 657 listProto(nullProto(), dateProto(d2))), 658 StructTypeProto, 659 }, 660 { 661 "Null arrays of basic types.", 662 struct { 663 Stringf []NullString 664 Intf []NullInt64 665 Int64f []NullInt64 666 Boolf []NullBool 667 Floatf []NullFloat64 668 Bytef [][]byte 669 Timef []NullTime 670 Datef []NullDate 671 }{ 672 nil, 673 nil, 674 nil, 675 nil, 676 nil, 677 nil, 678 nil, 679 nil, 680 }, 681 listProto( 682 nullProto(), 683 nullProto(), 684 nullProto(), 685 nullProto(), 686 nullProto(), 687 nullProto(), 688 nullProto(), 689 nullProto()), 690 StructTypeProto, 691 }, 692 } { 693 encodeStructValue(test, t) 694 } 695} 696 697// Test decoding Values. 698func TestDecodeValue(t *testing.T) { 699 for i, test := range []struct { 700 in *proto3.Value 701 t *sppb.Type 702 want interface{} 703 fail bool 704 }{ 705 // STRING 706 {stringProto("abc"), stringType(), "abc", false}, 707 {nullProto(), stringType(), "abc", true}, 708 {stringProto("abc"), stringType(), NullString{"abc", true}, false}, 709 {nullProto(), stringType(), NullString{}, false}, 710 // STRING ARRAY with []NullString 711 { 712 listProto(stringProto("abc"), nullProto(), stringProto("bcd")), 713 listType(stringType()), 714 []NullString{{"abc", true}, {}, {"bcd", true}}, 715 false, 716 }, 717 {nullProto(), listType(stringType()), []NullString(nil), false}, 718 // STRING ARRAY with []string 719 { 720 listProto(stringProto("abc"), stringProto("bcd")), 721 listType(stringType()), 722 []string{"abc", "bcd"}, 723 false, 724 }, 725 // BYTES 726 {bytesProto([]byte("ab")), bytesType(), []byte("ab"), false}, 727 {nullProto(), bytesType(), []byte(nil), false}, 728 // BYTES ARRAY 729 {listProto(bytesProto([]byte("ab")), nullProto()), listType(bytesType()), [][]byte{[]byte("ab"), nil}, false}, 730 {nullProto(), listType(bytesType()), [][]byte(nil), false}, 731 //INT64 732 {intProto(15), intType(), int64(15), false}, 733 {nullProto(), intType(), int64(0), true}, 734 {intProto(15), intType(), NullInt64{15, true}, false}, 735 {nullProto(), intType(), NullInt64{}, false}, 736 // INT64 ARRAY with []NullInt64 737 {listProto(intProto(91), nullProto(), intProto(87)), listType(intType()), []NullInt64{{91, true}, {}, {87, true}}, false}, 738 {nullProto(), listType(intType()), []NullInt64(nil), false}, 739 // INT64 ARRAY with []int64 740 {listProto(intProto(91), intProto(87)), listType(intType()), []int64{91, 87}, false}, 741 // BOOL 742 {boolProto(true), boolType(), true, false}, 743 {nullProto(), boolType(), true, true}, 744 {boolProto(true), boolType(), NullBool{true, true}, false}, 745 {nullProto(), boolType(), NullBool{}, false}, 746 // BOOL ARRAY with []NullBool 747 {listProto(boolProto(true), boolProto(false), nullProto()), listType(boolType()), []NullBool{{true, true}, {false, true}, {}}, false}, 748 {nullProto(), listType(boolType()), []NullBool(nil), false}, 749 // BOOL ARRAY with []bool 750 {listProto(boolProto(true), boolProto(false)), listType(boolType()), []bool{true, false}, false}, 751 // FLOAT64 752 {floatProto(3.14), floatType(), 3.14, false}, 753 {nullProto(), floatType(), 0.00, true}, 754 {floatProto(3.14), floatType(), NullFloat64{3.14, true}, false}, 755 {nullProto(), floatType(), NullFloat64{}, false}, 756 // FLOAT64 ARRAY with []NullFloat64 757 { 758 listProto(floatProto(math.Inf(1)), floatProto(math.Inf(-1)), nullProto(), floatProto(3.1)), 759 listType(floatType()), 760 []NullFloat64{{math.Inf(1), true}, {math.Inf(-1), true}, {}, {3.1, true}}, 761 false, 762 }, 763 {nullProto(), listType(floatType()), []NullFloat64(nil), false}, 764 // FLOAT64 ARRAY with []float64 765 { 766 listProto(floatProto(math.Inf(1)), floatProto(math.Inf(-1)), floatProto(3.1)), 767 listType(floatType()), 768 []float64{math.Inf(1), math.Inf(-1), 3.1}, 769 false, 770 }, 771 // TIMESTAMP 772 {timeProto(t1), timeType(), t1, false}, 773 {timeProto(t1), timeType(), NullTime{t1, true}, false}, 774 {nullProto(), timeType(), NullTime{}, false}, 775 // TIMESTAMP ARRAY with []NullTime 776 {listProto(timeProto(t1), timeProto(t2), timeProto(t3), nullProto()), listType(timeType()), []NullTime{{t1, true}, {t2, true}, {t3, true}, {}}, false}, 777 {nullProto(), listType(timeType()), []NullTime(nil), false}, 778 // TIMESTAMP ARRAY with []time.Time 779 {listProto(timeProto(t1), timeProto(t2), timeProto(t3)), listType(timeType()), []time.Time{t1, t2, t3}, false}, 780 // DATE 781 {dateProto(d1), dateType(), d1, false}, 782 {dateProto(d1), dateType(), NullDate{d1, true}, false}, 783 {nullProto(), dateType(), NullDate{}, false}, 784 // DATE ARRAY with []NullDate 785 {listProto(dateProto(d1), dateProto(d2), nullProto()), listType(dateType()), []NullDate{{d1, true}, {d2, true}, {}}, false}, 786 {nullProto(), listType(dateType()), []NullDate(nil), false}, 787 // DATE ARRAY with []civil.Date 788 {listProto(dateProto(d1), dateProto(d2)), listType(dateType()), []civil.Date{d1, d2}, false}, 789 // STRUCT ARRAY 790 // STRUCT schema is equal to the following Go struct: 791 // type s struct { 792 // Col1 NullInt64 793 // Col2 []struct { 794 // SubCol1 float64 795 // SubCol2 string 796 // } 797 // } 798 { 799 in: listProto( 800 listProto( 801 intProto(3), 802 listProto( 803 listProto(floatProto(3.14), stringProto("this")), 804 listProto(floatProto(0.57), stringProto("siht")), 805 ), 806 ), 807 listProto( 808 nullProto(), 809 nullProto(), 810 ), 811 nullProto(), 812 ), 813 t: listType( 814 structType( 815 mkField("Col1", intType()), 816 mkField( 817 "Col2", 818 listType( 819 structType( 820 mkField("SubCol1", floatType()), 821 mkField("SubCol2", stringType()), 822 ), 823 ), 824 ), 825 ), 826 ), 827 want: []NullRow{ 828 { 829 Row: Row{ 830 fields: []*sppb.StructType_Field{ 831 mkField("Col1", intType()), 832 mkField( 833 "Col2", 834 listType( 835 structType( 836 mkField("SubCol1", floatType()), 837 mkField("SubCol2", stringType()), 838 ), 839 ), 840 ), 841 }, 842 vals: []*proto3.Value{ 843 intProto(3), 844 listProto( 845 listProto(floatProto(3.14), stringProto("this")), 846 listProto(floatProto(0.57), stringProto("siht")), 847 ), 848 }, 849 }, 850 Valid: true, 851 }, 852 { 853 Row: Row{ 854 fields: []*sppb.StructType_Field{ 855 mkField("Col1", intType()), 856 mkField( 857 "Col2", 858 listType( 859 structType( 860 mkField("SubCol1", floatType()), 861 mkField("SubCol2", stringType()), 862 ), 863 ), 864 ), 865 }, 866 vals: []*proto3.Value{ 867 nullProto(), 868 nullProto(), 869 }, 870 }, 871 Valid: true, 872 }, 873 {}, 874 }, 875 fail: false, 876 }, 877 { 878 in: listProto( 879 listProto( 880 intProto(3), 881 listProto( 882 listProto(floatProto(3.14), stringProto("this")), 883 listProto(floatProto(0.57), stringProto("siht")), 884 ), 885 ), 886 listProto( 887 nullProto(), 888 nullProto(), 889 ), 890 nullProto(), 891 ), 892 t: listType( 893 structType( 894 mkField("Col1", intType()), 895 mkField( 896 "Col2", 897 listType( 898 structType( 899 mkField("SubCol1", floatType()), 900 mkField("SubCol2", stringType()), 901 ), 902 ), 903 ), 904 ), 905 ), 906 want: []*struct { 907 Col1 NullInt64 908 StructCol []*struct { 909 SubCol1 NullFloat64 910 SubCol2 string 911 } `spanner:"Col2"` 912 }{ 913 { 914 Col1: NullInt64{3, true}, 915 StructCol: []*struct { 916 SubCol1 NullFloat64 917 SubCol2 string 918 }{ 919 { 920 SubCol1: NullFloat64{3.14, true}, 921 SubCol2: "this", 922 }, 923 { 924 SubCol1: NullFloat64{0.57, true}, 925 SubCol2: "siht", 926 }, 927 }, 928 }, 929 { 930 Col1: NullInt64{}, 931 StructCol: []*struct { 932 SubCol1 NullFloat64 933 SubCol2 string 934 }(nil), 935 }, 936 nil, 937 }, 938 fail: false, 939 }, 940 // GenericColumnValue 941 {stringProto("abc"), stringType(), GenericColumnValue{stringType(), stringProto("abc")}, false}, 942 {nullProto(), stringType(), GenericColumnValue{stringType(), nullProto()}, false}, 943 // not actually valid (stringProto inside int list), but demonstrates pass-through. 944 { 945 in: listProto(intProto(5), nullProto(), stringProto("bcd")), 946 t: listType(intType()), 947 want: GenericColumnValue{ 948 Type: listType(intType()), 949 Value: listProto(intProto(5), nullProto(), stringProto("bcd")), 950 }, 951 fail: false, 952 }, 953 } { 954 gotp := reflect.New(reflect.TypeOf(test.want)) 955 if err := decodeValue(test.in, test.t, gotp.Interface()); err != nil { 956 if !test.fail { 957 t.Errorf("%d: cannot decode %v(%v): %v", i, test.in, test.t, err) 958 } 959 continue 960 } 961 if test.fail { 962 t.Errorf("%d: decoding %v(%v) succeeds unexpectedly, want error", i, test.in, test.t) 963 continue 964 } 965 got := reflect.Indirect(gotp).Interface() 966 if !testEqual(got, test.want) { 967 t.Errorf("%d: unexpected decoding result - got %v, want %v", i, got, test.want) 968 continue 969 } 970 } 971} 972 973// Test error cases for decodeValue. 974func TestDecodeValueErrors(t *testing.T) { 975 var s string 976 for i, test := range []struct { 977 in *proto3.Value 978 t *sppb.Type 979 v interface{} 980 }{ 981 {nullProto(), stringType(), nil}, 982 {nullProto(), stringType(), 1}, 983 {timeProto(t1), timeType(), &s}, 984 } { 985 err := decodeValue(test.in, test.t, test.v) 986 if err == nil { 987 t.Errorf("#%d: want error, got nil", i) 988 } 989 } 990} 991 992// Test NaN encoding/decoding. 993func TestNaN(t *testing.T) { 994 // Decode NaN value. 995 f := 0.0 996 nf := NullFloat64{} 997 // To float64 998 if err := decodeValue(floatProto(math.NaN()), floatType(), &f); err != nil { 999 t.Errorf("decodeValue returns %q for %v, want nil", err, floatProto(math.NaN())) 1000 } 1001 if !math.IsNaN(f) { 1002 t.Errorf("f = %v, want %v", f, math.NaN()) 1003 } 1004 // To NullFloat64 1005 if err := decodeValue(floatProto(math.NaN()), floatType(), &nf); err != nil { 1006 t.Errorf("decodeValue returns %q for %v, want nil", err, floatProto(math.NaN())) 1007 } 1008 if !math.IsNaN(nf.Float64) || !nf.Valid { 1009 t.Errorf("f = %v, want %v", f, NullFloat64{math.NaN(), true}) 1010 } 1011 // Encode NaN value 1012 // From float64 1013 v, _, err := encodeValue(math.NaN()) 1014 if err != nil { 1015 t.Errorf("encodeValue returns %q for NaN, want nil", err) 1016 } 1017 x, ok := v.GetKind().(*proto3.Value_NumberValue) 1018 if !ok { 1019 t.Errorf("incorrect type for v.GetKind(): %T, want *proto3.Value_NumberValue", v.GetKind()) 1020 } 1021 if !math.IsNaN(x.NumberValue) { 1022 t.Errorf("x.NumberValue = %v, want %v", x.NumberValue, math.NaN()) 1023 } 1024 // From NullFloat64 1025 v, _, err = encodeValue(NullFloat64{math.NaN(), true}) 1026 if err != nil { 1027 t.Errorf("encodeValue returns %q for NaN, want nil", err) 1028 } 1029 x, ok = v.GetKind().(*proto3.Value_NumberValue) 1030 if !ok { 1031 t.Errorf("incorrect type for v.GetKind(): %T, want *proto3.Value_NumberValue", v.GetKind()) 1032 } 1033 if !math.IsNaN(x.NumberValue) { 1034 t.Errorf("x.NumberValue = %v, want %v", x.NumberValue, math.NaN()) 1035 } 1036} 1037 1038func TestGenericColumnValue(t *testing.T) { 1039 for _, test := range []struct { 1040 in GenericColumnValue 1041 want interface{} 1042 fail bool 1043 }{ 1044 {GenericColumnValue{stringType(), stringProto("abc")}, "abc", false}, 1045 {GenericColumnValue{stringType(), stringProto("abc")}, 5, true}, 1046 {GenericColumnValue{listType(intType()), listProto(intProto(91), nullProto(), intProto(87))}, []NullInt64{{91, true}, {}, {87, true}}, false}, 1047 {GenericColumnValue{intType(), intProto(42)}, GenericColumnValue{intType(), intProto(42)}, false}, // trippy! :-) 1048 } { 1049 gotp := reflect.New(reflect.TypeOf(test.want)) 1050 if err := test.in.Decode(gotp.Interface()); err != nil { 1051 if !test.fail { 1052 t.Errorf("cannot decode %v to %v: %v", test.in, test.want, err) 1053 } 1054 continue 1055 } 1056 if test.fail { 1057 t.Errorf("decoding %v to %v succeeds unexpectedly", test.in, test.want) 1058 } 1059 1060 // Test we can go backwards as well. 1061 v, err := newGenericColumnValue(test.want) 1062 if err != nil { 1063 t.Errorf("NewGenericColumnValue failed: %v", err) 1064 continue 1065 } 1066 if !testEqual(*v, test.in) { 1067 t.Errorf("unexpected encode result - got %v, want %v", v, test.in) 1068 } 1069 } 1070} 1071 1072func TestDecodeStruct(t *testing.T) { 1073 stype := &sppb.StructType{Fields: []*sppb.StructType_Field{ 1074 {Name: "Id", Type: stringType()}, 1075 {Name: "Time", Type: timeType()}, 1076 }} 1077 lv := listValueProto(stringProto("id"), timeProto(t1)) 1078 1079 type ( 1080 S1 struct { 1081 Id string 1082 Time time.Time 1083 } 1084 S2 struct { 1085 Id string 1086 Time string 1087 } 1088 ) 1089 var ( 1090 s1 S1 1091 s2 S2 1092 ) 1093 1094 for i, test := range []struct { 1095 ptr interface{} 1096 want interface{} 1097 fail bool 1098 }{ 1099 { 1100 ptr: &s1, 1101 want: &S1{Id: "id", Time: t1}, 1102 }, 1103 { 1104 ptr: &s2, 1105 fail: true, 1106 }, 1107 } { 1108 err := decodeStruct(stype, lv, test.ptr) 1109 if (err != nil) != test.fail { 1110 t.Errorf("#%d: got error %v, wanted fail: %v", i, err, test.fail) 1111 } 1112 if err == nil && !testEqual(test.ptr, test.want) { 1113 t.Errorf("#%d: got %+v, want %+v", i, test.ptr, test.want) 1114 } 1115 } 1116} 1117