github.com/dgraph-io/dgraph@v1.2.8/types/conversion_test.go (about) 1 /* 2 * Copyright 2016-2018 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package types 18 19 import ( 20 "encoding/binary" 21 "math" 22 "testing" 23 "time" 24 25 "github.com/stretchr/testify/require" 26 ) 27 28 func bs(v interface{}) []byte { 29 switch x := v.(type) { 30 case bool: 31 if x { 32 return []byte{1} 33 } 34 return []byte{0} 35 case int64: 36 var bs [8]byte 37 binary.LittleEndian.PutUint64(bs[:], uint64(x)) 38 return bs[:] 39 case float64: 40 var bs [8]byte 41 binary.LittleEndian.PutUint64(bs[:], math.Float64bits(x)) 42 return bs[:] 43 case time.Time: 44 bs, err := x.MarshalBinary() 45 if err == nil { 46 return bs 47 } 48 } 49 return nil 50 } 51 52 func TestSameConversionString(t *testing.T) { 53 tests := []struct { 54 in string 55 }{ 56 {in: "a"}, 57 {in: ""}, 58 } 59 60 for _, tc := range tests { 61 out, err := Convert(Val{Tid: BinaryID, Value: []byte(tc.in)}, StringID) 62 require.NoError(t, err) 63 require.EqualValues(t, Val{Tid: StringID, Value: tc.in}, out) 64 } 65 } 66 67 func TestSameConversionDateTime(t *testing.T) { 68 tests := []struct { 69 in time.Time 70 }{ 71 {in: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC)}, 72 {in: time.Time{}}, 73 } 74 75 for _, tc := range tests { 76 out, err := Convert(Val{Tid: BinaryID, Value: bs(tc.in)}, DateTimeID) 77 require.NoError(t, err) 78 require.EqualValues(t, Val{Tid: DateTimeID, Value: tc.in}, out) 79 } 80 } 81 82 func TestConversionEdgeCases(t *testing.T) { 83 tests := []struct { 84 in, out Val 85 failure string 86 }{ 87 {in: Val{Tid: BinaryID}, 88 out: Val{Tid: BinaryID}, 89 failure: "Invalid data to convert to binary"}, 90 91 // From BinaryID to X 92 {in: Val{Tid: BinaryID, Value: []byte{}}, 93 out: Val{Tid: IntID, Value: int64(0)}, 94 failure: "Invalid data for int64"}, 95 {in: Val{Tid: BinaryID, Value: []byte{}}, 96 out: Val{Tid: FloatID, Value: int64(0)}, 97 failure: "Invalid data for float"}, 98 {in: Val{Tid: BinaryID, Value: []byte{}}, 99 out: Val{Tid: BoolID, Value: false}}, 100 {in: Val{Tid: BinaryID, Value: []byte{2}}, 101 out: Val{Tid: BoolID, Value: false}, 102 failure: "Invalid value for bool"}, 103 {in: Val{Tid: BinaryID, Value: []byte{8}}, 104 out: Val{Tid: DateTimeID, Value: time.Time{}}, 105 failure: "Time.UnmarshalBinary:"}, 106 {in: Val{Tid: BinaryID, Value: []byte{}}, 107 out: Val{Tid: DateTimeID, Value: time.Time{}}, 108 failure: "Time.UnmarshalBinary:"}, 109 110 // From StringID|DefaultID to X 111 {in: Val{Tid: StringID, Value: []byte{}}, 112 out: Val{Tid: IntID, Value: int64(0)}, 113 failure: "strconv.ParseInt"}, 114 {in: Val{Tid: StringID, Value: []byte{}}, 115 out: Val{Tid: FloatID, Value: float64(0)}, 116 failure: "strconv.ParseFloat"}, 117 {in: Val{Tid: StringID, Value: []byte{}}, 118 out: Val{Tid: BoolID, Value: false}, 119 failure: "strconv.ParseBool"}, 120 {in: Val{Tid: StringID, Value: []byte{}}, 121 out: Val{Tid: DateTimeID, Value: time.Time{}}, 122 failure: `parsing time "" as "2006": cannot parse "" as "2006"`}, 123 124 // From IntID to X 125 {in: Val{Tid: IntID, Value: []byte{}}, 126 failure: "Invalid data for int64"}, 127 {in: Val{Tid: IntID, Value: bs(int64(0))}, 128 out: Val{Tid: DateTimeID, Value: time.Unix(0, 0).UTC()}}, 129 130 // From FloatID to X 131 {in: Val{Tid: FloatID, Value: []byte{}}, 132 failure: "Invalid data for float"}, 133 {in: Val{Tid: FloatID, Value: bs(float64(0))}, 134 out: Val{Tid: DateTimeID, Value: time.Unix(0, 0).UTC()}}, 135 136 // From BoolID to X 137 {in: Val{Tid: BoolID, Value: []byte{}}, 138 failure: "Invalid value for bool"}, 139 {in: Val{Tid: BoolID, Value: []byte{8}}, 140 failure: "Invalid value for bool"}, 141 142 // From DateTimeID to X 143 {in: Val{Tid: DateTimeID, Value: []byte{}}, 144 out: Val{Tid: DateTimeID, Value: time.Time{}}, 145 failure: "Time.UnmarshalBinary:"}, 146 {in: Val{Tid: DateTimeID, Value: bs(time.Time{})}, 147 out: Val{Tid: DateTimeID, Value: time.Time{}}}, 148 {in: Val{Tid: DateTimeID, Value: []byte{}}, 149 out: Val{Tid: BinaryID, Value: []byte{}}, 150 failure: "Time.UnmarshalBinary"}, 151 {in: Val{Tid: DateTimeID, Value: bs(time.Time{})}, 152 out: Val{Tid: BinaryID, Value: bs(time.Time{})}}, 153 {in: Val{Tid: DateTimeID, Value: []byte{}}, 154 out: Val{Tid: StringID, Value: ""}, 155 failure: "Time.UnmarshalBinary: no data"}, 156 {in: Val{Tid: DateTimeID, Value: bs(time.Time{})}, 157 out: Val{Tid: StringID, Value: "0001-01-01T00:00:00Z"}}, 158 {in: Val{Tid: DateTimeID, Value: []byte{}}, 159 out: Val{Tid: DefaultID, Value: ""}, 160 failure: "Time.UnmarshalBinary: no data"}, 161 {in: Val{Tid: DateTimeID, Value: bs(time.Time{})}, 162 out: Val{Tid: DefaultID, Value: "0001-01-01T00:00:00Z"}}, 163 {in: Val{Tid: DateTimeID, Value: []byte{}}, 164 out: Val{Tid: IntID, Value: int64(0)}, 165 failure: "Time.UnmarshalBinary: no data"}, 166 {in: Val{Tid: DateTimeID, Value: bs(time.Time{})}, 167 out: Val{Tid: IntID, Value: time.Time{}.Unix()}}, 168 {in: Val{Tid: DateTimeID, Value: []byte{}}, 169 out: Val{Tid: FloatID, Value: float64(0)}, 170 failure: "Time.UnmarshalBinary: no data"}, 171 {in: Val{Tid: DateTimeID, Value: bs(time.Time{})}, 172 out: Val{Tid: FloatID, 173 Value: float64(time.Time{}.UnixNano()) / float64(nanoSecondsInSec)}}, 174 } 175 for _, tc := range tests { 176 t.Logf("%s to %s != %v", tc.in.Tid.Name(), tc.out.Tid.Name(), tc.out.Value) 177 out, err := Convert(tc.in, tc.out.Tid) 178 if tc.failure != "" { 179 require.Error(t, err) 180 require.Contains(t, err.Error(), tc.failure) 181 } else { 182 require.NoError(t, err) 183 require.EqualValues(t, tc.out, out) 184 } 185 } 186 } 187 188 func TestConvertToDefault(t *testing.T) { 189 tests := []struct { 190 in Val 191 out string 192 }{ 193 {in: Val{StringID, []byte("a")}, out: "a"}, 194 {in: Val{StringID, []byte("")}, out: ""}, 195 {in: Val{DefaultID, []byte("abc")}, out: "abc"}, 196 {in: Val{BinaryID, []byte("2016")}, out: "2016"}, 197 {in: Val{IntID, bs(int64(3))}, out: "3"}, 198 {in: Val{FloatID, bs(float64(-3.5))}, out: "-3.5"}, 199 {in: Val{DateTimeID, bs(time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))}, out: "2006-01-02T15:04:05Z"}, 200 {in: Val{DateTimeID, bs(time.Time{})}, out: "0001-01-01T00:00:00Z"}, 201 } 202 203 for _, tc := range tests { 204 out, err := Convert(tc.in, DefaultID) 205 require.NoError(t, err) 206 require.EqualValues(t, Val{Tid: DefaultID, Value: tc.out}, out) 207 } 208 } 209 210 func TestConvertFromDefault(t *testing.T) { 211 tests := []struct { 212 in string 213 out Val 214 }{ 215 {in: "1", out: Val{IntID, int64(1)}}, 216 {in: "1.3", out: Val{FloatID, float64(1.3)}}, 217 {in: "true", out: Val{BoolID, true}}, 218 {in: "2016", out: Val{BinaryID, []byte("2016")}}, 219 {in: "", out: Val{BinaryID, []byte("")}}, 220 {in: "hello", out: Val{StringID, "hello"}}, 221 {in: "", out: Val{StringID, ""}}, 222 {in: "2016", out: Val{DateTimeID, time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)}}, 223 } 224 225 for _, tc := range tests { 226 out, err := Convert(Val{DefaultID, []byte(tc.in)}, tc.out.Tid) 227 require.NoError(t, err) 228 require.EqualValues(t, tc.out, out) 229 } 230 } 231 232 func TestConvertToBinary(t *testing.T) { 233 tests := []struct { 234 in Val 235 out []byte 236 }{ 237 {in: Val{StringID, []byte("a")}, out: []byte("a")}, 238 {in: Val{StringID, []byte("")}, out: []byte("")}, 239 {in: Val{DefaultID, []byte("abc")}, out: []byte("abc")}, 240 {in: Val{BinaryID, []byte("2016")}, out: []byte("2016")}, 241 {in: Val{IntID, bs(int64(3))}, out: bs(int64(3))}, 242 {in: Val{FloatID, bs(float64(-3.5))}, out: bs(float64(-3.5))}, 243 {in: Val{DateTimeID, bs(time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))}, out: bs(time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))}, 244 } 245 246 for _, tc := range tests { 247 out, err := Convert(tc.in, BinaryID) 248 require.NoError(t, err) 249 require.EqualValues(t, Val{Tid: BinaryID, Value: tc.out}, out) 250 } 251 } 252 253 func TestConvertFromBinary(t *testing.T) { 254 tests := []struct { 255 in []byte 256 out Val 257 }{ 258 {in: bs(true), out: Val{BoolID, true}}, 259 {in: bs(false), out: Val{BoolID, false}}, 260 {in: []byte(""), out: Val{BoolID, false}}, 261 {in: nil, out: Val{BoolID, false}}, 262 {in: bs(int64(1)), out: Val{IntID, int64(1)}}, 263 {in: bs(float64(1.3)), out: Val{FloatID, float64(1.3)}}, 264 {in: []byte("2016"), out: Val{BinaryID, []byte("2016")}}, 265 {in: []byte(""), out: Val{BinaryID, []byte("")}}, 266 {in: []byte("hello"), out: Val{StringID, "hello"}}, 267 {in: []byte(""), out: Val{StringID, ""}}, 268 {in: bs(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)), out: Val{DateTimeID, time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)}}, 269 {in: bs(time.Time{}), out: Val{DateTimeID, time.Time{}}}, 270 } 271 272 for _, tc := range tests { 273 out, err := Convert(Val{BinaryID, tc.in}, tc.out.Tid) 274 require.NoError(t, err) 275 require.EqualValues(t, tc.out, out) 276 } 277 } 278 279 func TestConvertStringToDateTime(t *testing.T) { 280 tests := []struct { 281 in string 282 out time.Time 283 }{ 284 {in: "2006-01-02T15:04:05", out: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC)}, 285 {in: "2006-01-02", out: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC)}, 286 {in: "2006-01", out: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC)}, 287 {in: "2006", out: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC)}, 288 } 289 290 for _, tc := range tests { 291 out, err := Convert(Val{Tid: StringID, Value: []byte(tc.in)}, DateTimeID) 292 require.NoError(t, err) 293 require.EqualValues(t, Val{Tid: DateTimeID, Value: tc.out}, out) 294 } 295 } 296 297 func TestConvertDateTimeToString(t *testing.T) { 298 tests := []struct { 299 in time.Time 300 out string 301 }{ 302 {in: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), out: "2006-01-02T15:04:05Z"}, 303 {in: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC), out: "2006-01-02T00:00:00Z"}, 304 {in: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC), out: "2006-01-01T00:00:00Z"}, 305 } 306 307 for _, tc := range tests { 308 out, err := Convert(Val{Tid: DateTimeID, Value: bs(tc.in)}, StringID) 309 require.NoError(t, err) 310 require.EqualValues(t, Val{Tid: StringID, Value: tc.out}, out) 311 } 312 } 313 314 func TestConvertFromPassword(t *testing.T) { 315 tests := []struct { 316 in string 317 out Val 318 failure string 319 }{ 320 {in: "", out: Val{StringID, ""}}, 321 {in: "password", out: Val{PasswordID, "password"}}, 322 {in: "password", out: Val{StringID, "password"}}, 323 {in: "password", out: Val{BinaryID, []byte("password")}}, 324 { 325 in: "password", 326 failure: `Cannot convert password to type default`, 327 }, 328 { 329 in: "password", out: Val{IntID, bs(int64(1))}, 330 failure: `Cannot convert password to type int`, 331 }, 332 { 333 in: "password", out: Val{FloatID, bs(float64(1.0))}, 334 failure: `Cannot convert password to type float`, 335 }, 336 { 337 in: "password", out: Val{BoolID, bs(true)}, 338 failure: `Cannot convert password to type bool`, 339 }, 340 } 341 342 for _, tc := range tests { 343 out, err := Convert(Val{Tid: PasswordID, Value: []byte(tc.in)}, tc.out.Tid) 344 if tc.failure != "" { 345 require.Error(t, err) 346 require.EqualError(t, err, tc.failure) 347 continue 348 } 349 require.NoError(t, err) 350 require.EqualValues(t, tc.out, out) 351 } 352 } 353 354 func TestConvertToPassword(t *testing.T) { 355 tests := []struct { 356 in Val 357 out string 358 failure string 359 }{ 360 {in: Val{StringID, []byte("testing")}, out: "$2a$10$"}, 361 {in: Val{PasswordID, []byte("testing")}, out: "testing"}, 362 {in: Val{DefaultID, []byte("testing")}, out: "$2a$10$"}, 363 { 364 in: Val{StringID, []byte("")}, 365 failure: `Password too short, i.e. should have at least 6 chars`, 366 }, 367 { 368 in: Val{IntID, bs(int64(1))}, 369 failure: `Cannot convert int to type password`, 370 }, 371 { 372 in: Val{FloatID, bs(float64(1.0))}, 373 failure: `Cannot convert float to type password`, 374 }, 375 { 376 in: Val{BoolID, bs(true)}, 377 failure: `Cannot convert bool to type password`, 378 }, 379 } 380 381 for _, tc := range tests { 382 out, err := Convert(tc.in, PasswordID) 383 if tc.failure != "" { 384 require.Error(t, err) 385 require.EqualError(t, err, tc.failure) 386 continue 387 } 388 require.NoError(t, err) 389 if tc.in.Tid == PasswordID { 390 require.EqualValues(t, Val{Tid: PasswordID, Value: tc.out}, out) 391 continue 392 } 393 require.True(t, out.Tid == PasswordID) 394 require.NoError(t, VerifyPassword(string(tc.in.Value.([]byte)), out.Value.(string))) 395 } 396 } 397 398 func TestSameConversionBool(t *testing.T) { 399 tests := []struct { 400 in bool 401 }{ 402 {in: true}, 403 {in: false}, 404 } 405 406 for _, tc := range tests { 407 out, err := Convert(Val{Tid: BinaryID, Value: bs(tc.in)}, BoolID) 408 require.NoError(t, err) 409 require.EqualValues(t, Val{Tid: BoolID, Value: tc.in}, out) 410 } 411 } 412 413 func TestConvertIntToBool(t *testing.T) { 414 tests := []struct { 415 in int64 416 out bool 417 }{ 418 {in: int64(3), out: true}, 419 {in: int64(-3), out: true}, 420 {in: int64(0), out: false}, 421 } 422 423 for _, tc := range tests { 424 out, err := Convert(Val{Tid: IntID, Value: bs(tc.in)}, BoolID) 425 require.NoError(t, err) 426 require.EqualValues(t, Val{Tid: BoolID, Value: tc.out}, out) 427 } 428 } 429 430 func TestConvertFloatToBool(t *testing.T) { 431 tests := []struct { 432 in float64 433 out bool 434 }{ 435 {in: float64(3.0), out: true}, 436 {in: float64(-3.5), out: true}, 437 {in: float64(0), out: false}, 438 {in: math.NaN(), out: true}, 439 {in: math.Inf(0), out: true}, 440 {in: math.Inf(-1), out: true}, 441 } 442 443 for _, tc := range tests { 444 out, err := Convert(Val{Tid: FloatID, Value: bs(tc.in)}, BoolID) 445 require.NoError(t, err) 446 require.EqualValues(t, Val{Tid: BoolID, Value: tc.out}, out) 447 } 448 } 449 450 func TestConvertStringToBool(t *testing.T) { 451 tests := []struct { 452 in string 453 out bool 454 failure string 455 }{ 456 {in: "1", out: true}, 457 {in: "true", out: true}, 458 {in: "True", out: true}, 459 {in: "T", out: true}, 460 {in: "F", out: false}, 461 {in: "0", out: false}, 462 {in: "false", out: false}, 463 {in: "False", out: false}, 464 { 465 in: "", 466 failure: `strconv.ParseBool: parsing "": invalid syntax`, 467 }, 468 { 469 in: "srfrog", 470 failure: `strconv.ParseBool: parsing "srfrog": invalid syntax`, 471 }, 472 { 473 in: "3", 474 failure: `strconv.ParseBool: parsing "3": invalid syntax`, 475 }, 476 { 477 in: "-3", 478 failure: `strconv.ParseBool: parsing "-3": invalid syntax`, 479 }, 480 } 481 482 for _, tc := range tests { 483 out, err := Convert(Val{Tid: StringID, Value: []byte(tc.in)}, BoolID) 484 if tc.failure != "" { 485 require.Error(t, err) 486 require.EqualError(t, err, tc.failure) 487 continue 488 } 489 require.NoError(t, err) 490 require.EqualValues(t, Val{Tid: BoolID, Value: tc.out}, out) 491 } 492 } 493 494 func TestConvertDateTimeToBool(t *testing.T) { 495 _, err := Convert(Val{Tid: DateTimeID, Value: bs(time.Now())}, BoolID) 496 require.Error(t, err) 497 require.EqualError(t, err, "Cannot convert datetime to type bool") 498 } 499 500 func TestConvertBoolToDateTime(t *testing.T) { 501 _, err := Convert(Val{Tid: BoolID, Value: bs(true)}, DateTimeID) 502 require.Error(t, err) 503 require.EqualError(t, err, "Cannot convert bool to type datetime") 504 } 505 506 func TestConvertBoolToInt(t *testing.T) { 507 tests := []struct { 508 in bool 509 out int64 510 }{ 511 {in: true, out: int64(1)}, 512 {in: false, out: int64(0)}, 513 } 514 515 for _, tc := range tests { 516 out, err := Convert(Val{Tid: BoolID, Value: bs(tc.in)}, IntID) 517 require.NoError(t, err) 518 require.EqualValues(t, Val{Tid: IntID, Value: tc.out}, out) 519 } 520 } 521 522 func TestTruthy(t *testing.T) { 523 tests := []struct { 524 in Val 525 }{ 526 {in: Val{Tid: StringID, Value: []byte("true")}}, 527 {in: Val{Tid: DefaultID, Value: []byte("true")}}, 528 {in: Val{Tid: IntID, Value: bs(int64(1))}}, 529 {in: Val{Tid: IntID, Value: bs(int64(-1))}}, 530 {in: Val{Tid: FloatID, Value: bs(float64(1.0))}}, 531 {in: Val{Tid: FloatID, Value: bs(float64(-1.0))}}, 532 } 533 for _, tc := range tests { 534 out, err := Convert(tc.in, BoolID) 535 require.NoError(t, err) 536 require.EqualValues(t, true, out.Value) 537 } 538 } 539 540 func TestFalsy(t *testing.T) { 541 tests := []struct { 542 in Val 543 }{ 544 {in: Val{Tid: StringID, Value: []byte("false")}}, 545 {in: Val{Tid: DefaultID, Value: []byte("false")}}, 546 {in: Val{Tid: IntID, Value: bs(int64(0))}}, 547 {in: Val{Tid: FloatID, Value: bs(float64(0.0))}}, 548 {in: Val{Tid: BinaryID, Value: []byte("")}}, 549 } 550 for _, tc := range tests { 551 out, err := Convert(tc.in, BoolID) 552 require.NoError(t, err) 553 require.EqualValues(t, false, out.Value) 554 } 555 } 556 557 func TestSameConversionFloat(t *testing.T) { 558 tests := []struct { 559 in float64 560 }{ 561 {in: float64(3.4434)}, 562 {in: float64(-3.0)}, 563 {in: float64(0.5e2)}, 564 } 565 566 for _, tc := range tests { 567 out, err := Convert(Val{Tid: BinaryID, Value: bs(tc.in)}, FloatID) 568 require.NoError(t, err) 569 require.EqualValues(t, Val{Tid: FloatID, Value: tc.in}, out) 570 } 571 } 572 573 func TestSameConversionInt(t *testing.T) { 574 tests := []struct { 575 in int64 576 }{ 577 {in: int64(3)}, 578 {in: int64(-3)}, 579 {in: int64(9999)}, 580 {in: int64(0)}, 581 } 582 583 for _, tc := range tests { 584 out, err := Convert(Val{Tid: BinaryID, Value: bs(tc.in)}, IntID) 585 require.NoError(t, err) 586 require.EqualValues(t, Val{Tid: IntID, Value: tc.in}, out) 587 } 588 } 589 590 func TestConvertBoolToFloat(t *testing.T) { 591 tests := []struct { 592 in bool 593 out float64 594 }{ 595 {in: true, out: float64(1.0)}, 596 {in: false, out: float64(0.0)}, 597 } 598 599 for _, tc := range tests { 600 out, err := Convert(Val{Tid: BoolID, Value: bs(tc.in)}, FloatID) 601 require.NoError(t, err) 602 require.EqualValues(t, Val{Tid: FloatID, Value: tc.out}, out) 603 } 604 } 605 606 func TestConvertBoolToString(t *testing.T) { 607 tests := []struct { 608 in bool 609 out string 610 }{ 611 {in: true, out: "true"}, 612 {in: false, out: "false"}, 613 } 614 615 for _, tc := range tests { 616 out, err := Convert(Val{Tid: BoolID, Value: bs(tc.in)}, StringID) 617 require.NoError(t, err) 618 require.EqualValues(t, Val{Tid: StringID, Value: tc.out}, out) 619 } 620 } 621 622 func TestConvertIntToFloat(t *testing.T) { 623 tests := []struct { 624 in int64 625 out float64 626 }{ 627 {in: int64(3), out: float64(3.0)}, 628 {in: int64(-3), out: float64(-3.0)}, 629 {in: int64(0), out: float64(0.0)}, 630 } 631 632 for _, tc := range tests { 633 out, err := Convert(Val{Tid: IntID, Value: bs(tc.in)}, FloatID) 634 require.NoError(t, err) 635 require.EqualValues(t, Val{Tid: FloatID, Value: tc.out}, out) 636 } 637 } 638 639 func TestConvertFloatToInt(t *testing.T) { 640 tests := []struct { 641 in float64 642 out int64 643 failure string 644 }{ 645 {in: float64(3), out: int64(3)}, 646 {in: float64(-3.0), out: int64(-3)}, 647 {in: float64(0), out: int64(0)}, 648 {in: float64(522638295213.3243), out: int64(522638295213)}, 649 {in: float64(-522638295213.3243), out: int64(-522638295213)}, 650 { 651 in: math.NaN(), 652 failure: "Float out of int64 range", 653 }, 654 { 655 in: math.Inf(0), 656 failure: "Float out of int64 range", 657 }, 658 { 659 in: math.Inf(-1), 660 failure: "Float out of int64 range", 661 }, 662 } 663 664 for _, tc := range tests { 665 out, err := Convert(Val{Tid: FloatID, Value: bs(tc.in)}, IntID) 666 if tc.failure != "" { 667 require.Error(t, err) 668 require.EqualError(t, err, tc.failure) 669 continue 670 } 671 require.NoError(t, err) 672 require.EqualValues(t, Val{Tid: IntID, Value: tc.out}, out) 673 } 674 } 675 676 func TestConvertStringToInt(t *testing.T) { 677 tests := []struct { 678 in string 679 out int64 680 failure string 681 }{ 682 {in: "1", out: int64(1)}, 683 {in: "13816", out: int64(13816)}, 684 {in: "-1221", out: int64(-1221)}, 685 {in: "0", out: int64(0)}, 686 {in: "203716381366627", out: int64(203716381366627)}, 687 { 688 in: "", 689 failure: `strconv.ParseInt: parsing "": invalid syntax`, 690 }, 691 { 692 in: "srfrog", 693 failure: `strconv.ParseInt: parsing "srfrog": invalid syntax`, 694 }, 695 { 696 in: "3.0", 697 failure: `strconv.ParseInt: parsing "3.0": invalid syntax`, 698 }, 699 { 700 in: "-3a.5", 701 failure: `strconv.ParseInt: parsing "-3a.5": invalid syntax`, 702 }, 703 } 704 705 for _, tc := range tests { 706 out, err := Convert(Val{Tid: StringID, Value: []byte(tc.in)}, IntID) 707 if tc.failure != "" { 708 require.Error(t, err) 709 require.EqualError(t, err, tc.failure) 710 continue 711 } 712 require.NoError(t, err) 713 require.EqualValues(t, Val{Tid: IntID, Value: tc.out}, out) 714 } 715 } 716 717 func TestConvertStringToFloat(t *testing.T) { 718 tests := []struct { 719 in string 720 out float64 721 failure string 722 }{ 723 {in: "1", out: float64(1)}, 724 {in: "13816.251", out: float64(13816.251)}, 725 {in: "-1221.12", out: float64(-1221.12)}, 726 {in: "-0.0", out: float64(-0.0)}, 727 {in: "1e10", out: float64(1e10)}, 728 {in: "1e-2", out: float64(0.01)}, 729 { 730 in: "", 731 failure: `strconv.ParseFloat: parsing "": invalid syntax`, 732 }, 733 { 734 in: "srfrog", 735 failure: `strconv.ParseFloat: parsing "srfrog": invalid syntax`, 736 }, 737 { 738 in: "-3a.5", 739 failure: `strconv.ParseFloat: parsing "-3a.5": invalid syntax`, 740 }, 741 { 742 in: "1e400", 743 failure: `strconv.ParseFloat: parsing "1e400": value out of range`, 744 }, 745 } 746 747 for _, tc := range tests { 748 out, err := Convert(Val{Tid: StringID, Value: []byte(tc.in)}, FloatID) 749 if tc.failure != "" { 750 require.Error(t, err) 751 require.EqualError(t, err, tc.failure) 752 continue 753 } 754 require.NoError(t, err) 755 require.EqualValues(t, Val{Tid: FloatID, Value: tc.out}, out) 756 } 757 } 758 759 func TestConvertFloatToDateTime(t *testing.T) { 760 tests := []struct { 761 in float64 762 out time.Time 763 }{ 764 {in: float64(1257894000), out: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)}, 765 {in: float64(-4410000), out: time.Date(1969, time.November, 10, 23, 0, 0, 0, time.UTC)}, 766 {in: float64(2204578800), out: time.Date(2039, time.November, 10, 23, 0, 0, 0, time.UTC)}, 767 {in: float64(-2150326800), out: time.Date(1901, time.November, 10, 23, 0, 0, 0, time.UTC)}, 768 {in: float64(1257894000.001), out: time.Date(2009, time.November, 10, 23, 0, 0, 999927, time.UTC)}, 769 {in: float64(-4409999.999), out: time.Date(1969, time.November, 10, 23, 0, 0, 1000001, time.UTC)}, 770 } 771 772 for _, tc := range tests { 773 out, err := Convert(Val{Tid: FloatID, Value: bs(tc.in)}, DateTimeID) 774 require.NoError(t, err) 775 require.EqualValues(t, Val{Tid: DateTimeID, Value: tc.out}, out) 776 } 777 } 778 779 func TestConvertDateTimeToFloat(t *testing.T) { 780 tests := []struct { 781 in time.Time 782 out float64 783 }{ 784 {in: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), out: float64(1257894000)}, 785 {in: time.Date(1969, time.November, 10, 23, 0, 0, 0, time.UTC), out: float64(-4410000)}, 786 {in: time.Date(2039, time.November, 10, 23, 0, 0, 0, time.UTC), out: float64(2204578800)}, 787 {in: time.Date(1901, time.November, 10, 23, 0, 0, 0, time.UTC), out: float64(-2150326800)}, 788 {in: time.Date(2009, time.November, 10, 23, 0, 0, 1000000, time.UTC), out: float64(1257894000.001)}, 789 {in: time.Date(1969, time.November, 10, 23, 0, 0, 1000000, time.UTC), out: float64(-4409999.999)}, 790 } 791 792 for _, tc := range tests { 793 out, err := Convert(Val{Tid: DateTimeID, Value: bs(tc.in)}, FloatID) 794 require.NoError(t, err) 795 require.EqualValues(t, Val{Tid: FloatID, Value: tc.out}, out) 796 } 797 } 798 799 func TestConvertIntToDateTime(t *testing.T) { 800 tests := []struct { 801 in int64 802 out time.Time 803 }{ 804 {in: int64(1257894000), out: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)}, 805 {in: int64(-4410000), out: time.Date(1969, time.November, 10, 23, 0, 0, 0, time.UTC)}, 806 } 807 808 for _, tc := range tests { 809 out, err := Convert(Val{Tid: IntID, Value: bs(tc.in)}, DateTimeID) 810 require.NoError(t, err) 811 require.EqualValues(t, Val{Tid: DateTimeID, Value: tc.out}, out) 812 } 813 } 814 815 func TestConvertDateTimeToInt(t *testing.T) { 816 tests := []struct { 817 in time.Time 818 out int64 819 }{ 820 {in: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), out: int64(1257894000)}, 821 {in: time.Date(1969, time.November, 10, 23, 0, 0, 0, time.UTC), out: int64(-4410000)}, 822 {in: time.Date(2039, time.November, 10, 23, 0, 0, 0, time.UTC), out: int64(2204578800)}, 823 {in: time.Date(1901, time.November, 10, 23, 0, 0, 0, time.UTC), out: int64(-2150326800)}, 824 } 825 826 for _, tc := range tests { 827 out, err := Convert(Val{Tid: DateTimeID, Value: bs(tc.in)}, IntID) 828 require.NoError(t, err) 829 require.EqualValues(t, Val{Tid: IntID, Value: tc.out}, out) 830 } 831 } 832 833 func TestConvertToString(t *testing.T) { 834 tests := []struct { 835 in Val 836 out string 837 }{ 838 {in: Val{Tid: FloatID, Value: bs(float64(13816.251))}, out: "13816.251"}, 839 {in: Val{Tid: IntID, Value: bs(int64(-1221))}, out: "-1221"}, 840 {in: Val{Tid: BoolID, Value: bs(true)}, out: "true"}, 841 {in: Val{Tid: StringID, Value: []byte("srfrog")}, out: "srfrog"}, 842 {in: Val{Tid: PasswordID, Value: []byte("password")}, out: "password"}, 843 {in: Val{Tid: DateTimeID, Value: bs(time.Date(2006, time.January, 2, 15, 4, 5, 0, time.UTC))}, out: "2006-01-02T15:04:05Z"}, 844 } 845 846 for _, tc := range tests { 847 out, err := Convert(tc.in, StringID) 848 require.NoError(t, err) 849 require.EqualValues(t, Val{Tid: StringID, Value: tc.out}, out) 850 } 851 }