github.com/AbsaOSS/env-binder@v1.0.1/env/bind_test.go (about) 1 /* 2 Copyright 2021 The k8gb 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 Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic 17 */ 18 19 package env 20 21 import ( 22 "os" 23 "reflect" 24 "strings" 25 "testing" 26 27 "github.com/stretchr/testify/assert" 28 ) 29 30 // Testee public test structure 31 type Testee struct { 32 ID int `env:"TESTEE_ID"` 33 Value string `env:"TESTEE_VALUE"` 34 } 35 36 func TestDefaultAndRequireinOppositeOrder(t *testing.T) { 37 defer cleanup() 38 // arrange 39 _ = os.Setenv(tokenID, "") 40 _ = os.Setenv(tokenValue, "") 41 type token struct { 42 ID int `env:"TOKEN_ID, require=true, default = 066, protected=true"` 43 Value string `env:"TOKEN_VALUE, protected=true, default = AAAA, require=true"` 44 } 45 // act 46 tok := &token{ID: 5} 47 err := Bind(tok) 48 // assert 49 assert.NoError(t, err) 50 assert.Equal(t, 5, tok.ID) 51 assert.Equal(t, "", tok.Value) 52 } 53 54 func TestParseNil(t *testing.T) { 55 defer cleanup() 56 err := Bind(nil) 57 assert.Error(t, err) 58 } 59 60 func TestParseNotPointer(t *testing.T) { 61 defer cleanup() 62 err := Bind(Testee{}) 63 assert.Error(t, err) 64 } 65 66 func TestInvalidEnvVar(t *testing.T) { 67 defer cleanup() 68 // arrange 69 type token struct { 70 ID int `env:"GG%%^"` 71 } 72 // act 73 tok := &token{ID: 5} 74 err := Bind(tok) 75 // assert 76 assert.NoError(t, err) 77 assert.Equal(t, 0, tok.ID) 78 } 79 80 func TestUnsupportedDataType(t *testing.T) { 81 defer cleanup() 82 // arrange 83 type token struct { 84 ID reflect.Type `env:"TOKEN_ID"` 85 } 86 // act 87 tok := &token{} 88 err := Bind(tok) 89 // assert 90 assert.Error(t, err) 91 } 92 93 func TestENVVARIsRequiredError(t *testing.T) { 94 defer cleanup() 95 // arrange 96 type token struct { 97 ID int `env:"TOKEN_ID, require=true"` 98 Value string `env:"TOKEN_VALUE"` 99 } 100 // act 101 tok := &token{ID: 5} 102 err := Bind(tok) 103 // assert 104 assert.Error(t, err) 105 assert.Equal(t, 5, tok.ID) 106 } 107 108 func TestENVVARIsRequiredPass(t *testing.T) { 109 defer cleanup() 110 // arrange 111 const val = "4BMKKDsdfsf5f7=" 112 _ = os.Setenv(tokenValue, val) 113 type token struct { 114 Value string `env:"TOKEN_VALUE, require=true"` 115 } 116 // act 117 tok := &token{Value: "AAAA"} 118 err := Bind(tok) 119 // assert 120 assert.NoError(t, err) 121 assert.Equal(t, val, tok.Value) 122 } 123 124 func TestENVVARIsNotRequiredPass(t *testing.T) { 125 defer cleanup() 126 // arrange 127 type token struct { 128 ID string `env:"TOKEN_ID, require=false"` 129 } 130 tok := &token{ID: "AAAA"} 131 // act 132 err := Bind(tok) 133 // assert 134 assert.NoError(t, err) 135 assert.Equal(t, "", tok.ID) 136 } 137 138 func TestSetDefaultEmpty(t *testing.T) { 139 defer cleanup() 140 // arrange 141 type token struct { 142 ID int `env:"TOKEN_ID, default=0"` 143 Value string `env:"TOKEN_VALUE, default="` 144 Ratio float64 `env:"TOKEN_RATIO, default=0"` 145 Readonly bool `env:"TOKEN_READONLY, default=false"` 146 Hours []int `env:"TOKEN_HOURS, default[]"` // can't be parsed! 147 URLs []string `env:"TOKEN_URLS, default=[]"` 148 Enabled []bool `env:"TOKEN_BOOLS, default=[]"` 149 Coordinates []float64 `env:"TOKEN_COORDINATES, default=[]"` 150 } 151 tok := &token{} 152 // act 153 err := Bind(tok) 154 155 // assert 156 assert.NoError(t, err) 157 assert.Equal(t, 0, tok.ID) 158 assert.Equal(t, "", tok.Value) 159 assert.Equal(t, 0., tok.Ratio) 160 assert.Equal(t, false, tok.Readonly) 161 assert.Equal(t, []int(nil), tok.Hours) 162 assert.Equal(t, []string{}, tok.URLs) 163 assert.Equal(t, []bool{}, tok.Enabled) 164 assert.Equal(t, []float64{}, tok.Coordinates) 165 } 166 167 func TestInvalidValue(t *testing.T) { 168 defer cleanup() 169 _ = os.Setenv(envString, "invalid") 170 _ = os.Setenv(envBool, "invalid") 171 _ = os.Setenv(envFloat64, "invalid") 172 _ = os.Setenv(envInt, "invalid") 173 _ = os.Setenv(envStringSlice, "[]") 174 _ = os.Setenv(envBoolSlice, "invalid") 175 _ = os.Setenv(envFloat64Slice, "invalid") 176 _ = os.Setenv(envIntSlice, "invalid") 177 // arrange 178 type token1 struct { 179 envString string `env:"ENV_STRING, default=test"` 180 } 181 type token2 struct { 182 envInt int `env:"ENV_INT, default=22"` 183 } 184 type token3 struct { 185 envBool bool `env:"ENV_BOOL, default=true"` 186 } 187 type token4 struct { 188 envFloat float32 `env:"ENV_FLOAT64, default=22.0"` 189 } 190 type token5 struct { 191 envStringSlice []string `env:"ENV_STRING_SLICE, default=[test,test]"` 192 } 193 type token6 struct { 194 envIntSlice []int `env:"ENV_INT_SLICE, default=[22]"` 195 } 196 type token7 struct { 197 envBoolSlice []bool `env:"ENV_BOOL_SLICE, default=[T]"` 198 } 199 type token8 struct { 200 envFloatSlice []float32 `env:"ENV_FLOAT64_SLICE, default=[22.0]"` 201 } 202 203 // act 204 // assert 205 err := Bind(&token1{}) 206 assert.NoError(t, err) 207 err = Bind(&token2{}) 208 assert.Error(t, err) 209 err = Bind(&token3{}) 210 assert.Error(t, err) 211 err = Bind(&token4{}) 212 assert.Error(t, err) 213 err = Bind(&token5{}) 214 assert.NoError(t, err) 215 err = Bind(&token6{}) 216 assert.Error(t, err) 217 err = Bind(&token7{}) 218 assert.Error(t, err) 219 err = Bind(&token8{}) 220 assert.Error(t, err) 221 } 222 223 func TestEmptyValue(t *testing.T) { 224 defer cleanup() 225 _ = os.Setenv(envString, "") 226 _ = os.Setenv(envInt, "") 227 _ = os.Setenv(envBool, "") 228 _ = os.Setenv(envFloat64, "") 229 _ = os.Setenv(envStringSlice, "") 230 _ = os.Setenv(envIntSlice, "") 231 _ = os.Setenv(envBoolSlice, "") 232 _ = os.Setenv(envFloat64Slice, "") 233 // arrange 234 // arrange 235 type tokenString struct { 236 envString string `env:"ENV_STRING, default=test"` 237 } 238 type tokenInt struct { 239 envInt int `env:"ENV_INT, default=22"` 240 } 241 type tokenBool struct { 242 envBool bool `env:"ENV_BOOL, default=true"` 243 } 244 type tokenFloat struct { 245 envFloat float32 `env:"ENV_FLOAT64, default=22.0"` 246 } 247 type tokenStringSlice struct { 248 envStringSlice []string `env:"ENV_STRING_SLICE, default=[test,test]"` 249 } 250 type tokenIntSlice struct { 251 envIntSlice []int `env:"ENV_INT_SLICE, default=[22]"` 252 } 253 type tokenBoolSlice struct { 254 envBoolSlice []bool `env:"ENV_BOOL_SLICE, default=[T]"` 255 } 256 type tokenFloatSlice struct { 257 envFloatSlice []float32 `env:"ENV_FLOAT64_SLICE, default=[22.0]"` 258 } 259 260 // act 261 // assert 262 t1 := &tokenString{} 263 err := Bind(t1) 264 assert.NoError(t, err) 265 assert.Equal(t, "", t1.envString) 266 err = Bind(&tokenInt{}) 267 assert.Error(t, err) 268 err = Bind(&tokenBool{}) 269 assert.Error(t, err) 270 err = Bind(&tokenFloat{}) 271 assert.Error(t, err) 272 t5 := &tokenStringSlice{} 273 err = Bind(t5) 274 assert.NoError(t, err) 275 assert.Equal(t, []string{}, t5.envStringSlice) 276 t6 := &tokenIntSlice{} 277 err = Bind(t6) 278 assert.NoError(t, err) 279 assert.Equal(t, []int{}, t6.envIntSlice) 280 t7 := &tokenBoolSlice{} 281 err = Bind(t7) 282 assert.NoError(t, err) 283 assert.Equal(t, []bool{}, t7.envBoolSlice) 284 t8 := &tokenFloatSlice{} 285 err = Bind(t8) 286 assert.NoError(t, err) 287 assert.Equal(t, []float32{}, t8.envFloatSlice) 288 } 289 290 func TestProtected(t *testing.T) { 291 defer cleanup() 292 _ = os.Setenv(envString, "200") 293 _ = os.Setenv(envInt, "200") 294 _ = os.Setenv(envBool, "false") 295 _ = os.Setenv(envFloat64, "200") 296 _ = os.Setenv(envStringSlice, "2,0,0") 297 _ = os.Setenv(envIntSlice, "2,0,0") 298 _ = os.Setenv(envBoolSlice, "1,0,0") 299 _ = os.Setenv(envFloat64Slice, "2,0,0") 300 // arrange 301 type token struct { 302 envInt int `env:"ENV_INT, protected=true, default=100"` 303 envString string `env:"ENV_STRING, default=100, protected=true"` 304 envBool bool `env:"ENV_BOOL, default=F, protected=true"` 305 envFloat float64 `env:"ENV_FLOAT64, default=100, protected =true"` 306 envIntSlice []int `env:"ENV_INT_SLICE, default=[1,0,0], protected=true"` 307 envStringSlice []string `env:"ENV_STRING_SLICE, protected=true, default=[1,0,0]"` 308 envBoolSlice []bool `env:"ENV_BOOL_SLICE, protected=true, default=[1,0,0]"` 309 envFloatSlice []float64 `env:"ENV_FLOAT64_SLICE, protected=true, default=[100,100,100]"` 310 } 311 type token2 struct { 312 envInt int `env:"ENV_INT, protected=false, default=100"` 313 envString string `env:"ENV_STRING, default=100, protected=false"` 314 envBool bool `env:"ENV_BOOL, default=F, protected=false"` 315 envFloat float64 `env:"ENV_FLOAT64, default=100"` 316 envIntSlice []int `env:"ENV_INT_SLICE, default=[1,0,0]"` 317 envStringSlice []string `env:"ENV_STRING_SLICE, default=[1,0,0]"` 318 envBoolSlice []bool `env:"ENV_BOOL_SLICE, protected=false, default=[1,0,0]"` 319 envFloatSlice []float64 `env:"ENV_FLOAT64_SLICE, protected=false, default=[100,100,100]"` 320 } 321 unprotected := &token2{ 322 envInt: 300, 323 envString: "300", 324 envFloat: 300.0, 325 envBool: true, 326 envIntSlice: []int{3, 0, 0}, 327 envBoolSlice: []bool{true, true, true}, 328 envStringSlice: []string{"300"}, 329 envFloatSlice: []float64{3, 0, 0}, 330 } 331 unprotectedEmpty := &token2{} 332 333 filled := &token{ 334 envInt: 300, 335 envString: "300", 336 envFloat: 300.0, 337 envBool: true, 338 envIntSlice: []int{3, 0, 0}, 339 envBoolSlice: []bool{true, true, true}, 340 envStringSlice: []string{"300"}, 341 envFloatSlice: []float64{3, 0, 0}, 342 } 343 empty := &token{} 344 // act 345 err1 := Bind(filled) 346 err2 := Bind(empty) 347 err3 := Bind(unprotected) 348 err4 := Bind(unprotectedEmpty) 349 350 // assert 351 assert.NoError(t, err1) 352 assert.Equal(t, filled.envInt, 300) 353 assert.Equal(t, filled.envString, "300") 354 assert.Equal(t, filled.envBool, true) 355 assert.Equal(t, filled.envFloat, 300.0) 356 assert.Equal(t, filled.envIntSlice, []int{3, 0, 0}) 357 assert.Equal(t, filled.envStringSlice, []string{"300"}) 358 assert.Equal(t, filled.envBoolSlice, []bool{true, true, true}) 359 assert.Equal(t, filled.envFloatSlice, []float64{3, 0, 0}) 360 assert.NoError(t, err2) 361 assert.Equal(t, empty.envInt, 200) 362 assert.Equal(t, empty.envString, "200") 363 assert.Equal(t, empty.envBool, false) 364 assert.Equal(t, empty.envFloat, 200.0) 365 assert.Equal(t, empty.envIntSlice, []int{2, 0, 0}) 366 assert.Equal(t, empty.envStringSlice, []string{"2", "0", "0"}) 367 assert.Equal(t, empty.envBoolSlice, []bool{true, false, false}) 368 assert.Equal(t, empty.envFloatSlice, []float64{2, 0, 0}) 369 370 assert.NoError(t, err3) 371 assert.Equal(t, unprotected.envInt, 200) 372 assert.Equal(t, unprotected.envString, "200") 373 assert.Equal(t, unprotected.envBool, false) 374 assert.Equal(t, unprotected.envFloat, 200.0) 375 assert.Equal(t, unprotected.envIntSlice, []int{2, 0, 0}) 376 assert.Equal(t, unprotected.envStringSlice, []string{"2", "0", "0"}) 377 assert.Equal(t, unprotected.envBoolSlice, []bool{true, false, false}) 378 assert.Equal(t, unprotected.envFloatSlice, []float64{2, 0, 0}) 379 assert.NoError(t, err4) 380 assert.Equal(t, unprotectedEmpty.envInt, 200) 381 assert.Equal(t, unprotectedEmpty.envString, "200") 382 assert.Equal(t, unprotectedEmpty.envBool, false) 383 assert.Equal(t, unprotectedEmpty.envFloat, 200.0) 384 assert.Equal(t, unprotectedEmpty.envIntSlice, []int{2, 0, 0}) 385 assert.Equal(t, unprotectedEmpty.envStringSlice, []string{"2", "0", "0"}) 386 assert.Equal(t, unprotectedEmpty.envBoolSlice, []bool{true, false, false}) 387 assert.Equal(t, unprotectedEmpty.envFloatSlice, []float64{2, 0, 0}) 388 } 389 390 func TestEnvVarDoesntExists(t *testing.T) { 391 defer cleanup() 392 // arrange 393 type token struct { 394 ID int `env:"TOKEN_IDX, default=22"` 395 } 396 tok := &token{ID: 50} 397 // act 398 err := Bind(tok) 399 400 // assert 401 assert.NoError(t, err) 402 assert.Equal(t, 22, tok.ID) 403 } 404 405 func TestSetFieldWhenVariableDoesntExists(t *testing.T) { 406 defer cleanup() 407 408 // arrange 409 type token struct { 410 ID int `env:"TOKEN_ID, default=22"` 411 Value string `env:"TOKEN_VALUE, default=fc3"` 412 Ratio float64 `env:"TOKEN_RATIO, default=-0.000123"` 413 Readonly bool `env:"TOKEN_READONLY, default=1"` 414 Hours []int `env:"TOKEN_HOURS, default=[2,5,10]"` 415 URLs []string `env:"TOKEN_URLS, default=[http://server.local:8080,https://server.exposed.com:80]"` 416 Enabled []bool `env:"TOKEN_BOOLS, default=[true, false, true]"` 417 Coordinates []float64 `env:"TOKEN_COORDINATES, default=[0.000123,-12.2250]"` 418 EmptySlice []bool `env:"EMPTY_SLICE, default=[]"` 419 } 420 tok := &token{ 421 ID: 11, 422 Value: "AAAA", 423 Ratio: 70.0, 424 Readonly: false, 425 Hours: []int{0}, 426 URLs: nil, 427 Enabled: []bool{}, 428 Coordinates: nil, 429 EmptySlice: []bool{true, true}, 430 } 431 432 // act 433 err := Bind(tok) 434 435 // assert 436 assert.NoError(t, err) 437 assert.Equal(t, 22, tok.ID) 438 assert.Equal(t, "fc3", tok.Value) 439 assert.Equal(t, -0.000123, tok.Ratio) 440 assert.Equal(t, true, tok.Readonly) 441 assert.Equal(t, []int{2, 5, 10}, tok.Hours) 442 assert.Equal(t, []string{"http://server.local:8080", "https://server.exposed.com:80"}, tok.URLs) 443 assert.Equal(t, []bool{true, false, true}, tok.Enabled) 444 assert.Equal(t, []float64{0.000123, -12.2250}, tok.Coordinates) 445 assert.Equal(t, []bool{}, tok.EmptySlice) 446 } 447 448 func TestReadingPrivateFields(t *testing.T) { 449 defer cleanup() 450 // arrange 451 const val = "4BMKKDsdfsf5f7=" 452 _ = os.Setenv(tokenValue, val) 453 type token struct { 454 id int `env:"TOKEN_ID, default=22"` 455 readonly bool `env:"TOKEN_READONLY, require=0"` 456 value string `env:"TOKEN_VALUE, default=fc3, require=1"` 457 } 458 459 // act 460 tok := &token{id: 11, value: ""} 461 462 // act 463 err := Bind(tok) 464 assert.NoError(t, err) 465 assert.Equal(t, 22, tok.id) 466 assert.Equal(t, false, tok.readonly) 467 assert.Equal(t, val, tok.value) 468 } 469 470 func TestReadingAnonymousFields(t *testing.T) { 471 defer cleanup() 472 // arrange 473 _ = os.Setenv(tokenReadOnly, "false, false") 474 type token struct { 475 private struct { 476 readonly []bool `env:"TOKEN_READONLY, require=0"` 477 } 478 Exported struct { 479 Value string `env:"TOKEN_VALUE, default=#fc3, require=1"` 480 } 481 } 482 483 // act 484 tok := &token{} 485 486 // act 487 err := Bind(tok) 488 assert.NoError(t, err) 489 assert.Equal(t, []bool{false, false}, tok.private.readonly) 490 assert.Equal(t, "#fc3", tok.Exported.Value) 491 } 492 493 func TestReadingStructuresFields(t *testing.T) { 494 defer cleanup() 495 // arrange 496 _ = os.Setenv(tokenReadOnly, "false, false") 497 type private struct { 498 readonly []bool `env:"TOKEN_READONLY, require=0"` 499 } 500 type Exported struct { 501 Value string `env:"TOKEN_VALUE, default=#fc3, require=1"` 502 } 503 type token struct { 504 ID int 505 private private 506 Exported Exported 507 } 508 509 // act 510 tok := &token{ID: 50} 511 512 // act 513 err := Bind(tok) 514 assert.NoError(t, err) 515 assert.Equal(t, []bool{false, false}, tok.private.readonly) 516 assert.Equal(t, "#fc3", tok.Exported.Value) 517 } 518 519 func TestNoEnv(t *testing.T) { 520 defer cleanup() 521 // arrange 522 type private struct { 523 readonly []bool 524 } 525 type Exported struct { 526 Value string 527 } 528 type token struct { 529 ID int 530 private private 531 Exported Exported 532 Anonymous struct { 533 A string 534 b string 535 } 536 } 537 538 // act 539 tok := &token{ 540 ID: 22, 541 private: private{ 542 readonly: []bool{true, true}, 543 }, 544 Exported: Exported{ 545 Value: "exported"}, 546 } 547 tok.Anonymous.A = "B" 548 tok.Anonymous.b = "a" 549 550 // assert 551 err := Bind(tok) 552 assert.NoError(t, err) 553 assert.Equal(t, 22, tok.ID) 554 assert.Equal(t, []bool{true, true}, tok.private.readonly) 555 assert.Equal(t, "exported", tok.Exported.Value) 556 assert.Equal(t, "B", tok.Anonymous.A) 557 assert.Equal(t, "a", tok.Anonymous.b) 558 } 559 560 func TestSpecialSymbols(t *testing.T) { 561 defer cleanup() 562 // arrange 563 _ = os.Setenv(tokenValue, `----~<>/?.;:/!@#$%^&*()_+_=---\-\`) 564 type token struct { 565 ID string `env:"TOKEN_ID, default=----~<>/?.;:/!@#$%^&*()_+_=---\\-"` 566 Value string `env:"TOKEN_VALUE, require=true"` 567 Slice []string `env:"TOKEN_SLICE, default=[--- -~<>/?.;:/!@#$%^&*()_+_=----, ----~<>/?.;:/!@#$%^&*()_+_=----]"` 568 } 569 tok := &token{} 570 // act 571 err := Bind(tok) 572 // assert 573 assert.NoError(t, err) 574 assert.Equal(t, `----~<>/?.;:/!@#$%^&*()_+_=---\-`, tok.ID) 575 assert.Equal(t, "----~<>/?.;:/!@#$%^&*()_+_=---\\-\\", tok.Value) 576 assert.Equal(t, []string{"--- -~<>/?.;:/!@#$%^&*()_+_=----", " ----~<>/?.;:/!@#$%^&*()_+_=----"}, tok.Slice) 577 } 578 579 func TestSetFieldWhenVariableExists(t *testing.T) { 580 defer cleanup() 581 // arrange 582 const val = "4BMKKDsdfsf5f7=" 583 _ = os.Setenv(tokenValue, val) 584 type token struct { 585 ID int `env:"TOKEN_ID"` 586 Value string `env:"TOKEN_VALUE"` 587 } 588 tok := &token{Value: "AAAA", ID: 5} 589 // act 590 err := Bind(tok) 591 // assert 592 assert.NoError(t, err) 593 assert.Equal(t, val, tok.Value) 594 assert.Equal(t, 0, tok.ID) 595 } 596 597 func TestArray(t *testing.T) { 598 defer cleanup() 599 // arrange 600 _ = os.Setenv(tokenValue, "1,2,3") 601 _ = os.Setenv(tokenID, "1, 2, 3") 602 _ = os.Setenv(tokenBools, "1, 0, false, true, F,T") 603 _ = os.Setenv(tokenCoordinates, "1.01, -0.05") 604 type token struct { 605 IDs []int `env:"TOKEN_VALUE"` 606 Value []string `env:"TOKEN_VALUE"` 607 Bools []bool `env:"TOKEN_SWITCH"` 608 Floats []float64 `env:"TOKEN_COORDINATES"` 609 } 610 tok := &token{} 611 // act 612 err := Bind(tok) 613 // assert 614 assert.NoError(t, err) 615 assert.Equal(t, []int{1, 2, 3}, tok.IDs) 616 assert.Equal(t, []string{"1", "2", "3"}, tok.Value) 617 assert.Equal(t, []bool{true, false, false, true, false, true}, tok.Bools) 618 assert.Equal(t, []float64{1.01, -0.05}, tok.Floats) 619 } 620 621 func TestSetMultipleFieldsByOneVariable(t *testing.T) { 622 // arrange 623 defer cleanup() 624 const val = "4BMKKDsdfsf5f7=" 625 _ = os.Setenv(tokenValue, val) 626 type token struct { 627 ID1 int `env:"TOKEN_ID, default=50"` 628 ID2 int `env:"TOKEN_ID, default=10"` 629 Value1 string `env:"TOKEN_VALUE, require=true"` 630 Value2 string `env:"TOKEN_VALUE, require=true"` 631 } 632 // act 633 tok := &token{} 634 err := Bind(tok) 635 // assert 636 assert.NoError(t, err) 637 assert.Equal(t, tok.ID1, 50) 638 assert.Equal(t, tok.ID2, 10) 639 assert.Equal(t, tok.Value1, val) 640 assert.Equal(t, tok.Value2, val) 641 } 642 643 func TestLowercase(t *testing.T) { 644 // arrange 645 val := "private field" 646 _ = os.Unsetenv(strings.ToLower(strings.ToLower(privateTokenValue))) 647 _ = os.Setenv(strings.ToLower(privateTokenValue), val) 648 // act 649 type token struct { 650 valLowerCase string `env:"private_token_value"` 651 valUpperCase string `env:"PRIVATE_TOKEN_VALUE"` 652 } 653 tok := &token{} 654 655 // assert 656 err := Bind(tok) 657 assert.NoError(t, err) 658 assert.Equal(t, val, tok.valLowerCase) 659 assert.Equal(t, "", tok.valUpperCase) 660 } 661 662 func TestPrefixSuccessfully(t *testing.T) { 663 defer cleanup() 664 // arrange 665 _ = os.Setenv(privateTokenValue, "private field") 666 _ = os.Setenv(exportedTokenValue, "exported field") 667 _ = os.Setenv(privateExportedTokenValue, "private in exported field") 668 _ = os.Setenv("TEMP_TOKEN_ID", "20") 669 _ = os.Setenv("TEMP_FIELD_HIDDEN", "very hidden") 670 type private struct { 671 Value string `env:"TOKEN_VALUE, require=0"` 672 } 673 type Exported struct { 674 Value string `env:"TOKEN_VALUE, require=1"` 675 } 676 type token struct { 677 private private `env:"PRIVATE"` 678 Exported Exported `env:"EXPORTED"` 679 Temp struct { 680 ID int `env:"TOKEN_ID"` 681 field struct { 682 hidden string `env:"HIDDEN"` 683 } `env:"FIELD"` 684 } `env:"TEMP"` 685 ID int `env:"TOKEN_ID, default=-1"` 686 } 687 688 // act 689 tok := &token{ID: 50} 690 err := Bind(tok) 691 // assert 692 assert.NoError(t, err) 693 assert.Equal(t, -1, tok.ID) 694 assert.Equal(t, tok.private.Value, "private field") 695 assert.Equal(t, tok.Exported.Value, "exported field") 696 assert.Equal(t, tok.Temp.ID, 20) 697 assert.Equal(t, tok.Temp.field.hidden, "very hidden") 698 } 699 700 func TestParseSimple(t *testing.T) { 701 // arrange 702 defer cleanup() 703 env := make(map[string]string) 704 env[envString] = "foo" 705 env[envBool] = "true" 706 setEnv(env) 707 708 type token struct { 709 ID int `env:"TOKEN_ID"` 710 Value string `env:"TOKEN_VALUE"` 711 } 712 type s struct { 713 UID int `env:"ENV_INT,default=55"` 714 name string `env:"ENV_STRING,require=true, default=michal"` 715 B bool `env:"ENV_BOOL"` 716 Bs []bool `env:"ENV_BOOL_SLICE,default=[true, false, true]"` 717 nums []int `env:"ENV_INT_SLICE,default=[10,0,5, 3, 4, 5]"` 718 F float64 `env:"ENV_FLOAT64, default=0.000000002121"` 719 Fs []float64 `env:"ENV_FLOAT64_SLICE,default=[0.0021,0.002,1.13,2.15]"` 720 surname string 721 Token token 722 Anonymous struct { 723 secret string `env:"ENV_STRING_PRIVATE"` 724 TopSecret bool 725 TokenBase64 string `env:"ENV_STRING_EXPORTED"` 726 arr []string `env:"ANONYMOUS_ARR, default= [abc, xyz, 123] "` 727 } 728 } 729 testee := &s{name: "Michal"} 730 731 // act 732 err := Bind(testee) 733 734 // assert 735 assert.Equal(t, testee.name, "foo") 736 assert.Equal(t, testee.UID, 55) 737 assert.Equal(t, testee.nums, []int{10, 0, 5, 3, 4, 5}) 738 assert.Equal(t, testee.Bs, []bool{true, false, true}) 739 assert.True(t, reflect.DeepEqual(testee.Anonymous.arr, []string{"abc", " xyz", " 123"})) 740 assert.Equal(t, testee.F, 0.000000002121) 741 assert.Equal(t, []float64{0.0021, 0.002, 1.13, 2.15}, testee.Fs) 742 assert.False(t, testee.Anonymous.TopSecret) 743 assert.NoError(t, err) 744 } 745 746 func TestService(t *testing.T) { 747 type Endpoint struct { 748 URL string `env:"ENDPOINT_URL, require=true"` 749 } 750 type Config struct { 751 // reading string value from NAME 752 Name string `env:"NAME"` 753 // reading int with 8080 as default value 754 DefaultPot int `env:"PORT, default=8080"` 755 // reading slice of strings with default values 756 Regions []string `env:"REGIONS, default=[us-east-1,us-east-2,us-west-1]"` 757 // inline structure 758 Credentials struct { 759 // binding required value 760 KeyID string `env:"ACCESS_KEY_ID, require=true"` 761 // binding to private field 762 secretKey string `env:"SECRET_ACCESS_KEY, require=true"` 763 } 764 // expected PRIMARY_ prefix in nested environment variables 765 Endpoint1 Endpoint `env:"PRIMARY"` 766 // expected FAILOVER_ prefix in nested environment variables 767 Endpoint2 Endpoint `env:"FAILOVER"` 768 // reuse an already bound env variable NAME 769 Description string `env:"NAME"` 770 // the field does not have a bind tag set, so it will be ignored during bind 771 Args []string 772 } 773 774 _ = os.Setenv(primaryEndpointURL, "https://ep1.cloud.example.com") 775 _ = os.Setenv(failoverEndpointURL, "https://ep2.cloud.example.com") 776 _ = os.Setenv(name, "Hello from 12-factor") 777 _ = os.Setenv(defaultPort, "9000") 778 _ = os.Setenv(accessKeyID, "AKIAIOSFODNN7EXAMPLE") 779 _ = os.Setenv(secretAccessKey, `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`) 780 781 // act 782 c := Config{Description: "Hello from os.LookupEnv()", Args: []string{"debug=true"}} 783 err := Bind(&c) 784 // assert 785 assert.NoError(t, err) 786 assert.Equal(t, "https://ep1.cloud.example.com", c.Endpoint1.URL) 787 assert.Equal(t, "https://ep2.cloud.example.com", c.Endpoint2.URL) 788 assert.Equal(t, "Hello from 12-factor", c.Name) 789 assert.Equal(t, 9000, c.DefaultPot) 790 assert.Equal(t, "AKIAIOSFODNN7EXAMPLE", c.Credentials.KeyID) 791 assert.Equal(t, `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`, c.Credentials.secretKey) 792 } 793 794 func TestTypeInt(t *testing.T) { 795 cleanup() 796 _ = os.Setenv(envInt, "") 797 _ = os.Setenv(envInt2, "1") 798 type token struct { 799 empty int `env:"ENV_INT"` 800 filled int `env:"ENV_INT2, require=true"` 801 protected int `env:"ENV_INT, protected=true"` 802 doesntExists int `env:"ENV_INT3, default=20"` 803 } 804 805 tok := &token{protected: 80} 806 err := Bind(tok) 807 assert.Error(t, err) 808 _ = os.Setenv(envInt, "1") 809 err = Bind(tok) 810 assert.NoError(t, err) 811 assert.Equal(t, 1, tok.empty) 812 assert.Equal(t, 1, tok.filled) 813 assert.Equal(t, 80, tok.protected) 814 assert.Equal(t, 20, tok.doesntExists) 815 } 816 817 func TestTypeInt8(t *testing.T) { 818 cleanup() 819 _ = os.Setenv(envInt, "") 820 _ = os.Setenv(envInt2, "1") 821 type token struct { 822 empty int8 `env:"ENV_INT"` 823 filled int8 `env:"ENV_INT2, require=true"` 824 protected int8 `env:"ENV_INT, protected=true"` 825 doesntExists int8 `env:"ENV_INT3, default=20"` 826 } 827 828 tok := &token{protected: 80} 829 err := Bind(tok) 830 assert.Error(t, err) 831 _ = os.Setenv(envInt, "1") 832 err = Bind(tok) 833 assert.NoError(t, err) 834 assert.Equal(t, int8(1), tok.empty) 835 assert.Equal(t, int8(1), tok.filled) 836 assert.Equal(t, int8(80), tok.protected) 837 assert.Equal(t, int8(20), tok.doesntExists) 838 } 839 840 func TestTypeInt16(t *testing.T) { 841 cleanup() 842 _ = os.Setenv(envInt, "") 843 _ = os.Setenv(envInt2, "1") 844 type token struct { 845 empty int16 `env:"ENV_INT"` 846 filled int16 `env:"ENV_INT2, require=true"` 847 protected int16 `env:"ENV_INT, protected=true"` 848 doesntExists int16 `env:"ENV_INT3, default=20"` 849 } 850 851 tok := &token{protected: 80} 852 err := Bind(tok) 853 assert.Error(t, err) 854 _ = os.Setenv(envInt, "1") 855 err = Bind(tok) 856 assert.NoError(t, err) 857 assert.Equal(t, int16(1), tok.empty) 858 assert.Equal(t, int16(1), tok.filled) 859 assert.Equal(t, int16(80), tok.protected) 860 assert.Equal(t, int16(20), tok.doesntExists) 861 } 862 863 func TestTypeInt32(t *testing.T) { 864 cleanup() 865 _ = os.Setenv(envInt, "") 866 _ = os.Setenv(envInt2, "1") 867 type token struct { 868 empty int32 `env:"ENV_INT"` 869 filled int32 `env:"ENV_INT2, require=true"` 870 protected int32 `env:"ENV_INT, protected=true"` 871 doesntExists int32 `env:"ENV_INT3, default=20"` 872 } 873 874 tok := &token{protected: 80} 875 err := Bind(tok) 876 assert.Error(t, err) 877 _ = os.Setenv(envInt, "1") 878 err = Bind(tok) 879 assert.NoError(t, err) 880 assert.Equal(t, int32(1), tok.empty) 881 assert.Equal(t, int32(1), tok.filled) 882 assert.Equal(t, int32(80), tok.protected) 883 assert.Equal(t, int32(20), tok.doesntExists) 884 } 885 886 func TestTypeInt64(t *testing.T) { 887 cleanup() 888 _ = os.Setenv(envInt, "") 889 _ = os.Setenv(envInt2, "1") 890 type token struct { 891 empty int64 `env:"ENV_INT"` 892 filled int64 `env:"ENV_INT2, require=true"` 893 protected int64 `env:"ENV_INT, protected=true"` 894 doesntExists int64 `env:"ENV_INT3, default=20"` 895 } 896 897 tok := &token{protected: 80} 898 err := Bind(tok) 899 assert.Error(t, err) 900 _ = os.Setenv(envInt, "1") 901 err = Bind(tok) 902 assert.NoError(t, err) 903 assert.Equal(t, int64(1), tok.empty) 904 assert.Equal(t, int64(1), tok.filled) 905 assert.Equal(t, int64(80), tok.protected) 906 assert.Equal(t, int64(20), tok.doesntExists) 907 } 908 909 func TestTypeFloat32(t *testing.T) { 910 cleanup() 911 _ = os.Setenv(envInt, "") 912 _ = os.Setenv(envInt2, "1") 913 type token struct { 914 empty float32 `env:"ENV_INT"` 915 filled float32 `env:"ENV_INT2, require=true"` 916 protected float32 `env:"ENV_INT, protected=true"` 917 doesntExists float32 `env:"ENV_INT3, default=20"` 918 } 919 920 tok := &token{protected: 80} 921 err := Bind(tok) 922 assert.Error(t, err) 923 _ = os.Setenv(envInt, "1") 924 err = Bind(tok) 925 assert.NoError(t, err) 926 assert.Equal(t, float32(1), tok.empty) 927 assert.Equal(t, float32(1), tok.filled) 928 assert.Equal(t, float32(80), tok.protected) 929 assert.Equal(t, float32(20), tok.doesntExists) 930 } 931 932 func TestTypeFloat64(t *testing.T) { 933 cleanup() 934 _ = os.Setenv(envInt, "") 935 _ = os.Setenv(envInt2, "1") 936 type token struct { 937 empty float64 `env:"ENV_INT"` 938 filled float64 `env:"ENV_INT2, require=true"` 939 protected float64 `env:"ENV_INT, protected=true"` 940 doesntExists float64 `env:"ENV_INT3, default=20"` 941 } 942 943 tok := &token{protected: 80} 944 err := Bind(tok) 945 assert.Error(t, err) 946 _ = os.Setenv(envInt, "1") 947 err = Bind(tok) 948 assert.NoError(t, err) 949 assert.Equal(t, float64(1), tok.empty) 950 assert.Equal(t, float64(1), tok.filled) 951 assert.Equal(t, float64(80), tok.protected) 952 assert.Equal(t, float64(20), tok.doesntExists) 953 } 954 955 func TestTypeUint(t *testing.T) { 956 cleanup() 957 _ = os.Setenv(envInt, "") 958 _ = os.Setenv(envInt2, "1") 959 type token struct { 960 empty uint `env:"ENV_INT"` 961 filled uint `env:"ENV_INT2, require=true"` 962 protected uint `env:"ENV_INT, protected=true"` 963 doesntExists uint `env:"ENV_INT3, default=20"` 964 } 965 966 tok := &token{protected: 80} 967 err := Bind(tok) 968 assert.Error(t, err) 969 _ = os.Setenv(envInt, "1") 970 err = Bind(tok) 971 assert.NoError(t, err) 972 assert.Equal(t, uint(1), tok.empty) 973 assert.Equal(t, uint(1), tok.filled) 974 assert.Equal(t, uint(80), tok.protected) 975 assert.Equal(t, uint(20), tok.doesntExists) 976 } 977 978 func TestTypeUint8(t *testing.T) { 979 cleanup() 980 _ = os.Setenv(envInt, "") 981 _ = os.Setenv(envInt2, "1") 982 type token struct { 983 empty uint8 `env:"ENV_INT"` 984 filled uint8 `env:"ENV_INT2, require=true"` 985 protected uint8 `env:"ENV_INT, protected=true"` 986 doesntExists uint8 `env:"ENV_INT3, default=20"` 987 } 988 989 tok := &token{protected: 80} 990 err := Bind(tok) 991 assert.Error(t, err) 992 _ = os.Setenv(envInt, "1") 993 err = Bind(tok) 994 assert.NoError(t, err) 995 assert.Equal(t, uint8(1), tok.empty) 996 assert.Equal(t, uint8(1), tok.filled) 997 assert.Equal(t, uint8(80), tok.protected) 998 assert.Equal(t, uint8(20), tok.doesntExists) 999 } 1000 1001 func TestTypeUint16(t *testing.T) { 1002 cleanup() 1003 _ = os.Setenv(envInt, "") 1004 _ = os.Setenv(envInt2, "1") 1005 type token struct { 1006 empty uint16 `env:"ENV_INT"` 1007 filled uint16 `env:"ENV_INT2, require=true"` 1008 protected uint16 `env:"ENV_INT, protected=true"` 1009 doesntExists uint16 `env:"ENV_INT3, default=20"` 1010 } 1011 1012 tok := &token{protected: 80} 1013 err := Bind(tok) 1014 assert.Error(t, err) 1015 _ = os.Setenv(envInt, "1") 1016 err = Bind(tok) 1017 assert.NoError(t, err) 1018 assert.Equal(t, uint16(1), tok.empty) 1019 assert.Equal(t, uint16(1), tok.filled) 1020 assert.Equal(t, uint16(80), tok.protected) 1021 assert.Equal(t, uint16(20), tok.doesntExists) 1022 } 1023 1024 func TestTypeUint32(t *testing.T) { 1025 cleanup() 1026 _ = os.Setenv(envInt, "") 1027 _ = os.Setenv(envInt2, "1") 1028 type token struct { 1029 empty uint32 `env:"ENV_INT"` 1030 filled uint32 `env:"ENV_INT2, require=true"` 1031 protected uint32 `env:"ENV_INT, protected=true"` 1032 doesntExists uint32 `env:"ENV_INT3, default=20"` 1033 } 1034 1035 tok := &token{protected: 80} 1036 err := Bind(tok) 1037 assert.Error(t, err) 1038 _ = os.Setenv(envInt, "1") 1039 err = Bind(tok) 1040 assert.NoError(t, err) 1041 assert.Equal(t, uint32(1), tok.empty) 1042 assert.Equal(t, uint32(1), tok.filled) 1043 assert.Equal(t, uint32(80), tok.protected) 1044 assert.Equal(t, uint32(20), tok.doesntExists) 1045 } 1046 1047 func TestTypeUint64(t *testing.T) { 1048 cleanup() 1049 _ = os.Setenv(envInt, "") 1050 _ = os.Setenv(envInt2, "1") 1051 type token struct { 1052 empty uint64 `env:"ENV_INT"` 1053 filled uint64 `env:"ENV_INT2, require=true"` 1054 protected uint64 `env:"ENV_INT, protected=true"` 1055 doesntExists uint64 `env:"ENV_INT3, default=20"` 1056 } 1057 1058 tok := &token{protected: 80} 1059 err := Bind(tok) 1060 assert.Error(t, err) 1061 _ = os.Setenv(envInt, "1") 1062 err = Bind(tok) 1063 assert.NoError(t, err) 1064 assert.Equal(t, uint64(1), tok.empty) 1065 assert.Equal(t, uint64(1), tok.filled) 1066 assert.Equal(t, uint64(80), tok.protected) 1067 assert.Equal(t, uint64(20), tok.doesntExists) 1068 } 1069 1070 func TestTypeString(t *testing.T) { 1071 cleanup() 1072 _ = os.Setenv(envInt, "") 1073 _ = os.Setenv(envInt2, "1") 1074 type token struct { 1075 empty string `env:"ENV_INT"` 1076 filled string `env:"ENV_INT2, require=true"` 1077 protected string `env:"ENV_INT, protected=true"` 1078 doesntExists string `env:"ENV_INT3, default=20"` 1079 } 1080 1081 tok := &token{protected: "80"} 1082 err := Bind(tok) 1083 assert.NoError(t, err) 1084 _ = os.Setenv(envInt, "1") 1085 err = Bind(tok) 1086 assert.NoError(t, err) 1087 assert.Equal(t, "1", tok.empty) 1088 assert.Equal(t, "1", tok.filled) 1089 assert.Equal(t, "80", tok.protected) 1090 assert.Equal(t, "20", tok.doesntExists) 1091 } 1092 1093 func TestTypeBool(t *testing.T) { 1094 cleanup() 1095 _ = os.Setenv(envInt, "") 1096 _ = os.Setenv(envInt2, "1") 1097 type token struct { 1098 empty bool `env:"ENV_INT"` 1099 filled bool `env:"ENV_INT2, require=true"` 1100 protected bool `env:"ENV_INT, protected=true"` 1101 doesntExists bool `env:"ENV_INT3, default=1"` 1102 } 1103 1104 tok := &token{protected: true} 1105 err := Bind(tok) 1106 assert.Error(t, err) 1107 _ = os.Setenv(envInt, "true") 1108 err = Bind(tok) 1109 assert.NoError(t, err) 1110 assert.Equal(t, true, tok.empty) 1111 assert.Equal(t, true, tok.filled) 1112 assert.Equal(t, true, tok.protected) 1113 assert.Equal(t, true, tok.doesntExists) 1114 } 1115 1116 func TestTypeIntSlice(t *testing.T) { 1117 cleanup() 1118 _ = os.Setenv(envInt, "") 1119 _ = os.Setenv(envInt2, "1,1") 1120 type token struct { 1121 empty []int `env:"ENV_INT"` 1122 filled []int `env:"ENV_INT2, require=true"` 1123 protected []int `env:"ENV_INT, protected=true"` 1124 doesntExists []int `env:"ENV_INT3, default=[20,20]"` 1125 } 1126 1127 tok := &token{protected: []int{80, 80}} 1128 err := Bind(tok) 1129 assert.NoError(t, err) 1130 assert.Equal(t, []int{}, tok.empty) 1131 assert.Equal(t, []int{1, 1}, tok.filled) 1132 assert.Equal(t, []int{80, 80}, tok.protected) 1133 assert.Equal(t, []int{20, 20}, tok.doesntExists) 1134 } 1135 1136 func TestTypeInt8Slice(t *testing.T) { 1137 cleanup() 1138 _ = os.Setenv(envInt, "") 1139 _ = os.Setenv(envInt2, "1,1") 1140 type token struct { 1141 empty []int8 `env:"ENV_INT"` 1142 filled []int8 `env:"ENV_INT2, require=true"` 1143 protected []int8 `env:"ENV_INT, protected=true"` 1144 doesntExists []int8 `env:"ENV_INT3, default=[20,20]"` 1145 } 1146 1147 tok := &token{protected: []int8{80, 80}} 1148 err := Bind(tok) 1149 assert.NoError(t, err) 1150 assert.Equal(t, []int8{}, tok.empty) 1151 assert.Equal(t, []int8{1, 1}, tok.filled) 1152 assert.Equal(t, []int8{80, 80}, tok.protected) 1153 assert.Equal(t, []int8{20, 20}, tok.doesntExists) 1154 } 1155 1156 func TestTypeInt16Slice(t *testing.T) { 1157 cleanup() 1158 _ = os.Setenv(envInt, "") 1159 _ = os.Setenv(envInt2, "1,1") 1160 type token struct { 1161 empty []int16 `env:"ENV_INT"` 1162 filled []int16 `env:"ENV_INT2, require=true"` 1163 protected []int16 `env:"ENV_INT, protected=true"` 1164 doesntExists []int16 `env:"ENV_INT3, default=[20,20]"` 1165 } 1166 1167 tok := &token{protected: []int16{80, 80}} 1168 err := Bind(tok) 1169 assert.NoError(t, err) 1170 assert.Equal(t, []int16{}, tok.empty) 1171 assert.Equal(t, []int16{1, 1}, tok.filled) 1172 assert.Equal(t, []int16{80, 80}, tok.protected) 1173 assert.Equal(t, []int16{20, 20}, tok.doesntExists) 1174 } 1175 1176 func TestTypeInt32Slice(t *testing.T) { 1177 cleanup() 1178 _ = os.Setenv(envInt, "") 1179 _ = os.Setenv(envInt2, "1,1") 1180 type token struct { 1181 empty []int32 `env:"ENV_INT"` 1182 filled []int32 `env:"ENV_INT2, require=true"` 1183 protected []int32 `env:"ENV_INT, protected=true"` 1184 doesntExists []int32 `env:"ENV_INT3, default=[20,20]"` 1185 } 1186 1187 tok := &token{protected: []int32{80, 80}} 1188 err := Bind(tok) 1189 assert.NoError(t, err) 1190 assert.Equal(t, []int32{}, tok.empty) 1191 assert.Equal(t, []int32{1, 1}, tok.filled) 1192 assert.Equal(t, []int32{80, 80}, tok.protected) 1193 assert.Equal(t, []int32{20, 20}, tok.doesntExists) 1194 } 1195 1196 func TestTypeInt64Slice(t *testing.T) { 1197 cleanup() 1198 _ = os.Setenv(envInt, "") 1199 _ = os.Setenv(envInt2, "1,1") 1200 type token struct { 1201 empty []int64 `env:"ENV_INT"` 1202 filled []int64 `env:"ENV_INT2, require=true"` 1203 protected []int64 `env:"ENV_INT, protected=true"` 1204 doesntExists []int64 `env:"ENV_INT3, default=[20,20]"` 1205 } 1206 1207 tok := &token{protected: []int64{80, 80}} 1208 err := Bind(tok) 1209 assert.NoError(t, err) 1210 assert.Equal(t, []int64{}, tok.empty) 1211 assert.Equal(t, []int64{1, 1}, tok.filled) 1212 assert.Equal(t, []int64{80, 80}, tok.protected) 1213 assert.Equal(t, []int64{20, 20}, tok.doesntExists) 1214 } 1215 1216 func TestTypeFloat32Slice(t *testing.T) { 1217 cleanup() 1218 _ = os.Setenv(envInt, "") 1219 _ = os.Setenv(envInt2, "1,1") 1220 type token struct { 1221 empty []float32 `env:"ENV_INT"` 1222 filled []float32 `env:"ENV_INT2, require=true"` 1223 protected []float32 `env:"ENV_INT, protected=true"` 1224 doesntExists []float32 `env:"ENV_INT3, default=[20,20]"` 1225 } 1226 1227 tok := &token{protected: []float32{80, 80}} 1228 err := Bind(tok) 1229 assert.NoError(t, err) 1230 assert.Equal(t, []float32{}, tok.empty) 1231 assert.Equal(t, []float32{1, 1}, tok.filled) 1232 assert.Equal(t, []float32{80, 80}, tok.protected) 1233 assert.Equal(t, []float32{20, 20}, tok.doesntExists) 1234 } 1235 1236 func TestTypeFloat64Slice(t *testing.T) { 1237 cleanup() 1238 _ = os.Setenv(envInt, "") 1239 _ = os.Setenv(envInt2, "1,1") 1240 type token struct { 1241 empty []float64 `env:"ENV_INT"` 1242 filled []float64 `env:"ENV_INT2, require=true"` 1243 protected []float64 `env:"ENV_INT, protected=true"` 1244 doesntExists []float64 `env:"ENV_INT3, default=[20,20]"` 1245 } 1246 1247 tok := &token{protected: []float64{80, 80}} 1248 err := Bind(tok) 1249 assert.NoError(t, err) 1250 assert.Equal(t, []float64{}, tok.empty) 1251 assert.Equal(t, []float64{1, 1}, tok.filled) 1252 assert.Equal(t, []float64{80, 80}, tok.protected) 1253 assert.Equal(t, []float64{20, 20}, tok.doesntExists) 1254 } 1255 1256 func TestTypeUIntSlice(t *testing.T) { 1257 cleanup() 1258 _ = os.Setenv(envInt, "") 1259 _ = os.Setenv(envInt2, "1,1") 1260 type token struct { 1261 empty []uint `env:"ENV_INT"` 1262 filled []uint `env:"ENV_INT2, require=true"` 1263 protected []uint `env:"ENV_INT, protected=true"` 1264 doesntExists []uint `env:"ENV_INT3, default=[20,20]"` 1265 } 1266 1267 tok := &token{protected: []uint{80, 80}} 1268 err := Bind(tok) 1269 assert.NoError(t, err) 1270 assert.Equal(t, []uint{}, tok.empty) 1271 assert.Equal(t, []uint{1, 1}, tok.filled) 1272 assert.Equal(t, []uint{80, 80}, tok.protected) 1273 assert.Equal(t, []uint{20, 20}, tok.doesntExists) 1274 } 1275 1276 func TestTypeUInt16Slice(t *testing.T) { 1277 cleanup() 1278 _ = os.Setenv(envInt, "") 1279 _ = os.Setenv(envInt2, "1,1") 1280 type token struct { 1281 empty []uint16 `env:"ENV_INT"` 1282 filled []uint16 `env:"ENV_INT2, require=true"` 1283 protected []uint16 `env:"ENV_INT, protected=true"` 1284 doesntExists []uint16 `env:"ENV_INT3, default=[20,20]"` 1285 } 1286 1287 tok := &token{protected: []uint16{80, 80}} 1288 err := Bind(tok) 1289 assert.NoError(t, err) 1290 assert.Equal(t, []uint16{}, tok.empty) 1291 assert.Equal(t, []uint16{1, 1}, tok.filled) 1292 assert.Equal(t, []uint16{80, 80}, tok.protected) 1293 assert.Equal(t, []uint16{20, 20}, tok.doesntExists) 1294 } 1295 1296 func TestTypeUInt32Slice(t *testing.T) { 1297 cleanup() 1298 _ = os.Setenv(envInt, "") 1299 _ = os.Setenv(envInt2, "1,1") 1300 type token struct { 1301 empty []uint32 `env:"ENV_INT"` 1302 filled []uint32 `env:"ENV_INT2, require=true"` 1303 protected []uint32 `env:"ENV_INT, protected=true"` 1304 doesntExists []uint32 `env:"ENV_INT3, default=[20,20]"` 1305 } 1306 1307 tok := &token{protected: []uint32{80, 80}} 1308 err := Bind(tok) 1309 assert.NoError(t, err) 1310 assert.Equal(t, []uint32{}, tok.empty) 1311 assert.Equal(t, []uint32{1, 1}, tok.filled) 1312 assert.Equal(t, []uint32{80, 80}, tok.protected) 1313 assert.Equal(t, []uint32{20, 20}, tok.doesntExists) 1314 } 1315 1316 func TestTypeUInt64Slice(t *testing.T) { 1317 cleanup() 1318 _ = os.Setenv(envInt, "") 1319 _ = os.Setenv(envInt2, "1,1") 1320 type token struct { 1321 empty []uint64 `env:"ENV_INT"` 1322 filled []uint64 `env:"ENV_INT2, require=true"` 1323 protected []uint64 `env:"ENV_INT, protected=true"` 1324 doesntExists []uint64 `env:"ENV_INT3, default=[20,20]"` 1325 } 1326 1327 tok := &token{protected: []uint64{80, 80}} 1328 err := Bind(tok) 1329 assert.NoError(t, err) 1330 assert.Equal(t, []uint64{}, tok.empty) 1331 assert.Equal(t, []uint64{1, 1}, tok.filled) 1332 assert.Equal(t, []uint64{80, 80}, tok.protected) 1333 assert.Equal(t, []uint64{20, 20}, tok.doesntExists) 1334 } 1335 1336 func TestTypeStringSlice(t *testing.T) { 1337 cleanup() 1338 _ = os.Setenv(envInt, "") 1339 _ = os.Setenv(envInt2, "1,1") 1340 type token struct { 1341 empty []string `env:"ENV_INT"` 1342 filled []string `env:"ENV_INT2, require=true"` 1343 protected []string `env:"ENV_INT, protected=true"` 1344 doesntExists []string `env:"ENV_INT3, default=[20,20]"` 1345 } 1346 1347 tok := &token{protected: []string{"80", "80"}} 1348 err := Bind(tok) 1349 assert.NoError(t, err) 1350 assert.Equal(t, []string{}, tok.empty) 1351 assert.Equal(t, []string{"1", "1"}, tok.filled) 1352 assert.Equal(t, []string{"80", "80"}, tok.protected) 1353 assert.Equal(t, []string{"20", "20"}, tok.doesntExists) 1354 } 1355 1356 func TestTypeBoolSlice(t *testing.T) { 1357 cleanup() 1358 _ = os.Setenv(envInt, "") 1359 _ = os.Setenv(envInt2, "1,1") 1360 type token struct { 1361 empty []bool `env:"ENV_INT"` 1362 filled []bool `env:"ENV_INT2, require=true"` 1363 protected []bool `env:"ENV_INT, protected=true"` 1364 doesntExists []bool `env:"ENV_INT3, default=[true,true]"` 1365 } 1366 1367 tok := &token{protected: []bool{true, true}} 1368 err := Bind(tok) 1369 assert.NoError(t, err) 1370 assert.Equal(t, []bool{}, tok.empty) 1371 assert.Equal(t, []bool{true, true}, tok.filled) 1372 assert.Equal(t, []bool{true, true}, tok.protected) 1373 assert.Equal(t, []bool{true, true}, tok.doesntExists) 1374 } 1375 1376 func TestPublicAPI(t *testing.T) { 1377 defer cleanup() 1378 _ = os.Setenv(envInt, "1") 1379 _ = os.Setenv(envString, "1") 1380 _ = os.Setenv(envBool, "1") 1381 _ = os.Setenv(envFloat64, "1") 1382 _ = os.Setenv(envIntSlice, "1") 1383 _ = os.Setenv(envStringSlice, "1") 1384 _ = os.Setenv(envBoolSlice, "1") 1385 _ = os.Setenv(envFloat64Slice, "1") 1386 const none = "none" 1387 var err error 1388 var fs []float64 1389 var bs []bool 1390 var ss []string 1391 var is []int 1392 1393 var f float64 1394 var b bool 1395 var i int 1396 var s string 1397 1398 fs, err = GetEnvAsArrayOfFloat64OrFallback(envFloat64Slice, []float64{20, 20}) 1399 assert.NoError(t, err) 1400 assert.Equal(t, []float64{1}, fs) 1401 fs, err = GetEnvAsArrayOfFloat64OrFallback(none, []float64{20, 20}) 1402 assert.NoError(t, err) 1403 assert.Equal(t, []float64{20, 20}, fs) 1404 1405 ss = GetEnvAsArrayOfStringsOrFallback(envStringSlice, []string{"20", "20"}) 1406 assert.Equal(t, []string{"1"}, ss) 1407 ss = GetEnvAsArrayOfStringsOrFallback(none, []string{"20", "20"}) 1408 assert.Equal(t, []string{"20", "20"}, ss) 1409 1410 bs, err = GetEnvAsArrayOfBoolOrFallback(envStringSlice, []bool{true, true}) 1411 assert.NoError(t, err) 1412 assert.Equal(t, []bool{true}, bs) 1413 bs, err = GetEnvAsArrayOfBoolOrFallback(none, []bool{true, true}) 1414 assert.NoError(t, err) 1415 assert.Equal(t, []bool{true, true}, bs) 1416 1417 is, err = GetEnvAsArrayOfIntsOrFallback(envIntSlice, []int{1, 1}) 1418 assert.NoError(t, err) 1419 assert.Equal(t, []int{1}, is) 1420 is, err = GetEnvAsArrayOfIntsOrFallback(none, []int{1, 1}) 1421 assert.NoError(t, err) 1422 assert.Equal(t, []int{1, 1}, is) 1423 1424 i, err = GetEnvAsIntOrFallback(envInt, 1) 1425 assert.NoError(t, err) 1426 assert.Equal(t, 1, i) 1427 i, err = GetEnvAsIntOrFallback(none, 1) 1428 assert.NoError(t, err) 1429 assert.Equal(t, 1, i) 1430 1431 b, err = GetEnvAsBoolOrFallback(envBool, true) 1432 assert.NoError(t, err) 1433 assert.Equal(t, true, b) 1434 b, err = GetEnvAsBoolOrFallback(none, true) 1435 assert.NoError(t, err) 1436 assert.Equal(t, true, b) 1437 1438 f, err = GetEnvAsFloat64OrFallback(envFloat64, 1) 1439 assert.NoError(t, err) 1440 assert.Equal(t, 1., f) 1441 f, err = GetEnvAsFloat64OrFallback(none, 1) 1442 assert.NoError(t, err) 1443 assert.Equal(t, 1., f) 1444 1445 s = GetEnvAsStringOrFallback(envString, "1") 1446 assert.Equal(t, "1", s) 1447 s = GetEnvAsStringOrFallback(none, "1") 1448 assert.Equal(t, "1", s) 1449 } 1450 1451 func TestEmptySlice(t *testing.T) { 1452 defer cleanup() 1453 type token struct { 1454 strSlice []string `env:"NONE"` 1455 strSlice2 []string `env:"NONE, default=[]"` 1456 intSlice []int `env:"NONE"` 1457 intSlice2 []int `env:"NONE, default=[]"` 1458 int8Slice []int8 `env:"NONE"` 1459 int8Slice2 []int8 `env:"NONE, default=[]"` 1460 int16Slice []int16 `env:"NONE"` 1461 int16Slice2 []int16 `env:"NONE, default=[]"` 1462 int32Slice []int32 `env:"NONE"` 1463 int32Slice2 []int32 `env:"NONE, default=[]"` 1464 int64Slice []int64 `env:"NONE"` 1465 int64Slice2 []int64 `env:"NONE, default=[]"` 1466 uintSlice []uint `env:"NONE"` 1467 uintSlice2 []uint `env:"NONE, default=[]"` 1468 uint8Slice []uint8 `env:"NONE"` 1469 uint8Slice2 []uint8 `env:"NONE, default=[]"` 1470 uint16Slice []uint16 `env:"NONE"` 1471 uint16Slice2 []uint16 `env:"NONE, default=[]"` 1472 uint32Slice []uint32 `env:"NONE"` 1473 uint32Slice2 []uint32 `env:"NONE, default=[]"` 1474 uint64Slice []uint64 `env:"NONE"` 1475 uint64Slice2 []uint64 `env:"NONE, default=[]"` 1476 float32Slice []float32 `env:"NONE"` 1477 float32Slice2 []float32 `env:"NONE, default=[]"` 1478 float64Slice []float64 `env:"NONE"` 1479 float64Slice2 []float64 `env:"NONE, default=[]"` 1480 boolSlice []bool `env:"NONE"` 1481 boolSlice2 []bool `env:"NONE, default=[]"` 1482 } 1483 tok := &token{} 1484 err := Bind(tok) 1485 assert.NoError(t, err) 1486 1487 assert.Nil(t, tok.strSlice) 1488 assert.Equal(t, []string{}, tok.strSlice2) 1489 1490 assert.Nil(t, tok.intSlice) 1491 assert.Equal(t, []int{}, tok.intSlice2) 1492 1493 assert.Nil(t, tok.int8Slice) 1494 assert.Equal(t, []int8{}, tok.int8Slice2) 1495 1496 assert.Nil(t, tok.int16Slice) 1497 assert.Equal(t, []int16{}, tok.int16Slice2) 1498 1499 assert.Nil(t, tok.int32Slice) 1500 assert.Equal(t, []int32{}, tok.int32Slice2) 1501 1502 assert.Nil(t, tok.int64Slice) 1503 assert.Equal(t, []int64{}, tok.int64Slice2) 1504 1505 assert.Nil(t, tok.uintSlice) 1506 assert.Equal(t, []uint{}, tok.uintSlice2) 1507 1508 assert.Nil(t, tok.uint8Slice) 1509 assert.Equal(t, []uint8{}, tok.uint8Slice2) 1510 1511 assert.Nil(t, tok.uint16Slice) 1512 assert.Equal(t, []uint16{}, tok.uint16Slice2) 1513 1514 assert.Nil(t, tok.uint32Slice) 1515 assert.Equal(t, []uint32{}, tok.uint32Slice2) 1516 1517 assert.Nil(t, tok.uint64Slice) 1518 assert.Equal(t, []uint64{}, tok.uint64Slice2) 1519 1520 assert.Nil(t, tok.float32Slice) 1521 assert.Equal(t, []float32{}, tok.float32Slice2) 1522 1523 assert.Nil(t, tok.float64Slice) 1524 assert.Equal(t, []float64{}, tok.float64Slice2) 1525 1526 assert.Nil(t, tok.boolSlice) 1527 assert.Equal(t, []bool{}, tok.boolSlice2) 1528 } 1529 1530 func setEnv(m map[string]string) { 1531 for k, v := range m { 1532 _ = os.Setenv(k, v) 1533 } 1534 } 1535 1536 const ( 1537 tokenID = "TOKEN_ID" 1538 tokenValue = "TOKEN_VALUE" 1539 tokenRatio = "TOKEN_RATIO" 1540 tokenReadOnly = "TOKEN_READONLY" 1541 tokenHours = "TOKEN_HOURS" 1542 tokenURLs = "TOKEN_URLS" 1543 tokenBools = "TOKEN_SWITCH" 1544 tokenCoordinates = "TOKEN_COORDINATES" 1545 1546 privateTokenValue = "PRIVATE_TOKEN_VALUE" 1547 // #nosec G101; 1548 exportedTokenValue = "EXPORTED_TOKEN_VALUE" 1549 privateExportedTokenValue = "PRIVATE_EXPORTED_TOKEN_VALUE" 1550 1551 primaryEndpointURL = "PRIMARY_ENDPOINT_URL" 1552 failoverEndpointURL = "FAILOVER_ENDPOINT_URL" 1553 name = "NAME" 1554 defaultPort = "PORT" 1555 accessKeyID = "ACCESS_KEY_ID" 1556 secretAccessKey = "SECRET_ACCESS_KEY" 1557 1558 envInt = "ENV_INT" 1559 envInt2 = "ENV_INT2" 1560 envString = "ENV_STRING" 1561 envStringSlice = "ENV_STRING_SLICE" 1562 envBool = "ENV_BOOL" 1563 envBoolSlice = "ENV_BOOL_SLICE" 1564 envFloat64 = "ENV_FLOAT64" 1565 envFloat64Slice = "ENV_FLOAT64_SLICE" 1566 envStringPrivate = "ENV_STRING_PRIVATE" 1567 envStringExported = "ENV_STRING_EXPORTED" 1568 envIntSlice = "ENV_INT_SLICE" 1569 ) 1570 1571 func cleanup() { 1572 _ = os.Unsetenv(tokenID) 1573 _ = os.Unsetenv(tokenValue) 1574 _ = os.Unsetenv(tokenRatio) 1575 _ = os.Unsetenv(tokenReadOnly) 1576 _ = os.Unsetenv(tokenHours) 1577 _ = os.Unsetenv(tokenURLs) 1578 _ = os.Unsetenv(tokenBools) 1579 _ = os.Unsetenv(tokenCoordinates) 1580 1581 _ = os.Unsetenv(privateTokenValue) 1582 _ = os.Unsetenv(privateExportedTokenValue) 1583 _ = os.Unsetenv(exportedTokenValue) 1584 1585 _ = os.Unsetenv(primaryEndpointURL) 1586 _ = os.Unsetenv(failoverEndpointURL) 1587 _ = os.Unsetenv(name) 1588 _ = os.Unsetenv(defaultPort) 1589 _ = os.Unsetenv(accessKeyID) 1590 _ = os.Unsetenv(secretAccessKey) 1591 1592 _ = os.Unsetenv(envInt) 1593 _ = os.Unsetenv(envString) 1594 _ = os.Unsetenv(envBool) 1595 _ = os.Unsetenv(envBoolSlice) 1596 _ = os.Unsetenv(envStringPrivate) 1597 _ = os.Unsetenv(envStringExported) 1598 _ = os.Unsetenv(envIntSlice) 1599 _ = os.Unsetenv(envFloat64) 1600 _ = os.Unsetenv(envFloat64Slice) 1601 }