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 "encoding/json" 21 "fmt" 22 "math" 23 "reflect" 24 "testing" 25 "time" 26 27 "cloud.google.com/go/civil" 28 "cloud.google.com/go/internal/testutil" 29 "github.com/golang/protobuf/proto" 30 proto3 "github.com/golang/protobuf/ptypes/struct" 31 "github.com/google/go-cmp/cmp" 32 sppb "google.golang.org/genproto/googleapis/spanner/v1" 33) 34 35var ( 36 t1 = mustParseTime("2016-11-15T15:04:05.999999999Z") 37 // Boundaries 38 t2 = mustParseTime("0001-01-01T00:00:00.000000000Z") 39 t3 = mustParseTime("9999-12-31T23:59:59.999999999Z") 40 // Local timezone 41 t4 = time.Now() 42 d1 = mustParseDate("2016-11-15") 43 d2 = mustParseDate("1678-01-01") 44) 45 46func mustParseTime(s string) time.Time { 47 t, err := time.Parse(time.RFC3339Nano, s) 48 if err != nil { 49 panic(err) 50 } 51 return t 52} 53 54func mustParseDate(s string) civil.Date { 55 d, err := civil.ParseDate(s) 56 if err != nil { 57 panic(err) 58 } 59 return d 60} 61 62// Test encoding Values. 63func TestEncodeValue(t *testing.T) { 64 type CustomString string 65 type CustomBytes []byte 66 type CustomInt64 int64 67 type CustomBool bool 68 type CustomFloat64 float64 69 type CustomTime time.Time 70 type CustomDate civil.Date 71 72 type CustomNullString NullString 73 type CustomNullInt64 NullInt64 74 type CustomNullBool NullBool 75 type CustomNullFloat64 NullFloat64 76 type CustomNullTime NullTime 77 type CustomNullDate NullDate 78 79 sValue := "abc" 80 var sNilPtr *string 81 iValue := int64(7) 82 var iNilPtr *int64 83 bValue := true 84 var bNilPtr *bool 85 fValue := 3.14 86 var fNilPtr *float64 87 tValue := t1 88 var tNilPtr *time.Time 89 dValue := d1 90 var dNilPtr *civil.Date 91 92 var ( 93 tString = stringType() 94 tInt = intType() 95 tBool = boolType() 96 tFloat = floatType() 97 tBytes = bytesType() 98 tTime = timeType() 99 tDate = dateType() 100 ) 101 for i, test := range []struct { 102 in interface{} 103 want *proto3.Value 104 wantType *sppb.Type 105 name string 106 }{ 107 // STRING / STRING ARRAY: 108 {"abc", stringProto("abc"), tString, "string"}, 109 {NullString{"abc", true}, stringProto("abc"), tString, "NullString with value"}, 110 {NullString{"abc", false}, nullProto(), tString, "NullString with null"}, 111 {&sValue, stringProto("abc"), tString, "*string with value"}, 112 {sNilPtr, nullProto(), tString, "*string with null"}, 113 {[]string(nil), nullProto(), listType(tString), "null []string"}, 114 {[]string{"abc", "bcd"}, listProto(stringProto("abc"), stringProto("bcd")), listType(tString), "[]string"}, 115 {[]NullString{{"abcd", true}, {"xyz", false}}, listProto(stringProto("abcd"), nullProto()), listType(tString), "[]NullString"}, 116 {[]*string{&sValue, sNilPtr}, listProto(stringProto("abc"), nullProto()), listType(tString), "[]*string"}, 117 // BYTES / BYTES ARRAY 118 {[]byte("foo"), bytesProto([]byte("foo")), tBytes, "[]byte with value"}, 119 {[]byte(nil), nullProto(), tBytes, "null []byte"}, 120 {[][]byte{nil, []byte("ab")}, listProto(nullProto(), bytesProto([]byte("ab"))), listType(tBytes), "[][]byte"}, 121 {[][]byte(nil), nullProto(), listType(tBytes), "null [][]byte"}, 122 // INT64 / INT64 ARRAY 123 {7, intProto(7), tInt, "int"}, 124 {[]int(nil), nullProto(), listType(tInt), "null []int"}, 125 {[]int{31, 127}, listProto(intProto(31), intProto(127)), listType(tInt), "[]int"}, 126 {int64(81), intProto(81), tInt, "int64"}, 127 {[]int64(nil), nullProto(), listType(tInt), "null []int64"}, 128 {[]int64{33, 129}, listProto(intProto(33), intProto(129)), listType(tInt), "[]int64"}, 129 {NullInt64{11, true}, intProto(11), tInt, "NullInt64 with value"}, 130 {NullInt64{11, false}, nullProto(), tInt, "NullInt64 with null"}, 131 {&iValue, intProto(7), tInt, "*int64 with value"}, 132 {iNilPtr, nullProto(), tInt, "*int64 with null"}, 133 {[]NullInt64{{35, true}, {131, false}}, listProto(intProto(35), nullProto()), listType(tInt), "[]NullInt64"}, 134 {[]*int64{&iValue, iNilPtr}, listProto(intProto(7), nullProto()), listType(tInt), "[]*int64"}, 135 // BOOL / BOOL ARRAY 136 {true, boolProto(true), tBool, "bool"}, 137 {NullBool{true, true}, boolProto(true), tBool, "NullBool with value"}, 138 {NullBool{true, false}, nullProto(), tBool, "NullBool with null"}, 139 {&bValue, boolProto(true), tBool, "*bool with value"}, 140 {bNilPtr, nullProto(), tBool, "*bool with null"}, 141 {[]bool{true, false}, listProto(boolProto(true), boolProto(false)), listType(tBool), "[]bool"}, 142 {[]NullBool{{true, true}, {true, false}}, listProto(boolProto(true), nullProto()), listType(tBool), "[]NullBool"}, 143 {[]*bool{&bValue, bNilPtr}, listProto(boolProto(true), nullProto()), listType(tBool), "[]*bool"}, 144 // FLOAT64 / FLOAT64 ARRAY 145 {3.14, floatProto(3.14), tFloat, "float"}, 146 {NullFloat64{3.1415, true}, floatProto(3.1415), tFloat, "NullFloat64 with value"}, 147 {NullFloat64{math.Inf(1), true}, floatProto(math.Inf(1)), tFloat, "NullFloat64 with infinity"}, 148 {NullFloat64{3.14159, false}, nullProto(), tFloat, "NullFloat64 with null"}, 149 {&fValue, floatProto(3.14), tFloat, "*float64 with value"}, 150 {fNilPtr, nullProto(), tFloat, "*float64 with null"}, 151 {[]float64(nil), nullProto(), listType(tFloat), "null []float64"}, 152 {[]float64{3.141, 0.618, math.Inf(-1)}, listProto(floatProto(3.141), floatProto(0.618), floatProto(math.Inf(-1))), listType(tFloat), "[]float64"}, 153 {[]NullFloat64{{3.141, true}, {0.618, false}}, listProto(floatProto(3.141), nullProto()), listType(tFloat), "[]NullFloat64"}, 154 {[]*float64{&fValue, fNilPtr}, listProto(floatProto(3.14), nullProto()), listType(tFloat), "[]NullFloat64"}, 155 // TIMESTAMP / TIMESTAMP ARRAY 156 {t1, timeProto(t1), tTime, "time"}, 157 {NullTime{t1, true}, timeProto(t1), tTime, "NullTime with value"}, 158 {NullTime{t1, false}, nullProto(), tTime, "NullTime with null"}, 159 {&tValue, timeProto(t1), tTime, "*time.Time with value"}, 160 {tNilPtr, nullProto(), tTime, "*time.Time with null"}, 161 {[]time.Time(nil), nullProto(), listType(tTime), "null []time"}, 162 {[]time.Time{t1, t2, t3, t4}, listProto(timeProto(t1), timeProto(t2), timeProto(t3), timeProto(t4)), listType(tTime), "[]time"}, 163 {[]NullTime{{t1, true}, {t1, false}}, listProto(timeProto(t1), nullProto()), listType(tTime), "[]NullTime"}, 164 {[]*time.Time{&tValue, tNilPtr}, listProto(timeProto(t1), nullProto()), listType(tTime), "[]*time.Time"}, 165 // DATE / DATE ARRAY 166 {d1, dateProto(d1), tDate, "date"}, 167 {NullDate{d1, true}, dateProto(d1), tDate, "NullDate with value"}, 168 {NullDate{civil.Date{}, false}, nullProto(), tDate, "NullDate with null"}, 169 {&dValue, dateProto(d1), tDate, "*civil.Date with value"}, 170 {dNilPtr, nullProto(), tDate, "*civil.Date with null"}, 171 {[]civil.Date(nil), nullProto(), listType(tDate), "null []date"}, 172 {[]civil.Date{d1, d2}, listProto(dateProto(d1), dateProto(d2)), listType(tDate), "[]date"}, 173 {[]NullDate{{d1, true}, {civil.Date{}, false}}, listProto(dateProto(d1), nullProto()), listType(tDate), "[]NullDate"}, 174 {[]*civil.Date{&dValue, dNilPtr}, listProto(dateProto(d1), nullProto()), listType(tDate), "[]*civil.Date"}, 175 // GenericColumnValue 176 {GenericColumnValue{tString, stringProto("abc")}, stringProto("abc"), tString, "GenericColumnValue with value"}, 177 {GenericColumnValue{tString, nullProto()}, nullProto(), tString, "GenericColumnValue with null"}, 178 // not actually valid (stringProto inside int list), but demonstrates pass-through. 179 { 180 GenericColumnValue{ 181 Type: listType(tInt), 182 Value: listProto(intProto(5), nullProto(), stringProto("bcd")), 183 }, 184 listProto(intProto(5), nullProto(), stringProto("bcd")), 185 listType(tInt), 186 "pass-through", 187 }, 188 // placeholder 189 {CommitTimestamp, stringProto(commitTimestampPlaceholderString), tTime, "CommitTimestampPlaceholder"}, 190 // CUSTOM STRING / CUSTOM STRING ARRAY 191 {CustomString("abc"), stringProto("abc"), tString, "CustomString"}, 192 {CustomNullString{"abc", true}, stringProto("abc"), tString, "CustomNullString with value"}, 193 {CustomNullString{"abc", false}, nullProto(), tString, "CustomNullString with null"}, 194 {[]CustomString(nil), nullProto(), listType(tString), "null []CustomString"}, 195 {[]CustomString{"abc", "bcd"}, listProto(stringProto("abc"), stringProto("bcd")), listType(tString), "[]CustomString"}, 196 {[]CustomNullString(nil), nullProto(), listType(tString), "null []NullCustomString"}, 197 {[]CustomNullString{{"abcd", true}, {"xyz", false}}, listProto(stringProto("abcd"), nullProto()), listType(tString), "[]NullCustomString"}, 198 // CUSTOM BYTES / CUSTOM BYTES ARRAY 199 {CustomBytes("foo"), bytesProto([]byte("foo")), tBytes, "CustomBytes with value"}, 200 {CustomBytes(nil), nullProto(), tBytes, "null CustomBytes"}, 201 {[]CustomBytes{nil, CustomBytes("ab")}, listProto(nullProto(), bytesProto([]byte("ab"))), listType(tBytes), "[]CustomBytes"}, 202 {[]CustomBytes(nil), nullProto(), listType(tBytes), "null []CustomBytes"}, 203 // CUSTOM INT64 / CUSTOM INT64 ARRAY 204 {CustomInt64(81), intProto(81), tInt, "CustomInt64"}, 205 {[]CustomInt64(nil), nullProto(), listType(tInt), "null []CustomInt64"}, 206 {[]CustomInt64{33, 129}, listProto(intProto(33), intProto(129)), listType(tInt), "[]CustomInt64"}, 207 {CustomNullInt64{11, true}, intProto(11), tInt, "CustomNullInt64 with value"}, 208 {CustomNullInt64{11, false}, nullProto(), tInt, "CustomNullInt64 with null"}, 209 {[]CustomNullInt64(nil), nullProto(), listType(tInt), "null []CustomNullInt64"}, 210 {[]CustomNullInt64{{35, true}, {131, false}}, listProto(intProto(35), nullProto()), listType(tInt), "[]CustomNullInt64"}, 211 // CUSTOM BOOL / CUSTOM BOOL ARRAY 212 {CustomBool(true), boolProto(true), tBool, "CustomBool"}, 213 {CustomNullBool{true, true}, boolProto(true), tBool, "CustomNullBool with value"}, 214 {CustomNullBool{true, false}, nullProto(), tBool, "CustomNullBool with null"}, 215 {[]CustomBool{true, false}, listProto(boolProto(true), boolProto(false)), listType(tBool), "[]CustomBool"}, 216 {[]CustomNullBool{{true, true}, {true, false}}, listProto(boolProto(true), nullProto()), listType(tBool), "[]CustomNullBool"}, 217 // FLOAT64 / FLOAT64 ARRAY 218 {CustomFloat64(3.14), floatProto(3.14), tFloat, "CustomFloat64"}, 219 {CustomNullFloat64{3.1415, true}, floatProto(3.1415), tFloat, "CustomNullFloat64 with value"}, 220 {CustomNullFloat64{math.Inf(1), true}, floatProto(math.Inf(1)), tFloat, "CustomNullFloat64 with infinity"}, 221 {CustomNullFloat64{3.14159, false}, nullProto(), tFloat, "CustomNullFloat64 with null"}, 222 {[]CustomFloat64(nil), nullProto(), listType(tFloat), "null []CustomFloat64"}, 223 {[]CustomFloat64{3.141, 0.618, CustomFloat64(math.Inf(-1))}, listProto(floatProto(3.141), floatProto(0.618), floatProto(math.Inf(-1))), listType(tFloat), "[]CustomFloat64"}, 224 {[]CustomNullFloat64(nil), nullProto(), listType(tFloat), "null []CustomNullFloat64"}, 225 {[]CustomNullFloat64{{3.141, true}, {0.618, false}}, listProto(floatProto(3.141), nullProto()), listType(tFloat), "[]CustomNullFloat64"}, 226 // CUSTOM TIMESTAMP / CUSTOM TIMESTAMP ARRAY 227 {CustomTime(t1), timeProto(t1), tTime, "CustomTime"}, 228 {CustomNullTime{t1, true}, timeProto(t1), tTime, "CustomNullTime with value"}, 229 {CustomNullTime{t1, false}, nullProto(), tTime, "CustomNullTime with null"}, 230 {[]CustomTime(nil), nullProto(), listType(tTime), "null []CustomTime"}, 231 {[]CustomTime{CustomTime(t1), CustomTime(t2), CustomTime(t3), CustomTime(t4)}, listProto(timeProto(t1), timeProto(t2), timeProto(t3), timeProto(t4)), listType(tTime), "[]CustomTime"}, 232 {[]CustomNullTime(nil), nullProto(), listType(tTime), "null []CustomNullTime"}, 233 {[]CustomNullTime{{t1, true}, {t1, false}}, listProto(timeProto(t1), nullProto()), listType(tTime), "[]CustomNullTime"}, 234 // CUSTOM DATE / CUSTOM DATE ARRAY 235 {CustomDate(d1), dateProto(d1), tDate, "CustomDate"}, 236 {CustomNullDate{d1, true}, dateProto(d1), tDate, "CustomNullDate with value"}, 237 {CustomNullDate{civil.Date{}, false}, nullProto(), tDate, "CustomNullDate with null"}, 238 {[]CustomDate(nil), nullProto(), listType(tDate), "null []CustomDate"}, 239 {[]CustomDate{CustomDate(d1), CustomDate(d2)}, listProto(dateProto(d1), dateProto(d2)), listType(tDate), "[]CustomDate"}, 240 {[]CustomNullDate(nil), nullProto(), listType(tDate), "null []CustomNullDate"}, 241 {[]CustomNullDate{{d1, true}, {civil.Date{}, false}}, listProto(dateProto(d1), nullProto()), listType(tDate), "[]NullDate"}, 242 } { 243 got, gotType, err := encodeValue(test.in) 244 if err != nil { 245 t.Fatalf("#%d (%s): got error during encoding: %v, want nil", i, test.name, err) 246 } 247 if !testEqual(got, test.want) { 248 t.Errorf("#%d (%s): got encode result: %v, want %v", i, test.name, got, test.want) 249 } 250 if !testEqual(gotType, test.wantType) { 251 t.Errorf("#%d (%s): got encode type: %v, want %v", i, test.name, gotType, test.wantType) 252 } 253 } 254} 255 256type encodeTest struct { 257 desc string 258 in interface{} 259 want *proto3.Value 260 wantType *sppb.Type 261} 262 263func checkStructEncoding(desc string, got *proto3.Value, gotType *sppb.Type, 264 want *proto3.Value, wantType *sppb.Type, t *testing.T) { 265 if !testEqual(got, want) { 266 t.Errorf("Test %s: got encode result: %v, want %v", desc, got, want) 267 } 268 if !testEqual(gotType, wantType) { 269 t.Errorf("Test %s: got encode type: %v, want %v", desc, gotType, wantType) 270 } 271} 272 273// Testcase code 274func encodeStructValue(test encodeTest, t *testing.T) { 275 got, gotType, err := encodeValue(test.in) 276 if err != nil { 277 t.Fatalf("Test %s: got error during encoding: %v, want nil", test.desc, err) 278 } 279 checkStructEncoding(test.desc, got, gotType, test.want, test.wantType, t) 280} 281 282func TestEncodeStructValuePointers(t *testing.T) { 283 type structf struct { 284 F int `spanner:"ff2"` 285 } 286 nestedStructProto := structType(mkField("ff2", intType())) 287 288 type testType struct { 289 Stringf string 290 Structf *structf 291 ArrStructf []*structf 292 } 293 testTypeProto := structType( 294 mkField("Stringf", stringType()), 295 mkField("Structf", nestedStructProto), 296 mkField("ArrStructf", listType(nestedStructProto))) 297 298 for _, test := range []encodeTest{ 299 { 300 "Pointer to Go struct with pointers-to-(array)-struct fields.", 301 &testType{"hello", &structf{50}, []*structf{{30}, {40}}}, 302 listProto( 303 stringProto("hello"), 304 listProto(intProto(50)), 305 listProto( 306 listProto(intProto(30)), 307 listProto(intProto(40)))), 308 testTypeProto, 309 }, 310 { 311 "Nil pointer to Go struct representing a NULL struct value.", 312 (*testType)(nil), 313 nullProto(), 314 testTypeProto, 315 }, 316 { 317 "Slice of pointers to Go structs with NULL and non-NULL elements.", 318 []*testType{ 319 (*testType)(nil), 320 {"hello", nil, []*structf{nil, {40}}}, 321 {"world", &structf{70}, nil}, 322 }, 323 listProto( 324 nullProto(), 325 listProto( 326 stringProto("hello"), 327 nullProto(), 328 listProto(nullProto(), listProto(intProto(40)))), 329 listProto( 330 stringProto("world"), 331 listProto(intProto(70)), 332 nullProto())), 333 listType(testTypeProto), 334 }, 335 { 336 "Nil slice of pointers to structs representing a NULL array of structs.", 337 []*testType(nil), 338 nullProto(), 339 listType(testTypeProto), 340 }, 341 { 342 "Empty slice of pointers to structs representing an empty array of structs.", 343 []*testType{}, 344 listProto(), 345 listType(testTypeProto), 346 }, 347 } { 348 encodeStructValue(test, t) 349 } 350} 351 352func TestEncodeStructValueErrors(t *testing.T) { 353 type Embedded struct { 354 A int 355 } 356 type embedded struct { 357 B bool 358 } 359 x := 0 360 361 for _, test := range []struct { 362 desc string 363 in interface{} 364 wantErr error 365 }{ 366 { 367 "Unsupported embedded fields.", 368 struct{ Embedded }{Embedded{10}}, 369 errUnsupportedEmbeddedStructFields("Embedded"), 370 }, 371 { 372 "Unsupported pointer to embedded fields.", 373 struct{ *Embedded }{&Embedded{10}}, 374 errUnsupportedEmbeddedStructFields("Embedded"), 375 }, 376 { 377 "Unsupported embedded + unexported fields.", 378 struct { 379 int 380 *bool 381 embedded 382 }{10, nil, embedded{false}}, 383 errUnsupportedEmbeddedStructFields("int"), 384 }, 385 { 386 "Unsupported type.", 387 (**struct{})(nil), 388 errEncoderUnsupportedType((**struct{})(nil)), 389 }, 390 { 391 "Unsupported type.", 392 3, 393 errEncoderUnsupportedType(3), 394 }, 395 { 396 "Unsupported type.", 397 &x, 398 errEncoderUnsupportedType(&x), 399 }, 400 } { 401 _, _, got := encodeStruct(test.in) 402 if got == nil || !testEqual(test.wantErr, got) { 403 t.Errorf("Test: %s, expected error %v during decoding, got %v", test.desc, test.wantErr, got) 404 } 405 } 406} 407 408func TestEncodeStructValueArrayStructFields(t *testing.T) { 409 type structf struct { 410 Intff int 411 } 412 413 structfType := structType(mkField("Intff", intType())) 414 for _, test := range []encodeTest{ 415 { 416 "Unnamed array-of-struct-typed field.", 417 struct { 418 Intf int 419 ArrStructf []structf `spanner:""` 420 }{10, []structf{{1}, {2}}}, 421 listProto( 422 intProto(10), 423 listProto( 424 listProto(intProto(1)), 425 listProto(intProto(2)))), 426 structType( 427 mkField("Intf", intType()), 428 mkField("", listType(structfType))), 429 }, 430 { 431 "Null array-of-struct-typed field.", 432 struct { 433 Intf int 434 ArrStructf []structf 435 }{10, []structf(nil)}, 436 listProto(intProto(10), nullProto()), 437 structType( 438 mkField("Intf", intType()), 439 mkField("ArrStructf", listType(structfType))), 440 }, 441 { 442 "Array-of-struct-typed field representing empty array.", 443 struct { 444 Intf int 445 ArrStructf []structf 446 }{10, []structf{}}, 447 listProto(intProto(10), listProto([]*proto3.Value{}...)), 448 structType( 449 mkField("Intf", intType()), 450 mkField("ArrStructf", listType(structfType))), 451 }, 452 { 453 "Array-of-struct-typed field with nullable struct elements.", 454 struct { 455 Intf int 456 ArrStructf []*structf 457 }{ 458 10, 459 []*structf{(*structf)(nil), {1}}, 460 }, 461 listProto( 462 intProto(10), 463 listProto( 464 nullProto(), 465 listProto(intProto(1)))), 466 structType( 467 mkField("Intf", intType()), 468 mkField("ArrStructf", listType(structfType))), 469 }, 470 } { 471 encodeStructValue(test, t) 472 } 473} 474 475func TestEncodeStructValueStructFields(t *testing.T) { 476 type structf struct { 477 Intff int 478 } 479 structfType := structType(mkField("Intff", intType())) 480 for _, test := range []encodeTest{ 481 { 482 "Named struct-type field.", 483 struct { 484 Intf int 485 Structf structf 486 }{10, structf{10}}, 487 listProto(intProto(10), listProto(intProto(10))), 488 structType( 489 mkField("Intf", intType()), 490 mkField("Structf", structfType)), 491 }, 492 { 493 "Unnamed struct-type field.", 494 struct { 495 Intf int 496 Structf structf `spanner:""` 497 }{10, structf{10}}, 498 listProto(intProto(10), listProto(intProto(10))), 499 structType( 500 mkField("Intf", intType()), 501 mkField("", structfType)), 502 }, 503 { 504 "Duplicate struct-typed field.", 505 struct { 506 Structf1 structf `spanner:""` 507 Structf2 structf `spanner:""` 508 }{structf{10}, structf{20}}, 509 listProto(listProto(intProto(10)), listProto(intProto(20))), 510 structType( 511 mkField("", structfType), 512 mkField("", structfType)), 513 }, 514 { 515 "Null struct-typed field.", 516 struct { 517 Intf int 518 Structf *structf 519 }{10, nil}, 520 listProto(intProto(10), nullProto()), 521 structType( 522 mkField("Intf", intType()), 523 mkField("Structf", structfType)), 524 }, 525 { 526 "Empty struct-typed field.", 527 struct { 528 Intf int 529 Structf struct{} 530 }{10, struct{}{}}, 531 listProto(intProto(10), listProto([]*proto3.Value{}...)), 532 structType( 533 mkField("Intf", intType()), 534 mkField("Structf", structType([]*sppb.StructType_Field{}...))), 535 }, 536 } { 537 encodeStructValue(test, t) 538 } 539} 540 541func TestEncodeStructValueFieldNames(t *testing.T) { 542 type embedded struct { 543 B bool 544 } 545 546 for _, test := range []encodeTest{ 547 { 548 "Duplicate fields.", 549 struct { 550 Field1 int `spanner:"field"` 551 DupField1 int `spanner:"field"` 552 }{10, 20}, 553 listProto(intProto(10), intProto(20)), 554 structType( 555 mkField("field", intType()), 556 mkField("field", intType())), 557 }, 558 { 559 "Duplicate Fields (different types).", 560 struct { 561 IntField int `spanner:"field"` 562 StringField string `spanner:"field"` 563 }{10, "abc"}, 564 listProto(intProto(10), stringProto("abc")), 565 structType( 566 mkField("field", intType()), 567 mkField("field", stringType())), 568 }, 569 { 570 "Duplicate unnamed fields.", 571 struct { 572 Dup int `spanner:""` 573 Dup1 int `spanner:""` 574 }{10, 20}, 575 listProto(intProto(10), intProto(20)), 576 structType( 577 mkField("", intType()), 578 mkField("", intType())), 579 }, 580 { 581 "Named and unnamed fields.", 582 struct { 583 Field string 584 Field1 int `spanner:""` 585 Field2 string `spanner:"field"` 586 }{"abc", 10, "def"}, 587 listProto(stringProto("abc"), intProto(10), stringProto("def")), 588 structType( 589 mkField("Field", stringType()), 590 mkField("", intType()), 591 mkField("field", stringType())), 592 }, 593 { 594 "Ignored unexported fields.", 595 struct { 596 Field int 597 field bool 598 Field1 string `spanner:"field"` 599 }{10, false, "abc"}, 600 listProto(intProto(10), stringProto("abc")), 601 structType( 602 mkField("Field", intType()), 603 mkField("field", stringType())), 604 }, 605 { 606 "Ignored unexported struct/slice fields.", 607 struct { 608 a []*embedded 609 b []embedded 610 c embedded 611 d *embedded 612 Field1 string `spanner:"field"` 613 }{nil, nil, embedded{}, nil, "def"}, 614 listProto(stringProto("def")), 615 structType( 616 mkField("field", stringType())), 617 }, 618 } { 619 encodeStructValue(test, t) 620 } 621} 622 623func TestEncodeStructValueBasicFields(t *testing.T) { 624 type CustomString string 625 type CustomBytes []byte 626 type CustomInt64 int64 627 type CustomBool bool 628 type CustomFloat64 float64 629 type CustomTime time.Time 630 type CustomDate civil.Date 631 632 type CustomNullString NullString 633 type CustomNullInt64 NullInt64 634 type CustomNullBool NullBool 635 type CustomNullFloat64 NullFloat64 636 type CustomNullTime NullTime 637 type CustomNullDate NullDate 638 639 sValue := "abc" 640 iValue := int64(300) 641 bValue := false 642 fValue := 3.45 643 tValue := t1 644 dValue := d1 645 646 StructTypeProto := structType( 647 mkField("Stringf", stringType()), 648 mkField("Intf", intType()), 649 mkField("Boolf", boolType()), 650 mkField("Floatf", floatType()), 651 mkField("Bytef", bytesType()), 652 mkField("Timef", timeType()), 653 mkField("Datef", dateType())) 654 655 for _, test := range []encodeTest{ 656 { 657 "Basic types.", 658 struct { 659 Stringf string 660 Intf int 661 Boolf bool 662 Floatf float64 663 Bytef []byte 664 Timef time.Time 665 Datef civil.Date 666 }{"abc", 300, false, 3.45, []byte("foo"), t1, d1}, 667 listProto( 668 stringProto("abc"), 669 intProto(300), 670 boolProto(false), 671 floatProto(3.45), 672 bytesProto([]byte("foo")), 673 timeProto(t1), 674 dateProto(d1)), 675 StructTypeProto, 676 }, 677 { 678 "Pointers to basic types.", 679 struct { 680 Stringf *string 681 Intf *int64 682 Boolf *bool 683 Floatf *float64 684 Bytef []byte 685 Timef *time.Time 686 Datef *civil.Date 687 }{&sValue, &iValue, &bValue, &fValue, []byte("foo"), &tValue, &dValue}, 688 listProto( 689 stringProto("abc"), 690 intProto(300), 691 boolProto(false), 692 floatProto(3.45), 693 bytesProto([]byte("foo")), 694 timeProto(t1), 695 dateProto(d1)), 696 StructTypeProto, 697 }, 698 { 699 "Pointers to basic types with null values.", 700 struct { 701 Stringf *string 702 Intf *int64 703 Boolf *bool 704 Floatf *float64 705 Bytef []byte 706 Timef *time.Time 707 Datef *civil.Date 708 }{nil, nil, nil, nil, nil, nil, nil}, 709 listProto( 710 nullProto(), 711 nullProto(), 712 nullProto(), 713 nullProto(), 714 nullProto(), 715 nullProto(), 716 nullProto()), 717 StructTypeProto, 718 }, 719 { 720 "Basic custom types.", 721 struct { 722 Stringf CustomString 723 Intf CustomInt64 724 Boolf CustomBool 725 Floatf CustomFloat64 726 Bytef CustomBytes 727 Timef CustomTime 728 Datef CustomDate 729 }{"abc", 300, false, 3.45, []byte("foo"), CustomTime(t1), CustomDate(d1)}, 730 listProto( 731 stringProto("abc"), 732 intProto(300), 733 boolProto(false), 734 floatProto(3.45), 735 bytesProto([]byte("foo")), 736 timeProto(t1), 737 dateProto(d1)), 738 StructTypeProto, 739 }, 740 { 741 "Basic types null values.", 742 struct { 743 Stringf NullString 744 Intf NullInt64 745 Boolf NullBool 746 Floatf NullFloat64 747 Bytef []byte 748 Timef NullTime 749 Datef NullDate 750 }{ 751 NullString{"abc", false}, 752 NullInt64{4, false}, 753 NullBool{false, false}, 754 NullFloat64{5.6, false}, 755 nil, 756 NullTime{t1, false}, 757 NullDate{d1, false}, 758 }, 759 listProto( 760 nullProto(), 761 nullProto(), 762 nullProto(), 763 nullProto(), 764 nullProto(), 765 nullProto(), 766 nullProto()), 767 StructTypeProto, 768 }, 769 { 770 "Basic custom types null values.", 771 struct { 772 Stringf CustomNullString 773 Intf CustomNullInt64 774 Boolf CustomNullBool 775 Floatf CustomNullFloat64 776 Bytef CustomBytes 777 Timef CustomNullTime 778 Datef CustomNullDate 779 }{ 780 CustomNullString{"abc", false}, 781 CustomNullInt64{4, false}, 782 CustomNullBool{false, false}, 783 CustomNullFloat64{5.6, false}, 784 nil, 785 CustomNullTime{t1, false}, 786 CustomNullDate{d1, false}, 787 }, 788 listProto( 789 nullProto(), 790 nullProto(), 791 nullProto(), 792 nullProto(), 793 nullProto(), 794 nullProto(), 795 nullProto()), 796 StructTypeProto, 797 }, 798 } { 799 encodeStructValue(test, t) 800 } 801} 802 803func TestEncodeStructValueArrayFields(t *testing.T) { 804 type CustomString string 805 type CustomBytes []byte 806 type CustomInt64 int64 807 type CustomBool bool 808 type CustomFloat64 float64 809 type CustomTime time.Time 810 type CustomDate civil.Date 811 812 type CustomNullString NullString 813 type CustomNullInt64 NullInt64 814 type CustomNullBool NullBool 815 type CustomNullFloat64 NullFloat64 816 type CustomNullTime NullTime 817 type CustomNullDate NullDate 818 819 sValue := "def" 820 var sNilPtr *string 821 iValue := int64(68) 822 var iNilPtr *int64 823 bValue := true 824 var bNilPtr *bool 825 fValue := 3.14 826 var fNilPtr *float64 827 tValue := t1 828 var tNilPtr *time.Time 829 dValue := d1 830 var dNilPtr *civil.Date 831 832 StructTypeProto := structType( 833 mkField("Stringf", listType(stringType())), 834 mkField("Intf", listType(intType())), 835 mkField("Int64f", listType(intType())), 836 mkField("Boolf", listType(boolType())), 837 mkField("Floatf", listType(floatType())), 838 mkField("Bytef", listType(bytesType())), 839 mkField("Timef", listType(timeType())), 840 mkField("Datef", listType(dateType()))) 841 842 for _, test := range []encodeTest{ 843 { 844 "Arrays of basic types with non-nullable elements", 845 struct { 846 Stringf []string 847 Intf []int 848 Int64f []int64 849 Boolf []bool 850 Floatf []float64 851 Bytef [][]byte 852 Timef []time.Time 853 Datef []civil.Date 854 }{ 855 []string{"abc", "def"}, 856 []int{4, 67}, 857 []int64{5, 68}, 858 []bool{false, true}, 859 []float64{3.45, 0.93}, 860 [][]byte{[]byte("foo"), nil}, 861 []time.Time{t1, t2}, 862 []civil.Date{d1, d2}, 863 }, 864 listProto( 865 listProto(stringProto("abc"), stringProto("def")), 866 listProto(intProto(4), intProto(67)), 867 listProto(intProto(5), intProto(68)), 868 listProto(boolProto(false), boolProto(true)), 869 listProto(floatProto(3.45), floatProto(0.93)), 870 listProto(bytesProto([]byte("foo")), nullProto()), 871 listProto(timeProto(t1), timeProto(t2)), 872 listProto(dateProto(d1), dateProto(d2))), 873 StructTypeProto, 874 }, 875 { 876 "Arrays of basic custom types with non-nullable elements", 877 struct { 878 Stringf []CustomString 879 Intf []CustomInt64 880 Int64f []CustomInt64 881 Boolf []CustomBool 882 Floatf []CustomFloat64 883 Bytef []CustomBytes 884 Timef []CustomTime 885 Datef []CustomDate 886 }{ 887 []CustomString{"abc", "def"}, 888 []CustomInt64{4, 67}, 889 []CustomInt64{5, 68}, 890 []CustomBool{false, true}, 891 []CustomFloat64{3.45, 0.93}, 892 []CustomBytes{[]byte("foo"), nil}, 893 []CustomTime{CustomTime(t1), CustomTime(t2)}, 894 []CustomDate{CustomDate(d1), CustomDate(d2)}, 895 }, 896 listProto( 897 listProto(stringProto("abc"), stringProto("def")), 898 listProto(intProto(4), intProto(67)), 899 listProto(intProto(5), intProto(68)), 900 listProto(boolProto(false), boolProto(true)), 901 listProto(floatProto(3.45), floatProto(0.93)), 902 listProto(bytesProto([]byte("foo")), nullProto()), 903 listProto(timeProto(t1), timeProto(t2)), 904 listProto(dateProto(d1), dateProto(d2))), 905 StructTypeProto, 906 }, 907 { 908 "Arrays of basic types with nullable elements.", 909 struct { 910 Stringf []NullString 911 Intf []NullInt64 912 Int64f []NullInt64 913 Boolf []NullBool 914 Floatf []NullFloat64 915 Bytef [][]byte 916 Timef []NullTime 917 Datef []NullDate 918 }{ 919 []NullString{{"abc", false}, {"def", true}}, 920 []NullInt64{{4, false}, {67, true}}, 921 []NullInt64{{5, false}, {68, true}}, 922 []NullBool{{true, false}, {false, true}}, 923 []NullFloat64{{3.45, false}, {0.93, true}}, 924 [][]byte{[]byte("foo"), nil}, 925 []NullTime{{t1, false}, {t2, true}}, 926 []NullDate{{d1, false}, {d2, true}}, 927 }, 928 listProto( 929 listProto(nullProto(), stringProto("def")), 930 listProto(nullProto(), intProto(67)), 931 listProto(nullProto(), intProto(68)), 932 listProto(nullProto(), boolProto(false)), 933 listProto(nullProto(), floatProto(0.93)), 934 listProto(bytesProto([]byte("foo")), nullProto()), 935 listProto(nullProto(), timeProto(t2)), 936 listProto(nullProto(), dateProto(d2))), 937 StructTypeProto, 938 }, 939 { 940 "Arrays of pointers to basic types with nullable elements.", 941 struct { 942 Stringf []*string 943 Intf []*int64 944 Int64f []*int64 945 Boolf []*bool 946 Floatf []*float64 947 Bytef [][]byte 948 Timef []*time.Time 949 Datef []*civil.Date 950 }{ 951 []*string{sNilPtr, &sValue}, 952 []*int64{iNilPtr, &iValue}, 953 []*int64{iNilPtr, &iValue}, 954 []*bool{bNilPtr, &bValue}, 955 []*float64{fNilPtr, &fValue}, 956 [][]byte{[]byte("foo"), nil}, 957 []*time.Time{tNilPtr, &tValue}, 958 []*civil.Date{dNilPtr, &dValue}, 959 }, 960 listProto( 961 listProto(nullProto(), stringProto("def")), 962 listProto(nullProto(), intProto(68)), 963 listProto(nullProto(), intProto(68)), 964 listProto(nullProto(), boolProto(true)), 965 listProto(nullProto(), floatProto(3.14)), 966 listProto(bytesProto([]byte("foo")), nullProto()), 967 listProto(nullProto(), timeProto(t1)), 968 listProto(nullProto(), dateProto(d1))), 969 StructTypeProto, 970 }, 971 { 972 "Arrays of basic custom types with nullable elements.", 973 struct { 974 Stringf []CustomNullString 975 Intf []CustomNullInt64 976 Int64f []CustomNullInt64 977 Boolf []CustomNullBool 978 Floatf []CustomNullFloat64 979 Bytef []CustomBytes 980 Timef []CustomNullTime 981 Datef []CustomNullDate 982 }{ 983 []CustomNullString{{"abc", false}, {"def", true}}, 984 []CustomNullInt64{{4, false}, {67, true}}, 985 []CustomNullInt64{{5, false}, {68, true}}, 986 []CustomNullBool{{true, false}, {false, true}}, 987 []CustomNullFloat64{{3.45, false}, {0.93, true}}, 988 []CustomBytes{[]byte("foo"), nil}, 989 []CustomNullTime{{t1, false}, {t2, true}}, 990 []CustomNullDate{{d1, false}, {d2, true}}, 991 }, 992 listProto( 993 listProto(nullProto(), stringProto("def")), 994 listProto(nullProto(), intProto(67)), 995 listProto(nullProto(), intProto(68)), 996 listProto(nullProto(), boolProto(false)), 997 listProto(nullProto(), floatProto(0.93)), 998 listProto(bytesProto([]byte("foo")), nullProto()), 999 listProto(nullProto(), timeProto(t2)), 1000 listProto(nullProto(), dateProto(d2))), 1001 StructTypeProto, 1002 }, 1003 { 1004 "Null arrays of basic types.", 1005 struct { 1006 Stringf []NullString 1007 Intf []NullInt64 1008 Int64f []NullInt64 1009 Boolf []NullBool 1010 Floatf []NullFloat64 1011 Bytef [][]byte 1012 Timef []NullTime 1013 Datef []NullDate 1014 }{ 1015 nil, 1016 nil, 1017 nil, 1018 nil, 1019 nil, 1020 nil, 1021 nil, 1022 nil, 1023 }, 1024 listProto( 1025 nullProto(), 1026 nullProto(), 1027 nullProto(), 1028 nullProto(), 1029 nullProto(), 1030 nullProto(), 1031 nullProto(), 1032 nullProto()), 1033 StructTypeProto, 1034 }, 1035 { 1036 "Null arrays of basic custom types.", 1037 struct { 1038 Stringf []CustomNullString 1039 Intf []CustomNullInt64 1040 Int64f []CustomNullInt64 1041 Boolf []CustomNullBool 1042 Floatf []CustomNullFloat64 1043 Bytef []CustomBytes 1044 Timef []CustomNullTime 1045 Datef []CustomNullDate 1046 }{ 1047 nil, 1048 nil, 1049 nil, 1050 nil, 1051 nil, 1052 nil, 1053 nil, 1054 nil, 1055 }, 1056 listProto( 1057 nullProto(), 1058 nullProto(), 1059 nullProto(), 1060 nullProto(), 1061 nullProto(), 1062 nullProto(), 1063 nullProto(), 1064 nullProto()), 1065 StructTypeProto, 1066 }, 1067 } { 1068 encodeStructValue(test, t) 1069 } 1070} 1071 1072// Test decoding Values. 1073func TestDecodeValue(t *testing.T) { 1074 type CustomString string 1075 type CustomBytes []byte 1076 type CustomInt64 int64 1077 type CustomBool bool 1078 type CustomFloat64 float64 1079 type CustomTime time.Time 1080 type CustomDate civil.Date 1081 1082 type CustomNullString NullString 1083 type CustomNullInt64 NullInt64 1084 type CustomNullBool NullBool 1085 type CustomNullFloat64 NullFloat64 1086 type CustomNullTime NullTime 1087 type CustomNullDate NullDate 1088 1089 // Pointer values. 1090 sValue := "abc" 1091 var sNilPtr *string 1092 s2Value := "bcd" 1093 1094 iValue := int64(15) 1095 var iNilPtr *int64 1096 i1Value := int64(91) 1097 i2Value := int64(87) 1098 1099 bValue := true 1100 var bNilPtr *bool 1101 b2Value := false 1102 1103 fValue := 3.14 1104 var fNilPtr *float64 1105 f2Value := 6.626 1106 1107 tValue := t1 1108 var tNilPtr *time.Time 1109 t2Value := t2 1110 1111 dValue := d1 1112 var dNilPtr *civil.Date 1113 d2Value := d2 1114 1115 for _, test := range []struct { 1116 desc string 1117 proto *proto3.Value 1118 protoType *sppb.Type 1119 want interface{} 1120 wantErr bool 1121 }{ 1122 // STRING 1123 {desc: "decode STRING to string", proto: stringProto("abc"), protoType: stringType(), want: "abc"}, 1124 {desc: "decode NULL to string", proto: nullProto(), protoType: stringType(), want: "abc", wantErr: true}, 1125 {desc: "decode STRING to *string", proto: stringProto("abc"), protoType: stringType(), want: &sValue}, 1126 {desc: "decode NULL to *string", proto: nullProto(), protoType: stringType(), want: sNilPtr}, 1127 {desc: "decode STRING to NullString", proto: stringProto("abc"), protoType: stringType(), want: NullString{"abc", true}}, 1128 {desc: "decode NULL to NullString", proto: nullProto(), protoType: stringType(), want: NullString{}}, 1129 // STRING ARRAY with []NullString 1130 {desc: "decode ARRAY<STRING> to []NullString", proto: listProto(stringProto("abc"), nullProto(), stringProto("bcd")), protoType: listType(stringType()), want: []NullString{{"abc", true}, {}, {"bcd", true}}}, 1131 {desc: "decode NULL to []NullString", proto: nullProto(), protoType: listType(stringType()), want: []NullString(nil)}, 1132 // STRING ARRAY with []string 1133 {desc: "decode ARRAY<STRING> to []string", proto: listProto(stringProto("abc"), stringProto("bcd")), protoType: listType(stringType()), want: []string{"abc", "bcd"}}, 1134 // STRING ARRAY with []*string 1135 {desc: "decode ARRAY<STRING> to []*string", proto: listProto(stringProto("abc"), nullProto(), stringProto("bcd")), protoType: listType(stringType()), want: []*string{&sValue, sNilPtr, &s2Value}}, 1136 {desc: "decode NULL to []*string", proto: nullProto(), protoType: listType(stringType()), want: []*string(nil)}, 1137 // BYTES 1138 {desc: "decode BYTES to []byte", proto: bytesProto([]byte("ab")), protoType: bytesType(), want: []byte("ab")}, 1139 {desc: "decode NULL to []byte", proto: nullProto(), protoType: bytesType(), want: []byte(nil)}, 1140 // BYTES ARRAY 1141 {desc: "decode ARRAY<BYTES> to [][]byte", proto: listProto(bytesProto([]byte("ab")), nullProto()), protoType: listType(bytesType()), want: [][]byte{[]byte("ab"), nil}}, 1142 {desc: "decode NULL to [][]byte", proto: nullProto(), protoType: listType(bytesType()), want: [][]byte(nil)}, 1143 //INT64 1144 {desc: "decode INT64 to int64", proto: intProto(15), protoType: intType(), want: int64(15)}, 1145 {desc: "decode NULL to int64", proto: nullProto(), protoType: intType(), want: int64(0), wantErr: true}, 1146 {desc: "decode INT64 to *int64", proto: intProto(15), protoType: intType(), want: &iValue}, 1147 {desc: "decode NULL to *int64", proto: nullProto(), protoType: intType(), want: iNilPtr}, 1148 {desc: "decode INT64 to NullInt64", proto: intProto(15), protoType: intType(), want: NullInt64{15, true}}, 1149 {desc: "decode NULL to NullInt64", proto: nullProto(), protoType: intType(), want: NullInt64{}}, 1150 // INT64 ARRAY with []NullInt64 1151 {desc: "decode ARRAY<INT64> to []NullInt64", proto: listProto(intProto(91), nullProto(), intProto(87)), protoType: listType(intType()), want: []NullInt64{{91, true}, {}, {87, true}}}, 1152 {desc: "decode NULL to []NullInt64", proto: nullProto(), protoType: listType(intType()), want: []NullInt64(nil)}, 1153 // INT64 ARRAY with []int64 1154 {desc: "decode ARRAY<INT64> to []int64", proto: listProto(intProto(91), intProto(87)), protoType: listType(intType()), want: []int64{91, 87}}, 1155 // INT64 ARRAY with []*int64 1156 {desc: "decode ARRAY<INT64> to []*int64", proto: listProto(intProto(91), nullProto(), intProto(87)), protoType: listType(intType()), want: []*int64{&i1Value, nil, &i2Value}}, 1157 {desc: "decode NULL to []*int64", proto: nullProto(), protoType: listType(intType()), want: []*int64(nil)}, 1158 // BOOL 1159 {desc: "decode BOOL to bool", proto: boolProto(true), protoType: boolType(), want: true}, 1160 {desc: "decode NULL to bool", proto: nullProto(), protoType: boolType(), want: true, wantErr: true}, 1161 {desc: "decode BOOL to *bool", proto: boolProto(true), protoType: boolType(), want: &bValue}, 1162 {desc: "decode NULL to *bool", proto: nullProto(), protoType: boolType(), want: bNilPtr}, 1163 {desc: "decode BOOL to NullBool", proto: boolProto(true), protoType: boolType(), want: NullBool{true, true}}, 1164 {desc: "decode BOOL to NullBool", proto: nullProto(), protoType: boolType(), want: NullBool{}}, 1165 // BOOL ARRAY with []NullBool 1166 {desc: "decode ARRAY<BOOL> to []NullBool", proto: listProto(boolProto(true), boolProto(false), nullProto()), protoType: listType(boolType()), want: []NullBool{{true, true}, {false, true}, {}}}, 1167 {desc: "decode NULL to []NullBool", proto: nullProto(), protoType: listType(boolType()), want: []NullBool(nil)}, 1168 // BOOL ARRAY with []bool 1169 {desc: "decode ARRAY<BOOL> to []bool", proto: listProto(boolProto(true), boolProto(false)), protoType: listType(boolType()), want: []bool{true, false}}, 1170 // BOOL ARRAY with []*bool 1171 {desc: "decode ARRAY<BOOL> to []*bool", proto: listProto(boolProto(true), nullProto(), boolProto(false)), protoType: listType(boolType()), want: []*bool{&bValue, bNilPtr, &b2Value}}, 1172 {desc: "decode NULL to []*bool", proto: nullProto(), protoType: listType(boolType()), want: []*bool(nil)}, 1173 // FLOAT64 1174 {desc: "decode FLOAT64 to float64", proto: floatProto(3.14), protoType: floatType(), want: 3.14}, 1175 {desc: "decode NULL to float64", proto: nullProto(), protoType: floatType(), want: 0.00, wantErr: true}, 1176 {desc: "decode FLOAT64 to *float64", proto: floatProto(3.14), protoType: floatType(), want: &fValue}, 1177 {desc: "decode NULL to *float64", proto: nullProto(), protoType: floatType(), want: fNilPtr}, 1178 {desc: "decode FLOAT64 to NullFloat64", proto: floatProto(3.14), protoType: floatType(), want: NullFloat64{3.14, true}}, 1179 {desc: "decode NULL to NullFloat64", proto: nullProto(), protoType: floatType(), want: NullFloat64{}}, 1180 // FLOAT64 ARRAY with []NullFloat64 1181 {desc: "decode ARRAY<FLOAT64> to []NullFloat64", proto: listProto(floatProto(math.Inf(1)), floatProto(math.Inf(-1)), nullProto(), floatProto(3.1)), protoType: listType(floatType()), want: []NullFloat64{{math.Inf(1), true}, {math.Inf(-1), true}, {}, {3.1, true}}}, 1182 {desc: "decode NULL to []NullFloat64", proto: nullProto(), protoType: listType(floatType()), want: []NullFloat64(nil)}, 1183 // FLOAT64 ARRAY with []float64 1184 {desc: "decode ARRAY<FLOAT64> to []float64", proto: listProto(floatProto(math.Inf(1)), floatProto(math.Inf(-1)), floatProto(3.1)), protoType: listType(floatType()), want: []float64{math.Inf(1), math.Inf(-1), 3.1}}, 1185 // FLOAT64 ARRAY with []NullFloat64 1186 {desc: "decode ARRAY<FLOAT64> to []*float64", proto: listProto(floatProto(fValue), nullProto(), floatProto(f2Value)), protoType: listType(floatType()), want: []*float64{&fValue, nil, &f2Value}}, 1187 {desc: "decode NULL to []*float64", proto: nullProto(), protoType: listType(floatType()), want: []*float64(nil)}, 1188 // TIMESTAMP 1189 {desc: "decode TIMESTAMP to time.Time", proto: timeProto(t1), protoType: timeType(), want: t1}, 1190 {desc: "decode TIMESTAMP to NullTime", proto: timeProto(t1), protoType: timeType(), want: NullTime{t1, true}}, 1191 {desc: "decode NULL to NullTime", proto: nullProto(), protoType: timeType(), want: NullTime{}}, 1192 {desc: "decode TIMESTAMP to *time.Time", proto: timeProto(t1), protoType: timeType(), want: &tValue}, 1193 {desc: "decode NULL to *time.Time", proto: nullProto(), protoType: timeType(), want: tNilPtr}, 1194 {desc: "decode INT64 to time.Time", proto: intProto(7), protoType: timeType(), want: time.Time{}, wantErr: true}, 1195 // TIMESTAMP ARRAY with []NullTime 1196 {desc: "decode ARRAY<TIMESTAMP> to []NullTime", proto: listProto(timeProto(t1), timeProto(t2), timeProto(t3), nullProto()), protoType: listType(timeType()), want: []NullTime{{t1, true}, {t2, true}, {t3, true}, {}}}, 1197 {desc: "decode NULL to []NullTime", proto: nullProto(), protoType: listType(timeType()), want: []NullTime(nil)}, 1198 // TIMESTAMP ARRAY with []time.Time 1199 {desc: "decode ARRAY<TIMESTAMP> to []time.Time", proto: listProto(timeProto(t1), timeProto(t2), timeProto(t3)), protoType: listType(timeType()), want: []time.Time{t1, t2, t3}}, 1200 // TIMESTAMP ARRAY with []*time.Time 1201 {desc: "decode ARRAY<TIMESTAMP> to []*time.Time", proto: listProto(timeProto(t1), nullProto(), timeProto(t2)), protoType: listType(timeType()), want: []*time.Time{&tValue, nil, &t2Value}}, 1202 {desc: "decode NULL to []*time.Time", proto: nullProto(), protoType: listType(timeType()), want: []*time.Time(nil)}, 1203 // DATE 1204 {desc: "decode DATE to civil.Date", proto: dateProto(d1), protoType: dateType(), want: d1}, 1205 {desc: "decode DATE to NullDate", proto: dateProto(d1), protoType: dateType(), want: NullDate{d1, true}}, 1206 {desc: "decode NULL to NullDate", proto: nullProto(), protoType: dateType(), want: NullDate{}}, 1207 {desc: "decode DATE to *civil.Date", proto: dateProto(d1), protoType: dateType(), want: &dValue}, 1208 {desc: "decode NULL to *civil.Date", proto: nullProto(), protoType: dateType(), want: dNilPtr}, 1209 // DATE ARRAY with []NullDate 1210 {desc: "decode ARRAY<DATE> to []NullDate", proto: listProto(dateProto(d1), dateProto(d2), nullProto()), protoType: listType(dateType()), want: []NullDate{{d1, true}, {d2, true}, {}}}, 1211 {desc: "decode NULL to []NullDate", proto: nullProto(), protoType: listType(dateType()), want: []NullDate(nil)}, 1212 // DATE ARRAY with []civil.Date 1213 {desc: "decode ARRAY<DATE> to []civil.Date", proto: listProto(dateProto(d1), dateProto(d2)), protoType: listType(dateType()), want: []civil.Date{d1, d2}}, 1214 // DATE ARRAY with []NullDate 1215 {desc: "decode ARRAY<DATE> to []*civil.Date", proto: listProto(dateProto(d1), nullProto(), dateProto(d2)), protoType: listType(dateType()), want: []*civil.Date{&dValue, nil, &d2Value}}, 1216 {desc: "decode NULL to []*civil.Date", proto: nullProto(), protoType: listType(dateType()), want: []*civil.Date(nil)}, 1217 // STRUCT ARRAY 1218 // STRUCT schema is equal to the following Go struct: 1219 // type s struct { 1220 // Col1 NullInt64 1221 // Col2 []struct { 1222 // SubCol1 float64 1223 // SubCol2 string 1224 // } 1225 // } 1226 { 1227 desc: "decode ARRAY<STRUCT> to []NullRow", 1228 proto: listProto( 1229 listProto( 1230 intProto(3), 1231 listProto( 1232 listProto(floatProto(3.14), stringProto("this")), 1233 listProto(floatProto(0.57), stringProto("siht")), 1234 ), 1235 ), 1236 listProto( 1237 nullProto(), 1238 nullProto(), 1239 ), 1240 nullProto(), 1241 ), 1242 protoType: listType( 1243 structType( 1244 mkField("Col1", intType()), 1245 mkField( 1246 "Col2", 1247 listType( 1248 structType( 1249 mkField("SubCol1", floatType()), 1250 mkField("SubCol2", stringType()), 1251 ), 1252 ), 1253 ), 1254 ), 1255 ), 1256 want: []NullRow{ 1257 { 1258 Row: Row{ 1259 fields: []*sppb.StructType_Field{ 1260 mkField("Col1", intType()), 1261 mkField( 1262 "Col2", 1263 listType( 1264 structType( 1265 mkField("SubCol1", floatType()), 1266 mkField("SubCol2", stringType()), 1267 ), 1268 ), 1269 ), 1270 }, 1271 vals: []*proto3.Value{ 1272 intProto(3), 1273 listProto( 1274 listProto(floatProto(3.14), stringProto("this")), 1275 listProto(floatProto(0.57), stringProto("siht")), 1276 ), 1277 }, 1278 }, 1279 Valid: true, 1280 }, 1281 { 1282 Row: Row{ 1283 fields: []*sppb.StructType_Field{ 1284 mkField("Col1", intType()), 1285 mkField( 1286 "Col2", 1287 listType( 1288 structType( 1289 mkField("SubCol1", floatType()), 1290 mkField("SubCol2", stringType()), 1291 ), 1292 ), 1293 ), 1294 }, 1295 vals: []*proto3.Value{ 1296 nullProto(), 1297 nullProto(), 1298 }, 1299 }, 1300 Valid: true, 1301 }, 1302 {}, 1303 }, 1304 }, 1305 { 1306 desc: "decode ARRAY<STRUCT> to []*struct", 1307 proto: listProto( 1308 listProto( 1309 intProto(3), 1310 listProto( 1311 listProto(floatProto(3.14), stringProto("this")), 1312 listProto(floatProto(0.57), stringProto("siht")), 1313 ), 1314 ), 1315 listProto( 1316 nullProto(), 1317 nullProto(), 1318 ), 1319 nullProto(), 1320 ), 1321 protoType: listType( 1322 structType( 1323 mkField("Col1", intType()), 1324 mkField( 1325 "Col2", 1326 listType( 1327 structType( 1328 mkField("SubCol1", floatType()), 1329 mkField("SubCol2", stringType()), 1330 ), 1331 ), 1332 ), 1333 ), 1334 ), 1335 want: []*struct { 1336 Col1 NullInt64 1337 StructCol []*struct { 1338 SubCol1 NullFloat64 1339 SubCol2 string 1340 } `spanner:"Col2"` 1341 }{ 1342 { 1343 Col1: NullInt64{3, true}, 1344 StructCol: []*struct { 1345 SubCol1 NullFloat64 1346 SubCol2 string 1347 }{ 1348 { 1349 SubCol1: NullFloat64{3.14, true}, 1350 SubCol2: "this", 1351 }, 1352 { 1353 SubCol1: NullFloat64{0.57, true}, 1354 SubCol2: "siht", 1355 }, 1356 }, 1357 }, 1358 { 1359 Col1: NullInt64{}, 1360 StructCol: []*struct { 1361 SubCol1 NullFloat64 1362 SubCol2 string 1363 }(nil), 1364 }, 1365 nil, 1366 }, 1367 }, 1368 // GenericColumnValue 1369 {desc: "decode STRING to GenericColumnValue", proto: stringProto("abc"), protoType: stringType(), want: GenericColumnValue{stringType(), stringProto("abc")}}, 1370 {desc: "decode NULL to GenericColumnValue", proto: nullProto(), protoType: stringType(), want: GenericColumnValue{stringType(), nullProto()}}, 1371 // not actually valid (stringProto inside int list), but demonstrates pass-through. 1372 {desc: "decode ARRAY<INT64> to GenericColumnValue", proto: listProto(intProto(5), nullProto(), stringProto("bcd")), protoType: listType(intType()), want: GenericColumnValue{Type: listType(intType()), Value: listProto(intProto(5), nullProto(), stringProto("bcd"))}}, 1373 1374 // Custom base types. 1375 {desc: "decode STRING to CustomString", proto: stringProto("bar"), protoType: stringType(), want: CustomString("bar")}, 1376 {desc: "decode BYTES to CustomBytes", proto: bytesProto([]byte("ab")), protoType: bytesType(), want: CustomBytes("ab")}, 1377 {desc: "decode INT64 to CustomInt64", proto: intProto(-100), protoType: intType(), want: CustomInt64(-100)}, 1378 {desc: "decode BOOL to CustomBool", proto: boolProto(true), protoType: boolType(), want: CustomBool(true)}, 1379 {desc: "decode FLOAT64 to CustomFloat64", proto: floatProto(6.626), protoType: floatType(), want: CustomFloat64(6.626)}, 1380 {desc: "decode TIMESTAMP to CustomTimestamp", proto: timeProto(t1), protoType: timeType(), want: CustomTime(t1)}, 1381 {desc: "decode DATE to CustomDate", proto: dateProto(d1), protoType: dateType(), want: CustomDate(d1)}, 1382 1383 {desc: "decode NULL to CustomString", proto: nullProto(), protoType: stringType(), want: CustomString(""), wantErr: true}, 1384 {desc: "decode NULL to CustomBytes", proto: nullProto(), protoType: bytesType(), want: CustomBytes(nil)}, 1385 {desc: "decode NULL to CustomInt64", proto: nullProto(), protoType: intType(), want: CustomInt64(0), wantErr: true}, 1386 {desc: "decode NULL to CustomBool", proto: nullProto(), protoType: boolType(), want: CustomBool(false), wantErr: true}, 1387 {desc: "decode NULL to CustomFloat64", proto: nullProto(), protoType: floatType(), want: CustomFloat64(0), wantErr: true}, 1388 {desc: "decode NULL to CustomTime", proto: nullProto(), protoType: timeType(), want: CustomTime{}, wantErr: true}, 1389 {desc: "decode NULL to CustomDate", proto: nullProto(), protoType: dateType(), want: CustomDate{}, wantErr: true}, 1390 1391 {desc: "decode STRING to CustomNullString", proto: stringProto("bar"), protoType: stringType(), want: CustomNullString{"bar", true}}, 1392 {desc: "decode INT64 to CustomNullInt64", proto: intProto(-100), protoType: intType(), want: CustomNullInt64{-100, true}}, 1393 {desc: "decode BOOL to CustomNullBool", proto: boolProto(true), protoType: boolType(), want: CustomNullBool{true, true}}, 1394 {desc: "decode FLOAT64 to CustomNullFloat64", proto: floatProto(6.626), protoType: floatType(), want: CustomNullFloat64{6.626, true}}, 1395 {desc: "decode TIMESTAMP to CustomNullTime", proto: timeProto(t1), protoType: timeType(), want: CustomNullTime{t1, true}}, 1396 {desc: "decode DATE to CustomNullDate", proto: dateProto(d1), protoType: dateType(), want: CustomNullDate{d1, true}}, 1397 1398 {desc: "decode NULL to CustomNullString", proto: nullProto(), protoType: stringType(), want: CustomNullString{}}, 1399 {desc: "decode NULL to CustomNullInt64", proto: nullProto(), protoType: intType(), want: CustomNullInt64{}}, 1400 {desc: "decode NULL to CustomNullBool", proto: nullProto(), protoType: boolType(), want: CustomNullBool{}}, 1401 {desc: "decode NULL to CustomNullFloat64", proto: nullProto(), protoType: floatType(), want: CustomNullFloat64{}}, 1402 {desc: "decode NULL to CustomNullTime", proto: nullProto(), protoType: timeType(), want: CustomNullTime{}}, 1403 {desc: "decode NULL to CustomNullDate", proto: nullProto(), protoType: dateType(), want: CustomNullDate{}}, 1404 1405 // STRING ARRAY 1406 {desc: "decode NULL to []CustomString", proto: nullProto(), protoType: listType(stringType()), want: []CustomString(nil)}, 1407 {desc: "decode ARRAY<STRING> to []CustomString", proto: listProto(stringProto("abc"), stringProto("bcd")), protoType: listType(stringType()), want: []CustomString{"abc", "bcd"}}, 1408 {desc: "decode ARRAY<STRING> with NULL values to []CustomString", proto: listProto(stringProto("abc"), nullProto(), stringProto("bcd")), protoType: listType(stringType()), want: []CustomString{}, wantErr: true}, 1409 {desc: "decode NULL to []CustomNullString", proto: nullProto(), protoType: listType(stringType()), want: []CustomNullString(nil)}, 1410 {desc: "decode ARRAY<STRING> to []CustomNullString", proto: listProto(stringProto("abc"), nullProto(), stringProto("bcd")), protoType: listType(stringType()), want: []CustomNullString{{"abc", true}, {}, {"bcd", true}}}, 1411 // BYTES ARRAY 1412 {desc: "decode NULL to []CustomBytes", proto: nullProto(), protoType: listType(bytesType()), want: []CustomBytes(nil)}, 1413 {desc: "decode ARRAY<BYTES> to []CustomBytes", proto: listProto(bytesProto([]byte("abc")), nullProto(), bytesProto([]byte("bcd"))), protoType: listType(bytesType()), want: []CustomBytes{CustomBytes("abc"), CustomBytes(nil), CustomBytes("bcd")}}, 1414 // INT64 ARRAY 1415 {desc: "decode NULL to []CustomInt64", proto: nullProto(), protoType: listType(intType()), want: []CustomInt64(nil)}, 1416 {desc: "decode ARRAY<INT64> with NULL values to []CustomInt64", proto: listProto(intProto(-100), nullProto(), intProto(100)), protoType: listType(intType()), want: []CustomInt64{}, wantErr: true}, 1417 {desc: "decode ARRAY<INT64> to []CustomInt64", proto: listProto(intProto(-100), intProto(100)), protoType: listType(intType()), want: []CustomInt64{-100, 100}}, 1418 {desc: "decode NULL to []CustomNullInt64", proto: nullProto(), protoType: listType(intType()), want: []CustomNullInt64(nil)}, 1419 {desc: "decode ARRAY<INT64> to []CustomNullInt64", proto: listProto(intProto(-100), nullProto(), intProto(100)), protoType: listType(intType()), want: []CustomNullInt64{{-100, true}, {}, {100, true}}}, 1420 // BOOL ARRAY 1421 {desc: "decode NULL to []CustomBool", proto: nullProto(), protoType: listType(boolType()), want: []CustomBool(nil)}, 1422 {desc: "decode ARRAY<BOOL> with NULL values to []CustomBool", proto: listProto(boolProto(false), nullProto(), boolProto(true)), protoType: listType(boolType()), want: []CustomBool{}, wantErr: true}, 1423 {desc: "decode ARRAY<BOOL> to []CustomBool", proto: listProto(boolProto(false), boolProto(true)), protoType: listType(boolType()), want: []CustomBool{false, true}}, 1424 {desc: "decode NULL to []CustomNullBool", proto: nullProto(), protoType: listType(boolType()), want: []CustomNullBool(nil)}, 1425 {desc: "decode ARRAY<BOOL> to []CustomNullBool", proto: listProto(boolProto(false), nullProto(), boolProto(true)), protoType: listType(boolType()), want: []CustomNullBool{{false, true}, {}, {true, true}}}, 1426 // FLOAT64 ARRAY 1427 {desc: "decode NULL to []CustomFloat64", proto: nullProto(), protoType: listType(floatType()), want: []CustomFloat64(nil)}, 1428 {desc: "decode ARRAY<FLOAT64> with NULL values to []CustomFloat64", proto: listProto(floatProto(3.14), nullProto(), floatProto(6.626)), protoType: listType(floatType()), want: []CustomFloat64{}, wantErr: true}, 1429 {desc: "decode ARRAY<FLOAT64> to []CustomFloat64", proto: listProto(floatProto(3.14), floatProto(6.626)), protoType: listType(floatType()), want: []CustomFloat64{3.14, 6.626}}, 1430 {desc: "decode NULL to []CustomNullFloat64", proto: nullProto(), protoType: listType(floatType()), want: []CustomNullFloat64(nil)}, 1431 {desc: "decode ARRAY<FLOAT64> to []CustomNullFloat64", proto: listProto(floatProto(3.14), nullProto(), floatProto(6.626)), protoType: listType(floatType()), want: []CustomNullFloat64{{3.14, true}, {}, {6.626, true}}}, 1432 // TIME ARRAY 1433 {desc: "decode NULL to []CustomTime", proto: nullProto(), protoType: listType(timeType()), want: []CustomTime(nil)}, 1434 {desc: "decode ARRAY<TIMESTAMP> with NULL values to []CustomTime", proto: listProto(timeProto(t1), nullProto(), timeProto(t2)), protoType: listType(timeType()), want: []CustomTime{}, wantErr: true}, 1435 {desc: "decode ARRAY<TIMESTAMP> to []CustomTime", proto: listProto(timeProto(t1), timeProto(t2)), protoType: listType(timeType()), want: []CustomTime{CustomTime(t1), CustomTime(t2)}}, 1436 {desc: "decode NULL to []CustomNullTime", proto: nullProto(), protoType: listType(timeType()), want: []CustomNullTime(nil)}, 1437 {desc: "decode ARRAY<TIMESTAMP> to []CustomNullTime", proto: listProto(timeProto(t1), nullProto(), timeProto(t2)), protoType: listType(timeType()), want: []CustomNullTime{{t1, true}, {}, {t2, true}}}, 1438 // DATE ARRAY 1439 {desc: "decode NULL to []CustomDate", proto: nullProto(), protoType: listType(dateType()), want: []CustomDate(nil)}, 1440 {desc: "decode ARRAY<DATE> with NULL values to []CustomDate", proto: listProto(dateProto(d1), nullProto(), dateProto(d2)), protoType: listType(dateType()), want: []CustomDate{}, wantErr: true}, 1441 {desc: "decode ARRAY<DATE> to []CustomDate", proto: listProto(dateProto(d1), dateProto(d2)), protoType: listType(dateType()), want: []CustomDate{CustomDate(d1), CustomDate(d2)}}, 1442 {desc: "decode NULL to []CustomNullDate", proto: nullProto(), protoType: listType(dateType()), want: []CustomNullDate(nil)}, 1443 {desc: "decode ARRAY<DATE> to []CustomNullDate", proto: listProto(dateProto(d1), nullProto(), dateProto(d2)), protoType: listType(dateType()), want: []CustomNullDate{{d1, true}, {}, {d2, true}}}, 1444 } { 1445 gotp := reflect.New(reflect.TypeOf(test.want)) 1446 err := decodeValue(test.proto, test.protoType, gotp.Interface()) 1447 if test.wantErr { 1448 if err == nil { 1449 t.Errorf("%s: missing expected decode failure for %v(%v)", test.desc, test.proto, test.protoType) 1450 } 1451 continue 1452 } 1453 if err != nil { 1454 t.Errorf("%s: cannot decode %v(%v): %v", test.desc, test.proto, test.protoType, err) 1455 continue 1456 } 1457 got := reflect.Indirect(gotp).Interface() 1458 if !testutil.Equal(got, test.want, cmp.AllowUnexported(CustomTime{}, CustomDate{}, Row{})) { 1459 t.Errorf("%s: unexpected decoding result - got %v (%T), want %v (%T)", test.desc, got, got, test.want, test.want) 1460 } 1461 } 1462} 1463 1464// Test error cases for decodeValue. 1465func TestDecodeValueErrors(t *testing.T) { 1466 var s string 1467 for i, test := range []struct { 1468 in *proto3.Value 1469 t *sppb.Type 1470 v interface{} 1471 }{ 1472 {nullProto(), stringType(), nil}, 1473 {nullProto(), stringType(), 1}, 1474 {timeProto(t1), timeType(), &s}, 1475 } { 1476 err := decodeValue(test.in, test.t, test.v) 1477 if err == nil { 1478 t.Errorf("#%d: want error, got nil", i) 1479 } 1480 } 1481} 1482 1483func TestGetDecodableSpannerType(t *testing.T) { 1484 type CustomString string 1485 type CustomInt64 int64 1486 type CustomBool bool 1487 type CustomFloat64 float64 1488 type CustomTime time.Time 1489 type CustomDate civil.Date 1490 1491 type CustomNullString NullString 1492 type CustomNullInt64 NullInt64 1493 type CustomNullBool NullBool 1494 type CustomNullFloat64 NullFloat64 1495 type CustomNullTime NullTime 1496 type CustomNullDate NullDate 1497 1498 type StringEmbedded struct { 1499 string 1500 } 1501 type NullStringEmbedded struct { 1502 NullString 1503 } 1504 1505 for i, test := range []struct { 1506 in interface{} 1507 want decodableSpannerType 1508 }{ 1509 {"foo", spannerTypeNonNullString}, 1510 {[]byte("ab"), spannerTypeByteArray}, 1511 {[]byte(nil), spannerTypeByteArray}, 1512 {int64(123), spannerTypeNonNullInt64}, 1513 {true, spannerTypeNonNullBool}, 1514 {3.14, spannerTypeNonNullFloat64}, 1515 {time.Now(), spannerTypeNonNullTime}, 1516 {civil.DateOf(time.Now()), spannerTypeNonNullDate}, 1517 {NullString{}, spannerTypeNullString}, 1518 {NullInt64{}, spannerTypeNullInt64}, 1519 {NullBool{}, spannerTypeNullBool}, 1520 {NullFloat64{}, spannerTypeNullFloat64}, 1521 {NullTime{}, spannerTypeNullTime}, 1522 {NullDate{}, spannerTypeNullDate}, 1523 1524 {[]string{"foo", "bar"}, spannerTypeArrayOfNonNullString}, 1525 {[][]byte{{1, 2, 3}, {3, 2, 1}}, spannerTypeArrayOfByteArray}, 1526 {[][]byte{}, spannerTypeArrayOfByteArray}, 1527 {[]int64{int64(123)}, spannerTypeArrayOfNonNullInt64}, 1528 {[]bool{true}, spannerTypeArrayOfNonNullBool}, 1529 {[]float64{3.14}, spannerTypeArrayOfNonNullFloat64}, 1530 {[]time.Time{time.Now()}, spannerTypeArrayOfNonNullTime}, 1531 {[]civil.Date{civil.DateOf(time.Now())}, spannerTypeArrayOfNonNullDate}, 1532 {[]NullString{}, spannerTypeArrayOfNullString}, 1533 {[]NullInt64{}, spannerTypeArrayOfNullInt64}, 1534 {[]NullBool{}, spannerTypeArrayOfNullBool}, 1535 {[]NullFloat64{}, spannerTypeArrayOfNullFloat64}, 1536 {[]NullTime{}, spannerTypeArrayOfNullTime}, 1537 {[]NullDate{}, spannerTypeArrayOfNullDate}, 1538 1539 {CustomString("foo"), spannerTypeNonNullString}, 1540 {CustomInt64(-100), spannerTypeNonNullInt64}, 1541 {CustomBool(true), spannerTypeNonNullBool}, 1542 {CustomFloat64(3.141592), spannerTypeNonNullFloat64}, 1543 {CustomTime(time.Now()), spannerTypeNonNullTime}, 1544 {CustomDate(civil.DateOf(time.Now())), spannerTypeNonNullDate}, 1545 1546 {[]CustomString{}, spannerTypeArrayOfNonNullString}, 1547 {[]CustomInt64{}, spannerTypeArrayOfNonNullInt64}, 1548 {[]CustomBool{}, spannerTypeArrayOfNonNullBool}, 1549 {[]CustomFloat64{}, spannerTypeArrayOfNonNullFloat64}, 1550 {[]CustomTime{}, spannerTypeArrayOfNonNullTime}, 1551 {[]CustomDate{}, spannerTypeArrayOfNonNullDate}, 1552 1553 {CustomNullString{}, spannerTypeNullString}, 1554 {CustomNullInt64{}, spannerTypeNullInt64}, 1555 {CustomNullBool{}, spannerTypeNullBool}, 1556 {CustomNullFloat64{}, spannerTypeNullFloat64}, 1557 {CustomNullTime{}, spannerTypeNullTime}, 1558 {CustomNullDate{}, spannerTypeNullDate}, 1559 1560 {[]CustomNullString{}, spannerTypeArrayOfNullString}, 1561 {[]CustomNullInt64{}, spannerTypeArrayOfNullInt64}, 1562 {[]CustomNullBool{}, spannerTypeArrayOfNullBool}, 1563 {[]CustomNullFloat64{}, spannerTypeArrayOfNullFloat64}, 1564 {[]CustomNullTime{}, spannerTypeArrayOfNullTime}, 1565 {[]CustomNullDate{}, spannerTypeArrayOfNullDate}, 1566 1567 {StringEmbedded{}, spannerTypeUnknown}, 1568 {NullStringEmbedded{}, spannerTypeUnknown}, 1569 } { 1570 gotp := reflect.New(reflect.TypeOf(test.in)) 1571 got := getDecodableSpannerType(gotp.Interface()) 1572 if got != test.want { 1573 t.Errorf("%d: unexpected decodable type - got %v, want %v", i, got, test.want) 1574 } 1575 } 1576} 1577 1578// Test NaN encoding/decoding. 1579func TestNaN(t *testing.T) { 1580 // Decode NaN value. 1581 f := 0.0 1582 nf := NullFloat64{} 1583 // To float64 1584 if err := decodeValue(floatProto(math.NaN()), floatType(), &f); err != nil { 1585 t.Errorf("decodeValue returns %q for %v, want nil", err, floatProto(math.NaN())) 1586 } 1587 if !math.IsNaN(f) { 1588 t.Errorf("f = %v, want %v", f, math.NaN()) 1589 } 1590 // To NullFloat64 1591 if err := decodeValue(floatProto(math.NaN()), floatType(), &nf); err != nil { 1592 t.Errorf("decodeValue returns %q for %v, want nil", err, floatProto(math.NaN())) 1593 } 1594 if !math.IsNaN(nf.Float64) || !nf.Valid { 1595 t.Errorf("f = %v, want %v", f, NullFloat64{math.NaN(), true}) 1596 } 1597 // Encode NaN value 1598 // From float64 1599 v, _, err := encodeValue(math.NaN()) 1600 if err != nil { 1601 t.Errorf("encodeValue returns %q for NaN, want nil", err) 1602 } 1603 x, ok := v.GetKind().(*proto3.Value_NumberValue) 1604 if !ok { 1605 t.Errorf("incorrect type for v.GetKind(): %T, want *proto3.Value_NumberValue", v.GetKind()) 1606 } 1607 if !math.IsNaN(x.NumberValue) { 1608 t.Errorf("x.NumberValue = %v, want %v", x.NumberValue, math.NaN()) 1609 } 1610 // From NullFloat64 1611 v, _, err = encodeValue(NullFloat64{math.NaN(), true}) 1612 if err != nil { 1613 t.Errorf("encodeValue returns %q for NaN, want nil", err) 1614 } 1615 x, ok = v.GetKind().(*proto3.Value_NumberValue) 1616 if !ok { 1617 t.Errorf("incorrect type for v.GetKind(): %T, want *proto3.Value_NumberValue", v.GetKind()) 1618 } 1619 if !math.IsNaN(x.NumberValue) { 1620 t.Errorf("x.NumberValue = %v, want %v", x.NumberValue, math.NaN()) 1621 } 1622} 1623 1624func TestGenericColumnValue(t *testing.T) { 1625 for _, test := range []struct { 1626 in GenericColumnValue 1627 want interface{} 1628 fail bool 1629 }{ 1630 {GenericColumnValue{stringType(), stringProto("abc")}, "abc", false}, 1631 {GenericColumnValue{stringType(), stringProto("abc")}, 5, true}, 1632 {GenericColumnValue{listType(intType()), listProto(intProto(91), nullProto(), intProto(87))}, []NullInt64{{91, true}, {}, {87, true}}, false}, 1633 {GenericColumnValue{intType(), intProto(42)}, GenericColumnValue{intType(), intProto(42)}, false}, // trippy! :-) 1634 } { 1635 gotp := reflect.New(reflect.TypeOf(test.want)) 1636 if err := test.in.Decode(gotp.Interface()); err != nil { 1637 if !test.fail { 1638 t.Errorf("cannot decode %v to %v: %v", test.in, test.want, err) 1639 } 1640 continue 1641 } 1642 if test.fail { 1643 t.Errorf("decoding %v to %v succeeds unexpectedly", test.in, test.want) 1644 } 1645 1646 // Test we can go backwards as well. 1647 v, err := newGenericColumnValue(test.want) 1648 if err != nil { 1649 t.Errorf("NewGenericColumnValue failed: %v", err) 1650 continue 1651 } 1652 if !testEqual(*v, test.in) { 1653 t.Errorf("unexpected encode result - got %v, want %v", v, test.in) 1654 } 1655 } 1656} 1657 1658func TestDecodeStruct(t *testing.T) { 1659 type CustomString string 1660 type CustomTime time.Time 1661 stype := &sppb.StructType{Fields: []*sppb.StructType_Field{ 1662 {Name: "Id", Type: stringType()}, 1663 {Name: "Time", Type: timeType()}, 1664 }} 1665 lv := listValueProto(stringProto("id"), timeProto(t1)) 1666 1667 type ( 1668 S1 struct { 1669 ID string 1670 Time time.Time 1671 } 1672 S2 struct { 1673 ID string 1674 Time string 1675 } 1676 S3 struct { 1677 ID CustomString 1678 Time CustomTime 1679 } 1680 S4 struct { 1681 ID CustomString 1682 Time CustomString 1683 } 1684 S5 struct { 1685 NullString 1686 Time CustomTime 1687 } 1688 ) 1689 var ( 1690 s1 S1 1691 s2 S2 1692 s3 S3 1693 s4 S4 1694 s5 S5 1695 ) 1696 1697 for _, test := range []struct { 1698 desc string 1699 ptr interface{} 1700 want interface{} 1701 fail bool 1702 }{ 1703 { 1704 desc: "decode to S1", 1705 ptr: &s1, 1706 want: &S1{ID: "id", Time: t1}, 1707 }, 1708 { 1709 desc: "decode to S2", 1710 ptr: &s2, 1711 fail: true, 1712 }, 1713 { 1714 desc: "decode to S3", 1715 ptr: &s3, 1716 want: &S3{ID: CustomString("id"), Time: CustomTime(t1)}, 1717 }, 1718 { 1719 desc: "decode to S4", 1720 ptr: &s4, 1721 fail: true, 1722 }, 1723 { 1724 desc: "decode to S5", 1725 ptr: &s5, 1726 fail: true, 1727 }, 1728 } { 1729 err := decodeStruct(stype, lv, test.ptr) 1730 if (err != nil) != test.fail { 1731 t.Errorf("%s: got error %v, wanted fail: %v", test.desc, err, test.fail) 1732 } 1733 if err == nil { 1734 if !testutil.Equal(test.ptr, test.want, cmp.AllowUnexported(CustomTime{})) { 1735 t.Errorf("%s: got %+v, want %+v", test.desc, test.ptr, test.want) 1736 } 1737 } 1738 } 1739} 1740 1741func TestDecodeStructWithPointers(t *testing.T) { 1742 stype := &sppb.StructType{Fields: []*sppb.StructType_Field{ 1743 {Name: "Str", Type: stringType()}, 1744 {Name: "Int", Type: intType()}, 1745 {Name: "Bool", Type: boolType()}, 1746 {Name: "Float", Type: floatType()}, 1747 {Name: "Time", Type: timeType()}, 1748 {Name: "Date", Type: dateType()}, 1749 {Name: "StrArray", Type: listType(stringType())}, 1750 {Name: "IntArray", Type: listType(intType())}, 1751 {Name: "BoolArray", Type: listType(boolType())}, 1752 {Name: "FloatArray", Type: listType(floatType())}, 1753 {Name: "TimeArray", Type: listType(timeType())}, 1754 {Name: "DateArray", Type: listType(dateType())}, 1755 }} 1756 lv := []*proto3.ListValue{ 1757 listValueProto( 1758 stringProto("id"), 1759 intProto(15), 1760 boolProto(true), 1761 floatProto(3.14), 1762 timeProto(t1), 1763 dateProto(d1), 1764 listProto(stringProto("id1"), nullProto(), stringProto("id2")), 1765 listProto(intProto(16), nullProto(), intProto(17)), 1766 listProto(boolProto(true), nullProto(), boolProto(false)), 1767 listProto(floatProto(3.14), nullProto(), floatProto(6.626)), 1768 listProto(timeProto(t1), nullProto(), timeProto(t2)), 1769 listProto(dateProto(d1), nullProto(), dateProto(d2)), 1770 ), 1771 listValueProto( 1772 nullProto(), 1773 nullProto(), 1774 nullProto(), 1775 nullProto(), 1776 nullProto(), 1777 nullProto(), 1778 nullProto(), 1779 nullProto(), 1780 nullProto(), 1781 nullProto(), 1782 nullProto(), 1783 nullProto(), 1784 ), 1785 } 1786 1787 type S1 struct { 1788 Str *string 1789 Int *int64 1790 Bool *bool 1791 Float *float64 1792 Time *time.Time 1793 Date *civil.Date 1794 StrArray []*string 1795 IntArray []*int64 1796 BoolArray []*bool 1797 FloatArray []*float64 1798 TimeArray []*time.Time 1799 DateArray []*civil.Date 1800 } 1801 var s1 S1 1802 sValue := "id" 1803 iValue := int64(15) 1804 bValue := true 1805 fValue := 3.14 1806 tValue := t1 1807 dValue := d1 1808 sArrayValue1 := "id1" 1809 sArrayValue2 := "id2" 1810 sArrayValue := []*string{&sArrayValue1, nil, &sArrayValue2} 1811 iArrayValue1 := int64(16) 1812 iArrayValue2 := int64(17) 1813 iArrayValue := []*int64{&iArrayValue1, nil, &iArrayValue2} 1814 bArrayValue1 := true 1815 bArrayValue2 := false 1816 bArrayValue := []*bool{&bArrayValue1, nil, &bArrayValue2} 1817 f1Value := 3.14 1818 f2Value := 6.626 1819 fArrayValue := []*float64{&f1Value, nil, &f2Value} 1820 t1Value := t1 1821 t2Value := t2 1822 tArrayValue := []*time.Time{&t1Value, nil, &t2Value} 1823 d1Value := d1 1824 d2Value := d2 1825 dArrayValue := []*civil.Date{&d1Value, nil, &d2Value} 1826 1827 for i, test := range []struct { 1828 desc string 1829 ptr *S1 1830 want *S1 1831 fail bool 1832 }{ 1833 { 1834 desc: "decode values to S1", 1835 ptr: &s1, 1836 want: &S1{Str: &sValue, Int: &iValue, Bool: &bValue, Float: &fValue, Time: &tValue, Date: &dValue, StrArray: sArrayValue, IntArray: iArrayValue, BoolArray: bArrayValue, FloatArray: fArrayValue, TimeArray: tArrayValue, DateArray: dArrayValue}, 1837 }, 1838 { 1839 desc: "decode nulls to S1", 1840 ptr: &s1, 1841 want: &S1{Str: nil, Int: nil, Bool: nil, Float: nil, Time: nil, Date: nil, StrArray: nil, IntArray: nil, BoolArray: nil, FloatArray: nil, TimeArray: nil, DateArray: nil}, 1842 }, 1843 } { 1844 err := decodeStruct(stype, lv[i], test.ptr) 1845 if (err != nil) != test.fail { 1846 t.Errorf("%s: got error %v, wanted fail: %v", test.desc, err, test.fail) 1847 } 1848 if err == nil { 1849 if !testutil.Equal(test.ptr, test.want) { 1850 t.Errorf("%s: got %+v, want %+v", test.desc, test.ptr, test.want) 1851 } 1852 } 1853 } 1854} 1855 1856func TestEncodeStructValueDynamicStructs(t *testing.T) { 1857 dynStructType := reflect.StructOf([]reflect.StructField{ 1858 {Name: "A", Type: reflect.TypeOf(0), Tag: `spanner:"a"`}, 1859 {Name: "B", Type: reflect.TypeOf(""), Tag: `spanner:"b"`}, 1860 }) 1861 dynNullableStructType := reflect.PtrTo(dynStructType) 1862 dynStructArrType := reflect.SliceOf(dynStructType) 1863 dynNullableStructArrType := reflect.SliceOf(dynNullableStructType) 1864 1865 dynStructValue := reflect.New(dynStructType) 1866 dynStructValue.Elem().Field(0).SetInt(10) 1867 dynStructValue.Elem().Field(1).SetString("abc") 1868 1869 dynStructArrValue := reflect.MakeSlice(dynNullableStructArrType, 2, 2) 1870 dynStructArrValue.Index(0).Set(reflect.Zero(dynNullableStructType)) 1871 dynStructArrValue.Index(1).Set(dynStructValue) 1872 1873 structProtoType := structType( 1874 mkField("a", intType()), 1875 mkField("b", stringType())) 1876 1877 arrProtoType := listType(structProtoType) 1878 1879 for _, test := range []encodeTest{ 1880 { 1881 "Dynanic non-NULL struct value.", 1882 dynStructValue.Elem().Interface(), 1883 listProto(intProto(10), stringProto("abc")), 1884 structProtoType, 1885 }, 1886 { 1887 "Dynanic NULL struct value.", 1888 reflect.Zero(dynNullableStructType).Interface(), 1889 nullProto(), 1890 structProtoType, 1891 }, 1892 { 1893 "Empty array of dynamic structs.", 1894 reflect.MakeSlice(dynStructArrType, 0, 0).Interface(), 1895 listProto([]*proto3.Value{}...), 1896 arrProtoType, 1897 }, 1898 { 1899 "NULL array of non-NULL-able dynamic structs.", 1900 reflect.Zero(dynStructArrType).Interface(), 1901 nullProto(), 1902 arrProtoType, 1903 }, 1904 { 1905 "NULL array of NULL-able(nil) dynamic structs.", 1906 reflect.Zero(dynNullableStructArrType).Interface(), 1907 nullProto(), 1908 arrProtoType, 1909 }, 1910 { 1911 "Array containing NULL(nil) dynamic-typed struct elements.", 1912 dynStructArrValue.Interface(), 1913 listProto( 1914 nullProto(), 1915 listProto(intProto(10), stringProto("abc"))), 1916 arrProtoType, 1917 }, 1918 } { 1919 encodeStructValue(test, t) 1920 } 1921} 1922 1923func TestEncodeStructValueEmptyStruct(t *testing.T) { 1924 emptyListValue := listProto([]*proto3.Value{}...) 1925 emptyStructType := structType([]*sppb.StructType_Field{}...) 1926 emptyStruct := struct{}{} 1927 nullEmptyStruct := (*struct{})(nil) 1928 1929 dynamicEmptyStructType := reflect.StructOf(make([]reflect.StructField, 0, 0)) 1930 dynamicStructArrType := reflect.SliceOf(reflect.PtrTo((dynamicEmptyStructType))) 1931 1932 dynamicEmptyStruct := reflect.New(dynamicEmptyStructType) 1933 dynamicNullEmptyStruct := reflect.Zero(reflect.PtrTo(dynamicEmptyStructType)) 1934 1935 dynamicStructArrValue := reflect.MakeSlice(dynamicStructArrType, 2, 2) 1936 dynamicStructArrValue.Index(0).Set(dynamicNullEmptyStruct) 1937 dynamicStructArrValue.Index(1).Set(dynamicEmptyStruct) 1938 1939 for _, test := range []encodeTest{ 1940 { 1941 "Go empty struct.", 1942 emptyStruct, 1943 emptyListValue, 1944 emptyStructType, 1945 }, 1946 { 1947 "Dynamic empty struct.", 1948 dynamicEmptyStruct.Interface(), 1949 emptyListValue, 1950 emptyStructType, 1951 }, 1952 { 1953 "Go NULL empty struct.", 1954 nullEmptyStruct, 1955 nullProto(), 1956 emptyStructType, 1957 }, 1958 { 1959 "Dynamic NULL empty struct.", 1960 dynamicNullEmptyStruct.Interface(), 1961 nullProto(), 1962 emptyStructType, 1963 }, 1964 { 1965 "Non-empty array of dynamic NULL and non-NULL empty structs.", 1966 dynamicStructArrValue.Interface(), 1967 listProto(nullProto(), emptyListValue), 1968 listType(emptyStructType), 1969 }, 1970 { 1971 "Non-empty array of nullable empty structs.", 1972 []*struct{}{nullEmptyStruct, &emptyStruct}, 1973 listProto(nullProto(), emptyListValue), 1974 listType(emptyStructType), 1975 }, 1976 { 1977 "Empty array of empty struct.", 1978 []struct{}{}, 1979 emptyListValue, 1980 listType(emptyStructType), 1981 }, 1982 { 1983 "Null array of empty structs.", 1984 []struct{}(nil), 1985 nullProto(), 1986 listType(emptyStructType), 1987 }, 1988 } { 1989 encodeStructValue(test, t) 1990 } 1991} 1992 1993func TestEncodeStructValueMixedStructTypes(t *testing.T) { 1994 type staticStruct struct { 1995 F int `spanner:"fStatic"` 1996 } 1997 s1 := staticStruct{10} 1998 s2 := (*staticStruct)(nil) 1999 2000 var f float64 2001 dynStructType := reflect.StructOf([]reflect.StructField{ 2002 {Name: "A", Type: reflect.TypeOf(f), Tag: `spanner:"fDynamic"`}, 2003 }) 2004 s3 := reflect.New(dynStructType) 2005 s3.Elem().Field(0).SetFloat(3.14) 2006 2007 for _, test := range []encodeTest{ 2008 { 2009 "'struct' with static and dynamic *struct, []*struct, []struct fields", 2010 struct { 2011 A []staticStruct 2012 B []*staticStruct 2013 C interface{} 2014 }{ 2015 []staticStruct{s1, s1}, 2016 []*staticStruct{&s1, s2}, 2017 s3.Interface(), 2018 }, 2019 listProto( 2020 listProto(listProto(intProto(10)), listProto(intProto(10))), 2021 listProto(listProto(intProto(10)), nullProto()), 2022 listProto(floatProto(3.14))), 2023 structType( 2024 mkField("A", listType(structType(mkField("fStatic", intType())))), 2025 mkField("B", listType(structType(mkField("fStatic", intType())))), 2026 mkField("C", structType(mkField("fDynamic", floatType())))), 2027 }, 2028 } { 2029 encodeStructValue(test, t) 2030 } 2031} 2032 2033func TestBindParamsDynamic(t *testing.T) { 2034 // Verify Statement.bindParams generates correct values and types. 2035 st := Statement{ 2036 SQL: "SELECT id from t_foo WHERE col = @var", 2037 Params: map[string]interface{}{"var": nil}, 2038 } 2039 want := &sppb.ExecuteSqlRequest{ 2040 Params: &proto3.Struct{ 2041 Fields: map[string]*proto3.Value{"var": nil}, 2042 }, 2043 ParamTypes: map[string]*sppb.Type{"var": nil}, 2044 } 2045 var ( 2046 t1, _ = time.Parse(time.RFC3339Nano, "2016-11-15T15:04:05.999999999Z") 2047 // Boundaries 2048 t2, _ = time.Parse(time.RFC3339Nano, "0001-01-01T00:00:00.000000000Z") 2049 ) 2050 dynamicStructType := reflect.StructOf([]reflect.StructField{ 2051 {Name: "A", Type: reflect.TypeOf(t1), Tag: `spanner:"field"`}, 2052 {Name: "B", Type: reflect.TypeOf(3.14), Tag: `spanner:""`}, 2053 }) 2054 dynamicStructArrType := reflect.SliceOf(reflect.PtrTo(dynamicStructType)) 2055 dynamicEmptyStructType := reflect.StructOf(make([]reflect.StructField, 0, 0)) 2056 2057 dynamicStructTypeProto := structType( 2058 mkField("field", timeType()), 2059 mkField("", floatType())) 2060 2061 s3 := reflect.New(dynamicStructType) 2062 s3.Elem().Field(0).Set(reflect.ValueOf(t1)) 2063 s3.Elem().Field(1).SetFloat(1.4) 2064 2065 s4 := reflect.New(dynamicStructType) 2066 s4.Elem().Field(0).Set(reflect.ValueOf(t2)) 2067 s4.Elem().Field(1).SetFloat(-13.3) 2068 2069 dynamicStructArrayVal := reflect.MakeSlice(dynamicStructArrType, 2, 2) 2070 dynamicStructArrayVal.Index(0).Set(s3) 2071 dynamicStructArrayVal.Index(1).Set(s4) 2072 2073 for _, test := range []struct { 2074 val interface{} 2075 wantField *proto3.Value 2076 wantType *sppb.Type 2077 }{ 2078 { 2079 s3.Interface(), 2080 listProto(timeProto(t1), floatProto(1.4)), 2081 structType( 2082 mkField("field", timeType()), 2083 mkField("", floatType())), 2084 }, 2085 { 2086 reflect.Zero(reflect.PtrTo(dynamicEmptyStructType)).Interface(), 2087 nullProto(), 2088 structType([]*sppb.StructType_Field{}...), 2089 }, 2090 { 2091 dynamicStructArrayVal.Interface(), 2092 listProto( 2093 listProto(timeProto(t1), floatProto(1.4)), 2094 listProto(timeProto(t2), floatProto(-13.3))), 2095 listType(dynamicStructTypeProto), 2096 }, 2097 { 2098 []*struct { 2099 F1 time.Time `spanner:"field"` 2100 F2 float64 `spanner:""` 2101 }{ 2102 nil, 2103 {t1, 1.4}, 2104 }, 2105 listProto( 2106 nullProto(), 2107 listProto(timeProto(t1), floatProto(1.4))), 2108 listType(dynamicStructTypeProto), 2109 }, 2110 } { 2111 st.Params["var"] = test.val 2112 want.Params.Fields["var"] = test.wantField 2113 want.ParamTypes["var"] = test.wantType 2114 gotParams, gotParamTypes, gotErr := st.convertParams() 2115 if gotErr != nil { 2116 t.Error(gotErr) 2117 continue 2118 } 2119 gotParamField := gotParams.Fields["var"] 2120 if !proto.Equal(gotParamField, test.wantField) { 2121 // handle NaN 2122 if test.wantType.Code == floatType().Code && proto.MarshalTextString(gotParamField) == proto.MarshalTextString(test.wantField) { 2123 continue 2124 } 2125 t.Errorf("%#v: got %v, want %v\n", test.val, gotParamField, test.wantField) 2126 } 2127 gotParamType := gotParamTypes["var"] 2128 if !proto.Equal(gotParamType, test.wantType) { 2129 t.Errorf("%#v: got %v, want %v\n", test.val, gotParamType, test.wantField) 2130 } 2131 } 2132} 2133 2134// Test converting nullable types to json strings. 2135func TestJSONMarshal_NullTypes(t *testing.T) { 2136 type testcase struct { 2137 input interface{} 2138 expect string 2139 } 2140 2141 for _, test := range []struct { 2142 name string 2143 cases []testcase 2144 }{ 2145 { 2146 "NullString", 2147 []testcase{ 2148 {input: NullString{"this is a test string", true}, expect: `"this is a test string"`}, 2149 {input: &NullString{"this is a test string", true}, expect: `"this is a test string"`}, 2150 {input: &NullString{"this is a test string", false}, expect: "null"}, 2151 {input: NullString{}, expect: "null"}, 2152 }, 2153 }, 2154 { 2155 "NullInt64", 2156 []testcase{ 2157 {input: NullInt64{int64(123), true}, expect: "123"}, 2158 {input: &NullInt64{int64(123), true}, expect: "123"}, 2159 {input: &NullInt64{int64(123), false}, expect: "null"}, 2160 {input: NullInt64{}, expect: "null"}, 2161 }, 2162 }, 2163 { 2164 "NullFloat64", 2165 []testcase{ 2166 {input: NullFloat64{float64(123.123), true}, expect: "123.123"}, 2167 {input: &NullFloat64{float64(123.123), true}, expect: "123.123"}, 2168 {input: &NullFloat64{float64(123.123), false}, expect: "null"}, 2169 {input: NullFloat64{}, expect: "null"}, 2170 }, 2171 }, 2172 { 2173 "NullBool", 2174 []testcase{ 2175 {input: NullBool{true, true}, expect: "true"}, 2176 {input: &NullBool{true, true}, expect: "true"}, 2177 {input: &NullBool{true, false}, expect: "null"}, 2178 {input: NullBool{}, expect: "null"}, 2179 }, 2180 }, 2181 { 2182 "NullTime", 2183 []testcase{ 2184 {input: NullTime{time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC), true}, expect: `"2009-11-17T20:34:58.651387237Z"`}, 2185 {input: &NullTime{time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC), true}, expect: `"2009-11-17T20:34:58.651387237Z"`}, 2186 {input: &NullTime{time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC), false}, expect: "null"}, 2187 {input: NullTime{}, expect: "null"}, 2188 }, 2189 }, 2190 { 2191 "NullDate", 2192 []testcase{ 2193 {input: NullDate{civil.Date{Year: 2009, Month: time.November, Day: 17}, true}, expect: `"2009-11-17"`}, 2194 {input: &NullDate{civil.Date{Year: 2009, Month: time.November, Day: 17}, true}, expect: `"2009-11-17"`}, 2195 {input: &NullDate{civil.Date{Year: 2009, Month: time.November, Day: 17}, false}, expect: "null"}, 2196 {input: NullDate{}, expect: "null"}, 2197 }, 2198 }, 2199 } { 2200 t.Run(test.name, func(t *testing.T) { 2201 for _, tc := range test.cases { 2202 bytes, _ := json.Marshal(tc.input) 2203 got := string(bytes) 2204 if got != tc.expect { 2205 t.Fatalf("Incorrect marshalling to json strings: got %v, want %v", got, tc.expect) 2206 } 2207 } 2208 }) 2209 } 2210} 2211 2212// Test converting json strings to nullable types. 2213func TestJSONUnmarshal_NullTypes(t *testing.T) { 2214 type testcase struct { 2215 input []byte 2216 got interface{} 2217 isNull bool 2218 expect string 2219 expectError bool 2220 } 2221 2222 for _, test := range []struct { 2223 name string 2224 cases []testcase 2225 }{ 2226 { 2227 "NullString", 2228 []testcase{ 2229 {input: []byte(`"this is a test string"`), got: NullString{}, isNull: false, expect: "this is a test string", expectError: false}, 2230 {input: []byte(`""`), got: NullString{}, isNull: false, expect: "", expectError: false}, 2231 {input: []byte("null"), got: NullString{}, isNull: true, expect: nullString, expectError: false}, 2232 {input: nil, got: NullString{}, isNull: true, expect: nullString, expectError: true}, 2233 {input: []byte(""), got: NullString{}, isNull: true, expect: nullString, expectError: true}, 2234 {input: []byte(`"hello`), got: NullString{}, isNull: true, expect: nullString, expectError: true}, 2235 }, 2236 }, 2237 { 2238 "NullInt64", 2239 []testcase{ 2240 {input: []byte("123"), got: NullInt64{}, isNull: false, expect: "123", expectError: false}, 2241 {input: []byte("null"), got: NullInt64{}, isNull: true, expect: nullString, expectError: false}, 2242 {input: nil, got: NullInt64{}, isNull: true, expect: nullString, expectError: true}, 2243 {input: []byte(""), got: NullInt64{}, isNull: true, expect: nullString, expectError: true}, 2244 {input: []byte(`"hello`), got: NullInt64{}, isNull: true, expect: nullString, expectError: true}, 2245 }, 2246 }, 2247 { 2248 "NullFloat64", 2249 []testcase{ 2250 {input: []byte("123.123"), got: NullFloat64{}, isNull: false, expect: "123.123", expectError: false}, 2251 {input: []byte("null"), got: NullFloat64{}, isNull: true, expect: nullString, expectError: false}, 2252 {input: nil, got: NullFloat64{}, isNull: true, expect: nullString, expectError: true}, 2253 {input: []byte(""), got: NullFloat64{}, isNull: true, expect: nullString, expectError: true}, 2254 {input: []byte(`"hello`), got: NullFloat64{}, isNull: true, expect: nullString, expectError: true}, 2255 }, 2256 }, 2257 { 2258 "NullBool", 2259 []testcase{ 2260 {input: []byte("true"), got: NullBool{}, isNull: false, expect: "true", expectError: false}, 2261 {input: []byte("null"), got: NullBool{}, isNull: true, expect: nullString, expectError: false}, 2262 {input: nil, got: NullBool{}, isNull: true, expect: nullString, expectError: true}, 2263 {input: []byte(""), got: NullBool{}, isNull: true, expect: nullString, expectError: true}, 2264 {input: []byte(`"hello`), got: NullBool{}, isNull: true, expect: nullString, expectError: true}, 2265 }, 2266 }, 2267 { 2268 "NullTime", 2269 []testcase{ 2270 {input: []byte(`"2009-11-17T20:34:58.651387237Z"`), got: NullTime{}, isNull: false, expect: "2009-11-17T20:34:58.651387237Z", expectError: false}, 2271 {input: []byte("null"), got: NullTime{}, isNull: true, expect: nullString, expectError: false}, 2272 {input: nil, got: NullTime{}, isNull: true, expect: nullString, expectError: true}, 2273 {input: []byte(""), got: NullTime{}, isNull: true, expect: nullString, expectError: true}, 2274 {input: []byte(`"hello`), got: NullTime{}, isNull: true, expect: nullString, expectError: true}, 2275 }, 2276 }, 2277 { 2278 "NullDate", 2279 []testcase{ 2280 {input: []byte(`"2009-11-17"`), got: NullDate{}, isNull: false, expect: "2009-11-17", expectError: false}, 2281 {input: []byte("null"), got: NullDate{}, isNull: true, expect: nullString, expectError: false}, 2282 {input: nil, got: NullDate{}, isNull: true, expect: nullString, expectError: true}, 2283 {input: []byte(""), got: NullDate{}, isNull: true, expect: nullString, expectError: true}, 2284 {input: []byte(`"hello`), got: NullDate{}, isNull: true, expect: nullString, expectError: true}, 2285 }, 2286 }, 2287 } { 2288 t.Run(test.name, func(t *testing.T) { 2289 for _, tc := range test.cases { 2290 switch v := tc.got.(type) { 2291 case NullString: 2292 err := json.Unmarshal(tc.input, &v) 2293 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2294 case NullInt64: 2295 err := json.Unmarshal(tc.input, &v) 2296 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2297 case NullFloat64: 2298 err := json.Unmarshal(tc.input, &v) 2299 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2300 case NullBool: 2301 err := json.Unmarshal(tc.input, &v) 2302 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2303 case NullTime: 2304 err := json.Unmarshal(tc.input, &v) 2305 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2306 case NullDate: 2307 err := json.Unmarshal(tc.input, &v) 2308 expectUnmarshalNullableTypes(t, err, v, tc.isNull, tc.expect, tc.expectError) 2309 default: 2310 t.Fatalf("Unknown type: %T", v) 2311 } 2312 } 2313 }) 2314 } 2315} 2316 2317func expectUnmarshalNullableTypes(t *testing.T, err error, v interface{}, isNull bool, expect string, expectError bool) { 2318 if expectError { 2319 if err == nil { 2320 t.Fatalf("Expect to get an error, but got a nil") 2321 } 2322 return 2323 } 2324 2325 if err != nil { 2326 t.Fatalf("Got an error when unmarshalling a valid json string: %q", err) 2327 } 2328 if s, ok := v.(NullableValue); !ok || s.IsNull() != isNull { 2329 t.Fatalf("Incorrect unmarshalling a json string to nullable types: got %q, want %q", v, expect) 2330 } 2331 if s, ok := v.(fmt.Stringer); !ok || s.String() != expect { 2332 t.Fatalf("Incorrect unmarshalling a json string to nullable types: got %q, want %q", v, expect) 2333 } 2334} 2335