package org.pitest.mutationtest.execute; import static org.mockito.Matchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.pitest.mutationtest.LocationMother.aLocation; import static org.pitest.mutationtest.LocationMother.aMutationId; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import junit.framework.AssertionFailedError; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.pitest.classinfo.ClassName; import org.pitest.functional.F3; import org.pitest.mutationtest.DetectionStatus; import org.pitest.mutationtest.MutationStatusTestPair; import org.pitest.mutationtest.engine.Mutant; import org.pitest.mutationtest.engine.Mutater; import org.pitest.mutationtest.engine.MutationDetails; import org.pitest.mutationtest.engine.MutationIdentifier; import org.pitest.testapi.Description; import org.pitest.testapi.ResultCollector; import org.pitest.testapi.TestUnit; public class MutationTestWorkerTest { private MutationTestWorker testee; @Mock private ClassLoader loader; @Mock private Mutater mutater; @Mock private F3<ClassName, ClassLoader, byte[], Boolean> hotswapper; @Mock private TimeOutDecoratedTestSource testSource; @Mock private Reporter reporter; @Before public void setUp() { MockitoAnnotations.initMocks(this); this.testee = new MutationTestWorker(this.hotswapper, this.mutater, this.loader); } @Test public void shouldDescribeEachExaminedMutation() throws IOException { final MutationDetails mutantOne = makeMutant("foo", 1); final MutationDetails mutantTwo = makeMutant("foo", 2); final Collection<MutationDetails> range = Arrays.asList(mutantOne, mutantTwo); this.testee.run(range, this.reporter, this.testSource); verify(this.reporter).describe(mutantOne.getId()); verify(this.reporter).describe(mutantTwo.getId()); } @Test @Ignore("disabled while checking coverage issue") public void shouldReportNoCoverageForMutationWithNoTestCoverage() throws IOException { final MutationDetails mutantOne = makeMutant("foo", 1); final Collection<MutationDetails> range = Arrays.asList(mutantOne); this.testee.run(range, this.reporter, this.testSource); verify(this.reporter).report(mutantOne.getId(), new MutationStatusTestPair(0, DetectionStatus.NO_COVERAGE)); } @SuppressWarnings("unchecked") @Test public void shouldReportWhenMutationNotDetected() throws IOException { final MutationDetails mutantOne = makeMutant("foo", 1); final Collection<MutationDetails> range = Arrays.asList(mutantOne); final TestUnit tu = makePassingTest(); when(this.testSource.translateTests(any(List.class))).thenReturn( Collections.singletonList(tu)); when( this.hotswapper.apply(any(ClassName.class), any(ClassLoader.class), any(byte[].class))).thenReturn(true); this.testee.run(range, this.reporter, this.testSource); verify(this.reporter).report(mutantOne.getId(), new MutationStatusTestPair(1, DetectionStatus.SURVIVED)); } @SuppressWarnings("unchecked") @Test public void shouldReportWhenMutationNotViable() throws IOException { final MutationDetails mutantOne = makeMutant("foo", 1); final Collection<MutationDetails> range = Arrays.asList(mutantOne); final TestUnit tu = makePassingTest(); when(this.testSource.translateTests(any(List.class))).thenReturn( Collections.singletonList(tu)); when( this.hotswapper.apply(any(ClassName.class), any(ClassLoader.class), any(byte[].class))).thenReturn(false); this.testee.run(range, this.reporter, this.testSource); verify(this.reporter).report(mutantOne.getId(), new MutationStatusTestPair(0, DetectionStatus.NON_VIABLE)); } @SuppressWarnings("unchecked") @Test public void shouldReportWhenMutationKilledByTest() throws IOException { final MutationDetails mutantOne = makeMutant("foo", 1); final Collection<MutationDetails> range = Arrays.asList(mutantOne); final TestUnit tu = makeFailingTest(); when(this.testSource.translateTests(any(List.class))).thenReturn( Collections.singletonList(tu)); when( this.hotswapper.apply(any(ClassName.class), any(ClassLoader.class), any(byte[].class))).thenReturn(true); this.testee.run(range, this.reporter, this.testSource); verify(this.reporter).report( mutantOne.getId(), new MutationStatusTestPair(1, DetectionStatus.KILLED, tu .getDescription().getName())); } private TestUnit makeFailingTest() { return new TestUnit() { @Override public void execute(final ClassLoader loader, final ResultCollector rc) { rc.notifyStart(getDescription()); rc.notifyEnd(getDescription(), new AssertionFailedError()); } @Override public Description getDescription() { return new Description("atest"); } }; } private TestUnit makePassingTest() { return new TestUnit() { @Override public void execute(final ClassLoader loader, final ResultCollector rc) { rc.notifyStart(getDescription()); rc.notifyEnd(getDescription()); } @Override public Description getDescription() { return new Description("atest"); } }; } public MutationDetails makeMutant(final String clazz, final int index) { MutationIdentifier id = aMutationId() .withLocation(aLocation().withClass(ClassName.fromString(clazz))) .withIndex(index).withMutator("mutator").build(); final MutationDetails md = new MutationDetails(id, "sourceFile", "desc", 42, 0); when(this.mutater.getMutation(md.getId())).thenReturn( new Mutant(md, new byte[0])); return md; } }