diff --git a/src/main/java/gr/uom/java/xmi/decomposition/UMLOperationBodyMapper.java b/src/main/java/gr/uom/java/xmi/decomposition/UMLOperationBodyMapper.java index 36ebdd250..b3ec14a09 100644 --- a/src/main/java/gr/uom/java/xmi/decomposition/UMLOperationBodyMapper.java +++ b/src/main/java/gr/uom/java/xmi/decomposition/UMLOperationBodyMapper.java @@ -20,6 +20,8 @@ import static gr.uom.java.xmi.decomposition.ReplacementAlgorithm.streamAPIName; import static gr.uom.java.xmi.decomposition.StringBasedHeuristics.*; import static gr.uom.java.xmi.decomposition.Visitor.stringify; +import static gr.uom.java.xmi.diff.UMLClassBaseDiff.getParameterValues; +import static gr.uom.java.xmi.diff.UMLClassBaseDiff.matchParamsWithReplacements; import gr.uom.java.xmi.decomposition.replacement.CompositeReplacement; import gr.uom.java.xmi.decomposition.replacement.IntersectionReplacement; @@ -113,6 +115,7 @@ public class UMLOperationBodyMapper implements Comparable addedVariables; private Set> movedVariables; private int callsToExtractedMethod = 0; + private List> internalParameterizeTestMultiMappings = new ArrayList>(); private boolean nested; private boolean lambdaBodyMapper; private AbstractCall operationInvocation; @@ -3726,6 +3729,50 @@ public Set getReplacements() { return replacements; } + public List> getInternalParameterizeTestMultiMappings() { + return internalParameterizeTestMultiMappings; + } + + public int countMappingsForInternalParameterizedTest() { + if(this.internalParameterizeTestMultiMappings.size() > 0) { + int count = 0; + Set processedMappings = new LinkedHashSet(); + for(Set set : internalParameterizeTestMultiMappings) { + count++; + processedMappings.addAll(set); + } + for(AbstractCodeMapping mapping : getMappings()) { + if(!processedMappings.contains(mapping)) { + count++; + } + } + return count; + } + return getMappings().size(); + } + + public int countReplacementsForInternalParameterizedTest() { + if(this.internalParameterizeTestMultiMappings.size() > 0) { + int count = 0; + Set processedMappings = new LinkedHashSet(); + for(Set set : internalParameterizeTestMultiMappings) { + int localCount = 0; + for(AbstractCodeMapping mapping : set) { + localCount += mapping.getReplacements().size(); + } + count += localCount/set.size(); + processedMappings.addAll(set); + } + for(AbstractCodeMapping mapping : getMappings()) { + if(!processedMappings.contains(mapping)) { + count += mapping.getReplacements().size(); + } + } + return count; + } + return getReplacements().size(); + } + public Set getReplacementsOfType(ReplacementType type) { Set replacements = new LinkedHashSet(); for(AbstractCodeMapping mapping : getMappings()) { @@ -6247,6 +6294,16 @@ else if((catchBlockMap = allMappingsNestedUnderCatchBlocks(mappingSet)) != null) leafIterator2.remove(); checkForMatchingMergedVariableDeclaration(leaf2, leaves1, parameterToArgumentMap, equalNumberOfAssertions); } + else if(internalParameterizeTest(mappingSet) && mappingSet.size() > 1) { + Set multiMappings = new LinkedHashSet(); + for(AbstractCodeMapping mapping : mappingSet) { + multiMappings.add(mapping); + addToMappings((LeafMapping) mapping, mappingSet); + leaves1.remove(mapping.getFragment1()); + } + this.internalParameterizeTestMultiMappings.add(multiMappings); + leafIterator2.remove(); + } else { if(!duplicateMappingInParentMapper(mappingSet)) { AbstractCodeMapping alreadyMatched = null; @@ -6331,6 +6388,23 @@ else if(existingMappingWithCommonParents(variableDeclarationMapping)) { } } + private boolean internalParameterizeTest(Set mappingSet) { + if(container2.hasParameterizedTestAnnotation() && !container1.hasParameterizedTestAnnotation()) { + List parameterNames = container2.getParameterNameList(); + List> parameterValues = getParameterValues((UMLOperation)container2, modelDiff); + Set replacements = new LinkedHashSet(); + for(AbstractCodeMapping mapping : mappingSet) { + replacements.addAll(mapping.getReplacements()); + } + Map matchingTestParameters = matchParamsWithReplacements(parameterValues, parameterNames, replacements); + int max = matchingTestParameters.isEmpty() ? 0 : Collections.max(matchingTestParameters.values()); + if(max >= 1) { + return true; + } + } + return false; + } + private boolean nestedDirectlyUnderMethodBody(AbstractCodeMapping mapping) { AbstractCodeFragment f1 = mapping.getFragment1(); AbstractCodeFragment f2 = mapping.getFragment2(); diff --git a/src/main/java/gr/uom/java/xmi/diff/UMLClassBaseDiff.java b/src/main/java/gr/uom/java/xmi/diff/UMLClassBaseDiff.java index 56487e1f3..a9a025212 100644 --- a/src/main/java/gr/uom/java/xmi/diff/UMLClassBaseDiff.java +++ b/src/main/java/gr/uom/java/xmi/diff/UMLClassBaseDiff.java @@ -1310,10 +1310,15 @@ else if(removedOperation.hasTestAnnotation() && addedOperation.hasParameterizedT if(!matchingMergeCandidateFound && !matchingSplitCandidateFound) { if(addedOperation.hasParameterizedTestAnnotation() && !firstMapper.getContainer1().hasParameterizedTestAnnotation()) { Set filteredMapperSet = new LinkedHashSet(); - List> parameterValues = getParameterValues(addedOperation); + List> parameterValues = getParameterValues(addedOperation, modelDiff); List parameterNames = addedOperation.getParameterNameList(); int overallMaxMatchingTestParameters = -1; + Map overallMatchingTestParameters = new LinkedHashMap(); + boolean internalParameterizeTest = false; for(UMLOperationBodyMapper mapper : mapperSet) { + if(mapper.getInternalParameterizeTestMultiMappings().size() > 0) { + internalParameterizeTest = true; + } Map matchingTestParameters = matchParamsWithReplacements(parameterValues, parameterNames, mapper.getReplacements()); if (matchingTestParameters.isEmpty()) { matchingTestParameters = matchParamsWithRemovedStatements(parameterValues, parameterNames, mapper.getNonMappedLeavesT1()); @@ -1323,7 +1328,16 @@ else if(removedOperation.hasTestAnnotation() && addedOperation.hasParameterizedT if(max > overallMaxMatchingTestParameters) { overallMaxMatchingTestParameters = max; } - filteredMapperSet.add(mapper); + int sizeBefore = overallMatchingTestParameters.size(); + overallMatchingTestParameters.putAll(matchingTestParameters); + if(internalParameterizeTest) { + if(overallMatchingTestParameters.size() > sizeBefore) { + filteredMapperSet.add(mapper); + } + } + else { + filteredMapperSet.add(mapper); + } } } //cluster mappers based on number of mappings and number of total replacements @@ -1331,11 +1345,11 @@ else if(removedOperation.hasTestAnnotation() && addedOperation.hasParameterizedT int maxMappings = -1; int minReplacements = Integer.MAX_VALUE; for(UMLOperationBodyMapper mapper : filteredMapperSet) { - int mappings = mapper.getMappings().size(); + int mappings = mapper.countMappingsForInternalParameterizedTest(); if(mappings > maxMappings) { maxMappings = mappings; } - int replacements = mapper.getReplacements().size(); + int replacements = mapper.countReplacementsForInternalParameterizedTest(); if(replacements < minReplacements) { minReplacements = replacements; } @@ -1512,7 +1526,7 @@ private boolean isPerfectMapper(UMLOperationBodyMapper mapper) { return mapper.getMappings().size() > 0 && nonMappedLeavesT1 <= 0 && nonMappedLeavesT2 <= 0 && nonMappedInnerNodesT1 == 0 && nonMappedInnerNodesT2 == 0; } - private List> getParameterValues(UMLOperation addedOperation) { + public static List> getParameterValues(UMLOperation addedOperation, UMLModelDiff modelDiff) { List> parameterValues = new ArrayList<>(); for(UMLAnnotation annotation : addedOperation.getAnnotations()) { try { @@ -1545,7 +1559,7 @@ private Map matchParamsWithRemovedStatements(List return matchingTestParameters; } - private static Map matchParamsWithReplacements(List> testParameters, List parameterNames, Set replacements) { + public static Map matchParamsWithReplacements(List> testParameters, List parameterNames, Set replacements) { Map matchingTestParameters = new LinkedHashMap<>(); for(Replacement r : replacements) { if(parameterNames.contains(r.getAfter())) { diff --git a/src/test/java/org/refactoringminer/test/TestStatementMappings.java b/src/test/java/org/refactoringminer/test/TestStatementMappings.java index ab9b6d9b3..0d0651ad1 100644 --- a/src/test/java/org/refactoringminer/test/TestStatementMappings.java +++ b/src/test/java/org/refactoringminer/test/TestStatementMappings.java @@ -962,6 +962,31 @@ public void testParameterizedTestMappings() throws Exception { Assertions.assertTrue(expected.size() == actual.size() && expected.containsAll(actual) && actual.containsAll(expected)); } + @Test + public void testParameterizedTestMappings4() throws Exception { + final List actual = new ArrayList<>(); + Map fileContentsBefore = new LinkedHashMap(); + Map fileContentsCurrent = new LinkedHashMap(); + String contentsV1 = FileUtils.readFileToString(new File(EXPECTED_PATH + "FileNameCleanerTest-v1.txt")); + String contentsV2 = FileUtils.readFileToString(new File(EXPECTED_PATH + "FileNameCleanerTest-v2.txt")); + fileContentsBefore.put("src/test/java/org/jabref/logic/util/FileNameCleanerTest.java", contentsV1); + fileContentsCurrent.put("src/test/java/org/jabref/logic/util/FileNameCleanerTest.java", contentsV2); + UMLModel parentUMLModel = GitHistoryRefactoringMinerImpl.createModel(fileContentsBefore, new LinkedHashSet()); + UMLModel currentUMLModel = GitHistoryRefactoringMinerImpl.createModel(fileContentsCurrent, new LinkedHashSet()); + + UMLModelDiff modelDiff = parentUMLModel.diff(currentUMLModel); + List refactorings = modelDiff.getRefactorings(); + for(Refactoring r : refactorings) { + if(r instanceof ParameterizeTestRefactoring) { + ParameterizeTestRefactoring parameterizeTest = (ParameterizeTestRefactoring)r; + UMLOperationBodyMapper mapper = parameterizeTest.getBodyMapper(); + mapperInfo(mapper, actual); + } + } + List expected = IOUtils.readLines(new FileReader(EXPECTED_PATH + "jabRef-FileNameCleanerTest.txt")); + Assertions.assertTrue(expected.size() == actual.size() && expected.containsAll(actual) && actual.containsAll(expected)); + } + @ParameterizedTest @CsvSource({ "https://github.com/apache/camel.git, b57b72d0e85f2340cb2d55be44d2175c0caa7cc1, camel-b57b72d0e85f2340cb2d55be44d2175c0caa7cc1.txt", diff --git a/src/test/java/org/refactoringminer/test/TestStatementMappingsJunit4.java b/src/test/java/org/refactoringminer/test/TestStatementMappingsJunit4.java index d48d2fbdc..0cc15a80b 100644 --- a/src/test/java/org/refactoringminer/test/TestStatementMappingsJunit4.java +++ b/src/test/java/org/refactoringminer/test/TestStatementMappingsJunit4.java @@ -1874,6 +1874,31 @@ public void testParameterizedTestMappings() throws Exception { Assert.assertTrue(expected.size() == actual.size() && expected.containsAll(actual) && actual.containsAll(expected)); } + @Test + public void testParameterizedTestMappings4() throws Exception { + final List actual = new ArrayList<>(); + Map fileContentsBefore = new LinkedHashMap(); + Map fileContentsCurrent = new LinkedHashMap(); + String contentsV1 = FileUtils.readFileToString(new File(EXPECTED_PATH + "FileNameCleanerTest-v1.txt")); + String contentsV2 = FileUtils.readFileToString(new File(EXPECTED_PATH + "FileNameCleanerTest-v2.txt")); + fileContentsBefore.put("src/test/java/org/jabref/logic/util/FileNameCleanerTest.java", contentsV1); + fileContentsCurrent.put("src/test/java/org/jabref/logic/util/FileNameCleanerTest.java", contentsV2); + UMLModel parentUMLModel = GitHistoryRefactoringMinerImpl.createModel(fileContentsBefore, new LinkedHashSet()); + UMLModel currentUMLModel = GitHistoryRefactoringMinerImpl.createModel(fileContentsCurrent, new LinkedHashSet()); + + UMLModelDiff modelDiff = parentUMLModel.diff(currentUMLModel); + List refactorings = modelDiff.getRefactorings(); + for(Refactoring r : refactorings) { + if(r instanceof ParameterizeTestRefactoring) { + ParameterizeTestRefactoring parameterizeTest = (ParameterizeTestRefactoring)r; + UMLOperationBodyMapper mapper = parameterizeTest.getBodyMapper(); + mapperInfo(mapper, actual); + } + } + List expected = IOUtils.readLines(new FileReader(EXPECTED_PATH + "jabRef-FileNameCleanerTest.txt")); + Assert.assertTrue(expected.size() == actual.size() && expected.containsAll(actual) && actual.containsAll(expected)); + } + @Test public void testParameterizedTestMappings2() throws Exception { GitHistoryRefactoringMinerImpl miner = new GitHistoryRefactoringMinerImpl(); diff --git a/src/test/resources/mappings/FileNameCleanerTest-v1.txt b/src/test/resources/mappings/FileNameCleanerTest-v1.txt new file mode 100644 index 000000000..d4ae98057 --- /dev/null +++ b/src/test/resources/mappings/FileNameCleanerTest-v1.txt @@ -0,0 +1,36 @@ +package org.jabref.logic.util; + +import org.jabref.logic.util.io.FileNameCleaner; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class FileNameCleanerTest { + + @Test + void cleanFileName() { + assertEquals("legalFilename.txt", FileNameCleaner.cleanFileName("legalFilename.txt")); + assertEquals("illegalFilename______.txt", FileNameCleaner.cleanFileName("illegalFilename/?*<>|.txt")); + assertEquals("illegalFileName_.txt", FileNameCleaner.cleanFileName("illegalFileName{.txt")); + } + + @Test + void cleanDirectoryName() { + assertEquals("legalFilename.txt", FileNameCleaner.cleanDirectoryName("legalFilename.txt")); + assertEquals("subdir/legalFilename.txt", FileNameCleaner.cleanDirectoryName("subdir/legalFilename.txt")); + assertEquals("illegalFilename/_____.txt", FileNameCleaner.cleanDirectoryName("illegalFilename/?*<>|.txt")); + } + + @Test + void cleanDirectoryNameForWindows() { + assertEquals("legalFilename.txt", FileNameCleaner.cleanDirectoryName("legalFilename.txt")); + assertEquals("subdir\\legalFilename.txt", FileNameCleaner.cleanDirectoryName("subdir\\legalFilename.txt")); + assertEquals("illegalFilename\\_____.txt", FileNameCleaner.cleanDirectoryName("illegalFilename\\?*<>|.txt")); + } + + @Test + void cleanCurlyBracesAsWell() { + assertEquals("The Evolution of Sentiment_ Analysis_A Review of Research Topics, Venues, and Top Cited Papers.PDF", FileNameCleaner.cleanFileName("The Evolution of Sentiment} Analysis}A Review of Research Topics, Venues, and Top Cited Papers.PDF")); + } +} diff --git a/src/test/resources/mappings/FileNameCleanerTest-v2.txt b/src/test/resources/mappings/FileNameCleanerTest-v2.txt new file mode 100644 index 000000000..1193075cd --- /dev/null +++ b/src/test/resources/mappings/FileNameCleanerTest-v2.txt @@ -0,0 +1,43 @@ +package org.jabref.logic.util; + +import org.jabref.logic.util.io.FileNameCleaner; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class FileNameCleanerTest { + + @ParameterizedTest + @CsvSource({ + "legalFilename.txt, legalFilename.txt", + "illegalFilename______.txt, illegalFilename/?*<>|.txt", + "illegalFileName_.txt, illegalFileName{.txt", + "_The Evolution of Sentiment_ Analysis_.PDF, ?The Evolution of Sentiment} Analysis}.PDF", + "'The Evolution of Sentiment_ Analysis_A Review of Research Topics, Venues, and Top Cited Papers.PDF', 'The Evolution of Sentiment} Analysis}A Review of Research Topics, Venues, and Top Cited Papers.PDF'" + }) + void cleanFileName(String expected, String input) { + assertEquals(expected, FileNameCleaner.cleanFileName(input)); + } + + @ParameterizedTest + @CsvSource({ + "legalFilename.txt, legalFilename.txt", + "subdir/legalFilename.txt, subdir/legalFilename.txt", + "illegalFilename/_____.txt, illegalFilename/?*<>|.txt" + }) + void cleanDirectoryName(String expected, String input) { + assertEquals(expected, FileNameCleaner.cleanDirectoryName(input)); + } + + @ParameterizedTest + @CsvSource({ + "legalFilename.txt, legalFilename.txt", + "subdir\\legalFilename.txt, subdir\\legalFilename.txt", + "illegalFilename\\_____.txt, illegalFilename\\?*<>|.txt" + }) + void cleanDirectoryNameForWindows(String expected, String input) { + assertEquals(expected, FileNameCleaner.cleanDirectoryName(input)); + } +} diff --git a/src/test/resources/mappings/jabRef-FileNameCleanerTest.txt b/src/test/resources/mappings/jabRef-FileNameCleanerTest.txt new file mode 100644 index 000000000..484c48be6 --- /dev/null +++ b/src/test/resources/mappings/jabRef-FileNameCleanerTest.txt @@ -0,0 +1,14 @@ +package cleanFileName() : void -> package cleanFileName(expected String, input String) : void +line range:13-13==line range:21-21 +line range:15-15==line range:21-21 +line range:14-14==line range:21-21 +package cleanCurlyBracesAsWell() : void -> package cleanFileName(expected String, input String) : void +line range:34-34==line range:21-21 +package cleanDirectoryName() : void -> package cleanDirectoryName(expected String, input String) : void +line range:20-20==line range:31-31 +line range:21-21==line range:31-31 +line range:22-22==line range:31-31 +package cleanDirectoryNameForWindows() : void -> package cleanDirectoryNameForWindows(expected String, input String) : void +line range:27-27==line range:41-41 +line range:28-28==line range:41-41 +line range:29-29==line range:41-41 \ No newline at end of file