Skip to content

Commit

Permalink
mutate custom record hashCode and toString
Browse files Browse the repository at this point in the history
  • Loading branch information
Henry Coles committed Aug 6, 2021
1 parent 81ffeec commit 6a1ef3f
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 5 deletions.
4 changes: 4 additions & 0 deletions README.md
Expand Up @@ -8,6 +8,10 @@ Read all about it at http://pitest.org

## Releases

### current snapshot

* #919 Filter junk mutations in java records

### 1.6.8

* #917 - Add method to retrieve all mutator ids for pitclipse and other tooling
Expand Down
Expand Up @@ -51,8 +51,10 @@ private Predicate<MutationDetails> makeMethodFilter(ClassTree currentClass) {
}

private boolean isStandardMethod(int numberOfComponents, MutationDetails m) {
String name = m.getMethod().name();
return isRecordInit(m, numberOfComponents) || isRecordEquals(m) || name.equals("hashCode") || name.equals("toString");
return isRecordInit(m, numberOfComponents)
|| isRecordEquals(m)
|| isRecordHashCode(m)
|| isRecordToString(m);
}

private boolean isRecordInit(MutationDetails m, int numberOfComponents) {
Expand All @@ -68,9 +70,21 @@ private boolean isRecordEquals(MutationDetails m) {
&& hasDynamicObjectMethodsCall(m);
}

private boolean isRecordHashCode(MutationDetails m) {
return m.getId().getLocation().getMethodDesc().equals("()I")
&& m.getMethod().name().equals("hashCode")
&& hasDynamicObjectMethodsCall(m);
}

private boolean isRecordToString(MutationDetails m) {
return m.getId().getLocation().getMethodDesc().equals("()Ljava/lang/String;")
&& m.getMethod().name().equals("toString")
&& hasDynamicObjectMethodsCall(m);
}

private boolean hasDynamicObjectMethodsCall(MutationDetails mutation) {
// java/lang/runtime/ObjectMethods was added to support records and can be used as a marker
// for an auth generated equals method. It's not likely that a custom equals method would
// for an auth generated equals method. It's not likely that a custom method would
// contain a dynamic call to it
Optional<MethodTree> method = currentClass.method(mutation.getId().getLocation());
return method.filter(m -> m.instructions().stream().anyMatch(this::isInvokeDynamicCallToObjectMethods))
Expand All @@ -80,8 +94,8 @@ private boolean hasDynamicObjectMethodsCall(MutationDetails mutation) {
private boolean isInvokeDynamicCallToObjectMethods(AbstractInsnNode node) {
if (node instanceof InvokeDynamicInsnNode) {
InvokeDynamicInsnNode call = (InvokeDynamicInsnNode) node;
return call.bsm.getOwner().equals("java/lang/runtime/ObjectMethods") &&
call.bsm.getName().equals("bootstrap");
return call.bsm.getOwner().equals("java/lang/runtime/ObjectMethods")
&& call.bsm.getName().equals("bootstrap");

}
return false;
Expand Down
Expand Up @@ -52,6 +52,18 @@ public void mutatesCustomEqualsMethods() {
"RecordWithCustomEquals");
}

@Test
public void mutatesCustomHashCodeMethods() {
this.verifier.assertFiltersNoMutationsMatching(inMethodCalled("hashCode"),
"RecordWithCustomHashCode");
}

@Test
public void mutatesCustomToStringMethods() {
this.verifier.assertFiltersNoMutationsMatching(inMethodCalled("toString"),
"RecordWithCustomToString");
}

private Predicate<MutationDetails> removesSysOutCall() {
return m -> m.getDescription().contains("PrintStream::println");
}
Expand Down
Binary file not shown.
Binary file not shown.
Expand Up @@ -3,6 +3,7 @@
import java.util.List;

public record RecordWithCustomEquals(List<Integer> ints, String data) {
@Override
public boolean equals(Object o) {
return o == this;
}
Expand Down
10 changes: 10 additions & 0 deletions samples/src/main/java/com/example/RecordWithCustomHashCode.java
@@ -0,0 +1,10 @@
package com.example;

import java.util.List;

public record RecordWithCustomHashCode(List<Integer> ints, String data) {
@Override
public int hashCode() {
return 42;
}
}
10 changes: 10 additions & 0 deletions samples/src/main/java/com/example/RecordWithCustomToString.java
@@ -0,0 +1,10 @@
package com.example;

import java.util.List;

public record RecordWithCustomToString(List<Integer> ints, String data) {
@Override
public String toString() {
return data;
}
}

0 comments on commit 6a1ef3f

Please sign in to comment.