diff --git a/go/cucumber_expression_generator_test.go b/go/cucumber_expression_generator_test.go index c0fabd9b4..a5e2a18ea 100644 --- a/go/cucumber_expression_generator_test.go +++ b/go/cucumber_expression_generator_test.go @@ -12,20 +12,7 @@ type Currency struct { ISO4217 string } -func TestCucumberExpressionGeneratory(t *testing.T) { - t.Run("documents expression generation", func(t *testing.T) { - parameterTypeRegistry := NewParameterTypeRegistry() - - /// [generate-expression] - generator := NewCucumberExpressionGenerator(parameterTypeRegistry) - undefinedStepText := "I have 2 cucumbers and 1.5 tomato" - generatedExpression := generator.GenerateExpressions(undefinedStepText)[0] - require.Equal(t, "I have {int} cucumbers and {float} tomato", generatedExpression.Source()) - require.Equal(t, "int", generatedExpression.ParameterNames()[0]) - require.Equal(t, "float", generatedExpression.ParameterTypes()[1].Name()) - /// [generate-expression] - }) - +func TestCucumberExpressionGenerator(t *testing.T) { t.Run("generates expression for no args", func(t *testing.T) { assertExpression(t, "hello", []string{}, "hello") }) diff --git a/go/cucumber_expression_parser_test.go b/go/cucumber_expression_parser_test.go index 7462721a1..5de11a311 100644 --- a/go/cucumber_expression_parser_test.go +++ b/go/cucumber_expression_parser_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -type AstExpectation struct { +type ParserExpectation struct { Expression string `yaml:"expression"` ExpectedAst node `yaml:"expected_ast"` Exception string `yaml:"exception"` @@ -26,7 +26,7 @@ func TestCucumberExpressionParser(t *testing.T) { require.Equal(t, expected, err.Error()) } - directory := "../testdata/ast/" + directory := "../testdata/cucumber-expression/parser/" files, err := ioutil.ReadDir(directory) require.NoError(t, err) @@ -34,7 +34,7 @@ func TestCucumberExpressionParser(t *testing.T) { contents, err := ioutil.ReadFile(directory + file.Name()) require.NoError(t, err) t.Run(fmt.Sprintf("%s", file.Name()), func(t *testing.T) { - var expectation AstExpectation + var expectation ParserExpectation err = yaml.Unmarshal(contents, &expectation) require.NoError(t, err) diff --git a/go/cucumber_expression_test.go b/go/cucumber_expression_test.go index 155d2f071..93b8b7f31 100644 --- a/go/cucumber_expression_test.go +++ b/go/cucumber_expression_test.go @@ -10,18 +10,13 @@ import ( "testing" ) -type ExpressionExpectation struct { +type CucumberExpressionMatchingExpectation struct { Expression string `yaml:"expression"` Text string `yaml:"text"` ExpectedArgs []interface{} `yaml:"expected_args"` Exception string `yaml:"exception"` } -type RegexExpectation struct { - Expression string `yaml:"expression"` - ExpectedRegex string `yaml:"expected_regex"` -} - func TestCucumberExpression(t *testing.T) { t.Run("acceptance tests pass", func(t *testing.T) { @@ -49,7 +44,7 @@ func TestCucumberExpression(t *testing.T) { } } - directory := "../testdata/expression/" + directory := "../testdata/cucumber-expression/matching/" files, err := ioutil.ReadDir(directory) require.NoError(t, err) @@ -57,7 +52,7 @@ func TestCucumberExpression(t *testing.T) { contents, err := ioutil.ReadFile(directory + file.Name()) require.NoError(t, err) t.Run(fmt.Sprintf("%s", file.Name()), func(t *testing.T) { - var expectation ExpressionExpectation + var expectation CucumberExpressionMatchingExpectation err = yaml.Unmarshal(contents, &expectation) require.NoError(t, err) if expectation.Exception == "" { @@ -67,28 +62,6 @@ func TestCucumberExpression(t *testing.T) { } }) } - - assertRegex := func(t *testing.T, expected string, expr string) { - parameterTypeRegistry := NewParameterTypeRegistry() - expression, err := NewCucumberExpression(expr, parameterTypeRegistry) - require.NoError(t, err) - require.Equal(t, expected, expression.Regexp().String()) - } - - directory = "../testdata/regex/" - files, err = ioutil.ReadDir(directory) - require.NoError(t, err) - - for _, file := range files { - contents, err := ioutil.ReadFile(directory + file.Name()) - require.NoError(t, err) - t.Run(fmt.Sprintf("%s", file.Name()), func(t *testing.T) { - var expectation RegexExpectation - err = yaml.Unmarshal(contents, &expectation) - require.NoError(t, err) - assertRegex(t, expectation.ExpectedRegex, expectation.Expression) - }) - } }) t.Run("documents expression generation", func(t *testing.T) { diff --git a/go/cucumber_expression_tokenizer_test.go b/go/cucumber_expression_tokenizer_test.go index 2c9577577..a1ae74ebe 100644 --- a/go/cucumber_expression_tokenizer_test.go +++ b/go/cucumber_expression_tokenizer_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -type TokenExpectation struct { +type TokenizerExpectation struct { Expression string `yaml:"expression"` ExpectedTokens []token `yaml:"expected_tokens"` Exception string `yaml:"exception"` @@ -16,7 +16,7 @@ type TokenExpectation struct { func TestCucumberExpressionTokenizer(t *testing.T) { - directory := "../testdata/tokens/" + directory := "../testdata/cucumber-expression/tokenizer/" files, err := ioutil.ReadDir(directory) require.NoError(t, err) @@ -24,7 +24,7 @@ func TestCucumberExpressionTokenizer(t *testing.T) { contents, err := ioutil.ReadFile(directory + file.Name()) require.NoError(t, err) t.Run(fmt.Sprintf("%s", file.Name()), func(t *testing.T) { - var expectation TokenExpectation + var expectation TokenizerExpectation err = yaml.Unmarshal(contents, &expectation) require.NoError(t, err) diff --git a/go/cucumber_expression_transformation_test.go b/go/cucumber_expression_transformation_test.go new file mode 100644 index 000000000..547032c05 --- /dev/null +++ b/go/cucumber_expression_transformation_test.go @@ -0,0 +1,41 @@ +package cucumberexpressions + +import ( + "fmt" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" + "io/ioutil" + "testing" +) + +type TransformationExpectation struct { + Expression string `yaml:"expression"` + ExpectedRegex string `yaml:"expected_regex"` +} + +func TestCucumberExpressionTransformation(t *testing.T) { + + t.Run("acceptance tests pass", func(t *testing.T) { + assertRegex := func(t *testing.T, expected string, expr string) { + parameterTypeRegistry := NewParameterTypeRegistry() + expression, err := NewCucumberExpression(expr, parameterTypeRegistry) + require.NoError(t, err) + require.Equal(t, expected, expression.Regexp().String()) + } + + directory := "../testdata/cucumber-expression/transformation/" + files, err := ioutil.ReadDir(directory) + require.NoError(t, err) + + for _, file := range files { + contents, err := ioutil.ReadFile(directory + file.Name()) + require.NoError(t, err) + t.Run(fmt.Sprintf("%s", file.Name()), func(t *testing.T) { + var expectation TransformationExpectation + err = yaml.Unmarshal(contents, &expectation) + require.NoError(t, err) + assertRegex(t, expectation.ExpectedRegex, expectation.Expression) + }) + } + }) +} diff --git a/go/regular_expression_test.go b/go/regular_expression_test.go index 94e62cf11..709f9e02a 100644 --- a/go/regular_expression_test.go +++ b/go/regular_expression_test.go @@ -1,6 +1,9 @@ package cucumberexpressions import ( + "fmt" + "gopkg.in/yaml.v3" + "io/ioutil" "reflect" "regexp" "testing" @@ -8,18 +11,48 @@ import ( "github.com/stretchr/testify/require" ) +type RegularExpressionMatchingExpectation struct { + Expression string `yaml:"expression"` + Text string `yaml:"text"` + ExpectedArgs []interface{} `yaml:"expected_args"` +} + func TestRegularExpression(t *testing.T) { + directory := "../testdata/regular-expression/matching/" + files, err := ioutil.ReadDir(directory) + require.NoError(t, err) + + for _, file := range files { + contents, err := ioutil.ReadFile(directory + file.Name()) + require.NoError(t, err) + t.Run(fmt.Sprintf("%s", file.Name()), func(t *testing.T) { + var expectation RegularExpressionMatchingExpectation + err = yaml.Unmarshal(contents, &expectation) + require.NoError(t, err) + + parameterTypeRegistry := NewParameterTypeRegistry() + expr := regexp.MustCompile(expectation.Expression) + expression := NewRegularExpression(expr, parameterTypeRegistry) + args, err := expression.Match(expectation.Text) + require.NoError(t, err) + values := make([]interface{}, len(args)) + for i, arg := range args { + values[i] = arg.GetValue() + } + + require.Equal(t, expectation.ExpectedArgs, values) + }) + } + t.Run("documents match arguments", func(t *testing.T) { parameterTypeRegistry := NewParameterTypeRegistry() - /// [capture-match-arguments] expr := regexp.MustCompile(`I have (\d+) cukes? in my (\w+) now`) expression := NewRegularExpression(expr, parameterTypeRegistry) args, err := expression.Match("I have 7 cukes in my belly now") require.NoError(t, err) require.Equal(t, args[0].GetValue(), 7) require.Equal(t, args[1].GetValue(), "belly") - /// [capture-match-arguments] }) t.Run("does no transform by default", func(t *testing.T) { diff --git a/java/src/test/java/io/cucumber/cucumberexpressions/AstExpectation.java b/java/src/test/java/io/cucumber/cucumberexpressions/AstExpectation.java deleted file mode 100644 index 3b35287fb..000000000 --- a/java/src/test/java/io/cucumber/cucumberexpressions/AstExpectation.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.cucumber.cucumberexpressions; - -import io.cucumber.cucumberexpressions.Ast.Node; -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.params.converter.ArgumentConversionException; -import org.junit.jupiter.params.converter.ArgumentConverter; -import org.yaml.snakeyaml.Yaml; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Path; -import java.util.List; -import java.util.stream.Collectors; - -import static java.nio.file.Files.newInputStream; - -class AstExpectation { - public String expression; - public YamlableNode expected_ast; - public String exception; - - static class Converter implements ArgumentConverter { - Yaml yaml = new Yaml(); - - @Override - public AstExpectation convert(Object source, ParameterContext context) throws ArgumentConversionException { - try { - Path path = (Path) source; - InputStream inputStream = newInputStream(path); - return yaml.loadAs(inputStream, AstExpectation.class); - } catch (IOException e) { - throw new ArgumentConversionException("Could not load " + source, e); - } - } - } - - static class YamlableNode { - public Ast.Node.Type type; - public List nodes; - public String token; - public int start; - public int end; - - public Node toNode() { - if (token != null) { - return new Node(type, start, end, token); - } else { - return new Node(type, start, end, nodes.stream().map(YamlableNode::toNode).collect(Collectors.toList())); - } - } - } -} diff --git a/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionParserTest.java b/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionParserTest.java index e01ace098..3221a59dd 100644 --- a/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionParserTest.java +++ b/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionParserTest.java @@ -1,18 +1,25 @@ package io.cucumber.cucumberexpressions; import io.cucumber.cucumberexpressions.Ast.Node; +import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.converter.ArgumentConversionException; +import org.junit.jupiter.params.converter.ArgumentConverter; import org.junit.jupiter.params.converter.ConvertWith; import org.junit.jupiter.params.provider.MethodSource; +import org.yaml.snakeyaml.Yaml; import java.io.IOException; +import java.io.InputStream; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; import static java.nio.file.Files.newDirectoryStream; +import static java.nio.file.Files.newInputStream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -23,14 +30,14 @@ class CucumberExpressionParserTest { private static List acceptance_tests_pass() throws IOException { List paths = new ArrayList<>(); - newDirectoryStream(Paths.get("..", "testdata", "ast")).forEach(paths::add); + newDirectoryStream(Paths.get("..", "testdata", "cucumber-expression", "parser")).forEach(paths::add); paths.sort(Comparator.naturalOrder()); return paths; } @ParameterizedTest @MethodSource - void acceptance_tests_pass(@ConvertWith(AstExpectation.Converter.class) AstExpectation expectation) { + void acceptance_tests_pass(@ConvertWith(Converter.class) Expectation expectation) { if (expectation.exception == null) { Node node = parser.parse(expectation.expression); assertThat(node, is(expectation.expected_ast.toNode())); @@ -42,4 +49,40 @@ void acceptance_tests_pass(@ConvertWith(AstExpectation.Converter.class) AstExpec } } + static class Expectation { + public String expression; + public YamlableNode expected_ast; + public String exception; + } + + static class Converter implements ArgumentConverter { + Yaml yaml = new Yaml(); + + @Override + public Expectation convert(Object source, ParameterContext context) throws ArgumentConversionException { + try { + Path path = (Path) source; + InputStream inputStream = newInputStream(path); + return yaml.loadAs(inputStream, Expectation.class); + } catch (IOException e) { + throw new ArgumentConversionException("Could not load " + source, e); + } + } + } + + static class YamlableNode { + public Ast.Node.Type type; + public List nodes; + public String token; + public int start; + public int end; + + public Node toNode() { + if (token != null) { + return new Node(type, start, end, token); + } else { + return new Node(type, start, end, nodes.stream().map(YamlableNode::toNode).collect(Collectors.toList())); + } + } + } } diff --git a/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTest.java b/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTest.java index 32a34a9c0..9b7932e98 100644 --- a/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTest.java +++ b/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTest.java @@ -1,14 +1,17 @@ package io.cucumber.cucumberexpressions; -import org.hamcrest.Matcher; -import org.hamcrest.collection.IsIterableContainingInOrder; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.api.function.Executable; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.converter.ArgumentConversionException; +import org.junit.jupiter.params.converter.ArgumentConverter; import org.junit.jupiter.params.converter.ConvertWith; import org.junit.jupiter.params.provider.MethodSource; +import org.yaml.snakeyaml.Yaml; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; @@ -21,10 +24,10 @@ import java.util.stream.Collectors; import static java.nio.file.Files.newDirectoryStream; +import static java.nio.file.Files.newInputStream; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.closeTo; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.core.Is.is; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -33,32 +36,25 @@ class CucumberExpressionTest { private final ParameterTypeRegistry parameterTypeRegistry = new ParameterTypeRegistry(Locale.ENGLISH); - private static List expression_acceptance_tests_pass() throws IOException { + private static List acceptance_tests_pass() throws IOException { List paths = new ArrayList<>(); - newDirectoryStream(Paths.get("..", "testdata", "expression")).forEach(paths::add); - paths.sort(Comparator.naturalOrder()); - return paths; - } - - private static List regex_acceptance_tests_pass() throws IOException { - List paths = new ArrayList<>(); - newDirectoryStream(Paths.get("..", "testdata", "regex")).forEach(paths::add); + newDirectoryStream(Paths.get("..", "testdata", "cucumber-expression", "matching")).forEach(paths::add); paths.sort(Comparator.naturalOrder()); return paths; } @ParameterizedTest @MethodSource - void expression_acceptance_tests_pass(@ConvertWith(ExpressionExpectation.Converter.class) ExpressionExpectation expectation) { + void acceptance_tests_pass(@ConvertWith(Converter.class) Expectation expectation) { if (expectation.exception == null) { CucumberExpression expression = new CucumberExpression(expectation.expression, parameterTypeRegistry); List> match = expression.match(expectation.text); List values = match == null ? null : match.stream() .map(Argument::getValue) - .map(e -> e instanceof Float ? ((Float)e).doubleValue() : e) + .map(e -> e instanceof Float ? ((Float) e).doubleValue() : e) .collect(Collectors.toList()); - assertThat(values, equalOrCloseTo(expectation.expected_args)); + assertThat(values, CustomMatchers.equalOrCloseTo(expectation.expected_args)); } else { Executable executable = () -> { CucumberExpression expression = new CucumberExpression(expectation.expression, parameterTypeRegistry); @@ -69,17 +65,26 @@ void expression_acceptance_tests_pass(@ConvertWith(ExpressionExpectation.Convert } } - public static Matcher> equalOrCloseTo(List list) { - if (list == null || list.isEmpty()) return equalTo(list); - List> matchers = list.stream().map(e -> e instanceof Double ? closeTo(((Double) e), 0.0001) : equalTo(e)).collect(Collectors.toList()); - return new IsIterableContainingInOrder(matchers); + static class Expectation { + public String expression; + public String text; + public List expected_args; + public String exception; } - @ParameterizedTest - @MethodSource - void regex_acceptance_tests_pass(@ConvertWith(RegexExpectation.Converter.class) RegexExpectation expectation) { - CucumberExpression expression = new CucumberExpression(expectation.expression, parameterTypeRegistry); - assertEquals(expectation.expected_regex, expression.getRegexp().pattern()); + static class Converter implements ArgumentConverter { + Yaml yaml = new Yaml(); + + @Override + public io.cucumber.cucumberexpressions.CucumberExpressionTest.Expectation convert(Object source, ParameterContext context) throws ArgumentConversionException { + try { + Path path = (Path) source; + InputStream inputStream = newInputStream(path); + return yaml.loadAs(inputStream, io.cucumber.cucumberexpressions.CucumberExpressionTest.Expectation.class); + } catch (IOException e) { + throw new ArgumentConversionException("Could not load " + source, e); + } + } } // Misc tests diff --git a/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTokenizerTest.java b/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTokenizerTest.java index cffd7eb70..11c0cef97 100644 --- a/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTokenizerTest.java +++ b/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTokenizerTest.java @@ -1,11 +1,16 @@ package io.cucumber.cucumberexpressions; import io.cucumber.cucumberexpressions.Ast.Token; +import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.converter.ArgumentConversionException; +import org.junit.jupiter.params.converter.ArgumentConverter; import org.junit.jupiter.params.converter.ConvertWith; import org.junit.jupiter.params.provider.MethodSource; +import org.yaml.snakeyaml.Yaml; import java.io.IOException; +import java.io.InputStream; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -14,6 +19,7 @@ import java.util.stream.Collectors; import static java.nio.file.Files.newDirectoryStream; +import static java.nio.file.Files.newInputStream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -24,19 +30,19 @@ class CucumberExpressionTokenizerTest { private static List acceptance_tests_pass() throws IOException { List paths = new ArrayList<>(); - newDirectoryStream(Paths.get("..", "testdata", "tokens")).forEach(paths::add); + newDirectoryStream(Paths.get("..", "testdata", "cucumber-expression", "tokenizer")).forEach(paths::add); paths.sort(Comparator.naturalOrder()); return paths; } @ParameterizedTest @MethodSource - void acceptance_tests_pass(@ConvertWith(TokenExpectation.Converter.class) TokenExpectation expectation) { + void acceptance_tests_pass(@ConvertWith(Converter.class) Expectation expectation) { if (expectation.exception == null) { List tokens = tokenizer.tokenize(expectation.expression); List expectedTokens = expectation.expected_tokens .stream() - .map(TokenExpectation.YamlableToken::toToken) + .map(YamlableToken::toToken) .collect(Collectors.toList()); assertThat(tokens, is(expectedTokens)); } else { @@ -47,4 +53,35 @@ void acceptance_tests_pass(@ConvertWith(TokenExpectation.Converter.class) TokenE } } + static class Expectation { + public String expression; + public List expected_tokens; + public String exception; + } + + static class Converter implements ArgumentConverter { + Yaml yaml = new Yaml(); + + @Override + public Expectation convert(Object source, ParameterContext context) throws ArgumentConversionException { + try { + Path path = (Path) source; + InputStream inputStream = newInputStream(path); + return yaml.loadAs(inputStream, Expectation.class); + } catch (IOException e) { + throw new ArgumentConversionException("Could not load " + source, e); + } + } + } + + static class YamlableToken { + public String text; + public Token.Type type; + public int start; + public int end; + + public Token toToken() { + return new Token(text, type, start, end); + } + } } diff --git a/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTransformationTest.java b/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTransformationTest.java new file mode 100644 index 000000000..a4c86c75c --- /dev/null +++ b/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTransformationTest.java @@ -0,0 +1,60 @@ +package io.cucumber.cucumberexpressions; + +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.converter.ArgumentConversionException; +import org.junit.jupiter.params.converter.ArgumentConverter; +import org.junit.jupiter.params.converter.ConvertWith; +import org.junit.jupiter.params.provider.MethodSource; +import org.yaml.snakeyaml.Yaml; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; + +import static java.nio.file.Files.newDirectoryStream; +import static java.nio.file.Files.newInputStream; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CucumberExpressionTransformationTest { + private final ParameterTypeRegistry parameterTypeRegistry = new ParameterTypeRegistry(Locale.ENGLISH); + + private static List acceptance_tests_pass() throws IOException { + List paths = new ArrayList<>(); + newDirectoryStream(Paths.get("..", "testdata", "cucumber-expression", "transformation")).forEach(paths::add); + paths.sort(Comparator.naturalOrder()); + return paths; + } + + @ParameterizedTest + @MethodSource + void acceptance_tests_pass(@ConvertWith(Converter.class) Expectation expectation) { + CucumberExpression expression = new CucumberExpression(expectation.expression, parameterTypeRegistry); + assertEquals(expectation.expected_regex, expression.getRegexp().pattern()); + } + + static class Expectation { + public String expression; + public String expected_regex; + } + + static class Converter implements ArgumentConverter { + Yaml yaml = new Yaml(); + + @Override + public Expectation convert(Object source, ParameterContext context) throws ArgumentConversionException { + try { + Path path = (Path) source; + InputStream inputStream = newInputStream(path); + return yaml.loadAs(inputStream, Expectation.class); + } catch (IOException e) { + throw new ArgumentConversionException("Could not load " + source, e); + } + } + } +} diff --git a/java/src/test/java/io/cucumber/cucumberexpressions/CustomMatchers.java b/java/src/test/java/io/cucumber/cucumberexpressions/CustomMatchers.java new file mode 100644 index 000000000..09b72d073 --- /dev/null +++ b/java/src/test/java/io/cucumber/cucumberexpressions/CustomMatchers.java @@ -0,0 +1,18 @@ +package io.cucumber.cucumberexpressions; + +import org.hamcrest.Matcher; +import org.hamcrest.collection.IsIterableContainingInOrder; + +import java.util.List; +import java.util.stream.Collectors; + +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.equalTo; + +public class CustomMatchers { + public static Matcher> equalOrCloseTo(List list) { + if (list == null || list.isEmpty()) return equalTo(list); + List> matchers = list.stream().map(e -> e instanceof Double ? closeTo(((Double) e), 0.0001) : equalTo(e)).collect(Collectors.toList()); + return new IsIterableContainingInOrder(matchers); + } +} diff --git a/java/src/test/java/io/cucumber/cucumberexpressions/RegexExpectation.java b/java/src/test/java/io/cucumber/cucumberexpressions/RegexExpectation.java deleted file mode 100644 index 54ae44ee9..000000000 --- a/java/src/test/java/io/cucumber/cucumberexpressions/RegexExpectation.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.cucumber.cucumberexpressions; - -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.params.converter.ArgumentConversionException; -import org.junit.jupiter.params.converter.ArgumentConverter; -import org.yaml.snakeyaml.Yaml; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Path; -import java.util.List; - -import static java.nio.file.Files.newInputStream; - -class RegexExpectation { - public String expression; - public String expected_regex; - - static class Converter implements ArgumentConverter { - Yaml yaml = new Yaml(); - - @Override - public RegexExpectation convert(Object source, ParameterContext context) throws ArgumentConversionException { - try { - Path path = (Path) source; - InputStream inputStream = newInputStream(path); - return yaml.loadAs(inputStream, RegexExpectation.class); - } catch (IOException e) { - throw new ArgumentConversionException("Could not load " + source, e); - } - } - } -} diff --git a/java/src/test/java/io/cucumber/cucumberexpressions/ExpressionExpectation.java b/java/src/test/java/io/cucumber/cucumberexpressions/RegularExpressionExpectation.java similarity index 77% rename from java/src/test/java/io/cucumber/cucumberexpressions/ExpressionExpectation.java rename to java/src/test/java/io/cucumber/cucumberexpressions/RegularExpressionExpectation.java index cd15f6dd7..747215e86 100644 --- a/java/src/test/java/io/cucumber/cucumberexpressions/ExpressionExpectation.java +++ b/java/src/test/java/io/cucumber/cucumberexpressions/RegularExpressionExpectation.java @@ -12,21 +12,20 @@ import static java.nio.file.Files.newInputStream; -class ExpressionExpectation { +class RegularExpressionExpectation { public String expression; public String text; public List expected_args; - public String exception; static class Converter implements ArgumentConverter { Yaml yaml = new Yaml(); @Override - public ExpressionExpectation convert(Object source, ParameterContext context) throws ArgumentConversionException { + public RegularExpressionExpectation convert(Object source, ParameterContext context) throws ArgumentConversionException { try { Path path = (Path) source; InputStream inputStream = newInputStream(path); - return yaml.loadAs(inputStream, ExpressionExpectation.class); + return yaml.loadAs(inputStream, RegularExpressionExpectation.class); } catch (IOException e) { throw new ArgumentConversionException("Could not load " + source, e); } diff --git a/java/src/test/java/io/cucumber/cucumberexpressions/RegularExpressionTest.java b/java/src/test/java/io/cucumber/cucumberexpressions/RegularExpressionTest.java index ab4e6d3d5..a85896bab 100644 --- a/java/src/test/java/io/cucumber/cucumberexpressions/RegularExpressionTest.java +++ b/java/src/test/java/io/cucumber/cucumberexpressions/RegularExpressionTest.java @@ -1,23 +1,57 @@ package io.cucumber.cucumberexpressions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.converter.ConvertWith; +import org.junit.jupiter.params.provider.MethodSource; +import java.io.IOException; import java.lang.reflect.Type; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Locale; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import static io.cucumber.cucumberexpressions.CustomMatchers.equalOrCloseTo; +import static java.nio.file.Files.newDirectoryStream; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.regex.Pattern.compile; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class RegularExpressionTest { private final ParameterTypeRegistry parameterTypeRegistry = new ParameterTypeRegistry(Locale.ENGLISH); + private static List acceptance_tests_pass() throws IOException { + List paths = new ArrayList<>(); + newDirectoryStream(Paths.get("..", "testdata", "regular-expression", "matching")).forEach(paths::add); + paths.sort(Comparator.naturalOrder()); + return paths; + } + + @ParameterizedTest + @MethodSource + void acceptance_tests_pass(@ConvertWith(RegularExpressionExpectation.Converter.class) RegularExpressionExpectation expectation) { + RegularExpression expression = new RegularExpression(Pattern.compile(expectation.expression), parameterTypeRegistry); + List> match = expression.match(expectation.text); + List values = match == null ? null : match.stream() + .map(Argument::getValue) + .map(e -> e instanceof Float ? ((Float)e).doubleValue() : e) + .collect(Collectors.toList()); + + assertThat(values, CustomMatchers.equalOrCloseTo(expectation.expected_args)); + } + @Test public void documentation_match_arguments() { Pattern expr = Pattern.compile("I have (\\d+) cukes? in my (\\w+) now"); diff --git a/java/src/test/java/io/cucumber/cucumberexpressions/TokenExpectation.java b/java/src/test/java/io/cucumber/cucumberexpressions/TokenExpectation.java deleted file mode 100644 index 9105cd959..000000000 --- a/java/src/test/java/io/cucumber/cucumberexpressions/TokenExpectation.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.cucumber.cucumberexpressions; - -import io.cucumber.cucumberexpressions.Ast.Token; -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.params.converter.ArgumentConversionException; -import org.junit.jupiter.params.converter.ArgumentConverter; -import org.yaml.snakeyaml.Yaml; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Path; -import java.util.List; - -import static java.nio.file.Files.newInputStream; - -class TokenExpectation { - public String expression; - public List expected_tokens; - public String exception; - - static class Converter implements ArgumentConverter { - Yaml yaml = new Yaml(); - - @Override - public TokenExpectation convert(Object source, ParameterContext context) throws ArgumentConversionException { - try { - Path path = (Path) source; - InputStream inputStream = newInputStream(path); - return yaml.loadAs(inputStream, TokenExpectation.class); - } catch (IOException e) { - throw new ArgumentConversionException("Could not load " + source, e); - } - } - } - - static class YamlableToken { - public String text; - public Token.Type type; - public int start; - public int end; - - public Token toToken() { - return new Token(text, type, start, end); - } - } -} diff --git a/javascript/package-lock.json b/javascript/package-lock.json index 428354f52..2410f676b 100644 --- a/javascript/package-lock.json +++ b/javascript/package-lock.json @@ -21,6 +21,7 @@ "@stryker-mutator/core": "^5.4.1", "@stryker-mutator/mocha-runner": "^5.4.1", "@tailwindcss/forms": "0.3.4", + "@types/glob": "^7.1.4", "@types/js-yaml": "4.0.3", "@types/mocha": "9.0.0", "@types/node": "16.10.3", @@ -39,6 +40,7 @@ "eslint-plugin-react": "7.26.1", "eslint-plugin-react-hooks": "4.2.0", "eslint-plugin-simple-import-sort": "7.0.0", + "glob": "^7.2.0", "js-yaml": "4.1.0", "mocha": "9.1.2", "npm-check-updates": "11.8.5", @@ -713,9 +715,9 @@ "dev": true }, "node_modules/@codemirror/tooltip": { - "version": "0.19.3", - "resolved": "https://registry.npmjs.org/@codemirror/tooltip/-/tooltip-0.19.3.tgz", - "integrity": "sha512-JM9AVdzi3u2PWFgfx6hIxsh4VyDyIW+N0V7hfjkMNGRCJngiT+KmWiMsAdozQVwGhRzhqbUklSoqVOGDZI/b4g==", + "version": "0.19.4", + "resolved": "https://registry.npmjs.org/@codemirror/tooltip/-/tooltip-0.19.4.tgz", + "integrity": "sha512-DTv6SOzjw8LbHdTd2FszpIkQCUKRl0dqh1pWqawR31Lu/ZCz1nOiOY1sxkiEZVXMTFg44V0Uff0YlY6mTVK2DQ==", "dev": true, "dependencies": { "@codemirror/state": "^0.19.0", @@ -1199,6 +1201,16 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, + "node_modules/@types/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, "node_modules/@types/history": { "version": "4.7.9", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz", @@ -2011,16 +2023,16 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz", - "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", + "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", "dev": true, "dependencies": { - "caniuse-lite": "^1.0.30001264", - "electron-to-chromium": "^1.3.857", + "caniuse-lite": "^1.0.30001265", + "electron-to-chromium": "^1.3.867", "escalade": "^3.1.1", - "node-releases": "^1.1.77", - "picocolors": "^0.2.1" + "node-releases": "^2.0.0", + "picocolors": "^1.0.0" }, "bin": { "browserslist": "cli.js" @@ -2033,6 +2045,12 @@ "url": "https://opencollective.com/browserslist" } }, + "node_modules/browserslist/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -2187,9 +2205,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001265", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz", - "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==", + "version": "1.0.30001267", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001267.tgz", + "integrity": "sha512-r1mjTzAuJ9W8cPBGbbus8E0SKcUP7gn03R14Wk8FlAlqhH9hroy9nLqmpuXlfKEw/oILW+FGz47ipXV2O7x8lg==", "dev": true, "funding": { "type": "opencollective", @@ -2803,9 +2821,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.3.866", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.866.tgz", - "integrity": "sha512-iYze6TpDXWxk+sfcpUUdTs6Pv/3kG45Pnjer2DxEeFw0N08bZeNLuz97s2lMgy8yObon48o0WHY2Bkg3xuAPOA==", + "version": "1.3.870", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.870.tgz", + "integrity": "sha512-PiJMshfq6PL+i1V+nKLwhHbCKeD8eAz8rvO9Cwk/7cChOHJBtufmjajLyYLsSRHguRFiOCVx3XzJLeZsIAYfSA==", "dev": true }, "node_modules/emoji-regex": { @@ -3302,9 +3320,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.0.tgz", - "integrity": "sha512-hqSE88MmHl3ru9SYvDyGrlo0JwROlf9fiEMplEV7j/EAuq9iSlIlyCFbBT6pdULQBSnBYtYKiMLps+hKkyP7Gg==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", + "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", "dev": true, "dependencies": { "debug": "^3.2.7", @@ -4911,9 +4929,9 @@ } }, "node_modules/is-core-module": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz", - "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -5770,9 +5788,9 @@ } }, "node_modules/mini-svg-data-uri": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.3.3.tgz", - "integrity": "sha512-+fA2oRcR1dJI/7ITmeQJDrYWks0wodlOz0pAEhKYJ2IVc1z0AnwJUsKY2fzFmPAM3Jo9J0rBx8JAA9QQSJ5PuA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.3.tgz", + "integrity": "sha512-gSfqpMRC8IxghvMcxzzmMnWpXAChSA+vy4cia33RgerMS8Fex95akUyQZPbxJJmeBGiGmK7n/1OpUX8ksRjIdA==", "dev": true, "bin": { "mini-svg-data-uri": "cli.js" @@ -6199,9 +6217,9 @@ } }, "node_modules/node-releases": { - "version": "1.1.77", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", - "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", + "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", "dev": true }, "node_modules/nopt": { @@ -7121,9 +7139,9 @@ } }, "node_modules/postcss-reporter": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.3.tgz", - "integrity": "sha512-WoYHwtStmiR74UQDO3vZMbkhOBXSXyteWnhMCVbAK6KRRKLTS0EnTZxOxvbUEnQiMZ+3xRG04x41HhHnLBtQfA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.4.tgz", + "integrity": "sha512-jY/fnpGSin7kwJeunXbY35STp5O3VIxSFdjee5JkoPQ+FfGH5JW3N+Xe9oAPcL9UkjWjkK+JC72o8XH4XXKdhw==", "dev": true, "dependencies": { "lodash.difference": "^4.5.0", @@ -7131,7 +7149,7 @@ "lodash.get": "^4.4.2", "lodash.groupby": "^4.6.0", "lodash.sortby": "^4.7.0", - "nanocolors": "^0.2.6" + "picocolors": "^1.0.0" }, "engines": { "node": ">=10" @@ -7144,6 +7162,12 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-reporter/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/postcss-selector-parser": { "version": "6.0.6", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", @@ -7164,9 +7188,9 @@ "dev": true }, "node_modules/postcss/node_modules/nanoid": { - "version": "3.1.29", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.29.tgz", - "integrity": "sha512-dW2pUSGZ8ZnCFIlBIA31SV8huOGCHb6OwzVCc7A69rb/a+SgPBwfmLvK5TKQ3INPbRkcI8a/Owo0XbiTNH19wg==", + "version": "3.1.30", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", + "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" @@ -9907,9 +9931,9 @@ "dev": true }, "@codemirror/tooltip": { - "version": "0.19.3", - "resolved": "https://registry.npmjs.org/@codemirror/tooltip/-/tooltip-0.19.3.tgz", - "integrity": "sha512-JM9AVdzi3u2PWFgfx6hIxsh4VyDyIW+N0V7hfjkMNGRCJngiT+KmWiMsAdozQVwGhRzhqbUklSoqVOGDZI/b4g==", + "version": "0.19.4", + "resolved": "https://registry.npmjs.org/@codemirror/tooltip/-/tooltip-0.19.4.tgz", + "integrity": "sha512-DTv6SOzjw8LbHdTd2FszpIkQCUKRl0dqh1pWqawR31Lu/ZCz1nOiOY1sxkiEZVXMTFg44V0Uff0YlY6mTVK2DQ==", "dev": true, "requires": { "@codemirror/state": "^0.19.0", @@ -10306,6 +10330,16 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, + "@types/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, "@types/history": { "version": "4.7.9", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz", @@ -10913,16 +10947,24 @@ "dev": true }, "browserslist": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz", - "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", + "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001264", - "electron-to-chromium": "^1.3.857", + "caniuse-lite": "^1.0.30001265", + "electron-to-chromium": "^1.3.867", "escalade": "^3.1.1", - "node-releases": "^1.1.77", - "picocolors": "^0.2.1" + "node-releases": "^2.0.0", + "picocolors": "^1.0.0" + }, + "dependencies": { + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + } } }, "buffer": { @@ -11034,9 +11076,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001265", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz", - "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==", + "version": "1.0.30001267", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001267.tgz", + "integrity": "sha512-r1mjTzAuJ9W8cPBGbbus8E0SKcUP7gn03R14Wk8FlAlqhH9hroy9nLqmpuXlfKEw/oILW+FGz47ipXV2O7x8lg==", "dev": true }, "caseless": { @@ -11510,9 +11552,9 @@ } }, "electron-to-chromium": { - "version": "1.3.866", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.866.tgz", - "integrity": "sha512-iYze6TpDXWxk+sfcpUUdTs6Pv/3kG45Pnjer2DxEeFw0N08bZeNLuz97s2lMgy8yObon48o0WHY2Bkg3xuAPOA==", + "version": "1.3.870", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.870.tgz", + "integrity": "sha512-PiJMshfq6PL+i1V+nKLwhHbCKeD8eAz8rvO9Cwk/7cChOHJBtufmjajLyYLsSRHguRFiOCVx3XzJLeZsIAYfSA==", "dev": true }, "emoji-regex": { @@ -11935,9 +11977,9 @@ } }, "eslint-module-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.0.tgz", - "integrity": "sha512-hqSE88MmHl3ru9SYvDyGrlo0JwROlf9fiEMplEV7j/EAuq9iSlIlyCFbBT6pdULQBSnBYtYKiMLps+hKkyP7Gg==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", + "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", "dev": true, "requires": { "debug": "^3.2.7", @@ -13082,9 +13124,9 @@ } }, "is-core-module": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz", - "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", "dev": true, "requires": { "has": "^1.0.3" @@ -13743,9 +13785,9 @@ } }, "mini-svg-data-uri": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.3.3.tgz", - "integrity": "sha512-+fA2oRcR1dJI/7ITmeQJDrYWks0wodlOz0pAEhKYJ2IVc1z0AnwJUsKY2fzFmPAM3Jo9J0rBx8JAA9QQSJ5PuA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.3.tgz", + "integrity": "sha512-gSfqpMRC8IxghvMcxzzmMnWpXAChSA+vy4cia33RgerMS8Fex95akUyQZPbxJJmeBGiGmK7n/1OpUX8ksRjIdA==", "dev": true }, "minimatch": { @@ -14062,9 +14104,9 @@ } }, "node-releases": { - "version": "1.1.77", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", - "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", + "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", "dev": true }, "nopt": { @@ -14617,9 +14659,9 @@ }, "dependencies": { "nanoid": { - "version": "3.1.29", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.29.tgz", - "integrity": "sha512-dW2pUSGZ8ZnCFIlBIA31SV8huOGCHb6OwzVCc7A69rb/a+SgPBwfmLvK5TKQ3INPbRkcI8a/Owo0XbiTNH19wg==", + "version": "3.1.30", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", + "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", "dev": true } } @@ -14724,9 +14766,9 @@ } }, "postcss-reporter": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.3.tgz", - "integrity": "sha512-WoYHwtStmiR74UQDO3vZMbkhOBXSXyteWnhMCVbAK6KRRKLTS0EnTZxOxvbUEnQiMZ+3xRG04x41HhHnLBtQfA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.4.tgz", + "integrity": "sha512-jY/fnpGSin7kwJeunXbY35STp5O3VIxSFdjee5JkoPQ+FfGH5JW3N+Xe9oAPcL9UkjWjkK+JC72o8XH4XXKdhw==", "dev": true, "requires": { "lodash.difference": "^4.5.0", @@ -14734,7 +14776,15 @@ "lodash.get": "^4.4.2", "lodash.groupby": "^4.6.0", "lodash.sortby": "^4.7.0", - "nanocolors": "^0.2.6" + "picocolors": "^1.0.0" + }, + "dependencies": { + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + } } }, "postcss-selector-parser": { diff --git a/javascript/package.json b/javascript/package.json index 5f1d64ed9..b4cd7361b 100644 --- a/javascript/package.json +++ b/javascript/package.json @@ -59,6 +59,7 @@ "@stryker-mutator/core": "^5.4.1", "@stryker-mutator/mocha-runner": "^5.4.1", "@tailwindcss/forms": "0.3.4", + "@types/glob": "^7.1.4", "@types/js-yaml": "4.0.3", "@types/mocha": "9.0.0", "@types/node": "16.10.3", @@ -77,6 +78,7 @@ "eslint-plugin-react": "7.26.1", "eslint-plugin-react-hooks": "4.2.0", "eslint-plugin-simple-import-sort": "7.0.0", + "glob": "^7.2.0", "js-yaml": "4.1.0", "mocha": "9.1.2", "npm-check-updates": "11.8.5", diff --git a/javascript/test/CucumberExpressionParserTest.ts b/javascript/test/CucumberExpressionParserTest.ts index b7dd64c9e..93ad76700 100644 --- a/javascript/test/CucumberExpressionParserTest.ts +++ b/javascript/test/CucumberExpressionParserTest.ts @@ -1,22 +1,22 @@ import assert from 'assert' import fs from 'fs' +import glob from 'glob' import yaml from 'js-yaml' import CucumberExpressionError from '../src/CucumberExpressionError.js' import CucumberExpressionParser from '../src/CucumberExpressionParser.js' import { testDataDir } from './testDataDir.js' -type AstExpectation = { +type Expectation = { expression: string expected_ast?: unknown exception?: string } -describe('Cucumber expression parser', () => { - fs.readdirSync(`${testDataDir}/ast`).forEach((testcase) => { - const testCaseData = fs.readFileSync(`${testDataDir}/ast/${testcase}`, 'utf-8') - const expectation = yaml.load(testCaseData) as AstExpectation - it(`${testcase}`, () => { +describe('CucumberExpressionParser', () => { + for (const path of glob.sync(`${testDataDir}/cucumber-expression/parser/*.yaml`)) { + const expectation = yaml.load(fs.readFileSync(path, 'utf-8')) as Expectation + it(`parses ${path}`, () => { const parser = new CucumberExpressionParser() if (expectation.expected_ast !== undefined) { const node = parser.parse(expectation.expression) @@ -34,5 +34,5 @@ describe('Cucumber expression parser', () => { ) } }) - }) + } }) diff --git a/javascript/test/CucumberExpressionTest.ts b/javascript/test/CucumberExpressionTest.ts index 240e777f0..86c4419d1 100644 --- a/javascript/test/CucumberExpressionTest.ts +++ b/javascript/test/CucumberExpressionTest.ts @@ -1,5 +1,6 @@ import assert from 'assert' import fs from 'fs' +import glob from 'glob' import yaml from 'js-yaml' import CucumberExpression from '../src/CucumberExpression.js' @@ -8,23 +9,17 @@ import ParameterType from '../src/ParameterType.js' import ParameterTypeRegistry from '../src/ParameterTypeRegistry.js' import { testDataDir } from './testDataDir.js' -type ExpressionExpectation = { +type Expectation = { expression: string text: string expected_args?: unknown[] exception?: string } -type RegexExpectation = { - expression: string - expected_regex: string -} - describe('CucumberExpression', () => { - fs.readdirSync(`${testDataDir}/expression`).forEach((testcase) => { - const testCaseData = fs.readFileSync(`${testDataDir}/expression/${testcase}`, 'utf-8') - const expectation = yaml.load(testCaseData) as ExpressionExpectation - it(`${testcase}`, () => { + for (const path of glob.sync(`${testDataDir}/cucumber-expression/matching/*.yaml`)) { + const expectation = yaml.load(fs.readFileSync(path, 'utf-8')) as Expectation + it(`matches ${path}`, () => { const parameterTypeRegistry = new ParameterTypeRegistry() if (expectation.expected_args !== undefined) { const expression = new CucumberExpression(expectation.expression, parameterTypeRegistry) @@ -44,28 +39,7 @@ describe('CucumberExpression', () => { ) } }) - }) - - fs.readdirSync(`${testDataDir}/regex`).forEach((testcase) => { - const testCaseData = fs.readFileSync(`${testDataDir}/regex/${testcase}`, 'utf-8') - const expectation = yaml.load(testCaseData) as RegexExpectation - it(`${testcase}`, () => { - const parameterTypeRegistry = new ParameterTypeRegistry() - const expression = new CucumberExpression(expectation.expression, parameterTypeRegistry) - assert.deepStrictEqual(expression.regexp.source, expectation.expected_regex) - }) - }) - - it('documents match arguments', () => { - const parameterTypeRegistry = new ParameterTypeRegistry() - - /// [capture-match-arguments] - const expr = 'I have {int} cuke(s)' - const expression = new CucumberExpression(expr, parameterTypeRegistry) - const args = expression.match('I have 7 cukes')! - assert.strictEqual(7, args[0].getValue(null)) - /// [capture-match-arguments] - }) + } it('matches float', () => { assert.deepStrictEqual(match('{float}', ''), null) diff --git a/javascript/test/CucumberExpressionTokenizerTest.ts b/javascript/test/CucumberExpressionTokenizerTest.ts index 55b70efab..a2f590031 100644 --- a/javascript/test/CucumberExpressionTokenizerTest.ts +++ b/javascript/test/CucumberExpressionTokenizerTest.ts @@ -1,22 +1,22 @@ import assert from 'assert' import fs from 'fs' +import glob from 'glob' import yaml from 'js-yaml' import CucumberExpressionError from '../src/CucumberExpressionError.js' import CucumberExpressionTokenizer from '../src/CucumberExpressionTokenizer.js' import { testDataDir } from './testDataDir.js' -type TokenExpectation = { +type Expectation = { expression: string expected_tokens?: unknown exception?: string } -describe('Cucumber expression tokenizer', () => { - fs.readdirSync(`${testDataDir}/tokens`).forEach((testcase) => { - const testCaseData = fs.readFileSync(`${testDataDir}/tokens/${testcase}`, 'utf-8') - const expectation = yaml.load(testCaseData) as TokenExpectation - it(`${testcase}`, () => { +describe('CucumberExpressionTokenizer', () => { + for (const path of glob.sync(`${testDataDir}/cucumber-expression/tokenizer/*.yaml`)) { + const expectation = yaml.load(fs.readFileSync(path, 'utf-8')) as Expectation + it(`tokenizes ${path}`, () => { const tokenizer = new CucumberExpressionTokenizer() if (expectation.expected_tokens !== undefined) { const tokens = tokenizer.tokenize(expectation.expression) @@ -34,5 +34,5 @@ describe('Cucumber expression tokenizer', () => { ) } }) - }) + } }) diff --git a/javascript/test/CucumberExpressionTransformationTest.ts b/javascript/test/CucumberExpressionTransformationTest.ts new file mode 100644 index 000000000..810da0509 --- /dev/null +++ b/javascript/test/CucumberExpressionTransformationTest.ts @@ -0,0 +1,24 @@ +import assert from 'assert' +import fs from 'fs' +import glob from 'glob' +import yaml from 'js-yaml' + +import CucumberExpression from '../src/CucumberExpression.js' +import ParameterTypeRegistry from '../src/ParameterTypeRegistry.js' +import { testDataDir } from './testDataDir.js' + +type Expectation = { + expression: string + expected_regex: string +} + +describe('CucumberExpression', () => { + for (const path of glob.sync(`${testDataDir}/cucumber-expression/transformation/*.yaml`)) { + const expectation = yaml.load(fs.readFileSync(path, 'utf-8')) as Expectation + it(`transforms ${path}`, () => { + const parameterTypeRegistry = new ParameterTypeRegistry() + const expression = new CucumberExpression(expectation.expression, parameterTypeRegistry) + assert.deepStrictEqual(expression.regexp.source, expectation.expected_regex) + }) + } +}) diff --git a/javascript/test/RegularExpressionTest.ts b/javascript/test/RegularExpressionTest.ts index 3f7dad165..641433edd 100644 --- a/javascript/test/RegularExpressionTest.ts +++ b/javascript/test/RegularExpressionTest.ts @@ -1,20 +1,34 @@ import assert from 'assert' +import fs from 'fs' +import glob from 'glob' +import yaml from 'js-yaml' import ParameterTypeRegistry from '../src/ParameterTypeRegistry.js' import RegularExpression from '../src/RegularExpression.js' +import { testDataDir } from './testDataDir.js' + +interface Expectation { + expression: string + text: string + expected_args: string +} describe('RegularExpression', () => { - it('documents match arguments', () => { - const parameterRegistry = new ParameterTypeRegistry() - - /// [capture-match-arguments] - const expr = /I have (\d+) cukes? in my (\w+) now/ - const expression = new RegularExpression(expr, parameterRegistry) - const args = expression.match('I have 7 cukes in my belly now')! - assert.strictEqual(7, args[0].getValue(null)) - assert.strictEqual('belly', args[1].getValue(null)) - /// [capture-match-arguments] - }) + for (const path of glob.sync(`${testDataDir}/regular-expression/matching/*.yaml`)) { + const expectation = yaml.load(fs.readFileSync(path, 'utf-8')) as Expectation + it(`matches ${path}`, () => { + const parameterTypeRegistry = new ParameterTypeRegistry() + const expression = new RegularExpression( + new RegExp(expectation.expression), + parameterTypeRegistry + ) + const matches = expression.match(expectation.text) + assert.deepStrictEqual( + JSON.parse(JSON.stringify(matches ? matches.map((value) => value.getValue(null)) : null)), // Removes type information. + expectation.expected_args + ) + }) + } it('does no transform by default', () => { assert.deepStrictEqual(match(/(\d\d)/, '22'), ['22']) diff --git a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_parser_spec.rb b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_parser_spec.rb index ee74bcbdd..e2b78b703 100644 --- a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_parser_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_parser_spec.rb @@ -1,14 +1,13 @@ require 'yaml' -require 'json' require 'cucumber/cucumber_expressions/cucumber_expression_parser' require 'cucumber/cucumber_expressions/errors' module Cucumber module CucumberExpressions - describe 'Cucumber expression parser' do - Dir['../testdata/ast/*.yaml'].each do |testcase| - expectation = YAML.load_file(testcase) # encoding? - it "#{testcase}" do + describe CucumberExpressionParser do + Dir['../testdata/cucumber-expression/parser/*.yaml'].each do |path| + expectation = YAML.load_file(path) + it "parses #{path}" do parser = CucumberExpressionParser.new if expectation['exception'] expect { parser.parse(expectation['expression']) }.to raise_error(expectation['exception']) diff --git a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb index 63ea73004..13baa299f 100644 --- a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb @@ -1,5 +1,4 @@ require 'yaml' -require 'json' require 'cucumber/cucumber_expressions/cucumber_expression' require 'cucumber/cucumber_expressions/parameter_type_registry' @@ -7,9 +6,9 @@ module Cucumber module CucumberExpressions describe CucumberExpression do - Dir['../testdata/expression/*.yaml'].each do |testcase| - expectation = YAML.load_file(testcase) # encoding? - it "#{testcase}" do + Dir['../testdata/cucumber-expression/matching/*.yaml'].each do |path| + expectation = YAML.load_file(path) + it "matches #{path}" do parameter_registry = ParameterTypeRegistry.new if expectation['exception'] expect { @@ -25,15 +24,6 @@ module CucumberExpressions end end - Dir['../testdata/regex/*.yaml'].each do |testcase| - expectation = YAML.load_file(testcase) # encoding? - it "#{testcase}" do - parameter_registry = ParameterTypeRegistry.new - cucumber_expression = CucumberExpression.new(expectation['expression'], parameter_registry) - expect(cucumber_expression.regexp.source).to eq(expectation['expected_regex']) - end - end - it "documents match arguments" do parameter_registry = ParameterTypeRegistry.new diff --git a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_tokenizer_spec.rb b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_tokenizer_spec.rb index 5e25d215c..78895f91f 100644 --- a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_tokenizer_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_tokenizer_spec.rb @@ -1,14 +1,13 @@ require 'yaml' -require 'json' require 'cucumber/cucumber_expressions/cucumber_expression_tokenizer' require 'cucumber/cucumber_expressions/errors' module Cucumber module CucumberExpressions - describe 'Cucumber expression tokenizer' do - Dir['../testdata/tokens/*.yaml'].each do |testcase| - expectation = YAML.load_file(testcase) # encoding? - it "#{testcase}" do + describe CucumberExpressionTokenizer do + Dir['../testdata/cucumber-expression/tokenizer/*.yaml'].each do |path| + expectation = YAML.load_file(path) + it "tokenizes #{path}" do tokenizer = CucumberExpressionTokenizer.new if expectation['exception'] expect { tokenizer.tokenize(expectation['expression']) }.to raise_error(expectation['exception']) diff --git a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_transformation_spec.rb b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_transformation_spec.rb new file mode 100644 index 000000000..c83cea69c --- /dev/null +++ b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_transformation_spec.rb @@ -0,0 +1,27 @@ +require 'yaml' +require 'cucumber/cucumber_expressions/cucumber_expression' +require 'cucumber/cucumber_expressions/parameter_type_registry' + +module Cucumber + module CucumberExpressions + describe CucumberExpression do + Dir['../testdata/cucumber-expression/transformation/*.yaml'].each do |path| + expectation = YAML.load_file(path) + it "transforms #{path}" do + parameter_registry = ParameterTypeRegistry.new + if expectation['exception'] + expect { + cucumber_expression = CucumberExpression.new(expectation['expression'], parameter_registry) + cucumber_expression.match(expectation['text']) + }.to raise_error(expectation['exception']) + else + cucumber_expression = CucumberExpression.new(expectation['expression'], parameter_registry) + matches = cucumber_expression.match(expectation['text']) + values = matches.nil? ? nil : matches.map { |arg| arg.value(nil) } + expect(values).to eq(expectation['expected_args']) + end + end + end + end + end +end diff --git a/ruby/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb b/ruby/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb index 847155e46..f4c7e1517 100644 --- a/ruby/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb @@ -7,13 +7,10 @@ module CucumberExpressions class Color attr_reader :name - ### [color-constructor] def initialize(name) @name = name end - ### [color-constructor] - def ==(other) other.is_a?(Color) && other.name == name end @@ -46,7 +43,6 @@ def ==(other) describe "Custom parameter type" do before do parameter_type_registry = ParameterTypeRegistry.new - ### [add-color-parameter-type] parameter_type_registry.define_parameter_type(ParameterType.new( 'color', # name /red|blue|yellow/, # regexp @@ -55,7 +51,6 @@ def ==(other) true, # use_for_snippets false # prefer_for_regexp_match )) - ### [add-color-parameter-type] @parameter_type_registry = parameter_type_registry end diff --git a/ruby/spec/cucumber/cucumber_expressions/regular_expression_spec.rb b/ruby/spec/cucumber/cucumber_expressions/regular_expression_spec.rb index 955af9855..f21ae72ed 100644 --- a/ruby/spec/cucumber/cucumber_expressions/regular_expression_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/regular_expression_spec.rb @@ -1,19 +1,19 @@ +require 'yaml' require 'cucumber/cucumber_expressions/regular_expression' require 'cucumber/cucumber_expressions/parameter_type_registry' module Cucumber module CucumberExpressions describe RegularExpression do - it "documents match arguments" do - parameter_type_registry = ParameterTypeRegistry.new - - ### [capture-match-arguments] - expr = /I have (\d+) cukes? in my (\w*) now/ - expression = RegularExpression.new(expr, parameter_type_registry) - args = expression.match("I have 7 cukes in my belly now") - expect( args[0].value(nil) ).to eq(7) - expect( args[1].value(nil) ).to eq("belly") - ### [capture-match-arguments] + Dir['../testdata/regular-expression/matching/*.yaml'].each do |path| + expectation = YAML.load_file(path) + it "matches #{path}" do + parameter_registry = ParameterTypeRegistry.new + expression = RegularExpression.new(Regexp.new(expectation['expression']), parameter_registry) + matches = expression.match(expectation['text']) + values = matches.map { |arg| arg.value(nil) } + expect(values).to eq(expectation['expected_args']) + end end it "does no transform by default" do diff --git a/testdata/expression/allows-escaped-optional-parameter-types.yaml b/testdata/cucumber-expression/matching/allows-escaped-optional-parameter-types.yaml similarity index 100% rename from testdata/expression/allows-escaped-optional-parameter-types.yaml rename to testdata/cucumber-expression/matching/allows-escaped-optional-parameter-types.yaml diff --git a/testdata/expression/allows-parameter-type-in-alternation-1.yaml b/testdata/cucumber-expression/matching/allows-parameter-type-in-alternation-1.yaml similarity index 100% rename from testdata/expression/allows-parameter-type-in-alternation-1.yaml rename to testdata/cucumber-expression/matching/allows-parameter-type-in-alternation-1.yaml diff --git a/testdata/expression/allows-parameter-type-in-alternation-2.yaml b/testdata/cucumber-expression/matching/allows-parameter-type-in-alternation-2.yaml similarity index 100% rename from testdata/expression/allows-parameter-type-in-alternation-2.yaml rename to testdata/cucumber-expression/matching/allows-parameter-type-in-alternation-2.yaml diff --git a/testdata/expression/does-allow-parameter-adjacent-to-alternation.yaml b/testdata/cucumber-expression/matching/does-allow-parameter-adjacent-to-alternation.yaml similarity index 100% rename from testdata/expression/does-allow-parameter-adjacent-to-alternation.yaml rename to testdata/cucumber-expression/matching/does-allow-parameter-adjacent-to-alternation.yaml diff --git a/testdata/expression/does-not-allow-alternation-in-optional.yaml b/testdata/cucumber-expression/matching/does-not-allow-alternation-in-optional.yaml similarity index 100% rename from testdata/expression/does-not-allow-alternation-in-optional.yaml rename to testdata/cucumber-expression/matching/does-not-allow-alternation-in-optional.yaml diff --git a/testdata/expression/does-not-allow-alternation-with-empty-alternative-by-adjacent-left-parameter.yaml b/testdata/cucumber-expression/matching/does-not-allow-alternation-with-empty-alternative-by-adjacent-left-parameter.yaml similarity index 100% rename from testdata/expression/does-not-allow-alternation-with-empty-alternative-by-adjacent-left-parameter.yaml rename to testdata/cucumber-expression/matching/does-not-allow-alternation-with-empty-alternative-by-adjacent-left-parameter.yaml diff --git a/testdata/expression/does-not-allow-alternation-with-empty-alternative-by-adjacent-optional.yaml b/testdata/cucumber-expression/matching/does-not-allow-alternation-with-empty-alternative-by-adjacent-optional.yaml similarity index 100% rename from testdata/expression/does-not-allow-alternation-with-empty-alternative-by-adjacent-optional.yaml rename to testdata/cucumber-expression/matching/does-not-allow-alternation-with-empty-alternative-by-adjacent-optional.yaml diff --git a/testdata/expression/does-not-allow-alternation-with-empty-alternative-by-adjacent-right-parameter.yaml b/testdata/cucumber-expression/matching/does-not-allow-alternation-with-empty-alternative-by-adjacent-right-parameter.yaml similarity index 100% rename from testdata/expression/does-not-allow-alternation-with-empty-alternative-by-adjacent-right-parameter.yaml rename to testdata/cucumber-expression/matching/does-not-allow-alternation-with-empty-alternative-by-adjacent-right-parameter.yaml diff --git a/testdata/expression/does-not-allow-alternation-with-empty-alternative.yaml b/testdata/cucumber-expression/matching/does-not-allow-alternation-with-empty-alternative.yaml similarity index 100% rename from testdata/expression/does-not-allow-alternation-with-empty-alternative.yaml rename to testdata/cucumber-expression/matching/does-not-allow-alternation-with-empty-alternative.yaml diff --git a/testdata/expression/does-not-allow-empty-optional.yaml b/testdata/cucumber-expression/matching/does-not-allow-empty-optional.yaml similarity index 100% rename from testdata/expression/does-not-allow-empty-optional.yaml rename to testdata/cucumber-expression/matching/does-not-allow-empty-optional.yaml diff --git a/testdata/expression/does-not-allow-nested-optional.yaml b/testdata/cucumber-expression/matching/does-not-allow-nested-optional.yaml similarity index 100% rename from testdata/expression/does-not-allow-nested-optional.yaml rename to testdata/cucumber-expression/matching/does-not-allow-nested-optional.yaml diff --git a/testdata/expression/does-not-allow-optional-parameter-types.yaml b/testdata/cucumber-expression/matching/does-not-allow-optional-parameter-types.yaml similarity index 100% rename from testdata/expression/does-not-allow-optional-parameter-types.yaml rename to testdata/cucumber-expression/matching/does-not-allow-optional-parameter-types.yaml diff --git a/testdata/expression/does-not-allow-parameter-name-with-reserved-characters.yaml b/testdata/cucumber-expression/matching/does-not-allow-parameter-name-with-reserved-characters.yaml similarity index 100% rename from testdata/expression/does-not-allow-parameter-name-with-reserved-characters.yaml rename to testdata/cucumber-expression/matching/does-not-allow-parameter-name-with-reserved-characters.yaml diff --git a/testdata/expression/does-not-allow-unfinished-parenthesis-1.yaml b/testdata/cucumber-expression/matching/does-not-allow-unfinished-parenthesis-1.yaml similarity index 100% rename from testdata/expression/does-not-allow-unfinished-parenthesis-1.yaml rename to testdata/cucumber-expression/matching/does-not-allow-unfinished-parenthesis-1.yaml diff --git a/testdata/expression/does-not-allow-unfinished-parenthesis-2.yaml b/testdata/cucumber-expression/matching/does-not-allow-unfinished-parenthesis-2.yaml similarity index 100% rename from testdata/expression/does-not-allow-unfinished-parenthesis-2.yaml rename to testdata/cucumber-expression/matching/does-not-allow-unfinished-parenthesis-2.yaml diff --git a/testdata/expression/does-not-allow-unfinished-parenthesis-3.yaml b/testdata/cucumber-expression/matching/does-not-allow-unfinished-parenthesis-3.yaml similarity index 100% rename from testdata/expression/does-not-allow-unfinished-parenthesis-3.yaml rename to testdata/cucumber-expression/matching/does-not-allow-unfinished-parenthesis-3.yaml diff --git a/testdata/expression/does-not-match-misquoted-string.yaml b/testdata/cucumber-expression/matching/does-not-match-misquoted-string.yaml similarity index 100% rename from testdata/expression/does-not-match-misquoted-string.yaml rename to testdata/cucumber-expression/matching/does-not-match-misquoted-string.yaml diff --git a/testdata/expression/doesnt-match-float-as-int.yaml b/testdata/cucumber-expression/matching/doesnt-match-float-as-int.yaml similarity index 100% rename from testdata/expression/doesnt-match-float-as-int.yaml rename to testdata/cucumber-expression/matching/doesnt-match-float-as-int.yaml diff --git a/testdata/expression/matches-alternation.yaml b/testdata/cucumber-expression/matching/matches-alternation.yaml similarity index 100% rename from testdata/expression/matches-alternation.yaml rename to testdata/cucumber-expression/matching/matches-alternation.yaml diff --git a/testdata/expression/matches-anonymous-parameter-type.yaml b/testdata/cucumber-expression/matching/matches-anonymous-parameter-type.yaml similarity index 100% rename from testdata/expression/matches-anonymous-parameter-type.yaml rename to testdata/cucumber-expression/matching/matches-anonymous-parameter-type.yaml diff --git a/testdata/expression/matches-double-quoted-empty-string-as-empty-string-along-with-other-strings.yaml b/testdata/cucumber-expression/matching/matches-double-quoted-empty-string-as-empty-string-along-with-other-strings.yaml similarity index 100% rename from testdata/expression/matches-double-quoted-empty-string-as-empty-string-along-with-other-strings.yaml rename to testdata/cucumber-expression/matching/matches-double-quoted-empty-string-as-empty-string-along-with-other-strings.yaml diff --git a/testdata/expression/matches-double-quoted-empty-string-as-empty-string.yaml b/testdata/cucumber-expression/matching/matches-double-quoted-empty-string-as-empty-string.yaml similarity index 100% rename from testdata/expression/matches-double-quoted-empty-string-as-empty-string.yaml rename to testdata/cucumber-expression/matching/matches-double-quoted-empty-string-as-empty-string.yaml diff --git a/testdata/expression/matches-double-quoted-string-with-escaped-double-quote.yaml b/testdata/cucumber-expression/matching/matches-double-quoted-string-with-escaped-double-quote.yaml similarity index 100% rename from testdata/expression/matches-double-quoted-string-with-escaped-double-quote.yaml rename to testdata/cucumber-expression/matching/matches-double-quoted-string-with-escaped-double-quote.yaml diff --git a/testdata/expression/matches-double-quoted-string-with-single-quotes.yaml b/testdata/cucumber-expression/matching/matches-double-quoted-string-with-single-quotes.yaml similarity index 100% rename from testdata/expression/matches-double-quoted-string-with-single-quotes.yaml rename to testdata/cucumber-expression/matching/matches-double-quoted-string-with-single-quotes.yaml diff --git a/testdata/expression/matches-double-quoted-string.yaml b/testdata/cucumber-expression/matching/matches-double-quoted-string.yaml similarity index 100% rename from testdata/expression/matches-double-quoted-string.yaml rename to testdata/cucumber-expression/matching/matches-double-quoted-string.yaml diff --git a/testdata/expression/matches-doubly-escaped-parenthesis.yaml b/testdata/cucumber-expression/matching/matches-doubly-escaped-parenthesis.yaml similarity index 100% rename from testdata/expression/matches-doubly-escaped-parenthesis.yaml rename to testdata/cucumber-expression/matching/matches-doubly-escaped-parenthesis.yaml diff --git a/testdata/expression/matches-doubly-escaped-slash-1.yaml b/testdata/cucumber-expression/matching/matches-doubly-escaped-slash-1.yaml similarity index 100% rename from testdata/expression/matches-doubly-escaped-slash-1.yaml rename to testdata/cucumber-expression/matching/matches-doubly-escaped-slash-1.yaml diff --git a/testdata/expression/matches-doubly-escaped-slash-2.yaml b/testdata/cucumber-expression/matching/matches-doubly-escaped-slash-2.yaml similarity index 100% rename from testdata/expression/matches-doubly-escaped-slash-2.yaml rename to testdata/cucumber-expression/matching/matches-doubly-escaped-slash-2.yaml diff --git a/testdata/expression/matches-escaped-parenthesis-1.yaml b/testdata/cucumber-expression/matching/matches-escaped-parenthesis-1.yaml similarity index 100% rename from testdata/expression/matches-escaped-parenthesis-1.yaml rename to testdata/cucumber-expression/matching/matches-escaped-parenthesis-1.yaml diff --git a/testdata/expression/matches-escaped-parenthesis-2.yaml b/testdata/cucumber-expression/matching/matches-escaped-parenthesis-2.yaml similarity index 100% rename from testdata/expression/matches-escaped-parenthesis-2.yaml rename to testdata/cucumber-expression/matching/matches-escaped-parenthesis-2.yaml diff --git a/testdata/expression/matches-escaped-parenthesis-3.yaml b/testdata/cucumber-expression/matching/matches-escaped-parenthesis-3.yaml similarity index 100% rename from testdata/expression/matches-escaped-parenthesis-3.yaml rename to testdata/cucumber-expression/matching/matches-escaped-parenthesis-3.yaml diff --git a/testdata/expression/matches-escaped-slash.yaml b/testdata/cucumber-expression/matching/matches-escaped-slash.yaml similarity index 100% rename from testdata/expression/matches-escaped-slash.yaml rename to testdata/cucumber-expression/matching/matches-escaped-slash.yaml diff --git a/testdata/expression/matches-float-1.yaml b/testdata/cucumber-expression/matching/matches-float-1.yaml similarity index 100% rename from testdata/expression/matches-float-1.yaml rename to testdata/cucumber-expression/matching/matches-float-1.yaml diff --git a/testdata/expression/matches-float-2.yaml b/testdata/cucumber-expression/matching/matches-float-2.yaml similarity index 100% rename from testdata/expression/matches-float-2.yaml rename to testdata/cucumber-expression/matching/matches-float-2.yaml diff --git a/testdata/expression/matches-int.yaml b/testdata/cucumber-expression/matching/matches-int.yaml similarity index 100% rename from testdata/expression/matches-int.yaml rename to testdata/cucumber-expression/matching/matches-int.yaml diff --git a/testdata/expression/matches-multiple-double-quoted-strings.yaml b/testdata/cucumber-expression/matching/matches-multiple-double-quoted-strings.yaml similarity index 100% rename from testdata/expression/matches-multiple-double-quoted-strings.yaml rename to testdata/cucumber-expression/matching/matches-multiple-double-quoted-strings.yaml diff --git a/testdata/expression/matches-multiple-single-quoted-strings.yaml b/testdata/cucumber-expression/matching/matches-multiple-single-quoted-strings.yaml similarity index 100% rename from testdata/expression/matches-multiple-single-quoted-strings.yaml rename to testdata/cucumber-expression/matching/matches-multiple-single-quoted-strings.yaml diff --git a/testdata/expression/matches-optional-before-alternation-1.yaml b/testdata/cucumber-expression/matching/matches-optional-before-alternation-1.yaml similarity index 100% rename from testdata/expression/matches-optional-before-alternation-1.yaml rename to testdata/cucumber-expression/matching/matches-optional-before-alternation-1.yaml diff --git a/testdata/expression/matches-optional-before-alternation-2.yaml b/testdata/cucumber-expression/matching/matches-optional-before-alternation-2.yaml similarity index 100% rename from testdata/expression/matches-optional-before-alternation-2.yaml rename to testdata/cucumber-expression/matching/matches-optional-before-alternation-2.yaml diff --git a/testdata/expression/matches-optional-before-alternation-with-regex-characters-1.yaml b/testdata/cucumber-expression/matching/matches-optional-before-alternation-with-regex-characters-1.yaml similarity index 100% rename from testdata/expression/matches-optional-before-alternation-with-regex-characters-1.yaml rename to testdata/cucumber-expression/matching/matches-optional-before-alternation-with-regex-characters-1.yaml diff --git a/testdata/expression/matches-optional-before-alternation-with-regex-characters-2.yaml b/testdata/cucumber-expression/matching/matches-optional-before-alternation-with-regex-characters-2.yaml similarity index 100% rename from testdata/expression/matches-optional-before-alternation-with-regex-characters-2.yaml rename to testdata/cucumber-expression/matching/matches-optional-before-alternation-with-regex-characters-2.yaml diff --git a/testdata/expression/matches-optional-in-alternation-1.yaml b/testdata/cucumber-expression/matching/matches-optional-in-alternation-1.yaml similarity index 100% rename from testdata/expression/matches-optional-in-alternation-1.yaml rename to testdata/cucumber-expression/matching/matches-optional-in-alternation-1.yaml diff --git a/testdata/expression/matches-optional-in-alternation-2.yaml b/testdata/cucumber-expression/matching/matches-optional-in-alternation-2.yaml similarity index 100% rename from testdata/expression/matches-optional-in-alternation-2.yaml rename to testdata/cucumber-expression/matching/matches-optional-in-alternation-2.yaml diff --git a/testdata/expression/matches-optional-in-alternation-3.yaml b/testdata/cucumber-expression/matching/matches-optional-in-alternation-3.yaml similarity index 100% rename from testdata/expression/matches-optional-in-alternation-3.yaml rename to testdata/cucumber-expression/matching/matches-optional-in-alternation-3.yaml diff --git a/testdata/expression/matches-single-quoted-empty-string-as-empty-string-along-with-other-strings.yaml b/testdata/cucumber-expression/matching/matches-single-quoted-empty-string-as-empty-string-along-with-other-strings.yaml similarity index 100% rename from testdata/expression/matches-single-quoted-empty-string-as-empty-string-along-with-other-strings.yaml rename to testdata/cucumber-expression/matching/matches-single-quoted-empty-string-as-empty-string-along-with-other-strings.yaml diff --git a/testdata/expression/matches-single-quoted-empty-string-as-empty-string.yaml b/testdata/cucumber-expression/matching/matches-single-quoted-empty-string-as-empty-string.yaml similarity index 100% rename from testdata/expression/matches-single-quoted-empty-string-as-empty-string.yaml rename to testdata/cucumber-expression/matching/matches-single-quoted-empty-string-as-empty-string.yaml diff --git a/testdata/expression/matches-single-quoted-string-with-double-quotes.yaml b/testdata/cucumber-expression/matching/matches-single-quoted-string-with-double-quotes.yaml similarity index 100% rename from testdata/expression/matches-single-quoted-string-with-double-quotes.yaml rename to testdata/cucumber-expression/matching/matches-single-quoted-string-with-double-quotes.yaml diff --git a/testdata/expression/matches-single-quoted-string-with-escaped-single-quote.yaml b/testdata/cucumber-expression/matching/matches-single-quoted-string-with-escaped-single-quote.yaml similarity index 100% rename from testdata/expression/matches-single-quoted-string-with-escaped-single-quote.yaml rename to testdata/cucumber-expression/matching/matches-single-quoted-string-with-escaped-single-quote.yaml diff --git a/testdata/expression/matches-single-quoted-string.yaml b/testdata/cucumber-expression/matching/matches-single-quoted-string.yaml similarity index 100% rename from testdata/expression/matches-single-quoted-string.yaml rename to testdata/cucumber-expression/matching/matches-single-quoted-string.yaml diff --git a/testdata/expression/matches-word.yaml b/testdata/cucumber-expression/matching/matches-word.yaml similarity index 100% rename from testdata/expression/matches-word.yaml rename to testdata/cucumber-expression/matching/matches-word.yaml diff --git a/testdata/expression/throws-unknown-parameter-type.yaml b/testdata/cucumber-expression/matching/throws-unknown-parameter-type.yaml similarity index 100% rename from testdata/expression/throws-unknown-parameter-type.yaml rename to testdata/cucumber-expression/matching/throws-unknown-parameter-type.yaml diff --git a/testdata/ast/alternation-followed-by-optional.yaml b/testdata/cucumber-expression/parser/alternation-followed-by-optional.yaml similarity index 100% rename from testdata/ast/alternation-followed-by-optional.yaml rename to testdata/cucumber-expression/parser/alternation-followed-by-optional.yaml diff --git a/testdata/ast/alternation-phrase.yaml b/testdata/cucumber-expression/parser/alternation-phrase.yaml similarity index 100% rename from testdata/ast/alternation-phrase.yaml rename to testdata/cucumber-expression/parser/alternation-phrase.yaml diff --git a/testdata/ast/alternation-with-parameter.yaml b/testdata/cucumber-expression/parser/alternation-with-parameter.yaml similarity index 100% rename from testdata/ast/alternation-with-parameter.yaml rename to testdata/cucumber-expression/parser/alternation-with-parameter.yaml diff --git a/testdata/ast/alternation-with-unused-end-optional.yaml b/testdata/cucumber-expression/parser/alternation-with-unused-end-optional.yaml similarity index 100% rename from testdata/ast/alternation-with-unused-end-optional.yaml rename to testdata/cucumber-expression/parser/alternation-with-unused-end-optional.yaml diff --git a/testdata/ast/alternation-with-unused-start-optional.yaml b/testdata/cucumber-expression/parser/alternation-with-unused-start-optional.yaml similarity index 100% rename from testdata/ast/alternation-with-unused-start-optional.yaml rename to testdata/cucumber-expression/parser/alternation-with-unused-start-optional.yaml diff --git a/testdata/ast/alternation-with-white-space.yaml b/testdata/cucumber-expression/parser/alternation-with-white-space.yaml similarity index 100% rename from testdata/ast/alternation-with-white-space.yaml rename to testdata/cucumber-expression/parser/alternation-with-white-space.yaml diff --git a/testdata/ast/alternation.yaml b/testdata/cucumber-expression/parser/alternation.yaml similarity index 100% rename from testdata/ast/alternation.yaml rename to testdata/cucumber-expression/parser/alternation.yaml diff --git a/testdata/ast/anonymous-parameter.yaml b/testdata/cucumber-expression/parser/anonymous-parameter.yaml similarity index 100% rename from testdata/ast/anonymous-parameter.yaml rename to testdata/cucumber-expression/parser/anonymous-parameter.yaml diff --git a/testdata/ast/closing-brace.yaml b/testdata/cucumber-expression/parser/closing-brace.yaml similarity index 100% rename from testdata/ast/closing-brace.yaml rename to testdata/cucumber-expression/parser/closing-brace.yaml diff --git a/testdata/ast/closing-parenthesis.yaml b/testdata/cucumber-expression/parser/closing-parenthesis.yaml similarity index 100% rename from testdata/ast/closing-parenthesis.yaml rename to testdata/cucumber-expression/parser/closing-parenthesis.yaml diff --git a/testdata/ast/empty-alternation.yaml b/testdata/cucumber-expression/parser/empty-alternation.yaml similarity index 100% rename from testdata/ast/empty-alternation.yaml rename to testdata/cucumber-expression/parser/empty-alternation.yaml diff --git a/testdata/ast/empty-alternations.yaml b/testdata/cucumber-expression/parser/empty-alternations.yaml similarity index 100% rename from testdata/ast/empty-alternations.yaml rename to testdata/cucumber-expression/parser/empty-alternations.yaml diff --git a/testdata/ast/empty-string.yaml b/testdata/cucumber-expression/parser/empty-string.yaml similarity index 100% rename from testdata/ast/empty-string.yaml rename to testdata/cucumber-expression/parser/empty-string.yaml diff --git a/testdata/ast/escaped-alternation.yaml b/testdata/cucumber-expression/parser/escaped-alternation.yaml similarity index 100% rename from testdata/ast/escaped-alternation.yaml rename to testdata/cucumber-expression/parser/escaped-alternation.yaml diff --git a/testdata/ast/escaped-backslash.yaml b/testdata/cucumber-expression/parser/escaped-backslash.yaml similarity index 100% rename from testdata/ast/escaped-backslash.yaml rename to testdata/cucumber-expression/parser/escaped-backslash.yaml diff --git a/testdata/ast/escaped-opening-parenthesis.yaml b/testdata/cucumber-expression/parser/escaped-opening-parenthesis.yaml similarity index 100% rename from testdata/ast/escaped-opening-parenthesis.yaml rename to testdata/cucumber-expression/parser/escaped-opening-parenthesis.yaml diff --git a/testdata/ast/escaped-optional-followed-by-optional.yaml b/testdata/cucumber-expression/parser/escaped-optional-followed-by-optional.yaml similarity index 100% rename from testdata/ast/escaped-optional-followed-by-optional.yaml rename to testdata/cucumber-expression/parser/escaped-optional-followed-by-optional.yaml diff --git a/testdata/ast/escaped-optional-phrase.yaml b/testdata/cucumber-expression/parser/escaped-optional-phrase.yaml similarity index 100% rename from testdata/ast/escaped-optional-phrase.yaml rename to testdata/cucumber-expression/parser/escaped-optional-phrase.yaml diff --git a/testdata/ast/escaped-optional.yaml b/testdata/cucumber-expression/parser/escaped-optional.yaml similarity index 100% rename from testdata/ast/escaped-optional.yaml rename to testdata/cucumber-expression/parser/escaped-optional.yaml diff --git a/testdata/ast/opening-brace.yaml b/testdata/cucumber-expression/parser/opening-brace.yaml similarity index 100% rename from testdata/ast/opening-brace.yaml rename to testdata/cucumber-expression/parser/opening-brace.yaml diff --git a/testdata/ast/opening-parenthesis.yaml b/testdata/cucumber-expression/parser/opening-parenthesis.yaml similarity index 100% rename from testdata/ast/opening-parenthesis.yaml rename to testdata/cucumber-expression/parser/opening-parenthesis.yaml diff --git a/testdata/ast/optional-containing-nested-optional.yaml b/testdata/cucumber-expression/parser/optional-containing-nested-optional.yaml similarity index 100% rename from testdata/ast/optional-containing-nested-optional.yaml rename to testdata/cucumber-expression/parser/optional-containing-nested-optional.yaml diff --git a/testdata/ast/optional-phrase.yaml b/testdata/cucumber-expression/parser/optional-phrase.yaml similarity index 100% rename from testdata/ast/optional-phrase.yaml rename to testdata/cucumber-expression/parser/optional-phrase.yaml diff --git a/testdata/ast/optional.yaml b/testdata/cucumber-expression/parser/optional.yaml similarity index 100% rename from testdata/ast/optional.yaml rename to testdata/cucumber-expression/parser/optional.yaml diff --git a/testdata/ast/parameter.yaml b/testdata/cucumber-expression/parser/parameter.yaml similarity index 100% rename from testdata/ast/parameter.yaml rename to testdata/cucumber-expression/parser/parameter.yaml diff --git a/testdata/ast/phrase.yaml b/testdata/cucumber-expression/parser/phrase.yaml similarity index 100% rename from testdata/ast/phrase.yaml rename to testdata/cucumber-expression/parser/phrase.yaml diff --git a/testdata/ast/unfinished-parameter.yaml b/testdata/cucumber-expression/parser/unfinished-parameter.yaml similarity index 100% rename from testdata/ast/unfinished-parameter.yaml rename to testdata/cucumber-expression/parser/unfinished-parameter.yaml diff --git a/testdata/tokens/alternation-phrase.yaml b/testdata/cucumber-expression/tokenizer/alternation-phrase.yaml similarity index 100% rename from testdata/tokens/alternation-phrase.yaml rename to testdata/cucumber-expression/tokenizer/alternation-phrase.yaml diff --git a/testdata/tokens/alternation.yaml b/testdata/cucumber-expression/tokenizer/alternation.yaml similarity index 100% rename from testdata/tokens/alternation.yaml rename to testdata/cucumber-expression/tokenizer/alternation.yaml diff --git a/testdata/tokens/empty-string.yaml b/testdata/cucumber-expression/tokenizer/empty-string.yaml similarity index 100% rename from testdata/tokens/empty-string.yaml rename to testdata/cucumber-expression/tokenizer/empty-string.yaml diff --git a/testdata/tokens/escape-non-reserved-character.yaml b/testdata/cucumber-expression/tokenizer/escape-non-reserved-character.yaml similarity index 100% rename from testdata/tokens/escape-non-reserved-character.yaml rename to testdata/cucumber-expression/tokenizer/escape-non-reserved-character.yaml diff --git a/testdata/tokens/escaped-alternation.yaml b/testdata/cucumber-expression/tokenizer/escaped-alternation.yaml similarity index 100% rename from testdata/tokens/escaped-alternation.yaml rename to testdata/cucumber-expression/tokenizer/escaped-alternation.yaml diff --git a/testdata/tokens/escaped-char-has-start-index-of-text-token.yaml b/testdata/cucumber-expression/tokenizer/escaped-char-has-start-index-of-text-token.yaml similarity index 100% rename from testdata/tokens/escaped-char-has-start-index-of-text-token.yaml rename to testdata/cucumber-expression/tokenizer/escaped-char-has-start-index-of-text-token.yaml diff --git a/testdata/tokens/escaped-end-of-line.yaml b/testdata/cucumber-expression/tokenizer/escaped-end-of-line.yaml similarity index 100% rename from testdata/tokens/escaped-end-of-line.yaml rename to testdata/cucumber-expression/tokenizer/escaped-end-of-line.yaml diff --git a/testdata/tokens/escaped-optional.yaml b/testdata/cucumber-expression/tokenizer/escaped-optional.yaml similarity index 100% rename from testdata/tokens/escaped-optional.yaml rename to testdata/cucumber-expression/tokenizer/escaped-optional.yaml diff --git a/testdata/tokens/escaped-parameter.yaml b/testdata/cucumber-expression/tokenizer/escaped-parameter.yaml similarity index 100% rename from testdata/tokens/escaped-parameter.yaml rename to testdata/cucumber-expression/tokenizer/escaped-parameter.yaml diff --git a/testdata/tokens/escaped-space.yaml b/testdata/cucumber-expression/tokenizer/escaped-space.yaml similarity index 100% rename from testdata/tokens/escaped-space.yaml rename to testdata/cucumber-expression/tokenizer/escaped-space.yaml diff --git a/testdata/tokens/optional-phrase.yaml b/testdata/cucumber-expression/tokenizer/optional-phrase.yaml similarity index 100% rename from testdata/tokens/optional-phrase.yaml rename to testdata/cucumber-expression/tokenizer/optional-phrase.yaml diff --git a/testdata/tokens/optional.yaml b/testdata/cucumber-expression/tokenizer/optional.yaml similarity index 100% rename from testdata/tokens/optional.yaml rename to testdata/cucumber-expression/tokenizer/optional.yaml diff --git a/testdata/tokens/parameter-phrase.yaml b/testdata/cucumber-expression/tokenizer/parameter-phrase.yaml similarity index 100% rename from testdata/tokens/parameter-phrase.yaml rename to testdata/cucumber-expression/tokenizer/parameter-phrase.yaml diff --git a/testdata/tokens/parameter.yaml b/testdata/cucumber-expression/tokenizer/parameter.yaml similarity index 100% rename from testdata/tokens/parameter.yaml rename to testdata/cucumber-expression/tokenizer/parameter.yaml diff --git a/testdata/tokens/phrase.yaml b/testdata/cucumber-expression/tokenizer/phrase.yaml similarity index 100% rename from testdata/tokens/phrase.yaml rename to testdata/cucumber-expression/tokenizer/phrase.yaml diff --git a/testdata/regex/alternation-with-optional.yaml b/testdata/cucumber-expression/transformation/alternation-with-optional.yaml similarity index 100% rename from testdata/regex/alternation-with-optional.yaml rename to testdata/cucumber-expression/transformation/alternation-with-optional.yaml diff --git a/testdata/regex/alternation.yaml b/testdata/cucumber-expression/transformation/alternation.yaml similarity index 100% rename from testdata/regex/alternation.yaml rename to testdata/cucumber-expression/transformation/alternation.yaml diff --git a/testdata/regex/empty.yaml b/testdata/cucumber-expression/transformation/empty.yaml similarity index 100% rename from testdata/regex/empty.yaml rename to testdata/cucumber-expression/transformation/empty.yaml diff --git a/testdata/regex/escape-regex-characters.yaml b/testdata/cucumber-expression/transformation/escape-regex-characters.yaml similarity index 100% rename from testdata/regex/escape-regex-characters.yaml rename to testdata/cucumber-expression/transformation/escape-regex-characters.yaml diff --git a/testdata/regex/optional.yaml b/testdata/cucumber-expression/transformation/optional.yaml similarity index 100% rename from testdata/regex/optional.yaml rename to testdata/cucumber-expression/transformation/optional.yaml diff --git a/testdata/regex/parameter.yaml b/testdata/cucumber-expression/transformation/parameter.yaml similarity index 100% rename from testdata/regex/parameter.yaml rename to testdata/cucumber-expression/transformation/parameter.yaml diff --git a/testdata/regex/text.yaml b/testdata/cucumber-expression/transformation/text.yaml similarity index 100% rename from testdata/regex/text.yaml rename to testdata/cucumber-expression/transformation/text.yaml diff --git a/testdata/regex/unicode.yaml b/testdata/cucumber-expression/transformation/unicode.yaml similarity index 100% rename from testdata/regex/unicode.yaml rename to testdata/cucumber-expression/transformation/unicode.yaml diff --git a/testdata/regular-expression/matching/optional-capture-groups-all.yaml b/testdata/regular-expression/matching/optional-capture-groups-all.yaml new file mode 100644 index 000000000..61e785664 --- /dev/null +++ b/testdata/regular-expression/matching/optional-capture-groups-all.yaml @@ -0,0 +1,7 @@ +--- +expression: "^a (b )?c (d )?e (f )?g$" +text: a b c d e f g +expected_args: +- 'b ' +- 'd ' +- 'f ' diff --git a/testdata/regular-expression/matching/optional-capture-groups-some.yaml b/testdata/regular-expression/matching/optional-capture-groups-some.yaml new file mode 100644 index 000000000..7e597cf11 --- /dev/null +++ b/testdata/regular-expression/matching/optional-capture-groups-some.yaml @@ -0,0 +1,7 @@ +--- +expression: "^a (b )?c (d )?e (f )?g$" +text: a b c e f g +expected_args: +- 'b ' +- +- 'f '