# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. import unittest from mozunit import main from mozbuild.configure.options import ( CommandLineHelper, ConflictingOptionError, InvalidOptionError, NegativeOptionValue, Option, OptionValue, PositiveOptionValue, ) class Option(Option): def __init__(self, *args, **kwargs): kwargs["help"] = "Dummy help" super(Option, self).__init__(*args, **kwargs) class TestOption(unittest.TestCase): def test_option(self): option = Option("--option") self.assertEqual(option.prefix, "") self.assertEqual(option.name, "option") self.assertEqual(option.env, None) self.assertFalse(option.default) option = Option("--enable-option") self.assertEqual(option.prefix, "enable") self.assertEqual(option.name, "option") self.assertEqual(option.env, None) self.assertFalse(option.default) option = Option("--disable-option") self.assertEqual(option.prefix, "disable") self.assertEqual(option.name, "option") self.assertEqual(option.env, None) self.assertTrue(option.default) option = Option("--with-option") self.assertEqual(option.prefix, "with") self.assertEqual(option.name, "option") self.assertEqual(option.env, None) self.assertFalse(option.default) option = Option("--without-option") self.assertEqual(option.prefix, "without") self.assertEqual(option.name, "option") self.assertEqual(option.env, None) self.assertTrue(option.default) option = Option("--without-option-foo", env="MOZ_OPTION") self.assertEqual(option.env, "MOZ_OPTION") option = Option(env="MOZ_OPTION") self.assertEqual(option.prefix, "") self.assertEqual(option.name, None) self.assertEqual(option.env, "MOZ_OPTION") self.assertFalse(option.default) with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs=0, default=("a",)) self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs=1, default=()) self.assertEqual( str(e.exception), "default must be a bool, a string or a tuple of strings" ) with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs=1, default=True) self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs=1, default=("a", "b")) self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs=2, default=()) self.assertEqual( str(e.exception), "default must be a bool, a string or a tuple of strings" ) with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs=2, default=True) self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs=2, default=("a",)) self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs="?", default=("a", "b")) self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs="+", default=()) self.assertEqual( str(e.exception), "default must be a bool, a string or a tuple of strings" ) with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs="+", default=True) self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) # --disable options with a nargs value that requires at least one # argument need to be given a default. with self.assertRaises(InvalidOptionError) as e: Option("--disable-option", nargs=1) self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) with self.assertRaises(InvalidOptionError) as e: Option("--disable-option", nargs="+") self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) # Test nargs inference from default value option = Option("--with-foo", default=True) self.assertEqual(option.nargs, 0) option = Option("--with-foo", default=False) self.assertEqual(option.nargs, 0) option = Option("--with-foo", default="a") self.assertEqual(option.nargs, "?") option = Option("--with-foo", default=("a",)) self.assertEqual(option.nargs, "?") option = Option("--with-foo", default=("a", "b")) self.assertEqual(option.nargs, "*") option = Option(env="FOO", default=True) self.assertEqual(option.nargs, 0) option = Option(env="FOO", default=False) self.assertEqual(option.nargs, 0) option = Option(env="FOO", default="a") self.assertEqual(option.nargs, "?") option = Option(env="FOO", default=("a",)) self.assertEqual(option.nargs, "?") option = Option(env="FOO", default=("a", "b")) self.assertEqual(option.nargs, "*") def test_option_option(self): for option in ( "--option", "--enable-option", "--disable-option", "--with-option", "--without-option", ): self.assertEqual(Option(option).option, option) self.assertEqual(Option(option, env="FOO").option, option) opt = Option(option, default=False) self.assertEqual( opt.option, option.replace("-disable-", "-enable-").replace("-without-", "-with-"), ) opt = Option(option, default=True) self.assertEqual( opt.option, option.replace("-enable-", "-disable-").replace("-with-", "-without-"), ) self.assertEqual(Option(env="FOO").option, "FOO") def test_option_choices(self): with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs=3, choices=("a", "b")) self.assertEqual(str(e.exception), "Not enough `choices` for `nargs`") with self.assertRaises(InvalidOptionError) as e: Option("--without-option", nargs=1, choices=("a", "b")) self.assertEqual( str(e.exception), "A `default` must be given along with `choices`" ) with self.assertRaises(InvalidOptionError) as e: Option("--without-option", nargs="+", choices=("a", "b")) self.assertEqual( str(e.exception), "A `default` must be given along with `choices`" ) with self.assertRaises(InvalidOptionError) as e: Option("--without-option", default="c", choices=("a", "b")) self.assertEqual( str(e.exception), "The `default` value must be one of 'a', 'b'" ) with self.assertRaises(InvalidOptionError) as e: Option( "--without-option", default=( "a", "c", ), choices=("a", "b"), ) self.assertEqual( str(e.exception), "The `default` value must be one of 'a', 'b'" ) with self.assertRaises(InvalidOptionError) as e: Option("--without-option", default=("c",), choices=("a", "b")) self.assertEqual( str(e.exception), "The `default` value must be one of 'a', 'b'" ) option = Option("--with-option", nargs="+", choices=("a", "b")) with self.assertRaises(InvalidOptionError) as e: option.get_value("--with-option=c") self.assertEqual(str(e.exception), "'c' is not one of 'a', 'b'") value = option.get_value("--with-option=b,a") self.assertTrue(value) self.assertEqual(PositiveOptionValue(("b", "a")), value) option = Option("--without-option", nargs="*", default="a", choices=("a", "b")) with self.assertRaises(InvalidOptionError) as e: option.get_value("--with-option=c") self.assertEqual(str(e.exception), "'c' is not one of 'a', 'b'") value = option.get_value("--with-option=b,a") self.assertTrue(value) self.assertEqual(PositiveOptionValue(("b", "a")), value) # Test nargs inference from choices option = Option("--with-option", choices=("a", "b")) self.assertEqual(option.nargs, 1) # Test "relative" values option = Option( "--with-option", nargs="*", default=("b", "c"), choices=("a", "b", "c", "d") ) value = option.get_value("--with-option=+d") self.assertEqual(PositiveOptionValue(("b", "c", "d")), value) value = option.get_value("--with-option=-b") self.assertEqual(PositiveOptionValue(("c",)), value) value = option.get_value("--with-option=-b,+d") self.assertEqual(PositiveOptionValue(("c", "d")), value) # Adding something that is in the default is fine value = option.get_value("--with-option=+b") self.assertEqual(PositiveOptionValue(("b", "c")), value) # Removing something that is not in the default is fine, as long as it # is one of the choices value = option.get_value("--with-option=-a") self.assertEqual(PositiveOptionValue(("b", "c")), value) with self.assertRaises(InvalidOptionError) as e: option.get_value("--with-option=-e") self.assertEqual(str(e.exception), "'e' is not one of 'a', 'b', 'c', 'd'") # Other "not a choice" errors. with self.assertRaises(InvalidOptionError) as e: option.get_value("--with-option=+e") self.assertEqual(str(e.exception), "'e' is not one of 'a', 'b', 'c', 'd'") with self.assertRaises(InvalidOptionError) as e: option.get_value("--with-option=e") self.assertEqual(str(e.exception), "'e' is not one of 'a', 'b', 'c', 'd'") def test_option_value_compare(self): # OptionValue are tuple and equivalence should compare as tuples. val = PositiveOptionValue(("foo",)) self.assertEqual(val[0], "foo") self.assertEqual(val, PositiveOptionValue(("foo",))) self.assertNotEqual(val, PositiveOptionValue(("foo", "bar"))) # Can compare a tuple to an OptionValue. self.assertEqual(val, ("foo",)) self.assertNotEqual(val, ("foo", "bar")) # Different OptionValue types are never equal. self.assertNotEqual(val, OptionValue(("foo",))) # For usability reasons, we raise TypeError when attempting to compare # against a non-tuple. with self.assertRaisesRegexp(TypeError, "cannot compare a"): val == "foo" # But we allow empty option values to compare otherwise we can't # easily compare value-less types like PositiveOptionValue and # NegativeOptionValue. empty_positive = PositiveOptionValue() empty_negative = NegativeOptionValue() self.assertEqual(empty_positive, ()) self.assertEqual(empty_positive, PositiveOptionValue()) self.assertEqual(empty_negative, ()) self.assertEqual(empty_negative, NegativeOptionValue()) self.assertNotEqual(empty_positive, "foo") self.assertNotEqual(empty_positive, ("foo",)) self.assertNotEqual(empty_negative, "foo") self.assertNotEqual(empty_negative, ("foo",)) def test_option_value_format(self): val = PositiveOptionValue() self.assertEqual("--with-value", val.format("--with-value")) self.assertEqual("--with-value", val.format("--without-value")) self.assertEqual("--enable-value", val.format("--enable-value")) self.assertEqual("--enable-value", val.format("--disable-value")) self.assertEqual("--value", val.format("--value")) self.assertEqual("VALUE=1", val.format("VALUE")) val = PositiveOptionValue(("a",)) self.assertEqual("--with-value=a", val.format("--with-value")) self.assertEqual("--with-value=a", val.format("--without-value")) self.assertEqual("--enable-value=a", val.format("--enable-value")) self.assertEqual("--enable-value=a", val.format("--disable-value")) self.assertEqual("--value=a", val.format("--value")) self.assertEqual("VALUE=a", val.format("VALUE")) val = PositiveOptionValue(("a", "b")) self.assertEqual("--with-value=a,b", val.format("--with-value")) self.assertEqual("--with-value=a,b", val.format("--without-value")) self.assertEqual("--enable-value=a,b", val.format("--enable-value")) self.assertEqual("--enable-value=a,b", val.format("--disable-value")) self.assertEqual("--value=a,b", val.format("--value")) self.assertEqual("VALUE=a,b", val.format("VALUE")) val = NegativeOptionValue() self.assertEqual("--without-value", val.format("--with-value")) self.assertEqual("--without-value", val.format("--without-value")) self.assertEqual("--disable-value", val.format("--enable-value")) self.assertEqual("--disable-value", val.format("--disable-value")) self.assertEqual("", val.format("--value")) self.assertEqual("VALUE=", val.format("VALUE")) def test_option_value(self, name="option", nargs=0, default=None): disabled = name.startswith(("disable-", "without-")) if disabled: negOptionValue = PositiveOptionValue posOptionValue = NegativeOptionValue else: posOptionValue = PositiveOptionValue negOptionValue = NegativeOptionValue defaultValue = PositiveOptionValue(default) if default else negOptionValue() option = Option("--%s" % name, nargs=nargs, default=default) if nargs in (0, "?", "*") or disabled: value = option.get_value("--%s" % name, "option") self.assertEqual(value, posOptionValue()) self.assertEqual(value.origin, "option") else: with self.assertRaises(InvalidOptionError) as e: option.get_value("--%s" % name) if nargs == 1: self.assertEqual(str(e.exception), "--%s takes 1 value" % name) elif nargs == "+": self.assertEqual(str(e.exception), "--%s takes 1 or more values" % name) else: self.assertEqual(str(e.exception), "--%s takes 2 values" % name) value = option.get_value("") self.assertEqual(value, defaultValue) self.assertEqual(value.origin, "default") value = option.get_value(None) self.assertEqual(value, defaultValue) self.assertEqual(value.origin, "default") with self.assertRaises(AssertionError): value = option.get_value("MOZ_OPTION=", "environment") with self.assertRaises(AssertionError): value = option.get_value("MOZ_OPTION=1", "environment") with self.assertRaises(AssertionError): value = option.get_value("--foo") if nargs in (1, "?", "*", "+") and not disabled: value = option.get_value("--%s=" % name, "option") self.assertEqual(value, PositiveOptionValue(("",))) self.assertEqual(value.origin, "option") else: with self.assertRaises(InvalidOptionError) as e: option.get_value("--%s=" % name) if disabled: self.assertEqual(str(e.exception), "Cannot pass a value to --%s" % name) else: self.assertEqual( str(e.exception), "--%s takes %d values" % (name, nargs) ) if nargs in (1, "?", "*", "+") and not disabled: value = option.get_value("--%s=foo" % name, "option") self.assertEqual(value, PositiveOptionValue(("foo",))) self.assertEqual(value.origin, "option") else: with self.assertRaises(InvalidOptionError) as e: option.get_value("--%s=foo" % name) if disabled: self.assertEqual(str(e.exception), "Cannot pass a value to --%s" % name) else: self.assertEqual( str(e.exception), "--%s takes %d values" % (name, nargs) ) if nargs in (2, "*", "+") and not disabled: value = option.get_value("--%s=foo,bar" % name, "option") self.assertEqual(value, PositiveOptionValue(("foo", "bar"))) self.assertEqual(value.origin, "option") else: with self.assertRaises(InvalidOptionError) as e: option.get_value("--%s=foo,bar" % name, "option") if disabled: self.assertEqual(str(e.exception), "Cannot pass a value to --%s" % name) elif nargs == "?": self.assertEqual(str(e.exception), "--%s takes 0 or 1 values" % name) else: self.assertEqual( str(e.exception), "--%s takes %d value%s" % (name, nargs, "s" if nargs != 1 else ""), ) option = Option("--%s" % name, env="MOZ_OPTION", nargs=nargs, default=default) if nargs in (0, "?", "*") or disabled: value = option.get_value("--%s" % name, "option") self.assertEqual(value, posOptionValue()) self.assertEqual(value.origin, "option") else: with self.assertRaises(InvalidOptionError) as e: option.get_value("--%s" % name) if disabled: self.assertEqual(str(e.exception), "Cannot pass a value to --%s" % name) elif nargs == "+": self.assertEqual(str(e.exception), "--%s takes 1 or more values" % name) else: self.assertEqual( str(e.exception), "--%s takes %d value%s" % (name, nargs, "s" if nargs != 1 else ""), ) value = option.get_value("") self.assertEqual(value, defaultValue) self.assertEqual(value.origin, "default") value = option.get_value(None) self.assertEqual(value, defaultValue) self.assertEqual(value.origin, "default") value = option.get_value("MOZ_OPTION=", "environment") self.assertEqual(value, NegativeOptionValue()) self.assertEqual(value.origin, "environment") if nargs in (0, "?", "*"): value = option.get_value("MOZ_OPTION=1", "environment") self.assertEqual(value, PositiveOptionValue()) self.assertEqual(value.origin, "environment") elif nargs in (1, "+"): value = option.get_value("MOZ_OPTION=1", "environment") self.assertEqual(value, PositiveOptionValue(("1",))) self.assertEqual(value.origin, "environment") else: with self.assertRaises(InvalidOptionError) as e: option.get_value("MOZ_OPTION=1", "environment") self.assertEqual(str(e.exception), "MOZ_OPTION takes 2 values") if nargs in (1, "?", "*", "+") and not disabled: value = option.get_value("--%s=" % name, "option") self.assertEqual(value, PositiveOptionValue(("",))) self.assertEqual(value.origin, "option") else: with self.assertRaises(InvalidOptionError) as e: option.get_value("--%s=" % name, "option") if disabled: self.assertEqual(str(e.exception), "Cannot pass a value to --%s" % name) else: self.assertEqual( str(e.exception), "--%s takes %d values" % (name, nargs) ) with self.assertRaises(AssertionError): value = option.get_value("--foo", "option") if nargs in (1, "?", "*", "+"): value = option.get_value("MOZ_OPTION=foo", "environment") self.assertEqual(value, PositiveOptionValue(("foo",))) self.assertEqual(value.origin, "environment") else: with self.assertRaises(InvalidOptionError) as e: option.get_value("MOZ_OPTION=foo", "environment") self.assertEqual(str(e.exception), "MOZ_OPTION takes %d values" % nargs) if nargs in (2, "*", "+"): value = option.get_value("MOZ_OPTION=foo,bar", "environment") self.assertEqual(value, PositiveOptionValue(("foo", "bar"))) self.assertEqual(value.origin, "environment") else: with self.assertRaises(InvalidOptionError) as e: option.get_value("MOZ_OPTION=foo,bar", "environment") if nargs == "?": self.assertEqual(str(e.exception), "MOZ_OPTION takes 0 or 1 values") else: self.assertEqual( str(e.exception), "MOZ_OPTION takes %d value%s" % (nargs, "s" if nargs != 1 else ""), ) if disabled: return option env_option = Option(env="MOZ_OPTION", nargs=nargs, default=default) with self.assertRaises(AssertionError): env_option.get_value("--%s" % name) value = env_option.get_value("") self.assertEqual(value, defaultValue) self.assertEqual(value.origin, "default") value = env_option.get_value("MOZ_OPTION=", "environment") self.assertEqual(value, negOptionValue()) self.assertEqual(value.origin, "environment") if nargs in (0, "?", "*"): value = env_option.get_value("MOZ_OPTION=1", "environment") self.assertEqual(value, posOptionValue()) self.assertTrue(value) self.assertEqual(value.origin, "environment") elif nargs in (1, "+"): value = env_option.get_value("MOZ_OPTION=1", "environment") self.assertEqual(value, PositiveOptionValue(("1",))) self.assertEqual(value.origin, "environment") else: with self.assertRaises(InvalidOptionError) as e: env_option.get_value("MOZ_OPTION=1", "environment") self.assertEqual(str(e.exception), "MOZ_OPTION takes 2 values") with self.assertRaises(AssertionError) as e: env_option.get_value("--%s" % name) with self.assertRaises(AssertionError) as e: env_option.get_value("--foo") if nargs in (1, "?", "*", "+"): value = env_option.get_value("MOZ_OPTION=foo", "environment") self.assertEqual(value, PositiveOptionValue(("foo",))) self.assertEqual(value.origin, "environment") else: with self.assertRaises(InvalidOptionError) as e: env_option.get_value("MOZ_OPTION=foo", "environment") self.assertEqual(str(e.exception), "MOZ_OPTION takes %d values" % nargs) if nargs in (2, "*", "+"): value = env_option.get_value("MOZ_OPTION=foo,bar", "environment") self.assertEqual(value, PositiveOptionValue(("foo", "bar"))) self.assertEqual(value.origin, "environment") else: with self.assertRaises(InvalidOptionError) as e: env_option.get_value("MOZ_OPTION=foo,bar", "environment") if nargs == "?": self.assertEqual(str(e.exception), "MOZ_OPTION takes 0 or 1 values") else: self.assertEqual( str(e.exception), "MOZ_OPTION takes %d value%s" % (nargs, "s" if nargs != 1 else ""), ) return option def test_option_value_enable( self, enable="enable", disable="disable", nargs=0, default=None ): option = self.test_option_value( "%s-option" % enable, nargs=nargs, default=default ) value = option.get_value("--%s-option" % disable, "option") self.assertEqual(value, NegativeOptionValue()) self.assertEqual(value.origin, "option") option = self.test_option_value( "%s-option" % disable, nargs=nargs, default=default ) if nargs in (0, "?", "*"): value = option.get_value("--%s-option" % enable, "option") self.assertEqual(value, PositiveOptionValue()) self.assertEqual(value.origin, "option") else: with self.assertRaises(InvalidOptionError) as e: option.get_value("--%s-option" % enable, "option") if nargs == 1: self.assertEqual(str(e.exception), "--%s-option takes 1 value" % enable) elif nargs == "+": self.assertEqual( str(e.exception), "--%s-option takes 1 or more values" % enable ) else: self.assertEqual( str(e.exception), "--%s-option takes 2 values" % enable ) def test_option_value_with(self): self.test_option_value_enable("with", "without") def test_option_value_invalid_nargs(self): with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs="foo") self.assertEqual( str(e.exception), "nargs must be a positive integer, '?', '*' or '+'" ) with self.assertRaises(InvalidOptionError) as e: Option("--option", nargs=-2) self.assertEqual( str(e.exception), "nargs must be a positive integer, '?', '*' or '+'" ) def test_option_value_nargs_1(self): self.test_option_value(nargs=1) self.test_option_value(nargs=1, default=("a",)) self.test_option_value_enable(nargs=1, default=("a",)) # A default is required with self.assertRaises(InvalidOptionError) as e: Option("--disable-option", nargs=1) self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) def test_option_value_nargs_2(self): self.test_option_value(nargs=2) self.test_option_value(nargs=2, default=("a", "b")) self.test_option_value_enable(nargs=2, default=("a", "b")) # A default is required with self.assertRaises(InvalidOptionError) as e: Option("--disable-option", nargs=2) self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) def test_option_value_nargs_0_or_1(self): self.test_option_value(nargs="?") self.test_option_value(nargs="?", default=("a",)) self.test_option_value_enable(nargs="?") self.test_option_value_enable(nargs="?", default=("a",)) def test_option_value_nargs_0_or_more(self): self.test_option_value(nargs="*") self.test_option_value(nargs="*", default=("a",)) self.test_option_value(nargs="*", default=("a", "b")) self.test_option_value_enable(nargs="*") self.test_option_value_enable(nargs="*", default=("a",)) self.test_option_value_enable(nargs="*", default=("a", "b")) def test_option_value_nargs_1_or_more(self): self.test_option_value(nargs="+") self.test_option_value(nargs="+", default=("a",)) self.test_option_value(nargs="+", default=("a", "b")) self.test_option_value_enable(nargs="+", default=("a",)) self.test_option_value_enable(nargs="+", default=("a", "b")) # A default is required with self.assertRaises(InvalidOptionError) as e: Option("--disable-option", nargs="+") self.assertEqual( str(e.exception), "The given `default` doesn't satisfy `nargs`" ) class TestCommandLineHelper(unittest.TestCase): def test_basic(self): helper = CommandLineHelper({}, ["cmd", "--foo", "--bar"]) self.assertEqual(["--foo", "--bar"], list(helper)) helper.add("--enable-qux") self.assertEqual(["--foo", "--bar", "--enable-qux"], list(helper)) value, option = helper.handle(Option("--bar")) self.assertEqual(["--foo", "--enable-qux"], list(helper)) self.assertEqual(PositiveOptionValue(), value) self.assertEqual("--bar", option) value, option = helper.handle(Option("--baz")) self.assertEqual(["--foo", "--enable-qux"], list(helper)) self.assertEqual(NegativeOptionValue(), value) self.assertEqual(None, option) with self.assertRaises(AssertionError): CommandLineHelper({}, ["--foo", "--bar"]) def test_precedence(self): foo = Option("--with-foo", nargs="*") helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b"]) value, option = helper.handle(foo) self.assertEqual(PositiveOptionValue(("a", "b")), value) self.assertEqual("command-line", value.origin) self.assertEqual("--with-foo=a,b", option) helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b", "--without-foo"]) value, option = helper.handle(foo) self.assertEqual(NegativeOptionValue(), value) self.assertEqual("command-line", value.origin) self.assertEqual("--without-foo", option) helper = CommandLineHelper({}, ["cmd", "--without-foo", "--with-foo=a,b"]) value, option = helper.handle(foo) self.assertEqual(PositiveOptionValue(("a", "b")), value) self.assertEqual("command-line", value.origin) self.assertEqual("--with-foo=a,b", option) foo = Option("--with-foo", env="FOO", nargs="*") helper = CommandLineHelper({"FOO": ""}, ["cmd", "--with-foo=a,b"]) value, option = helper.handle(foo) self.assertEqual(PositiveOptionValue(("a", "b")), value) self.assertEqual("command-line", value.origin) self.assertEqual("--with-foo=a,b", option) helper = CommandLineHelper({"FOO": "a,b"}, ["cmd", "--without-foo"]) value, option = helper.handle(foo) self.assertEqual(NegativeOptionValue(), value) self.assertEqual("command-line", value.origin) self.assertEqual("--without-foo", option) helper = CommandLineHelper({"FOO": ""}, ["cmd", "--with-bar=a,b"]) value, option = helper.handle(foo) self.assertEqual(NegativeOptionValue(), value) self.assertEqual("environment", value.origin) self.assertEqual("FOO=", option) helper = CommandLineHelper({"FOO": "a,b"}, ["cmd", "--without-bar"]) value, option = helper.handle(foo) self.assertEqual(PositiveOptionValue(("a", "b")), value) self.assertEqual("environment", value.origin) self.assertEqual("FOO=a,b", option) helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b", "FOO="]) value, option = helper.handle(foo) self.assertEqual(NegativeOptionValue(), value) self.assertEqual("command-line", value.origin) self.assertEqual("FOO=", option) helper = CommandLineHelper({}, ["cmd", "--without-foo", "FOO=a,b"]) value, option = helper.handle(foo) self.assertEqual(PositiveOptionValue(("a", "b")), value) self.assertEqual("command-line", value.origin) self.assertEqual("FOO=a,b", option) helper = CommandLineHelper({}, ["cmd", "FOO=", "--with-foo=a,b"]) value, option = helper.handle(foo) self.assertEqual(PositiveOptionValue(("a", "b")), value) self.assertEqual("command-line", value.origin) self.assertEqual("--with-foo=a,b", option) helper = CommandLineHelper({}, ["cmd", "FOO=a,b", "--without-foo"]) value, option = helper.handle(foo) self.assertEqual(NegativeOptionValue(), value) self.assertEqual("command-line", value.origin) self.assertEqual("--without-foo", option) def test_extra_args(self): foo = Option("--with-foo", env="FOO", nargs="*") helper = CommandLineHelper({}, ["cmd"]) helper.add("FOO=a,b,c", "other-origin") value, option = helper.handle(foo) self.assertEqual(PositiveOptionValue(("a", "b", "c")), value) self.assertEqual("other-origin", value.origin) self.assertEqual("FOO=a,b,c", option) helper = CommandLineHelper({}, ["cmd"]) helper.add("FOO=a,b,c", "other-origin") helper.add("--with-foo=a,b,c", "other-origin") value, option = helper.handle(foo) self.assertEqual(PositiveOptionValue(("a", "b", "c")), value) self.assertEqual("other-origin", value.origin) self.assertEqual("--with-foo=a,b,c", option) # Adding conflicting options is not allowed. helper = CommandLineHelper({}, ["cmd"]) helper.add("FOO=a,b,c", "other-origin") with self.assertRaises(ConflictingOptionError) as cm: helper.add("FOO=", "other-origin") self.assertEqual("FOO=", cm.exception.arg) self.assertEqual("other-origin", cm.exception.origin) self.assertEqual("FOO=a,b,c", cm.exception.old_arg) self.assertEqual("other-origin", cm.exception.old_origin) with self.assertRaises(ConflictingOptionError) as cm: helper.add("FOO=a,b", "other-origin") self.assertEqual("FOO=a,b", cm.exception.arg) self.assertEqual("other-origin", cm.exception.origin) self.assertEqual("FOO=a,b,c", cm.exception.old_arg) self.assertEqual("other-origin", cm.exception.old_origin) # But adding the same is allowed. helper.add("FOO=a,b,c", "other-origin") value, option = helper.handle(foo) self.assertEqual(PositiveOptionValue(("a", "b", "c")), value) self.assertEqual("other-origin", value.origin) self.assertEqual("FOO=a,b,c", option) # The same rule as above applies when using the option form vs. the # variable form. But we can't detect it when .add is called. helper = CommandLineHelper({}, ["cmd"]) helper.add("FOO=a,b,c", "other-origin") helper.add("--without-foo", "other-origin") with self.assertRaises(ConflictingOptionError) as cm: helper.handle(foo) self.assertEqual("--without-foo", cm.exception.arg) self.assertEqual("other-origin", cm.exception.origin) self.assertEqual("FOO=a,b,c", cm.exception.old_arg) self.assertEqual("other-origin", cm.exception.old_origin) helper = CommandLineHelper({}, ["cmd"]) helper.add("FOO=a,b,c", "other-origin") helper.add("--with-foo=a,b", "other-origin") with self.assertRaises(ConflictingOptionError) as cm: helper.handle(foo) self.assertEqual("--with-foo=a,b", cm.exception.arg) self.assertEqual("other-origin", cm.exception.origin) self.assertEqual("FOO=a,b,c", cm.exception.old_arg) self.assertEqual("other-origin", cm.exception.old_origin) helper = CommandLineHelper({}, ["cmd"]) helper.add("FOO=a,b,c", "other-origin") helper.add("--with-foo=a,b,c", "other-origin") value, option = helper.handle(foo) self.assertEqual(PositiveOptionValue(("a", "b", "c")), value) self.assertEqual("other-origin", value.origin) self.assertEqual("--with-foo=a,b,c", option) # Conflicts are also not allowed against what is in the # environment/on the command line. helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b"]) helper.add("FOO=a,b,c", "other-origin") with self.assertRaises(ConflictingOptionError) as cm: helper.handle(foo) self.assertEqual("FOO=a,b,c", cm.exception.arg) self.assertEqual("other-origin", cm.exception.origin) self.assertEqual("--with-foo=a,b", cm.exception.old_arg) self.assertEqual("command-line", cm.exception.old_origin) helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b"]) helper.add("--without-foo", "other-origin") with self.assertRaises(ConflictingOptionError) as cm: helper.handle(foo) self.assertEqual("--without-foo", cm.exception.arg) self.assertEqual("other-origin", cm.exception.origin) self.assertEqual("--with-foo=a,b", cm.exception.old_arg) self.assertEqual("command-line", cm.exception.old_origin) def test_possible_origins(self): with self.assertRaises(InvalidOptionError): Option("--foo", possible_origins="command-line") helper = CommandLineHelper({"BAZ": "1"}, ["cmd", "--foo", "--bar"]) foo = Option("--foo", possible_origins=("command-line",)) value, option = helper.handle(foo) self.assertEqual(PositiveOptionValue(), value) self.assertEqual("command-line", value.origin) self.assertEqual("--foo", option) bar = Option("--bar", possible_origins=("mozconfig",)) with self.assertRaisesRegexp( InvalidOptionError, "--bar can not be set by command-line. Values are accepted from: mozconfig", ): helper.handle(bar) baz = Option(env="BAZ", possible_origins=("implied",)) with self.assertRaisesRegexp( InvalidOptionError, "BAZ=1 can not be set by environment. Values are accepted from: implied", ): helper.handle(baz) if __name__ == "__main__": main()