spock icon indicating copy to clipboard operation
spock copied to clipboard

==~ causes PatternSyntaxException when used in a block

Open kdebski85 opened this issue 7 months ago • 3 comments

Describe the bug

Spock version: 2.3

    def "should compare lists"() {
        given:
        Consumer<Integer> c = { [] ==~ [] }
        c.accept(1)

        expect:
        true
    }

It fails with java.util.regex.PatternSyntaxException: Unclosed character class near index 1

To Reproduce

  def "should compare lists"() {
        given:
        Consumer<Integer> c = { [] ==~ [] }
        c.accept(1)

        expect:
        true
    }

Expected behavior

==~ spock operator should work in blocks

Alternatively, https://spockframework.org/spock/docs/2.3/utilities.html#_strict_match should state clearly this limitation.

Actual behavior

It fails with java.util.regex.PatternSyntaxException: Unclosed character class near index 1

Java version

21.0.1

Buildtool version

Gradle 8.14.2

What operating system are you using

Mac

Dependencies

none

Additional context

No response

kdebski85 avatar Jun 17 '25 12:06 kdebski85

That's just the normal "it isn't treated as condition" limitation.

For most parts only top-level expression statements are treated as conditions which is documented at https://spockframework.org/spock/docs/2.3/all_in_one.html#_implicit_and_explicit_conditions.

You can reproduce even easier with

def "should compare lists"() {
  expect:
    if (true) [] ==~ []
}

If it is not considered a condition, the operator has its original Groovy meaning.

If you make it an explicit condition by moving the expression to top-level, or make it an explicit condition by adding assert, the special handling of the operator kicks in and it works and also throws as expected if the check fails.

Vampire avatar Jun 17 '25 22:06 Vampire

@Vampire Thank you for the explanation.

However, I think it is a documentation issue. I cannot see this limitation mentioned at https://spockframework.org/spock/docs/2.3/utilities.html#_strict_match

There is a NOTE section saying Both operands must be Iterable for this to work. I think the note should be extended to state that the operator can be used only in conditions.

kdebski85 avatar Jun 18 '25 07:06 kdebski85

The heading says it. The heading is "Collection Conditions". And the part I linked to explains where you have a condition when.

If you for example have in the snippet [] ==~ [1] instead of [] ==~ [], it will compile and run fine and not fail, as it is not a condition either, but just an expression statement evaluating to false.

Never trust a test you did not see failing for the correct reason. :-)

But anyway, I'll leave the decision with @leonard84 .

Vampire avatar Jun 20 '25 08:06 Vampire