import os import re from ..check import Check from ..frontmatter import parse class CheckIncludes(Check): '''Ensure tests make use of the harness files that they require via the `includes` directive.''' ID = 'INCLUDES' _cache = dict() @staticmethod def _remove_frontmatter(source): return re.sub( r'/\*---.*---\*/', '', source, flags=re.DOTALL ) @staticmethod def _load(include_name): if include_name not in CheckIncludes._cache: with open(os.path.join('harness', include_name), 'r') as f: source = f.read() CheckIncludes._cache[include_name] = { 'name': include_name, 'source': CheckIncludes._remove_frontmatter(source), 'defines': parse(source)['defines'] } return CheckIncludes._cache.get(include_name) @staticmethod def _has_reference(source, names): for name in names: if name in source: return True return False def run(self, name, meta, source): if not meta or 'includes' not in meta: return harness_files = [self._load(name) for name in meta['includes']] if len(harness_files) == 0: return 'If present, the `includes` tag must have at least one member' without_frontmatter = self._remove_frontmatter(source) for harness_file in harness_files: if self._has_reference(without_frontmatter, harness_file['defines']): continue # If the test file does not reference a value defined by a given # include file, inspect each of the other include files for such a # reference. for other_harness_file in harness_files: if other_harness_file == harness_file: continue if self._has_reference(other_harness_file['source'], harness_file['defines']): break else: return 'Unused include: "%s"' % harness_file['name']