Repository: mauriciotogneri/green-coffee Branch: master Commit: caf960ec6f63 Files: 95 Total size: 372.6 KB Directory structure: gitextract_xuvgahf2/ ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── greencoffee/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ └── java/ │ ├── com/ │ │ └── mauriciotogneri/ │ │ └── greencoffee/ │ │ ├── GreenCoffeeConfig.java │ │ ├── GreenCoffeeSteps.java │ │ ├── GreenCoffeeTest.java │ │ ├── Localization.java │ │ ├── Scenario.java │ │ ├── ScenarioConfig.java │ │ ├── ScreenCapture.java │ │ ├── ScreenshotProvider.java │ │ ├── StepDefinition.java │ │ ├── TestLog.java │ │ ├── TimedIdlingResource.java │ │ ├── annotations/ │ │ │ ├── And.java │ │ │ ├── But.java │ │ │ ├── Given.java │ │ │ ├── Then.java │ │ │ └── When.java │ │ ├── exceptions/ │ │ │ ├── DuplicatedStepDefinitionException.java │ │ │ ├── InvalidExampleException.java │ │ │ ├── InvalidMethodSignatureException.java │ │ │ ├── InvalidStepDefinitionException.java │ │ │ ├── NoStepsDefinedException.java │ │ │ ├── StepDefinitionNotFoundException.java │ │ │ └── StepFailureException.java │ │ └── interactions/ │ │ ├── ActionableData.java │ │ ├── ActionableObject.java │ │ ├── ActionableView.java │ │ ├── DataMatcher.java │ │ └── ObjectMatcher.java │ └── gherkin/ │ ├── AstBuilder.java │ ├── AstNode.java │ ├── Func.java │ ├── GenerateTokens.java │ ├── GherkinDialect.java │ ├── GherkinDialectProvider.java │ ├── GherkinLanguageConstants.java │ ├── GherkinLine.java │ ├── GherkinLineSpan.java │ ├── IGherkinDialectProvider.java │ ├── IGherkinLine.java │ ├── Parser.java │ ├── ParserException.java │ ├── StringUtils.java │ ├── SymbolCounter.java │ ├── Token.java │ ├── TokenFormatter.java │ ├── TokenFormatterBuilder.java │ ├── TokenMatcher.java │ ├── TokenScanner.java │ ├── ast/ │ │ ├── Background.java │ │ ├── Comment.java │ │ ├── DataTable.java │ │ ├── DocString.java │ │ ├── Examples.java │ │ ├── Feature.java │ │ ├── GherkinDocument.java │ │ ├── Location.java │ │ ├── Node.java │ │ ├── Scenario.java │ │ ├── ScenarioDefinition.java │ │ ├── ScenarioOutline.java │ │ ├── Step.java │ │ ├── TableCell.java │ │ ├── TableRow.java │ │ └── Tag.java │ ├── cli/ │ │ └── Main.java │ ├── events/ │ │ ├── AttachmentEvent.java │ │ ├── CucumberEvent.java │ │ ├── GherkinDocumentEvent.java │ │ ├── PickleEvent.java │ │ └── SourceEvent.java │ ├── pickles/ │ │ ├── Argument.java │ │ ├── Compiler.java │ │ ├── Pickle.java │ │ ├── PickleCell.java │ │ ├── PickleLocation.java │ │ ├── PickleRow.java │ │ ├── PickleStep.java │ │ ├── PickleString.java │ │ ├── PickleTable.java │ │ └── PickleTag.java │ └── stream/ │ ├── GherkinEvents.java │ ├── SourceEvents.java │ └── Stdio.java └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.iml gradle.properties .gradle /.idea /local.properties /greencoffee/build /build ================================================ FILE: CHANGELOG.md ================================================ # Change Log All notable changes to this project are documented in this file. ## [3.6.0] - 2021-02-15 ### Changed - Removed JCenter support ## [3.5.0] - 2018-10-01 ### Changed - Updated dependencies and build tools ## [3.3.0] - 2018-08-23 ### Changed - Updated screenshot interface to allow to pass a custom screenshot provider ## [3.2.1] - 2018-04-13 ### Changed - Updated screenshot parameter from path to boolean. When set to `true`, screenshots will be placed in the folder `Android/data/your_package/files/screenshots` ### Removed - Method `grantPermission`. Use `GrantPermissionRule` instead ## [3.0.0] - 2018-02-12 ### Changed - Updated to Java 8 - Updated Android build tools, compile version and Gradle version - Updated visibility of some classes and methods - Some constructor parameters of the class `ScenarioConfig` are optional ## [2.9.0] - 2017-09-18 ### Changed - Using Espresso `3.0.1` ## [2.8.1] - 2017-07-06 ### Added - Added method `text()` to `ActionableObject` - Added method `onViewWithAll(Matcher... matchers)` - Added class `TimedIdlingResource` ## [2.8.0] - 2017-07-05 ### Added - Added boolean methods for actionable elements - Improved data matchers ## [2.7.0] - 2017-07-04 ### Added - Added methods `waitFor(long millis)` and `waitFor(long value, TimeUnit timeUnit)` - Added class `SpinnerMatcher` ## [2.6.0] - 2017-04-28 ### Added - Improvements in `ActionableView` (by @thanhlcm90) - Added callback `afterScenarioEnds(Scenario scenario, Locale locale)` - Added method `grantPermission(String permission)` ## [2.5.0] - 2017-04-26 ### Added - Improvements in `ActionableView` (by @thanhlcm90) ## [2.4.0] - 2017-04-02 ### Changed - Using Gradle plugin version 2.3.0 - Overridden method `toString()` for class `ScenarioConfig` ## [2.2.0] - 2017-03-17 ### Removed - Unused third party libraries ## [2.1.1] - 2017-03-02 ### Added - Added the helper methods `closeKeyboard()` and `pressBack()` - Added method `beforeScenarioStarts(Scenario scenario, Locale locale)` ## [2.0.1] - 2017-02-24 ### Added - Support to launch the scenarios with different locales - Support to take screenshots during the tests - This CHANGELOG ### Changed - The constructor of `GreenCoffeeTest` - Updated to latest version of [Gherkin java](https://github.com/cucumber/gherkin-java) ### Removed - Example app. Moved [here](https://github.com/vndly/green-coffee-example) ## [1.0.0] - 2016-09-04 ### Added - First stable version of the library ================================================ FILE: LICENSE.md ================================================ MIT License Copyright (c) 2021 Mauricio Togneri Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/mauriciotogneri/green-coffee/blob/master/LICENSE.md) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-green--coffee-green.svg?style=true)](https://android-arsenal.com/details/1/4313) # Green Coffee **Green Coffee** is a library that allows you to run your acceptance tests written in Gherkin in your Android instrumentation tests using the step definitions that you declare. Visit the [wiki](https://github.com/mauriciotogneri/green-coffee/wiki) for more detailed information. ## Example Given the following feature: ```gherkin Feature: Login screen to authenticate users Scenario: Invalid username and password Given I see an empty login form When I introduce an invalid username And I introduce an invalid password And I press the login button Then I see an error message saying 'Invalid credentials' ``` First, create a class that extends from `GreenCoffeeTest` and declare the Activity, the feature and the step definitions that will be used: ```java @RunWith(Parameterized.class) public class LoginFeatureTest extends GreenCoffeeTest { @Rule public ActivityTestRule activity = new ActivityTestRule<>(LoginActivity.class); public LoginFeatureTest(ScenarioConfig scenarioConfig) { super(scenarioConfig); } @Parameters(name = "{0}") public static Iterable scenarios() throws IOException { return new GreenCoffeeConfig() .withFeatureFromAssets("assets/login.feature") .takeScreenshotOnFail() .scenarios( new Locale("en", "GB"), new Locale("es", "ES") ); // the locales used to run the scenarios (optional) } @Test public void test() { start(new LoginSteps()); } } ``` Next, create a class containing the steps definitions: ```java public class LoginSteps extends GreenCoffeeSteps { @Given("^I see an empty login form$") public void iSeeAnEmptyLoginForm() { onViewWithId(R.id.login_input_username).isEmpty(); onViewWithId(R.id.login_input_password).isEmpty(); } @When("^I introduce an invalid username$") public void iIntroduceAnInvalidUsername() { onViewWithId(R.id.login_input_username).type("guest"); } @When("^I introduce an invalid password$") public void iIntroduceAnInvalidPassword() { onViewWithId(R.id.login_input_password).type("1234"); } @When("^I press the login button$") public void iPressTheLoginButton() { onViewWithId(R.id.login_button_doLogin).click(); } @Then("^I see an error message saying 'Invalid credentials'$") public void iSeeAnErrorMessageSayingInvalidCredentials() { onViewWithText(R.string.login_credentials_error).isDisplayed(); } } ``` And that's it, now you can create your own tests using Green Coffee. This is how it looks when you run a more complex test: ![Example](http://i.imgur.com/4rMK1KK.gif) You can see an example applied to a full app [here](https://github.com/vndly/green-coffee-example). ## Installation Add the following code to your root `build.gradle`: ```groovy allprojects { repositories { maven { url 'https://jitpack.io' } } } ``` Add the following code to your module `build.gradle` file: ```groovy dependencies { androidTestImplementation 'androidx.test:runner:1.3.0' androidTestImplementation 'androidx.test:rules:1.3.0' androidTestImplementation 'com.github.mauriciotogneri:green-coffee:3.6.0' } ``` And the following test instrumentation runner: ```groovy defaultConfig { testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } ``` ================================================ FILE: build.gradle ================================================ buildscript { repositories { google() mavenCentral() maven { url 'https://plugins.gradle.org/m2/' } } dependencies { classpath 'com.android.tools.build:gradle:4.1.2' } } allprojects { repositories { google() mavenCentral() maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } } } task clean(type: Delete) { delete rootProject.buildDir } ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ #Mon Feb 15 21:58:43 CET 2021 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip ================================================ FILE: gradlew ================================================ #!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; esac # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" ================================================ FILE: gradlew.bat ================================================ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: greencoffee/build.gradle ================================================ apply plugin: 'com.android.library' android { compileSdkVersion 30 buildToolsVersion '30.0.3' defaultConfig { minSdkVersion 14 targetSdkVersion 30 versionCode 1 versionName '3.6.0' } dexOptions { javaMaxHeapSize '2g' preDexLibraries true } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { implementation 'io.cucumber:gherkin-jvm-deps:1.0.6' implementation 'com.android.support.test.espresso:espresso-core:3.0.2' } ================================================ FILE: greencoffee/src/main/AndroidManifest.xml ================================================ ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/GreenCoffeeConfig.java ================================================ package com.mauriciotogneri.greencoffee; import com.mauriciotogneri.greencoffee.exceptions.InvalidExampleException; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import gherkin.AstBuilder; import gherkin.Parser; import gherkin.ast.Examples; import gherkin.ast.Feature; import gherkin.ast.GherkinDocument; import gherkin.ast.ScenarioDefinition; import gherkin.ast.ScenarioOutline; import gherkin.ast.Step; import gherkin.ast.TableCell; import gherkin.ast.TableRow; import gherkin.ast.Tag; public class GreenCoffeeConfig { private final List scenarios; private final ScreenshotProvider screenshotProvider; private GreenCoffeeConfig(List scenarios, ScreenshotProvider screenshotProvider) { this.scenarios = scenarios; this.screenshotProvider = screenshotProvider; } public GreenCoffeeConfig() { this(new ArrayList<>(), null); } public List scenarios(Locale... locales) { List scenarioConfigs = new ArrayList<>(); Locale[] finalLocales = locales; if (finalLocales.length == 0) { finalLocales = new Locale[1]; finalLocales[0] = Locale.getDefault(); } for (Locale locale : finalLocales) { for (Scenario scenario : scenarios) { scenarioConfigs.add(new ScenarioConfig(scenario, locale, screenshotProvider)); } } return scenarioConfigs; } public GreenCoffeeConfig takeScreenshotOnFail() { return new GreenCoffeeConfig(scenarios, ScreenshotProvider.getDefault()); } public GreenCoffeeConfig takeScreenshotOnFail(ScreenshotProvider screenshotProvider) { return new GreenCoffeeConfig(scenarios, screenshotProvider); } public GreenCoffeeConfig withTags(String firstTag, String... restTags) { List tagList = new ArrayList<>(); tagList.add(firstTag); tagList.addAll(Arrays.asList(restTags)); List filtered = new ArrayList<>(); for (Scenario scenario : scenarios) { if (scenario.hasTags(tagList)) { filtered.add(scenario); } } return new GreenCoffeeConfig(filtered, screenshotProvider); } public GreenCoffeeConfig withFeatureFromString(String featureSource) { return new GreenCoffeeConfig(scenarios(featureSource), screenshotProvider); } public GreenCoffeeConfig withFeatureFromAssets(String featurePath) throws IOException { InputStream stream = getClass().getClassLoader().getResourceAsStream(featurePath); return withFeatureFromInputStream(stream); } public GreenCoffeeConfig withFeatureFromUrl(String featureUrl) throws IOException { URL url = new URL(featureUrl); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("GET"); return withFeatureFromInputStream(urlConnection.getInputStream()); } public GreenCoffeeConfig withFeatureFromInputStream(InputStream featureInput) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(featureInput)); StringBuilder builder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { builder.append(String.format("%s%n", line)); } reader.close(); return new GreenCoffeeConfig(scenarios(builder.toString()), screenshotProvider); } private List scenarios(String featureSource) { Parser parser = new Parser<>(new AstBuilder()); GherkinDocument gherkinDocument = parser.parse(featureSource); Feature feature = gherkinDocument.getFeature(); List backgrounds = backgrounds(feature); List scenarios = scenarios(feature); List result = new ArrayList<>(); for (ScenarioDefinition scenarioDefinition : scenarios) { String name = scenarioDefinition.getName(); String description = scenarioDefinition.getDescription(); List steps = new ArrayList<>(); List tags = new ArrayList<>(); for (ScenarioDefinition background : backgrounds) { steps.addAll(background.getSteps()); } if (isScenarioNormal(scenarioDefinition)) { gherkin.ast.Scenario scenarioNormal = (gherkin.ast.Scenario) scenarioDefinition; tags.addAll(tags(scenarioNormal.getTags())); } else if (isScenarioOutline(scenarioDefinition)) { ScenarioOutline scenarioOutline = (ScenarioOutline) scenarioDefinition; tags.addAll(tags(scenarioOutline.getTags())); } steps.addAll(scenarioDefinition.getSteps()); result.add(new Scenario(name, description, steps, tags)); } return result; } private List tags(List tags) { List result = new ArrayList<>(); for (Tag tag : tags) { result.add(tag.getName()); } return result; } private List backgrounds(Feature feature) { List result = new ArrayList<>(); for (ScenarioDefinition scenario : feature.getChildren()) { if (gherkin.ast.Background.class.isInstance(scenario)) { result.add(scenario); } } return result; } private List scenarios(Feature feature) { List result = new ArrayList<>(); for (ScenarioDefinition scenario : feature.getChildren()) { if (isScenarioNormal(scenario)) { result.add(scenario); } else if (isScenarioOutline(scenario)) { ScenarioOutline scenarioOutline = (ScenarioOutline) scenario; for (Examples examples : scenarioOutline.getExamples()) { for (TableRow row : examples.getTableBody()) { result.add(concreteScenario(scenarioOutline, parametersMap(examples.getTableHeader(), row))); } } } } return result; } private boolean isScenarioNormal(ScenarioDefinition scenario) { return gherkin.ast.Scenario.class.isInstance(scenario); } private boolean isScenarioOutline(ScenarioDefinition scenario) { return gherkin.ast.ScenarioOutline.class.isInstance(scenario); } private Map parametersMap(TableRow header, TableRow row) { List headerCells = header.getCells(); List rowCells = row.getCells(); if (headerCells.size() == rowCells.size()) { Map parameters = new LinkedHashMap<>(); for (int i = 0; i < headerCells.size(); i++) { TableCell headerCell = headerCells.get(i); TableCell rowCell = rowCells.get(i); parameters.put(headerCell.getValue(), rowCell.getValue()); } return parameters; } else { throw new InvalidExampleException(header.getLocation().getLine(), header.getLocation().getColumn()); } } private ScenarioDefinition concreteScenario(ScenarioOutline abstractScenario, Map parameters) { List steps = new ArrayList<>(); for (Step step : abstractScenario.getSteps()) { steps.add(concreteStep(step, parameters)); } return new gherkin.ast.Scenario( abstractScenario.getTags(), abstractScenario.getLocation(), abstractScenario.getKeyword(), abstractScenario.getName(), abstractScenario.getDescription(), steps); } private Step concreteStep(Step abstractStep, Map parameters) { String text = abstractStep.getText(); for (Entry entry : parameters.entrySet()) { String target = String.format("<%s>", entry.getKey()); String replacement = entry.getValue(); text = text.replace(target, replacement); } return new Step( abstractStep.getLocation(), abstractStep.getKeyword(), text, abstractStep.getArgument()); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/GreenCoffeeSteps.java ================================================ package com.mauriciotogneri.greencoffee; import android.support.annotation.IdRes; import android.support.annotation.StringRes; import android.support.test.InstrumentationRegistry; import android.support.test.espresso.Espresso; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.espresso.matcher.ViewMatchers; import android.view.View; import android.view.ViewGroup; import com.mauriciotogneri.greencoffee.annotations.And; import com.mauriciotogneri.greencoffee.annotations.But; import com.mauriciotogneri.greencoffee.annotations.Given; import com.mauriciotogneri.greencoffee.annotations.Then; import com.mauriciotogneri.greencoffee.annotations.When; import com.mauriciotogneri.greencoffee.exceptions.InvalidStepDefinitionException; import com.mauriciotogneri.greencoffee.interactions.ActionableData; import com.mauriciotogneri.greencoffee.interactions.ActionableObject; import com.mauriciotogneri.greencoffee.interactions.ActionableView; import com.mauriciotogneri.greencoffee.interactions.DataMatcher; import com.mauriciotogneri.greencoffee.interactions.ObjectMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; import java.io.File; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.concurrent.TimeUnit; import static android.support.test.espresso.Espresso.onData; import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.matcher.ViewMatchers.isRoot; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static org.hamcrest.Matchers.allOf; public class GreenCoffeeSteps { List stepDefinitions() { List stepDefinitions = new ArrayList<>(); for (Method method : getClass().getDeclaredMethods()) { String pattern = pattern(method); if (pattern != null) { StepDefinition stepDefinition = new StepDefinition(pattern, method, this); stepDefinitions.add(stepDefinition); } } return stepDefinitions; } private String pattern(Method method) { String result = null; Given given = method.getAnnotation(Given.class); if (given != null) { result = given.value(); } When when = method.getAnnotation(When.class); if (when != null) { checkInvalidStepDefinition(result, method); result = when.value(); } Then then = method.getAnnotation(Then.class); if (then != null) { checkInvalidStepDefinition(result, method); result = then.value(); } And and = method.getAnnotation(And.class); if (and != null) { checkInvalidStepDefinition(result, method); result = and.value(); } But but = method.getAnnotation(But.class); if (but != null) { checkInvalidStepDefinition(result, method); result = but.value(); } return result; } private void checkInvalidStepDefinition(String pattern, Method method) { if (pattern != null) { throw new InvalidStepDefinitionException(method); } } protected ActionableObject onViewWithId(@IdRes int resourceId) { return new ActionableView(onView(withId(resourceId))); } protected ActionableObject onViewWithId(@IdRes int resourceId, int index) { return new ActionableView(onView(withIndex(withId(resourceId), index))); } protected ActionableObject onViewWithText(@StringRes int resourceId) { return new ActionableView(onView(ViewMatchers.withText(resourceId))); } protected ActionableObject onViewWithText(@StringRes int resourceId, int index) { return new ActionableView(onView(withIndex(ViewMatchers.withText(resourceId), index))); } protected ActionableObject onViewWithText(Object text) { return new ActionableView(onView(ViewMatchers.withText(text.toString()))); } protected ActionableObject onViewWithText(Object text, int index) { return new ActionableView(onView(withIndex(ViewMatchers.withText(text.toString()), index))); } protected ActionableObject onViewWithAll(Matcher... matchers) { return new ActionableView(onView(allOf(matchers))); } protected ActionableObject onViewWithObject(T object) { return new ActionableData(onData(new ObjectMatcher<>(object))); } protected ActionableObject onViewWithObject(@IdRes int resourceId, Class clazz, T object) { return new DataMatcher<>(resourceId, clazz).with(object); } protected ActionableObject onViewChildOf(@IdRes int parentViewId, int index) { return new ActionableView(onView(nthChildOf(withId(parentViewId), index))); } protected void pressBack() { Espresso.pressBack(); } protected void closeKeyboard() { Espresso.closeSoftKeyboard(); } protected String string(@StringRes int stringId) { return InstrumentationRegistry.getTargetContext().getString(stringId); } protected Locale locale() { return new Localization(InstrumentationRegistry.getTargetContext()).locale(); } protected void takeScreenshot(File file) { ScreenCapture screenCapture = new ScreenCapture(); screenCapture.takeScreenshot(file); } protected Matcher withIndex(Matcher matcher, int index) { return new TypeSafeMatcher() { private int currentIndex; private int viewObjHash; @Override public void describeTo(Description description) { description.appendText(String.format("with index: %d", index)); } @Override public boolean matchesSafely(View view) { if (matcher.matches(view) && (currentIndex++ == index)) { viewObjHash = view.hashCode(); } return (view.hashCode() == viewObjHash); } }; } protected Matcher nthChildOf(Matcher parentMatcher, int childPosition) { return new TypeSafeMatcher() { @Override public void describeTo(Description description) { description.appendText(String.format("with %d child view of type parentMatcher", childPosition)); } @Override public boolean matchesSafely(View view) { if (!(view.getParent() instanceof ViewGroup)) { return parentMatcher.matches(view.getParent()); } ViewGroup group = (ViewGroup) view.getParent(); return parentMatcher.matches(view.getParent()) && group.getChildAt(childPosition).equals(view); } }; } protected void waitFor(long value, TimeUnit timeUnit) { onView(isRoot()).perform(actionWaitFor(value, timeUnit)); } protected void waitFor(long millis) { waitFor(millis, TimeUnit.MILLISECONDS); } private ViewAction actionWaitFor(long value, TimeUnit timeUnit) { long millis = timeUnit.toMillis(value); return new ViewAction() { @Override public Matcher getConstraints() { return isRoot(); } @Override public String getDescription() { return "Wait for " + millis + " milliseconds."; } @Override public void perform(UiController uiController, View view) { uiController.loopMainThreadForAtLeast(millis); } }; } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/GreenCoffeeTest.java ================================================ package com.mauriciotogneri.greencoffee; import com.mauriciotogneri.greencoffee.exceptions.DuplicatedStepDefinitionException; import com.mauriciotogneri.greencoffee.exceptions.NoStepsDefinedException; import com.mauriciotogneri.greencoffee.exceptions.StepDefinitionNotFoundException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; import static android.support.test.InstrumentationRegistry.getTargetContext; import gherkin.ast.Node; import gherkin.ast.Step; public class GreenCoffeeTest { private final ScenarioConfig scenarioConfig; private final TestLog testLog; public GreenCoffeeTest(ScenarioConfig scenario) { this.scenarioConfig = scenario; this.testLog = new TestLog(); beforeScenarioStarts(scenario.scenario(), scenario.locale()); Localization localization = new Localization(getTargetContext()); localization.locale(scenarioConfig.locale()); } protected void beforeScenarioStarts(Scenario scenario, Locale locale) { } protected void afterScenarioEnds(Scenario scenario, Locale locale) { } protected void start(GreenCoffeeSteps... targets) { if (targets.length == 0) { throw new NoStepsDefinedException(); } Scenario scenario = scenarioConfig.scenario(); testLog.logScenario(scenario); List stepDefinitions = new ArrayList<>(); for (GreenCoffeeSteps greenCoffeeSteps : targets) { stepDefinitions.addAll(greenCoffeeSteps.stepDefinitions()); } validateStepDefinitions(stepDefinitions); try { for (Step step : scenario.steps()) { processStep(step, stepDefinitions); } } catch (Exception e) { if (scenarioConfig.hasScreenshotProvider()) { ScreenshotProvider screenshotProvider = scenarioConfig.screenshotProvider(); screenshotProvider.takeScreenshot(scenario); } throw e; } finally { afterScenarioEnds(scenarioConfig.scenario(), scenarioConfig.locale()); } } private void validateStepDefinitions(List stepDefinitions) { Set patterns = new HashSet<>(); for (StepDefinition stepDefinition : stepDefinitions) { String pattern = stepDefinition.pattern(); if (!patterns.contains(pattern)) { patterns.add(pattern); } else { throw new DuplicatedStepDefinitionException(stepDefinition.method(), pattern); } } } private void processStep(Step step, List stepDefinitions) { String keyword = step.getKeyword().trim(); String text = step.getText().trim(); Node argument = step.getArgument(); testLog.logStep(keyword, text); for (StepDefinition stepDefinition : stepDefinitions) { if (stepDefinition.matches(text)) { stepDefinition.invoke(text, argument); return; } } throw new StepDefinitionNotFoundException(keyword, text); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/Localization.java ================================================ package com.mauriciotogneri.greencoffee; import android.annotation.TargetApi; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; import android.util.DisplayMetrics; import java.util.Locale; public class Localization { private final Context context; public Localization(Context context) { this.context = context; } public Locale locale() { return getSystemLocale(configuration(resources())); } public boolean locale(Locale newLocale) { Resources resources = resources(); DisplayMetrics displayMetrics = resources.getDisplayMetrics(); Configuration config = configuration(resources); Locale systemLocale = getSystemLocale(config); if (!systemLocale.equals(newLocale)) { updateSystemLocale(config, newLocale); updateSystemConfiguration(resources, config, displayMetrics); return true; } else { return false; } } public void reset() { locale(Locale.getDefault()); } // ============================================================================================= private Resources resources() { return context.getResources(); } private Configuration configuration(Resources resources) { return resources.getConfiguration(); } // ============================================================================================= private Locale getSystemLocale(Configuration config) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return systemLocale(config); } else { return systemLocaleLegacy(config); } } @SuppressWarnings("deprecation") private Locale systemLocaleLegacy(Configuration config) { return config.locale; } @TargetApi(Build.VERSION_CODES.N) private Locale systemLocale(Configuration config) { return config.getLocales().get(0); } // ============================================================================================= private void updateSystemLocale(Configuration config, Locale locale) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { systemLocale(config, locale); } else { systemLocaleLegacy(config, locale); } } @SuppressWarnings("deprecation") private void systemLocaleLegacy(Configuration config, Locale locale) { config.locale = locale; } @TargetApi(Build.VERSION_CODES.N) private void systemLocale(Configuration config, Locale locale) { config.setLocale(locale); } // ============================================================================================= @SuppressWarnings("deprecation") private void updateSystemConfiguration(Resources resources, Configuration config, DisplayMetrics displayMetrics) { resources.updateConfiguration(config, displayMetrics); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/Scenario.java ================================================ package com.mauriciotogneri.greencoffee; import java.util.Collections; import java.util.List; import gherkin.ast.Step; public class Scenario { private final String name; private final String description; private final List tags; private final List steps; public Scenario(String name, String description, List steps, List tags) { this.name = name; this.description = description; this.tags = tags; this.steps = Collections.unmodifiableList(steps); } public String name() { return name; } public String description() { return description; } public boolean hasTags(List tagList) { for (String tag : tagList) { if (tags.contains(tag)) { return true; } } return false; } public boolean hasTags(String... tagList) { for (String tag : tagList) { if (tags.contains(tag)) { return true; } } return false; } public List steps() { return steps; } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/ScenarioConfig.java ================================================ package com.mauriciotogneri.greencoffee; import java.util.Locale; public class ScenarioConfig { private final Scenario scenario; private final Locale locale; private final ScreenshotProvider screenshotProvider; public ScenarioConfig(Scenario scenario, Locale locale, ScreenshotProvider screenshotProvider) { this.scenario = scenario; this.locale = locale; this.screenshotProvider = screenshotProvider; } public ScenarioConfig(Scenario scenario, Locale locale) { this(scenario, locale, ScreenshotProvider.getDefault()); } public ScenarioConfig(Scenario scenario) { this(scenario, null, ScreenshotProvider.getDefault()); } public Scenario scenario() { return scenario; } public Locale locale() { return (locale != null) ? locale : Locale.getDefault(); } public Boolean hasScreenshotProvider() { return (screenshotProvider != null); } public ScreenshotProvider screenshotProvider() { return screenshotProvider; } @Override public String toString() { if (locale != null) { return String.format("%s - %s", scenario.name(), locale.toString()); } else { return scenario.name(); } } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/ScreenCapture.java ================================================ package com.mauriciotogneri.greencoffee; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.support.test.InstrumentationRegistry; import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; import android.support.test.runner.lifecycle.Stage; import android.view.View; import java.io.File; import java.io.FileOutputStream; import java.util.Collection; import java.util.Iterator; class ScreenCapture { void takeScreenshot(File file) { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { Collection resumedActivities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED); Iterator iterator = resumedActivities.iterator(); if (iterator.hasNext()) { Activity activity = iterator.next(); try { takeScreenshot(activity, file); } catch (Exception e) { // ignore } } }); } private void takeScreenshot(Activity activity, File file) throws Exception { View view = activity.getWindow().getDecorView().getRootView(); view.setDrawingCacheEnabled(true); view.buildDrawingCache(true); Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache()); view.setDrawingCacheEnabled(false); File parentFolder = file.getParentFile(); if (parentFolder.exists() || parentFolder.mkdirs()) { FileOutputStream outputStream = new FileOutputStream(file); bitmap.compress(CompressFormat.JPEG, 100, outputStream); outputStream.flush(); outputStream.close(); } } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/ScreenshotProvider.java ================================================ package com.mauriciotogneri.greencoffee; import java.io.File; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import static android.support.test.InstrumentationRegistry.getTargetContext; public interface ScreenshotProvider { static ScreenshotProvider getDefault() { return new DefaultScreenshotProvider(); } void takeScreenshot(Scenario scenario); class DefaultScreenshotProvider implements ScreenshotProvider { private final ScreenCapture screenCapture; DefaultScreenshotProvider() { screenCapture = new ScreenCapture(); } @Override public void takeScreenshot(Scenario scenario) { DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); String fileName = String.format("%s - %s.jpg", scenario.name(), dateFormat.format(new Date())); File file = new File(getTargetContext().getExternalFilesDir("screenshots"), fileName); screenCapture.takeScreenshot(file); } } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/StepDefinition.java ================================================ package com.mauriciotogneri.greencoffee; import com.mauriciotogneri.greencoffee.exceptions.InvalidMethodSignatureException; import com.mauriciotogneri.greencoffee.exceptions.StepFailureException; import java.lang.reflect.Method; import java.util.regex.Matcher; import java.util.regex.Pattern; import gherkin.ast.DataTable; import gherkin.ast.DocString; import gherkin.ast.Node; class StepDefinition { private final Pattern pattern; private final Method method; private final Object target; StepDefinition(String expression, Method method, Object target) { this.pattern = Pattern.compile(expression); this.method = method; this.target = target; } String pattern() { return pattern.pattern(); } Method method() { return method; } boolean matches(String text) { Matcher matcher = pattern.matcher(text); return matcher.find(); } void invoke(String text, Node argument) { Matcher matcher = pattern.matcher(text); if (matcher.find()) { Object[] parameters; try { parameters = parameters(matcher, argument); } catch (Exception e) { throw new InvalidMethodSignatureException(method, pattern.pattern(), text); } try { method.invoke(target, parameters); } catch (Exception e) { Throwable cause = e.getCause(); throw new StepFailureException(method, pattern.pattern(), text, (cause != null) ? cause.toString() : e.toString()); } } else { throw new RuntimeException(); } } private Object[] parameters(Matcher matcher, Node argument) { Object[] parameters = new Object[matcher.groupCount() + ((argument != null) ? 1 : 0)]; Class[] types = method.getParameterTypes(); int limit = (argument != null) ? (parameters.length - 1) : parameters.length; for (int i = 0; i < limit; i++) { parameters[i] = castParameter(matcher.group(i + 1), types[i]); } if (argument != null) { if (argument.getClass().equals(DocString.class)) { DocString docString = (DocString) argument; parameters[parameters.length - 1] = docString.getContent(); } else if (argument.getClass().equals(DataTable.class)) { DataTable dataTable = (DataTable) argument; parameters[parameters.length - 1] = dataTable.getRows(); } } return parameters; } private Object castParameter(String value, Class clazz) { if (clazz.equals(int.class) || clazz.equals(Integer.class)) { return Integer.parseInt(value); } else if (clazz.equals(long.class) || clazz.equals(Long.class)) { return Long.parseLong(value); } else if (clazz.equals(float.class) || clazz.equals(Float.class)) { return Float.parseFloat(value); } else if (clazz.equals(double.class) || clazz.equals(Double.class)) { return Double.parseDouble(value); } else if (clazz.equals(byte.class) || clazz.equals(Byte.class)) { return Byte.parseByte(value); } else if (clazz.equals(short.class) || clazz.equals(Short.class)) { return Short.parseShort(value); } else if (clazz.equals(boolean.class) || clazz.equals(Boolean.class)) { return Boolean.parseBoolean(value); } else if (clazz.equals(char.class) || clazz.equals(Character.class)) { return value.charAt(0); } else { return value; } } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/TestLog.java ================================================ package com.mauriciotogneri.greencoffee; import android.text.TextUtils; class TestLog { void logScenario(Scenario scenario) { log(String.format("Scenario: %s", scenario.name())); if (!TextUtils.isEmpty(scenario.description())) { for (String line : scenario.description().split("\n")) { log(String.format("\t%s", line.trim())); } } } void logStep(String keyword, String text) { log(String.format("\t%s %s", keyword, text)); } private void log(String message) { System.out.println(message); System.out.flush(); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/TimedIdlingResource.java ================================================ package com.mauriciotogneri.greencoffee; import android.support.test.espresso.Espresso; import android.support.test.espresso.IdlingResource; import java.util.concurrent.TimeUnit; public class TimedIdlingResource implements IdlingResource { private final long timeout; private ResourceCallback resourceCallback; public TimedIdlingResource(long millis) { this.timeout = System.currentTimeMillis() + millis; } public TimedIdlingResource(long value, TimeUnit timeUnit) { this.timeout = timeUnit.toMillis(value); } @Override public String getName() { return getClass().getName() + ":" + (timeout - System.currentTimeMillis()); } @Override public boolean isIdleNow() { boolean idle = System.currentTimeMillis() >= timeout; if (idle && (resourceCallback != null)) { resourceCallback.onTransitionToIdle(); } return idle; } @Override public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { this.resourceCallback = resourceCallback; } public void start() { Espresso.registerIdlingResources(this); } public void stop() { Espresso.unregisterIdlingResources(this); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/annotations/And.java ================================================ package com.mauriciotogneri.greencoffee.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface And { String value(); } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/annotations/But.java ================================================ package com.mauriciotogneri.greencoffee.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface But { String value(); } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/annotations/Given.java ================================================ package com.mauriciotogneri.greencoffee.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Given { String value(); } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/annotations/Then.java ================================================ package com.mauriciotogneri.greencoffee.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Then { String value(); } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/annotations/When.java ================================================ package com.mauriciotogneri.greencoffee.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface When { String value(); } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/exceptions/DuplicatedStepDefinitionException.java ================================================ package com.mauriciotogneri.greencoffee.exceptions; import java.lang.reflect.Method; public class DuplicatedStepDefinitionException extends RuntimeException { public DuplicatedStepDefinitionException(Method method, String pattern) { super(String.format("Duplicated step definition%n%nClass: %s%nMethod: %s%nPattern: \"%s\"%n", method.getDeclaringClass().getSimpleName(), method.getName(), pattern)); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/exceptions/InvalidExampleException.java ================================================ package com.mauriciotogneri.greencoffee.exceptions; public class InvalidExampleException extends RuntimeException { public InvalidExampleException(int line, int column) { super(String.format("Invalid example format at: [%s, %s]", line, column)); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/exceptions/InvalidMethodSignatureException.java ================================================ package com.mauriciotogneri.greencoffee.exceptions; import java.lang.reflect.Method; public class InvalidMethodSignatureException extends RuntimeException { public InvalidMethodSignatureException(Method method, String pattern, String text) { super(String.format("Invalid number of type of parameters%n%nClass: %s%nMethod: %s%nPattern: \"%s\"%nText matched: \"%s\"%n", method.getDeclaringClass().getSimpleName(), method.getName(), pattern, text)); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/exceptions/InvalidStepDefinitionException.java ================================================ package com.mauriciotogneri.greencoffee.exceptions; import java.lang.reflect.Method; public class InvalidStepDefinitionException extends RuntimeException { public InvalidStepDefinitionException(Method method) { super(String.format("A step definition cannot have more than one annotation%n%nClass: %s%nMethod: %s%n", method.getDeclaringClass().getSimpleName(), method.getName())); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/exceptions/NoStepsDefinedException.java ================================================ package com.mauriciotogneri.greencoffee.exceptions; public class NoStepsDefinedException extends RuntimeException { public NoStepsDefinedException() { super("No steps defined for the feature"); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/exceptions/StepDefinitionNotFoundException.java ================================================ package com.mauriciotogneri.greencoffee.exceptions; public class StepDefinitionNotFoundException extends RuntimeException { public StepDefinitionNotFoundException(String keyword, String text) { super(String.format("Step definition not found for: '%s: %s'", keyword, text)); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/exceptions/StepFailureException.java ================================================ package com.mauriciotogneri.greencoffee.exceptions; import java.lang.reflect.Method; public class StepFailureException extends RuntimeException { public StepFailureException(Method method, String pattern, String text, String cause) { super(String.format("Error processing step%n%nClass: %s%nMethod: %s%nPattern: \"%s\"%nText matched: \"%s\"%n%n%s", method.getDeclaringClass().getSimpleName(), method.getName(), pattern, text, cause)); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/interactions/ActionableData.java ================================================ package com.mauriciotogneri.greencoffee.interactions; import android.support.test.espresso.DataInteraction; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.espresso.ViewAssertion; import android.view.View; import android.widget.TextView; import org.hamcrest.Matcher; import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; public class ActionableData extends ActionableObject { private final DataInteraction dataInteraction; public ActionableData(DataInteraction dataInteraction) { this.dataInteraction = dataInteraction; } @Override public ActionableObject check(ViewAssertion viewAssertion) { return new ActionableView(dataInteraction.check(viewAssertion)); } @Override public ActionableObject perform(ViewAction viewAction) { return new ActionableView(dataInteraction.perform(viewAction)); } @Override public String text() { String[] stringHolder = {null}; dataInteraction.perform(new ViewAction() { @Override public Matcher getConstraints() { return isAssignableFrom(TextView.class); } @Override public String getDescription() { return "getting text from a TextView"; } @Override public void perform(UiController uiController, View view) { TextView textView = (TextView) view; stringHolder[0] = textView.getText().toString(); } }); return stringHolder[0]; } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/interactions/ActionableObject.java ================================================ package com.mauriciotogneri.greencoffee.interactions; import android.support.test.espresso.ViewAction; import android.support.test.espresso.ViewAssertion; import android.support.test.espresso.action.ViewActions; import android.support.test.espresso.assertion.ViewAssertions; import android.support.test.espresso.matcher.BoundedMatcher; import android.support.test.espresso.matcher.ViewMatchers; import android.view.View; import android.widget.ImageView; import org.hamcrest.Description; import org.hamcrest.Matchers; public abstract class ActionableObject { public ActionableObject click() { return perform(ViewActions.click()); } public ActionableObject doubleClick() { return perform(ViewActions.doubleClick()); } public ActionableObject longClick() { return perform(ViewActions.longClick()); } public ActionableObject type(String text) { return perform(ViewActions.typeText(text)); } public ActionableObject clearText() { return perform(ViewActions.clearText()); } public ActionableObject scrollTo() { return perform(ViewActions.scrollTo()); } public ActionableObject swipeUp() { return perform(ViewActions.swipeUp()); } public ActionableObject swipeDown() { return perform(ViewActions.swipeDown()); } public ActionableObject swipeLeft() { return perform(ViewActions.swipeLeft()); } public ActionableObject swipeRight() { return perform(ViewActions.swipeRight()); } public ActionableObject doesNotExist() { return check(ViewAssertions.doesNotExist()); } public boolean checkIfDoesNotExist() { return checkIf(this::doesNotExist); } public ActionableObject contains(Object text) { return check(ViewAssertions.matches(ViewMatchers.withText(Matchers.containsString(text.toString())))); } public boolean checkIfContains(Object text) { return checkIf(() -> contains(text)); } public ActionableObject doesNotContain(Object text) { return check(ViewAssertions.matches(ViewMatchers.withText(Matchers.not(Matchers.containsString(text.toString()))))); } public boolean checkIfDoesNotContain(Object text) { return checkIf(() -> doesNotContain(text)); } public ActionableObject isEmpty() { return check(ViewAssertions.matches(ViewMatchers.withText(""))); } public boolean checkIfIsEmpty() { return checkIf(this::isEmpty); } public ActionableObject isNotEmpty() { return check(ViewAssertions.matches(Matchers.not(ViewMatchers.withText("")))); } public boolean checkIfIsNotEmpty() { return checkIf(this::isNotEmpty); } public ActionableObject hasFocus() { return check(ViewAssertions.matches(ViewMatchers.hasFocus())); } public boolean checkIfHasFocus() { return checkIf(this::hasFocus); } public ActionableObject doesNotHaveFocus() { return check(ViewAssertions.matches(Matchers.not(ViewMatchers.hasFocus()))); } public boolean checkIfDoesNotHaveFocus() { return checkIf(this::doesNotHaveFocus); } public ActionableObject hasErrorText(Object text) { return check(ViewAssertions.matches(ViewMatchers.hasErrorText(text.toString()))); } public boolean checkIfHasErrorText(Object text) { return checkIf(() -> hasErrorText(text)); } public ActionableObject isChecked() { return check(ViewAssertions.matches(ViewMatchers.isChecked())); } public boolean checkIfIsChecked() { return checkIf(this::isChecked); } public ActionableObject isNotChecked() { return check(ViewAssertions.matches(ViewMatchers.isNotChecked())); } public boolean checkIfIsNotChecked() { return checkIf(this::isNotChecked); } public ActionableObject isClickable() { return check(ViewAssertions.matches(ViewMatchers.isClickable())); } public boolean checkIfIsClickable() { return checkIf(this::isClickable); } public ActionableObject isFocusable() { return check(ViewAssertions.matches(ViewMatchers.isFocusable())); } public boolean checkIfIsFocusable() { return checkIf(this::isFocusable); } public ActionableObject isNotFocusable() { return check(ViewAssertions.matches(Matchers.not(ViewMatchers.isFocusable()))); } public boolean checkIfIsNotFocusable() { return checkIf(this::isNotFocusable); } public ActionableObject isEnabled() { return check(ViewAssertions.matches(ViewMatchers.isEnabled())); } public boolean checkIfIsEnabled() { return checkIf(this::isEnabled); } public ActionableObject isDisabled() { return check(ViewAssertions.matches(Matchers.not(ViewMatchers.isEnabled()))); } public boolean checkIfIsDisabled() { return checkIf(this::isDisabled); } public ActionableObject isSelected() { return check(ViewAssertions.matches(ViewMatchers.isSelected())); } public boolean checkIfIsSelected() { return checkIf(this::isSelected); } public ActionableObject isNotSelected() { return check(ViewAssertions.matches(Matchers.not(ViewMatchers.isSelected()))); } public boolean checkIfIsNotSelected() { return checkIf(this::isNotSelected); } public ActionableObject isDisplayed() { return check(ViewAssertions.matches(ViewMatchers.isDisplayed())); } public boolean checkIfIsDisplayed() { return checkIf(this::isDisplayed); } public ActionableObject isCompletelyDisplayed() { return check(ViewAssertions.matches(ViewMatchers.isCompletelyDisplayed())); } public boolean checkIfIsCompletelyDisplayed() { return checkIf(this::isCompletelyDisplayed); } public ActionableObject isNotDisplayed() { return check(ViewAssertions.matches(Matchers.not(ViewMatchers.isDisplayed()))); } public boolean checkIfIsNotDisplayed() { return checkIf(this::isNotDisplayed); } public ActionableObject hasDrawable() { return check(ViewAssertions.matches(hasDrawableImageView())); } public boolean checkIfHasDrawable() { return checkIf(this::hasDrawable); } public ActionableObject doesNotHaveDrawable() { return check(ViewAssertions.matches(Matchers.not(hasDrawableImageView()))); } public boolean checkIfDoesNotHaveDrawable() { return checkIf(this::doesNotHaveDrawable); } public abstract ActionableObject check(ViewAssertion viewAssertion); public abstract ActionableObject perform(ViewAction viewAction); public abstract String text(); private boolean checkIf(Runnable runnable) { try { runnable.run(); return true; } catch (Exception e) { return false; } } public BoundedMatcher hasDrawableImageView() { return new BoundedMatcher(ImageView.class) { @Override public void describeTo(Description description) { description.appendText("has drawable"); } @Override public boolean matchesSafely(ImageView imageView) { return (imageView.getDrawable() != null); } }; } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/interactions/ActionableView.java ================================================ package com.mauriciotogneri.greencoffee.interactions; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.espresso.ViewAssertion; import android.support.test.espresso.ViewInteraction; import android.view.View; import android.widget.TextView; import org.hamcrest.Matcher; import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; public class ActionableView extends ActionableObject { private final ViewInteraction viewInteraction; public ActionableView(ViewInteraction viewInteraction) { this.viewInteraction = viewInteraction; } @Override public ActionableObject check(ViewAssertion viewAssertion) { return new ActionableView(viewInteraction.check(viewAssertion)); } @Override public ActionableObject perform(ViewAction viewAction) { return new ActionableView(viewInteraction.perform(viewAction)); } @Override public String text() { String[] stringHolder = {null}; viewInteraction.perform(new ViewAction() { @Override public Matcher getConstraints() { return isAssignableFrom(TextView.class); } @Override public String getDescription() { return "getting text from a TextView"; } @Override public void perform(UiController uiController, View view) { TextView textView = (TextView) view; stringHolder[0] = textView.getText().toString(); } }); return stringHolder[0]; } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/interactions/DataMatcher.java ================================================ package com.mauriciotogneri.greencoffee.interactions; import android.support.annotation.IdRes; import android.support.test.espresso.DataInteraction; import android.support.test.espresso.matcher.BoundedMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; import static android.support.test.espresso.Espresso.onData; import static android.support.test.espresso.matcher.ViewMatchers.withId; public class DataMatcher { private final int resourceId; private final Class clazz; public DataMatcher(@IdRes int resourceId, Class clazz) { this.resourceId = resourceId; this.clazz = clazz; } public DataMatcher(Class clazz) { this(0, clazz); } public ActionableData with(C content) { DataInteraction dataInteraction = onData(dataMatcher(content)); if (resourceId != 0) { return new ActionableData(dataInteraction.inAdapterView(withId(resourceId))); } else { return new ActionableData(dataInteraction); } } private Matcher dataMatcher(C content) { DataMatcher dataMatcher = this; return new BoundedMatcher(clazz) { @Override public boolean matchesSafely(T data) { return dataMatcher.matches(data, content); } @Override public void describeTo(Description description) { description.appendText(String.format("with content: '%s'", content)); } }; } public boolean matches(T element, C content) { return element.equals(content); } } ================================================ FILE: greencoffee/src/main/java/com/mauriciotogneri/greencoffee/interactions/ObjectMatcher.java ================================================ package com.mauriciotogneri.greencoffee.interactions; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; public class ObjectMatcher extends BaseMatcher { private final T element; public ObjectMatcher(T element) { this.element = element; } @Override public boolean matches(Object object) { return element.equals(object); } @Override public void describeTo(Description description) { description.appendText("Spinner matcher for: " + element); } } ================================================ FILE: greencoffee/src/main/java/gherkin/AstBuilder.java ================================================ package gherkin; import gherkin.ast.Background; import gherkin.ast.Comment; import gherkin.ast.DataTable; import gherkin.ast.DocString; import gherkin.ast.Examples; import gherkin.ast.Feature; import gherkin.ast.GherkinDocument; import gherkin.ast.Location; import gherkin.ast.Node; import gherkin.ast.Scenario; import gherkin.ast.ScenarioDefinition; import gherkin.ast.ScenarioOutline; import gherkin.ast.Step; import gherkin.ast.TableCell; import gherkin.ast.TableRow; import gherkin.ast.Tag; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; import static gherkin.Parser.Builder; import static gherkin.Parser.RuleType; import static gherkin.Parser.TokenType; import static gherkin.StringUtils.join; public class AstBuilder implements Builder { private Deque stack; private List comments; public AstBuilder() { reset(); } @Override public void reset() { stack = new ArrayDeque<>(); stack.push(new AstNode(RuleType.None)); comments = new ArrayList<>(); } private AstNode currentNode() { return stack.peek(); } @Override public void build(Token token) { RuleType ruleType = RuleType.cast(token.matchedType); if (token.matchedType == TokenType.Comment) { comments.add(new Comment(getLocation(token, 0), token.matchedText)); } else { currentNode().add(ruleType, token); } } @Override public void startRule(RuleType ruleType) { stack.push(new AstNode(ruleType)); } @Override public void endRule(RuleType ruleType) { AstNode node = stack.pop(); Object transformedNode = getTransformedNode(node); currentNode().add(node.ruleType, transformedNode); } private Object getTransformedNode(AstNode node) { switch (node.ruleType) { case Step: { Token stepLine = node.getToken(TokenType.StepLine); Node stepArg = node.getSingle(RuleType.DataTable, null); if (stepArg == null) { stepArg = node.getSingle(RuleType.DocString, null); } return new Step(getLocation(stepLine, 0), stepLine.matchedKeyword, stepLine.matchedText, stepArg); } case DocString: { Token separatorToken = node.getTokens(TokenType.DocStringSeparator).get(0); String contentType = separatorToken.matchedText.length() > 0 ? separatorToken.matchedText : null; List lineTokens = node.getTokens(TokenType.Other); StringBuilder content = new StringBuilder(); boolean newLine = false; for (Token lineToken : lineTokens) { if (newLine) content.append("\n"); newLine = true; content.append(lineToken.matchedText); } return new DocString(getLocation(separatorToken, 0), contentType, content.toString()); } case DataTable: { List rows = getTableRows(node); return new DataTable(rows); } case Background: { Token backgroundLine = node.getToken(TokenType.BackgroundLine); String description = getDescription(node); List steps = getSteps(node); return new Background(getLocation(backgroundLine, 0), backgroundLine.matchedKeyword, backgroundLine.matchedText, description, steps); } case Scenario_Definition: { List tags = getTags(node); AstNode scenarioNode = node.getSingle(RuleType.Scenario, null); if (scenarioNode != null) { Token scenarioLine = scenarioNode.getToken(TokenType.ScenarioLine); String description = getDescription(scenarioNode); List steps = getSteps(scenarioNode); return new Scenario(tags, getLocation(scenarioLine, 0), scenarioLine.matchedKeyword, scenarioLine.matchedText, description, steps); } else { AstNode scenarioOutlineNode = node.getSingle(RuleType.ScenarioOutline, null); if (scenarioOutlineNode == null) { throw new RuntimeException("Internal grammar error"); } Token scenarioOutlineLine = scenarioOutlineNode.getToken(TokenType.ScenarioOutlineLine); String description = getDescription(scenarioOutlineNode); List steps = getSteps(scenarioOutlineNode); List examplesList = scenarioOutlineNode.getItems(RuleType.Examples_Definition); return new ScenarioOutline(tags, getLocation(scenarioOutlineLine, 0), scenarioOutlineLine.matchedKeyword, scenarioOutlineLine.matchedText, description, steps, examplesList); } } case Examples_Definition: { List tags = getTags(node); AstNode examplesNode = node.getSingle(RuleType.Examples, null); Token examplesLine = examplesNode.getToken(TokenType.ExamplesLine); String description = getDescription(examplesNode); List rows = examplesNode.getSingle(RuleType.Examples_Table, null); TableRow tableHeader = rows != null && !rows.isEmpty() ? rows.get(0) : null; List tableBody = rows != null && !rows.isEmpty() ? rows.subList(1, rows.size()) : null; return new Examples(getLocation(examplesLine, 0), tags, examplesLine.matchedKeyword, examplesLine.matchedText, description, tableHeader, tableBody); } case Examples_Table: { return getTableRows(node); } case Description: { List lineTokens = node.getTokens(TokenType.Other); // Trim trailing empty lines int end = lineTokens.size(); while (end > 0 && lineTokens.get(end - 1).matchedText.matches("\\s*")) { end--; } lineTokens = lineTokens.subList(0, end); return join(new StringUtils.ToString() { @Override public String toString(Token t) { return t.matchedText; } }, "\n", lineTokens); } case Feature: { AstNode header = node.getSingle(RuleType.Feature_Header, new AstNode(RuleType.Feature_Header)); if (header == null) return null; List tags = getTags(header); Token featureLine = header.getToken(TokenType.FeatureLine); if (featureLine == null) return null; List scenarioDefinitions = new ArrayList<>(); Background background = node.getSingle(RuleType.Background, null); if (background != null) scenarioDefinitions.add(background); scenarioDefinitions.addAll(node.getItems(RuleType.Scenario_Definition)); String description = getDescription(header); if (featureLine.matchedGherkinDialect == null) return null; String language = featureLine.matchedGherkinDialect.getLanguage(); return new Feature(tags, getLocation(featureLine, 0), language, featureLine.matchedKeyword, featureLine.matchedText, description, scenarioDefinitions); } case GherkinDocument: { Feature feature = node.getSingle(RuleType.Feature, null); return new GherkinDocument(feature, comments); } } return node; } private List getTableRows(AstNode node) { List rows = new ArrayList<>(); for (Token token : node.getTokens(TokenType.TableRow)) { rows.add(new TableRow(getLocation(token, 0), getCells(token))); } ensureCellCount(rows); return rows; } private void ensureCellCount(List rows) { if (rows.isEmpty()) return; int cellCount = rows.get(0).getCells().size(); for (TableRow row : rows) { if (row.getCells().size() != cellCount) { throw new ParserException.AstBuilderException("inconsistent cell count within the table", row.getLocation()); } } } private List getCells(Token token) { List cells = new ArrayList<>(); for (GherkinLineSpan cellItem : token.mathcedItems) { cells.add(new TableCell(getLocation(token, cellItem.column), cellItem.text)); } return cells; } private List getSteps(AstNode node) { return node.getItems(RuleType.Step); } private Location getLocation(Token token, int column) { return column == 0 ? token.location : new Location(token.location.getLine(), column); } private String getDescription(AstNode node) { return node.getSingle(RuleType.Description, null); } private List getTags(AstNode node) { AstNode tagsNode = node.getSingle(RuleType.Tags, new AstNode(RuleType.None)); if (tagsNode == null) return new ArrayList<>(); List tokens = tagsNode.getTokens(TokenType.TagLine); List tags = new ArrayList<>(); for (Token token : tokens) { for (GherkinLineSpan tagItem : token.mathcedItems) { tags.add(new Tag(getLocation(token, tagItem.column), tagItem.text)); } } return tags; } @Override public GherkinDocument getResult() { return currentNode().getSingle(RuleType.GherkinDocument, null); } } ================================================ FILE: greencoffee/src/main/java/gherkin/AstNode.java ================================================ package gherkin; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import static gherkin.Parser.RuleType; import static gherkin.Parser.TokenType; public class AstNode { private final Map> subItems = new HashMap>(); public final RuleType ruleType; public AstNode(RuleType ruleType) { this.ruleType = ruleType; } public void add(RuleType ruleType, Object obj) { List items = subItems.get(ruleType); if (items == null) { items = new ArrayList(); subItems.put(ruleType, items); } items.add(obj); } public T getSingle(RuleType ruleType, T defaultResult) { List items = getItems(ruleType); return (T) (items.isEmpty() ? defaultResult : items.get(0)); } public List getItems(RuleType ruleType) { List items = (List) subItems.get(ruleType); if (items == null) { return Collections.emptyList(); } return items; } public Token getToken(TokenType tokenType) { RuleType ruleType = RuleType.cast(tokenType); return getSingle(ruleType, new Token(null, null)); } public List getTokens(TokenType tokenType) { return getItems(RuleType.cast(tokenType)); } } ================================================ FILE: greencoffee/src/main/java/gherkin/Func.java ================================================ package gherkin; public interface Func { V call(); } ================================================ FILE: greencoffee/src/main/java/gherkin/GenerateTokens.java ================================================ package gherkin; import gherkin.stream.Stdio; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; public class GenerateTokens { public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException { TokenFormatterBuilder builder = new TokenFormatterBuilder(); Parser parser = new Parser<>(builder); TokenMatcher matcher = new TokenMatcher(); for (String fileName : args) { InputStreamReader in = new InputStreamReader(new FileInputStream(fileName), "UTF-8"); String result = parser.parse(in, matcher); Stdio.out.print(result); Stdio.out.flush(); // print doesn't autoflush } } } ================================================ FILE: greencoffee/src/main/java/gherkin/GherkinDialect.java ================================================ package gherkin; import java.util.ArrayList; import java.util.List; import java.util.Map; public class GherkinDialect { private final Map> keywords; private String language; public GherkinDialect(String language, Map> keywords) { this.language = language; this.keywords = keywords; } public List getFeatureKeywords() { return keywords.get("feature"); } public List getScenarioKeywords() { return keywords.get("scenario"); } public List getStepKeywords() { List result = new ArrayList<>(); result.addAll(keywords.get("given")); result.addAll(keywords.get("when")); result.addAll(keywords.get("then")); result.addAll(keywords.get("and")); result.addAll(keywords.get("but")); return result; } public List getBackgroundKeywords() { return keywords.get("background"); } public List getScenarioOutlineKeywords() { return keywords.get("scenarioOutline"); } public List getExamplesKeywords() { return keywords.get("examples"); } public String getLanguage() { return language; } } ================================================ FILE: greencoffee/src/main/java/gherkin/GherkinDialectProvider.java ================================================ package gherkin; import java.util.List; import java.util.Map; import gherkin.ast.Location; import gherkin.deps.com.google.gson.Gson; public class GherkinDialectProvider implements IGherkinDialectProvider { private static Map>> DIALECTS; private final String default_dialect_name; static { Gson gson = new Gson(); try { //Reader dialects = new InputStreamReader(GherkinDialectProvider.class.getResourceAsStream("/gherkin/gherkin-languages.json"), "UTF-8"); String dialects = "{\n" + " \"af\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"En \"\n" + " ],\n" + " \"background\": [\n" + " \"Agtergrond\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Maar \"\n" + " ],\n" + " \"examples\": [\n" + " \"Voorbeelde\"\n" + " ],\n" + " \"feature\": [\n" + " \"Funksie\",\n" + " \"Besigheid Behoefte\",\n" + " \"Vermoë\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Gegewe \"\n" + " ],\n" + " \"name\": \"Afrikaans\",\n" + " \"native\": \"Afrikaans\",\n" + " \"scenario\": [\n" + " \"Situasie\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Situasie Uiteensetting\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Dan \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Wanneer \"\n" + " ]\n" + " },\n" + " \"am\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Եվ \"\n" + " ],\n" + " \"background\": [\n" + " \"Կոնտեքստ\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Բայց \"\n" + " ],\n" + " \"examples\": [\n" + " \"Օրինակներ\"\n" + " ],\n" + " \"feature\": [\n" + " \"Ֆունկցիոնալություն\",\n" + " \"Հատկություն\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Դիցուք \"\n" + " ],\n" + " \"name\": \"Armenian\",\n" + " \"native\": \"հայերեն\",\n" + " \"scenario\": [\n" + " \"Սցենար\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Սցենարի կառուցվացքը\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Ապա \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Եթե \",\n" + " \"Երբ \"\n" + " ]\n" + " },\n" + " \"ar\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"و \"\n" + " ],\n" + " \"background\": [\n" + " \"الخلفية\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"لكن \"\n" + " ],\n" + " \"examples\": [\n" + " \"امثلة\"\n" + " ],\n" + " \"feature\": [\n" + " \"خاصية\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"بفرض \"\n" + " ],\n" + " \"name\": \"Arabic\",\n" + " \"native\": \"العربية\",\n" + " \"scenario\": [\n" + " \"سيناريو\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"سيناريو مخطط\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"اذاً \",\n" + " \"ثم \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"متى \",\n" + " \"عندما \"\n" + " ]\n" + " },\n" + " \"ast\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Y \",\n" + " \"Ya \"\n" + " ],\n" + " \"background\": [\n" + " \"Antecedentes\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Peru \"\n" + " ],\n" + " \"examples\": [\n" + " \"Exemplos\"\n" + " ],\n" + " \"feature\": [\n" + " \"Carauterística\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Dáu \",\n" + " \"Dada \",\n" + " \"Daos \",\n" + " \"Daes \"\n" + " ],\n" + " \"name\": \"Asturian\",\n" + " \"native\": \"asturianu\",\n" + " \"scenario\": [\n" + " \"Casu\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Esbozu del casu\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Entós \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Cuando \"\n" + " ]\n" + " },\n" + " \"az\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Və \",\n" + " \"Həm \"\n" + " ],\n" + " \"background\": [\n" + " \"Keçmiş\",\n" + " \"Kontekst\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Amma \",\n" + " \"Ancaq \"\n" + " ],\n" + " \"examples\": [\n" + " \"Nümunələr\"\n" + " ],\n" + " \"feature\": [\n" + " \"Özəllik\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Tutaq ki \",\n" + " \"Verilir \"\n" + " ],\n" + " \"name\": \"Azerbaijani\",\n" + " \"native\": \"Azərbaycanca\",\n" + " \"scenario\": [\n" + " \"Ssenari\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Ssenarinin strukturu\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"O halda \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Əgər \",\n" + " \"Nə vaxt ki \"\n" + " ]\n" + " },\n" + " \"bg\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"И \"\n" + " ],\n" + " \"background\": [\n" + " \"Предистория\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Но \"\n" + " ],\n" + " \"examples\": [\n" + " \"Примери\"\n" + " ],\n" + " \"feature\": [\n" + " \"Функционалност\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Дадено \"\n" + " ],\n" + " \"name\": \"Bulgarian\",\n" + " \"native\": \"български\",\n" + " \"scenario\": [\n" + " \"Сценарий\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Рамка на сценарий\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"То \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Когато \"\n" + " ]\n" + " },\n" + " \"bm\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Dan \"\n" + " ],\n" + " \"background\": [\n" + " \"Latar Belakang\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Tetapi \",\n" + " \"Tapi \"\n" + " ],\n" + " \"examples\": [\n" + " \"Contoh\"\n" + " ],\n" + " \"feature\": [\n" + " \"Fungsi\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Diberi \",\n" + " \"Bagi \"\n" + " ],\n" + " \"name\": \"Malay\",\n" + " \"native\": \"Bahasa Melayu\",\n" + " \"scenario\": [\n" + " \"Senario\",\n" + " \"Situasi\",\n" + " \"Keadaan\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Kerangka Senario\",\n" + " \"Kerangka Situasi\",\n" + " \"Kerangka Keadaan\",\n" + " \"Garis Panduan Senario\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Maka \",\n" + " \"Kemudian \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Apabila \"\n" + " ]\n" + " },\n" + " \"bs\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"I \",\n" + " \"A \"\n" + " ],\n" + " \"background\": [\n" + " \"Pozadina\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Ali \"\n" + " ],\n" + " \"examples\": [\n" + " \"Primjeri\"\n" + " ],\n" + " \"feature\": [\n" + " \"Karakteristika\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Dato \"\n" + " ],\n" + " \"name\": \"Bosnian\",\n" + " \"native\": \"Bosanski\",\n" + " \"scenario\": [\n" + " \"Scenariju\",\n" + " \"Scenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Scenariju-obris\",\n" + " \"Scenario-outline\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Zatim \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Kada \"\n" + " ]\n" + " },\n" + " \"ca\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"I \"\n" + " ],\n" + " \"background\": [\n" + " \"Rerefons\",\n" + " \"Antecedents\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Però \"\n" + " ],\n" + " \"examples\": [\n" + " \"Exemples\"\n" + " ],\n" + " \"feature\": [\n" + " \"Característica\",\n" + " \"Funcionalitat\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Donat \",\n" + " \"Donada \",\n" + " \"Atès \",\n" + " \"Atesa \"\n" + " ],\n" + " \"name\": \"Catalan\",\n" + " \"native\": \"català\",\n" + " \"scenario\": [\n" + " \"Escenari\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Esquema de l'escenari\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Aleshores \",\n" + " \"Cal \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Quan \"\n" + " ]\n" + " },\n" + " \"cs\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"A také \",\n" + " \"A \"\n" + " ],\n" + " \"background\": [\n" + " \"Pozadí\",\n" + " \"Kontext\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Ale \"\n" + " ],\n" + " \"examples\": [\n" + " \"Příklady\"\n" + " ],\n" + " \"feature\": [\n" + " \"Požadavek\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Pokud \",\n" + " \"Za předpokladu \"\n" + " ],\n" + " \"name\": \"Czech\",\n" + " \"native\": \"Česky\",\n" + " \"scenario\": [\n" + " \"Scénář\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Náčrt Scénáře\",\n" + " \"Osnova scénáře\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Pak \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Když \"\n" + " ]\n" + " },\n" + " \"cy-GB\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"A \"\n" + " ],\n" + " \"background\": [\n" + " \"Cefndir\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Ond \"\n" + " ],\n" + " \"examples\": [\n" + " \"Enghreifftiau\"\n" + " ],\n" + " \"feature\": [\n" + " \"Arwedd\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Anrhegedig a \"\n" + " ],\n" + " \"name\": \"Welsh\",\n" + " \"native\": \"Cymraeg\",\n" + " \"scenario\": [\n" + " \"Scenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Scenario Amlinellol\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Yna \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Pryd \"\n" + " ]\n" + " },\n" + " \"da\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Og \"\n" + " ],\n" + " \"background\": [\n" + " \"Baggrund\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Men \"\n" + " ],\n" + " \"examples\": [\n" + " \"Eksempler\"\n" + " ],\n" + " \"feature\": [\n" + " \"Egenskab\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Givet \"\n" + " ],\n" + " \"name\": \"Danish\",\n" + " \"native\": \"dansk\",\n" + " \"scenario\": [\n" + " \"Scenarie\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Abstrakt Scenario\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Så \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Når \"\n" + " ]\n" + " },\n" + " \"de\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Und \"\n" + " ],\n" + " \"background\": [\n" + " \"Grundlage\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Aber \"\n" + " ],\n" + " \"examples\": [\n" + " \"Beispiele\"\n" + " ],\n" + " \"feature\": [\n" + " \"Funktionalität\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Angenommen \",\n" + " \"Gegeben sei \",\n" + " \"Gegeben seien \"\n" + " ],\n" + " \"name\": \"German\",\n" + " \"native\": \"Deutsch\",\n" + " \"scenario\": [\n" + " \"Szenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Szenariogrundriss\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Dann \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Wenn \"\n" + " ]\n" + " },\n" + " \"el\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Και \"\n" + " ],\n" + " \"background\": [\n" + " \"Υπόβαθρο\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Αλλά \"\n" + " ],\n" + " \"examples\": [\n" + " \"Παραδείγματα\",\n" + " \"Σενάρια\"\n" + " ],\n" + " \"feature\": [\n" + " \"Δυνατότητα\",\n" + " \"Λειτουργία\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Δεδομένου \"\n" + " ],\n" + " \"name\": \"Greek\",\n" + " \"native\": \"Ελληνικά\",\n" + " \"scenario\": [\n" + " \"Σενάριο\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Περιγραφή Σεναρίου\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Τότε \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Όταν \"\n" + " ]\n" + " },\n" + " \"em\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"\uD83D\uDE02\"\n" + " ],\n" + " \"background\": [\n" + " \"\uD83D\uDCA4\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"\uD83D\uDE14\"\n" + " ],\n" + " \"examples\": [\n" + " \"\uD83D\uDCD3\"\n" + " ],\n" + " \"feature\": [\n" + " \"\uD83D\uDCDA\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"\uD83D\uDE10\"\n" + " ],\n" + " \"name\": \"Emoji\",\n" + " \"native\": \"\uD83D\uDE00\",\n" + " \"scenario\": [\n" + " \"\uD83D\uDCD5\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"\uD83D\uDCD6\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"\uD83D\uDE4F\"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"\uD83C\uDFAC\"\n" + " ]\n" + " },\n" + " \"en\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"And \"\n" + " ],\n" + " \"background\": [\n" + " \"Background\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"But \"\n" + " ],\n" + " \"examples\": [\n" + " \"Examples\",\n" + " \"Scenarios\"\n" + " ],\n" + " \"feature\": [\n" + " \"Feature\",\n" + " \"Business Need\",\n" + " \"Ability\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Given \"\n" + " ],\n" + " \"name\": \"English\",\n" + " \"native\": \"English\",\n" + " \"scenario\": [\n" + " \"Scenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Scenario Outline\",\n" + " \"Scenario Template\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Then \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"When \"\n" + " ]\n" + " },\n" + " \"en-Scouse\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"An \"\n" + " ],\n" + " \"background\": [\n" + " \"Dis is what went down\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Buh \"\n" + " ],\n" + " \"examples\": [\n" + " \"Examples\"\n" + " ],\n" + " \"feature\": [\n" + " \"Feature\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Givun \",\n" + " \"Youse know when youse got \"\n" + " ],\n" + " \"name\": \"Scouse\",\n" + " \"native\": \"Scouse\",\n" + " \"scenario\": [\n" + " \"The thing of it is\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Wharrimean is\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Dun \",\n" + " \"Den youse gotta \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Wun \",\n" + " \"Youse know like when \"\n" + " ]\n" + " },\n" + " \"en-au\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Too right \"\n" + " ],\n" + " \"background\": [\n" + " \"First off\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Yeah nah \"\n" + " ],\n" + " \"examples\": [\n" + " \"You'll wanna\"\n" + " ],\n" + " \"feature\": [\n" + " \"Pretty much\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Y'know \"\n" + " ],\n" + " \"name\": \"Australian\",\n" + " \"native\": \"Australian\",\n" + " \"scenario\": [\n" + " \"Awww, look mate\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Reckon it's like\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"But at the end of the day I reckon \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"It's just unbelievable \"\n" + " ]\n" + " },\n" + " \"en-lol\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"AN \"\n" + " ],\n" + " \"background\": [\n" + " \"B4\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"BUT \"\n" + " ],\n" + " \"examples\": [\n" + " \"EXAMPLZ\"\n" + " ],\n" + " \"feature\": [\n" + " \"OH HAI\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"I CAN HAZ \"\n" + " ],\n" + " \"name\": \"LOLCAT\",\n" + " \"native\": \"LOLCAT\",\n" + " \"scenario\": [\n" + " \"MISHUN\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"MISHUN SRSLY\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"DEN \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"WEN \"\n" + " ]\n" + " },\n" + " \"en-old\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Ond \",\n" + " \"7 \"\n" + " ],\n" + " \"background\": [\n" + " \"Aer\",\n" + " \"Ær\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Ac \"\n" + " ],\n" + " \"examples\": [\n" + " \"Se the\",\n" + " \"Se þe\",\n" + " \"Se ðe\"\n" + " ],\n" + " \"feature\": [\n" + " \"Hwaet\",\n" + " \"Hwæt\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Thurh \",\n" + " \"Þurh \",\n" + " \"Ðurh \"\n" + " ],\n" + " \"name\": \"Old English\",\n" + " \"native\": \"Englisc\",\n" + " \"scenario\": [\n" + " \"Swa\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Swa hwaer swa\",\n" + " \"Swa hwær swa\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Tha \",\n" + " \"Þa \",\n" + " \"Ða \",\n" + " \"Tha the \",\n" + " \"Þa þe \",\n" + " \"Ða ðe \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Tha \",\n" + " \"Þa \",\n" + " \"Ða \"\n" + " ]\n" + " },\n" + " \"en-pirate\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Aye \"\n" + " ],\n" + " \"background\": [\n" + " \"Yo-ho-ho\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Avast! \"\n" + " ],\n" + " \"examples\": [\n" + " \"Dead men tell no tales\"\n" + " ],\n" + " \"feature\": [\n" + " \"Ahoy matey!\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Gangway! \"\n" + " ],\n" + " \"name\": \"Pirate\",\n" + " \"native\": \"Pirate\",\n" + " \"scenario\": [\n" + " \"Heave to\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Shiver me timbers\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Let go and haul \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Blimey! \"\n" + " ]\n" + " },\n" + " \"eo\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Kaj \"\n" + " ],\n" + " \"background\": [\n" + " \"Fono\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Sed \"\n" + " ],\n" + " \"examples\": [\n" + " \"Ekzemploj\"\n" + " ],\n" + " \"feature\": [\n" + " \"Trajto\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Donitaĵo \",\n" + " \"Komence \"\n" + " ],\n" + " \"name\": \"Esperanto\",\n" + " \"native\": \"Esperanto\",\n" + " \"scenario\": [\n" + " \"Scenaro\",\n" + " \"Kazo\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Konturo de la scenaro\",\n" + " \"Skizo\",\n" + " \"Kazo-skizo\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Do \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Se \"\n" + " ]\n" + " },\n" + " \"es\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Y \",\n" + " \"E \"\n" + " ],\n" + " \"background\": [\n" + " \"Antecedentes\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Pero \"\n" + " ],\n" + " \"examples\": [\n" + " \"Ejemplos\"\n" + " ],\n" + " \"feature\": [\n" + " \"Característica\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Dado \",\n" + " \"Dada \",\n" + " \"Dados \",\n" + " \"Dadas \"\n" + " ],\n" + " \"name\": \"Spanish\",\n" + " \"native\": \"español\",\n" + " \"scenario\": [\n" + " \"Escenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Esquema del escenario\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Entonces \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Cuando \"\n" + " ]\n" + " },\n" + " \"et\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Ja \"\n" + " ],\n" + " \"background\": [\n" + " \"Taust\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Kuid \"\n" + " ],\n" + " \"examples\": [\n" + " \"Juhtumid\"\n" + " ],\n" + " \"feature\": [\n" + " \"Omadus\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Eeldades \"\n" + " ],\n" + " \"name\": \"Estonian\",\n" + " \"native\": \"eesti keel\",\n" + " \"scenario\": [\n" + " \"Stsenaarium\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Raamstsenaarium\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Siis \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Kui \"\n" + " ]\n" + " },\n" + " \"fa\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"و \"\n" + " ],\n" + " \"background\": [\n" + " \"زمینه\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"اما \"\n" + " ],\n" + " \"examples\": [\n" + " \"نمونه ها\"\n" + " ],\n" + " \"feature\": [\n" + " \"وِیژگی\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"با فرض \"\n" + " ],\n" + " \"name\": \"Persian\",\n" + " \"native\": \"فارسی\",\n" + " \"scenario\": [\n" + " \"سناریو\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"الگوی سناریو\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"آنگاه \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"هنگامی \"\n" + " ]\n" + " },\n" + " \"fi\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Ja \"\n" + " ],\n" + " \"background\": [\n" + " \"Tausta\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Mutta \"\n" + " ],\n" + " \"examples\": [\n" + " \"Tapaukset\"\n" + " ],\n" + " \"feature\": [\n" + " \"Ominaisuus\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Oletetaan \"\n" + " ],\n" + " \"name\": \"Finnish\",\n" + " \"native\": \"suomi\",\n" + " \"scenario\": [\n" + " \"Tapaus\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Tapausaihio\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Niin \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Kun \"\n" + " ]\n" + " },\n" + " \"fr\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Et que \",\n" + " \"Et qu'\",\n" + " \"Et \"\n" + " ],\n" + " \"background\": [\n" + " \"Contexte\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Mais que \",\n" + " \"Mais qu'\",\n" + " \"Mais \"\n" + " ],\n" + " \"examples\": [\n" + " \"Exemples\"\n" + " ],\n" + " \"feature\": [\n" + " \"Fonctionnalité\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Soit \",\n" + " \"Etant donné que \",\n" + " \"Etant donné qu'\",\n" + " \"Etant donné \",\n" + " \"Etant donnée \",\n" + " \"Etant donnés \",\n" + " \"Etant données \",\n" + " \"Étant donné que \",\n" + " \"Étant donné qu'\",\n" + " \"Étant donné \",\n" + " \"Étant donnée \",\n" + " \"Étant donnés \",\n" + " \"Étant données \"\n" + " ],\n" + " \"name\": \"French\",\n" + " \"native\": \"français\",\n" + " \"scenario\": [\n" + " \"Scénario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Plan du scénario\",\n" + " \"Plan du Scénario\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Alors \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Quand \",\n" + " \"Lorsque \",\n" + " \"Lorsqu'\"\n" + " ]\n" + " },\n" + " \"ga\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Agus\"\n" + " ],\n" + " \"background\": [\n" + " \"Cúlra\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Ach\"\n" + " ],\n" + " \"examples\": [\n" + " \"Samplaí\"\n" + " ],\n" + " \"feature\": [\n" + " \"Gné\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Cuir i gcás go\",\n" + " \"Cuir i gcás nach\",\n" + " \"Cuir i gcás gur\",\n" + " \"Cuir i gcás nár\"\n" + " ],\n" + " \"name\": \"Irish\",\n" + " \"native\": \"Gaeilge\",\n" + " \"scenario\": [\n" + " \"Cás\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Cás Achomair\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Ansin\"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Nuair a\",\n" + " \"Nuair nach\",\n" + " \"Nuair ba\",\n" + " \"Nuair nár\"\n" + " ]\n" + " },\n" + " \"gj\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"અને \"\n" + " ],\n" + " \"background\": [\n" + " \"બેકગ્રાઉન્ડ\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"પણ \"\n" + " ],\n" + " \"examples\": [\n" + " \"ઉદાહરણો\"\n" + " ],\n" + " \"feature\": [\n" + " \"લક્ષણ\",\n" + " \"વ્યાપાર જરૂર\",\n" + " \"ક્ષમતા\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"આપેલ છે \"\n" + " ],\n" + " \"name\": \"Gujarati\",\n" + " \"native\": \"ગુજરાતી\",\n" + " \"scenario\": [\n" + " \"સ્થિતિ\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"પરિદ્દશ્ય રૂપરેખા\",\n" + " \"પરિદ્દશ્ય ઢાંચો\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"પછી \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"ક્યારે \"\n" + " ]\n" + " },\n" + " \"gl\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"E \"\n" + " ],\n" + " \"background\": [\n" + " \"Contexto\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Mais \",\n" + " \"Pero \"\n" + " ],\n" + " \"examples\": [\n" + " \"Exemplos\"\n" + " ],\n" + " \"feature\": [\n" + " \"Característica\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Dado \",\n" + " \"Dada \",\n" + " \"Dados \",\n" + " \"Dadas \"\n" + " ],\n" + " \"name\": \"Galician\",\n" + " \"native\": \"galego\",\n" + " \"scenario\": [\n" + " \"Escenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Esbozo do escenario\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Entón \",\n" + " \"Logo \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Cando \"\n" + " ]\n" + " },\n" + " \"he\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"וגם \"\n" + " ],\n" + " \"background\": [\n" + " \"רקע\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"אבל \"\n" + " ],\n" + " \"examples\": [\n" + " \"דוגמאות\"\n" + " ],\n" + " \"feature\": [\n" + " \"תכונה\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"בהינתן \"\n" + " ],\n" + " \"name\": \"Hebrew\",\n" + " \"native\": \"עברית\",\n" + " \"scenario\": [\n" + " \"תרחיש\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"תבנית תרחיש\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"אז \",\n" + " \"אזי \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"כאשר \"\n" + " ]\n" + " },\n" + " \"hi\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"और \",\n" + " \"तथा \"\n" + " ],\n" + " \"background\": [\n" + " \"पृष्ठभूमि\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"पर \",\n" + " \"परन्तु \",\n" + " \"किन्तु \"\n" + " ],\n" + " \"examples\": [\n" + " \"उदाहरण\"\n" + " ],\n" + " \"feature\": [\n" + " \"रूप लेख\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"अगर \",\n" + " \"यदि \",\n" + " \"चूंकि \"\n" + " ],\n" + " \"name\": \"Hindi\",\n" + " \"native\": \"हिंदी\",\n" + " \"scenario\": [\n" + " \"परिदृश्य\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"परिदृश्य रूपरेखा\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"तब \",\n" + " \"तदा \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"जब \",\n" + " \"कदा \"\n" + " ]\n" + " },\n" + " \"hr\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"I \"\n" + " ],\n" + " \"background\": [\n" + " \"Pozadina\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Ali \"\n" + " ],\n" + " \"examples\": [\n" + " \"Primjeri\",\n" + " \"Scenariji\"\n" + " ],\n" + " \"feature\": [\n" + " \"Osobina\",\n" + " \"Mogućnost\",\n" + " \"Mogucnost\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Zadan \",\n" + " \"Zadani \",\n" + " \"Zadano \"\n" + " ],\n" + " \"name\": \"Croatian\",\n" + " \"native\": \"hrvatski\",\n" + " \"scenario\": [\n" + " \"Scenarij\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Skica\",\n" + " \"Koncept\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Onda \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Kada \",\n" + " \"Kad \"\n" + " ]\n" + " },\n" + " \"ht\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Ak \",\n" + " \"Epi \",\n" + " \"E \"\n" + " ],\n" + " \"background\": [\n" + " \"Kontèks\",\n" + " \"Istorik\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Men \"\n" + " ],\n" + " \"examples\": [\n" + " \"Egzanp\"\n" + " ],\n" + " \"feature\": [\n" + " \"Karakteristik\",\n" + " \"Mak\",\n" + " \"Fonksyonalite\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Sipoze \",\n" + " \"Sipoze ke \",\n" + " \"Sipoze Ke \"\n" + " ],\n" + " \"name\": \"Creole\",\n" + " \"native\": \"kreyòl\",\n" + " \"scenario\": [\n" + " \"Senaryo\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Plan senaryo\",\n" + " \"Plan Senaryo\",\n" + " \"Senaryo deskripsyon\",\n" + " \"Senaryo Deskripsyon\",\n" + " \"Dyagram senaryo\",\n" + " \"Dyagram Senaryo\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Lè sa a \",\n" + " \"Le sa a \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Lè \",\n" + " \"Le \"\n" + " ]\n" + " },\n" + " \"hu\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"És \"\n" + " ],\n" + " \"background\": [\n" + " \"Háttér\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"De \"\n" + " ],\n" + " \"examples\": [\n" + " \"Példák\"\n" + " ],\n" + " \"feature\": [\n" + " \"Jellemző\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Amennyiben \",\n" + " \"Adott \"\n" + " ],\n" + " \"name\": \"Hungarian\",\n" + " \"native\": \"magyar\",\n" + " \"scenario\": [\n" + " \"Forgatókönyv\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Forgatókönyv vázlat\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Akkor \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Majd \",\n" + " \"Ha \",\n" + " \"Amikor \"\n" + " ]\n" + " },\n" + " \"id\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Dan \"\n" + " ],\n" + " \"background\": [\n" + " \"Dasar\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Tapi \"\n" + " ],\n" + " \"examples\": [\n" + " \"Contoh\"\n" + " ],\n" + " \"feature\": [\n" + " \"Fitur\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Dengan \"\n" + " ],\n" + " \"name\": \"Indonesian\",\n" + " \"native\": \"Bahasa Indonesia\",\n" + " \"scenario\": [\n" + " \"Skenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Skenario konsep\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Maka \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Ketika \"\n" + " ]\n" + " },\n" + " \"is\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Og \"\n" + " ],\n" + " \"background\": [\n" + " \"Bakgrunnur\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"En \"\n" + " ],\n" + " \"examples\": [\n" + " \"Dæmi\",\n" + " \"Atburðarásir\"\n" + " ],\n" + " \"feature\": [\n" + " \"Eiginleiki\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Ef \"\n" + " ],\n" + " \"name\": \"Icelandic\",\n" + " \"native\": \"Íslenska\",\n" + " \"scenario\": [\n" + " \"Atburðarás\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Lýsing Atburðarásar\",\n" + " \"Lýsing Dæma\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Þá \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Þegar \"\n" + " ]\n" + " },\n" + " \"it\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"E \"\n" + " ],\n" + " \"background\": [\n" + " \"Contesto\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Ma \"\n" + " ],\n" + " \"examples\": [\n" + " \"Esempi\"\n" + " ],\n" + " \"feature\": [\n" + " \"Funzionalità\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Dato \",\n" + " \"Data \",\n" + " \"Dati \",\n" + " \"Date \"\n" + " ],\n" + " \"name\": \"Italian\",\n" + " \"native\": \"italiano\",\n" + " \"scenario\": [\n" + " \"Scenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Schema dello scenario\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Allora \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Quando \"\n" + " ]\n" + " },\n" + " \"ja\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"かつ\"\n" + " ],\n" + " \"background\": [\n" + " \"背景\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"しかし\",\n" + " \"但し\",\n" + " \"ただし\"\n" + " ],\n" + " \"examples\": [\n" + " \"例\",\n" + " \"サンプル\"\n" + " ],\n" + " \"feature\": [\n" + " \"フィーチャ\",\n" + " \"機能\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"前提\"\n" + " ],\n" + " \"name\": \"Japanese\",\n" + " \"native\": \"日本語\",\n" + " \"scenario\": [\n" + " \"シナリオ\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"シナリオアウトライン\",\n" + " \"シナリオテンプレート\",\n" + " \"テンプレ\",\n" + " \"シナリオテンプレ\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"ならば\"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"もし\"\n" + " ]\n" + " },\n" + " \"jv\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Lan \"\n" + " ],\n" + " \"background\": [\n" + " \"Dasar\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Tapi \",\n" + " \"Nanging \",\n" + " \"Ananging \"\n" + " ],\n" + " \"examples\": [\n" + " \"Conto\",\n" + " \"Contone\"\n" + " ],\n" + " \"feature\": [\n" + " \"Fitur\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Nalika \",\n" + " \"Nalikaning \"\n" + " ],\n" + " \"name\": \"Javanese\",\n" + " \"native\": \"Basa Jawa\",\n" + " \"scenario\": [\n" + " \"Skenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Konsep skenario\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Njuk \",\n" + " \"Banjur \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Manawa \",\n" + " \"Menawa \"\n" + " ]\n" + " },\n" + " \"ka\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"და\"\n" + " ],\n" + " \"background\": [\n" + " \"კონტექსტი\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"მაგ\u00ADრამ\"\n" + " ],\n" + " \"examples\": [\n" + " \"მაგალითები\"\n" + " ],\n" + " \"feature\": [\n" + " \"თვისება\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"მოცემული\"\n" + " ],\n" + " \"name\": \"Georgian\",\n" + " \"native\": \"ქართველი\",\n" + " \"scenario\": [\n" + " \"სცენარის\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"სცენარის ნიმუში\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"მაშინ\"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"როდესაც\"\n" + " ]\n" + " },\n" + " \"kn\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"ಮತ್ತು \"\n" + " ],\n" + " \"background\": [\n" + " \"ಹಿನ್ನೆಲೆ\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"ಆದರೆ \"\n" + " ],\n" + " \"examples\": [\n" + " \"ಉದಾಹರಣೆಗಳು\"\n" + " ],\n" + " \"feature\": [\n" + " \"ಹೆಚ್ಚಳ\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"ನೀಡಿದ \"\n" + " ],\n" + " \"name\": \"Kannada\",\n" + " \"native\": \"ಕನ್ನಡ\",\n" + " \"scenario\": [\n" + " \"ಕಥಾಸಾರಾಂಶ\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"ವಿವರಣೆ\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"ನಂತರ \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"ಸ್ಥಿತಿಯನ್ನು \"\n" + " ]\n" + " },\n" + " \"ko\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"그리고\"\n" + " ],\n" + " \"background\": [\n" + " \"배경\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"하지만\",\n" + " \"단\"\n" + " ],\n" + " \"examples\": [\n" + " \"예\"\n" + " ],\n" + " \"feature\": [\n" + " \"기능\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"조건\",\n" + " \"먼저\"\n" + " ],\n" + " \"name\": \"Korean\",\n" + " \"native\": \"한국어\",\n" + " \"scenario\": [\n" + " \"시나리오\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"시나리오 개요\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"그러면\"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"만일\",\n" + " \"만약\"\n" + " ]\n" + " },\n" + " \"lt\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Ir \"\n" + " ],\n" + " \"background\": [\n" + " \"Kontekstas\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Bet \"\n" + " ],\n" + " \"examples\": [\n" + " \"Pavyzdžiai\",\n" + " \"Scenarijai\",\n" + " \"Variantai\"\n" + " ],\n" + " \"feature\": [\n" + " \"Savybė\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Duota \"\n" + " ],\n" + " \"name\": \"Lithuanian\",\n" + " \"native\": \"lietuvių kalba\",\n" + " \"scenario\": [\n" + " \"Scenarijus\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Scenarijaus šablonas\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Tada \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Kai \"\n" + " ]\n" + " },\n" + " \"lu\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"an \",\n" + " \"a \"\n" + " ],\n" + " \"background\": [\n" + " \"Hannergrond\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"awer \",\n" + " \"mä \"\n" + " ],\n" + " \"examples\": [\n" + " \"Beispiller\"\n" + " ],\n" + " \"feature\": [\n" + " \"Funktionalitéit\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"ugeholl \"\n" + " ],\n" + " \"name\": \"Luxemburgish\",\n" + " \"native\": \"Lëtzebuergesch\",\n" + " \"scenario\": [\n" + " \"Szenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Plang vum Szenario\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"dann \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"wann \"\n" + " ]\n" + " },\n" + " \"lv\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Un \"\n" + " ],\n" + " \"background\": [\n" + " \"Konteksts\",\n" + " \"Situācija\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Bet \"\n" + " ],\n" + " \"examples\": [\n" + " \"Piemēri\",\n" + " \"Paraugs\"\n" + " ],\n" + " \"feature\": [\n" + " \"Funkcionalitāte\",\n" + " \"Fīča\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Kad \"\n" + " ],\n" + " \"name\": \"Latvian\",\n" + " \"native\": \"latviešu\",\n" + " \"scenario\": [\n" + " \"Scenārijs\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Scenārijs pēc parauga\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Tad \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Ja \"\n" + " ]\n" + " },\n" + " \"mk-Cyrl\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"И \"\n" + " ],\n" + " \"background\": [\n" + " \"Контекст\",\n" + " \"Содржина\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Но \"\n" + " ],\n" + " \"examples\": [\n" + " \"Примери\",\n" + " \"Сценарија\"\n" + " ],\n" + " \"feature\": [\n" + " \"Функционалност\",\n" + " \"Бизнис потреба\",\n" + " \"Можност\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Дадено \",\n" + " \"Дадена \"\n" + " ],\n" + " \"name\": \"Macedonian\",\n" + " \"native\": \"Македонски\",\n" + " \"scenario\": [\n" + " \"Сценарио\",\n" + " \"На пример\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Преглед на сценарија\",\n" + " \"Скица\",\n" + " \"Концепт\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Тогаш \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Кога \"\n" + " ]\n" + " },\n" + " \"mk-Latn\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"I \"\n" + " ],\n" + " \"background\": [\n" + " \"Kontekst\",\n" + " \"Sodrzhina\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"No \"\n" + " ],\n" + " \"examples\": [\n" + " \"Primeri\",\n" + " \"Scenaria\"\n" + " ],\n" + " \"feature\": [\n" + " \"Funkcionalnost\",\n" + " \"Biznis potreba\",\n" + " \"Mozhnost\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Dadeno \",\n" + " \"Dadena \"\n" + " ],\n" + " \"name\": \"Macedonian (Latin)\",\n" + " \"native\": \"Makedonski (Latinica)\",\n" + " \"scenario\": [\n" + " \"Scenario\",\n" + " \"Na primer\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Pregled na scenarija\",\n" + " \"Skica\",\n" + " \"Koncept\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Togash \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Koga \"\n" + " ]\n" + " },\n" + " \"mn\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Мөн \",\n" + " \"Тэгээд \"\n" + " ],\n" + " \"background\": [\n" + " \"Агуулга\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Гэхдээ \",\n" + " \"Харин \"\n" + " ],\n" + " \"examples\": [\n" + " \"Тухайлбал\"\n" + " ],\n" + " \"feature\": [\n" + " \"Функц\",\n" + " \"Функционал\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Өгөгдсөн нь \",\n" + " \"Анх \"\n" + " ],\n" + " \"name\": \"Mongolian\",\n" + " \"native\": \"монгол\",\n" + " \"scenario\": [\n" + " \"Сценар\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Сценарын төлөвлөгөө\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Тэгэхэд \",\n" + " \"Үүний дараа \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Хэрэв \"\n" + " ]\n" + " },\n" + " \"nl\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"En \"\n" + " ],\n" + " \"background\": [\n" + " \"Achtergrond\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Maar \"\n" + " ],\n" + " \"examples\": [\n" + " \"Voorbeelden\"\n" + " ],\n" + " \"feature\": [\n" + " \"Functionaliteit\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Gegeven \",\n" + " \"Stel \"\n" + " ],\n" + " \"name\": \"Dutch\",\n" + " \"native\": \"Nederlands\",\n" + " \"scenario\": [\n" + " \"Scenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Abstract Scenario\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Dan \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Als \",\n" + " \"Wanneer \"\n" + " ]\n" + " },\n" + " \"no\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Og \"\n" + " ],\n" + " \"background\": [\n" + " \"Bakgrunn\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Men \"\n" + " ],\n" + " \"examples\": [\n" + " \"Eksempler\"\n" + " ],\n" + " \"feature\": [\n" + " \"Egenskap\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Gitt \"\n" + " ],\n" + " \"name\": \"Norwegian\",\n" + " \"native\": \"norsk\",\n" + " \"scenario\": [\n" + " \"Scenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Scenariomal\",\n" + " \"Abstrakt Scenario\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Så \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Når \"\n" + " ]\n" + " },\n" + " \"pa\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"ਅਤੇ \"\n" + " ],\n" + " \"background\": [\n" + " \"ਪਿਛੋਕੜ\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"ਪਰ \"\n" + " ],\n" + " \"examples\": [\n" + " \"ਉਦਾਹਰਨਾਂ\"\n" + " ],\n" + " \"feature\": [\n" + " \"ਖਾਸੀਅਤ\",\n" + " \"ਮੁਹਾਂਦਰਾ\",\n" + " \"ਨਕਸ਼ ਨੁਹਾਰ\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"ਜੇਕਰ \",\n" + " \"ਜਿਵੇਂ ਕਿ \"\n" + " ],\n" + " \"name\": \"Panjabi\",\n" + " \"native\": \"ਪੰਜਾਬੀ\",\n" + " \"scenario\": [\n" + " \"ਪਟਕਥਾ\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"ਪਟਕਥਾ ਢਾਂਚਾ\",\n" + " \"ਪਟਕਥਾ ਰੂਪ ਰੇਖਾ\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"ਤਦ \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"ਜਦੋਂ \"\n" + " ]\n" + " },\n" + " \"pl\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Oraz \",\n" + " \"I \"\n" + " ],\n" + " \"background\": [\n" + " \"Założenia\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Ale \"\n" + " ],\n" + " \"examples\": [\n" + " \"Przykłady\"\n" + " ],\n" + " \"feature\": [\n" + " \"Właściwość\",\n" + " \"Funkcja\",\n" + " \"Aspekt\",\n" + " \"Potrzeba biznesowa\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Zakładając \",\n" + " \"Mając \",\n" + " \"Zakładając, że \"\n" + " ],\n" + " \"name\": \"Polish\",\n" + " \"native\": \"polski\",\n" + " \"scenario\": [\n" + " \"Scenariusz\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Szablon scenariusza\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Wtedy \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Jeżeli \",\n" + " \"Jeśli \",\n" + " \"Gdy \",\n" + " \"Kiedy \"\n" + " ]\n" + " },\n" + " \"pt\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"E \"\n" + " ],\n" + " \"background\": [\n" + " \"Contexto\",\n" + " \"Cenário de Fundo\",\n" + " \"Cenario de Fundo\",\n" + " \"Fundo\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Mas \"\n" + " ],\n" + " \"examples\": [\n" + " \"Exemplos\",\n" + " \"Cenários\",\n" + " \"Cenarios\"\n" + " ],\n" + " \"feature\": [\n" + " \"Funcionalidade\",\n" + " \"Característica\",\n" + " \"Caracteristica\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Dado \",\n" + " \"Dada \",\n" + " \"Dados \",\n" + " \"Dadas \"\n" + " ],\n" + " \"name\": \"Portuguese\",\n" + " \"native\": \"português\",\n" + " \"scenario\": [\n" + " \"Cenário\",\n" + " \"Cenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Esquema do Cenário\",\n" + " \"Esquema do Cenario\",\n" + " \"Delineação do Cenário\",\n" + " \"Delineacao do Cenario\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Então \",\n" + " \"Entao \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Quando \"\n" + " ]\n" + " },\n" + " \"ro\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Si \",\n" + " \"Și \",\n" + " \"Şi \"\n" + " ],\n" + " \"background\": [\n" + " \"Context\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Dar \"\n" + " ],\n" + " \"examples\": [\n" + " \"Exemple\"\n" + " ],\n" + " \"feature\": [\n" + " \"Functionalitate\",\n" + " \"Funcționalitate\",\n" + " \"Funcţionalitate\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Date fiind \",\n" + " \"Dat fiind \",\n" + " \"Dati fiind \",\n" + " \"Dați fiind \",\n" + " \"Daţi fiind \"\n" + " ],\n" + " \"name\": \"Romanian\",\n" + " \"native\": \"română\",\n" + " \"scenario\": [\n" + " \"Scenariu\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Structura scenariu\",\n" + " \"Structură scenariu\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Atunci \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Cand \",\n" + " \"Când \"\n" + " ]\n" + " },\n" + " \"ru\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"И \",\n" + " \"К тому же \",\n" + " \"Также \"\n" + " ],\n" + " \"background\": [\n" + " \"Предыстория\",\n" + " \"Контекст\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Но \",\n" + " \"А \"\n" + " ],\n" + " \"examples\": [\n" + " \"Примеры\"\n" + " ],\n" + " \"feature\": [\n" + " \"Функция\",\n" + " \"Функциональность\",\n" + " \"Функционал\",\n" + " \"Свойство\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Допустим \",\n" + " \"Дано \",\n" + " \"Пусть \"\n" + " ],\n" + " \"name\": \"Russian\",\n" + " \"native\": \"русский\",\n" + " \"scenario\": [\n" + " \"Сценарий\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Структура сценария\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"То \",\n" + " \"Затем \",\n" + " \"Тогда \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Если \",\n" + " \"Когда \"\n" + " ]\n" + " },\n" + " \"sk\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"A \",\n" + " \"A tiež \",\n" + " \"A taktiež \",\n" + " \"A zároveň \"\n" + " ],\n" + " \"background\": [\n" + " \"Pozadie\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Ale \"\n" + " ],\n" + " \"examples\": [\n" + " \"Príklady\"\n" + " ],\n" + " \"feature\": [\n" + " \"Požiadavka\",\n" + " \"Funkcia\",\n" + " \"Vlastnosť\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Pokiaľ \",\n" + " \"Za predpokladu \"\n" + " ],\n" + " \"name\": \"Slovak\",\n" + " \"native\": \"Slovensky\",\n" + " \"scenario\": [\n" + " \"Scenár\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Náčrt Scenáru\",\n" + " \"Náčrt Scenára\",\n" + " \"Osnova Scenára\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Tak \",\n" + " \"Potom \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Keď \",\n" + " \"Ak \"\n" + " ]\n" + " },\n" + " \"sl\": {\n" + " \"and\": [\n" + " \"In \",\n" + " \"Ter \"\n" + " ],\n" + " \"background\": [\n" + " \"Kontekst\",\n" + " \"Osnova\",\n" + " \"Ozadje\"\n" + " ],\n" + " \"but\": [\n" + " \"Toda \",\n" + " \"Ampak \",\n" + " \"Vendar \"\n" + " ],\n" + " \"examples\": [\n" + " \"Primeri\",\n" + " \"Scenariji\"\n" + " ],\n" + " \"feature\": [\n" + " \"Funkcionalnost\",\n" + " \"Funkcija\",\n" + " \"Možnosti\",\n" + " \"Moznosti\",\n" + " \"Lastnost\",\n" + " \"Značilnost\"\n" + " ],\n" + " \"given\": [\n" + " \"Dano \",\n" + " \"Podano \",\n" + " \"Zaradi \",\n" + " \"Privzeto \"\n" + " ],\n" + " \"name\": \"Slovenian\",\n" + " \"native\": \"Slovenski\",\n" + " \"scenario\": [\n" + " \"Scenarij\",\n" + " \"Primer\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Struktura scenarija\",\n" + " \"Skica\",\n" + " \"Koncept\",\n" + " \"Oris scenarija\",\n" + " \"Osnutek\"\n" + " ],\n" + " \"then\": [\n" + " \"Nato \",\n" + " \"Potem \",\n" + " \"Takrat \"\n" + " ],\n" + " \"when\": [\n" + " \"Ko \",\n" + " \"Ce \",\n" + " \"Če \",\n" + " \"Kadar \"\n" + " ]\n" + " },\n" + " \"sr-Cyrl\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"И \"\n" + " ],\n" + " \"background\": [\n" + " \"Контекст\",\n" + " \"Основа\",\n" + " \"Позадина\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Али \"\n" + " ],\n" + " \"examples\": [\n" + " \"Примери\",\n" + " \"Сценарији\"\n" + " ],\n" + " \"feature\": [\n" + " \"Функционалност\",\n" + " \"Могућност\",\n" + " \"Особина\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"За дато \",\n" + " \"За дате \",\n" + " \"За дати \"\n" + " ],\n" + " \"name\": \"Serbian\",\n" + " \"native\": \"Српски\",\n" + " \"scenario\": [\n" + " \"Сценарио\",\n" + " \"Пример\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Структура сценарија\",\n" + " \"Скица\",\n" + " \"Концепт\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Онда \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Када \",\n" + " \"Кад \"\n" + " ]\n" + " },\n" + " \"sr-Latn\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"I \"\n" + " ],\n" + " \"background\": [\n" + " \"Kontekst\",\n" + " \"Osnova\",\n" + " \"Pozadina\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Ali \"\n" + " ],\n" + " \"examples\": [\n" + " \"Primeri\",\n" + " \"Scenariji\"\n" + " ],\n" + " \"feature\": [\n" + " \"Funkcionalnost\",\n" + " \"Mogućnost\",\n" + " \"Mogucnost\",\n" + " \"Osobina\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Za dato \",\n" + " \"Za date \",\n" + " \"Za dati \"\n" + " ],\n" + " \"name\": \"Serbian (Latin)\",\n" + " \"native\": \"Srpski (Latinica)\",\n" + " \"scenario\": [\n" + " \"Scenario\",\n" + " \"Primer\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Struktura scenarija\",\n" + " \"Skica\",\n" + " \"Koncept\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Onda \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Kada \",\n" + " \"Kad \"\n" + " ]\n" + " },\n" + " \"sv\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Och \"\n" + " ],\n" + " \"background\": [\n" + " \"Bakgrund\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Men \"\n" + " ],\n" + " \"examples\": [\n" + " \"Exempel\"\n" + " ],\n" + " \"feature\": [\n" + " \"Egenskap\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Givet \"\n" + " ],\n" + " \"name\": \"Swedish\",\n" + " \"native\": \"Svenska\",\n" + " \"scenario\": [\n" + " \"Scenario\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Abstrakt Scenario\",\n" + " \"Scenariomall\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Så \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"När \"\n" + " ]\n" + " },\n" + " \"ta\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"மேலும் \",\n" + " \"மற்றும் \"\n" + " ],\n" + " \"background\": [\n" + " \"பின்னணி\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"ஆனால் \"\n" + " ],\n" + " \"examples\": [\n" + " \"எடுத்துக்காட்டுகள்\",\n" + " \"காட்சிகள்\",\n" + " \" நிலைமைகளில்\"\n" + " ],\n" + " \"feature\": [\n" + " \"அம்சம்\",\n" + " \"வணிக தேவை\",\n" + " \"திறன்\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"கொடுக்கப்பட்ட \"\n" + " ],\n" + " \"name\": \"Tamil\",\n" + " \"native\": \"தமிழ்\",\n" + " \"scenario\": [\n" + " \"காட்சி\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"காட்சி சுருக்கம்\",\n" + " \"காட்சி வார்ப்புரு\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"அப்பொழுது \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"எப்போது \"\n" + " ]\n" + " },\n" + " \"th\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"และ \"\n" + " ],\n" + " \"background\": [\n" + " \"แนวคิด\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"แต่ \"\n" + " ],\n" + " \"examples\": [\n" + " \"ชุดของตัวอย่าง\",\n" + " \"ชุดของเหตุการณ์\"\n" + " ],\n" + " \"feature\": [\n" + " \"โครงหลัก\",\n" + " \"ความต้องการทางธุรกิจ\",\n" + " \"ความสามารถ\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"กำหนดให้ \"\n" + " ],\n" + " \"name\": \"Thai\",\n" + " \"native\": \"ไทย\",\n" + " \"scenario\": [\n" + " \"เหตุการณ์\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"สรุปเหตุการณ์\",\n" + " \"โครงสร้างของเหตุการณ์\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"ดังนั้น \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"เมื่อ \"\n" + " ]\n" + " },\n" + " \"tl\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"మరియు \"\n" + " ],\n" + " \"background\": [\n" + " \"నేపథ్యం\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"కాని \"\n" + " ],\n" + " \"examples\": [\n" + " \"ఉదాహరణలు\"\n" + " ],\n" + " \"feature\": [\n" + " \"గుణము\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"చెప్పబడినది \"\n" + " ],\n" + " \"name\": \"Telugu\",\n" + " \"native\": \"తెలుగు\",\n" + " \"scenario\": [\n" + " \"సన్నివేశం\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"కథనం\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"అప్పుడు \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"ఈ పరిస్థితిలో \"\n" + " ]\n" + " },\n" + " \"tlh\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"'ej \",\n" + " \"latlh \"\n" + " ],\n" + " \"background\": [\n" + " \"mo'\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"'ach \",\n" + " \"'a \"\n" + " ],\n" + " \"examples\": [\n" + " \"ghantoH\",\n" + " \"lutmey\"\n" + " ],\n" + " \"feature\": [\n" + " \"Qap\",\n" + " \"Qu'meH 'ut\",\n" + " \"perbogh\",\n" + " \"poQbogh malja'\",\n" + " \"laH\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"ghu' noblu' \",\n" + " \"DaH ghu' bejlu' \"\n" + " ],\n" + " \"name\": \"Klingon\",\n" + " \"native\": \"tlhIngan\",\n" + " \"scenario\": [\n" + " \"lut\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"lut chovnatlh\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"vaj \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"qaSDI' \"\n" + " ]\n" + " },\n" + " \"tr\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Ve \"\n" + " ],\n" + " \"background\": [\n" + " \"Geçmiş\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Fakat \",\n" + " \"Ama \"\n" + " ],\n" + " \"examples\": [\n" + " \"Örnekler\"\n" + " ],\n" + " \"feature\": [\n" + " \"Özellik\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Diyelim ki \"\n" + " ],\n" + " \"name\": \"Turkish\",\n" + " \"native\": \"Türkçe\",\n" + " \"scenario\": [\n" + " \"Senaryo\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Senaryo taslağı\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"O zaman \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Eğer ki \"\n" + " ]\n" + " },\n" + " \"tt\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Һәм \",\n" + " \"Вә \"\n" + " ],\n" + " \"background\": [\n" + " \"Кереш\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Ләкин \",\n" + " \"Әмма \"\n" + " ],\n" + " \"examples\": [\n" + " \"Үрнәкләр\",\n" + " \"Мисаллар\"\n" + " ],\n" + " \"feature\": [\n" + " \"Мөмкинлек\",\n" + " \"Үзенчәлеклелек\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Әйтик \"\n" + " ],\n" + " \"name\": \"Tatar\",\n" + " \"native\": \"Татарча\",\n" + " \"scenario\": [\n" + " \"Сценарий\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Сценарийның төзелеше\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Нәтиҗәдә \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Әгәр \"\n" + " ]\n" + " },\n" + " \"uk\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"І \",\n" + " \"А також \",\n" + " \"Та \"\n" + " ],\n" + " \"background\": [\n" + " \"Передумова\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Але \"\n" + " ],\n" + " \"examples\": [\n" + " \"Приклади\"\n" + " ],\n" + " \"feature\": [\n" + " \"Функціонал\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Припустимо \",\n" + " \"Припустимо, що \",\n" + " \"Нехай \",\n" + " \"Дано \"\n" + " ],\n" + " \"name\": \"Ukrainian\",\n" + " \"native\": \"Українська\",\n" + " \"scenario\": [\n" + " \"Сценарій\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Структура сценарію\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"То \",\n" + " \"Тоді \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Якщо \",\n" + " \"Коли \"\n" + " ]\n" + " },\n" + " \"ur\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"اور \"\n" + " ],\n" + " \"background\": [\n" + " \"پس منظر\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"لیکن \"\n" + " ],\n" + " \"examples\": [\n" + " \"مثالیں\"\n" + " ],\n" + " \"feature\": [\n" + " \"صلاحیت\",\n" + " \"کاروبار کی ضرورت\",\n" + " \"خصوصیت\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"اگر \",\n" + " \"بالفرض \",\n" + " \"فرض کیا \"\n" + " ],\n" + " \"name\": \"Urdu\",\n" + " \"native\": \"اردو\",\n" + " \"scenario\": [\n" + " \"منظرنامہ\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"منظر نامے کا خاکہ\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"پھر \",\n" + " \"تب \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"جب \"\n" + " ]\n" + " },\n" + " \"uz\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Ва \"\n" + " ],\n" + " \"background\": [\n" + " \"Тарих\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Лекин \",\n" + " \"Бирок \",\n" + " \"Аммо \"\n" + " ],\n" + " \"examples\": [\n" + " \"Мисоллар\"\n" + " ],\n" + " \"feature\": [\n" + " \"Функционал\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Агар \"\n" + " ],\n" + " \"name\": \"Uzbek\",\n" + " \"native\": \"Узбекча\",\n" + " \"scenario\": [\n" + " \"Сценарий\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Сценарий структураси\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Унда \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Агар \"\n" + " ]\n" + " },\n" + " \"vi\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"Và \"\n" + " ],\n" + " \"background\": [\n" + " \"Bối cảnh\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"Nhưng \"\n" + " ],\n" + " \"examples\": [\n" + " \"Dữ liệu\"\n" + " ],\n" + " \"feature\": [\n" + " \"Tính năng\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"Biết \",\n" + " \"Cho \"\n" + " ],\n" + " \"name\": \"Vietnamese\",\n" + " \"native\": \"Tiếng Việt\",\n" + " \"scenario\": [\n" + " \"Tình huống\",\n" + " \"Kịch bản\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"Khung tình huống\",\n" + " \"Khung kịch bản\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"Thì \"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"Khi \"\n" + " ]\n" + " },\n" + " \"zh-CN\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"而且\",\n" + " \"并且\",\n" + " \"同时\"\n" + " ],\n" + " \"background\": [\n" + " \"背景\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"但是\"\n" + " ],\n" + " \"examples\": [\n" + " \"例子\"\n" + " ],\n" + " \"feature\": [\n" + " \"功能\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"假如\",\n" + " \"假设\",\n" + " \"假定\"\n" + " ],\n" + " \"name\": \"Chinese simplified\",\n" + " \"native\": \"简体中文\",\n" + " \"scenario\": [\n" + " \"场景\",\n" + " \"剧本\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"场景大纲\",\n" + " \"剧本大纲\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"那么\"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"当\"\n" + " ]\n" + " },\n" + " \"zh-TW\": {\n" + " \"and\": [\n" + " \"* \",\n" + " \"而且\",\n" + " \"並且\",\n" + " \"同時\"\n" + " ],\n" + " \"background\": [\n" + " \"背景\"\n" + " ],\n" + " \"but\": [\n" + " \"* \",\n" + " \"但是\"\n" + " ],\n" + " \"examples\": [\n" + " \"例子\"\n" + " ],\n" + " \"feature\": [\n" + " \"功能\"\n" + " ],\n" + " \"given\": [\n" + " \"* \",\n" + " \"假如\",\n" + " \"假設\",\n" + " \"假定\"\n" + " ],\n" + " \"name\": \"Chinese traditional\",\n" + " \"native\": \"繁體中文\",\n" + " \"scenario\": [\n" + " \"場景\",\n" + " \"劇本\"\n" + " ],\n" + " \"scenarioOutline\": [\n" + " \"場景大綱\",\n" + " \"劇本大綱\"\n" + " ],\n" + " \"then\": [\n" + " \"* \",\n" + " \"那麼\"\n" + " ],\n" + " \"when\": [\n" + " \"* \",\n" + " \"當\"\n" + " ]\n" + " }\n" + "}\n"; DIALECTS = gson.fromJson(dialects, Map.class); } catch (Exception e) { throw new RuntimeException(e); } } public GherkinDialectProvider(String default_dialect_name) { this.default_dialect_name = default_dialect_name; } public GherkinDialectProvider() { this("en"); } public GherkinDialect getDefaultDialect() { return getDialect(default_dialect_name, null); } @Override public GherkinDialect getDialect(String language, Location location) { Map> map = DIALECTS.get(language); if (map == null) { throw new ParserException.NoSuchLanguageException(language, location); } return new GherkinDialect(language, map); } } ================================================ FILE: greencoffee/src/main/java/gherkin/GherkinLanguageConstants.java ================================================ package gherkin; public interface GherkinLanguageConstants { String TAG_PREFIX = "@"; String COMMENT_PREFIX = "#"; String TITLE_KEYWORD_SEPARATOR = ":"; String TABLE_CELL_SEPARATOR = "|"; String DOCSTRING_SEPARATOR = "\"\"\""; String DOCSTRING_ALTERNATIVE_SEPARATOR = "```"; } ================================================ FILE: greencoffee/src/main/java/gherkin/GherkinLine.java ================================================ package gherkin; import java.util.ArrayList; import java.util.List; import java.util.Scanner; import static gherkin.StringUtils.ltrim; import static gherkin.SymbolCounter.countSymbols; public class GherkinLine implements IGherkinLine { private final String lineText; private final String trimmedLineText; public GherkinLine(String lineText) { this.lineText = lineText; this.trimmedLineText = ltrim(lineText); } @Override public Integer indent() { return countSymbols(lineText) - countSymbols(trimmedLineText); } @Override public void detach() { } @Override public String getLineText(int indentToRemove) { if (indentToRemove < 0 || indentToRemove > indent()) return trimmedLineText; return lineText.substring(indentToRemove); } @Override public boolean isEmpty() { return trimmedLineText.length() == 0; } @Override public boolean startsWith(String prefix) { return trimmedLineText.startsWith(prefix); } @Override public String getRestTrimmed(int length) { return trimmedLineText.substring(length).trim(); } @Override public List getTags() { return getSpans("\\s+"); } @Override public boolean startsWithTitleKeyword(String text) { int textLength = text.length(); return trimmedLineText.length() > textLength && trimmedLineText.startsWith(text) && trimmedLineText.substring(textLength, textLength + GherkinLanguageConstants.TITLE_KEYWORD_SEPARATOR.length()) .equals(GherkinLanguageConstants.TITLE_KEYWORD_SEPARATOR); // TODO aslak: extract startsWithFrom method for clarity } @Override public List getTableCells() { List lineSpans = new ArrayList(); StringBuilder cell = new StringBuilder(); boolean beforeFirst = true; int startCol = 0; for (int col = 0; col < trimmedLineText.length(); col++) { char c = trimmedLineText.charAt(col); if (c == '|') { if (beforeFirst) { // Skip the first empty span beforeFirst = false; } else { int contentStart = 0; while (contentStart < cell.length() && Character.isWhitespace(cell.charAt(contentStart))) { contentStart++; } if (contentStart == cell.length()) { contentStart = 0; } lineSpans.add(new GherkinLineSpan(indent() + startCol + contentStart + 2, cell.toString().trim())); startCol = col; } cell = new StringBuilder(); } else if (c == '\\') { col++; c = trimmedLineText.charAt(col); if (c == 'n') { cell.append('\n'); } else { if (c != '|' && c != '\\') { cell.append('\\'); } cell.append(c); } } else { cell.append(c); } } return lineSpans; } private List getSpans(String delimiter) { List lineSpans = new ArrayList(); Scanner scanner = new Scanner(trimmedLineText).useDelimiter(delimiter); while (scanner.hasNext()) { String cell = scanner.next(); int column = scanner.match().start() + indent() + 1; lineSpans.add(new GherkinLineSpan(column, cell)); } return lineSpans; } } ================================================ FILE: greencoffee/src/main/java/gherkin/GherkinLineSpan.java ================================================ package gherkin; public class GherkinLineSpan { // One-based line position public final int column; // text part of the line public final String text; public GherkinLineSpan(int column, String text) { this.column = column; this.text = text; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; GherkinLineSpan that = (GherkinLineSpan) o; return column == that.column && text.equals(that.text); } @Override public int hashCode() { int result = column; result = 31 * result + text.hashCode(); return result; } } ================================================ FILE: greencoffee/src/main/java/gherkin/IGherkinDialectProvider.java ================================================ package gherkin; import gherkin.ast.Location; public interface IGherkinDialectProvider { GherkinDialect getDefaultDialect(); GherkinDialect getDialect(String language, Location location); } ================================================ FILE: greencoffee/src/main/java/gherkin/IGherkinLine.java ================================================ package gherkin; import java.util.List; public interface IGherkinLine { Integer indent(); void detach(); String getLineText(int indentToRemove); boolean isEmpty(); boolean startsWith(String prefix); String getRestTrimmed(int length); List getTags(); boolean startsWithTitleKeyword(String keyword); List getTableCells(); } ================================================ FILE: greencoffee/src/main/java/gherkin/Parser.java ================================================ // This code was generated by Berp (http://https://github.com/gasparnagy/berp/). // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. package gherkin; import java.io.Reader; import java.io.StringReader; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue; import static java.util.Arrays.asList; public class Parser { public enum TokenType { None, EOF, Empty, Comment, TagLine, FeatureLine, BackgroundLine, ScenarioLine, ScenarioOutlineLine, ExamplesLine, StepLine, DocStringSeparator, TableRow, Language, Other, ; } public enum RuleType { None, _EOF, // #EOF _Empty, // #Empty _Comment, // #Comment _TagLine, // #TagLine _FeatureLine, // #FeatureLine _BackgroundLine, // #BackgroundLine _ScenarioLine, // #ScenarioLine _ScenarioOutlineLine, // #ScenarioOutlineLine _ExamplesLine, // #ExamplesLine _StepLine, // #StepLine _DocStringSeparator, // #DocStringSeparator _TableRow, // #TableRow _Language, // #Language _Other, // #Other GherkinDocument, // GherkinDocument! := Feature? Feature, // Feature! := Feature_Header Background? Scenario_Definition* Feature_Header, // Feature_Header! := #Language? Tags? #FeatureLine Feature_Description Background, // Background! := #BackgroundLine Background_Description Scenario_Step* Scenario_Definition, // Scenario_Definition! := Tags? (Scenario | ScenarioOutline) Scenario, // Scenario! := #ScenarioLine Scenario_Description Scenario_Step* ScenarioOutline, // ScenarioOutline! := #ScenarioOutlineLine ScenarioOutline_Description ScenarioOutline_Step* Examples_Definition* Examples_Definition, // Examples_Definition! [#Empty|#Comment|#TagLine->#ExamplesLine] := Tags? Examples Examples, // Examples! := #ExamplesLine Examples_Description Examples_Table? Examples_Table, // Examples_Table! := #TableRow #TableRow* Scenario_Step, // Scenario_Step := Step ScenarioOutline_Step, // ScenarioOutline_Step := Step Step, // Step! := #StepLine Step_Arg? Step_Arg, // Step_Arg := (DataTable | DocString) DataTable, // DataTable! := #TableRow+ DocString, // DocString! := #DocStringSeparator #Other* #DocStringSeparator Tags, // Tags! := #TagLine+ Feature_Description, // Feature_Description := Description_Helper Background_Description, // Background_Description := Description_Helper Scenario_Description, // Scenario_Description := Description_Helper ScenarioOutline_Description, // ScenarioOutline_Description := Description_Helper Examples_Description, // Examples_Description := Description_Helper Description_Helper, // Description_Helper := #Empty* Description? #Comment* Description, // Description! := #Other+ ; public static RuleType cast(TokenType tokenType) { return RuleType.values()[tokenType.ordinal()]; } } private final Builder builder; public boolean stopAtFirstError; class ParserContext { public final ITokenScanner tokenScanner; public final ITokenMatcher tokenMatcher; public final Queue tokenQueue; public final List errors; ParserContext(ITokenScanner tokenScanner, ITokenMatcher tokenMatcher, Queue tokenQueue, List errors) { this.tokenScanner = tokenScanner; this.tokenMatcher = tokenMatcher; this.tokenQueue = tokenQueue; this.errors = errors; } } public Parser(Builder builder) { this.builder = builder; } public T parse(String sourceEvent) { return parse(new StringReader(sourceEvent)); } public T parse(Reader sourceEvent) { return parse(new TokenScanner(sourceEvent)); } public T parse(ITokenScanner tokenScanner) { return parse(tokenScanner, new TokenMatcher()); } public T parse(String sourceEvent, ITokenMatcher tokenMatcher) { return parse(new StringReader(sourceEvent), tokenMatcher); } public T parse(Reader sourceEvent, ITokenMatcher tokenMatcher) { return parse(new TokenScanner(sourceEvent), tokenMatcher); } public T parse(ITokenScanner tokenScanner, ITokenMatcher tokenMatcher) { builder.reset(); tokenMatcher.reset(); ParserContext context = new ParserContext( tokenScanner, tokenMatcher, new LinkedList(), new ArrayList() ); startRule(context, RuleType.GherkinDocument); int state = 0; Token token; do { token = readToken(context); state = matchToken(state, token, context); } while (!token.isEOF()); endRule(context, RuleType.GherkinDocument); if (context.errors.size() > 0) { throw new ParserException.CompositeParserException(context.errors); } return builder.getResult(); } private void addError(ParserContext context, ParserException error) { context.errors.add(error); if (context.errors.size() > 10) throw new ParserException.CompositeParserException(context.errors); } private V handleAstError(ParserContext context, final Func action) { return handleExternalError(context, action, null); } private V handleExternalError(ParserContext context, Func action, V defaultValue) { if (stopAtFirstError) { return action.call(); } try { return action.call(); } catch (ParserException.CompositeParserException compositeParserException) { for (ParserException error : compositeParserException.errors) { addError(context, error); } } catch (ParserException error) { addError(context, error); } return defaultValue; } private void build(final ParserContext context, final Token token) { handleAstError(context, new Func() { public Void call() { builder.build(token); return null; } }); } private void startRule(final ParserContext context, final RuleType ruleType) { handleAstError(context, new Func() { public Void call() { builder.startRule(ruleType); return null; } }); } private void endRule(final ParserContext context, final RuleType ruleType) { handleAstError(context, new Func() { public Void call() { builder.endRule(ruleType); return null; } }); } private Token readToken(ParserContext context) { return context.tokenQueue.size() > 0 ? context.tokenQueue.remove() : context.tokenScanner.read(); } private boolean match_EOF(final ParserContext context, final Token token) { return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_EOF(token); } }, false); } private boolean match_Empty(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_Empty(token); } }, false); } private boolean match_Comment(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_Comment(token); } }, false); } private boolean match_TagLine(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_TagLine(token); } }, false); } private boolean match_FeatureLine(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_FeatureLine(token); } }, false); } private boolean match_BackgroundLine(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_BackgroundLine(token); } }, false); } private boolean match_ScenarioLine(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_ScenarioLine(token); } }, false); } private boolean match_ScenarioOutlineLine(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_ScenarioOutlineLine(token); } }, false); } private boolean match_ExamplesLine(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_ExamplesLine(token); } }, false); } private boolean match_StepLine(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_StepLine(token); } }, false); } private boolean match_DocStringSeparator(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_DocStringSeparator(token); } }, false); } private boolean match_TableRow(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_TableRow(token); } }, false); } private boolean match_Language(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_Language(token); } }, false); } private boolean match_Other(final ParserContext context, final Token token) { if (token.isEOF()) return false; return handleExternalError(context, new Func() { public Boolean call() { return context.tokenMatcher.match_Other(token); } }, false); } private int matchToken(int state, Token token, ParserContext context) { int newState; switch(state) { case 0: newState = matchTokenAt_0(token, context); break; case 1: newState = matchTokenAt_1(token, context); break; case 2: newState = matchTokenAt_2(token, context); break; case 3: newState = matchTokenAt_3(token, context); break; case 4: newState = matchTokenAt_4(token, context); break; case 5: newState = matchTokenAt_5(token, context); break; case 6: newState = matchTokenAt_6(token, context); break; case 7: newState = matchTokenAt_7(token, context); break; case 8: newState = matchTokenAt_8(token, context); break; case 9: newState = matchTokenAt_9(token, context); break; case 10: newState = matchTokenAt_10(token, context); break; case 11: newState = matchTokenAt_11(token, context); break; case 12: newState = matchTokenAt_12(token, context); break; case 13: newState = matchTokenAt_13(token, context); break; case 14: newState = matchTokenAt_14(token, context); break; case 15: newState = matchTokenAt_15(token, context); break; case 16: newState = matchTokenAt_16(token, context); break; case 17: newState = matchTokenAt_17(token, context); break; case 18: newState = matchTokenAt_18(token, context); break; case 19: newState = matchTokenAt_19(token, context); break; case 20: newState = matchTokenAt_20(token, context); break; case 21: newState = matchTokenAt_21(token, context); break; case 22: newState = matchTokenAt_22(token, context); break; case 23: newState = matchTokenAt_23(token, context); break; case 24: newState = matchTokenAt_24(token, context); break; case 25: newState = matchTokenAt_25(token, context); break; case 26: newState = matchTokenAt_26(token, context); break; case 28: newState = matchTokenAt_28(token, context); break; case 29: newState = matchTokenAt_29(token, context); break; case 30: newState = matchTokenAt_30(token, context); break; case 31: newState = matchTokenAt_31(token, context); break; case 32: newState = matchTokenAt_32(token, context); break; case 33: newState = matchTokenAt_33(token, context); break; default: throw new IllegalStateException("Unknown state: " + state); } return newState; } // Start private int matchTokenAt_0(Token token, ParserContext context) { if (match_EOF(context, token)) { build(context, token); return 27; } if (match_Language(context, token)) { startRule(context, RuleType.Feature); startRule(context, RuleType.Feature_Header); build(context, token); return 1; } if (match_TagLine(context, token)) { startRule(context, RuleType.Feature); startRule(context, RuleType.Feature_Header); startRule(context, RuleType.Tags); build(context, token); return 2; } if (match_FeatureLine(context, token)) { startRule(context, RuleType.Feature); startRule(context, RuleType.Feature_Header); build(context, token); return 3; } if (match_Comment(context, token)) { build(context, token); return 0; } if (match_Empty(context, token)) { build(context, token); return 0; } final String stateComment = "State: 0 - Start"; token.detach(); List expectedTokens = asList("#EOF", "#Language", "#TagLine", "#FeatureLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 0; } // GherkinDocument:0>Feature:0>Feature_Header:0>#Language:0 private int matchTokenAt_1(Token token, ParserContext context) { if (match_TagLine(context, token)) { startRule(context, RuleType.Tags); build(context, token); return 2; } if (match_FeatureLine(context, token)) { build(context, token); return 3; } if (match_Comment(context, token)) { build(context, token); return 1; } if (match_Empty(context, token)) { build(context, token); return 1; } final String stateComment = "State: 1 - GherkinDocument:0>Feature:0>Feature_Header:0>#Language:0"; token.detach(); List expectedTokens = asList("#TagLine", "#FeatureLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 1; } // GherkinDocument:0>Feature:0>Feature_Header:1>Tags:0>#TagLine:0 private int matchTokenAt_2(Token token, ParserContext context) { if (match_TagLine(context, token)) { build(context, token); return 2; } if (match_FeatureLine(context, token)) { endRule(context, RuleType.Tags); build(context, token); return 3; } if (match_Comment(context, token)) { build(context, token); return 2; } if (match_Empty(context, token)) { build(context, token); return 2; } final String stateComment = "State: 2 - GherkinDocument:0>Feature:0>Feature_Header:1>Tags:0>#TagLine:0"; token.detach(); List expectedTokens = asList("#TagLine", "#FeatureLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 2; } // GherkinDocument:0>Feature:0>Feature_Header:2>#FeatureLine:0 private int matchTokenAt_3(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Feature_Header); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Empty(context, token)) { build(context, token); return 3; } if (match_Comment(context, token)) { build(context, token); return 5; } if (match_BackgroundLine(context, token)) { endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Background); build(context, token); return 6; } if (match_TagLine(context, token)) { endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Other(context, token)) { startRule(context, RuleType.Description); build(context, token); return 4; } final String stateComment = "State: 3 - GherkinDocument:0>Feature:0>Feature_Header:2>#FeatureLine:0"; token.detach(); List expectedTokens = asList("#EOF", "#Empty", "#Comment", "#BackgroundLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 3; } // GherkinDocument:0>Feature:0>Feature_Header:3>Feature_Description:0>Description_Helper:1>Description:0>#Other:0 private int matchTokenAt_4(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Feature_Header); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Comment(context, token)) { endRule(context, RuleType.Description); build(context, token); return 5; } if (match_BackgroundLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Background); build(context, token); return 6; } if (match_TagLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Other(context, token)) { build(context, token); return 4; } final String stateComment = "State: 4 - GherkinDocument:0>Feature:0>Feature_Header:3>Feature_Description:0>Description_Helper:1>Description:0>#Other:0"; token.detach(); List expectedTokens = asList("#EOF", "#Comment", "#BackgroundLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 4; } // GherkinDocument:0>Feature:0>Feature_Header:3>Feature_Description:0>Description_Helper:2>#Comment:0 private int matchTokenAt_5(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Feature_Header); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Comment(context, token)) { build(context, token); return 5; } if (match_BackgroundLine(context, token)) { endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Background); build(context, token); return 6; } if (match_TagLine(context, token)) { endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Feature_Header); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Empty(context, token)) { build(context, token); return 5; } final String stateComment = "State: 5 - GherkinDocument:0>Feature:0>Feature_Header:3>Feature_Description:0>Description_Helper:2>#Comment:0"; token.detach(); List expectedTokens = asList("#EOF", "#Comment", "#BackgroundLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 5; } // GherkinDocument:0>Feature:1>Background:0>#BackgroundLine:0 private int matchTokenAt_6(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Background); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Empty(context, token)) { build(context, token); return 6; } if (match_Comment(context, token)) { build(context, token); return 8; } if (match_StepLine(context, token)) { startRule(context, RuleType.Step); build(context, token); return 9; } if (match_TagLine(context, token)) { endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Other(context, token)) { startRule(context, RuleType.Description); build(context, token); return 7; } final String stateComment = "State: 6 - GherkinDocument:0>Feature:1>Background:0>#BackgroundLine:0"; token.detach(); List expectedTokens = asList("#EOF", "#Empty", "#Comment", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 6; } // GherkinDocument:0>Feature:1>Background:1>Background_Description:0>Description_Helper:1>Description:0>#Other:0 private int matchTokenAt_7(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Background); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Comment(context, token)) { endRule(context, RuleType.Description); build(context, token); return 8; } if (match_StepLine(context, token)) { endRule(context, RuleType.Description); startRule(context, RuleType.Step); build(context, token); return 9; } if (match_TagLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Other(context, token)) { build(context, token); return 7; } final String stateComment = "State: 7 - GherkinDocument:0>Feature:1>Background:1>Background_Description:0>Description_Helper:1>Description:0>#Other:0"; token.detach(); List expectedTokens = asList("#EOF", "#Comment", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 7; } // GherkinDocument:0>Feature:1>Background:1>Background_Description:0>Description_Helper:2>#Comment:0 private int matchTokenAt_8(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Background); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Comment(context, token)) { build(context, token); return 8; } if (match_StepLine(context, token)) { startRule(context, RuleType.Step); build(context, token); return 9; } if (match_TagLine(context, token)) { endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Empty(context, token)) { build(context, token); return 8; } final String stateComment = "State: 8 - GherkinDocument:0>Feature:1>Background:1>Background_Description:0>Description_Helper:2>#Comment:0"; token.detach(); List expectedTokens = asList("#EOF", "#Comment", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 8; } // GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:0>#StepLine:0 private int matchTokenAt_9(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.Background); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_TableRow(context, token)) { startRule(context, RuleType.DataTable); build(context, token); return 10; } if (match_DocStringSeparator(context, token)) { startRule(context, RuleType.DocString); build(context, token); return 32; } if (match_StepLine(context, token)) { endRule(context, RuleType.Step); startRule(context, RuleType.Step); build(context, token); return 9; } if (match_TagLine(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 9; } if (match_Empty(context, token)) { build(context, token); return 9; } final String stateComment = "State: 9 - GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:0>#StepLine:0"; token.detach(); List expectedTokens = asList("#EOF", "#TableRow", "#DocStringSeparator", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 9; } // GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0 private int matchTokenAt_10(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.Background); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_TableRow(context, token)) { build(context, token); return 10; } if (match_StepLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); startRule(context, RuleType.Step); build(context, token); return 9; } if (match_TagLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 10; } if (match_Empty(context, token)) { build(context, token); return 10; } final String stateComment = "State: 10 - GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0"; token.detach(); List expectedTokens = asList("#EOF", "#TableRow", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 10; } // GherkinDocument:0>Feature:2>Scenario_Definition:0>Tags:0>#TagLine:0 private int matchTokenAt_11(Token token, ParserContext context) { if (match_TagLine(context, token)) { build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Tags); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Tags); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 11; } if (match_Empty(context, token)) { build(context, token); return 11; } final String stateComment = "State: 11 - GherkinDocument:0>Feature:2>Scenario_Definition:0>Tags:0>#TagLine:0"; token.detach(); List expectedTokens = asList("#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 11; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:0>#ScenarioLine:0 private int matchTokenAt_12(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Empty(context, token)) { build(context, token); return 12; } if (match_Comment(context, token)) { build(context, token); return 14; } if (match_StepLine(context, token)) { startRule(context, RuleType.Step); build(context, token); return 15; } if (match_TagLine(context, token)) { endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Other(context, token)) { startRule(context, RuleType.Description); build(context, token); return 13; } final String stateComment = "State: 12 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:0>#ScenarioLine:0"; token.detach(); List expectedTokens = asList("#EOF", "#Empty", "#Comment", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 12; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Scenario_Description:0>Description_Helper:1>Description:0>#Other:0 private int matchTokenAt_13(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Comment(context, token)) { endRule(context, RuleType.Description); build(context, token); return 14; } if (match_StepLine(context, token)) { endRule(context, RuleType.Description); startRule(context, RuleType.Step); build(context, token); return 15; } if (match_TagLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Other(context, token)) { build(context, token); return 13; } final String stateComment = "State: 13 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Scenario_Description:0>Description_Helper:1>Description:0>#Other:0"; token.detach(); List expectedTokens = asList("#EOF", "#Comment", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 13; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Scenario_Description:0>Description_Helper:2>#Comment:0 private int matchTokenAt_14(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Comment(context, token)) { build(context, token); return 14; } if (match_StepLine(context, token)) { startRule(context, RuleType.Step); build(context, token); return 15; } if (match_TagLine(context, token)) { endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Empty(context, token)) { build(context, token); return 14; } final String stateComment = "State: 14 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Scenario_Description:0>Description_Helper:2>#Comment:0"; token.detach(); List expectedTokens = asList("#EOF", "#Comment", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 14; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:0>#StepLine:0 private int matchTokenAt_15(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_TableRow(context, token)) { startRule(context, RuleType.DataTable); build(context, token); return 16; } if (match_DocStringSeparator(context, token)) { startRule(context, RuleType.DocString); build(context, token); return 30; } if (match_StepLine(context, token)) { endRule(context, RuleType.Step); startRule(context, RuleType.Step); build(context, token); return 15; } if (match_TagLine(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 15; } if (match_Empty(context, token)) { build(context, token); return 15; } final String stateComment = "State: 15 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:0>#StepLine:0"; token.detach(); List expectedTokens = asList("#EOF", "#TableRow", "#DocStringSeparator", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 15; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0 private int matchTokenAt_16(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_TableRow(context, token)) { build(context, token); return 16; } if (match_StepLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); startRule(context, RuleType.Step); build(context, token); return 15; } if (match_TagLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 16; } if (match_Empty(context, token)) { build(context, token); return 16; } final String stateComment = "State: 16 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0"; token.detach(); List expectedTokens = asList("#EOF", "#TableRow", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 16; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:0>#ScenarioOutlineLine:0 private int matchTokenAt_17(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Empty(context, token)) { build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 19; } if (match_StepLine(context, token)) { startRule(context, RuleType.Step); build(context, token); return 20; } if (match_TagLine(context, token)) { if (lookahead_0(context, token)) { startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Tags); build(context, token); return 22; } } if (match_TagLine(context, token)) { endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ExamplesLine(context, token)) { startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples); build(context, token); return 23; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Other(context, token)) { startRule(context, RuleType.Description); build(context, token); return 18; } final String stateComment = "State: 17 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:0>#ScenarioOutlineLine:0"; token.detach(); List expectedTokens = asList("#EOF", "#Empty", "#Comment", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 17; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>ScenarioOutline_Description:0>Description_Helper:1>Description:0>#Other:0 private int matchTokenAt_18(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Comment(context, token)) { endRule(context, RuleType.Description); build(context, token); return 19; } if (match_StepLine(context, token)) { endRule(context, RuleType.Description); startRule(context, RuleType.Step); build(context, token); return 20; } if (match_TagLine(context, token)) { if (lookahead_0(context, token)) { endRule(context, RuleType.Description); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Tags); build(context, token); return 22; } } if (match_TagLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ExamplesLine(context, token)) { endRule(context, RuleType.Description); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples); build(context, token); return 23; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Other(context, token)) { build(context, token); return 18; } final String stateComment = "State: 18 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>ScenarioOutline_Description:0>Description_Helper:1>Description:0>#Other:0"; token.detach(); List expectedTokens = asList("#EOF", "#Comment", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 18; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>ScenarioOutline_Description:0>Description_Helper:2>#Comment:0 private int matchTokenAt_19(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Comment(context, token)) { build(context, token); return 19; } if (match_StepLine(context, token)) { startRule(context, RuleType.Step); build(context, token); return 20; } if (match_TagLine(context, token)) { if (lookahead_0(context, token)) { startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Tags); build(context, token); return 22; } } if (match_TagLine(context, token)) { endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ExamplesLine(context, token)) { startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples); build(context, token); return 23; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Empty(context, token)) { build(context, token); return 19; } final String stateComment = "State: 19 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>ScenarioOutline_Description:0>Description_Helper:2>#Comment:0"; token.detach(); List expectedTokens = asList("#EOF", "#Comment", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 19; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:0>#StepLine:0 private int matchTokenAt_20(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_TableRow(context, token)) { startRule(context, RuleType.DataTable); build(context, token); return 21; } if (match_DocStringSeparator(context, token)) { startRule(context, RuleType.DocString); build(context, token); return 28; } if (match_StepLine(context, token)) { endRule(context, RuleType.Step); startRule(context, RuleType.Step); build(context, token); return 20; } if (match_TagLine(context, token)) { if (lookahead_0(context, token)) { endRule(context, RuleType.Step); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Tags); build(context, token); return 22; } } if (match_TagLine(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ExamplesLine(context, token)) { endRule(context, RuleType.Step); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples); build(context, token); return 23; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 20; } if (match_Empty(context, token)) { build(context, token); return 20; } final String stateComment = "State: 20 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:0>#StepLine:0"; token.detach(); List expectedTokens = asList("#EOF", "#TableRow", "#DocStringSeparator", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 20; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0 private int matchTokenAt_21(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_TableRow(context, token)) { build(context, token); return 21; } if (match_StepLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); startRule(context, RuleType.Step); build(context, token); return 20; } if (match_TagLine(context, token)) { if (lookahead_0(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Tags); build(context, token); return 22; } } if (match_TagLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ExamplesLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples); build(context, token); return 23; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.DataTable); endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 21; } if (match_Empty(context, token)) { build(context, token); return 21; } final String stateComment = "State: 21 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0"; token.detach(); List expectedTokens = asList("#EOF", "#TableRow", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 21; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:0>Tags:0>#TagLine:0 private int matchTokenAt_22(Token token, ParserContext context) { if (match_TagLine(context, token)) { build(context, token); return 22; } if (match_ExamplesLine(context, token)) { endRule(context, RuleType.Tags); startRule(context, RuleType.Examples); build(context, token); return 23; } if (match_Comment(context, token)) { build(context, token); return 22; } if (match_Empty(context, token)) { build(context, token); return 22; } final String stateComment = "State: 22 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:0>Tags:0>#TagLine:0"; token.detach(); List expectedTokens = asList("#TagLine", "#ExamplesLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 22; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:0>#ExamplesLine:0 private int matchTokenAt_23(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Empty(context, token)) { build(context, token); return 23; } if (match_Comment(context, token)) { build(context, token); return 25; } if (match_TableRow(context, token)) { startRule(context, RuleType.Examples_Table); build(context, token); return 26; } if (match_TagLine(context, token)) { if (lookahead_0(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Tags); build(context, token); return 22; } } if (match_TagLine(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ExamplesLine(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples); build(context, token); return 23; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Other(context, token)) { startRule(context, RuleType.Description); build(context, token); return 24; } final String stateComment = "State: 23 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:0>#ExamplesLine:0"; token.detach(); List expectedTokens = asList("#EOF", "#Empty", "#Comment", "#TableRow", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 23; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Examples_Description:0>Description_Helper:1>Description:0>#Other:0 private int matchTokenAt_24(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Comment(context, token)) { endRule(context, RuleType.Description); build(context, token); return 25; } if (match_TableRow(context, token)) { endRule(context, RuleType.Description); startRule(context, RuleType.Examples_Table); build(context, token); return 26; } if (match_TagLine(context, token)) { if (lookahead_0(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Tags); build(context, token); return 22; } } if (match_TagLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ExamplesLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples); build(context, token); return 23; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Description); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Other(context, token)) { build(context, token); return 24; } final String stateComment = "State: 24 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Examples_Description:0>Description_Helper:1>Description:0>#Other:0"; token.detach(); List expectedTokens = asList("#EOF", "#Comment", "#TableRow", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 24; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Examples_Description:0>Description_Helper:2>#Comment:0 private int matchTokenAt_25(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_Comment(context, token)) { build(context, token); return 25; } if (match_TableRow(context, token)) { startRule(context, RuleType.Examples_Table); build(context, token); return 26; } if (match_TagLine(context, token)) { if (lookahead_0(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Tags); build(context, token); return 22; } } if (match_TagLine(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ExamplesLine(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples); build(context, token); return 23; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Empty(context, token)) { build(context, token); return 25; } final String stateComment = "State: 25 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Examples_Description:0>Description_Helper:2>#Comment:0"; token.detach(); List expectedTokens = asList("#EOF", "#Comment", "#TableRow", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 25; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:2>Examples_Table:0>#TableRow:0 private int matchTokenAt_26(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.Examples_Table); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_TableRow(context, token)) { build(context, token); return 26; } if (match_TagLine(context, token)) { if (lookahead_0(context, token)) { endRule(context, RuleType.Examples_Table); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Tags); build(context, token); return 22; } } if (match_TagLine(context, token)) { endRule(context, RuleType.Examples_Table); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ExamplesLine(context, token)) { endRule(context, RuleType.Examples_Table); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples); build(context, token); return 23; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.Examples_Table); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.Examples_Table); endRule(context, RuleType.Examples); endRule(context, RuleType.Examples_Definition); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 26; } if (match_Empty(context, token)) { build(context, token); return 26; } final String stateComment = "State: 26 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:2>Examples_Table:0>#TableRow:0"; token.detach(); List expectedTokens = asList("#EOF", "#TableRow", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 26; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0 private int matchTokenAt_28(Token token, ParserContext context) { if (match_DocStringSeparator(context, token)) { build(context, token); return 29; } if (match_Other(context, token)) { build(context, token); return 28; } final String stateComment = "State: 28 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0"; token.detach(); List expectedTokens = asList("#DocStringSeparator", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 28; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0 private int matchTokenAt_29(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_StepLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); startRule(context, RuleType.Step); build(context, token); return 20; } if (match_TagLine(context, token)) { if (lookahead_0(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Tags); build(context, token); return 22; } } if (match_TagLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ExamplesLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); startRule(context, RuleType.Examples_Definition); startRule(context, RuleType.Examples); build(context, token); return 23; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.ScenarioOutline); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 29; } if (match_Empty(context, token)) { build(context, token); return 29; } final String stateComment = "State: 29 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0"; token.detach(); List expectedTokens = asList("#EOF", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 29; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0 private int matchTokenAt_30(Token token, ParserContext context) { if (match_DocStringSeparator(context, token)) { build(context, token); return 31; } if (match_Other(context, token)) { build(context, token); return 30; } final String stateComment = "State: 30 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0"; token.detach(); List expectedTokens = asList("#DocStringSeparator", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 30; } // GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0 private int matchTokenAt_31(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_StepLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); startRule(context, RuleType.Step); build(context, token); return 15; } if (match_TagLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.Scenario); endRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 31; } if (match_Empty(context, token)) { build(context, token); return 31; } final String stateComment = "State: 31 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0"; token.detach(); List expectedTokens = asList("#EOF", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 31; } // GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0 private int matchTokenAt_32(Token token, ParserContext context) { if (match_DocStringSeparator(context, token)) { build(context, token); return 33; } if (match_Other(context, token)) { build(context, token); return 32; } final String stateComment = "State: 32 - GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0"; token.detach(); List expectedTokens = asList("#DocStringSeparator", "#Other"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 32; } // GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0 private int matchTokenAt_33(Token token, ParserContext context) { if (match_EOF(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.Background); endRule(context, RuleType.Feature); build(context, token); return 27; } if (match_StepLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); startRule(context, RuleType.Step); build(context, token); return 9; } if (match_TagLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Tags); build(context, token); return 11; } if (match_ScenarioLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.Scenario); build(context, token); return 12; } if (match_ScenarioOutlineLine(context, token)) { endRule(context, RuleType.DocString); endRule(context, RuleType.Step); endRule(context, RuleType.Background); startRule(context, RuleType.Scenario_Definition); startRule(context, RuleType.ScenarioOutline); build(context, token); return 17; } if (match_Comment(context, token)) { build(context, token); return 33; } if (match_Empty(context, token)) { build(context, token); return 33; } final String stateComment = "State: 33 - GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0"; token.detach(); List expectedTokens = asList("#EOF", "#StepLine", "#TagLine", "#ScenarioLine", "#ScenarioOutlineLine", "#Comment", "#Empty"); ParserException error = token.isEOF() ? new ParserException.UnexpectedEOFException(token, expectedTokens, stateComment) : new ParserException.UnexpectedTokenException(token, expectedTokens, stateComment); if (stopAtFirstError) throw error; addError(context, error); return 33; } private boolean lookahead_0(ParserContext context, Token currentToken) { currentToken.detach(); Token token; Queue queue = new ArrayDeque(); boolean match = false; do { token = readToken(context); token.detach(); queue.add(token); if (false || match_ExamplesLine(context, token) ) { match = true; break; } } while (false || match_Empty(context, token) || match_Comment(context, token) || match_TagLine(context, token) ); context.tokenQueue.addAll(queue); return match; } public interface Builder { void build(Token token); void startRule(RuleType ruleType); void endRule(RuleType ruleType); T getResult(); void reset(); } public interface ITokenScanner { Token read(); } public interface ITokenMatcher { boolean match_EOF(Token token); boolean match_Empty(Token token); boolean match_Comment(Token token); boolean match_TagLine(Token token); boolean match_FeatureLine(Token token); boolean match_BackgroundLine(Token token); boolean match_ScenarioLine(Token token); boolean match_ScenarioOutlineLine(Token token); boolean match_ExamplesLine(Token token); boolean match_StepLine(Token token); boolean match_DocStringSeparator(Token token); boolean match_TableRow(Token token); boolean match_Language(Token token); boolean match_Other(Token token); void reset(); } } ================================================ FILE: greencoffee/src/main/java/gherkin/ParserException.java ================================================ package gherkin; import gherkin.ast.Location; import java.util.Collections; import java.util.List; public class ParserException extends RuntimeException { public final Location location; protected ParserException(String message) { super(message); location = null; } protected ParserException(String message, Location location) { super(getMessage(message, location)); this.location = location; } private static String getMessage(String message, Location location) { return String.format("(%s:%s): %s", location.getLine(), location.getColumn(), message); } public static class AstBuilderException extends ParserException { public AstBuilderException(String message, Location location) { super(message, location); } } public static class NoSuchLanguageException extends ParserException { public NoSuchLanguageException(String language, Location location) { super("Language not supported: " + language, location); } } public static class UnexpectedTokenException extends ParserException { public String stateComment; public final Token receivedToken; public final List expectedTokenTypes; public UnexpectedTokenException(Token receivedToken, List expectedTokenTypes, String stateComment) { super(getMessage(receivedToken, expectedTokenTypes), getLocation(receivedToken)); this.receivedToken = receivedToken; this.expectedTokenTypes = expectedTokenTypes; this.stateComment = stateComment; } private static String getMessage(Token receivedToken, List expectedTokenTypes) { return String.format("expected: %s, got '%s'", StringUtils.join(", ", expectedTokenTypes), receivedToken.getTokenValue().trim()); } private static Location getLocation(Token receivedToken) { return receivedToken.location.getColumn() > 1 ? receivedToken.location : new Location(receivedToken.location.getLine(), receivedToken.line.indent() + 1); } } public static class UnexpectedEOFException extends ParserException { public final String stateComment; public final List expectedTokenTypes; public UnexpectedEOFException(Token receivedToken, List expectedTokenTypes, String stateComment) { super(getMessage(expectedTokenTypes), receivedToken.location); this.expectedTokenTypes = expectedTokenTypes; this.stateComment = stateComment; } private static String getMessage(List expectedTokenTypes) { return String.format("unexpected end of file, expected: %s", StringUtils.join(", ", expectedTokenTypes)); } } public static class CompositeParserException extends ParserException { public final List errors; public CompositeParserException(List errors) { super(getMessage(errors)); this.errors = Collections.unmodifiableList(errors); } private static String getMessage(List errors) { if (errors == null) throw new NullPointerException("errors"); StringUtils.ToString exceptionToString = new StringUtils.ToString() { @Override public String toString(ParserException e) { return e.getMessage(); } }; return "Parser errors:\n" + StringUtils.join(exceptionToString, "\n", errors); } } } ================================================ FILE: greencoffee/src/main/java/gherkin/StringUtils.java ================================================ package gherkin; import java.util.List; public class StringUtils { public static String join(String separator, List items) { return join(ToString.DEFAULT, separator, items); } public static String join(ToString toString, String separator, Iterable items) { StringBuilder sb = new StringBuilder(); boolean useSeparator = false; for (T item : items) { if (useSeparator) sb.append(separator); useSeparator = true; sb.append(toString.toString(item)); } return sb.toString(); } public static String ltrim(String s) { int i = 0; while (i < s.length() && Character.isWhitespace(s.charAt(i))) { i++; } return s.substring(i); } public interface ToString { ToString DEFAULT = new ToString() { @Override public String toString(String o) { return o; } }; String toString(T o); } } ================================================ FILE: greencoffee/src/main/java/gherkin/SymbolCounter.java ================================================ package gherkin; // http://rosettacode.org/wiki/String_length#Java public class SymbolCounter { public static int countSymbols(String string) { return string.codePointCount(0, string.length()); } } ================================================ FILE: greencoffee/src/main/java/gherkin/Token.java ================================================ package gherkin; import gherkin.ast.Location; import java.util.List; public class Token { public final IGherkinLine line; public Parser.TokenType matchedType; public String matchedKeyword; public String matchedText; public List mathcedItems; public int matchedIndent; public GherkinDialect matchedGherkinDialect; public Location location; public Token(IGherkinLine line, Location location) { this.line = line; this.location = location; } public boolean isEOF() { return line == null; } public void detach() { if (line != null) line.detach(); } public String getTokenValue() { return isEOF() ? "EOF" : line.getLineText(-1); } @Override public String toString() { return String.format("%s: %s/%s", matchedType, matchedKeyword, matchedText); } } ================================================ FILE: greencoffee/src/main/java/gherkin/TokenFormatter.java ================================================ package gherkin; public class TokenFormatter { private static final StringUtils.ToString SPAN_TO_STRING = new StringUtils.ToString() { @Override public String toString(GherkinLineSpan o) { return o.column + ":" + o.text; } }; public String formatToken(Token token) { if (token.isEOF()) return "EOF"; return String.format("(%s:%s)%s:%s/%s/%s", toString(token.location.getLine()), toString(token.location.getColumn()), toString(token.matchedType), toString(token.matchedKeyword), toString(token.matchedText), toString(token.mathcedItems == null ? "" : StringUtils.join(SPAN_TO_STRING, ",", token.mathcedItems)) ); } private String toString(Object o) { return o == null ? "" : o.toString(); } } ================================================ FILE: greencoffee/src/main/java/gherkin/TokenFormatterBuilder.java ================================================ package gherkin; public class TokenFormatterBuilder implements Parser.Builder { private final TokenFormatter formatter = new TokenFormatter(); private final StringBuilder tokensTextBuilder = new StringBuilder(); @Override public void build(Token token) { tokensTextBuilder.append(formatter.formatToken(token)).append("\n"); } @Override public void startRule(Parser.RuleType ruleType) { } @Override public void endRule(Parser.RuleType ruleType) { } @Override public String getResult() { return tokensTextBuilder.toString(); } @Override public void reset() { } } ================================================ FILE: greencoffee/src/main/java/gherkin/TokenMatcher.java ================================================ package gherkin; import gherkin.ast.Location; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import static gherkin.Parser.ITokenMatcher; import static gherkin.Parser.TokenType; public class TokenMatcher implements ITokenMatcher { private static final Pattern LANGUAGE_PATTERN = Pattern.compile("^\\s*#\\s*language\\s*:\\s*([a-zA-Z\\-_]+)\\s*$"); private final IGherkinDialectProvider dialectProvider; private GherkinDialect currentDialect; private String activeDocStringSeparator = null; private int indentToRemove = 0; public TokenMatcher(IGherkinDialectProvider dialectProvider) { this.dialectProvider = dialectProvider; reset(); } public TokenMatcher() { this(new GherkinDialectProvider()); } public TokenMatcher(String default_dialect_name) { this(new GherkinDialectProvider(default_dialect_name)); } @Override public void reset() { activeDocStringSeparator = null; indentToRemove = 0; currentDialect = dialectProvider.getDefaultDialect(); } public GherkinDialect getCurrentDialect() { return currentDialect; } protected void setTokenMatched(Token token, TokenType matchedType, String text, String keyword, Integer indent, List items) { token.matchedType = matchedType; token.matchedKeyword = keyword; token.matchedText = text; token.mathcedItems = items; token.matchedGherkinDialect = getCurrentDialect(); token.matchedIndent = indent != null ? indent : (token.line == null ? 0 : token.line.indent()); token.location = new Location(token.location.getLine(), token.matchedIndent + 1); } @Override public boolean match_EOF(Token token) { if (token.isEOF()) { setTokenMatched(token, TokenType.EOF, null, null, null, null); return true; } return false; } @Override public boolean match_Other(Token token) { String text = token.line.getLineText(indentToRemove); //take the entire line, except removing DocString indents setTokenMatched(token, TokenType.Other, unescapeDocString(text), null, 0, null); return true; } @Override public boolean match_Empty(Token token) { if (token.line.isEmpty()) { setTokenMatched(token, TokenType.Empty, null, null, null, null); return true; } return false; } @Override public boolean match_Comment(Token token) { if (token.line.startsWith(GherkinLanguageConstants.COMMENT_PREFIX)) { String text = token.line.getLineText(0); //take the entire line setTokenMatched(token, TokenType.Comment, text, null, 0, null); return true; } return false; } @Override public boolean match_Language(Token token) { Matcher matcher = LANGUAGE_PATTERN.matcher(token.line.getLineText(0)); if (matcher.matches()) { String language = matcher.group(1); setTokenMatched(token, TokenType.Language, language, null, null, null); currentDialect = dialectProvider.getDialect(language, token.location); return true; } return false; } @Override public boolean match_TagLine(Token token) { if (token.line.startsWith(GherkinLanguageConstants.TAG_PREFIX)) { setTokenMatched(token, TokenType.TagLine, null, null, null, token.line.getTags()); return true; } return false; } @Override public boolean match_FeatureLine(Token token) { return matchTitleLine(token, TokenType.FeatureLine, currentDialect.getFeatureKeywords()); } @Override public boolean match_BackgroundLine(Token token) { return matchTitleLine(token, TokenType.BackgroundLine, currentDialect.getBackgroundKeywords()); } @Override public boolean match_ScenarioLine(Token token) { return matchTitleLine(token, TokenType.ScenarioLine, currentDialect.getScenarioKeywords()); } @Override public boolean match_ScenarioOutlineLine(Token token) { return matchTitleLine(token, TokenType.ScenarioOutlineLine, currentDialect.getScenarioOutlineKeywords()); } @Override public boolean match_ExamplesLine(Token token) { return matchTitleLine(token, TokenType.ExamplesLine, currentDialect.getExamplesKeywords()); } private boolean matchTitleLine(Token token, TokenType tokenType, List keywords) { for (String keyword : keywords) { if (token.line.startsWithTitleKeyword(keyword)) { String title = token.line.getRestTrimmed(keyword.length() + GherkinLanguageConstants.TITLE_KEYWORD_SEPARATOR.length()); setTokenMatched(token, tokenType, title, keyword, null, null); return true; } } return false; } @Override public boolean match_DocStringSeparator(Token token) { return activeDocStringSeparator == null // open ? match_DocStringSeparator(token, GherkinLanguageConstants.DOCSTRING_SEPARATOR, true) || match_DocStringSeparator(token, GherkinLanguageConstants.DOCSTRING_ALTERNATIVE_SEPARATOR, true) // close : match_DocStringSeparator(token, activeDocStringSeparator, false); } private boolean match_DocStringSeparator(Token token, String separator, boolean isOpen) { if (token.line.startsWith(separator)) { String contentType = null; if (isOpen) { contentType = token.line.getRestTrimmed(separator.length()); activeDocStringSeparator = separator; indentToRemove = token.line.indent(); } else { activeDocStringSeparator = null; indentToRemove = 0; } setTokenMatched(token, TokenType.DocStringSeparator, contentType, null, null, null); return true; } return false; } @Override public boolean match_StepLine(Token token) { List keywords = currentDialect.getStepKeywords(); for (String keyword : keywords) { if (token.line.startsWith(keyword)) { String stepText = token.line.getRestTrimmed(keyword.length()); setTokenMatched(token, TokenType.StepLine, stepText, keyword, null, null); return true; } } return false; } @Override public boolean match_TableRow(Token token) { if (token.line.startsWith(GherkinLanguageConstants.TABLE_CELL_SEPARATOR)) { setTokenMatched(token, TokenType.TableRow, null, null, null, token.line.getTableCells()); return true; } return false; } private String unescapeDocString(String text) { return activeDocStringSeparator != null ? text.replace("\\\"\\\"\\\"", "\"\"\"") : text; } } ================================================ FILE: greencoffee/src/main/java/gherkin/TokenScanner.java ================================================ package gherkin; import gherkin.ast.Location; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.io.StringReader; /** *

