<commit_before>package org.jbehave.scenario.parser;

import static java.util.regex.Pattern.DOTALL;
import static java.util.regex.Pattern.compile;
import static org.jbehave.scenario.definition.Blurb.EMPTY;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jbehave.scenario.Configuration;
import org.jbehave.scenario.PropertyBasedConfiguration;
import org.jbehave.scenario.definition.Blurb;
import org.jbehave.scenario.definition.KeyWords;
import org.jbehave.scenario.definition.ScenarioDefinition;
import org.jbehave.scenario.definition.StoryDefinition;

/**
 * Pattern-based scenario parser, which uses the configured keywords to find the
 * steps in the text scenarios.
 */
public class PatternScenarioParser implements ScenarioParser {

	private final Configuration configuration;

	public PatternScenarioParser() {
		this(new PropertyBasedConfiguration());
	}

	public PatternScenarioParser(Configuration configuration) {
		this.configuration = configuration;
	}

	public StoryDefinition defineStoryFrom(String wholeStoryAsString) {
		Blurb blurb = parseBlurbFrom(wholeStoryAsString);
		List<ScenarioDefinition> scenarioDefinitions = parseScenariosFrom(wholeStoryAsString);
		return new StoryDefinition(blurb, scenarioDefinitions);
	}

	private List<ScenarioDefinition> parseScenariosFrom(
			String wholeStoryAsString) {
		List<ScenarioDefinition> scenarioDefinitions = new ArrayList<ScenarioDefinition>();
		List<String> scenarios = splitScenarios(wholeStoryAsString);
		for (String scenario : scenarios) {
			Matcher findingTitle = patternToPullScenarioTitlesIntoGroupOne()
					.matcher(scenario);
			scenarioDefinitions.add(new ScenarioDefinition(
					findingTitle.find() ? findingTitle.group(1).trim() : "",
					findSteps(scenario)));
		}
		return scenarioDefinitions;
	}

	private List<String> findSteps(String scenarioAsString) {
		Matcher matcher = patternToPullOutSteps().matcher(scenarioAsString);
		List<String> steps = new ArrayList<String>();
		int startAt = 0;
		while (matcher.find(startAt)) {
			steps.add(matcher.group(1));
			startAt = matcher.start(4);
		}

		return steps;
	}

	private Blurb parseBlurbFrom(String wholeStoryAsString) {
		String scenario = configuration.keywords().scenario();
		Pattern findStoryBlurb = compile("(.*?)(" + scenario + ").*", DOTALL);
		Matcher matcher = findStoryBlurb.matcher(wholeStoryAsString);
		if (matcher.find()) {
			return new Blurb(matcher.group(1).trim());
		} else {
			return EMPTY;
		}
	}

	private List<String> splitScenarios(String allScenariosInFile) {
		Pattern scenarioSplitter = patternToPullScenariosIntoGroupFour();
		Matcher matcher = scenarioSplitter.matcher(allScenariosInFile);
		int startAt = 0;
		List<String> scenarios = new ArrayList<String>();
		if (matcher.matches()) {
			while (matcher.find(startAt)) {
				scenarios.add(matcher.group(1));
				startAt = matcher.start(4);
			}
		} else {
			String loneScenario = allScenariosInFile;
			scenarios.add(loneScenario);
		}
		return scenarios;
	}<commit_msg>try to wrap regex exception, as the user will be clueless as to what to do next without it<commit_after>package org.jbehave.scenario.parser;

import static java.util.regex.Pattern.DOTALL;
import static java.util.regex.Pattern.compile;
import static org.jbehave.scenario.definition.Blurb.EMPTY;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jbehave.scenario.Configuration;
import org.jbehave.scenario.PropertyBasedConfiguration;
import org.jbehave.scenario.definition.Blurb;
import org.jbehave.scenario.definition.KeyWords;
import org.jbehave.scenario.definition.ScenarioDefinition;
import org.jbehave.scenario.definition.StoryDefinition;

/**
 * Pattern-based scenario parser, which uses the configured keywords to find the
 * steps in the text scenarios.
 */
public class PatternScenarioParser implements ScenarioParser {

	private final Configuration configuration;

	public PatternScenarioParser() {
		this(new PropertyBasedConfiguration());
	}

	public PatternScenarioParser(Configuration configuration) {
		this.configuration = configuration;
	}

	public StoryDefinition defineStoryFrom(String wholeStoryAsString) {
		Blurb blurb = parseBlurbFrom(wholeStoryAsString);
		List<ScenarioDefinition> scenarioDefinitions = parseScenariosFrom(wholeStoryAsString);
		return new StoryDefinition(blurb, scenarioDefinitions);
	}

	private List<ScenarioDefinition> parseScenariosFrom(
			String wholeStoryAsString) {
		List<ScenarioDefinition> scenarioDefinitions = new ArrayList<ScenarioDefinition>();
		List<String> scenarios = splitScenarios(wholeStoryAsString);
		for (String scenario : scenarios) {
			Matcher findingTitle = patternToPullScenarioTitlesIntoGroupOne()
					.matcher(scenario);
			scenarioDefinitions.add(new ScenarioDefinition(
					findingTitle.find() ? findingTitle.group(1).trim() : "",
					findSteps(scenario)));
		}
		return scenarioDefinitions;
	}

	private List<String> findSteps(String scenarioAsString) {
		Matcher matcher = patternToPullOutSteps().matcher(scenarioAsString);
		List<String> steps = new ArrayList<String>();
		int startAt = 0;
		while (matcher.find(startAt)) {
			steps.add(matcher.group(1));
			startAt = matcher.start(4);
		}

		return steps;
	}

	private Blurb parseBlurbFrom(String wholeStoryAsString) {
		String scenario = configuration.keywords().scenario();
		Pattern findStoryBlurb = compile("(.*?)(" + scenario + ").*", DOTALL);
		Matcher matcher = findStoryBlurb.matcher(wholeStoryAsString);
		if (matcher.find()) {
			return new Blurb(matcher.group(1).trim());
		} else {
			return EMPTY;
		}
	}

    @SuppressWarnings("serial")
	public static class InvalidPatternException extends RuntimeException {
		public InvalidPatternException(String message, Throwable cause) {
			super(message, cause);
		}

	}

    private List<String> splitScenarios(String allScenariosInFile) {
		Pattern scenarioSplitter = patternToPullScenariosIntoGroupFour();
		Matcher matcher = scenarioSplitter.matcher(allScenariosInFile);
		int startAt = 0;
		List<String> scenarios = new ArrayList<String>();
        try {
            if (matcher.matches()) {
                while (matcher.find(startAt)) {
                    scenarios.add(matcher.group(1));
                    startAt = matcher.start(4);
                }
            } else {
                String loneScenario = allScenariosInFile;
                scenarios.add(loneScenario);
            }
        } catch (StackOverflowError e) {
            // TODO - wish we had the scenario file name here.
            throw new InvalidPatternException("Regex failure for scenario.  See http://jbehave.org/documentation/regex-stack-overflow-errors", e);  
        }
        return scenarios;
	}
{'fraction_non_alphanumeric': 0.10146412884333822, 'fraction_numerical': 0.002342606149341142, 'mean_word_length': 4.716317991631799, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '144362', 'n_tokens_mistral': 2170, 'n_tokens_neox': 1963, 'n_words': 416}