package cucumber.runtime;
import cucumber.runtime.io.Resource;
import cucumber.runtime.model.CucumberFeature;
import gherkin.I18n;
import gherkin.formatter.FilterFormatter;
import gherkin.formatter.Formatter;
import gherkin.formatter.model.Background;
import gherkin.formatter.model.Examples;
import gherkin.formatter.model.Feature;
import gherkin.formatter.model.Scenario;
import gherkin.formatter.model.ScenarioOutline;
import gherkin.formatter.model.Step;
import gherkin.lexer.Encoding;
import gherkin.parser.Parser;
import gherkin.util.FixJava;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FeatureBuilder implements Formatter {
private static final Charset UTF8 = Charset.forName("UTF-8");
private final List<CucumberFeature> cucumberFeatures;
private final char fileSeparatorChar;
private final MessageDigest md5;
private final Map<String, String> pathsByChecksum = new HashMap<String, String>();
private CucumberFeature currentCucumberFeature;
private String featurePath;
public FeatureBuilder(List<CucumberFeature> cucumberFeatures) {
this(cucumberFeatures, File.separatorChar);
}
FeatureBuilder(List<CucumberFeature> cucumberFeatures, char fileSeparatorChar) {
this.cucumberFeatures = cucumberFeatures;
this.fileSeparatorChar = fileSeparatorChar;
try {
this.md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new CucumberException(e);
}
}
@Override
public void uri(String uri) {
this.featurePath = uri;
}
@Override
public void feature(Feature feature) {
currentCucumberFeature = new CucumberFeature(feature, featurePath);
cucumberFeatures.add(currentCucumberFeature);
}
@Override
public void background(Background background) {
currentCucumberFeature.background(background);
}
@Override
public void scenario(Scenario scenario) {
currentCucumberFeature.scenario(scenario);
}
@Override
public void scenarioOutline(ScenarioOutline scenarioOutline) {
currentCucumberFeature.scenarioOutline(scenarioOutline);
}
@Override
public void examples(Examples examples) {
currentCucumberFeature.examples(examples);
}
@Override
public void step(Step step) {
currentCucumberFeature.step(step);
}
@Override
public void eof() {
}
@Override
public void syntaxError(String state, String event, List<String> legalEvents, String uri, Integer line) {
}
@Override
public void done() {
}
@Override
public void close() {
}
@Override
public void startOfScenarioLifeCycle(Scenario scenario) {
// NoOp
}
@Override
public void endOfScenarioLifeCycle(Scenario scenario) {
// NoOp
}
public void parse(Resource resource, List<Object> filters) {
String gherkin = read(resource);
String checksum = checksum(gherkin);
String path = pathsByChecksum.get(checksum);
if (path != null) {
return;
}
pathsByChecksum.put(checksum, resource.getPath());
Formatter formatter = this;
if (!filters.isEmpty()) {
formatter = new FilterFormatter(this, filters);
}
Parser parser = new Parser(formatter);
try {
parser.parse(gherkin, convertFileSeparatorToForwardSlash(resource.getPath()), 0);
} catch (Exception e) {
throw new CucumberException(String.format("Error parsing feature file %s", convertFileSeparatorToForwardSlash(resource.getPath())), e);
}
I18n i18n = parser.getI18nLanguage();
if (currentCucumberFeature != null) {
// The current feature may be null if we used a very restrictive filter, say a tag that isn't used.
// Might also happen if the feature file itself is empty.
currentCucumberFeature.setI18n(i18n);
}
}
private String convertFileSeparatorToForwardSlash(String path) {
return path.replace(fileSeparatorChar, '/');
}
private String checksum(String gherkin) {
return new BigInteger(1, md5.digest(gherkin.getBytes(UTF8))).toString(16);
}
public String read(Resource resource) {
try {
String source = FixJava.readReader(new InputStreamReader(resource.getInputStream(), "UTF-8"));
String encoding = new Encoding().encoding(source);
if (!"UTF-8".equals(encoding)) {
source = FixJava.readReader(new InputStreamReader(resource.getInputStream(), encoding));
}
return source;
} catch (IOException e) {
throw new CucumberException("Failed to read resource:" + resource.getPath(), e);
}
}
}