0

I'd like to have a JUnit test that verifies a specific constant is a Compile-Time Constant. How would I go about doing that?

I found a solution for Scala, but I'd like on for plain Java.
Is there a way to test at compile-time that a constant is a compile-time constant?

Root Cause:

The value for annotation attribute ApiModelProperty.allowableValues must be a constant expression

What I'd like in a Unit Test:
    validateCompileTimeConstant(SomeClass.CONSTANT_VALUE, "Message Here!!");
Usage
    @ApiModelProperty(name = "name", required = true, value = "Name", allowableValues=SomeClass.API_ALLOWABLE_VALUES, notes=SomeClass.API_NOTES)
    private String name;
SomeClass
public enum SomeClass {
    BOB(4,  "Bob"),//
    TED(9,  "Ted"),//
    NED(13, "Ned");

    public static final String API_ALLOWABLE_VALUES = "4,9,13,16,21,26,27,170";
    public static final String API_NOTES = "4 - Bob\n" +
                                           "9 - Ted\n" +
                                           "13 - Ned";

    public int code;
    public String desc;

    private ContentCategoryCode(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public static final String apiAllowableValues() {
        StringBuilder b = new StringBuilder();
        for (ContentCategoryCode catCode : values()) {
            b.append(catCode.code);
            b.append(',');
        }
        b.setLength(b.length()-1);
        return b.toString();
    }

    public static final String apiNotes() {
        StringBuilder b = new StringBuilder();
        for (ContentCategoryCode catCode : values()) {
            b.append(catCode.code).append(" - ").append(catCode.desc);
            b.append('\n');
        }
        b.setLength(b.length()-1);
        return b.toString();
    }
}
user11058144
  • 137
  • 1
  • 1
  • 7
  • 5
    That's not something you would test at runtime. By its very essence, the misuse of a compile time constant would fail at compile time, where it would be detected by the compiler. – Savior May 09 '19 at 17:14
  • You shouldn't write code which depends on this one way or another. – Peter Lawrey May 09 '19 at 17:16
  • I can only second @Savior. Why run a unit test when the compiler did already tell you that there is an error? – Holger May 09 '19 at 17:46
  • 1
    It's more so I can document the fix if someone tries to generate the value of the constant. Essentially, I want the "Why it failed to compile" in the unit test class. – user11058144 May 09 '19 at 17:54

2 Answers2

3

The Error Prone project has a @CompileTimeConstant annotation which can be used to enforce exactly this.

It's not a test that you run with JUnit, but a compiler plug-in that enforces this (and other bug patterns) at compile time.

Here is the documentation: https://errorprone.info/bugpattern/CompileTimeConstant

Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135
1

I ended up creating my own annotation, since it required less setup than using Error Prone.

Annotation Class:

@Target(ElementType.METHOD)
public @interface TestCompileTimeConstant {
    public String key() default "";
}

JUnit Test:

public class SomeClassTest {

    @Test
    public void test() {
        assertEquals(SomeClass.API_ALLOWABLE_VALUES, SomeClass.apiAllowableValues());
        assertEquals(SomeClass.API_NOTES, SomeClass.apiNotes());
    }

    @Test
    @TestCompileTimeConstant(key=SomeClass.API_ALLOWABLE_VALUES)
    public void testIsCompileTimeConstant1() {
        //Pass - If this doesn't compile, you need to make sure API_ALLOWABLE_VALUES doesn't call any methods.
    }

    @Test
    @TestCompileTimeConstant(key=SomeClass.API_NOTES)
    public void testIsCompileTimeConstant2() {
        //Pass - If this doesn't compile, you need to make sure API_NOTES doesn't call any methods. 
    }
}

user11058144
  • 137
  • 1
  • 1
  • 7