tests/misc.py

Tue, 25 Aug 2020 23:20:22 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Tue, 25 Aug 2020 23:20:22 +0300
changeset 105
43c367c8895b
parent 94
109fb7cf658f
child 145
fde18c4d6784
permissions
-rw-r--r--

split header tests into their own file

from testsuite import problem_type, report_problem
import linetypes

@problem_type('bad-colour',
    severity = 'hold',
    message = lambda colour_index, count: str.format(
        'invalid colour {} used {} time(s)',
        colour_index,
        count,
    ),
)
def colours_test(model):
    ''' Checks that all colours used in the part model are valid. '''
    from collections import defaultdict
    bad_colours = defaultdict(lambda: {'count': 0, 'first-occurrence': None})
    for element in model.body:
        if hasattr(element, 'colour') and not element.colour.is_valid:
            bad_colours[element.colour.index]['count'] += 1
            if not bad_colours[element.colour.index]['first-occurrence']:
                bad_colours[element.colour.index]['first-occurrence'] = element
    yield from [
        report_problem(
            'bad-colour',
            bad_object = bad_colour['first-occurrence'],
            colour_index = colour_index,
            count = bad_colour['count'],
        )
        for colour_index, bad_colour in bad_colours.items()
    ]

@problem_type('syntax-error',
    severity = 'hold',
    message = lambda reason: str.format('syntax error: {}', reason),
)
def syntax_errors(model):
    yield from (
        report_problem('syntax-error',
            bad_object = element,
            reason = element.reason
        )
        for element in model.body
        if isinstance(element, linetypes.Error)
    )

@problem_type('unknown-metacommand',
    severity = 'hold',
    message = lambda command_text: str.format(
        'unknown or deprecated metacommand: {command_text}',
        command_text = command_text,
    )
)
def metacommands_test(model):
    allowed_metacommand_patterns = [
        r'^BFC (CLIP|NOCLIP|INVERTNEXT)$',
        r'^\!TEXMAP (START|NEXT) .+',
        r'^\!: .+',
        r'^\!TEXMAP (FALLBACK|END)$',
    ]
    import re
    for element in model.body[model.header_size:]:
        if isinstance(element, linetypes.MetaCommand):
            if element.text and not any(
                re.match(pattern, element.text)
                for pattern in allowed_metacommand_patterns
            ):
                yield report_problem('unknown-metacommand',
                    bad_object = element,
                    command_text = element.text,
                )

@problem_type('bad-line-endings',
    severity = 'hold',
    message = lambda count: str.format(
        'file contains non-DOS line endings ({count} total)',
        count = count,
    ),
)
def line_endings_test(model):
    # Line endings are already checked during parse. This function
    # only serves to report them.
    if model.line_ending_errors != None:
        yield report_problem(
            'bad-line-endings',
            bad_object = model.body[model.line_ending_errors['first-at']],
            count = model.line_ending_errors['count'],
        )

@problem_type('bfc-invertnext-not-on-subfile',
    severity = 'hold',
    message = '"BFC INVERTNEXT" not followed by a type-1 line',
)
def bfc_invertnext_not_on_subfile_test(model):
    def get_invertnexts(model):
        yield from [
            (index, element)
            for index, element in enumerate(model.body)
            if isinstance(element, linetypes.MetaCommand) \
                and element.text == 'BFC INVERTNEXT'
        ]
    def has_subfile_after_invertnext(index):
        index_subfile = index + 1 # subfile reference should be on the next line
        if index_subfile >= len(model.body):
            return False # past the end...
        else:
            element = model.body[index_subfile]
            return isinstance(element, linetypes.SubfileReference)
    for index, invertnext in get_invertnexts(model):
        if not has_subfile_after_invertnext(index):
            yield report_problem('bfc-invertnext-not-on-subfile',
                bad_object = model.body[index],
            )

manifest = {
    'tests': [
        colours_test,
        syntax_errors,
        bfc_invertnext_not_on_subfile_test,
        metacommands_test,
        line_endings_test,
    ],
}

mercurial