Closed moqimoqidea closed 2 years ago
Related to #1406 but different, I have the suspicion this is actually caused by groovy as you are not trying to create a Mock but use closure conversion. Could you try the same in a JUnit 4/5 Test?
Related to #1406 but different, I have the suspicion this is actually caused by groovy as you are not trying to create a Mock but use closure conversion. Could you try the same in a JUnit 4/5 Test?
thank you, I will try it later.
What is bi | (domain, x) -> domain.equalsIgnoreCase("MICROSOFT.COM")
supposed to do? Should it not be either bi
or the inline closure? What are you trying to achieve by trying a bitwise OR of those two closures? If you simply use one of them, the spec will run normally and fail because the condition is violated. If then you also fix the filter condition, the test passes:
def "test a domain with or syntax should return right result"() {
given:
def domainList = [
new Domain("google.com", 1),
new Domain("i-am-spammer.com", 10),
new Domain("mkyong.com", 0),
new Domain("microsoft.com", 2)
]
when:
def result = filterBadDomain(domainList, (domain, score) -> !domain.equalsIgnoreCase("I-AM-SPAMMER.COM"))
then:
result == [["google.com", 1] as Domain, ["mkyong.com", 0] as Domain, ["microsoft.com", 2] as Domain]
}
Hm, I see that Groovy seems to permit chaining of bi-predicates and/or closures using bitwise logical operators. As a Groovy non-expert, I had no idea that was possible. I also did not find any relevant documentation about this. Maybe I searched for the wrong keywords.
Anyway, without Spock, this works in JDK <16, while it fails the way you described above in JDK 16+. This holds true independent of whether we use Java lambda or Groovy closure syntax.
package org.acme
import java.util.function.BiPredicate
class CombineBiPredicatesAndClosures {
static void main(String[] args) {
println System.properties["java.version"]
// Lambda syntax only works in Groovy 3.0
// BiPredicate<String, Integer> bi = (domain, score) -> domain.equalsIgnoreCase("google.com")
// def bi2 = (domain, score) -> score == 11
// Closure syntax works in Groovy 2.5, too
BiPredicate<String, Integer> bi = { domain, score -> domain.equalsIgnoreCase("google.com") }
def bi2 = { domain, score -> score == 11 }
def logicalOr = bi | bi2
assert logicalOr.test("google.com", 11)
assert logicalOr.test("google.com", 0)
assert logicalOr.test("x", 11)
assert !logicalOr.test("x", 0)
def logicalAnd = bi & bi2
assert logicalAnd.test("google.com", 11)
assert !logicalAnd.test("google.com", 0)
assert !logicalAnd.test("x", 11)
assert !logicalAnd.test("x", 0)
}
}
Try it in the Groovy Web Console, where it always works, because GWC runs on JRE 11.
So we are dealing with a Groovy issue, as it seems. As usual, @leonard84 is right in such things.
Thank you for your awesome work.
As To Reproduce
said, the code is from Java 8 BiPredicate Examples, I just tested it with Spock. And after upgrading to Java17 I found that it doesn't work properly.
I'm happy to see this bug show on the table, should I go to Groovy Project to open the issue, or is there a better way? thank you.
As
To Reproduce
said, the code is from Java 8 BiPredicate Examples, I just tested it with Spock.
Thanks for bringing the original Java code to my attention again. Java functional interfaces are not my strong suit. Now I understand that BiPredicate
simply has methods called or
, and
, negate
which are meant to logically combine bi-predicates. Groovy therefore also accepts bitwise logical operators in this case, because when overloading them they happen to have the same method names, at least for bitwise AND and OR. There is however no overloading for !
, only for ~
(bitwise negate, method name bitwiseNegate
and therefore different from the BiPredicate
method name).
Somehow Groovy has problems if the first of the two chained bi-predicates is a closure or lambda. Even without chaining, it is impossible to call bi.negate()
upon it on JVM 16+. If however we change the code to read
// Use old-school anonymous class instead of closure or lambda
BiPredicate<String, Integer> bi = new BiPredicate<String, Integer>() {
@Override
boolean test(String domain, Integer score) {
return domain.equalsIgnoreCase("google.com")
}
}
def bi2 = { domain, score -> score == 11 }
it runs smoothly.
Sorry to spam this issue, but I was curious and tried Groovy 4.0.0-rc-2: It works! So this seems to be a Groovy 3 problem. Maybe we really open an issue and have this fix backported, if possible. Here is my Maven project which works without Surefire, JUnit or Spock. It simply uses Exec Maven Plugin to automatically run the example class during the test
phase. This way we can exclude any test tools or plugins as root causes.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Spock_GH_1412</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy-bom</artifactId>
<version>4.0.0-rc-2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
</dependency>
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy-json</artifactId>
</dependency>
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy-xml</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.13.0</version>
<configuration>
<targetBytecode>${java.version}</targetBytecode>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>run-groovy-example</id>
<phase>test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>CombineBiPredicatesAndClosures</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
src/main/groovy/CombineBiPredicatesAndClosures.groovy
import java.util.function.BiPredicate
class CombineBiPredicatesAndClosures {
static void main(String[] args) {
println "Java version: ${System.properties['java.version']}"
// Old-school anonymous class instead of closure or lambda
/*
BiPredicate<String, Integer> bi = new BiPredicate<String, Integer>() {
@Override
boolean test(String domain, Integer score) {
return domain.equalsIgnoreCase("google.com")
}
}
*/
// Lambda syntax only works in Groovy 3+
//BiPredicate<String, Integer> bi = (domain, score) -> domain.equalsIgnoreCase("google.com")
//def bi2 = (domain, score) -> score == 11
// Closure syntax works in Groovy 2.5, too
BiPredicate<String, Integer> bi = { domain, score -> domain.equalsIgnoreCase("google.com") }
def bi2 = { domain, score -> score == 11 }
def logicalNot = bi.negate()
assert logicalNot.test("acme.org", 11)
assert !logicalNot.test("google.com", 11)
def logicalOr = bi | bi2
assert logicalOr.test("google.com", 11)
assert logicalOr.test("google.com", 0)
assert logicalOr.test("x", 11)
assert !logicalOr.test("x", 0)
def logicalAnd = bi & bi2
assert logicalAnd.test("google.com", 11)
assert !logicalAnd.test("google.com", 0)
assert !logicalAnd.test("x", 11)
assert !logicalAnd.test("x", 0)
}
}
I created GROOVY-10450. Let's see what the maintainers say.
Thank you for your awesome work again!
I aleady remove the unnecessary full quote.
It looks like this was a Groovy issue and was fixed in version 4.0.0.
Thank you for your great work, if this issue has fulfilled its historic mission, you can close it.
Closing as the issue is with Groovy.
FYI, the upstream Groovy issue was fixed in an incomplete way for 3.0.15. The commit adding the last bit was added after the release (I just retested it successfully with the latest snapshot), so unfortunately, we will have to wait for 3.0.16 for it to be fixed for good. But at least, after more than a year, there are some good news.
@leonard84, Groovy 3.0.16 has been released a couple of days ago, i.e. this issue is now fixed upstream. Maybe it makes sense to also bump Spock 3.x to that release. If you want to somehow refactor my sample code into a regression test, is up to you.
Describe the bug
To Reproduce
Preview:
Expected behavior
The code should not fail.
Actual behavior
The code fails with the given exception.
Java version
openjdk version "17.0.1" 2021-10-19 LTS OpenJDK Runtime Environment Corretto-17.0.1.12.1 (build 17.0.1+12-LTS) OpenJDK 64-Bit Server VM Corretto-17.0.1.12.1 (build 17.0.1+12-LTS, mixed mode, sharing)
Buildtool version
Gradle 7.3.3
Build time: 2021-12-22 12:37:54 UTC Revision: 6f556c80f945dc54b50e0be633da6c62dbe8dc71
Kotlin: 1.5.31 Groovy: 3.0.9 Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021 JVM: 17.0.1 (Amazon.com Inc. 17.0.1+12-LTS) OS: Mac OS X 12.1 x86_64
What operating system are you using
Mac
Dependencies
Additional context
No response