summaryrefslogtreecommitdiffstats
path: root/python/mozbuild/mozbuild/test/test_mozconfig.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/mozbuild/mozbuild/test/test_mozconfig.py')
-rw-r--r--python/mozbuild/mozbuild/test/test_mozconfig.py275
1 files changed, 275 insertions, 0 deletions
diff --git a/python/mozbuild/mozbuild/test/test_mozconfig.py b/python/mozbuild/mozbuild/test/test_mozconfig.py
new file mode 100644
index 0000000000..20827d7f29
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/test_mozconfig.py
@@ -0,0 +1,275 @@
+# 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 unittest
+from shutil import rmtree
+from tempfile import mkdtemp
+
+from mozfile.mozfile import NamedTemporaryFile
+from mozunit import main
+
+from mozbuild.mozconfig import MozconfigLoader, MozconfigLoadException
+
+
+class TestMozconfigLoader(unittest.TestCase):
+ def setUp(self):
+ self._old_env = dict(os.environ)
+ os.environ.pop("MOZCONFIG", None)
+ os.environ.pop("MOZ_OBJDIR", None)
+ os.environ.pop("CC", None)
+ os.environ.pop("CXX", None)
+ self._temp_dirs = set()
+
+ def tearDown(self):
+ os.environ.clear()
+ os.environ.update(self._old_env)
+
+ for d in self._temp_dirs:
+ rmtree(d)
+
+ def get_loader(self):
+ return MozconfigLoader(self.get_temp_dir())
+
+ def get_temp_dir(self):
+ d = mkdtemp()
+ self._temp_dirs.add(d)
+
+ return d
+
+ def test_read_no_mozconfig(self):
+ # This is basically to ensure changes to defaults incur a test failure.
+ result = self.get_loader().read_mozconfig()
+
+ self.assertEqual(
+ result,
+ {
+ "path": None,
+ "topobjdir": None,
+ "configure_args": None,
+ "make_flags": None,
+ "make_extra": None,
+ "env": None,
+ "vars": None,
+ },
+ )
+
+ def test_read_empty_mozconfig(self):
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+
+ self.assertEqual(result["path"], mozconfig.name)
+ self.assertIsNone(result["topobjdir"])
+ self.assertEqual(result["configure_args"], [])
+ self.assertEqual(result["make_flags"], [])
+ self.assertEqual(result["make_extra"], [])
+
+ for f in ("added", "removed", "modified"):
+ self.assertEqual(len(result["vars"][f]), 0)
+ self.assertEqual(len(result["env"][f]), 0)
+
+ self.assertEqual(result["env"]["unmodified"], {})
+
+ def test_read_capture_ac_options(self):
+ """Ensures ac_add_options calls are captured."""
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write("ac_add_options --enable-debug\n")
+ mozconfig.write("ac_add_options --disable-tests --enable-foo\n")
+ mozconfig.write('ac_add_options --foo="bar baz"\n')
+ mozconfig.flush()
+
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+ self.assertEqual(
+ result["configure_args"],
+ ["--enable-debug", "--disable-tests", "--enable-foo", "--foo=bar baz"],
+ )
+
+ def test_read_ac_options_substitution(self):
+ """Ensure ac_add_options values are substituted."""
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write("ac_add_options --foo=@TOPSRCDIR@\n")
+ mozconfig.flush()
+
+ loader = self.get_loader()
+ result = loader.read_mozconfig(mozconfig.name)
+ self.assertEqual(result["configure_args"], ["--foo=%s" % loader.topsrcdir])
+
+ def test_read_capture_mk_options(self):
+ """Ensures mk_add_options calls are captured."""
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write("mk_add_options MOZ_OBJDIR=/foo/bar\n")
+ mozconfig.write('mk_add_options MOZ_MAKE_FLAGS="-j8 -s"\n')
+ mozconfig.write('mk_add_options FOO="BAR BAZ"\n')
+ mozconfig.write("mk_add_options BIZ=1\n")
+ mozconfig.flush()
+
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+ self.assertEqual(result["topobjdir"], "/foo/bar")
+ self.assertEqual(result["make_flags"], ["-j8", "-s"])
+ self.assertEqual(result["make_extra"], ["FOO=BAR BAZ", "BIZ=1"])
+
+ def test_read_no_mozconfig_objdir_environ(self):
+ os.environ["MOZ_OBJDIR"] = "obj-firefox"
+ result = self.get_loader().read_mozconfig()
+ self.assertEqual(result["topobjdir"], "obj-firefox")
+
+ def test_read_empty_mozconfig_objdir_environ(self):
+ os.environ["MOZ_OBJDIR"] = "obj-firefox"
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+ self.assertEqual(result["topobjdir"], "obj-firefox")
+
+ def test_read_capture_mk_options_objdir_environ(self):
+ """Ensures mk_add_options calls are captured and override the environ."""
+ os.environ["MOZ_OBJDIR"] = "obj-firefox"
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write("mk_add_options MOZ_OBJDIR=/foo/bar\n")
+ mozconfig.flush()
+
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+ self.assertEqual(result["topobjdir"], "/foo/bar")
+
+ def test_read_moz_objdir_substitution(self):
+ """Ensure @TOPSRCDIR@ substitution is recognized in MOZ_OBJDIR."""
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write("mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/some-objdir")
+ mozconfig.flush()
+
+ loader = self.get_loader()
+ result = loader.read_mozconfig(mozconfig.name)
+
+ self.assertEqual(result["topobjdir"], "%s/some-objdir" % loader.topsrcdir)
+
+ def test_read_new_variables(self):
+ """New variables declared in mozconfig file are detected."""
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write("CC=/usr/local/bin/clang\n")
+ mozconfig.write("CXX=/usr/local/bin/clang++\n")
+ mozconfig.flush()
+
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+
+ self.assertEqual(
+ result["vars"]["added"],
+ {"CC": "/usr/local/bin/clang", "CXX": "/usr/local/bin/clang++"},
+ )
+ self.assertEqual(result["env"]["added"], {})
+
+ def test_read_exported_variables(self):
+ """Exported variables are caught as new variables."""
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write("export MY_EXPORTED=woot\n")
+ mozconfig.flush()
+
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+
+ self.assertEqual(result["vars"]["added"], {})
+ self.assertEqual(result["env"]["added"], {"MY_EXPORTED": "woot"})
+
+ def test_read_modify_variables(self):
+ """Variables modified by mozconfig are detected."""
+ old_path = os.path.realpath("/usr/bin/gcc")
+ new_path = os.path.realpath("/usr/local/bin/clang")
+ os.environ["CC"] = old_path
+
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write('CC="%s"\n' % new_path)
+ mozconfig.flush()
+
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+
+ self.assertEqual(result["vars"]["modified"], {})
+ self.assertEqual(result["env"]["modified"], {"CC": (old_path, new_path)})
+
+ def test_read_unmodified_variables(self):
+ """Variables modified by mozconfig are detected."""
+ cc_path = os.path.realpath("/usr/bin/gcc")
+ os.environ["CC"] = cc_path
+
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.flush()
+
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+
+ self.assertEqual(result["vars"]["unmodified"], {})
+ self.assertEqual(result["env"]["unmodified"], {"CC": cc_path})
+
+ def test_read_removed_variables(self):
+ """Variables unset by the mozconfig are detected."""
+ cc_path = os.path.realpath("/usr/bin/clang")
+ os.environ["CC"] = cc_path
+
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write("unset CC\n")
+ mozconfig.flush()
+
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+
+ self.assertEqual(result["vars"]["removed"], {})
+ self.assertEqual(result["env"]["removed"], {"CC": cc_path})
+
+ def test_read_multiline_variables(self):
+ """Ensure multi-line variables are captured properly."""
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write('multi="foo\nbar"\n')
+ mozconfig.write("single=1\n")
+ mozconfig.flush()
+
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+
+ self.assertEqual(
+ result["vars"]["added"], {"multi": "foo\nbar", "single": "1"}
+ )
+ self.assertEqual(result["env"]["added"], {})
+
+ def test_read_topsrcdir_defined(self):
+ """Ensure $topsrcdir references work as expected."""
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write("TEST=$topsrcdir")
+ mozconfig.flush()
+
+ loader = self.get_loader()
+ result = loader.read_mozconfig(mozconfig.name)
+
+ self.assertEqual(
+ result["vars"]["added"]["TEST"], loader.topsrcdir.replace(os.sep, "/")
+ )
+ self.assertEqual(result["env"]["added"], {})
+
+ def test_read_empty_variable_value(self):
+ """Ensure empty variable values are parsed properly."""
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write("EMPTY=\n")
+ mozconfig.write("export EXPORT_EMPTY=\n")
+ mozconfig.flush()
+
+ result = self.get_loader().read_mozconfig(mozconfig.name)
+
+ self.assertEqual(
+ result["vars"]["added"],
+ {
+ "EMPTY": "",
+ },
+ )
+ self.assertEqual(result["env"]["added"], {"EXPORT_EMPTY": ""})
+
+ def test_read_load_exception(self):
+ """Ensure non-0 exit codes in mozconfigs are handled properly."""
+ with NamedTemporaryFile(mode="w") as mozconfig:
+ mozconfig.write('echo "hello world"\n')
+ mozconfig.write("exit 1\n")
+ mozconfig.flush()
+
+ with self.assertRaises(MozconfigLoadException) as e:
+ self.get_loader().read_mozconfig(mozconfig.name)
+
+ self.assertIn(
+ "Evaluation of your mozconfig exited with an error", str(e.exception)
+ )
+ self.assertEqual(e.exception.path, mozconfig.name.replace(os.sep, "/"))
+ self.assertEqual(e.exception.output, ["hello world"])
+
+
+if __name__ == "__main__":
+ main()