pkg.re/essentialkaos/ek.10@v12.41.0+incompatible/options/options_test.go (about) 1 package options 2 3 // ////////////////////////////////////////////////////////////////////////////////// // 4 // // 5 // Copyright (c) 2022 ESSENTIAL KAOS // 6 // Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0> // 7 // // 8 // ////////////////////////////////////////////////////////////////////////////////// // 9 10 import ( 11 "strings" 12 "testing" 13 14 . "pkg.re/essentialkaos/check.v1" 15 ) 16 17 // ////////////////////////////////////////////////////////////////////////////////// // 18 19 func Test(t *testing.T) { TestingT(t) } 20 21 type OptUtilSuite struct{} 22 23 // ////////////////////////////////////////////////////////////////////////////////// // 24 25 var _ = Suite(&OptUtilSuite{}) 26 27 // ////////////////////////////////////////////////////////////////////////////////// // 28 29 func (s *OptUtilSuite) TestAdd(c *C) { 30 opts := &Options{} 31 32 c.Assert(opts.Add("", &V{}), NotNil) 33 c.Assert(opts.Add("t:", &V{}), NotNil) 34 35 c.Assert(opts.Add("test", &V{}), IsNil) 36 c.Assert(opts.Add(":test1", &V{}), IsNil) 37 c.Assert(opts.Add("t:test2", &V{}), IsNil) 38 39 c.Assert(opts.Add("t1:test", &V{}), NotNil) 40 c.Assert(opts.Add("t:test3", &V{}), NotNil) 41 c.Assert(opts.Add("t:test3", nil), NotNil) 42 } 43 44 func (s *OptUtilSuite) TestAddMap(c *C) { 45 opts := NewOptions() 46 47 m1 := Map{"": {}} 48 m2 := Map{"t:": {}} 49 50 c.Assert(opts.AddMap(m1), Not(HasLen), 0) 51 c.Assert(opts.AddMap(m2), Not(HasLen), 0) 52 53 m3 := Map{"test": {}} 54 m4 := Map{"t:test2": {}} 55 56 c.Assert(opts.AddMap(m3), HasLen, 0) 57 c.Assert(opts.AddMap(m4), HasLen, 0) 58 59 m5 := Map{ 60 "t:test": {}, 61 "T:test1": {}, 62 "t:test2": {}, 63 } 64 65 c.Assert(opts.AddMap(m5), HasLen, 2) 66 } 67 68 func (s *OptUtilSuite) TestGlobal(c *C) { 69 long, short := ParseOptionName("t:test") 70 71 c.Assert(short, Equals, "t") 72 c.Assert(long, Equals, "test") 73 74 c.Assert(GetS("s:string"), Equals, "") 75 c.Assert(GetI("i:int"), Equals, 0) 76 c.Assert(GetF("f:float"), Equals, 0.0) 77 c.Assert(GetB("b:bool"), Equals, false) 78 c.Assert(Has("s:string"), Equals, false) 79 80 c.Assert(Add("t:test", &V{}), IsNil) 81 82 global = nil 83 84 c.Assert(AddMap(Map{}), IsNil) 85 86 global = nil 87 88 Parse(Map{}) 89 90 global = NewOptions() 91 92 _, errs := global.Parse( 93 strings.Split("-s Test -i 123 -f 100.5 -b", " "), 94 Map{ 95 "s:string": {}, 96 "i:int": {Type: INT}, 97 "f:float": {Type: FLOAT}, 98 "b:bool": {Type: BOOL}, 99 }, 100 ) 101 102 c.Assert(errs, HasLen, 0) 103 104 c.Assert(Has("s:string"), Equals, true) 105 c.Assert(Has("string1"), Equals, false) 106 c.Assert(GetS("s:string"), Equals, "Test") 107 c.Assert(GetI("i:int"), Equals, 123) 108 c.Assert(GetF("f:float"), Equals, 100.5) 109 c.Assert(GetB("b:bool"), Equals, true) 110 } 111 112 func (s *OptUtilSuite) TestLimiters(c *C) { 113 argline := "--int1 1 --int2 5 --int3 10 --float1 1.0 --float2 5.0 --float3 10.0" 114 115 optMap := Map{ 116 "int1": {Type: INT, Min: 3, Max: 7}, 117 "int2": {Type: INT, Min: 3, Max: 7}, 118 "int3": {Type: INT, Min: 3, Max: 7}, 119 "float1": {Type: FLOAT, Min: 3.0, Max: 7.0}, 120 "float2": {Type: FLOAT, Min: 3.0, Max: 7.0}, 121 "float3": {Type: FLOAT, Min: 3.0, Max: 7.0}, 122 } 123 124 opts := NewOptions() 125 opts.Parse(strings.Split(argline, " "), optMap) 126 127 c.Assert(opts.GetI("int1"), Equals, 3) 128 c.Assert(opts.GetI("int2"), Equals, 5) 129 c.Assert(opts.GetI("int3"), Equals, 7) 130 c.Assert(opts.GetF("float1"), Equals, 3.0) 131 c.Assert(opts.GetF("float2"), Equals, 5.0) 132 c.Assert(opts.GetF("float3"), Equals, 7.0) 133 } 134 135 func (s *OptUtilSuite) TestConflicts(c *C) { 136 argline := "--test1 abc --test2 123" 137 138 optMap := Map{ 139 "test1": {Conflicts: "test2"}, 140 "test2": {}, 141 } 142 143 opts := NewOptions() 144 _, errs := opts.Parse(strings.Split(argline, " "), optMap) 145 146 c.Assert(errs, Not(HasLen), 0) 147 c.Assert(errs[0].(OptionError).Type, Equals, ERROR_CONFLICT) 148 c.Assert(errs[0].Error(), Equals, "Option test1 conflicts with option test2") 149 150 argline = "--test0 xyz" 151 152 optMap = Map{ 153 "test0": {}, 154 "test1": {Conflicts: "test2"}, 155 "test2": {}, 156 } 157 158 opts = NewOptions() 159 _, errs = opts.Parse(strings.Split(argline, " "), optMap) 160 161 c.Assert(errs, HasLen, 0) 162 } 163 164 func (s *OptUtilSuite) TestBound(c *C) { 165 argline := "--test1 abc" 166 167 optMap := Map{ 168 "test1": {Bound: "test2"}, 169 "test2": {}, 170 } 171 172 opts := NewOptions() 173 _, errs := opts.Parse(strings.Split(argline, " "), optMap) 174 175 c.Assert(errs, Not(HasLen), 0) 176 c.Assert(errs[0].(OptionError).Type, Equals, ERROR_BOUND_NOT_SET) 177 c.Assert(errs[0].Error(), Equals, "Option test2 must be defined with option test1") 178 179 argline = "--test0 xyz" 180 181 optMap = Map{ 182 "test0": {}, 183 "test1": {Bound: "test2"}, 184 "test2": {}, 185 } 186 187 opts = NewOptions() 188 _, errs = opts.Parse(strings.Split(argline, " "), optMap) 189 190 c.Assert(errs, HasLen, 0) 191 } 192 193 func (s *OptUtilSuite) TestGetters(c *C) { 194 argline := "file.mp3 -s STRING --required TEST -i 320 -b -f 1.098765 -S2 100 -f1 5 -f2 1 -ms ABC --merg-string DEF -mi 6 --merg-int 6 -f3 12 -mf 10.1 -mf 10.1 -i1 5" 195 196 optMap := Map{ 197 "s:string": {Type: STRING, Value: "STRING"}, 198 "S:empty-string": {Type: STRING}, 199 "r:required": {Required: true, Alias: "A:alias"}, 200 "i:int": {Type: INT}, 201 "i1:int-between": {Type: INT, Min: 1, Max: 3}, 202 "I:not-set-int": {Type: INT, Value: 0}, 203 "b:bool": {Type: BOOL}, 204 "B:empty-bool": {Type: BOOL}, 205 "B1:not-set-bool": {Type: BOOL, Value: false}, 206 "f:float": {Type: FLOAT}, 207 "F:not-set-float": {Type: FLOAT, Value: 0.0}, 208 "f1:float-max": {Type: FLOAT, Max: 3.0}, 209 "f2:float-min": {Type: FLOAT, Min: 3.0}, 210 "f3:float-between": {Type: FLOAT, Min: 3.0, Max: 10.0}, 211 "ms:merg-string": {Mergeble: true}, 212 "mi:merg-int": {Type: INT, Mergeble: true}, 213 "mf:merg-float": {Type: FLOAT, Mergeble: true}, 214 "S1:not-set-string": {Type: STRING, Value: ""}, 215 "S2:string-as-num": {Type: STRING}, 216 "M:mixed": {Type: MIXED}, 217 } 218 219 opts := NewOptions() 220 opts.Parse(strings.Split(argline, " "), optMap) 221 222 c.Assert(opts.GetS("_not_exist_"), Equals, "") 223 c.Assert(opts.GetI("_not_exist_"), Equals, 0) 224 c.Assert(opts.GetB("_not_exist_"), Equals, false) 225 c.Assert(opts.GetF("_not_exist_"), Equals, 0.0) 226 227 c.Assert(opts.GetS("s:string"), Equals, "STRING") 228 c.Assert(opts.GetS("string"), Equals, "STRING") 229 c.Assert(opts.GetS("S:empty-string"), Equals, "") 230 c.Assert(opts.GetS("empty-string"), Equals, "") 231 c.Assert(opts.GetB("string"), Equals, true) 232 c.Assert(opts.GetI("string"), Equals, 0) 233 c.Assert(opts.GetF("string"), Equals, 0.0) 234 c.Assert(opts.GetB("empty-string"), Equals, false) 235 c.Assert(opts.GetI("empty-string"), Equals, 0) 236 c.Assert(opts.GetF("empty-string"), Equals, 0.0) 237 c.Assert(opts.GetB("not-set-string"), Equals, false) 238 c.Assert(opts.GetI("not-set-string"), Equals, 0) 239 c.Assert(opts.GetF("not-set-string"), Equals, 0.0) 240 c.Assert(opts.GetS("S2:string-as-num"), Equals, "100") 241 c.Assert(opts.GetB("S2:string-as-num"), Equals, true) 242 c.Assert(opts.GetI("S2:string-as-num"), Equals, 100) 243 c.Assert(opts.GetF("S2:string-as-num"), Equals, 100.0) 244 245 c.Assert(opts.GetS("r:required"), Equals, "TEST") 246 c.Assert(opts.GetS("required"), Equals, "TEST") 247 c.Assert(opts.GetS("A:alias"), Equals, "TEST") 248 c.Assert(opts.GetS("alias"), Equals, "TEST") 249 250 c.Assert(opts.GetS("int"), Equals, "320") 251 c.Assert(opts.GetB("int"), Equals, true) 252 c.Assert(opts.GetI("int"), Equals, 320) 253 c.Assert(opts.GetF("int"), Equals, 320.0) 254 c.Assert(opts.GetI("int-between"), Equals, 3) 255 c.Assert(opts.GetS("not-set-int"), Equals, "0") 256 c.Assert(opts.GetB("not-set-int"), Equals, false) 257 c.Assert(opts.GetI("not-set-int"), Equals, 0) 258 c.Assert(opts.GetF("not-set-int"), Equals, 0.0) 259 260 c.Assert(opts.GetS("b:bool"), Equals, "true") 261 c.Assert(opts.GetI("b:bool"), Equals, 1) 262 c.Assert(opts.GetB("b:bool"), Equals, true) 263 c.Assert(opts.GetF("b:bool"), Equals, 1.0) 264 c.Assert(opts.GetS("empty-bool"), Equals, "") 265 c.Assert(opts.GetI("empty-bool"), Equals, 0) 266 c.Assert(opts.GetB("empty-bool"), Equals, false) 267 c.Assert(opts.GetF("empty-bool"), Equals, 0.0) 268 c.Assert(opts.GetS("not-set-bool"), Equals, "false") 269 c.Assert(opts.GetI("not-set-bool"), Equals, 0) 270 c.Assert(opts.GetB("not-set-bool"), Equals, false) 271 c.Assert(opts.GetF("not-set-bool"), Equals, 0.0) 272 273 c.Assert(opts.GetS("float"), Equals, "1.098765") 274 c.Assert(opts.GetB("float"), Equals, true) 275 c.Assert(opts.GetI("float"), Equals, 1) 276 c.Assert(opts.GetF("float"), Equals, 1.098765) 277 c.Assert(opts.GetS("not-set-float"), Equals, "0") 278 c.Assert(opts.GetB("not-set-float"), Equals, false) 279 c.Assert(opts.GetI("not-set-float"), Equals, 0) 280 c.Assert(opts.GetF("not-set-float"), Equals, 0.0) 281 282 c.Assert(opts.GetF("float-max"), Equals, 3.0) 283 c.Assert(opts.GetF("float-min"), Equals, 3.0) 284 c.Assert(opts.GetF("float-between"), Equals, 10.0) 285 286 c.Assert(opts.GetS("merg-string"), Equals, "ABC DEF") 287 c.Assert(opts.GetI("merg-int"), Equals, 12) 288 c.Assert(opts.GetF("merg-float"), Equals, 20.2) 289 290 c.Assert(opts.Has("_not_exist_"), Equals, false) 291 c.Assert(opts.Has("empty-string"), Equals, false) 292 c.Assert(opts.Has("s:string"), Equals, true) 293 } 294 295 func (s *OptUtilSuite) TestMixed(c *C) { 296 optMap := Map{ 297 "M:mixed": {Type: MIXED}, 298 "t:test": {}, 299 } 300 301 argline := "-M -t 123" 302 opts := NewOptions() 303 opts.Parse(strings.Split(argline, " "), optMap) 304 305 c.Assert(opts.Has("M:mixed"), Equals, true) 306 c.Assert(opts.GetS("M:mixed"), Equals, "true") 307 c.Assert(opts.GetS("t:test"), Equals, "123") 308 309 argline = "-M TEST123 --test 123" 310 opts = NewOptions() 311 opts.Parse(strings.Split(argline, " "), optMap) 312 313 c.Assert(opts.Has("M:mixed"), Equals, true) 314 c.Assert(opts.GetS("M:mixed"), Equals, "TEST123") 315 c.Assert(opts.GetS("t:test"), Equals, "123") 316 317 argline = "--test 123 -M" 318 opts = NewOptions() 319 opts.Parse(strings.Split(argline, " "), optMap) 320 321 c.Assert(opts.Has("M:mixed"), Equals, true) 322 c.Assert(opts.GetS("M:mixed"), Equals, "true") 323 c.Assert(opts.GetS("t:test"), Equals, "123") 324 } 325 326 func (s *OptUtilSuite) TestParsing(c *C) { 327 _, errs := NewOptions().Parse([]string{}, Map{}) 328 329 c.Assert(errs, HasLen, 0) 330 331 // //////////////////////////////////////////////////////////////////////////////// // 332 333 _, errs = NewOptions().Parse([]string{"--test", "100"}, Map{"t:test": {Type: 10}}) 334 335 c.Assert(errs, Not(HasLen), 0) 336 c.Assert(errs[0].Error(), Equals, "Option --test has unsupported type") 337 338 // //////////////////////////////////////////////////////////////////////////////// // 339 340 _, errs = NewOptions().Parse([]string{}, Map{"s:string": {}, "s:trace": {}}) 341 342 c.Assert(errs, Not(HasLen), 0) 343 c.Assert(errs[0].Error(), Equals, "Option -s defined 2 or more times") 344 345 // //////////////////////////////////////////////////////////////////////////////// // 346 347 _, errs = NewOptions().Parse([]string{"-t"}, Map{"s:string": {}}) 348 349 c.Assert(errs, Not(HasLen), 0) 350 c.Assert(errs[0].Error(), Equals, "Option -t is not supported") 351 352 // //////////////////////////////////////////////////////////////////////////////// // 353 354 _, errs = NewOptions().Parse([]string{"-t=100"}, Map{"s:string": {}}) 355 356 c.Assert(errs, Not(HasLen), 0) 357 c.Assert(errs[0].Error(), Equals, "Option -t is not supported") 358 359 // //////////////////////////////////////////////////////////////////////////////// // 360 361 _, errs = NewOptions().Parse([]string{"--test"}, Map{"s:string": {}}) 362 363 c.Assert(errs, Not(HasLen), 0) 364 c.Assert(errs[0].Error(), Equals, "Option --test is not supported") 365 366 // //////////////////////////////////////////////////////////////////////////////// // 367 368 fArgs, errs := NewOptions().Parse([]string{"-", "--"}, Map{"t:test": {}}) 369 370 c.Assert(errs, HasLen, 0) 371 c.Assert(fArgs, DeepEquals, Arguments{"-", "--"}) 372 373 // //////////////////////////////////////////////////////////////////////////////// // 374 375 _, errs = NewOptions().Parse([]string{"--asd="}, Map{"t:test": {}}) 376 377 c.Assert(errs, Not(HasLen), 0) 378 c.Assert(errs[0].Error(), Equals, "Option --asd has wrong format") 379 380 // //////////////////////////////////////////////////////////////////////////////// // 381 382 _, errs = NewOptions().Parse([]string{"-j="}, Map{"t:test": {}}) 383 384 c.Assert(errs, Not(HasLen), 0) 385 c.Assert(errs[0].Error(), Equals, "Option -j has wrong format") 386 387 // //////////////////////////////////////////////////////////////////////////////// // 388 389 _, errs = NewOptions().Parse([]string{}, Map{"t:test": {Required: true}}) 390 391 c.Assert(errs, Not(HasLen), 0) 392 c.Assert(errs[0].Error(), Equals, "Required option test is not set") 393 394 // //////////////////////////////////////////////////////////////////////////////// // 395 396 _, errs = NewOptions().Parse([]string{"-t"}, Map{"t:test": {}}) 397 398 c.Assert(errs, Not(HasLen), 0) 399 c.Assert(errs[0].Error(), Equals, "Non-boolean option --test is empty") 400 401 // //////////////////////////////////////////////////////////////////////////////// // 402 403 _, errs = NewOptions().Parse([]string{"--test=!"}, Map{"t:test": {Type: FLOAT}}) 404 405 c.Assert(errs, Not(HasLen), 0) 406 c.Assert(errs[0].Error(), Equals, "Option --test has wrong format") 407 408 // //////////////////////////////////////////////////////////////////////////////// // 409 410 _, errs = NewOptions().Parse([]string{"-t=!"}, Map{"t:test": {Type: INT}}) 411 412 c.Assert(errs, Not(HasLen), 0) 413 c.Assert(errs[0].Error(), Equals, "Option --test has wrong format") 414 415 // //////////////////////////////////////////////////////////////////////////////// // 416 417 _, errs = NewOptions().Parse([]string{"--test", "!"}, Map{"t:test": {Type: INT}}) 418 419 c.Assert(errs, Not(HasLen), 0) 420 c.Assert(errs[0].Error(), Equals, "Option --test has wrong format") 421 422 // //////////////////////////////////////////////////////////////////////////////// // 423 424 _, errs = NewOptions().Parse([]string{}, Map{"t:test": nil}) 425 426 c.Assert(errs, Not(HasLen), 0) 427 c.Assert(errs[0].Error(), Equals, "Struct for option --test is nil") 428 429 // //////////////////////////////////////////////////////////////////////////////// // 430 431 _, errs = NewOptions().Parse([]string{}, Map{"t:test": {Value: []string{}}}) 432 433 c.Assert(errs, Not(HasLen), 0) 434 c.Assert(errs[0].Error(), Equals, "Option test contains unsupported default value") 435 436 // //////////////////////////////////////////////////////////////////////////////// // 437 438 _, errs = NewOptions().Parse([]string{}, Map{"": {}}) 439 440 c.Assert(errs, Not(HasLen), 0) 441 c.Assert(errs[0].Error(), Equals, "Some option does not have a name") 442 } 443 444 func (s *OptUtilSuite) TestMerging(c *C) { 445 c.Assert(Q(), Equals, "") 446 c.Assert(Q("test"), Equals, "test") 447 c.Assert(Q("test1", "test2"), Equals, "test1 test2") 448 } 449 450 func (s *OptUtilSuite) TestGuessType(c *C) { 451 c.Assert(guessType(nil), Equals, STRING) 452 c.Assert(guessType("test"), Equals, STRING) 453 c.Assert(guessType(4), Equals, INT) 454 c.Assert(guessType(true), Equals, BOOL) 455 c.Assert(guessType(3.3), Equals, FLOAT) 456 } 457 458 func (s *OptUtilSuite) TestArguments(c *C) { 459 a := Arguments([]string{"test", "6", "2.67", "true"}) 460 461 c.Assert(a.Has(1), Equals, true) 462 c.Assert(a.Has(9), Equals, false) 463 464 c.Assert(a.Get(0), Equals, "test") 465 c.Assert(a.Get(1), Equals, "6") 466 c.Assert(a.Get(2), Equals, "2.67") 467 c.Assert(a.Get(3), Equals, "true") 468 c.Assert(a.Get(4), Equals, "") 469 470 iv, err := a.GetI(0) 471 c.Assert(err, NotNil) 472 c.Assert(iv, Equals, 0) 473 iv, err = a.GetI(1) 474 c.Assert(err, IsNil) 475 c.Assert(iv, Equals, 6) 476 477 fv, err := a.GetF(0) 478 c.Assert(err, NotNil) 479 c.Assert(fv, Equals, 0.0) 480 fv, err = a.GetF(2) 481 c.Assert(err, IsNil) 482 c.Assert(fv, Equals, 2.67) 483 484 a = Arguments([]string{"true", "yes", "y", "1", "false", "no", "n", "0", "", "TEST"}) 485 486 bv, err := a.GetB(0) 487 c.Assert(err, IsNil) 488 c.Assert(bv, Equals, true) 489 bv, err = a.GetB(1) 490 c.Assert(err, IsNil) 491 c.Assert(bv, Equals, true) 492 bv, err = a.GetB(2) 493 c.Assert(err, IsNil) 494 c.Assert(bv, Equals, true) 495 bv, err = a.GetB(3) 496 c.Assert(err, IsNil) 497 c.Assert(bv, Equals, true) 498 bv, err = a.GetB(4) 499 c.Assert(err, IsNil) 500 c.Assert(bv, Equals, false) 501 bv, err = a.GetB(5) 502 c.Assert(err, IsNil) 503 c.Assert(bv, Equals, false) 504 bv, err = a.GetB(6) 505 c.Assert(err, IsNil) 506 c.Assert(bv, Equals, false) 507 bv, err = a.GetB(7) 508 c.Assert(err, IsNil) 509 c.Assert(bv, Equals, false) 510 bv, err = a.GetB(8) 511 c.Assert(err, IsNil) 512 c.Assert(bv, Equals, false) 513 bv, err = a.GetB(9) 514 c.Assert(err, NotNil) 515 c.Assert(bv, Equals, false) 516 }