Bug 1438250 - Make mozunit pip installable; r?ahal draft
authorDave Hunt <dhunt@mozilla.com>
Wed, 28 Mar 2018 18:08:51 +0100
changeset 773946 55a3febe7a3d9a382673427d8a14055127b2424a
parent 773797 a456475502b80a1264642d9eaee9394a8fad8315
push id104349
push userbmo:dave.hunt@gmail.com
push dateWed, 28 Mar 2018 17:57:26 +0000
reviewersahal
bugs1438250
milestone61.0a1
Bug 1438250 - Make mozunit pip installable; r?ahal MozReview-Commit-ID: FHxFQJ3NUUc
config/mozunit.py
config/mozunit/mozunit/__init__.py
config/mozunit/mozunit/mozunit.py
config/mozunit/setup.py
deleted file mode 100644
--- a/config/mozunit.py
+++ /dev/null
@@ -1,240 +0,0 @@
-# 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
-import inspect
-import os
-import sys
-import unittest
-from unittest import TextTestRunner as _TestRunner, TestResult as _TestResult
-
-import pytest
-import six
-
-StringIO = six.StringIO
-
-'''Helper to make python unit tests report the way that the Mozilla
-unit test infrastructure expects tests to report.
-
-Usage:
-
-import mozunit
-
-if __name__ == '__main__':
-    mozunit.main()
-'''
-
-
-class _MozTestResult(_TestResult):
-    def __init__(self, stream, descriptions):
-        _TestResult.__init__(self)
-        self.stream = stream
-        self.descriptions = descriptions
-
-    def getDescription(self, test):
-        if self.descriptions:
-            return test.shortDescription() or str(test)
-        else:
-            return str(test)
-
-    def printStatus(self, status, test, message=''):
-        line = "{status} | {file} | {klass}.{test}{sep}{message}".format(
-            status=status,
-            file=inspect.getfile(test.__class__),
-            klass=test.__class__.__name__,
-            test=test._testMethodName,
-            sep=', ' if message else '',
-            message=message,
-        )
-        self.stream.writeln(line)
-
-    def addSuccess(self, test):
-        _TestResult.addSuccess(self, test)
-        self.printStatus('TEST-PASS', test)
-
-    def addSkip(self, test, reason):
-        _TestResult.addSkip(self, test, reason)
-        self.printStatus('TEST-SKIP', test)
-
-    def addExpectedFailure(self, test, err):
-        _TestResult.addExpectedFailure(self, test, err)
-        self.printStatus('TEST-KNOWN-FAIL', test)
-
-    def addUnexpectedSuccess(self, test):
-        _TestResult.addUnexpectedSuccess(self, test)
-        self.printStatus('TEST-UNEXPECTED-PASS', test)
-
-    def addError(self, test, err):
-        _TestResult.addError(self, test, err)
-        self.printFail(test, err)
-        self.stream.writeln("ERROR: {0}".format(self.getDescription(test)))
-        self.stream.writeln(self.errors[-1][1])
-
-    def addFailure(self, test, err):
-        _TestResult.addFailure(self, test, err)
-        self.printFail(test, err)
-        self.stream.writeln("FAIL: {0}".format(self.getDescription(test)))
-        self.stream.writeln(self.failures[-1][1])
-
-    def printFail(self, test, err):
-        exctype, value, tb = err
-        message = value or 'NO MESSAGE'
-        if hasattr(value, 'message'):
-            message = value.message.splitlines()[0]
-        # Skip test runner traceback levels
-        while tb and self._is_relevant_tb_level(tb):
-            tb = tb.tb_next
-        if tb:
-            _, ln, _ = inspect.getframeinfo(tb)[:3]
-            message = 'line {0}: {1}'.format(ln, message)
-        self.printStatus("TEST-UNEXPECTED-FAIL", test, message)
-
-
-class MozTestRunner(_TestRunner):
-    def _makeResult(self):
-        return _MozTestResult(self.stream, self.descriptions)
-
-    def run(self, test):
-        result = self._makeResult()
-        test(result)
-        return result
-
-
-class MockedFile(StringIO):
-    def __init__(self, context, filename, content=''):
-        self.context = context
-        self.name = filename
-        StringIO.__init__(self, content)
-
-    def close(self):
-        self.context.files[self.name] = self.getvalue()
-        StringIO.close(self)
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, type, value, traceback):
-        self.close()
-
-
-def normcase(path):
-    '''
-    Normalize the case of `path`.
-
-    Don't use `os.path.normcase` because that also normalizes forward slashes
-    to backslashes on Windows.
-    '''
-    if sys.platform.startswith('win'):
-        return path.lower()
-    return path
-
-
-class MockedOpen(object):
-    '''
-    Context manager diverting the open builtin such that opening files
-    can open "virtual" file instances given when creating a MockedOpen.
-
-    with MockedOpen({'foo': 'foo', 'bar': 'bar'}):
-        f = open('foo', 'r')
-
-    will thus open the virtual file instance for the file 'foo' to f.
-
-    If the content of a file is given as None, then that file will be
-    represented as not existing (even if it does, actually, exist).
-
-    MockedOpen also masks writes, so that creating or replacing files
-    doesn't touch the file system, while subsequently opening the file
-    will return the recorded content.
-
-    with MockedOpen():
-        f = open('foo', 'w')
-        f.write('foo')
-    self.assertRaises(Exception,f.open('foo', 'r'))
-    '''
-    def __init__(self, files={}):
-        self.files = {}
-        for name, content in files.items():
-            self.files[normcase(os.path.abspath(name))] = content
-
-    def __call__(self, name, mode='r'):
-        absname = normcase(os.path.abspath(name))
-        if 'w' in mode:
-            file = MockedFile(self, absname)
-        elif absname in self.files:
-            content = self.files[absname]
-            if content is None:
-                raise IOError(2, 'No such file or directory')
-            file = MockedFile(self, absname, content)
-        elif 'a' in mode:
-            file = MockedFile(self, absname, self.open(name, 'r').read())
-        else:
-            file = self.open(name, mode)
-        if 'a' in mode:
-            file.seek(0, os.SEEK_END)
-        return file
-
-    def __enter__(self):
-        import six.moves.builtins
-        self.open = six.moves.builtins.open
-        self._orig_path_exists = os.path.exists
-        self._orig_path_isdir = os.path.isdir
-        self._orig_path_isfile = os.path.isfile
-        six.moves.builtins.open = self
-        os.path.exists = self._wrapped_exists
-        os.path.isdir = self._wrapped_isdir
-        os.path.isfile = self._wrapped_isfile
-
-    def __exit__(self, type, value, traceback):
-        import six.moves.builtins
-        six.moves.builtins.open = self.open
-        os.path.exists = self._orig_path_exists
-        os.path.isdir = self._orig_path_isdir
-        os.path.isfile = self._orig_path_isfile
-
-    def _wrapped_exists(self, p):
-        return (self._wrapped_isfile(p) or
-                self._wrapped_isdir(p))
-
-    def _wrapped_isfile(self, p):
-        p = normcase(p)
-        if p in self.files:
-            return self.files[p] is not None
-
-        abspath = normcase(os.path.abspath(p))
-        if abspath in self.files:
-            return self.files[abspath] is not None
-
-        return self._orig_path_isfile(p)
-
-    def _wrapped_isdir(self, p):
-        p = normcase(p)
-        p = p if p.endswith(('/', '\\')) else p + os.sep
-        if any(f.startswith(p) for f in self.files):
-            return True
-
-        abspath = normcase(os.path.abspath(p) + os.sep)
-        if any(f.startswith(abspath) for f in self.files):
-            return True
-
-        return self._orig_path_isdir(p)
-
-
-def main(*args, **kwargs):
-    runwith = kwargs.pop('runwith', 'pytest')
-
-    if runwith == 'unittest':
-        unittest.main(testRunner=MozTestRunner(), *args, **kwargs)
-    else:
-        args = list(args)
-        if os.environ.get('MACH_STDOUT_ISATTY') and not any(a.startswith('--color') for a in args):
-            args.append('--color=yes')
-
-        module = __import__('__main__')
-        args.extend([
-            '-vv',
-            '-p', 'mozlog.pytest_mozlog.plugin',
-            '-p', 'no:cacheprovider',
-            module.__file__,
-        ])
-        sys.exit(pytest.main(args))
new file mode 100644
--- /dev/null
+++ b/config/mozunit/mozunit/__init__.py
@@ -0,0 +1,8 @@
+# flake8: noqa
+# 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
+
+from .mozunit import *
new file mode 100644
--- /dev/null
+++ b/config/mozunit/mozunit/mozunit.py
@@ -0,0 +1,240 @@
+# 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
+import inspect
+import os
+import sys
+import unittest
+from unittest import TextTestRunner as _TestRunner, TestResult as _TestResult
+
+import pytest
+import six
+
+StringIO = six.StringIO
+
+'''Helper to make python unit tests report the way that the Mozilla
+unit test infrastructure expects tests to report.
+
+Usage:
+
+import mozunit
+
+if __name__ == '__main__':
+    mozunit.main()
+'''
+
+
+class _MozTestResult(_TestResult):
+    def __init__(self, stream, descriptions):
+        _TestResult.__init__(self)
+        self.stream = stream
+        self.descriptions = descriptions
+
+    def getDescription(self, test):
+        if self.descriptions:
+            return test.shortDescription() or str(test)
+        else:
+            return str(test)
+
+    def printStatus(self, status, test, message=''):
+        line = "{status} | {file} | {klass}.{test}{sep}{message}".format(
+            status=status,
+            file=inspect.getfile(test.__class__),
+            klass=test.__class__.__name__,
+            test=test._testMethodName,
+            sep=', ' if message else '',
+            message=message,
+        )
+        self.stream.writeln(line)
+
+    def addSuccess(self, test):
+        _TestResult.addSuccess(self, test)
+        self.printStatus('TEST-PASS', test)
+
+    def addSkip(self, test, reason):
+        _TestResult.addSkip(self, test, reason)
+        self.printStatus('TEST-SKIP', test)
+
+    def addExpectedFailure(self, test, err):
+        _TestResult.addExpectedFailure(self, test, err)
+        self.printStatus('TEST-KNOWN-FAIL', test)
+
+    def addUnexpectedSuccess(self, test):
+        _TestResult.addUnexpectedSuccess(self, test)
+        self.printStatus('TEST-UNEXPECTED-PASS', test)
+
+    def addError(self, test, err):
+        _TestResult.addError(self, test, err)
+        self.printFail(test, err)
+        self.stream.writeln("ERROR: {0}".format(self.getDescription(test)))
+        self.stream.writeln(self.errors[-1][1])
+
+    def addFailure(self, test, err):
+        _TestResult.addFailure(self, test, err)
+        self.printFail(test, err)
+        self.stream.writeln("FAIL: {0}".format(self.getDescription(test)))
+        self.stream.writeln(self.failures[-1][1])
+
+    def printFail(self, test, err):
+        exctype, value, tb = err
+        message = value or 'NO MESSAGE'
+        if hasattr(value, 'message'):
+            message = value.message.splitlines()[0]
+        # Skip test runner traceback levels
+        while tb and self._is_relevant_tb_level(tb):
+            tb = tb.tb_next
+        if tb:
+            _, ln, _ = inspect.getframeinfo(tb)[:3]
+            message = 'line {0}: {1}'.format(ln, message)
+        self.printStatus("TEST-UNEXPECTED-FAIL", test, message)
+
+
+class MozTestRunner(_TestRunner):
+    def _makeResult(self):
+        return _MozTestResult(self.stream, self.descriptions)
+
+    def run(self, test):
+        result = self._makeResult()
+        test(result)
+        return result
+
+
+class MockedFile(StringIO):
+    def __init__(self, context, filename, content=''):
+        self.context = context
+        self.name = filename
+        StringIO.__init__(self, content)
+
+    def close(self):
+        self.context.files[self.name] = self.getvalue()
+        StringIO.close(self)
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, value, traceback):
+        self.close()
+
+
+def normcase(path):
+    '''
+    Normalize the case of `path`.
+
+    Don't use `os.path.normcase` because that also normalizes forward slashes
+    to backslashes on Windows.
+    '''
+    if sys.platform.startswith('win'):
+        return path.lower()
+    return path
+
+
+class MockedOpen(object):
+    '''
+    Context manager diverting the open builtin such that opening files
+    can open "virtual" file instances given when creating a MockedOpen.
+
+    with MockedOpen({'foo': 'foo', 'bar': 'bar'}):
+        f = open('foo', 'r')
+
+    will thus open the virtual file instance for the file 'foo' to f.
+
+    If the content of a file is given as None, then that file will be
+    represented as not existing (even if it does, actually, exist).
+
+    MockedOpen also masks writes, so that creating or replacing files
+    doesn't touch the file system, while subsequently opening the file
+    will return the recorded content.
+
+    with MockedOpen():
+        f = open('foo', 'w')
+        f.write('foo')
+    self.assertRaises(Exception,f.open('foo', 'r'))
+    '''
+    def __init__(self, files={}):
+        self.files = {}
+        for name, content in files.items():
+            self.files[normcase(os.path.abspath(name))] = content
+
+    def __call__(self, name, mode='r'):
+        absname = normcase(os.path.abspath(name))
+        if 'w' in mode:
+            file = MockedFile(self, absname)
+        elif absname in self.files:
+            content = self.files[absname]
+            if content is None:
+                raise IOError(2, 'No such file or directory')
+            file = MockedFile(self, absname, content)
+        elif 'a' in mode:
+            file = MockedFile(self, absname, self.open(name, 'r').read())
+        else:
+            file = self.open(name, mode)
+        if 'a' in mode:
+            file.seek(0, os.SEEK_END)
+        return file
+
+    def __enter__(self):
+        import six.moves.builtins
+        self.open = six.moves.builtins.open
+        self._orig_path_exists = os.path.exists
+        self._orig_path_isdir = os.path.isdir
+        self._orig_path_isfile = os.path.isfile
+        six.moves.builtins.open = self
+        os.path.exists = self._wrapped_exists
+        os.path.isdir = self._wrapped_isdir
+        os.path.isfile = self._wrapped_isfile
+
+    def __exit__(self, type, value, traceback):
+        import six.moves.builtins
+        six.moves.builtins.open = self.open
+        os.path.exists = self._orig_path_exists
+        os.path.isdir = self._orig_path_isdir
+        os.path.isfile = self._orig_path_isfile
+
+    def _wrapped_exists(self, p):
+        return (self._wrapped_isfile(p) or
+                self._wrapped_isdir(p))
+
+    def _wrapped_isfile(self, p):
+        p = normcase(p)
+        if p in self.files:
+            return self.files[p] is not None
+
+        abspath = normcase(os.path.abspath(p))
+        if abspath in self.files:
+            return self.files[abspath] is not None
+
+        return self._orig_path_isfile(p)
+
+    def _wrapped_isdir(self, p):
+        p = normcase(p)
+        p = p if p.endswith(('/', '\\')) else p + os.sep
+        if any(f.startswith(p) for f in self.files):
+            return True
+
+        abspath = normcase(os.path.abspath(p) + os.sep)
+        if any(f.startswith(abspath) for f in self.files):
+            return True
+
+        return self._orig_path_isdir(p)
+
+
+def main(*args, **kwargs):
+    runwith = kwargs.pop('runwith', 'pytest')
+
+    if runwith == 'unittest':
+        unittest.main(testRunner=MozTestRunner(), *args, **kwargs)
+    else:
+        args = list(args)
+        if os.environ.get('MACH_STDOUT_ISATTY') and not any(a.startswith('--color') for a in args):
+            args.append('--color=yes')
+
+        module = __import__('__main__')
+        args.extend([
+            '-vv',
+            '-p', 'mozlog.pytest_mozlog.plugin',
+            '-p', 'no:cacheprovider',
+            module.__file__,
+        ])
+        sys.exit(pytest.main(args))
new file mode 100644
--- /dev/null
+++ b/config/mozunit/setup.py
@@ -0,0 +1,19 @@
+# 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
+
+from setuptools import setup
+
+setup(name='mozunit',
+      version='1.0',
+      description="Make unit tests report the way Mozilla infrastructure expects",
+      classifiers=['Programming Language :: Python :: 2.7'],
+      keywords='mozilla',
+      author='Mozilla Automation and Tools team',
+      author_email='tools@lists.mozilla.org',
+      license='MPL',
+      packages=['mozunit'],
+      include_package_data=True,
+      zip_safe=False)