LSSTApplications  11.0-24-g0a022a1,12.1-4-g110c6f4+31,15.0+15,15.0+9,15.0-1-g19261fa+7,15.0-1-g60afb23+15,15.0-1-g615e0bb+7,15.0-1-g6668b0b+5,15.0-1-g788a293+15,15.0-1-ga91101e+15,15.0-1-gae1598d+8,15.0-1-gd076f1f+14,15.0-1-gdf18595+2,15.0-1-gf4f1c34+8,15.0-2-g100d730+8,15.0-2-g18f3f21+9,15.0-2-g20c4630+3,15.0-2-g35685a8+10,15.0-2-g5dfaa72+3,15.0-2-gf38729e+9,15.0-23-g309a1dfe0+1,15.0-3-g150fc43+18,15.0-3-g6f085af+8,15.0-3-g707930d,15.0-3-g9103c06+8,15.0-3-ga03b4ca+21,15.0-3-gaec6799+5,15.0-4-g5589a47+1,15.0-4-g654b129+13,15.0-4-gff20472+18,15.0-5-g0db841d+2,15.0-5-g23e394c+2,15.0-6-g4cfb9db,15.0-6-g9a9df217+10,15.0-8-g0cd0e28,15.0-8-g11095dd+1,15.0-8-g306a5613+1
LSSTDataManagementBasePackage
tests.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 #
4 # Copyright 2008-2017 AURA/LSST.
5 #
6 # This product includes software developed by the
7 # LSST Project (http://www.lsst.org/).
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the LSST License Statement and
20 # the GNU General Public License along with this program. If not,
21 # see <https://www.lsstcorp.org/LegalNotices/>.
22 #
23 """Support code for running unit tests"""
24 from __future__ import print_function
25 from __future__ import division
26 from builtins import zip
27 from builtins import range
28 
29 import contextlib
30 import gc
31 import inspect
32 import os
33 import subprocess
34 import sys
35 import unittest
36 import warnings
37 import numpy
38 import functools
39 import tempfile
40 
41 __all__ = ["init", "run", "MemoryTestCase", "ExecutablesTestCase", "getTempFilePath",
42  "TestCase", "assertFloatsAlmostEqual", "assertFloatsNotEqual", "assertFloatsEqual"]
43 
44 # File descriptor leak test will be skipped if psutil can not be imported
45 try:
46  import psutil
47 except ImportError:
48  psutil = None
49 
50 try:
51  import lsst.daf.base as dafBase
52 except ImportError:
53  dafBase = None
54 
55 try:
56  type(memId0)
57 except NameError:
58  memId0 = 0 # ignore leaked blocks with IDs before memId0
59  nleakPrintMax = 20 # maximum number of leaked blocks to print
60 
61 # Initialize the list of open files to an empty set
62 open_files = set()
63 
64 
65 def _get_open_files():
66  """Return a set containing the list of open files."""
67  if psutil is None:
68  return set()
69  return set(p.path for p in psutil.Process().open_files())
70 
71 
72 def init():
73  """Initialize the memory tester"""
74  global memId0
75  global open_files
76  if dafBase:
77  memId0 = dafBase.Citizen.getNextMemId() # used by MemoryTestCase
78  # Reset the list of open files
79  open_files = _get_open_files()
80 
81 
82 def run(suite, exit=True):
83  """Exit with the status code resulting from running the provided test suite"""
84 
85  if unittest.TextTestRunner().run(suite).wasSuccessful():
86  status = 0
87  else:
88  status = 1
89 
90  if exit:
91  sys.exit(status)
92  else:
93  return status
94 
95 
96 def sort_tests(tests):
97  """Go through the supplied sequence of test suites and sort them to ensure that
98  MemoryTestCases are at the end of the test list. Returns a combined
99  TestSuite."""
100 
101  suite = unittest.TestSuite()
102  memtests = []
103  for test_suite in tests:
104  try:
105  # Just test the first test method in the suite for MemoryTestCase
106  # Use loop rather than next as it is possible for a test class
107  # to not have any test methods and the Python community prefers
108  # for loops over catching a StopIteration exception.
109  bases = None
110  for method in test_suite:
111  bases = inspect.getmro(method.__class__)
112  break
113  if bases is not None and MemoryTestCase in bases:
114  memtests.append(test_suite)
115  else:
116  suite.addTests(test_suite)
117  except TypeError:
118  if isinstance(test_suite, MemoryTestCase):
119  memtests.append(test_suite)
120  else:
121  suite.addTest(test_suite)
122  suite.addTests(memtests)
123  return suite
124 
125 
126 def suiteClassWrapper(tests):
127  return unittest.TestSuite(sort_tests(tests))
128 
129 
130 # Replace the suiteClass callable in the defaultTestLoader
131 # so that we can reorder the test ordering. This will have
132 # no effect if no memory test cases are found.
133 unittest.defaultTestLoader.suiteClass = suiteClassWrapper
134 
135 
136 class MemoryTestCase(unittest.TestCase):
137  """Check for memory leaks since memId0 was allocated"""
138 
139  def setUp(self):
140  pass
141 
142  @classmethod
143  def tearDownClass(cls):
144  """Reset the leak counter when the tests have been completed"""
145  init()
146 
147  def testLeaks(self):
148  """Check for memory leaks in the preceding tests"""
149  if dafBase:
150  gc.collect()
151  global memId0, nleakPrintMax
152  nleak = dafBase.Citizen.census(0, memId0)
153  if nleak != 0:
154  plural = "s" if nleak != 1 else ""
155  print("\n%d Object%s leaked:" % (nleak, plural))
156 
157  if nleak <= nleakPrintMax:
158  print(dafBase.Citizen.census(memId0))
159  else:
160  census = dafBase.Citizen.census()
161  print("...")
162  for i in range(nleakPrintMax - 1, -1, -1):
163  print(census[i].repr())
164 
165  self.fail("Leaked %d block%s" % (nleak, plural))
166 
168  if psutil is None:
169  self.skipTest("Unable to test file descriptor leaks. psutil unavailable.")
170  gc.collect()
171  global open_files
172  now_open = _get_open_files()
173 
174  # Some files are opened out of the control of the stack.
175  now_open = set(f for f in now_open if not f.endswith(".car") and
176  not f.startswith("/proc/") and
177  not f.endswith(".ttf") and
178  f != "/var/lib/sss/mc/passwd" and
179  not f.endswith("astropy.log"))
180 
181  diff = now_open.difference(open_files)
182  if diff:
183  for f in diff:
184  print("File open: %s" % f)
185  self.fail("Failed to close %d file%s" % (len(diff), "s" if len(diff) != 1 else ""))
186 
187 
188 class ExecutablesTestCase(unittest.TestCase):
189  """Test that executables can be run and return good status.
190 
191  The test methods are dynamically created. Callers
192  must subclass this class in their own test file and invoke
193  the create_executable_tests() class method to register the tests.
194  """
195  TESTS_DISCOVERED = -1
196 
197  @classmethod
198  def setUpClass(cls):
199  """Abort testing if automated test creation was enabled and
200  yet not tests were found."""
201 
202  if cls.TESTS_DISCOVERED == 0:
203  raise Exception("No executables discovered.")
204 
205  def testSanity(self):
206  """This test exists to ensure that there is at least one test to be
207  executed. This allows the test runner to trigger the class set up
208  machinery to test whether there are some executables to test."""
209  pass
210 
211  def assertExecutable(self, executable, root_dir=None, args=None, msg=None):
212  """Check an executable runs and returns good status.
213 
214  Prints output to standard out. On bad exit status the test
215  fails. If the executable can not be located the test is skipped.
216 
217  Parameters
218  ----------
219  executable : `str`
220  Path to an executable. root_dir is not used if this is an
221  absolute path.
222 
223  root_dir : `str`
224  Directory containing exe. Ignored if None.
225 
226  args : list or tuple
227  Arguments to be provided to the executable.
228 
229  msg : `str`
230  Message to use when the test fails. Can be None for default message.
231  """
232 
233  if root_dir is not None and not os.path.isabs(executable):
234  executable = os.path.join(root_dir, executable)
235 
236  # Form the argument list for subprocess
237  sp_args = [executable]
238  argstr = "no arguments"
239  if args is not None:
240  sp_args.extend(args)
241  argstr = 'arguments "' + " ".join(args) + '"'
242 
243  print("Running executable '{}' with {}...".format(executable, argstr))
244  if not os.path.exists(executable):
245  self.skipTest("Executable {} is unexpectedly missing".format(executable))
246  failmsg = None
247  try:
248  output = subprocess.check_output(sp_args)
249  except subprocess.CalledProcessError as e:
250  output = e.output
251  failmsg = "Bad exit status from '{}': {}".format(executable, e.returncode)
252  print(output.decode('utf-8'))
253  if failmsg:
254  if msg is None:
255  msg = failmsg
256  self.fail(msg)
257 
258  @classmethod
259  def _build_test_method(cls, executable, root_dir):
260  """Build a test method and attach to class.
261 
262  The method is built for the supplied excutable located
263  in the supplied root directory.
264 
265  cls._build_test_method(root_dir, executable)
266 
267  Parameters
268  ----------
269  cls : `object`
270  The class in which to create the tests.
271 
272  executable : `str`
273  Name of executable. Can be absolute path.
274 
275  root_dir : `str`
276  Path to executable. Not used if executable path is absolute.
277  """
278  if not os.path.isabs(executable):
279  executable = os.path.abspath(os.path.join(root_dir, executable))
280 
281  # Create the test name from the executable path.
282  test_name = "test_exe_" + executable.replace("/", "_")
283 
284  # This is the function that will become the test method
285  def test_executable_runs(*args):
286  self = args[0]
287  self.assertExecutable(executable)
288 
289  # Give it a name and attach it to the class
290  test_executable_runs.__name__ = test_name
291  setattr(cls, test_name, test_executable_runs)
292 
293  @classmethod
294  def create_executable_tests(cls, ref_file, executables=None):
295  """Discover executables to test and create corresponding test methods.
296 
297  Scans the directory containing the supplied reference file
298  (usually __file__ supplied from the test class) to look for
299  executables. If executables are found a test method is created
300  for each one. That test method will run the executable and
301  check the returned value.
302 
303  Executable scripts with a .py extension and shared libraries
304  are ignored by the scanner.
305 
306  This class method must be called before test discovery.
307 
308  Example:
309 
310  cls.create_executable_tests(__file__)
311 
312  The list of executables can be overridden by passing in a
313  sequence of explicit executables that should be tested.
314  If an item in the sequence can not be found the
315  test will be configured to skip rather than fail.
316  """
317 
318  # Get the search directory from the reference file
319  ref_dir = os.path.abspath(os.path.dirname(ref_file))
320 
321  if executables is None:
322  # Look for executables to test by walking the tree
323  executables = []
324  for root, dirs, files in os.walk(ref_dir):
325  for f in files:
326  # Skip Python files. Shared libraries are executable.
327  if not f.endswith(".py") and not f.endswith(".so"):
328  full_path = os.path.join(root, f)
329  if os.access(full_path, os.X_OK):
330  executables.append(full_path)
331 
332  # Store the number of tests found for later assessment.
333  # Do not raise an exception if we have no executables as this would
334  # cause the testing to abort before the test runner could properly
335  # integrate it into the failure report.
336  cls.TESTS_DISCOVERED = len(executables)
337 
338  # Create the test functions and attach them to the class
339  for e in executables:
340  cls._build_test_method(e, ref_dir)
341 
342 
343 def findFileFromRoot(ifile):
344  """Find file which is specified as a path relative to the toplevel directory;
345  we start in $cwd and walk up until we find the file (or throw IOError if it doesn't exist)
346 
347  This is useful for running tests that may be run from _dir_/tests or _dir_"""
348 
349  if os.path.isfile(ifile):
350  return ifile
351 
352  ofile = None
353  file = ifile
354  while file != "":
355  dirname, basename = os.path.split(file)
356  if ofile:
357  ofile = os.path.join(basename, ofile)
358  else:
359  ofile = basename
360 
361  if os.path.isfile(ofile):
362  return ofile
363 
364  file = dirname
365 
366  raise IOError("Can't find %s" % ifile)
367 
368 
369 @contextlib.contextmanager
370 def getTempFilePath(ext, expectOutput=True):
371  """Return a path suitable for a temporary file and try to delete the file on success
372 
373  If the with block completes successfully then the file is deleted, if possible;
374  failure results in a printed warning.
375  If a file is remains when it should not, a RuntimeError exception is raised. This
376  exception is also raised if a file is not present on context manager exit when one
377  is expected to exist.
378  If the block exits with an exception the file if left on disk so it can be examined.
379  The file name has a random component such that nested context managers can be used
380  with the same file suffix.
381 
382  Parameters
383  ----------
384 
385  ext : `str` file name extension, e.g. ".fits"
386  expectOutput : `bool`
387  If true, a file should be created within the context manager.
388  If false, a file should not be present when the context manager exits.
389 
390  Returns
391  -------
392  `str`
393  Path for a temporary file. The path is a combination of the caller's
394  file path and the name of the top-level function
395 
396  Notes
397  -----
398  ::
399 
400  # file tests/testFoo.py
401  import unittest
402  import lsst.utils.tests
403  class FooTestCase(unittest.TestCase):
404  def testBasics(self):
405  self.runTest()
406 
407  def runTest(self):
408  with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
409  # if tests/.tests exists then tmpFile = "tests/.tests/testFoo_testBasics.fits"
410  # otherwise tmpFile = "testFoo_testBasics.fits"
411  ...
412  # at the end of this "with" block the path tmpFile will be deleted, but only if
413  # the file exists and the "with" block terminated normally (rather than with an exception)
414  ...
415  """
416  stack = inspect.stack()
417  # get name of first function in the file
418  for i in range(2, len(stack)):
419  frameInfo = inspect.getframeinfo(stack[i][0])
420  if i == 2:
421  callerFilePath = frameInfo.filename
422  callerFuncName = frameInfo.function
423  elif callerFilePath == frameInfo.filename:
424  # this function called the previous function
425  callerFuncName = frameInfo.function
426  else:
427  break
428 
429  callerDir, callerFileNameWithExt = os.path.split(callerFilePath)
430  callerFileName = os.path.splitext(callerFileNameWithExt)[0]
431  outDir = os.path.join(callerDir, ".tests")
432  if not os.path.isdir(outDir):
433  outDir = ""
434  prefix = "%s_%s-" % (callerFileName, callerFuncName)
435  outPath = tempfile.mktemp(dir=outDir, suffix=ext, prefix=prefix)
436  if os.path.exists(outPath):
437  # There should not be a file there given the randomizer. Warn and remove.
438  # Use stacklevel 3 so that the warning is reported from the end of the with block
439  warnings.warn("Unexpectedly found pre-existing tempfile named %r" % (outPath,),
440  stacklevel=3)
441  try:
442  os.remove(outPath)
443  except OSError:
444  pass
445 
446  yield outPath
447 
448  fileExists = os.path.exists(outPath)
449  if expectOutput:
450  if not fileExists:
451  raise RuntimeError("Temp file expected named {} but none found".format(outPath))
452  else:
453  if fileExists:
454  raise RuntimeError("Unexpectedly discovered temp file named {}".format(outPath))
455  # Try to clean up the file regardless
456  if fileExists:
457  try:
458  os.remove(outPath)
459  except OSError as e:
460  # Use stacklevel 3 so that the warning is reported from the end of the with block
461  warnings.warn("Warning: could not remove file %r: %s" % (outPath, e), stacklevel=3)
462 
463 
464 class TestCase(unittest.TestCase):
465  """Subclass of unittest.TestCase that adds some custom assertions for
466  convenience.
467  """
468 
469 
470 def inTestCase(func):
471  """A decorator to add a free function to our custom TestCase class, while also
472  making it available as a free function.
473  """
474  setattr(TestCase, func.__name__, func)
475  return func
476 
477 
478 @inTestCase
479 def assertRaisesLsstCpp(testcase, excClass, callableObj, *args, **kwargs):
480  """.. note:: Deprecated in 12_0"""
481  warnings.warn("assertRaisesLsstCpp is deprecated; please just use TestCase.assertRaises",
482  DeprecationWarning, stacklevel=2)
483  return testcase.assertRaises(excClass, callableObj, *args, **kwargs)
484 
485 
486 def debugger(*exceptions):
487  """Decorator to enter the debugger when there's an uncaught exception
488 
489  To use, just slap a "@debugger()" on your function.
490 
491  You may provide specific exception classes to catch as arguments to
492  the decorator function, e.g., "@debugger(RuntimeError, NotImplementedError)".
493  This defaults to just 'AssertionError', for use on unittest.TestCase methods.
494 
495  Code provided by "Rosh Oxymoron" on StackOverflow:
496  http://stackoverflow.com/questions/4398967/python-unit-testing-automatically-running-the-debugger-when-a-test-fails
497  """
498  if not exceptions:
499  exceptions = (AssertionError, )
500 
501  def decorator(f):
502  @functools.wraps(f)
503  def wrapper(*args, **kwargs):
504  try:
505  return f(*args, **kwargs)
506  except exceptions:
507  import sys
508  import pdb
509  pdb.post_mortem(sys.exc_info()[2])
510  return wrapper
511  return decorator
512 
513 
514 def plotImageDiff(lhs, rhs, bad=None, diff=None, plotFileName=None):
515  """Plot the comparison of two 2-d NumPy arrays.
516 
517  NOTE: this method uses matplotlib and imports it internally; it should be
518  wrapped in a try/except block within packages that do not depend on
519  matplotlib (including utils).
520 
521  Parameters
522  ----------
523  lhs : `numpy.ndarray`
524  LHS values to compare; a 2-d NumPy array
525  rhs : `numpy.ndarray`
526  RHS values to compare; a 2-d NumPy array
527  bad : `numpy.ndarray`
528  A 2-d boolean NumPy array of values to emphasize in the plots
529  diff : `numpy.ndarray`
530  difference array; a 2-d NumPy array, or None to show lhs-rhs
531  plotFileName : `str`
532  Filename to save the plot to. If None, the plot will be displayed in
533  a window.
534  """
535  from matplotlib import pyplot
536  if diff is None:
537  diff = lhs - rhs
538  pyplot.figure()
539  if bad is not None:
540  # make an rgba image that's red and transparent where not bad
541  badImage = numpy.zeros(bad.shape + (4,), dtype=numpy.uint8)
542  badImage[:, :, 0] = 255
543  badImage[:, :, 1] = 0
544  badImage[:, :, 2] = 0
545  badImage[:, :, 3] = 255*bad
546  vmin1 = numpy.minimum(numpy.min(lhs), numpy.min(rhs))
547  vmax1 = numpy.maximum(numpy.max(lhs), numpy.max(rhs))
548  vmin2 = numpy.min(diff)
549  vmax2 = numpy.max(diff)
550  for n, (image, title) in enumerate([(lhs, "lhs"), (rhs, "rhs"), (diff, "diff")]):
551  pyplot.subplot(2, 3, n + 1)
552  im1 = pyplot.imshow(image, cmap=pyplot.cm.gray, interpolation='nearest', origin='lower',
553  vmin=vmin1, vmax=vmax1)
554  if bad is not None:
555  pyplot.imshow(badImage, alpha=0.2, interpolation='nearest', origin='lower')
556  pyplot.axis("off")
557  pyplot.title(title)
558  pyplot.subplot(2, 3, n + 4)
559  im2 = pyplot.imshow(image, cmap=pyplot.cm.gray, interpolation='nearest', origin='lower',
560  vmin=vmin2, vmax=vmax2)
561  if bad is not None:
562  pyplot.imshow(badImage, alpha=0.2, interpolation='nearest', origin='lower')
563  pyplot.axis("off")
564  pyplot.title(title)
565  pyplot.subplots_adjust(left=0.05, bottom=0.05, top=0.92, right=0.75, wspace=0.05, hspace=0.05)
566  cax1 = pyplot.axes([0.8, 0.55, 0.05, 0.4])
567  pyplot.colorbar(im1, cax=cax1)
568  cax2 = pyplot.axes([0.8, 0.05, 0.05, 0.4])
569  pyplot.colorbar(im2, cax=cax2)
570  if plotFileName:
571  pyplot.savefig(plotFileName)
572  else:
573  pyplot.show()
574 
575 
576 @inTestCase
577 def assertFloatsAlmostEqual(testCase, lhs, rhs, rtol=sys.float_info.epsilon,
578  atol=sys.float_info.epsilon, relTo=None,
579  printFailures=True, plotOnFailure=False,
580  plotFileName=None, invert=False, msg=None):
581  """Highly-configurable floating point comparisons for scalars and arrays.
582 
583  The test assertion will fail if all elements lhs and rhs are not equal to within the tolerances
584  specified by rtol and atol. More precisely, the comparison is:
585 
586  ``abs(lhs - rhs) <= relTo*rtol OR abs(lhs - rhs) <= atol``
587 
588  If rtol or atol is None, that term in the comparison is not performed at all.
589 
590  When not specified, relTo is the elementwise maximum of the absolute values of lhs and rhs. If
591  set manually, it should usually be set to either lhs or rhs, or a scalar value typical of what
592  is expected.
593 
594  Parameters
595  ----------
596  testCase : `unittest.TestCase`
597  Instance the test is part of.
598  lhs : scalar or array-like
599  LHS value(s) to compare; may be a scalar or array-like of any dimension
600  rhs : scalar or array-like
601  RHS value(s) to compare; may be a scalar or array-like of any dimension
602  rtol : `float` or None
603  Relative tolerance for comparison; defaults to double-precision epsilon.
604  atol : `float` or None
605  Absolute tolerance for comparison; defaults to double-precision epsilon.
606  relTo : `float`
607  Value to which comparison with rtol is relative.
608  printFailures : `bool`
609  Upon failure, print all inequal elements as part of the message.
610  plotOnFailure : `bool`
611  Upon failure, plot the originals and their residual with matplotlib.
612  Only 2-d arrays are supported.
613  plotFileName : `str`
614  Filename to save the plot to. If None, the plot will be displayed in
615  a window.
616  invert : `bool`
617  If True, invert the comparison and fail only if any elements *are* equal.
618  Used to implement assertFloatsNotEqual, which should generally be used instead
619  for clarity.
620  msg : `str`
621  String to append to the error message when assert fails.
622  """
623  if not numpy.isfinite(lhs).all():
624  testCase.fail("Non-finite values in lhs")
625  if not numpy.isfinite(rhs).all():
626  testCase.fail("Non-finite values in rhs")
627  diff = lhs - rhs
628  absDiff = numpy.abs(lhs - rhs)
629  if rtol is not None:
630  if relTo is None:
631  relTo = numpy.maximum(numpy.abs(lhs), numpy.abs(rhs))
632  else:
633  relTo = numpy.abs(relTo)
634  bad = absDiff > rtol*relTo
635  if atol is not None:
636  bad = numpy.logical_and(bad, absDiff > atol)
637  else:
638  if atol is None:
639  raise ValueError("rtol and atol cannot both be None")
640  bad = absDiff > atol
641  failed = numpy.any(bad)
642  if invert:
643  failed = not failed
644  bad = numpy.logical_not(bad)
645  cmpStr = "=="
646  failStr = "are the same"
647  else:
648  cmpStr = "!="
649  failStr = "differ"
650  errMsg = []
651  if failed:
652  if numpy.isscalar(bad):
653  if rtol is None:
654  errMsg = ["%s %s %s; diff=%s with atol=%s"
655  % (lhs, cmpStr, rhs, absDiff, atol)]
656  elif atol is None:
657  errMsg = ["%s %s %s; diff=%s/%s=%s with rtol=%s"
658  % (lhs, cmpStr, rhs, absDiff, relTo, absDiff/relTo, rtol)]
659  else:
660  errMsg = ["%s %s %s; diff=%s/%s=%s with rtol=%s, atol=%s"
661  % (lhs, cmpStr, rhs, absDiff, relTo, absDiff/relTo, rtol, atol)]
662  else:
663  errMsg = ["%d/%d elements %s with rtol=%s, atol=%s"
664  % (bad.sum(), bad.size, failStr, rtol, atol)]
665  if plotOnFailure:
666  if len(lhs.shape) != 2 or len(rhs.shape) != 2:
667  raise ValueError("plotOnFailure is only valid for 2-d arrays")
668  try:
669  plotImageDiff(lhs, rhs, bad, diff=diff, plotFileName=plotFileName)
670  except ImportError:
671  errMsg.append("Failure plot requested but matplotlib could not be imported.")
672  if printFailures:
673  # Make sure everything is an array if any of them are, so we can treat
674  # them the same (diff and absDiff are arrays if either rhs or lhs is),
675  # and we don't get here if neither is.
676  if numpy.isscalar(relTo):
677  relTo = numpy.ones(bad.shape, dtype=float) * relTo
678  if numpy.isscalar(lhs):
679  lhs = numpy.ones(bad.shape, dtype=float) * lhs
680  if numpy.isscalar(rhs):
681  rhs = numpy.ones(bad.shape, dtype=float) * rhs
682  if rtol is None:
683  for a, b, diff in zip(lhs[bad], rhs[bad], absDiff[bad]):
684  errMsg.append("%s %s %s (diff=%s)" % (a, cmpStr, b, diff))
685  else:
686  for a, b, diff, rel in zip(lhs[bad], rhs[bad], absDiff[bad], relTo[bad]):
687  errMsg.append("%s %s %s (diff=%s/%s=%s)" % (a, cmpStr, b, diff, rel, diff/rel))
688 
689  if msg is not None:
690  errMsg.append(msg)
691  testCase.assertFalse(failed, msg="\n".join(errMsg))
692 
693 
694 @inTestCase
695 def assertFloatsNotEqual(testCase, lhs, rhs, **kwds):
696  """
697  Fail a test if the given floating point values are equal to within the given tolerances.
698 
699  See assertFloatsAlmostEqual (called with rtol=atol=0) for more information.
700  """
701  return assertFloatsAlmostEqual(testCase, lhs, rhs, invert=True, **kwds)
702 
703 
704 @inTestCase
705 def assertFloatsEqual(testCase, lhs, rhs, **kwargs):
706  """
707  Assert that lhs == rhs (both numeric types, whether scalar or array).
708 
709  See assertFloatsAlmostEqual (called with rtol=atol=0) for more information.
710  """
711  return assertFloatsAlmostEqual(testCase, lhs, rhs, rtol=0, atol=0, **kwargs)
712 
713 
714 @inTestCase
715 def assertClose(*args, **kwargs):
716  """.. note:: Deprecated in 12_0"""
717  warnings.warn("assertClose is deprecated; please use TestCase.assertFloatsAlmostEqual",
718  DeprecationWarning, stacklevel=2)
719  return assertFloatsAlmostEqual(*args, **kwargs)
720 
721 
722 @inTestCase
723 def assertNotClose(*args, **kwargs):
724  """.. note:: Deprecated in 12_0"""
725  warnings.warn("assertNotClose is deprecated; please use TestCase.assertFloatsNotEqual",
726  DeprecationWarning, stacklevel=2)
727  return assertFloatsNotEqual(*args, **kwargs)
def suiteClassWrapper(tests)
Definition: tests.py:126
bool all(CoordinateExpr< N > const &expr)
Return true if all elements are true.
def assertExecutable(self, executable, root_dir=None, args=None, msg=None)
Definition: tests.py:211
def assertFloatsEqual(testCase, lhs, rhs, kwargs)
Definition: tests.py:705
def init()
Definition: tests.py:72
def plotImageDiff(lhs, rhs, bad=None, diff=None, plotFileName=None)
Definition: tests.py:514
def inTestCase(func)
Definition: tests.py:470
def assertClose(args, kwargs)
Definition: tests.py:715
daf::base::PropertySet * set
Definition: fits.cc:818
def _build_test_method(cls, executable, root_dir)
Definition: tests.py:259
def assertFloatsAlmostEqual(testCase, lhs, rhs, rtol=sys.float_info.epsilon, atol=sys.float_info.epsilon, relTo=None, printFailures=True, plotOnFailure=False, plotFileName=None, invert=False, msg=None)
Definition: tests.py:580
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:134
def assertFloatsNotEqual(testCase, lhs, rhs, kwds)
Definition: tests.py:695
def run(suite, exit=True)
Definition: tests.py:82
def getTempFilePath(ext, expectOutput=True)
Definition: tests.py:370
def debugger(exceptions)
Definition: tests.py:486
def findFileFromRoot(ifile)
Definition: tests.py:343
def assertNotClose(args, kwargs)
Definition: tests.py:723
def create_executable_tests(cls, ref_file, executables=None)
Definition: tests.py:294
def assertRaisesLsstCpp(testcase, excClass, callableObj, args, kwargs)
Definition: tests.py:479
def sort_tests(tests)
Definition: tests.py:96