Keywords.java
package org.jbehave.core.configuration;
import static java.util.Arrays.asList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.jbehave.core.steps.StepType;
/**
* Provides the keywords which allow parsers to find steps in stories and match
* those steps with candidates through the annotations. It provides the starting
* words (Given, When, Then And, "!--") using in parsing, as well as providing
* keywords used in reporting.
*/
@SuppressWarnings("checkstyle:MemberName")
public class Keywords {
private static final String SYNONYM_SEPARATOR = "\\|";
public static final String META = "Meta";
public static final String META_PROPERTY = "MetaProperty";
public static final String NARRATIVE = "Narrative";
public static final String IN_ORDER_TO = "InOrderTo";
public static final String AS_A = "AsA";
public static final String I_WANT_TO = "IWantTo";
public static final String SO_THAT = "SoThat";
public static final String SCENARIO = "Scenario";
public static final String GIVEN_STORIES = "GivenStories";
public static final String LIFECYCLE = "Lifecycle";
public static final String BEFORE = "Before";
public static final String AFTER = "After";
public static final String EXAMPLES_TABLE = "ExamplesTable";
public static final String EXAMPLES_TABLE_ROW = "ExamplesTableRow";
public static final String EXAMPLES_TABLE_HEADER_SEPARATOR = "ExamplesTableHeaderSeparator";
public static final String EXAMPLES_TABLE_VALUE_SEPARATOR = "ExamplesTableValueSeparator";
public static final String EXAMPLES_TABLE_IGNORABLE_SEPARATOR = "ExamplesTableIgnorableSeparator";
public static final String GIVEN = "Given";
public static final String WHEN = "When";
public static final String THEN = "Then";
public static final String AND = "And";
public static final String IGNORABLE = "Ignorable";
public static final String COMPOSITE = "Composite";
public static final String PRIORITY = "Priority";
public static final String PENDING = "Pending";
public static final String NOT_PERFORMED = "NotPerformed";
public static final String FAILED = "Failed";
public static final String DRY_RUN = "DryRun";
public static final String STORY_CANCELLED = "StoryCancelled";
public static final String DURATION = "Duration";
public static final String SCOPE = "Scope";
public static final String SCOPE_STEP = "ScopeStep";
public static final String SCOPE_SCENARIO = "ScopeScenario";
public static final String SCOPE_STORY = "ScopeStory";
public static final String OUTCOME = "Outcome";
public static final String OUTCOME_ANY = "OutcomeAny";
public static final String OUTCOME_SUCCESS = "OutcomeSuccess";
public static final String OUTCOME_FAILURE = "OutcomeFailure";
public static final String OUTCOME_DESCRIPTION = "OutcomeDescription";
public static final String OUTCOME_VALUE = "OutcomeValue";
public static final String OUTCOME_MATCHER = "OutcomeMatcher";
public static final String OUTCOME_VERIFIED = "OutcomeVerified";
public static final String META_FILTER = "MetaFilter";
public static final String YES = "Yes";
public static final String NO = "No";
public static final List<String> KEYWORDS = asList(
META,
META_PROPERTY,
NARRATIVE,
IN_ORDER_TO,
AS_A,
I_WANT_TO,
SO_THAT,
SCENARIO,
GIVEN_STORIES,
LIFECYCLE,
BEFORE,
AFTER,
EXAMPLES_TABLE,
EXAMPLES_TABLE_ROW,
EXAMPLES_TABLE_HEADER_SEPARATOR,
EXAMPLES_TABLE_VALUE_SEPARATOR,
EXAMPLES_TABLE_IGNORABLE_SEPARATOR,
GIVEN,
WHEN,
THEN,
AND,
IGNORABLE,
COMPOSITE,
PRIORITY,
PENDING,
NOT_PERFORMED,
FAILED,
DRY_RUN,
STORY_CANCELLED,
DURATION,
SCOPE,
SCOPE_STEP,
SCOPE_SCENARIO,
SCOPE_STORY,
OUTCOME,
OUTCOME_ANY,
OUTCOME_SUCCESS,
OUTCOME_FAILURE,
OUTCOME_DESCRIPTION,
OUTCOME_VALUE,
OUTCOME_MATCHER,
OUTCOME_VERIFIED,
META_FILTER,
YES,
NO
);
private final String meta;
private final String metaProperty;
private final String narrative;
private final String inOrderTo;
private final String asA;
private final String iWantTo;
private final String soThat;
private final String scenario;
private final String givenStories;
private final String lifecycle;
private final String before;
private final String after;
private final String examplesTable;
private final String examplesTableRow;
private final String examplesTableHeaderSeparator;
private final String examplesTableValueSeparator;
private final String examplesTableIgnorableSeparator;
private final String given;
private final String when;
private final String then;
private final String and;
private final String ignorable;
private final String composite;
private final String priority;
private final String pending;
private final String notPerformed;
private final String failed;
private final String dryRun;
private final String storyCancelled;
private final String duration;
private final String scope;
private final String scopeStep;
private final String scopeScenario;
private final String scopeStory;
private final String outcome;
private final String outcomeAny;
private final String outcomeSuccess;
private final String outcomeFailure;
private final String outcomeDescription;
private final String outcomeValue;
private final String outcomeMatcher;
private final String outcomeVerified;
private final String metaFilter;
private final String yes;
private final String no;
private final Map<StepType, String> startingWordsByType = new HashMap<>();
public static Map<String, String> defaultKeywords() {
Map<String, String> keywords = new HashMap<>();
keywords.put(META, "Meta:");
keywords.put(META_PROPERTY, "@");
keywords.put(NARRATIVE, "Narrative:");
keywords.put(IN_ORDER_TO, "In order to");
keywords.put(AS_A, "As a");
keywords.put(I_WANT_TO, "I want to");
keywords.put(SO_THAT, "So that");
keywords.put(SCENARIO, "Scenario:");
keywords.put(GIVEN_STORIES, "GivenStories:");
keywords.put(LIFECYCLE, "Lifecycle:");
keywords.put(BEFORE, "Before:");
keywords.put(AFTER, "After:");
keywords.put(EXAMPLES_TABLE, "Examples:");
keywords.put(EXAMPLES_TABLE_ROW, "Example:");
keywords.put(EXAMPLES_TABLE_HEADER_SEPARATOR, "|");
keywords.put(EXAMPLES_TABLE_VALUE_SEPARATOR, "|");
keywords.put(EXAMPLES_TABLE_IGNORABLE_SEPARATOR, "|--");
keywords.put(GIVEN, "Given");
keywords.put(WHEN, "When");
keywords.put(THEN, "Then");
keywords.put(AND, "And");
keywords.put(IGNORABLE, "!--");
keywords.put(COMPOSITE, "Composite:");
keywords.put(PRIORITY, "Priority:");
keywords.put(PENDING, "PENDING");
keywords.put(NOT_PERFORMED, "NOT PERFORMED");
keywords.put(FAILED, "FAILED");
keywords.put(DRY_RUN, "DRY RUN");
keywords.put(STORY_CANCELLED, "STORY CANCELLED");
keywords.put(DURATION, "DURATION");
keywords.put(SCOPE, "Scope:");
keywords.put(SCOPE_STEP, "STEP");
keywords.put(SCOPE_SCENARIO, "SCENARIO");
keywords.put(SCOPE_STORY, "STORY");
keywords.put(OUTCOME, "Outcome:");
keywords.put(OUTCOME_ANY, "ANY");
keywords.put(OUTCOME_SUCCESS, "SUCCESS");
keywords.put(OUTCOME_FAILURE, "FAILURE");
keywords.put(OUTCOME_DESCRIPTION, "DESCRIPTION");
keywords.put(OUTCOME_MATCHER, "MATCHER");
keywords.put(OUTCOME_VALUE, "VALUE");
keywords.put(OUTCOME_VERIFIED, "VERIFIED");
keywords.put(META_FILTER, "MetaFilter:");
keywords.put(YES, "Yes");
keywords.put(NO, "No");
return keywords;
}
/**
* Creates Keywords with default values {@link #defaultKeywords()}
*/
public Keywords() {
this(defaultKeywords());
}
/**
* Creates Keywords with provided keywords Map and Encoding
*
* @param keywords the Map of keywords indexed by their name
*/
public Keywords(Map<String, String> keywords) {
this.meta = keyword(META, keywords);
this.metaProperty = keyword(META_PROPERTY, keywords);
this.narrative = keyword(NARRATIVE, keywords);
this.inOrderTo = keyword(IN_ORDER_TO, keywords);
this.asA = keyword(AS_A, keywords);
this.iWantTo = keyword(I_WANT_TO, keywords);
this.soThat = keyword(SO_THAT, keywords);
this.scenario = keyword(SCENARIO, keywords);
this.givenStories = keyword(GIVEN_STORIES, keywords);
this.lifecycle = keyword(LIFECYCLE, keywords);
this.before = keyword(BEFORE, keywords);
this.after = keyword(AFTER, keywords);
this.examplesTable = keyword(EXAMPLES_TABLE, keywords);
this.examplesTableRow = keyword(EXAMPLES_TABLE_ROW, keywords);
this.examplesTableHeaderSeparator = keyword(EXAMPLES_TABLE_HEADER_SEPARATOR, keywords);
this.examplesTableValueSeparator = keyword(EXAMPLES_TABLE_VALUE_SEPARATOR, keywords);
this.examplesTableIgnorableSeparator = keyword(EXAMPLES_TABLE_IGNORABLE_SEPARATOR, keywords);
this.given = keyword(GIVEN, keywords);
this.when = keyword(WHEN, keywords);
this.then = keyword(THEN, keywords);
this.and = keyword(AND, keywords);
this.ignorable = keyword(IGNORABLE, keywords);
this.composite = keyword(COMPOSITE, keywords);
this.priority = keyword(PRIORITY, keywords);
this.pending = keyword(PENDING, keywords);
this.notPerformed = keyword(NOT_PERFORMED, keywords);
this.failed = keyword(FAILED, keywords);
this.dryRun = keyword(DRY_RUN, keywords);
this.storyCancelled = keyword(STORY_CANCELLED, keywords);
this.duration = keyword(DURATION, keywords);
this.scope = keyword(SCOPE, keywords);
this.scopeStep = keyword(SCOPE_STEP, keywords);
this.scopeScenario = keyword(SCOPE_SCENARIO, keywords);
this.scopeStory = keyword(SCOPE_STORY, keywords);
this.outcome = keyword(OUTCOME, keywords);
this.outcomeAny = keyword(OUTCOME_ANY, keywords);
this.outcomeSuccess = keyword(OUTCOME_SUCCESS, keywords);
this.outcomeFailure = keyword(OUTCOME_FAILURE, keywords);
this.outcomeDescription = keyword(OUTCOME_DESCRIPTION, keywords);
this.outcomeMatcher = keyword(OUTCOME_MATCHER, keywords);
this.outcomeValue = keyword(OUTCOME_VALUE, keywords);
this.outcomeVerified = keyword(OUTCOME_VERIFIED, keywords);
this.metaFilter = keyword(META_FILTER, keywords);
this.yes = keyword(YES, keywords);
this.no = keyword(NO, keywords);
startingWordsByType.put(StepType.GIVEN, given());
startingWordsByType.put(StepType.WHEN, when());
startingWordsByType.put(StepType.THEN, then());
startingWordsByType.put(StepType.AND, and());
startingWordsByType.put(StepType.IGNORABLE, ignorable());
}
private String keyword(String name, Map<String, String> keywords) {
String keyword = keywords.get(name);
if (keyword == null) {
throw new KeywordNotFound(name, keywords);
}
return keyword;
}
public String meta() {
return meta;
}
public String metaProperty() {
return metaProperty;
}
public String narrative() {
return narrative;
}
public String inOrderTo() {
return inOrderTo;
}
public String asA() {
return asA;
}
@SuppressWarnings("checkstyle:MethodName")
public String iWantTo() {
return iWantTo;
}
public String soThat() {
return soThat;
}
public String scenario() {
return scenario;
}
public String givenStories() {
return givenStories;
}
public String lifecycle() {
return lifecycle;
}
public String before() {
return before;
}
public String after() {
return after;
}
public String examplesTable() {
return examplesTable;
}
public String examplesTableRow() {
return examplesTableRow;
}
public String examplesTableHeaderSeparator() {
return examplesTableHeaderSeparator;
}
public String examplesTableValueSeparator() {
return examplesTableValueSeparator;
}
public String examplesTableIgnorableSeparator() {
return examplesTableIgnorableSeparator;
}
public String given() {
return given;
}
public String when() {
return when;
}
public String then() {
return then;
}
public String and() {
return and;
}
public String ignorable() {
return ignorable;
}
public String composite() {
return composite;
}
public String priority() {
return priority;
}
public String pending() {
return pending;
}
public String notPerformed() {
return notPerformed;
}
public String failed() {
return failed;
}
public String dryRun() {
return dryRun;
}
public String storyCancelled() {
return storyCancelled;
}
public String duration() {
return duration;
}
public String scope() {
return scope;
}
public String scopeStep() {
return scopeStep;
}
public String scopeScenario() {
return scopeScenario;
}
public String scopeStory() {
return scopeStory;
}
public String outcome() {
return outcome;
}
public String outcomeAny() {
return outcomeAny;
}
public String outcomeSuccess() {
return outcomeSuccess;
}
public String outcomeFailure() {
return outcomeFailure;
}
public String outcomeDescription() {
return outcomeDescription;
}
public String outcomeValue() {
return outcomeValue;
}
public String outcomeMatcher() {
return outcomeMatcher;
}
public String outcomeVerified() {
return outcomeVerified;
}
public List<String> outcomeFields() {
return asList(outcomeDescription, outcomeValue, outcomeMatcher, outcomeVerified);
}
public String metaFilter() {
return metaFilter;
}
public String yes() {
return yes;
}
public String no() {
return no;
}
public String[] synonymsOf(String word) {
return word.split(SYNONYM_SEPARATOR);
}
public Stream<String> startingWords(Predicate<StepType> stepTypeFilter) {
return startingWordsByType()
.entrySet()
.stream()
.filter(e -> stepTypeFilter.test(e.getKey()))
.map(Entry::getValue)
.map(this::synonymsOf)
.flatMap(Stream::of);
}
public Map<StepType, String> startingWordsByType() {
return startingWordsByType;
}
private boolean ofStepType(String stepAsString, StepType stepType) {
boolean isType = false;
for (String word : startingWordsFor(stepType)) {
isType = stepStartsWithWord(stepAsString, word);
if (isType) {
break;
}
}
return isType;
}
public boolean isAndStep(String stepAsString) {
return ofStepType(stepAsString, StepType.AND);
}
public boolean isIgnorableStep(String stepAsString) {
return ofStepType(stepAsString, StepType.IGNORABLE);
}
public String stepWithoutStartingWord(String stepAsString, StepType stepType) {
String startingWord = startingWord(stepAsString, stepType);
return stepAsString.substring(startingWord.length() + 1); // 1 for the space after
}
public String stepWithoutStartingWord(String stepAsString) {
StepType stepType = stepTypeFor(stepAsString);
return stepWithoutStartingWord(stepAsString, stepType);
}
public String startingWord(String stepAsString, StepType stepType) throws StartingWordNotFound {
for (String wordForType : startingWordsFor(stepType)) {
if (stepStartsWithWord(stepAsString, wordForType)) {
return wordForType;
}
}
for (String andWord : startingWordsFor(StepType.AND)) {
if (stepStartsWithWord(stepAsString, andWord)) {
return andWord;
}
}
throw new StartingWordNotFound(stepAsString, stepType, startingWordsByType);
}
public String startingWord(String stepAsString) throws StartingWordNotFound {
for (StepType stepType : startingWordsByType.keySet()) {
for (String wordForType : startingWordsFor(stepType)) {
if (stepStartsWithWord(stepAsString, wordForType)) {
return wordForType;
}
}
}
throw new StartingWordNotFound(stepAsString, startingWordsByType);
}
public StepType stepTypeFor(String stepAsString) throws StartingWordNotFound {
for (StepType stepType : startingWordsByType.keySet()) {
for (String wordForType : startingWordsFor(stepType)) {
if (stepStartsWithWord(stepAsString, wordForType)) {
return stepType;
}
}
}
throw new StartingWordNotFound(stepAsString, startingWordsByType);
}
public boolean stepStartsWithWord(String step, String word) {
return stepStartsWithWords(step, word);
}
public boolean stepStartsWithWords(String step, String... words) {
char separator = ' '; // space after qualifies it as word
String start = StringUtils.join(words, separator) + separator;
return step.startsWith(start);
}
public String startingWordFor(StepType stepType) {
String startingWord = startingWordsByType.get(stepType);
if (startingWord == null) {
throw new StartingWordNotFound(stepType, startingWordsByType);
}
return startingWord;
}
public String[] startingWordsFor(StepType stepType) {
return synonymsOf(startingWordFor(stepType));
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
@SuppressWarnings("serial")
public static class KeywordNotFound extends RuntimeException {
public KeywordNotFound(String name, Map<String, String> keywords) {
super("Keyword " + name + " not found amongst " + keywords);
}
}
@SuppressWarnings("serial")
public static class StartingWordNotFound extends RuntimeException {
public StartingWordNotFound(String step, StepType stepType, Map<StepType, String> startingWordsByType) {
super("No starting word found for step '" + step + "' of type '" + stepType + "' amongst '"
+ startingWordsByType + "'");
}
public StartingWordNotFound(String step, Map<StepType, String> startingWordsByType) {
super("No starting word found for step '" + step + "' amongst '" + startingWordsByType + "'");
}
public StartingWordNotFound(StepType stepType, Map<StepType, String> startingWordsByType) {
super("No starting word found of type '" + stepType + "' amongst '" + startingWordsByType + "'");
}
}
}