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

NPE in enum constructors if hamcrest on classpath #770

Closed
aJanuary opened this issue Jun 3, 2020 · 2 comments · Fixed by #850
Closed

NPE in enum constructors if hamcrest on classpath #770

aJanuary opened this issue Jun 3, 2020 · 2 comments · Fixed by #850

Comments

@aJanuary
Copy link

aJanuary commented Jun 3, 2020

Since 1.4.7, if I have hamcrest in the classpath I get a NullPointerException thrown in the <init> method of enums with constructors if I try to load them using Class.forName when pitest does the initial test run.

package com.example;

import org.junit.Test;

public class NestedClassTest {
	public static enum MyEnum {
		A { }
	}

	@Test
	public void test() throws ClassNotFoundException {
		Class.forName("com.example.NestedClassTest$MyEnum$1");
	}
}
   [pitest] 12:06:57 PIT >> INFO : MINION : 12:06:57 PIT >> INFO : 1 tests received
   [pitest] 
   [pitest] 12:06:57 PIT >> INFO : MINION : 12:06:57 PIT >> FINE : Running 1 units
   [pitest] 
   [pitest] 12:06:57 PIT >> INFO : MINION : 12:06:57 PIT >> FINE : Gathering coverage for test Description [testClass=com.example.NestedClassTest, name=test(com.example.NestedClassTest)]
   [pitest] 
   [pitest] 12:06:57 PIT >> INFO : MINION : 12:06:57 PIT >> SEVERE : Description [testClass=com.example.NestedClassTest, name=test(com.example.NestedClassTest)]
   [pitest] java.lang.ExceptionInInitializerError
   [pitest] 	at java.lang.Class.forName0(Native Method)
   [pitest] 	at java.lang.Class.forName(Class.java:264)
   [pitest] 	at com.examp
   [pitest] 12:06:57 PIT >> INFO : MINION : le.NestedClassTest.test(Unknown Source)
   [pitest] 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   [pitest] 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
   [pitest] 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAc
   [pitest] 12:06:57 PIT >> INFO : MINION : cessorImpl.java:43)
   [pitest] 	at java.lang.reflect.Method.invoke(Method.java:498)
   [pitest] 	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
   [pitest] 	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
   [pitest] 	at or
   [pitest] 12:06:57 PIT >> INFO : MINION : g.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
   [pitest] 	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
   [pitest] 	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
   [pitest] 	at org.junit.runners.B
   [pitest] 12:06:57 PIT >> INFO : MINION : lockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
   [pitest] 	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
   [pitest] 	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
   [pitest] 	at org.junit.runners.ParentRunner$1.schedu
   [pitest] 12:06:57 PIT >> INFO : MINION : le(ParentRunner.java:71)
   [pitest] 	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
   [pitest] 	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
   [pitest] 	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
   [pitest] 	at org.junit.runners.Pa
   [pitest] 12:06:57 PIT >> INFO : MINION : rentRunner.run(ParentRunner.java:363)
   [pitest] 	at org.pitest.junit.adapter.CustomRunnerExecutor.run(CustomRunnerExecutor.java:42)
   [pitest] 	at org.pitest.junit.adapter.AdaptedJUnitTestUnit.execute(AdaptedJUnitTestUnit.java:69)
   [pitest] 	at org.pitest.coverage.execute.CoverageDecora
   [pitest] 12:06:57 PIT >> INFO : MINION : tor.execute(CoverageDecorator.java:49)
   [pitest] 	at org.pitest.testapi.execute.containers.UnContainer.execute(UnContainer.java:31)
   [pitest] 	at org.pitest.testapi.execute.Pitest.executeTests(Pitest.java:57)
   [pitest] 	at org.pitest.testapi.execute.Pitest.run(Pitest.java:48)
   [pitest] 	at org.p
   [pitest] 12:06:57 PIT >> INFO : MINION : itest.coverage.execute.CoverageWorker.run(CoverageWorker.java:49)
   [pitest] 	at org.pitest.coverage.execute.CoverageMinion.main(CoverageMinion.java:90)
   [pitest] Caused by: java.lang.NullPointerException
   [pitest] 	at com.example.NestedClassTest$MyEnum$1.<init>(Unknown Source)
   [pitest] 	at com.
   [pitest] 12:06:57 PIT >> INFO : MINION : example.NestedClassTest$MyEnum.<clinit>(Unknown Source)
   [pitest] 	... 28 more
   [pitest] 
   [pitest] 12:06:57 PIT >> SEVERE : Description [testClass=com.example.NestedClassTest, name=test(com.example.NestedClassTest)] did not pass without mutation.
   [pitest] 12:06:57 PIT >> FINE : Coverage generator Minion exited ok
   [pitest] 12:06:57 PIT >> INFO : Calculated coverage in 1 seconds.
   [pitest] 12:06:57 PIT >> SEVERE : Tests failing without mutation: 
   [pitest] Description [testClass=com.example.NestedClassTest, name=test(com.example.NestedClassTest)]
   [pitest] Exception in thread "main" org.pitest.help.PitHelpError: 1 tests did not pass without mutation when calculating line coverage. Mutation testing requires a green suite.
   [pitest] See http://pitest.org for more details.
   [pitest] 	at org.pitest.coverage.execute.DefaultCoverageGenerator.verifyBuildSuitableForMutationTesting(DefaultCoverageGenerator.java:114)
   [pitest] 	at org.pitest.coverage.execute.DefaultCoverageGenerator.calculateCoverage(DefaultCoverageGenerator.java:96)
   [pitest] 	at org.pitest.coverage.execute.DefaultCoverageGenerator.calculateCoverage(DefaultCoverageGenerator.java:51)
   [pitest] 	at org.pitest.mutationtest.tooling.MutationCoverage.runReport(MutationCoverage.java:115)
   [pitest] 	at org.pitest.mutationtest.tooling.EntryPoint.execute(EntryPoint.java:121)
   [pitest] 	at org.pitest.mutationtest.tooling.EntryPoint.execute(EntryPoint.java:51)
   [pitest] 	at org.pitest.mutationtest.commandline.MutationCoverageReport.runReport(MutationCoverageReport.java:87)
   [pitest] 	at org.pitest.mutationtest.commandline.MutationCoverageReport.main(MutationCoverageReport.java:45)

