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_defaults(self): config = self.get_config() self.maxDiff = None self.assertEquals( { 'CHOICES': NegativeOptionValue(), 'DEFAULTED': PositiveOptionValue(('not-simple', )), 'IS_GCC': NegativeOptionValue(), 'REMAINDER': (PositiveOptionValue(), NegativeOptionValue(), NegativeOptionValue(), NegativeOptionValue()), 'SIMPLE': NegativeOptionValue(), 'VALUES': NegativeOptionValue(), 'VALUES2': NegativeOptionValue(), 'VALUES3': NegativeOptionValue(), 'WITH_ENV': NegativeOptionValue(), 'IMPLIED': NegativeOptionValue(), 'IMPLIED_ENV': NegativeOptionValue(), 'IMPLIED_VALUES': NegativeOptionValue(), }, config)
def test_option_choices(self): with self.assertRaises(InvalidOptionError) as e: Option('--option', nargs=3, choices=('a', 'b')) self.assertEquals(e.exception.message, 'Not enough `choices` for `nargs`') with self.assertRaises(InvalidOptionError) as e: Option('--without-option', nargs=1, choices=('a', 'b')) self.assertEquals(e.exception.message, 'A `default` must be given along with `choices`') with self.assertRaises(InvalidOptionError) as e: Option('--without-option', nargs='+', choices=('a', 'b')) self.assertEquals(e.exception.message, 'A `default` must be given along with `choices`') with self.assertRaises(InvalidOptionError) as e: Option('--without-option', default='c', choices=('a', 'b')) self.assertEquals(e.exception.message, "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.assertEquals(e.exception.message, "The `default` value must be one of 'a', 'b'") with self.assertRaises(InvalidOptionError) as e: Option('--without-option', default=('c', ), choices=('a', 'b')) self.assertEquals(e.exception.message, "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.assertEquals(e.exception.message, "'c' is not one of 'a', 'b'") value = option.get_value('--with-option=b,a') self.assertTrue(value) self.assertEquals(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.assertEquals(e.exception.message, "'c' is not one of 'a', 'b'") value = option.get_value('--with-option=b,a') self.assertTrue(value) self.assertEquals(PositiveOptionValue(('b', 'a')), value) # Test nargs inference from choices option = Option('--with-option', choices=('a', 'b')) self.assertEqual(option.nargs, 1)
def test_imply_option_values(self): def get_config(*args): return self.get_config(*args, configure='imply_option/values.configure') help, config = get_config(['--help']) self.assertEquals(config, {}) config = get_config([]) self.assertEquals(config, {}) config = get_config(['--enable-foo=a']) self.assertIn('BAR', config) self.assertEquals(config['BAR'], PositiveOptionValue(('a', ))) config = get_config(['--enable-foo=a,b']) self.assertIn('BAR', config) self.assertEquals(config['BAR'], PositiveOptionValue(('a', 'b'))) with self.assertRaises(InvalidOptionError) as e: get_config(['--enable-foo=a,b', '--disable-bar']) self.assertEquals( e.exception.message, "'--enable-bar=a,b' implied by '--enable-foo' conflicts with " "'--disable-bar' from the command-line")
def test_depends_or(self): with self.moz_configure(''' option('--foo', nargs=1, help='foo') @depends('--foo') def foo(value): return value or None option('--bar', nargs=1, help='bar') @depends('--bar') def bar(value): return value set_config('FOOBAR', foo | bar) '''): config = self.get_config() self.assertEqual(config, { 'FOOBAR': NegativeOptionValue(), }) config = self.get_config(['--foo=foo']) self.assertEqual(config, { 'FOOBAR': PositiveOptionValue(('foo', )), }) config = self.get_config(['--bar=bar']) self.assertEqual(config, { 'FOOBAR': PositiveOptionValue(('bar', )), }) config = self.get_config(['--foo=foo', '--bar=bar']) self.assertEqual(config, { 'FOOBAR': PositiveOptionValue(('foo', )), })
def _value_for_option(self, option): implied = {} for implied_option in self._implied_options[:]: if implied_option.name not in (option.name, option.env): continue self._implied_options.remove(implied_option) if (implied_option.when and not self._value_for(implied_option.when)): continue value = self._resolve(implied_option.value, need_help_dependency=False) if value is not None: if isinstance(value, OptionValue): pass elif value is True: value = PositiveOptionValue() elif value is False or value == (): value = NegativeOptionValue() elif isinstance(value, types.StringTypes): value = PositiveOptionValue((value,)) elif isinstance(value, tuple): value = PositiveOptionValue(value) else: raise TypeError("Unexpected type: '%s'" % type(value).__name__) opt = value.format(implied_option.option) self._helper.add(opt, 'implied') implied[opt] = implied_option try: value, option_string = self._helper.handle(option) except ConflictingOptionError as e: reason = implied[e.arg].reason if isinstance(reason, Option): reason = self._raw_options.get(reason) or reason.option reason = reason.split('=', 1)[0] raise InvalidOptionError( "'%s' implied by '%s' conflicts with '%s' from the %s" % (e.arg, reason, e.old_arg, e.old_origin)) if option_string: self._raw_options[option] = option_string when = self._conditions.get(option) if (when and not self._value_for(when, need_help_dependency=True) and value is not None and value.origin != 'default'): if value.origin == 'environment': # The value we return doesn't really matter, because of the # requirement for @depends to have the same when. return None raise InvalidOptionError( '%s is not available in this configuration' % option_string.split('=', 1)[0]) return value
def test_returned_default(self): config = self.get_config(['--enable-simple']) self.assertIn('DEFAULTED', config) self.assertEquals(PositiveOptionValue(('simple', )), config['DEFAULTED']) config = self.get_config(['--disable-simple']) self.assertIn('DEFAULTED', config) self.assertEquals(PositiveOptionValue(('not-simple', )), config['DEFAULTED'])
def _value_for_option(self, option): implied = {} for implied_option in self._implied_options[:]: if implied_option.name not in (option.name, option.env): continue self._implied_options.remove(implied_option) if (implied_option.when and not self._value_for(implied_option.when)): continue value = self._resolve(implied_option.value, need_help_dependency=False) if value is not None: if isinstance(value, OptionValue): pass elif value is True: value = PositiveOptionValue() elif value is False or value == (): value = NegativeOptionValue() elif isinstance(value, types.StringTypes): value = PositiveOptionValue((value, )) elif isinstance(value, tuple): value = PositiveOptionValue(value) else: raise TypeError("Unexpected type: '%s'" % type(value).__name__) opt = value.format(implied_option.option) self._helper.add(opt, 'implied') implied[opt] = implied_option try: value, option_string = self._helper.handle(option) except ConflictingOptionError as e: reason = implied[e.arg].reason if isinstance(reason, Option): reason = self._raw_options.get(reason) or reason.option reason = reason.split('=', 1)[0] raise InvalidOptionError( "'%s' implied by '%s' conflicts with '%s' from the %s" % (e.arg, reason, e.old_arg, e.old_origin)) if option_string: self._raw_options[option] = option_string when = self._conditions.get(option) if (when and not self._value_for(when, need_help_dependency=True) and value is not None and value.origin != 'default'): if value.origin == 'environment': # The value we return doesn't really matter, because of the # requirement for @depends to have the same when. return None raise InvalidOptionError( '%s is not available in this configuration' % option_string.split('=', 1)[0]) return value
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.assertEquals(value, NegativeOptionValue()) self.assertEquals(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.assertEquals(value, PositiveOptionValue()) self.assertEquals(value.origin, 'option') else: with self.assertRaises(InvalidOptionError) as e: option.get_value('--%s-option' % enable, 'option') if nargs == 1: self.assertEquals(e.exception.message, '--%s-option takes 1 value' % enable) elif nargs == '+': self.assertEquals( e.exception.message, '--%s-option takes 1 or more values' % enable) else: self.assertEquals(e.exception.message, '--%s-option takes 2 values' % enable)
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.assertEquals(value, NegativeOptionValue()) self.assertEquals(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.assertEquals(value, PositiveOptionValue()) self.assertEquals(value.origin, "option") else: with self.assertRaises(InvalidOptionError) as e: option.get_value("--%s-option" % enable, "option") if nargs == 1: self.assertEquals( str(e.exception), "--%s-option takes 1 value" % enable ) elif nargs == "+": self.assertEquals( str(e.exception), "--%s-option takes 1 or more values" % enable ) else: self.assertEquals( str(e.exception), "--%s-option takes 2 values" % enable )
def test_with_env(self): for config in ( self.get_config(), self.get_config(['--disable-with-env']), self.get_config(['--enable-with-env', '--disable-with-env']), self.get_config(env={'MOZ_WITH_ENV': ''}), # Options win over environment self.get_config(['--disable-with-env'], env={'MOZ_WITH_ENV': '1'}), ): self.assertIn('WITH_ENV', config) self.assertEquals(NegativeOptionValue(), config['WITH_ENV']) for config in ( self.get_config(['--enable-with-env']), self.get_config(['--disable-with-env', '--enable-with-env']), self.get_config(env={'MOZ_WITH_ENV': '1'}), self.get_config(['--enable-with-env'], env={'MOZ_WITH_ENV': ''}), ): self.assertIn('WITH_ENV', config) self.assertEquals(PositiveOptionValue(), config['WITH_ENV']) with self.assertRaises(InvalidOptionError): self.get_config(['--enable-with-env=value']) with self.assertRaises(InvalidOptionError): self.get_config(env={'MOZ_WITH_ENV': 'value'})
def test_depends_getattr(self): with self.moz_configure(''' @imports(_from='mozbuild.util', _import='ReadOnlyNamespace') def namespace(**kwargs): return ReadOnlyNamespace(**kwargs) option('--foo', nargs=1, help='foo') @depends('--foo') def foo(value): return value option('--bar', nargs=1, help='bar') @depends('--bar') def bar(value): return value or None @depends(foo, bar) def foobar(foo, bar): return namespace(foo=foo, bar=bar) set_config('FOO', foobar.foo) set_config('BAR', foobar.bar) set_config('BAZ', foobar.baz) '''): config = self.get_config() self.assertEqual(config, { 'FOO': NegativeOptionValue(), }) config = self.get_config(['--foo=foo']) self.assertEqual(config, { 'FOO': PositiveOptionValue(('foo', )), }) config = self.get_config(['--bar=bar']) self.assertEqual( config, { 'FOO': NegativeOptionValue(), 'BAR': PositiveOptionValue(('bar', )), }) config = self.get_config(['--foo=foo', '--bar=bar']) self.assertEqual( config, { 'FOO': PositiveOptionValue(('foo', )), 'BAR': PositiveOptionValue(('bar', )), })
def test_depends_binary_ops(self): with self.moz_configure(''' option('--foo', nargs=1, help='foo') @depends('--foo') def foo(value): return value or 0 option('--bar', nargs=1, help='bar') @depends('--bar') def bar(value): return value or '' option('--baz', nargs=1, help='baz') @depends('--baz') def baz(value): return value set_config('FOOorBAR', foo | bar) set_config('FOOorBARorBAZ', foo | bar | baz) set_config('FOOandBAR', foo & bar) set_config('FOOandBARandBAZ', foo & bar & baz) '''): for foo_opt, foo_value in (('', 0), ('--foo=foo', PositiveOptionValue( ('foo', )))): for bar_opt, bar_value in (('', ''), ('--bar=bar', PositiveOptionValue( ('bar', )))): for baz_opt, baz_value in (('', NegativeOptionValue()), ('--baz=baz', PositiveOptionValue( ('baz', )))): config = self.get_config( [x for x in (foo_opt, bar_opt, baz_opt) if x]) self.assertEqual( config, { 'FOOorBAR': foo_value or bar_value, 'FOOorBARorBAZ': foo_value or bar_value or baz_value, 'FOOandBAR': foo_value and bar_value, 'FOOandBARandBAZ': foo_value and bar_value and baz_value, })
def test_returned_choices(self): for val in ('a', 'b', 'c'): config = self.get_config( ['--enable-values=alpha', '--returned-choices=%s' % val]) self.assertIn('CHOICES', config) self.assertEquals(PositiveOptionValue((val,)), config['CHOICES']) for val in ('0', '1', '2'): config = self.get_config( ['--enable-values=numeric', '--returned-choices=%s' % val]) self.assertIn('CHOICES', config) self.assertEquals(PositiveOptionValue((val,)), config['CHOICES']) with self.assertRaises(InvalidOptionError): self.get_config(['--enable-values=numeric', '--returned-choices=a']) with self.assertRaises(InvalidOptionError): self.get_config(['--enable-values=alpha', '--returned-choices=0'])
def test_included(self): config = self.get_config(env={'CC': 'gcc'}) self.assertIn('IS_GCC', config) self.assertEquals(config['IS_GCC'], True) config = self.get_config( ['--enable-include=extra.configure', '--extra']) self.assertIn('EXTRA', config) self.assertEquals(PositiveOptionValue(), config['EXTRA']) with self.assertRaises(InvalidOptionError): self.get_config(['--extra'])
def test_option_choices(self): with self.assertRaises(InvalidOptionError): Option('--option', nargs=3, choices=('a', 'b')) with self.assertRaises(InvalidOptionError): Option('--without-option', nargs=1, choices=('a', 'b')) with self.assertRaises(InvalidOptionError): Option('--without-option', nargs='+', choices=('a', 'b')) with self.assertRaises(InvalidOptionError): Option('--without-option', default='c', choices=('a', 'b')) with self.assertRaises(InvalidOptionError): Option('--without-option', default=('a', 'c',), choices=('a', 'b')) with self.assertRaises(InvalidOptionError): Option('--without-option', default=('c',), choices=('a', 'b')) option = Option('--with-option', nargs='+', choices=('a', 'b')) with self.assertRaises(InvalidOptionError): option.get_value('--with-option=c') value = option.get_value('--with-option=b,a') self.assertTrue(value) self.assertEquals(PositiveOptionValue(('b', 'a')), value) option = Option('--without-option', nargs='*', default='a', choices=('a', 'b')) with self.assertRaises(InvalidOptionError): option.get_value('--with-option=c') value = option.get_value('--with-option=b,a') self.assertTrue(value) self.assertEquals(PositiveOptionValue(('b', 'a')), value) # Test nargs inference from choices option = Option('--with-option', choices=('a', 'b')) self.assertEqual(option.nargs, 1)
def test_values(self, name='VALUES'): for config in ( self.get_config(), self.get_config(['--disable-values']), self.get_config(['--enable-values', '--disable-values']), ): self.assertIn(name, config) self.assertEquals(NegativeOptionValue(), config[name]) for config in ( self.get_config(['--enable-values']), self.get_config(['--disable-values', '--enable-values']), ): self.assertIn(name, config) self.assertEquals(PositiveOptionValue(), config[name]) config = self.get_config(['--enable-values=foo']) self.assertIn(name, config) self.assertEquals(PositiveOptionValue(('foo', )), config[name]) config = self.get_config(['--enable-values=foo,bar']) self.assertIn(name, config) self.assertTrue(config[name]) self.assertEquals(PositiveOptionValue(('foo', 'bar')), config[name])
def test_implied_options(self): config = self.get_config(['--enable-values']) self.assertIn('IMPLIED', config) self.assertIn('IMPLIED_VALUES', config) self.assertIn('IMPLIED_ENV', config) self.assertEquals(PositiveOptionValue(), config['IMPLIED']) self.assertEquals(PositiveOptionValue(), config['IMPLIED_VALUES']) self.assertEquals(PositiveOptionValue(), config['IMPLIED_ENV']) config = self.get_config(['--enable-values=a']) self.assertIn('IMPLIED', config) self.assertIn('IMPLIED_VALUES', config) self.assertIn('IMPLIED_ENV', config) self.assertEquals(PositiveOptionValue(), config['IMPLIED']) self.assertEquals(PositiveOptionValue(('a', )), config['IMPLIED_VALUES']) self.assertEquals(PositiveOptionValue(('a', )), config['IMPLIED_ENV']) config = self.get_config(['--enable-values=a,b']) self.assertIn('IMPLIED', config) self.assertIn('IMPLIED_VALUES', config) self.assertIn('IMPLIED_ENV', config) self.assertEquals(PositiveOptionValue(), config['IMPLIED']) self.assertEquals(PositiveOptionValue(('a', 'b')), config['IMPLIED_VALUES']) self.assertEquals(PositiveOptionValue(('a', 'b')), config['IMPLIED_ENV']) config = self.get_config(['--disable-values']) self.assertIn('IMPLIED', config) self.assertIn('IMPLIED_VALUES', config) self.assertIn('IMPLIED_ENV', config) self.assertEquals(NegativeOptionValue(), config['IMPLIED']) self.assertEquals(NegativeOptionValue(), config['IMPLIED_VALUES']) self.assertEquals(NegativeOptionValue(), config['IMPLIED_ENV']) # --enable-values implies --enable-implied, which conflicts with # --disable-implied with self.assertRaises(InvalidOptionError): self.get_config(['--enable-values', '--disable-implied'])
def test_imply_option_when(self): with self.moz_configure(''' option('--with-foo', help='foo') imply_option('--with-qux', True, when='--with-foo') option('--with-qux', help='qux') set_config('QUX', depends('--with-qux')(lambda x: x)) '''): config = self.get_config() self.assertEquals(config, { 'QUX': NegativeOptionValue(), }) config = self.get_config(['--with-foo']) self.assertEquals(config, { 'QUX': PositiveOptionValue(), })
def _value_for_option(self, option): implied = {} for implied_option in self._implied_options[:]: if implied_option.name not in (option.name, option.env): continue self._implied_options.remove(implied_option) value = self._resolve(implied_option.value, need_help_dependency=False) if value is not None: if isinstance(value, OptionValue): pass elif value is True: value = PositiveOptionValue() elif value is False or value == (): value = NegativeOptionValue() elif isinstance(value, types.StringTypes): value = PositiveOptionValue((value,)) elif isinstance(value, tuple): value = PositiveOptionValue(value) else: raise TypeError("Unexpected type: '%s'" % type(value).__name__) opt = value.format(implied_option.option) self._helper.add(opt, 'implied') implied[opt] = implied_option try: value, option_string = self._helper.handle(option) except ConflictingOptionError as e: reason = implied[e.arg].reason if isinstance(reason, Option): reason = self._raw_options.get(reason) or reason.option reason = reason.split('=', 1)[0] raise InvalidOptionError( "'%s' implied by '%s' conflicts with '%s' from the %s" % (e.arg, reason, e.old_arg, e.old_origin)) if option_string: self._raw_options[option] = option_string return value
def test_basic(self): helper = CommandLineHelper({}, ['cmd', '--foo', '--bar']) self.assertEquals(['--foo', '--bar'], list(helper)) helper.add('--enable-qux') self.assertEquals(['--foo', '--bar', '--enable-qux'], list(helper)) value, option = helper.handle(Option('--bar')) self.assertEquals(['--foo', '--enable-qux'], list(helper)) self.assertEquals(PositiveOptionValue(), value) self.assertEquals('--bar', option) value, option = helper.handle(Option('--baz')) self.assertEquals(['--foo', '--enable-qux'], list(helper)) self.assertEquals(NegativeOptionValue(), value) self.assertEquals(None, 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.assertEquals(value, NegativeOptionValue()) self.assertEquals(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.assertEquals(value, PositiveOptionValue()) self.assertEquals(value.origin, 'option') else: with self.assertRaises(InvalidOptionError): option.get_value('--%s-option' % enable, 'option')
def test_basic(self): helper = CommandLineHelper({}, ["cmd", "--foo", "--bar"]) self.assertEquals(["--foo", "--bar"], list(helper)) helper.add("--enable-qux") self.assertEquals(["--foo", "--bar", "--enable-qux"], list(helper)) value, option = helper.handle(Option("--bar")) self.assertEquals(["--foo", "--enable-qux"], list(helper)) self.assertEquals(PositiveOptionValue(), value) self.assertEquals("--bar", option) value, option = helper.handle(Option("--baz")) self.assertEquals(["--foo", "--enable-qux"], list(helper)) self.assertEquals(NegativeOptionValue(), value) self.assertEquals(None, option) with self.assertRaises(AssertionError): CommandLineHelper({}, ["--foo", "--bar"])
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.assertEquals(PositiveOptionValue(), value) self.assertEquals('command-line', value.origin) self.assertEquals('--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)
def test_imply_option_simple(self): def get_config(*args): return self.get_config(*args, configure='imply_option/simple.configure') config, out = self.get_result( ['--help'], configure='imply_option/simple.configure') self.assertEquals(config, {}) config = get_config([]) self.assertEquals(config, {}) config = get_config(['--enable-foo']) self.assertIn('BAR', config) self.assertEquals(config['BAR'], PositiveOptionValue()) with self.assertRaises(InvalidOptionError) as e: get_config(['--enable-foo', '--disable-bar']) self.assertEquals( e.exception.message, "'--enable-bar' implied by '--enable-foo' conflicts with " "'--disable-bar' from the command-line")
def test_simple(self): for config in ( self.get_config(), self.get_config(['--disable-simple']), # Last option wins. self.get_config(['--enable-simple', '--disable-simple']), ): self.assertNotIn('ENABLED_SIMPLE', config) self.assertIn('SIMPLE', config) self.assertEquals(NegativeOptionValue(), config['SIMPLE']) for config in ( self.get_config(['--enable-simple']), self.get_config(['--disable-simple', '--enable-simple']), ): self.assertIn('ENABLED_SIMPLE', config) self.assertIn('SIMPLE', config) self.assertEquals(PositiveOptionValue(), config['SIMPLE']) self.assertIs(config['SIMPLE'], config['ENABLED_SIMPLE']) # --enable-simple doesn't take values. with self.assertRaises(InvalidOptionError): self.get_config(['--enable-simple=value'])
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.assertEquals(PositiveOptionValue(), value) self.assertEquals("command-line", value.origin) self.assertEquals("--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)
def test_option_when(self): with self.moz_configure(''' option('--with-foo', help='foo', when=True) option('--with-bar', help='bar', when=False) option('--with-qux', env="QUX", help='qux', when='--with-foo') set_config('FOO', depends('--with-foo', when=True)(lambda x: x)) set_config('BAR', depends('--with-bar', when=False)(lambda x: x)) set_config('QUX', depends('--with-qux', when='--with-foo')(lambda x: x)) '''): config = self.get_config() self.assertEquals(config, { 'FOO': NegativeOptionValue(), }) config = self.get_config(['--with-foo']) self.assertEquals(config, { 'FOO': PositiveOptionValue(), 'QUX': NegativeOptionValue(), }) config = self.get_config(['--with-foo', '--with-qux']) self.assertEquals(config, { 'FOO': PositiveOptionValue(), 'QUX': PositiveOptionValue(), }) with self.assertRaises(InvalidOptionError) as e: self.get_config(['--with-bar']) self.assertEquals( e.exception.message, '--with-bar is not available in this configuration') with self.assertRaises(InvalidOptionError) as e: self.get_config(['--with-qux']) self.assertEquals( e.exception.message, '--with-qux is not available in this configuration') with self.assertRaises(InvalidOptionError) as e: self.get_config(['QUX=1']) self.assertEquals(e.exception.message, 'QUX is not available in this configuration') config = self.get_config(env={'QUX': '1'}) self.assertEquals(config, { 'FOO': NegativeOptionValue(), }) help, config = self.get_config(['--help']) self.assertEquals( help, textwrap.dedent('''\ Usage: configure [options] Options: [defaults in brackets after descriptions] --help print this message --with-foo foo Environment variables: ''')) help, config = self.get_config(['--help', '--with-foo']) self.assertEquals( help, textwrap.dedent('''\ Usage: configure [options] Options: [defaults in brackets after descriptions] --help print this message --with-foo foo --with-qux qux Environment variables: ''')) with self.moz_configure(''' option('--with-foo', help='foo', when=True) set_config('FOO', depends('--with-foo')(lambda x: x)) '''): with self.assertRaises(ConfigureError) as e: self.get_config() self.assertEquals( e.exception.message, '@depends function needs the same `when` as ' 'options it depends on') with self.moz_configure(''' @depends(when=True) def always(): return True @depends(when=True) def always2(): return True option('--with-foo', help='foo', when=always) set_config('FOO', depends('--with-foo', when=always2)(lambda x: x)) '''): with self.assertRaises(ConfigureError) as e: self.get_config() self.assertEquals( e.exception.message, '@depends function needs the same `when` as ' 'options it depends on') with self.moz_configure(''' @depends(when=True) def always(): return True @depends(when=True) def always2(): return True with only_when(always2): option('--with-foo', help='foo', when=always) # include() triggers resolution of its dependencies, and their # side effects. include(depends('--with-foo', when=always)(lambda x: x)) # The sandbox should figure that the `when` here is # appropriate. Bad behavior in CombinedDependsFunction.__eq__ # made this fail in the past. set_config('FOO', depends('--with-foo', when=always)(lambda x: x)) '''): self.get_config() with self.moz_configure(''' option('--with-foo', help='foo') option('--without-bar', help='bar', when='--with-foo') option('--with-qux', help='qux', when='--with-bar') set_config('QUX', True, when='--with-qux') '''): # These are valid: self.get_config(['--with-foo']) self.get_config(['--with-foo', '--with-bar']) self.get_config(['--with-foo', '--without-bar']) self.get_config(['--with-foo', '--with-bar', '--with-qux']) self.get_config(['--with-foo', '--with-bar', '--without-qux']) with self.assertRaises(InvalidOptionError) as e: self.get_config(['--with-bar']) with self.assertRaises(InvalidOptionError) as e: self.get_config(['--without-bar']) with self.assertRaises(InvalidOptionError) as e: self.get_config(['--with-qux']) with self.assertRaises(InvalidOptionError) as e: self.get_config(['--without-qux']) with self.assertRaises(InvalidOptionError) as e: self.get_config(['--with-foo', '--without-bar', '--with-qux']) with self.assertRaises(InvalidOptionError) as e: self.get_config( ['--with-foo', '--without-bar', '--without-qux'])
def test_option_value_format(self): val = PositiveOptionValue() self.assertEquals('--with-value', val.format('--with-value')) self.assertEquals('--with-value', val.format('--without-value')) self.assertEquals('--enable-value', val.format('--enable-value')) self.assertEquals('--enable-value', val.format('--disable-value')) self.assertEquals('--value', val.format('--value')) self.assertEquals('VALUE=1', val.format('VALUE')) val = PositiveOptionValue(('a',)) self.assertEquals('--with-value=a', val.format('--with-value')) self.assertEquals('--with-value=a', val.format('--without-value')) self.assertEquals('--enable-value=a', val.format('--enable-value')) self.assertEquals('--enable-value=a', val.format('--disable-value')) self.assertEquals('--value=a', val.format('--value')) self.assertEquals('VALUE=a', val.format('VALUE')) val = PositiveOptionValue(('a', 'b')) self.assertEquals('--with-value=a,b', val.format('--with-value')) self.assertEquals('--with-value=a,b', val.format('--without-value')) self.assertEquals('--enable-value=a,b', val.format('--enable-value')) self.assertEquals('--enable-value=a,b', val.format('--disable-value')) self.assertEquals('--value=a,b', val.format('--value')) self.assertEquals('VALUE=a,b', val.format('VALUE')) val = NegativeOptionValue() self.assertEquals('--without-value', val.format('--with-value')) self.assertEquals('--without-value', val.format('--without-value')) self.assertEquals('--disable-value', val.format('--enable-value')) self.assertEquals('--disable-value', val.format('--disable-value')) self.assertEquals('', val.format('--value')) self.assertEquals('VALUE=', val.format('VALUE'))
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.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value) self.assertEquals('other-origin', value.origin) self.assertEquals('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.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value) self.assertEquals('other-origin', value.origin) self.assertEquals('--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.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value) self.assertEquals('other-origin', value.origin) self.assertEquals('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.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value) self.assertEquals('other-origin', value.origin) self.assertEquals('--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 imply_option_impl(self, option, value, reason=None): '''Implementation of imply_option(). Injects additional options as if they had been passed on the command line. The `option` argument is a string as in option()'s `name` or `env`. The option must be declared after `imply_option` references it. The `value` argument indicates the value to pass to the option. It can be: - True. In this case `imply_option` injects the positive option (--enable-foo/--with-foo). imply_option('--enable-foo', True) imply_option('--disable-foo', True) are both equivalent to `--enable-foo` on the command line. - False. In this case `imply_option` injects the negative option (--disable-foo/--without-foo). imply_option('--enable-foo', False) imply_option('--disable-foo', False) are both equivalent to `--disable-foo` on the command line. - None. In this case `imply_option` does nothing. imply_option('--enable-foo', None) imply_option('--disable-foo', None) are both equivalent to not passing any flag on the command line. - a string or a tuple. In this case `imply_option` injects the positive option with the given value(s). imply_option('--enable-foo', 'a') imply_option('--disable-foo', 'a') are both equivalent to `--enable-foo=a` on the command line. imply_option('--enable-foo', ('a', 'b')) imply_option('--disable-foo', ('a', 'b')) are both equivalent to `--enable-foo=a,b` on the command line. Because imply_option('--disable-foo', ...) can be misleading, it is recommended to use the positive form ('--enable' or '--with') for `option`. The `value` argument can also be (and usually is) a reference to a @depends function, in which case the result of that function will be used as per the descripted mapping above. The `reason` argument indicates what caused the option to be implied. It is necessary when it cannot be inferred from the `value`. ''' # Don't do anything when --help was on the command line if self._help: return if not reason and isinstance(value, DummyFunction): deps = self._depends[value][1] possible_reasons = [d for d in deps if d != self._help_option] if len(possible_reasons) == 1: if isinstance(possible_reasons[0], Option): reason = (self._raw_options.get(possible_reasons[0]) or possible_reasons[0].option) if not reason or not isinstance(value, DummyFunction): raise ConfigureError( "Cannot infer what implies '%s'. Please add a `reason` to " "the `imply_option` call." % option) value = self._resolve(value, need_help_dependency=False) if value is not None: if isinstance(value, OptionValue): pass elif value is True: value = PositiveOptionValue() elif value is False or value == (): value = NegativeOptionValue() elif isinstance(value, types.StringTypes): value = PositiveOptionValue((value, )) elif isinstance(value, tuple): value = PositiveOptionValue(value) else: raise TypeError("Unexpected type: '%s'" % type(value)) option = value.format(option) self._helper.add(option, 'implied') self._implied_options[option] = inspect.stack()[1], reason
def test_only_when(self): moz_configure = ''' option('--enable-when', help='when') @depends('--enable-when', '--help') def when(value, _): return bool(value) with only_when(when): option('--foo', nargs='*', help='foo') @depends('--foo') def foo(value): return value set_config('FOO', foo) set_define('FOO', foo) # It is possible to depend on a function defined in a only_when # block. It then resolves to `None`. set_config('BAR', depends(foo)(lambda x: x)) set_define('BAR', depends(foo)(lambda x: x)) ''' with self.moz_configure(moz_configure): config = self.get_config() self.assertEqual(config, { 'DEFINES': {}, }) config = self.get_config(['--enable-when']) self.assertEqual( config, { 'BAR': NegativeOptionValue(), 'FOO': NegativeOptionValue(), 'DEFINES': { 'BAR': NegativeOptionValue(), 'FOO': NegativeOptionValue(), }, }) config = self.get_config(['--enable-when', '--foo=bar']) self.assertEqual( config, { 'BAR': PositiveOptionValue(['bar']), 'FOO': PositiveOptionValue(['bar']), 'DEFINES': { 'BAR': PositiveOptionValue(['bar']), 'FOO': PositiveOptionValue(['bar']), }, }) # The --foo option doesn't exist when --enable-when is not given. with self.assertRaises(InvalidOptionError) as e: self.get_config(['--foo']) self.assertEquals(e.exception.message, '--foo is not available in this configuration') # Cannot depend on an option defined in a only_when block, because we # don't know what OptionValue would make sense. with self.moz_configure(moz_configure + ''' set_config('QUX', depends('--foo')(lambda x: x)) '''): with self.assertRaises(ConfigureError) as e: self.get_config() self.assertEquals( e.exception.message, '@depends function needs the same `when` as ' 'options it depends on') with self.moz_configure(moz_configure + ''' set_config('QUX', depends('--foo', when=when)(lambda x: x)) '''): self.get_config(['--enable-when']) # Using imply_option for an option defined in a only_when block fails # similarly if the imply_option happens outside the block. with self.moz_configure(''' imply_option('--foo', True) ''' + moz_configure): with self.assertRaises(InvalidOptionError) as e: self.get_config() self.assertEquals(e.exception.message, '--foo is not available in this configuration') # And similarly doesn't fail when the condition is true. with self.moz_configure(''' imply_option('--foo', True) ''' + moz_configure): self.get_config(['--enable-when'])
def imply_option_impl(self, option, value, reason=None): '''Implementation of imply_option(). Injects additional options as if they had been passed on the command line. The `option` argument is a string as in option()'s `name` or `env`. The option must be declared after `imply_option` references it. The `value` argument indicates the value to pass to the option. It can be: - True. In this case `imply_option` injects the positive option (--enable-foo/--with-foo). imply_option('--enable-foo', True) imply_option('--disable-foo', True) are both equivalent to `--enable-foo` on the command line. - False. In this case `imply_option` injects the negative option (--disable-foo/--without-foo). imply_option('--enable-foo', False) imply_option('--disable-foo', False) are both equivalent to `--disable-foo` on the command line. - None. In this case `imply_option` does nothing. imply_option('--enable-foo', None) imply_option('--disable-foo', None) are both equivalent to not passing any flag on the command line. - a string or a tuple. In this case `imply_option` injects the positive option with the given value(s). imply_option('--enable-foo', 'a') imply_option('--disable-foo', 'a') are both equivalent to `--enable-foo=a` on the command line. imply_option('--enable-foo', ('a', 'b')) imply_option('--disable-foo', ('a', 'b')) are both equivalent to `--enable-foo=a,b` on the command line. Because imply_option('--disable-foo', ...) can be misleading, it is recommended to use the positive form ('--enable' or '--with') for `option`. The `value` argument can also be (and usually is) a reference to a @depends function, in which case the result of that function will be used as per the descripted mapping above. The `reason` argument indicates what caused the option to be implied. It is necessary when it cannot be inferred from the `value`. ''' # Don't do anything when --help was on the command line if self._help: return if not reason and isinstance(value, DummyFunction): deps = self._depends[value][1] possible_reasons = [d for d in deps if d != self._help_option] if len(possible_reasons) == 1: if isinstance(possible_reasons[0], Option): reason = (self._raw_options.get(possible_reasons[0]) or possible_reasons[0].option) if not reason or not isinstance(value, DummyFunction): raise ConfigureError( "Cannot infer what implies '%s'. Please add a `reason` to " "the `imply_option` call." % option) value = self._resolve(value, need_help_dependency=False) if value is not None: if isinstance(value, OptionValue): pass elif value is True: value = PositiveOptionValue() elif value is False or value == (): value = NegativeOptionValue() elif isinstance(value, types.StringTypes): value = PositiveOptionValue((value,)) elif isinstance(value, tuple): value = PositiveOptionValue(value) else: raise TypeError("Unexpected type: '%s'" % type(value)) option = value.format(option) self._helper.add(option, 'implied') self._implied_options[option] = inspect.stack()[1], reason