|  | # 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 unittest import TextTestRunner as _TestRunner, TestResult as _TestResult | 
|  | import unittest | 
|  | import inspect | 
|  | from StringIO import StringIO | 
|  | import os | 
|  |  | 
|  | '''Helper to make python unit tests report the way that the Mozilla | 
|  | unit test infrastructure expects tests to report. | 
|  |  | 
|  | Usage: | 
|  |  | 
|  | import unittest | 
|  | 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 addSuccess(self, test): | 
|  | _TestResult.addSuccess(self, test) | 
|  | filename = inspect.getfile(test.__class__) | 
|  | testname = test._testMethodName | 
|  | self.stream.writeln("TEST-PASS | {0} | {1}".format(filename, testname)) | 
|  |  | 
|  | def addError(self, test, err): | 
|  | _TestResult.addError(self, test, err) | 
|  | self.printFail(test, err) | 
|  |  | 
|  | def addFailure(self, test, err): | 
|  | _TestResult.addFailure(self, test, err) | 
|  | self.printFail(test,err) | 
|  |  | 
|  | def printFail(self, test, err): | 
|  | exctype, value, tb = err | 
|  | # Skip test runner traceback levels | 
|  | while tb and self._is_relevant_tb_level(tb): | 
|  | tb = tb.tb_next | 
|  | if not tb: | 
|  | self.stream.writeln("TEST-UNEXPECTED-FAIL | NO TRACEBACK |") | 
|  | _f, _ln, _t = inspect.getframeinfo(tb)[:3] | 
|  | self.stream.writeln("TEST-UNEXPECTED-FAIL | {0} | line {1}, {2}: {3}" | 
|  | .format(_f, _ln, _t, value.message)) | 
|  |  | 
|  | def printErrorList(self): | 
|  | for test, err in self.errors: | 
|  | self.stream.writeln("ERROR: {0}".format(self.getDescription(test))) | 
|  | self.stream.writeln("{0}".format(err)) | 
|  |  | 
|  |  | 
|  | class MozTestRunner(_TestRunner): | 
|  | def _makeResult(self): | 
|  | return _MozTestResult(self.stream, self.descriptions) | 
|  | def run(self, test): | 
|  | result = self._makeResult() | 
|  | test(result) | 
|  | result.printErrorList() | 
|  | 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() | 
|  |  | 
|  | 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. | 
|  |  | 
|  | 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.iteritems(): | 
|  | self.files[os.path.abspath(name)] = content | 
|  |  | 
|  | def __call__(self, name, mode = 'r'): | 
|  | absname = os.path.abspath(name) | 
|  | if 'w' in mode: | 
|  | file = MockedFile(self, absname) | 
|  | elif absname in self.files: | 
|  | file = MockedFile(self, absname, self.files[absname]) | 
|  | 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 __builtin__ | 
|  | self.open = __builtin__.open | 
|  | self._orig_path_exists = os.path.exists | 
|  | __builtin__.open = self | 
|  | os.path.exists = self._wrapped_exists | 
|  |  | 
|  | def __exit__(self, type, value, traceback): | 
|  | import __builtin__ | 
|  | __builtin__.open = self.open | 
|  | os.path.exists = self._orig_path_exists | 
|  |  | 
|  | def _wrapped_exists(self, p): | 
|  | if p in self.files: | 
|  | return True | 
|  |  | 
|  | abspath = os.path.abspath(p) | 
|  | if abspath in self.files: | 
|  | return True | 
|  |  | 
|  | return self._orig_path_exists(p) | 
|  |  | 
|  | def main(*args): | 
|  | unittest.main(testRunner=MozTestRunner(),*args) |