diff --git a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/CollectorKind.java b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/CollectorKind.java new file mode 100644 index 00000000..5936bcc9 --- /dev/null +++ b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/CollectorKind.java @@ -0,0 +1,6 @@ +package edu.cuny.hunter.streamrefactoring.core.analysis; + +public enum CollectorKind { + CONCURRENT, + NONCONCURRENT +} \ No newline at end of file diff --git a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/PreconditionSuccess.java b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/PreconditionSuccess.java index 00619e50..561f4801 100644 --- a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/PreconditionSuccess.java +++ b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/PreconditionSuccess.java @@ -5,5 +5,13 @@ public enum PreconditionSuccess { P2, P3, P4, - P5 + P5, + P6, + P7, + P8, + P9, + P10, + P11, + P12, + P13 } diff --git a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Refactoring.java b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Refactoring.java index 892152c6..e5de7b5e 100644 --- a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Refactoring.java +++ b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Refactoring.java @@ -7,5 +7,6 @@ */ public enum Refactoring { CONVERT_SEQUENTIAL_STREAM_TO_PARALLEL, - OPTIMIZE_PARALLEL_STREAM + OPTIMIZE_PARALLEL_STREAM, + OPTIMIZE_COMPLEX_MUTABLE_REDUCTION } diff --git a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Stream.java b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Stream.java index c593e790..8400decd 100644 --- a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Stream.java +++ b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Stream.java @@ -101,6 +101,8 @@ public class Stream { private IR enclosingMethodDeclarationIR; private final TypeDeclaration enclosingTypeDeclaration; + + private CollectorKind collectorKind; private boolean hasNoTerminalOperation; @@ -508,6 +510,10 @@ public Set getPossibleOrderings() { return this.possibleOrderings.stream().map(e -> e == null ? initialOrdering : e).collect(Collectors.toSet()); } + public CollectorKind getCollectorKind() { + return this.collectorKind; + } + public Refactoring getRefactoring() { return this.refactoring; } @@ -707,6 +713,10 @@ protected void setInitialOrdering(Ordering initialOrdering) { Objects.requireNonNull(initialOrdering); this.initialOrdering = initialOrdering; } + + protected void setCollectorKind(CollectorKind collectorKind) { + this.collectorKind = collectorKind; + } private void setPassingPrecondition(PreconditionSuccess succcess) { if (this.passingPrecondition == null) diff --git a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/StreamStateMachine.java b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/StreamStateMachine.java index bdd0a69d..7284a6cf 100644 --- a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/StreamStateMachine.java +++ b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/StreamStateMachine.java @@ -58,6 +58,7 @@ import com.ibm.wala.ipa.callgraph.propagation.NormalAllocationInNode; import com.ibm.wala.ipa.callgraph.propagation.PointerKey; import com.ibm.wala.ipa.cfg.BasicBlockInContext; +import com.ibm.wala.ipa.cha.ClassHierarchy; import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.ipa.modref.ModRef; import com.ibm.wala.shrikeCT.InvalidClassFileException; @@ -209,8 +210,17 @@ protected static StreamAttributeTypestateRule[] createStreamAttributeTypestateRu // @formatter:on } - private static boolean deriveRomForScalarMethod(SSAInvokeInstruction invokeInstruction) + private static boolean deriveRomForScalarMethod(Collection possibleReturnTypes, + SSAInvokeInstruction invokeInstruction, IClassHierarchy hierarchy) throws UnknownIfReduceOrderMattersException { + boolean allImplementMap = possibleReturnTypes.stream().map(TypeAbstraction::getTypeReference) + .allMatch(t -> Util.implementsMap(t, hierarchy)); + + if (allImplementMap) { + // TODO: we should be the complex mutable reduction case #64. Note that it may + // not be a call to collect(). It could be a call to reduce(). + } + MethodReference declaredTarget = invokeInstruction.getCallSite().getDeclaredTarget(); if (isTerminalOperationWhereReduceOrderMattersIsUnknown(declaredTarget)) @@ -553,7 +563,7 @@ private boolean deriveRomForNonScalarMethod(Collection possible // default to ordered. ordering = Ordering.ORDERED; LOGGER.warning("Can't determine ordering for possible return types: " + possibleReturnTypes - + ". Defaulting to: " + ordering); + + ". Defaulting to: " + ordering + "."); } switch (ordering) { @@ -606,7 +616,8 @@ private void discoverIfReduceOrderingPossiblyMatters(EclipseProjectAnalysisEngin else { boolean scalar = Util.isScalar(possibleReturnTypes); if (scalar) - rom = deriveRomForScalarMethod(invokeInstruction); + rom = deriveRomForScalarMethod(possibleReturnTypes, invokeInstruction, + engine.getClassHierarchy()); else // !scalar rom = this.deriveRomForNonScalarMethod(possibleReturnTypes, orderingInference); } diff --git a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/TransformationAction.java b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/TransformationAction.java index b126de5d..03e9bfe5 100644 --- a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/TransformationAction.java +++ b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/TransformationAction.java @@ -3,6 +3,7 @@ public enum TransformationAction { CONVERT_TO_PARALLEL, UNORDER, - CONVERT_TO_SEQUENTIAL - + CONVERT_TO_SEQUENTIAL, + CONVERT_COLLECTOR_TO_CONCURRENT, + CONVERT_COLLECTOR_TO_NON_CONCURRENT } diff --git a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Util.java b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Util.java index 7eddf3b1..cfeaf1d6 100644 --- a/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Util.java +++ b/edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Util.java @@ -576,6 +576,10 @@ public static boolean implementsIterable(TypeReference reference, IClassHierarch return implementsType(reference, classHierarchy, Util::isIterable); } + public static boolean implementsMap(TypeReference reference, IClassHierarchy hierarchy) { + return implementsType(reference, hierarchy, Util::isMap); + } + public static boolean implementsType(TypeReference typeReference, IClassHierarchy classHierarchy, Predicate predicate) { IClass clazz = classHierarchy.lookupClass(typeReference); @@ -618,6 +622,10 @@ public static boolean isCollector(IClass clazz) { return Util.isType(clazz, "java/util/stream", "Collector"); } + public static boolean isMap(IClass clazz) { + return Util.isType(clazz, "java/util", "Map"); + } + /** * check whether the annotation is "EntryPoint" */ @@ -655,8 +663,7 @@ else if (typeReference.isPrimitiveType()) return true; else if (typeReference.isReferenceType()) { IClass type = typeAbstraction.getType(); - return !edu.cuny.hunter.streamrefactoring.core.analysis.Util.isIterable(type) - && type.getAllImplementedInterfaces().stream().noneMatch(Util::isIterable); + return !isIterable(type) && type.getAllImplementedInterfaces().stream().noneMatch(Util::isIterable); } else throw new IllegalArgumentException("Can't tell if type is scalar: " + typeAbstraction); } diff --git a/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction/in/A.java b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction/in/A.java new file mode 100644 index 00000000..942fe5d1 --- /dev/null +++ b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction/in/A.java @@ -0,0 +1,43 @@ +package p; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ConcurrentNavigableMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.stream.Collectors; +import java.util.Set; + +import edu.cuny.hunter.streamrefactoring.annotations.EntryPoint; + +import p.A.Widget.Color; + +public class A { + + static class Widget { + enum Color { + RED, + BLUE, + GREEN, + PINK, + ORANGE, + YELLOW + }; + + public Color getColor() { + return this.getColor(); + } + } + + @EntryPoint + void m() { + Collection orderedWidgets = new ArrayList<>(); + + Map> widgetsByColor = orderedWidgets.parallelStream() + .collect(Collectors.groupingBy(Widget::getColor)); + } +} diff --git a/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction1/in/A.java b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction1/in/A.java new file mode 100644 index 00000000..7e15e8db --- /dev/null +++ b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction1/in/A.java @@ -0,0 +1,38 @@ +package p; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import edu.cuny.hunter.streamrefactoring.annotations.*; +import p.A.Widget.Color; + +public class A { + + static class Widget { + enum Color { + RED, + BLUE, + GREEN, + PINK, + ORANGE, + YELLOW + }; + + public Color getColor() { + return this.getColor(); + } + } + + @EntryPoint + void m() { + // an "unordered" collection of widgets. + Collection unorderedWidgets = new HashSet<>(); + // populate the collection ... + + Map> widgetsByColor = unorderedWidgets.stream() + .collect(Collectors.groupingBy(Widget::getColor)); + } +} diff --git a/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction2/in/A.java b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction2/in/A.java new file mode 100644 index 00000000..3da86cb6 --- /dev/null +++ b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction2/in/A.java @@ -0,0 +1,37 @@ +package p; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.stream.Collectors; + +import edu.cuny.hunter.streamrefactoring.annotations.*; +import p.A.Widget.Color; + +public class A { + + static class Widget { + enum Color { + RED, + BLUE, + GREEN, + PINK, + ORANGE, + YELLOW + }; + + public Color getColor() { + return this.getColor(); + } + } + + @EntryPoint + void m() { + Collection orderedWidgets = new ArrayList<>(); + + Map> widgetsByColor2 = orderedWidgets.stream() + .collect(Collectors.groupingBy(Widget::getColor, HashMap::new, Collectors.toSet())); + } +} diff --git a/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction3/in/A.java b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction3/in/A.java new file mode 100644 index 00000000..90afad7c --- /dev/null +++ b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction3/in/A.java @@ -0,0 +1,34 @@ +package p; + +import java.util.*; +import java.util.stream.*; +import java.util.concurrent.*; + +import edu.cuny.hunter.streamrefactoring.annotations.*; +import p.A.Widget.Color; + +public class A { + + static class Widget { + enum Color { + RED, + BLUE, + GREEN, + PINK, + ORANGE, + YELLOW + }; + + public Color getColor() { + return this.getColor(); + } + } + + @EntryPoint + void m() { + Collection orderedWidgets = new ArrayList<>(); + + Map> widgetsByColor2 = orderedWidgets.stream().collect(Collectors.groupingByConcurrent( + Widget::getColor, ConcurrentHashMap::new, Collectors.toCollection(LinkedHashSet::new))); + } +} diff --git a/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction4/in/A.java b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction4/in/A.java new file mode 100644 index 00000000..b9d47447 --- /dev/null +++ b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction4/in/A.java @@ -0,0 +1,35 @@ +package p; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +import edu.cuny.hunter.streamrefactoring.annotations.*; +import p.A.Widget.Color; + +public class A { + + static class Widget { + enum Color { + RED, BLUE, GREEN, PINK, ORANGE, YELLOW + }; + + public Color getColor() { + return this.getColor(); + } + } + + /** + * P10 in table 3 + */ + @EntryPoint + void m() { + Collection orderedWidgets = new ArrayList<>(); + Map> widgetsByColor = orderedWidgets.stream().collect(Collectors.groupingByConcurrent( + Widget::getColor, ConcurrentHashMap::new, Collectors.toCollection(LinkedHashSet::new))); + } +} diff --git a/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction5/in/A.java b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction5/in/A.java new file mode 100644 index 00000000..a9b8128b --- /dev/null +++ b/edu.cuny.hunter.streamrefactoring.tests/resources/ConvertStreamToParallel/testConcurrentReduction5/in/A.java @@ -0,0 +1,34 @@ +package p; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import edu.cuny.hunter.streamrefactoring.annotations.*; +import p.A.Widget.Color; + +public class A { + + static class Widget { + enum Color { + RED, BLUE, GREEN, PINK, ORANGE, YELLOW + }; + + public Color getColor() { + return this.getColor(); + } + } + + /** + * P11 in table 3 + */ + @EntryPoint + void m() { + Collection orderedWidgets = new ArrayList<>(); + Map> widgetsByColor = orderedWidgets.parallelStream() + .collect(Collectors.groupingBy(Widget::getColor, HashMap::new, Collectors.toSet())); + } +} diff --git a/edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/ConvertStreamToParallelRefactoringTest.java b/edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/ConvertStreamToParallelRefactoringTest.java index a444442e..25517ebb 100644 --- a/edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/ConvertStreamToParallelRefactoringTest.java +++ b/edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/ConvertStreamToParallelRefactoringTest.java @@ -7,7 +7,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; -import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; @@ -37,6 +36,7 @@ import org.eclipse.jdt.ui.tests.refactoring.RefactoringTest; import org.eclipse.ltk.core.refactoring.RefactoringStatus; +import edu.cuny.hunter.streamrefactoring.core.analysis.CollectorKind; import edu.cuny.hunter.streamrefactoring.core.analysis.ExecutionMode; import edu.cuny.hunter.streamrefactoring.core.analysis.Ordering; import edu.cuny.hunter.streamrefactoring.core.analysis.PreconditionFailure; @@ -142,10 +142,6 @@ public static ICompilationUnit createCU(IPackageFragment pack, String name, Stri return cu; } - private static String errorMessage(String attribute, StreamAnalysisExpectedResult result) { - return "Unexpected " + attribute + " for " + result.getExpectedCreation() + "."; - } - private static Path getAbsolutePath(String fileName) { Path path = Paths.get(RESOURCE_PATH, fileName); Path absolutePath = path.toAbsolutePath(); @@ -359,35 +355,7 @@ private void helper(int nToUseForStreams, StreamAnalysisExpectedResult... expect expectingStreams.size()); Stream stream = expectingStreams.get(0); - - Set executionModes = stream.getPossibleExecutionModes(); - assertEquals(errorMessage("execution mode", result), result.getExpectedExecutionModes(), executionModes); - - Set orderings = stream.getPossibleOrderings(); - assertEquals(errorMessage("orderings", result), result.getExpectedOrderings(), orderings); - - assertEquals(errorMessage("side effects", result), result.isExpectingSideEffects(), - stream.hasPossibleSideEffects()); - assertEquals(errorMessage("stateful intermediate operations", result), - result.isExpectingStatefulIntermediateOperation(), - stream.hasPossibleStatefulIntermediateOperations()); - assertEquals(errorMessage("ROM", result), result.isExpectingThatReduceOrderingMatters(), - stream.reduceOrderingPossiblyMatters()); - assertEquals(errorMessage("transformation actions", result), result.getExpectedActions(), - stream.getActions()); - assertEquals(errorMessage("passing precondition", result), result.getExpectedPassingPrecondition(), - stream.getPassingPrecondition()); - assertEquals(errorMessage("refactoring", result), result.getExpectedRefactoring(), stream.getRefactoring()); - assertEquals(errorMessage("status severity", result), result.getExpectedStatusSeverity(), - stream.getStatus().getSeverity()); - - Set actualCodes = Arrays.stream(stream.getStatus().getEntries()).map(e -> e.getCode()) - .collect(Collectors.toSet()); - - Set expectedCodes = result.getExpectedFailures().stream().map(e -> e.getCode()) - .collect(Collectors.toSet()); - - assertEquals(errorMessage("status codes", result), expectedCodes, actualCodes); + result.evaluate(stream); } } @@ -541,6 +509,77 @@ public void testConcat() throws Exception { RefactoringStatus.ERROR, Collections.singleton(PreconditionFailure.CURRENTLY_NOT_HANDLED))); } + /** + * Test #64. + */ + public void testConcurrentReduction() throws Exception { + this.helper(new StreamAnalysisExpectedResultWithCollectorKind("orderedWidgets.parallelStream()", + EnumSet.of(ExecutionMode.PARALLEL), EnumSet.of(Ordering.ORDERED), CollectorKind.NONCONCURRENT, false, + false, true, EnumSet.of(TransformationAction.CONVERT_TO_SEQUENTIAL), PreconditionSuccess.P7, + Refactoring.OPTIMIZE_COMPLEX_MUTABLE_REDUCTION, RefactoringStatus.OK, Collections.emptySet())); + } + + /** + * Test #64. + */ + public void testConcurrentReduction1() throws Exception { + this.helper(new StreamAnalysisExpectedResultWithCollectorKind("unorderedWidgets.stream()", + EnumSet.of(ExecutionMode.SEQUENTIAL), EnumSet.of(Ordering.UNORDERED), CollectorKind.NONCONCURRENT, + false, false, true, + EnumSet.of(TransformationAction.CONVERT_TO_PARALLEL, + TransformationAction.CONVERT_COLLECTOR_TO_CONCURRENT), + PreconditionSuccess.P12, Refactoring.OPTIMIZE_COMPLEX_MUTABLE_REDUCTION, RefactoringStatus.OK, + Collections.emptySet())); + } + + /** + * Test #64. + */ + public void testConcurrentReduction2() throws Exception { + this.helper(new StreamAnalysisExpectedResultWithCollectorKind("orderedWidgets.stream()", + EnumSet.of(ExecutionMode.SEQUENTIAL), EnumSet.of(Ordering.ORDERED), CollectorKind.NONCONCURRENT, false, + false, false, + EnumSet.of(TransformationAction.CONVERT_TO_PARALLEL, + TransformationAction.CONVERT_COLLECTOR_TO_CONCURRENT), + PreconditionSuccess.P9, Refactoring.OPTIMIZE_COMPLEX_MUTABLE_REDUCTION, RefactoringStatus.OK, + Collections.emptySet())); + } + + /** + * Test #64. + */ + public void testConcurrentReduction3() throws Exception { + this.helper(new StreamAnalysisExpectedResultWithCollectorKind("orderedWidgets.stream()", + EnumSet.of(ExecutionMode.SEQUENTIAL), EnumSet.of(Ordering.ORDERED), CollectorKind.CONCURRENT, false, + false, true, EnumSet.of(TransformationAction.CONVERT_COLLECTOR_TO_NON_CONCURRENT), + PreconditionSuccess.P6, Refactoring.OPTIMIZE_COMPLEX_MUTABLE_REDUCTION, RefactoringStatus.OK, + Collections.emptySet())); + } + + /** + * TODO: Test #64. + */ + // @formatter:off +// public void testConcurrentReduction4() throws Exception { +// this.helper(new StreamAnalysisExpectedResultWithCollectorKind("orderedWidgets.stream()", +// EnumSet.of(ExecutionMode.SEQUENTIAL), EnumSet.of(Ordering.ORDERED), CollectorKind.CONCURRENT, false, +// false, false, EnumSet.of(TransformationAction.CONVERT_TO_PARALLEL), PreconditionSuccess.P10, +// Refactoring.OPTIMIZE_COMPLEX_MUTABLE_REDUCTION, RefactoringStatus.OK, Collections.emptySet())); +// } + // @formatter:on + + /** + * TODO: Test #64. + */ + // @formatter:off +// public void testConcurrentReduction5() throws Exception { +// this.helper(new StreamAnalysisExpectedResultWithCollectorKind("orderedWidgets.stream()", +// EnumSet.of(ExecutionMode.PARALLEL), EnumSet.of(Ordering.ORDERED), CollectorKind.NONCONCURRENT, false, +// false, false, EnumSet.of(TransformationAction.CONVERT_COLLECTOR_TO_CONCURRENT), PreconditionSuccess.P11, +// Refactoring.OPTIMIZE_COMPLEX_MUTABLE_REDUCTION, RefactoringStatus.OK, Collections.emptySet())); +// } + // @formatter:on + public void testConstructor() throws Exception { this.helper(new StreamAnalysisExpectedResult("new ArrayList().stream()", Collections.singleton(ExecutionMode.SEQUENTIAL), EnumSet.of(Ordering.ORDERED), false, false, false, diff --git a/edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/StreamAnalysisExpectedResult.java b/edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/StreamAnalysisExpectedResult.java index eba7b220..12429f29 100644 --- a/edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/StreamAnalysisExpectedResult.java +++ b/edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/StreamAnalysisExpectedResult.java @@ -1,12 +1,17 @@ package edu.cuny.hunter.streamrefactoring.ui.tests; +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; import java.util.Set; +import java.util.stream.Collectors; import edu.cuny.hunter.streamrefactoring.core.analysis.ExecutionMode; import edu.cuny.hunter.streamrefactoring.core.analysis.Ordering; import edu.cuny.hunter.streamrefactoring.core.analysis.PreconditionFailure; import edu.cuny.hunter.streamrefactoring.core.analysis.PreconditionSuccess; import edu.cuny.hunter.streamrefactoring.core.analysis.Refactoring; +import edu.cuny.hunter.streamrefactoring.core.analysis.Stream; import edu.cuny.hunter.streamrefactoring.core.analysis.TransformationAction; class StreamAnalysisExpectedResult { @@ -50,6 +55,38 @@ public StreamAnalysisExpectedResult(String expectedCreation, Set this.expectedFailures = expectedFailures; } + protected String errorMessage(String attribute) { + return "Unexpected " + attribute + " for " + this.getExpectedCreation() + "."; + } + + public void evaluate(Stream stream) { + Set executionModes = stream.getPossibleExecutionModes(); + assertEquals(this.errorMessage("execution mode"), this.getExpectedExecutionModes(), executionModes); + + Set orderings = stream.getPossibleOrderings(); + assertEquals(this.errorMessage("orderings"), this.getExpectedOrderings(), orderings); + + assertEquals(this.errorMessage("side effects"), this.isExpectingSideEffects(), stream.hasPossibleSideEffects()); + assertEquals(this.errorMessage("stateful intermediate operations"), + this.isExpectingStatefulIntermediateOperation(), stream.hasPossibleStatefulIntermediateOperations()); + assertEquals(this.errorMessage("ROM"), this.isExpectingThatReduceOrderingMatters(), + stream.reduceOrderingPossiblyMatters()); + assertEquals(this.errorMessage("transformation actions"), this.getExpectedActions(), stream.getActions()); + assertEquals(this.errorMessage("passing precondition"), this.getExpectedPassingPrecondition(), + stream.getPassingPrecondition()); + assertEquals(this.errorMessage("refactoring"), this.getExpectedRefactoring(), stream.getRefactoring()); + assertEquals(this.errorMessage("status severity"), this.getExpectedStatusSeverity(), + stream.getStatus().getSeverity()); + + Set actualCodes = Arrays.stream(stream.getStatus().getEntries()).map(e -> e.getCode()) + .collect(Collectors.toSet()); + + Set expectedCodes = this.getExpectedFailures().stream().map(e -> e.getCode()) + .collect(Collectors.toSet()); + + assertEquals(this.errorMessage("status codes"), expectedCodes, actualCodes); + } + public Set getExpectedActions() { return this.expectedActions; } diff --git a/edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/StreamAnalysisExpectedResultWithCollectorKind.java b/edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/StreamAnalysisExpectedResultWithCollectorKind.java new file mode 100644 index 00000000..3f712af0 --- /dev/null +++ b/edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/StreamAnalysisExpectedResultWithCollectorKind.java @@ -0,0 +1,43 @@ +package edu.cuny.hunter.streamrefactoring.ui.tests; + +import static org.junit.Assert.assertEquals; + +import java.util.Set; + +import edu.cuny.hunter.streamrefactoring.core.analysis.CollectorKind; +import edu.cuny.hunter.streamrefactoring.core.analysis.ExecutionMode; +import edu.cuny.hunter.streamrefactoring.core.analysis.Ordering; +import edu.cuny.hunter.streamrefactoring.core.analysis.PreconditionFailure; +import edu.cuny.hunter.streamrefactoring.core.analysis.PreconditionSuccess; +import edu.cuny.hunter.streamrefactoring.core.analysis.Refactoring; +import edu.cuny.hunter.streamrefactoring.core.analysis.Stream; +import edu.cuny.hunter.streamrefactoring.core.analysis.TransformationAction; + +public class StreamAnalysisExpectedResultWithCollectorKind extends StreamAnalysisExpectedResult { + + private CollectorKind expectedCollectorKind; + + public StreamAnalysisExpectedResultWithCollectorKind(String expectedCreation, + Set expectedExecutionModes, Set expectedOrderings, + CollectorKind expectedCollectorKind, boolean expectingSideEffects, + boolean expectingStatefulIntermediateOperation, boolean expectingThatReduceOrderingMatters, + Set expectedActions, PreconditionSuccess expectedPassingPrecondition, + Refactoring expectedRefactoring, int expectedStatusSeverity, Set expectedFailures) { + super(expectedCreation, expectedExecutionModes, expectedOrderings, expectingSideEffects, + expectingStatefulIntermediateOperation, expectingThatReduceOrderingMatters, expectedActions, + expectedPassingPrecondition, expectedRefactoring, expectedStatusSeverity, expectedFailures); + this.expectedCollectorKind = expectedCollectorKind; + } + + @Override + public void evaluate(Stream stream) { + super.evaluate(stream); + + CollectorKind collectorKind = stream.getCollectorKind(); + assertEquals(this.errorMessage("collector kind"), this.getExpectedCollectorKind(), collectorKind); + } + + public CollectorKind getExpectedCollectorKind() { + return this.expectedCollectorKind; + } +}