├── src ├── test │ ├── resources │ │ ├── uncorrect │ │ │ ├── empty.feature │ │ │ └── example7.feature │ │ └── correct │ │ │ ├── example1.feature │ │ │ ├── example2.feature │ │ │ ├── example4.feature │ │ │ ├── example3.feature │ │ │ ├── example5.feature │ │ │ ├── example6.feature │ │ │ └── example8.feature │ └── java │ │ ├── TestUtils.java │ │ ├── TGLexerTest.java │ │ └── TGParserTest.java └── main │ ├── java │ └── com │ │ └── github │ │ └── _1c_syntax │ │ └── turbo │ │ └── gherkin │ │ └── parser │ │ ├── GherkinParserRuleContext.java │ │ ├── CRAwareLexerATNSimulatorWrapper.java │ │ └── GherkinTokenizer.java │ └── antlr │ ├── TurboGherkinParser.g4 │ └── TurboGherkinLexer.g4 ├── .gitattributes ├── settings.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .idea ├── encodings.xml └── codeStyles │ └── Project.xml ├── .gitignore ├── readme.md ├── license └── HEADER.txt ├── gradlew.bat ├── gradlew ├── COPYING.LESSER.md └── COPYING.md /src/test/resources/uncorrect/empty.feature: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.java eol=lf 2 | *.g4 eol=lf 3 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "turbo-gherkin-parser" 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1c-syntax/turbo-gherkin-parser/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.gradle/ 2 | /.idea/jarRepositories.xml 3 | /.idea/sonarlint/ 4 | /.idea/misc.xml 5 | /build/ 6 | /src/main/gen/ 7 | /.idea/gradle.xml 8 | /.idea/compiler.xml 9 | /.idea/.gitignore 10 | /src/main/antlr/gen/ 11 | /.idea/vcs.xml 12 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Turbo Gherkin parser 2 | 3 | Библиотека для парсинга файлов сценариев на языке Gherkin в редакции Turbo Gherkin. 4 | 5 | На данный момент поддерживается большая часть синтаксиса на английском и русском языках. 6 | 7 | ## TODO LIST 8 | * доделать условия IF_KEYWORD 9 | * доделать обработку комментариев-метаданных 10 | * доделать вставок для инструкций 11 | * реализовать поддержку расширения СППР 12 | * реализовать поддержку циклов 13 | * реализовать поддержку комментариев `//` 14 | * реализовать национальных языков -------------------------------------------------------------------------------- /src/test/resources/correct/example1.feature: -------------------------------------------------------------------------------- 1 | # from https://cucumber.io/docs/gherkin/reference/ 2 | Feature: Guess the word 3 | 4 | # The first example has two steps 5 | Scenario: Maker starts a game 6 | When the Maker starts a game 7 | Then the Maker waits for a Breaker to join 8 | 9 | # The second example has three steps 10 | Scenario: Breaker joins a game 11 | Given the Maker has started a game with the word "silky" 12 | When the Breaker joins the Maker's game 13 | Then the Breaker must guess a word with 5 characters -------------------------------------------------------------------------------- /src/test/resources/correct/example2.feature: -------------------------------------------------------------------------------- 1 | # from https://cucumber.io/docs/gherkin/reference/ 2 | Feature: Highlander 3 | 4 | Rule: There can be only One 5 | 6 | Example: Only One -- More than one alive 7 | Given there are 3 ninjas 8 | And there are more than one ninja alive 9 | When 2 ninjas meet, they will fight 10 | Then one ninja dies (but not me) 11 | And there is one ninja less alive 12 | 13 | Example: Only One -- One alive 14 | Given there is only 1 ninja alive 15 | Then he (or she) will live forever ;-) 16 | 17 | Rule: There can be Two (in some cases) 18 | 19 | Example: Two -- Dead and Reborn as Phoenix -------------------------------------------------------------------------------- /src/test/resources/correct/example4.feature: -------------------------------------------------------------------------------- 1 | # from https://cucumber.io/docs/gherkin/reference/ 2 | Feature: Overdue tasks 3 | Let users know when tasks are overdue, even when using other 4 | features of the app 5 | 6 | Rule: Users are notified about overdue tasks on first use of the day 7 | Background: 8 | Given I have overdue tasks 9 | 10 | Example: First use of the day 11 | Given I last used the app yesterday 12 | When I use the app 13 | Then I am notified about overdue tasks 14 | 15 | Example: Already used today 16 | Given I last used the app earlier today 17 | When I use the app 18 | Then I am not notified about overdue tasks -------------------------------------------------------------------------------- /license/HEADER.txt: -------------------------------------------------------------------------------- 1 | This file is a part of ${project}. 2 | 3 | Copyright © ${year} 4 | ${name} and contributors 5 | 6 | SPDX-License-Identifier: LGPL-3.0-or-later 7 | 8 | ${project} is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU Lesser General Public 10 | License as published by the Free Software Foundation; either 11 | version 3.0 of the License, or (at your option) any later version. 12 | 13 | ${project} is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | Lesser General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public 19 | License along with ${project}. 20 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/correct/example3.feature: -------------------------------------------------------------------------------- 1 | # from https://cucumber.io/docs/gherkin/reference/ 2 | Feature: Multiple site support 3 | Only blog owners can post to a blog, except administrators, 4 | who can post to all blogs. 5 | 6 | Background: 7 | Given a global administrator named "Greg" 8 | And a blog named "Greg's anti-tax rants" 9 | And a customer named "Dr. Bill" 10 | And a blog named "Expensive Therapy" owned by "Dr. Bill" 11 | 12 | Scenario: Dr. Bill posts to his own blog 13 | Given I am logged in as Dr. Bill 14 | When I try to post to "Expensive Therapy" 15 | Then I should see "Your article was published." 16 | 17 | Scenario: Dr. Bill tries to post to somebody else's blog, and fails 18 | Given I am logged in as Dr. Bill 19 | When I try to post to "Greg's anti-tax rants" 20 | Then I should see "Hey! That's not your blog!" 21 | 22 | Scenario: Greg posts to a client's blog 23 | Given I am logged in as Greg 24 | When I try to post to "Expensive Therapy" 25 | Then I should see "Your article was published." -------------------------------------------------------------------------------- /src/test/resources/correct/example5.feature: -------------------------------------------------------------------------------- 1 | # from https://cucumber.io/docs/gherkin/reference/ 2 | Feature: params 3 | Scenario: eat 5 out of 12 4 | Given there are 12 cucumbers 5 | When I eat 5 cucumbers 6 | Then I should have 7 cucumbers 7 | 8 | Given a blog post named "Random" with Markdown body 9 | """ 10 | Some Title, Eh? 11 | =============== 12 | Here is the first paragraph of my blog post. Lorem ipsum dolor sit amet, 13 | consectetur adipiscing elit. 14 | """ 15 | 16 | Scenario: eat 5 out of 20 17 | Given there are 20 cucumbers 18 | When I eat 5 cucumbers 19 | Then I should have 15 cucumbers 20 | 21 | Scenario Outline: eating 22 | Given there are cucumbers 23 | When I eat cucumbers 24 | Then I should have cucumbers 25 | 26 | Given the following users exist: 27 | | name | email | twitter | 28 | | Aslak | aslak@cucumber.io | @aslak_hellesoy | 29 | | Julien | julien@cucumber.io | @jbpros | 30 | | Matt | matt@cucumber.io | @mattwynne | 31 | 32 | Examples: 33 | | start | eat | left | 34 | | 12 | 5 | 7 | 35 | | 20 | 5 | 15 | -------------------------------------------------------------------------------- /src/test/resources/correct/example6.feature: -------------------------------------------------------------------------------- 1 | # from https://github.com/Pr-Mex/vanessa-automation/blob/develop/features/Core/CucumberReport/%D0%A4%D0%BE%D1%80%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%9E%D1%82%D1%87%D0%B5%D1%82%D0%B0Cucumber.feature 2 | # language: ru 3 | #parent uf: 4 | @UF5_формирование_результатов_выполнения_сценариев 5 | #parent ua: 6 | @UA19_формировать_отчет_Cucumber 7 | 8 | @IgnoreOn82Builds 9 | @IgnoreOnOFBuilds 10 | @IgnoreOnWeb 11 | 12 | Функционал: Проверка формирования отчета Cucumber 13 | 14 | Как разработчик 15 | Я хочу чтобы корректно формировался отчет Cucumber 16 | Чтобы я мог видеть результат работы сценариев 17 | 18 | Контекст: 19 | Когда Я открываю VanessaAutomation в режиме TestClient со стандартной библиотекой 20 | 21 | Сценарий: Проверка отчета Cucumber 22 | Когда В поле с именем "КаталогФичСлужебный" я указываю путь к служебной фиче "ФичаДляПроверкиОтчетаCucumber" 23 | И в открытой форме я перехожу к закладке с заголовком "Сервис" 24 | И я перехожу к закладке с именем "СтраницаОтчетыОЗапуске" 25 | И я разворачиваю группу с именем "ГруппаОтчеты" 26 | И я перехожу к закладке с именем "ГруппаCucumber" 27 | И я устанавливаю флаг с именем 'ДелатьОтчетВФорматеCucumberJson' 28 | И в поле каталог отчета Cucumber я указываю путь к относительному каталогу "tools\Cucumber" 29 | И Я нажимаю на кнопку перезагрузить сценарии в Vanessa-Automation TestClient 30 | И Я нажимаю на кнопку выполнить сценарии в Vanessa-Automation TestClient 31 | И в каталоге Cucumber появился 1 файл json -------------------------------------------------------------------------------- /src/main/java/com/github/_1c_syntax/turbo/gherkin/parser/GherkinParserRuleContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of Turbo Gherkin Parser. 3 | * 4 | * Copyright © 2020-2020 5 | * Valery Maximov , 1c-syntax team , BIA Technologies team and contributors 6 | * 7 | * SPDX-License-Identifier: LGPL-3.0-or-later 8 | * 9 | * Turbo Gherkin Parser is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3.0 of the License, or (at your option) any later version. 13 | * 14 | * Turbo Gherkin Parser is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Turbo Gherkin Parser. 21 | */ 22 | package com.github._1c_syntax.turbo.gherkin.parser; 23 | 24 | import com.github._1c_syntax.bsl.parser.BSLParserRuleContext; 25 | import org.antlr.v4.runtime.ParserRuleContext; 26 | 27 | /** 28 | * Враппер над BSLParserRuleContext 29 | */ 30 | public class GherkinParserRuleContext extends BSLParserRuleContext { 31 | public GherkinParserRuleContext() { 32 | super(); 33 | } 34 | 35 | public GherkinParserRuleContext(ParserRuleContext parent, int invokingStateNumber) { 36 | super(parent, invokingStateNumber); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/github/_1c_syntax/turbo/gherkin/parser/CRAwareLexerATNSimulatorWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of Turbo Gherkin Parser. 3 | * 4 | * Copyright © 2020-2020 5 | * Valery Maximov , 1c-syntax team , BIA Technologies team and contributors 6 | * 7 | * SPDX-License-Identifier: LGPL-3.0-or-later 8 | * 9 | * Turbo Gherkin Parser is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3.0 of the License, or (at your option) any later version. 13 | * 14 | * Turbo Gherkin Parser is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Turbo Gherkin Parser. 21 | */ 22 | package com.github._1c_syntax.turbo.gherkin.parser; 23 | 24 | import com.github._1c_syntax.bsl.parser.CRAwareLexerATNSimulator; 25 | import org.antlr.v4.runtime.Lexer; 26 | import org.antlr.v4.runtime.atn.ATN; 27 | 28 | /** 29 | * Враппер класс над {@link CRAwareLexerATNSimulator} 30 | */ 31 | public class CRAwareLexerATNSimulatorWrapper extends CRAwareLexerATNSimulator { 32 | public CRAwareLexerATNSimulatorWrapper(ATN atn) { 33 | super(atn); 34 | } 35 | 36 | public CRAwareLexerATNSimulatorWrapper(Lexer recog, ATN atn) { 37 | super(recog, atn); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/github/_1c_syntax/turbo/gherkin/parser/GherkinTokenizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of Turbo Gherkin Parser. 3 | * 4 | * Copyright © 2020-2020 5 | * Valery Maximov , 1c-syntax team , BIA Technologies team and contributors 6 | * 7 | * SPDX-License-Identifier: LGPL-3.0-or-later 8 | * 9 | * Turbo Gherkin Parser is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3.0 of the License, or (at your option) any later version. 13 | * 14 | * Turbo Gherkin Parser is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Turbo Gherkin Parser. 21 | */ 22 | package com.github._1c_syntax.turbo.gherkin.parser; 23 | 24 | import com.github._1c_syntax.bsl.parser.Tokenizer; 25 | import org.antlr.v4.runtime.CharStreams; 26 | 27 | /** 28 | * Токенайзер 29 | * Расширяет класс Tokenizer из bsl-parser 30 | */ 31 | public class GherkinTokenizer extends Tokenizer { 32 | public GherkinTokenizer(String content) { 33 | super(content, new TurboGherkinLexer(CharStreams.fromString(""), true), TurboGherkinParser.class); 34 | } 35 | 36 | @Override 37 | protected TurboGherkinParser.FeatureContext rootAST() { 38 | return parser.feature(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/antlr/TurboGherkinParser.g4: -------------------------------------------------------------------------------- 1 | parser grammar TurboGherkinParser; 2 | 3 | options { 4 | tokenVocab = TurboGherkinLexer; 5 | contextSuperClass = 'GherkinParserRuleContext'; 6 | } 7 | 8 | // структура фиче-файла 9 | feature: white tags FEATURE_KEYWORD space* featureName white featureDescription featureBody EOF; 10 | 11 | // теги 12 | tags: white (tag (SPACE | TAB | EOL)+)*; 13 | tag: AT (~(AT | SPACE | TAB | EOL))+; 14 | 15 | // название фичи 16 | featureName: (~EOL)*; // символы до конца строки 17 | // описание фичи 18 | featureDescription: 19 | (white 20 | (~(SCENARIO_OUTLINE_KEYWORD | SCENARIO_KEYWORD | BACKGROUND_KEYWORD | EXAMPLE_KEYWORD | RULE_KEYWORD | EOL))* EOL 21 | )*; 22 | // содержимое фичи 23 | featureBody: background? (businessRules | scenarios); 24 | 25 | // бизнес-правила (GHERKIN 6) 26 | businessRules: businessRule+; 27 | businessRule: white RULE_KEYWORD space* name white description background? scenarios; 28 | 29 | // общий контекст фичи или бизнес правила, если используются они 30 | background: white BACKGROUND_KEYWORD white description steps; 31 | 32 | // элементы 33 | scenarios: (scenario | scenarioOutline)+; 34 | scenario: white (SCENARIO_KEYWORD | EXAMPLE_KEYWORD) space* name white description steps; 35 | 36 | scenarioOutline: white SCENARIO_OUTLINE_KEYWORD space* name white description steps examples; 37 | 38 | // примеры 39 | examples: white (EXAMPLES_KEYWORD | SCENARIOS_KEYWORD) space* (EOL+ | EOF) table; 40 | 41 | // шаги 42 | steps: step*; 43 | step: white stepKeyword SPACE name (EOL+ | EOF) (docStrings | table)?; 44 | 45 | // пустая строка 46 | white: (SPACE | TAB | EOL)*; 47 | // допустимый пробел 48 | space: SPACE | TAB; 49 | 50 | // общие 51 | name: 52 | (parameter | partName | space+)+; 53 | parameter: DECIMAL | FLOAT | STRING | (LABRACKET ~(EOL | LABRACKET | RABRACKET)+ RABRACKET); 54 | partName: ~(EOL | DECIMAL | STRING | LABRACKET | SPACE | TAB)+; 55 | 56 | description: 57 | (white 58 | (~(GIVEN_KEYWORD | WHEN_KEYWORD | THEN_KEYWORD | AND_KEYWORD | BUT_KEYWORD | EOL | SPACE)) (~EOL)+ EOL 59 | )*; 60 | 61 | // таблица Gherkin 62 | table: white tableHead tableRows; 63 | tableHead: space* BAR tableCell+ space* (EOL+ | EOF); 64 | tableRows: tableRow+; 65 | tableRow: space* BAR tableCell+ space* (EOL+ | EOF); 66 | tableCell: tableCellValue BAR; 67 | tableCellValue: (~(EOL | BAR))*; 68 | 69 | docStrings: space* DOC_STRINGS space* EOL docStringsValue space* DOC_STRINGS space* (EOL+ | EOF); 70 | docStringsValue: (~DOC_STRINGS)*; 71 | 72 | // ключевые слова для шагов 73 | stepKeyword: 74 | GIVEN_KEYWORD 75 | | WHEN_KEYWORD 76 | | THEN_KEYWORD 77 | | AND_KEYWORD 78 | | BUT_KEYWORD 79 | ; 80 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /src/main/antlr/TurboGherkinLexer.g4: -------------------------------------------------------------------------------- 1 | lexer grammar TurboGherkinLexer; 2 | 3 | @members { 4 | public TurboGherkinLexer(CharStream input, boolean crAwareCostructor) { 5 | super(input); 6 | _interp = new CRAwareLexerATNSimulatorWrapper(this, _ATN); 7 | validateInputStream(_ATN, input); 8 | } 9 | } 10 | 11 | // COMMON 12 | EOL : '\r'? '\n'; 13 | SPACE : ' '; 14 | TAB : '\t'; 15 | HASH : '#' ~[\r\n]* -> channel(HIDDEN); 16 | AT : '@'; 17 | BAR : '|'; 18 | LABRACKET: '<'; 19 | RABRACKET: '>'; 20 | DOLLAR: '$'; 21 | DDOLLAR: '$$'; 22 | TDOLLAR: '$$$'; 23 | DOC_STRINGS : '"""'; 24 | COMMENT_LINE : '//' ~[\r\n]* -> channel(HIDDEN); 25 | 26 | DECIMAL: [0-9]+; 27 | 28 | FLOAT : [0-9]+ '.' [0-9]*; 29 | STRING: ('"' (~[\r\n"] | '""')* '"') 30 | | ('\'' (~[\r\n'])* '\''); 31 | 32 | // KEYWORDS (https://cucumber.io/docs/gherkin/languages/) 33 | // Хотя Gherkin поддерживает использование звездочки ( *) вместо обычных ключевых слов шагов, 34 | // в турбогеркине они используются для иных целей 35 | FEATURE_KEYWORD : (F E A T U R E | RU_F RU_U RU_N RU_K RU_C RU_I RU_YA 36 | | RU_F RU_U RU_N RU_K RU_C RU_I RU_O RU_N RU_A RU_L RU_SOFT_SIGN RU_N RU_O RU_S RU_T RU_SOFT_SIGN 37 | | RU_F RU_U RU_N RU_K RU_C RU_I RU_O RU_N RU_A RU_L 38 | | RU_S RU_V RU_O RU_J RU_S RU_T RU_V RU_O 39 | ) ':'; 40 | BACKGROUND_KEYWORD : (B A C K G R O U N D | RU_K RU_O RU_N RU_T RU_E RU_K RU_S RU_T 41 | | RU_P RU_R RU_E RU_D RU_Y RU_S RU_T RU_O RU_R RU_I RU_YA 42 | ) ':'; 43 | SCENARIO_KEYWORD : (S C E N A R I O | RU_S RU_C RU_E RU_N RU_A RU_R RU_I RU_J 44 | ) ':'; 45 | SCENARIOS_KEYWORD : (S C E N A R I O S | RU_S RU_C RU_E RU_N RU_A RU_R RU_I RU_I 46 | ) ':'; 47 | SCENARIO_OUTLINE_KEYWORD : ( S C E N A R I O ' ' O U T L I N E 48 | | S C E N A R I O ' ' T E M P L A T E 49 | | RU_S RU_T RU_R RU_U RU_K RU_T RU_U RU_R RU_A ' ' RU_S RU_C RU_E RU_N RU_A RU_R RU_I RU_YA 50 | ) ':'; 51 | EXAMPLE_KEYWORD : (E X A M P L E | RU_P RU_R RU_I RU_M RU_E RU_R 52 | ) ':'; 53 | EXAMPLES_KEYWORD : (E X A M P L E S | RU_P RU_R RU_I RU_M RU_E RU_R RU_Y 54 | ) ':'; 55 | GIVEN_KEYWORD : G I V E N | RU_D RU_A RU_N RU_O 56 | | RU_D RU_O RU_P RU_U RU_S RU_T RU_I RU_M 57 | | RU_P RU_U RU_S RU_T RU_SOFT_SIGN 58 | ; 59 | WHEN_KEYWORD : W H E N | RU_K RU_O RU_G RU_D RU_A 60 | ; 61 | IF_KEYWORD : I F | RU_E RU_S RU_L RU_I 62 | ; 63 | THEN_KEYWORD : T H E N | RU_T RU_O RU_G RU_D RU_A 64 | | RU_T RU_O 65 | | RU_Z RU_A RU_T RU_E RU_M 66 | ; 67 | AND_KEYWORD : A N D | RU_I 68 | | RU_K ' ' RU_T RU_O RU_M RU_U ' ' RU_ZH RU_E 69 | | RU_T RU_A RU_K RU_ZH RU_E 70 | ; 71 | BUT_KEYWORD : B U T | RU_N RU_O 72 | | RU_A 73 | | RU_I RU_N RU_A RU_CH RU_E 74 | ; 75 | RULE_KEYWORD : (R U L E | RU_P RU_R RU_A RU_V RU_I RU_L RU_O 76 | ) ':'; 77 | 78 | // OTHER 79 | ANYSYMBOL: .; 80 | 81 | // LETTERS 82 | fragment RU_A: 'А' | 'а'; 83 | fragment RU_B: 'Б' | 'б'; 84 | fragment RU_V: 'В' | 'в'; 85 | fragment RU_G: 'Г' | 'г'; 86 | fragment RU_D: 'Д' | 'д'; 87 | fragment RU_YO: 'Ё' | 'ё'; 88 | fragment RU_E: 'Е' | 'е'; 89 | fragment RU_ZH: 'Ж' | 'ж'; 90 | fragment RU_Z: 'З' | 'з'; 91 | fragment RU_I: 'И' | 'и'; 92 | fragment RU_J: 'Й' | 'й'; 93 | fragment RU_K: 'К' | 'к'; 94 | fragment RU_L: 'Л' | 'л'; 95 | fragment RU_M: 'М' | 'м'; 96 | fragment RU_N: 'Н' | 'н'; 97 | fragment RU_O: 'О' | 'о'; 98 | fragment RU_P: 'П' | 'п'; 99 | fragment RU_R: 'Р' | 'р'; 100 | fragment RU_S: 'С' | 'с'; 101 | fragment RU_T: 'Т' | 'т'; 102 | fragment RU_U: 'У' | 'у'; 103 | fragment RU_F: 'Ф' | 'ф'; 104 | fragment RU_H: 'Х' | 'х'; 105 | fragment RU_C: 'Ц' | 'ц'; 106 | fragment RU_CH: 'Ч' | 'ч'; 107 | fragment RU_SH: 'Ш' | 'ш'; 108 | fragment RU_SCH: 'Щ' | 'щ'; 109 | fragment RU_SOLID_SIGN: 'Ъ' | 'ъ'; 110 | fragment RU_Y: 'Ы' | 'ы'; 111 | fragment RU_SOFT_SIGN: 'Ь' | 'ь'; 112 | fragment RU_EH: 'Э' | 'э'; 113 | fragment RU_YU: 'Ю' | 'ю'; 114 | fragment RU_YA: 'Я' | 'я'; 115 | fragment A: 'A' | 'a'; 116 | fragment B: 'B' | 'b'; 117 | fragment C: 'C' | 'c'; 118 | fragment D: 'D' | 'd'; 119 | fragment I: 'I' | 'i'; 120 | fragment J: 'J' | 'j'; 121 | fragment E: 'E' | 'e'; 122 | fragment F: 'F' | 'f'; 123 | fragment G: 'G' | 'g'; 124 | fragment U: 'U' | 'u'; 125 | fragment K: 'K' | 'k'; 126 | fragment L: 'L' | 'l'; 127 | fragment M: 'M' | 'm'; 128 | fragment N: 'N' | 'n'; 129 | fragment O: 'O' | 'o'; 130 | fragment P: 'P' | 'p'; 131 | fragment Q: 'Q' | 'q'; 132 | fragment R: 'R' | 'r'; 133 | fragment S: 'S' | 's'; 134 | fragment T: 'T' | 't'; 135 | fragment V: 'V' | 'v'; 136 | fragment H: 'H' | 'h'; 137 | fragment W: 'W' | 'w'; 138 | fragment X: 'X' | 'x'; 139 | fragment Y: 'Y' | 'y'; 140 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /src/test/java/TestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of Turbo Gherkin Parser. 3 | * 4 | * Copyright © 2020-2020 5 | * Valery Maximov , 1c-syntax team , BIA Technologies team and contributors 6 | * 7 | * SPDX-License-Identifier: LGPL-3.0-or-later 8 | * 9 | * Turbo Gherkin Parser is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3.0 of the License, or (at your option) any later version. 13 | * 14 | * Turbo Gherkin Parser is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Turbo Gherkin Parser. 21 | */ 22 | 23 | import com.github._1c_syntax.bsl.parser.CaseChangingCharStream; 24 | import com.github._1c_syntax.bsl.parser.UnicodeBOMInputStream; 25 | import org.antlr.v4.runtime.CharStream; 26 | import org.antlr.v4.runtime.CharStreams; 27 | import org.antlr.v4.runtime.CodePointCharStream; 28 | import org.antlr.v4.runtime.CommonTokenStream; 29 | import org.antlr.v4.runtime.ConsoleErrorListener; 30 | import org.antlr.v4.runtime.Token; 31 | import org.antlr.v4.runtime.tree.ParseTree; 32 | import org.antlr.v4.runtime.tree.Tree; 33 | import org.apache.commons.io.IOUtils; 34 | import com.github._1c_syntax.turbo.gherkin.parser.GherkinParserRuleContext; 35 | import com.github._1c_syntax.turbo.gherkin.parser.TurboGherkinLexer; 36 | import com.github._1c_syntax.turbo.gherkin.parser.TurboGherkinParser; 37 | 38 | import java.io.IOException; 39 | import java.io.InputStream; 40 | import java.io.InputStreamReader; 41 | import java.io.Reader; 42 | import java.nio.charset.StandardCharsets; 43 | import java.util.Arrays; 44 | import java.util.HashSet; 45 | import java.util.List; 46 | import java.util.Set; 47 | import java.util.stream.IntStream; 48 | import java.util.stream.Stream; 49 | 50 | import static org.assertj.core.api.Assertions.assertThat; 51 | 52 | /** 53 | * Утилиты для тестов 54 | */ 55 | public final class TestUtils { 56 | 57 | public TestUtils() { 58 | // utils 59 | } 60 | 61 | /** 62 | * Проверяет входную строку на соответствие списку ожидаемых токенов 63 | * 64 | * @param inputString строка с примером 65 | * @param tokensIds список идентификаторов токенов 66 | */ 67 | public static void assertThatTokens(String inputString, Integer... tokensIds) { 68 | assertThat(getTokens(inputString)).extracting(Token::getType).containsExactly(tokensIds); 69 | } 70 | 71 | /** 72 | * Проверяет входную строку на наличие нужного токена 73 | * 74 | * @param inputString строка с примером 75 | * @param tokensIds список идентификаторов токенов 76 | */ 77 | public static void assertThatContains(String inputString, Integer... tokensIds) { 78 | assertThat(getTokens(inputString)).extracting(Token::getType).contains(tokensIds); 79 | } 80 | 81 | /** 82 | * Проверяет наличие в дереве нужных узлов 83 | * 84 | * @param tree Исходное дерево 85 | * @param index Индекс узла 86 | */ 87 | public static void assertThatContains(ParseTree tree, Integer... index) { 88 | Set indexes = new HashSet<>(Arrays.asList(index)); 89 | assertThat(IntStream.range(0, tree.getChildCount()) 90 | .mapToObj(tree::getChild) 91 | .filter((Tree child) -> 92 | child instanceof GherkinParserRuleContext 93 | && indexes.contains(((GherkinParserRuleContext) child).getRuleIndex()) 94 | && !((GherkinParserRuleContext) child).getText().isBlank()) 95 | .map((Tree child) -> ((GherkinParserRuleContext) child).getRuleIndex())).contains(index); 96 | } 97 | 98 | /** 99 | * Проверяет входную строку на отсутствие нужного токена 100 | * 101 | * @param inputString строка с примером 102 | * @param tokensIds список идентификаторов токенов 103 | */ 104 | public static void assertThatNotContains(String inputString, Integer... tokensIds) { 105 | assertThat(getTokens(inputString)).extracting(Token::getType).doesNotContain(tokensIds); 106 | } 107 | 108 | /** 109 | * Возвращает все дочерние узны от переданного корня дерева 110 | * 111 | * @param tree Корень дерева 112 | * @return найденные дочерние узлы 113 | */ 114 | protected static Stream getAllChildren(Tree tree) { 115 | return IntStream.range(0, tree.getChildCount()) 116 | .mapToObj(tree::getChild) 117 | .filter((Tree child) -> child instanceof GherkinParserRuleContext) 118 | .map(child -> (GherkinParserRuleContext) child); 119 | } 120 | 121 | /** 122 | * Возвращает список токенов в строке 123 | * 124 | * @param inputString исходная строка для анализа 125 | * @return список найденных токенов 126 | */ 127 | public static List getTokens(String inputString) { 128 | CharStream input; 129 | 130 | try ( 131 | InputStream inputStream = IOUtils.toInputStream(inputString, StandardCharsets.UTF_8); 132 | UnicodeBOMInputStream ubis = new UnicodeBOMInputStream(inputStream); 133 | Reader inputStreamReader = new InputStreamReader(ubis, StandardCharsets.UTF_8) 134 | ) { 135 | ubis.skipBOM(); 136 | CodePointCharStream inputTemp = CharStreams.fromReader(inputStreamReader); 137 | input = new CaseChangingCharStream(inputTemp); 138 | } catch (IOException e) { 139 | throw new RuntimeException(e); 140 | } 141 | 142 | var lexer = createLexer(input); 143 | CommonTokenStream tempTokenStream = new CommonTokenStream(lexer); 144 | tempTokenStream.fill(); 145 | 146 | return tempTokenStream.getTokens(); 147 | } 148 | 149 | /** 150 | * Анализирует дерево на наличие ошибок парсинга 151 | * 152 | * @param tree корень анализируемого дерева 153 | * @return признак наличия ошибки 154 | */ 155 | public static boolean treeContainsErrors(ParseTree tree) { 156 | if (!(tree instanceof GherkinParserRuleContext)) { 157 | return false; 158 | } 159 | 160 | var ruleContext = (GherkinParserRuleContext) tree; 161 | 162 | if (ruleContext.exception != null) { 163 | return true; 164 | } 165 | 166 | return ruleContext.children != null 167 | && ruleContext.children.stream().anyMatch(TestUtils::treeContainsErrors); 168 | } 169 | 170 | protected static TurboGherkinParser createParser(String inputString) { 171 | CharStream input; 172 | 173 | try ( 174 | InputStream inputStream = IOUtils.toInputStream(inputString, StandardCharsets.UTF_8); 175 | UnicodeBOMInputStream ubis = new UnicodeBOMInputStream(inputStream); 176 | Reader inputStreamReader = new InputStreamReader(ubis, StandardCharsets.UTF_8) 177 | ) { 178 | ubis.skipBOM(); 179 | CodePointCharStream inputTemp = CharStreams.fromReader(inputStreamReader); 180 | input = new CaseChangingCharStream(inputTemp); 181 | } catch (IOException e) { 182 | throw new RuntimeException(e); 183 | } 184 | 185 | var lexer = new TurboGherkinLexer(input); 186 | CommonTokenStream tokenStream = new CommonTokenStream(lexer); 187 | tokenStream.fill(); 188 | 189 | var parser = new TurboGherkinParser(tokenStream); 190 | parser.removeErrorListener(ConsoleErrorListener.INSTANCE); 191 | return parser; 192 | } 193 | 194 | protected static TurboGherkinLexer createLexer(CharStream inputStream) { 195 | var lexer = new TurboGherkinLexer(inputStream); 196 | lexer.removeErrorListener(ConsoleErrorListener.INSTANCE); 197 | lexer.pushMode(TurboGherkinLexer.DEFAULT_MODE); 198 | return lexer; 199 | } 200 | 201 | } 202 | -------------------------------------------------------------------------------- /src/test/resources/uncorrect/example7.feature: -------------------------------------------------------------------------------- 1 | # from https://github.com/Pr-Mex/vanessa-automation/blob/develop/features/Core/ErrorDetails/%D0%9E%D0%BA%D0%BD%D0%BE%D0%94%D0%B5%D1%82%D0%B0%D0%BB%D0%B5%D0%B9%D0%9E%D1%88%D0%B8%D0%B1%D0%BA%D0%B8.feature 2 | # language: ru 3 | # encoding: utf-8 4 | #parent uf: 5 | @UF2_запуск_сценариев_на_выполнение 6 | #parent ua: 7 | @UA11_запускать_сценарии_на_выполнение 8 | 9 | @IgnoreOn82Builds 10 | @IgnoreOnOFBuilds 11 | @IgnoreOnUFSovm82Builds 12 | @IgnoreOnWeb 13 | @IgnoreOn836 14 | @IgnoreOn837 15 | @IgnoreOn838 16 | @IgnoreOn839 17 | 18 | @SingleCodeCoverage 19 | 20 | @tree 21 | 22 | 23 | Функционал: Детали ошибки 24 | 25 | 26 | 27 | Сценарий: Детали ошибки. Сравнение макетов. Толстый клиент. 28 | 29 | И Я запоминаю значение выражения '$КаталогИнструментов$\Tools\CompareFiles' в переменную "КаталогСлужебнойБазы" 30 | Если Файл "$КаталогСлужебнойБазы$" существует тогда 31 | Тогда я очищаю каталог "$КаталогСлужебнойБазы$" 32 | Тогда я удаляю файл "$КаталогСлужебнойБазы$" 33 | 34 | Дано Я закрыл все окна клиентского приложения 35 | И я закрываю сеанс TESTCLIENT 36 | Когда Я запускаю служебный сеанс TestClient с ключом TestManager толстый клиент в той же базе 37 | 38 | 39 | Когда Я открываю VanessaAutomation в режиме TestClient со стандартной библиотекой 40 | 41 | //для формы списка 42 | И В поле с именем "КаталогФичСлужебный" я указываю путь к служебной фиче "ДеталиОшибки/ДеталиОшибки01" 43 | 44 | 45 | 46 | Когда открылось окно '*Vanessa Automation' 47 | И я перехожу к закладке с именем "ГруппаСлужебная" 48 | И в поле с именем 'КаталогПроекта' я ввожу текст '$КаталогИнструментов$' 49 | 50 | //контроль, всё работает, когда пустой каталог для формирования json с ошибкой 51 | И я перехожу к закладке с именем "ГруппаНастройки" 52 | И я перехожу к закладке с именем "СтраницаОтчетыОЗапуске" 53 | И я устанавливаю флаг с именем 'ДелатьЛогОшибокВТекстовыйФайл' 54 | И в поле с именем 'ИмяКаталогаЛогОшибок' я ввожу текст '' 55 | И я перехожу к следующему реквизиту 56 | И я снимаю флаг с именем 'ДелатьЛогОшибокВТекстовыйФайл' 57 | 58 | 59 | И Я нажимаю на кнопку перезагрузить сценарии в Vanessa-Automation TestClient 60 | И Я нажимаю на кнопку выполнить сценарии в Vanessa-Automation TestClient 61 | 62 | И пауза 3 63 | 64 | И в таблице "ДеревоТестов" я перехожу к строке: 65 | | 'Наименование' | 66 | | 'Дано Табличный документ "РеквизитТабличныйДокумент" равен макету "ДляДеталейОшибки01"' | 67 | 68 | И в таблице "ДеревоТестов" я выбираю текущую строку 69 | Тогда открылось окно 'Детали ошибки' 70 | 71 | И я устанавливаю флаг с именем 'ТолькоТекстЯчеек' 72 | И я устанавливаю флаг с именем 'СУчетомРегулярныхВыражений' 73 | 74 | И я нажимаю на кнопку с именем 'ФормаСравнитьТаблицы' 75 | 76 | Когда В панели открытых я выбираю '*Vanessa Automation*' 77 | 78 | И Я закрываю окно 'Детали ошибки' 79 | Тогда открылось окно '*Vanessa Automation*' 80 | 81 | И В поле с именем "КаталогФичСлужебный" я указываю путь к служебной фиче "ЗакрытьПодключенныйTestClient/ЗакрытьПодключенныйTestClient" 82 | 83 | И Я нажимаю на кнопку перезагрузить сценарии в Vanessa-Automation TestClient 84 | И Я нажимаю на кнопку выполнить сценарии в Vanessa-Automation TestClient 85 | 86 | 87 | Сценарий: Активизация основного клиента 88 | И я закрываю TestClient "TM_Толстый" 89 | И в таблице клиентов тестирования я активизирую строку 'Этот клиент' 90 | 91 | 92 | Сценарий: Детали ошибки. Сравнение макетов. Тонкий клиент. Для основной сборки. 93 | 94 | И Я запоминаю значение выражения '$КаталогИнструментов$\Tools\CompareFiles' в переменную "КаталогСлужебнойБазы" 95 | Если Файл "$КаталогСлужебнойБазы$" существует тогда 96 | Тогда я очищаю каталог "$КаталогСлужебнойБазы$" 97 | Тогда я удаляю файл "$КаталогСлужебнойБазы$" 98 | 99 | Дано Я закрыл все окна клиентского приложения 100 | И я закрываю сеанс TESTCLIENT 101 | Когда я запускаю служебный сеанс TestClient с ключом TestManager в той же базе 102 | 103 | 104 | Когда Я открываю VanessaAutomation в режиме TestClient со стандартной библиотекой 105 | 106 | //для формы списка 107 | И В поле с именем "КаталогФичСлужебный" я указываю путь к служебной фиче "ДеталиОшибки/ДеталиОшибки01" 108 | 109 | 110 | 111 | Когда открылось окно '*Vanessa Automation' 112 | И я перехожу к закладке с именем "ГруппаСлужебная" 113 | И в поле с именем 'КаталогПроекта' я ввожу текст '$КаталогИнструментов$' 114 | 115 | 116 | И Я нажимаю на кнопку перезагрузить сценарии в Vanessa-Automation TestClient 117 | И Я нажимаю на кнопку выполнить сценарии в Vanessa-Automation TestClient 118 | 119 | И пауза 3 120 | 121 | И в таблице "ДеревоТестов" я перехожу к строке: 122 | | 'Наименование' | 123 | | 'Дано Табличный документ "РеквизитТабличныйДокумент" равен макету "ДляДеталейОшибки01"' | 124 | 125 | И в таблице "ДеревоТестов" я выбираю текущую строку 126 | Тогда открылось окно 'Детали ошибки' 127 | 128 | И я устанавливаю флаг с именем 'ТолькоТекстЯчеек' 129 | И я устанавливаю флаг с именем 'СУчетомРегулярныхВыражений' 130 | 131 | И я нажимаю на кнопку с именем 'ФормаСравнитьТаблицы' 132 | 133 | И пауза 30 134 | 135 | 136 | И Я закрываю окно 'Детали ошибки' 137 | И пауза 1 138 | И я активизирую окно "*Vanessa Automation*" 139 | Тогда открылось окно '*Vanessa Automation*' 140 | 141 | И В поле с именем "КаталогФичСлужебный" я указываю путь к служебной фиче "ЗакрытьПодключенныйTestClient/ЗакрытьПодключенныйTestClient" 142 | 143 | И Я нажимаю на кнопку перезагрузить сценарии в Vanessa-Automation TestClient 144 | И Я нажимаю на кнопку выполнить сценарии в Vanessa-Automation TestClient 145 | 146 | 147 | И я перехожу к закладке с именем "ГруппаНесколькоКлиентовТестирования" 148 | 149 | И я перехожу к закладке с именем "ГруппаНастройки" 150 | И я устанавливаю флаг с именем 'DebugLog2' 151 | 152 | 153 | И в таблице "ДанныеКлиентовТестирования" я нажимаю на кнопку с именем 'ТестКлиентДобавить' 154 | И в таблице "ДанныеКлиентовТестирования" в поле с именем 'ДанныеКлиентовТестированияИмя' я ввожу текст 'ОкноСравнениеМакетов' 155 | И я перехожу к следующему реквизиту 156 | И я перехожу к следующему реквизиту 157 | И в таблице "ДанныеКлиентовТестирования" из выпадающего списка с именем "ДанныеКлиентовТестированияТипКлиента" я выбираю точное значение 'Тонкий' 158 | И я перехожу к следующему реквизиту 159 | И в таблице "ДанныеКлиентовТестирования" в поле с именем 'ДанныеКлиентовТестированияПутьКИнфобазе' я ввожу текст '111' 160 | И я перехожу к следующему реквизиту 161 | И я перехожу к следующему реквизиту 162 | И в таблице "ДанныеКлиентовТестирования" в поле с именем 'ДанныеКлиентовТестированияИмяКомпьютера' я ввожу текст 'localhost' 163 | И я перехожу к следующему реквизиту 164 | И в таблице "ДанныеКлиентовТестирования" в поле с именем 'ДанныеКлиентовТестированияПорт' я ввожу текст '48222' 165 | И в таблице "ДанныеКлиентовТестирования" я завершаю редактирование строки 166 | 167 | И я выбираю пункт контекстного меню с именем 'КонтМенюПодключитьВыбранного' на элементе формы с именем "ДанныеКлиентовТестирования" 168 | 169 | Затем я жду, что в сообщениях пользователю будет подстрока "Уже открытый TestClient подключен" в течение 30 секунд 170 | 171 | И Я нажимаю на кнопку выполнить сценарии в Vanessa-Automation TestClient 172 | 173 | 174 | Сценарий: Активизация основного клиента 175 | И я закрываю TestClient "TM" 176 | И в таблице клиентов тестирования я активизирую строку 'Этот клиент' -------------------------------------------------------------------------------- /src/test/resources/correct/example8.feature: -------------------------------------------------------------------------------- 1 | # from https://github.com/Pr-Mex/vanessa-automation/blob/develop/features/Core/ErrorDetails/%D0%9E%D0%BA%D0%BD%D0%BE%D0%94%D0%B5%D1%82%D0%B0%D0%BB%D0%B5%D0%B9%D0%9E%D1%88%D0%B8%D0%B1%D0%BA%D0%B8.feature 2 | # language: ru 3 | # encoding: utf-8 4 | #parent uf: 5 | @UF2_запуск_сценариев_на_выполнение 6 | #parent ua: 7 | @UA11_запускать_сценарии_на_выполнение 8 | 9 | @IgnoreOn82Builds 10 | @IgnoreOnOFBuilds 11 | @IgnoreOnUFSovm82Builds 12 | @IgnoreOnWeb 13 | @IgnoreOn836 14 | @IgnoreOn837 15 | @IgnoreOn838 16 | @IgnoreOn839 17 | 18 | @SingleCodeCoverage 19 | 20 | @tree 21 | 22 | 23 | Функционал: Детали ошибки 24 | 25 | 26 | 27 | Сценарий: Детали ошибки. Сравнение макетов. Толстый клиент. 28 | 29 | И Я запоминаю значение выражения '$КаталогИнструментов$\Tools\CompareFiles' в переменную "КаталогСлужебнойБазы" 30 | // Если Файл "$КаталогСлужебнойБазы$" существует тогда 31 | Тогда я очищаю каталог "$КаталогСлужебнойБазы$" 32 | Тогда я удаляю файл "$КаталогСлужебнойБазы$" 33 | 34 | Дано Я закрыл все окна клиентского приложения 35 | И я закрываю сеанс TESTCLIENT 36 | Когда Я запускаю служебный сеанс TestClient с ключом TestManager толстый клиент в той же базе 37 | 38 | 39 | Когда Я открываю VanessaAutomation в режиме TestClient со стандартной библиотекой 40 | 41 | //для формы списка 42 | И В поле с именем "КаталогФичСлужебный" я указываю путь к служебной фиче "ДеталиОшибки/ДеталиОшибки01" 43 | 44 | 45 | 46 | Когда открылось окно '*Vanessa Automation' 47 | И я перехожу к закладке с именем "ГруппаСлужебная" 48 | И в поле с именем 'КаталогПроекта' я ввожу текст '$КаталогИнструментов$' 49 | 50 | //контроль, всё работает, когда пустой каталог для формирования json с ошибкой 51 | И я перехожу к закладке с именем "ГруппаНастройки" 52 | И я перехожу к закладке с именем "СтраницаОтчетыОЗапуске" 53 | И я устанавливаю флаг с именем 'ДелатьЛогОшибокВТекстовыйФайл' 54 | И в поле с именем 'ИмяКаталогаЛогОшибок' я ввожу текст '' 55 | И я перехожу к следующему реквизиту 56 | И я снимаю флаг с именем 'ДелатьЛогОшибокВТекстовыйФайл' 57 | 58 | 59 | И Я нажимаю на кнопку перезагрузить сценарии в Vanessa-Automation TestClient 60 | И Я нажимаю на кнопку выполнить сценарии в Vanessa-Automation TestClient 61 | 62 | И пауза 3 63 | 64 | И в таблице "ДеревоТестов" я перехожу к строке: 65 | | 'Наименование' | 66 | | 'Дано Табличный документ "РеквизитТабличныйДокумент" равен макету "ДляДеталейОшибки01"' | 67 | 68 | И в таблице "ДеревоТестов" я выбираю текущую строку 69 | Тогда открылось окно 'Детали ошибки' 70 | 71 | И я устанавливаю флаг с именем 'ТолькоТекстЯчеек' 72 | И я устанавливаю флаг с именем 'СУчетомРегулярныхВыражений' 73 | 74 | И я нажимаю на кнопку с именем 'ФормаСравнитьТаблицы' 75 | 76 | Когда В панели открытых я выбираю '*Vanessa Automation*' 77 | 78 | И Я закрываю окно 'Детали ошибки' 79 | Тогда открылось окно '*Vanessa Automation*' 80 | 81 | И В поле с именем "КаталогФичСлужебный" я указываю путь к служебной фиче "ЗакрытьПодключенныйTestClient/ЗакрытьПодключенныйTestClient" 82 | 83 | И Я нажимаю на кнопку перезагрузить сценарии в Vanessa-Automation TestClient 84 | И Я нажимаю на кнопку выполнить сценарии в Vanessa-Automation TestClient 85 | 86 | 87 | Сценарий: Активизация основного клиента 88 | И я закрываю TestClient "TM_Толстый" 89 | И в таблице клиентов тестирования я активизирую строку 'Этот клиент' 90 | 91 | 92 | Сценарий: Детали ошибки. Сравнение макетов. Тонкий клиент. Для основной сборки. 93 | 94 | И Я запоминаю значение выражения '$КаталогИнструментов$\Tools\CompareFiles' в переменную "КаталогСлужебнойБазы" 95 | // Если Файл "$КаталогСлужебнойБазы$" существует тогда 96 | Тогда я очищаю каталог "$КаталогСлужебнойБазы$" 97 | Тогда я удаляю файл "$КаталогСлужебнойБазы$" 98 | 99 | Дано Я закрыл все окна клиентского приложения 100 | И я закрываю сеанс TESTCLIENT 101 | Когда я запускаю служебный сеанс TestClient с ключом TestManager в той же базе 102 | 103 | 104 | Когда Я открываю VanessaAutomation в режиме TestClient со стандартной библиотекой 105 | 106 | //для формы списка 107 | И В поле с именем "КаталогФичСлужебный" я указываю путь к служебной фиче "ДеталиОшибки/ДеталиОшибки01" 108 | 109 | 110 | 111 | Когда открылось окно '*Vanessa Automation' 112 | И я перехожу к закладке с именем "ГруппаСлужебная" 113 | И в поле с именем 'КаталогПроекта' я ввожу текст '$КаталогИнструментов$' 114 | 115 | 116 | И Я нажимаю на кнопку перезагрузить сценарии в Vanessa-Automation TestClient 117 | И Я нажимаю на кнопку выполнить сценарии в Vanessa-Automation TestClient 118 | 119 | И пауза 3 120 | 121 | И в таблице "ДеревоТестов" я перехожу к строке: 122 | | 'Наименование' | 123 | | 'Дано Табличный документ "РеквизитТабличныйДокумент" равен макету "ДляДеталейОшибки01"' | 124 | 125 | И в таблице "ДеревоТестов" я выбираю текущую строку 126 | Тогда открылось окно 'Детали ошибки' 127 | 128 | И я устанавливаю флаг с именем 'ТолькоТекстЯчеек' 129 | И я устанавливаю флаг с именем 'СУчетомРегулярныхВыражений' 130 | 131 | И я нажимаю на кнопку с именем 'ФормаСравнитьТаблицы' 132 | 133 | И пауза 30 134 | 135 | 136 | И Я закрываю окно 'Детали ошибки' 137 | И пауза 1 138 | И я активизирую окно "*Vanessa Automation*" 139 | Тогда открылось окно '*Vanessa Automation*' 140 | 141 | И В поле с именем "КаталогФичСлужебный" я указываю путь к служебной фиче "ЗакрытьПодключенныйTestClient/ЗакрытьПодключенныйTestClient" 142 | 143 | И Я нажимаю на кнопку перезагрузить сценарии в Vanessa-Automation TestClient 144 | И Я нажимаю на кнопку выполнить сценарии в Vanessa-Automation TestClient 145 | 146 | 147 | И я перехожу к закладке с именем "ГруппаНесколькоКлиентовТестирования" 148 | 149 | И я перехожу к закладке с именем "ГруппаНастройки" 150 | И я устанавливаю флаг с именем 'DebugLog2' 151 | 152 | 153 | И в таблице "ДанныеКлиентовТестирования" я нажимаю на кнопку с именем 'ТестКлиентДобавить' 154 | И в таблице "ДанныеКлиентовТестирования" в поле с именем 'ДанныеКлиентовТестированияИмя' я ввожу текст 'ОкноСравнениеМакетов' 155 | И я перехожу к следующему реквизиту 156 | И я перехожу к следующему реквизиту 157 | И в таблице "ДанныеКлиентовТестирования" из выпадающего списка с именем "ДанныеКлиентовТестированияТипКлиента" я выбираю точное значение 'Тонкий' 158 | И я перехожу к следующему реквизиту 159 | И в таблице "ДанныеКлиентовТестирования" в поле с именем 'ДанныеКлиентовТестированияПутьКИнфобазе' я ввожу текст '111' 160 | И я перехожу к следующему реквизиту 161 | И я перехожу к следующему реквизиту 162 | И в таблице "ДанныеКлиентовТестирования" в поле с именем 'ДанныеКлиентовТестированияИмяКомпьютера' я ввожу текст 'localhost' 163 | И я перехожу к следующему реквизиту 164 | И в таблице "ДанныеКлиентовТестирования" в поле с именем 'ДанныеКлиентовТестированияПорт' я ввожу текст '48222' 165 | И в таблице "ДанныеКлиентовТестирования" я завершаю редактирование строки 166 | 167 | И я выбираю пункт контекстного меню с именем 'КонтМенюПодключитьВыбранного' на элементе формы с именем "ДанныеКлиентовТестирования" 168 | 169 | Затем я жду, что в сообщениях пользователю будет подстрока "Уже открытый TestClient подключен" в течение 30 секунд 170 | 171 | И Я нажимаю на кнопку выполнить сценарии в Vanessa-Automation TestClient 172 | 173 | 174 | Сценарий: Активизация основного клиента 175 | И я закрываю TestClient "TM" 176 | И в таблице клиентов тестирования я активизирую строку 'Этот клиент' -------------------------------------------------------------------------------- /COPYING.LESSER.md: -------------------------------------------------------------------------------- 1 | GNU Lesser General Public License 2 | ================================= 3 | 4 | _Version 3, 29 June 2007_ 5 | _Copyright © 2007 Free Software Foundation, Inc. <>_ 6 | 7 | Everyone is permitted to copy and distribute verbatim copies 8 | of this license document, but changing it is not allowed. 9 | 10 | 11 | This version of the GNU Lesser General Public License incorporates 12 | the terms and conditions of version 3 of the GNU General Public 13 | License, supplemented by the additional permissions listed below. 14 | 15 | ### 0. Additional Definitions 16 | 17 | As used herein, “this License” refers to version 3 of the GNU Lesser 18 | General Public License, and the “GNU GPL” refers to version 3 of the GNU 19 | General Public License. 20 | 21 | “The Library” refers to a covered work governed by this License, 22 | other than an Application or a Combined Work as defined below. 23 | 24 | An “Application” is any work that makes use of an interface provided 25 | by the Library, but which is not otherwise based on the Library. 26 | Defining a subclass of a class defined by the Library is deemed a mode 27 | of using an interface provided by the Library. 28 | 29 | A “Combined Work” is a work produced by combining or linking an 30 | Application with the Library. The particular version of the Library 31 | with which the Combined Work was made is also called the “Linked 32 | Version”. 33 | 34 | The “Minimal Corresponding Source” for a Combined Work means the 35 | Corresponding Source for the Combined Work, excluding any source code 36 | for portions of the Combined Work that, considered in isolation, are 37 | based on the Application, and not on the Linked Version. 38 | 39 | The “Corresponding Application Code” for a Combined Work means the 40 | object code and/or source code for the Application, including any data 41 | and utility programs needed for reproducing the Combined Work from the 42 | Application, but excluding the System Libraries of the Combined Work. 43 | 44 | ### 1. Exception to Section 3 of the GNU GPL 45 | 46 | You may convey a covered work under sections 3 and 4 of this License 47 | without being bound by section 3 of the GNU GPL. 48 | 49 | ### 2. Conveying Modified Versions 50 | 51 | If you modify a copy of the Library, and, in your modifications, a 52 | facility refers to a function or data to be supplied by an Application 53 | that uses the facility (other than as an argument passed when the 54 | facility is invoked), then you may convey a copy of the modified 55 | version: 56 | 57 | * **a)** under this License, provided that you make a good faith effort to 58 | ensure that, in the event an Application does not supply the 59 | function or data, the facility still operates, and performs 60 | whatever part of its purpose remains meaningful, or 61 | 62 | * **b)** under the GNU GPL, with none of the additional permissions of 63 | this License applicable to that copy. 64 | 65 | ### 3. Object Code Incorporating Material from Library Header Files 66 | 67 | The object code form of an Application may incorporate material from 68 | a header file that is part of the Library. You may convey such object 69 | code under terms of your choice, provided that, if the incorporated 70 | material is not limited to numerical parameters, data structure 71 | layouts and accessors, or small macros, inline functions and templates 72 | (ten or fewer lines in length), you do both of the following: 73 | 74 | * **a)** Give prominent notice with each copy of the object code that the 75 | Library is used in it and that the Library and its use are 76 | covered by this License. 77 | * **b)** Accompany the object code with a copy of the GNU GPL and this license 78 | document. 79 | 80 | ### 4. Combined Works 81 | 82 | You may convey a Combined Work under terms of your choice that, 83 | taken together, effectively do not restrict modification of the 84 | portions of the Library contained in the Combined Work and reverse 85 | engineering for debugging such modifications, if you also do each of 86 | the following: 87 | 88 | * **a)** Give prominent notice with each copy of the Combined Work that 89 | the Library is used in it and that the Library and its use are 90 | covered by this License. 91 | 92 | * **b)** Accompany the Combined Work with a copy of the GNU GPL and this license 93 | document. 94 | 95 | * **c)** For a Combined Work that displays copyright notices during 96 | execution, include the copyright notice for the Library among 97 | these notices, as well as a reference directing the user to the 98 | copies of the GNU GPL and this license document. 99 | 100 | * **d)** Do one of the following: 101 | - **0)** Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | - **1)** Use a suitable shared library mechanism for linking with the 109 | Library. A suitable mechanism is one that **(a)** uses at run time 110 | a copy of the Library already present on the user's computer 111 | system, and **(b)** will operate properly with a modified version 112 | of the Library that is interface-compatible with the Linked 113 | Version. 114 | 115 | * **e)** Provide Installation Information, but only if you would otherwise 116 | be required to provide such information under section 6 of the 117 | GNU GPL, and only to the extent that such information is 118 | necessary to install and execute a modified version of the 119 | Combined Work produced by recombining or relinking the 120 | Application with a modified version of the Linked Version. (If 121 | you use option **4d0**, the Installation Information must accompany 122 | the Minimal Corresponding Source and Corresponding Application 123 | Code. If you use option **4d1**, you must provide the Installation 124 | Information in the manner specified by section 6 of the GNU GPL 125 | for conveying Corresponding Source.) 126 | 127 | ### 5. Combined Libraries 128 | 129 | You may place library facilities that are a work based on the 130 | Library side by side in a single library together with other library 131 | facilities that are not Applications and are not covered by this 132 | License, and convey such a combined library under terms of your 133 | choice, if you do both of the following: 134 | 135 | * **a)** Accompany the combined library with a copy of the same work based 136 | on the Library, uncombined with any other library facilities, 137 | conveyed under the terms of this License. 138 | * **b)** Give prominent notice with the combined library that part of it 139 | is a work based on the Library, and explaining where to find the 140 | accompanying uncombined form of the same work. 141 | 142 | ### 6. Revised Versions of the GNU Lesser General Public License 143 | 144 | The Free Software Foundation may publish revised and/or new versions 145 | of the GNU Lesser General Public License from time to time. Such new 146 | versions will be similar in spirit to the present version, but may 147 | differ in detail to address new problems or concerns. 148 | 149 | Each version is given a distinguishing version number. If the 150 | Library as you received it specifies that a certain numbered version 151 | of the GNU Lesser General Public License “or any later version” 152 | applies to it, you have the option of following the terms and 153 | conditions either of that published version or of any later version 154 | published by the Free Software Foundation. If the Library as you 155 | received it does not specify a version number of the GNU Lesser 156 | General Public License, you may choose any version of the GNU Lesser 157 | General Public License ever published by the Free Software Foundation. 158 | 159 | If the Library as you received it specifies that a proxy can decide 160 | whether future versions of the GNU Lesser General Public License shall 161 | apply, that proxy's public statement of acceptance of any version is 162 | permanent authorization for you to choose that version for the 163 | Library. 164 | -------------------------------------------------------------------------------- /src/test/java/TGLexerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of Turbo Gherkin Parser. 3 | * 4 | * Copyright © 2020-2020 5 | * Valery Maximov , 1c-syntax team , BIA Technologies team and contributors 6 | * 7 | * SPDX-License-Identifier: LGPL-3.0-or-later 8 | * 9 | * Turbo Gherkin Parser is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3.0 of the License, or (at your option) any later version. 13 | * 14 | * Turbo Gherkin Parser is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Turbo Gherkin Parser. 21 | */ 22 | 23 | import org.junit.jupiter.api.Test; 24 | import com.github._1c_syntax.turbo.gherkin.parser.TurboGherkinLexer; 25 | 26 | class TGLexerTest { 27 | 28 | @Test 29 | void testWhitespaces() { 30 | TestUtils.assertThatTokens(" @А\t\t", 31 | TurboGherkinLexer.SPACE, 32 | TurboGherkinLexer.SPACE, 33 | TurboGherkinLexer.AT, 34 | TurboGherkinLexer.BUT_KEYWORD, 35 | TurboGherkinLexer.TAB, 36 | TurboGherkinLexer.TAB, 37 | TurboGherkinLexer.EOF 38 | ); 39 | 40 | TestUtils.assertThatTokens(" \"@А\t\t\"", 41 | TurboGherkinLexer.SPACE, 42 | TurboGherkinLexer.SPACE, 43 | TurboGherkinLexer.STRING, 44 | TurboGherkinLexer.EOF 45 | ); 46 | } 47 | 48 | @Test 49 | void testBOM() { 50 | TestUtils.assertThatTokens('\uFEFF' + "Feature:", 51 | TurboGherkinLexer.FEATURE_KEYWORD, 52 | TurboGherkinLexer.EOF); 53 | } 54 | 55 | @Test 56 | void testFEATURE_KEYWORD() { 57 | var checkToken = TurboGherkinLexer.FEATURE_KEYWORD; 58 | TestUtils.assertThatContains("Feature:", checkToken); 59 | TestUtils.assertThatContains("Функция:", checkToken); 60 | TestUtils.assertThatContains("Функционал:", checkToken); 61 | TestUtils.assertThatContains("Функциональность:", checkToken); 62 | TestUtils.assertThatContains("Свойство:", checkToken); 63 | TestUtils.assertThatNotContains("Feature", checkToken); 64 | TestUtils.assertThatNotContains("Функция :", checkToken); 65 | TestUtils.assertThatNotContains("Функционал\t:", checkToken); 66 | TestUtils.assertThatNotContains("Функциональность\n:", checkToken); 67 | TestUtils.assertThatNotContains("Свойство#:", checkToken); 68 | } 69 | 70 | @Test 71 | void testBACKGROUND_KEYWORD() { 72 | var checkToken = TurboGherkinLexer.BACKGROUND_KEYWORD; 73 | TestUtils.assertThatContains("Background:", checkToken); 74 | TestUtils.assertThatContains("Контекст:", checkToken); 75 | TestUtils.assertThatContains("Предыстория:", checkToken); 76 | TestUtils.assertThatNotContains("Background", checkToken); 77 | TestUtils.assertThatNotContains("Контекст :", checkToken); 78 | TestUtils.assertThatNotContains("Предыстория\t:", checkToken); 79 | TestUtils.assertThatNotContains("Предыстория\n:", checkToken); 80 | TestUtils.assertThatNotContains("Предыстория#:", checkToken); 81 | } 82 | 83 | @Test 84 | void testSCENARIO_KEYWORD() { 85 | var checkToken = TurboGherkinLexer.SCENARIO_KEYWORD; 86 | TestUtils.assertThatContains("Scenario:", checkToken); 87 | TestUtils.assertThatContains("Сценарий:", checkToken); 88 | TestUtils.assertThatNotContains("Scenario", checkToken); 89 | TestUtils.assertThatNotContains("Сценарий :", checkToken); 90 | TestUtils.assertThatNotContains("Scenario\t:", checkToken); 91 | TestUtils.assertThatNotContains("Scenario\n:", checkToken); 92 | TestUtils.assertThatNotContains("Scenario#:", checkToken); 93 | } 94 | 95 | @Test 96 | void testSCENARIOS_KEYWORD() { 97 | var checkToken = TurboGherkinLexer.SCENARIOS_KEYWORD; 98 | TestUtils.assertThatContains("Scenarios:", checkToken); 99 | TestUtils.assertThatContains("Сценарии:", checkToken); 100 | TestUtils.assertThatNotContains("Scenari", checkToken); 101 | TestUtils.assertThatNotContains("Сценарии :", checkToken); 102 | TestUtils.assertThatNotContains("Scenarios\t:", checkToken); 103 | TestUtils.assertThatNotContains("Scenarios\n:", checkToken); 104 | TestUtils.assertThatNotContains("Scenarios#:", checkToken); 105 | } 106 | 107 | @Test 108 | void testSCENARIO_OUTLINE_KEYWORD() { 109 | var checkToken = TurboGherkinLexer.SCENARIO_OUTLINE_KEYWORD; 110 | TestUtils.assertThatContains("Scenario outline:", checkToken); 111 | TestUtils.assertThatContains("Scenario template:", checkToken); 112 | TestUtils.assertThatContains("Структура сценария:", checkToken); 113 | TestUtils.assertThatNotContains("Scenario outline", checkToken); 114 | TestUtils.assertThatNotContains("Scenario outline :", checkToken); 115 | TestUtils.assertThatNotContains("Scenario outline:", checkToken); 116 | TestUtils.assertThatNotContains("Scenario\toutline:", checkToken); 117 | TestUtils.assertThatNotContains("Scenariooutline:", checkToken); 118 | } 119 | 120 | @Test 121 | void testEXAMPLE_KEYWORD() { 122 | var checkToken = TurboGherkinLexer.EXAMPLE_KEYWORD; 123 | TestUtils.assertThatContains("Example:", checkToken); 124 | TestUtils.assertThatContains("Пример:", checkToken); 125 | TestUtils.assertThatNotContains("Example", checkToken); 126 | TestUtils.assertThatNotContains("Примеры:", checkToken); 127 | TestUtils.assertThatNotContains("Пример :", checkToken); 128 | TestUtils.assertThatNotContains("Пример\t:", checkToken); 129 | } 130 | 131 | @Test 132 | void testEXAMPLES_KEYWORD() { 133 | var checkToken = TurboGherkinLexer.EXAMPLES_KEYWORD; 134 | TestUtils.assertThatContains("Examples:", checkToken); 135 | TestUtils.assertThatContains("Примеры:", checkToken); 136 | TestUtils.assertThatNotContains("Examples", checkToken); 137 | TestUtils.assertThatNotContains("Пример:", checkToken); 138 | TestUtils.assertThatNotContains("Примеры :", checkToken); 139 | TestUtils.assertThatNotContains("Примеры\t:", checkToken); 140 | } 141 | 142 | @Test 143 | void testGIVEN_KEYWORD() { 144 | var checkToken = TurboGherkinLexer.GIVEN_KEYWORD; 145 | TestUtils.assertThatContains("Given", checkToken); 146 | TestUtils.assertThatContains("Дано", checkToken); 147 | TestUtils.assertThatContains("Допустим", checkToken); 148 | TestUtils.assertThatContains("Пусть", checkToken); 149 | TestUtils.assertThatContains("Пусть будет", checkToken); 150 | TestUtils.assertThatContains("Пусть\t Будет \n #Мир", checkToken); 151 | TestUtils.assertThatContains("Ну и пусть", checkToken); 152 | TestUtils.assertThatNotContains("#Пусть:", checkToken); 153 | TestUtils.assertThatNotContains("Данo", checkToken); 154 | } 155 | 156 | @Test 157 | void testWHEN_KEYWORD() { 158 | var checkToken = TurboGherkinLexer.WHEN_KEYWORD; 159 | TestUtils.assertThatContains("When", checkToken); 160 | TestUtils.assertThatContains("КОгда", checkToken); 161 | TestUtils.assertThatContains("КОгда нибудь", checkToken); 162 | TestUtils.assertThatNotContains("#КОгда:", checkToken); 163 | } 164 | 165 | @Test 166 | void testIF_KEYWORD() { 167 | var checkToken = TurboGherkinLexer.IF_KEYWORD; 168 | TestUtils.assertThatContains("If", checkToken); 169 | TestUtils.assertThatContains("Если", checkToken); 170 | TestUtils.assertThatContains("Если мы будем", checkToken); 171 | TestUtils.assertThatNotContains("#If:", checkToken); 172 | } 173 | 174 | @Test 175 | void testTHEN_KEYWORD() { 176 | var checkToken = TurboGherkinLexer.THEN_KEYWORD; 177 | TestUtils.assertThatContains("Then", checkToken); 178 | TestUtils.assertThatContains("Тогда", checkToken); 179 | TestUtils.assertThatContains("То", checkToken); 180 | TestUtils.assertThatContains("Затем", checkToken); 181 | TestUtils.assertThatContains("Тогда или не тогда", checkToken); 182 | TestUtils.assertThatNotContains("#Потому", checkToken); 183 | } 184 | 185 | @Test 186 | void testAND_KEYWORD() { 187 | var checkToken = TurboGherkinLexer.AND_KEYWORD; 188 | TestUtils.assertThatContains("And", checkToken); 189 | TestUtils.assertThatContains("И", checkToken); 190 | TestUtils.assertThatContains("К тому же", checkToken); 191 | TestUtils.assertThatContains("И так", checkToken); 192 | TestUtils.assertThatContains("Также", checkToken); 193 | TestUtils.assertThatNotContains("К тому\tже", checkToken); 194 | } 195 | 196 | @Test 197 | void testBUT_KEYWORD() { 198 | var checkToken = TurboGherkinLexer.BUT_KEYWORD; 199 | TestUtils.assertThatContains("But", checkToken); 200 | TestUtils.assertThatContains("Но", checkToken); 201 | TestUtils.assertThatContains("А", checkToken); 202 | TestUtils.assertThatContains("Иначе", checkToken); 203 | TestUtils.assertThatNotContains("не", checkToken); 204 | } 205 | 206 | @Test 207 | void testRULE_KEYWORD() { 208 | var checkToken = TurboGherkinLexer.RULE_KEYWORD; 209 | TestUtils.assertThatContains("Rule:", checkToken); 210 | TestUtils.assertThatContains("Правило:", checkToken); 211 | TestUtils.assertThatNotContains("Правила", checkToken); 212 | TestUtils.assertThatNotContains("Правило", checkToken); 213 | TestUtils.assertThatNotContains("Правило :", checkToken); 214 | TestUtils.assertThatNotContains("Правило\t:", checkToken); 215 | } 216 | 217 | @Test 218 | void testString() { 219 | var checkToken = TurboGherkinLexer.STRING; 220 | TestUtils.assertThatContains("'Строка в одинарных кавычках'", checkToken); 221 | TestUtils.assertThatContains("\"Строка в двойных кавычках\"", checkToken); 222 | TestUtils.assertThatNotContains("\"Неправльная строка'", checkToken); 223 | } 224 | 225 | @Test 226 | void testMultiString() { 227 | TestUtils.assertThatTokens(" \"\"\"\n bb \"бла\" bb\n\"\"\"", 228 | TurboGherkinLexer.SPACE, 229 | TurboGherkinLexer.DOC_STRINGS, 230 | TurboGherkinLexer.EOL, 231 | TurboGherkinLexer.SPACE, 232 | TurboGherkinLexer.ANYSYMBOL, 233 | TurboGherkinLexer.ANYSYMBOL, 234 | TurboGherkinLexer.SPACE, 235 | TurboGherkinLexer.STRING, 236 | TurboGherkinLexer.SPACE, 237 | TurboGherkinLexer.ANYSYMBOL, 238 | TurboGherkinLexer.ANYSYMBOL, 239 | TurboGherkinLexer.EOL, 240 | TurboGherkinLexer.DOC_STRINGS, 241 | TurboGherkinLexer.EOF 242 | ); 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/test/java/TGParserTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of Turbo Gherkin Parser. 3 | * 4 | * Copyright © 2020-2020 5 | * Valery Maximov , 1c-syntax team , BIA Technologies team and contributors 6 | * 7 | * SPDX-License-Identifier: LGPL-3.0-or-later 8 | * 9 | * Turbo Gherkin Parser is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 3.0 of the License, or (at your option) any later version. 13 | * 14 | * Turbo Gherkin Parser is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Turbo Gherkin Parser. 21 | */ 22 | 23 | import org.apache.commons.io.FileUtils; 24 | import org.junit.jupiter.api.Test; 25 | import com.github._1c_syntax.turbo.gherkin.parser.GherkinParserRuleContext; 26 | import com.github._1c_syntax.turbo.gherkin.parser.TurboGherkinLexer; 27 | import com.github._1c_syntax.turbo.gherkin.parser.TurboGherkinParser; 28 | 29 | import java.io.IOException; 30 | import java.nio.charset.StandardCharsets; 31 | import java.nio.file.Paths; 32 | 33 | import static org.assertj.core.api.Assertions.assertThat; 34 | 35 | class TGParserTest { 36 | 37 | @Test 38 | void testFeature() { 39 | var parser = TestUtils.createParser( 40 | "Функционал: тестовый пример\n" + 41 | "Описание тестового сценария\n" + 42 | "Сценарий: тестовый сценарий"); 43 | var feature = parser.feature(); 44 | assertThat(TestUtils.treeContainsErrors(feature)).isFalse(); 45 | TestUtils.assertThatContains(feature, 46 | TurboGherkinParser.RULE_featureName, 47 | TurboGherkinParser.RULE_featureDescription, 48 | TurboGherkinParser.RULE_featureBody); 49 | 50 | assertThat(feature.featureName()).isNotNull(); 51 | assertThat(feature.featureName().getText()) 52 | .isNotNull() 53 | .isEqualTo("тестовый пример"); 54 | assertThat(feature.featureDescription()).isNotNull(); 55 | assertThat(feature.featureDescription().getText()) 56 | .isNotNull() 57 | .isEqualTo("Описание тестового сценария\n"); 58 | } 59 | 60 | @Test 61 | void testTags() { 62 | var parser = TestUtils.createParser( 63 | "@Тег1\n\n" + 64 | "@Тег2\n" + 65 | "Функционал: тестовый пример\n" + 66 | "Описание тестового сценария\n" + 67 | "Сценарий: тестовый сценарий"); 68 | var feature = parser.feature(); 69 | assertThat(TestUtils.treeContainsErrors(feature)).isFalse(); 70 | TestUtils.assertThatContains(feature, 71 | TurboGherkinParser.RULE_featureName, 72 | TurboGherkinParser.RULE_tags, 73 | TurboGherkinParser.RULE_featureDescription, 74 | TurboGherkinParser.RULE_featureBody); 75 | 76 | var tags = feature.tags(); 77 | TestUtils.assertThatContains(tags, 78 | TurboGherkinParser.RULE_tag); 79 | assertThat(TestUtils.getAllChildren(tags)) 80 | .filteredOn(child -> child.getRuleIndex() == TurboGherkinParser.RULE_tag) 81 | .hasSize(2) 82 | .anyMatch(child -> "@Тег1".equals(child.getText())) 83 | .anyMatch(child -> "@Тег2".equals(child.getText())); 84 | } 85 | 86 | @Test 87 | void testFeatureBody() { 88 | var parser = TestUtils.createParser( 89 | "Функционал: тестовый пример\n" + 90 | "Контекст: \n" + 91 | "Тестовое описание контекста\n" + 92 | "Дано что-to \n" + 93 | "И что-то еще\n" + 94 | "Сценарий: тестовый сценарий\n" + 95 | "У сценария тоже бывает описание, перед шагами\n" + 96 | "Когда первый шаг сценария\n" + 97 | "Затем второй"); 98 | var feature = parser.feature(); 99 | assertThat(TestUtils.treeContainsErrors(feature)).isFalse(); 100 | TestUtils.assertThatContains(feature, 101 | TurboGherkinParser.RULE_featureName, 102 | TurboGherkinParser.RULE_featureBody); 103 | 104 | var featureBody = feature.featureBody(); 105 | TestUtils.assertThatContains(featureBody, 106 | TurboGherkinParser.RULE_background, 107 | TurboGherkinParser.RULE_scenarios); 108 | 109 | parser = TestUtils.createParser( 110 | "Функционал: тестовый пример\n" + 111 | "Контекст: \n" + 112 | "Тестовое описание контекста\n" + 113 | "Дано что-to \n" + 114 | "И что-то еще\n" + 115 | "Правило: бизнес правило номер 1\n" + 116 | "Сценарий: тестовый сценарий\n" + 117 | "У сценария тоже бывает описание, перед шагами\n" + 118 | "Когда первый шаг сценария\n" + 119 | "Затем второй"); 120 | feature = parser.feature(); 121 | assertThat(TestUtils.treeContainsErrors(feature)).isFalse(); 122 | TestUtils.assertThatContains(feature, 123 | TurboGherkinParser.RULE_featureName, 124 | TurboGherkinParser.RULE_featureBody); 125 | 126 | featureBody = feature.featureBody(); 127 | TestUtils.assertThatContains(featureBody, 128 | TurboGherkinParser.RULE_background, 129 | TurboGherkinParser.RULE_businessRules); 130 | } 131 | 132 | @Test 133 | void testBackground() { 134 | var parser = TestUtils.createParser( 135 | "Функционал: тестовый пример\n" + 136 | "Контекст: \n" + 137 | "Тестовое описание контекста\n" + 138 | "Дано что-to \n" + 139 | "И что-то еще\n" + 140 | "Сценарий: тестовый сценарий\n" + 141 | "У сценария тоже бывает описание, перед шагами\n" + 142 | "Когда первый шаг сценария\n" + 143 | "Затем второй"); 144 | var feature = parser.feature(); 145 | assertThat(TestUtils.treeContainsErrors(feature)).isFalse(); 146 | TestUtils.assertThatContains(feature, TurboGherkinParser.RULE_featureBody); 147 | var featureBody = feature.featureBody(); 148 | TestUtils.assertThatContains(featureBody, TurboGherkinParser.RULE_background); 149 | 150 | var background = featureBody.background(); 151 | TestUtils.assertThatContains(background, 152 | TurboGherkinParser.RULE_description, 153 | TurboGherkinParser.RULE_steps); 154 | 155 | assertThat(background.description()).isNotNull(); 156 | assertThat(background.description().getText()) 157 | .isNotNull() 158 | .isEqualTo("Тестовое описание контекста\n"); 159 | 160 | assertThat(TestUtils.getAllChildren(background.steps())) 161 | .filteredOn(child -> child.getRuleIndex() == TurboGherkinParser.RULE_step) 162 | .hasSize(2) 163 | .allMatch(child -> !child.getText().isBlank()); 164 | 165 | parser = TestUtils.createParser( 166 | "Функционал: тестовый пример\n" + 167 | "Контекст: \n" + 168 | "Дано что-to \n" + 169 | "Сценарий: тестовый сценарий\n" + 170 | "У сценария тоже бывает описание, перед шагами\n" + 171 | "Когда первый шаг сценария\n" + 172 | "Затем второй"); 173 | 174 | background = parser.feature().featureBody().background(); 175 | TestUtils.assertThatContains(background, TurboGherkinParser.RULE_steps); 176 | 177 | } 178 | 179 | @Test 180 | void testScenarios() { 181 | var parser = TestUtils.createParser( 182 | "Функционал: тестовый пример\n" + 183 | "Контекст: \n" + 184 | "Тестовое описание контекста\n" + 185 | "Дано что-to \n" + 186 | "И что-то еще\n" + 187 | "Сценарий: тестовый сценарий\n" + 188 | "У сценария тоже бывает описание\n, перед шагами\n" + 189 | "Когда первый шаг сценария\n" + 190 | "Затем второй\n" + 191 | "Сценарий: второй тестовый сценарий\n" + 192 | "Когда второй сценарий без описания\n" + 193 | "Тогда разбор тоже работает корректно\n" + 194 | "And no problem\n\n" + 195 | "Структура Сценария: Шаблонный тестовый сценарий\n" + 196 | "Шаблонный сценарий может иметь описание, как и все остальные\n" + 197 | "Когда <Парам1> сценарий без описания\n" + 198 | "Тогда <Значение2>\n" + 199 | "Примеры:\n" + 200 | "|Парам1|Значение2|\n" + 201 | "|ЫЫ|1|"); 202 | var feature = parser.feature(); 203 | assertThat(TestUtils.treeContainsErrors(feature)).isFalse(); 204 | TestUtils.assertThatContains(feature, TurboGherkinParser.RULE_featureBody); 205 | var featureBody = feature.featureBody(); 206 | TestUtils.assertThatContains(featureBody, 207 | TurboGherkinParser.RULE_background, 208 | TurboGherkinParser.RULE_scenarios); 209 | 210 | var scenarios = featureBody.scenarios(); 211 | TestUtils.assertThatContains(scenarios, 212 | TurboGherkinParser.RULE_scenario, 213 | TurboGherkinParser.RULE_scenarioOutline); 214 | assertThat(scenarios.scenario()).hasSize(2); 215 | assertThat(scenarios.scenarioOutline()).hasSize(1); 216 | 217 | // первый сценарий 218 | var scenario = (TurboGherkinParser.ScenarioContext) 219 | ((GherkinParserRuleContext) scenarios.getChild(0)).getRuleContext(); 220 | 221 | assertThat(scenario.description()).isNotNull(); 222 | assertThat(scenario.description().getText()) 223 | .isNotNull() 224 | .isEqualTo("У сценария тоже бывает описание\n, перед шагами\n"); 225 | 226 | assertThat(scenario.name().getText()) 227 | .isNotNull() 228 | .isEqualTo("тестовый сценарий"); 229 | 230 | assertThat(TestUtils.getAllChildren(scenario.steps())) 231 | .filteredOn(child -> child.getRuleIndex() == TurboGherkinParser.RULE_step) 232 | .hasSize(2) 233 | .allMatch(child -> !child.getText().isBlank()); 234 | 235 | // второй сценарий 236 | scenario = (TurboGherkinParser.ScenarioContext) 237 | ((GherkinParserRuleContext) scenarios.getChild(1)).getRuleContext(); 238 | 239 | assertThat(scenario.description()).isNotNull(); 240 | assertThat(scenario.description().getText()) 241 | .isNotNull() 242 | .isEmpty(); 243 | 244 | assertThat(scenario.name().getText()) 245 | .isNotNull() 246 | .isEqualTo("второй тестовый сценарий"); 247 | 248 | assertThat(TestUtils.getAllChildren(scenario.steps())) 249 | .filteredOn(child -> child.getRuleIndex() == TurboGherkinParser.RULE_step) 250 | .hasSize(3) 251 | .allMatch(child -> !child.getText().isBlank()); 252 | 253 | // шаблонный сценарий 254 | var scenarioOutline = (TurboGherkinParser.ScenarioOutlineContext) 255 | ((GherkinParserRuleContext) scenarios.getChild(2)).getRuleContext(); 256 | 257 | TestUtils.assertThatContains(scenarioOutline, 258 | TurboGherkinParser.RULE_steps, 259 | TurboGherkinParser.RULE_examples, 260 | TurboGherkinParser.RULE_name, 261 | TurboGherkinParser.RULE_description); 262 | 263 | assertThat(TestUtils.getAllChildren(scenarioOutline.steps())) 264 | .filteredOn(child -> child.getRuleIndex() == TurboGherkinParser.RULE_step) 265 | .hasSize(2) 266 | .allMatch(child -> !child.getText().isBlank()); 267 | 268 | assertThat(scenarioOutline.examples().table()).isNotNull(); 269 | assertThat(scenarioOutline.examples().table().tableHead()).isNotNull(); 270 | assertThat(scenarioOutline.examples().table().tableRows()).isNotNull(); 271 | assertThat(scenarioOutline.examples().table().tableRows().tableRow()).hasSize(1); 272 | } 273 | 274 | @Test 275 | void testBusinessRules() { 276 | var parser = TestUtils.createParser( 277 | "Функционал: тестовый пример\n" + 278 | "Контекст: \n" + 279 | "Тестовое описание контекста\n" + 280 | "Дано что-to \n" + 281 | "И что-то еще\n" + 282 | "Rule: Business rule №1\n" + 283 | "Description rule\n" + 284 | "Сценарий: тестовый сценарий\n" + 285 | "У сценария тоже бывает описание\n, перед шагами\n" + 286 | "Когда первый шаг сценария\n" + 287 | "Затем второй\n" + 288 | "Правило: Бизнес правило 2\n" + 289 | "Контекст: \n" + 290 | "У бизнес правила может быть контекст\n" + 291 | "Хотя и считается деприкейтом\n" + 292 | "Дано что-to важное\n" + 293 | "Структура Сценария: Шаблонный тестовый сценарий\n" + 294 | "Когда <Парам1> сценарий без описания\n" + 295 | "Тогда <Значение2>\n" + 296 | "Примеры:\n" + 297 | "|Парам1|Значение2|\n" + 298 | "|ЫЫ|1|"); 299 | var feature = parser.feature(); 300 | assertThat(TestUtils.treeContainsErrors(feature)).isFalse(); 301 | TestUtils.assertThatContains(feature, TurboGherkinParser.RULE_featureBody); 302 | var featureBody = feature.featureBody(); 303 | TestUtils.assertThatContains(featureBody, 304 | TurboGherkinParser.RULE_background, 305 | TurboGherkinParser.RULE_businessRules); 306 | 307 | var businessRules = featureBody.businessRules(); 308 | TestUtils.assertThatContains(businessRules, TurboGherkinParser.RULE_businessRule); 309 | assertThat(businessRules.businessRule()).hasSize(2); 310 | 311 | // первое правило 312 | var rule = (TurboGherkinParser.BusinessRuleContext) 313 | ((GherkinParserRuleContext) businessRules.getChild(0)).getRuleContext(); 314 | 315 | assertThat(rule.description()).isNotNull(); 316 | assertThat(rule.description().getText()) 317 | .isNotNull() 318 | .isEqualTo("Description rule\n"); 319 | 320 | assertThat(rule.name()).isNotNull(); 321 | assertThat(rule.name().getText()) 322 | .isNotNull() 323 | .isEqualTo("Business rule №1"); 324 | 325 | TestUtils.assertThatContains(rule, TurboGherkinParser.RULE_scenarios); 326 | 327 | assertThat(rule.scenarios().scenario()).isNotNull().hasSize(1); 328 | 329 | // второе правило 330 | rule = (TurboGherkinParser.BusinessRuleContext) 331 | ((GherkinParserRuleContext) businessRules.getChild(1)).getRuleContext(); 332 | 333 | assertThat(rule.description()).isNotNull(); 334 | assertThat(rule.description().getText()) 335 | .isNotNull() 336 | .isEmpty(); 337 | 338 | assertThat(rule.name()).isNotNull(); 339 | assertThat(rule.name().getText()) 340 | .isNotNull() 341 | .isEqualTo("Бизнес правило 2"); 342 | 343 | TestUtils.assertThatContains(rule, 344 | TurboGherkinParser.RULE_background, 345 | TurboGherkinParser.RULE_scenarios); 346 | } 347 | 348 | @Test 349 | void testTable() { 350 | var parser = TestUtils.createParser( 351 | "Функционал: тестовый пример\n" + 352 | "Структура Сценария: Шаблонный тестовый сценарий\n" + 353 | "Когда <Парам1> сценарий без описания\n" + 354 | "Тогда <Значение2>\n" + 355 | "Примеры:\n" + 356 | "|Парам1|Значение2|\n" + 357 | "|Парам1|||||||||||\n" + 358 | "|||||знач|||||||\n" + 359 | "||\n" + 360 | "\n" + 361 | "|ЫЫ|1|"); 362 | var feature = parser.feature(); 363 | assertThat(TestUtils.treeContainsErrors(feature)).isFalse(); 364 | TestUtils.assertThatContains(feature, TurboGherkinParser.RULE_featureBody); 365 | assertThat(feature.featureBody().scenarios()).isNotNull(); 366 | 367 | var scenarioOutlines = feature.featureBody().scenarios().scenarioOutline(); 368 | assertThat(scenarioOutlines).isNotNull().hasSize(1); 369 | var scenarioOutline = scenarioOutlines.get(0); 370 | assertThat(scenarioOutline.examples()).isNotNull(); 371 | assertThat(scenarioOutline.examples().table()).isNotNull(); 372 | var table = scenarioOutline.examples().table(); 373 | assertThat(table.tableHead()).isNotNull(); 374 | assertThat(table.tableHead().tableCell()) 375 | .isNotNull() 376 | .hasSize(2) 377 | .allMatch(cell -> cell.tableCellValue() != null && cell.tableCellValue().getText() != null) 378 | .extracting(TurboGherkinParser.TableCellContext::tableCellValue) 379 | .anyMatch(cell -> "Парам1".equals(cell.getText())) 380 | .anyMatch(cell -> "Значение2".equals(cell.getText())); 381 | 382 | assertThat(table.tableRows()).isNotNull(); 383 | assertThat(table.tableRows().tableRow()).hasSize(4); 384 | 385 | assertThat(table.tableRows().tableRow().get(0).tableCell()).isNotNull().hasSize(11); 386 | assertThat(table.tableRows().tableRow().get(1).tableCell()).isNotNull().hasSize(11); 387 | assertThat(table.tableRows().tableRow().get(2).tableCell()).isNotNull().hasSize(1); 388 | assertThat(table.tableRows().tableRow().get(3).tableCell()).isNotNull().hasSize(2); 389 | 390 | } 391 | 392 | @Test 393 | void testParameters() { 394 | var parser = TestUtils.createParser( 395 | "Функционал: тестовый пример\n" + 396 | "Сценарий: Сценарий с \"Параметром\"\n" + 397 | "Когда параметр равен 'строковый параметр' или \n" + 398 | "\"\"\"\n" + 399 | "многострочный \n" + 400 | "сложный параметр\n" + 401 | "\"\"\"\n" + 402 | "Тогда Значение больше 1.23 но меньше 0.99\n" + 403 | "И Значение не равно 1\n" + 404 | "И Значение нет в табличке\n" + 405 | " |Парам1|Значение2|\n" + 406 | " |ЫЫ|1|"); 407 | 408 | var feature = parser.feature(); 409 | assertThat(TestUtils.treeContainsErrors(feature)).isFalse(); 410 | TestUtils.assertThatContains(feature, TurboGherkinParser.RULE_featureBody); 411 | assertThat(feature.featureBody().scenarios()).isNotNull(); 412 | assertThat(feature.featureBody().scenarios().scenario()).hasSize(1); 413 | 414 | var scenario = feature.featureBody().scenarios().scenario().get(0); 415 | assertThat(scenario.name()).isNotNull(); 416 | assertThat(scenario.name().parameter()) 417 | .isNotNull() 418 | .hasSize(1); 419 | assertThat(scenario.name().parameter().get(0)).isNotNull(); 420 | var param = scenario.name().parameter().get(0).getTokens().get(0); 421 | assertThat(param.getType()).isEqualTo(TurboGherkinLexer.STRING); 422 | assertThat(param.getText()).isEqualTo("\"Параметром\""); 423 | 424 | assertThat(scenario.steps()).isNotNull(); 425 | assertThat(scenario.steps().step()).hasSize(4); 426 | 427 | var step = scenario.steps().step().get(0); 428 | assertThat(step.name()).isNotNull(); 429 | assertThat(step.name().parameter()) 430 | .isNotNull() 431 | .hasSize(1); 432 | 433 | assertThat(step.docStrings()).isNotNull(); 434 | assertThat(step.docStrings().docStringsValue()).isNotNull(); 435 | assertThat(step.docStrings().docStringsValue().getText()) 436 | .isNotNull() 437 | .isEqualTo("многострочный \nсложный параметр\n"); 438 | 439 | param = step.name().parameter().get(0).getTokens().get(0); 440 | assertThat(param.getType()).isEqualTo(TurboGherkinLexer.STRING); 441 | assertThat(param.getText()).isEqualTo("'строковый параметр'"); 442 | 443 | step = scenario.steps().step().get(1); 444 | assertThat(step.name()).isNotNull(); 445 | assertThat(step.name().parameter()) 446 | .isNotNull() 447 | .hasSize(2); 448 | 449 | param = step.name().parameter().get(0).getTokens().get(0); 450 | assertThat(param.getType()).isEqualTo(TurboGherkinLexer.FLOAT); 451 | assertThat(param.getText()).isEqualTo("1.23"); 452 | 453 | step = scenario.steps().step().get(2); 454 | assertThat(step.name()).isNotNull(); 455 | assertThat(step.name().parameter()) 456 | .isNotNull() 457 | .hasSize(1); 458 | 459 | param = step.name().parameter().get(0).getTokens().get(0); 460 | assertThat(param.getType()).isEqualTo(TurboGherkinLexer.DECIMAL); 461 | assertThat(param.getText()).isEqualTo("1"); 462 | 463 | step = scenario.steps().step().get(3); 464 | assertThat(step.name()).isNotNull(); 465 | assertThat(step.name().parameter()) 466 | .isNotNull() 467 | .isEmpty(); 468 | 469 | assertThat(step.table()).isNotNull(); 470 | } 471 | 472 | @Test 473 | void testSmokyNoParsingError() { 474 | var srcDir = "./src/test/resources/correct"; 475 | FileUtils.listFiles(Paths.get(srcDir).toAbsolutePath().toFile(), new String[]{"feature"}, true) 476 | .forEach(filePath -> { 477 | try { 478 | var fileSource = FileUtils.readFileToString(filePath, StandardCharsets.UTF_8); 479 | var parser = TestUtils.createParser(fileSource); 480 | var feature = parser.feature(); 481 | assertThat(TestUtils.treeContainsErrors(feature)).isFalse(); 482 | 483 | } catch (IOException e) { 484 | e.printStackTrace(); 485 | } 486 | }); 487 | } 488 | 489 | @Test 490 | void testSmokyParsingError() { 491 | var srcDir = "./src/test/resources/uncorrect"; 492 | FileUtils.listFiles(Paths.get(srcDir).toAbsolutePath().toFile(), new String[]{"feature"}, true) 493 | .forEach(filePath -> { 494 | try { 495 | var fileSource = FileUtils.readFileToString(filePath, StandardCharsets.UTF_8); 496 | var parser = TestUtils.createParser(fileSource); 497 | var feature = parser.feature(); 498 | assertThat(TestUtils.treeContainsErrors(feature)).isTrue(); 499 | 500 | } catch (IOException e) { 501 | e.printStackTrace(); 502 | } 503 | }); 504 | } 505 | } 506 | -------------------------------------------------------------------------------- /COPYING.md: -------------------------------------------------------------------------------- 1 | GNU General Public License 2 | ========================== 3 | 4 | _Version 3, 29 June 2007_ 5 | _Copyright © 2007 Free Software Foundation, Inc. <>_ 6 | 7 | Everyone is permitted to copy and distribute verbatim copies of this license 8 | document, but changing it is not allowed. 9 | 10 | ## Preamble 11 | 12 | The GNU General Public License is a free, copyleft license for software and other 13 | kinds of works. 14 | 15 | The licenses for most software and other practical works are designed to take away 16 | your freedom to share and change the works. By contrast, the GNU General Public 17 | License is intended to guarantee your freedom to share and change all versions of a 18 | program--to make sure it remains free software for all its users. We, the Free 19 | Software Foundation, use the GNU General Public License for most of our software; it 20 | applies also to any other work released this way by its authors. You can apply it to 21 | your programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not price. Our General 24 | Public Licenses are designed to make sure that you have the freedom to distribute 25 | copies of free software (and charge for them if you wish), that you receive source 26 | code or can get it if you want it, that you can change the software or use pieces of 27 | it in new free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you these rights or 30 | asking you to surrender the rights. Therefore, you have certain responsibilities if 31 | you distribute copies of the software, or if you modify it: responsibilities to 32 | respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether gratis or for a fee, 35 | you must pass on to the recipients the same freedoms that you received. You must make 36 | sure that they, too, receive or can get the source code. And you must show them these 37 | terms so they know their rights. 38 | 39 | Developers that use the GNU GPL protect your rights with two steps: **(1)** assert 40 | copyright on the software, and **(2)** offer you this License giving you legal permission 41 | to copy, distribute and/or modify it. 42 | 43 | For the developers' and authors' protection, the GPL clearly explains that there is 44 | no warranty for this free software. For both users' and authors' sake, the GPL 45 | requires that modified versions be marked as changed, so that their problems will not 46 | be attributed erroneously to authors of previous versions. 47 | 48 | Some devices are designed to deny users access to install or run modified versions of 49 | the software inside them, although the manufacturer can do so. This is fundamentally 50 | incompatible with the aim of protecting users' freedom to change the software. The 51 | systematic pattern of such abuse occurs in the area of products for individuals to 52 | use, which is precisely where it is most unacceptable. Therefore, we have designed 53 | this version of the GPL to prohibit the practice for those products. If such problems 54 | arise substantially in other domains, we stand ready to extend this provision to 55 | those domains in future versions of the GPL, as needed to protect the freedom of 56 | users. 57 | 58 | Finally, every program is threatened constantly by software patents. States should 59 | not allow patents to restrict development and use of software on general-purpose 60 | computers, but in those that do, we wish to avoid the special danger that patents 61 | applied to a free program could make it effectively proprietary. To prevent this, the 62 | GPL assures that patents cannot be used to render the program non-free. 63 | 64 | The precise terms and conditions for copying, distribution and modification follow. 65 | 66 | ## TERMS AND CONDITIONS 67 | 68 | ### 0. Definitions 69 | 70 | “This License” refers to version 3 of the GNU General Public License. 71 | 72 | “Copyright” also means copyright-like laws that apply to other kinds of 73 | works, such as semiconductor masks. 74 | 75 | “The Program” refers to any copyrightable work licensed under this 76 | License. Each licensee is addressed as “you”. “Licensees” and 77 | “recipients” may be individuals or organizations. 78 | 79 | To “modify” a work means to copy from or adapt all or part of the work in 80 | a fashion requiring copyright permission, other than the making of an exact copy. The 81 | resulting work is called a “modified version” of the earlier work or a 82 | work “based on” the earlier work. 83 | 84 | A “covered work” means either the unmodified Program or a work based on 85 | the Program. 86 | 87 | To “propagate” a work means to do anything with it that, without 88 | permission, would make you directly or secondarily liable for infringement under 89 | applicable copyright law, except executing it on a computer or modifying a private 90 | copy. Propagation includes copying, distribution (with or without modification), 91 | making available to the public, and in some countries other activities as well. 92 | 93 | To “convey” a work means any kind of propagation that enables other 94 | parties to make or receive copies. Mere interaction with a user through a computer 95 | network, with no transfer of a copy, is not conveying. 96 | 97 | An interactive user interface displays “Appropriate Legal Notices” to the 98 | extent that it includes a convenient and prominently visible feature that **(1)** 99 | displays an appropriate copyright notice, and **(2)** tells the user that there is no 100 | warranty for the work (except to the extent that warranties are provided), that 101 | licensees may convey the work under this License, and how to view a copy of this 102 | License. If the interface presents a list of user commands or options, such as a 103 | menu, a prominent item in the list meets this criterion. 104 | 105 | ### 1. Source Code 106 | 107 | The “source code” for a work means the preferred form of the work for 108 | making modifications to it. “Object code” means any non-source form of a 109 | work. 110 | 111 | A “Standard Interface” means an interface that either is an official 112 | standard defined by a recognized standards body, or, in the case of interfaces 113 | specified for a particular programming language, one that is widely used among 114 | developers working in that language. 115 | 116 | The “System Libraries” of an executable work include anything, other than 117 | the work as a whole, that **(a)** is included in the normal form of packaging a Major 118 | Component, but which is not part of that Major Component, and **(b)** serves only to 119 | enable use of the work with that Major Component, or to implement a Standard 120 | Interface for which an implementation is available to the public in source code form. 121 | A “Major Component”, in this context, means a major essential component 122 | (kernel, window system, and so on) of the specific operating system (if any) on which 123 | the executable work runs, or a compiler used to produce the work, or an object code 124 | interpreter used to run it. 125 | 126 | The “Corresponding Source” for a work in object code form means all the 127 | source code needed to generate, install, and (for an executable work) run the object 128 | code and to modify the work, including scripts to control those activities. However, 129 | it does not include the work's System Libraries, or general-purpose tools or 130 | generally available free programs which are used unmodified in performing those 131 | activities but which are not part of the work. For example, Corresponding Source 132 | includes interface definition files associated with source files for the work, and 133 | the source code for shared libraries and dynamically linked subprograms that the work 134 | is specifically designed to require, such as by intimate data communication or 135 | control flow between those subprograms and other parts of the work. 136 | 137 | The Corresponding Source need not include anything that users can regenerate 138 | automatically from other parts of the Corresponding Source. 139 | 140 | The Corresponding Source for a work in source code form is that same work. 141 | 142 | ### 2. Basic Permissions 143 | 144 | All rights granted under this License are granted for the term of copyright on the 145 | Program, and are irrevocable provided the stated conditions are met. This License 146 | explicitly affirms your unlimited permission to run the unmodified Program. The 147 | output from running a covered work is covered by this License only if the output, 148 | given its content, constitutes a covered work. This License acknowledges your rights 149 | of fair use or other equivalent, as provided by copyright law. 150 | 151 | You may make, run and propagate covered works that you do not convey, without 152 | conditions so long as your license otherwise remains in force. You may convey covered 153 | works to others for the sole purpose of having them make modifications exclusively 154 | for you, or provide you with facilities for running those works, provided that you 155 | comply with the terms of this License in conveying all material for which you do not 156 | control copyright. Those thus making or running the covered works for you must do so 157 | exclusively on your behalf, under your direction and control, on terms that prohibit 158 | them from making any copies of your copyrighted material outside their relationship 159 | with you. 160 | 161 | Conveying under any other circumstances is permitted solely under the conditions 162 | stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 163 | 164 | ### 3. Protecting Users' Legal Rights From Anti-Circumvention Law 165 | 166 | No covered work shall be deemed part of an effective technological measure under any 167 | applicable law fulfilling obligations under article 11 of the WIPO copyright treaty 168 | adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention 169 | of such measures. 170 | 171 | When you convey a covered work, you waive any legal power to forbid circumvention of 172 | technological measures to the extent such circumvention is effected by exercising 173 | rights under this License with respect to the covered work, and you disclaim any 174 | intention to limit operation or modification of the work as a means of enforcing, 175 | against the work's users, your or third parties' legal rights to forbid circumvention 176 | of technological measures. 177 | 178 | ### 4. Conveying Verbatim Copies 179 | 180 | You may convey verbatim copies of the Program's source code as you receive it, in any 181 | medium, provided that you conspicuously and appropriately publish on each copy an 182 | appropriate copyright notice; keep intact all notices stating that this License and 183 | any non-permissive terms added in accord with section 7 apply to the code; keep 184 | intact all notices of the absence of any warranty; and give all recipients a copy of 185 | this License along with the Program. 186 | 187 | You may charge any price or no price for each copy that you convey, and you may offer 188 | support or warranty protection for a fee. 189 | 190 | ### 5. Conveying Modified Source Versions 191 | 192 | You may convey a work based on the Program, or the modifications to produce it from 193 | the Program, in the form of source code under the terms of section 4, provided that 194 | you also meet all of these conditions: 195 | 196 | * **a)** The work must carry prominent notices stating that you modified it, and giving a 197 | relevant date. 198 | * **b)** The work must carry prominent notices stating that it is released under this 199 | License and any conditions added under section 7. This requirement modifies the 200 | requirement in section 4 to “keep intact all notices”. 201 | * **c)** You must license the entire work, as a whole, under this License to anyone who 202 | comes into possession of a copy. This License will therefore apply, along with any 203 | applicable section 7 additional terms, to the whole of the work, and all its parts, 204 | regardless of how they are packaged. This License gives no permission to license the 205 | work in any other way, but it does not invalidate such permission if you have 206 | separately received it. 207 | * **d)** If the work has interactive user interfaces, each must display Appropriate Legal 208 | Notices; however, if the Program has interactive interfaces that do not display 209 | Appropriate Legal Notices, your work need not make them do so. 210 | 211 | A compilation of a covered work with other separate and independent works, which are 212 | not by their nature extensions of the covered work, and which are not combined with 213 | it such as to form a larger program, in or on a volume of a storage or distribution 214 | medium, is called an “aggregate” if the compilation and its resulting 215 | copyright are not used to limit the access or legal rights of the compilation's users 216 | beyond what the individual works permit. Inclusion of a covered work in an aggregate 217 | does not cause this License to apply to the other parts of the aggregate. 218 | 219 | ### 6. Conveying Non-Source Forms 220 | 221 | You may convey a covered work in object code form under the terms of sections 4 and 222 | 5, provided that you also convey the machine-readable Corresponding Source under the 223 | terms of this License, in one of these ways: 224 | 225 | * **a)** Convey the object code in, or embodied in, a physical product (including a 226 | physical distribution medium), accompanied by the Corresponding Source fixed on a 227 | durable physical medium customarily used for software interchange. 228 | * **b)** Convey the object code in, or embodied in, a physical product (including a 229 | physical distribution medium), accompanied by a written offer, valid for at least 230 | three years and valid for as long as you offer spare parts or customer support for 231 | that product model, to give anyone who possesses the object code either **(1)** a copy of 232 | the Corresponding Source for all the software in the product that is covered by this 233 | License, on a durable physical medium customarily used for software interchange, for 234 | a price no more than your reasonable cost of physically performing this conveying of 235 | source, or **(2)** access to copy the Corresponding Source from a network server at no 236 | charge. 237 | * **c)** Convey individual copies of the object code with a copy of the written offer to 238 | provide the Corresponding Source. This alternative is allowed only occasionally and 239 | noncommercially, and only if you received the object code with such an offer, in 240 | accord with subsection 6b. 241 | * **d)** Convey the object code by offering access from a designated place (gratis or for 242 | a charge), and offer equivalent access to the Corresponding Source in the same way 243 | through the same place at no further charge. You need not require recipients to copy 244 | the Corresponding Source along with the object code. If the place to copy the object 245 | code is a network server, the Corresponding Source may be on a different server 246 | (operated by you or a third party) that supports equivalent copying facilities, 247 | provided you maintain clear directions next to the object code saying where to find 248 | the Corresponding Source. Regardless of what server hosts the Corresponding Source, 249 | you remain obligated to ensure that it is available for as long as needed to satisfy 250 | these requirements. 251 | * **e)** Convey the object code using peer-to-peer transmission, provided you inform 252 | other peers where the object code and Corresponding Source of the work are being 253 | offered to the general public at no charge under subsection 6d. 254 | 255 | A separable portion of the object code, whose source code is excluded from the 256 | Corresponding Source as a System Library, need not be included in conveying the 257 | object code work. 258 | 259 | A “User Product” is either **(1)** a “consumer product”, which 260 | means any tangible personal property which is normally used for personal, family, or 261 | household purposes, or **(2)** anything designed or sold for incorporation into a 262 | dwelling. In determining whether a product is a consumer product, doubtful cases 263 | shall be resolved in favor of coverage. For a particular product received by a 264 | particular user, “normally used” refers to a typical or common use of 265 | that class of product, regardless of the status of the particular user or of the way 266 | in which the particular user actually uses, or expects or is expected to use, the 267 | product. A product is a consumer product regardless of whether the product has 268 | substantial commercial, industrial or non-consumer uses, unless such uses represent 269 | the only significant mode of use of the product. 270 | 271 | “Installation Information” for a User Product means any methods, 272 | procedures, authorization keys, or other information required to install and execute 273 | modified versions of a covered work in that User Product from a modified version of 274 | its Corresponding Source. The information must suffice to ensure that the continued 275 | functioning of the modified object code is in no case prevented or interfered with 276 | solely because modification has been made. 277 | 278 | If you convey an object code work under this section in, or with, or specifically for 279 | use in, a User Product, and the conveying occurs as part of a transaction in which 280 | the right of possession and use of the User Product is transferred to the recipient 281 | in perpetuity or for a fixed term (regardless of how the transaction is 282 | characterized), the Corresponding Source conveyed under this section must be 283 | accompanied by the Installation Information. But this requirement does not apply if 284 | neither you nor any third party retains the ability to install modified object code 285 | on the User Product (for example, the work has been installed in ROM). 286 | 287 | The requirement to provide Installation Information does not include a requirement to 288 | continue to provide support service, warranty, or updates for a work that has been 289 | modified or installed by the recipient, or for the User Product in which it has been 290 | modified or installed. Access to a network may be denied when the modification itself 291 | materially and adversely affects the operation of the network or violates the rules 292 | and protocols for communication across the network. 293 | 294 | Corresponding Source conveyed, and Installation Information provided, in accord with 295 | this section must be in a format that is publicly documented (and with an 296 | implementation available to the public in source code form), and must require no 297 | special password or key for unpacking, reading or copying. 298 | 299 | ### 7. Additional Terms 300 | 301 | “Additional permissions” are terms that supplement the terms of this 302 | License by making exceptions from one or more of its conditions. Additional 303 | permissions that are applicable to the entire Program shall be treated as though they 304 | were included in this License, to the extent that they are valid under applicable 305 | law. If additional permissions apply only to part of the Program, that part may be 306 | used separately under those permissions, but the entire Program remains governed by 307 | this License without regard to the additional permissions. 308 | 309 | When you convey a copy of a covered work, you may at your option remove any 310 | additional permissions from that copy, or from any part of it. (Additional 311 | permissions may be written to require their own removal in certain cases when you 312 | modify the work.) You may place additional permissions on material, added by you to a 313 | covered work, for which you have or can give appropriate copyright permission. 314 | 315 | Notwithstanding any other provision of this License, for material you add to a 316 | covered work, you may (if authorized by the copyright holders of that material) 317 | supplement the terms of this License with terms: 318 | 319 | * **a)** Disclaiming warranty or limiting liability differently from the terms of 320 | sections 15 and 16 of this License; or 321 | * **b)** Requiring preservation of specified reasonable legal notices or author 322 | attributions in that material or in the Appropriate Legal Notices displayed by works 323 | containing it; or 324 | * **c)** Prohibiting misrepresentation of the origin of that material, or requiring that 325 | modified versions of such material be marked in reasonable ways as different from the 326 | original version; or 327 | * **d)** Limiting the use for publicity purposes of names of licensors or authors of the 328 | material; or 329 | * **e)** Declining to grant rights under trademark law for use of some trade names, 330 | trademarks, or service marks; or 331 | * **f)** Requiring indemnification of licensors and authors of that material by anyone 332 | who conveys the material (or modified versions of it) with contractual assumptions of 333 | liability to the recipient, for any liability that these contractual assumptions 334 | directly impose on those licensors and authors. 335 | 336 | All other non-permissive additional terms are considered “further 337 | restrictions” within the meaning of section 10. If the Program as you received 338 | it, or any part of it, contains a notice stating that it is governed by this License 339 | along with a term that is a further restriction, you may remove that term. If a 340 | license document contains a further restriction but permits relicensing or conveying 341 | under this License, you may add to a covered work material governed by the terms of 342 | that license document, provided that the further restriction does not survive such 343 | relicensing or conveying. 344 | 345 | If you add terms to a covered work in accord with this section, you must place, in 346 | the relevant source files, a statement of the additional terms that apply to those 347 | files, or a notice indicating where to find the applicable terms. 348 | 349 | Additional terms, permissive or non-permissive, may be stated in the form of a 350 | separately written license, or stated as exceptions; the above requirements apply 351 | either way. 352 | 353 | ### 8. Termination 354 | 355 | You may not propagate or modify a covered work except as expressly provided under 356 | this License. Any attempt otherwise to propagate or modify it is void, and will 357 | automatically terminate your rights under this License (including any patent licenses 358 | granted under the third paragraph of section 11). 359 | 360 | However, if you cease all violation of this License, then your license from a 361 | particular copyright holder is reinstated **(a)** provisionally, unless and until the 362 | copyright holder explicitly and finally terminates your license, and **(b)** permanently, 363 | if the copyright holder fails to notify you of the violation by some reasonable means 364 | prior to 60 days after the cessation. 365 | 366 | Moreover, your license from a particular copyright holder is reinstated permanently 367 | if the copyright holder notifies you of the violation by some reasonable means, this 368 | is the first time you have received notice of violation of this License (for any 369 | work) from that copyright holder, and you cure the violation prior to 30 days after 370 | your receipt of the notice. 371 | 372 | Termination of your rights under this section does not terminate the licenses of 373 | parties who have received copies or rights from you under this License. If your 374 | rights have been terminated and not permanently reinstated, you do not qualify to 375 | receive new licenses for the same material under section 10. 376 | 377 | ### 9. Acceptance Not Required for Having Copies 378 | 379 | You are not required to accept this License in order to receive or run a copy of the 380 | Program. Ancillary propagation of a covered work occurring solely as a consequence of 381 | using peer-to-peer transmission to receive a copy likewise does not require 382 | acceptance. However, nothing other than this License grants you permission to 383 | propagate or modify any covered work. These actions infringe copyright if you do not 384 | accept this License. Therefore, by modifying or propagating a covered work, you 385 | indicate your acceptance of this License to do so. 386 | 387 | ### 10. Automatic Licensing of Downstream Recipients 388 | 389 | Each time you convey a covered work, the recipient automatically receives a license 390 | from the original licensors, to run, modify and propagate that work, subject to this 391 | License. You are not responsible for enforcing compliance by third parties with this 392 | License. 393 | 394 | An “entity transaction” is a transaction transferring control of an 395 | organization, or substantially all assets of one, or subdividing an organization, or 396 | merging organizations. If propagation of a covered work results from an entity 397 | transaction, each party to that transaction who receives a copy of the work also 398 | receives whatever licenses to the work the party's predecessor in interest had or 399 | could give under the previous paragraph, plus a right to possession of the 400 | Corresponding Source of the work from the predecessor in interest, if the predecessor 401 | has it or can get it with reasonable efforts. 402 | 403 | You may not impose any further restrictions on the exercise of the rights granted or 404 | affirmed under this License. For example, you may not impose a license fee, royalty, 405 | or other charge for exercise of rights granted under this License, and you may not 406 | initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging 407 | that any patent claim is infringed by making, using, selling, offering for sale, or 408 | importing the Program or any portion of it. 409 | 410 | ### 11. Patents 411 | 412 | A “contributor” is a copyright holder who authorizes use under this 413 | License of the Program or a work on which the Program is based. The work thus 414 | licensed is called the contributor's “contributor version”. 415 | 416 | A contributor's “essential patent claims” are all patent claims owned or 417 | controlled by the contributor, whether already acquired or hereafter acquired, that 418 | would be infringed by some manner, permitted by this License, of making, using, or 419 | selling its contributor version, but do not include claims that would be infringed 420 | only as a consequence of further modification of the contributor version. For 421 | purposes of this definition, “control” includes the right to grant patent 422 | sublicenses in a manner consistent with the requirements of this License. 423 | 424 | Each contributor grants you a non-exclusive, worldwide, royalty-free patent license 425 | under the contributor's essential patent claims, to make, use, sell, offer for sale, 426 | import and otherwise run, modify and propagate the contents of its contributor 427 | version. 428 | 429 | In the following three paragraphs, a “patent license” is any express 430 | agreement or commitment, however denominated, not to enforce a patent (such as an 431 | express permission to practice a patent or covenant not to sue for patent 432 | infringement). To “grant” such a patent license to a party means to make 433 | such an agreement or commitment not to enforce a patent against the party. 434 | 435 | If you convey a covered work, knowingly relying on a patent license, and the 436 | Corresponding Source of the work is not available for anyone to copy, free of charge 437 | and under the terms of this License, through a publicly available network server or 438 | other readily accessible means, then you must either **(1)** cause the Corresponding 439 | Source to be so available, or **(2)** arrange to deprive yourself of the benefit of the 440 | patent license for this particular work, or **(3)** arrange, in a manner consistent with 441 | the requirements of this License, to extend the patent license to downstream 442 | recipients. “Knowingly relying” means you have actual knowledge that, but 443 | for the patent license, your conveying the covered work in a country, or your 444 | recipient's use of the covered work in a country, would infringe one or more 445 | identifiable patents in that country that you have reason to believe are valid. 446 | 447 | If, pursuant to or in connection with a single transaction or arrangement, you 448 | convey, or propagate by procuring conveyance of, a covered work, and grant a patent 449 | license to some of the parties receiving the covered work authorizing them to use, 450 | propagate, modify or convey a specific copy of the covered work, then the patent 451 | license you grant is automatically extended to all recipients of the covered work and 452 | works based on it. 453 | 454 | A patent license is “discriminatory” if it does not include within the 455 | scope of its coverage, prohibits the exercise of, or is conditioned on the 456 | non-exercise of one or more of the rights that are specifically granted under this 457 | License. You may not convey a covered work if you are a party to an arrangement with 458 | a third party that is in the business of distributing software, under which you make 459 | payment to the third party based on the extent of your activity of conveying the 460 | work, and under which the third party grants, to any of the parties who would receive 461 | the covered work from you, a discriminatory patent license **(a)** in connection with 462 | copies of the covered work conveyed by you (or copies made from those copies), or **(b)** 463 | primarily for and in connection with specific products or compilations that contain 464 | the covered work, unless you entered into that arrangement, or that patent license 465 | was granted, prior to 28 March 2007. 466 | 467 | Nothing in this License shall be construed as excluding or limiting any implied 468 | license or other defenses to infringement that may otherwise be available to you 469 | under applicable patent law. 470 | 471 | ### 12. No Surrender of Others' Freedom 472 | 473 | If conditions are imposed on you (whether by court order, agreement or otherwise) 474 | that contradict the conditions of this License, they do not excuse you from the 475 | conditions of this License. If you cannot convey a covered work so as to satisfy 476 | simultaneously your obligations under this License and any other pertinent 477 | obligations, then as a consequence you may not convey it at all. For example, if you 478 | agree to terms that obligate you to collect a royalty for further conveying from 479 | those to whom you convey the Program, the only way you could satisfy both those terms 480 | and this License would be to refrain entirely from conveying the Program. 481 | 482 | ### 13. Use with the GNU Affero General Public License 483 | 484 | Notwithstanding any other provision of this License, you have permission to link or 485 | combine any covered work with a work licensed under version 3 of the GNU Affero 486 | General Public License into a single combined work, and to convey the resulting work. 487 | The terms of this License will continue to apply to the part which is the covered 488 | work, but the special requirements of the GNU Affero General Public License, section 489 | 13, concerning interaction through a network will apply to the combination as such. 490 | 491 | ### 14. Revised Versions of this License 492 | 493 | The Free Software Foundation may publish revised and/or new versions of the GNU 494 | General Public License from time to time. Such new versions will be similar in spirit 495 | to the present version, but may differ in detail to address new problems or concerns. 496 | 497 | Each version is given a distinguishing version number. If the Program specifies that 498 | a certain numbered version of the GNU General Public License “or any later 499 | version” applies to it, you have the option of following the terms and 500 | conditions either of that numbered version or of any later version published by the 501 | Free Software Foundation. If the Program does not specify a version number of the GNU 502 | General Public License, you may choose any version ever published by the Free 503 | Software Foundation. 504 | 505 | If the Program specifies that a proxy can decide which future versions of the GNU 506 | General Public License can be used, that proxy's public statement of acceptance of a 507 | version permanently authorizes you to choose that version for the Program. 508 | 509 | Later license versions may give you additional or different permissions. However, no 510 | additional obligations are imposed on any author or copyright holder as a result of 511 | your choosing to follow a later version. 512 | 513 | ### 15. Disclaimer of Warranty 514 | 515 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 516 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 517 | PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER 518 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 519 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE 520 | QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE 521 | DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 522 | 523 | ### 16. Limitation of Liability 524 | 525 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY 526 | COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS 527 | PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, 528 | INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 529 | PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE 530 | OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE 531 | WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 532 | POSSIBILITY OF SUCH DAMAGES. 533 | 534 | ### 17. Interpretation of Sections 15 and 16 535 | 536 | If the disclaimer of warranty and limitation of liability provided above cannot be 537 | given local legal effect according to their terms, reviewing courts shall apply local 538 | law that most closely approximates an absolute waiver of all civil liability in 539 | connection with the Program, unless a warranty or assumption of liability accompanies 540 | a copy of the Program in return for a fee. 541 | 542 | _END OF TERMS AND CONDITIONS_ 543 | 544 | ## How to Apply These Terms to Your New Programs 545 | 546 | If you develop a new program, and you want it to be of the greatest possible use to 547 | the public, the best way to achieve this is to make it free software which everyone 548 | can redistribute and change under these terms. 549 | 550 | To do so, attach the following notices to the program. It is safest to attach them 551 | to the start of each source file to most effectively state the exclusion of warranty; 552 | and each file should have at least the “copyright” line and a pointer to 553 | where the full notice is found. 554 | 555 | 556 | Copyright (C) 557 | 558 | This program is free software: you can redistribute it and/or modify 559 | it under the terms of the GNU General Public License as published by 560 | the Free Software Foundation, either version 3 of the License, or 561 | (at your option) any later version. 562 | 563 | This program is distributed in the hope that it will be useful, 564 | but WITHOUT ANY WARRANTY; without even the implied warranty of 565 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 566 | GNU General Public License for more details. 567 | 568 | You should have received a copy of the GNU General Public License 569 | along with this program. If not, see . 570 | 571 | Also add information on how to contact you by electronic and paper mail. 572 | 573 | If the program does terminal interaction, make it output a short notice like this 574 | when it starts in an interactive mode: 575 | 576 | Copyright (C) 577 | This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. 578 | This is free software, and you are welcome to redistribute it 579 | under certain conditions; type 'show c' for details. 580 | 581 | The hypothetical commands `show w` and `show c` should show the appropriate parts of 582 | the General Public License. Of course, your program's commands might be different; 583 | for a GUI interface, you would use an “about box”. 584 | 585 | You should also get your employer (if you work as a programmer) or school, if any, to 586 | sign a “copyright disclaimer” for the program, if necessary. For more 587 | information on this, and how to apply and follow the GNU GPL, see 588 | <>. 589 | 590 | The GNU General Public License does not permit incorporating your program into 591 | proprietary programs. If your program is a subroutine library, you may consider it 592 | more useful to permit linking proprietary applications with the library. If this is 593 | what you want to do, use the GNU Lesser General Public License instead of this 594 | License. But first, please read 595 | <>. 596 | --------------------------------------------------------------------------------