11 from builtins
import str
29 from contextlib
import contextmanager
33 from TestSupport.TestHelper import TestHelper, UseStackFrameFromCallerForLogging, SetLoggingCallerStackFrame, \
34 SuppressedErrors, SuppressedWarnings, ExpectInfos
39 gEncodingRegExp = re.compile(
"^[ \t\v]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)")
47 encoding = gEncodingCache.get(filename)
51 with open(filename,
'rb')
as fh:
55 if bom == b
"\xef\xbb\xbf":
58 line = linecache.getline(filename, 0)
59 m = gEncodingRegExp.match(line)
61 line = linecache.getline(filename, 1)
62 m = gEncodingRegExp.match(line)
65 gEncodingCache[filename] = encoding
71 decodedLine = line.decode(encoding)
72 except UnicodeDecodeError:
73 decodedLine = line.decode(
"latin1")
108 frame = sys._getframe()
109 lastFunction = frame.f_code.co_name
111 if frame.f_code.co_name ==
'__callTestFunction':
112 class_ = frame.f_locals[
'self'].__class__
114 if hasattr(class_,
'_TestCase__callSetUpTestCase'):
116 lastFunction = frame.f_code.co_name
129 TestHelper.getInstance().setMacrosLogOnSuccess(logOnSuccess)
132 if logOnSuccess
is None:
133 return TestHelper.getInstance().getMacrosLogOnSuccess()
148 def wrapper (*args, **kwds):
149 logOnSuccess = TestHelper.getInstance().getMacrosLogOnSuccess()
152 r = func(*args, **kwds)
163 def wrapper (*args, **kwds):
165 expr, msg, comment, logOnSuccess = func(*args, **kwds)
166 stackLine = traceback.extract_stack(TestHelper.getInstance().getCallerStackFrame(), 1)[0]
167 codeLine = stackLine[3]
168 if isinstance(codeLine, bytes):
171 Logging_error(
"%s: %s%s" % (codeLine, msg,
": %s" % (comment)
if comment
else ''), type=
"Compare", depth=1)
174 Logging_info(
"%s: %s%s" % (codeLine, msg,
": %s" % (comment)
if comment
else ''), type=
"Compare", depth=1)
181 """ Returns a unicode representation of value. If value is of type bytes then non-ASCII characters
182 are escaped and a representation of the string is returned.
183 For example, the 8-bit literal b'\x01' becomes 'u"\x01"'.
185 if isinstance(value, bytes):
186 return repr(str(value))
201 if hasattr(expr,
'all'):
217 if hasattr(expr,
'any'):
257 msg =
u"Comparing %s (%s) == %s (%s) with epsilon=%f" % (str(a), type(a).__name__, str(b), type(b).__name__, epsilon)
258 return Math_compareFloatEqual(a, b, epsilon), msg, comment,
shouldLogOnSuccess(logOnSuccess)
271 msg =
u"Comparing %s (%s) != %s (%s) with epsilon=%f" % (str(a), type(a).__name__, str(b), type(b).__name__, epsilon)
272 return not Math_compareFloatEqual(a, b, epsilon), msg, comment,
shouldLogOnSuccess(logOnSuccess)
284 msg =
u"Comparing %s (%s) < %s (%s)" % (str(a), type(a).__name__, str(b), type(b).__name__)
285 return Math_compareFloatLessThan(a, b), msg, comment,
shouldLogOnSuccess(logOnSuccess)
299 msg =
u"Comparing %s (%s) <= %s (%s) with epsilon=%f" % (str(a), type(a).__name__, str(b), type(b).__name__, epsilon)
300 return Math_compareFloatLessThanOrEqual(a, b, epsilon), msg, comment,
shouldLogOnSuccess(logOnSuccess)
310 def verifyTrue (expr, comment="", logOnSuccess=None, msg=None):
311 success = bool( expr )
313 msg =
u"Must evaluate to True: {} ({})".format(
escapedUnicode(expr), type(expr).__name__ )
325 success =
not bool( expr )
327 msg =
u"Must evaluate to False: {} ({})".format( expr, type(expr).__name__ )
344 @UseStackFrameFromCallerForLogging
345 def expectError (function, args=[], kargs={}, errorRegExp=None, preventReplacingMessageSeverity=False):
346 testHelper = TestHelper.getInstance()
347 logHandler = testHelper.getLogHandler()
348 assert not logHandler
is None
350 errors =
SuppressedErrors(errorRegExp, Logging_error, preventReplacingMessageSeverity)
352 retVal = function(*args, **kargs)
354 errors.handleResult()
369 @UseStackFrameFromCallerForLogging
371 testHelper = TestHelper.getInstance()
372 logHandler = testHelper.getLogHandler()
373 assert not logHandler
is None
377 retVal = function(*args, **kargs)
379 warnings.handleResult()
394 @UseStackFrameFromCallerForLogging
396 testHelper = TestHelper.getInstance()
397 logHandler = testHelper.getLogHandler()
398 assert not logHandler
is None
403 retVal = function(*args, **kargs)
405 errors.handleResult()
406 warnings.handleResult()
424 @UseStackFrameFromCallerForLogging
425 def ignoreError (function, args=(), kargs=
None, errorRegExp=
None, resultInfoDict=
None):
426 def ___doNotLog( _msg ):
pass
429 testHelper = TestHelper.getInstance()
430 logHandler = testHelper.getLogHandler()
432 assert not logHandler
is None
434 hadIgnoredErrors =
False
437 retVal = function(*args, **kargs)
439 hadIgnoredErrors = errors.handleResult()
440 if isinstance( resultInfoDict, dict ):
441 resultInfoDict[
"hadIgnoredErrors" ] = hadIgnoredErrors
461 @UseStackFrameFromCallerForLogging
462 def ignoreWarning (function, args=(), kargs=
None, warningRegExp=
None, resultInfoDict=
None ):
463 def ___doNotLog( _msg ):
pass
466 testHelper = TestHelper.getInstance()
467 logHandler = testHelper.getLogHandler()
469 assert not logHandler
is None
471 hadIgnoredWarnings =
False
474 retVal = function(*args, **kargs)
476 hadIgnoredWarnings = warnings.handleResult()
477 if isinstance( resultInfoDict, dict ):
478 resultInfoDict[
"hadIgnoredWarnings" ] = hadIgnoredWarnings
497 @UseStackFrameFromCallerForLogging
499 testHelper = TestHelper.getInstance()
500 logHandler = testHelper.getLogHandler()
501 assert not logHandler
is None
506 retVal = function(*args, **kargs)
508 hadIgnoredErrors = errors.handleResult()
509 hadIgnoredWarnings = warnings.handleResult()
510 if isinstance( resultInfoDict, dict ):
511 resultInfoDict[
"hadIgnoredWarnings" ] = hadIgnoredWarnings
512 resultInfoDict[
"hadIgnoredErrors" ] = hadIgnoredErrors
528 @UseStackFrameFromCallerForLogging
529 def expectInfo (function, args=[], kargs={}, infoRegExp=None, allowUnexpectedMessages=True):
530 testHelper = TestHelper.getInstance()
531 logHandler = testHelper.getLogHandler()
532 assert not logHandler
is None
534 expectInfos =
ExpectInfos(infoRegExp, allowUnexpectedMessages, Logging_error)
536 retVal = function(*args, **kargs)
538 expectInfos.handleResult()
548 @UseStackFrameFromCallerForLogging
550 """Expect that the expression in the context block issues no warning that matches `warningRegExp`.
551 If `warningRegExp` is not given, no warning is expected at all.
561 warnings.handleResult()
565 @UseStackFrameFromCallerForLogging
567 """Expect that the expression in the context block logs a warning that matches `warningRegExp`.
568 If `warningRegExp` is not given, any warning is expected.
578 warnings.handleResult()
582 @UseStackFrameFromCallerForLogging
584 """Expect that the expression in the context logs an error that matches `errorRegExp`.
585 If `errorRegExp` is not given, any error is expected.
595 errors.handleResult()
599 @UseStackFrameFromCallerForLogging
601 """Expect that the expression in the context logs errors and warnings.
602 See `hasError` and `hasWarning` for the arguments.
605 with hasWarningAndError():
613 errors.handleResult()
614 warnings.handleResult()
618 @UseStackFrameFromCallerForLogging
619 def hasInfo(infoRegExp=None, allowUnexpectedMessages=True):
620 """Expect that the expression in the context logs an info entry that matches `infoRegExp`.
621 If `infoRegExp` is not given, any info message is expected.
622 If `allowUnexpectedMessages` is set to True (the default), messages that do not match `infoRegExp` are ignored,
623 otherwise they are considered a failure.
626 with hasInfo(infoRegExp=".*Unknown module.*"):
629 expectInfos =
ExpectInfos(infoRegExp, allowUnexpectedMessages, Logging_error)
633 expectInfos.handleResult()
643 return TestHelper.getInstance().getTestCaseResultDirectory()
654 return TestHelper.getInstance().getTestCaseDataDirectory()
682 testHelper = TestHelper.getInstance()
683 testCaseContext = testHelper.getTestCaseContext()
684 externalDataVariable =
'TESTCENTER_EXTERNAL_DATA_%s' % name
685 externalDataPlaceholder =
'$(%s)' % externalDataVariable
686 externalDataBaseDirectory = testCaseContext.expandFilename(externalDataPlaceholder)
687 if externalDataBaseDirectory == externalDataPlaceholder:
688 raise LookupError(
'Variable %s could not be expanded. Please define it in your .prefs file.' %
689 externalDataVariable)
690 if os.path.isdir(externalDataBaseDirectory):
692 return os.path.join(externalDataBaseDirectory, subDirectory)
694 testCasePath = testCaseContext.localPath()
695 path = mevis.MLABPackageManager.findPackageIdentifierAndRelativePath(testCasePath)[1]
696 return os.path.join(externalDataBaseDirectory, path)
697 raise ValueError(
'"%s" is not a directory.' % externalDataBaseDirectory)
712 if TestHelper.getInstance().getChangeSetStackLength() > 2:
727 def getHash (filename, hash="SHA1", encoder="Hex"):
730 b, ext = os.path.splitext(filename)
731 if ext.lower()
in (
".dcm",
".hdr",
".img",
".bmp",
".jpg",
".jpeg",
".png",
".pnm",
".quo",
".raw",
".tif",
".tiff"):
732 result = Image_calculateHashFromImage(filename, hash, encoder)
735 h = hashlib.new(hash)
736 with open(filename,
"rb")
as f:
739 result = h.hexdigest()
740 elif encoder ==
"Base64":
743 Logging_error(
"Unknown encoder (%s) selected." % (encoder))
744 except Exception
as e:
745 Logging_error(
"Failed to generate hash: %s." % e)
758 def createExtraTestCaseResult(testCaseName, package, author, duration, maintainer=None, file=None, line=None, comment=None, showTestFunctionSortingLiterals=False):
759 return ExtraTestCaseResult(testCaseName, package, author, duration, maintainer, file, line, comment, showTestFunctionSortingLiterals)
793 def wrapper (*args, **kwds):
797 result = func(*args, **kwds)
805 def wrapper (*args, **kwds):
806 wereHighPrecisionTimeStampsEnabled = mevis.MLAB.setHighPrecisionLoggingTimeStampsEnabled(
True)
808 result = func(*args, **kwds)
810 mevis.MLAB.setHighPrecisionLoggingTimeStampsEnabled(wereHighPrecisionTimeStampsEnabled)
817 table.diff {font-family:monospace;border:medium;margin:0;}
818 .diff_header {background-color:#e0e0e0}
819 td.diff_header {text-align:right}
820 .diff_next {background-color:#c0c0c0}
821 .diff_add {background-color:#aaffaa}
822 .diff_chg {background-color:#ffff77}
823 .diff_sub {background-color:#ffaaaa}
824 tr, td, th {vertical-align:top;}
826 white-space: -pre-wrap;
827 white-space: -o-pre-wrap;
828 white-space: -moz-pre-wrap;
829 white-space: pre-wrap;
830 word-wrap: break-word;
833 _table_template =
"""
834 <table class="diff" id="difflib_chg_%(prefix)s_top"
835 cellspacing="0" cellpadding="1" rules="groups" width="100%%">
836 <colgroup></colgroup> <colgroup></colgroup> <colgroup width="50%%"></colgroup>
837 <colgroup></colgroup> <colgroup></colgroup> <colgroup width="50%%"></colgroup>
840 %(data_rows)s </tbody>
844 difflib.HtmlDiff.__init__(self)
846 def _format_line(self,side,flag,linenum,text):
848 linenum =
'%d' % linenum
849 id =
' id="%s%s"' % (self._prefix[side],linenum)
854 text=text.replace(
"&",
"&").replace(
">",
">").replace(
"<",
"<")
855 if len(text) == 0
or text ==
'\n':
856 text =
'<span style="display: block; background-color:#e0e0e0;">' + text +
'</span>'
857 return '<td class="diff_header"%s>%s</td><td>%s</td>' \
869 def createHtmlDiff(fromLines, toLines, showOnlyContextOfDiff=False, numberOfContextLines=10):
870 diff =
HtmlDiff().make_file(fromLines, toLines,
"",
"", showOnlyContextOfDiff, numberOfContextLines)
878 def MLABTC__disableTestFunctionIf_Decorator(func):
879 disableTestFunction = condition()
if isinstance(condition, collections.abc.Callable)
else condition
880 if disableTestFunction:
881 module = sys.modules[func.__module__]
882 if not hasattr(module,
'MLABTC_DISABLED_TEST_FUNCTIONS'):
883 setattr(module,
'MLABTC_DISABLED_TEST_FUNCTIONS', [])
884 module.MLABTC_DISABLED_TEST_FUNCTIONS.append(func.__name__)
886 return MLABTC__disableTestFunctionIf_Decorator
891 context = TestHelper.getInstance().getHelperContext()
892 return context.field(
'oSSOffscreenRender.supported').value
908 def runProcess(command, wait=True, expectSuccess=True, expectFailure=False, verbose=True, env=None):
909 Macros_INFO(
"Running: " +
" ".join(command))
913 p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
915 p = subprocess.Popen(command, env=env)
919 if len(os.path.splitext(c)[1]) > 0:
920 c = os.path.basename(c)
921 shortCommand.append(c)
922 shortCommand =
" ".join(shortCommand)
923 stdout, stderr = p.communicate()
924 stdout = stdout.strip()
925 stderr = stderr.strip()
926 stderr = stderr.decode(
'utf-8',
'replace')
927 stdout = stdout.decode(
'utf-8',
'replace')
928 verifyProcessResult(
" ".join(command), shortCommand, p.returncode, stdout, stderr, expectSuccess, expectFailure, verbose)
929 return stdout, stderr, p.returncode
945 def verifyProcessResult(command, shortCommand, returncode, stdout, stderr, expectSuccess=True, expectFailure=False, verbose=True):
948 Macros_ERROR(
"Command returned non-zero: '" + command +
"', return code: " + str(returncode))
949 if len(stderr): Macros_ERROR(stderr)
950 if len(stdout): Macros_ERROR(stdout)
952 msg =
"Success: " + shortCommand
954 if len(stderr): msg +=
"\n\n" + stderr
955 if len(stdout): msg +=
"\n\n" + stdout
959 Macros_ERROR(
"Command returned zero: '" + command +
"'")
960 if len(stderr): Macros_ERROR(stderr)
961 if len(stdout): Macros_ERROR(stdout)
963 msg =
"Expected failure: " + shortCommand
965 if len(stderr): msg +=
"\n\n" + stderr
966 if len(stdout): msg +=
"\n\n" + stdout
982 def runPythonScript(script, arguments, wait=True, expectSuccess=True, expectFailure=False, verbose=True, env=None):
983 python = mevis.MLABFileManager.getExecutable(
"MeVisPython")
984 command = [python,
"-u", script]
985 command.extend(arguments)
986 return runProcess(command, wait=wait, expectSuccess=expectSuccess, expectFailure=expectFailure, verbose=verbose, env=env)
989 from .ExtraTestCaseResult
import ExtraTestCaseResult
990 from .Image
import calculateHashFromImage
as Image_calculateHashFromImage
991 from .Logging
import error
as Logging_error, warning
as Logging_warning, info
as Logging_info
992 from .Macros
import ERROR
as Macros_ERROR, INFO
as Macros_INFO
993 from .Math
import compareFloatEqual
as Math_compareFloatEqual, \
994 compareFloatLessThan
as Math_compareFloatLessThan, \
995 compareFloatLessThanOrEqual
as Math_compareFloatLessThanOrEqual
Decorator to globally enable or disable if the ASSERT_*/EXPECT_* macros log an info message on succes...
def __init__(self, logOnSuccess)
def pushEnvironment()
Pushes the current environment dictionary on a stack, so that modifications can be applied and be pop...
def hardwareSupportsOffscreenRendering()
def ignoreWarning(function, args=(), kargs=None, warningRegExp=None, resultInfoDict=None)
Call the given function with the given parameters and ignores potential warnings.
def pushEnvironmentDecorator(func)
def getHash(filename, hash="SHA1", encoder="Hex")
Compute a hash for the content of the given file.
def hasWarningAndError(errorRegExp=None, warningRegExp=None)
def getTestCaseContext()
Get the context of the test.
def compareNotEqual(a, b, comment="", logOnSuccess=None)
Compare the two given values for inequality.
def decodeSourceCodeLine(filename, line)
def getDataDirectory()
Method to return path to the data files.
def compareFloatEqual(a, b, comment="", epsilon=0.0001, logOnSuccess=None)
Compare the two given float values if they are epsilon-equal.
def getResultDirectory()
Getter for the directory used to save results.
def addExtraTestCaseResult(extraTestCaseResult)
Adds an ExtraTestCaseResult object.
def compareLessThan(a, b, comment="", logOnSuccess=None)
Compare the two given values if the first one is less than the second.
def hasNoWarning(warningRegExp=None)
def compareFloatNotEqual(a, b, comment="", epsilon=0.0001, logOnSuccess=None)
Compare the two given float values if they are epsilon-unequal.
def hasInfo(infoRegExp=None, allowUnexpectedMessages=True)
def ignoreWarningAndError(function, args=[], kargs={}, errorRegExp=None, warningRegExp=None, resultInfoDict=None)
Call the given function with the given parameters and ignore both a warning and an error.
def runPythonScript(script, arguments, wait=True, expectSuccess=True, expectFailure=False, verbose=True, env=None)
def compareFloatLessThanOrEqual(a, b, comment="", epsilon=0.0001, logOnSuccess=None)
Compare the two given float values if the first is less than or equal to the second.
def verifyTrue(expr, comment="", logOnSuccess=None, msg=None)
If the given expression evaluates to False, an error is logged.
def createExtraTestCaseResult(testCaseName, package, author, duration, maintainer=None, file=None, line=None, comment=None, showTestFunctionSortingLiterals=False)
Creates an ExtraTestCaseResult object.
def pushChangeSet()
Push a new ChangeSet to the stack.
def runProcess(command, wait=True, expectSuccess=True, expectFailure=False, verbose=True, env=None)
def ignoreError(function, args=(), kargs=None, errorRegExp=None, resultInfoDict=None)
Call the given function with the given parameters and ignores potential errors.
def getPackageList()
Returns the list of available packages.
def existsFileInDataDirectory(filename)
Checks if the given file exists in the data directory.
def EnableHighPrecisionLoggingTimeStampsDecorator(func)
def escapedUnicode(value)
def expectInfo(function, args=[], kargs={}, infoRegExp=None, allowUnexpectedMessages=True)
Call the given function with the given parameters and expect an info message.
def disableTestFunctionIf(condition)
def popEnvironment()
Pops the last pushed environment dictionary from a stack and makes it the current one.
def getTestFunctionName()
Returns the name of the current test function.
def getFileInDataDirectory(filename)
Returns the absolute filename of a file in the data directory using getDataDirectory().
def getModuleName()
Return the name of the currently tested module.
def hasError(errorRegExp=None)
def expectError(function, args=[], kargs={}, errorRegExp=None, preventReplacingMessageSeverity=False)
Call the given function with the given parameters and expect an error.
def verifyProcessResult(command, shortCommand, returncode, stdout, stderr, expectSuccess=True, expectFailure=False, verbose=True)
def popChangeSet()
Pop the last ChangeSet from the stack.
def LoggingDecorator(func)
Internal decorator used for creating messages in compare methods.
def compareFloatLessThan(a, b, comment="", logOnSuccess=None)
Compare the two given float values if the first is less than the second.
def setMacrosShouldLogOnSuccess(logOnSuccess)
Globally enables or disables if the ASSERT_*/EXPECT_* macros log an info message on success.
def verifyFalse(expr, comment="", logOnSuccess=None, msg=None)
If the given expression evaluates to True, an error is logged.
def hasWarning(warningRegExp=None)
def shouldLogOnSuccess(logOnSuccess=None)
def createHtmlDiff(fromLines, toLines, showOnlyContextOfDiff=False, numberOfContextLines=10)
def getExternalDataDirectory(name, subDirectory=None)
Method to return path to the external data directory.
def compareEqual(a, b, comment="", logOnSuccess=None)
Compare the two given values for equality.
def expectWarning(function, args=[], kargs={}, warningRegExp=None)
Call the given function with the given parameters and expect a warning.
def expectWarningAndError(function, args=[], kargs={}, errorRegExp=None, warningRegExp=None)
Call the given function with the given parameters and expect both a warning and an error.
def getSourceFileEncoding(filename)
def compareLessThanOrEqual(a, b, comment="", logOnSuccess=None)
Compare the two given values if the first one is less than or equal to the second.