Sfoglia il codice sorgente

re-enable E2E result json generation
cleanup E2E code

Jan Wittler 3 anni fa
parent
commit
90e79f0ac7

+ 2 - 1
endtoend-testing/README.md

@@ -175,7 +175,8 @@ public void BubbleSortWithoutRecursion(Integer arr[]) {
 The plagiarisms created in [Creating The Plagiarism](#creating-the-plagiarism) need now to be copied to the corresponding resources folder. For each test suite, the resources must be placed in `JPlag/jplag.endToEndTesting/src/test/resources/languageTestFiles/<languageIdentifier>/<testSuiteIdentifier>`. For example, for the existing test suite `sortAlgo` of language `java`, the path is `JPlag/jplag.endToEndTesting/src/test/resources/languageTestFiles/java/sortAlgo`.
 It is important to note that the language identifier must match `Language#getIdentifier` to correctly load the language during testing.
 
-Once the tests have been run for the first time, the information for the tests is stored in the folder `../target/testing-directory-submission/LANGUAGE`.  This data can be copied to the path `[...]/resources/results/LANGUAGE`. Each subdirectory gets its result JSON file as `[...]/resources/results/LANGUAGE/TEST_SUITE_NAME.json`. Once the test data has been copied, the end-to-end tests can be successfully tested. As soon as a change in the detection takes place, the results will differ from the stored results and the tests will fail if the results have changed.
+To automatically generate expected results, the test in `EndToEndGeneratorTest` can be executed to generate a JSON result description file. This file has to be copied to `JPlag/jplag.endToEndTesting/src/test/resources/results/<languageIdentifier>/<testSuiteIdentifier>.json`.
+Once the test data has been copied, the end-to-end tests can be successfully tested. As soon as a change in the detection takes place, the results will differ from the stored results and the tests will fail if the results have changed.
 
 ### Extending The Comparison Value
 

+ 0 - 6
endtoend-testing/src/main/java/de/jplag/endtoend/constants/TestDirectoryConstants.java

@@ -11,12 +11,6 @@ public final class TestDirectoryConstants {
         // private constructor to prevent instantiation
     }
 
-    /**
-     * Create the complete path to the temporary result files. Here the temporary system path is extended with the
-     * "RESULT_DIRECTORY_NAME", which is predefined in this class.
-     */
-    public static final Path TEMPORARY_RESULT_DIRECTORY_NAME = Path.of("target", "testing-directory-temporary-result");
-
     /**
      * Base path to the saved results
      */

+ 5 - 87
endtoend-testing/src/main/java/de/jplag/endtoend/helper/FileHelper.java

@@ -2,14 +2,6 @@ package de.jplag.endtoend.helper;
 
 import java.io.File;
 import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-import de.jplag.endtoend.constants.TestDirectoryConstants;
 
 /**
  * Helper class to perform all necessary operations or functions on files or folders.
@@ -20,78 +12,17 @@ public class FileHelper {
         // private constructor to prevent instantiation
     }
 
+    /**
+     * Returns the name of the passed file, trimming its file extension.
+     * @param file is the file to obtain the name from
+     * @return returns the name of the file without file extension
+     */
     public static String getFileNameWithoutFileExtension(File file) {
         String name = file.getName();
         int index = name.lastIndexOf('.');
         return index == -1 ? name : name.substring(0, index);
     }
 
-    /**
-     * Load all possible languages in resource path
-     * @param directoryNames folder names for which the language options should be listed.
-     * @return list of all LanguageOptions included in the resource path
-     */
-    public static List<String> getLanguageOptionsFromPath(String[] directoryNames) {
-        return Arrays.stream(directoryNames).map(language -> language).filter(Objects::nonNull).toList();
-    }
-
-    /**
-     * @param directorieRoot path from which all folders should be loaded
-     * @return all folders found in the specified path
-     */
-    public static String[] getAllDirectoriesInPath(Path directorieRoot) {
-        return directorieRoot.toFile().list((dir, name) -> new File(dir, name).isDirectory());
-    }
-
-    /**
-     * Copies the passed filenames to a temporary path to use them in the tests
-     * @param classNames for which the test case is to be created
-     * @return paths created to the test submissions
-     * @throws IOException Exception can be thrown in cases that involve reading, copying or locating files.
-     */
-    public static String[] createNewTestCaseDirectory(String[] classNames) throws IOException {
-        // Copy the resources data to the temporary path
-        String[] returnSubmissionPath = new String[classNames.length];
-        for (int counter = 0; counter < classNames.length; counter++) {
-            Path originalPath = Path.of(classNames[counter]);
-            returnSubmissionPath[counter] = Path
-                    .of(TestDirectoryConstants.TEMPORARY_SUBMISSION_DIRECTORY_NAME.toString(), "submission" + (counter + 1)).toAbsolutePath()
-                    .toString();
-            Path copyPath = Path.of(TestDirectoryConstants.TEMPORARY_SUBMISSION_DIRECTORY_NAME.toString(), "submission" + (counter + 1),
-                    originalPath.getFileName().toString());
-
-            File directory = new File(copyPath.toString());
-            if (!directory.exists()) {
-                directory.mkdirs();
-            }
-            Files.copy(originalPath, copyPath, StandardCopyOption.REPLACE_EXISTING);
-        }
-        return returnSubmissionPath;
-    }
-
-    /**
-     * Delete directory with including files
-     * @param folder Path to a folder or file to be deleted. This happens recursively to the path
-     * @throws IOException if an I/O error occurs
-     */
-    public static void deleteCopiedFiles(File folder) throws IOException {
-        if (!folder.exists()) {
-            return;
-        }
-        File[] files = folder.listFiles();
-        if (files == null) { // some JVMs return null for empty dirs
-            return;
-        }
-        for (File file : files) {
-            if (file.isDirectory()) {
-                deleteCopiedFiles(file);
-            } else {
-                Files.delete(file.toPath());
-            }
-        }
-        Files.delete(folder.toPath());
-    }
-
     /**
      * Creates directory if it dose not exist
      * @param directory to be created
@@ -114,19 +45,6 @@ public class FileHelper {
         }
     }
 
-    /**
-     * @param resourcenPaths list of paths that lead to test resources
-     * @return all filenames contained in the paths
-     */
-    public static String[] loadAllTestFileNames(Path resourcenPaths) {
-        var files = resourcenPaths.toFile().listFiles();
-        String[] fileNames = new String[files.length];
-        for (int i = 0; i < files.length; i++) {
-            fileNames[i] = files[i].getName();
-        }
-        return fileNames;
-    }
-
     /**
      * @param file for which the exception text is to be created
      * @return exception text for the specified file

+ 0 - 83
endtoend-testing/src/main/java/de/jplag/endtoend/helper/JsonHelper.java

@@ -1,83 +0,0 @@
-package de.jplag.endtoend.helper;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.ObjectWriter;
-
-import de.jplag.endtoend.constants.TestDirectoryConstants;
-import de.jplag.endtoend.model.ResultDescription;
-
-/**
- * Helper class for serialization and deserialization of the used json format into the correct record classes. The
- * serialization/deserialization is enabled using the Jackson library. The record classes used can be found at
- * {@link de.jplag.endtoend.model}.
- */
-public class JsonHelper {
-    /**
-     * private constructor to prevent instantiation
-     */
-    private JsonHelper() {
-        // For Serialization
-    }
-
-    /**
-     * @param directoryName name to the result path
-     * @param languageIdentifier for which the results are to be loaded
-     * @return ResultDescription as serialized object
-     * @throws IOException is thrown for all problems that may occur while parsing the json file. This includes both reading
-     */
-    public static List<ResultDescription> getJsonModelListFromPath(String directoryName, String languageIdentifier) throws IOException {
-
-        Path jsonPath = Path.of(TestDirectoryConstants.BASE_PATH_TO_RESULT_JSON.toString(), languageIdentifier, directoryName + ".json");
-
-        if (jsonPath.toFile().exists() && jsonPath.toFile().length() > 0) {
-
-            return Arrays.asList(new ObjectMapper().readValue(jsonPath.toFile(), ResultDescription[].class));
-        } else {
-            return Collections.<ResultDescription>emptyList();
-        }
-    }
-
-    public static ResultDescription[] getResultDescriptionFromFile(File resultFile) {
-        if (resultFile.exists()) {
-            try {
-                return new ObjectMapper().readValue(resultFile, ResultDescription[].class);
-            } catch (IOException e) {
-                return null;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Saves the passed object as a json file to the given path
-     * @param resultDescriptionist list of elements to be saved
-     * @param directoryName path to the temporary storage location
-     * @param languageIdentifier for which the results should be stored
-     * @throws IOException Signals that an I/O exception of some sort has occurred. Thisclass is the general class of
-     * exceptions produced by failed orinterrupted I/O operations.
-     */
-    public static void writeJsonModelsToJsonFile(List<ResultDescription> resultDescriptionist, String directoryName, String languageIdentifier)
-            throws IOException {
-        // create an instance of DefaultPrettyPrinter
-        // new DefaultPrettyPrinter()
-        ObjectWriter writer = new ObjectMapper().writer().withDefaultPrettyPrinter();
-
-        Path temporaryDirectory = Path.of(TestDirectoryConstants.TEMPORARY_SUBMISSION_DIRECTORY_NAME.toString(), languageIdentifier,
-                directoryName + ".json");
-
-        FileHelper.createDirectoryIfItDoesNotExist(temporaryDirectory.getParent().toFile());
-        FileHelper.createFileIfItDoesNotExist(temporaryDirectory.toFile());
-
-        // convert book object to JSON file
-
-        writer.writeValue(temporaryDirectory.toFile(), resultDescriptionist.toArray());
-
-    }
-}

+ 14 - 51
endtoend-testing/src/main/java/de/jplag/endtoend/helper/TestSuiteHelper.java

@@ -1,13 +1,7 @@
 package de.jplag.endtoend.helper;
 
 import java.io.File;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.stream.Collectors;
 
 import de.jplag.JPlagComparison;
@@ -27,28 +21,6 @@ public class TestSuiteHelper {
         // For Serialization
     }
 
-    /**
-     * Loads all existing test data into a test structure. the complex structure consists of the LanguageOption and their
-     * data to be tested. These are divided into folders. for more information please read the README file
-     * @return mapped LanguageOption to the data under test
-     */
-    public static Map<String, Map<String, Path>> getAllLanguageResources() {
-        String[] languageDirectoryNames = FileHelper.getAllDirectoriesInPath(TestDirectoryConstants.BASE_PATH_TO_LANGUAGE_RESOURCES);
-        List<String> languageInPathList = FileHelper.getLanguageOptionsFromPath(languageDirectoryNames);
-
-        Map<String, Map<String, Path>> returnMap = new HashMap<>();
-
-        for (String languageIdentifier : languageInPathList) {
-            var tempMap = new HashMap<String, Path>();
-            var allDirectoriesInPath = FileHelper
-                    .getAllDirectoriesInPath(Path.of(TestDirectoryConstants.BASE_PATH_TO_LANGUAGE_RESOURCES.toString(), languageIdentifier));
-            Arrays.asList(allDirectoriesInPath).forEach(directory -> tempMap.put(Path.of(directory).toFile().getName(),
-                    Path.of(TestDirectoryConstants.BASE_PATH_TO_LANGUAGE_RESOURCES.toString(), languageIdentifier, directory)));
-            returnMap.put(languageIdentifier, tempMap);
-        }
-        return returnMap;
-    }
-
     /**
      * Creates a unique identifier from the submissions in the JPlagComparison object which is used to find the results in
      * the json files.
@@ -61,34 +33,25 @@ public class TestSuiteHelper {
 
     }
 
-    public static File getSubmissionDirectory(Language language, File resultJSON) {
-        return TestDirectoryConstants.BASE_PATH_TO_LANGUAGE_RESOURCES.resolve(language.getIdentifier())
-                .resolve(FileHelper.getFileNameWithoutFileExtension(resultJSON)).toFile();
-    }
-
     /**
-     * Creates the permutation of all data contained in the passed parameters and adds it to the given path.
-     * @param fileNames for which the permutations are needed
-     * @param path to which the permutations are to be copied
-     * @return all permutations of the specified files to the path specified
+     * Returns the file pointing to the directory of the submissions for the given language and result json. The result
+     * json's name is expected to be equal to the test suite identifier.
+     * @param language is the language for the tests
+     * @param resultJSON is the json containing the expected values
+     * @return returns the directory of the submissions
      */
-    public static List<String[]> getTestCases(String[] fileNames, Path path) {
-        ArrayList<String[]> testCases = new ArrayList<>();
-
-        for (int outerCounter = 0; outerCounter < fileNames.length; outerCounter++) {
-            for (int innerCounter = outerCounter + 1; innerCounter < fileNames.length; innerCounter++) {
-                testCases.add(new String[] {Path.of(path.toAbsolutePath().toString(), fileNames[outerCounter]).toString(),
-                        Path.of(path.toAbsolutePath().toString(), fileNames[innerCounter]).toString()});
-            }
-        }
-        return testCases;
+    public static File getSubmissionDirectory(Language language, File resultJSON) {
+        return getSubmissionDirectory(language, FileHelper.getFileNameWithoutFileExtension(resultJSON));
     }
 
     /**
-     * The copied data should be deleted after instance closure
-     * @throws IOException if an I/O error occurs
+     * Returns the file pointing to the directory of the submissions for the given language and test suite identifier as
+     * described in the Readme.md.
+     * @param language is the langauge for the tests
+     * @param testSuiteIdentifier is the test suite identifier of the tests
+     * @return returns the directory of the submissions
      */
-    public static void clear() throws IOException {
-        FileHelper.deleteCopiedFiles(new File(TestDirectoryConstants.TEMPORARY_SUBMISSION_DIRECTORY_NAME.toString()));
+    public static File getSubmissionDirectory(Language language, String testSuiteIdentifier) {
+        return TestDirectoryConstants.BASE_PATH_TO_LANGUAGE_RESOURCES.resolve(language.getIdentifier()).resolve(testSuiteIdentifier).toFile();
     }
 }

+ 87 - 0
endtoend-testing/src/test/java/de/jplag/endtoend/EndToEndGeneratorTest.java

@@ -0,0 +1,87 @@
+package de.jplag.endtoend;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+
+import de.jplag.JPlag;
+import de.jplag.JPlagComparison;
+import de.jplag.JPlagResult;
+import de.jplag.Language;
+import de.jplag.LanguageLoader;
+import de.jplag.endtoend.constants.TestDirectoryConstants;
+import de.jplag.endtoend.helper.FileHelper;
+import de.jplag.endtoend.helper.TestSuiteHelper;
+import de.jplag.endtoend.model.ExpectedResult;
+import de.jplag.endtoend.model.Options;
+import de.jplag.endtoend.model.ResultDescription;
+import de.jplag.exceptions.ExitException;
+import de.jplag.options.JPlagOptions;
+
+/**
+ * Test class for automatically generating the json file describing the expected results. To generate a result json,
+ * adapt the three constants to your requirements and enable the test case.
+ */
+class EndToEndGeneratorTest {
+    private static final String LANGUAGE_IDENTIFIER = "java";
+    private static final String TEST_SUITE_IDENTIFIER = "sortAlgo";
+    private static final List<Options> OPTIONS = List.of(new Options(3), new Options(9));
+
+    private static final Logger logger = LoggerFactory.getLogger(EndToEndGeneratorTest.class);
+
+    @Disabled("only enable to generate result json file")
+    @Test
+    void generateResultJson() throws ExitException, IOException {
+        Language language = LanguageLoader.getLanguage(LANGUAGE_IDENTIFIER).orElseThrow();
+        File submissionDirectory = TestSuiteHelper.getSubmissionDirectory(language, TEST_SUITE_IDENTIFIER);
+        List<ResultDescription> resultDescriptions = new ArrayList<>();
+        for (var option : OPTIONS) {
+            JPlagOptions jplagOptions = new JPlagOptions(language, Set.of(submissionDirectory), Set.of())
+                    .withMinimumTokenMatch(option.minimumTokenMatch());
+            JPlagResult jplagResult = new JPlag(jplagOptions).run();
+            List<JPlagComparison> jPlagComparisons = jplagResult.getAllComparisons();
+            Map<String, ExpectedResult> expectedResults = jPlagComparisons.stream()
+                    .collect(Collectors.toMap(TestSuiteHelper::getTestIdentifier, comparison -> new ExpectedResult(comparison.minimalSimilarity(),
+                            comparison.maximalSimilarity(), comparison.getNumberOfMatchedTokens())));
+            resultDescriptions.add(new ResultDescription(language.getIdentifier(), option, expectedResults));
+        }
+        File outputFile = writeJsonModelsToJsonFile(resultDescriptions, TEST_SUITE_IDENTIFIER, LANGUAGE_IDENTIFIER);
+        logger.info("result JSON written to file '{}'", outputFile);
+    }
+
+    /**
+     * Saves the passed object as a json file to the file identified by the test suite and language. Returns that file.
+     * @param resultDescriptions list of elements to be saved
+     * @param testSuiteIdentifier identifier of the test suite
+     * @param languageIdentifier identifier of the language
+     * @throws IOException Signals that an I/O exception of some sort has occurred. Thisclass is the general class of
+     * exceptions produced by failed orinterrupted I/O operations.
+     */
+    private static File writeJsonModelsToJsonFile(List<ResultDescription> resultDescriptions, String testSuiteIdentifier, String languageIdentifier)
+            throws IOException {
+        ObjectWriter writer = new ObjectMapper().writer().withDefaultPrettyPrinter();
+        File outputFile = TestDirectoryConstants.TEMPORARY_SUBMISSION_DIRECTORY_NAME.resolve(languageIdentifier)
+                .resolve(testSuiteIdentifier + ".json").toFile();
+
+        FileHelper.createDirectoryIfItDoesNotExist(outputFile.getParentFile());
+        FileHelper.createFileIfItDoesNotExist(outputFile);
+
+        // convert book object to JSON file
+
+        writer.writeValue(outputFile, resultDescriptions.toArray());
+        return outputFile;
+
+    }
+}

+ 5 - 15
endtoend-testing/src/test/java/de/jplag/endtoend/EndToEndSuiteTest.java

@@ -5,7 +5,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
-import java.io.FileFilter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -19,6 +18,8 @@ import org.junit.jupiter.api.DynamicContainer;
 import org.junit.jupiter.api.DynamicTest;
 import org.junit.jupiter.api.TestFactory;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 import de.jplag.JPlag;
 import de.jplag.JPlagComparison;
 import de.jplag.JPlagResult;
@@ -26,7 +27,6 @@ import de.jplag.Language;
 import de.jplag.LanguageLoader;
 import de.jplag.endtoend.constants.TestDirectoryConstants;
 import de.jplag.endtoend.helper.FileHelper;
-import de.jplag.endtoend.helper.JsonHelper;
 import de.jplag.endtoend.helper.TestSuiteHelper;
 import de.jplag.endtoend.model.ExpectedResult;
 import de.jplag.endtoend.model.ResultDescription;
@@ -49,25 +49,15 @@ public class EndToEndSuiteTest {
     @TestFactory
     Collection<DynamicContainer> dynamicOverAllTest() throws IOException, ExitException {
         File resultsDirectory = TestDirectoryConstants.BASE_PATH_TO_RESULT_JSON.toFile();
-        File[] languageDirectories = resultsDirectory.listFiles(new FileFilter() {
-            @Override
-            public boolean accept(File pathname) {
-                return pathname.isDirectory();
-            }
-        });
+        File[] languageDirectories = resultsDirectory.listFiles(File::isDirectory);
         List<DynamicContainer> allTests = new LinkedList<>();
         for (File languageDirectory : languageDirectories) {
             Language language = LanguageLoader.getLanguage(languageDirectory.getName()).orElseThrow();
-            File[] resultJsons = languageDirectory.listFiles(new FileFilter() {
-                @Override
-                public boolean accept(File pathname) {
-                    return !pathname.isDirectory() && pathname.getName().endsWith(".json");
-                }
-            });
+            File[] resultJsons = languageDirectory.listFiles(file -> !file.isDirectory() && file.getName().endsWith(".json"));
             List<DynamicContainer> languageTests = new LinkedList<>();
             for (File resultJson : resultJsons) {
                 List<DynamicContainer> testContainers = new LinkedList<>();
-                ResultDescription[] results = JsonHelper.getResultDescriptionFromFile(resultJson);
+                ResultDescription[] results = new ObjectMapper().readValue(resultJson, ResultDescription[].class);
                 for (var result : results) {
                     var testCases = generateTestsForResultDescription(resultJson, result, language);
                     testContainers.add(DynamicContainer.dynamicContainer("MTM: " + result.options().minimumTokenMatch(), testCases));