Skip to content

Useless assignment of enum values to corresponding static fields in generated tests #618

Closed
@dtim

Description

@dtim

Description

Generated tests explicitly assign enum values to corresponding static fields, which is useless as the set of enum values is fixed, and no new instances can be created.

To Reproduce

Generate a test suite for the Coin.reverse() method in the following code.

public enum Coin {
    HEADS,
    TAILS;

    public Coin reverse() {
        return this == HEADS ? TAILS : HEADS;
    }
}

Expected behavior

Generated tests should not contain assignments of enum values to corresponding static fields.

Actual behavior

Generated tests explicitly assign enum values to corresponding static fields using reflection.

Note: this behavior depends on the enum support that is not in main yet (PR #611). When checking on main, the behavior may differ.

Visual proofs (screenshots, logs, images)

Generated tests:

   ///region SUCCESSFUL EXECUTIONS for method reverse()

    /**
     * <pre>
     * Test executes conditions:
     *     {@code (this == HEADS): False }
     * returns from: {@code return this == HEADS ? TAILS : HEADS; }
     * </pre>
     */
    @Test
    //@org.junit.jupiter.api.DisplayName("reverse: this == HEADS : False -> return this == HEADS ? TAILS : HEADS")
    public void testReverse_NotEqualsHEADS() throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
        Coin prevHEADS = Coin.HEADS;
        try {
            Coin heads = Coin.HEADS;
            Class coinClazz = Class.forName("enums.Coin");
            setStaticField(coinClazz, "HEADS", heads);
            Coin coin = Coin.TAILS;

            Coin actual = coin.reverse();


            assertEquals(heads, actual);
        } finally {
            setStaticField(Coin.class, "HEADS", prevHEADS);
        }
    }

    /**
     * <pre>
     * Test executes conditions:
     *     {@code (this == HEADS): True }
     * returns from: {@code return this == HEADS ? TAILS : HEADS; }
     * </pre>
     */
    @Test
    //@org.junit.jupiter.api.DisplayName("reverse: this == HEADS : True -> return this == HEADS ? TAILS : HEADS")
    public void testReverse_EqualsHEADS() throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
        Coin prevHEADS = Coin.HEADS;
        Coin prevTAILS = Coin.TAILS;
        try {
            Coin heads = Coin.HEADS;
            Class coinClazz = Class.forName("enums.Coin");
            setStaticField(coinClazz, "HEADS", heads);
            Coin tails = Coin.TAILS;
            setStaticField(coinClazz, "TAILS", tails);

            Coin actual = heads.reverse();


            assertEquals(tails, actual);
        } finally {
            setStaticField(Coin.class, "HEADS", prevHEADS);
            setStaticField(Coin.class, "TAILS", prevTAILS);
        }
    }
    ///endregion

Environment

This behavior does not depend on any specific test environment.

Additional context

Assignment of specific values to static fields (usually using reflection) and restoring old values after the test is a common trait of UTBot-generated tests. Generally this behavior is necessary as the codegen should guarantee that the initial state of each object matches the expected initial state induced by the symbolic engine. On the other hand, often these assignment are useless. For example, final static fields of JDK classes are correctly initialized by the JDK code, and there is no sensible way to assign something else to these fields without risking to break things. Unfortunately, it seems that the correct and non-redundant object initialization is hard.

Maybe it might be done for some special cases like enum value initialization, as we can be sure that each corresponding static field already has the correct value at the start of the test.

Metadata

Metadata

Assignees

Labels

comp-codegenIssue is related to code generatorcomp-symbolic-engineIssue is related to the symbolic execution enginectg-bugIssue is a bugspec-release-tailingsFailed to include in the current release, let's include it in the next one

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions