# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- # vi: set ft=python sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the NiBabel package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## ''' Tests for BatteryRunner and Report objects ''' from ..externals.six import StringIO import logging from ..batteryrunners import BatteryRunner, Report from ..testing import (assert_true, assert_false, assert_equal, assert_not_equal, assert_raises) # define some trivial functions as checks def chk1(obj, fix=False): rep = Report(KeyError) if 'testkey' in obj: return obj, rep rep.problem_level = 20 rep.problem_msg = 'no "testkey"' if fix: obj['testkey'] = 1 rep.fix_msg = 'added "testkey"' return obj, rep def chk2(obj, fix=False): # Can return different codes for different errors in same check rep = Report() try: ok = obj['testkey'] == 0 except KeyError: rep.problem_level = 20 rep.problem_msg = 'no "testkey"' rep.error = KeyError if fix: obj['testkey'] = 1 rep.fix_msg = 'added "testkey"' return obj, rep if ok: return obj, rep rep.problem_level = 10 rep.problem_msg = '"testkey" != 0' rep.error = ValueError if fix: rep.fix_msg = 'set "testkey" to 0' obj['testkey'] = 0 return obj, rep def chk_warn(obj, fix=False): rep = Report(KeyError) if not 'anotherkey' in obj: rep.problem_level = 30 rep.problem_msg = 'no "anotherkey"' if fix: obj['anotherkey'] = 'a string' rep.fix_msg = 'added "anotherkey"' return obj, rep def chk_error(obj, fix=False): rep = Report(KeyError) if not 'thirdkey' in obj: rep.problem_level = 40 rep.problem_msg = 'no "thirdkey"' if fix: obj['anotherkey'] = 'a string' rep.fix_msg = 'added "anotherkey"' return obj, rep def test_init_basic(): # With no args, raise assert_raises(TypeError, BatteryRunner) # Len returns number of checks battrun = BatteryRunner((chk1,)) assert_equal(len(battrun), 1) battrun = BatteryRunner((chk1,chk2)) assert_equal(len(battrun), 2) def test_init_report(): rep = Report() assert_equal(rep, Report(Exception, 0, '', '')) def test_report_strings(): rep = Report() assert_not_equal(rep.__str__(), '') assert_equal(rep.message, '') str_io = StringIO() rep.write_raise(str_io) assert_equal(str_io.getvalue(), '') rep = Report(ValueError, 20, 'msg', 'fix') rep.write_raise(str_io) assert_equal(str_io.getvalue(), '') rep.problem_level = 30 rep.write_raise(str_io) assert_equal(str_io.getvalue(), 'Level 30: msg; fix\n') str_io.truncate(0); str_io.seek(0) # No fix string, no fix message rep.fix_msg = '' rep.write_raise(str_io) assert_equal(str_io.getvalue(), 'Level 30: msg\n') rep.fix_msg = 'fix' str_io.truncate(0); str_io.seek(0) # If we drop the level, nothing goes to the log rep.problem_level = 20 rep.write_raise(str_io) assert_equal(str_io.getvalue(), '') # Unless we set the default log level in the call rep.write_raise(str_io, log_level=20) assert_equal(str_io.getvalue(), 'Level 20: msg; fix\n') str_io.truncate(0); str_io.seek(0) # If we set the error level down this low, we raise an error assert_raises(ValueError, rep.write_raise, str_io, 20) # But the log level wasn't low enough to do a log entry assert_equal(str_io.getvalue(), '') # Error still raised with lower log threshold, but now we do get a # log entry assert_raises(ValueError, rep.write_raise, str_io, 20, 20) assert_equal(str_io.getvalue(), 'Level 20: msg; fix\n') # If there's no error, we can't raise str_io.truncate(0); str_io.seek(0) rep.error = None rep.write_raise(str_io, 20) assert_equal(str_io.getvalue(), '') def test_logging(): rep = Report(ValueError, 20, 'msg', 'fix') str_io = StringIO() logger = logging.getLogger('test.logger') logger.setLevel(30) # defaultish level logger.addHandler(logging.StreamHandler(str_io)) rep.log_raise(logger) assert_equal(str_io.getvalue(), '') rep.problem_level = 30 rep.log_raise(logger) assert_equal(str_io.getvalue(), 'msg; fix\n') str_io.truncate(0); str_io.seek(0) def test_checks(): battrun = BatteryRunner((chk1,)) reports = battrun.check_only({}) assert_equal(reports[0], Report(KeyError, 20, 'no "testkey"', '')) obj, reports = battrun.check_fix({}) assert_equal(reports[0], Report(KeyError, 20, 'no "testkey"', 'added "testkey"')) assert_equal(obj, {'testkey':1}) battrun = BatteryRunner((chk1,chk2)) reports = battrun.check_only({}) assert_equal(reports[0], Report(KeyError, 20, 'no "testkey"', '')) assert_equal(reports[1], Report(KeyError, 20, 'no "testkey"', '')) obj, reports = battrun.check_fix({}) # In the case of fix, the previous fix exposes a different error # Note, because obj is mutable, first and second point to modified # (and final) dictionary output_obj = {'testkey':0} assert_equal(reports[0], Report(KeyError, 20, 'no "testkey"', 'added "testkey"')) assert_equal(reports[1], Report(ValueError, 10, '"testkey" != 0', 'set "testkey" to 0')) assert_equal(obj, output_obj)