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

Handle parent before child initialisation order #850

Merged
merged 6 commits into from
Dec 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ jobs:
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven-
- name: 'Test'
run: mvn -B verify
# install rather than verify to ensure correct version used during integration test
run: mvn -B install
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ target/
dependency-reduced-pom.xml
.flattened-pom.xml
*/bin
.DS_Store

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.example.coverage.execute.samples.simple;

import org.junit.Test;

public class ParentChildInitializationTest {
@Test
public void test() {
new TesteeChild();
}
}

class TesteeParent {
static TesteeChild child = new TesteeChild();
}

class TesteeChild extends TesteeParent {
final static Object f = "hello";

TesteeChild() {
System.out.println(f);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.example.coverage.execute.samples.exceptions.ThrowsExceptionFromLargeMethodTestee;
import com.example.coverage.execute.samples.exceptions.ThrowsExceptionInFinallyBlockTestee;
import com.example.coverage.execute.samples.exceptions.ThrowsExceptionTestee;
import com.example.coverage.execute.samples.simple.ParentChildInitializationTest;
import com.example.coverage.execute.samples.simple.Testee;
import com.example.coverage.execute.samples.simple.Testee2;
import com.example.coverage.execute.samples.simple.TesteeWithComplexConstructorsTest;
Expand Down Expand Up @@ -57,8 +58,7 @@ public class CoverageProcessSystemTest {
private final MethodName foo = MethodName.fromString("foo");

@Test
public void shouldRecordSomeCoverage() throws IOException,
InterruptedException, ExecutionException {
public void shouldRecordSomeCoverage() throws Exception {
final List<CoverageResult> coverage = runCoverageForTest(TestsForMultiBlockCoverage.class);
assertFalse(coverage.iterator().next().getCoverage().isEmpty());
}
Expand All @@ -80,8 +80,7 @@ public void shouldCalculateCoverageForSingleBlockMethods()
// }

@Test
public void shouldCalculateCoverageFor3BlockMethods() throws IOException,
InterruptedException, ExecutionException {
public void shouldCalculateCoverageFor3BlockMethods() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestsForMultiBlockCoverage.class);
assertCoverage(coveredClasses, "test3", 2);
}
Expand Down Expand Up @@ -122,22 +121,19 @@ public void shouldCalculateCoverageForBlockMethods() throws IOException,
}

@Test
public void shouldCalculateCoverageFor7BlockMethods() throws IOException,
InterruptedException, ExecutionException {
public void shouldCalculateCoverageFor7BlockMethods() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestsForMultiBlockCoverage.class);
assertCoverage(coveredClasses, "test7", 2);
}

@Test
public void shouldCalculateCoverageFor8BlockMethods() throws IOException,
InterruptedException, ExecutionException {
public void shouldCalculateCoverageFor8BlockMethods() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestsForMultiBlockCoverage.class);
assertCoverage(coveredClasses, "test8", 2);
}

@Test
public void shouldCalculateCoverageFor9BlockMethods() throws IOException,
InterruptedException, ExecutionException {
public void shouldCalculateCoverageFor9BlockMethods() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestsForMultiBlockCoverage.class);
assertCoverage(coveredClasses, "test9", 2);
}
Expand All @@ -150,50 +146,44 @@ public void shouldCalculateCoverageFor10BlockMethods() throws IOException,
}

@Test
public void shouldCalculateCoverageFor11BlockMethods() throws IOException,
InterruptedException, ExecutionException {
public void shouldCalculateCoverageFor11BlockMethods() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestsForMultiBlockCoverage.class);
assertCoverage(coveredClasses, "test11", 2);
}

@Test
public void shouldCalculateCoverageFor12BlockMethods() throws IOException,
InterruptedException, ExecutionException {
public void shouldCalculateCoverageFor12BlockMethods() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestsForMultiBlockCoverage.class);
assertCoverage(coveredClasses, "test12", 2);
}

@Test
public void shouldCalculateCoverageFor13BlockMethods() throws IOException,
InterruptedException, ExecutionException {
public void shouldCalculateCoverageFor13BlockMethods() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestsForMultiBlockCoverage.class);
assertCoverage(coveredClasses, "test13", 2);
}

@Test
public void shouldCalculateCoverageFor14BlockMethods() throws IOException,
InterruptedException, ExecutionException {
public void shouldCalculateCoverageFor14BlockMethods() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestsForMultiBlockCoverage.class);
assertCoverage(coveredClasses, "test14", 2);
}

@Test
public void shouldCalculateCoverageFor15BlockMethods() throws IOException,
InterruptedException, ExecutionException {
public void shouldCalculateCoverageFor15BlockMethods() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestsForMultiBlockCoverage.class);
assertCoverage(coveredClasses, "test15", 2);
}

@Test
public void shouldCalculateCoverageForLargeBlockMethods() throws IOException,
InterruptedException, ExecutionException {
public void shouldCalculateCoverageForLargeBlockMethods() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestsForMultiBlockCoverage.class);
assertCoverage(coveredClasses, "testMany", 2);
}

