1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5from __future__ import absolute_import, print_function, unicode_literals 6 7import unittest 8 9from mozunit import main 10 11from mozbuild.configure.options import ( 12 CommandLineHelper, 13 ConflictingOptionError, 14 InvalidOptionError, 15 NegativeOptionValue, 16 Option, 17 OptionValue, 18 PositiveOptionValue, 19) 20 21 22class Option(Option): 23 def __init__(self, *args, **kwargs): 24 kwargs["help"] = "Dummy help" 25 super(Option, self).__init__(*args, **kwargs) 26 27 28class TestOption(unittest.TestCase): 29 def test_option(self): 30 option = Option("--option") 31 self.assertEquals(option.prefix, "") 32 self.assertEquals(option.name, "option") 33 self.assertEquals(option.env, None) 34 self.assertFalse(option.default) 35 36 option = Option("--enable-option") 37 self.assertEquals(option.prefix, "enable") 38 self.assertEquals(option.name, "option") 39 self.assertEquals(option.env, None) 40 self.assertFalse(option.default) 41 42 option = Option("--disable-option") 43 self.assertEquals(option.prefix, "disable") 44 self.assertEquals(option.name, "option") 45 self.assertEquals(option.env, None) 46 self.assertTrue(option.default) 47 48 option = Option("--with-option") 49 self.assertEquals(option.prefix, "with") 50 self.assertEquals(option.name, "option") 51 self.assertEquals(option.env, None) 52 self.assertFalse(option.default) 53 54 option = Option("--without-option") 55 self.assertEquals(option.prefix, "without") 56 self.assertEquals(option.name, "option") 57 self.assertEquals(option.env, None) 58 self.assertTrue(option.default) 59 60 option = Option("--without-option-foo", env="MOZ_OPTION") 61 self.assertEquals(option.env, "MOZ_OPTION") 62 63 option = Option(env="MOZ_OPTION") 64 self.assertEquals(option.prefix, "") 65 self.assertEquals(option.name, None) 66 self.assertEquals(option.env, "MOZ_OPTION") 67 self.assertFalse(option.default) 68 69 with self.assertRaises(InvalidOptionError) as e: 70 Option("--option", nargs=0, default=("a",)) 71 self.assertEquals( 72 str(e.exception), "The given `default` doesn't satisfy `nargs`" 73 ) 74 75 with self.assertRaises(InvalidOptionError) as e: 76 Option("--option", nargs=1, default=()) 77 self.assertEquals( 78 str(e.exception), "default must be a bool, a string or a tuple of strings" 79 ) 80 81 with self.assertRaises(InvalidOptionError) as e: 82 Option("--option", nargs=1, default=True) 83 self.assertEquals( 84 str(e.exception), "The given `default` doesn't satisfy `nargs`" 85 ) 86 87 with self.assertRaises(InvalidOptionError) as e: 88 Option("--option", nargs=1, default=("a", "b")) 89 self.assertEquals( 90 str(e.exception), "The given `default` doesn't satisfy `nargs`" 91 ) 92 93 with self.assertRaises(InvalidOptionError) as e: 94 Option("--option", nargs=2, default=()) 95 self.assertEquals( 96 str(e.exception), "default must be a bool, a string or a tuple of strings" 97 ) 98 99 with self.assertRaises(InvalidOptionError) as e: 100 Option("--option", nargs=2, default=True) 101 self.assertEquals( 102 str(e.exception), "The given `default` doesn't satisfy `nargs`" 103 ) 104 105 with self.assertRaises(InvalidOptionError) as e: 106 Option("--option", nargs=2, default=("a",)) 107 self.assertEquals( 108 str(e.exception), "The given `default` doesn't satisfy `nargs`" 109 ) 110 111 with self.assertRaises(InvalidOptionError) as e: 112 Option("--option", nargs="?", default=("a", "b")) 113 self.assertEquals( 114 str(e.exception), "The given `default` doesn't satisfy `nargs`" 115 ) 116 117 with self.assertRaises(InvalidOptionError) as e: 118 Option("--option", nargs="+", default=()) 119 self.assertEquals( 120 str(e.exception), "default must be a bool, a string or a tuple of strings" 121 ) 122 123 with self.assertRaises(InvalidOptionError) as e: 124 Option("--option", nargs="+", default=True) 125 self.assertEquals( 126 str(e.exception), "The given `default` doesn't satisfy `nargs`" 127 ) 128 129 # --disable options with a nargs value that requires at least one 130 # argument need to be given a default. 131 with self.assertRaises(InvalidOptionError) as e: 132 Option("--disable-option", nargs=1) 133 self.assertEquals( 134 str(e.exception), "The given `default` doesn't satisfy `nargs`" 135 ) 136 137 with self.assertRaises(InvalidOptionError) as e: 138 Option("--disable-option", nargs="+") 139 self.assertEquals( 140 str(e.exception), "The given `default` doesn't satisfy `nargs`" 141 ) 142 143 # Test nargs inference from default value 144 option = Option("--with-foo", default=True) 145 self.assertEquals(option.nargs, 0) 146 147 option = Option("--with-foo", default=False) 148 self.assertEquals(option.nargs, 0) 149 150 option = Option("--with-foo", default="a") 151 self.assertEquals(option.nargs, "?") 152 153 option = Option("--with-foo", default=("a",)) 154 self.assertEquals(option.nargs, "?") 155 156 option = Option("--with-foo", default=("a", "b")) 157 self.assertEquals(option.nargs, "*") 158 159 option = Option(env="FOO", default=True) 160 self.assertEquals(option.nargs, 0) 161 162 option = Option(env="FOO", default=False) 163 self.assertEquals(option.nargs, 0) 164 165 option = Option(env="FOO", default="a") 166 self.assertEquals(option.nargs, "?") 167 168 option = Option(env="FOO", default=("a",)) 169 self.assertEquals(option.nargs, "?") 170 171 option = Option(env="FOO", default=("a", "b")) 172 self.assertEquals(option.nargs, "*") 173 174 def test_option_option(self): 175 for option in ( 176 "--option", 177 "--enable-option", 178 "--disable-option", 179 "--with-option", 180 "--without-option", 181 ): 182 self.assertEquals(Option(option).option, option) 183 self.assertEquals(Option(option, env="FOO").option, option) 184 185 opt = Option(option, default=False) 186 self.assertEquals( 187 opt.option, 188 option.replace("-disable-", "-enable-").replace("-without-", "-with-"), 189 ) 190 191 opt = Option(option, default=True) 192 self.assertEquals( 193 opt.option, 194 option.replace("-enable-", "-disable-").replace("-with-", "-without-"), 195 ) 196 197 self.assertEquals(Option(env="FOO").option, "FOO") 198 199 def test_option_choices(self): 200 with self.assertRaises(InvalidOptionError) as e: 201 Option("--option", nargs=3, choices=("a", "b")) 202 self.assertEquals(str(e.exception), "Not enough `choices` for `nargs`") 203 204 with self.assertRaises(InvalidOptionError) as e: 205 Option("--without-option", nargs=1, choices=("a", "b")) 206 self.assertEquals( 207 str(e.exception), "A `default` must be given along with `choices`" 208 ) 209 210 with self.assertRaises(InvalidOptionError) as e: 211 Option("--without-option", nargs="+", choices=("a", "b")) 212 self.assertEquals( 213 str(e.exception), "A `default` must be given along with `choices`" 214 ) 215 216 with self.assertRaises(InvalidOptionError) as e: 217 Option("--without-option", default="c", choices=("a", "b")) 218 self.assertEquals( 219 str(e.exception), "The `default` value must be one of 'a', 'b'" 220 ) 221 222 with self.assertRaises(InvalidOptionError) as e: 223 Option( 224 "--without-option", 225 default=( 226 "a", 227 "c", 228 ), 229 choices=("a", "b"), 230 ) 231 self.assertEquals( 232 str(e.exception), "The `default` value must be one of 'a', 'b'" 233 ) 234 235 with self.assertRaises(InvalidOptionError) as e: 236 Option("--without-option", default=("c",), choices=("a", "b")) 237 self.assertEquals( 238 str(e.exception), "The `default` value must be one of 'a', 'b'" 239 ) 240 241 option = Option("--with-option", nargs="+", choices=("a", "b")) 242 with self.assertRaises(InvalidOptionError) as e: 243 option.get_value("--with-option=c") 244 self.assertEquals(str(e.exception), "'c' is not one of 'a', 'b'") 245 246 value = option.get_value("--with-option=b,a") 247 self.assertTrue(value) 248 self.assertEquals(PositiveOptionValue(("b", "a")), value) 249 250 option = Option("--without-option", nargs="*", default="a", choices=("a", "b")) 251 with self.assertRaises(InvalidOptionError) as e: 252 option.get_value("--with-option=c") 253 self.assertEquals(str(e.exception), "'c' is not one of 'a', 'b'") 254 255 value = option.get_value("--with-option=b,a") 256 self.assertTrue(value) 257 self.assertEquals(PositiveOptionValue(("b", "a")), value) 258 259 # Test nargs inference from choices 260 option = Option("--with-option", choices=("a", "b")) 261 self.assertEqual(option.nargs, 1) 262 263 # Test "relative" values 264 option = Option( 265 "--with-option", nargs="*", default=("b", "c"), choices=("a", "b", "c", "d") 266 ) 267 268 value = option.get_value("--with-option=+d") 269 self.assertEquals(PositiveOptionValue(("b", "c", "d")), value) 270 271 value = option.get_value("--with-option=-b") 272 self.assertEquals(PositiveOptionValue(("c",)), value) 273 274 value = option.get_value("--with-option=-b,+d") 275 self.assertEquals(PositiveOptionValue(("c", "d")), value) 276 277 # Adding something that is in the default is fine 278 value = option.get_value("--with-option=+b") 279 self.assertEquals(PositiveOptionValue(("b", "c")), value) 280 281 # Removing something that is not in the default is fine, as long as it 282 # is one of the choices 283 value = option.get_value("--with-option=-a") 284 self.assertEquals(PositiveOptionValue(("b", "c")), value) 285 286 with self.assertRaises(InvalidOptionError) as e: 287 option.get_value("--with-option=-e") 288 self.assertEquals(str(e.exception), "'e' is not one of 'a', 'b', 'c', 'd'") 289 290 # Other "not a choice" errors. 291 with self.assertRaises(InvalidOptionError) as e: 292 option.get_value("--with-option=+e") 293 self.assertEquals(str(e.exception), "'e' is not one of 'a', 'b', 'c', 'd'") 294 295 with self.assertRaises(InvalidOptionError) as e: 296 option.get_value("--with-option=e") 297 self.assertEquals(str(e.exception), "'e' is not one of 'a', 'b', 'c', 'd'") 298 299 def test_option_value_compare(self): 300 # OptionValue are tuple and equivalence should compare as tuples. 301 val = PositiveOptionValue(("foo",)) 302 303 self.assertEqual(val[0], "foo") 304 self.assertEqual(val, PositiveOptionValue(("foo",))) 305 self.assertNotEqual(val, PositiveOptionValue(("foo", "bar"))) 306 307 # Can compare a tuple to an OptionValue. 308 self.assertEqual(val, ("foo",)) 309 self.assertNotEqual(val, ("foo", "bar")) 310 311 # Different OptionValue types are never equal. 312 self.assertNotEqual(val, OptionValue(("foo",))) 313 314 # For usability reasons, we raise TypeError when attempting to compare 315 # against a non-tuple. 316 with self.assertRaisesRegexp(TypeError, "cannot compare a"): 317 val == "foo" 318 319 # But we allow empty option values to compare otherwise we can't 320 # easily compare value-less types like PositiveOptionValue and 321 # NegativeOptionValue. 322 empty_positive = PositiveOptionValue() 323 empty_negative = NegativeOptionValue() 324 self.assertEqual(empty_positive, ()) 325 self.assertEqual(empty_positive, PositiveOptionValue()) 326 self.assertEqual(empty_negative, ()) 327 self.assertEqual(empty_negative, NegativeOptionValue()) 328 self.assertNotEqual(empty_positive, "foo") 329 self.assertNotEqual(empty_positive, ("foo",)) 330 self.assertNotEqual(empty_negative, "foo") 331 self.assertNotEqual(empty_negative, ("foo",)) 332 333 def test_option_value_format(self): 334 val = PositiveOptionValue() 335 self.assertEquals("--with-value", val.format("--with-value")) 336 self.assertEquals("--with-value", val.format("--without-value")) 337 self.assertEquals("--enable-value", val.format("--enable-value")) 338 self.assertEquals("--enable-value", val.format("--disable-value")) 339 self.assertEquals("--value", val.format("--value")) 340 self.assertEquals("VALUE=1", val.format("VALUE")) 341 342 val = PositiveOptionValue(("a",)) 343 self.assertEquals("--with-value=a", val.format("--with-value")) 344 self.assertEquals("--with-value=a", val.format("--without-value")) 345 self.assertEquals("--enable-value=a", val.format("--enable-value")) 346 self.assertEquals("--enable-value=a", val.format("--disable-value")) 347 self.assertEquals("--value=a", val.format("--value")) 348 self.assertEquals("VALUE=a", val.format("VALUE")) 349 350 val = PositiveOptionValue(("a", "b")) 351 self.assertEquals("--with-value=a,b", val.format("--with-value")) 352 self.assertEquals("--with-value=a,b", val.format("--without-value")) 353 self.assertEquals("--enable-value=a,b", val.format("--enable-value")) 354 self.assertEquals("--enable-value=a,b", val.format("--disable-value")) 355 self.assertEquals("--value=a,b", val.format("--value")) 356 self.assertEquals("VALUE=a,b", val.format("VALUE")) 357 358 val = NegativeOptionValue() 359 self.assertEquals("--without-value", val.format("--with-value")) 360 self.assertEquals("--without-value", val.format("--without-value")) 361 self.assertEquals("--disable-value", val.format("--enable-value")) 362 self.assertEquals("--disable-value", val.format("--disable-value")) 363 self.assertEquals("", val.format("--value")) 364 self.assertEquals("VALUE=", val.format("VALUE")) 365 366 def test_option_value(self, name="option", nargs=0, default=None): 367 disabled = name.startswith(("disable-", "without-")) 368 if disabled: 369 negOptionValue = PositiveOptionValue 370 posOptionValue = NegativeOptionValue 371 else: 372 posOptionValue = PositiveOptionValue 373 negOptionValue = NegativeOptionValue 374 defaultValue = PositiveOptionValue(default) if default else negOptionValue() 375 376 option = Option("--%s" % name, nargs=nargs, default=default) 377 378 if nargs in (0, "?", "*") or disabled: 379 value = option.get_value("--%s" % name, "option") 380 self.assertEquals(value, posOptionValue()) 381 self.assertEquals(value.origin, "option") 382 else: 383 with self.assertRaises(InvalidOptionError) as e: 384 option.get_value("--%s" % name) 385 if nargs == 1: 386 self.assertEquals(str(e.exception), "--%s takes 1 value" % name) 387 elif nargs == "+": 388 self.assertEquals( 389 str(e.exception), "--%s takes 1 or more values" % name 390 ) 391 else: 392 self.assertEquals(str(e.exception), "--%s takes 2 values" % name) 393 394 value = option.get_value("") 395 self.assertEquals(value, defaultValue) 396 self.assertEquals(value.origin, "default") 397 398 value = option.get_value(None) 399 self.assertEquals(value, defaultValue) 400 self.assertEquals(value.origin, "default") 401 402 with self.assertRaises(AssertionError): 403 value = option.get_value("MOZ_OPTION=", "environment") 404 405 with self.assertRaises(AssertionError): 406 value = option.get_value("MOZ_OPTION=1", "environment") 407 408 with self.assertRaises(AssertionError): 409 value = option.get_value("--foo") 410 411 if nargs in (1, "?", "*", "+") and not disabled: 412 value = option.get_value("--%s=" % name, "option") 413 self.assertEquals(value, PositiveOptionValue(("",))) 414 self.assertEquals(value.origin, "option") 415 else: 416 with self.assertRaises(InvalidOptionError) as e: 417 option.get_value("--%s=" % name) 418 if disabled: 419 self.assertEquals( 420 str(e.exception), "Cannot pass a value to --%s" % name 421 ) 422 else: 423 self.assertEquals( 424 str(e.exception), "--%s takes %d values" % (name, nargs) 425 ) 426 427 if nargs in (1, "?", "*", "+") and not disabled: 428 value = option.get_value("--%s=foo" % name, "option") 429 self.assertEquals(value, PositiveOptionValue(("foo",))) 430 self.assertEquals(value.origin, "option") 431 else: 432 with self.assertRaises(InvalidOptionError) as e: 433 option.get_value("--%s=foo" % name) 434 if disabled: 435 self.assertEquals( 436 str(e.exception), "Cannot pass a value to --%s" % name 437 ) 438 else: 439 self.assertEquals( 440 str(e.exception), "--%s takes %d values" % (name, nargs) 441 ) 442 443 if nargs in (2, "*", "+") and not disabled: 444 value = option.get_value("--%s=foo,bar" % name, "option") 445 self.assertEquals(value, PositiveOptionValue(("foo", "bar"))) 446 self.assertEquals(value.origin, "option") 447 else: 448 with self.assertRaises(InvalidOptionError) as e: 449 option.get_value("--%s=foo,bar" % name, "option") 450 if disabled: 451 self.assertEquals( 452 str(e.exception), "Cannot pass a value to --%s" % name 453 ) 454 elif nargs == "?": 455 self.assertEquals(str(e.exception), "--%s takes 0 or 1 values" % name) 456 else: 457 self.assertEquals( 458 str(e.exception), 459 "--%s takes %d value%s" % (name, nargs, "s" if nargs != 1 else ""), 460 ) 461 462 option = Option("--%s" % name, env="MOZ_OPTION", nargs=nargs, default=default) 463 if nargs in (0, "?", "*") or disabled: 464 value = option.get_value("--%s" % name, "option") 465 self.assertEquals(value, posOptionValue()) 466 self.assertEquals(value.origin, "option") 467 else: 468 with self.assertRaises(InvalidOptionError) as e: 469 option.get_value("--%s" % name) 470 if disabled: 471 self.assertEquals( 472 str(e.exception), "Cannot pass a value to --%s" % name 473 ) 474 elif nargs == "+": 475 self.assertEquals( 476 str(e.exception), "--%s takes 1 or more values" % name 477 ) 478 else: 479 self.assertEquals( 480 str(e.exception), 481 "--%s takes %d value%s" % (name, nargs, "s" if nargs != 1 else ""), 482 ) 483 484 value = option.get_value("") 485 self.assertEquals(value, defaultValue) 486 self.assertEquals(value.origin, "default") 487 488 value = option.get_value(None) 489 self.assertEquals(value, defaultValue) 490 self.assertEquals(value.origin, "default") 491 492 value = option.get_value("MOZ_OPTION=", "environment") 493 self.assertEquals(value, NegativeOptionValue()) 494 self.assertEquals(value.origin, "environment") 495 496 if nargs in (0, "?", "*"): 497 value = option.get_value("MOZ_OPTION=1", "environment") 498 self.assertEquals(value, PositiveOptionValue()) 499 self.assertEquals(value.origin, "environment") 500 elif nargs in (1, "+"): 501 value = option.get_value("MOZ_OPTION=1", "environment") 502 self.assertEquals(value, PositiveOptionValue(("1",))) 503 self.assertEquals(value.origin, "environment") 504 else: 505 with self.assertRaises(InvalidOptionError) as e: 506 option.get_value("MOZ_OPTION=1", "environment") 507 self.assertEquals(str(e.exception), "MOZ_OPTION takes 2 values") 508 509 if nargs in (1, "?", "*", "+") and not disabled: 510 value = option.get_value("--%s=" % name, "option") 511 self.assertEquals(value, PositiveOptionValue(("",))) 512 self.assertEquals(value.origin, "option") 513 else: 514 with self.assertRaises(InvalidOptionError) as e: 515 option.get_value("--%s=" % name, "option") 516 if disabled: 517 self.assertEquals( 518 str(e.exception), "Cannot pass a value to --%s" % name 519 ) 520 else: 521 self.assertEquals( 522 str(e.exception), "--%s takes %d values" % (name, nargs) 523 ) 524 525 with self.assertRaises(AssertionError): 526 value = option.get_value("--foo", "option") 527 528 if nargs in (1, "?", "*", "+"): 529 value = option.get_value("MOZ_OPTION=foo", "environment") 530 self.assertEquals(value, PositiveOptionValue(("foo",))) 531 self.assertEquals(value.origin, "environment") 532 else: 533 with self.assertRaises(InvalidOptionError) as e: 534 option.get_value("MOZ_OPTION=foo", "environment") 535 self.assertEquals(str(e.exception), "MOZ_OPTION takes %d values" % nargs) 536 537 if nargs in (2, "*", "+"): 538 value = option.get_value("MOZ_OPTION=foo,bar", "environment") 539 self.assertEquals(value, PositiveOptionValue(("foo", "bar"))) 540 self.assertEquals(value.origin, "environment") 541 else: 542 with self.assertRaises(InvalidOptionError) as e: 543 option.get_value("MOZ_OPTION=foo,bar", "environment") 544 if nargs == "?": 545 self.assertEquals(str(e.exception), "MOZ_OPTION takes 0 or 1 values") 546 else: 547 self.assertEquals( 548 str(e.exception), 549 "MOZ_OPTION takes %d value%s" % (nargs, "s" if nargs != 1 else ""), 550 ) 551 552 if disabled: 553 return option 554 555 env_option = Option(env="MOZ_OPTION", nargs=nargs, default=default) 556 with self.assertRaises(AssertionError): 557 env_option.get_value("--%s" % name) 558 559 value = env_option.get_value("") 560 self.assertEquals(value, defaultValue) 561 self.assertEquals(value.origin, "default") 562 563 value = env_option.get_value("MOZ_OPTION=", "environment") 564 self.assertEquals(value, negOptionValue()) 565 self.assertEquals(value.origin, "environment") 566 567 if nargs in (0, "?", "*"): 568 value = env_option.get_value("MOZ_OPTION=1", "environment") 569 self.assertEquals(value, posOptionValue()) 570 self.assertTrue(value) 571 self.assertEquals(value.origin, "environment") 572 elif nargs in (1, "+"): 573 value = env_option.get_value("MOZ_OPTION=1", "environment") 574 self.assertEquals(value, PositiveOptionValue(("1",))) 575 self.assertEquals(value.origin, "environment") 576 else: 577 with self.assertRaises(InvalidOptionError) as e: 578 env_option.get_value("MOZ_OPTION=1", "environment") 579 self.assertEquals(str(e.exception), "MOZ_OPTION takes 2 values") 580 581 with self.assertRaises(AssertionError) as e: 582 env_option.get_value("--%s" % name) 583 584 with self.assertRaises(AssertionError) as e: 585 env_option.get_value("--foo") 586 587 if nargs in (1, "?", "*", "+"): 588 value = env_option.get_value("MOZ_OPTION=foo", "environment") 589 self.assertEquals(value, PositiveOptionValue(("foo",))) 590 self.assertEquals(value.origin, "environment") 591 else: 592 with self.assertRaises(InvalidOptionError) as e: 593 env_option.get_value("MOZ_OPTION=foo", "environment") 594 self.assertEquals(str(e.exception), "MOZ_OPTION takes %d values" % nargs) 595 596 if nargs in (2, "*", "+"): 597 value = env_option.get_value("MOZ_OPTION=foo,bar", "environment") 598 self.assertEquals(value, PositiveOptionValue(("foo", "bar"))) 599 self.assertEquals(value.origin, "environment") 600 else: 601 with self.assertRaises(InvalidOptionError) as e: 602 env_option.get_value("MOZ_OPTION=foo,bar", "environment") 603 if nargs == "?": 604 self.assertEquals(str(e.exception), "MOZ_OPTION takes 0 or 1 values") 605 else: 606 self.assertEquals( 607 str(e.exception), 608 "MOZ_OPTION takes %d value%s" % (nargs, "s" if nargs != 1 else ""), 609 ) 610 611 return option 612 613 def test_option_value_enable( 614 self, enable="enable", disable="disable", nargs=0, default=None 615 ): 616 option = self.test_option_value( 617 "%s-option" % enable, nargs=nargs, default=default 618 ) 619 620 value = option.get_value("--%s-option" % disable, "option") 621 self.assertEquals(value, NegativeOptionValue()) 622 self.assertEquals(value.origin, "option") 623 624 option = self.test_option_value( 625 "%s-option" % disable, nargs=nargs, default=default 626 ) 627 628 if nargs in (0, "?", "*"): 629 value = option.get_value("--%s-option" % enable, "option") 630 self.assertEquals(value, PositiveOptionValue()) 631 self.assertEquals(value.origin, "option") 632 else: 633 with self.assertRaises(InvalidOptionError) as e: 634 option.get_value("--%s-option" % enable, "option") 635 if nargs == 1: 636 self.assertEquals( 637 str(e.exception), "--%s-option takes 1 value" % enable 638 ) 639 elif nargs == "+": 640 self.assertEquals( 641 str(e.exception), "--%s-option takes 1 or more values" % enable 642 ) 643 else: 644 self.assertEquals( 645 str(e.exception), "--%s-option takes 2 values" % enable 646 ) 647 648 def test_option_value_with(self): 649 self.test_option_value_enable("with", "without") 650 651 def test_option_value_invalid_nargs(self): 652 with self.assertRaises(InvalidOptionError) as e: 653 Option("--option", nargs="foo") 654 self.assertEquals( 655 str(e.exception), "nargs must be a positive integer, '?', '*' or '+'" 656 ) 657 658 with self.assertRaises(InvalidOptionError) as e: 659 Option("--option", nargs=-2) 660 self.assertEquals( 661 str(e.exception), "nargs must be a positive integer, '?', '*' or '+'" 662 ) 663 664 def test_option_value_nargs_1(self): 665 self.test_option_value(nargs=1) 666 self.test_option_value(nargs=1, default=("a",)) 667 self.test_option_value_enable(nargs=1, default=("a",)) 668 669 # A default is required 670 with self.assertRaises(InvalidOptionError) as e: 671 Option("--disable-option", nargs=1) 672 self.assertEquals( 673 str(e.exception), "The given `default` doesn't satisfy `nargs`" 674 ) 675 676 def test_option_value_nargs_2(self): 677 self.test_option_value(nargs=2) 678 self.test_option_value(nargs=2, default=("a", "b")) 679 self.test_option_value_enable(nargs=2, default=("a", "b")) 680 681 # A default is required 682 with self.assertRaises(InvalidOptionError) as e: 683 Option("--disable-option", nargs=2) 684 self.assertEquals( 685 str(e.exception), "The given `default` doesn't satisfy `nargs`" 686 ) 687 688 def test_option_value_nargs_0_or_1(self): 689 self.test_option_value(nargs="?") 690 self.test_option_value(nargs="?", default=("a",)) 691 self.test_option_value_enable(nargs="?") 692 self.test_option_value_enable(nargs="?", default=("a",)) 693 694 def test_option_value_nargs_0_or_more(self): 695 self.test_option_value(nargs="*") 696 self.test_option_value(nargs="*", default=("a",)) 697 self.test_option_value(nargs="*", default=("a", "b")) 698 self.test_option_value_enable(nargs="*") 699 self.test_option_value_enable(nargs="*", default=("a",)) 700 self.test_option_value_enable(nargs="*", default=("a", "b")) 701 702 def test_option_value_nargs_1_or_more(self): 703 self.test_option_value(nargs="+") 704 self.test_option_value(nargs="+", default=("a",)) 705 self.test_option_value(nargs="+", default=("a", "b")) 706 self.test_option_value_enable(nargs="+", default=("a",)) 707 self.test_option_value_enable(nargs="+", default=("a", "b")) 708 709 # A default is required 710 with self.assertRaises(InvalidOptionError) as e: 711 Option("--disable-option", nargs="+") 712 self.assertEquals( 713 str(e.exception), "The given `default` doesn't satisfy `nargs`" 714 ) 715 716 717class TestCommandLineHelper(unittest.TestCase): 718 def test_basic(self): 719 helper = CommandLineHelper({}, ["cmd", "--foo", "--bar"]) 720 721 self.assertEquals(["--foo", "--bar"], list(helper)) 722 723 helper.add("--enable-qux") 724 725 self.assertEquals(["--foo", "--bar", "--enable-qux"], list(helper)) 726 727 value, option = helper.handle(Option("--bar")) 728 self.assertEquals(["--foo", "--enable-qux"], list(helper)) 729 self.assertEquals(PositiveOptionValue(), value) 730 self.assertEquals("--bar", option) 731 732 value, option = helper.handle(Option("--baz")) 733 self.assertEquals(["--foo", "--enable-qux"], list(helper)) 734 self.assertEquals(NegativeOptionValue(), value) 735 self.assertEquals(None, option) 736 737 with self.assertRaises(AssertionError): 738 CommandLineHelper({}, ["--foo", "--bar"]) 739 740 def test_precedence(self): 741 foo = Option("--with-foo", nargs="*") 742 helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b"]) 743 value, option = helper.handle(foo) 744 self.assertEquals(PositiveOptionValue(("a", "b")), value) 745 self.assertEquals("command-line", value.origin) 746 self.assertEquals("--with-foo=a,b", option) 747 748 helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b", "--without-foo"]) 749 value, option = helper.handle(foo) 750 self.assertEquals(NegativeOptionValue(), value) 751 self.assertEquals("command-line", value.origin) 752 self.assertEquals("--without-foo", option) 753 754 helper = CommandLineHelper({}, ["cmd", "--without-foo", "--with-foo=a,b"]) 755 value, option = helper.handle(foo) 756 self.assertEquals(PositiveOptionValue(("a", "b")), value) 757 self.assertEquals("command-line", value.origin) 758 self.assertEquals("--with-foo=a,b", option) 759 760 foo = Option("--with-foo", env="FOO", nargs="*") 761 helper = CommandLineHelper({"FOO": ""}, ["cmd", "--with-foo=a,b"]) 762 value, option = helper.handle(foo) 763 self.assertEquals(PositiveOptionValue(("a", "b")), value) 764 self.assertEquals("command-line", value.origin) 765 self.assertEquals("--with-foo=a,b", option) 766 767 helper = CommandLineHelper({"FOO": "a,b"}, ["cmd", "--without-foo"]) 768 value, option = helper.handle(foo) 769 self.assertEquals(NegativeOptionValue(), value) 770 self.assertEquals("command-line", value.origin) 771 self.assertEquals("--without-foo", option) 772 773 helper = CommandLineHelper({"FOO": ""}, ["cmd", "--with-bar=a,b"]) 774 value, option = helper.handle(foo) 775 self.assertEquals(NegativeOptionValue(), value) 776 self.assertEquals("environment", value.origin) 777 self.assertEquals("FOO=", option) 778 779 helper = CommandLineHelper({"FOO": "a,b"}, ["cmd", "--without-bar"]) 780 value, option = helper.handle(foo) 781 self.assertEquals(PositiveOptionValue(("a", "b")), value) 782 self.assertEquals("environment", value.origin) 783 self.assertEquals("FOO=a,b", option) 784 785 helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b", "FOO="]) 786 value, option = helper.handle(foo) 787 self.assertEquals(NegativeOptionValue(), value) 788 self.assertEquals("command-line", value.origin) 789 self.assertEquals("FOO=", option) 790 791 helper = CommandLineHelper({}, ["cmd", "--without-foo", "FOO=a,b"]) 792 value, option = helper.handle(foo) 793 self.assertEquals(PositiveOptionValue(("a", "b")), value) 794 self.assertEquals("command-line", value.origin) 795 self.assertEquals("FOO=a,b", option) 796 797 helper = CommandLineHelper({}, ["cmd", "FOO=", "--with-foo=a,b"]) 798 value, option = helper.handle(foo) 799 self.assertEquals(PositiveOptionValue(("a", "b")), value) 800 self.assertEquals("command-line", value.origin) 801 self.assertEquals("--with-foo=a,b", option) 802 803 helper = CommandLineHelper({}, ["cmd", "FOO=a,b", "--without-foo"]) 804 value, option = helper.handle(foo) 805 self.assertEquals(NegativeOptionValue(), value) 806 self.assertEquals("command-line", value.origin) 807 self.assertEquals("--without-foo", option) 808 809 def test_extra_args(self): 810 foo = Option("--with-foo", env="FOO", nargs="*") 811 helper = CommandLineHelper({}, ["cmd"]) 812 helper.add("FOO=a,b,c", "other-origin") 813 value, option = helper.handle(foo) 814 self.assertEquals(PositiveOptionValue(("a", "b", "c")), value) 815 self.assertEquals("other-origin", value.origin) 816 self.assertEquals("FOO=a,b,c", option) 817 818 helper = CommandLineHelper({}, ["cmd"]) 819 helper.add("FOO=a,b,c", "other-origin") 820 helper.add("--with-foo=a,b,c", "other-origin") 821 value, option = helper.handle(foo) 822 self.assertEquals(PositiveOptionValue(("a", "b", "c")), value) 823 self.assertEquals("other-origin", value.origin) 824 self.assertEquals("--with-foo=a,b,c", option) 825 826 # Adding conflicting options is not allowed. 827 helper = CommandLineHelper({}, ["cmd"]) 828 helper.add("FOO=a,b,c", "other-origin") 829 with self.assertRaises(ConflictingOptionError) as cm: 830 helper.add("FOO=", "other-origin") 831 self.assertEqual("FOO=", cm.exception.arg) 832 self.assertEqual("other-origin", cm.exception.origin) 833 self.assertEqual("FOO=a,b,c", cm.exception.old_arg) 834 self.assertEqual("other-origin", cm.exception.old_origin) 835 with self.assertRaises(ConflictingOptionError) as cm: 836 helper.add("FOO=a,b", "other-origin") 837 self.assertEqual("FOO=a,b", cm.exception.arg) 838 self.assertEqual("other-origin", cm.exception.origin) 839 self.assertEqual("FOO=a,b,c", cm.exception.old_arg) 840 self.assertEqual("other-origin", cm.exception.old_origin) 841 # But adding the same is allowed. 842 helper.add("FOO=a,b,c", "other-origin") 843 value, option = helper.handle(foo) 844 self.assertEquals(PositiveOptionValue(("a", "b", "c")), value) 845 self.assertEquals("other-origin", value.origin) 846 self.assertEquals("FOO=a,b,c", option) 847 848 # The same rule as above applies when using the option form vs. the 849 # variable form. But we can't detect it when .add is called. 850 helper = CommandLineHelper({}, ["cmd"]) 851 helper.add("FOO=a,b,c", "other-origin") 852 helper.add("--without-foo", "other-origin") 853 with self.assertRaises(ConflictingOptionError) as cm: 854 helper.handle(foo) 855 self.assertEqual("--without-foo", cm.exception.arg) 856 self.assertEqual("other-origin", cm.exception.origin) 857 self.assertEqual("FOO=a,b,c", cm.exception.old_arg) 858 self.assertEqual("other-origin", cm.exception.old_origin) 859 helper = CommandLineHelper({}, ["cmd"]) 860 helper.add("FOO=a,b,c", "other-origin") 861 helper.add("--with-foo=a,b", "other-origin") 862 with self.assertRaises(ConflictingOptionError) as cm: 863 helper.handle(foo) 864 self.assertEqual("--with-foo=a,b", cm.exception.arg) 865 self.assertEqual("other-origin", cm.exception.origin) 866 self.assertEqual("FOO=a,b,c", cm.exception.old_arg) 867 self.assertEqual("other-origin", cm.exception.old_origin) 868 helper = CommandLineHelper({}, ["cmd"]) 869 helper.add("FOO=a,b,c", "other-origin") 870 helper.add("--with-foo=a,b,c", "other-origin") 871 value, option = helper.handle(foo) 872 self.assertEquals(PositiveOptionValue(("a", "b", "c")), value) 873 self.assertEquals("other-origin", value.origin) 874 self.assertEquals("--with-foo=a,b,c", option) 875 876 # Conflicts are also not allowed against what is in the 877 # environment/on the command line. 878 helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b"]) 879 helper.add("FOO=a,b,c", "other-origin") 880 with self.assertRaises(ConflictingOptionError) as cm: 881 helper.handle(foo) 882 self.assertEqual("FOO=a,b,c", cm.exception.arg) 883 self.assertEqual("other-origin", cm.exception.origin) 884 self.assertEqual("--with-foo=a,b", cm.exception.old_arg) 885 self.assertEqual("command-line", cm.exception.old_origin) 886 887 helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b"]) 888 helper.add("--without-foo", "other-origin") 889 with self.assertRaises(ConflictingOptionError) as cm: 890 helper.handle(foo) 891 self.assertEqual("--without-foo", cm.exception.arg) 892 self.assertEqual("other-origin", cm.exception.origin) 893 self.assertEqual("--with-foo=a,b", cm.exception.old_arg) 894 self.assertEqual("command-line", cm.exception.old_origin) 895 896 def test_possible_origins(self): 897 with self.assertRaises(InvalidOptionError): 898 Option("--foo", possible_origins="command-line") 899 900 helper = CommandLineHelper({"BAZ": "1"}, ["cmd", "--foo", "--bar"]) 901 foo = Option("--foo", possible_origins=("command-line",)) 902 value, option = helper.handle(foo) 903 self.assertEquals(PositiveOptionValue(), value) 904 self.assertEquals("command-line", value.origin) 905 self.assertEquals("--foo", option) 906 907 bar = Option("--bar", possible_origins=("mozconfig",)) 908 with self.assertRaisesRegexp( 909 InvalidOptionError, 910 "--bar can not be set by command-line. Values are accepted from: mozconfig", 911 ): 912 helper.handle(bar) 913 914 baz = Option(env="BAZ", possible_origins=("implied",)) 915 with self.assertRaisesRegexp( 916 InvalidOptionError, 917 "BAZ=1 can not be set by environment. Values are accepted from: implied", 918 ): 919 helper.handle(baz) 920 921 922if __name__ == "__main__": 923 main() 924