def many_from_lines(klass, lines, filename=None, original_string=None): """Parses a set of steps from lines of input. This will correctly parse and produce a list of steps from lines without any Scenario: heading at the top. Examples in table form are correctly parsed, but must be well-formed under a regular step sentence. """ invalid_first_line_error = '\nFirst line of step "%s" is in %s form.' if lines and strings.wise_startswith(lines[0], u'|'): raise LettuceSyntaxError( None, invalid_first_line_error % (lines[0], 'table')) if lines and strings.wise_startswith(lines[0], u'"""'): raise LettuceSyntaxError( None, invalid_first_line_error % (lines[0], 'multiline')) # Select only lines that aren't end-to-end whitespace only_whitspace = re.compile('^\s*$') lines = filter(lambda x: not only_whitspace.match(x), lines) step_strings = [] in_multiline = False for line in lines: if strings.wise_startswith(line, u'"""'): in_multiline = not in_multiline step_strings[-1] += "\n%s" % line elif strings.wise_startswith(line, u"|") or in_multiline: step_strings[-1] += "\n%s" % line else: step_strings.append(line) mkargs = lambda s: [s, filename, original_string] return [klass.from_string(*mkargs(s)) for s in step_strings]
def from_string(new_feature, string, with_file=None, language=None): """Creates a new feature from string""" lines = strings.get_stripped_lines(string, ignore_lines_starting_with='#') if not language: language = Language() found = len( re.findall(r'%s:[ ]*\w+' % language.feature, "\n".join(lines))) if found > 1: raise LettuceSyntaxError( with_file, 'A feature file must contain ONLY ONE feature!') elif found == 0: raise LettuceSyntaxError( with_file, 'Features must have a name. e.g: "Feature: This is my name"') while lines: matched = re.search(r'%s:(.*)' % language.feature, lines[0], re.I) if matched: name = matched.groups()[0].strip() break lines.pop(0) feature = new_feature(name=name, remaining_lines=lines, with_file=with_file, original_string=string, language=language) return feature
def _parse_remaining_lines(self, lines, with_file, original_string): invalid_first_line_error = '\nInvalid step on scenario "%s".\n' \ 'Maybe you killed the first step text of that scenario\n' if lines and strings.wise_startswith(lines[0], u'|'): raise LettuceSyntaxError(with_file, invalid_first_line_error % self.name) return Step.many_from_lines(lines, with_file, original_string)
def _check_scenario_syntax(self, lines, filename): empty_scenario = ('%s:' % (self.language.first_of_scenario)).lower() for line in lines: if line.lower() == empty_scenario: raise LettuceSyntaxError( filename, ('In the feature "%s", scenarios ' 'must have a name, make sure to declare a scenario like ' 'this: `Scenario: name of your scenario`' % self.name), )
def many_from_lines(klass, lines, filename=None, original_string=None): """Parses a set of steps from lines of input. This will correctly parse and produce a list of steps from lines without any Scenario: heading at the top. Examples in table form are correctly parsed, but must be well-formed under a regular step sentence. """ invalid_first_line_error = '\nFirst line of step "%s" is in %s form.' if lines and strings.wise_startswith(lines[0], '|'): raise LettuceSyntaxError( None, invalid_first_line_error % (lines[0], 'table')) if lines and strings.wise_startswith(lines[0], '"""'): raise LettuceSyntaxError( None, invalid_first_line_error % (lines[0], 'multiline')) # Select only lines that aren't end-to-end whitespace and aren't tags # Tags could be included as steps if the first scenario following a background is tagged # This then causes the test to fail, because lettuce looks for the step's definition (which doesn't exist) lines = [ x for x in lines if not (REP.only_whitespace.match(x) or re.match(r'^\s*@', x)) ] step_strings = [] in_multiline = False for line in lines: if strings.wise_startswith(line, '"""'): in_multiline = not in_multiline step_strings[-1] += "\n%s" % line elif strings.wise_startswith(line, "|") or in_multiline: step_strings[-1] += "\n%s" % line elif '#' in line: step_strings.append(klass._handle_inline_comments(line)) else: step_strings.append(line) mkargs = lambda s: [s, filename, original_string] return [klass.from_string(*mkargs(s)) for s in step_strings]
def _parse_remaining_lines(self, lines, original_string, with_file=None): joined = u"\n".join(lines[1:]) self._check_scenario_syntax(lines, filename=with_file) # replacing occurrences of Scenario Outline, with just "Scenario" scenario_prefix = u'%s:' % self.language.first_of_scenario regex = re.compile( ur"%s:[\t\r\f\v]*" % self.language.scenario_separator, re.U | re.I | re.DOTALL) joined = regex.sub(scenario_prefix, joined) parts = strings.split_wisely(joined, scenario_prefix) description = u"" background = None tags_scenario = [] if not re.search("^" + scenario_prefix, joined): if not parts: raise LettuceSyntaxError(with_file, ( u"Features must have scenarios.\n" "Please refer to the documentation available at http://lettuce.it for more information." )) tags_scenario, description_and_background = self._extract_tags( parts[0]) description, background_lines = self._extract_desc_and_bg( description_and_background) background = background_lines and Background.from_string( background_lines, self, with_file=with_file, original_string=original_string, language=self.language, ) or None parts.pop(0) prefix = self.language.first_of_scenario upcoming_scenarios = [ u"%s: %s" % (prefix, s) for s in parts if s.strip() ] kw = dict( original_string=original_string, with_file=with_file, language=self.language, ) scenarios = [] while upcoming_scenarios: tags_next_scenario, current = self._extract_tags( upcoming_scenarios[0]) current = self._strip_next_scenario_tags(upcoming_scenarios.pop(0)) params = dict(tags=tags_scenario, ) params.update(kw) current_scenario = Scenario.from_string(current, **params) current_scenario.background = background scenarios.append(current_scenario) tags_scenario = tags_next_scenario return background, scenarios, description