summaryrefslogtreecommitdiffstats
path: root/python/mozbuild/mozbuild/test/configure/test_configure.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/mozbuild/mozbuild/test/configure/test_configure.py')
-rw-r--r--python/mozbuild/mozbuild/test/configure/test_configure.py1986
1 files changed, 1986 insertions, 0 deletions
diff --git a/python/mozbuild/mozbuild/test/configure/test_configure.py b/python/mozbuild/mozbuild/test/configure/test_configure.py
new file mode 100644
index 0000000000..a5e42faae3
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/configure/test_configure.py
@@ -0,0 +1,1986 @@
+# 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 os
+import sys
+import textwrap
+import unittest
+
+import mozpack.path as mozpath
+import six
+from mozunit import MockedOpen, main
+from six import StringIO
+
+from mozbuild.configure import ConfigureError, ConfigureSandbox
+from mozbuild.configure.options import (
+ InvalidOptionError,
+ NegativeOptionValue,
+ PositiveOptionValue,
+)
+from mozbuild.util import ReadOnlyNamespace, exec_, memoized_property
+
+test_data_path = mozpath.abspath(mozpath.dirname(__file__))
+test_data_path = mozpath.join(test_data_path, "data")
+
+
+class TestConfigure(unittest.TestCase):
+ def get_config(
+ self, options=[], env={}, configure="moz.configure", prog="/bin/configure"
+ ):
+ config = {}
+ out = StringIO()
+ sandbox = ConfigureSandbox(config, env, [prog] + options, out, out)
+
+ sandbox.run(mozpath.join(test_data_path, configure))
+
+ if "--help" in options:
+ return six.ensure_text(out.getvalue()), config
+ self.assertEqual("", out.getvalue())
+ return config
+
+ def moz_configure(self, source):
+ return MockedOpen(
+ {os.path.join(test_data_path, "moz.configure"): textwrap.dedent(source)}
+ )
+
+ def test_defaults(self):
+ config = self.get_config()
+ self.maxDiff = None
+ self.assertEqual(
+ {
+ "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(),
+ },
+ config,
+ )
+
+ def test_help(self):
+ help, config = self.get_config(["--help"], prog="configure")
+
+ self.assertEqual({}, config)
+ self.maxDiff = None
+ self.assertEqual(
+ "Usage: configure [options]\n"
+ "\n"
+ "Options: [defaults in brackets after descriptions]\n"
+ " Help options:\n"
+ " --help print this message\n"
+ "\n"
+ " Options from python/mozbuild/mozbuild/test/configure/data/included.configure:\n"
+ " --enable-imports-in-template\n Imports in template\n"
+ "\n"
+ " Options from python/mozbuild/mozbuild/test/configure/data/moz.configure:\n"
+ " --enable-include Include\n"
+ " --enable-simple Enable simple\n"
+ " --enable-values Enable values\n"
+ " --enable-with-env Enable with env\n"
+ " --indirect-option Indirectly defined option\n"
+ " --option Option\n"
+ " --returned-choices Choices\n"
+ " --with-imports Imports\n"
+ " --with-returned-default Returned default [not-simple]\n"
+ " --with-stuff Build with stuff\n"
+ " --without-thing Build without thing\n"
+ "\n"
+ "\n"
+ "Environment variables:\n"
+ " Options from python/mozbuild/mozbuild/test/configure/data/moz.configure:\n"
+ " CC C Compiler\n"
+ "\n",
+ help.replace("\\", "/"),
+ )
+
+ def test_unknown(self):
+ with self.assertRaises(InvalidOptionError):
+ self.get_config(["--unknown"])
+
+ 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.assertEqual(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.assertEqual(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_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.assertEqual(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.assertEqual(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_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.assertEqual(NegativeOptionValue(), config[name])
+
+ for config in (
+ self.get_config(["--enable-values"]),
+ self.get_config(["--disable-values", "--enable-values"]),
+ ):
+ self.assertIn(name, config)
+ self.assertEqual(PositiveOptionValue(), config[name])
+
+ config = self.get_config(["--enable-values=foo"])
+ self.assertIn(name, config)
+ self.assertEqual(PositiveOptionValue(("foo",)), config[name])
+
+ config = self.get_config(["--enable-values=foo,bar"])
+ self.assertIn(name, config)
+ self.assertTrue(config[name])
+ self.assertEqual(PositiveOptionValue(("foo", "bar")), config[name])
+
+ def test_values2(self):
+ self.test_values("VALUES2")
+
+ def test_values3(self):
+ self.test_values("VALUES3")
+
+ def test_returned_default(self):
+ config = self.get_config(["--enable-simple"])
+ self.assertIn("DEFAULTED", config)
+ self.assertEqual(PositiveOptionValue(("simple",)), config["DEFAULTED"])
+
+ config = self.get_config(["--disable-simple"])
+ self.assertIn("DEFAULTED", config)
+ self.assertEqual(PositiveOptionValue(("not-simple",)), config["DEFAULTED"])
+
+ 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.assertEqual(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.assertEqual(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.assertEqual(config["IS_GCC"], True)
+
+ config = self.get_config(["--enable-include=extra.configure", "--extra"])
+ self.assertIn("EXTRA", config)
+ self.assertEqual(PositiveOptionValue(), config["EXTRA"])
+
+ with self.assertRaises(InvalidOptionError):
+ self.get_config(["--extra"])
+
+ def test_template(self):
+ config = self.get_config(env={"CC": "gcc"})
+ self.assertIn("CFLAGS", config)
+ self.assertEqual(config["CFLAGS"], ["-Werror=foobar"])
+
+ config = self.get_config(env={"CC": "clang"})
+ self.assertNotIn("CFLAGS", config)
+
+ def test_imports(self):
+ config = {}
+ out = StringIO()
+ sandbox = ConfigureSandbox(config, {}, ["configure"], out, out)
+
+ with self.assertRaises(ImportError):
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ def foo():
+ import sys
+ foo()"""
+ ),
+ sandbox,
+ )
+
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ @imports('sys')
+ def foo():
+ return sys"""
+ ),
+ sandbox,
+ )
+
+ self.assertIs(sandbox["foo"](), sys)
+
+ # os.path after an import is a mix of vanilla os.path and sandbox os.path.
+ os_path = {}
+ exec_("from os.path import *", {}, os_path)
+ os_path.update(sandbox.OS.path.__dict__)
+ os_path = ReadOnlyNamespace(**os_path)
+
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ @imports(_from='os', _import='path')
+ def foo():
+ return path"""
+ ),
+ sandbox,
+ )
+
+ self.assertEqual(sandbox["foo"](), os_path)
+
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ @imports(_from='os', _import='path', _as='os_path')
+ def foo():
+ return os_path"""
+ ),
+ sandbox,
+ )
+
+ self.assertEqual(sandbox["foo"](), os_path)
+
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ @imports('__builtin__')
+ def foo():
+ return __builtin__"""
+ ),
+ sandbox,
+ )
+
+ self.assertIs(sandbox["foo"](), six.moves.builtins)
+
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ @imports(_from='__builtin__', _import='open')
+ def foo():
+ return open('%s')"""
+ % os.devnull
+ ),
+ sandbox,
+ )
+
+ f = sandbox["foo"]()
+ self.assertEqual(f.name, os.devnull)
+ f.close()
+
+ # This unlocks the sandbox
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ @imports(_import='__builtin__', _as='__builtins__')
+ def foo():
+ import sys
+ return sys"""
+ ),
+ sandbox,
+ )
+
+ self.assertIs(sandbox["foo"](), sys)
+
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ @imports('__sandbox__')
+ def foo():
+ return __sandbox__"""
+ ),
+ sandbox,
+ )
+
+ self.assertIs(sandbox["foo"](), sandbox)
+
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ @imports(_import='__sandbox__', _as='s')
+ def foo():
+ return s"""
+ ),
+ sandbox,
+ )
+
+ self.assertIs(sandbox["foo"](), sandbox)
+
+ # Nothing leaked from the function being executed
+ self.assertEqual(list(sandbox), ["__builtins__", "foo"])
+ self.assertEqual(sandbox["__builtins__"], ConfigureSandbox.BUILTINS)
+
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ @imports('sys')
+ def foo():
+ @depends(when=True)
+ def bar():
+ return sys
+ return bar
+ bar = foo()"""
+ ),
+ sandbox,
+ )
+
+ with self.assertRaises(NameError) as e:
+ sandbox._depends[sandbox["bar"]].result()
+
+ self.assertIn("name 'sys' is not defined", str(e.exception))
+
+ def test_apply_imports(self):
+ imports = []
+
+ class CountApplyImportsSandbox(ConfigureSandbox):
+ def _apply_imports(self, *args, **kwargs):
+ imports.append((args, kwargs))
+ super(CountApplyImportsSandbox, self)._apply_imports(*args, **kwargs)
+
+ config = {}
+ out = StringIO()
+ sandbox = CountApplyImportsSandbox(config, {}, ["configure"], out, out)
+
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ @imports('sys')
+ def foo():
+ return sys
+ foo()
+ foo()"""
+ ),
+ sandbox,
+ )
+
+ self.assertEqual(len(imports), 1)
+
+ def test_import_wrapping(self):
+ bar = object()
+ foo = ReadOnlyNamespace(bar=bar)
+
+ class BasicWrappingSandbox(ConfigureSandbox):
+ @memoized_property
+ def _wrapped_foo(self):
+ return foo
+
+ config = {}
+ out = StringIO()
+ sandbox = BasicWrappingSandbox(config, {}, ["configure"], out, out)
+
+ exec_(
+ textwrap.dedent(
+ """
+ @template
+ @imports('foo')
+ def toplevel():
+ return foo
+ @template
+ @imports('foo.bar')
+ def bar():
+ return foo.bar
+ @template
+ @imports('foo.bar')
+ def bar_upper():
+ return foo
+ @template
+ @imports(_from='foo', _import='bar')
+ def from_import():
+ return bar
+ @template
+ @imports(_from='foo', _import='bar', _as='custom_name')
+ def from_import_as():
+ return custom_name
+ @template
+ @imports(_import='foo', _as='custom_name')
+ def import_as():
+ return custom_name
+ """
+ ),
+ sandbox,
+ )
+ self.assertIs(sandbox["toplevel"](), foo)
+ self.assertIs(sandbox["bar"](), bar)
+ self.assertIs(sandbox["bar_upper"](), foo)
+ self.assertIs(sandbox["from_import"](), bar)
+ self.assertIs(sandbox["from_import_as"](), bar)
+ self.assertIs(sandbox["import_as"](), foo)
+
+ def test_os_path(self):
+ config = self.get_config(["--with-imports=%s" % __file__])
+ self.assertIn("HAS_ABSPATH", config)
+ self.assertEqual(config["HAS_ABSPATH"], True)
+ self.assertIn("HAS_GETATIME", config)
+ self.assertEqual(config["HAS_GETATIME"], True)
+ self.assertIn("HAS_GETATIME2", config)
+ self.assertEqual(config["HAS_GETATIME2"], False)
+
+ def test_template_call(self):
+ config = self.get_config(env={"CC": "gcc"})
+ self.assertIn("TEMPLATE_VALUE", config)
+ self.assertEqual(config["TEMPLATE_VALUE"], 42)
+ self.assertIn("TEMPLATE_VALUE_2", config)
+ self.assertEqual(config["TEMPLATE_VALUE_2"], 21)
+
+ def test_template_imports(self):
+ config = self.get_config(["--enable-imports-in-template"])
+ self.assertIn("PLATFORM", config)
+ self.assertEqual(config["PLATFORM"], sys.platform)
+
+ def test_decorators(self):
+ config = {}
+ out = StringIO()
+ sandbox = ConfigureSandbox(config, {}, ["configure"], out, out)
+
+ sandbox.include_file(mozpath.join(test_data_path, "decorators.configure"))
+
+ self.assertNotIn("FOO", sandbox)
+ self.assertNotIn("BAR", sandbox)
+ self.assertNotIn("QUX", sandbox)
+
+ def test_set_config(self):
+ def get_config(*args):
+ return self.get_config(*args, configure="set_config.configure")
+
+ help, config = get_config(["--help"])
+ self.assertEqual(config, {})
+
+ config = get_config(["--set-foo"])
+ self.assertIn("FOO", config)
+ self.assertEqual(config["FOO"], True)
+
+ config = get_config(["--set-bar"])
+ self.assertNotIn("FOO", config)
+ self.assertIn("BAR", config)
+ self.assertEqual(config["BAR"], True)
+
+ config = get_config(["--set-value=qux"])
+ self.assertIn("VALUE", config)
+ self.assertEqual(config["VALUE"], "qux")
+
+ config = get_config(["--set-name=hoge"])
+ self.assertIn("hoge", config)
+ self.assertEqual(config["hoge"], True)
+
+ config = get_config([])
+ self.assertEqual(config, {"BAR": False})
+
+ with self.assertRaises(ConfigureError):
+ # Both --set-foo and --set-name=FOO are going to try to
+ # set_config('FOO'...)
+ get_config(["--set-foo", "--set-name=FOO"])
+
+ def test_set_config_when(self):
+ with self.moz_configure(
+ """
+ option('--with-qux', help='qux')
+ set_config('FOO', 'foo', when=True)
+ set_config('BAR', 'bar', when=False)
+ set_config('QUX', 'qux', when='--with-qux')
+ """
+ ):
+ config = self.get_config()
+ self.assertEqual(
+ config,
+ {
+ "FOO": "foo",
+ },
+ )
+ config = self.get_config(["--with-qux"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": "foo",
+ "QUX": "qux",
+ },
+ )
+
+ def test_set_config_when_disable(self):
+ with self.moz_configure(
+ """
+ option('--disable-baz', help='Disable baz')
+ set_config('BAZ', True, when='--enable-baz')
+ """
+ ):
+ config = self.get_config()
+ self.assertEqual(config["BAZ"], True)
+ config = self.get_config(["--enable-baz"])
+ self.assertEqual(config["BAZ"], True)
+ config = self.get_config(["--disable-baz"])
+ self.assertEqual(config, {})
+
+ def test_set_define(self):
+ def get_config(*args):
+ return self.get_config(*args, configure="set_define.configure")
+
+ help, config = get_config(["--help"])
+ self.assertEqual(config, {"DEFINES": {}})
+
+ config = get_config(["--set-foo"])
+ self.assertIn("FOO", config["DEFINES"])
+ self.assertEqual(config["DEFINES"]["FOO"], True)
+
+ config = get_config(["--set-bar"])
+ self.assertNotIn("FOO", config["DEFINES"])
+ self.assertIn("BAR", config["DEFINES"])
+ self.assertEqual(config["DEFINES"]["BAR"], True)
+
+ config = get_config(["--set-value=qux"])
+ self.assertIn("VALUE", config["DEFINES"])
+ self.assertEqual(config["DEFINES"]["VALUE"], "qux")
+
+ config = get_config(["--set-name=hoge"])
+ self.assertIn("hoge", config["DEFINES"])
+ self.assertEqual(config["DEFINES"]["hoge"], True)
+
+ config = get_config([])
+ self.assertEqual(config["DEFINES"], {"BAR": False})
+
+ with self.assertRaises(ConfigureError):
+ # Both --set-foo and --set-name=FOO are going to try to
+ # set_define('FOO'...)
+ get_config(["--set-foo", "--set-name=FOO"])
+
+ def test_set_define_when(self):
+ with self.moz_configure(
+ """
+ option('--with-qux', help='qux')
+ set_define('FOO', 'foo', when=True)
+ set_define('BAR', 'bar', when=False)
+ set_define('QUX', 'qux', when='--with-qux')
+ """
+ ):
+ config = self.get_config()
+ self.assertEqual(
+ config["DEFINES"],
+ {
+ "FOO": "foo",
+ },
+ )
+ config = self.get_config(["--with-qux"])
+ self.assertEqual(
+ config["DEFINES"],
+ {
+ "FOO": "foo",
+ "QUX": "qux",
+ },
+ )
+
+ def test_set_define_when_disable(self):
+ with self.moz_configure(
+ """
+ option('--disable-baz', help='Disable baz')
+ set_define('BAZ', True, when='--enable-baz')
+ """
+ ):
+ config = self.get_config()
+ self.assertEqual(config["DEFINES"]["BAZ"], True)
+ config = self.get_config(["--enable-baz"])
+ self.assertEqual(config["DEFINES"]["BAZ"], True)
+ config = self.get_config(["--disable-baz"])
+ self.assertEqual(config["DEFINES"], {})
+
+ def test_imply_option_simple(self):
+ def get_config(*args):
+ return self.get_config(*args, configure="imply_option/simple.configure")
+
+ help, config = get_config(["--help"])
+ self.assertEqual(config, {})
+
+ config = get_config([])
+ self.assertEqual(config, {})
+
+ config = get_config(["--enable-foo"])
+ self.assertIn("BAR", config)
+ self.assertEqual(config["BAR"], PositiveOptionValue())
+
+ with self.assertRaises(InvalidOptionError) as e:
+ get_config(["--enable-foo", "--disable-bar"])
+
+ self.assertEqual(
+ str(e.exception),
+ "'--enable-bar' implied by '--enable-foo' conflicts with "
+ "'--disable-bar' from the command-line",
+ )
+
+ def test_imply_option_negative(self):
+ def get_config(*args):
+ return self.get_config(*args, configure="imply_option/negative.configure")
+
+ help, config = get_config(["--help"])
+ self.assertEqual(config, {})
+
+ config = get_config([])
+ self.assertEqual(config, {})
+
+ config = get_config(["--enable-foo"])
+ self.assertIn("BAR", config)
+ self.assertEqual(config["BAR"], NegativeOptionValue())
+
+ with self.assertRaises(InvalidOptionError) as e:
+ get_config(["--enable-foo", "--enable-bar"])
+
+ self.assertEqual(
+ str(e.exception),
+ "'--disable-bar' implied by '--enable-foo' conflicts with "
+ "'--enable-bar' from the command-line",
+ )
+
+ config = get_config(["--disable-hoge"])
+ self.assertIn("BAR", config)
+ self.assertEqual(config["BAR"], NegativeOptionValue())
+
+ with self.assertRaises(InvalidOptionError) as e:
+ get_config(["--disable-hoge", "--enable-bar"])
+
+ self.assertEqual(
+ str(e.exception),
+ "'--disable-bar' implied by '--disable-hoge' conflicts with "
+ "'--enable-bar' from the command-line",
+ )
+
+ 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.assertEqual(config, {})
+
+ config = get_config([])
+ self.assertEqual(config, {})
+
+ config = get_config(["--enable-foo=a"])
+ self.assertIn("BAR", config)
+ self.assertEqual(config["BAR"], PositiveOptionValue(("a",)))
+
+ config = get_config(["--enable-foo=a,b"])
+ self.assertIn("BAR", config)
+ self.assertEqual(config["BAR"], PositiveOptionValue(("a", "b")))
+
+ with self.assertRaises(InvalidOptionError) as e:
+ get_config(["--enable-foo=a,b", "--disable-bar"])
+
+ self.assertEqual(
+ str(e.exception),
+ "'--enable-bar=a,b' implied by '--enable-foo' conflicts with "
+ "'--disable-bar' from the command-line",
+ )
+
+ def test_imply_option_infer(self):
+ def get_config(*args):
+ return self.get_config(*args, configure="imply_option/infer.configure")
+
+ help, config = get_config(["--help"])
+ self.assertEqual(config, {})
+
+ config = get_config([])
+ self.assertEqual(config, {})
+
+ with self.assertRaises(InvalidOptionError) as e:
+ get_config(["--enable-foo", "--disable-bar"])
+
+ self.assertEqual(
+ str(e.exception),
+ "'--enable-bar' implied by '--enable-foo' conflicts with "
+ "'--disable-bar' from the command-line",
+ )
+
+ with self.assertRaises(ConfigureError) as e:
+ self.get_config([], configure="imply_option/infer_ko.configure")
+
+ self.assertEqual(
+ str(e.exception),
+ "Cannot infer what implies '--enable-bar'. Please add a `reason` "
+ "to the `imply_option` call.",
+ )
+
+ def test_imply_option_immediate_value(self):
+ def get_config(*args):
+ return self.get_config(*args, configure="imply_option/imm.configure")
+
+ help, config = get_config(["--help"])
+ self.assertEqual(config, {})
+
+ config = get_config([])
+ self.assertEqual(config, {})
+
+ config_path = mozpath.abspath(
+ mozpath.join(test_data_path, "imply_option", "imm.configure")
+ )
+
+ with self.assertRaisesRegexp(
+ InvalidOptionError,
+ "--enable-foo' implied by 'imply_option at %s:7' conflicts "
+ "with '--disable-foo' from the command-line" % config_path,
+ ):
+ get_config(["--disable-foo"])
+
+ with self.assertRaisesRegexp(
+ InvalidOptionError,
+ "--enable-bar=foo,bar' implied by 'imply_option at %s:18' "
+ "conflicts with '--enable-bar=a,b,c' from the command-line" % config_path,
+ ):
+ get_config(["--enable-bar=a,b,c"])
+
+ with self.assertRaisesRegexp(
+ InvalidOptionError,
+ "--enable-baz=BAZ' implied by 'imply_option at %s:29' "
+ "conflicts with '--enable-baz=QUUX' from the command-line" % config_path,
+ ):
+ get_config(["--enable-baz=QUUX"])
+
+ def test_imply_option_failures(self):
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ imply_option('--with-foo', ('a',), 'bar')
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(
+ str(e.exception),
+ "`--with-foo`, emitted from `%s` line 2, is unknown."
+ % mozpath.join(test_data_path, "moz.configure"),
+ )
+
+ with self.assertRaises(TypeError) as e:
+ with self.moz_configure(
+ """
+ imply_option('--with-foo', 42, 'bar')
+
+ option('--with-foo', help='foo')
+ @depends('--with-foo')
+ def foo(value):
+ return value
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Unexpected type: 'int'")
+
+ 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.assertEqual(
+ config,
+ {
+ "QUX": NegativeOptionValue(),
+ },
+ )
+
+ config = self.get_config(["--with-foo"])
+ self.assertEqual(
+ config,
+ {
+ "QUX": PositiveOptionValue(),
+ },
+ )
+
+ def test_imply_option_dependency_loop(self):
+ with self.moz_configure(
+ """
+ option('--without-foo', help='foo')
+
+ @depends('--with-foo')
+ def qux_default(foo):
+ return bool(foo)
+
+ option('--with-qux', default=qux_default, help='qux')
+
+ imply_option('--with-foo', depends('--with-qux')(lambda x: x or None))
+
+ set_config('FOO', depends('--with-foo')(lambda x: x))
+ set_config('QUX', depends('--with-qux')(lambda x: x))
+ """
+ ):
+ config = self.get_config()
+ self.assertEqual(
+ config,
+ {
+ "FOO": PositiveOptionValue(),
+ "QUX": PositiveOptionValue(),
+ },
+ )
+
+ config = self.get_config(["--without-foo"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": NegativeOptionValue(),
+ "QUX": NegativeOptionValue(),
+ },
+ )
+
+ config = self.get_config(["--with-qux"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": PositiveOptionValue(),
+ "QUX": PositiveOptionValue(),
+ },
+ )
+
+ with self.assertRaises(InvalidOptionError) as e:
+ config = self.get_config(["--without-foo", "--with-qux"])
+
+ self.assertEqual(
+ str(e.exception),
+ "'--with-foo' implied by '--with-qux' conflicts "
+ "with '--without-foo' from the command-line",
+ )
+
+ config = self.get_config(["--without-qux"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": PositiveOptionValue(),
+ "QUX": NegativeOptionValue(),
+ },
+ )
+
+ with self.moz_configure(
+ """
+ option('--with-foo', help='foo')
+
+ @depends('--with-foo')
+ def qux_default(foo):
+ return bool(foo)
+
+ option('--with-qux', default=qux_default, help='qux')
+
+ imply_option('--with-foo', depends('--with-qux')(lambda x: x or None))
+
+ set_config('FOO', depends('--with-foo')(lambda x: x))
+ set_config('QUX', depends('--with-qux')(lambda x: x))
+ """
+ ):
+ config = self.get_config()
+ self.assertEqual(
+ config,
+ {
+ "FOO": NegativeOptionValue(),
+ "QUX": NegativeOptionValue(),
+ },
+ )
+
+ config = self.get_config(["--with-foo"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": PositiveOptionValue(),
+ "QUX": PositiveOptionValue(),
+ },
+ )
+
+ with self.assertRaises(InvalidOptionError) as e:
+ config = self.get_config(["--with-qux"])
+
+ self.assertEqual(
+ str(e.exception),
+ "'--with-foo' implied by '--with-qux' conflicts "
+ "with '--without-foo' from the default",
+ )
+
+ with self.assertRaises(InvalidOptionError) as e:
+ config = self.get_config(["--without-foo", "--with-qux"])
+
+ self.assertEqual(
+ str(e.exception),
+ "'--with-foo' implied by '--with-qux' conflicts "
+ "with '--without-foo' from the command-line",
+ )
+
+ config = self.get_config(["--without-qux"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": NegativeOptionValue(),
+ "QUX": NegativeOptionValue(),
+ },
+ )
+
+ config_path = mozpath.abspath(mozpath.join(test_data_path, "moz.configure"))
+
+ # Same test as above, but using `when` in the `imply_option`.
+ with self.moz_configure(
+ """
+ option('--with-foo', help='foo')
+
+ @depends('--with-foo')
+ def qux_default(foo):
+ return bool(foo)
+
+ option('--with-qux', default=qux_default, help='qux')
+
+ imply_option('--with-foo', True, when='--with-qux')
+
+ set_config('FOO', depends('--with-foo')(lambda x: x))
+ set_config('QUX', depends('--with-qux')(lambda x: x))
+ """
+ ):
+ config = self.get_config()
+ self.assertEqual(
+ config,
+ {
+ "FOO": NegativeOptionValue(),
+ "QUX": NegativeOptionValue(),
+ },
+ )
+
+ config = self.get_config(["--with-foo"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": PositiveOptionValue(),
+ "QUX": PositiveOptionValue(),
+ },
+ )
+
+ with self.assertRaises(InvalidOptionError) as e:
+ config = self.get_config(["--with-qux"])
+
+ self.assertEqual(
+ str(e.exception),
+ "'--with-foo' implied by 'imply_option at %s:10' conflicts "
+ "with '--without-foo' from the default" % config_path,
+ )
+
+ with self.assertRaises(InvalidOptionError) as e:
+ config = self.get_config(["--without-foo", "--with-qux"])
+
+ self.assertEqual(
+ str(e.exception),
+ "'--with-foo' implied by 'imply_option at %s:10' conflicts "
+ "with '--without-foo' from the command-line" % config_path,
+ )
+
+ config = self.get_config(["--without-qux"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": NegativeOptionValue(),
+ "QUX": NegativeOptionValue(),
+ },
+ )
+
+ def test_imply_option_recursion(self):
+ config_path = mozpath.abspath(mozpath.join(test_data_path, "moz.configure"))
+
+ message = (
+ "'--without-foo' appears somewhere in the direct or indirect dependencies "
+ "when resolving imply_option at %s:8" % config_path
+ )
+
+ with self.moz_configure(
+ """
+ option('--without-foo', help='foo')
+
+ imply_option('--with-qux', depends('--with-foo')(lambda x: x or None))
+
+ option('--with-qux', help='qux')
+
+ imply_option('--with-foo', depends('--with-qux')(lambda x: x or None))
+
+ set_config('FOO', depends('--with-foo')(lambda x: x))
+ set_config('QUX', depends('--with-qux')(lambda x: x))
+ """
+ ):
+ # Note: no error is detected when the depends function in the
+ # imply_options resolve to None, which disables the imply_option.
+
+ with self.assertRaises(ConfigureError) as e:
+ self.get_config()
+
+ self.assertEqual(str(e.exception), message)
+
+ with self.assertRaises(ConfigureError) as e:
+ self.get_config(["--with-qux"])
+
+ self.assertEqual(str(e.exception), message)
+
+ with self.assertRaises(ConfigureError) as e:
+ self.get_config(["--without-foo", "--with-qux"])
+
+ self.assertEqual(str(e.exception), message)
+
+ def test_option_failures(self):
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure('option("--with-foo", help="foo")'):
+ self.get_config()
+
+ self.assertEqual(
+ str(e.exception),
+ "Option `--with-foo` is not handled ; reference it with a @depends",
+ )
+
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ option("--with-foo", help="foo")
+ option("--with-foo", help="foo")
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Option `--with-foo` already defined")
+
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ option(env="MOZ_FOO", help="foo")
+ option(env="MOZ_FOO", help="foo")
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Option `MOZ_FOO` already defined")
+
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ option('--with-foo', env="MOZ_FOO", help="foo")
+ option(env="MOZ_FOO", help="foo")
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Option `MOZ_FOO` already defined")
+
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ option(env="MOZ_FOO", help="foo")
+ option('--with-foo', env="MOZ_FOO", help="foo")
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Option `MOZ_FOO` already defined")
+
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ option('--with-foo', env="MOZ_FOO", help="foo")
+ option('--with-foo', help="foo")
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Option `--with-foo` already defined")
+
+ 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.assertEqual(
+ config,
+ {
+ "FOO": NegativeOptionValue(),
+ },
+ )
+
+ config = self.get_config(["--with-foo"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": PositiveOptionValue(),
+ "QUX": NegativeOptionValue(),
+ },
+ )
+
+ config = self.get_config(["--with-foo", "--with-qux"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": PositiveOptionValue(),
+ "QUX": PositiveOptionValue(),
+ },
+ )
+
+ with self.assertRaises(InvalidOptionError) as e:
+ self.get_config(["--with-bar"])
+
+ self.assertEqual(
+ str(e.exception), "--with-bar is not available in this configuration"
+ )
+
+ with self.assertRaises(InvalidOptionError) as e:
+ self.get_config(["--with-qux"])
+
+ self.assertEqual(
+ str(e.exception), "--with-qux is not available in this configuration"
+ )
+
+ with self.assertRaises(InvalidOptionError) as e:
+ self.get_config(["QUX=1"])
+
+ self.assertEqual(
+ str(e.exception), "QUX is not available in this configuration"
+ )
+
+ config = self.get_config(env={"QUX": "1"})
+ self.assertEqual(
+ config,
+ {
+ "FOO": NegativeOptionValue(),
+ },
+ )
+
+ help, config = self.get_config(["--help"])
+ self.assertEqual(
+ help.replace("\\", "/"),
+ textwrap.dedent(
+ """\
+ Usage: configure [options]
+
+ Options: [defaults in brackets after descriptions]
+ Help options:
+ --help print this message
+
+ Options from python/mozbuild/mozbuild/test/configure/data/moz.configure:
+ --with-foo foo
+
+
+ Environment variables:
+ """
+ ),
+ )
+
+ help, config = self.get_config(["--help", "--with-foo"])
+ self.assertEqual(
+ help.replace("\\", "/"),
+ textwrap.dedent(
+ """\
+ Usage: configure [options]
+
+ Options: [defaults in brackets after descriptions]
+ Help options:
+ --help print this message
+
+ Options from python/mozbuild/mozbuild/test/configure/data/moz.configure:
+ --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.assertEqual(
+ str(e.exception),
+ "@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.assertEqual(
+ str(e.exception),
+ "@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_include_failures(self):
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure('include("../foo.configure")'):
+ self.get_config()
+
+ self.assertEqual(
+ str(e.exception),
+ "Cannot include `%s` because it is not in a subdirectory of `%s`"
+ % (
+ mozpath.normpath(mozpath.join(test_data_path, "..", "foo.configure")),
+ mozpath.normsep(test_data_path),
+ ),
+ )
+
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ include('extra.configure')
+ include('extra.configure')
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(
+ str(e.exception),
+ "Cannot include `%s` because it was included already."
+ % mozpath.normpath(mozpath.join(test_data_path, "extra.configure")),
+ )
+
+ with self.assertRaises(TypeError) as e:
+ with self.moz_configure(
+ """
+ include(42)
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Unexpected type: 'int'")
+
+ def test_include_when(self):
+ with MockedOpen(
+ {
+ os.path.join(test_data_path, "moz.configure"): textwrap.dedent(
+ """
+ option('--with-foo', help='foo')
+
+ include('always.configure', when=True)
+ include('never.configure', when=False)
+ include('foo.configure', when='--with-foo')
+
+ set_config('FOO', foo)
+ set_config('BAR', bar)
+ set_config('QUX', qux)
+ """
+ ),
+ os.path.join(test_data_path, "always.configure"): textwrap.dedent(
+ """
+ option('--with-bar', help='bar')
+ @depends('--with-bar')
+ def bar(x):
+ if x:
+ return 'bar'
+ """
+ ),
+ os.path.join(test_data_path, "never.configure"): textwrap.dedent(
+ """
+ option('--with-qux', help='qux')
+ @depends('--with-qux')
+ def qux(x):
+ if x:
+ return 'qux'
+ """
+ ),
+ os.path.join(test_data_path, "foo.configure"): textwrap.dedent(
+ """
+ option('--with-foo-really', help='really foo')
+ @depends('--with-foo-really')
+ def foo(x):
+ if x:
+ return 'foo'
+
+ include('foo2.configure', when='--with-foo-really')
+ """
+ ),
+ os.path.join(test_data_path, "foo2.configure"): textwrap.dedent(
+ """
+ set_config('FOO2', True)
+ """
+ ),
+ }
+ ):
+ config = self.get_config()
+ self.assertEqual(config, {})
+
+ config = self.get_config(["--with-foo"])
+ self.assertEqual(config, {})
+
+ config = self.get_config(["--with-bar"])
+ self.assertEqual(
+ config,
+ {
+ "BAR": "bar",
+ },
+ )
+
+ with self.assertRaises(InvalidOptionError) as e:
+ self.get_config(["--with-qux"])
+
+ self.assertEqual(
+ str(e.exception), "--with-qux is not available in this configuration"
+ )
+
+ config = self.get_config(["--with-foo", "--with-foo-really"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": "foo",
+ "FOO2": True,
+ },
+ )
+
+ def test_sandbox_failures(self):
+ with self.assertRaises(KeyError) as e:
+ with self.moz_configure(
+ """
+ include = 42
+ """
+ ):
+ self.get_config()
+
+ self.assertIn("Cannot reassign builtins", str(e.exception))
+
+ with self.assertRaises(KeyError) as e:
+ with self.moz_configure(
+ """
+ foo = 42
+ """
+ ):
+ self.get_config()
+
+ self.assertIn(
+ "Cannot assign `foo` because it is neither a @depends nor a " "@template",
+ str(e.exception),
+ )
+
+ def test_depends_failures(self):
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ @depends()
+ def foo():
+ return
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "@depends needs at least one argument")
+
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ @depends('--with-foo')
+ def foo(value):
+ return value
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(
+ str(e.exception),
+ "'--with-foo' is not a known option. Maybe it's " "declared too late?",
+ )
+
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ @depends('--with-foo=42')
+ def foo(value):
+ return value
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Option must not contain an '='")
+
+ with self.assertRaises(TypeError) as e:
+ with self.moz_configure(
+ """
+ @depends(42)
+ def foo(value):
+ return value
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(
+ str(e.exception),
+ "Cannot use object of type 'int' as argument " "to @depends",
+ )
+
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ @depends('--help')
+ def foo(value):
+ yield
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(
+ str(e.exception), "Cannot decorate generator functions with @depends"
+ )
+
+ with self.assertRaises(TypeError) as e:
+ with self.moz_configure(
+ """
+ @depends('--help')
+ def foo(value):
+ return value
+
+ depends('--help')(foo)
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Cannot nest @depends functions")
+
+ with self.assertRaises(TypeError) as e:
+ with self.moz_configure(
+ """
+ @template
+ def foo(f):
+ pass
+
+ depends('--help')(foo)
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Cannot use a @template function here")
+
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ option('--foo', help='foo')
+ @depends('--foo')
+ def foo(value):
+ return value
+
+ foo()
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "The `foo` function may not be called")
+
+ with self.assertRaises(TypeError) as e:
+ with self.moz_configure(
+ """
+ @depends('--help', foo=42)
+ def foo(_):
+ return
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(
+ str(e.exception), "depends_impl() got an unexpected keyword argument 'foo'"
+ )
+
+ def test_depends_when(self):
+ with self.moz_configure(
+ """
+ @depends(when=True)
+ def foo():
+ return 'foo'
+
+ set_config('FOO', foo)
+
+ @depends(when=False)
+ def bar():
+ return 'bar'
+
+ set_config('BAR', bar)
+
+ option('--with-qux', help='qux')
+ @depends(when='--with-qux')
+ def qux():
+ return 'qux'
+
+ set_config('QUX', qux)
+ """
+ ):
+ config = self.get_config()
+ self.assertEqual(
+ config,
+ {
+ "FOO": "foo",
+ },
+ )
+
+ config = self.get_config(["--with-qux"])
+ self.assertEqual(
+ config,
+ {
+ "FOO": "foo",
+ "QUX": "qux",
+ },
+ )
+
+ def test_depends_value(self):
+ with self.moz_configure(
+ """
+ foo = depends(when=True)('foo')
+
+ set_config('FOO', foo)
+
+ bar = depends(when=False)('bar')
+
+ set_config('BAR', bar)
+
+ option('--with-qux', help='qux')
+ @depends(when='--with-qux')
+ def qux():
+ return 'qux'
+
+ set_config('QUX', qux)
+ """
+ ):
+ config = self.get_config()
+ self.assertEqual(
+ config,
+ {
+ "FOO": "foo",
+ },
+ )
+
+ with self.assertRaises(TypeError) as e:
+ with self.moz_configure(
+ """
+ option('--foo', help='foo')
+
+ depends('--foo')('foo')
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(
+ str(e.exception), "Cannot wrap literal values in @depends with dependencies"
+ )
+
+ def test_imports_failures(self):
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ @imports('os')
+ @template
+ def foo(value):
+ return value
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "@imports must appear after @template")
+
+ with self.assertRaises(ConfigureError) as e:
+ with self.moz_configure(
+ """
+ option('--foo', help='foo')
+ @imports('os')
+ @depends('--foo')
+ def foo(value):
+ return value
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "@imports must appear after @depends")
+
+ for import_ in (
+ "42",
+ "_from=42, _import='os'",
+ "_from='os', _import='path', _as=42",
+ ):
+ with self.assertRaises(TypeError) as e:
+ with self.moz_configure(
+ """
+ @imports(%s)
+ @template
+ def foo(value):
+ return value
+ """
+ % import_
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Unexpected type: 'int'")
+
+ with self.assertRaises(TypeError) as e:
+ with self.moz_configure(
+ """
+ @imports('os', 42)
+ @template
+ def foo(value):
+ return value
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Unexpected type: 'int'")
+
+ with self.assertRaises(ValueError) as e:
+ with self.moz_configure(
+ """
+ @imports('os*')
+ def foo(value):
+ return value
+ """
+ ):
+ self.get_config()
+
+ self.assertEqual(str(e.exception), "Invalid argument to @imports: 'os*'")
+
+ 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.assertEqual(
+ str(e.exception), "--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.assertEqual(
+ str(e.exception),
+ "@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.assertEqual(
+ str(e.exception), "--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 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_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",)),
+ },
+ )
+
+
+if __name__ == "__main__":
+ main()