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

Handling empty enums #199

Closed
io7m opened this issue Jul 8, 2018 · 5 comments
Closed

Handling empty enums #199

io7m opened this issue Jul 8, 2018 · 5 comments
Labels

Comments

@io7m
Copy link

io7m commented Jul 8, 2018

What steps will reproduce the problem?

Define a class that depends on an enum that has no values, and then try verifying it:

enum E { }

class T {
  E e;
}

Please scroll down to the bottom for the reasons why I might want to do such a thing!

What is the code that triggers this problem?

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

import java.util.Objects;

public class Bug
{
  enum E
  {

  }

  final class K
  {
    private final E e;

    public K(final E e)
    {
      this.e = e;
    }

    @Override
    public boolean equals(final Object o)
    {
      if (this == o) {
        return true;
      }
      if (o == null || !Objects.equals(this.getClass(), o.getClass())) {
        return false;
      }
      final K k = (K) o;
      return this.e == k.e;
    }

    @Override
    public int hashCode()
    {
      return Objects.hash(this.e);
    }
  }
  
  @Test
  public void testEquals()
  {
    EqualsVerifier.forClass(K.class).verify();
  }
}

What error message or stack trace does EqualsVerifier give?

java.lang.AssertionError: ReflectionException: Enum E has no elements
For more information, go to: http://www.jqno.nl/equalsverifier/errormessages

	at nl.jqno.equalsverifier.EqualsVerifier.handleError(EqualsVerifier.java:375)
	at nl.jqno.equalsverifier.EqualsVerifier.verify(EqualsVerifier.java:364)
	at com.io7m.jcoronado.tests.Bug.testEquals(Bug.java:47)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:515)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170)
	at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:134)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:128)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:109)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1378)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:128)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:109)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1378)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:128)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:109)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:49)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:47)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:184)
	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:152)
	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:166)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:145)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:92)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: nl.jqno.equalsverifier.internal.exceptions.ReflectionException: Enum E has no elements
	at nl.jqno.equalsverifier.internal.prefabvalues.factories.FallbackFactory.giveEnumInstances(FallbackFactory.java:48)
	at nl.jqno.equalsverifier.internal.prefabvalues.factories.FallbackFactory.createValues(FallbackFactory.java:32)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.createTuple(PrefabValues.java:179)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.realizeCacheFor(PrefabValues.java:162)
	at nl.jqno.equalsverifier.internal.prefabvalues.factories.FallbackFactory.traverseFields(FallbackFactory.java:79)
	at nl.jqno.equalsverifier.internal.prefabvalues.factories.FallbackFactory.createValues(FallbackFactory.java:38)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.createTuple(PrefabValues.java:179)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.realizeCacheFor(PrefabValues.java:162)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.giveTuple(PrefabValues.java:110)
	at nl.jqno.equalsverifier.internal.prefabvalues.PrefabValues.giveRed(PrefabValues.java:74)
	at nl.jqno.equalsverifier.internal.checkers.AbstractDelegationChecker.check(AbstractDelegationChecker.java:38)
	at nl.jqno.equalsverifier.EqualsVerifier.verifyWithoutExamples(EqualsVerifier.java:399)
	at nl.jqno.equalsverifier.EqualsVerifier.performVerification(EqualsVerifier.java:385)
	at nl.jqno.equalsverifier.EqualsVerifier.verify(EqualsVerifier.java:358)
	... 40 more

What did you expect?

Perhaps nothing.

Which version of EqualsVerifier are you using?

2.4.8

Please provide any additional information below.

I'm working on a type-safe wrapper to the LWJGL bindings to the Vulkan API. The Vulkan API is still very young, and it defines multiple enum types that don't yet have any members but are reserved for future expansion. For example:

https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkShaderModuleCreateFlags.html

The Java equivalent of this is:

package com.io7m.jcoronado.api;

/**
 * Flags specified when creating shader modules.
 *
 * Vulkan 1.1 specification: "VulkanShaderModuleCreateFlag is a bitmask type for setting a mask, but
 * is currently reserved for future use."
 */

public enum VulkanShaderModuleCreateFlag implements VulkanEnumBitmaskType
{
  ;

  @Override
  public int value()
  {
    return 0;
  }
}

There are then various data structures that declare fields of type Set<VulkanShaderModuleCreateFlag> which, naturally, will be empty until the Vulkan API defines some flags.

I thought I could possibly ignore the fields (although I don't want to do this: Adding new enum members later on would mean that tests might silently break, as the verifier is ignoring the now non-empty enum). Even ignoring the field raises the exception, however.

@jqno
Copy link
Owner

jqno commented Jul 8, 2018 via email

@io7m
Copy link
Author

io7m commented Jul 8, 2018

Sounds good.

I think what I can do in the mean time, at least for enum types that represent bit masks, is add a spurious "none" case. For example: VK_SHADER_MODULE_CREATE_FLAG_NONE(0x0). Obviously this only works for enum types that represent bitmasks (because 0 just means that no bits are set).

@jqno
Copy link
Owner

jqno commented Jul 8, 2018 via email

io7m added a commit to io7m-com/jcoronado that referenced this issue Jul 8, 2018
This also adds `NONE` enum members to bitmask types as a workaround
for jqno/equalsverifier#199.
@jqno jqno added the accepted label Jul 26, 2018
jqno added a commit that referenced this issue Jul 30, 2018
@jqno
Copy link
Owner

jqno commented Jul 30, 2018

I just released version 2.5, which supports empty enums.

@jqno jqno closed this as completed Jul 30, 2018
@io7m
Copy link
Author

io7m commented Jul 30, 2018

Thanks! I'll give this a shot at the end of the week.

akhalikov pushed a commit to akhalikov/equalsverifier that referenced this issue Nov 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants