Bug 1257516 - Add a unit test for check_prog(). r=ted
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 25 Mar 2016 17:15:47 +0900
changeset 328789 e521d0d6b1bf2fe858519d98e452581953cdee6a
parent 328788 2a6f03d3e6d446601bffcf88de57b649e5b41c90
child 328790 062e0b17553ccac075a0cab36f012d9633a64665
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs1257516
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1257516 - Add a unit test for check_prog(). r=ted At the same time, shell quote the result it prints if it needs to be.
build/moz.configure/checks.configure
python/moz.build
python/mozbuild/mozbuild/configure/__init__.py
python/mozbuild/mozbuild/test/configure/test_checks_configure.py
--- a/build/moz.configure/checks.configure
+++ b/build/moz.configure/checks.configure
@@ -43,38 +43,39 @@ def checking(what, callback=None):
 
 
 # Template to check for programs in $PATH.
 #   check('PROG', ('a', 'b'))
 # will look for 'a' or 'b' in $PATH, and set_config PROG to the one
 # it can find. If PROG is already set from the environment or command line,
 # use that value instead.
 @template
+@advanced
 def check_prog(var, progs, allow_missing=False):
+    from mozbuild.shellutil import quote
+
     option(env=var, nargs=1, help='Path to the %s program' % var.lower())
 
     if not (isinstance(progs, tuple) or isinstance(progs, list)):
         configure_error('progs should be a list or tuple!')
     progs = list(progs)
 
     @depends(var)
-    @checking('for %s' % var.lower(), lambda x: x or 'not found')
+    @checking('for %s' % var.lower(), lambda x: quote(x) if x else 'not found')
     def check(value):
         if value:
             progs[:] = value
         for prog in progs:
             result = find_program(prog)
             if result:
                 return result
 
     @depends(check, var)
-    @advanced
     def postcheck(value, raw_value):
         if value is None and (not allow_missing or raw_value):
-            from mozbuild.shellutil import quote
             die('Cannot find %s (tried: %s)', var.lower(),
                 ', '.join(quote(p) for p in progs))
 
     @depends(check)
     def normalized_for_config(value):
         return ':' if value is None else value
 
     set_config(var, normalized_for_config)
--- a/python/moz.build
+++ b/python/moz.build
@@ -29,16 +29,17 @@ PYTHON_UNIT_TESTS += [
     'mozbuild/mozbuild/test/action/test_buildlist.py',
     'mozbuild/mozbuild/test/action/test_generate_browsersearch.py',
     'mozbuild/mozbuild/test/backend/test_android_eclipse.py',
     'mozbuild/mozbuild/test/backend/test_build.py',
     'mozbuild/mozbuild/test/backend/test_configenvironment.py',
     'mozbuild/mozbuild/test/backend/test_recursivemake.py',
     'mozbuild/mozbuild/test/backend/test_visualstudio.py',
     'mozbuild/mozbuild/test/compilation/test_warnings.py',
+    'mozbuild/mozbuild/test/configure/test_checks_configure.py',
     'mozbuild/mozbuild/test/configure/test_configure.py',
     'mozbuild/mozbuild/test/configure/test_options.py',
     'mozbuild/mozbuild/test/configure/test_util.py',
     'mozbuild/mozbuild/test/controller/test_ccachestats.py',
     'mozbuild/mozbuild/test/controller/test_clobber.py',
     'mozbuild/mozbuild/test/frontend/test_context.py',
     'mozbuild/mozbuild/test/frontend/test_emitter.py',
     'mozbuild/mozbuild/test/frontend/test_namespaces.py',
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -523,17 +523,17 @@ class ConfigureSandbox(dict):
         if not inspect.isfunction(func):
             raise TypeError("Unexpected type: '%s'" % type(func))
         if func in self._prepared_functions:
             return func, func.func_globals
 
         glob = SandboxedGlobal(func.func_globals)
         glob.update(
             __builtins__=self.BUILTINS,
-            __file__=self._paths[-1],
+            __file__=self._paths[-1] if self._paths else '',
             os=self.OS,
             log=self.log_impl,
         )
         func = wraps(func)(types.FunctionType(
             func.func_code,
             glob,
             func.__name__,
             func.func_defaults,
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
@@ -0,0 +1,160 @@
+# 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/.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from StringIO import StringIO
+import os
+import unittest
+
+from mozunit import main
+
+from mozbuild.configure import (
+    ConfigureError,
+    ConfigureSandbox,
+)
+
+from buildconfig import topsrcdir
+
+
+class FindProgramSandbox(ConfigureSandbox):
+    def __init__(self, *args, **kwargs):
+        super(FindProgramSandbox, self).__init__(*args, **kwargs)
+
+        # We could define self.find_program_impl and have it automatically
+        # declared, but then it wouldn't be available in the tested templates.
+        # We also need to use super().__setitem__ because ours would do
+        # nothing.
+        super(FindProgramSandbox, self).__setitem__(
+            'find_program', self.template_impl(self.find_program))
+
+    PROGRAMS = {
+        'known-a': '/usr/bin/known-a',
+        'known-b': '/usr/local/bin/known-b',
+        'known c': '/home/user/bin/known c',
+    }
+
+    for p in PROGRAMS.values():
+        PROGRAMS[p] = p
+
+    @staticmethod
+    def find_program(prog):
+        return FindProgramSandbox.PROGRAMS.get(prog)
+
+    def __setitem__(self, key, value):
+        # Avoid util.configure overwriting our mock find_program
+        if key == 'find_program':
+            return
+
+        super(FindProgramSandbox, self).__setitem__(key, value)
+
+
+class TestChecksConfigure(unittest.TestCase):
+    def get_result(self, command='', args=[], environ={},
+                   prog='/bin/configure'):
+        config = {}
+        out = StringIO()
+        sandbox = FindProgramSandbox(config, environ, [prog] + args, out, out)
+        base_dir = os.path.join(topsrcdir, 'build', 'moz.configure')
+        sandbox.exec_file(os.path.join(base_dir, 'util.configure'))
+        sandbox.exec_file(os.path.join(base_dir, 'checks.configure'))
+
+        status = 0
+        try:
+            exec(command, sandbox)
+        except SystemExit as e:
+            status = e.code
+
+        return config, out.getvalue(), status
+
+    def test_check_prog(self):
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("known-a",))')
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'FOO': '/usr/bin/known-a'})
+        self.assertEqual(out, 'checking for foo... /usr/bin/known-a\n')
+
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown", "known-b", "known c"))')
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'FOO': '/usr/local/bin/known-b'})
+        self.assertEqual(out, 'checking for foo... /usr/local/bin/known-b\n')
+
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown", "unknown-2", "known c"))')
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'FOO': '/home/user/bin/known c'})
+        self.assertEqual(out, "checking for foo... '/home/user/bin/known c'\n")
+
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown",))')
+        self.assertEqual(status, 1)
+        self.assertEqual(config, {})
+        self.assertEqual(out, 'checking for foo... not found\n'
+                              'ERROR: Cannot find foo (tried: unknown)\n')
+
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown", "unknown-2", "unknown 3"))')
+        self.assertEqual(status, 1)
+        self.assertEqual(config, {})
+        self.assertEqual(out, 'checking for foo... not found\n'
+                              'ERROR: Cannot find foo '
+                              "(tried: unknown, unknown-2, 'unknown 3')\n")
+
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown", "unknown-2", "unknown 3"), '
+            'allow_missing=True)')
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'FOO': ':'})
+        self.assertEqual(out, 'checking for foo... not found\n')
+
+    def test_check_prog_with_args(self):
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown", "known-b", "known c"))',
+            ['FOO=known-a'])
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'FOO': '/usr/bin/known-a'})
+        self.assertEqual(out, 'checking for foo... /usr/bin/known-a\n')
+
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown", "known-b", "known c"))',
+            ['FOO=/usr/bin/known-a'])
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'FOO': '/usr/bin/known-a'})
+        self.assertEqual(out, 'checking for foo... /usr/bin/known-a\n')
+
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown", "known-b", "known c"))',
+            ['FOO=/usr/local/bin/known-a'])
+        self.assertEqual(status, 1)
+        self.assertEqual(config, {})
+        self.assertEqual(out, 'checking for foo... not found\n'
+                              'ERROR: Cannot find foo '
+                              '(tried: /usr/local/bin/known-a)\n')
+
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown",))',
+            ['FOO=known c'])
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'FOO': '/home/user/bin/known c'})
+        self.assertEqual(out, "checking for foo... '/home/user/bin/known c'\n")
+
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown", "unknown-2", "unknown 3"), '
+            'allow_missing=True)', ['FOO=unknown'])
+        self.assertEqual(status, 1)
+        self.assertEqual(config, {})
+        self.assertEqual(out, 'checking for foo... not found\n'
+                              'ERROR: Cannot find foo (tried: unknown)\n')
+
+    def test_check_prog_configure_error(self):
+        with self.assertRaises(ConfigureError) as e:
+            self.get_result('check_prog("FOO", "foo")')
+
+        self.assertEqual(e.exception.message,
+                         'progs should be a list or tuple!')
+
+
+if __name__ == '__main__':
+    main()