If I run the tests using junit directly, the exception is not thrown. If I remove hamcrest from the classpath, the exception is not thrown.

I have tried with hamcrest 1.3 and hamcrest 2.2 and both cause the exception to be thrown.

I have tried with both openjdk 11.0.6 and oracle Java JDK 8 [1.8.0_251]. Both cause the exception to be thrown.

I have attached a minimal example using pitest-ant.

pitest-npe-in-enum-ctor.zip

Full output:

Buildfile: /Users/work/Projects/pitest-ant-example/build.xml

clean:
   [delete] Deleting directory /Users/work/Projects/pitest-ant-example/build

compile:
    [mkdir] Created dir: /Users/work/Projects/pitest-ant-example/build/classes
    [javac] Compiling 1 source file to /Users/work/Projects/pitest-ant-example/build/classes
    [mkdir] Created dir: /Users/work/Projects/pitest-ant-example/build/test-classes
    [javac] Compiling 1 source file to /Users/work/Projects/pitest-ant-example/build/test-classes

pit:
   [pitest] 12:06:55 PIT >> INFO : ---------------------------------------------------------------------------
   [pitest] 12:06:55 PIT >> INFO : Enabled (+) and disabled (-) features.
   [pitest] 12:06:55 PIT >> INFO : -----------------------------------------
   [pitest] 12:06:55 PIT >> INFO : +FANN           Filters mutations in classes and methods with matching annotations of class or runtime retention
   [pitest] 12:06:55 PIT >> INFO :   [annotation]    Annotation to avoid (full package name not required)
   [pitest] 12:06:55 PIT >> INFO : +FENUM          Filters mutations in enum constructors
   [pitest] 12:06:55 PIT >> INFO : +FFBLOCK        Filters mutations in code duplicated by finally block inlining
   [pitest] 12:06:55 PIT >> INFO : +FFEACH         Filters mutations in compiler generated code that implements for each loops
   [pitest] 12:06:55 PIT >> INFO : +FFLOOP         Filters any mutations to increments in for loops as they may cause timeouts
   [pitest] 12:06:55 PIT >> INFO : +FINFINC        Filters mutations to increments that may cause infinite loops
   [pitest] 12:06:55 PIT >> INFO : +FINFIT         Filters mutations that may cause infinite loops by removing calls to iterator.next
   [pitest] 12:06:55 PIT >> INFO : +FINULL         Filters mutations in compiler generated code that checks for null by calling getClass
   [pitest] 12:06:55 PIT >> INFO : +FKOTLIN        Filters out junk mutations in bytecode created by compiler for kotlin language features
   [pitest] 12:06:55 PIT >> INFO : +FLOGCALL       Filters mutations in code that makes calls to logging frameworks
   [pitest] 12:06:55 PIT >> INFO : +FMRNULL        Filters mutations in compiler generated code that inserts Objects.requireNonNull for method references
   [pitest] 12:06:55 PIT >> INFO : +FRETEQUIV      Filters return vals mutants with bytecode equivalent to the unmutated class
   [pitest] 12:06:55 PIT >> INFO : +FSEQUIVEQUALS  Filters equivalent mutations that affect only performance in short cutting equals methods
   [pitest] 12:06:55 PIT >> INFO : +FSTATI         Filters mutations in static initializers and code called only from them
   [pitest] 12:06:55 PIT >> INFO : +FSTATINIT      Filters mutations in static initializers and code called only from them
   [pitest] 12:06:55 PIT >> INFO : +FTRYWR         Filters mutations in code generated for try with resources statements
   [pitest] 12:06:55 PIT >> INFO : -CLASSLIMIT     Limits the maximum number of mutations per class
   [pitest] 12:06:55 PIT >> INFO :   [limit]         Integer value for maximum mutations to create per class
   [pitest] 12:06:55 PIT >> INFO : -EXPORT         Exports mutants bytecode and other details to disk
   [pitest] 12:06:55 PIT >> INFO : ---------------------------------------------------------------------------
   [pitest] 12:06:56 PIT >> FINE : Running report with ReportOptions [targetClasses=[com.example.*], excludedMethods=[], excludedClasses=[], excludedTestClasses=[], codePaths=[], reportDir=pitReports, historyInputLocation=null, historyOutputLocation=null, sourceDirs=[src], classPathElements=[/Users/work/Projects/pitest-ant-example/lib/pitest-1.5.2.jar, /Users/work/Projects/pitest-ant-example/build/classes, /Users/work/Projects/pitest-ant-example/build/test-classes, /Users/work/Projects/pitest-ant-example/lib/junit-4.12.jar, /Users/work/Projects/pitest-ant-example/lib/hamcrest-2.2.jar], mutators=[], features=[], dependencyAnalysisMaxDistance=-1, jvmArgs=[-Djava.awt.headless=true], numberOfThreads=1, timeoutFactor=1.25, timeoutConstant=4000, targetTests=[^com\.example\..*$], loggingClasses=[], maxMutationsPerClass=0, verbose=true, failWhenNoMutations=true, outputs=[HTML], groupConfig=TestGroupConfig [excludedGroups=[], includedGroups=[]], fullMutationMatrix=false, mutationUnitSize=0, shouldCreateTimestampedReports=true, detectInlinedCode=false, exportLineCoverage=false, mutationThreshold=0, coverageThreshold=0, mutationEngine=gregor, javaExecutable=null, includeLaunchClasspath=false, properties={}, maxSurvivors=-1, excludedRunners=[], includedTestMethods=[], testPlugin=junit, useClasspathJar=false, skipFailingTests=false]
   [pitest] 12:06:56 PIT >> FINE : System class path is /Users/work/Projects/pitest-ant-example/lib/junit-4.12.jar:/Users/work/Projects/pitest-ant-example/lib/xstream-1.4.8.jar:/Users/work/Projects/pitest-ant-example/lib/xmlpull-1.1.3.1.jar:/Users/work/Projects/pitest-ant-example/lib/pitest-1.5.2.jar:/Users/work/Projects/pitest-ant-example/lib/pitest-entry-1.5.2.jar:/Users/work/Projects/pitest-ant-example/lib/pitest-ant-1.5.2.jar
   [pitest] 12:06:56 PIT >> FINE : Maximum available memory is 910 mb
   [pitest] 12:06:56 PIT >> FINE : MINION : Installing PIT agent
   [pitest] 
   [pitest] 12:06:56 PIT >> INFO : Sending 5 test classes to minion
   [pitest] 12:06:56 PIT >> INFO : Sent tests to minion
   [pitest] 12:06:56 PIT >> INFO : MINION : 12:06:56 PIT >> FINE : Expecting 5 tests classes from parent
   [pitest] 12:06:56 PIT >> FINE : Tests classes received
   [pitest] 
   [pitest] 12:06:56 PIT >> INFO : MINION : 12:06:56 PIT >> INFO : Checking environment
   [pitest] 
   [pitest] 12:06:57 PIT >> INFO : MINION : 12:06:57 PIT >> INFO : Found  1 tests
   [pitest] 
   [pitest] 12:06:57 PIT >> INFO : MINION : 12:06:57 PIT >> INFO : Dependency analysis reduced number of potential tests by 0
   [pitest] 
   [pitest] 12:06:57 PIT >> INFO : MINION : 12:06:57 PIT >> INFO : 1 tests received
   [pitest] 
   [pitest] 12:06:57 PIT >> INFO : MINION : 12:06:57 PIT >> FINE : Running 1 units
   [pitest] 
   [pitest] 12:06:57 PIT >> INFO : MINION : 12:06:57 PIT >> FINE : Gathering coverage for test Description [testClass=com.example.NestedClassTest, name=test(com.example.NestedClassTest)]
   [pitest] 
   [pitest] 12:06:57 PIT >> INFO : MINION : 12:06:57 PIT >> SEVERE : Description [testClass=com.example.NestedClassTest, name=test(com.example.NestedClassTest)]
   [pitest] java.lang.ExceptionInInitializerError
   [pitest] 	at java.lang.Class.forName0(Native Method)
   [pitest] 	at java.lang.Class.forName(Class.java:264)
   [pitest] 	at com.examp
   [pitest] 12:06:57 PIT >> INFO : MINION : le.NestedClassTest.test(Unknown Source)
   [pitest] 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   [pitest] 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
   [pitest] 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAc
   [pitest] 12:06:57 PIT >> INFO : MINION : cessorImpl.java:43)
   [pitest] 	at java.lang.reflect.Method.invoke(Method.java:498)
   [pitest] 	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
   [pitest] 	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
   [pitest] 	at or
   [pitest] 12:06:57 PIT >> INFO : MINION : g.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
   [pitest] 	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
   [pitest] 	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
   [pitest] 	at org.junit.runners.B
   [pitest] 12:06:57 PIT >> INFO : MINION : lockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
   [pitest] 	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
   [pitest] 	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
   [pitest] 	at org.junit.runners.ParentRunner$1.schedu
   [pitest] 12:06:57 PIT >> INFO : MINION : le(ParentRunner.java:71)
   [pitest] 	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
   [pitest] 	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
   [pitest] 	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
   [pitest] 	at org.junit.runners.Pa
   [pitest] 12:06:57 PIT >> INFO : MINION : rentRunner.run(ParentRunner.java:363)
   [pitest] 	at org.pitest.junit.adapter.CustomRunnerExecutor.run(CustomRunnerExecutor.java:42)
   [pitest] 	at org.pitest.junit.adapter.AdaptedJUnitTestUnit.execute(AdaptedJUnitTestUnit.java:69)
   [pitest] 	at org.pitest.coverage.execute.CoverageDecora
   [pitest] 12:06:57 PIT >> INFO : MINION : tor.execute(CoverageDecorator.java:49)
   [pitest] 	at org.pitest.testapi.execute.containers.UnContainer.execute(UnContainer.java:31)
   [pitest] 	at org.pitest.testapi.execute.Pitest.executeTests(Pitest.java:57)
   [pitest] 	at org.pitest.testapi.execute.Pitest.run(Pitest.java:48)
   [pitest] 	at org.p
   [pitest] 12:06:57 PIT >> INFO : MINION : itest.coverage.execute.CoverageWorker.run(CoverageWorker.java:49)
   [pitest] 	at org.pitest.coverage.execute.CoverageMinion.main(CoverageMinion.java:90)
   [pitest] Caused by: java.lang.NullPointerException
   [pitest] 	at com.example.NestedClassTest$MyEnum$1.<init>(Unknown Source)
   [pitest] 	at com.
   [pitest] 12:06:57 PIT >> INFO : MINION : example.NestedClassTest$MyEnum.<clinit>(Unknown Source)
   [pitest] 	... 28 more
   [pitest] 
   [pitest] 12:06:57 PIT >> SEVERE : Description [testClass=com.example.NestedClassTest, name=test(com.example.NestedClassTest)] did not pass without mutation.
   [pitest] 12:06:57 PIT >> FINE : Coverage generator Minion exited ok
   [pitest] 12:06:57 PIT >> INFO : Calculated coverage in 1 seconds.
   [pitest] 12:06:57 PIT >> SEVERE : Tests failing without mutation: 
   [pitest] Description [testClass=com.example.NestedClassTest, name=test(com.example.NestedClassTest)]
   [pitest] Exception in thread "main" org.pitest.help.PitHelpError: 1 tests did not pass without mutation when calculating line coverage. Mutation testing requires a green suite.
   [pitest] See http://pitest.org for more details.
   [pitest] 	at org.pitest.coverage.execute.DefaultCoverageGenerator.verifyBuildSuitableForMutationTesting(DefaultCoverageGenerator.java:114)
   [pitest] 	at org.pitest.coverage.execute.DefaultCoverageGenerator.calculateCoverage(DefaultCoverageGenerator.java:96)
   [pitest] 	at org.pitest.coverage.execute.DefaultCoverageGenerator.calculateCoverage(DefaultCoverageGenerator.java:51)
   [pitest] 	at org.pitest.mutationtest.tooling.MutationCoverage.runReport(MutationCoverage.java:115)
   [pitest] 	at org.pitest.mutationtest.tooling.EntryPoint.execute(EntryPoint.java:121)
   [pitest] 	at org.pitest.mutationtest.tooling.EntryPoint.execute(EntryPoint.java:51)
   [pitest] 	at org.pitest.mutationtest.commandline.MutationCoverageReport.runReport(MutationCoverageReport.java:87)
   [pitest] 	at org.pitest.mutationtest.commandline.MutationCoverageReport.main(MutationCoverageReport.java:45)

BUILD FAILED
/Users/work/Projects/pitest-ant-example/build.xml:49: /Users/work/Projects/pitest-ant-example/build.xml:49: Java returned: 1

Total time: 5 seconds
@hcoles
Copy link
Owner

hcoles commented Jun 3, 2020

Thanks for the report that is ... strange.

@aJanuary
Copy link
Author

aJanuary commented Jun 4, 2020

I have managed to narrow it down to adfe9de (probably not too surprising).

If CoverageTransformer.shouldInclude is changed to return false for com.example.NestedClassTest$MyEnum$1 it no longer throws the NPE. This suggests the issue lies somewhere in CoverageTransformer.transformBytes. Hopefully I'll have some time tomorrow to continue narrowing it down.

hcoles pushed a commit that referenced this issue Dec 31, 2020
Failing test to describe general issue behind coverage bugs - child
classes are initialized after their parents, so coverage probe is not
initialized when parent refers to child in a static initializer block.
hcoles pushed a commit that referenced this issue Dec 31, 2020
Failing test to describe general issue behind coverage bugs - child
classes are initialized after their parents, so coverage probe is not
initialized when parent refers to child in a static initializer block.
@hcoles hcoles mentioned this issue Dec 31, 2020
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

Successfully merging a pull request may close this issue.

2 participants