CucumberExpressionGenerator { public List<GeneratedExpression> generateExpressions(String text) { List<List<ParameterType<?>>> parameterTypeCombinations = new ArrayList<>(); List<ParameterTypeMatcher> parameterTypeMatchers = createParameterTypeMatchers(text); StringBuilder expressionTemplate = new StringBuilder(); int pos = 0; while (true) { List<ParameterTypeMatcher> matchingParameterTypeMatchers = new ArrayList<>(); for (ParameterTypeMatcher parameterTypeMatcher : parameterTypeMatchers) { if (parameterTypeMatcher.advanceToAndFind(pos)) { matchingParameterTypeMatchers.add(parameterTypeMatcher); } } if (!matchingParameterTypeMatchers.isEmpty()) { Collections.sort(matchingParameterTypeMatchers); ParameterTypeMatcher bestParameterTypeMatcher = matchingParameterTypeMatchers.get(0); List<ParameterTypeMatcher> bestParameterTypeMatchers = new ArrayList<>(); for (ParameterTypeMatcher m : matchingParameterTypeMatchers) { if (m.compareTo(bestParameterTypeMatcher) == 0) { bestParameterTypeMatchers.add(m); } } Set<ParameterType<?>> set = new HashSet<>(); for (ParameterTypeMatcher parameterTypeMatcher : bestParameterTypeMatchers) { ParameterType<?> parameterType = parameterTypeMatcher.getParameterType(); set.add(parameterType); } SortedSet<ParameterType<?>> parameterTypes = new TreeSet<>(set); parameterTypeCombinations.add(new ArrayList<>(parameterTypes)); expressionTemplate .append(escape(text.substring(pos, bestParameterTypeMatcher.start()))) .append("{%s}"); pos = bestParameterTypeMatcher.start() + bestParameterTypeMatcher.group().length(); } else { break; } if (pos >= text.length()) { break; } } expressionTemplate.append(escape(text.substring(pos))); return new CombinatorialGeneratedExpressionFactory(expressionTemplate.toString(), parameterTypeCombinations).generateExpressions(); } CucumberExpressionGenerator(ParameterTypeRegistry parameterTypeRegistry); List<GeneratedExpression> generateExpressions(String text); @Deprecated GeneratedExpression generateExpression(String text);  }
@Test public void documents_expression_generation() { CucumberExpressionGenerator generator = new CucumberExpressionGenerator(parameterTypeRegistry); String undefinedStepText = "I have 2 cucumbers and 1.5 tomato"; GeneratedExpression generatedExpression = generator.generateExpressions(undefinedStepText).get(0); assertEquals("I have {int} cucumbers and {double} tomato", generatedExpression.getSource()); assertEquals(Double.class, generatedExpression.getParameterTypes().get(1).getType()); }
@Test public void generates_all_combinations_of_expressions_when_several_parameter_types_match() { parameterTypeRegistry.defineParameterType(new ParameterType<>( "currency", "x", Currency.class, (Transformer<Currency>) Currency::getInstance, true, true )); parameterTypeRegistry.defineParameterType(new ParameterType<>( "date", "x", Date.class, new Transformer<Date>() { @Override public Date transform(String arg) { try { return df.parse(arg); } catch (ParseException e) { throw new RuntimeException(e); } } }, true, false )); List<GeneratedExpression> generatedExpressions = generator.generateExpressions("I have x and x and another x"); List<String> expressions = new ArrayList<>(); for (GeneratedExpression generatedExpression : generatedExpressions) { String source = generatedExpression.getSource(); expressions.add(source); } assertEquals(asList( "I have {currency} and {currency} and another {currency}", "I have {currency} and {currency} and another {date}", "I have {currency} and {date} and another {currency}", "I have {currency} and {date} and another {date}", "I have {date} and {currency} and another {currency}", "I have {date} and {currency} and another {date}", "I have {date} and {date} and another {currency}", "I have {date} and {date} and another {date}" ), expressions); }
@Test public void exposes_transforms_in_generated_expression() { GeneratedExpression generatedExpression = generator.generateExpressions("I have 2 cukes and 1.5 euro").get(0); assertEquals(Integer.class, generatedExpression.getParameterTypes().get(0).getType()); assertEquals(Double.class, generatedExpression.getParameterTypes().get(1).getType()); }
@Test public void matches_parameter_types_with_optional_capture_groups() { ParameterType<String> optionalFlight = new ParameterType<>( "optional-flight", "(1st flight)?", String.class, (Transformer<String>) arg -> arg, true, false ); ParameterType<String> optionalHotel = new ParameterType<>( "optional-hotel", "(1 hotel)?", String.class, (Transformer<String>) arg -> arg, true, false ); parameterTypeRegistry.defineParameterType(optionalFlight); parameterTypeRegistry.defineParameterType(optionalHotel); List<GeneratedExpression> generatedExpressions = generator.generateExpressions("I reach Stage 4: 1st flight -1 hotel"); assertEquals("I reach Stage {int}: {optional-flight} {int} hotel", generatedExpressions.get(0).getSource()); }
@Test public void generates_at_most_256_expressions() { for (int i = 0; i < 4; i++) { ParameterType<String> myType = new ParameterType<>( "my-type-" + i, "[a-z]", String.class, (Transformer<String>) arg -> arg, true, false ); parameterTypeRegistry.defineParameterType(myType); } assertEquals(256, generator.generateExpressions("a b c d e f g h i j k").size()); }
@Test public void prefers_expression_with_longest_non_empty_match() { ParameterType<String> zeroOrMore = new ParameterType<>( "zero-or-more", "[a-z]*", String.class, (Transformer<String>) arg -> arg, true, false ); parameterTypeRegistry.defineParameterType(zeroOrMore); ParameterType<String> exactlyOne = new ParameterType<>( "exactly-one", "[a-z]", String.class, (Transformer<String>) arg -> arg, true, false ); parameterTypeRegistry.defineParameterType(exactlyOne); List<GeneratedExpression> generatedExpressions = generator.generateExpressions("a simple step"); assertEquals(2, generatedExpressions.size()); assertEquals("{exactly-one} {zero-or-more} {zero-or-more}", generatedExpressions.get(0).getSource()); assertEquals("{zero-or-more} {zero-or-more} {zero-or-more}", generatedExpressions.get(1).getSource()); }