* The scanner reads a gherkin doc (typically read from a .feature file) and creates a token * for each line. The tokens are passed to the parser, which outputs an AST (Abstract Syntax Tree).

*

*

* If the scanner sees a # language header, it will reconfigure itself dynamically to look for * Gherkin keywords for the associated language. The keywords are defined in gherkin-languages.json.

*/ public class TokenScanner implements Parser.ITokenScanner { private final BufferedReader reader; private int lineNumber; public TokenScanner(String source) { this(new StringReader(source)); } public TokenScanner(Reader source) { this.reader = new BufferedReader(source); } @Override public Token read() { try { String line = reader.readLine(); Location location = new Location(++lineNumber, 0); return line == null ? new Token(null, location) : new Token(new GherkinLine(line), location); } catch (IOException e) { throw new RuntimeException(e); } } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/Background.java ================================================ package gherkin.ast; import java.util.List; public class Background extends ScenarioDefinition { public Background(Location location, String keyword, String name, String description, List steps) { super(location, keyword, name, description, steps); } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/Comment.java ================================================ package gherkin.ast; public class Comment extends Node { private final String text; public Comment(Location location, String text) { super(location); this.text = text; } public String getText() { return text; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/DataTable.java ================================================ package gherkin.ast; import java.util.Collections; import java.util.List; public class DataTable extends Node { private final List rows; public DataTable(List rows) { super(rows.get(0).getLocation()); this.rows = Collections.unmodifiableList(rows); } public List getRows() { return rows; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/DocString.java ================================================ package gherkin.ast; public class DocString extends Node { private final String contentType; private final String content; public DocString(Location location, String contentType, String content) { super(location); this.contentType = contentType; this.content = content; } public String getContent() { return content; } public String getContentType() { return contentType; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/Examples.java ================================================ package gherkin.ast; import java.util.Collections; import java.util.List; public class Examples extends Node { private final List tags; private final String keyword; private final String name; private final String description; private final TableRow tableHeader; private final List tableBody; public Examples(Location location, List tags, String keyword, String name, String description, TableRow tableHeader, List tableBody) { super(location); this.tags = Collections.unmodifiableList(tags); this.keyword = keyword; this.name = name; this.description = description; this.tableHeader = tableHeader; this.tableBody = tableBody != null ? Collections.unmodifiableList(tableBody) : null; } public String getKeyword() { return keyword; } public String getName() { return name; } public String getDescription() { return description; } public List getTableBody() { return tableBody; } public TableRow getTableHeader() { return tableHeader; } public List getTags() { return tags; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/Feature.java ================================================ package gherkin.ast; import java.util.Collections; import java.util.List; public class Feature extends Node { private final List tags; private final String language; private final String keyword; private final String name; private final String description; private final List children; public Feature( List tags, Location location, String language, String keyword, String name, String description, List children) { super(location); this.tags = Collections.unmodifiableList(tags); this.language = language; this.keyword = keyword; this.name = name; this.description = description; this.children = Collections.unmodifiableList(children); } public List getChildren() { return children; } public String getLanguage() { return language; } public String getKeyword() { return keyword; } public String getName() { return name; } public String getDescription() { return description; } public List getTags() { return tags; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/GherkinDocument.java ================================================ package gherkin.ast; import java.util.Collections; import java.util.List; public class GherkinDocument extends Node { private final Feature feature; private final List comments; public GherkinDocument( Feature feature, List comments) { super(null); this.feature = feature; this.comments = Collections.unmodifiableList(comments); } public Feature getFeature() { return feature; } public List getComments() { return comments; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/Location.java ================================================ package gherkin.ast; public class Location { private final int line; private final int column; public Location(int line, int column) { this.line = line; this.column = column; } public int getLine() { return line; } public int getColumn() { return column; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/Node.java ================================================ package gherkin.ast; public abstract class Node { private final String type = getClass().getSimpleName(); private final Location location; protected Node(Location location) { this.location = location; } public Location getLocation() { return location; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/Scenario.java ================================================ package gherkin.ast; import java.util.Collections; import java.util.List; public class Scenario extends ScenarioDefinition { private final List tags; public Scenario(List tags, Location location, String keyword, String name, String description, List steps) { super(location, keyword, name, description, steps); this.tags = Collections.unmodifiableList(tags); } public List getTags() { return tags; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/ScenarioDefinition.java ================================================ package gherkin.ast; import java.util.Collections; import java.util.List; public abstract class ScenarioDefinition extends Node { private final String keyword; private final String name; private final String description; private final List steps; public ScenarioDefinition(Location location, String keyword, String name, String description, List steps) { super(location); this.keyword = keyword; this.name = name; this.description = description; this.steps = Collections.unmodifiableList(steps); } public String getName() { return name; } public String getKeyword() { return keyword; } public String getDescription() { return description; } public List getSteps() { return steps; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/ScenarioOutline.java ================================================ package gherkin.ast; import java.util.Collections; import java.util.List; public class ScenarioOutline extends ScenarioDefinition { private final List tags; private final List examples; public ScenarioOutline(List tags, Location location, String keyword, String name, String description, List steps, List examples) { super(location, keyword, name, description, steps); this.tags = Collections.unmodifiableList(tags); this.examples = Collections.unmodifiableList(examples); } public List getTags() { return tags; } public List getExamples() { return examples; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/Step.java ================================================ package gherkin.ast; public class Step extends Node { private final String keyword; private final String text; private final Node argument; public Step(Location location, String keyword, String text, Node argument) { super(location); this.keyword = keyword; this.text = text; this.argument = argument; } public String getText() { return text; } public String getKeyword() { return keyword; } public Node getArgument() { return argument; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/TableCell.java ================================================ package gherkin.ast; public class TableCell extends Node { private final String value; public TableCell(Location location, String value) { super(location); this.value = value; } public String getValue() { return value; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/TableRow.java ================================================ package gherkin.ast; import java.util.Collections; import java.util.List; public class TableRow extends Node { private final List cells; public TableRow(Location location, List cells) { super(location); this.cells = Collections.unmodifiableList(cells); } public List getCells() { return cells; } } ================================================ FILE: greencoffee/src/main/java/gherkin/ast/Tag.java ================================================ package gherkin.ast; public class Tag extends Node { private final String name; public Tag(Location location, String name) { super(location); this.name = name; } public String getName() { return name; } } ================================================ FILE: greencoffee/src/main/java/gherkin/cli/Main.java ================================================ package gherkin.cli; import gherkin.stream.Stdio; import gherkin.deps.com.google.gson.Gson; import gherkin.deps.com.google.gson.GsonBuilder; import gherkin.events.CucumberEvent; import gherkin.events.SourceEvent; import gherkin.stream.GherkinEvents; import gherkin.stream.SourceEvents; import java.io.IOException; import java.util.ArrayList; import java.util.List; import static java.util.Arrays.asList; public class Main { public static void main(String[] argv) throws IOException { final Gson gson = new GsonBuilder().create(); List args = new ArrayList<>(asList(argv)); List paths = new ArrayList<>(); boolean printSource = true; boolean printAst = true; boolean printPickles = true; while (!args.isEmpty()) { String arg = args.remove(0).trim(); switch (arg) { case "--no-source": printSource = false; break; case "--no-ast": printAst = false; break; case "--no-pickles": printPickles = false; break; default: paths.add(arg); } } SourceEvents sourceEvents = new SourceEvents(paths); GherkinEvents gherkinEvents = new GherkinEvents(printSource, printAst, printPickles); for (SourceEvent sourceEventEvent : sourceEvents) { for (CucumberEvent cucumberEvent : gherkinEvents.iterable(sourceEventEvent)) { Stdio.out.write(gson.toJson(cucumberEvent)); Stdio.out.write("\n"); Stdio.out.flush(); } } } } ================================================ FILE: greencoffee/src/main/java/gherkin/events/AttachmentEvent.java ================================================ package gherkin.events; public class AttachmentEvent implements CucumberEvent { private final String type = "attachment"; private final SourceRef source; private final String data; private final Media media = new Media(); public AttachmentEvent(SourceRef source, String data) { this.source = source; this.data = data; } public static class SourceRef { private final String uri; private final Location start; public SourceRef(String uri, Location start) { this.uri = uri; this.start = start; } } public static class Location { private final int line; private final int column; public Location(int line, int column) { this.line = line; this.column = column; } } public static class Media { private final String encoding = "utf-8"; private final String type = "text/vnd.cucumber.stacktrace+plain"; } } ================================================ FILE: greencoffee/src/main/java/gherkin/events/CucumberEvent.java ================================================ package gherkin.events; public interface CucumberEvent { } ================================================ FILE: greencoffee/src/main/java/gherkin/events/GherkinDocumentEvent.java ================================================ package gherkin.events; import gherkin.ast.GherkinDocument; public class GherkinDocumentEvent implements CucumberEvent { private final String type = "gherkin-document"; public final String uri; public final GherkinDocument document; public GherkinDocumentEvent(String uri, GherkinDocument document) { this.uri = uri; this.document = document; } } ================================================ FILE: greencoffee/src/main/java/gherkin/events/PickleEvent.java ================================================ package gherkin.events; import gherkin.pickles.Pickle; public class PickleEvent implements CucumberEvent { private final String type = "pickle"; public final String uri; public final Pickle pickle; public PickleEvent(String uri, Pickle pickle) { this.uri = uri; this.pickle = pickle; } } ================================================ FILE: greencoffee/src/main/java/gherkin/events/SourceEvent.java ================================================ package gherkin.events; public class SourceEvent implements CucumberEvent { private final String type = "source"; public final String uri; public final String data; private final Media media = new Media(); public SourceEvent(String uri, String data) { this.uri = uri; this.data = data; } public static class Media { private final String encoding = "utf-8"; private final String type = "text/vnd.cucumber.gherkin+plain"; } } ================================================ FILE: greencoffee/src/main/java/gherkin/pickles/Argument.java ================================================ package gherkin.pickles; public interface Argument { PickleLocation getLocation(); } ================================================ FILE: greencoffee/src/main/java/gherkin/pickles/Compiler.java ================================================ package gherkin.pickles; import gherkin.SymbolCounter; import gherkin.ast.Background; import gherkin.ast.DataTable; import gherkin.ast.DocString; import gherkin.ast.Examples; import gherkin.ast.Feature; import gherkin.ast.GherkinDocument; import gherkin.ast.Location; import gherkin.ast.Node; import gherkin.ast.Scenario; import gherkin.ast.ScenarioDefinition; import gherkin.ast.ScenarioOutline; import gherkin.ast.Step; import gherkin.ast.TableCell; import gherkin.ast.TableRow; import gherkin.ast.Tag; import java.util.ArrayList; import java.util.List; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.Collections.unmodifiableList; public class Compiler { public List compile(GherkinDocument gherkinDocument) { List pickles = new ArrayList<>(); Feature feature = gherkinDocument.getFeature(); if (feature == null) { return pickles; } List featureTags = feature.getTags(); List backgroundSteps = new ArrayList<>(); for (ScenarioDefinition scenarioDefinition : feature.getChildren()) { if (scenarioDefinition instanceof Background) { backgroundSteps = pickleSteps(scenarioDefinition); } else if (scenarioDefinition instanceof Scenario) { compileScenario(pickles, backgroundSteps, (Scenario) scenarioDefinition, featureTags); } else { compileScenarioOutline(pickles, backgroundSteps, (ScenarioOutline) scenarioDefinition, featureTags); } } return pickles; } private void compileScenario(List pickles, List backgroundSteps, Scenario scenario, List featureTags) { if (scenario.getSteps().isEmpty()) return; List steps = new ArrayList<>(); steps.addAll(backgroundSteps); List scenarioTags = new ArrayList<>(); scenarioTags.addAll(featureTags); scenarioTags.addAll(scenario.getTags()); steps.addAll(pickleSteps(scenario)); Pickle pickle = new Pickle( scenario.getName(), steps, pickleTags(scenarioTags), singletonList(pickleLocation(scenario.getLocation())) ); pickles.add(pickle); } private void compileScenarioOutline(List pickles, List backgroundSteps, ScenarioOutline scenarioOutline, List featureTags) { if (scenarioOutline.getSteps().isEmpty()) return; for (final Examples examples : scenarioOutline.getExamples()) { if (examples.getTableHeader() == null) continue; List variableCells = examples.getTableHeader().getCells(); for (final TableRow values : examples.getTableBody()) { List valueCells = values.getCells(); List steps = new ArrayList<>(); steps.addAll(backgroundSteps); List tags = new ArrayList<>(); tags.addAll(featureTags); tags.addAll(scenarioOutline.getTags()); tags.addAll(examples.getTags()); for (Step scenarioOutlineStep : scenarioOutline.getSteps()) { String stepText = interpolate(scenarioOutlineStep.getText(), variableCells, valueCells); // TODO: Use an Array of location in DataTable/DocString as well. // If the Gherkin AST classes supported // a list of locations, we could just reuse the same classes PickleStep pickleStep = new PickleStep( stepText, createPickleArguments(scenarioOutlineStep.getArgument(), variableCells, valueCells), asList( pickleLocation(values.getLocation()), pickleStepLocation(scenarioOutlineStep) ) ); steps.add(pickleStep); } Pickle pickle = new Pickle( interpolate(scenarioOutline.getName(), variableCells, valueCells), steps, pickleTags(tags), asList( pickleLocation(values.getLocation()), pickleLocation(scenarioOutline.getLocation()) ) ); pickles.add(pickle); } } } private List createPickleArguments(Node argument) { List noCells = emptyList(); return createPickleArguments(argument, noCells, noCells); } private List createPickleArguments(Node argument, List variableCells, List valueCells) { List result = new ArrayList<>(); if (argument == null) return result; if (argument instanceof DataTable) { DataTable t = (DataTable) argument; List rows = t.getRows(); List newRows = new ArrayList<>(rows.size()); for (TableRow row : rows) { List cells = row.getCells(); List newCells = new ArrayList<>(); for (TableCell cell : cells) { newCells.add( new PickleCell( pickleLocation(cell.getLocation()), interpolate(cell.getValue(), variableCells, valueCells) ) ); } newRows.add(new PickleRow(newCells)); } result.add(new PickleTable(newRows)); } else if (argument instanceof DocString) { DocString ds = (DocString) argument; result.add( new PickleString( pickleLocation(ds.getLocation()), interpolate(ds.getContent(), variableCells, valueCells) ) ); } else { throw new RuntimeException("Unexpected argument type: " + argument); } return result; } private List pickleSteps(ScenarioDefinition scenarioDefinition) { List result = new ArrayList<>(); for (Step step : scenarioDefinition.getSteps()) { result.add(pickleStep(step)); } return unmodifiableList(result); } private PickleStep pickleStep(Step step) { return new PickleStep( step.getText(), createPickleArguments(step.getArgument()), singletonList(pickleStepLocation(step)) ); } private String interpolate(String name, List variableCells, List valueCells) { int col = 0; for (TableCell variableCell : variableCells) { TableCell valueCell = valueCells.get(col++); String header = variableCell.getValue(); String value = valueCell.getValue(); name = name.replace("<" + header + ">", value); } return name; } private PickleLocation pickleStepLocation(Step step) { return new PickleLocation( step.getLocation().getLine(), step.getLocation().getColumn() + (step.getKeyword() != null ? SymbolCounter.countSymbols(step.getKeyword()) : 0) ); } private PickleLocation pickleLocation(Location location) { return new PickleLocation(location.getLine(), location.getColumn()); } private List pickleTags(List tags) { List result = new ArrayList<>(); for (Tag tag : tags) { result.add(pickleTag(tag)); } return result; } private PickleTag pickleTag(Tag tag) { return new PickleTag(pickleLocation(tag.getLocation()), tag.getName()); } } ================================================ FILE: greencoffee/src/main/java/gherkin/pickles/Pickle.java ================================================ package gherkin.pickles; import java.util.List; import static java.util.Collections.unmodifiableList; public class Pickle { private final String name; private final List steps; private final List tags; private final List locations; public Pickle(String name, List steps, List tags, List locations) { this.name = name; this.steps = unmodifiableList(steps); this.tags = tags; this.locations = unmodifiableList(locations); } public String getName() { return name; } public List getSteps() { return steps; } public List getLocations() { return locations; } public List getTags() { return tags; } } ================================================ FILE: greencoffee/src/main/java/gherkin/pickles/PickleCell.java ================================================ package gherkin.pickles; public class PickleCell { private final PickleLocation location; private final String value; public PickleCell(PickleLocation location, String value) { this.location = location; this.value = value; } public String getValue() { return value; } public PickleLocation getLocation() { return location; } } ================================================ FILE: greencoffee/src/main/java/gherkin/pickles/PickleLocation.java ================================================ package gherkin.pickles; public class PickleLocation { private final int line; private final int column; public PickleLocation(int line, int column) { this.line = line; this.column = column; } public int getLine() { return line; } public int getColumn() { return column; } } ================================================ FILE: greencoffee/src/main/java/gherkin/pickles/PickleRow.java ================================================ package gherkin.pickles; import java.util.List; import static java.util.Collections.unmodifiableList; public class PickleRow { private final List cells; public PickleRow(List cells) { this.cells = unmodifiableList(cells); } public List getCells() { return cells; } } ================================================ FILE: greencoffee/src/main/java/gherkin/pickles/PickleStep.java ================================================ package gherkin.pickles; import java.util.List; import static java.util.Collections.unmodifiableList; public class PickleStep { private final String text; private final List arguments; private final List locations; public PickleStep(String text, List arguments, List locations) { this.text = text; this.arguments = unmodifiableList(arguments); this.locations = unmodifiableList(locations); } public String getText() { return text; } public List getLocations() { return locations; } public List getArgument() { return arguments; } } ================================================ FILE: greencoffee/src/main/java/gherkin/pickles/PickleString.java ================================================ package gherkin.pickles; public class PickleString implements Argument { private final PickleLocation location; private final String content; public PickleString(PickleLocation location, String content) { this.location = location; this.content = content; } @Override public PickleLocation getLocation() { return location; } public String getContent() { return content; } } ================================================ FILE: greencoffee/src/main/java/gherkin/pickles/PickleTable.java ================================================ package gherkin.pickles; import java.util.List; import static java.util.Collections.unmodifiableList; public class PickleTable implements Argument { private final List rows; public PickleTable(List rows) { this.rows = unmodifiableList(rows); } public List getRows() { return rows; } @Override public PickleLocation getLocation() { return rows.get(0).getCells().get(0).getLocation(); } } ================================================ FILE: greencoffee/src/main/java/gherkin/pickles/PickleTag.java ================================================ package gherkin.pickles; public class PickleTag { private final PickleLocation location; private final String name; public PickleTag(PickleLocation location, String name) { this.location = location; this.name = name; } public String getName() { return name; } } ================================================ FILE: greencoffee/src/main/java/gherkin/stream/GherkinEvents.java ================================================ package gherkin.stream; import gherkin.AstBuilder; import gherkin.Parser; import gherkin.ParserException; import gherkin.TokenMatcher; import gherkin.ast.GherkinDocument; import gherkin.events.AttachmentEvent; import gherkin.events.CucumberEvent; import gherkin.events.GherkinDocumentEvent; import gherkin.events.PickleEvent; import gherkin.events.SourceEvent; import gherkin.pickles.Compiler; import gherkin.pickles.Pickle; import java.util.ArrayList; import java.util.List; public class GherkinEvents { private final Parser parser = new Parser<>(new AstBuilder()); private final TokenMatcher matcher = new TokenMatcher(); private final Compiler compiler = new Compiler(); private final boolean printSource; private final boolean printAst; private final boolean printPickles; public GherkinEvents(boolean printSource, boolean printAst, boolean printPickles) { this.printSource = printSource; this.printAst = printAst; this.printPickles = printPickles; } public Iterable iterable(SourceEvent sourceEvent) { List cucumberEvents = new ArrayList<>(); try { GherkinDocument gherkinDocument = parser.parse(sourceEvent.data, matcher); if (printSource) { cucumberEvents.add(sourceEvent); } if (printAst) { cucumberEvents.add(new GherkinDocumentEvent(sourceEvent.uri, gherkinDocument)); } if (printPickles) { List pickles = compiler.compile(gherkinDocument); for (Pickle pickle : pickles) { cucumberEvents.add(new PickleEvent(sourceEvent.uri, pickle)); } } } catch (ParserException.CompositeParserException e) { for (ParserException error : e.errors) { addErrorAttachment(cucumberEvents, error, sourceEvent.uri); } } catch (ParserException e) { addErrorAttachment(cucumberEvents, e, sourceEvent.uri); } return cucumberEvents; } private void addErrorAttachment(List cucumberEvents, ParserException e, String uri) { cucumberEvents.add(new AttachmentEvent( new AttachmentEvent.SourceRef( uri, new AttachmentEvent.Location( e.location.getLine(), e.location.getColumn() ) ), e.getMessage() )); } } ================================================ FILE: greencoffee/src/main/java/gherkin/stream/SourceEvents.java ================================================ package gherkin.stream; import gherkin.events.SourceEvent; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.util.Iterator; import java.util.List; public class SourceEvents implements Iterable { private final List paths; public SourceEvents(List paths) { this.paths = paths; } @Override public Iterator iterator() { final Iterator pathIterator = paths.iterator(); return new Iterator() { @Override public boolean hasNext() { return pathIterator.hasNext(); } @Override public SourceEvent next() { try { String path = pathIterator.next(); String data = read(new InputStreamReader(new FileInputStream(path), "UTF-8")); return new SourceEvent(path, data); } catch (IOException e) { throw new RuntimeException(e); } } @Override public void remove() { throw new UnsupportedOperationException(); } }; } private static String read(Reader reader) throws IOException { final char[] buffer = new char[0x10000]; StringBuilder sb = new StringBuilder(); int read; do { read = reader.read(buffer, 0, buffer.length); if (read > 0) { sb.append(buffer, 0, read); } } while (read >= 0); return sb.toString(); } } ================================================ FILE: greencoffee/src/main/java/gherkin/stream/Stdio.java ================================================ package gherkin.stream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.Charset; /** * UTF-8 STDOUT and STDERR */ public class Stdio { public static final PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out, Charset.forName("UTF-8")), true); public static final PrintWriter err = new PrintWriter(new OutputStreamWriter(System.err, Charset.forName("UTF-8")), true); } ================================================ FILE: settings.gradle ================================================ include ':greencoffee'