diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationCoverage.java b/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationCoverage.java index d80ec4e2e..4312a78fa 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationCoverage.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationCoverage.java @@ -162,7 +162,7 @@ private CombinedStatistics runAnalysis(Runtime runtime, long t0, EngineArguments engine, args, allInterceptors()); this.timings.registerEnd(Timings.Stage.BUILD_MUTATION_TESTS); - LOG.info("Created " + tus.size() + " mutation test units"); + LOG.info("Created " + tus.size() + " mutation test units" ); recordClassPath(history, coverageData); diff --git a/pitest-entry/src/main/java/org/pitest/sequence/Context.java b/pitest-entry/src/main/java/org/pitest/sequence/Context.java index 70b69452a..f4a2efd4b 100644 --- a/pitest-entry/src/main/java/org/pitest/sequence/Context.java +++ b/pitest-entry/src/main/java/org/pitest/sequence/Context.java @@ -1,59 +1,32 @@ package org.pitest.sequence; -import java.util.IdentityHashMap; - -import java.util.Map; import java.util.Optional; -public final class Context { - - private final boolean debug; - private final Map slots; - - Context(Map slots, boolean debug) { - this.slots = slots; - this.debug = debug; - } +public interface Context { - public static Context start() { + static Context start() { return start(false); } - public static Context start(boolean debug) { - return new Context(new IdentityHashMap<>(), debug); + static Context start(boolean debug) { + if (debug) { + return EmptyContext.WITH_DEBUG; + } + return EmptyContext.WITHOUT_DEBUG; } - public Context store(SlotWrite slot, S value) { - Map mutatedSlots = new IdentityHashMap<>(slots); - mutatedSlots.put(slot.slot(), value); - return new Context(mutatedSlots, debug); - } + Context store(SlotWrite slot, S value); @SuppressWarnings("unchecked") - public Optional retrieve(SlotRead slot) { - return Optional.ofNullable((S)slots.get(slot.slot())); - } + Optional retrieve(SlotRead slot); - public void debug(String msg, T t) { - if (this.debug) { - System.out.println(msg + " for " + t); - } + default boolean debug() { + return false; } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Context)) { - return false; + default void debug(String msg, T t) { + if (debug()) { + System.out.println(msg + " for " + t); } - Context context = (Context) o; - return slots.equals(context.slots); - } - - @Override - public int hashCode() { - return slots.hashCode(); } } diff --git a/pitest-entry/src/main/java/org/pitest/sequence/Context1.java b/pitest-entry/src/main/java/org/pitest/sequence/Context1.java new file mode 100644 index 000000000..bc523131c --- /dev/null +++ b/pitest-entry/src/main/java/org/pitest/sequence/Context1.java @@ -0,0 +1,60 @@ +package org.pitest.sequence; + +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +/** + * Specialisation of context for single values + */ +final class Context1 implements Context { + private final boolean debug; + private final Slot slot; + private final Object value; + + Context1(Slot slot, Object value, boolean debug) { + this.slot = slot; + this.value = value; + this.debug = debug; + } + + @Override + public boolean debug() { + return debug; + } + + @Override + public Context store(SlotWrite slot, S value) { + Map mutatedSlots = new IdentityHashMap<>(); + mutatedSlots.put(this.slot, this.value); + mutatedSlots.put(slot.slot(), value); + return new MultiContext(mutatedSlots, debug); + } + + @SuppressWarnings("unchecked") + @Override + public Optional retrieve(SlotRead read) { + if (read.slot().equals(slot)) { + return (Optional) Optional.ofNullable(value); + } + return Optional.empty(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Context1)) { + return false; + } + Context1 context1 = (Context1) o; + return slot.equals(context1.slot) && Objects.equals(value, context1.value); + } + + @Override + public int hashCode() { + return Objects.hash(slot, value); + } +} diff --git a/pitest-entry/src/main/java/org/pitest/sequence/EmptyContext.java b/pitest-entry/src/main/java/org/pitest/sequence/EmptyContext.java new file mode 100644 index 000000000..9b04564e9 --- /dev/null +++ b/pitest-entry/src/main/java/org/pitest/sequence/EmptyContext.java @@ -0,0 +1,35 @@ +package org.pitest.sequence; + +import java.util.Optional; + +/** + * Specialisation of context with no data + */ +enum EmptyContext implements Context { + + WITHOUT_DEBUG(false), + WITH_DEBUG(true); + + private final boolean debug; + + EmptyContext(boolean debug) { + this.debug = debug; + } + + @Override + public boolean debug() { + return debug; + } + + @Override + public Context store(SlotWrite slot, S value) { + return new Context1(slot.slot(), value, debug); + } + + @SuppressWarnings("unchecked") + @Override + public Optional retrieve(SlotRead slot) { + return Optional.empty(); + } + +} diff --git a/pitest-entry/src/main/java/org/pitest/sequence/MultiContext.java b/pitest-entry/src/main/java/org/pitest/sequence/MultiContext.java new file mode 100644 index 000000000..ea2cd4a99 --- /dev/null +++ b/pitest-entry/src/main/java/org/pitest/sequence/MultiContext.java @@ -0,0 +1,55 @@ +package org.pitest.sequence; + +import java.util.IdentityHashMap; + +import java.util.Map; +import java.util.Optional; + +/** + * Specialisation of context for unlimited values + */ +final class MultiContext implements Context { + + private final boolean debug; + private final Map slots; + + MultiContext(Map slots, boolean debug) { + this.slots = slots; + this.debug = debug; + } + + @Override + public boolean debug() { + return debug; + } + + @Override + public Context store(SlotWrite slot, S value) { + Map mutatedSlots = new IdentityHashMap<>(slots); + mutatedSlots.put(slot.slot(), value); + return new MultiContext(mutatedSlots, debug); + } + + @SuppressWarnings("unchecked") + @Override + public Optional retrieve(SlotRead slot) { + return Optional.ofNullable((S)slots.get(slot.slot())); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof MultiContext)) { + return false; + } + MultiContext context = (MultiContext) o; + return slots.equals(context.slots); + } + + @Override + public int hashCode() { + return slots.hashCode(); + } +} diff --git a/pitest-entry/src/test/java/org/pitest/sequence/Context1Test.java b/pitest-entry/src/test/java/org/pitest/sequence/Context1Test.java new file mode 100644 index 000000000..bdfc80d42 --- /dev/null +++ b/pitest-entry/src/test/java/org/pitest/sequence/Context1Test.java @@ -0,0 +1,15 @@ +package org.pitest.sequence; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.Test; + +public class Context1Test { + + @Test + public void obeysHashCodeEqualsContract() { + EqualsVerifier.forClass(Context1.class) + .withNonnullFields("slot") + .withIgnoredFields("debug") + .verify(); + } +} \ No newline at end of file diff --git a/pitest-entry/src/test/java/org/pitest/sequence/ContextTest.java b/pitest-entry/src/test/java/org/pitest/sequence/ContextTest.java index e4eacda42..b4c24b739 100644 --- a/pitest-entry/src/test/java/org/pitest/sequence/ContextTest.java +++ b/pitest-entry/src/test/java/org/pitest/sequence/ContextTest.java @@ -1,16 +1,76 @@ package org.pitest.sequence; -import nl.jqno.equalsverifier.EqualsVerifier; import org.junit.Test; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + public class ContextTest { @Test - public void obeysHashCodeEqualsContract() { - EqualsVerifier.forClass(Context.class) - .withNonnullFields("slots") - .withIgnoredFields("debug") - .verify(); + public void retrieveIsStartsEmpty() { + SlotRead slot = Slot.create(Integer.class).read(); + assertThat(Context.start().retrieve(slot)).isEmpty(); + } + + @Test + public void canStoreThenRetrieve() { + SlotRead slot = Slot.create(Integer.class).read(); + Context underTest = Context.start().store(slot.slot().write(), 42); + + Optional actual = underTest.retrieve(slot); + assertThat(actual).contains(42); + } + + @Test + public void canStoreAndRetrieveTwoValues() { + Slot slot1 = Slot.create(Integer.class); + Slot slot2 = Slot.create(Integer.class); + Context underTest = Context.start() + .store(slot1.write(), 42) + .store(slot2.write(), 101); + + assertThat(underTest.retrieve(slot1.read())).contains(42); + assertThat(underTest.retrieve(slot2.read())).contains(101); + } + + @Test + public void canStoreAndRetrieveThreeValues() { + Slot slot1 = Slot.create(Integer.class); + Slot slot2 = Slot.create(Integer.class); + Slot slot3 = Slot.create(Integer.class); + Context underTest = Context.start() + .store(slot1.write(), 42) + .store(slot2.write(), 101) + .store(slot3.write(), 8); + + assertThat(underTest.retrieve(slot1.read())).contains(42); + assertThat(underTest.retrieve(slot2.read())).contains(101); + assertThat(underTest.retrieve(slot3.read())).contains(8); + } + + @Test + public void canStoreAndRetrieveMultipleValues() { + Slot slot1 = Slot.create(Integer.class); + Slot slot2 = Slot.create(Integer.class); + Slot slot3 = Slot.create(Integer.class); + Slot slot4 = Slot.create(Integer.class); + Slot slot5 = Slot.create(Integer.class); + Context underTest = Context.start() + .store(slot1.write(), 1) + .store(slot2.write(), 2) + .store(slot3.write(), 3) + .store(slot4.write(), 4) + .store(slot5.write(), 5); + + + assertThat(underTest.retrieve(slot1.read())).contains(1); + assertThat(underTest.retrieve(slot2.read())).contains(2); + assertThat(underTest.retrieve(slot3.read())).contains(3); + assertThat(underTest.retrieve(slot4.read())).contains(4); + assertThat(underTest.retrieve(slot5.read())).contains(5); } + } \ No newline at end of file diff --git a/pitest-entry/src/test/java/org/pitest/sequence/MultiContextTest.java b/pitest-entry/src/test/java/org/pitest/sequence/MultiContextTest.java new file mode 100644 index 000000000..a474bef31 --- /dev/null +++ b/pitest-entry/src/test/java/org/pitest/sequence/MultiContextTest.java @@ -0,0 +1,16 @@ +package org.pitest.sequence; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.Test; + +public class MultiContextTest { + + @Test + public void obeysHashCodeEqualsContract() { + EqualsVerifier.forClass(MultiContext.class) + .withNonnullFields("slots") + .withIgnoredFields("debug") + .verify(); + } + +} \ No newline at end of file