27 from contextlib
import contextmanager
33 UseStackFrameFromCallerForLogging,
34 SetLoggingCallerStackFrame,
44 gEncodingRegExp = re.compile(
"^[ \t\v]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)")
54 encoding = gEncodingCache.get(filename)
58 with open(filename,
"rb")
as fh:
62 if bom == b
"\xef\xbb\xbf":
65 line = linecache.getline(filename, 0)
66 m = gEncodingRegExp.match(line)
68 line = linecache.getline(filename, 1)
69 m = gEncodingRegExp.match(line)
72 gEncodingCache[filename] = encoding
79 decodedLine = line.decode(encoding)
80 except UnicodeDecodeError:
81 decodedLine = line.decode(
"latin1")
125 frame = sys._getframe()
126 lastFunction = frame.f_code.co_name
128 if frame.f_code.co_name ==
"__callTestFunction":
129 class_ = frame.f_locals[
"self"].__class__
131 if hasattr(class_,
"_TestCase__callSetUpTestCase"):
133 lastFunction = frame.f_code.co_name
147 TestHelper.getInstance().setMacrosLogOnSuccess(logOnSuccess)
151 if logOnSuccess
is None:
152 return TestHelper.getInstance().getMacrosLogOnSuccess()
169 def wrapper(*args, **kwds):
170 logOnSuccess = TestHelper.getInstance().getMacrosLogOnSuccess()
173 r = func(*args, **kwds)
188 def wrapper(*args, **kwds):
190 expr, msg, comment, logOnSuccess = func(*args, **kwds)
191 stackLine = traceback.extract_stack(TestHelper.getInstance().getCallerStackFrame(), 1)[0]
192 codeLine = stackLine[3]
193 if isinstance(codeLine, bytes):
197 "%s: %s%s" % (codeLine, msg,
": %s" % (comment)
if comment
else ""), type=
"Compare", depth=1
202 "%s: %s%s" % (codeLine, msg,
": %s" % (comment)
if comment
else ""), type=
"Compare", depth=1
214 """Returns a unicode representation of value. If value is of type bytes then non-ASCII characters
215 are escaped and a representation of the string is returned.
216 For example, the 8-bit literal b'\x01' becomes 'u"\x01"'.
218 if isinstance(value, bytes):
219 return repr(str(value))
235 if hasattr(expr,
"all"):
239 f
"{escapedUnicode(a)} ({type(a).__name__}) == {escapedUnicode(b)} ({type(b).__name__})",
259 if hasattr(expr,
"any"):
263 f
"{escapedUnicode(a)} ({type(a).__name__}) != {escapedUnicode(b)} ({type(b).__name__})",
283 f
"{escapedUnicode(a)} ({type(a).__name__}) < {escapedUnicode(b)} ({type(b).__name__})",
303 f
"{escapedUnicode(a)} ({type(a).__name__}) > {escapedUnicode(b)} ({type(b).__name__})",
324 f
"{escapedUnicode(a)} ({type(a).__name__}) >= {escapedUnicode(b)} ({type(b).__name__})",
345 f
"{escapedUnicode(a)} ({type(a).__name__}) <= {escapedUnicode(b)} ({type(b).__name__})",
364 msg = f
"Comparing {str(a)} ({type(a).__name__}) == {str(b)} ({type(b).__name__}) with epsilon={epsilon}"
365 return Math_compareFloatEqual(a, b, epsilon), msg, comment,
shouldLogOnSuccess(logOnSuccess)
381 msg = f
"Comparing {str(a)} ({type(a).__name__}) != {str(b)} ({type(b).__name__}) with epsilon={epsilon}"
382 return not Math_compareFloatEqual(a, b, epsilon), msg, comment,
shouldLogOnSuccess(logOnSuccess)
397 msg = f
"Comparing {str(a)} ({type(a).__name__}) < {str(b)} ({type(b).__name__})"
398 return Math_compareFloatLessThan(a, b), msg, comment,
shouldLogOnSuccess(logOnSuccess)
413 msg = f
"Comparing {str(a)} ({type(a).__name__}) > {str(b)} ({type(b).__name__})"
414 return Math_compareFloatLessThan(b, a), msg, comment,
shouldLogOnSuccess(logOnSuccess)
431 msg = f
"Comparing {str(a)} ({type(a).__name__}) <= {str(b)} ({type(b).__name__}) with epsilon={epsilon}"
432 return Math_compareFloatLessThanOrEqual(a, b, epsilon), msg, comment,
shouldLogOnSuccess(logOnSuccess)
449 msg = f
"Comparing {str(a)} ({type(a).__name__}) >= {str(b)} ({type(b).__name__}) with epsilon={epsilon}"
450 return Math_compareFloatLessThanOrEqual(b, a, epsilon), msg, comment,
shouldLogOnSuccess(logOnSuccess)
463 def verifyTrue(expr, comment="", logOnSuccess=None, msg=None):
468 msg = f
"Must evaluate to True: {escapedUnicode(expr)} ({type(expr).__name__})"
487 msg = f
"Must evaluate to False: {escapedUnicode(expr)} ({type(expr).__name__})"
507 @UseStackFrameFromCallerForLogging
508 def expectError(function, args=[], kargs={}, errorRegExp=None, preventReplacingMessageSeverity=False):
509 testHelper = TestHelper.getInstance()
510 logHandler = testHelper.getLogHandler()
511 assert not logHandler
is None
513 errors =
SuppressedErrors(errorRegExp, Logging_error, preventReplacingMessageSeverity)
515 retVal = function(*args, **kargs)
517 errors.handleResult()
535 @UseStackFrameFromCallerForLogging
537 testHelper = TestHelper.getInstance()
538 logHandler = testHelper.getLogHandler()
539 assert not logHandler
is None
543 retVal = function(*args, **kargs)
545 warnings.handleResult()
563 @UseStackFrameFromCallerForLogging
565 testHelper = TestHelper.getInstance()
566 logHandler = testHelper.getLogHandler()
567 assert not logHandler
is None
572 retVal = function(*args, **kargs)
574 errors.handleResult()
575 warnings.handleResult()
594 @UseStackFrameFromCallerForLogging
595 def ignoreError(function, args=(), kargs=
None, errorRegExp=
None, resultInfoDict=
None):
596 def ___doNotLog(_msg):
601 testHelper = TestHelper.getInstance()
602 logHandler = testHelper.getLogHandler()
604 assert not logHandler
is None
606 hadIgnoredErrors =
False
607 errors = SuppressedErrors(errorRegExp, logErrorFunc=
None)
609 retVal = function(*args, **kargs)
611 hadIgnoredErrors = errors.handleResult()
612 if isinstance(resultInfoDict, dict):
613 resultInfoDict[
"hadIgnoredErrors"] = hadIgnoredErrors
635 @UseStackFrameFromCallerForLogging
636 def ignoreWarning(function, args=(), kargs=
None, warningRegExp=
None, resultInfoDict=
None):
637 def ___doNotLog(_msg):
642 testHelper = TestHelper.getInstance()
643 logHandler = testHelper.getLogHandler()
645 assert not logHandler
is None
647 hadIgnoredWarnings =
False
648 warnings = SuppressedWarnings(warningRegExp, logErrorFunc=
None)
650 retVal = function(*args, **kargs)
652 hadIgnoredWarnings = warnings.handleResult()
653 if isinstance(resultInfoDict, dict):
654 resultInfoDict[
"hadIgnoredWarnings"] = hadIgnoredWarnings
676 @UseStackFrameFromCallerForLogging
678 testHelper = TestHelper.getInstance()
679 logHandler = testHelper.getLogHandler()
680 assert not logHandler
is None
685 retVal = function(*args, **kargs)
687 hadIgnoredErrors = errors.handleResult()
688 hadIgnoredWarnings = warnings.handleResult()
689 if isinstance(resultInfoDict, dict):
690 resultInfoDict[
"hadIgnoredWarnings"] = hadIgnoredWarnings
691 resultInfoDict[
"hadIgnoredErrors"] = hadIgnoredErrors
709 @UseStackFrameFromCallerForLogging
710 def expectInfo(function, args=[], kargs={}, infoRegExp=None, allowUnexpectedMessages=True):
711 testHelper = TestHelper.getInstance()
712 logHandler = testHelper.getLogHandler()
713 assert not logHandler
is None
715 expectInfos =
ExpectInfos(infoRegExp, allowUnexpectedMessages, Logging_error)
717 retVal = function(*args, **kargs)
719 expectInfos.handleResult()
731 @UseStackFrameFromCallerForLogging
733 """Expect that the expression in the context block issues no warning that matches `warningRegExp`.
734 If `warningRegExp` is not given, no warning is expected at all.
744 warnings.handleResult()
748 @UseStackFrameFromCallerForLogging
750 """Expect that the expression in the context block logs a warning that matches `warningRegExp`.
751 If `warningRegExp` is not given, any warning is expected.
761 warnings.handleResult()
765 @UseStackFrameFromCallerForLogging
767 """Expect that the expression in the context logs an error that matches `errorRegExp`.
768 If `errorRegExp` is not given, any error is expected.
778 errors.handleResult()
782 @UseStackFrameFromCallerForLogging
784 """Expect that the expression in the context logs errors and warnings.
785 See `hasError` and `hasWarning` for the arguments.
788 with hasWarningAndError():
796 errors.handleResult()
797 warnings.handleResult()
801 @UseStackFrameFromCallerForLogging
802 def hasInfo(infoRegExp=None, allowUnexpectedMessages=True):
803 """Expect that the expression in the context logs an info entry that matches `infoRegExp`.
804 If `infoRegExp` is not given, any info message is expected.
805 If `allowUnexpectedMessages` is set to True (the default), messages that do not match `infoRegExp` are ignored,
806 otherwise they are considered a failure.
809 with hasInfo(infoRegExp=".*Unknown module.*"):
812 expectInfos =
ExpectInfos(infoRegExp, allowUnexpectedMessages, Logging_error)
816 expectInfos.handleResult()
828 return TestHelper.getInstance().getTestCaseResultDirectory()
842 return TestHelper.getInstance().getTestCaseDataDirectory()
879 testHelper = TestHelper.getInstance()
880 testCaseContext = testHelper.getTestCaseContext()
881 externalDataVariable =
"TESTCENTER_EXTERNAL_DATA_%s" % name
882 externalDataPlaceholder =
"$(%s)" % externalDataVariable
883 externalDataBaseDirectory = testCaseContext.expandFilename(externalDataPlaceholder)
884 if externalDataBaseDirectory == externalDataPlaceholder:
886 "Variable %s could not be expanded. Please define it in your .prefs file." % externalDataVariable
888 if os.path.isdir(externalDataBaseDirectory):
890 return os.path.join(externalDataBaseDirectory, subDirectory)
892 testCasePath = testCaseContext.localPath()
893 path = mevis.MLABPackageManager.findPackageIdentifierAndRelativePath(testCasePath)[1]
894 return os.path.join(externalDataBaseDirectory, path)
895 raise ValueError(
'"%s" is not a directory.' % externalDataBaseDirectory)
916 if TestHelper.getInstance().getChangeSetStackLength() > 2:
934 def getHash(filename, hash="SHA1", encoder="Hex"):
937 b, ext = os.path.splitext(filename)
952 result = Image_calculateHashFromImage(filename, hash, encoder)
955 h = hashlib.new(hash)
956 with open(filename,
"rb")
as f:
959 result = h.hexdigest()
960 elif encoder ==
"Base64":
963 Logging_error(
"Unknown encoder (%s) selected." % (encoder))
964 except Exception
as e:
965 Logging_error(
"Failed to generate hash: %s." % e)
990 showTestFunctionSortingLiterals=False,
993 testCaseName, package, author, duration, maintainer, file, line, comment, showTestFunctionSortingLiterals
1037 def wrapper(*args, **kwds):
1041 result = func(*args, **kwds)
1053 def wrapper(*args, **kwds):
1054 wereHighPrecisionTimeStampsEnabled = mevis.MLAB.setHighPrecisionLoggingTimeStampsEnabled(
True)
1056 result = func(*args, **kwds)
1058 mevis.MLAB.setHighPrecisionLoggingTimeStampsEnabled(wereHighPrecisionTimeStampsEnabled)
1067 table.diff {font-family:monospace;border:medium;margin:0;}
1068 .diff_header {background-color:#e0e0e0}
1069 td.diff_header {text-align:right}
1070 .diff_next {background-color:#c0c0c0}
1071 .diff_add {background-color:#aaffaa}
1072 .diff_chg {background-color:#ffff77}
1073 .diff_sub {background-color:#ffaaaa}
1074 tr, td, th {vertical-align:top;}
1076 white-space: -pre-wrap;
1077 white-space: -o-pre-wrap;
1078 white-space: -moz-pre-wrap;
1079 white-space: pre-wrap;
1080 word-wrap: break-word;
1083 _table_template =
"""
1084 <table class="diff" id="difflib_chg_%(prefix)s_top"
1085 cellspacing="0" cellpadding="1" rules="groups" width="100%%">
1086 <colgroup></colgroup> <colgroup></colgroup> <colgroup width="50%%"></colgroup>
1087 <colgroup></colgroup> <colgroup></colgroup> <colgroup width="50%%"></colgroup>
1090 %(data_rows)s </tbody>
1094 difflib.HtmlDiff.__init__(self)
1096 def _format_line(self, side, flag, linenum, text):
1098 linenum =
"%d" % linenum
1099 id =
' id="%s%s"' % (self._prefix[side], linenum)
1104 text = text.replace(
"&",
"&").replace(
">",
">").replace(
"<",
"<")
1105 if len(text) == 0
or text ==
"\n":
1106 text =
'<span style="display: block; background-color:#e0e0e0;">' + text +
"</span>"
1107 return '<td class="diff_header"%s>%s</td><td>%s</td>' % (id, linenum, text)
1120 def createHtmlDiff(fromLines, toLines, showOnlyContextOfDiff=False, numberOfContextLines=10):
1121 diff =
HtmlDiff().make_file(fromLines, toLines,
"",
"", showOnlyContextOfDiff, numberOfContextLines)
1130 def MLABTC__disableTestFunctionIf_Decorator(func):
1131 disableTestFunction = condition()
if isinstance(condition, collections.abc.Callable)
else condition
1132 if disableTestFunction:
1133 module = sys.modules[func.__module__]
1134 if not hasattr(module,
"MLABTC_DISABLED_TEST_FUNCTIONS"):
1135 setattr(module,
"MLABTC_DISABLED_TEST_FUNCTIONS", [])
1136 module.MLABTC_DISABLED_TEST_FUNCTIONS.append(func.__name__)
1139 return MLABTC__disableTestFunctionIf_Decorator
1144 context = TestHelper.getInstance().getHelperContext()
1145 return context.field(
"oSSOffscreenRender.supported").value
1161 def runProcess(command, wait=True, expectSuccess=True, expectFailure=False, verbose=True, env=None):
1162 Macros_INFO(
"Running: " +
" ".join(command))
1166 p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
1168 p = subprocess.Popen(command, env=env)
1172 if len(os.path.splitext(c)[1]) > 0:
1173 c = os.path.basename(c)
1174 shortCommand.append(c)
1175 shortCommand =
" ".join(shortCommand)
1176 stdout, stderr = p.communicate()
1177 stdout = stdout.strip()
1178 stderr = stderr.strip()
1179 stderr = stderr.decode(
"utf-8",
"replace")
1180 stdout = stdout.decode(
"utf-8",
"replace")
1182 " ".join(command), shortCommand, p.returncode, stdout, stderr, expectSuccess, expectFailure, verbose
1184 return stdout, stderr, p.returncode
1201 command, shortCommand, returncode, stdout, stderr, expectSuccess=True, expectFailure=False, verbose=True
1205 Macros_ERROR(
"Command returned non-zero: '" + command +
"', return code: " + str(returncode))
1207 Macros_ERROR(stderr)
1209 Macros_ERROR(stdout)
1211 msg =
"Success: " + shortCommand
1214 msg +=
"\n\n" + stderr
1216 msg +=
"\n\n" + stdout
1220 Macros_ERROR(
"Command returned zero: '" + command +
"'")
1222 Macros_ERROR(stderr)
1224 Macros_ERROR(stdout)
1226 msg =
"Expected failure: " + shortCommand
1229 msg +=
"\n\n" + stderr
1231 msg +=
"\n\n" + stdout
1247 def runPythonScript(script, arguments, wait=True, expectSuccess=True, expectFailure=False, verbose=True, env=None):
1248 python = mevis.MLABFileManager.getExecutable(
"MeVisPython")
1249 command = [python,
"-u", script]
1250 command.extend(arguments)
1252 command, wait=wait, expectSuccess=expectSuccess, expectFailure=expectFailure, verbose=verbose, env=env
1256 from .ExtraTestCaseResult
import ExtraTestCaseResult
1257 from .Image
import calculateHashFromImage
as Image_calculateHashFromImage
1258 from .Logging
import error
as Logging_error, warning
as Logging_warning, info
as Logging_info
1259 from .Macros
import ERROR
as Macros_ERROR, INFO
as Macros_INFO
1261 compareFloatEqual
as Math_compareFloatEqual,
1262 compareFloatLessThan
as Math_compareFloatLessThan,
1263 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 compareFloatGreaterThan(a, b, comment="", logOnSuccess=None)
Compare the two given float values if the first is greater 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 compareGreaterThan(a, b, comment="", logOnSuccess=None)
Compare the two given values if the first one is greater than the second.
def ignoreError(function, args=(), kargs=None, errorRegExp=None, resultInfoDict=None)
Call the given function with the given parameters and ignores potential errors.
def compareGreaterThanOrEqual(a, b, comment="", logOnSuccess=None)
Compare the two given values if the first one is greater than or equal to the second.
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.
def compareFloatGreaterThanOrEqual(a, b, comment="", epsilon=0.0001, logOnSuccess=None)
Compare the two given float values if the first is greater than or equal to the second.