diff --git a/.rsync b/.rsync new file mode 100644 index 0000000..5181199 --- /dev/null +++ b/.rsync @@ -0,0 +1,5 @@ +../LICENSE LICENSE +../testdata/ testdata/ +../gherkin.berp gherkin.berp +../bin/ berp/ +../gherkin-languages.json gherkin-languages.json diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..79d0ac9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,37 @@ +dist: trusty +language: c +sudo: required +compiler: +- clang +- gcc +- i686-w64-mingw32-gcc +os: +- linux +- osx +before_install: +- if [[ "$CC" == "i686-w64-mingw32-gcc" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then sudo dpkg --add-architecture i386 ; fi +- if [[ "$CC" == "i686-w64-mingw32-gcc" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then sudo add-apt-repository -y ppa:ubuntu-wine/ppa ; fi +- if [[ "$CC" == "i686-w64-mingw32-gcc" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then sudo apt-get update -qq ; fi +- if [[ "$CC" == "i686-w64-mingw32-gcc" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then sudo apt-get remove -qq -y mingw32 ; fi +- if [[ "$CC" == "i686-w64-mingw32-gcc" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then sudo apt-get install -q -y mingw-w64 ; fi +- if [[ "$CC" == "i686-w64-mingw32-gcc" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then sudo apt-get install --no-install-recommends -y wine1.8 ; fi +- if [[ "$CC" == "i686-w64-mingw32-gcc" ]] && [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew install mingw-w64 ; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install jq ; + fi +script: if [[ "$CC" == "i686-w64-mingw32-gcc" ]] && [[ "$TRAVIS_OS_NAME" == "osx" + ]]; then make CC=${CC} cli; else make CC=${CC} ; fi +addons: + artifacts: true +env: + global: + - ARTIFACTS_PATHS="./bin:./libs" + - ARTIFACTS_BUCKET=cucumber-oss + - secure: aaC95l0Tq63040to71E2WGQHGyW+5qq9T0cujbgtx7UlVKq3XJ4IdPt+gT+GO9EddLkrrQ+09T27G56RO9hjfLWd3Xxf4+TCIhUQUEp5yD2ApLBP/BM4UeRgwjZKaxdtXsLcv8B8FNWAlZ0IyvA6TssZLge2gXIECm7yfJFJlQhjP0exmP5AN1YaC8IV8KwNT2rx8JZo5Q2nERKH0MCtuPCGdAIBCqZbrYwLj//FMl+YSTuzpAGiqXXosgSIsNJwIrKNJckEMoB7ZDWLCsCdzSZKNabpPd1yqwNxM/5zncfQ7V0oXx6mY2iusR64d8Icq5HAdGe9g2Pwpsme1Ptydiw19dwFaxs1PSJwFRiRhkMZIRZFHzyCpOZg9Zr1uftyPmV7RfKI0FUvmkuYGF0VxDXwP7B/nKWTSNqBvTlZ48O5b3rslNLqFf20WF1Qvll2IZ3Dmj8tcZYa1Rr9fivWnCKUZVfcADG98lcyVgpi9sojb4nvGLGB7Ux8tQt9Ka0jfp/7eaXAf8LLGDXYSj1VHKw94vgnM0ESsjTFBMLUtjymvUaQPGZeiIzcA8m6jo6Sjatg+GBZKADZo4R351BotUWzsLCyYfS0k+HJFpKKjPFKdFZob+6B5yJUk18Xcnj3vo+P0L6v2EpEE70qzQuAmCFTUXpVPAqoYtnxko10i4Y= + - secure: Cm9A5zBoy2rbgTeh+70ZGyWgnoeiLzQwKPrC9EksWUNuOzTEfAsV5+2c+owb6DKshoI6tGye3tl61q36A1nhJgZ/DyjDoIOa+hi+IAbBw4u0CbFjEEbdbGxyoe0PbcBaLgDFMnvA1wzITisfhdVNoOhQIO+DhsuhpVn/fj14hUdi1s4vujSwZLIPPWUe7FT0B4tIsV0+wBflGdLa55j3oEIB6CyMFaa2v5xTFdqteiWlfapojJGQ20VQz9TerJFFdIMyKiPb5shsO9zd1ioxZRpL7iJDUuWKzNq90iQX6++62veAdoJR4EX+arJbhfQl/oLCeExI3nlP00qx6jku/AIO6lsdW8kwmeEeiD1BjC1btwQaeJ6Vx+eex02ZO27CSyulzDB3KttrKcfwnxwgjDzi8oNy2WhnHN6nNH7S9+dbhzGo50dJeQhdQUHKqHPBnAvHJBhuYsy3xaOD0n2Ys3ixT1lAsjwwPBstC/4T8TgBJ1HcxINCYwjnUZNc5JKhZLTh37HZCl5ROuANeaJDSbKvjwIf7bXIBO5+5xsgWtRbbXz3KQ04hTSVCuDaPbG/TPyQIMafgGuTgEhcEoex7KZWMk8f1GecjlJcit7v2VidFahdbRPZxF+HRugw6rVHxhfhjZdgZRpBWi3O9YGoJrQx7C6DgkKK3xrATOK0lmQ= diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b669c46 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,133 @@ +PROJECT(gherkin C) +cmake_minimum_required(VERSION 3.0) +# Install library & headers in your directory +#SET(CMAKE_INSTALL_PREFIX "") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +LIST(APPEND GHERKIN_SRS + src/file_reader.c + src/file_utf8_source.c + src/print_utilities.c + src/string_utilities.c + src/unicode_utilities.c + src/utf8_source.c + src/parser.c + src/token_scanner.c + src/file_token_scanner.c + src/string_token_scanner.c + src/token_matcher.c + src/token.c + src/token_queue.c + src/item_queue.c + src/gherkin_line.c + src/error.c + src/error_list.c + src/dialect.c + src/ast_builder.c + src/ast_node.c + src/gherkin_document.c + src/feature.c + src/scenario.c + src/scenario_outline.c + src/background.c + src/comment.c + src/data_table.c + src/doc_string.c + src/example_table.c + src/step.c + src/table_cell.c + src/table_row.c + src/tag.c + src/compiler.c + src/pickle.c + src/pickle_cell.c + src/pickle_location.c + src/pickle_row.c + src/pickle_step.c + src/pickle_string.c + src/pickle_table.c + src/pickle_tag.c + src/event.c + src/attachment_event.c + src/gherkin_document_event.c + src/pickle_event.c + src/source_event.c + src/ast_printer.c + src/pickle_printer.c + ) + +LIST(APPEND GENERATE_TOKEN + src/token_formatter_builder.c + src/gherkin_generate_tokens.c + ) +LIST(APPEND GHERKIN_CLI + src/gherkin_cli.c + ) + + +add_library(gherkin SHARED ${GHERKIN_SRS}) +target_include_directories(gherkin PUBLIC + "$") + +add_executable(gherkinexe ${GHERKIN_CLI}) +target_link_libraries(gherkinexe gherkin) +target_include_directories(gherkinexe PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src) + +add_executable(gherkin_generate_tokens ${GENERATE_TOKEN}) +target_link_libraries(gherkin_generate_tokens gherkin) + +file(GLOB GOOD_FEATURE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/testdata/good/*.feature + ) +file(GLOB BAD_FEATURE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/testdata/bad/*.feature + ) +add_custom_target(invo DEPENDS invo) +add_dependencies(invo gherkinexe) +FOREACH(ENTITY ${GOOD_FEATURE_FILES}) + add_custom_command( + TARGET gherkinexe + POST_BUILD + COMMAND gherkinexe ${ENTITY} + DEPENDS invo + ) +ENDFOREACH() +############ Installation section ############ +set(include_install_dir "include") +set(lib_install_dir "lib/") +set(bin_install_dir "bin/") +set(config_install_dir "lib/cmake/") + +set(project_config "${CMAKE_CURRENT_BINARY_DIR}/generated/${PROJECT_NAME}Config.cmake") +set(targets_export_name "${PROJECT_NAME}Targets") + +set(namespace "${PROJECT_NAME}::") + +configure_file("${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in" "${project_config}" @ONLY) + +# Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable) +install( + TARGETS gherkin + EXPORT ${targets_export_name} + ARCHIVE DESTINATION ${lib_install_dir} + LIBRARY DESTINATION ${lib_install_dir} + RUNTIME DESTINATION ${lib_install_dir} + INCLUDES DESTINATION ${include_install_dir}) + +install( + DIRECTORY "${PROJECT_SOURCE_DIR}/include/" + DESTINATION ${include_install_dir} + FILES_MATCHING PATTERN "*.*h") + +install( + FILES "${project_config}" + DESTINATION "${config_install_dir}") + +install( + EXPORT "${targets_export_name}" + NAMESPACE "${namespace}" + DESTINATION "${config_install_dir}") + +add_custom_target(install_${PROJECT_NAME} + $(MAKE) install + DEPENDS gherkin + COMMENT "Installing ${PROJECT_NAME}") \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8d35a66 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# Building the `gin/gherkin` binary + +## Build with gcc: + + make cli + +## Build with clang + + make CC=clang cli + +## Build Windows binaries with mingw + +Install the toolchain (OS X) + + brew install mingw-w64 + # Run `brew info mingw-w64` to verify the path before next command + export PATH=/usr/local/Cellar/mingw-w64/5.0.1/bin:$PATH + # Install wine - for testing + brew cask install xquartz + brew install wine + +Build: + + make CC=i686-w64-mingw32-gcc cli + +## Build with other compilers + +Edit `src/Makefile` and set CC, CC_FLAGS, AR, AR_FLAGS, LD, LD_FLAGS appropriately, then run `make cli` diff --git a/Makefile b/Makefile index 39578e8..71ebb1f 100644 --- a/Makefile +++ b/Makefile @@ -1,94 +1,111 @@ SHELL := /usr/bin/env bash -GOOD_FEATURE_FILES = $(shell find ../testdata/good -name "*.feature") -BAD_FEATURE_FILES = $(shell find ../testdata/bad -name "*.feature") +GOOD_FEATURE_FILES = $(shell find testdata/good -name "*.feature") +BAD_FEATURE_FILES = $(shell find testdata/bad -name "*.feature") -TOKENS = $(patsubst ../testdata/%.feature,acceptance/testdata/%.feature.tokens,$(GOOD_FEATURE_FILES)) -ASTS = $(patsubst ../testdata/%.feature,acceptance/testdata/%.feature.ast.ndjson,$(GOOD_FEATURE_FILES)) -PICKLES = $(patsubst ../testdata/%.feature,acceptance/testdata/%.feature.pickles.ndjson,$(GOOD_FEATURE_FILES)) -SOURCES = $(patsubst ../testdata/%.feature,acceptance/testdata/%.feature.source.ndjson,$(GOOD_FEATURE_FILES)) -ERRORS = $(patsubst ../testdata/%.feature,acceptance/testdata/%.feature.errors.ndjson,$(BAD_FEATURE_FILES)) +TOKENS = $(patsubst testdata/%.feature,acceptance/testdata/%.feature.tokens,$(GOOD_FEATURE_FILES)) +ASTS = $(patsubst testdata/%.feature,acceptance/testdata/%.feature.ast.ndjson,$(GOOD_FEATURE_FILES)) +PICKLES = $(patsubst testdata/%.feature,acceptance/testdata/%.feature.pickles.ndjson,$(GOOD_FEATURE_FILES)) +SOURCES = $(patsubst testdata/%.feature,acceptance/testdata/%.feature.source.ndjson,$(GOOD_FEATURE_FILES)) +ERRORS = $(patsubst testdata/%.feature,acceptance/testdata/%.feature.errors.ndjson,$(BAD_FEATURE_FILES)) SRC_FILES= $(shell find src -name "*.[ch]*") -all: .compared -.PHONY: all +ifeq ($(CC),i686-w64-mingw32-gcc) + GHERKIN=bin/gherkin.exe + RUN_GHERKIN=wine $(GHERKIN) + GHERKIN_GENERATE_TOKENS=bin/gherkin_generate_tokens.exe + RUN_GHERKIN_GENERATE_TOKENS=wine $(GHERKIN_GENERATE_TOKENS) +else + GHERKIN=bin/gherkin + RUN_GHERKIN=$(GHERKIN) + GHERKIN_GENERATE_TOKENS=bin/gherkin_generate_tokens + RUN_GHERKIN_GENERATE_TOKENS=$(GHERKIN_GENERATE_TOKENS) +endif + +.DELETE_ON_ERROR: + +default: .compared +.PHONY: default .compared: .built $(TOKENS) $(ASTS) $(PICKLES) $(ERRORS) $(SOURCES) .run touch $@ .built: ./include/rule_type.h src/parser.c src/dialect.c $(SRC_FILES) src/Makefile LICENSE + $(CC) --version cd src; $(MAKE) touch $@ clean: - rm -rf .compared .built .run acceptance ./include/rule_type.h src/parser.c src/dialect.c + rm -rf .compared .built .run acceptance cd src; $(MAKE) $@ .PHONY: clean -cli: ./include/rule_type.h src/parser.c src/dialect.c $(SRC_FILES) src/Makefile - cd src; $(MAKE) $@ +clobber: clean + rm -rf ./include/rule_type.h src/parser.c src/dialect.c +.PHONY: clobber + +cli: ./include/rule_type.h src/parser.c src/dialect.c $(SRC_FILES) src/Makefile + cd src; $(MAKE) CC=$(CC) $@ .PHONY: libs -libs: ./include/rule_type.h src/parser.c src/dialect.c $(SRC_FILES) src/Makefile - cd src; $(MAKE) $@ +libs: ./include/rule_type.h src/parser.c src/dialect.c $(SRC_FILES) src/Makefile + cd src; $(MAKE) CC=$(CC) $@ .PHONY: libs -.run: bin/gherkin $(GOOD_FEATURE_FILES) - bin/gherkin --no-source --no-ast --no-pickles $(GOOD_FEATURE_FILES) - touch .run +libs_so: ./include/rule_type.h src/parser.c src/dialect.c $(SRC_FILES) src/Makefile + cd src; $(MAKE) CC=$(CC) $@ +.PHONY: libs_so -./include/rule_type.h: ../gherkin.berp gherkin-c-rule-type.razor ../bin/berp.exe - mono ../bin/berp.exe -g ../gherkin.berp -t gherkin-c-rule-type.razor -o $@ +.run: cli $(GHERKIN) $(GOOD_FEATURE_FILES) + $(RUN_GHERKIN) $(GOOD_FEATURE_FILES) | jq . > /dev/null + touch $@ + +./include/rule_type.h: gherkin.berp gherkin-c-rule-type.razor + # Some build environments (Travis) mess up timestamps + # so that all files have the same timestamp, causing make to think this + # file needs to be rebuilt when it's actually uptodate. Our travis build doesn't + # have mono, so we'll allow this line to fail. + -mono berp/berp.exe -g gherkin.berp -t gherkin-c-rule-type.razor -o $@ # Remove BOM - tail -c +4 $@ > $@.nobom + awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}{print}' < $@ > $@.nobom mv $@.nobom $@ -src/parser.c: ../gherkin.berp gherkin-c-parser.razor ../bin/berp.exe - mono ../bin/berp.exe -g ../gherkin.berp -t gherkin-c-parser.razor -o $@ +src/parser.c: gherkin.berp gherkin-c-parser.razor + # Some build environments (Travis) mess up timestamps + # so that all files have the same timestamp, causing make to think this + # file needs to be rebuilt when it's actually uptodate. Our travis build doesn't + # have mono, so we'll allow this line to fail. + -mono berp/berp.exe -g gherkin.berp -t gherkin-c-parser.razor -o $@ # Remove BOM - tail -c +4 $@ > $@.nobom + awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}{print}' < $@ > $@.nobom mv $@.nobom $@ -src/dialect.c: ../gherkin-languages.json dialect.c.jq - $(MAKE) update-gherkin-languages +src/dialect.c: gherkin-languages.json dialect.c.jq + cat $< | jq -f dialect.c.jq -r -c > $@ -acceptance/testdata/%.feature.tokens: ../testdata/%.feature ../testdata/%.feature.tokens bin/gherkin_generate_tokens +acceptance/testdata/%.feature.tokens: testdata/%.feature testdata/%.feature.tokens $(GHERKIN_GENERATE_TOKENS) mkdir -p `dirname $@` - bin/gherkin_generate_tokens $< > $@ - diff --unified $<.tokens $@ -.DELETE_ON_ERROR: acceptance/testdata/%.feature.tokens + echo $(RUN_GHERKIN_GENERATE_TOKENS) + $(RUN_GHERKIN_GENERATE_TOKENS) $< > $@ + diff --strip-trailing-cr --unified $<.tokens $@ -acceptance/testdata/%.feature.ast.ndjson: ../testdata/%.feature ../testdata/%.feature.ast.ndjson bin/gherkin +acceptance/testdata/%.feature.ast.ndjson: testdata/%.feature testdata/%.feature.ast.ndjson $(GHERKIN) mkdir -p `dirname $@` - bin/gherkin --no-source --no-pickles $< | jq --sort-keys --compact-output "." > $@ + $(RUN_GHERKIN) --no-source --no-pickles $< | jq --sort-keys --compact-output "." > $@ diff --unified <(jq "." $<.ast.ndjson) <(jq "." $@) -.DELETE_ON_ERROR: acceptance/testdata/%.feature.ast.ndjson -acceptance/testdata/%.feature.errors.ndjson: ../testdata/%.feature ../testdata/%.feature.errors.ndjson bin/gherkin +acceptance/testdata/%.feature.errors.ndjson: testdata/%.feature testdata/%.feature.errors.ndjson $(GHERKIN) mkdir -p `dirname $@` - bin/gherkin --no-source --no-pickles $< | jq --sort-keys --compact-output "." > $@ + $(RUN_GHERKIN) --no-source --no-pickles $< | jq --sort-keys --compact-output "." > $@ diff --unified <(jq "." $<.errors.ndjson) <(jq "." $@) -.DELETE_ON_ERROR: acceptance/testdata/%.feature.errors.ndjson -acceptance/testdata/%.feature.pickles.ndjson: ../testdata/%.feature ../testdata/%.feature.pickles.ndjson bin/gherkin +acceptance/testdata/%.feature.pickles.ndjson: testdata/%.feature testdata/%.feature.pickles.ndjson $(GHERKIN) mkdir -p `dirname $@` - bin/gherkin --no-source --no-ast $< | jq --sort-keys --compact-output "." > $@ + $(RUN_GHERKIN) --no-source --no-ast $< | jq --sort-keys --compact-output "." > $@ diff --unified <(jq "." $<.pickles.ndjson) <(jq "." $@) -.DELETE_ON_ERROR: acceptance/testdata/%.feature.pickles.ndjson -acceptance/testdata/%.feature.source.ndjson: ../testdata/%.feature ../testdata/%.feature.source.ndjson .built +acceptance/testdata/%.feature.source.ndjson: testdata/%.feature testdata/%.feature.source.ndjson .built mkdir -p `dirname $@` - bin/gherkin --no-ast --no-pickles $< | jq --sort-keys --compact-output "." > $@ + $(RUN_GHERKIN) --no-ast --no-pickles $< | jq --sort-keys --compact-output "." > $@ diff --unified <(jq "." $<.source.ndjson) <(jq "." $@) -.DELETE_ON_ERROR: acceptance/testdata/%.feature.source.ndjson - -update-gherkin-languages: src/dialect.c.tmp - diff -q src/dialect.c.tmp src/dialect.c || mv src/dialect.c.tmp src/dialect.c -.PHONY: update-gherkin-languages - -src/dialect.c.tmp: ../gherkin-languages.json dialect.c.jq - cat $< | jq -f dialect.c.jq -r -c > $@ -.INTERMEDIATE: src/dialect.c.tmp -LICENSE: ../LICENSE - cp $< $@ diff --git a/README.md b/README.md index 18ffda3..7e96009 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,25 @@ -# Gherkin parser/compiler for C. +[![Build Status](https://travis-ci.org/cucumber/gherkin-c.svg?branch=master)](https://travis-ci.org/cucumber/gherkin-c) -See also [Gherkin](https://github.com/cucumber/gherkin). +

Build instruction:

-## Parsing and generating Gherkin events +``` +mkdir build +cd build +cmake .. +cmake --build . --target install +``` -`bin/gherkin | ` +![](https://raw.githubusercontent.com/Pwera/gherkin-c/master/gherkin.gif) -## Building the `gin/gherkin` binary +You can use this library in your project like this
+``` +cmake_minimum_required(VERSION 3.0) +project(gherkincsample) +list(APPEND CMAKE_PREFIX_PATH "INSTALLATION_DIRECTORY") +set(CMAKE_CXX_STANDARD 11) +find_package(gherkin REQUIRED) +add_executable(gherkincsample main.cpp) +target_link_libraries(gherkincsample gherkin::gherkin) +``` -Build with gcc: -`make cli` - -Build with clang: -`make CC=clang cli` - -Build with other compilers: -Edit `src/Makefile` and set CC, CC_FLAGS, AR, AR_FLAGS, LD, LD_FLAGS appropriately, then run `make cli` +[The docs are here](https://docs.cucumber.io/). \ No newline at end of file diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..32f3eaa --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +5.0.1 \ No newline at end of file diff --git a/berp/CommandLine.dll b/berp/CommandLine.dll new file mode 100755 index 0000000..d5497ef Binary files /dev/null and b/berp/CommandLine.dll differ diff --git a/berp/RazorEngine.dll b/berp/RazorEngine.dll new file mode 100755 index 0000000..ae6f70e Binary files /dev/null and b/berp/RazorEngine.dll differ diff --git a/berp/RazorEngine.pdb b/berp/RazorEngine.pdb new file mode 100755 index 0000000..ec9e248 Binary files /dev/null and b/berp/RazorEngine.pdb differ diff --git a/berp/System.Web.Razor.dll b/berp/System.Web.Razor.dll new file mode 100755 index 0000000..8a6fca7 Binary files /dev/null and b/berp/System.Web.Razor.dll differ diff --git a/berp/berp.exe b/berp/berp.exe new file mode 100755 index 0000000..84e7bbb Binary files /dev/null and b/berp/berp.exe differ diff --git a/berp/berp.pdb b/berp/berp.pdb new file mode 100755 index 0000000..fa33298 Binary files /dev/null and b/berp/berp.pdb differ diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in new file mode 100644 index 0000000..6e9256e --- /dev/null +++ b/cmake/Config.cmake.in @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake") diff --git a/gherkin-c-parser.razor b/gherkin-c-parser.razor index e1fd114..a683595 100644 --- a/gherkin-c-parser.razor +++ b/gherkin-c-parser.razor @@ -32,7 +32,6 @@ #include "token_scanner.h" #include "token_matcher.h" #include "token_queue.h" -#include "builder.h" #include "error_list.h" #include #include @@ -46,11 +45,11 @@ typedef struct ParserContext { ErrorList* errors; } ParserContext; -typedef struct @Model.ParserClassName { +struct @Model.ParserClassName { ParserContext* parser_context; Builder* builder; ErrorList* errors; -} @Model.ParserClassName; +}; static Token* read_token(ParserContext* context); diff --git a/gherkin-languages.json b/gherkin-languages.json new file mode 100644 index 0000000..9e74ed1 --- /dev/null +++ b/gherkin-languages.json @@ -0,0 +1,3239 @@ +{ + "af": { + "and": [ + "* ", + "En " + ], + "background": [ + "Agtergrond" + ], + "but": [ + "* ", + "Maar " + ], + "examples": [ + "Voorbeelde" + ], + "feature": [ + "Funksie", + "Besigheid Behoefte", + "Vermoë" + ], + "given": [ + "* ", + "Gegewe " + ], + "name": "Afrikaans", + "native": "Afrikaans", + "scenario": [ + "Situasie" + ], + "scenarioOutline": [ + "Situasie Uiteensetting" + ], + "then": [ + "* ", + "Dan " + ], + "when": [ + "* ", + "Wanneer " + ] + }, + "am": { + "and": [ + "* ", + "Եվ " + ], + "background": [ + "Կոնտեքստ" + ], + "but": [ + "* ", + "Բայց " + ], + "examples": [ + "Օրինակներ" + ], + "feature": [ + "Ֆունկցիոնալություն", + "Հատկություն" + ], + "given": [ + "* ", + "Դիցուք " + ], + "name": "Armenian", + "native": "հայերեն", + "scenario": [ + "Սցենար" + ], + "scenarioOutline": [ + "Սցենարի կառուցվացքը" + ], + "then": [ + "* ", + "Ապա " + ], + "when": [ + "* ", + "Եթե ", + "Երբ " + ] + }, + "an": { + "and": [ + "* ", + "Y ", + "E " + ], + "background": [ + "Antecedents" + ], + "but": [ + "* ", + "Pero " + ], + "examples": [ + "Eixemplos" + ], + "feature": [ + "Caracteristica" + ], + "given": [ + "* ", + "Dau ", + "Dada ", + "Daus ", + "Dadas " + ], + "name": "Aragonese", + "native": "Aragonés", + "scenario": [ + "Caso" + ], + "scenarioOutline": [ + "Esquema del caso" + ], + "then": [ + "* ", + "Alavez ", + "Allora ", + "Antonces " + ], + "when": [ + "* ", + "Cuan " + ] + }, + "ar": { + "and": [ + "* ", + "و " + ], + "background": [ + "الخلفية" + ], + "but": [ + "* ", + "لكن " + ], + "examples": [ + "امثلة" + ], + "feature": [ + "خاصية" + ], + "given": [ + "* ", + "بفرض " + ], + "name": "Arabic", + "native": "العربية", + "scenario": [ + "سيناريو" + ], + "scenarioOutline": [ + "سيناريو مخطط" + ], + "then": [ + "* ", + "اذاً ", + "ثم " + ], + "when": [ + "* ", + "متى ", + "عندما " + ] + }, + "ast": { + "and": [ + "* ", + "Y ", + "Ya " + ], + "background": [ + "Antecedentes" + ], + "but": [ + "* ", + "Peru " + ], + "examples": [ + "Exemplos" + ], + "feature": [ + "Carauterística" + ], + "given": [ + "* ", + "Dáu ", + "Dada ", + "Daos ", + "Daes " + ], + "name": "Asturian", + "native": "asturianu", + "scenario": [ + "Casu" + ], + "scenarioOutline": [ + "Esbozu del casu" + ], + "then": [ + "* ", + "Entós " + ], + "when": [ + "* ", + "Cuando " + ] + }, + "az": { + "and": [ + "* ", + "Və ", + "Həm " + ], + "background": [ + "Keçmiş", + "Kontekst" + ], + "but": [ + "* ", + "Amma ", + "Ancaq " + ], + "examples": [ + "Nümunələr" + ], + "feature": [ + "Özəllik" + ], + "given": [ + "* ", + "Tutaq ki ", + "Verilir " + ], + "name": "Azerbaijani", + "native": "Azərbaycanca", + "scenario": [ + "Ssenari" + ], + "scenarioOutline": [ + "Ssenarinin strukturu" + ], + "then": [ + "* ", + "O halda " + ], + "when": [ + "* ", + "Əgər ", + "Nə vaxt ki " + ] + }, + "bg": { + "and": [ + "* ", + "И " + ], + "background": [ + "Предистория" + ], + "but": [ + "* ", + "Но " + ], + "examples": [ + "Примери" + ], + "feature": [ + "Функционалност" + ], + "given": [ + "* ", + "Дадено " + ], + "name": "Bulgarian", + "native": "български", + "scenario": [ + "Сценарий" + ], + "scenarioOutline": [ + "Рамка на сценарий" + ], + "then": [ + "* ", + "То " + ], + "when": [ + "* ", + "Когато " + ] + }, + "bm": { + "and": [ + "* ", + "Dan " + ], + "background": [ + "Latar Belakang" + ], + "but": [ + "* ", + "Tetapi ", + "Tapi " + ], + "examples": [ + "Contoh" + ], + "feature": [ + "Fungsi" + ], + "given": [ + "* ", + "Diberi ", + "Bagi " + ], + "name": "Malay", + "native": "Bahasa Melayu", + "scenario": [ + "Senario", + "Situasi", + "Keadaan" + ], + "scenarioOutline": [ + "Kerangka Senario", + "Kerangka Situasi", + "Kerangka Keadaan", + "Garis Panduan Senario" + ], + "then": [ + "* ", + "Maka ", + "Kemudian " + ], + "when": [ + "* ", + "Apabila " + ] + }, + "bs": { + "and": [ + "* ", + "I ", + "A " + ], + "background": [ + "Pozadina" + ], + "but": [ + "* ", + "Ali " + ], + "examples": [ + "Primjeri" + ], + "feature": [ + "Karakteristika" + ], + "given": [ + "* ", + "Dato " + ], + "name": "Bosnian", + "native": "Bosanski", + "scenario": [ + "Scenariju", + "Scenario" + ], + "scenarioOutline": [ + "Scenariju-obris", + "Scenario-outline" + ], + "then": [ + "* ", + "Zatim " + ], + "when": [ + "* ", + "Kada " + ] + }, + "ca": { + "and": [ + "* ", + "I " + ], + "background": [ + "Rerefons", + "Antecedents" + ], + "but": [ + "* ", + "Però " + ], + "examples": [ + "Exemples" + ], + "feature": [ + "Característica", + "Funcionalitat" + ], + "given": [ + "* ", + "Donat ", + "Donada ", + "Atès ", + "Atesa " + ], + "name": "Catalan", + "native": "català", + "scenario": [ + "Escenari" + ], + "scenarioOutline": [ + "Esquema de l'escenari" + ], + "then": [ + "* ", + "Aleshores ", + "Cal " + ], + "when": [ + "* ", + "Quan " + ] + }, + "cs": { + "and": [ + "* ", + "A také ", + "A " + ], + "background": [ + "Pozadí", + "Kontext" + ], + "but": [ + "* ", + "Ale " + ], + "examples": [ + "Příklady" + ], + "feature": [ + "Požadavek" + ], + "given": [ + "* ", + "Pokud ", + "Za předpokladu " + ], + "name": "Czech", + "native": "Česky", + "scenario": [ + "Scénář" + ], + "scenarioOutline": [ + "Náčrt Scénáře", + "Osnova scénáře" + ], + "then": [ + "* ", + "Pak " + ], + "when": [ + "* ", + "Když " + ] + }, + "cy-GB": { + "and": [ + "* ", + "A " + ], + "background": [ + "Cefndir" + ], + "but": [ + "* ", + "Ond " + ], + "examples": [ + "Enghreifftiau" + ], + "feature": [ + "Arwedd" + ], + "given": [ + "* ", + "Anrhegedig a " + ], + "name": "Welsh", + "native": "Cymraeg", + "scenario": [ + "Scenario" + ], + "scenarioOutline": [ + "Scenario Amlinellol" + ], + "then": [ + "* ", + "Yna " + ], + "when": [ + "* ", + "Pryd " + ] + }, + "da": { + "and": [ + "* ", + "Og " + ], + "background": [ + "Baggrund" + ], + "but": [ + "* ", + "Men " + ], + "examples": [ + "Eksempler" + ], + "feature": [ + "Egenskab" + ], + "given": [ + "* ", + "Givet " + ], + "name": "Danish", + "native": "dansk", + "scenario": [ + "Scenarie" + ], + "scenarioOutline": [ + "Abstrakt Scenario" + ], + "then": [ + "* ", + "Så " + ], + "when": [ + "* ", + "Når " + ] + }, + "de": { + "and": [ + "* ", + "Und " + ], + "background": [ + "Grundlage" + ], + "but": [ + "* ", + "Aber " + ], + "examples": [ + "Beispiele" + ], + "feature": [ + "Funktionalität" + ], + "given": [ + "* ", + "Angenommen ", + "Gegeben sei ", + "Gegeben seien " + ], + "name": "German", + "native": "Deutsch", + "scenario": [ + "Szenario" + ], + "scenarioOutline": [ + "Szenariogrundriss" + ], + "then": [ + "* ", + "Dann " + ], + "when": [ + "* ", + "Wenn " + ] + }, + "el": { + "and": [ + "* ", + "Και " + ], + "background": [ + "Υπόβαθρο" + ], + "but": [ + "* ", + "Αλλά " + ], + "examples": [ + "Παραδείγματα", + "Σενάρια" + ], + "feature": [ + "Δυνατότητα", + "Λειτουργία" + ], + "given": [ + "* ", + "Δεδομένου " + ], + "name": "Greek", + "native": "Ελληνικά", + "scenario": [ + "Σενάριο" + ], + "scenarioOutline": [ + "Περιγραφή Σεναρίου", + "Περίγραμμα Σεναρίου" + ], + "then": [ + "* ", + "Τότε " + ], + "when": [ + "* ", + "Όταν " + ] + }, + "em": { + "and": [ + "* ", + "😂" + ], + "background": [ + "💤" + ], + "but": [ + "* ", + "😔" + ], + "examples": [ + "📓" + ], + "feature": [ + "📚" + ], + "given": [ + "* ", + "😐" + ], + "name": "Emoji", + "native": "😀", + "scenario": [ + "📕" + ], + "scenarioOutline": [ + "📖" + ], + "then": [ + "* ", + "🙏" + ], + "when": [ + "* ", + "🎬" + ] + }, + "en": { + "and": [ + "* ", + "And " + ], + "background": [ + "Background" + ], + "but": [ + "* ", + "But " + ], + "examples": [ + "Examples", + "Scenarios" + ], + "feature": [ + "Feature", + "Business Need", + "Ability" + ], + "given": [ + "* ", + "Given " + ], + "name": "English", + "native": "English", + "scenario": [ + "Scenario" + ], + "scenarioOutline": [ + "Scenario Outline", + "Scenario Template" + ], + "then": [ + "* ", + "Then " + ], + "when": [ + "* ", + "When " + ] + }, + "en-Scouse": { + "and": [ + "* ", + "An " + ], + "background": [ + "Dis is what went down" + ], + "but": [ + "* ", + "Buh " + ], + "examples": [ + "Examples" + ], + "feature": [ + "Feature" + ], + "given": [ + "* ", + "Givun ", + "Youse know when youse got " + ], + "name": "Scouse", + "native": "Scouse", + "scenario": [ + "The thing of it is" + ], + "scenarioOutline": [ + "Wharrimean is" + ], + "then": [ + "* ", + "Dun ", + "Den youse gotta " + ], + "when": [ + "* ", + "Wun ", + "Youse know like when " + ] + }, + "en-au": { + "and": [ + "* ", + "Too right " + ], + "background": [ + "First off" + ], + "but": [ + "* ", + "Yeah nah " + ], + "examples": [ + "You'll wanna" + ], + "feature": [ + "Pretty much" + ], + "given": [ + "* ", + "Y'know " + ], + "name": "Australian", + "native": "Australian", + "scenario": [ + "Awww, look mate" + ], + "scenarioOutline": [ + "Reckon it's like" + ], + "then": [ + "* ", + "But at the end of the day I reckon " + ], + "when": [ + "* ", + "It's just unbelievable " + ] + }, + "en-lol": { + "and": [ + "* ", + "AN " + ], + "background": [ + "B4" + ], + "but": [ + "* ", + "BUT " + ], + "examples": [ + "EXAMPLZ" + ], + "feature": [ + "OH HAI" + ], + "given": [ + "* ", + "I CAN HAZ " + ], + "name": "LOLCAT", + "native": "LOLCAT", + "scenario": [ + "MISHUN" + ], + "scenarioOutline": [ + "MISHUN SRSLY" + ], + "then": [ + "* ", + "DEN " + ], + "when": [ + "* ", + "WEN " + ] + }, + "en-old": { + "and": [ + "* ", + "Ond ", + "7 " + ], + "background": [ + "Aer", + "Ær" + ], + "but": [ + "* ", + "Ac " + ], + "examples": [ + "Se the", + "Se þe", + "Se ðe" + ], + "feature": [ + "Hwaet", + "Hwæt" + ], + "given": [ + "* ", + "Thurh ", + "Þurh ", + "Ðurh " + ], + "name": "Old English", + "native": "Englisc", + "scenario": [ + "Swa" + ], + "scenarioOutline": [ + "Swa hwaer swa", + "Swa hwær swa" + ], + "then": [ + "* ", + "Tha ", + "Þa ", + "Ða ", + "Tha the ", + "Þa þe ", + "Ða ðe " + ], + "when": [ + "* ", + "Tha ", + "Þa ", + "Ða " + ] + }, + "en-pirate": { + "and": [ + "* ", + "Aye " + ], + "background": [ + "Yo-ho-ho" + ], + "but": [ + "* ", + "Avast! " + ], + "examples": [ + "Dead men tell no tales" + ], + "feature": [ + "Ahoy matey!" + ], + "given": [ + "* ", + "Gangway! " + ], + "name": "Pirate", + "native": "Pirate", + "scenario": [ + "Heave to" + ], + "scenarioOutline": [ + "Shiver me timbers" + ], + "then": [ + "* ", + "Let go and haul " + ], + "when": [ + "* ", + "Blimey! " + ] + }, + "eo": { + "and": [ + "* ", + "Kaj " + ], + "background": [ + "Fono" + ], + "but": [ + "* ", + "Sed " + ], + "examples": [ + "Ekzemploj" + ], + "feature": [ + "Trajto" + ], + "given": [ + "* ", + "Donitaĵo ", + "Komence " + ], + "name": "Esperanto", + "native": "Esperanto", + "scenario": [ + "Scenaro", + "Kazo" + ], + "scenarioOutline": [ + "Konturo de la scenaro", + "Skizo", + "Kazo-skizo" + ], + "then": [ + "* ", + "Do " + ], + "when": [ + "* ", + "Se " + ] + }, + "es": { + "and": [ + "* ", + "Y ", + "E " + ], + "background": [ + "Antecedentes" + ], + "but": [ + "* ", + "Pero " + ], + "examples": [ + "Ejemplos" + ], + "feature": [ + "Característica" + ], + "given": [ + "* ", + "Dado ", + "Dada ", + "Dados ", + "Dadas " + ], + "name": "Spanish", + "native": "español", + "scenario": [ + "Escenario" + ], + "scenarioOutline": [ + "Esquema del escenario" + ], + "then": [ + "* ", + "Entonces " + ], + "when": [ + "* ", + "Cuando " + ] + }, + "et": { + "and": [ + "* ", + "Ja " + ], + "background": [ + "Taust" + ], + "but": [ + "* ", + "Kuid " + ], + "examples": [ + "Juhtumid" + ], + "feature": [ + "Omadus" + ], + "given": [ + "* ", + "Eeldades " + ], + "name": "Estonian", + "native": "eesti keel", + "scenario": [ + "Stsenaarium" + ], + "scenarioOutline": [ + "Raamstsenaarium" + ], + "then": [ + "* ", + "Siis " + ], + "when": [ + "* ", + "Kui " + ] + }, + "fa": { + "and": [ + "* ", + "و " + ], + "background": [ + "زمینه" + ], + "but": [ + "* ", + "اما " + ], + "examples": [ + "نمونه ها" + ], + "feature": [ + "وِیژگی" + ], + "given": [ + "* ", + "با فرض " + ], + "name": "Persian", + "native": "فارسی", + "scenario": [ + "سناریو" + ], + "scenarioOutline": [ + "الگوی سناریو" + ], + "then": [ + "* ", + "آنگاه " + ], + "when": [ + "* ", + "هنگامی " + ] + }, + "fi": { + "and": [ + "* ", + "Ja " + ], + "background": [ + "Tausta" + ], + "but": [ + "* ", + "Mutta " + ], + "examples": [ + "Tapaukset" + ], + "feature": [ + "Ominaisuus" + ], + "given": [ + "* ", + "Oletetaan " + ], + "name": "Finnish", + "native": "suomi", + "scenario": [ + "Tapaus" + ], + "scenarioOutline": [ + "Tapausaihio" + ], + "then": [ + "* ", + "Niin " + ], + "when": [ + "* ", + "Kun " + ] + }, + "fr": { + "and": [ + "* ", + "Et que ", + "Et qu'", + "Et " + ], + "background": [ + "Contexte" + ], + "but": [ + "* ", + "Mais que ", + "Mais qu'", + "Mais " + ], + "examples": [ + "Exemples" + ], + "feature": [ + "Fonctionnalité" + ], + "given": [ + "* ", + "Soit ", + "Etant donné que ", + "Etant donné qu'", + "Etant donné ", + "Etant donnée ", + "Etant donnés ", + "Etant données ", + "Étant donné que ", + "Étant donné qu'", + "Étant donné ", + "Étant donnée ", + "Étant donnés ", + "Étant données " + ], + "name": "French", + "native": "français", + "scenario": [ + "Scénario" + ], + "scenarioOutline": [ + "Plan du scénario", + "Plan du Scénario" + ], + "then": [ + "* ", + "Alors " + ], + "when": [ + "* ", + "Quand ", + "Lorsque ", + "Lorsqu'" + ] + }, + "ga": { + "and": [ + "* ", + "Agus" + ], + "background": [ + "Cúlra" + ], + "but": [ + "* ", + "Ach" + ], + "examples": [ + "Samplaí" + ], + "feature": [ + "Gné" + ], + "given": [ + "* ", + "Cuir i gcás go", + "Cuir i gcás nach", + "Cuir i gcás gur", + "Cuir i gcás nár" + ], + "name": "Irish", + "native": "Gaeilge", + "scenario": [ + "Cás" + ], + "scenarioOutline": [ + "Cás Achomair" + ], + "then": [ + "* ", + "Ansin" + ], + "when": [ + "* ", + "Nuair a", + "Nuair nach", + "Nuair ba", + "Nuair nár" + ] + }, + "gj": { + "and": [ + "* ", + "અને " + ], + "background": [ + "બેકગ્રાઉન્ડ" + ], + "but": [ + "* ", + "પણ " + ], + "examples": [ + "ઉદાહરણો" + ], + "feature": [ + "લક્ષણ", + "વ્યાપાર જરૂર", + "ક્ષમતા" + ], + "given": [ + "* ", + "આપેલ છે " + ], + "name": "Gujarati", + "native": "ગુજરાતી", + "scenario": [ + "સ્થિતિ" + ], + "scenarioOutline": [ + "પરિદ્દશ્ય રૂપરેખા", + "પરિદ્દશ્ય ઢાંચો" + ], + "then": [ + "* ", + "પછી " + ], + "when": [ + "* ", + "ક્યારે " + ] + }, + "gl": { + "and": [ + "* ", + "E " + ], + "background": [ + "Contexto" + ], + "but": [ + "* ", + "Mais ", + "Pero " + ], + "examples": [ + "Exemplos" + ], + "feature": [ + "Característica" + ], + "given": [ + "* ", + "Dado ", + "Dada ", + "Dados ", + "Dadas " + ], + "name": "Galician", + "native": "galego", + "scenario": [ + "Escenario" + ], + "scenarioOutline": [ + "Esbozo do escenario" + ], + "then": [ + "* ", + "Entón ", + "Logo " + ], + "when": [ + "* ", + "Cando " + ] + }, + "he": { + "and": [ + "* ", + "וגם " + ], + "background": [ + "רקע" + ], + "but": [ + "* ", + "אבל " + ], + "examples": [ + "דוגמאות" + ], + "feature": [ + "תכונה" + ], + "given": [ + "* ", + "בהינתן " + ], + "name": "Hebrew", + "native": "עברית", + "scenario": [ + "תרחיש" + ], + "scenarioOutline": [ + "תבנית תרחיש" + ], + "then": [ + "* ", + "אז ", + "אזי " + ], + "when": [ + "* ", + "כאשר " + ] + }, + "hi": { + "and": [ + "* ", + "और ", + "तथा " + ], + "background": [ + "पृष्ठभूमि" + ], + "but": [ + "* ", + "पर ", + "परन्तु ", + "किन्तु " + ], + "examples": [ + "उदाहरण" + ], + "feature": [ + "रूप लेख" + ], + "given": [ + "* ", + "अगर ", + "यदि ", + "चूंकि " + ], + "name": "Hindi", + "native": "हिंदी", + "scenario": [ + "परिदृश्य" + ], + "scenarioOutline": [ + "परिदृश्य रूपरेखा" + ], + "then": [ + "* ", + "तब ", + "तदा " + ], + "when": [ + "* ", + "जब ", + "कदा " + ] + }, + "hr": { + "and": [ + "* ", + "I " + ], + "background": [ + "Pozadina" + ], + "but": [ + "* ", + "Ali " + ], + "examples": [ + "Primjeri", + "Scenariji" + ], + "feature": [ + "Osobina", + "Mogućnost", + "Mogucnost" + ], + "given": [ + "* ", + "Zadan ", + "Zadani ", + "Zadano " + ], + "name": "Croatian", + "native": "hrvatski", + "scenario": [ + "Scenarij" + ], + "scenarioOutline": [ + "Skica", + "Koncept" + ], + "then": [ + "* ", + "Onda " + ], + "when": [ + "* ", + "Kada ", + "Kad " + ] + }, + "ht": { + "and": [ + "* ", + "Ak ", + "Epi ", + "E " + ], + "background": [ + "Kontèks", + "Istorik" + ], + "but": [ + "* ", + "Men " + ], + "examples": [ + "Egzanp" + ], + "feature": [ + "Karakteristik", + "Mak", + "Fonksyonalite" + ], + "given": [ + "* ", + "Sipoze ", + "Sipoze ke ", + "Sipoze Ke " + ], + "name": "Creole", + "native": "kreyòl", + "scenario": [ + "Senaryo" + ], + "scenarioOutline": [ + "Plan senaryo", + "Plan Senaryo", + "Senaryo deskripsyon", + "Senaryo Deskripsyon", + "Dyagram senaryo", + "Dyagram Senaryo" + ], + "then": [ + "* ", + "Lè sa a ", + "Le sa a " + ], + "when": [ + "* ", + "Lè ", + "Le " + ] + }, + "hu": { + "and": [ + "* ", + "És " + ], + "background": [ + "Háttér" + ], + "but": [ + "* ", + "De " + ], + "examples": [ + "Példák" + ], + "feature": [ + "Jellemző" + ], + "given": [ + "* ", + "Amennyiben ", + "Adott " + ], + "name": "Hungarian", + "native": "magyar", + "scenario": [ + "Forgatókönyv" + ], + "scenarioOutline": [ + "Forgatókönyv vázlat" + ], + "then": [ + "* ", + "Akkor " + ], + "when": [ + "* ", + "Majd ", + "Ha ", + "Amikor " + ] + }, + "id": { + "and": [ + "* ", + "Dan " + ], + "background": [ + "Dasar" + ], + "but": [ + "* ", + "Tapi " + ], + "examples": [ + "Contoh" + ], + "feature": [ + "Fitur" + ], + "given": [ + "* ", + "Dengan " + ], + "name": "Indonesian", + "native": "Bahasa Indonesia", + "scenario": [ + "Skenario" + ], + "scenarioOutline": [ + "Skenario konsep" + ], + "then": [ + "* ", + "Maka " + ], + "when": [ + "* ", + "Ketika " + ] + }, + "is": { + "and": [ + "* ", + "Og " + ], + "background": [ + "Bakgrunnur" + ], + "but": [ + "* ", + "En " + ], + "examples": [ + "Dæmi", + "Atburðarásir" + ], + "feature": [ + "Eiginleiki" + ], + "given": [ + "* ", + "Ef " + ], + "name": "Icelandic", + "native": "Íslenska", + "scenario": [ + "Atburðarás" + ], + "scenarioOutline": [ + "Lýsing Atburðarásar", + "Lýsing Dæma" + ], + "then": [ + "* ", + "Þá " + ], + "when": [ + "* ", + "Þegar " + ] + }, + "it": { + "and": [ + "* ", + "E " + ], + "background": [ + "Contesto" + ], + "but": [ + "* ", + "Ma " + ], + "examples": [ + "Esempi" + ], + "feature": [ + "Funzionalità" + ], + "given": [ + "* ", + "Dato ", + "Data ", + "Dati ", + "Date " + ], + "name": "Italian", + "native": "italiano", + "scenario": [ + "Scenario" + ], + "scenarioOutline": [ + "Schema dello scenario" + ], + "then": [ + "* ", + "Allora " + ], + "when": [ + "* ", + "Quando " + ] + }, + "ja": { + "and": [ + "* ", + "かつ" + ], + "background": [ + "背景" + ], + "but": [ + "* ", + "しかし", + "但し", + "ただし" + ], + "examples": [ + "例", + "サンプル" + ], + "feature": [ + "フィーチャ", + "機能" + ], + "given": [ + "* ", + "前提" + ], + "name": "Japanese", + "native": "日本語", + "scenario": [ + "シナリオ" + ], + "scenarioOutline": [ + "シナリオアウトライン", + "シナリオテンプレート", + "テンプレ", + "シナリオテンプレ" + ], + "then": [ + "* ", + "ならば" + ], + "when": [ + "* ", + "もし" + ] + }, + "jv": { + "and": [ + "* ", + "Lan " + ], + "background": [ + "Dasar" + ], + "but": [ + "* ", + "Tapi ", + "Nanging ", + "Ananging " + ], + "examples": [ + "Conto", + "Contone" + ], + "feature": [ + "Fitur" + ], + "given": [ + "* ", + "Nalika ", + "Nalikaning " + ], + "name": "Javanese", + "native": "Basa Jawa", + "scenario": [ + "Skenario" + ], + "scenarioOutline": [ + "Konsep skenario" + ], + "then": [ + "* ", + "Njuk ", + "Banjur " + ], + "when": [ + "* ", + "Manawa ", + "Menawa " + ] + }, + "ka": { + "and": [ + "* ", + "და" + ], + "background": [ + "კონტექსტი" + ], + "but": [ + "* ", + "მაგ­რამ" + ], + "examples": [ + "მაგალითები" + ], + "feature": [ + "თვისება" + ], + "given": [ + "* ", + "მოცემული" + ], + "name": "Georgian", + "native": "ქართველი", + "scenario": [ + "სცენარის" + ], + "scenarioOutline": [ + "სცენარის ნიმუში" + ], + "then": [ + "* ", + "მაშინ" + ], + "when": [ + "* ", + "როდესაც" + ] + }, + "kn": { + "and": [ + "* ", + "ಮತ್ತು " + ], + "background": [ + "ಹಿನ್ನೆಲೆ" + ], + "but": [ + "* ", + "ಆದರೆ " + ], + "examples": [ + "ಉದಾಹರಣೆಗಳು" + ], + "feature": [ + "ಹೆಚ್ಚಳ" + ], + "given": [ + "* ", + "ನೀಡಿದ " + ], + "name": "Kannada", + "native": "ಕನ್ನಡ", + "scenario": [ + "ಕಥಾಸಾರಾಂಶ" + ], + "scenarioOutline": [ + "ವಿವರಣೆ" + ], + "then": [ + "* ", + "ನಂತರ " + ], + "when": [ + "* ", + "ಸ್ಥಿತಿಯನ್ನು " + ] + }, + "ko": { + "and": [ + "* ", + "그리고" + ], + "background": [ + "배경" + ], + "but": [ + "* ", + "하지만", + "단" + ], + "examples": [ + "예" + ], + "feature": [ + "기능" + ], + "given": [ + "* ", + "조건", + "먼저" + ], + "name": "Korean", + "native": "한국어", + "scenario": [ + "시나리오" + ], + "scenarioOutline": [ + "시나리오 개요" + ], + "then": [ + "* ", + "그러면" + ], + "when": [ + "* ", + "만일", + "만약" + ] + }, + "lt": { + "and": [ + "* ", + "Ir " + ], + "background": [ + "Kontekstas" + ], + "but": [ + "* ", + "Bet " + ], + "examples": [ + "Pavyzdžiai", + "Scenarijai", + "Variantai" + ], + "feature": [ + "Savybė" + ], + "given": [ + "* ", + "Duota " + ], + "name": "Lithuanian", + "native": "lietuvių kalba", + "scenario": [ + "Scenarijus" + ], + "scenarioOutline": [ + "Scenarijaus šablonas" + ], + "then": [ + "* ", + "Tada " + ], + "when": [ + "* ", + "Kai " + ] + }, + "lu": { + "and": [ + "* ", + "an ", + "a " + ], + "background": [ + "Hannergrond" + ], + "but": [ + "* ", + "awer ", + "mä " + ], + "examples": [ + "Beispiller" + ], + "feature": [ + "Funktionalitéit" + ], + "given": [ + "* ", + "ugeholl " + ], + "name": "Luxemburgish", + "native": "Lëtzebuergesch", + "scenario": [ + "Szenario" + ], + "scenarioOutline": [ + "Plang vum Szenario" + ], + "then": [ + "* ", + "dann " + ], + "when": [ + "* ", + "wann " + ] + }, + "lv": { + "and": [ + "* ", + "Un " + ], + "background": [ + "Konteksts", + "Situācija" + ], + "but": [ + "* ", + "Bet " + ], + "examples": [ + "Piemēri", + "Paraugs" + ], + "feature": [ + "Funkcionalitāte", + "Fīča" + ], + "given": [ + "* ", + "Kad " + ], + "name": "Latvian", + "native": "latviešu", + "scenario": [ + "Scenārijs" + ], + "scenarioOutline": [ + "Scenārijs pēc parauga" + ], + "then": [ + "* ", + "Tad " + ], + "when": [ + "* ", + "Ja " + ] + }, + "mk-Cyrl": { + "and": [ + "* ", + "И " + ], + "background": [ + "Контекст", + "Содржина" + ], + "but": [ + "* ", + "Но " + ], + "examples": [ + "Примери", + "Сценарија" + ], + "feature": [ + "Функционалност", + "Бизнис потреба", + "Можност" + ], + "given": [ + "* ", + "Дадено ", + "Дадена " + ], + "name": "Macedonian", + "native": "Македонски", + "scenario": [ + "Сценарио", + "На пример" + ], + "scenarioOutline": [ + "Преглед на сценарија", + "Скица", + "Концепт" + ], + "then": [ + "* ", + "Тогаш " + ], + "when": [ + "* ", + "Кога " + ] + }, + "mk-Latn": { + "and": [ + "* ", + "I " + ], + "background": [ + "Kontekst", + "Sodrzhina" + ], + "but": [ + "* ", + "No " + ], + "examples": [ + "Primeri", + "Scenaria" + ], + "feature": [ + "Funkcionalnost", + "Biznis potreba", + "Mozhnost" + ], + "given": [ + "* ", + "Dadeno ", + "Dadena " + ], + "name": "Macedonian (Latin)", + "native": "Makedonski (Latinica)", + "scenario": [ + "Scenario", + "Na primer" + ], + "scenarioOutline": [ + "Pregled na scenarija", + "Skica", + "Koncept" + ], + "then": [ + "* ", + "Togash " + ], + "when": [ + "* ", + "Koga " + ] + }, + "mn": { + "and": [ + "* ", + "Мөн ", + "Тэгээд " + ], + "background": [ + "Агуулга" + ], + "but": [ + "* ", + "Гэхдээ ", + "Харин " + ], + "examples": [ + "Тухайлбал" + ], + "feature": [ + "Функц", + "Функционал" + ], + "given": [ + "* ", + "Өгөгдсөн нь ", + "Анх " + ], + "name": "Mongolian", + "native": "монгол", + "scenario": [ + "Сценар" + ], + "scenarioOutline": [ + "Сценарын төлөвлөгөө" + ], + "then": [ + "* ", + "Тэгэхэд ", + "Үүний дараа " + ], + "when": [ + "* ", + "Хэрэв " + ] + }, + "nl": { + "and": [ + "* ", + "En " + ], + "background": [ + "Achtergrond" + ], + "but": [ + "* ", + "Maar " + ], + "examples": [ + "Voorbeelden" + ], + "feature": [ + "Functionaliteit" + ], + "given": [ + "* ", + "Gegeven ", + "Stel " + ], + "name": "Dutch", + "native": "Nederlands", + "scenario": [ + "Scenario" + ], + "scenarioOutline": [ + "Abstract Scenario" + ], + "then": [ + "* ", + "Dan " + ], + "when": [ + "* ", + "Als ", + "Wanneer " + ] + }, + "no": { + "and": [ + "* ", + "Og " + ], + "background": [ + "Bakgrunn" + ], + "but": [ + "* ", + "Men " + ], + "examples": [ + "Eksempler" + ], + "feature": [ + "Egenskap" + ], + "given": [ + "* ", + "Gitt " + ], + "name": "Norwegian", + "native": "norsk", + "scenario": [ + "Scenario" + ], + "scenarioOutline": [ + "Scenariomal", + "Abstrakt Scenario" + ], + "then": [ + "* ", + "Så " + ], + "when": [ + "* ", + "Når " + ] + }, + "pa": { + "and": [ + "* ", + "ਅਤੇ " + ], + "background": [ + "ਪਿਛੋਕੜ" + ], + "but": [ + "* ", + "ਪਰ " + ], + "examples": [ + "ਉਦਾਹਰਨਾਂ" + ], + "feature": [ + "ਖਾਸੀਅਤ", + "ਮੁਹਾਂਦਰਾ", + "ਨਕਸ਼ ਨੁਹਾਰ" + ], + "given": [ + "* ", + "ਜੇਕਰ ", + "ਜਿਵੇਂ ਕਿ " + ], + "name": "Panjabi", + "native": "ਪੰਜਾਬੀ", + "scenario": [ + "ਪਟਕਥਾ" + ], + "scenarioOutline": [ + "ਪਟਕਥਾ ਢਾਂਚਾ", + "ਪਟਕਥਾ ਰੂਪ ਰੇਖਾ" + ], + "then": [ + "* ", + "ਤਦ " + ], + "when": [ + "* ", + "ਜਦੋਂ " + ] + }, + "pl": { + "and": [ + "* ", + "Oraz ", + "I " + ], + "background": [ + "Założenia" + ], + "but": [ + "* ", + "Ale " + ], + "examples": [ + "Przykłady" + ], + "feature": [ + "Właściwość", + "Funkcja", + "Aspekt", + "Potrzeba biznesowa" + ], + "given": [ + "* ", + "Zakładając ", + "Mając ", + "Zakładając, że " + ], + "name": "Polish", + "native": "polski", + "scenario": [ + "Scenariusz" + ], + "scenarioOutline": [ + "Szablon scenariusza" + ], + "then": [ + "* ", + "Wtedy " + ], + "when": [ + "* ", + "Jeżeli ", + "Jeśli ", + "Gdy ", + "Kiedy " + ] + }, + "pt": { + "and": [ + "* ", + "E " + ], + "background": [ + "Contexto", + "Cenário de Fundo", + "Cenario de Fundo", + "Fundo" + ], + "but": [ + "* ", + "Mas " + ], + "examples": [ + "Exemplos", + "Cenários", + "Cenarios" + ], + "feature": [ + "Funcionalidade", + "Característica", + "Caracteristica" + ], + "given": [ + "* ", + "Dado ", + "Dada ", + "Dados ", + "Dadas " + ], + "name": "Portuguese", + "native": "português", + "scenario": [ + "Cenário", + "Cenario" + ], + "scenarioOutline": [ + "Esquema do Cenário", + "Esquema do Cenario", + "Delineação do Cenário", + "Delineacao do Cenario" + ], + "then": [ + "* ", + "Então ", + "Entao " + ], + "when": [ + "* ", + "Quando " + ] + }, + "ro": { + "and": [ + "* ", + "Si ", + "Și ", + "Şi " + ], + "background": [ + "Context" + ], + "but": [ + "* ", + "Dar " + ], + "examples": [ + "Exemple" + ], + "feature": [ + "Functionalitate", + "Funcționalitate", + "Funcţionalitate" + ], + "given": [ + "* ", + "Date fiind ", + "Dat fiind ", + "Dată fiind", + "Dati fiind ", + "Dați fiind ", + "Daţi fiind " + ], + "name": "Romanian", + "native": "română", + "scenario": [ + "Scenariu" + ], + "scenarioOutline": [ + "Structura scenariu", + "Structură scenariu" + ], + "then": [ + "* ", + "Atunci " + ], + "when": [ + "* ", + "Cand ", + "Când " + ] + }, + "ru": { + "and": [ + "* ", + "И ", + "К тому же ", + "Также " + ], + "background": [ + "Предыстория", + "Контекст" + ], + "but": [ + "* ", + "Но ", + "А ", + "Иначе " + ], + "examples": [ + "Примеры" + ], + "feature": [ + "Функция", + "Функциональность", + "Функционал", + "Свойство" + ], + "given": [ + "* ", + "Допустим ", + "Дано ", + "Пусть ", + "Если " + ], + "name": "Russian", + "native": "русский", + "scenario": [ + "Сценарий" + ], + "scenarioOutline": [ + "Структура сценария" + ], + "then": [ + "* ", + "То ", + "Затем ", + "Тогда " + ], + "when": [ + "* ", + "Когда " + ] + }, + "sk": { + "and": [ + "* ", + "A ", + "A tiež ", + "A taktiež ", + "A zároveň " + ], + "background": [ + "Pozadie" + ], + "but": [ + "* ", + "Ale " + ], + "examples": [ + "Príklady" + ], + "feature": [ + "Požiadavka", + "Funkcia", + "Vlastnosť" + ], + "given": [ + "* ", + "Pokiaľ ", + "Za predpokladu " + ], + "name": "Slovak", + "native": "Slovensky", + "scenario": [ + "Scenár" + ], + "scenarioOutline": [ + "Náčrt Scenáru", + "Náčrt Scenára", + "Osnova Scenára" + ], + "then": [ + "* ", + "Tak ", + "Potom " + ], + "when": [ + "* ", + "Keď ", + "Ak " + ] + }, + "sl": { + "and": [ + "In ", + "Ter " + ], + "background": [ + "Kontekst", + "Osnova", + "Ozadje" + ], + "but": [ + "Toda ", + "Ampak ", + "Vendar " + ], + "examples": [ + "Primeri", + "Scenariji" + ], + "feature": [ + "Funkcionalnost", + "Funkcija", + "Možnosti", + "Moznosti", + "Lastnost", + "Značilnost" + ], + "given": [ + "Dano ", + "Podano ", + "Zaradi ", + "Privzeto " + ], + "name": "Slovenian", + "native": "Slovenski", + "scenario": [ + "Scenarij", + "Primer" + ], + "scenarioOutline": [ + "Struktura scenarija", + "Skica", + "Koncept", + "Oris scenarija", + "Osnutek" + ], + "then": [ + "Nato ", + "Potem ", + "Takrat " + ], + "when": [ + "Ko ", + "Ce ", + "Če ", + "Kadar " + ] + }, + "sr-Cyrl": { + "and": [ + "* ", + "И " + ], + "background": [ + "Контекст", + "Основа", + "Позадина" + ], + "but": [ + "* ", + "Али " + ], + "examples": [ + "Примери", + "Сценарији" + ], + "feature": [ + "Функционалност", + "Могућност", + "Особина" + ], + "given": [ + "* ", + "За дато ", + "За дате ", + "За дати " + ], + "name": "Serbian", + "native": "Српски", + "scenario": [ + "Сценарио", + "Пример" + ], + "scenarioOutline": [ + "Структура сценарија", + "Скица", + "Концепт" + ], + "then": [ + "* ", + "Онда " + ], + "when": [ + "* ", + "Када ", + "Кад " + ] + }, + "sr-Latn": { + "and": [ + "* ", + "I " + ], + "background": [ + "Kontekst", + "Osnova", + "Pozadina" + ], + "but": [ + "* ", + "Ali " + ], + "examples": [ + "Primeri", + "Scenariji" + ], + "feature": [ + "Funkcionalnost", + "Mogućnost", + "Mogucnost", + "Osobina" + ], + "given": [ + "* ", + "Za dato ", + "Za date ", + "Za dati " + ], + "name": "Serbian (Latin)", + "native": "Srpski (Latinica)", + "scenario": [ + "Scenario", + "Primer" + ], + "scenarioOutline": [ + "Struktura scenarija", + "Skica", + "Koncept" + ], + "then": [ + "* ", + "Onda " + ], + "when": [ + "* ", + "Kada ", + "Kad " + ] + }, + "sv": { + "and": [ + "* ", + "Och " + ], + "background": [ + "Bakgrund" + ], + "but": [ + "* ", + "Men " + ], + "examples": [ + "Exempel" + ], + "feature": [ + "Egenskap" + ], + "given": [ + "* ", + "Givet " + ], + "name": "Swedish", + "native": "Svenska", + "scenario": [ + "Scenario" + ], + "scenarioOutline": [ + "Abstrakt Scenario", + "Scenariomall" + ], + "then": [ + "* ", + "Så " + ], + "when": [ + "* ", + "När " + ] + }, + "ta": { + "and": [ + "* ", + "மேலும் ", + "மற்றும் " + ], + "background": [ + "பின்னணி" + ], + "but": [ + "* ", + "ஆனால் " + ], + "examples": [ + "எடுத்துக்காட்டுகள்", + "காட்சிகள்", + " நிலைமைகளில்" + ], + "feature": [ + "அம்சம்", + "வணிக தேவை", + "திறன்" + ], + "given": [ + "* ", + "கொடுக்கப்பட்ட " + ], + "name": "Tamil", + "native": "தமிழ்", + "scenario": [ + "காட்சி" + ], + "scenarioOutline": [ + "காட்சி சுருக்கம்", + "காட்சி வார்ப்புரு" + ], + "then": [ + "* ", + "அப்பொழுது " + ], + "when": [ + "* ", + "எப்போது " + ] + }, + "th": { + "and": [ + "* ", + "และ " + ], + "background": [ + "แนวคิด" + ], + "but": [ + "* ", + "แต่ " + ], + "examples": [ + "ชุดของตัวอย่าง", + "ชุดของเหตุการณ์" + ], + "feature": [ + "โครงหลัก", + "ความต้องการทางธุรกิจ", + "ความสามารถ" + ], + "given": [ + "* ", + "กำหนดให้ " + ], + "name": "Thai", + "native": "ไทย", + "scenario": [ + "เหตุการณ์" + ], + "scenarioOutline": [ + "สรุปเหตุการณ์", + "โครงสร้างของเหตุการณ์" + ], + "then": [ + "* ", + "ดังนั้น " + ], + "when": [ + "* ", + "เมื่อ " + ] + }, + "tl": { + "and": [ + "* ", + "మరియు " + ], + "background": [ + "నేపథ్యం" + ], + "but": [ + "* ", + "కాని " + ], + "examples": [ + "ఉదాహరణలు" + ], + "feature": [ + "గుణము" + ], + "given": [ + "* ", + "చెప్పబడినది " + ], + "name": "Telugu", + "native": "తెలుగు", + "scenario": [ + "సన్నివేశం" + ], + "scenarioOutline": [ + "కథనం" + ], + "then": [ + "* ", + "అప్పుడు " + ], + "when": [ + "* ", + "ఈ పరిస్థితిలో " + ] + }, + "tlh": { + "and": [ + "* ", + "'ej ", + "latlh " + ], + "background": [ + "mo'" + ], + "but": [ + "* ", + "'ach ", + "'a " + ], + "examples": [ + "ghantoH", + "lutmey" + ], + "feature": [ + "Qap", + "Qu'meH 'ut", + "perbogh", + "poQbogh malja'", + "laH" + ], + "given": [ + "* ", + "ghu' noblu' ", + "DaH ghu' bejlu' " + ], + "name": "Klingon", + "native": "tlhIngan", + "scenario": [ + "lut" + ], + "scenarioOutline": [ + "lut chovnatlh" + ], + "then": [ + "* ", + "vaj " + ], + "when": [ + "* ", + "qaSDI' " + ] + }, + "tr": { + "and": [ + "* ", + "Ve " + ], + "background": [ + "Geçmiş" + ], + "but": [ + "* ", + "Fakat ", + "Ama " + ], + "examples": [ + "Örnekler" + ], + "feature": [ + "Özellik" + ], + "given": [ + "* ", + "Diyelim ki " + ], + "name": "Turkish", + "native": "Türkçe", + "scenario": [ + "Senaryo" + ], + "scenarioOutline": [ + "Senaryo taslağı" + ], + "then": [ + "* ", + "O zaman " + ], + "when": [ + "* ", + "Eğer ki " + ] + }, + "tt": { + "and": [ + "* ", + "Һәм ", + "Вә " + ], + "background": [ + "Кереш" + ], + "but": [ + "* ", + "Ләкин ", + "Әмма " + ], + "examples": [ + "Үрнәкләр", + "Мисаллар" + ], + "feature": [ + "Мөмкинлек", + "Үзенчәлеклелек" + ], + "given": [ + "* ", + "Әйтик " + ], + "name": "Tatar", + "native": "Татарча", + "scenario": [ + "Сценарий" + ], + "scenarioOutline": [ + "Сценарийның төзелеше" + ], + "then": [ + "* ", + "Нәтиҗәдә " + ], + "when": [ + "* ", + "Әгәр " + ] + }, + "uk": { + "and": [ + "* ", + "І ", + "А також ", + "Та " + ], + "background": [ + "Передумова" + ], + "but": [ + "* ", + "Але " + ], + "examples": [ + "Приклади" + ], + "feature": [ + "Функціонал" + ], + "given": [ + "* ", + "Припустимо ", + "Припустимо, що ", + "Нехай ", + "Дано " + ], + "name": "Ukrainian", + "native": "Українська", + "scenario": [ + "Сценарій" + ], + "scenarioOutline": [ + "Структура сценарію" + ], + "then": [ + "* ", + "То ", + "Тоді " + ], + "when": [ + "* ", + "Якщо ", + "Коли " + ] + }, + "ur": { + "and": [ + "* ", + "اور " + ], + "background": [ + "پس منظر" + ], + "but": [ + "* ", + "لیکن " + ], + "examples": [ + "مثالیں" + ], + "feature": [ + "صلاحیت", + "کاروبار کی ضرورت", + "خصوصیت" + ], + "given": [ + "* ", + "اگر ", + "بالفرض ", + "فرض کیا " + ], + "name": "Urdu", + "native": "اردو", + "scenario": [ + "منظرنامہ" + ], + "scenarioOutline": [ + "منظر نامے کا خاکہ" + ], + "then": [ + "* ", + "پھر ", + "تب " + ], + "when": [ + "* ", + "جب " + ] + }, + "uz": { + "and": [ + "* ", + "Ва " + ], + "background": [ + "Тарих" + ], + "but": [ + "* ", + "Лекин ", + "Бирок ", + "Аммо " + ], + "examples": [ + "Мисоллар" + ], + "feature": [ + "Функционал" + ], + "given": [ + "* ", + "Агар " + ], + "name": "Uzbek", + "native": "Узбекча", + "scenario": [ + "Сценарий" + ], + "scenarioOutline": [ + "Сценарий структураси" + ], + "then": [ + "* ", + "Унда " + ], + "when": [ + "* ", + "Агар " + ] + }, + "vi": { + "and": [ + "* ", + "Và " + ], + "background": [ + "Bối cảnh" + ], + "but": [ + "* ", + "Nhưng " + ], + "examples": [ + "Dữ liệu" + ], + "feature": [ + "Tính năng" + ], + "given": [ + "* ", + "Biết ", + "Cho " + ], + "name": "Vietnamese", + "native": "Tiếng Việt", + "scenario": [ + "Tình huống", + "Kịch bản" + ], + "scenarioOutline": [ + "Khung tình huống", + "Khung kịch bản" + ], + "then": [ + "* ", + "Thì " + ], + "when": [ + "* ", + "Khi " + ] + }, + "zh-CN": { + "and": [ + "* ", + "而且", + "并且", + "同时" + ], + "background": [ + "背景" + ], + "but": [ + "* ", + "但是" + ], + "examples": [ + "例子" + ], + "feature": [ + "功能" + ], + "given": [ + "* ", + "假如", + "假设", + "假定" + ], + "name": "Chinese simplified", + "native": "简体中文", + "scenario": [ + "场景", + "剧本" + ], + "scenarioOutline": [ + "场景大纲", + "剧本大纲" + ], + "then": [ + "* ", + "那么" + ], + "when": [ + "* ", + "当" + ] + }, + "zh-TW": { + "and": [ + "* ", + "而且", + "並且", + "同時" + ], + "background": [ + "背景" + ], + "but": [ + "* ", + "但是" + ], + "examples": [ + "例子" + ], + "feature": [ + "功能" + ], + "given": [ + "* ", + "假如", + "假設", + "假定" + ], + "name": "Chinese traditional", + "native": "繁體中文", + "scenario": [ + "場景", + "劇本" + ], + "scenarioOutline": [ + "場景大綱", + "劇本大綱" + ], + "then": [ + "* ", + "那麼" + ], + "when": [ + "* ", + "當" + ] + } +} diff --git a/gherkin.berp b/gherkin.berp new file mode 100644 index 0000000..f895f3e --- /dev/null +++ b/gherkin.berp @@ -0,0 +1,37 @@ +[ + Tokens -> #Empty,#Comment,#TagLine,#FeatureLine,#BackgroundLine,#ScenarioLine,#ScenarioOutlineLine,#ExamplesLine,#StepLine,#DocStringSeparator,#TableRow,#Language + IgnoredTokens -> #Comment,#Empty + ClassName -> Parser + Namespace -> Gherkin +] + +GherkinDocument! := Feature? +Feature! := Feature_Header Background? Scenario_Definition* +Feature_Header! := #Language? Tags? #FeatureLine Description_Helper + +Background! := #BackgroundLine Description_Helper Step* + +// we could avoid defining Scenario_Definition, but that would require regular look-aheads, so worse performance +Scenario_Definition! := Tags? (Scenario | ScenarioOutline) + +Scenario! := #ScenarioLine Description_Helper Step* + +ScenarioOutline! := #ScenarioOutlineLine Description_Helper Step* Examples_Definition* +// after the first "Examples" block, interpreting a tag line is ambiguous (tagline of next examples or of next scenario) +// because of this, we need a lookahead hint, that connects the tag line to the next examples, if there is an examples block ahead +Examples_Definition! [#Empty|#Comment|#TagLine->#ExamplesLine]:= Tags? Examples +Examples! := #ExamplesLine Description_Helper Examples_Table? +Examples_Table! := #TableRow #TableRow* + +Step! := #StepLine Step_Arg? +Step_Arg := (DataTable | DocString) + +DataTable! := #TableRow+ +DocString! := #DocStringSeparator #Other* #DocStringSeparator + +Tags! := #TagLine+ + +// we need to explicitly mention comment, to avoid merging it into the description line's #Other token +// we also eat the leading empty lines, the tailing lines are not removed by the parser to avoid lookahead, this has to be done by the AST builder +Description_Helper := #Empty* Description? #Comment* +Description! := #Other+ diff --git a/gherkin.gif b/gherkin.gif new file mode 100644 index 0000000..0c6e2e5 Binary files /dev/null and b/gherkin.gif differ diff --git a/include/builder.h b/include/builder.h index 85f26c9..7457ea6 100644 --- a/include/builder.h +++ b/include/builder.h @@ -1,11 +1,10 @@ #ifndef GHERKIN_BUILDER_H_ #define GHERKIN_BUILDER_H_ +#include "error_list.h" #include "rule_type.h" #include "token.h" -typedef struct ErrorList ErrorList; - typedef struct Builder Builder; typedef void (*builder_reset_function) (Builder*); @@ -16,14 +15,12 @@ typedef void (*build_function) (Builder*, Token*); typedef void (*rule_function) (Builder*, RuleType); -typedef void (*rule_function) (Builder*, RuleType); - -typedef struct Builder { +struct Builder { builder_reset_function reset; builder_error_context_function set_error_context; build_function build; rule_function start_rule; rule_function end_rule; -} Builder; +}; #endif /* GHERKIN_BUILDER_H_ */ diff --git a/include/compiler.h b/include/compiler.h index ac55f6d..b90fb32 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -3,6 +3,8 @@ #include #include +#include "gherkin_document.h" +#include "pickle.h" #ifdef __cplusplus extern "C" { @@ -10,10 +12,6 @@ extern "C" { typedef struct Compiler Compiler; -typedef struct GherkinDocument GherkinDocument; - -typedef struct Pickle Pickle; - Compiler* Compiler_new(); void Compiler_delete(Compiler* compiler); diff --git a/src/error_list.h b/include/error_list.h similarity index 100% rename from src/error_list.h rename to include/error_list.h diff --git a/include/event.h b/include/event.h index 1dbea76..ef793e2 100644 --- a/include/event.h +++ b/include/event.h @@ -20,11 +20,11 @@ typedef enum EventType { Gherkin_PickleEvent } EventType; -typedef struct Event { +struct Event { event_delete_function event_delete; event_print_function event_print; EventType event_type; -} Event; +}; void Event_delete(const Event* event); diff --git a/src/file_reader.h b/include/file_reader.h similarity index 100% rename from src/file_reader.h rename to include/file_reader.h diff --git a/include/item.h b/include/item.h index 36aa984..9e19bfe 100644 --- a/include/item.h +++ b/include/item.h @@ -5,8 +5,8 @@ typedef struct Item Item; typedef void (*item_delete_function) (Item*); -typedef struct Item { +struct Item { item_delete_function item_delete; -} Item; +}; #endif /* GHERKIN_ITEM_H_ */ diff --git a/include/parser.h b/include/parser.h index 7b45565..26ee333 100644 --- a/include/parser.h +++ b/include/parser.h @@ -1,7 +1,10 @@ #ifndef GHERKIN_PARSER_H_ #define GHERKIN_PARSER_H_ +#include "builder.h" #include "error.h" +#include "token_matcher.h" +#include "token_scanner.h" #include #include @@ -11,14 +14,6 @@ extern "C" { typedef struct Parser Parser; -typedef struct Builder Builder; - -typedef struct TokenMatcher TokenMatcher; - -typedef struct TokenScanner TokenScanner; - -typedef struct Feature Feature; - Parser* Parser_new(Builder* builder); void Parser_delete(Parser* parser); diff --git a/include/pickle_string.h b/include/pickle_string.h index 228498e..381253e 100644 --- a/include/pickle_string.h +++ b/include/pickle_string.h @@ -13,10 +13,11 @@ extern "C" { typedef struct PickleString { PickleArgumentType type; PickleLocation location; + wchar_t* content_type; wchar_t* content; } PickleString; -const PickleString* PickleString_new(const wchar_t* content, int line, int column); +const PickleString* PickleString_new(const wchar_t* content, int line, int column, const wchar_t* content_type); void PickleString_delete(const PickleString* pickle_string); diff --git a/include/rule_type.h b/include/rule_type.h index f35c7b0..adb5623 100644 --- a/include/rule_type.h +++ b/include/rule_type.h @@ -20,26 +20,19 @@ typedef enum RuleType { Rule_Other, /* #Other */ Rule_GherkinDocument, /* GherkinDocument! := Feature? */ Rule_Feature, /* Feature! := Feature_Header Background? Scenario_Definition* */ - Rule_Feature_Header, /* Feature_Header! := #Language? Tags? #FeatureLine Feature_Description */ - Rule_Background, /* Background! := #BackgroundLine Background_Description Scenario_Step* */ + Rule_Feature_Header, /* Feature_Header! := #Language? Tags? #FeatureLine Description_Helper */ + Rule_Background, /* Background! := #BackgroundLine Description_Helper Step* */ Rule_Scenario_Definition, /* Scenario_Definition! := Tags? (Scenario | ScenarioOutline) */ - Rule_Scenario, /* Scenario! := #ScenarioLine Scenario_Description Scenario_Step* */ - Rule_ScenarioOutline, /* ScenarioOutline! := #ScenarioOutlineLine ScenarioOutline_Description ScenarioOutline_Step* Examples_Definition* */ + Rule_Scenario, /* Scenario! := #ScenarioLine Description_Helper Step* */ + Rule_ScenarioOutline, /* ScenarioOutline! := #ScenarioOutlineLine Description_Helper Step* Examples_Definition* */ Rule_Examples_Definition, /* Examples_Definition! [#Empty|#Comment|#TagLine->#ExamplesLine] := Tags? Examples */ - Rule_Examples, /* Examples! := #ExamplesLine Examples_Description Examples_Table? */ + Rule_Examples, /* Examples! := #ExamplesLine Description_Helper Examples_Table? */ Rule_Examples_Table, /* Examples_Table! := #TableRow #TableRow* */ - Rule_Scenario_Step, /* Scenario_Step := Step */ - Rule_ScenarioOutline_Step, /* ScenarioOutline_Step := Step */ Rule_Step, /* Step! := #StepLine Step_Arg? */ Rule_Step_Arg, /* Step_Arg := (DataTable | DocString) */ Rule_DataTable, /* DataTable! := #TableRow+ */ Rule_DocString, /* DocString! := #DocStringSeparator #Other* #DocStringSeparator */ Rule_Tags, /* Tags! := #TagLine+ */ - Rule_Feature_Description, /* Feature_Description := Description_Helper */ - Rule_Background_Description, /* Background_Description := Description_Helper */ - Rule_Scenario_Description, /* Scenario_Description := Description_Helper */ - Rule_ScenarioOutline_Description, /* ScenarioOutline_Description := Description_Helper */ - Rule_Examples_Description, /* Examples_Description := Description_Helper */ Rule_Description_Helper, /* Description_Helper := #Empty* Description? #Comment* */ Rule_Description, /* Description! := #Other+ */ Rule_Count diff --git a/include/token_matcher.h b/include/token_matcher.h index e91a9f7..ce8409e 100644 --- a/include/token_matcher.h +++ b/include/token_matcher.h @@ -2,23 +2,21 @@ #define GHERKIN_TOKEN_MATCHER_H_ #include +#include "dialect.h" +#include "error_list.h" #include "token.h" #ifdef __cplusplus extern "C" { #endif -typedef struct Dialect Dialect; - -typedef struct ErrorList ErrorList; - typedef struct TokenMatcher TokenMatcher; typedef void (*matcher_reset_function) (TokenMatcher*); typedef bool (*match_function) (TokenMatcher*, Token*); -typedef struct TokenMatcher { +struct TokenMatcher { const wchar_t* default_language; const wchar_t* language; const Dialect* dialect; @@ -40,7 +38,7 @@ typedef struct TokenMatcher { match_function match_Language; match_function match_Other; match_function match_EOF; -} TokenMatcher; +}; TokenMatcher* TokenMatcher_new(const wchar_t* default_language); diff --git a/include/token_scanner.h b/include/token_scanner.h index dc6e21e..8f1783b 100644 --- a/include/token_scanner.h +++ b/include/token_scanner.h @@ -15,10 +15,10 @@ typedef Token* (*read_function) (TokenScanner*); typedef void (*delete_function) (TokenScanner*); -typedef struct TokenScanner { +struct TokenScanner { read_function read; delete_function delete; -} TokenScanner; +}; void TokenScanner_delete(TokenScanner* token_scanner); diff --git a/src/Makefile b/src/Makefile index e382752..2e2659d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,30 +1,48 @@ -GCC_FLAGS=-c -Wall -Werror -g -CLANG_FLAGS=-c -Wall -Wno-typedef-redefinition -Werror -g - -ifeq ($(CC),clang) - CC=clang - LD=clang - CC_FLAGS=$(CLANG_FLAGS) +GCC_FLAGS=-c -Wall -Werror -g -fPIC +CLANG_FLAGS=-c -Wall -Werror -g -fPIC +GCC_SO_FLAGS=-shared +MINGW_FLAGS=-c -Wall -Werror -g + +ifeq ($(CC),i686-w64-mingw32-gcc) + CC=i686-w64-mingw32-gcc + LD=i686-w64-mingw32-gcc + CC_FLAGS=$(MINGW_FLAGS) + AR=i686-w64-mingw32-ar + EXT=.exe +else ifeq ($(CC),clang) + CC=clang + LD=clang + CC_FLAGS=$(CLANG_FLAGS) + AR=ar else - CC=gcc - LD=gcc - CC_FLAGS=$(GCC_FLAGS) + CC=gcc + LD=gcc + CC_FLAGS=$(GCC_FLAGS) + AR=ar endif GENERATE_DEPS_FLAGS=-MMD -MP -MF $(basename $@).d -AR=ar AR_FLAGS=cr LD_FLAGS= -LD_LIBS= +LD_LIBS=-lm RM_CMD=rm -rf MKDIR_CMD=mkdir -p +VERSION=$(shell cat ../VERSION) + all: \ - cli \ - ../bin/gherkin_generate_tokens + cli \ + ../bin/gherkin_generate_tokens$(EXT) \ + libs_so +.PHONY: all -cli: ../bin/gherkin +cli: ../bin/gherkin$(EXT) +.PHONY: cli libs: ../libs/libgherkin.a +.PHONY: libs + +libs_so: ../libs/libgherkin.so.$(VERSION) +.PHONY: libs_so clean: $(RM_CMD) ../bin ../objs ../libs @@ -32,9 +50,11 @@ clean: UTILITIES_OBJS= \ ../objs/file_reader.o \ - ../objs/file_utilities.o \ + ../objs/file_utf8_source.o \ ../objs/print_utilities.o \ - ../objs/string_utilities.o + ../objs/string_utilities.o \ + ../objs/unicode_utilities.o \ + ../objs/utf8_source.o -include $(UTILITIES_OBJS:.o=.d) PARSER_OBJS= \ @@ -67,7 +87,7 @@ AST_OBJS= \ ../objs/step.o \ ../objs/table_cell.o \ ../objs/table_row.o \ - ../objs/tag.o + ../objs/tag.o -include $(AST_OBJS:.o=.d) COMPILER_OBJS= \ @@ -112,10 +132,14 @@ GHERKIN_CLI_OBJS= \ $(MKDIR_CMD) $(dir $@) $(AR) $(AR_FLAGS) $@ $(UTILITIES_OBJS) $(PARSER_OBJS) $(AST_OBJS) $(COMPILER_OBJS) $(PICKLES_OBJS) $(EVENT_OBJS) -../bin/gherkin_generate_tokens: ../libs/libgherkin.a $(GENERATE_TOKEN_OBJS) Makefile +../libs/libgherkin.so.$(VERSION): $(UTILITIES_OBJS) $(PARSER_OBJS) $(AST_OBJS) $(COMPILER_OBJS) $(PICKLES_OBJS) $(EVENT_OBJS) Makefile + $(MKDIR_CMD) $(dir $@) + $(CC) $(GCC_SO_FLAGS) $(UTILITIES_OBJS) $(PARSER_OBJS) $(AST_OBJS) $(COMPILER_OBJS) $(PICKLES_OBJS) $(EVENT_OBJS) -o $@ + +../bin/gherkin_generate_tokens$(EXT): ../libs/libgherkin.a $(GENERATE_TOKEN_OBJS) Makefile $(MKDIR_CMD) $(dir $@) $(LD) $(LD_FLAGS) $(GENERATE_TOKEN_OBJS) -L../libs/ -lgherkin $(LD_LIBS) -o $@ -../bin/gherkin: ../libs/libgherkin.a $(GHERKIN_CLI_OBJS) Makefile +../bin/gherkin$(EXT): ../libs/libgherkin.a $(GHERKIN_CLI_OBJS) Makefile $(MKDIR_CMD) $(dir $@) $(LD) $(LD_FLAGS) $(GHERKIN_CLI_OBJS) -L../libs/ -lgherkin $(LD_LIBS) -o $@ diff --git a/src/ast_builder.c b/src/ast_builder.c index baa8819..a12cf03 100644 --- a/src/ast_builder.c +++ b/src/ast_builder.c @@ -6,7 +6,6 @@ #include "scenario_outline.h" #include "data_table.h" #include "doc_string.h" -#include "error_list.h" #include #include diff --git a/src/ast_printer.c b/src/ast_printer.c index e255af5..e7bf998 100644 --- a/src/ast_printer.c +++ b/src/ast_printer.c @@ -93,7 +93,9 @@ static void print_doc_string(FILE* file, const DocString* doc_string) { fprintf(file, "{\"type\":\"%ls\",", ast_item_type_to_string(doc_string->type)); print_location(file, &doc_string->location); if (doc_string->content_type) { - fprintf(file, "\"contentType\":\"%ls\",", doc_string->content_type); + fprintf(file, "\"contentType\":\""); + PrintUtilities_print_json_string(file, doc_string->content_type); + fprintf(file, "\","); } fprintf(file, "\"content\":\""); if (doc_string->content) { @@ -102,11 +104,23 @@ static void print_doc_string(FILE* file, const DocString* doc_string) { fprintf(file, "\"}"); } +static void print_keyword(FILE* file, const wchar_t* keyword) { + fprintf(file, "\"keyword\":\""); + PrintUtilities_print_json_string(file, keyword); + fprintf(file, "\","); +} + +static void print_text(FILE* file, const wchar_t* text) { + fprintf(file, "\"text\":\""); + PrintUtilities_print_json_string(file, text); + fprintf(file, "\""); +} + static void print_step(FILE* file, const Step* step) { fprintf(file, "{\"type\":\"%ls\",", ast_item_type_to_string(step->type)); print_location(file, &step->location); - fprintf(file, "\"keyword\":\"%ls\",", step->keyword); - fprintf(file, "\"text\":\"%ls\"", step->text); + print_keyword(file, step->keyword); + print_text(file, step->text); if (step->argument) { fprintf(file, ",\"argument\":"); if (step->argument->type == Gherkin_DataTable) { @@ -136,7 +150,7 @@ static void print_description(FILE* file, const wchar_t* description) { static void print_background(FILE* file, const Background* background) { fprintf(file, "{\"type\":\"%ls\",", ast_item_type_to_string(background->type)); print_location(file, &background->location); - fprintf(file, "\"keyword\":\"%ls\",", background->keyword); + print_keyword(file, background->keyword); print_name(file, background->name); print_description(file, background->description); fprintf(file, "\"steps\":["); @@ -153,7 +167,9 @@ static void print_background(FILE* file, const Background* background) { static void print_tag(FILE* file, const Tag* tag) { fprintf(file, "{\"type\":\"%ls\",", ast_item_type_to_string(tag->type)); print_location(file, &tag->location); - fprintf(file, "\"name\":\"%ls\"}", tag->name); + fprintf(file, "\"name\":\""); + PrintUtilities_print_json_string(file, tag->name); + fprintf(file, "\"}"); } static void print_scenario(FILE* file, const Scenario* scenario) { @@ -168,7 +184,7 @@ static void print_scenario(FILE* file, const Scenario* scenario) { } fprintf(file, "],"); print_location(file, &scenario->location); - fprintf(file, "\"keyword\":\"%ls\",", scenario->keyword); + print_keyword(file, scenario->keyword); print_name(file, scenario->name); print_description(file, scenario->description); fprintf(file, "\"steps\":["); @@ -185,7 +201,7 @@ static void print_example_table(FILE* file, const ExampleTable* example_table) { fprintf(file, "{\"type\":\"%ls\",", ast_item_type_to_string(example_table->type)); print_location(file, &example_table->location); print_description(file, example_table->description); - fprintf(file, "\"keyword\":\"%ls\",", example_table->keyword); + print_keyword(file, example_table->keyword); print_name(file, example_table->name); fprintf(file, "\"tags\":["); int i; @@ -227,7 +243,7 @@ static void print_scenario_outline(FILE* file, const ScenarioOutline* scenario_o } fprintf(file, "],"); print_location(file, &scenario_outline->location); - fprintf(file, "\"keyword\":\"%ls\",", scenario_outline->keyword); + print_keyword(file, scenario_outline->keyword); print_name(file, scenario_outline->name); print_description(file, scenario_outline->description); fprintf(file, "\"steps\":["); @@ -251,7 +267,8 @@ static void print_scenario_outline(FILE* file, const ScenarioOutline* scenario_o static void print_comment(FILE* file, const Comment* comment) { fprintf(file, "{\"type\":\"%ls\",", ast_item_type_to_string(comment->type)); print_location(file, &comment->location); - fprintf(file, "\"text\":\"%ls\"}", comment->text); + print_text(file, comment->text); + fprintf(file, "}"); } void print_feature(FILE* file, const Feature* feature) { @@ -267,8 +284,10 @@ void print_feature(FILE* file, const Feature* feature) { } fprintf(file, "],"); print_location(file, &feature->location); - fprintf(file, "\"language\":\"%ls\",", feature->language); - fprintf(file, "\"keyword\":\"%ls\",", feature->keyword); + fprintf(file, "\"language\":\""); + PrintUtilities_print_json_string(file, feature->language); + fprintf(file, "\","); + print_keyword(file, feature->keyword); print_name(file, feature->name); print_description(file, feature->description); fprintf(file, "\"children\":["); diff --git a/src/attachment_event.c b/src/attachment_event.c index 8cfdd98..814f713 100644 --- a/src/attachment_event.c +++ b/src/attachment_event.c @@ -1,5 +1,6 @@ #include "attachment_event.h" - +#include "print_utilities.h" +#include "string_utilities.h" #include #include @@ -14,10 +15,7 @@ AttachmentEvent* AttachmentEvent_new(const char* uri, const Location location) { attachment_event->event.event_type = Gherkin_AttachmentEvent; attachment_event->uri = 0; if (uri) { - int uri_length = strlen(uri); - attachment_event->uri = (wchar_t*)malloc((uri_length + 1) * sizeof(wchar_t)); - swprintf(attachment_event->uri, uri_length + 1, L"%hs", uri); - attachment_event->uri[uri_length] = L'\0'; + attachment_event->uri = StringUtilities_copy_to_wide_string(uri); } attachment_event->location.line = location.line; attachment_event->location.column = location.column; @@ -49,12 +47,14 @@ static void AttachmentEvent_print(const Event* event, FILE* file) { } const AttachmentEvent* attachment_event = (const AttachmentEvent*)event; fprintf(file, "{"); - fprintf(file, "\"data\":\"%ls\",", attachment_event->data); - fprintf(file, "\"media\":{\"encoding\":\"utf-8\",\"type\":\"text/vnd.cucumber.stacktrace+plain\"},"); + fprintf(file, "\"data\":\""); + PrintUtilities_print_json_string(file, attachment_event->data); + fprintf(file, "\",\"media\":{\"encoding\":\"utf-8\",\"type\":\"text/x.cucumber.stacktrace+plain\"},"); fprintf(file, "\"source\":{\"start\":"); fprintf(file, "{\"line\":%d,", attachment_event->location.line); fprintf(file, "\"column\":%d},", attachment_event->location.column); - fprintf(file, "\"uri\":\"%ls\"},", attachment_event->uri); - fprintf(file, "\"type\":\"attachment\""); + fprintf(file, "\"uri\":\""); + PrintUtilities_print_json_string(file, attachment_event->uri); + fprintf(file, "\"},\"type\":\"attachment\""); fprintf(file, "}\n"); } diff --git a/src/compiler.c b/src/compiler.c index dbd9330..f940a2e 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -9,11 +9,12 @@ #include "pickle_table.h" #include "pickle_tag.h" #include "pickle_string.h" +#include "string_utilities.h" #include -typedef struct Compiler { +struct Compiler { ItemQueue* pickle_list; -} Compiler; +}; typedef struct ReplacementItem { item_delete_function item_delete; @@ -65,48 +66,52 @@ int Compiler_compile(Compiler* compiler, const GherkinDocument* gherkin_document } else if (feature->scenario_definitions->scenario_definitions[i]->type == Gherkin_Scenario) { const Scenario* scenario = (const Scenario*)feature->scenario_definitions->scenario_definitions[i]; - if (scenario->steps->step_count == 0) { - continue; - } const PickleLocations* locations = PickleLocations_new_single(scenario->location.line, scenario->location.column); const PickleTags* tags = create_pickle_tags(feature->tags, scenario->tags, 0); PickleSteps* steps = (PickleSteps*)malloc(sizeof(PickleSteps)); - steps->step_count = scenario->steps->step_count + background_step_count; - steps->steps = (PickleStep*)malloc(steps->step_count * sizeof(PickleStep)); - if (background_steps) { - copy_steps(steps->steps, background_steps); + if (scenario->steps->step_count == 0) { + steps->step_count = 0; + steps->steps = 0; + } else { + steps->step_count = scenario->steps->step_count + background_step_count; + steps->steps = (PickleStep*)malloc(steps->step_count * sizeof(PickleStep)); + if (background_steps) { + copy_steps(steps->steps, background_steps); + } + copy_steps(steps->steps + background_step_count, scenario->steps); } - copy_steps(steps->steps + background_step_count, scenario->steps); ItemQueue_add(compiler->pickle_list, (Item*)Pickle_new(feature->language, locations, tags, scenario->name, steps)); } else if (feature->scenario_definitions->scenario_definitions[i]->type == Gherkin_ScenarioOutline) { const ScenarioOutline* scenario_outline = (const ScenarioOutline*)feature->scenario_definitions->scenario_definitions[i]; - if (scenario_outline->steps->step_count == 0) { - continue; - } int k; for (k = 0; k < scenario_outline->examples->example_count; ++k) { ExampleTable* example_table = &scenario_outline->examples->example_table[k]; if (!example_table->table_header) { continue; } - const PickleTags* tags = create_pickle_tags(feature->tags, scenario_outline->tags, example_table->tags); int l; for (l = 0; l < example_table->table_body->row_count; ++l) { const TableRow* table_row = &example_table->table_body->table_rows[l]; const PickleLocations* locations = PickleLocations_new_double(table_row->location.line, table_row->location.column, scenario_outline->location.line, scenario_outline->location.column); + const PickleTags* tags = create_pickle_tags(feature->tags, scenario_outline->tags, example_table->tags); PickleSteps* steps = (PickleSteps*)malloc(sizeof(PickleSteps)); - steps->step_count = scenario_outline->steps->step_count + + background_step_count; - steps->steps = (PickleStep*)malloc(steps->step_count * sizeof(PickleStep)); - if (background_steps) { - copy_steps(steps->steps, background_steps); - } - int j; - for (j = 0; j < scenario_outline->steps->step_count; ++j) { - int column_offset = scenario_outline->steps->steps[j].keyword ? wcslen(scenario_outline->steps->steps[j].keyword) : 0; - const PickleLocations* step_locations = PickleLocations_new_double(table_row->location.line, table_row->location.column, scenario_outline->steps->steps[j].location.line, scenario_outline->steps->steps[j].location.column + column_offset); - const PickleStep* step = expand_outline_step(&scenario_outline->steps->steps[j], example_table->table_header, table_row, step_locations); - PickleStep_transfer(&steps->steps[background_step_count + j], (PickleStep*)step); + if (scenario_outline->steps->step_count == 0) { + steps->step_count = 0; + steps->steps = 0; + } else { + steps->step_count = scenario_outline->steps->step_count + background_step_count; + steps->steps = (PickleStep*)malloc(steps->step_count * sizeof(PickleStep)); + if (background_steps) { + copy_steps(steps->steps, background_steps); + } + int j; + for (j = 0; j < scenario_outline->steps->step_count; ++j) { + int column_offset = scenario_outline->steps->steps[j].keyword ? StringUtilities_code_point_length(scenario_outline->steps->steps[j].keyword) : 0; + const PickleLocations* step_locations = PickleLocations_new_double(table_row->location.line, table_row->location.column, scenario_outline->steps->steps[j].location.line, scenario_outline->steps->steps[j].location.column + column_offset); + const PickleStep* step = expand_outline_step(&scenario_outline->steps->steps[j], example_table->table_header, table_row, step_locations); + PickleStep_transfer(&steps->steps[background_step_count + j], (PickleStep*)step); + } } const wchar_t* new_name = create_expanded_text(scenario_outline->name, example_table->table_header, table_row); ItemQueue_add(compiler->pickle_list, (Item*)Pickle_new(feature->language, locations, tags, new_name, steps)); @@ -135,12 +140,19 @@ static const PickleArgument* create_pickle_argument(const StepArgument* step_arg else if (step_argument->type == Gherkin_DocString) { const DocString* doc_string = (DocString*)step_argument; if (!example_header) { - argument = (const PickleArgument*)PickleString_new(doc_string->content, doc_string->location.line, doc_string->location.column); + argument = (const PickleArgument*)PickleString_new(doc_string->content, doc_string->location.line, doc_string->location.column, doc_string->content_type); } else { const wchar_t* expanded_text = create_expanded_text(doc_string->content, example_header, body_row); - argument = (const PickleArgument*)PickleString_new(expanded_text, doc_string->location.line, doc_string->location.column); + const wchar_t* expanded_content_type = 0; + if(doc_string->content_type){ + expanded_content_type = create_expanded_text(doc_string->content_type, example_header, body_row); + } + argument = (const PickleArgument*)PickleString_new(expanded_text, doc_string->location.line, doc_string->location.column, expanded_content_type); free((void*)expanded_text); + if(expanded_content_type != 0){ + free((void*)expanded_content_type); + } } } } @@ -225,7 +237,7 @@ static void copy_tags(PickleTag* destination_array, const Tags* source) { static void copy_steps(PickleStep* destination_array, const Steps* source) { int i; for (i = 0; i < source->step_count; ++i) { - int column_offset = source->steps[i].keyword ? wcslen(source->steps[i].keyword) : 0; + int column_offset = source->steps[i].keyword ? StringUtilities_code_point_length(source->steps[i].keyword) : 0; const PickleLocations* step_locations = PickleLocations_new_single(source->steps[i].location.line, source->steps[i].location.column + column_offset); const PickleArgument* argument = create_pickle_argument(source->steps[i].argument, 0, 0); const PickleStep* step = PickleStep_new(step_locations, source->steps[i].text, argument); diff --git a/src/dialect.c b/src/dialect.c index 4bbda5b..49a9b5b 100644 --- a/src/dialect.c +++ b/src/dialect.c @@ -86,6 +86,49 @@ static const Dialect am_dialect = { &am_then_keywords, &am_when_keywords }; +static const wchar_t* const an_and_KEYWORDS[] = { L"* ", L"Y ", L"E " }; +static const Keywords an_and_keywords = { 3, an_and_KEYWORDS }; + +static const wchar_t* const an_background_KEYWORDS[] = { L"Antecedents" }; +static const Keywords an_background_keywords = { 1, an_background_KEYWORDS }; + +static const wchar_t* const an_but_KEYWORDS[] = { L"* ", L"Pero " }; +static const Keywords an_but_keywords = { 2, an_but_KEYWORDS }; + +static const wchar_t* const an_examples_KEYWORDS[] = { L"Eixemplos" }; +static const Keywords an_examples_keywords = { 1, an_examples_KEYWORDS }; + +static const wchar_t* const an_feature_KEYWORDS[] = { L"Caracteristica" }; +static const Keywords an_feature_keywords = { 1, an_feature_KEYWORDS }; + +static const wchar_t* const an_given_KEYWORDS[] = { L"* ", L"Dau ", L"Dada ", L"Daus ", L"Dadas " }; +static const Keywords an_given_keywords = { 5, an_given_KEYWORDS }; + +static const wchar_t* const an_scenario_KEYWORDS[] = { L"Caso" }; +static const Keywords an_scenario_keywords = { 1, an_scenario_KEYWORDS }; + +static const wchar_t* const an_scenarioOutline_KEYWORDS[] = { L"Esquema del caso" }; +static const Keywords an_scenarioOutline_keywords = { 1, an_scenarioOutline_KEYWORDS }; + +static const wchar_t* const an_then_KEYWORDS[] = { L"* ", L"Alavez ", L"Allora ", L"Antonces " }; +static const Keywords an_then_keywords = { 4, an_then_KEYWORDS }; + +static const wchar_t* const an_when_KEYWORDS[] = { L"* ", L"Cuan " }; +static const Keywords an_when_keywords = { 2, an_when_KEYWORDS }; + +static const Dialect an_dialect = { + L"an", + &an_and_keywords, + &an_background_keywords, + &an_but_keywords, + &an_examples_keywords, + &an_feature_keywords, + &an_given_keywords, + &an_scenario_keywords, + &an_scenarioOutline_keywords, + &an_then_keywords, + &an_when_keywords }; + static const wchar_t* const ar_and_KEYWORDS[] = { L"* ", L"و " }; static const Keywords ar_and_keywords = { 2, ar_and_KEYWORDS }; @@ -580,8 +623,8 @@ static const Keywords el_given_keywords = { 2, el_given_KEYWORDS }; static const wchar_t* const el_scenario_KEYWORDS[] = { L"Σενάριο" }; static const Keywords el_scenario_keywords = { 1, el_scenario_KEYWORDS }; -static const wchar_t* const el_scenarioOutline_KEYWORDS[] = { L"Περιγραφή Σεναρίου" }; -static const Keywords el_scenarioOutline_keywords = { 1, el_scenarioOutline_KEYWORDS }; +static const wchar_t* const el_scenarioOutline_KEYWORDS[] = { L"Περιγραφή Σεναρίου", L"Περίγραμμα Σεναρίου" }; +static const Keywords el_scenarioOutline_keywords = { 2, el_scenarioOutline_KEYWORDS }; static const wchar_t* const el_then_KEYWORDS[] = { L"* ", L"Τότε " }; static const Keywords el_then_keywords = { 2, el_then_KEYWORDS }; @@ -2337,8 +2380,8 @@ static const Keywords ro_examples_keywords = { 1, ro_examples_KEYWORDS }; static const wchar_t* const ro_feature_KEYWORDS[] = { L"Functionalitate", L"Funcționalitate", L"Funcţionalitate" }; static const Keywords ro_feature_keywords = { 3, ro_feature_KEYWORDS }; -static const wchar_t* const ro_given_KEYWORDS[] = { L"* ", L"Date fiind ", L"Dat fiind ", L"Dati fiind ", L"Dați fiind ", L"Daţi fiind " }; -static const Keywords ro_given_keywords = { 6, ro_given_KEYWORDS }; +static const wchar_t* const ro_given_KEYWORDS[] = { L"* ", L"Date fiind ", L"Dat fiind ", L"Dată fiind", L"Dati fiind ", L"Dați fiind ", L"Daţi fiind " }; +static const Keywords ro_given_keywords = { 7, ro_given_KEYWORDS }; static const wchar_t* const ro_scenario_KEYWORDS[] = { L"Scenariu" }; static const Keywords ro_scenario_keywords = { 1, ro_scenario_KEYWORDS }; @@ -2371,8 +2414,8 @@ static const Keywords ru_and_keywords = { 4, ru_and_KEYWORDS }; static const wchar_t* const ru_background_KEYWORDS[] = { L"Предыстория", L"Контекст" }; static const Keywords ru_background_keywords = { 2, ru_background_KEYWORDS }; -static const wchar_t* const ru_but_KEYWORDS[] = { L"* ", L"Но ", L"А " }; -static const Keywords ru_but_keywords = { 3, ru_but_KEYWORDS }; +static const wchar_t* const ru_but_KEYWORDS[] = { L"* ", L"Но ", L"А ", L"Иначе " }; +static const Keywords ru_but_keywords = { 4, ru_but_KEYWORDS }; static const wchar_t* const ru_examples_KEYWORDS[] = { L"Примеры" }; static const Keywords ru_examples_keywords = { 1, ru_examples_KEYWORDS }; @@ -3144,6 +3187,8 @@ const Dialect* Dialect_for(const wchar_t* language) { return &af_dialect; if (wcscmp(am_dialect.language_name, language) == 0) return &am_dialect; + if (wcscmp(an_dialect.language_name, language) == 0) + return &an_dialect; if (wcscmp(ar_dialect.language_name, language) == 0) return &ar_dialect; if (wcscmp(ast_dialect.language_name, language) == 0) diff --git a/src/error_list.c b/src/error_list.c index 92badb4..52438f9 100644 --- a/src/error_list.c +++ b/src/error_list.c @@ -2,15 +2,24 @@ #include "error.h" #include "item_queue.h" #include "token.h" +#include #include #include -typedef struct ErrorList { +struct ErrorList { ItemQueue* errors; QueueItem* current_error; jmp_buf* global_env; jmp_buf* local_env; -} ErrorList; +}; + +static int calculate_string_length_for_location(int line_width, int column_width); + +static int print_location_to_string(wchar_t* string, int pos, int line, int line_width, int column, int column_width); + +static int calculate_string_length_for_number(int number); + +static int print_number_to_string(wchar_t* string, int pos, int number, int number_width); ErrorList* ErrorList_new() { ErrorList* error_list = (ErrorList*)malloc(sizeof(ErrorList)); @@ -63,60 +72,87 @@ void ErrorList_add(ErrorList* error_list, const wchar_t* error_text, const Locat } void ErrorList_add_unexpected_eof_error(ErrorList* error_list, Token* received_token, const wchar_t* expected_tokens) { - const wchar_t* const message = L"unexpected end of file, expected: %ls"; - const int location_text_width = 11; // enough space for "(xxx:yyy): " to fit - const int message_length = wcslen(message) - 3 + wcslen(expected_tokens); - wchar_t* text = (wchar_t*)malloc((location_text_width + message_length + 1) * sizeof(wchar_t*)); - int actual_location_width = swprintf(text, location_text_width + message_length + 1, L"(%d:%d): ", received_token->location.line, received_token->location.column); - if (actual_location_width > location_text_width) { - text = (wchar_t*)realloc(text, (actual_location_width + message_length + 1) * sizeof(wchar_t*)); - } - swprintf(text + actual_location_width, message_length + 1, message, expected_tokens); + const wchar_t* const message = L"unexpected end of file, expected: "; + const int message_length = wcslen(message); + const int line_width = calculate_string_length_for_number(received_token->location.line); + const int column_width = calculate_string_length_for_number(received_token->location.column); + const int total_length = calculate_string_length_for_location(line_width, column_width) + message_length + wcslen(expected_tokens); + wchar_t* text = (wchar_t*)malloc((total_length + 1) * sizeof(wchar_t*)); + int pos = 0; + pos = print_location_to_string(text, pos, received_token->location.line, line_width, received_token->location.column, column_width); + wcscpy(text + pos, message); + pos += message_length; + wcscpy(text + pos, expected_tokens); + text[total_length] = L'\0'; ErrorList_add(error_list, text, received_token->location); } void ErrorList_add_unexpected_token_error(ErrorList* error_list, Token* received_token, const wchar_t* expected_tokens) { - const wchar_t* const message = L"expected: %ls, got '%ls'"; - const int location_text_width = 11; // enough space for "(xxx:yyy): " to fit - const int message_length = wcslen(message) - 6 + wcslen(expected_tokens) + wcslen(received_token->line->trimmed_line); - wchar_t* text = (wchar_t*)malloc((location_text_width + message_length + 1) * sizeof(wchar_t*)); + const wchar_t* const expected = L"expected: "; + const int expected_length = wcslen(expected); + const wchar_t* const got = L", got "; + const int got_length = wcslen(got); + const int expected_tokens_length = wcslen(expected_tokens); + const int received_tokens_length = wcslen(received_token->line->trimmed_line); + const int line_width = calculate_string_length_for_number(received_token->location.line); + const int column_width = calculate_string_length_for_number(received_token->location.column); + const int total_length = calculate_string_length_for_location(line_width, column_width) + expected_length + expected_tokens_length + got_length + received_tokens_length + 2; + wchar_t* text = (wchar_t*)malloc((total_length + 1) * sizeof(wchar_t*)); int column = received_token->location.column; if (column == 0) { column = received_token->line->indent + 1; } - int actual_location_width = swprintf(text, location_text_width + message_length + 1, L"(%d:%d): ", received_token->location.line, column); - if (actual_location_width > location_text_width) { - text = (wchar_t*)realloc(text, (actual_location_width + message_length + 1) * sizeof(wchar_t*)); - } - swprintf(text + actual_location_width, message_length + 1, message, expected_tokens, received_token->line->trimmed_line); + int pos = 0; + pos = print_location_to_string(text, pos, received_token->location.line, line_width, column, column_width); + wcscpy(text + pos, expected); + pos += expected_length; + wcscpy(text + pos, expected_tokens); + pos += expected_tokens_length; + wcscpy(text + pos, got); + pos += got_length; + text[pos++] = L'\''; + wcscpy(text + pos, received_token->line->trimmed_line); + pos += received_tokens_length; + text[pos++] = L'\''; + text[total_length] = L'\0'; Location location = {received_token->location.line, column}; ErrorList_add(error_list, text, location); } void ErrorList_add_no_such_language_error(ErrorList* error_list, Location* location, const wchar_t* language) { - const wchar_t* const message = L"Language not supported: %ls"; - const int location_text_width = 11; // enough space for "(xxx:yyy): " to fit - const int message_length = wcslen(message) - 3 + wcslen(language); - wchar_t* text = (wchar_t*)malloc((location_text_width + message_length + 1) * sizeof(wchar_t*)); - int actual_location_width = swprintf(text, location_text_width + message_length + 1, L"(%d:%d): ", location->line, location->column); - if (actual_location_width > location_text_width) { - text = (wchar_t*)realloc(text, (actual_location_width + message_length + 1) * sizeof(wchar_t*)); + const wchar_t* const message = L"Language not supported: "; + const int message_length = wcslen(message); + const int language_length = wcslen(language); + Location used_location = {-1, -1}; + if (location) { + used_location.line = location->line; + used_location.column = location->column; } - swprintf(text + actual_location_width, message_length + 1, message, language); - ErrorList_add(error_list, text, *location); + const int line_width = calculate_string_length_for_number(used_location.line); + const int column_width = calculate_string_length_for_number(used_location.column); + const int total_length = calculate_string_length_for_location(line_width, column_width) + message_length + language_length; + wchar_t* text = (wchar_t*)malloc((total_length + 1) * sizeof(wchar_t*)); + int pos = 0; + pos = print_location_to_string(text, pos, used_location.line, line_width, used_location.column, column_width); + wcscpy(text + pos, message); + pos += message_length; + wcscpy(text + pos, language); + text[total_length] = L'\0'; + ErrorList_add(error_list, text, used_location); ErrorList_jump_to_local_rescue_env(error_list); } void ErrorList_add_inconsisten_cell_count_error(ErrorList* error_list, Location location) { const wchar_t* const message = L"inconsistent cell count within the table"; - const int location_text_width = 11; // enough space for "(xxx:yyy): " to fit const int message_length = wcslen(message); - wchar_t* text = (wchar_t*)malloc((location_text_width + message_length + 1) * sizeof(wchar_t*)); - int actual_location_width = swprintf(text, location_text_width + message_length + 1, L"(%d:%d): ", location.line, location.column); - if (actual_location_width > location_text_width) { - text = (wchar_t*)realloc(text, (actual_location_width + message_length + 1) * sizeof(wchar_t*)); - } - wcscpy(text + actual_location_width, message); + const int line_width = calculate_string_length_for_number(location.line); + const int column_width = calculate_string_length_for_number(location.column); + const int total_length = calculate_string_length_for_location(line_width, column_width) + message_length; + wchar_t* text = (wchar_t*)malloc((total_length + 1) * sizeof(wchar_t*)); + int pos = 0; + pos = print_location_to_string(text, pos, location.line, line_width, location.column, column_width); + wcscpy(text + pos, message); + text[total_length] = L'\0'; ErrorList_add(error_list, text, location); ErrorList_jump_to_local_rescue_env(error_list); } @@ -132,10 +168,16 @@ void ErrorList_internal_grammar_error(ErrorList* error_list) { } void ErrorList_add_invalid_operation_error(ErrorList* error_list, int state) { - const wchar_t* const message = L"Unknown state: %d"; - const int message_length = wcslen(message) + 10; // some extra space for the state number - wchar_t* text = (wchar_t*)malloc((message_length + 1) * sizeof(wchar_t*)); - swprintf(text, message_length + 1, message, state); + const wchar_t* const message = L"Unknown state: "; + const int message_length = wcslen(message); + const int state_width = calculate_string_length_for_number(state); + const int total_length = message_length + state_width; + wchar_t* text = (wchar_t*)malloc((total_length + 1) * sizeof(wchar_t*)); + int pos = 0; + wcscpy(text + pos, message); + pos += message_length; + print_number_to_string(text, pos, state, state_width); + text[total_length] = L'\0'; Location location = {-1, -1}; ErrorList_add(error_list, text, location); } @@ -150,3 +192,36 @@ Error* ErrorList_next_error(ErrorList* error_list) { } return ErrorList_remove(error_list); } + +int calculate_string_length_for_location(int line_width, int column_width) { + return line_width + column_width + 5; /* "(:= 0; --i) { + string[pos + i] = L'0' + ((number / divisor) % 10); + divisor *= 10; + } + return pos + number_width; +} diff --git a/src/file_reader.c b/src/file_reader.c index aafbbf4..9241618 100644 --- a/src/file_reader.c +++ b/src/file_reader.c @@ -1,10 +1,13 @@ #include "file_reader.h" -#include "file_utilities.h" +#include "file_utf8_source.h" +#include "unicode_utilities.h" #include -typedef struct FileReader { +struct FileReader { const char* file_name; -} FileReader; +}; + +static void extend_buffer_if_needed(wchar_t** buffer, int* buffer_size, int pos); FileReader* FileReader_new(const char* const file_name) { FileReader* file_reader = (FileReader*)malloc(sizeof(FileReader)); @@ -16,19 +19,32 @@ const wchar_t* FileReader_read(FileReader* file_reader) { int buffer_size = 256; wchar_t* buffer = (wchar_t*)malloc(buffer_size * sizeof(wchar_t)); int pos = 0; - wchar_t c; - FILE* file = fopen(file_reader->file_name, "r"); + long code_point; + FILE* file = fopen(file_reader->file_name, "rb"); + + if(file == NULL) { + swprintf(buffer, sizeof(wchar_t), L"%c", ' '); + return buffer; + } + + Utf8Source* utf8_source = FileUtf8Source_new(file); do { - c = FileUtilities_read_wchar_from_file(file); - if (c != WEOF) { - buffer[pos++] = c; - if (pos >= buffer_size - 1) { - buffer_size *= 2; - buffer = (wchar_t*)realloc(buffer, buffer_size * sizeof(wchar_t)); + code_point = UnicodeUtilities_read_code_point_from_utf8_source(utf8_source); + if (code_point != WEOF) { + if (code_point <= 0xFFFF || sizeof(wchar_t) > 2) { + buffer[pos++] = (wchar_t)code_point; + extend_buffer_if_needed(&buffer, &buffer_size, pos); + } else { + Utf16Surrogates surrogates = UnicodeUtilities_get_utf16_surrogates(code_point); + buffer[pos++] = surrogates.leading; + extend_buffer_if_needed(&buffer, &buffer_size, pos); + buffer[pos++] = surrogates.trailing; + extend_buffer_if_needed(&buffer, &buffer_size, pos); } } - } while (c != WEOF); + } while (code_point != WEOF); buffer[pos] = L'\0'; + Utf8Source_delete(utf8_source); fclose(file); return buffer; } @@ -39,3 +55,10 @@ void FileReader_delete(FileReader* file_reader) { } free((void*)file_reader); } + +static void extend_buffer_if_needed(wchar_t** buffer, int* buffer_size, int pos) { + if (pos >= *buffer_size - 1) { + *buffer_size *= 2; + *buffer = (wchar_t*)realloc(*buffer, *buffer_size * sizeof(wchar_t)); + } +} diff --git a/src/file_token_scanner.c b/src/file_token_scanner.c index 4c636f1..d0648c4 100644 --- a/src/file_token_scanner.c +++ b/src/file_token_scanner.c @@ -1,19 +1,23 @@ #include "file_token_scanner.h" +#include "file_utf8_source.h" #include "gherkin_line.h" -#include "file_utilities.h" #include "string_utilities.h" +#include "unicode_utilities.h" #include typedef struct FileTokenScanner { TokenScanner token_scanner; int line; FILE* file; + Utf8Source* utf8_source; int buffer_size; wchar_t* buffer; } FileTokenScanner; static Token* FileTokenScanner_read(TokenScanner* token_scanner); +static void extend_buffer_if_needed(FileTokenScanner* token_scanner, int pos); + static void FileTokenScanner_delete(TokenScanner* token_scanner); TokenScanner* FileTokenScanner_new(const char* const file_name) { @@ -22,7 +26,8 @@ TokenScanner* FileTokenScanner_new(const char* const file_name) { token_scanner->token_scanner.delete = &FileTokenScanner_delete; token_scanner->line = 0; token_scanner->file = 0; - token_scanner->file = fopen(file_name, "r"); + token_scanner->file = fopen(file_name, "rb"); + token_scanner->utf8_source = FileUtf8Source_new(token_scanner->file); token_scanner->buffer_size = 128; token_scanner->buffer = (wchar_t*)malloc(token_scanner->buffer_size * sizeof(wchar_t)); return (TokenScanner*) token_scanner; @@ -35,6 +40,7 @@ static void FileTokenScanner_delete(TokenScanner* token_scanner) { FileTokenScanner* file_token_scanner = (FileTokenScanner*)token_scanner; if (file_token_scanner->file) fclose(file_token_scanner->file); + Utf8Source_delete(file_token_scanner->utf8_source); free((void*)file_token_scanner->buffer); free((void*)file_token_scanner); } @@ -47,18 +53,23 @@ static Token* FileTokenScanner_read(TokenScanner* token_scanner) { if (feof(file_token_scanner->file)) return Token_new(0, file_token_scanner->line); int pos = 0; - wchar_t c; + long code_point; do { - c = FileUtilities_read_wchar_from_file(file_token_scanner->file); - if (c != WEOF && c != L'\r' && c != L'\n') { - file_token_scanner->buffer[pos++] = c; - if (pos >= file_token_scanner->buffer_size - 1) { - file_token_scanner->buffer_size *= 2; - file_token_scanner->buffer = (wchar_t*)realloc(file_token_scanner->buffer, file_token_scanner->buffer_size * sizeof(wchar_t)); + code_point = UnicodeUtilities_read_code_point_from_utf8_source(file_token_scanner->utf8_source); + if (code_point != WEOF && code_point != L'\r' && code_point != L'\n') { + if (code_point <= 0xFFFF || sizeof(wchar_t) > 2) { + file_token_scanner->buffer[pos++] = (wchar_t)code_point; + extend_buffer_if_needed(file_token_scanner, pos); + } else { + Utf16Surrogates surrogates = UnicodeUtilities_get_utf16_surrogates(code_point); + file_token_scanner->buffer[pos++] = surrogates.leading; + extend_buffer_if_needed(file_token_scanner, pos); + file_token_scanner->buffer[pos++] = surrogates.trailing; + extend_buffer_if_needed(file_token_scanner, pos); } } - } while (c != WEOF && c != L'\r' && c != L'\n'); - if (c == L'\r') { + } while (code_point != WEOF && code_point != L'\r' && code_point != L'\n'); + if (code_point == L'\r') { unsigned char next_char = fgetc(file_token_scanner->file); if (next_char != L'\n') { ungetc(next_char, file_token_scanner->file); @@ -66,7 +77,7 @@ static Token* FileTokenScanner_read(TokenScanner* token_scanner) { } file_token_scanner->buffer[pos] = L'\0'; const GherkinLine* line; - if (c != WEOF || pos != 0) { + if (code_point != WEOF || pos != 0) { wchar_t* text = StringUtilities_copy_string_part(file_token_scanner->buffer, pos); line = GherkinLine_new(text, file_token_scanner->line); } @@ -74,3 +85,10 @@ static Token* FileTokenScanner_read(TokenScanner* token_scanner) { line = (GherkinLine*)0; return Token_new(line, file_token_scanner->line); } + +static void extend_buffer_if_needed(FileTokenScanner* file_token_scanner, int pos){ + if (pos >= file_token_scanner->buffer_size - 1) { + file_token_scanner->buffer_size *= 2; + file_token_scanner->buffer = (wchar_t*)realloc(file_token_scanner->buffer, file_token_scanner->buffer_size * sizeof(wchar_t)); + } +} diff --git a/src/file_utf8_source.c b/src/file_utf8_source.c new file mode 100644 index 0000000..19a2003 --- /dev/null +++ b/src/file_utf8_source.c @@ -0,0 +1,30 @@ +#include "file_utf8_source.h" +#include + +typedef struct FileUtf8Source { + Utf8Source utf8_source; + FILE* file; +} FileUtf8Source; + +static void FileUtf8Source_delete(Utf8Source* utf8_source); + +static unsigned char FileUtf8Source_read(Utf8Source* utf8_source); + +Utf8Source* FileUtf8Source_new(FILE* file) { + FileUtf8Source* file_utf8_source = (FileUtf8Source*)malloc(sizeof(FileUtf8Source)); + file_utf8_source->utf8_source.read = &FileUtf8Source_read; + file_utf8_source->utf8_source.delete = &FileUtf8Source_delete; + file_utf8_source->file = file; + return (Utf8Source*)file_utf8_source; +} + +void FileUtf8Source_delete(Utf8Source* utf8_source) { + if (!utf8_source) { + return; + } + free((void*)utf8_source); +} + +unsigned char FileUtf8Source_read(Utf8Source* utf8_source) { + return fgetc(((FileUtf8Source*)utf8_source)->file); +} diff --git a/src/file_utf8_source.h b/src/file_utf8_source.h new file mode 100644 index 0000000..22bc1ee --- /dev/null +++ b/src/file_utf8_source.h @@ -0,0 +1,18 @@ +#ifndef GHERKIN_FILE_UTF8_SOURCE_H_ +#define GHERKIN_FILE_UTF8_SOURCE_H_ + +#include + +#include "utf8_source.h" + +#ifdef __cplusplus +extern "C" { +#endif + +Utf8Source* FileUtf8Source_new(FILE* file); + +#ifdef __cplusplus +} +#endif + +#endif /* GHERKIN_FILE_UTF8_SOURCE_H_ */ diff --git a/src/file_utilities.c b/src/file_utilities.c deleted file mode 100644 index afe0a82..0000000 --- a/src/file_utilities.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "file_utilities.h" - -wchar_t FileUtilities_read_wchar_from_file(FILE* file) { - unsigned char c = fgetc(file); - if (c < 0x80) { - return (wchar_t)c; - } - unsigned char c2 = fgetc(file); - wchar_t lower_part = (wchar_t)(c2 & 0x3F); - if ((c & 0xE0) == 0xC0) { - return (((wchar_t)(c & 0x1F)) << 6) | lower_part; - } - c2 = fgetc(file); - lower_part = (lower_part << 6) | (wchar_t)(c2 & 0x3F); - if ((c & 0xF0) == 0xE0) { - return (((wchar_t)(c & 0x0F)) << 12) | lower_part; - } - c2 = fgetc(file); - lower_part = (lower_part << 6) | (wchar_t)(c2 & 0x3F); - if ((c & 0xF8) == 0xF0) { - return (((wchar_t)(c & 0x07)) << 18) | lower_part; - } - c2 = fgetc(file); - lower_part = (lower_part << 6) | (wchar_t)(c2 & 0x3F); - if ((c & 0xFC) == 0xF8) { - return (((wchar_t)(c & 0x03)) << 24) | lower_part; - } - c2 = fgetc(file); - lower_part = (lower_part << 6) | (wchar_t)(c2 & 0x3F); - if ((c & 0xFE) == 0xFC) { - return (((wchar_t)(c & 0x01)) << 30) | lower_part; - } - return WEOF; -} diff --git a/src/file_utilities.h b/src/file_utilities.h deleted file mode 100644 index 2a74691..0000000 --- a/src/file_utilities.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef GHERKIN_FILE_UTILITIES_H_ -#define GHERKIN_FILE_UTILITIES_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -wchar_t FileUtilities_read_wchar_from_file(FILE* file); - -#ifdef __cplusplus -} -#endif - -#endif /* GHERKIN_FILE_UTILITIES_H_ */ diff --git a/src/gherkin_cli.c b/src/gherkin_cli.c index cd210cb..53fa733 100644 --- a/src/gherkin_cli.c +++ b/src/gherkin_cli.c @@ -7,7 +7,6 @@ #include "file_reader.h" #include "string_token_scanner.h" -//#include "file_token_scanner.h" #include "token_matcher.h" #include "parser.h" #include "ast_builder.h" @@ -75,7 +74,6 @@ int main(int argc, char** argv) { Event_print((const Event*)source_event, stdout); } TokenScanner* token_scanner = StringTokenScanner_new(source_event->source); - //TokenScanner* token_scanner = FileTokenScanner_new(argv[i]); result_code = Parser_parse(parser, token_matcher, token_scanner); Event_delete((const Event*)source_event); if (result_code == 0) { diff --git a/src/gherkin_document_event.c b/src/gherkin_document_event.c index 204d5db..6f39611 100644 --- a/src/gherkin_document_event.c +++ b/src/gherkin_document_event.c @@ -1,5 +1,7 @@ #include "gherkin_document_event.h" #include "ast_printer.h" +#include "print_utilities.h" +#include "string_utilities.h" #include #include @@ -14,10 +16,7 @@ const GherkinDocumentEvent* GherkinDocumentEvent_new(const char* uri, const Gher gherkin_document_event->event.event_type = Gherkin_GherkinDocumentEvent; gherkin_document_event->uri = 0; if (uri) { - int uri_length = strlen(uri); - gherkin_document_event->uri = (wchar_t*)malloc((uri_length + 1) * sizeof(wchar_t)); - swprintf(gherkin_document_event->uri, uri_length + 1, L"%hs", uri); - gherkin_document_event->uri[uri_length] = L'\0'; + gherkin_document_event->uri = StringUtilities_copy_to_wide_string(uri); } gherkin_document_event->gherkin_document = gherkin_document; return gherkin_document_event; @@ -44,8 +43,9 @@ static void GherkinDocumentEvent_print(const Event* event, FILE* file) { const GherkinDocumentEvent* gherkin_document_event = (const GherkinDocumentEvent*)event; fprintf(file, "{"); fprintf(file, "\"type\":\"gherkin-document\","); - fprintf(file, "\"uri\":\"%ls\",", gherkin_document_event->uri); - fprintf(file, "\"document\":"); + fprintf(file, "\"uri\":\""); + PrintUtilities_print_json_string(file, gherkin_document_event->uri); + fprintf(file, "\",\"document\":"); AstPrinter_print_gherkin_document(file, gherkin_document_event->gherkin_document); fprintf(file, "}\n"); } diff --git a/src/gherkin_generate_tokens.c b/src/gherkin_generate_tokens.c index 3741653..d528219 100644 --- a/src/gherkin_generate_tokens.c +++ b/src/gherkin_generate_tokens.c @@ -1,8 +1,7 @@ #include #include #include "file_reader.h" -#include "string_token_scanner.h" -//#include "file_token_scanner.h" +#include "file_token_scanner.h" #include "token_matcher.h" #include "parser.h" #include "token_formatter_builder.h" @@ -11,16 +10,11 @@ int main(int argc, char** argv) { setlocale(LC_ALL, "en_US.UTF-8"); int i; for (i = 1; i < argc; ++i) { - FileReader* file_reader = FileReader_new(argv[i]); - const wchar_t* source = FileReader_read(file_reader); - FileReader_delete(file_reader); - TokenScanner* token_scanner = StringTokenScanner_new(source); - //TokenScanner* token_scanner = FileTokenScanner_new(argv[i]); + TokenScanner* token_scanner = FileTokenScanner_new(argv[i]); TokenMatcher* token_matcher = TokenMatcher_new(L"en"); Builder* builder = TokenFormatterBuilder_new(); Parser* parser = Parser_new(builder); Parser_parse(parser, token_matcher, token_scanner); - free((void*)source); Parser_delete(parser); TokenFormatterBuilder_delete(builder); TokenMatcher_delete(token_matcher); diff --git a/src/gherkin_line.c b/src/gherkin_line.c index 096cefa..f35d1c2 100644 --- a/src/gherkin_line.c +++ b/src/gherkin_line.c @@ -215,7 +215,7 @@ static const wchar_t* populate_cell_data(Span* item, const wchar_t* start_pos, i ++current_pos; while (end_text > current_pos && *(end_text - 1) == L' ') --end_text; - item->column = start_indent + (current_pos - start_pos) + 1; + item->column = start_indent + StringUtilities_code_point_length_for_part(start_pos, current_pos - start_pos) + 1; int text_length = end_text - current_pos; wchar_t* text = StringUtilities_copy_string_part(current_pos, text_length); const wchar_t* from = text; @@ -251,7 +251,7 @@ static const wchar_t* populate_tag_data(Span* item, const wchar_t* start_pos, in const wchar_t* end_text = end_pos; while (end_text > current_pos && *(end_text - 1) == L' ') --end_text; - item->column = start_indent + (current_pos - start_pos) + 1; + item->column = start_indent + StringUtilities_code_point_length_for_part(start_pos, current_pos - start_pos) + 1; int text_length = end_text - current_pos; if (text_length > 0) { item->text = StringUtilities_copy_string_part(current_pos, text_length); diff --git a/src/item_queue.h b/src/item_queue.h index 8d66592..e8e3711 100644 --- a/src/item_queue.h +++ b/src/item_queue.h @@ -10,10 +10,10 @@ extern "C" { typedef struct QueueItem QueueItem; -typedef struct QueueItem { +struct QueueItem { Item* item; QueueItem* next; -} QueueItem; +}; typedef struct ItemQueue { QueueItem* first; diff --git a/src/parser.c b/src/parser.c index c85c9c2..23f2daa 100644 --- a/src/parser.c +++ b/src/parser.c @@ -4,7 +4,6 @@ #include "token_scanner.h" #include "token_matcher.h" #include "token_queue.h" -#include "builder.h" #include "error_list.h" #include #include @@ -18,11 +17,11 @@ typedef struct ParserContext { ErrorList* errors; } ParserContext; -typedef struct Parser { +struct Parser { ParserContext* parser_context; Builder* builder; ErrorList* errors; -} Parser; +}; static Token* read_token(ParserContext* context); @@ -438,7 +437,7 @@ static int match_token_at_3(Token* token, ParserContext* context) { return 3; } -/* GherkinDocument:0>Feature:0>Feature_Header:3>Feature_Description:0>Description_Helper:1>Description:0>#Other:0 */ +/* GherkinDocument:0>Feature:0>Feature_Header:3>Description_Helper:1>Description:0>#Other:0 */ static int match_token_at_4(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Description); @@ -488,7 +487,7 @@ static int match_token_at_4(Token* token, ParserContext* context) { return 4; } - /* "State: 4 - GherkinDocument:0>Feature:0>Feature_Header:3>Feature_Description:0>Description_Helper:1>Description:0>#Other:0" */ + /* "State: 4 - GherkinDocument:0>Feature:0>Feature_Header:3>Description_Helper:1>Description:0>#Other:0" */ const wchar_t* const expected_tokens = L"#EOF, #Comment, #BackgroundLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Other"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -498,7 +497,7 @@ static int match_token_at_4(Token* token, ParserContext* context) { return 4; } -/* GherkinDocument:0>Feature:0>Feature_Header:3>Feature_Description:0>Description_Helper:2>#Comment:0 */ +/* GherkinDocument:0>Feature:0>Feature_Header:3>Description_Helper:2>#Comment:0 */ static int match_token_at_5(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Feature_Header); @@ -542,7 +541,7 @@ static int match_token_at_5(Token* token, ParserContext* context) { return 5; } - /* "State: 5 - GherkinDocument:0>Feature:0>Feature_Header:3>Feature_Description:0>Description_Helper:2>#Comment:0" */ + /* "State: 5 - GherkinDocument:0>Feature:0>Feature_Header:3>Description_Helper:2>#Comment:0" */ const wchar_t* const expected_tokens = L"#EOF, #Comment, #BackgroundLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -610,7 +609,7 @@ static int match_token_at_6(Token* token, ParserContext* context) { return 6; } -/* GherkinDocument:0>Feature:1>Background:1>Background_Description:0>Description_Helper:1>Description:0>#Other:0 */ +/* GherkinDocument:0>Feature:1>Background:1>Description_Helper:1>Description:0>#Other:0 */ static int match_token_at_7(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Description); @@ -659,7 +658,7 @@ static int match_token_at_7(Token* token, ParserContext* context) { return 7; } - /* "State: 7 - GherkinDocument:0>Feature:1>Background:1>Background_Description:0>Description_Helper:1>Description:0>#Other:0" */ + /* "State: 7 - GherkinDocument:0>Feature:1>Background:1>Description_Helper:1>Description:0>#Other:0" */ const wchar_t* const expected_tokens = L"#EOF, #Comment, #StepLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Other"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -669,7 +668,7 @@ static int match_token_at_7(Token* token, ParserContext* context) { return 7; } -/* GherkinDocument:0>Feature:1>Background:1>Background_Description:0>Description_Helper:2>#Comment:0 */ +/* GherkinDocument:0>Feature:1>Background:1>Description_Helper:2>#Comment:0 */ static int match_token_at_8(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Background); @@ -712,7 +711,7 @@ static int match_token_at_8(Token* token, ParserContext* context) { return 8; } - /* "State: 8 - GherkinDocument:0>Feature:1>Background:1>Background_Description:0>Description_Helper:2>#Comment:0" */ + /* "State: 8 - GherkinDocument:0>Feature:1>Background:1>Description_Helper:2>#Comment:0" */ const wchar_t* const expected_tokens = L"#EOF, #Comment, #StepLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -722,7 +721,7 @@ static int match_token_at_8(Token* token, ParserContext* context) { return 8; } -/* GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:0>#StepLine:0 */ +/* GherkinDocument:0>Feature:1>Background:2>Step:0>#StepLine:0 */ static int match_token_at_9(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Step); @@ -780,7 +779,7 @@ static int match_token_at_9(Token* token, ParserContext* context) { return 9; } - /* "State: 9 - GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:0>#StepLine:0" */ + /* "State: 9 - GherkinDocument:0>Feature:1>Background:2>Step:0>#StepLine:0" */ const wchar_t* const expected_tokens = L"#EOF, #TableRow, #DocStringSeparator, #StepLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Comment, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -790,7 +789,7 @@ static int match_token_at_9(Token* token, ParserContext* context) { return 9; } -/* GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0 */ +/* GherkinDocument:0>Feature:1>Background:2>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0 */ static int match_token_at_10(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_DataTable); @@ -847,7 +846,7 @@ static int match_token_at_10(Token* token, ParserContext* context) { return 10; } - /* "State: 10 - GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0" */ + /* "State: 10 - GherkinDocument:0>Feature:1>Background:2>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0" */ const wchar_t* const expected_tokens = L"#EOF, #TableRow, #StepLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Comment, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -956,7 +955,7 @@ static int match_token_at_12(Token* token, ParserContext* context) { return 12; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Scenario_Description:0>Description_Helper:1>Description:0>#Other:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Description_Helper:1>Description:0>#Other:0 */ static int match_token_at_13(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Description); @@ -1009,7 +1008,7 @@ static int match_token_at_13(Token* token, ParserContext* context) { return 13; } - /* "State: 13 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Scenario_Description:0>Description_Helper:1>Description:0>#Other:0" */ + /* "State: 13 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Description_Helper:1>Description:0>#Other:0" */ const wchar_t* const expected_tokens = L"#EOF, #Comment, #StepLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Other"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -1019,7 +1018,7 @@ static int match_token_at_13(Token* token, ParserContext* context) { return 13; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Scenario_Description:0>Description_Helper:2>#Comment:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Description_Helper:2>#Comment:0 */ static int match_token_at_14(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Scenario); @@ -1066,7 +1065,7 @@ static int match_token_at_14(Token* token, ParserContext* context) { return 14; } - /* "State: 14 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Scenario_Description:0>Description_Helper:2>#Comment:0" */ + /* "State: 14 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:1>Description_Helper:2>#Comment:0" */ const wchar_t* const expected_tokens = L"#EOF, #Comment, #StepLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -1076,7 +1075,7 @@ static int match_token_at_14(Token* token, ParserContext* context) { return 14; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:0>#StepLine:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Step:0>#StepLine:0 */ static int match_token_at_15(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Step); @@ -1138,7 +1137,7 @@ static int match_token_at_15(Token* token, ParserContext* context) { return 15; } - /* "State: 15 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:0>#StepLine:0" */ + /* "State: 15 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Step:0>#StepLine:0" */ const wchar_t* const expected_tokens = L"#EOF, #TableRow, #DocStringSeparator, #StepLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Comment, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -1148,7 +1147,7 @@ static int match_token_at_15(Token* token, ParserContext* context) { return 15; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0 */ static int match_token_at_16(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_DataTable); @@ -1209,7 +1208,7 @@ static int match_token_at_16(Token* token, ParserContext* context) { return 16; } - /* "State: 16 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0" */ + /* "State: 16 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0" */ const wchar_t* const expected_tokens = L"#EOF, #TableRow, #StepLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Comment, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -1295,7 +1294,7 @@ static int match_token_at_17(Token* token, ParserContext* context) { return 17; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>ScenarioOutline_Description:0>Description_Helper:1>Description:0>#Other:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>Description_Helper:1>Description:0>#Other:0 */ static int match_token_at_18(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Description); @@ -1364,7 +1363,7 @@ static int match_token_at_18(Token* token, ParserContext* context) { return 18; } - /* "State: 18 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>ScenarioOutline_Description:0>Description_Helper:1>Description:0>#Other:0" */ + /* "State: 18 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>Description_Helper:1>Description:0>#Other:0" */ const wchar_t* const expected_tokens = L"#EOF, #Comment, #StepLine, #TagLine, #ExamplesLine, #ScenarioLine, #ScenarioOutlineLine, #Other"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -1374,7 +1373,7 @@ static int match_token_at_18(Token* token, ParserContext* context) { return 18; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>ScenarioOutline_Description:0>Description_Helper:2>#Comment:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>Description_Helper:2>#Comment:0 */ static int match_token_at_19(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_ScenarioOutline); @@ -1435,7 +1434,7 @@ static int match_token_at_19(Token* token, ParserContext* context) { return 19; } - /* "State: 19 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>ScenarioOutline_Description:0>Description_Helper:2>#Comment:0" */ + /* "State: 19 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:1>Description_Helper:2>#Comment:0" */ const wchar_t* const expected_tokens = L"#EOF, #Comment, #StepLine, #TagLine, #ExamplesLine, #ScenarioLine, #ScenarioOutlineLine, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -1445,7 +1444,7 @@ static int match_token_at_19(Token* token, ParserContext* context) { return 19; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:0>#StepLine:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>Step:0>#StepLine:0 */ static int match_token_at_20(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Step); @@ -1523,7 +1522,7 @@ static int match_token_at_20(Token* token, ParserContext* context) { return 20; } - /* "State: 20 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:0>#StepLine:0" */ + /* "State: 20 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>Step:0>#StepLine:0" */ const wchar_t* const expected_tokens = L"#EOF, #TableRow, #DocStringSeparator, #StepLine, #TagLine, #ExamplesLine, #ScenarioLine, #ScenarioOutlineLine, #Comment, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -1533,7 +1532,7 @@ static int match_token_at_20(Token* token, ParserContext* context) { return 20; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0 */ static int match_token_at_21(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_DataTable); @@ -1612,7 +1611,7 @@ static int match_token_at_21(Token* token, ParserContext* context) { return 21; } - /* "State: 21 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0" */ + /* "State: 21 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>Step:1>Step_Arg:0>__alt1:0>DataTable:0>#TableRow:0" */ const wchar_t* const expected_tokens = L"#EOF, #TableRow, #StepLine, #TagLine, #ExamplesLine, #ScenarioLine, #ScenarioOutlineLine, #Comment, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -1741,7 +1740,7 @@ static int match_token_at_23(Token* token, ParserContext* context) { return 23; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Examples_Description:0>Description_Helper:1>Description:0>#Other:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Description_Helper:1>Description:0>#Other:0 */ static int match_token_at_24(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Description); @@ -1822,7 +1821,7 @@ static int match_token_at_24(Token* token, ParserContext* context) { return 24; } - /* "State: 24 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Examples_Description:0>Description_Helper:1>Description:0>#Other:0" */ + /* "State: 24 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Description_Helper:1>Description:0>#Other:0" */ const wchar_t* const expected_tokens = L"#EOF, #Comment, #TableRow, #TagLine, #ExamplesLine, #ScenarioLine, #ScenarioOutlineLine, #Other"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -1832,7 +1831,7 @@ static int match_token_at_24(Token* token, ParserContext* context) { return 24; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Examples_Description:0>Description_Helper:2>#Comment:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Description_Helper:2>#Comment:0 */ static int match_token_at_25(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_Examples); @@ -1905,7 +1904,7 @@ static int match_token_at_25(Token* token, ParserContext* context) { return 25; } - /* "State: 25 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Examples_Description:0>Description_Helper:2>#Comment:0" */ + /* "State: 25 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:3>Examples_Definition:1>Examples:1>Description_Helper:2>#Comment:0" */ const wchar_t* const expected_tokens = L"#EOF, #Comment, #TableRow, #TagLine, #ExamplesLine, #ScenarioLine, #ScenarioOutlineLine, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -2003,7 +2002,7 @@ static int match_token_at_26(Token* token, ParserContext* context) { return 26; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0 */ static int match_token_at_28(Token* token, ParserContext* context) { if (match_DocStringSeparator(context, token)) { build(context, token); @@ -2014,7 +2013,7 @@ static int match_token_at_28(Token* token, ParserContext* context) { return 28; } - /* "State: 28 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0" */ + /* "State: 28 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0" */ const wchar_t* const expected_tokens = L"#DocStringSeparator, #Other"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -2024,7 +2023,7 @@ static int match_token_at_28(Token* token, ParserContext* context) { return 28; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0 */ static int match_token_at_29(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_DocString); @@ -2099,7 +2098,7 @@ static int match_token_at_29(Token* token, ParserContext* context) { return 29; } - /* "State: 29 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>ScenarioOutline_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0" */ + /* "State: 29 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:1>ScenarioOutline:2>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0" */ const wchar_t* const expected_tokens = L"#EOF, #StepLine, #TagLine, #ExamplesLine, #ScenarioLine, #ScenarioOutlineLine, #Comment, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -2109,7 +2108,7 @@ static int match_token_at_29(Token* token, ParserContext* context) { return 29; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0 */ static int match_token_at_30(Token* token, ParserContext* context) { if (match_DocStringSeparator(context, token)) { build(context, token); @@ -2120,7 +2119,7 @@ static int match_token_at_30(Token* token, ParserContext* context) { return 30; } - /* "State: 30 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0" */ + /* "State: 30 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0" */ const wchar_t* const expected_tokens = L"#DocStringSeparator, #Other"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -2130,7 +2129,7 @@ static int match_token_at_30(Token* token, ParserContext* context) { return 30; } -/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0 */ +/* GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0 */ static int match_token_at_31(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_DocString); @@ -2187,7 +2186,7 @@ static int match_token_at_31(Token* token, ParserContext* context) { return 31; } - /* "State: 31 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0" */ + /* "State: 31 - GherkinDocument:0>Feature:2>Scenario_Definition:1>__alt0:0>Scenario:2>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0" */ const wchar_t* const expected_tokens = L"#EOF, #StepLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Comment, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -2197,7 +2196,7 @@ static int match_token_at_31(Token* token, ParserContext* context) { return 31; } -/* GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0 */ +/* GherkinDocument:0>Feature:1>Background:2>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0 */ static int match_token_at_32(Token* token, ParserContext* context) { if (match_DocStringSeparator(context, token)) { build(context, token); @@ -2208,7 +2207,7 @@ static int match_token_at_32(Token* token, ParserContext* context) { return 32; } - /* "State: 32 - GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0" */ + /* "State: 32 - GherkinDocument:0>Feature:1>Background:2>Step:1>Step_Arg:0>__alt1:1>DocString:0>#DocStringSeparator:0" */ const wchar_t* const expected_tokens = L"#DocStringSeparator, #Other"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); @@ -2218,7 +2217,7 @@ static int match_token_at_32(Token* token, ParserContext* context) { return 32; } -/* GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0 */ +/* GherkinDocument:0>Feature:1>Background:2>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0 */ static int match_token_at_33(Token* token, ParserContext* context) { if (match_EOF(context, token)) { end_rule(context, Rule_DocString); @@ -2271,7 +2270,7 @@ static int match_token_at_33(Token* token, ParserContext* context) { return 33; } - /* "State: 33 - GherkinDocument:0>Feature:1>Background:2>Scenario_Step:0>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0" */ + /* "State: 33 - GherkinDocument:0>Feature:1>Background:2>Step:1>Step_Arg:0>__alt1:1>DocString:2>#DocStringSeparator:0" */ const wchar_t* const expected_tokens = L"#EOF, #StepLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Comment, #Empty"; Token_is_eof(token) ? ErrorList_add_unexpected_eof_error(context->errors, token, expected_tokens) : ErrorList_add_unexpected_token_error(context->errors, token, expected_tokens); Token_delete(token); diff --git a/src/pickle_event.c b/src/pickle_event.c index 82dfe7b..bf21ceb 100644 --- a/src/pickle_event.c +++ b/src/pickle_event.c @@ -1,5 +1,7 @@ #include "pickle_event.h" #include "pickle_printer.h" +#include "print_utilities.h" +#include "string_utilities.h" #include #include @@ -14,10 +16,7 @@ const PickleEvent* PickleEvent_new(const char* uri, const Pickle* pickle) { pickle_event->event.event_type = Gherkin_PickleEvent; pickle_event->uri = 0; if (uri) { - int uri_length = strlen(uri); - pickle_event->uri = (wchar_t*)malloc((uri_length + 1) * sizeof(wchar_t)); - swprintf(pickle_event->uri, uri_length + 1, L"%hs", uri); - pickle_event->uri[uri_length] = L'\0'; + pickle_event->uri = StringUtilities_copy_to_wide_string(uri); } pickle_event->pickle = pickle; return pickle_event; @@ -45,8 +44,9 @@ static void PickleEvent_print(const Event* event, FILE* file) { if (pickle_event) { fprintf(file, "{"); fprintf(file, "\"type\":\"pickle\","); - fprintf(file, "\"uri\":\"%ls\",", pickle_event->uri); - fprintf(file, "\"pickle\":"); + fprintf(file, "\"uri\":\""); + PrintUtilities_print_json_string(file, pickle_event->uri); + fprintf(file, "\",\"pickle\":"); PicklePrinter_print_pickle(file, pickle_event->pickle); fprintf(file, "}\n"); } diff --git a/src/pickle_printer.c b/src/pickle_printer.c index 9cd1f43..9a247c5 100644 --- a/src/pickle_printer.c +++ b/src/pickle_printer.c @@ -64,13 +64,21 @@ static void print_pickle_string(FILE* file, const PickleString* pickle_string) { if (pickle_string->content) { PrintUtilities_print_json_string(file, pickle_string->content); } - fprintf(file, "\"}"); + fprintf(file, "\""); + if(pickle_string->content_type) { + fprintf(file, ",\"contentType\":\""); + PrintUtilities_print_json_string(file, pickle_string->content_type); + fprintf(file, "\""); + } + fprintf(file, "}"); } static void print_tag(FILE* file, const PickleTag* tag) { fprintf(file, "{\"location\":"); print_location(file, &tag->location); - fprintf(file, ",\"name\":\"%ls\"}", tag->name); + fprintf(file, ",\"name\":\""); + PrintUtilities_print_json_string(file, tag->name); + fprintf(file, "\"}"); } static void print_pickle_step(FILE* file, const PickleStep* step) { @@ -86,8 +94,9 @@ static void print_pickle_step(FILE* file, const PickleStep* step) { } } fprintf(file, "],"); - fprintf(file, "\"text\":\"%ls\"", step->text); - fprintf(file, "}"); + fprintf(file, "\"text\":\""); + PrintUtilities_print_json_string(file, step->text); + fprintf(file, "\"}"); } void PicklePrinter_print_pickle(FILE* file, const Pickle* pickle) { diff --git a/src/pickle_string.c b/src/pickle_string.c index e6504e3..6305a5d 100644 --- a/src/pickle_string.c +++ b/src/pickle_string.c @@ -2,7 +2,7 @@ #include "string_utilities.h" #include -const PickleString* PickleString_new(const wchar_t* content, int line, int column) { +const PickleString* PickleString_new(const wchar_t* content, int line, int column, const wchar_t* content_type) { PickleString* pickle_string = (PickleString*)malloc(sizeof(PickleString)); pickle_string->type = Argument_String; pickle_string->location.line = line; @@ -11,6 +11,10 @@ const PickleString* PickleString_new(const wchar_t* content, int line, int colum if (content) { pickle_string->content = StringUtilities_copy_string(content); } + pickle_string->content_type = 0; + if (content_type && wcslen(content_type) > 0) { + pickle_string->content_type = StringUtilities_copy_string(content_type); + } return pickle_string; } @@ -21,5 +25,8 @@ void PickleString_delete(const PickleString* pickle_string) { if (pickle_string->content) { free((void*)pickle_string->content); } + if (pickle_string->content_type) { + free((void*)pickle_string->content_type); + } free((void*)pickle_string); } diff --git a/src/print_utilities.c b/src/print_utilities.c index 0b4f218..18b6f84 100644 --- a/src/print_utilities.c +++ b/src/print_utilities.c @@ -1,22 +1,30 @@ #include "print_utilities.h" +#include "unicode_utilities.h" void PrintUtilities_print_json_string(FILE* file, const wchar_t* text) { int i; for (i = 0; i < wcslen(text); ++i) { if (text[i] == L'\\' || text[i] == L'"') { - fprintf(file, "%lc", (wint_t)L'\\'); - fprintf(file, "%lc", (wint_t)text[i]); + fputc((char)'\\', file); + fputc((char)text[i], file); } else if (text[i] == L'\n') { - fprintf(file, "%lc", (wint_t)L'\\'); - fprintf(file, "%lc", (wint_t)L'n'); + fputc((char)'\\', file); + fputc((char)'n', file); } else if (text[i] == L'\r') { - fprintf(file, "%lc", (wint_t)L'\\'); - fprintf(file, "%lc", (wint_t)L'r'); + fputc((char)'\\', file); + fputc((char)'r', file); } else { - fprintf(file, "%lc", (wint_t)text[i]); + i = UnicodeUtilities_print_wide_character_to_utf8_file(file, text, i); } } } + +void PrintUtilities_print_wide_string(FILE* file, const wchar_t* text) { + int i; + for (i = 0; i < wcslen(text); ++i) { + i = UnicodeUtilities_print_wide_character_to_utf8_file(file, text, i); + } +} diff --git a/src/print_utilities.h b/src/print_utilities.h index 91d25db..61bad1b 100644 --- a/src/print_utilities.h +++ b/src/print_utilities.h @@ -10,6 +10,8 @@ extern "C" { void PrintUtilities_print_json_string(FILE* file, const wchar_t* text); +void PrintUtilities_print_wide_string(FILE* file, const wchar_t* text); + #ifdef __cplusplus } #endif diff --git a/src/source_event.c b/src/source_event.c index f26fe7b..546e37f 100644 --- a/src/source_event.c +++ b/src/source_event.c @@ -1,5 +1,6 @@ #include "source_event.h" #include "print_utilities.h" +#include "string_utilities.h" #include #include @@ -14,10 +15,7 @@ SourceEvent* SourceEvent_new(const char* uri, const wchar_t* source) { source_event->event.event_type = Gherkin_SourceEvent; source_event->uri = 0; if (uri) { - int uri_length = strlen(uri); - source_event->uri = (wchar_t*)malloc((uri_length + 1) * sizeof(wchar_t)); - swprintf(source_event->uri, uri_length + 1, L"%hs", uri); - source_event->uri[uri_length] = L'\0'; + source_event->uri = StringUtilities_copy_to_wide_string(uri); } source_event->source = source; return source_event; @@ -44,9 +42,10 @@ static void SourceEvent_print(const Event* event, FILE* file) { const SourceEvent* source_event = (const SourceEvent*)event; fprintf(file, "{"); fprintf(file, "\"type\":\"source\","); - fprintf(file, "\"media\":{\"encoding\":\"utf-8\",\"type\":\"text/vnd.cucumber.gherkin+plain\"},"); - fprintf(file, "\"uri\":\"%ls\",", source_event->uri); - fprintf(file, "\"data\":\""); + fprintf(file, "\"media\":{\"encoding\":\"utf-8\",\"type\":\"text/x.cucumber.gherkin+plain\"},"); + fprintf(file, "\"uri\":\""); + PrintUtilities_print_json_string(file, source_event->uri); + fprintf(file, "\",\"data\":\""); PrintUtilities_print_json_string(file, source_event->source); fprintf(file, "\"}\n"); } diff --git a/src/string_utilities.c b/src/string_utilities.c index 926f8ee..db6a499 100644 --- a/src/string_utilities.c +++ b/src/string_utilities.c @@ -1,5 +1,21 @@ #include "string_utilities.h" +#include "unicode_utilities.h" +#include #include +#include + +typedef struct StringUtf8Source { + Utf8Source utf8_source; + int position; + int length; + const char* string; +} StringUtf8Source; + +static Utf8Source* StringUtf8Source_new(const char* string); + +static void StringUtf8Source_delete(Utf8Source* utf8_source); + +static unsigned char StringUtf8Source_read(Utf8Source* utf8_source); wchar_t* StringUtilities_copy_string(const wchar_t* string) { return StringUtilities_copy_string_part(string, wcslen(string)); @@ -11,3 +27,74 @@ wchar_t* StringUtilities_copy_string_part(const wchar_t* string, const int lengt copy[length] = L'\0'; return copy; } + +wchar_t* StringUtilities_copy_to_wide_string(const char* string) { + int length = strlen(string); + wchar_t* copy = (wchar_t*)malloc((length + 1) * sizeof(wchar_t)); + Utf8Source* utf8_source = StringUtf8Source_new(string); + int to_index = 0; + int i; + for (i = 0; i < length; ++i) { + long code_point = UnicodeUtilities_read_code_point_from_utf8_source(utf8_source); + if (code_point == WEOF) { + break; + } + if (code_point <= 0xFFFF || sizeof(wchar_t) > 2) { + copy[to_index++] = (wchar_t)code_point; + } else { + Utf16Surrogates surrogates = UnicodeUtilities_get_utf16_surrogates(code_point); + copy[to_index++] = surrogates.leading; + copy[to_index++] = surrogates.trailing; + } + } + copy[to_index] = L'\0'; + Utf8Source_delete(utf8_source); + return copy; +} + +size_t StringUtilities_code_point_length(const wchar_t* string) { + if (sizeof(wchar_t) > 2) { + return wcslen(string); + } else { + return StringUtilities_code_point_length_for_part(string, wcslen(string)); + } +} + +size_t StringUtilities_code_point_length_for_part(const wchar_t* string, const int length) { + int code_points = 0; + int i; + for (i = 0; i < length; ++i) { + ++code_points; + if (UnicodeUtilities_is_utf16_surrogate(string[i])) { + ++i; + } + + } + return code_points; +} + + +Utf8Source* StringUtf8Source_new(const char* string) { + StringUtf8Source* string_utf8_source = (StringUtf8Source*)malloc(sizeof(StringUtf8Source)); + string_utf8_source->utf8_source.read = &StringUtf8Source_read; + string_utf8_source->utf8_source.delete = &StringUtf8Source_delete; + string_utf8_source->position = 0; + string_utf8_source->length = strlen(string); + string_utf8_source->string = string; + return (Utf8Source*)string_utf8_source; +} + +void StringUtf8Source_delete(Utf8Source* utf8_source) { + if (!utf8_source) { + return; + } + free((void*)utf8_source); +} + +unsigned char StringUtf8Source_read(Utf8Source* utf8_source) { + StringUtf8Source* string_utf8_source = (StringUtf8Source*)utf8_source; + if (string_utf8_source->position < string_utf8_source->length) { + return string_utf8_source->string[string_utf8_source->position++]; + } + return EOF; +} diff --git a/src/string_utilities.h b/src/string_utilities.h index 2b78eb8..30472a5 100644 --- a/src/string_utilities.h +++ b/src/string_utilities.h @@ -11,6 +11,12 @@ wchar_t* StringUtilities_copy_string(const wchar_t* string); wchar_t* StringUtilities_copy_string_part(const wchar_t* string, const int length); +wchar_t* StringUtilities_copy_to_wide_string(const char* string); + +size_t StringUtilities_code_point_length(const wchar_t* string); + +size_t StringUtilities_code_point_length_for_part(const wchar_t* string, const int length); + #ifdef __cplusplus } #endif diff --git a/src/token_formatter_builder.c b/src/token_formatter_builder.c index 7324054..335e2cd 100644 --- a/src/token_formatter_builder.c +++ b/src/token_formatter_builder.c @@ -1,4 +1,5 @@ #include "token_formatter_builder.h" +#include "print_utilities.h" #include #include @@ -40,31 +41,41 @@ void TokenFormatterBuilder_build(Builder* builder, Token* token) { fprintf(((TokenFormatterBuilder*)builder)->file, "%s\n", token_type_to_string(token->matched_type)); else if (token->matched_type == Token_TableRow || token->matched_type == Token_TagLine) { fprintf(((TokenFormatterBuilder*)builder)->file, - "(%d:%d)%s:%ls/%ls/", + "(%d:%d)%s:", token->location.line, token->location.column, - token_type_to_string(token->matched_type), - token->matched_keyword ? token->matched_keyword : L"", - token->matched_text ? token->matched_text : L""); + token_type_to_string(token->matched_type)); + PrintUtilities_print_wide_string(((TokenFormatterBuilder*)builder)->file, + token->matched_keyword ? token->matched_keyword : L""); + fprintf(((TokenFormatterBuilder*)builder)->file, "/"); + PrintUtilities_print_wide_string(((TokenFormatterBuilder*)builder)->file, + token->matched_text ? token->matched_text : L""); + fprintf(((TokenFormatterBuilder*)builder)->file, "/"); int i; for (i = 0; i < token->matched_items->count; ++i) { if (i != 0) fprintf(((TokenFormatterBuilder*)builder)->file, ","); fprintf(((TokenFormatterBuilder*)builder)->file, - "%d:%ls", - token->matched_items->items[i].column, - token->matched_items->items[i].text); + "%d:", + token->matched_items->items[i].column); + PrintUtilities_print_wide_string(((TokenFormatterBuilder*)builder)->file, + token->matched_items->items[i].text); } fprintf(((TokenFormatterBuilder*)builder)->file, "\n"); } - else + else { fprintf(((TokenFormatterBuilder*)builder)->file, - "(%d:%d)%s:%ls/%ls/\n", + "(%d:%d)%s:", token->location.line, token->location.column, - token_type_to_string(token->matched_type), - token->matched_keyword ? token->matched_keyword : L"", - token->matched_text ? token->matched_text : L""); + token_type_to_string(token->matched_type)); + PrintUtilities_print_wide_string(((TokenFormatterBuilder*)builder)->file, + token->matched_keyword ? token->matched_keyword : L""); + fprintf(((TokenFormatterBuilder*)builder)->file, "/"); + PrintUtilities_print_wide_string(((TokenFormatterBuilder*)builder)->file, + token->matched_text ? token->matched_text : L""); + fprintf(((TokenFormatterBuilder*)builder)->file, "/\n"); + } Token_delete(token); } diff --git a/src/token_queue.c b/src/token_queue.c index d564a15..2677f84 100644 --- a/src/token_queue.c +++ b/src/token_queue.c @@ -2,8 +2,6 @@ #include "item_queue.h" #include -typedef struct QueueItem QueueItem; - TokenQueue* TokenQueue_new() { return (TokenQueue*)ItemQueue_new(); } diff --git a/src/token_queue.h b/src/token_queue.h index eaf1513..68a0cba 100644 --- a/src/token_queue.h +++ b/src/token_queue.h @@ -1,6 +1,7 @@ #ifndef GHERKIN_TOKEN_QUEUE_H_ #define GHERKIN_TOKEN_QUEUE_H_ +#include #include "token.h" #ifdef __cplusplus diff --git a/src/unicode_utilities.c b/src/unicode_utilities.c new file mode 100644 index 0000000..8e3575b --- /dev/null +++ b/src/unicode_utilities.c @@ -0,0 +1,100 @@ +#include "unicode_utilities.h" + +static void print_code_point_to_utf8_file(FILE* file, long code_point); + +long UnicodeUtilities_read_code_point_from_utf8_source(Utf8Source* utf8_source) { + unsigned char c = Utf8Source_read(utf8_source); + if (c < 0x80) { + return (long)c; + } + unsigned char c2 = Utf8Source_read(utf8_source); + long lower_part = (long)(c2 & 0x3F); + if ((c & 0xE0) == 0xC0) { + return (((long)(c & 0x1F)) << 6) | lower_part; + } + c2 = Utf8Source_read(utf8_source); + lower_part = (lower_part << 6) | (long)(c2 & 0x3F); + if ((c & 0xF0) == 0xE0) { + return (((long)(c & 0x0F)) << 12) | lower_part; + } + c2 = Utf8Source_read(utf8_source); + lower_part = (lower_part << 6) | (long)(c2 & 0x3F); + if ((c & 0xF8) == 0xF0) { + return (((long)(c & 0x07)) << 18) | lower_part; + } + c2 = Utf8Source_read(utf8_source); + lower_part = (lower_part << 6) | (long)(c2 & 0x3F); + if ((c & 0xFC) == 0xF8) { + return (((long)(c & 0x03)) << 24) | lower_part; + } + c2 = Utf8Source_read(utf8_source); + lower_part = (lower_part << 6) | (long)(c2 & 0x3F); + if ((c & 0xFE) == 0xFC) { + return (((long)(c & 0x01)) << 30) | lower_part; + } + return WEOF; +} + +Utf16Surrogates UnicodeUtilities_get_utf16_surrogates(long code_point){ + Utf16Surrogates surrogates; + long surrogates_base = code_point - 0x10000; + surrogates.leading = 0xD800 + (surrogates_base >> 10); + surrogates.trailing = 0xDC00 + (surrogates_base & 0x3FF); + return surrogates; +} + +int UnicodeUtilities_print_wide_character_to_utf8_file(FILE* file, const wchar_t* text, int pos) { + long code_point; + if (!UnicodeUtilities_is_utf16_surrogate(text[pos]) || sizeof(wchar_t) > 2) { + code_point = (long)text[pos]; + } else { + long leading_surrogate = (long)text[pos++]; + long trailing_surrogate = (long)text[pos]; + code_point = 0x10000 + ((leading_surrogate - 0xD800) << 10) + (trailing_surrogate - 0xDC00); + } + print_code_point_to_utf8_file(file, code_point); + return pos; +} + +bool UnicodeUtilities_is_utf16_surrogate(const wchar_t wide_char) { + return wide_char >= 0xD800 && wide_char < 0xE000; +} + +void print_code_point_to_utf8_file(FILE* file, long code_point) { + int trailing_bytes; + if (code_point < 0x80) { + fputc((char)code_point, file); + return; + } else if (code_point < 0x800) { + fputc((char)(0xC0 | ((code_point & 0x7C0) >> 6)), file); + trailing_bytes = 1; + } else if (code_point < 0x10000) { + fputc((char)(0xE0 | ((code_point & 0xF000) >> 12)), file); + trailing_bytes = 2; + } else if (code_point < 0x200000) { + fputc((char)(0xF0 | ((code_point & 0x1C0000) >> 18)), file); + trailing_bytes = 3; + } else if (code_point < 0x4000000) { + fputc((char)(0xF8 | ((code_point & 0x3000000) >> 24)), file); + trailing_bytes = 4; + } else { + fputc((char)(0xFC | ((code_point & 0x40000000) >> 30)), file); + trailing_bytes = 5; + } + switch (trailing_bytes) { + case 5: + fputc((char)(0x80 | ((code_point & 0x3F000000) >> 24)), file); + /* fall through */ + case 4: + fputc((char)(0x80 | ((code_point & 0xFC0000) >> 18)), file); + /* fall through */ + case 3: + fputc((char)(0x80 | ((code_point & 0x3F000) >> 12)), file); + /* fall through */ + case 2: + fputc((char)(0x80 | ((code_point & 0xFC0) >> 6)), file); + /* fall through */ + case 1: + fputc((char)(0x80 | (code_point & 0x3F)), file); + } +} diff --git a/src/unicode_utilities.h b/src/unicode_utilities.h new file mode 100644 index 0000000..006b695 --- /dev/null +++ b/src/unicode_utilities.h @@ -0,0 +1,31 @@ +#ifndef GHERKIN_UNICODE_UTILITIES_H_ +#define GHERKIN_UNICODE_UTILITIES_H_ + +#include +#include +#include + +#include "utf8_source.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Utf16Surrogates { + wchar_t leading; + wchar_t trailing; +} Utf16Surrogates; + +long UnicodeUtilities_read_code_point_from_utf8_source(Utf8Source* utf8_source); + +Utf16Surrogates UnicodeUtilities_get_utf16_surrogates(long code_point); + +int UnicodeUtilities_print_wide_character_to_utf8_file(FILE* file, const wchar_t* text, int pos); + +bool UnicodeUtilities_is_utf16_surrogate(const wchar_t wide_char); + +#ifdef __cplusplus +} +#endif + +#endif /* GHERKIN_UNICODE_UTILITIES_H_ */ diff --git a/src/utf8_source.c b/src/utf8_source.c new file mode 100644 index 0000000..fe216dc --- /dev/null +++ b/src/utf8_source.c @@ -0,0 +1,9 @@ +#include "utf8_source.h" + +unsigned char Utf8Source_read(Utf8Source* utf8_source) { + return utf8_source->read(utf8_source); +} + +void Utf8Source_delete(Utf8Source* utf8_source) { + utf8_source->delete(utf8_source); +} diff --git a/src/utf8_source.h b/src/utf8_source.h new file mode 100644 index 0000000..333871a --- /dev/null +++ b/src/utf8_source.h @@ -0,0 +1,31 @@ +#ifndef GHERKIN_UTF8_SOURCE_H_ +#define GHERKIN_UTF8_SOURCE_H_ + +#include + +#include "utf8_source.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Utf8Source Utf8Source; + +typedef unsigned char (*utf8_source_read_function) (Utf8Source*); + +typedef void (*utf8_source_delete_function) (Utf8Source*); + +struct Utf8Source { + utf8_source_read_function read; + utf8_source_delete_function delete; +}; + +unsigned char Utf8Source_read(Utf8Source* utf8_source); + +void Utf8Source_delete(Utf8Source* utf8_source); + +#ifdef __cplusplus +} +#endif + +#endif /* GHERKIN_UTF8_SOURCE_H_ */ diff --git a/testdata/bad/inconsistent_cell_count.feature b/testdata/bad/inconsistent_cell_count.feature new file mode 100644 index 0000000..721369c --- /dev/null +++ b/testdata/bad/inconsistent_cell_count.feature @@ -0,0 +1,14 @@ +Feature: Inconsistent cell counts + + Scenario: minimalistic + Given a data table with inconsistent cell count + | foo | bar | + | boz | + + + Scenario Outline: minimalistic + Given the + + Examples: + | what | + | minimalism | extra | diff --git a/testdata/bad/inconsistent_cell_count.feature.errors.ndjson b/testdata/bad/inconsistent_cell_count.feature.errors.ndjson new file mode 100644 index 0000000..aa1e2e3 --- /dev/null +++ b/testdata/bad/inconsistent_cell_count.feature.errors.ndjson @@ -0,0 +1,2 @@ +{"data":"(6:7): inconsistent cell count within the table","media":{"encoding":"utf-8","type":"text/x.cucumber.stacktrace+plain"},"source":{"start":{"column":7,"line":6},"uri":"testdata/bad/inconsistent_cell_count.feature"},"type":"attachment"} +{"data":"(14:5): inconsistent cell count within the table","media":{"encoding":"utf-8","type":"text/x.cucumber.stacktrace+plain"},"source":{"start":{"column":5,"line":14},"uri":"testdata/bad/inconsistent_cell_count.feature"},"type":"attachment"} diff --git a/testdata/bad/invalid_language.feature b/testdata/bad/invalid_language.feature new file mode 100644 index 0000000..6c8d892 --- /dev/null +++ b/testdata/bad/invalid_language.feature @@ -0,0 +1,6 @@ +#language:no-such + +Feature: Minimal + + Scenario: minimalistic + Given the minimalism diff --git a/testdata/bad/invalid_language.feature.errors.ndjson b/testdata/bad/invalid_language.feature.errors.ndjson new file mode 100644 index 0000000..29c89e3 --- /dev/null +++ b/testdata/bad/invalid_language.feature.errors.ndjson @@ -0,0 +1 @@ +{"data":"(1:1): Language not supported: no-such","media":{"encoding":"utf-8","type":"text/x.cucumber.stacktrace+plain"},"source":{"start":{"column":1,"line":1},"uri":"testdata/bad/invalid_language.feature"},"type":"attachment"} diff --git a/testdata/bad/multiple_parser_errors.feature b/testdata/bad/multiple_parser_errors.feature new file mode 100644 index 0000000..2d10f4f --- /dev/null +++ b/testdata/bad/multiple_parser_errors.feature @@ -0,0 +1,9 @@ + +invalid line here + +Feature: Multiple parser errors + + Scenario: minimalistic + Given the minimalism + +another invalid line here diff --git a/testdata/bad/multiple_parser_errors.feature.errors.ndjson b/testdata/bad/multiple_parser_errors.feature.errors.ndjson new file mode 100644 index 0000000..54b4804 --- /dev/null +++ b/testdata/bad/multiple_parser_errors.feature.errors.ndjson @@ -0,0 +1,2 @@ +{"data":"(2:1): expected: #EOF, #Language, #TagLine, #FeatureLine, #Comment, #Empty, got 'invalid line here'","media":{"encoding":"utf-8","type":"text/x.cucumber.stacktrace+plain"},"source":{"start":{"column":1,"line":2},"uri":"testdata/bad/multiple_parser_errors.feature"},"type":"attachment"} +{"data":"(9:1): expected: #EOF, #TableRow, #DocStringSeparator, #StepLine, #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Comment, #Empty, got 'another invalid line here'","media":{"encoding":"utf-8","type":"text/x.cucumber.stacktrace+plain"},"source":{"start":{"column":1,"line":9},"uri":"testdata/bad/multiple_parser_errors.feature"},"type":"attachment"} diff --git a/testdata/bad/not_gherkin.feature b/testdata/bad/not_gherkin.feature new file mode 100644 index 0000000..1999ac2 --- /dev/null +++ b/testdata/bad/not_gherkin.feature @@ -0,0 +1,2 @@ +not gherkin + diff --git a/testdata/bad/not_gherkin.feature.errors.ndjson b/testdata/bad/not_gherkin.feature.errors.ndjson new file mode 100644 index 0000000..d547f6a --- /dev/null +++ b/testdata/bad/not_gherkin.feature.errors.ndjson @@ -0,0 +1 @@ +{"data":"(1:1): expected: #EOF, #Language, #TagLine, #FeatureLine, #Comment, #Empty, got 'not gherkin'","media":{"encoding":"utf-8","type":"text/x.cucumber.stacktrace+plain"},"source":{"start":{"column":1,"line":1},"uri":"testdata/bad/not_gherkin.feature"},"type":"attachment"} diff --git a/testdata/bad/single_parser_error.feature b/testdata/bad/single_parser_error.feature new file mode 100644 index 0000000..3308ca8 --- /dev/null +++ b/testdata/bad/single_parser_error.feature @@ -0,0 +1,7 @@ + +invalid line here + +Feature: Single parser error + + Scenario: minimalistic + Given the minimalism diff --git a/testdata/bad/single_parser_error.feature.errors.ndjson b/testdata/bad/single_parser_error.feature.errors.ndjson new file mode 100644 index 0000000..e6acf18 --- /dev/null +++ b/testdata/bad/single_parser_error.feature.errors.ndjson @@ -0,0 +1 @@ +{"data":"(2:1): expected: #EOF, #Language, #TagLine, #FeatureLine, #Comment, #Empty, got 'invalid line here'","media":{"encoding":"utf-8","type":"text/x.cucumber.stacktrace+plain"},"source":{"start":{"column":1,"line":2},"uri":"testdata/bad/single_parser_error.feature"},"type":"attachment"} diff --git a/testdata/bad/unexpected_eof.feature b/testdata/bad/unexpected_eof.feature new file mode 100644 index 0000000..a374ecf --- /dev/null +++ b/testdata/bad/unexpected_eof.feature @@ -0,0 +1,6 @@ +Feature: Unexpected end of file + + Scenario Outline: minimalistic + Given the minimalism + + @tag diff --git a/testdata/bad/unexpected_eof.feature.errors.ndjson b/testdata/bad/unexpected_eof.feature.errors.ndjson new file mode 100644 index 0000000..48763e2 --- /dev/null +++ b/testdata/bad/unexpected_eof.feature.errors.ndjson @@ -0,0 +1 @@ +{"data":"(7:0): unexpected end of file, expected: #TagLine, #ScenarioLine, #ScenarioOutlineLine, #Comment, #Empty","media":{"encoding":"utf-8","type":"text/x.cucumber.stacktrace+plain"},"source":{"start":{"column":0,"line":7},"uri":"testdata/bad/unexpected_eof.feature"},"type":"attachment"} diff --git a/testdata/good/.gitignore b/testdata/good/.gitignore new file mode 100644 index 0000000..e4440b2 --- /dev/null +++ b/testdata/good/.gitignore @@ -0,0 +1,4 @@ +*.csharp.ast +*.csharp.tokens +*.java.ast +*.java.tokens diff --git a/testdata/good/background.feature b/testdata/good/background.feature new file mode 100644 index 0000000..9820aa2 --- /dev/null +++ b/testdata/good/background.feature @@ -0,0 +1,8 @@ +Feature: Background + + Background: a simple background + Given the minimalism inside a background + + + Scenario: minimalistic + Given the minimalism diff --git a/testdata/good/background.feature.ast.ndjson b/testdata/good/background.feature.ast.ndjson new file mode 100644 index 0000000..a42e96a --- /dev/null +++ b/testdata/good/background.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"Background","location":{"column":3,"line":3},"name":"a simple background","steps":[{"keyword":"Given ","location":{"column":5,"line":4},"text":"the minimalism inside a background","type":"Step"}],"type":"Background"},{"keyword":"Scenario","location":{"column":3,"line":7},"name":"minimalistic","steps":[{"keyword":"Given ","location":{"column":5,"line":8},"text":"the minimalism","type":"Step"}],"tags":[],"type":"Scenario"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Background","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/background.feature"} diff --git a/testdata/good/background.feature.pickles.ndjson b/testdata/good/background.feature.pickles.ndjson new file mode 100644 index 0000000..e7a5438 --- /dev/null +++ b/testdata/good/background.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":7}],"name":"minimalistic","steps":[{"arguments":[],"locations":[{"column":11,"line":4}],"text":"the minimalism inside a background"},{"arguments":[],"locations":[{"column":11,"line":8}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/background.feature"} diff --git a/testdata/good/background.feature.source.ndjson b/testdata/good/background.feature.source.ndjson new file mode 100644 index 0000000..f919225 --- /dev/null +++ b/testdata/good/background.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Background\n\n Background: a simple background\n Given the minimalism inside a background\n\n\n Scenario: minimalistic\n Given the minimalism\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/background.feature"} diff --git a/testdata/good/background.feature.tokens b/testdata/good/background.feature.tokens new file mode 100644 index 0000000..764b198 --- /dev/null +++ b/testdata/good/background.feature.tokens @@ -0,0 +1,9 @@ +(1:1)FeatureLine:Feature/Background/ +(2:1)Empty:// +(3:3)BackgroundLine:Background/a simple background/ +(4:5)StepLine:Given /the minimalism inside a background/ +(5:1)Empty:// +(6:1)Empty:// +(7:3)ScenarioLine:Scenario/minimalistic/ +(8:5)StepLine:Given /the minimalism/ +EOF diff --git a/testdata/good/datatables.feature b/testdata/good/datatables.feature new file mode 100644 index 0000000..ecc2ae2 --- /dev/null +++ b/testdata/good/datatables.feature @@ -0,0 +1,18 @@ +Feature: DataTables + + Scenario: minimalistic + Given a simple data table + | foo | bar | + | boz | boo | + And a data table with a single cell + | foo | + And a data table with different fromatting + | foo|bar| boz | + And a data table with an empty cell + |foo||boz| + And a data table with comments and newlines inside + | foo | bar | + + | boz | boo | + # this is a comment + | boz2 | boo2 | diff --git a/testdata/good/datatables.feature.ast.ndjson b/testdata/good/datatables.feature.ast.ndjson new file mode 100644 index 0000000..81a948d --- /dev/null +++ b/testdata/good/datatables.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[{"location":{"column":1,"line":17},"text":" # this is a comment","type":"Comment"}],"feature":{"children":[{"keyword":"Scenario","location":{"column":3,"line":3},"name":"minimalistic","steps":[{"argument":{"location":{"column":7,"line":5},"rows":[{"cells":[{"location":{"column":9,"line":5},"type":"TableCell","value":"foo"},{"location":{"column":15,"line":5},"type":"TableCell","value":"bar"}],"location":{"column":7,"line":5},"type":"TableRow"},{"cells":[{"location":{"column":9,"line":6},"type":"TableCell","value":"boz"},{"location":{"column":15,"line":6},"type":"TableCell","value":"boo"}],"location":{"column":7,"line":6},"type":"TableRow"}],"type":"DataTable"},"keyword":"Given ","location":{"column":5,"line":4},"text":"a simple data table","type":"Step"},{"argument":{"location":{"column":7,"line":8},"rows":[{"cells":[{"location":{"column":9,"line":8},"type":"TableCell","value":"foo"}],"location":{"column":7,"line":8},"type":"TableRow"}],"type":"DataTable"},"keyword":"And ","location":{"column":5,"line":7},"text":"a data table with a single cell","type":"Step"},{"argument":{"location":{"column":7,"line":10},"rows":[{"cells":[{"location":{"column":11,"line":10},"type":"TableCell","value":"foo"},{"location":{"column":15,"line":10},"type":"TableCell","value":"bar"},{"location":{"column":23,"line":10},"type":"TableCell","value":"boz"}],"location":{"column":7,"line":10},"type":"TableRow"}],"type":"DataTable"},"keyword":"And ","location":{"column":5,"line":9},"text":"a data table with different fromatting","type":"Step"},{"argument":{"location":{"column":7,"line":12},"rows":[{"cells":[{"location":{"column":8,"line":12},"type":"TableCell","value":"foo"},{"location":{"column":12,"line":12},"type":"TableCell","value":""},{"location":{"column":13,"line":12},"type":"TableCell","value":"boz"}],"location":{"column":7,"line":12},"type":"TableRow"}],"type":"DataTable"},"keyword":"And ","location":{"column":5,"line":11},"text":"a data table with an empty cell","type":"Step"},{"argument":{"location":{"column":7,"line":14},"rows":[{"cells":[{"location":{"column":9,"line":14},"type":"TableCell","value":"foo"},{"location":{"column":15,"line":14},"type":"TableCell","value":"bar"}],"location":{"column":7,"line":14},"type":"TableRow"},{"cells":[{"location":{"column":9,"line":16},"type":"TableCell","value":"boz"},{"location":{"column":16,"line":16},"type":"TableCell","value":"boo"}],"location":{"column":7,"line":16},"type":"TableRow"},{"cells":[{"location":{"column":9,"line":18},"type":"TableCell","value":"boz2"},{"location":{"column":16,"line":18},"type":"TableCell","value":"boo2"}],"location":{"column":7,"line":18},"type":"TableRow"}],"type":"DataTable"},"keyword":"And ","location":{"column":5,"line":13},"text":"a data table with comments and newlines inside","type":"Step"}],"tags":[],"type":"Scenario"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"DataTables","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/datatables.feature"} diff --git a/testdata/good/datatables.feature.pickles.ndjson b/testdata/good/datatables.feature.pickles.ndjson new file mode 100644 index 0000000..eb4a411 --- /dev/null +++ b/testdata/good/datatables.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":3}],"name":"minimalistic","steps":[{"arguments":[{"rows":[{"cells":[{"location":{"column":9,"line":5},"value":"foo"},{"location":{"column":15,"line":5},"value":"bar"}]},{"cells":[{"location":{"column":9,"line":6},"value":"boz"},{"location":{"column":15,"line":6},"value":"boo"}]}]}],"locations":[{"column":11,"line":4}],"text":"a simple data table"},{"arguments":[{"rows":[{"cells":[{"location":{"column":9,"line":8},"value":"foo"}]}]}],"locations":[{"column":9,"line":7}],"text":"a data table with a single cell"},{"arguments":[{"rows":[{"cells":[{"location":{"column":11,"line":10},"value":"foo"},{"location":{"column":15,"line":10},"value":"bar"},{"location":{"column":23,"line":10},"value":"boz"}]}]}],"locations":[{"column":9,"line":9}],"text":"a data table with different fromatting"},{"arguments":[{"rows":[{"cells":[{"location":{"column":8,"line":12},"value":"foo"},{"location":{"column":12,"line":12},"value":""},{"location":{"column":13,"line":12},"value":"boz"}]}]}],"locations":[{"column":9,"line":11}],"text":"a data table with an empty cell"},{"arguments":[{"rows":[{"cells":[{"location":{"column":9,"line":14},"value":"foo"},{"location":{"column":15,"line":14},"value":"bar"}]},{"cells":[{"location":{"column":9,"line":16},"value":"boz"},{"location":{"column":16,"line":16},"value":"boo"}]},{"cells":[{"location":{"column":9,"line":18},"value":"boz2"},{"location":{"column":16,"line":18},"value":"boo2"}]}]}],"locations":[{"column":9,"line":13}],"text":"a data table with comments and newlines inside"}],"tags":[]},"type":"pickle","uri":"testdata/good/datatables.feature"} diff --git a/testdata/good/datatables.feature.source.ndjson b/testdata/good/datatables.feature.source.ndjson new file mode 100644 index 0000000..f1f192e --- /dev/null +++ b/testdata/good/datatables.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: DataTables\n\n Scenario: minimalistic\n Given a simple data table\n | foo | bar |\r\n | boz | boo |\n And a data table with a single cell\n | foo |\n And a data table with different fromatting\n | foo|bar| boz | \n And a data table with an empty cell\n |foo||boz|\n And a data table with comments and newlines inside\n | foo | bar |\r\n\r\n | boz | boo |\r\n # this is a comment\r\n | boz2 | boo2 |\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/datatables.feature"} diff --git a/testdata/good/datatables.feature.tokens b/testdata/good/datatables.feature.tokens new file mode 100644 index 0000000..e6b3978 --- /dev/null +++ b/testdata/good/datatables.feature.tokens @@ -0,0 +1,19 @@ +(1:1)FeatureLine:Feature/DataTables/ +(2:1)Empty:// +(3:3)ScenarioLine:Scenario/minimalistic/ +(4:5)StepLine:Given /a simple data table/ +(5:7)TableRow://9:foo,15:bar +(6:7)TableRow://9:boz,15:boo +(7:5)StepLine:And /a data table with a single cell/ +(8:7)TableRow://9:foo +(9:5)StepLine:And /a data table with different fromatting/ +(10:7)TableRow://11:foo,15:bar,23:boz +(11:5)StepLine:And /a data table with an empty cell/ +(12:7)TableRow://8:foo,12:,13:boz +(13:5)StepLine:And /a data table with comments and newlines inside/ +(14:7)TableRow://9:foo,15:bar +(15:1)Empty:// +(16:7)TableRow://9:boz,16:boo +(17:1)Comment:/ # this is a comment/ +(18:7)TableRow://9:boz2,16:boo2 +EOF diff --git a/testdata/good/descriptions.feature b/testdata/good/descriptions.feature new file mode 100644 index 0000000..680a6bb --- /dev/null +++ b/testdata/good/descriptions.feature @@ -0,0 +1,52 @@ +Feature: Descriptions everywhere + This is a single line description + + Scenario: two lines + This description + has two lines and indented with two spaces + Given the minimalism + +Scenario: without indentation +This is a description without indentation + Given the minimalism + + Scenario: empty lines in the middle + This description + + has an empty line in the middle + Given the minimalism + + Scenario: empty lines around + + This description + has an empty lines around + + Given the minimalism + + Scenario: comment after description + This description + has a comment after + +# this is a comment + Given the minimalism + + Scenario: comment right after description + This description + has a comment right after + # this is another comment + + Given the minimalism + + Scenario: description with escaped docstring separator + This description has an \"\"\" (escaped docstring sparator) + + Given the minimalism + + Scenario Outline: scenario outline with a description +This is a scenario outline description + Given the minimalism + + Examples: examples with description +This is an examples description + | foo | + | bar | diff --git a/testdata/good/descriptions.feature.ast.ndjson b/testdata/good/descriptions.feature.ast.ndjson new file mode 100644 index 0000000..3f25383 --- /dev/null +++ b/testdata/good/descriptions.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[{"location":{"column":1,"line":30},"text":"# this is a comment","type":"Comment"},{"location":{"column":1,"line":36},"text":" # this is another comment","type":"Comment"}],"feature":{"children":[{"description":" This description\n has two lines and indented with two spaces","keyword":"Scenario","location":{"column":3,"line":4},"name":"two lines","steps":[{"keyword":"Given ","location":{"column":5,"line":7},"text":"the minimalism","type":"Step"}],"tags":[],"type":"Scenario"},{"description":"This is a description without indentation","keyword":"Scenario","location":{"column":1,"line":9},"name":"without indentation","steps":[{"keyword":"Given ","location":{"column":3,"line":11},"text":"the minimalism","type":"Step"}],"tags":[],"type":"Scenario"},{"description":" This description\n\n has an empty line in the middle","keyword":"Scenario","location":{"column":3,"line":13},"name":"empty lines in the middle","steps":[{"keyword":"Given ","location":{"column":5,"line":17},"text":"the minimalism","type":"Step"}],"tags":[],"type":"Scenario"},{"description":" This description\n has an empty lines around","keyword":"Scenario","location":{"column":3,"line":19},"name":"empty lines around","steps":[{"keyword":"Given ","location":{"column":5,"line":24},"text":"the minimalism","type":"Step"}],"tags":[],"type":"Scenario"},{"description":" This description\n has a comment after","keyword":"Scenario","location":{"column":3,"line":26},"name":"comment after description","steps":[{"keyword":"Given ","location":{"column":5,"line":31},"text":"the minimalism","type":"Step"}],"tags":[],"type":"Scenario"},{"description":" This description\n has a comment right after","keyword":"Scenario","location":{"column":3,"line":33},"name":"comment right after description","steps":[{"keyword":"Given ","location":{"column":5,"line":38},"text":"the minimalism","type":"Step"}],"tags":[],"type":"Scenario"},{"description":" This description has an \\\"\\\"\\\" (escaped docstring sparator)","keyword":"Scenario","location":{"column":3,"line":40},"name":"description with escaped docstring separator","steps":[{"keyword":"Given ","location":{"column":5,"line":43},"text":"the minimalism","type":"Step"}],"tags":[],"type":"Scenario"},{"description":"This is a scenario outline description","examples":[{"description":"This is an examples description","keyword":"Examples","location":{"column":3,"line":49},"name":"examples with description","tableBody":[{"cells":[{"location":{"column":7,"line":52},"type":"TableCell","value":"bar"}],"location":{"column":5,"line":52},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":7,"line":51},"type":"TableCell","value":"foo"}],"location":{"column":5,"line":51},"type":"TableRow"},"tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":45},"name":"scenario outline with a description","steps":[{"keyword":"Given ","location":{"column":5,"line":47},"text":"the minimalism","type":"Step"}],"tags":[],"type":"ScenarioOutline"}],"description":" This is a single line description","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Descriptions everywhere","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/descriptions.feature"} diff --git a/testdata/good/descriptions.feature.pickles.ndjson b/testdata/good/descriptions.feature.pickles.ndjson new file mode 100644 index 0000000..31748ac --- /dev/null +++ b/testdata/good/descriptions.feature.pickles.ndjson @@ -0,0 +1,8 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":4}],"name":"two lines","steps":[{"arguments":[],"locations":[{"column":11,"line":7}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/descriptions.feature"} +{"pickle":{"language":"en","locations":[{"column":1,"line":9}],"name":"without indentation","steps":[{"arguments":[],"locations":[{"column":9,"line":11}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/descriptions.feature"} +{"pickle":{"language":"en","locations":[{"column":3,"line":13}],"name":"empty lines in the middle","steps":[{"arguments":[],"locations":[{"column":11,"line":17}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/descriptions.feature"} +{"pickle":{"language":"en","locations":[{"column":3,"line":19}],"name":"empty lines around","steps":[{"arguments":[],"locations":[{"column":11,"line":24}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/descriptions.feature"} +{"pickle":{"language":"en","locations":[{"column":3,"line":26}],"name":"comment after description","steps":[{"arguments":[],"locations":[{"column":11,"line":31}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/descriptions.feature"} +{"pickle":{"language":"en","locations":[{"column":3,"line":33}],"name":"comment right after description","steps":[{"arguments":[],"locations":[{"column":11,"line":38}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/descriptions.feature"} +{"pickle":{"language":"en","locations":[{"column":3,"line":40}],"name":"description with escaped docstring separator","steps":[{"arguments":[],"locations":[{"column":11,"line":43}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/descriptions.feature"} +{"pickle":{"language":"en","locations":[{"column":5,"line":52},{"column":3,"line":45}],"name":"scenario outline with a description","steps":[{"arguments":[],"locations":[{"column":5,"line":52},{"column":11,"line":47}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/descriptions.feature"} diff --git a/testdata/good/descriptions.feature.source.ndjson b/testdata/good/descriptions.feature.source.ndjson new file mode 100644 index 0000000..5171889 --- /dev/null +++ b/testdata/good/descriptions.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Descriptions everywhere\n This is a single line description\n\n Scenario: two lines\n This description\n has two lines and indented with two spaces\n Given the minimalism\n\nScenario: without indentation\nThis is a description without indentation\n Given the minimalism\n\n Scenario: empty lines in the middle\n This description\n\n has an empty line in the middle\n Given the minimalism\n\n Scenario: empty lines around\n\n This description\n has an empty lines around\n\n Given the minimalism\n\n Scenario: comment after description\n This description\n has a comment after\n\n# this is a comment\n Given the minimalism\n\n Scenario: comment right after description\n This description\n has a comment right after\n # this is another comment\n\n Given the minimalism\n\n Scenario: description with escaped docstring separator\n This description has an \\\"\\\"\\\" (escaped docstring sparator)\n\n Given the minimalism\n\n Scenario Outline: scenario outline with a description\nThis is a scenario outline description\n Given the minimalism\n\n Examples: examples with description\nThis is an examples description\n | foo |\r\n | bar |\r\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/descriptions.feature"} diff --git a/testdata/good/descriptions.feature.tokens b/testdata/good/descriptions.feature.tokens new file mode 100644 index 0000000..8303876 --- /dev/null +++ b/testdata/good/descriptions.feature.tokens @@ -0,0 +1,53 @@ +(1:1)FeatureLine:Feature/Descriptions everywhere/ +(2:1)Other:/ This is a single line description/ +(3:1)Other:// +(4:3)ScenarioLine:Scenario/two lines/ +(5:1)Other:/ This description/ +(6:1)Other:/ has two lines and indented with two spaces/ +(7:5)StepLine:Given /the minimalism/ +(8:1)Empty:// +(9:1)ScenarioLine:Scenario/without indentation/ +(10:1)Other:/This is a description without indentation/ +(11:3)StepLine:Given /the minimalism/ +(12:1)Empty:// +(13:3)ScenarioLine:Scenario/empty lines in the middle/ +(14:1)Other:/ This description/ +(15:1)Other:// +(16:1)Other:/ has an empty line in the middle/ +(17:5)StepLine:Given /the minimalism/ +(18:1)Empty:// +(19:3)ScenarioLine:Scenario/empty lines around/ +(20:1)Empty:// +(21:1)Other:/ This description/ +(22:1)Other:/ has an empty lines around/ +(23:1)Other:// +(24:5)StepLine:Given /the minimalism/ +(25:1)Empty:// +(26:3)ScenarioLine:Scenario/comment after description/ +(27:1)Other:/ This description/ +(28:1)Other:/ has a comment after/ +(29:1)Other:// +(30:1)Comment:/# this is a comment/ +(31:5)StepLine:Given /the minimalism/ +(32:1)Empty:// +(33:3)ScenarioLine:Scenario/comment right after description/ +(34:1)Other:/ This description/ +(35:1)Other:/ has a comment right after/ +(36:1)Comment:/ # this is another comment/ +(37:1)Empty:// +(38:5)StepLine:Given /the minimalism/ +(39:1)Empty:// +(40:3)ScenarioLine:Scenario/description with escaped docstring separator/ +(41:1)Other:/ This description has an \"\"\" (escaped docstring sparator)/ +(42:1)Other:// +(43:5)StepLine:Given /the minimalism/ +(44:1)Empty:// +(45:3)ScenarioOutlineLine:Scenario Outline/scenario outline with a description/ +(46:1)Other:/This is a scenario outline description/ +(47:5)StepLine:Given /the minimalism/ +(48:1)Empty:// +(49:3)ExamplesLine:Examples/examples with description/ +(50:1)Other:/This is an examples description/ +(51:5)TableRow://7:foo +(52:5)TableRow://7:bar +EOF diff --git a/testdata/good/docstrings.feature b/testdata/good/docstrings.feature new file mode 100644 index 0000000..b3c68ed --- /dev/null +++ b/testdata/good/docstrings.feature @@ -0,0 +1,43 @@ +Feature: DocString variations + + Scenario: minimalistic + Given a simple DocString + """ + first line (no indent) + second line (indented with two spaces) + + third line was empty + """ + Given a DocString with content type + """xml + + + + """ + And a DocString with wrong indentation + """ + wrongly indented line + """ + And a DocString with alternative separator + ``` + first line + second line + ``` + And a DocString with normal separator inside + ``` + first line + """ + third line + ``` + And a DocString with alternative separator inside + """ + first line + ``` + third line + """ + And a DocString with escaped separator inside + """ + first line + \"\"\" + third line + """ diff --git a/testdata/good/docstrings.feature.ast.ndjson b/testdata/good/docstrings.feature.ast.ndjson new file mode 100644 index 0000000..5385260 --- /dev/null +++ b/testdata/good/docstrings.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"Scenario","location":{"column":3,"line":3},"name":"minimalistic","steps":[{"argument":{"content":"first line (no indent)\n second line (indented with two spaces)\n\nthird line was empty","location":{"column":7,"line":5},"type":"DocString"},"keyword":"Given ","location":{"column":5,"line":4},"text":"a simple DocString","type":"Step"},{"argument":{"content":"\n \n","contentType":"xml","location":{"column":7,"line":12},"type":"DocString"},"keyword":"Given ","location":{"column":5,"line":11},"text":"a DocString with content type","type":"Step"},{"argument":{"content":"wrongly indented line","location":{"column":7,"line":18},"type":"DocString"},"keyword":"And ","location":{"column":5,"line":17},"text":"a DocString with wrong indentation","type":"Step"},{"argument":{"content":"first line\nsecond line","location":{"column":7,"line":22},"type":"DocString"},"keyword":"And ","location":{"column":5,"line":21},"text":"a DocString with alternative separator","type":"Step"},{"argument":{"content":"first line\n\"\"\"\nthird line","location":{"column":7,"line":27},"type":"DocString"},"keyword":"And ","location":{"column":5,"line":26},"text":"a DocString with normal separator inside","type":"Step"},{"argument":{"content":"first line\n```\nthird line","location":{"column":7,"line":33},"type":"DocString"},"keyword":"And ","location":{"column":5,"line":32},"text":"a DocString with alternative separator inside","type":"Step"},{"argument":{"content":"first line\n\"\"\"\nthird line","location":{"column":7,"line":39},"type":"DocString"},"keyword":"And ","location":{"column":5,"line":38},"text":"a DocString with escaped separator inside","type":"Step"}],"tags":[],"type":"Scenario"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"DocString variations","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/docstrings.feature"} diff --git a/testdata/good/docstrings.feature.pickles.ndjson b/testdata/good/docstrings.feature.pickles.ndjson new file mode 100644 index 0000000..4fbf0c4 --- /dev/null +++ b/testdata/good/docstrings.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":3}],"name":"minimalistic","steps":[{"arguments":[{"content":"first line (no indent)\n second line (indented with two spaces)\n\nthird line was empty","location":{"column":7,"line":5}}],"locations":[{"column":11,"line":4}],"text":"a simple DocString"},{"arguments":[{"content":"\n \n","contentType":"xml","location":{"column":7,"line":12}}],"locations":[{"column":11,"line":11}],"text":"a DocString with content type"},{"arguments":[{"content":"wrongly indented line","location":{"column":7,"line":18}}],"locations":[{"column":9,"line":17}],"text":"a DocString with wrong indentation"},{"arguments":[{"content":"first line\nsecond line","location":{"column":7,"line":22}}],"locations":[{"column":9,"line":21}],"text":"a DocString with alternative separator"},{"arguments":[{"content":"first line\n\"\"\"\nthird line","location":{"column":7,"line":27}}],"locations":[{"column":9,"line":26}],"text":"a DocString with normal separator inside"},{"arguments":[{"content":"first line\n```\nthird line","location":{"column":7,"line":33}}],"locations":[{"column":9,"line":32}],"text":"a DocString with alternative separator inside"},{"arguments":[{"content":"first line\n\"\"\"\nthird line","location":{"column":7,"line":39}}],"locations":[{"column":9,"line":38}],"text":"a DocString with escaped separator inside"}],"tags":[]},"type":"pickle","uri":"testdata/good/docstrings.feature"} diff --git a/testdata/good/docstrings.feature.source.ndjson b/testdata/good/docstrings.feature.source.ndjson new file mode 100644 index 0000000..a80a5c3 --- /dev/null +++ b/testdata/good/docstrings.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: DocString variations\n\n Scenario: minimalistic\n Given a simple DocString\n \"\"\"\n first line (no indent)\n second line (indented with two spaces)\n\n third line was empty\n \"\"\"\n Given a DocString with content type\n \"\"\"xml\n \n \n \n \"\"\"\n And a DocString with wrong indentation\n \"\"\"\n wrongly indented line\n \"\"\"\n And a DocString with alternative separator\n ```\n first line\n second line\n ```\n And a DocString with normal separator inside\n ```\n first line\n \"\"\"\n third line\n ```\n And a DocString with alternative separator inside\n \"\"\"\n first line\n ```\n third line\n \"\"\"\n And a DocString with escaped separator inside\n \"\"\"\n first line\n \\\"\\\"\\\"\n third line\n \"\"\"\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/docstrings.feature"} diff --git a/testdata/good/docstrings.feature.tokens b/testdata/good/docstrings.feature.tokens new file mode 100644 index 0000000..b27cce6 --- /dev/null +++ b/testdata/good/docstrings.feature.tokens @@ -0,0 +1,44 @@ +(1:1)FeatureLine:Feature/DocString variations/ +(2:1)Empty:// +(3:3)ScenarioLine:Scenario/minimalistic/ +(4:5)StepLine:Given /a simple DocString/ +(5:7)DocStringSeparator:// +(6:1)Other:/first line (no indent)/ +(7:1)Other:/ second line (indented with two spaces)/ +(8:1)Other:// +(9:1)Other:/third line was empty/ +(10:7)DocStringSeparator:// +(11:5)StepLine:Given /a DocString with content type/ +(12:7)DocStringSeparator:/xml/ +(13:1)Other:// +(14:1)Other:/ / +(15:1)Other:// +(16:7)DocStringSeparator:// +(17:5)StepLine:And /a DocString with wrong indentation/ +(18:7)DocStringSeparator:// +(19:1)Other:/wrongly indented line/ +(20:7)DocStringSeparator:// +(21:5)StepLine:And /a DocString with alternative separator/ +(22:7)DocStringSeparator:// +(23:1)Other:/first line/ +(24:1)Other:/second line/ +(25:7)DocStringSeparator:// +(26:5)StepLine:And /a DocString with normal separator inside/ +(27:7)DocStringSeparator:// +(28:1)Other:/first line/ +(29:1)Other:/"""/ +(30:1)Other:/third line/ +(31:7)DocStringSeparator:// +(32:5)StepLine:And /a DocString with alternative separator inside/ +(33:7)DocStringSeparator:// +(34:1)Other:/first line/ +(35:1)Other:/```/ +(36:1)Other:/third line/ +(37:7)DocStringSeparator:// +(38:5)StepLine:And /a DocString with escaped separator inside/ +(39:7)DocStringSeparator:// +(40:1)Other:/first line/ +(41:1)Other:/"""/ +(42:1)Other:/third line/ +(43:7)DocStringSeparator:// +EOF diff --git a/testdata/good/empty.feature b/testdata/good/empty.feature new file mode 100644 index 0000000..e69de29 diff --git a/testdata/good/empty.feature.ast.ndjson b/testdata/good/empty.feature.ast.ndjson new file mode 100644 index 0000000..5a39026 --- /dev/null +++ b/testdata/good/empty.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/empty.feature"} diff --git a/testdata/good/empty.feature.pickles.ndjson b/testdata/good/empty.feature.pickles.ndjson new file mode 100644 index 0000000..e69de29 diff --git a/testdata/good/empty.feature.source.ndjson b/testdata/good/empty.feature.source.ndjson new file mode 100644 index 0000000..ebb0cc6 --- /dev/null +++ b/testdata/good/empty.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/empty.feature"} diff --git a/testdata/good/empty.feature.tokens b/testdata/good/empty.feature.tokens new file mode 100644 index 0000000..1a2b1dc --- /dev/null +++ b/testdata/good/empty.feature.tokens @@ -0,0 +1 @@ +EOF diff --git a/testdata/good/escaped_pipes.feature b/testdata/good/escaped_pipes.feature new file mode 100644 index 0000000..489a145 --- /dev/null +++ b/testdata/good/escaped_pipes.feature @@ -0,0 +1,11 @@ +Feature: Escaped pipes + The \-character will be considered as an escape in table cell + iff it is followed by a |-character, a \-character or an n. + + Scenario: They are the future + Given they have arrived + | æ | o | + | a | ø | + Given they have arrived + | \|æ\\n | \o\no\ | + | \\\|a\\\\n | ø\\\nø\\| diff --git a/testdata/good/escaped_pipes.feature.ast.ndjson b/testdata/good/escaped_pipes.feature.ast.ndjson new file mode 100644 index 0000000..f66285b --- /dev/null +++ b/testdata/good/escaped_pipes.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"Scenario","location":{"column":3,"line":5},"name":"They are the future","steps":[{"argument":{"location":{"column":7,"line":7},"rows":[{"cells":[{"location":{"column":9,"line":7},"type":"TableCell","value":"æ"},{"location":{"column":13,"line":7},"type":"TableCell","value":"o"}],"location":{"column":7,"line":7},"type":"TableRow"},{"cells":[{"location":{"column":9,"line":8},"type":"TableCell","value":"a"},{"location":{"column":13,"line":8},"type":"TableCell","value":"ø"}],"location":{"column":7,"line":8},"type":"TableRow"}],"type":"DataTable"},"keyword":"Given ","location":{"column":5,"line":6},"text":"they have arrived","type":"Step"},{"argument":{"location":{"column":7,"line":10},"rows":[{"cells":[{"location":{"column":9,"line":10},"type":"TableCell","value":"|æ\\n"},{"location":{"column":22,"line":10},"type":"TableCell","value":"\\o\no\\"}],"location":{"column":7,"line":10},"type":"TableRow"},{"cells":[{"location":{"column":9,"line":11},"type":"TableCell","value":"\\|a\\\\n"},{"location":{"column":22,"line":11},"type":"TableCell","value":"ø\\\nø\\"}],"location":{"column":7,"line":11},"type":"TableRow"}],"type":"DataTable"},"keyword":"Given ","location":{"column":5,"line":9},"text":"they have arrived","type":"Step"}],"tags":[],"type":"Scenario"}],"description":" The \\-character will be considered as an escape in table cell\n iff it is followed by a |-character, a \\-character or an n.","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Escaped pipes","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/escaped_pipes.feature"} diff --git a/testdata/good/escaped_pipes.feature.pickles.ndjson b/testdata/good/escaped_pipes.feature.pickles.ndjson new file mode 100644 index 0000000..789b2c3 --- /dev/null +++ b/testdata/good/escaped_pipes.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":5}],"name":"They are the future","steps":[{"arguments":[{"rows":[{"cells":[{"location":{"column":9,"line":7},"value":"æ"},{"location":{"column":13,"line":7},"value":"o"}]},{"cells":[{"location":{"column":9,"line":8},"value":"a"},{"location":{"column":13,"line":8},"value":"ø"}]}]}],"locations":[{"column":11,"line":6}],"text":"they have arrived"},{"arguments":[{"rows":[{"cells":[{"location":{"column":9,"line":10},"value":"|æ\\n"},{"location":{"column":22,"line":10},"value":"\\o\no\\"}]},{"cells":[{"location":{"column":9,"line":11},"value":"\\|a\\\\n"},{"location":{"column":22,"line":11},"value":"ø\\\nø\\"}]}]}],"locations":[{"column":11,"line":9}],"text":"they have arrived"}],"tags":[]},"type":"pickle","uri":"testdata/good/escaped_pipes.feature"} diff --git a/testdata/good/escaped_pipes.feature.source.ndjson b/testdata/good/escaped_pipes.feature.source.ndjson new file mode 100644 index 0000000..9c0db30 --- /dev/null +++ b/testdata/good/escaped_pipes.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Escaped pipes\n The \\-character will be considered as an escape in table cell\n iff it is followed by a |-character, a \\-character or an n.\n\n Scenario: They are the future\n Given they have arrived\n | æ | o |\n | a | ø |\n Given they have arrived\n | \\|æ\\\\n | \\o\\no\\ |\n | \\\\\\|a\\\\\\\\n | ø\\\\\\nø\\\\|\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/escaped_pipes.feature"} diff --git a/testdata/good/escaped_pipes.feature.tokens b/testdata/good/escaped_pipes.feature.tokens new file mode 100644 index 0000000..3208709 --- /dev/null +++ b/testdata/good/escaped_pipes.feature.tokens @@ -0,0 +1,14 @@ +(1:1)FeatureLine:Feature/Escaped pipes/ +(2:1)Other:/ The \-character will be considered as an escape in table cell/ +(3:1)Other:/ iff it is followed by a |-character, a \-character or an n./ +(4:1)Other:// +(5:3)ScenarioLine:Scenario/They are the future/ +(6:5)StepLine:Given /they have arrived/ +(7:7)TableRow://9:æ,13:o +(8:7)TableRow://9:a,13:ø +(9:5)StepLine:Given /they have arrived/ +(10:7)TableRow://9:|æ\n,22:\o +o\ +(11:7)TableRow://9:\|a\\n,22:ø\ +ø\ +EOF diff --git a/testdata/good/example_token_multiple.feature b/testdata/good/example_token_multiple.feature new file mode 100644 index 0000000..0471b7f --- /dev/null +++ b/testdata/good/example_token_multiple.feature @@ -0,0 +1,8 @@ +Feature: Example token used multiple times + + Scenario Outline: Token used twice in a single step + Given + + Examples: + | what | + | usage | diff --git a/testdata/good/example_token_multiple.feature.ast.ndjson b/testdata/good/example_token_multiple.feature.ast.ndjson new file mode 100644 index 0000000..43b6732 --- /dev/null +++ b/testdata/good/example_token_multiple.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"examples":[{"keyword":"Examples","location":{"column":5,"line":6},"name":"","tableBody":[{"cells":[{"location":{"column":9,"line":8},"type":"TableCell","value":"usage"}],"location":{"column":7,"line":8},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":9,"line":7},"type":"TableCell","value":"what"}],"location":{"column":7,"line":7},"type":"TableRow"},"tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":3},"name":"Token used twice in a single step","steps":[{"keyword":"Given ","location":{"column":5,"line":4},"text":" ","type":"Step"}],"tags":[],"type":"ScenarioOutline"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Example token used multiple times","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/example_token_multiple.feature"} diff --git a/testdata/good/example_token_multiple.feature.pickles.ndjson b/testdata/good/example_token_multiple.feature.pickles.ndjson new file mode 100644 index 0000000..b4b7a54 --- /dev/null +++ b/testdata/good/example_token_multiple.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":7,"line":8},{"column":3,"line":3}],"name":"Token used twice in a single step","steps":[{"arguments":[],"locations":[{"column":7,"line":8},{"column":11,"line":4}],"text":"usage usage"}],"tags":[]},"type":"pickle","uri":"testdata/good/example_token_multiple.feature"} diff --git a/testdata/good/example_token_multiple.feature.source.ndjson b/testdata/good/example_token_multiple.feature.source.ndjson new file mode 100644 index 0000000..a802c76 --- /dev/null +++ b/testdata/good/example_token_multiple.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Example token used multiple times\n\n Scenario Outline: Token used twice in a single step\n Given \n\n Examples:\n | what |\n | usage |\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/example_token_multiple.feature"} diff --git a/testdata/good/example_token_multiple.feature.tokens b/testdata/good/example_token_multiple.feature.tokens new file mode 100644 index 0000000..20a92da --- /dev/null +++ b/testdata/good/example_token_multiple.feature.tokens @@ -0,0 +1,9 @@ +(1:1)FeatureLine:Feature/Example token used multiple times/ +(2:1)Empty:// +(3:3)ScenarioOutlineLine:Scenario Outline/Token used twice in a single step/ +(4:5)StepLine:Given / / +(5:1)Empty:// +(6:5)ExamplesLine:Examples// +(7:7)TableRow://9:what +(8:7)TableRow://9:usage +EOF diff --git a/testdata/good/example_tokens_everywhere.feature b/testdata/good/example_tokens_everywhere.feature new file mode 100644 index 0000000..edeefd0 --- /dev/null +++ b/testdata/good/example_tokens_everywhere.feature @@ -0,0 +1,14 @@ +Feature: Example tokens everywhere + + Scenario Outline: the + Given the : + """ + + """ + Given the : + | | + + Examples: + | one | two | three | four | five | + | un | deux | trois | quatre | cinq | + | uno | dos | tres | quatro | cinco | diff --git a/testdata/good/example_tokens_everywhere.feature.ast.ndjson b/testdata/good/example_tokens_everywhere.feature.ast.ndjson new file mode 100644 index 0000000..27f3e6e --- /dev/null +++ b/testdata/good/example_tokens_everywhere.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"examples":[{"keyword":"Examples","location":{"column":5,"line":11},"name":"","tableBody":[{"cells":[{"location":{"column":9,"line":13},"type":"TableCell","value":"un"},{"location":{"column":15,"line":13},"type":"TableCell","value":"deux"},{"location":{"column":22,"line":13},"type":"TableCell","value":"trois"},{"location":{"column":30,"line":13},"type":"TableCell","value":"quatre"},{"location":{"column":39,"line":13},"type":"TableCell","value":"cinq"}],"location":{"column":7,"line":13},"type":"TableRow"},{"cells":[{"location":{"column":9,"line":14},"type":"TableCell","value":"uno"},{"location":{"column":15,"line":14},"type":"TableCell","value":"dos"},{"location":{"column":22,"line":14},"type":"TableCell","value":"tres"},{"location":{"column":30,"line":14},"type":"TableCell","value":"quatro"},{"location":{"column":39,"line":14},"type":"TableCell","value":"cinco"}],"location":{"column":7,"line":14},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":9,"line":12},"type":"TableCell","value":"one"},{"location":{"column":15,"line":12},"type":"TableCell","value":"two"},{"location":{"column":22,"line":12},"type":"TableCell","value":"three"},{"location":{"column":30,"line":12},"type":"TableCell","value":"four"},{"location":{"column":39,"line":12},"type":"TableCell","value":"five"}],"location":{"column":7,"line":12},"type":"TableRow"},"tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":3},"name":"the ","steps":[{"argument":{"content":"","location":{"column":7,"line":5},"type":"DocString"},"keyword":"Given ","location":{"column":5,"line":4},"text":"the :","type":"Step"},{"argument":{"location":{"column":7,"line":9},"rows":[{"cells":[{"location":{"column":9,"line":9},"type":"TableCell","value":""}],"location":{"column":7,"line":9},"type":"TableRow"}],"type":"DataTable"},"keyword":"Given ","location":{"column":5,"line":8},"text":"the :","type":"Step"}],"tags":[],"type":"ScenarioOutline"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Example tokens everywhere","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/example_tokens_everywhere.feature"} diff --git a/testdata/good/example_tokens_everywhere.feature.pickles.ndjson b/testdata/good/example_tokens_everywhere.feature.pickles.ndjson new file mode 100644 index 0000000..46559ef --- /dev/null +++ b/testdata/good/example_tokens_everywhere.feature.pickles.ndjson @@ -0,0 +1,2 @@ +{"pickle":{"language":"en","locations":[{"column":7,"line":13},{"column":3,"line":3}],"name":"the un","steps":[{"arguments":[{"content":"trois","location":{"column":7,"line":5}}],"locations":[{"column":7,"line":13},{"column":11,"line":4}],"text":"the deux:"},{"arguments":[{"rows":[{"cells":[{"location":{"column":9,"line":9},"value":"cinq"}]}]}],"locations":[{"column":7,"line":13},{"column":11,"line":8}],"text":"the quatre:"}],"tags":[]},"type":"pickle","uri":"testdata/good/example_tokens_everywhere.feature"} +{"pickle":{"language":"en","locations":[{"column":7,"line":14},{"column":3,"line":3}],"name":"the uno","steps":[{"arguments":[{"content":"tres","location":{"column":7,"line":5}}],"locations":[{"column":7,"line":14},{"column":11,"line":4}],"text":"the dos:"},{"arguments":[{"rows":[{"cells":[{"location":{"column":9,"line":9},"value":"cinco"}]}]}],"locations":[{"column":7,"line":14},{"column":11,"line":8}],"text":"the quatro:"}],"tags":[]},"type":"pickle","uri":"testdata/good/example_tokens_everywhere.feature"} diff --git a/testdata/good/example_tokens_everywhere.feature.source.ndjson b/testdata/good/example_tokens_everywhere.feature.source.ndjson new file mode 100644 index 0000000..78dccc3 --- /dev/null +++ b/testdata/good/example_tokens_everywhere.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Example tokens everywhere\n\n Scenario Outline: the \n Given the :\n \"\"\"\n \n \"\"\"\n Given the :\n | |\n\n Examples:\n | one | two | three | four | five |\n | un | deux | trois | quatre | cinq |\n | uno | dos | tres | quatro | cinco |\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/example_tokens_everywhere.feature"} diff --git a/testdata/good/example_tokens_everywhere.feature.tokens b/testdata/good/example_tokens_everywhere.feature.tokens new file mode 100644 index 0000000..d75ee60 --- /dev/null +++ b/testdata/good/example_tokens_everywhere.feature.tokens @@ -0,0 +1,15 @@ +(1:1)FeatureLine:Feature/Example tokens everywhere/ +(2:1)Empty:// +(3:3)ScenarioOutlineLine:Scenario Outline/the / +(4:5)StepLine:Given /the :/ +(5:7)DocStringSeparator:// +(6:1)Other:// +(7:7)DocStringSeparator:// +(8:5)StepLine:Given /the :/ +(9:7)TableRow://9: +(10:1)Empty:// +(11:5)ExamplesLine:Examples// +(12:7)TableRow://9:one,15:two,22:three,30:four,39:five +(13:7)TableRow://9:un,15:deux,22:trois,30:quatre,39:cinq +(14:7)TableRow://9:uno,15:dos,22:tres,30:quatro,39:cinco +EOF diff --git a/testdata/good/i18n_emoji.feature b/testdata/good/i18n_emoji.feature new file mode 100644 index 0000000..96c03ba --- /dev/null +++ b/testdata/good/i18n_emoji.feature @@ -0,0 +1,5 @@ +# language: em +📚: 🙈🙉🙊 + + 📕: 💃 + 😐🎸 diff --git a/testdata/good/i18n_emoji.feature.ast.ndjson b/testdata/good/i18n_emoji.feature.ast.ndjson new file mode 100644 index 0000000..df83524 --- /dev/null +++ b/testdata/good/i18n_emoji.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"📕","location":{"column":3,"line":4},"name":"💃","steps":[{"keyword":"😐","location":{"column":5,"line":5},"text":"🎸","type":"Step"}],"tags":[],"type":"Scenario"}],"keyword":"📚","language":"em","location":{"column":1,"line":2},"name":"🙈🙉🙊","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/i18n_emoji.feature"} diff --git a/testdata/good/i18n_emoji.feature.pickles.ndjson b/testdata/good/i18n_emoji.feature.pickles.ndjson new file mode 100644 index 0000000..8e2211f --- /dev/null +++ b/testdata/good/i18n_emoji.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"em","locations":[{"column":3,"line":4}],"name":"💃","steps":[{"arguments":[],"locations":[{"column":6,"line":5}],"text":"🎸"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_emoji.feature"} diff --git a/testdata/good/i18n_emoji.feature.source.ndjson b/testdata/good/i18n_emoji.feature.source.ndjson new file mode 100644 index 0000000..2bd2500 --- /dev/null +++ b/testdata/good/i18n_emoji.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"# language: em\n📚: 🙈🙉🙊\n\n 📕: 💃\n 😐🎸\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/i18n_emoji.feature"} diff --git a/testdata/good/i18n_emoji.feature.tokens b/testdata/good/i18n_emoji.feature.tokens new file mode 100644 index 0000000..306e717 --- /dev/null +++ b/testdata/good/i18n_emoji.feature.tokens @@ -0,0 +1,6 @@ +(1:1)Language:/em/ +(2:1)FeatureLine:📚/🙈🙉🙊/ +(3:1)Empty:// +(4:3)ScenarioLine:📕/💃/ +(5:5)StepLine:😐/🎸/ +EOF diff --git a/testdata/good/i18n_fr.feature b/testdata/good/i18n_fr.feature new file mode 100644 index 0000000..ddeafa4 --- /dev/null +++ b/testdata/good/i18n_fr.feature @@ -0,0 +1,63 @@ +#language:fr +Fonctionnalité: i18n support + + Scénario: Support des caractères spéciaux + Soit un exemple de scénario en français + Quand j'ai 1 gâteau + Alors je suis heureux + + Scénario: Support du mot-clef "Etant donné que " + Etant donné que j'aime les gâteaux + Lorsqu'on m'offre 1 gâteau + Alors je suis heureux + + Scénario: Support du mot-clef "Etant donné qu'" + Etant donné qu'offrir un gâteau rend heureux + Lorsqu'on m'offre 1 gâteau + Alors je suis heureux + + Scénario: Support du mot-clef "Étant donné que " + Étant donné que j'aime les gâteaux + Lorsqu'on m'offre 1 gâteau + Alors je suis heureux + + Scénario: Support du mot-clef "Étant donné qu'" + Étant donné qu'offrir un gâteau rend heureux + Lorsqu'on m'offre 1 gâteau + Alors je suis heureux + + Scénario: Support du mot-clef "Et que " + Soit un exemple de scénario en français + Lorsque j'ai 2 gâteaux + Et que quelqu'un m'offre 1 gâteau + Alors j'ai 3 gâteaux + + Scénario: Support du mot-clef "Et qu'" + Soit un exemple de scénario en français + Lorsque j'ai 2 gâteaux + Et qu'on m'offre 1 gâteau + Alors j'ai 3 gâteaux + + Scénario: Support du mot-clef "Et " + Soit un exemple de scénario en français + Quand j'ai 2 gâteaux + Et quelqu'un m'offre 1 gâteau + Alors j'ai 3 gâteaux + + Scénario: Support du mot-clef "Mais que " + Soit un exemple de scénario en français + Lorsque j'ai 2 gâteaux + Mais que quelqu'un me vole 1 gâteau + Alors j'ai 1 gâteau + + Scénario: Support du mot-clef "Mais qu'" + Soit un exemple de scénario en français + Lorsque j'ai 2 gâteaux + Mais qu'on me vole 1 gâteau + Alors j'ai 1 gâteau + + Scénario: Support du mot-clef "Mais " + Soit un exemple de scénario en français + Quand j'ai 2 gâteaux + Mais quelqu'un me vole 1 gâteau + Alors j'ai 1 gâteau diff --git a/testdata/good/i18n_fr.feature.ast.ndjson b/testdata/good/i18n_fr.feature.ast.ndjson new file mode 100644 index 0000000..0230861 --- /dev/null +++ b/testdata/good/i18n_fr.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"Scénario","location":{"column":3,"line":4},"name":"Support des caractères spéciaux","steps":[{"keyword":"Soit ","location":{"column":5,"line":5},"text":"un exemple de scénario en français","type":"Step"},{"keyword":"Quand ","location":{"column":5,"line":6},"text":"j'ai 1 gâteau","type":"Step"},{"keyword":"Alors ","location":{"column":5,"line":7},"text":"je suis heureux","type":"Step"}],"tags":[],"type":"Scenario"},{"keyword":"Scénario","location":{"column":3,"line":9},"name":"Support du mot-clef \"Etant donné que \"","steps":[{"keyword":"Etant donné que ","location":{"column":5,"line":10},"text":"j'aime les gâteaux","type":"Step"},{"keyword":"Lorsqu'","location":{"column":5,"line":11},"text":"on m'offre 1 gâteau","type":"Step"},{"keyword":"Alors ","location":{"column":5,"line":12},"text":"je suis heureux","type":"Step"}],"tags":[],"type":"Scenario"},{"keyword":"Scénario","location":{"column":3,"line":14},"name":"Support du mot-clef \"Etant donné qu'\"","steps":[{"keyword":"Etant donné qu'","location":{"column":5,"line":15},"text":"offrir un gâteau rend heureux","type":"Step"},{"keyword":"Lorsqu'","location":{"column":5,"line":16},"text":"on m'offre 1 gâteau","type":"Step"},{"keyword":"Alors ","location":{"column":5,"line":17},"text":"je suis heureux","type":"Step"}],"tags":[],"type":"Scenario"},{"keyword":"Scénario","location":{"column":3,"line":19},"name":"Support du mot-clef \"Étant donné que \"","steps":[{"keyword":"Étant donné que ","location":{"column":5,"line":20},"text":"j'aime les gâteaux","type":"Step"},{"keyword":"Lorsqu'","location":{"column":5,"line":21},"text":"on m'offre 1 gâteau","type":"Step"},{"keyword":"Alors ","location":{"column":5,"line":22},"text":"je suis heureux","type":"Step"}],"tags":[],"type":"Scenario"},{"keyword":"Scénario","location":{"column":3,"line":24},"name":"Support du mot-clef \"Étant donné qu'\"","steps":[{"keyword":"Étant donné qu'","location":{"column":5,"line":25},"text":"offrir un gâteau rend heureux","type":"Step"},{"keyword":"Lorsqu'","location":{"column":5,"line":26},"text":"on m'offre 1 gâteau","type":"Step"},{"keyword":"Alors ","location":{"column":5,"line":27},"text":"je suis heureux","type":"Step"}],"tags":[],"type":"Scenario"},{"keyword":"Scénario","location":{"column":3,"line":29},"name":"Support du mot-clef \"Et que \"","steps":[{"keyword":"Soit ","location":{"column":5,"line":30},"text":"un exemple de scénario en français","type":"Step"},{"keyword":"Lorsque ","location":{"column":5,"line":31},"text":"j'ai 2 gâteaux","type":"Step"},{"keyword":"Et que ","location":{"column":5,"line":32},"text":"quelqu'un m'offre 1 gâteau","type":"Step"},{"keyword":"Alors ","location":{"column":5,"line":33},"text":"j'ai 3 gâteaux","type":"Step"}],"tags":[],"type":"Scenario"},{"keyword":"Scénario","location":{"column":3,"line":35},"name":"Support du mot-clef \"Et qu'\"","steps":[{"keyword":"Soit ","location":{"column":5,"line":36},"text":"un exemple de scénario en français","type":"Step"},{"keyword":"Lorsque ","location":{"column":5,"line":37},"text":"j'ai 2 gâteaux","type":"Step"},{"keyword":"Et qu'","location":{"column":5,"line":38},"text":"on m'offre 1 gâteau","type":"Step"},{"keyword":"Alors ","location":{"column":5,"line":39},"text":"j'ai 3 gâteaux","type":"Step"}],"tags":[],"type":"Scenario"},{"keyword":"Scénario","location":{"column":3,"line":41},"name":"Support du mot-clef \"Et \"","steps":[{"keyword":"Soit ","location":{"column":5,"line":42},"text":"un exemple de scénario en français","type":"Step"},{"keyword":"Quand ","location":{"column":5,"line":43},"text":"j'ai 2 gâteaux","type":"Step"},{"keyword":"Et ","location":{"column":5,"line":44},"text":"quelqu'un m'offre 1 gâteau","type":"Step"},{"keyword":"Alors ","location":{"column":5,"line":45},"text":"j'ai 3 gâteaux","type":"Step"}],"tags":[],"type":"Scenario"},{"keyword":"Scénario","location":{"column":3,"line":47},"name":"Support du mot-clef \"Mais que \"","steps":[{"keyword":"Soit ","location":{"column":5,"line":48},"text":"un exemple de scénario en français","type":"Step"},{"keyword":"Lorsque ","location":{"column":5,"line":49},"text":"j'ai 2 gâteaux","type":"Step"},{"keyword":"Mais que ","location":{"column":5,"line":50},"text":"quelqu'un me vole 1 gâteau","type":"Step"},{"keyword":"Alors ","location":{"column":5,"line":51},"text":"j'ai 1 gâteau","type":"Step"}],"tags":[],"type":"Scenario"},{"keyword":"Scénario","location":{"column":3,"line":53},"name":"Support du mot-clef \"Mais qu'\"","steps":[{"keyword":"Soit ","location":{"column":5,"line":54},"text":"un exemple de scénario en français","type":"Step"},{"keyword":"Lorsque ","location":{"column":5,"line":55},"text":"j'ai 2 gâteaux","type":"Step"},{"keyword":"Mais qu'","location":{"column":5,"line":56},"text":"on me vole 1 gâteau","type":"Step"},{"keyword":"Alors ","location":{"column":5,"line":57},"text":"j'ai 1 gâteau","type":"Step"}],"tags":[],"type":"Scenario"},{"keyword":"Scénario","location":{"column":3,"line":59},"name":"Support du mot-clef \"Mais \"","steps":[{"keyword":"Soit ","location":{"column":5,"line":60},"text":"un exemple de scénario en français","type":"Step"},{"keyword":"Quand ","location":{"column":5,"line":61},"text":"j'ai 2 gâteaux","type":"Step"},{"keyword":"Mais ","location":{"column":5,"line":62},"text":"quelqu'un me vole 1 gâteau","type":"Step"},{"keyword":"Alors ","location":{"column":5,"line":63},"text":"j'ai 1 gâteau","type":"Step"}],"tags":[],"type":"Scenario"}],"keyword":"Fonctionnalité","language":"fr","location":{"column":1,"line":2},"name":"i18n support","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/i18n_fr.feature"} diff --git a/testdata/good/i18n_fr.feature.pickles.ndjson b/testdata/good/i18n_fr.feature.pickles.ndjson new file mode 100644 index 0000000..b2e6ac9 --- /dev/null +++ b/testdata/good/i18n_fr.feature.pickles.ndjson @@ -0,0 +1,11 @@ +{"pickle":{"language":"fr","locations":[{"column":3,"line":4}],"name":"Support des caractères spéciaux","steps":[{"arguments":[],"locations":[{"column":10,"line":5}],"text":"un exemple de scénario en français"},{"arguments":[],"locations":[{"column":11,"line":6}],"text":"j'ai 1 gâteau"},{"arguments":[],"locations":[{"column":11,"line":7}],"text":"je suis heureux"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_fr.feature"} +{"pickle":{"language":"fr","locations":[{"column":3,"line":9}],"name":"Support du mot-clef \"Etant donné que \"","steps":[{"arguments":[],"locations":[{"column":21,"line":10}],"text":"j'aime les gâteaux"},{"arguments":[],"locations":[{"column":12,"line":11}],"text":"on m'offre 1 gâteau"},{"arguments":[],"locations":[{"column":11,"line":12}],"text":"je suis heureux"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_fr.feature"} +{"pickle":{"language":"fr","locations":[{"column":3,"line":14}],"name":"Support du mot-clef \"Etant donné qu'\"","steps":[{"arguments":[],"locations":[{"column":20,"line":15}],"text":"offrir un gâteau rend heureux"},{"arguments":[],"locations":[{"column":12,"line":16}],"text":"on m'offre 1 gâteau"},{"arguments":[],"locations":[{"column":11,"line":17}],"text":"je suis heureux"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_fr.feature"} +{"pickle":{"language":"fr","locations":[{"column":3,"line":19}],"name":"Support du mot-clef \"Étant donné que \"","steps":[{"arguments":[],"locations":[{"column":21,"line":20}],"text":"j'aime les gâteaux"},{"arguments":[],"locations":[{"column":12,"line":21}],"text":"on m'offre 1 gâteau"},{"arguments":[],"locations":[{"column":11,"line":22}],"text":"je suis heureux"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_fr.feature"} +{"pickle":{"language":"fr","locations":[{"column":3,"line":24}],"name":"Support du mot-clef \"Étant donné qu'\"","steps":[{"arguments":[],"locations":[{"column":20,"line":25}],"text":"offrir un gâteau rend heureux"},{"arguments":[],"locations":[{"column":12,"line":26}],"text":"on m'offre 1 gâteau"},{"arguments":[],"locations":[{"column":11,"line":27}],"text":"je suis heureux"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_fr.feature"} +{"pickle":{"language":"fr","locations":[{"column":3,"line":29}],"name":"Support du mot-clef \"Et que \"","steps":[{"arguments":[],"locations":[{"column":10,"line":30}],"text":"un exemple de scénario en français"},{"arguments":[],"locations":[{"column":13,"line":31}],"text":"j'ai 2 gâteaux"},{"arguments":[],"locations":[{"column":12,"line":32}],"text":"quelqu'un m'offre 1 gâteau"},{"arguments":[],"locations":[{"column":11,"line":33}],"text":"j'ai 3 gâteaux"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_fr.feature"} +{"pickle":{"language":"fr","locations":[{"column":3,"line":35}],"name":"Support du mot-clef \"Et qu'\"","steps":[{"arguments":[],"locations":[{"column":10,"line":36}],"text":"un exemple de scénario en français"},{"arguments":[],"locations":[{"column":13,"line":37}],"text":"j'ai 2 gâteaux"},{"arguments":[],"locations":[{"column":11,"line":38}],"text":"on m'offre 1 gâteau"},{"arguments":[],"locations":[{"column":11,"line":39}],"text":"j'ai 3 gâteaux"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_fr.feature"} +{"pickle":{"language":"fr","locations":[{"column":3,"line":41}],"name":"Support du mot-clef \"Et \"","steps":[{"arguments":[],"locations":[{"column":10,"line":42}],"text":"un exemple de scénario en français"},{"arguments":[],"locations":[{"column":11,"line":43}],"text":"j'ai 2 gâteaux"},{"arguments":[],"locations":[{"column":8,"line":44}],"text":"quelqu'un m'offre 1 gâteau"},{"arguments":[],"locations":[{"column":11,"line":45}],"text":"j'ai 3 gâteaux"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_fr.feature"} +{"pickle":{"language":"fr","locations":[{"column":3,"line":47}],"name":"Support du mot-clef \"Mais que \"","steps":[{"arguments":[],"locations":[{"column":10,"line":48}],"text":"un exemple de scénario en français"},{"arguments":[],"locations":[{"column":13,"line":49}],"text":"j'ai 2 gâteaux"},{"arguments":[],"locations":[{"column":14,"line":50}],"text":"quelqu'un me vole 1 gâteau"},{"arguments":[],"locations":[{"column":11,"line":51}],"text":"j'ai 1 gâteau"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_fr.feature"} +{"pickle":{"language":"fr","locations":[{"column":3,"line":53}],"name":"Support du mot-clef \"Mais qu'\"","steps":[{"arguments":[],"locations":[{"column":10,"line":54}],"text":"un exemple de scénario en français"},{"arguments":[],"locations":[{"column":13,"line":55}],"text":"j'ai 2 gâteaux"},{"arguments":[],"locations":[{"column":13,"line":56}],"text":"on me vole 1 gâteau"},{"arguments":[],"locations":[{"column":11,"line":57}],"text":"j'ai 1 gâteau"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_fr.feature"} +{"pickle":{"language":"fr","locations":[{"column":3,"line":59}],"name":"Support du mot-clef \"Mais \"","steps":[{"arguments":[],"locations":[{"column":10,"line":60}],"text":"un exemple de scénario en français"},{"arguments":[],"locations":[{"column":11,"line":61}],"text":"j'ai 2 gâteaux"},{"arguments":[],"locations":[{"column":10,"line":62}],"text":"quelqu'un me vole 1 gâteau"},{"arguments":[],"locations":[{"column":11,"line":63}],"text":"j'ai 1 gâteau"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_fr.feature"} diff --git a/testdata/good/i18n_fr.feature.source.ndjson b/testdata/good/i18n_fr.feature.source.ndjson new file mode 100644 index 0000000..201dbd6 --- /dev/null +++ b/testdata/good/i18n_fr.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"#language:fr\nFonctionnalité: i18n support\n\n Scénario: Support des caractères spéciaux\n Soit un exemple de scénario en français\n Quand j'ai 1 gâteau\n Alors je suis heureux\n\n Scénario: Support du mot-clef \"Etant donné que \"\n Etant donné que j'aime les gâteaux\n Lorsqu'on m'offre 1 gâteau\n Alors je suis heureux\n\n Scénario: Support du mot-clef \"Etant donné qu'\"\n Etant donné qu'offrir un gâteau rend heureux\n Lorsqu'on m'offre 1 gâteau\n Alors je suis heureux\n\n Scénario: Support du mot-clef \"Étant donné que \"\n Étant donné que j'aime les gâteaux \n Lorsqu'on m'offre 1 gâteau\n Alors je suis heureux\n\n Scénario: Support du mot-clef \"Étant donné qu'\"\n Étant donné qu'offrir un gâteau rend heureux\n Lorsqu'on m'offre 1 gâteau\n Alors je suis heureux\n\n Scénario: Support du mot-clef \"Et que \"\n Soit un exemple de scénario en français\n Lorsque j'ai 2 gâteaux\n Et que quelqu'un m'offre 1 gâteau\n Alors j'ai 3 gâteaux\n\n Scénario: Support du mot-clef \"Et qu'\"\n Soit un exemple de scénario en français\n Lorsque j'ai 2 gâteaux\n Et qu'on m'offre 1 gâteau\n Alors j'ai 3 gâteaux\n\n Scénario: Support du mot-clef \"Et \"\n Soit un exemple de scénario en français\n Quand j'ai 2 gâteaux\n Et quelqu'un m'offre 1 gâteau\n Alors j'ai 3 gâteaux\n\n Scénario: Support du mot-clef \"Mais que \"\n Soit un exemple de scénario en français\n Lorsque j'ai 2 gâteaux\n Mais que quelqu'un me vole 1 gâteau\n Alors j'ai 1 gâteau\n\n Scénario: Support du mot-clef \"Mais qu'\"\n Soit un exemple de scénario en français\n Lorsque j'ai 2 gâteaux\n Mais qu'on me vole 1 gâteau\n Alors j'ai 1 gâteau\n\n Scénario: Support du mot-clef \"Mais \"\n Soit un exemple de scénario en français\n Quand j'ai 2 gâteaux\n Mais quelqu'un me vole 1 gâteau\n Alors j'ai 1 gâteau\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/i18n_fr.feature"} diff --git a/testdata/good/i18n_fr.feature.tokens b/testdata/good/i18n_fr.feature.tokens new file mode 100644 index 0000000..f9a00ea --- /dev/null +++ b/testdata/good/i18n_fr.feature.tokens @@ -0,0 +1,64 @@ +(1:1)Language:/fr/ +(2:1)FeatureLine:Fonctionnalité/i18n support/ +(3:1)Empty:// +(4:3)ScenarioLine:Scénario/Support des caractères spéciaux/ +(5:5)StepLine:Soit /un exemple de scénario en français/ +(6:5)StepLine:Quand /j'ai 1 gâteau/ +(7:5)StepLine:Alors /je suis heureux/ +(8:1)Empty:// +(9:3)ScenarioLine:Scénario/Support du mot-clef "Etant donné que "/ +(10:5)StepLine:Etant donné que /j'aime les gâteaux/ +(11:5)StepLine:Lorsqu'/on m'offre 1 gâteau/ +(12:5)StepLine:Alors /je suis heureux/ +(13:1)Empty:// +(14:3)ScenarioLine:Scénario/Support du mot-clef "Etant donné qu'"/ +(15:5)StepLine:Etant donné qu'/offrir un gâteau rend heureux/ +(16:5)StepLine:Lorsqu'/on m'offre 1 gâteau/ +(17:5)StepLine:Alors /je suis heureux/ +(18:1)Empty:// +(19:3)ScenarioLine:Scénario/Support du mot-clef "Étant donné que "/ +(20:5)StepLine:Étant donné que /j'aime les gâteaux/ +(21:5)StepLine:Lorsqu'/on m'offre 1 gâteau/ +(22:5)StepLine:Alors /je suis heureux/ +(23:1)Empty:// +(24:3)ScenarioLine:Scénario/Support du mot-clef "Étant donné qu'"/ +(25:5)StepLine:Étant donné qu'/offrir un gâteau rend heureux/ +(26:5)StepLine:Lorsqu'/on m'offre 1 gâteau/ +(27:5)StepLine:Alors /je suis heureux/ +(28:1)Empty:// +(29:3)ScenarioLine:Scénario/Support du mot-clef "Et que "/ +(30:5)StepLine:Soit /un exemple de scénario en français/ +(31:5)StepLine:Lorsque /j'ai 2 gâteaux/ +(32:5)StepLine:Et que /quelqu'un m'offre 1 gâteau/ +(33:5)StepLine:Alors /j'ai 3 gâteaux/ +(34:1)Empty:// +(35:3)ScenarioLine:Scénario/Support du mot-clef "Et qu'"/ +(36:5)StepLine:Soit /un exemple de scénario en français/ +(37:5)StepLine:Lorsque /j'ai 2 gâteaux/ +(38:5)StepLine:Et qu'/on m'offre 1 gâteau/ +(39:5)StepLine:Alors /j'ai 3 gâteaux/ +(40:1)Empty:// +(41:3)ScenarioLine:Scénario/Support du mot-clef "Et "/ +(42:5)StepLine:Soit /un exemple de scénario en français/ +(43:5)StepLine:Quand /j'ai 2 gâteaux/ +(44:5)StepLine:Et /quelqu'un m'offre 1 gâteau/ +(45:5)StepLine:Alors /j'ai 3 gâteaux/ +(46:1)Empty:// +(47:3)ScenarioLine:Scénario/Support du mot-clef "Mais que "/ +(48:5)StepLine:Soit /un exemple de scénario en français/ +(49:5)StepLine:Lorsque /j'ai 2 gâteaux/ +(50:5)StepLine:Mais que /quelqu'un me vole 1 gâteau/ +(51:5)StepLine:Alors /j'ai 1 gâteau/ +(52:1)Empty:// +(53:3)ScenarioLine:Scénario/Support du mot-clef "Mais qu'"/ +(54:5)StepLine:Soit /un exemple de scénario en français/ +(55:5)StepLine:Lorsque /j'ai 2 gâteaux/ +(56:5)StepLine:Mais qu'/on me vole 1 gâteau/ +(57:5)StepLine:Alors /j'ai 1 gâteau/ +(58:1)Empty:// +(59:3)ScenarioLine:Scénario/Support du mot-clef "Mais "/ +(60:5)StepLine:Soit /un exemple de scénario en français/ +(61:5)StepLine:Quand /j'ai 2 gâteaux/ +(62:5)StepLine:Mais /quelqu'un me vole 1 gâteau/ +(63:5)StepLine:Alors /j'ai 1 gâteau/ +EOF diff --git a/testdata/good/i18n_no.feature b/testdata/good/i18n_no.feature new file mode 100644 index 0000000..243a219 --- /dev/null +++ b/testdata/good/i18n_no.feature @@ -0,0 +1,7 @@ +#language:no +Egenskap: i18n support + + Scenario: Parsing many languages + Gitt Gherkin supports many languages + Når Norwegian keywords are parsed + Så they should be recognized diff --git a/testdata/good/i18n_no.feature.ast.ndjson b/testdata/good/i18n_no.feature.ast.ndjson new file mode 100644 index 0000000..ee78e12 --- /dev/null +++ b/testdata/good/i18n_no.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"Scenario","location":{"column":3,"line":4},"name":"Parsing many languages","steps":[{"keyword":"Gitt ","location":{"column":5,"line":5},"text":"Gherkin supports many languages","type":"Step"},{"keyword":"Når ","location":{"column":5,"line":6},"text":"Norwegian keywords are parsed","type":"Step"},{"keyword":"Så ","location":{"column":5,"line":7},"text":"they should be recognized","type":"Step"}],"tags":[],"type":"Scenario"}],"keyword":"Egenskap","language":"no","location":{"column":1,"line":2},"name":"i18n support","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/i18n_no.feature"} diff --git a/testdata/good/i18n_no.feature.pickles.ndjson b/testdata/good/i18n_no.feature.pickles.ndjson new file mode 100644 index 0000000..bc0f967 --- /dev/null +++ b/testdata/good/i18n_no.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"no","locations":[{"column":3,"line":4}],"name":"Parsing many languages","steps":[{"arguments":[],"locations":[{"column":10,"line":5}],"text":"Gherkin supports many languages"},{"arguments":[],"locations":[{"column":9,"line":6}],"text":"Norwegian keywords are parsed"},{"arguments":[],"locations":[{"column":8,"line":7}],"text":"they should be recognized"}],"tags":[]},"type":"pickle","uri":"testdata/good/i18n_no.feature"} diff --git a/testdata/good/i18n_no.feature.source.ndjson b/testdata/good/i18n_no.feature.source.ndjson new file mode 100644 index 0000000..38b5dcb --- /dev/null +++ b/testdata/good/i18n_no.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"#language:no\nEgenskap: i18n support\n\n Scenario: Parsing many languages\n Gitt Gherkin supports many languages\n Når Norwegian keywords are parsed\n Så they should be recognized\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/i18n_no.feature"} diff --git a/testdata/good/i18n_no.feature.tokens b/testdata/good/i18n_no.feature.tokens new file mode 100644 index 0000000..b2e938e --- /dev/null +++ b/testdata/good/i18n_no.feature.tokens @@ -0,0 +1,8 @@ +(1:1)Language:/no/ +(2:1)FeatureLine:Egenskap/i18n support/ +(3:1)Empty:// +(4:3)ScenarioLine:Scenario/Parsing many languages/ +(5:5)StepLine:Gitt /Gherkin supports many languages/ +(6:5)StepLine:Når /Norwegian keywords are parsed/ +(7:5)StepLine:Så /they should be recognized/ +EOF diff --git a/testdata/good/incomplete_background_1.feature b/testdata/good/incomplete_background_1.feature new file mode 100644 index 0000000..766d29d --- /dev/null +++ b/testdata/good/incomplete_background_1.feature @@ -0,0 +1,6 @@ +Feature: Incomplete backgrounds, Part 1 + + Background: no steps + + Scenario: still pickles up + * a step diff --git a/testdata/good/incomplete_background_1.feature.ast.ndjson b/testdata/good/incomplete_background_1.feature.ast.ndjson new file mode 100644 index 0000000..30bd57e --- /dev/null +++ b/testdata/good/incomplete_background_1.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"Background","location":{"column":3,"line":3},"name":"no steps","steps":[],"type":"Background"},{"keyword":"Scenario","location":{"column":3,"line":5},"name":"still pickles up","steps":[{"keyword":"* ","location":{"column":5,"line":6},"text":"a step","type":"Step"}],"tags":[],"type":"Scenario"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Incomplete backgrounds, Part 1","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/incomplete_background_1.feature"} diff --git a/testdata/good/incomplete_background_1.feature.pickles.ndjson b/testdata/good/incomplete_background_1.feature.pickles.ndjson new file mode 100644 index 0000000..a22dcdb --- /dev/null +++ b/testdata/good/incomplete_background_1.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":5}],"name":"still pickles up","steps":[{"arguments":[],"locations":[{"column":7,"line":6}],"text":"a step"}],"tags":[]},"type":"pickle","uri":"testdata/good/incomplete_background_1.feature"} diff --git a/testdata/good/incomplete_background_1.feature.source.ndjson b/testdata/good/incomplete_background_1.feature.source.ndjson new file mode 100644 index 0000000..89cbf38 --- /dev/null +++ b/testdata/good/incomplete_background_1.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Incomplete backgrounds, Part 1\n\n Background: no steps\n\n Scenario: still pickles up\n * a step\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/incomplete_background_1.feature"} diff --git a/testdata/good/incomplete_background_1.feature.tokens b/testdata/good/incomplete_background_1.feature.tokens new file mode 100644 index 0000000..6e6e218 --- /dev/null +++ b/testdata/good/incomplete_background_1.feature.tokens @@ -0,0 +1,7 @@ +(1:1)FeatureLine:Feature/Incomplete backgrounds, Part 1/ +(2:1)Empty:// +(3:3)BackgroundLine:Background/no steps/ +(4:1)Empty:// +(5:3)ScenarioLine:Scenario/still pickles up/ +(6:5)StepLine:* /a step/ +EOF diff --git a/testdata/good/incomplete_background_2.feature b/testdata/good/incomplete_background_2.feature new file mode 100644 index 0000000..c4941ae --- /dev/null +++ b/testdata/good/incomplete_background_2.feature @@ -0,0 +1,7 @@ +Feature: Incomplete backgrounds, Part 2 + + Background: just a description + A short description + + Scenario: still pickles up + * a step diff --git a/testdata/good/incomplete_background_2.feature.ast.ndjson b/testdata/good/incomplete_background_2.feature.ast.ndjson new file mode 100644 index 0000000..07ca303 --- /dev/null +++ b/testdata/good/incomplete_background_2.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"description":" A short description","keyword":"Background","location":{"column":3,"line":3},"name":"just a description","steps":[],"type":"Background"},{"keyword":"Scenario","location":{"column":3,"line":6},"name":"still pickles up","steps":[{"keyword":"* ","location":{"column":5,"line":7},"text":"a step","type":"Step"}],"tags":[],"type":"Scenario"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Incomplete backgrounds, Part 2","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/incomplete_background_2.feature"} diff --git a/testdata/good/incomplete_background_2.feature.pickles.ndjson b/testdata/good/incomplete_background_2.feature.pickles.ndjson new file mode 100644 index 0000000..a98d328 --- /dev/null +++ b/testdata/good/incomplete_background_2.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":6}],"name":"still pickles up","steps":[{"arguments":[],"locations":[{"column":7,"line":7}],"text":"a step"}],"tags":[]},"type":"pickle","uri":"testdata/good/incomplete_background_2.feature"} diff --git a/testdata/good/incomplete_background_2.feature.source.ndjson b/testdata/good/incomplete_background_2.feature.source.ndjson new file mode 100644 index 0000000..284e899 --- /dev/null +++ b/testdata/good/incomplete_background_2.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Incomplete backgrounds, Part 2\n\n Background: just a description\n A short description\n\n Scenario: still pickles up\n * a step\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/incomplete_background_2.feature"} diff --git a/testdata/good/incomplete_background_2.feature.tokens b/testdata/good/incomplete_background_2.feature.tokens new file mode 100644 index 0000000..93d10d7 --- /dev/null +++ b/testdata/good/incomplete_background_2.feature.tokens @@ -0,0 +1,8 @@ +(1:1)FeatureLine:Feature/Incomplete backgrounds, Part 2/ +(2:1)Empty:// +(3:3)BackgroundLine:Background/just a description/ +(4:1)Other:/ A short description/ +(5:1)Other:// +(6:3)ScenarioLine:Scenario/still pickles up/ +(7:5)StepLine:* /a step/ +EOF diff --git a/testdata/good/incomplete_feature_1.feature b/testdata/good/incomplete_feature_1.feature new file mode 100644 index 0000000..d8dd71b --- /dev/null +++ b/testdata/good/incomplete_feature_1.feature @@ -0,0 +1,2 @@ +Feature: Just a description + A short description diff --git a/testdata/good/incomplete_feature_1.feature.ast.ndjson b/testdata/good/incomplete_feature_1.feature.ast.ndjson new file mode 100644 index 0000000..2a060d9 --- /dev/null +++ b/testdata/good/incomplete_feature_1.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[],"description":" A short description","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Just a description","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/incomplete_feature_1.feature"} diff --git a/testdata/good/incomplete_feature_1.feature.pickles.ndjson b/testdata/good/incomplete_feature_1.feature.pickles.ndjson new file mode 100644 index 0000000..e69de29 diff --git a/testdata/good/incomplete_feature_1.feature.source.ndjson b/testdata/good/incomplete_feature_1.feature.source.ndjson new file mode 100644 index 0000000..9a07501 --- /dev/null +++ b/testdata/good/incomplete_feature_1.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Just a description\n A short description\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/incomplete_feature_1.feature"} diff --git a/testdata/good/incomplete_feature_1.feature.tokens b/testdata/good/incomplete_feature_1.feature.tokens new file mode 100644 index 0000000..12212f8 --- /dev/null +++ b/testdata/good/incomplete_feature_1.feature.tokens @@ -0,0 +1,3 @@ +(1:1)FeatureLine:Feature/Just a description/ +(2:1)Other:/ A short description/ +EOF diff --git a/testdata/good/incomplete_feature_2.feature b/testdata/good/incomplete_feature_2.feature new file mode 100644 index 0000000..6426c22 --- /dev/null +++ b/testdata/good/incomplete_feature_2.feature @@ -0,0 +1 @@ +Feature: Empty feature diff --git a/testdata/good/incomplete_feature_2.feature.ast.ndjson b/testdata/good/incomplete_feature_2.feature.ast.ndjson new file mode 100644 index 0000000..d75736a --- /dev/null +++ b/testdata/good/incomplete_feature_2.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Empty feature","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/incomplete_feature_2.feature"} diff --git a/testdata/good/incomplete_feature_2.feature.pickles.ndjson b/testdata/good/incomplete_feature_2.feature.pickles.ndjson new file mode 100644 index 0000000..e69de29 diff --git a/testdata/good/incomplete_feature_2.feature.source.ndjson b/testdata/good/incomplete_feature_2.feature.source.ndjson new file mode 100644 index 0000000..e17c619 --- /dev/null +++ b/testdata/good/incomplete_feature_2.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Empty feature\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/incomplete_feature_2.feature"} diff --git a/testdata/good/incomplete_feature_2.feature.tokens b/testdata/good/incomplete_feature_2.feature.tokens new file mode 100644 index 0000000..7ee29f1 --- /dev/null +++ b/testdata/good/incomplete_feature_2.feature.tokens @@ -0,0 +1,2 @@ +(1:1)FeatureLine:Feature/Empty feature/ +EOF diff --git a/testdata/good/incomplete_feature_3.feature b/testdata/good/incomplete_feature_3.feature new file mode 100644 index 0000000..5572bbc --- /dev/null +++ b/testdata/good/incomplete_feature_3.feature @@ -0,0 +1 @@ +# Just a comment \ No newline at end of file diff --git a/testdata/good/incomplete_feature_3.feature.ast.ndjson b/testdata/good/incomplete_feature_3.feature.ast.ndjson new file mode 100644 index 0000000..0072d28 --- /dev/null +++ b/testdata/good/incomplete_feature_3.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[{"location":{"column":1,"line":1},"text":"# Just a comment","type":"Comment"}],"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/incomplete_feature_3.feature"} diff --git a/testdata/good/incomplete_feature_3.feature.pickles.ndjson b/testdata/good/incomplete_feature_3.feature.pickles.ndjson new file mode 100644 index 0000000..e69de29 diff --git a/testdata/good/incomplete_feature_3.feature.source.ndjson b/testdata/good/incomplete_feature_3.feature.source.ndjson new file mode 100644 index 0000000..5268dd6 --- /dev/null +++ b/testdata/good/incomplete_feature_3.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"# Just a comment","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/incomplete_feature_3.feature"} diff --git a/testdata/good/incomplete_feature_3.feature.tokens b/testdata/good/incomplete_feature_3.feature.tokens new file mode 100644 index 0000000..5d6b880 --- /dev/null +++ b/testdata/good/incomplete_feature_3.feature.tokens @@ -0,0 +1,2 @@ +(1:1)Comment:/# Just a comment/ +EOF diff --git a/testdata/good/incomplete_scenario.feature b/testdata/good/incomplete_scenario.feature new file mode 100644 index 0000000..4b88e9b --- /dev/null +++ b/testdata/good/incomplete_scenario.feature @@ -0,0 +1,6 @@ +Feature: Incomplete scenarios + + Background: Adding a background won't make a pickle + * a step + + Scenario: no steps diff --git a/testdata/good/incomplete_scenario.feature.ast.ndjson b/testdata/good/incomplete_scenario.feature.ast.ndjson new file mode 100644 index 0000000..e89abcd --- /dev/null +++ b/testdata/good/incomplete_scenario.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"Background","location":{"column":3,"line":3},"name":"Adding a background won't make a pickle","steps":[{"keyword":"* ","location":{"column":5,"line":4},"text":"a step","type":"Step"}],"type":"Background"},{"keyword":"Scenario","location":{"column":3,"line":6},"name":"no steps","steps":[],"tags":[],"type":"Scenario"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Incomplete scenarios","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/incomplete_scenario.feature"} diff --git a/testdata/good/incomplete_scenario.feature.pickles.ndjson b/testdata/good/incomplete_scenario.feature.pickles.ndjson new file mode 100644 index 0000000..895b704 --- /dev/null +++ b/testdata/good/incomplete_scenario.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":6}],"name":"no steps","steps":[],"tags":[]},"type":"pickle","uri":"testdata/good/incomplete_scenario.feature"} diff --git a/testdata/good/incomplete_scenario.feature.source.ndjson b/testdata/good/incomplete_scenario.feature.source.ndjson new file mode 100644 index 0000000..5c9d71e --- /dev/null +++ b/testdata/good/incomplete_scenario.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Incomplete scenarios\n\n Background: Adding a background won't make a pickle\n * a step\n\n Scenario: no steps\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/incomplete_scenario.feature"} diff --git a/testdata/good/incomplete_scenario.feature.tokens b/testdata/good/incomplete_scenario.feature.tokens new file mode 100644 index 0000000..41a2513 --- /dev/null +++ b/testdata/good/incomplete_scenario.feature.tokens @@ -0,0 +1,7 @@ +(1:1)FeatureLine:Feature/Incomplete scenarios/ +(2:1)Empty:// +(3:3)BackgroundLine:Background/Adding a background won't make a pickle/ +(4:5)StepLine:* /a step/ +(5:1)Empty:// +(6:3)ScenarioLine:Scenario/no steps/ +EOF diff --git a/testdata/good/incomplete_scenario_outline.feature b/testdata/good/incomplete_scenario_outline.feature new file mode 100644 index 0000000..38f842c --- /dev/null +++ b/testdata/good/incomplete_scenario_outline.feature @@ -0,0 +1,24 @@ +Feature: Incomplete scenario outlines + + Background: Adding a background won't make a pickle + * a step + + Scenario Outline: steps, no examples + Given a step + + Scenario Outline: no steps, no examples + + Scenario Outline: no steps, no table + + Examples: + + Scenario Outline: no steps, only table header + + Examples: + | what | + + Scenario Outline: no steps, one example header + + Examples: + | nope | + | nada | diff --git a/testdata/good/incomplete_scenario_outline.feature.ast.ndjson b/testdata/good/incomplete_scenario_outline.feature.ast.ndjson new file mode 100644 index 0000000..640c04f --- /dev/null +++ b/testdata/good/incomplete_scenario_outline.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"Background","location":{"column":3,"line":3},"name":"Adding a background won't make a pickle","steps":[{"keyword":"* ","location":{"column":5,"line":4},"text":"a step","type":"Step"}],"type":"Background"},{"examples":[],"keyword":"Scenario Outline","location":{"column":3,"line":6},"name":"steps, no examples","steps":[{"keyword":"Given ","location":{"column":5,"line":7},"text":"a step","type":"Step"}],"tags":[],"type":"ScenarioOutline"},{"examples":[],"keyword":"Scenario Outline","location":{"column":3,"line":9},"name":"no steps, no examples","steps":[],"tags":[],"type":"ScenarioOutline"},{"examples":[{"keyword":"Examples","location":{"column":5,"line":13},"name":"","tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":11},"name":"no steps, no table","steps":[],"tags":[],"type":"ScenarioOutline"},{"examples":[{"keyword":"Examples","location":{"column":5,"line":17},"name":"","tableBody":[],"tableHeader":{"cells":[{"location":{"column":7,"line":18},"type":"TableCell","value":"what"}],"location":{"column":5,"line":18},"type":"TableRow"},"tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":15},"name":"no steps, only table header","steps":[],"tags":[],"type":"ScenarioOutline"},{"examples":[{"keyword":"Examples","location":{"column":5,"line":22},"name":"","tableBody":[{"cells":[{"location":{"column":7,"line":24},"type":"TableCell","value":"nada"}],"location":{"column":5,"line":24},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":7,"line":23},"type":"TableCell","value":"nope"}],"location":{"column":5,"line":23},"type":"TableRow"},"tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":20},"name":"no steps, one example header","steps":[],"tags":[],"type":"ScenarioOutline"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Incomplete scenario outlines","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/incomplete_scenario_outline.feature"} diff --git a/testdata/good/incomplete_scenario_outline.feature.pickles.ndjson b/testdata/good/incomplete_scenario_outline.feature.pickles.ndjson new file mode 100644 index 0000000..3c9bfa8 --- /dev/null +++ b/testdata/good/incomplete_scenario_outline.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":5,"line":24},{"column":3,"line":20}],"name":"no steps, one example header","steps":[],"tags":[]},"type":"pickle","uri":"testdata/good/incomplete_scenario_outline.feature"} diff --git a/testdata/good/incomplete_scenario_outline.feature.source.ndjson b/testdata/good/incomplete_scenario_outline.feature.source.ndjson new file mode 100644 index 0000000..f9dd648 --- /dev/null +++ b/testdata/good/incomplete_scenario_outline.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Incomplete scenario outlines\n\n Background: Adding a background won't make a pickle\n * a step\n\n Scenario Outline: steps, no examples\n Given a step\n\n Scenario Outline: no steps, no examples\n\n Scenario Outline: no steps, no table\n\n Examples:\n\n Scenario Outline: no steps, only table header\n\n Examples:\n | what |\n\n Scenario Outline: no steps, one example header\n\n Examples:\n | nope |\n | nada |\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/incomplete_scenario_outline.feature"} diff --git a/testdata/good/incomplete_scenario_outline.feature.tokens b/testdata/good/incomplete_scenario_outline.feature.tokens new file mode 100644 index 0000000..7de3448 --- /dev/null +++ b/testdata/good/incomplete_scenario_outline.feature.tokens @@ -0,0 +1,25 @@ +(1:1)FeatureLine:Feature/Incomplete scenario outlines/ +(2:1)Empty:// +(3:3)BackgroundLine:Background/Adding a background won't make a pickle/ +(4:5)StepLine:* /a step/ +(5:1)Empty:// +(6:3)ScenarioOutlineLine:Scenario Outline/steps, no examples/ +(7:5)StepLine:Given /a step/ +(8:1)Empty:// +(9:3)ScenarioOutlineLine:Scenario Outline/no steps, no examples/ +(10:1)Empty:// +(11:3)ScenarioOutlineLine:Scenario Outline/no steps, no table/ +(12:1)Empty:// +(13:5)ExamplesLine:Examples// +(14:1)Empty:// +(15:3)ScenarioOutlineLine:Scenario Outline/no steps, only table header/ +(16:1)Empty:// +(17:5)ExamplesLine:Examples// +(18:5)TableRow://7:what +(19:1)Empty:// +(20:3)ScenarioOutlineLine:Scenario Outline/no steps, one example header/ +(21:1)Empty:// +(22:5)ExamplesLine:Examples// +(23:5)TableRow://7:nope +(24:5)TableRow://7:nada +EOF diff --git a/testdata/good/language.feature b/testdata/good/language.feature new file mode 100644 index 0000000..564dd42 --- /dev/null +++ b/testdata/good/language.feature @@ -0,0 +1,6 @@ +#language:en + +Feature: Explicit language specification + + Scenario: minimalistic + Given the minimalism diff --git a/testdata/good/language.feature.ast.ndjson b/testdata/good/language.feature.ast.ndjson new file mode 100644 index 0000000..f9a6ac8 --- /dev/null +++ b/testdata/good/language.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"Scenario","location":{"column":3,"line":5},"name":"minimalistic","steps":[{"keyword":"Given ","location":{"column":5,"line":6},"text":"the minimalism","type":"Step"}],"tags":[],"type":"Scenario"}],"keyword":"Feature","language":"en","location":{"column":1,"line":3},"name":"Explicit language specification","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/language.feature"} diff --git a/testdata/good/language.feature.pickles.ndjson b/testdata/good/language.feature.pickles.ndjson new file mode 100644 index 0000000..5bd39e1 --- /dev/null +++ b/testdata/good/language.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":5}],"name":"minimalistic","steps":[{"arguments":[],"locations":[{"column":11,"line":6}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/language.feature"} diff --git a/testdata/good/language.feature.source.ndjson b/testdata/good/language.feature.source.ndjson new file mode 100644 index 0000000..2f66c09 --- /dev/null +++ b/testdata/good/language.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"#language:en\n\nFeature: Explicit language specification\n\n Scenario: minimalistic\n Given the minimalism\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/language.feature"} diff --git a/testdata/good/language.feature.tokens b/testdata/good/language.feature.tokens new file mode 100644 index 0000000..c914b35 --- /dev/null +++ b/testdata/good/language.feature.tokens @@ -0,0 +1,7 @@ +(1:1)Language:/en/ +(2:1)Empty:// +(3:1)FeatureLine:Feature/Explicit language specification/ +(4:1)Empty:// +(5:3)ScenarioLine:Scenario/minimalistic/ +(6:5)StepLine:Given /the minimalism/ +EOF diff --git a/testdata/good/minimal.feature b/testdata/good/minimal.feature new file mode 100644 index 0000000..9a62d86 --- /dev/null +++ b/testdata/good/minimal.feature @@ -0,0 +1,4 @@ +Feature: Minimal + + Scenario: minimalistic + Given the minimalism diff --git a/testdata/good/minimal.feature.ast.ndjson b/testdata/good/minimal.feature.ast.ndjson new file mode 100644 index 0000000..e7c81a5 --- /dev/null +++ b/testdata/good/minimal.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"Scenario","location":{"column":3,"line":3},"name":"minimalistic","steps":[{"keyword":"Given ","location":{"column":5,"line":4},"text":"the minimalism","type":"Step"}],"tags":[],"type":"Scenario"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Minimal","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/minimal.feature"} diff --git a/testdata/good/minimal.feature.pickles.ndjson b/testdata/good/minimal.feature.pickles.ndjson new file mode 100644 index 0000000..3654aaa --- /dev/null +++ b/testdata/good/minimal.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":3}],"name":"minimalistic","steps":[{"arguments":[],"locations":[{"column":11,"line":4}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/minimal.feature"} diff --git a/testdata/good/minimal.feature.source.ndjson b/testdata/good/minimal.feature.source.ndjson new file mode 100644 index 0000000..6fcbebf --- /dev/null +++ b/testdata/good/minimal.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Minimal\n\n Scenario: minimalistic\n Given the minimalism\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/minimal.feature"} diff --git a/testdata/good/minimal.feature.tokens b/testdata/good/minimal.feature.tokens new file mode 100644 index 0000000..a1958fa --- /dev/null +++ b/testdata/good/minimal.feature.tokens @@ -0,0 +1,5 @@ +(1:1)FeatureLine:Feature/Minimal/ +(2:1)Empty:// +(3:3)ScenarioLine:Scenario/minimalistic/ +(4:5)StepLine:Given /the minimalism/ +EOF diff --git a/testdata/good/readme_example.feature b/testdata/good/readme_example.feature new file mode 100644 index 0000000..4dff21a --- /dev/null +++ b/testdata/good/readme_example.feature @@ -0,0 +1,18 @@ +@a +Feature: + @b @c + Scenario Outline: + Given + + Examples: + | x | + | y | + + @d @e + Scenario Outline: + Given + + @f + Examples: + | m | + | n | diff --git a/testdata/good/readme_example.feature.ast.ndjson b/testdata/good/readme_example.feature.ast.ndjson new file mode 100644 index 0000000..27a2266 --- /dev/null +++ b/testdata/good/readme_example.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"examples":[{"keyword":"Examples","location":{"column":5,"line":7},"name":"","tableBody":[{"cells":[{"location":{"column":9,"line":9},"type":"TableCell","value":"y"}],"location":{"column":7,"line":9},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":9,"line":8},"type":"TableCell","value":"x"}],"location":{"column":7,"line":8},"type":"TableRow"},"tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":4},"name":"","steps":[{"keyword":"Given ","location":{"column":5,"line":5},"text":"","type":"Step"}],"tags":[{"location":{"column":3,"line":3},"name":"@b","type":"Tag"},{"location":{"column":6,"line":3},"name":"@c","type":"Tag"}],"type":"ScenarioOutline"},{"examples":[{"keyword":"Examples","location":{"column":5,"line":16},"name":"","tableBody":[{"cells":[{"location":{"column":9,"line":18},"type":"TableCell","value":"n"}],"location":{"column":7,"line":18},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":9,"line":17},"type":"TableCell","value":"m"}],"location":{"column":7,"line":17},"type":"TableRow"},"tags":[{"location":{"column":5,"line":15},"name":"@f","type":"Tag"}],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":12},"name":"","steps":[{"keyword":"Given ","location":{"column":5,"line":13},"text":"","type":"Step"}],"tags":[{"location":{"column":3,"line":11},"name":"@d","type":"Tag"},{"location":{"column":6,"line":11},"name":"@e","type":"Tag"}],"type":"ScenarioOutline"}],"keyword":"Feature","language":"en","location":{"column":1,"line":2},"name":"","tags":[{"location":{"column":1,"line":1},"name":"@a","type":"Tag"}],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/readme_example.feature"} diff --git a/testdata/good/readme_example.feature.pickles.ndjson b/testdata/good/readme_example.feature.pickles.ndjson new file mode 100644 index 0000000..39e6e75 --- /dev/null +++ b/testdata/good/readme_example.feature.pickles.ndjson @@ -0,0 +1,2 @@ +{"pickle":{"language":"en","locations":[{"column":7,"line":9},{"column":3,"line":4}],"name":"","steps":[{"arguments":[],"locations":[{"column":7,"line":9},{"column":11,"line":5}],"text":"y"}],"tags":[{"location":{"column":1,"line":1},"name":"@a"},{"location":{"column":3,"line":3},"name":"@b"},{"location":{"column":6,"line":3},"name":"@c"}]},"type":"pickle","uri":"testdata/good/readme_example.feature"} +{"pickle":{"language":"en","locations":[{"column":7,"line":18},{"column":3,"line":12}],"name":"","steps":[{"arguments":[],"locations":[{"column":7,"line":18},{"column":11,"line":13}],"text":"n"}],"tags":[{"location":{"column":1,"line":1},"name":"@a"},{"location":{"column":3,"line":11},"name":"@d"},{"location":{"column":6,"line":11},"name":"@e"},{"location":{"column":5,"line":15},"name":"@f"}]},"type":"pickle","uri":"testdata/good/readme_example.feature"} diff --git a/testdata/good/readme_example.feature.source.ndjson b/testdata/good/readme_example.feature.source.ndjson new file mode 100644 index 0000000..5e8ec20 --- /dev/null +++ b/testdata/good/readme_example.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"@a\nFeature:\n @b @c\n Scenario Outline:\n Given \n\n Examples:\n | x |\n | y |\n\n @d @e\n Scenario Outline:\n Given \n\n @f\n Examples:\n | m |\n | n |\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/readme_example.feature"} diff --git a/testdata/good/readme_example.feature.tokens b/testdata/good/readme_example.feature.tokens new file mode 100644 index 0000000..cdaf981 --- /dev/null +++ b/testdata/good/readme_example.feature.tokens @@ -0,0 +1,19 @@ +(1:1)TagLine://1:@a +(2:1)FeatureLine:Feature// +(3:3)TagLine://3:@b,6:@c +(4:3)ScenarioOutlineLine:Scenario Outline// +(5:5)StepLine:Given // +(6:1)Empty:// +(7:5)ExamplesLine:Examples// +(8:7)TableRow://9:x +(9:7)TableRow://9:y +(10:1)Empty:// +(11:3)TagLine://3:@d,6:@e +(12:3)ScenarioOutlineLine:Scenario Outline// +(13:5)StepLine:Given // +(14:1)Empty:// +(15:5)TagLine://5:@f +(16:5)ExamplesLine:Examples// +(17:7)TableRow://9:m +(18:7)TableRow://9:n +EOF diff --git a/testdata/good/scenario_outline.feature b/testdata/good/scenario_outline.feature new file mode 100644 index 0000000..df3e0a4 --- /dev/null +++ b/testdata/good/scenario_outline.feature @@ -0,0 +1,8 @@ +Feature: Minimal Scenario Outline + +Scenario Outline: minimalistic + Given the + +Examples: + | what | + | minimalism | diff --git a/testdata/good/scenario_outline.feature.ast.ndjson b/testdata/good/scenario_outline.feature.ast.ndjson new file mode 100644 index 0000000..7e7412b --- /dev/null +++ b/testdata/good/scenario_outline.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"examples":[{"keyword":"Examples","location":{"column":1,"line":6},"name":"","tableBody":[{"cells":[{"location":{"column":5,"line":8},"type":"TableCell","value":"minimalism"}],"location":{"column":3,"line":8},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":5,"line":7},"type":"TableCell","value":"what"}],"location":{"column":3,"line":7},"type":"TableRow"},"tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":1,"line":3},"name":"minimalistic","steps":[{"keyword":"Given ","location":{"column":5,"line":4},"text":"the ","type":"Step"}],"tags":[],"type":"ScenarioOutline"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Minimal Scenario Outline","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/scenario_outline.feature"} diff --git a/testdata/good/scenario_outline.feature.pickles.ndjson b/testdata/good/scenario_outline.feature.pickles.ndjson new file mode 100644 index 0000000..14f40b7 --- /dev/null +++ b/testdata/good/scenario_outline.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":8},{"column":1,"line":3}],"name":"minimalistic","steps":[{"arguments":[],"locations":[{"column":3,"line":8},{"column":11,"line":4}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/scenario_outline.feature"} diff --git a/testdata/good/scenario_outline.feature.source.ndjson b/testdata/good/scenario_outline.feature.source.ndjson new file mode 100644 index 0000000..1bff391 --- /dev/null +++ b/testdata/good/scenario_outline.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Minimal Scenario Outline\n\nScenario Outline: minimalistic\n Given the \n\nExamples:\n | what |\n | minimalism |\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/scenario_outline.feature"} diff --git a/testdata/good/scenario_outline.feature.tokens b/testdata/good/scenario_outline.feature.tokens new file mode 100644 index 0000000..2851d38 --- /dev/null +++ b/testdata/good/scenario_outline.feature.tokens @@ -0,0 +1,9 @@ +(1:1)FeatureLine:Feature/Minimal Scenario Outline/ +(2:1)Empty:// +(3:1)ScenarioOutlineLine:Scenario Outline/minimalistic/ +(4:5)StepLine:Given /the / +(5:1)Empty:// +(6:1)ExamplesLine:Examples// +(7:3)TableRow://5:what +(8:3)TableRow://5:minimalism +EOF diff --git a/testdata/good/scenario_outline_no_newline.feature b/testdata/good/scenario_outline_no_newline.feature new file mode 100644 index 0000000..10ed0af --- /dev/null +++ b/testdata/good/scenario_outline_no_newline.feature @@ -0,0 +1,8 @@ +Feature: Minimal Scenario Outline + +Scenario Outline: minimalistic + Given the + +Examples: + | what | + | minimalism | \ No newline at end of file diff --git a/testdata/good/scenario_outline_no_newline.feature.ast.ndjson b/testdata/good/scenario_outline_no_newline.feature.ast.ndjson new file mode 100644 index 0000000..541a244 --- /dev/null +++ b/testdata/good/scenario_outline_no_newline.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"examples":[{"keyword":"Examples","location":{"column":1,"line":6},"name":"","tableBody":[{"cells":[{"location":{"column":5,"line":8},"type":"TableCell","value":"minimalism"}],"location":{"column":3,"line":8},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":5,"line":7},"type":"TableCell","value":"what"}],"location":{"column":3,"line":7},"type":"TableRow"},"tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":1,"line":3},"name":"minimalistic","steps":[{"keyword":"Given ","location":{"column":5,"line":4},"text":"the ","type":"Step"}],"tags":[],"type":"ScenarioOutline"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Minimal Scenario Outline","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/scenario_outline_no_newline.feature"} diff --git a/testdata/good/scenario_outline_no_newline.feature.pickles.ndjson b/testdata/good/scenario_outline_no_newline.feature.pickles.ndjson new file mode 100644 index 0000000..c61baac --- /dev/null +++ b/testdata/good/scenario_outline_no_newline.feature.pickles.ndjson @@ -0,0 +1 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":8},{"column":1,"line":3}],"name":"minimalistic","steps":[{"arguments":[],"locations":[{"column":3,"line":8},{"column":11,"line":4}],"text":"the minimalism"}],"tags":[]},"type":"pickle","uri":"testdata/good/scenario_outline_no_newline.feature"} diff --git a/testdata/good/scenario_outline_no_newline.feature.source.ndjson b/testdata/good/scenario_outline_no_newline.feature.source.ndjson new file mode 100644 index 0000000..a4347c1 --- /dev/null +++ b/testdata/good/scenario_outline_no_newline.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Minimal Scenario Outline\n\nScenario Outline: minimalistic\n Given the \n\nExamples:\n | what |\n | minimalism |","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/scenario_outline_no_newline.feature"} diff --git a/testdata/good/scenario_outline_no_newline.feature.tokens b/testdata/good/scenario_outline_no_newline.feature.tokens new file mode 100644 index 0000000..2851d38 --- /dev/null +++ b/testdata/good/scenario_outline_no_newline.feature.tokens @@ -0,0 +1,9 @@ +(1:1)FeatureLine:Feature/Minimal Scenario Outline/ +(2:1)Empty:// +(3:1)ScenarioOutlineLine:Scenario Outline/minimalistic/ +(4:5)StepLine:Given /the / +(5:1)Empty:// +(6:1)ExamplesLine:Examples// +(7:3)TableRow://5:what +(8:3)TableRow://5:minimalism +EOF diff --git a/testdata/good/scenario_outline_with_docstring.feature b/testdata/good/scenario_outline_with_docstring.feature new file mode 100644 index 0000000..cfa9eef --- /dev/null +++ b/testdata/good/scenario_outline_with_docstring.feature @@ -0,0 +1,12 @@ +Feature: Scenario Outline with a docstring + +Scenario Outline: Greetings come in many forms + Given this file: + """ + Greeting: + """ + +Examples: + | type | content | + | en | Hello | + | fr | Bonjour | diff --git a/testdata/good/scenario_outline_with_docstring.feature.ast.ndjson b/testdata/good/scenario_outline_with_docstring.feature.ast.ndjson new file mode 100644 index 0000000..014a975 --- /dev/null +++ b/testdata/good/scenario_outline_with_docstring.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"examples":[{"keyword":"Examples","location":{"column":1,"line":9},"name":"","tableBody":[{"cells":[{"location":{"column":5,"line":11},"type":"TableCell","value":"en"},{"location":{"column":13,"line":11},"type":"TableCell","value":"Hello"}],"location":{"column":3,"line":11},"type":"TableRow"},{"cells":[{"location":{"column":5,"line":12},"type":"TableCell","value":"fr"},{"location":{"column":13,"line":12},"type":"TableCell","value":"Bonjour"}],"location":{"column":3,"line":12},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":5,"line":10},"type":"TableCell","value":"type"},{"location":{"column":13,"line":10},"type":"TableCell","value":"content"}],"location":{"column":3,"line":10},"type":"TableRow"},"tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":1,"line":3},"name":"Greetings come in many forms","steps":[{"argument":{"content":"Greeting:","contentType":"","location":{"column":5,"line":5},"type":"DocString"},"keyword":"Given ","location":{"column":5,"line":4},"text":"this file:","type":"Step"}],"tags":[],"type":"ScenarioOutline"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Scenario Outline with a docstring","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/scenario_outline_with_docstring.feature"} diff --git a/testdata/good/scenario_outline_with_docstring.feature.pickles.ndjson b/testdata/good/scenario_outline_with_docstring.feature.pickles.ndjson new file mode 100644 index 0000000..934b2fb --- /dev/null +++ b/testdata/good/scenario_outline_with_docstring.feature.pickles.ndjson @@ -0,0 +1,2 @@ +{"pickle":{"language":"en","locations":[{"column":3,"line":11},{"column":1,"line":3}],"name":"Greetings come in many forms","steps":[{"arguments":[{"content":"Greeting:Hello","contentType":"en","location":{"column":5,"line":5}}],"locations":[{"column":3,"line":11},{"column":11,"line":4}],"text":"this file:"}],"tags":[]},"type":"pickle","uri":"testdata/good/scenario_outline_with_docstring.feature"} +{"pickle":{"language":"en","locations":[{"column":3,"line":12},{"column":1,"line":3}],"name":"Greetings come in many forms","steps":[{"arguments":[{"content":"Greeting:Bonjour","contentType":"fr","location":{"column":5,"line":5}}],"locations":[{"column":3,"line":12},{"column":11,"line":4}],"text":"this file:"}],"tags":[]},"type":"pickle","uri":"testdata/good/scenario_outline_with_docstring.feature"} diff --git a/testdata/good/scenario_outline_with_docstring.feature.source.ndjson b/testdata/good/scenario_outline_with_docstring.feature.source.ndjson new file mode 100644 index 0000000..17fadf2 --- /dev/null +++ b/testdata/good/scenario_outline_with_docstring.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Scenario Outline with a docstring\n\nScenario Outline: Greetings come in many forms\n Given this file:\n \"\"\"\n Greeting:\n \"\"\"\n\nExamples:\n | type | content |\n | en | Hello |\n | fr | Bonjour |\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/scenario_outline_with_docstring.feature"} diff --git a/testdata/good/scenario_outline_with_docstring.feature.tokens b/testdata/good/scenario_outline_with_docstring.feature.tokens new file mode 100644 index 0000000..5b91732 --- /dev/null +++ b/testdata/good/scenario_outline_with_docstring.feature.tokens @@ -0,0 +1,13 @@ +(1:1)FeatureLine:Feature/Scenario Outline with a docstring/ +(2:1)Empty:// +(3:1)ScenarioOutlineLine:Scenario Outline/Greetings come in many forms/ +(4:5)StepLine:Given /this file:/ +(5:5)DocStringSeparator:// +(6:1)Other:/Greeting:/ +(7:5)DocStringSeparator:// +(8:1)Empty:// +(9:1)ExamplesLine:Examples// +(10:3)TableRow://5:type,13:content +(11:3)TableRow://5:en,13:Hello +(12:3)TableRow://5:fr,13:Bonjour +EOF diff --git a/testdata/good/scenario_outlines_with_tags.feature b/testdata/good/scenario_outlines_with_tags.feature new file mode 100644 index 0000000..4dff21a --- /dev/null +++ b/testdata/good/scenario_outlines_with_tags.feature @@ -0,0 +1,18 @@ +@a +Feature: + @b @c + Scenario Outline: + Given + + Examples: + | x | + | y | + + @d @e + Scenario Outline: + Given + + @f + Examples: + | m | + | n | diff --git a/testdata/good/scenario_outlines_with_tags.feature.ast.ndjson b/testdata/good/scenario_outlines_with_tags.feature.ast.ndjson new file mode 100644 index 0000000..cf63f6b --- /dev/null +++ b/testdata/good/scenario_outlines_with_tags.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"examples":[{"keyword":"Examples","location":{"column":5,"line":7},"name":"","tableBody":[{"cells":[{"location":{"column":9,"line":9},"type":"TableCell","value":"y"}],"location":{"column":7,"line":9},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":9,"line":8},"type":"TableCell","value":"x"}],"location":{"column":7,"line":8},"type":"TableRow"},"tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":4},"name":"","steps":[{"keyword":"Given ","location":{"column":5,"line":5},"text":"","type":"Step"}],"tags":[{"location":{"column":3,"line":3},"name":"@b","type":"Tag"},{"location":{"column":6,"line":3},"name":"@c","type":"Tag"}],"type":"ScenarioOutline"},{"examples":[{"keyword":"Examples","location":{"column":5,"line":16},"name":"","tableBody":[{"cells":[{"location":{"column":9,"line":18},"type":"TableCell","value":"n"}],"location":{"column":7,"line":18},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":9,"line":17},"type":"TableCell","value":"m"}],"location":{"column":7,"line":17},"type":"TableRow"},"tags":[{"location":{"column":5,"line":15},"name":"@f","type":"Tag"}],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":12},"name":"","steps":[{"keyword":"Given ","location":{"column":5,"line":13},"text":"","type":"Step"}],"tags":[{"location":{"column":3,"line":11},"name":"@d","type":"Tag"},{"location":{"column":6,"line":11},"name":"@e","type":"Tag"}],"type":"ScenarioOutline"}],"keyword":"Feature","language":"en","location":{"column":1,"line":2},"name":"","tags":[{"location":{"column":1,"line":1},"name":"@a","type":"Tag"}],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/scenario_outlines_with_tags.feature"} diff --git a/testdata/good/scenario_outlines_with_tags.feature.pickles.ndjson b/testdata/good/scenario_outlines_with_tags.feature.pickles.ndjson new file mode 100644 index 0000000..ecc15fc --- /dev/null +++ b/testdata/good/scenario_outlines_with_tags.feature.pickles.ndjson @@ -0,0 +1,2 @@ +{"pickle":{"language":"en","locations":[{"column":7,"line":9},{"column":3,"line":4}],"name":"","steps":[{"arguments":[],"locations":[{"column":7,"line":9},{"column":11,"line":5}],"text":"y"}],"tags":[{"location":{"column":1,"line":1},"name":"@a"},{"location":{"column":3,"line":3},"name":"@b"},{"location":{"column":6,"line":3},"name":"@c"}]},"type":"pickle","uri":"testdata/good/scenario_outlines_with_tags.feature"} +{"pickle":{"language":"en","locations":[{"column":7,"line":18},{"column":3,"line":12}],"name":"","steps":[{"arguments":[],"locations":[{"column":7,"line":18},{"column":11,"line":13}],"text":"n"}],"tags":[{"location":{"column":1,"line":1},"name":"@a"},{"location":{"column":3,"line":11},"name":"@d"},{"location":{"column":6,"line":11},"name":"@e"},{"location":{"column":5,"line":15},"name":"@f"}]},"type":"pickle","uri":"testdata/good/scenario_outlines_with_tags.feature"} diff --git a/testdata/good/scenario_outlines_with_tags.feature.source.ndjson b/testdata/good/scenario_outlines_with_tags.feature.source.ndjson new file mode 100644 index 0000000..391d1ad --- /dev/null +++ b/testdata/good/scenario_outlines_with_tags.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"@a\nFeature:\n @b @c\n Scenario Outline:\n Given \n\n Examples:\n | x |\n | y |\n\n @d @e\n Scenario Outline:\n Given \n\n @f\n Examples:\n | m |\n | n |\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/scenario_outlines_with_tags.feature"} diff --git a/testdata/good/scenario_outlines_with_tags.feature.tokens b/testdata/good/scenario_outlines_with_tags.feature.tokens new file mode 100644 index 0000000..cdaf981 --- /dev/null +++ b/testdata/good/scenario_outlines_with_tags.feature.tokens @@ -0,0 +1,19 @@ +(1:1)TagLine://1:@a +(2:1)FeatureLine:Feature// +(3:3)TagLine://3:@b,6:@c +(4:3)ScenarioOutlineLine:Scenario Outline// +(5:5)StepLine:Given // +(6:1)Empty:// +(7:5)ExamplesLine:Examples// +(8:7)TableRow://9:x +(9:7)TableRow://9:y +(10:1)Empty:// +(11:3)TagLine://3:@d,6:@e +(12:3)ScenarioOutlineLine:Scenario Outline// +(13:5)StepLine:Given // +(14:1)Empty:// +(15:5)TagLine://5:@f +(16:5)ExamplesLine:Examples// +(17:7)TableRow://9:m +(18:7)TableRow://9:n +EOF diff --git a/testdata/good/several_examples.feature b/testdata/good/several_examples.feature new file mode 100644 index 0000000..dcd6426 --- /dev/null +++ b/testdata/good/several_examples.feature @@ -0,0 +1,17 @@ +Feature: Tagged Examples + + Scenario Outline: minimalistic + Given the + + @foo + Examples: + | what | + | foo | + + @bar + Examples: + | what | + | bar | + + @zap + Scenario: ha ok diff --git a/testdata/good/several_examples.feature.ast.ndjson b/testdata/good/several_examples.feature.ast.ndjson new file mode 100644 index 0000000..b58f5a3 --- /dev/null +++ b/testdata/good/several_examples.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"examples":[{"keyword":"Examples","location":{"column":5,"line":7},"name":"","tableBody":[{"cells":[{"location":{"column":9,"line":9},"type":"TableCell","value":"foo"}],"location":{"column":7,"line":9},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":9,"line":8},"type":"TableCell","value":"what"}],"location":{"column":7,"line":8},"type":"TableRow"},"tags":[{"location":{"column":5,"line":6},"name":"@foo","type":"Tag"}],"type":"Examples"},{"keyword":"Examples","location":{"column":5,"line":12},"name":"","tableBody":[{"cells":[{"location":{"column":9,"line":14},"type":"TableCell","value":"bar"}],"location":{"column":7,"line":14},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":9,"line":13},"type":"TableCell","value":"what"}],"location":{"column":7,"line":13},"type":"TableRow"},"tags":[{"location":{"column":5,"line":11},"name":"@bar","type":"Tag"}],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":3},"name":"minimalistic","steps":[{"keyword":"Given ","location":{"column":5,"line":4},"text":"the ","type":"Step"}],"tags":[],"type":"ScenarioOutline"},{"keyword":"Scenario","location":{"column":3,"line":17},"name":"ha ok","steps":[],"tags":[{"location":{"column":3,"line":16},"name":"@zap","type":"Tag"}],"type":"Scenario"}],"keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Tagged Examples","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/several_examples.feature"} diff --git a/testdata/good/several_examples.feature.pickles.ndjson b/testdata/good/several_examples.feature.pickles.ndjson new file mode 100644 index 0000000..c6a038d --- /dev/null +++ b/testdata/good/several_examples.feature.pickles.ndjson @@ -0,0 +1,3 @@ +{"pickle":{"language":"en","locations":[{"column":7,"line":9},{"column":3,"line":3}],"name":"minimalistic","steps":[{"arguments":[],"locations":[{"column":7,"line":9},{"column":11,"line":4}],"text":"the foo"}],"tags":[{"location":{"column":5,"line":6},"name":"@foo"}]},"type":"pickle","uri":"testdata/good/several_examples.feature"} +{"pickle":{"language":"en","locations":[{"column":7,"line":14},{"column":3,"line":3}],"name":"minimalistic","steps":[{"arguments":[],"locations":[{"column":7,"line":14},{"column":11,"line":4}],"text":"the bar"}],"tags":[{"location":{"column":5,"line":11},"name":"@bar"}]},"type":"pickle","uri":"testdata/good/several_examples.feature"} +{"pickle":{"language":"en","locations":[{"column":3,"line":17}],"name":"ha ok","steps":[],"tags":[{"location":{"column":3,"line":16},"name":"@zap"}]},"type":"pickle","uri":"testdata/good/several_examples.feature"} diff --git a/testdata/good/several_examples.feature.source.ndjson b/testdata/good/several_examples.feature.source.ndjson new file mode 100644 index 0000000..d4f0b2e --- /dev/null +++ b/testdata/good/several_examples.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"Feature: Tagged Examples\n\n Scenario Outline: minimalistic\n Given the \n\n @foo\n Examples:\n | what |\n | foo |\n\n @bar\n Examples:\n | what |\n | bar |\n\n @zap\n Scenario: ha ok\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/several_examples.feature"} diff --git a/testdata/good/several_examples.feature.tokens b/testdata/good/several_examples.feature.tokens new file mode 100644 index 0000000..904c7a8 --- /dev/null +++ b/testdata/good/several_examples.feature.tokens @@ -0,0 +1,18 @@ +(1:1)FeatureLine:Feature/Tagged Examples/ +(2:1)Empty:// +(3:3)ScenarioOutlineLine:Scenario Outline/minimalistic/ +(4:5)StepLine:Given /the / +(5:1)Empty:// +(6:5)TagLine://5:@foo +(7:5)ExamplesLine:Examples// +(8:7)TableRow://9:what +(9:7)TableRow://9:foo +(10:1)Empty:// +(11:5)TagLine://5:@bar +(12:5)ExamplesLine:Examples// +(13:7)TableRow://9:what +(14:7)TableRow://9:bar +(15:1)Empty:// +(16:3)TagLine://3:@zap +(17:3)ScenarioLine:Scenario/ha ok/ +EOF diff --git a/testdata/good/spaces_in_language.feature b/testdata/good/spaces_in_language.feature new file mode 100644 index 0000000..5248fd7 --- /dev/null +++ b/testdata/good/spaces_in_language.feature @@ -0,0 +1,2 @@ + # language : en-lol +OH HAI: STUFFING diff --git a/testdata/good/spaces_in_language.feature.ast.ndjson b/testdata/good/spaces_in_language.feature.ast.ndjson new file mode 100644 index 0000000..e152835 --- /dev/null +++ b/testdata/good/spaces_in_language.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[],"keyword":"OH HAI","language":"en-lol","location":{"column":1,"line":2},"name":"STUFFING","tags":[],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/spaces_in_language.feature"} diff --git a/testdata/good/spaces_in_language.feature.pickles.ndjson b/testdata/good/spaces_in_language.feature.pickles.ndjson new file mode 100644 index 0000000..e69de29 diff --git a/testdata/good/spaces_in_language.feature.source.ndjson b/testdata/good/spaces_in_language.feature.source.ndjson new file mode 100644 index 0000000..2416ad0 --- /dev/null +++ b/testdata/good/spaces_in_language.feature.source.ndjson @@ -0,0 +1 @@ +{"data":" # language : en-lol\nOH HAI: STUFFING\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/spaces_in_language.feature"} diff --git a/testdata/good/spaces_in_language.feature.tokens b/testdata/good/spaces_in_language.feature.tokens new file mode 100644 index 0000000..55f55b2 --- /dev/null +++ b/testdata/good/spaces_in_language.feature.tokens @@ -0,0 +1,3 @@ +(1:3)Language:/en-lol/ +(2:1)FeatureLine:OH HAI/STUFFING/ +EOF diff --git a/testdata/good/tagged_feature_with_scenario_outline.feature b/testdata/good/tagged_feature_with_scenario_outline.feature new file mode 100644 index 0000000..d461062 --- /dev/null +++ b/testdata/good/tagged_feature_with_scenario_outline.feature @@ -0,0 +1,10 @@ +@sometag +Feature: Foo + + Scenario Outline: Bar + Then Baz + + Examples: + | name | + | X | + | Y | diff --git a/testdata/good/tagged_feature_with_scenario_outline.feature.ast.ndjson b/testdata/good/tagged_feature_with_scenario_outline.feature.ast.ndjson new file mode 100644 index 0000000..ab6b599 --- /dev/null +++ b/testdata/good/tagged_feature_with_scenario_outline.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"examples":[{"keyword":"Examples","location":{"column":5,"line":7},"name":"","tableBody":[{"cells":[{"location":{"column":7,"line":9},"type":"TableCell","value":"X"}],"location":{"column":5,"line":9},"type":"TableRow"},{"cells":[{"location":{"column":7,"line":10},"type":"TableCell","value":"Y"}],"location":{"column":5,"line":10},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":7,"line":8},"type":"TableCell","value":"name"}],"location":{"column":5,"line":8},"type":"TableRow"},"tags":[],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":3,"line":4},"name":"Bar","steps":[{"keyword":"Then ","location":{"column":5,"line":5},"text":"Baz","type":"Step"}],"tags":[],"type":"ScenarioOutline"}],"keyword":"Feature","language":"en","location":{"column":1,"line":2},"name":"Foo","tags":[{"location":{"column":1,"line":1},"name":"@sometag","type":"Tag"}],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/tagged_feature_with_scenario_outline.feature"} diff --git a/testdata/good/tagged_feature_with_scenario_outline.feature.pickles.ndjson b/testdata/good/tagged_feature_with_scenario_outline.feature.pickles.ndjson new file mode 100644 index 0000000..37ad16b --- /dev/null +++ b/testdata/good/tagged_feature_with_scenario_outline.feature.pickles.ndjson @@ -0,0 +1,2 @@ +{"pickle":{"language":"en","locations":[{"column":5,"line":9},{"column":3,"line":4}],"name":"Bar","steps":[{"arguments":[],"locations":[{"column":5,"line":9},{"column":10,"line":5}],"text":"Baz"}],"tags":[{"location":{"column":1,"line":1},"name":"@sometag"}]},"type":"pickle","uri":"testdata/good/tagged_feature_with_scenario_outline.feature"} +{"pickle":{"language":"en","locations":[{"column":5,"line":10},{"column":3,"line":4}],"name":"Bar","steps":[{"arguments":[],"locations":[{"column":5,"line":10},{"column":10,"line":5}],"text":"Baz"}],"tags":[{"location":{"column":1,"line":1},"name":"@sometag"}]},"type":"pickle","uri":"testdata/good/tagged_feature_with_scenario_outline.feature"} diff --git a/testdata/good/tagged_feature_with_scenario_outline.feature.source.ndjson b/testdata/good/tagged_feature_with_scenario_outline.feature.source.ndjson new file mode 100644 index 0000000..42e204f --- /dev/null +++ b/testdata/good/tagged_feature_with_scenario_outline.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"@sometag\nFeature: Foo\n\n Scenario Outline: Bar\n Then Baz\n\n Examples:\n | name |\n | X |\n | Y |\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/tagged_feature_with_scenario_outline.feature"} diff --git a/testdata/good/tagged_feature_with_scenario_outline.feature.tokens b/testdata/good/tagged_feature_with_scenario_outline.feature.tokens new file mode 100644 index 0000000..208b536 --- /dev/null +++ b/testdata/good/tagged_feature_with_scenario_outline.feature.tokens @@ -0,0 +1,11 @@ +(1:1)TagLine://1:@sometag +(2:1)FeatureLine:Feature/Foo/ +(3:1)Empty:// +(4:3)ScenarioOutlineLine:Scenario Outline/Bar/ +(5:5)StepLine:Then /Baz/ +(6:1)Empty:// +(7:5)ExamplesLine:Examples// +(8:5)TableRow://7:name +(9:5)TableRow://7:X +(10:5)TableRow://7:Y +EOF diff --git a/testdata/good/tags.feature b/testdata/good/tags.feature new file mode 100644 index 0000000..ae11471 --- /dev/null +++ b/testdata/good/tags.feature @@ -0,0 +1,25 @@ +@feature_tag1 @feature_tag2 + @feature_tag3 +Feature: Minimal Scenario Outline + +@scenario_tag1 @scenario_tag2 + @scenario_tag3 +Scenario: minimalistic + Given the minimalism + +@so_tag1 @so_tag2 + @so_tag3 +Scenario Outline: minimalistic outline + Given the + +@ex_tag1 @ex_tag2 + @ex_tag3 +Examples: + | what | + | minimalism | + +@ex_tag4 @ex_tag5 + @ex_tag6 +Examples: + | what | + | more minimalism | diff --git a/testdata/good/tags.feature.ast.ndjson b/testdata/good/tags.feature.ast.ndjson new file mode 100644 index 0000000..1062e78 --- /dev/null +++ b/testdata/good/tags.feature.ast.ndjson @@ -0,0 +1 @@ +{"document":{"comments":[],"feature":{"children":[{"keyword":"Scenario","location":{"column":1,"line":7},"name":"minimalistic","steps":[{"keyword":"Given ","location":{"column":5,"line":8},"text":"the minimalism","type":"Step"}],"tags":[{"location":{"column":1,"line":5},"name":"@scenario_tag1","type":"Tag"},{"location":{"column":16,"line":5},"name":"@scenario_tag2","type":"Tag"},{"location":{"column":3,"line":6},"name":"@scenario_tag3","type":"Tag"}],"type":"Scenario"},{"examples":[{"keyword":"Examples","location":{"column":1,"line":17},"name":"","tableBody":[{"cells":[{"location":{"column":5,"line":19},"type":"TableCell","value":"minimalism"}],"location":{"column":3,"line":19},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":5,"line":18},"type":"TableCell","value":"what"}],"location":{"column":3,"line":18},"type":"TableRow"},"tags":[{"location":{"column":1,"line":15},"name":"@ex_tag1","type":"Tag"},{"location":{"column":10,"line":15},"name":"@ex_tag2","type":"Tag"},{"location":{"column":3,"line":16},"name":"@ex_tag3","type":"Tag"}],"type":"Examples"},{"keyword":"Examples","location":{"column":1,"line":23},"name":"","tableBody":[{"cells":[{"location":{"column":5,"line":25},"type":"TableCell","value":"more minimalism"}],"location":{"column":3,"line":25},"type":"TableRow"}],"tableHeader":{"cells":[{"location":{"column":5,"line":24},"type":"TableCell","value":"what"}],"location":{"column":3,"line":24},"type":"TableRow"},"tags":[{"location":{"column":1,"line":21},"name":"@ex_tag4","type":"Tag"},{"location":{"column":10,"line":21},"name":"@ex_tag5","type":"Tag"},{"location":{"column":3,"line":22},"name":"@ex_tag6","type":"Tag"}],"type":"Examples"}],"keyword":"Scenario Outline","location":{"column":1,"line":12},"name":"minimalistic outline","steps":[{"keyword":"Given ","location":{"column":5,"line":13},"text":"the ","type":"Step"}],"tags":[{"location":{"column":1,"line":10},"name":"@so_tag1","type":"Tag"},{"location":{"column":11,"line":10},"name":"@so_tag2","type":"Tag"},{"location":{"column":3,"line":11},"name":"@so_tag3","type":"Tag"}],"type":"ScenarioOutline"}],"keyword":"Feature","language":"en","location":{"column":1,"line":3},"name":"Minimal Scenario Outline","tags":[{"location":{"column":1,"line":1},"name":"@feature_tag1","type":"Tag"},{"location":{"column":15,"line":1},"name":"@feature_tag2","type":"Tag"},{"location":{"column":3,"line":2},"name":"@feature_tag3","type":"Tag"}],"type":"Feature"},"type":"GherkinDocument"},"type":"gherkin-document","uri":"testdata/good/tags.feature"} diff --git a/testdata/good/tags.feature.pickles.ndjson b/testdata/good/tags.feature.pickles.ndjson new file mode 100644 index 0000000..876a263 --- /dev/null +++ b/testdata/good/tags.feature.pickles.ndjson @@ -0,0 +1,3 @@ +{"pickle":{"language":"en","locations":[{"column":1,"line":7}],"name":"minimalistic","steps":[{"arguments":[],"locations":[{"column":11,"line":8}],"text":"the minimalism"}],"tags":[{"location":{"column":1,"line":1},"name":"@feature_tag1"},{"location":{"column":15,"line":1},"name":"@feature_tag2"},{"location":{"column":3,"line":2},"name":"@feature_tag3"},{"location":{"column":1,"line":5},"name":"@scenario_tag1"},{"location":{"column":16,"line":5},"name":"@scenario_tag2"},{"location":{"column":3,"line":6},"name":"@scenario_tag3"}]},"type":"pickle","uri":"testdata/good/tags.feature"} +{"pickle":{"language":"en","locations":[{"column":3,"line":19},{"column":1,"line":12}],"name":"minimalistic outline","steps":[{"arguments":[],"locations":[{"column":3,"line":19},{"column":11,"line":13}],"text":"the minimalism"}],"tags":[{"location":{"column":1,"line":1},"name":"@feature_tag1"},{"location":{"column":15,"line":1},"name":"@feature_tag2"},{"location":{"column":3,"line":2},"name":"@feature_tag3"},{"location":{"column":1,"line":10},"name":"@so_tag1"},{"location":{"column":11,"line":10},"name":"@so_tag2"},{"location":{"column":3,"line":11},"name":"@so_tag3"},{"location":{"column":1,"line":15},"name":"@ex_tag1"},{"location":{"column":10,"line":15},"name":"@ex_tag2"},{"location":{"column":3,"line":16},"name":"@ex_tag3"}]},"type":"pickle","uri":"testdata/good/tags.feature"} +{"pickle":{"language":"en","locations":[{"column":3,"line":25},{"column":1,"line":12}],"name":"minimalistic outline","steps":[{"arguments":[],"locations":[{"column":3,"line":25},{"column":11,"line":13}],"text":"the more minimalism"}],"tags":[{"location":{"column":1,"line":1},"name":"@feature_tag1"},{"location":{"column":15,"line":1},"name":"@feature_tag2"},{"location":{"column":3,"line":2},"name":"@feature_tag3"},{"location":{"column":1,"line":10},"name":"@so_tag1"},{"location":{"column":11,"line":10},"name":"@so_tag2"},{"location":{"column":3,"line":11},"name":"@so_tag3"},{"location":{"column":1,"line":21},"name":"@ex_tag4"},{"location":{"column":10,"line":21},"name":"@ex_tag5"},{"location":{"column":3,"line":22},"name":"@ex_tag6"}]},"type":"pickle","uri":"testdata/good/tags.feature"} diff --git a/testdata/good/tags.feature.source.ndjson b/testdata/good/tags.feature.source.ndjson new file mode 100644 index 0000000..216ccfd --- /dev/null +++ b/testdata/good/tags.feature.source.ndjson @@ -0,0 +1 @@ +{"data":"@feature_tag1 @feature_tag2\n @feature_tag3\nFeature: Minimal Scenario Outline\n\n@scenario_tag1 @scenario_tag2\n @scenario_tag3\nScenario: minimalistic\n Given the minimalism\n\n@so_tag1 @so_tag2 \n @so_tag3\nScenario Outline: minimalistic outline\n Given the \n\n@ex_tag1 @ex_tag2\n @ex_tag3\nExamples: \n | what |\n | minimalism |\n\n@ex_tag4 @ex_tag5\n @ex_tag6\nExamples: \n | what |\n | more minimalism |\n","media":{"encoding":"utf-8","type":"text/x.cucumber.gherkin+plain"},"type":"source","uri":"testdata/good/tags.feature"} diff --git a/testdata/good/tags.feature.tokens b/testdata/good/tags.feature.tokens new file mode 100644 index 0000000..18254c9 --- /dev/null +++ b/testdata/good/tags.feature.tokens @@ -0,0 +1,26 @@ +(1:1)TagLine://1:@feature_tag1,15:@feature_tag2 +(2:3)TagLine://3:@feature_tag3 +(3:1)FeatureLine:Feature/Minimal Scenario Outline/ +(4:1)Empty:// +(5:1)TagLine://1:@scenario_tag1,16:@scenario_tag2 +(6:3)TagLine://3:@scenario_tag3 +(7:1)ScenarioLine:Scenario/minimalistic/ +(8:5)StepLine:Given /the minimalism/ +(9:1)Empty:// +(10:1)TagLine://1:@so_tag1,11:@so_tag2 +(11:3)TagLine://3:@so_tag3 +(12:1)ScenarioOutlineLine:Scenario Outline/minimalistic outline/ +(13:5)StepLine:Given /the / +(14:1)Empty:// +(15:1)TagLine://1:@ex_tag1,10:@ex_tag2 +(16:3)TagLine://3:@ex_tag3 +(17:1)ExamplesLine:Examples// +(18:3)TableRow://5:what +(19:3)TableRow://5:minimalism +(20:1)Empty:// +(21:1)TagLine://1:@ex_tag4,10:@ex_tag5 +(22:3)TagLine://3:@ex_tag6 +(23:1)ExamplesLine:Examples// +(24:3)TableRow://5:what +(25:3)TableRow://5:more minimalism +EOF