Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Semaphores #476

Closed
michaelAlvarino opened this issue Aug 3, 2021 · 3 comments
Closed

Support Semaphores #476

michaelAlvarino opened this issue Aug 3, 2021 · 3 comments

Comments

@michaelAlvarino
Copy link

Describe the bug
EqualsVerifier fails verification tests for classes using Semaphores due to recursive datastructures.

To Reproduce
Create the class/test below and run.

Code that triggers the behavior

package experiment;

import java.util.concurrent.Semaphore;

public class TestEqVerifier {
    private final Semaphore sem = new Semaphore(1);
}
package experiment;

import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.Test;

public class TestEqVerifierTest {
    @Test
    public void test() {
        EqualsVerifier.forClass(TestEqVerifier.class).verify();
    }
}

Error message

EqualsVerifier found a problem in class experiment.TestEqVerifier.
-> Recursive datastructure.
Add prefab values for one of the following types: Semaphore, Sync, Node.

For more information, go to: http://www.jqno.nl/equalsverifier/errormessages
java.lang.AssertionError: EqualsVerifier found a problem in class experiment.TestEqVerifier.
-> Recursive datastructure.
Add prefab values for one of the following types: Semaphore, Sync, Node.

For more information, go to: http://www.jqno.nl/equalsverifier/errormessages
	at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.verify(SingleTypeEqualsVerifierApi.java:306)
	at experiment.TestEqVerifierTest.test(TestEqVerifierTest.java:9)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
	at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
	at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:175)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:157)
	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
	at java.lang.Thread.run(Thread.java:748)
Caused by: nl.jqno.equalsverifier.internal.exceptions.RecursionException
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.createTuple(PrefabValues.java:145)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.realizeCacheFor(PrefabValues.java:138)
	at nl.jqno.equalsverifier.internal.prefabvalues.factories.FallbackFactory.traverseFields(FallbackFactory.java:88)
	at nl.jqno.equalsverifier.internal.prefabvalues.factories.FallbackFactory.createValues(FallbackFactory.java:39)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.createTuple(PrefabValues.java:155)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.realizeCacheFor(PrefabValues.java:138)
	at nl.jqno.equalsverifier.internal.prefabvalues.factories.FallbackFactory.traverseFields(FallbackFactory.java:88)
	at nl.jqno.equalsverifier.internal.prefabvalues.factories.FallbackFactory.createValues(FallbackFactory.java:39)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.createTuple(PrefabValues.java:155)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.realizeCacheFor(PrefabValues.java:138)
	at nl.jqno.equalsverifier.internal.prefabvalues.factories.FallbackFactory.traverseFields(FallbackFactory.java:88)
	at nl.jqno.equalsverifier.internal.prefabvalues.factories.FallbackFactory.createValues(FallbackFactory.java:39)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.createTuple(PrefabValues.java:155)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.realizeCacheFor(PrefabValues.java:138)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.giveTuple(PrefabValues.java:79)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.giveOther(PrefabValues.java:102)
	at nl.jqno.equalsverifier.internal.reflection.FieldModifier.lambda$changeField$2(FieldModifier.java:97)
	at nl.jqno.equalsverifier.internal.reflection.FieldModifier.lambda$change$3(FieldModifier.java:113)
	at nl.jqno.equalsverifier.internal.util.Rethrow.lambda$rethrow$0(Rethrow.java:47)
	at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:30)
	at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:45)
	at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:55)
	at nl.jqno.equalsverifier.internal.reflection.FieldModifier.change(FieldModifier.java:113)
	at nl.jqno.equalsverifier.internal.reflection.FieldModifier.changeField(FieldModifier.java:100)
	at nl.jqno.equalsverifier.internal.reflection.InPlaceObjectAccessor.scramble(InPlaceObjectAccessor.java:52)
	at nl.jqno.equalsverifier.internal.reflection.ClassAccessor.getRedAccessor(ClassAccessor.java:174)
	at nl.jqno.equalsverifier.internal.reflection.ClassAccessor.getRedObject(ClassAccessor.java:163)
	at nl.jqno.equalsverifier.internal.util.Configuration.ensureUnequalExamples(Configuration.java:198)
	at nl.jqno.equalsverifier.internal.util.Configuration.build(Configuration.java:98)
	at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.buildConfig(SingleTypeEqualsVerifierApi.java:373)
	at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.performVerification(SingleTypeEqualsVerifierApi.java:359)
	at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.verify(SingleTypeEqualsVerifierApi.java:304)
	... 48 more


experiment.TestEqVerifierTest > test FAILED
    java.lang.AssertionError at TestEqVerifierTest.java:9
        Caused by: nl.jqno.equalsverifier.internal.exceptions.RecursionException at TestEqVerifierTest.java:9
1 test completed, 1 failed

Expected behavior
Node is definitely a recursive class, but using a Semaphore for some internal implementation should not concern customers using my library as long as I have implemented equals and hashcode properly.

Version
What version of EqualsVerifier are you using?
3.7

Additional context
Add any other context about the problem here.
I think this is also a problem with CompletableFutures due to the Completion class.

@michaelAlvarino michaelAlvarino changed the title Support Semaphores without Support Semaphores Aug 3, 2021
@jqno
Copy link
Owner

jqno commented Aug 9, 2021

Thanks for letting me know about this one. I've made a fix, and I'll let you know when I make a release.
Until then, you can add .withPrefabValues(Semaphore.class, new Semaphore(1), new Semaphore(2)) as a workaround.

EqualsVerifier already has prefab values, so that shouldn't be a problem. But if they are, please let me know!

@michaelAlvarino
Copy link
Author

Whoops, closed a bit early. We should probably wait for the release.

@jqno
Copy link
Owner

jqno commented Aug 13, 2021

I've just released version 3.7.1. I'll close the issue now 😉

@jqno jqno closed this as completed Aug 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants