-
Notifications
You must be signed in to change notification settings - Fork 354
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
filter singleton constructors as per #903
Filter mutations in constructors called from the same class' static initializer. A check is not made that the constructor is private. Some killable mutants may therefore be filtered, but this needs to be weighed against the confusion caused by mutants appearing/disappearing based on code visibility.
- Loading branch information
Henry Coles
committed
Jun 13, 2022
1 parent
3b0fe10
commit e717f8c
Showing
6 changed files
with
148 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
...st-entry/src/test/java/com/example/staticinitializers/SingletonWithWorkInInitializer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.example.staticinitializers; | ||
|
||
public class SingletonWithWorkInInitializer { | ||
int num = 6; | ||
|
||
private static final SingletonWithWorkInInitializer INSTANCE = new SingletonWithWorkInInitializer(); | ||
|
||
private SingletonWithWorkInInitializer() { | ||
} | ||
|
||
public static SingletonWithWorkInInitializer getInstance() { | ||
return INSTANCE; | ||
} | ||
|
||
public boolean isMember6() { | ||
return 6 == num; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
196 changes: 115 additions & 81 deletions
196
...est/mutationtest/build/intercept/staticinitializers/StaticInitializerInterceptorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,129 +1,163 @@ | ||
package org.pitest.mutationtest.build.intercept.staticinitializers; | ||
|
||
import com.example.staticinitializers.SingletonWithWorkInInitializer; | ||
import org.junit.Test; | ||
import org.pitest.mutationtest.build.intercept.javafeatures.FilterTester; | ||
import org.pitest.mutationtest.engine.MutationDetails; | ||
import org.pitest.mutationtest.engine.gregor.mutators.NullMutateEverything; | ||
import org.pitest.verifier.interceptors.InterceptorVerifier; | ||
import org.pitest.verifier.interceptors.VerifierStart; | ||
|
||
import java.util.function.Predicate; | ||
|
||
|
||
public class StaticInitializerInterceptorTest { | ||
|
||
StaticInitializerInterceptor testee = new StaticInitializerInterceptor(); | ||
|
||
FilterTester verifier = new FilterTester("", this.testee, NullMutateEverything.asList()); | ||
|
||
|
||
@Test | ||
public void shouldNotFilterMutationsInClassWithoutStaticInitializer() { | ||
verifier.assertFiltersNMutationFromClass(0, NoStaticInializer.class); | ||
} | ||
|
||
@Test | ||
public void shouldFilterMutationsInStaticInitializer() { | ||
verifier.assertFiltersMutationsMatching(inMethodNamed("<clinit>"), HasStaticInializer.class); | ||
} | ||
|
||
@Test | ||
public void shouldMarkMutationsInPrivateMethodsCalledFromStaticInitializer() { | ||
verifier.assertFiltersMutationsMatching(inMethodNamed("a"), HasPrivateCallsFromStaticInializer.class); | ||
} | ||
InterceptorVerifier v = VerifierStart.forInterceptorFactory(new StaticInitializerInterceptorFactory()) | ||
.usingMutator(new NullMutateEverything()); | ||
|
||
|
||
@Test | ||
public void shouldNotFilterMutationsInClassWithoutStaticInitializer() { | ||
v.forClass(NoStaticInializer.class) | ||
.forAnyCode() | ||
.mutantsAreGenerated() | ||
.noMutantsAreFiltered() | ||
.verify(); | ||
} | ||
|
||
@Test | ||
public void shouldFilterMutationsInStaticInitializer() { | ||
v.forClass(HasStaticInializer.class) | ||
.forMethod("<clinit>") | ||
.forAnyCode() | ||
.mutantsAreGenerated() | ||
.allMutantsAreFiltered() | ||
.verify(); | ||
} | ||
|
||
@Test | ||
public void shouldMarkMutationsInPrivateMethodsCalledFromStaticInitializer() { | ||
v.forClass(HasPrivateCallsFromStaticInializer.class) | ||
.forMethod("a") | ||
.forAnyCode() | ||
.mutantsAreGenerated() | ||
.allMutantsAreFiltered() | ||
.verify(); | ||
} | ||
|
||
@Test | ||
public void shouldNotMarkMutationsInPackageDefaultMethodsCalledFromStaticInitializer() { | ||
v.forClass(HasDefaultCallsFromStaticInializer.class) | ||
.forMethod("a") | ||
.forAnyCode() | ||
.mutantsAreGenerated() | ||
.noMutantsAreFiltered() | ||
.verify(); | ||
} | ||
|
||
|
||
@Test | ||
public void shouldNotMarkMutationsInPrivateStaticMethodsNotInvolvedInInit() { | ||
v.forClass(HasOtherPrivateStaticMethods.class) | ||
.forMethod("b") | ||
.forAnyCode() | ||
.mutantsAreGenerated() | ||
.noMutantsAreFiltered() | ||
.verify(); | ||
} | ||
|
||
@Test | ||
public void shouldNotMarkMutationsInOverriddenMethodsNotInvolvedInStaticInit() { | ||
v.forClass(HasOverloadedMethodsThatAreNotUsedInStaticInitialization.class) | ||
.forMutantsMatching(inMethod("a", "(I)V")) | ||
.mutantsAreGenerated() | ||
.noMutantsAreFiltered() | ||
.verify(); | ||
} | ||
|
||
@Test | ||
public void shouldNotMarkMutationsInPackageDefaultMethodsCalledFromStaticInitializer() { | ||
verifier.assertFiltersNoMutationsMatching(inMethodNamed("a"), HasDefaultCallsFromStaticInializer.class); | ||
public void filtersMutantsInSingletonConstructor() { | ||
v.forClass(SingletonWithWorkInInitializer.class) | ||
.forMutantsMatching(inMethod("<init>", "()V")) | ||
.mutantsAreGenerated() | ||
.allMutantsAreFiltered() | ||
.verify(); | ||
} | ||
|
||
|
||
@Test | ||
public void shouldNotMarkMutationsInPrivateStaticMethodsNotInvolvedInInit() { | ||
verifier.assertFiltersNoMutationsMatching(inMethodNamed("b"), HasOtherPrivateStaticMethods.class); | ||
} | ||
|
||
@Test | ||
public void shouldNotMarkMutationsInOverriddenMethodsNotInvolvedInStaticInit() { | ||
verifier.assertFiltersNoMutationsMatching(inMethod("a", "(I)V"), HasOverloadedMethodsThatAreNotUsedInStaticInitialization.class); | ||
} | ||
|
||
private Predicate<MutationDetails> inMethodNamed(String name) { | ||
return m -> m.getMethod().equals(name); | ||
} | ||
|
||
private Predicate<MutationDetails> inMethod(String name, String desc) { | ||
return m -> m.getMethod().equals(name) && m.getId().getLocation().getMethodDesc().equals(desc); | ||
} | ||
private Predicate<MutationDetails> inMethod(String name, String desc) { | ||
return m -> m.getMethod().equals(name) && m.getId().getLocation().getMethodDesc().equals(desc); | ||
} | ||
|
||
} | ||
|
||
class NoStaticInializer { | ||
{ | ||
System.out.println("NOT static code"); | ||
} | ||
{ | ||
System.out.println("NOT static code"); | ||
} | ||
} | ||
|
||
class HasStaticInializer { | ||
static { | ||
System.out.println("static code"); | ||
} | ||
static { | ||
System.out.println("static code"); | ||
} | ||
} | ||
|
||
class HasPrivateCallsFromStaticInializer { | ||
static { | ||
a(); | ||
} | ||
static { | ||
a(); | ||
} | ||
|
||
private static void a() { | ||
System.out.println("static code"); | ||
} | ||
private static void a() { | ||
System.out.println("static code"); | ||
} | ||
} | ||
|
||
class HasDefaultCallsFromStaticInializer { | ||
static { | ||
a(); | ||
} | ||
static { | ||
a(); | ||
} | ||
|
||
static void a() { | ||
System.out.println("NOT guaranteed to be static code"); | ||
} | ||
static void a() { | ||
System.out.println("NOT guaranteed to be static code"); | ||
} | ||
} | ||
|
||
class HasOtherPrivateStaticMethods { | ||
static { | ||
a(); | ||
} | ||
static { | ||
a(); | ||
} | ||
|
||
private static void a() { | ||
private static void a() { | ||
|
||
} | ||
} | ||
|
||
public static void entryPoint(int i) { | ||
b(i); | ||
} | ||
public static void entryPoint(int i) { | ||
b(i); | ||
} | ||
|
||
|
||
private static void b(int i) { | ||
System.out.println("NOT static code"); | ||
} | ||
private static void b(int i) { | ||
System.out.println("NOT static code"); | ||
} | ||
} | ||
|
||
|
||
class HasOverloadedMethodsThatAreNotUsedInStaticInitialization { | ||
static { | ||
a(); | ||
} | ||
static { | ||
a(); | ||
} | ||
|
||
private static void a() { | ||
private static void a() { | ||
|
||
} | ||
} | ||
|
||
public static void entryPoint(int i) { | ||
a(i); | ||
} | ||
public static void entryPoint(int i) { | ||
a(i); | ||
} | ||
|
||
// same name, different sig | ||
private static void a(int i) { | ||
System.out.println("NOT static code"); | ||
} | ||
// same name, different sig | ||
private static void a(int i) { | ||
System.out.println("NOT static code"); | ||
} | ||
} | ||
|