testsuite.py

Mon, 22 Jan 2018 17:46:48 +0200

author
Santeri Piippo
date
Mon, 22 Jan 2018 17:46:48 +0200
changeset 19
9169bad392c4
parent 18
672ebc45685a
child 29
db6ca177c6c4
permissions
-rw-r--r--

better handling of ldraw code

from warnings import warn

def report_element(bad_object, type, error_name, args):
    return {
        'type': type,
        'object': bad_object,
        'name': error_name,
        'args': args,
    }

def warning(bad_object, error_name, **args):
    return report_element(bad_object, 'warning', error_name, args)

def error(bad_object, error_name, **args):
    return report_element(bad_object, 'error', error_name, args)

def test_discovery():
    '''
        Finds all test modules and yields their names.
    '''
    from pkgutil import walk_packages
    import tests
    yield from sorted(
        'tests.' + result.name
        for result in walk_packages(tests.__path__)
    )

def do_manifest_integrity_checks(test_suite, module):
    '''
        Runs integrity checks on a given module's manifest.
    '''
    def check_for_extra_keys():
        extra_keys = module.manifest.keys() - test_suite.keys()
        if extra_keys:
            warn(str.format(
                '{}: extra keys in manifest: {}',
                module.__name__,
                ', '.join(map(str, extra_keys))
            ))
    def check_for_manifest_duplicates():
        for key in test_suite.keys():
            duplicates = module.manifest[key].keys() & test_suite[key].keys()
            if duplicates:
                warn(str.format(
                    '{}: redefined {} in manifests: {}',
                    module.__name__,
                    key,
                    duplicates,
                ))
    check_for_extra_keys()
    check_for_manifest_duplicates()

def load_tests():
    '''
        Imports test modules and combines their manifests into a test suite.
    '''
    test_suite = {'tests': {}, 'messages': {}}
    for module_name in test_discovery():
        from importlib import import_module
        module = import_module(module_name)
        if hasattr(module, 'manifest'):
            do_manifest_integrity_checks(test_suite, module)
            # Merge the data from the manifest
            for key in module.manifest.keys() & test_suite.keys():
                test_suite[key].update(module.manifest[key])
        else:
            warn(str.format('Module {} does not have a manifest', module_name))
    return test_suite

def check_model(model, test_suite = None):
    if not test_suite:
        test_suite = load_tests()
    report = []
    line_numbers = {
        element: (i, i + 1 + model.body_offset)
        for i, element in enumerate(model.body)
    }
    for test_name, test_function in test_suite['tests'].items():
        problems = test_function(model)
        for problem in problems:
            problem['body-index'], problem['line-number'] \
                = line_numbers[problem['object']]
            del problem['object']
            report.append(problem)
    return report

def format_report(report, model, test_suite):
    import colorama
    colorama.init()
    result = []
    for problem in report:
        problem_text = test_suite['messages'][problem['name']]
        if callable(problem_text):
            problem_text = problem_text(**problem['args'])
        if problem['type'] == 'error':
            text_colour = colorama.Fore.LIGHTRED_EX
        elif problem['type'] == 'warning':
            text_colour = colorama.Fore.LIGHTYELLOW_EX
        else:
            text_colour = ''
        ldraw_code = model.body[problem['body-index']].textual_representation()
        message = str.format(
            '{text_colour}{model_name}:{line_number}: {problem_type}: {message}'
            '{colour_reset}\n\t{ldraw_code}',
            text_colour = text_colour,
            model_name = model.name,
            line_number = problem['line-number'],
            problem_type = problem['type'],
            message = problem_text,
            colour_reset = colorama.Fore.RESET,
            ldraw_code = ldraw_code,
        )
        result.append((problem['line-number'], message))
    return '\n'.join(
        problem[1]
        for problem in sorted(result)
    )

if __name__ == '__main__':
    from pprint import pprint
    pprint(load_tests())

mercurial