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

Fix/same submission #829

Merged
merged 10 commits into from
Dec 19, 2022
9 changes: 8 additions & 1 deletion core/src/main/java/de/jplag/JPlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import de.jplag.clustering.ClusteringFactory;
import de.jplag.exceptions.ExitException;
import de.jplag.exceptions.RootDirectoryException;
import de.jplag.exceptions.SubmissionException;
import de.jplag.options.JPlagOptions;
import de.jplag.reporting.reportobject.model.Version;
Expand Down Expand Up @@ -38,7 +39,13 @@ private static Version loadVersion() {
* @param options determines the parameterization.
*/
public JPlag(JPlagOptions options) {
this.options = options;
PreventSameRootName preventSameRootName = null;
try {
preventSameRootName = new PreventSameRootName(options);
} catch (RootDirectoryException e) {
e.printStackTrace();
}
this.options = preventSameRootName.getOptions();
language = this.options.language();
GreedyStringTiling coreAlgorithm = new GreedyStringTiling(options);
comparisonStrategy = new ParallelComparisonStrategy(options, coreAlgorithm);
Expand Down
141 changes: 141 additions & 0 deletions core/src/main/java/de/jplag/PreventSameRootName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package de.jplag;

import java.io.File;
import java.nio.file.Path;
import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.jplag.exceptions.RootDirectoryException;
import de.jplag.options.JPlagOptions;

/**
* This class prevents the same root name of submissions.
*/
public class PreventSameRootName {
private static final Logger logger = LoggerFactory.getLogger(PreventSameRootName.class);

private final Map<String, Integer> statistic = new HashMap<>(); // uses to store information of same roots (Key: same root name ---> Value: number
// of the same root name)
private final JPlagOptions options;

/**
* Creates and initializes a PreventSameRootName instance, parameterized by a set of options. If there are same names of
* root directories, they will be re-named before generating zip file and IDs. (e.g. two same root names: root ===>
* root_1 && root_2)
* @param options determines the parameterization
*/
public PreventSameRootName(JPlagOptions options) throws RootDirectoryException {
Set<File> newChangedSubmissionDirectories;
Set<File> oldChangedSubmissionDirectories;
Set<File> newSubmissionDirectories = options.submissionDirectories();
Set<File> oldSubmissionDirectories = options.oldSubmissionDirectories();
if (oldSubmissionDirectories == null && newSubmissionDirectories == null) {
throw new RootDirectoryException("No submission");
}
boolean hasSameRoots = false;
hasSameRoots = hasSameRoots(newSubmissionDirectories, oldSubmissionDirectories);
if (hasSameRoots) {
logger.info("Detected same name of root directories, the name will be re-named...");
newChangedSubmissionDirectories = renameRoots(newSubmissionDirectories);
oldChangedSubmissionDirectories = renameRoots(oldSubmissionDirectories);
} else {
newChangedSubmissionDirectories = newSubmissionDirectories;
oldChangedSubmissionDirectories = oldSubmissionDirectories;
}
this.options = new JPlagOptions(options.language(), options.minimumTokenMatch(), newChangedSubmissionDirectories,
oldChangedSubmissionDirectories, options.baseCodeSubmissionDirectory(), options.subdirectoryName(), options.fileSuffixes(),
options.exclusionFileName(), options.similarityMetric(), options.similarityThreshold(), options.maximumNumberOfComparisons(),
options.clusteringOptions(), options.debugParser());
}

/**
* @return a new options instance
*/
public JPlagOptions getOptions() {
return options;
}

/**
* @return the statistic map
*/
public Map<String, Integer> getStatistic() {
return statistic;
}

/**
* Counts the root directory names and their number with Map(named statistic).
* @param submissionDirectories SubmissionDirectories that need to be counted
*/
public void rootsClassification(Set<File> submissionDirectories) {
if (submissionDirectories == null)
return;
for (File submissionDirectory : submissionDirectories) {
String rootDirectory = getRootName(submissionDirectory);
statistic.put(rootDirectory, statistic.getOrDefault(rootDirectory, 0) + 1);
}
}

/**
* Renames the same root directory name.
* @param submissionDirectories SubmissionDirectories that need to be re-named
* @return SubmissionDirectories that have been re-named
*/
public Set<File> renameRoots(Set<File> submissionDirectories) {
if (submissionDirectories == null)
return Set.of();
Set<File> set = new HashSet<>();
for (File submissionDirectory : submissionDirectories) {
String rootDirectory = getRootName(submissionDirectory);
int index = statistic.getOrDefault(rootDirectory, -1);
if (index == -1)
continue;
String newRootDirectory = rootDirectory + "_" + index;
statistic.put(rootDirectory, statistic.get(rootDirectory) - 1);
File newFile = new File(Path.of(submissionDirectory.getParent(), newRootDirectory).toString());
set.add(newFile);
submissionDirectory.renameTo(newFile);
logger.info("Original submission path ===> Current submission path:" + submissionDirectory.getPath() + " ===> " + newFile.getPath());
}
return Set.copyOf(set);
}

/**
* Gets root name of a submissionDirectory.
* @param submissionDirectory A single submissionDirectory
* @return Root name of the submission
*/
public String getRootName(File submissionDirectory) {
return submissionDirectory.getPath().substring(submissionDirectory.getParent().length() + 1);
}

/**
* Determines if there are the same root directories.
* @param newSubmissionDirectories The new submissionDirectories
* @param oldSubmissionDirectories The old submissionDirectories
* @return True, if there are the same root directories. False, otherwise.
*/
public boolean hasSameRoots(Set<File> newSubmissionDirectories, Set<File> oldSubmissionDirectories) throws RootDirectoryException {
checkDirectoryExist(newSubmissionDirectories);
checkDirectoryExist(oldSubmissionDirectories);
rootsClassification(newSubmissionDirectories);
rootsClassification(oldSubmissionDirectories);
Set<Map.Entry<String, Integer>> entries = statistic.entrySet();
entries.removeIf(entry -> entry.getValue() == 1);
return !statistic.isEmpty();
}

/**
* Checks if directories exist. If not, throws RootDirectoryException.
* @param submissionDirectories The submissionDirectories which needs to be checked
*/
public void checkDirectoryExist(Set<File> submissionDirectories) throws RootDirectoryException {
for (File submissionDirectory : submissionDirectories) {
boolean exists = submissionDirectory.exists();
if (!exists) {
throw new RootDirectoryException("Submission Directory doesn't exist: " + submissionDirectory.getPath());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ private Match convertMatchToReportMatch(JPlagComparison comparison, de.jplag.Mat

private String relativizedFilePath(File file, Submission submission) {
if (file.toPath().equals(submission.getRoot().toPath())) {
return Path.of(submission.getName(), submission.getName()).toString();
return Path.of(submissionToIdFunction.apply(submission), submission.getName()).toString();
}
return Path.of(submission.getName(), submission.getRoot().toPath().relativize(file.toPath()).toString()).toString();
return Path.of(submissionToIdFunction.apply(submission), submission.getRoot().toPath().relativize(file.toPath()).toString()).toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ public static File createDirectory(String path, String name, File file, File sub
File directory;
String fileName = file.getPath();
String submissionRootPath = submissionRoot.getPath();
int lastDirectoryIndex = findRootDirIndex(name, submissionRootPath);
fileName = fileName.substring(lastDirectoryIndex).replaceFirst(name, "");
fileName = fileName.substring(submissionRootPath.length());
String outputRootDirectory = Path.of(path, name).toString();
if ("".equals(fileName)) {
directory = new File(Path.of(outputRootDirectory, name).toString());
Expand Down Expand Up @@ -119,15 +118,4 @@ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOExce
logger.info("Display the results with the report viewer at https://jplag.github.io/JPlag/");
return true;
}

/**
* finds the start index of root directory according to this name
* @param name The name of the root directory. According to this name we can find the index of this directory.
* @param submissionRootPath The path of the root directory
* @return The start index of the root directory
*/
public static int findRootDirIndex(String name, String submissionRootPath) {
int submissionRootPathLength = submissionRootPath.length();
return submissionRootPathLength - name.length();
}
}
85 changes: 85 additions & 0 deletions core/src/test/java/de/jplag/PreventSameRootNameTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package de.jplag;

import static org.junit.jupiter.api.Assertions.fail;

import java.io.File;
import java.nio.file.Path;
import java.util.Set;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import de.jplag.exceptions.RootDirectoryException;
import de.jplag.options.JPlagOptions;

/**
* Test for the same root cases that will be re-named.
*/
public class PreventSameRootNameTest extends TestBase {

private static final JPlagOptions BASEOPTIONS = new JPlagOptions(new de.jplag.java.Language(), Set.of(), Set.of());
private static final String NOTEXISTDIRECTORY = Path.of(TestBase.BASE_PATH, "basecode", "NotExistDirectory").toString();
private static final String SAMPLE_SAMEROOTNAME_1 = Path.of(TestBase.BASE_PATH, "SameRootName", "2019", "root").toString();
private static final String SAMPLE_SAMEROOTNAME_2 = Path.of(TestBase.BASE_PATH, "SameRootName", "2020", "root").toString();

@Test
@DisplayName("test same root directory with withSubmissionDirectories options")
void testSameRootWithNew() {
JPlagOptions options = BASEOPTIONS.withSubmissionDirectories(Set.of(new File(SAMPLE_SAMEROOTNAME_1), new File(SAMPLE_SAMEROOTNAME_2)));
try {
PreventSameRootName preventSameRootName = new PreventSameRootName(options);
JPlagOptions newOptions = preventSameRootName.getOptions();
File submissionDirectory_2 = options.submissionDirectories().stream().toList().get(0);
File submissionDirectory_1 = options.submissionDirectories().stream().toList().get(1);
File newChangedSubmissionDirectory_2 = newOptions.submissionDirectories().stream().toList().get(0);
File newChangedSubmissionDirectory_1 = newOptions.submissionDirectories().stream().toList().get(1);
Assertions.assertEquals(submissionDirectory_2.getPath() + "_2", newChangedSubmissionDirectory_2.getPath());
Assertions.assertEquals(submissionDirectory_1.getPath() + "_1", newChangedSubmissionDirectory_1.getPath());
} catch (RootDirectoryException e) {
fail("PreventSameRootName Class threw an exception:", e);
}
}

@Test
@DisplayName("test same root directory with withSubmissionDirectories and oldSubmissionDirectories options")
void testSameRootWithNewAndOld() {
JPlagOptions options = BASEOPTIONS.withSubmissionDirectories(Set.of(new File(SAMPLE_SAMEROOTNAME_2)))
.withOldSubmissionDirectories(Set.of(new File(SAMPLE_SAMEROOTNAME_1)));
try {
PreventSameRootName preventSameRootName = new PreventSameRootName(options);
JPlagOptions newOptions = preventSameRootName.getOptions();
File oldSubmissionDirectory = options.oldSubmissionDirectories().stream().toList().get(0);
File submissionDirectory = options.submissionDirectories().stream().toList().get(0);
File newChangedOldSubmissionDirectory = newOptions.oldSubmissionDirectories().stream().toList().get(0);
File newChangedSubmissionDirectory = newOptions.submissionDirectories().stream().toList().get(0);
Assertions.assertEquals(submissionDirectory.getPath() + "_2", newChangedSubmissionDirectory.getPath());
Assertions.assertEquals(oldSubmissionDirectory.getPath() + "_1", newChangedOldSubmissionDirectory.getPath());
} catch (RootDirectoryException e) {
fail("PreventSameRootName Class threw an exception:", e);
}
}

@Test
@DisplayName("test not existed root directory with withSubmissionDirectories option")
void testCheckDirectoryExistWithNewSubmissionDirectories() {
JPlagOptions options = BASEOPTIONS.withSubmissionDirectories(Set.of(new File(NOTEXISTDIRECTORY)));
testRootDirectoryException(options);
}

@Test
@DisplayName("test not existed root directory with withOldSubmissionDirectories option")
void testCheckDirectoryExistWithOldSubmissionDirectories() {
JPlagOptions options = BASEOPTIONS.withOldSubmissionDirectories(Set.of(new File(NOTEXISTDIRECTORY)));
testRootDirectoryException(options);
}

/**
* Test RootDirectoryException for a given Jplag-options.
* @param options is the customized Jplag-options.
*/
void testRootDirectoryException(JPlagOptions options) {
RootDirectoryException exception = Assertions.assertThrows(RootDirectoryException.class, () -> new PreventSameRootName(options));
Assertions.assertEquals("Submission Directory doesn't exist: " + NOTEXISTDIRECTORY, exception.getMessage());
}
}
Loading