diff --git a/.github/workflows/complete-e2e.yml b/.github/workflows/complete-e2e.yml index 332cc834e1..8616f35638 100644 --- a/.github/workflows/complete-e2e.yml +++ b/.github/workflows/complete-e2e.yml @@ -70,6 +70,7 @@ jobs: {zip: "folderMultiRoot.zip", name: "folderMultiRoot", folder: "f0", language: "java", cliArgs: "--new f1"}, {zip: "mixedMultiRoot.zip", name: "mixedBaseFile", folder: "f0", language: "java", cliArgs: "--new f1"}, {zip: "mixedMultiRoot.zip", name: "mixedBaseFolder", folder: "f1", language: "java", cliArgs: "--new f0"}, + {zip: "singleNewSubmission.zip", name: "singleNewSubmission", folder: "2023", language: "java", cliArgs: "--old 2022,2021,2020"}, {zip: "cpp.zip", name: "cpp", folder: "./cpp", language: "cpp", cliArgs: ""}, {zip: "csharp.zip", name: "csharp", folder: "./csharp", language: "csharp", cliArgs: ""}, {zip: "python.zip", name: "python", folder: "./python", language: "python3", cliArgs: ""} diff --git a/.github/workflows/files/singleNewSubmission.zip b/.github/workflows/files/singleNewSubmission.zip new file mode 100644 index 0000000000..e736486091 Binary files /dev/null and b/.github/workflows/files/singleNewSubmission.zip differ diff --git a/core/src/main/java/de/jplag/JPlag.java b/core/src/main/java/de/jplag/JPlag.java index 41f1c08c8e..a38de889ca 100644 --- a/core/src/main/java/de/jplag/JPlag.java +++ b/core/src/main/java/de/jplag/JPlag.java @@ -109,11 +109,11 @@ private static void logSkippedSubmissions(SubmissionSet submissionSet, JPlagOpti private static void checkForConfigurationConsistency(JPlagOptions options) throws RootDirectoryException { if (options.normalize() && !options.language().supportsNormalization()) { - logger.error(String.format("The language %s cannot be used with normalization.", options.language().getName())); + logger.error("The language {} cannot be used with normalization.", options.language().getName()); } List duplicateNames = getDuplicateSubmissionFolderNames(options); - if (duplicateNames.size() > 0) { + if (!duplicateNames.isEmpty()) { throw new RootDirectoryException(String.format("Duplicate root directory names found: %s", String.join(", ", duplicateNames))); } } diff --git a/core/src/test/java/de/jplag/RootFolderTest.java b/core/src/test/java/de/jplag/RootFolderTest.java index c5acd3cb1f..99d6253880 100644 --- a/core/src/test/java/de/jplag/RootFolderTest.java +++ b/core/src/test/java/de/jplag/RootFolderTest.java @@ -1,7 +1,6 @@ package de.jplag; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; import java.io.File; import java.util.List; @@ -84,4 +83,20 @@ void testBasecodeInOldDirectory() throws ExitException { int numberOfExpectedComparison = 1 + ROOT_COUNT_2 * (ROOT_COUNT_1 - 1); // -1 for basecode assertEquals(numberOfExpectedComparison, result.getAllComparisons().size()); } + + @Test + @DisplayName("test single new submission") + void testSingleNewSubmission() throws ExitException { + List newSubmissionsNames = List.of("2023"); + List oldSubmissionsNames = List.of("2022", "2021", "2020"); + List newSubmissions = newSubmissionsNames.stream().map(it -> getBasePath("SingleNewSubmission" + File.separator + it)).toList(); + List oldSubmissions = oldSubmissionsNames.stream().map(it -> getBasePath("SingleNewSubmission" + File.separator + it)).toList(); + + JPlagResult result = runJPlag(newSubmissions, oldSubmissions, it -> it); + + long numberOfNewSubmissions = result.getSubmissions().getSubmissions().stream().filter(Submission::isNew).count(); + long numberOfOldSubmissions = result.getSubmissions().getSubmissions().stream().filter(it -> !it.isNew()).count(); + assertEquals(1, numberOfNewSubmissions); + assertEquals(3, numberOfOldSubmissions); + } } diff --git a/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2020/QSort2020.java b/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2020/QSort2020.java new file mode 100644 index 0000000000..1fdfb3562f --- /dev/null +++ b/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2020/QSort2020.java @@ -0,0 +1,40 @@ +import java.util.ArrayList; +import java.util.List; + +public class QSort2020 { + public String[] qsort(String[] array) { + if (array == null || array.length == 0) { + return array; + } + List sortedList = quickSort(List.of(array)); + return sortedList.toArray(new String[0]); + } + + private List quickSort(List list) { + if (list.size() <= 1) { + return list; + } + + String pivot = list.get(list.size() / 2); + List less = new ArrayList<>(); + List equal = new ArrayList<>(); + List greater = new ArrayList<>(); + + for (String s : list) { + int comparison = s.compareTo(pivot); + if (comparison < 0) { + less.add(s); + } else if (comparison > 0) { + greater.add(s); + } else { + equal.add(s); + } + } + + List sorted = new ArrayList<>(); + sorted.addAll(quickSort(less)); + sorted.addAll(equal); + sorted.addAll(quickSort(greater)); + return sorted; + } +} diff --git a/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2021/QSort2021.java b/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2021/QSort2021.java new file mode 100644 index 0000000000..7fc96abd1b --- /dev/null +++ b/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2021/QSort2021.java @@ -0,0 +1,44 @@ +import java.util.Stack; + +public class QSort2021 { + public String[] qsort(String[] array) { + if (array == null || array.length == 0) { + return array; + } + + Stack stack = new Stack<>(); + stack.push(new int[] { 0, array.length - 1 }); + + while (!stack.isEmpty()) { + int[] range = stack.pop(); + int low = range[0], high = range[1]; + + if (low < high) { + int pivotIndex = partition(array, low, high); + stack.push(new int[] { low, pivotIndex - 1 }); + stack.push(new int[] { pivotIndex + 1, high }); + } + } + + return array; + } + + private int partition(String[] array, int low, int high) { + String pivot = array[high]; + int i = low - 1; + for (int j = low; j < high; j++) { + if (array[j].compareTo(pivot) <= 0) { + i++; + swap(array, i, j); + } + } + swap(array, i + 1, high); + return i + 1; + } + + private void swap(String[] array, int i, int j) { + String temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } +} diff --git a/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2022/QSort2022.java b/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2022/QSort2022.java new file mode 100644 index 0000000000..7b7dd9102b --- /dev/null +++ b/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2022/QSort2022.java @@ -0,0 +1,41 @@ +public class QSort2022 { + public String[] qsort(String[] array) { + if (array == null || array.length == 0) { + return array; + } + quickSort(array, 0, array.length - 1); + return array; + } + + private void quickSort(String[] array, int low, int high) { + while (low < high) { + int pivotIndex = partition(array, low, high); + if (pivotIndex - low < high - pivotIndex) { + quickSort(array, low, pivotIndex - 1); + low = pivotIndex + 1; + } else { + quickSort(array, pivotIndex + 1, high); + high = pivotIndex - 1; + } + } + } + + private int partition(String[] array, int low, int high) { + String pivot = array[high]; + int i = low - 1; + for (int j = low; j < high; j++) { + if (array[j].compareTo(pivot) <= 0) { + i++; + swap(array, i, j); + } + } + swap(array, i + 1, high); + return i + 1; + } + + private void swap(String[] array, int i, int j) { + String temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } +} diff --git a/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2023/QSort2023.java b/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2023/QSort2023.java new file mode 100644 index 0000000000..dfe08fddbb --- /dev/null +++ b/core/src/test/resources/de/jplag/samples/SingleNewSubmission/2023/QSort2023.java @@ -0,0 +1,37 @@ +public class QSort2023 { + public String[] qsort(String[] array) { + if (array == null || array.length == 0) { + return array; + } + quickSort(array, 0, array.length - 1); + return array; + } + + private void quickSort(String[] array, int low, int high) { + if (low < high) { + int pivotIndex = partition(array, low, high); + quickSort(array, low, pivotIndex - 1); + quickSort(array, pivotIndex + 1, high); + } + } + + private int partition(String[] array, int low, int high) { + String pivot = array[high]; + int i = low - 1; + for (int j = low; j < high; j++) { + if (array[j].compareTo(pivot) <= 0) { + i++; + swap(array, i, j); + } + } + swap(array, i + 1, high); + return i + 1; + } + + private void swap(String[] array, int i, int j) { + String temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + +} \ No newline at end of file diff --git a/report-viewer/tests/e2e/OpenComparisonTest.spec.ts b/report-viewer/tests/e2e/OpenComparisonTest.spec.ts index 8b9a9bdd16..f4b51f1cc0 100644 --- a/report-viewer/tests/e2e/OpenComparisonTest.spec.ts +++ b/report-viewer/tests/e2e/OpenComparisonTest.spec.ts @@ -8,6 +8,8 @@ interface DataSet { secondSubmissionName: string } +const regexPathSeparator = '(\\\\|\\/)'; + const testSets: DataSet[] = [ { datasetName: 'fileSingleRoot-report.zip', @@ -39,6 +41,11 @@ const testSets: DataSet[] = [ firstSubmissionName: 'f0\\\\|/0', secondSubmissionName: 'f1\\\\|/1' }, + { + datasetName: 'singleNewSubmission-report.zip', + firstSubmissionName: `2023${regexPathSeparator}QSort2023.java`, + secondSubmissionName: `2022${regexPathSeparator}QSort2022.java`, + }, { datasetName: 'python-report.zip', firstSubmissionName: '01.py',