# Copyright (c) 2016, Matt Layman from tap.adapter import Adapter from tap.directive import Directive from tap.i18n import _ from tap.line import Result class Rules(object): def __init__(self, filename, suite): self._filename = filename self._suite = suite self._lines_seen = {'plan': [], 'test': 0, 'version': []} def check(self, final_line_count): """Check the status of all provided data and update the suite.""" if self._lines_seen['version']: self._process_version_lines() self._process_plan_lines(final_line_count) def _process_version_lines(self): """Process version line rules.""" if len(self._lines_seen['version']) > 1: self._add_error(_('Multiple version lines appeared.')) elif self._lines_seen['version'][0] != 1: self._add_error(_('The version must be on the first line.')) def _process_plan_lines(self, final_line_count): """Process plan line rules.""" if not self._lines_seen['plan']: self._add_error(_('Missing a plan.')) return if len(self._lines_seen['plan']) > 1: self._add_error(_('Only one plan line is permitted per file.')) return plan, at_line = self._lines_seen['plan'][0] if not self._plan_on_valid_line(at_line, final_line_count): self._add_error( _('A plan must appear at the beginning or end of the file.')) return if plan.expected_tests != self._lines_seen['test']: self._add_error(_( 'Expected {expected_count} tests ' 'but only {seen_count} ran.').format( expected_count=plan.expected_tests, seen_count=self._lines_seen['test'])) def _plan_on_valid_line(self, at_line, final_line_count): """Check if a plan is on a valid line.""" # Put the common cases first. if at_line == 1 or at_line == final_line_count: return True # The plan may only appear on line 2 if the version is at line 1. after_version = ( self._lines_seen['version'] and self._lines_seen['version'][0] == 1 and at_line == 2) if after_version: return True return False def handle_bail(self, bail): """Handle a bail line.""" self._add_error(_('Bailed: {reason}').format(reason=bail.reason)) def handle_file_does_not_exist(self): """Handle a test file that does not exist.""" self._add_error(_('{filename} does not exist.').format( filename=self._filename)) def handle_skipping_plan(self, skip_plan): """Handle a plan that contains a SKIP directive.""" skip_line = Result( True, None, skip_plan.directive.text, Directive('SKIP')) self._suite.addTest(Adapter(self._filename, skip_line)) def saw_plan(self, plan, at_line): """Record when a plan line was seen.""" self._lines_seen['plan'].append((plan, at_line)) def saw_test(self): """Record when a test line was seen.""" self._lines_seen['test'] += 1 def saw_version_at(self, line_counter): """Record when a version line was seen.""" self._lines_seen['version'].append(line_counter) def _add_error(self, message): """Add an error test to the suite.""" error_line = Result(False, None, message, Directive('')) self._suite.addTest(Adapter(self._filename, error_line))