Search code examples
regexkotlincucumbercucumber-java

What's wrong with this cucumber regex?


I tried to define this custom parameter type:

ParameterType("complex", """(?x)
    | complex\( \s*
    |   (?:
    |     ($realRegex)
    |     (?:
    |       \s* ([+-]) \s* ($realRegex) \s* i
    |     )?
    |   |
    |     ($realRegex) \s* i
    |   )
    | \s* \)
    |""".trimMargin()) {
        realPartString: String?, joiner: String?, imaginaryPartString1: String?, imaginaryPartString2: String? ->

        // handling logic omitted as it doesn't matter yet
}

Cucumber is giving an error:

java.util.NoSuchElementException
    at java.base/java.util.Spliterators$2Adapter.nextInt(Spliterators.java:733)
    at java.base/java.util.PrimitiveIterator$OfInt.next(PrimitiveIterator.java:128)
    at java.base/java.util.PrimitiveIterator$OfInt.next(PrimitiveIterator.java:86)
    at io.cucumber.cucumberexpressions.GroupBuilder.build(GroupBuilder.java:18)
    at io.cucumber.cucumberexpressions.GroupBuilder.build(GroupBuilder.java:21)
    at io.cucumber.cucumberexpressions.GroupBuilder.build(GroupBuilder.java:21)
    at io.cucumber.cucumberexpressions.TreeRegexp.match(TreeRegexp.java:78)
    at io.cucumber.cucumberexpressions.Argument.build(Argument.java:15)
    at io.cucumber.cucumberexpressions.CucumberExpression.match(CucumberExpression.java:144)
    at io.cucumber.core.stepexpression.StepExpression.match(StepExpression.java:22)
    at io.cucumber.core.stepexpression.ArgumentMatcher.argumentsFrom(ArgumentMatcher.java:30)

It sounds as if I have missed a closing group but I've been staring at it for hours and can't see what I've done wrong yet.

I thought maybe throwing it to StackOverflow would immediately get someone to spot the issue. LOL

In case it matters, the definition of $realRegex is as follows:

private const val doubleTermRegex = "\\d+(?:\\.\\d+)?"
private const val realTermRegex = "(?:-?(?:√?(?:$doubleTermRegex|π)|∞))"
const val realRegex = "(?:$realTermRegex(?:\\s*\\/\\s*$realTermRegex)?)"

That code has been around for much longer and is exercised by many tests, so I'm guessing the issue is in the new code, but I guess you never know.

Versions in use:

  • Cucumber-Java8 5.7.0
  • Kotlin-JVM 1.5.21
  • Java 11

In any case, here's the whole file for context.

package garden.ephemeral.rocket.util

import garden.ephemeral.rocket.util.RealParser.Companion.realFromString
import garden.ephemeral.rocket.util.RealParser.Companion.realRegex
import io.cucumber.java8.En

class ComplexStepDefinitions: En {
    lateinit var z1: Complex
    lateinit var z2: Complex

    init {
        ParameterType("complex", """(?x)
            | complex\( \s*
            |   (?:
            |     ($realRegex)
            |     (?:
            |       \s* ([+-]) \s* ($realRegex) \s* i
            |     )?
            |   |
            |     ($realRegex) \s* i
            |   )
            | \s* \)
            |""".trimMargin()) {
                realPartString: String?,
                joiner: String?,
                imaginaryPartString1: String?,
                imaginaryPartString2: String? ->

            if (realPartString != null) {
                if (imaginaryPartString1 != null) {
                    val imaginarySign = if (joiner == "-") -1.0 else 1.0
                    Complex(realFromString(realPartString), imaginarySign * realFromString(imaginaryPartString1))
                } else {
                    Complex(realFromString(realPartString), 0.0)
                }
            } else if (imaginaryPartString2 != null) {
                Complex(0.0, realFromString(imaginaryPartString2))
            } else {
                throw AssertionError("It shouldn't have matched the regex")
            }
        }
    }
}

Solution

  • You've used (?x) as flag expression to enabled white-space and comments in pattern. Which is probably a good idea given the size of the monster.

    When using Cucumber Expressions, Cucumber parses your regex. And the parser didn't include support for flag expressions as you are experiencing now. Updating Cucumber to the latest version should fix that problem. You are welcome.