@Test
public void shouldCalculateCoverageForAllRelevantClasses()
throws IOException, InterruptedException, ExecutionException {
throws Exception{

final List<CoverageResult> coveredClasses = runCoverageForTest(Tests.class);

Expand All @@ -204,7 +194,7 @@ public void shouldCalculateCoverageForAllRelevantClasses()

@Test
public void shouldCalculateCoverageForSmallMethodThatThrowsException()
throws IOException, InterruptedException, ExecutionException {
throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestsClassWithException.class);
assertThat(coveredClasses).anyMatch(coverageFor(CoveredBeforeExceptionTestee.class));

Expand All @@ -222,7 +212,7 @@ public void shouldCalculateCoverageForSmallMethodThatThrowsException()

@Test
public void shouldCalculateCoverageForMethodThatThrowsExceptionWithFinallyBlock()
throws IOException, InterruptedException, ExecutionException {
throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestThrowsExceptionInFinallyBlock.class);

final ClassName clazz = ClassName
Expand All @@ -237,7 +227,7 @@ public void shouldCalculateCoverageForMethodThatThrowsExceptionWithFinallyBlock(

@Test
public void shouldCalculateCoverageForLargeMethodThatThrowsException()
throws IOException, InterruptedException, ExecutionException {
throws IOException, InterruptedException {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestThrowsExceptionFromLargeMethodTestee.class);

final ClassName clazz = ClassName
Expand All @@ -262,7 +252,7 @@ public void testFoo() {

@Test
public void shouldCalculateCoverageOfClassesRunInDifferentClassLoader()
throws IOException, InterruptedException, ExecutionException {
throws IOException, InterruptedException {
final List<CoverageResult> coveredClasses = runCoverageForTest(TestInDifferentClassLoader.class);
assertThat(coveredClasses).anyMatch(coverageFor(Testee2.class));
assertThat(coveredClasses).anyMatch(coverageFor(Testee.class));
Expand Down Expand Up @@ -314,6 +304,13 @@ public void shouldFailWithExitCode() throws Exception {
assertEquals(ExitCode.JUNIT_ISSUE, exitCode);
}

@Test
public void handlesParentChildInitializationOrderIssues() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(ParentChildInitializationTest.class);
assertThat(coveredClasses)
.anyMatch(coverageFor(ClassName.fromString("com.example.coverage.execute.samples.simple.TesteeChild")));
}

private ClassPath classPathWithoutJUnit() {
final List<File> cpWithoutJUnit =
ClassPath.getClassPathElementsAsFiles().stream()
Expand All @@ -328,7 +325,7 @@ private Predicate<CoverageResult> failingTest() {
}

private List<CoverageResult> runCoverageForTest(final Class<?> test)
throws IOException, InterruptedException, ExecutionException {
throws IOException, InterruptedException {

final List<CoverageResult> coveredClasses = new ArrayList<>();

Expand Down Expand Up @@ -360,16 +357,20 @@ private void runCoverageProcess(final Class<?> test,
}
}

private Predicate<CoverageResult> coverageFor(final Class<?> class1) {
private Predicate<CoverageResult> coverageFor(final Class<?> clazz) {
return coverageFor(ClassName.fromClass(clazz));
}

private Predicate<CoverageResult> coverageFor(ClassName clazz) {
return new Predicate<CoverageResult>() {

@Override
public boolean test(final CoverageResult a) {
return FCollection.contains(a.getCoverage(), resultFor(class1));
return FCollection.contains(a.getCoverage(), resultFor(clazz));
}

private Predicate<BlockLocation> resultFor(final Class<?> class1) {
return a -> a.isFor(ClassName.fromClass(class1));
private Predicate<BlockLocation> resultFor(ClassName clazz) {
return a -> a.isFor(clazz);
}
};
}
Expand Down
34 changes: 22 additions & 12 deletions pitest-maven-verification/src/test/java/org/pitest/PitMojoIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,6 @@
*/
package org.pitest;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.commons.io.FileUtils;
import org.apache.maven.it.VerificationException;
import org.apache.maven.it.Verifier;
Expand All @@ -43,6 +31,18 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;

/**
* @author Stefan Penndorf <stefan.penndorf@gmail.com>
*/
Expand Down Expand Up @@ -563,4 +563,14 @@ public void shouldFindOccupiedTestPackages() throws IOException, VerificationExc
"<mutation detected='true' status='KILLED' numberOfTestsRun='1'><sourceFile>DiscoveredClass.java</sourceFile>");
}

@Test
public void shouldNotNullPointerWhenEnumInitializerNotCalled() throws IOException, VerificationException {
File testDir = prepare("/pit-enum-constructor-npe");
verifier.executeGoal("test");
verifier.executeGoal("org.pitest:pitest-maven:mutationCoverage");

String actual = readResults(testDir);
assertThat(actual).isNotEmpty();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>pitest-sample</artifactId>
<version>0.1-SNAPSHOT</version>
<name>pit #770 npe in constructor</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.4</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>${pit.version}</version>
<configuration>
<verbose>true</verbose>
<outputFormats>
<value>XML</value>
</outputFormats>
<timestampedReports>false</timestampedReports>
<exportLineCoverage>true</exportLineCoverage>
<mutators>
<mutator>VOID_METHOD_CALLS</mutator>
</mutators>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example;

class Test {
public Test() {
System.out.println("I only exist so that pitest thinks there is something to mutate");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
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");
}
}

Loading