diff --git a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/CaughtException.java b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/CaughtException.java similarity index 97% rename from tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/CaughtException.java rename to tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/CaughtException.java index 6e89d609a..8af382234 100644 --- a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/CaughtException.java +++ b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/CaughtException.java @@ -1,4 +1,4 @@ -package fi.helsinki.cs.tmc.langs.java.testrunner; +package fi.helsinki.cs.tmc.langs; /** * Serializable form of an exception. diff --git a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCase.java b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/TestCase.java similarity index 98% rename from tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCase.java rename to tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/TestCase.java index 8cf04c7a8..a340589d0 100644 --- a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCase.java +++ b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/TestCase.java @@ -1,4 +1,4 @@ -package fi.helsinki.cs.tmc.langs.java.testrunner; +package fi.helsinki.cs.tmc.langs; import org.junit.runner.notification.Failure; diff --git a/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/DefaultFileMovingPolicy.java b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/DefaultFileMovingPolicy.java index 1f7291275..6167f857b 100644 --- a/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/DefaultFileMovingPolicy.java +++ b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/DefaultFileMovingPolicy.java @@ -8,7 +8,7 @@ public class DefaultFileMovingPolicy implements FileMovingPolicy { @Override - public boolean shouldMove(Path path) { + public boolean shouldMove(Path path, Path rootPath, Path target) { return true; } } diff --git a/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/ExtraStudentFileAwareFileMovingPolicy.java b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/ExtraStudentFileAwareFileMovingPolicy.java index 6c617ce40..18b7ffc02 100644 --- a/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/ExtraStudentFileAwareFileMovingPolicy.java +++ b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/ExtraStudentFileAwareFileMovingPolicy.java @@ -1,7 +1,16 @@ package fi.helsinki.cs.tmc.langs.sandbox; +import com.fasterxml.jackson.dataformat.yaml.snakeyaml.Yaml; + +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * An abstract {@link FileMovingPolicy} that also uses @@ -14,15 +23,19 @@ */ public abstract class ExtraStudentFileAwareFileMovingPolicy implements FileMovingPolicy { + private static final Path TMC_PROJECT_YML = Paths.get(".tmcproject.yml"); + private List extraStudentFiles; + private Path rootPath; + private Path target; /** * Determines whether a file should be moved even if it is not an ExtraStudentFile. */ - protected abstract boolean shouldMoveFile(Path path); + public abstract boolean shouldMoveFile(Path path); @Override - public boolean shouldMove(Path path) { + public boolean shouldMove(Path path, Path rootPath, Path target) { if (!path.toFile().exists()) { return false; } @@ -30,6 +43,13 @@ public boolean shouldMove(Path path) { if (path.toFile().isDirectory()) { return false; } + + if (path.getFileName().equals(TMC_PROJECT_YML)) { + return false; + } + + this.rootPath = rootPath; + this.target = target; return isExtraStudentFile(path) || shouldMoveFile(path); } @@ -58,6 +78,55 @@ private boolean isExtraStudentFile(Path path) { * and parses it for the necessary information. */ private void loadExtraStudentFileList() { + extraStudentFiles = new ArrayList<>(); + + File tmcprojectyml = this.target.toAbsolutePath().resolve(TMC_PROJECT_YML).toFile(); + + if (tmcprojectyml.exists()) { + parseExtraStudentFiles(tmcprojectyml); + } + } + + private void parseExtraStudentFiles(File file) { + String fileContents = initFileContents(file); + Yaml yaml = new Yaml(); + Object yamlSpecifications = yaml.load(fileContents); + + if (!(yamlSpecifications instanceof Map)) { + return; + } + + Map specsAsMap = (Map) yamlSpecifications; + Object files = specsAsMap.get("extra_student_files"); + addFiles(files); + } + private void addFiles(Object files) { + addAllIfList(files); + addIfString(files); + } + + private void addAllIfList(Object files) { + if (files instanceof List) { + for (Object value : (List) files) { + addIfString(value); + } + } + } + + private void addIfString(Object value) { + if (value instanceof String) { + Path path = this.rootPath.resolve((String) value); + extraStudentFiles.add(path); + } + } + + private String initFileContents(File file) { + try { + return FileUtils.readFileToString(file); + } catch (IOException e) { + e.printStackTrace(); + return ""; + } } } diff --git a/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/FileMovingPolicy.java b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/FileMovingPolicy.java index f6ffd2855..4b3fab719 100644 --- a/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/FileMovingPolicy.java +++ b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/FileMovingPolicy.java @@ -11,5 +11,5 @@ public interface FileMovingPolicy { /** * Answers whether a single file should be moved. */ - boolean shouldMove(Path path); + boolean shouldMove(Path path, Path rootPath, Path target); } diff --git a/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/SubmissionProcessor.java b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/SubmissionProcessor.java index ec53ef7ee..c779337ca 100644 --- a/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/SubmissionProcessor.java +++ b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/sandbox/SubmissionProcessor.java @@ -1,9 +1,12 @@ package fi.helsinki.cs.tmc.langs.sandbox; import java.io.IOException; -import java.nio.file.DirectoryStream; import java.nio.file.Files; +import java.nio.file.FileVisitResult; import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; import java.util.logging.Level; import java.util.logging.Logger; @@ -41,35 +44,44 @@ public SubmissionProcessor(FileMovingPolicy fileMovingPolicy) { * moved. * @param target Directory to which the source files are moved to. */ - public void moveFiles(Path source, Path target) { - try (DirectoryStream stream = Files.newDirectoryStream(source)) { - for (Path sourceFile : stream) { - if (fileMovingPolicy.shouldMove(sourceFile)) { - Path absoluteTargetPath = getAbsoluteTargetPath(source, target, sourceFile); - try { - moveFile(source, sourceFile.toAbsolutePath(), absoluteTargetPath); - } catch (IOException exception) { + public void moveFiles(final Path source, final Path target) { + try { + Files.walkFileTree(source, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + if (fileMovingPolicy.shouldMove(file, source, target)) { + try { + moveFile(source, file, target); + } catch (IOException exception) { + log.log(Level.WARNING, null, exception); + } + } + + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exception) + throws IOException { + if (exception == null) { + return FileVisitResult.CONTINUE; + } else { + // directory iteration failed log.log(Level.WARNING, null, exception); + throw exception; } } - } + }); } catch (IOException exception) { log.log(Level.WARNING, null, exception); return; } } - protected Path getAbsoluteTargetPath(Path sourceRootPath, - Path targetRootPath, - Path sourceFilePath) { - Path relativeFilePath = sourceRootPath.relativize(sourceFilePath.toAbsolutePath()); - return targetRootPath.resolve(relativeFilePath); - } - protected void moveFile(Path sourceRoot, Path sourceFile, Path target) throws IOException { Path relative = sourceRoot.relativize(sourceFile); Path targetFile = target.resolve(relative); Files.createDirectories(targetFile.getParent()); - Files.move(sourceFile, targetFile); + Files.move(sourceFile, targetFile, StandardCopyOption.REPLACE_EXISTING); } } diff --git a/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/utils/TestUtils.java b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/utils/TestUtils.java index 491ce6e77..49bc0d548 100644 --- a/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/utils/TestUtils.java +++ b/tmc-langs-framework/src/main/java/fi/helsinki/cs/tmc/langs/utils/TestUtils.java @@ -1,8 +1,12 @@ package fi.helsinki.cs.tmc.langs.utils; +import fi.helsinki.cs.tmc.langs.sandbox.ExtraStudentFileAwareFileMovingPolicy; + import com.google.common.base.Throwables; +import java.io.File; import java.io.IOException; +import java.io.PrintWriter; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; @@ -11,6 +15,7 @@ import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import java.util.List; public final class TestUtils { @@ -71,4 +76,60 @@ public FileVisitResult postVisitDirectory(Path dir, IOException ex) throws IOExc public static void removeDirRecursively(Class clazz, String location) throws IOException { removeDirRecursively(getPath(clazz, location)); } + + /** + * Collects a list of paths that are to be moved with the provided file moving policy. + */ + public static void collectPaths(final Path path, + final List toBeMoved, + final ExtraStudentFileAwareFileMovingPolicy fileMovingPolicy) + throws IOException { + Files.walkFileTree(path, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + if (fileMovingPolicy.shouldMoveFile(path.relativize(file))) { + toBeMoved.add(path.relativize(file).toString()); + } + + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exception) + throws IOException { + if (exception == null) { + return FileVisitResult.CONTINUE; + } else { + // directory iteration failed + throw exception; + } + } + }); + } + + /** + * Initializes a temporary file with content. + */ + public static File initTempFileWithContent(String prefix, String suffix, String content) + throws IOException { + return initTempFileWithContent(prefix, suffix, null, content); + } + + /** + * Initializes a temporary file in a specific directory with content. + */ + public static File initTempFileWithContent(String prefix, String suffix, File directory, + String content) throws IOException { + String suffixWithDot = "." + suffix; + File file = File.createTempFile(prefix, suffixWithDot, directory); + file.deleteOnExit(); + + PrintWriter pw = new PrintWriter(file, "UTF-8"); + pw.println(content); + pw.flush(); + pw.close(); + + return file; + } } diff --git a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/CaughtExceptionTest.java b/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/CaughtExceptionTest.java similarity index 85% rename from tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/CaughtExceptionTest.java rename to tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/CaughtExceptionTest.java index 09dff2e25..409186b90 100644 --- a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/CaughtExceptionTest.java +++ b/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/CaughtExceptionTest.java @@ -1,7 +1,9 @@ -package fi.helsinki.cs.tmc.langs.java.testrunner; +package fi.helsinki.cs.tmc.langs; import static org.junit.Assert.assertEquals; +import fi.helsinki.cs.tmc.langs.CaughtException; + import org.junit.Test; public class CaughtExceptionTest { diff --git a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseTest.java b/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/TestCaseTest.java similarity index 90% rename from tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseTest.java rename to tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/TestCaseTest.java index b2b4210e2..05c69ef53 100644 --- a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseTest.java +++ b/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/TestCaseTest.java @@ -1,8 +1,8 @@ -package fi.helsinki.cs.tmc.langs.java.testrunner; +package fi.helsinki.cs.tmc.langs; import static org.junit.Assert.assertEquals; -import fi.helsinki.cs.tmc.langs.java.testrunner.TestCase.Status; +import fi.helsinki.cs.tmc.langs.TestCase.Status; import org.junit.Test; import org.junit.runner.notification.Failure; @@ -46,5 +46,4 @@ public void testToString() { testCase.testFinished(); assertEquals("Method (Test) PASSED", testCase.toString()); } - } diff --git a/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/sandbox/ExtraStudentFileAwareFileMovingPolicyTest.java b/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/sandbox/ExtraStudentFileAwareFileMovingPolicyTest.java new file mode 100644 index 000000000..cd6c9fa2d --- /dev/null +++ b/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/sandbox/ExtraStudentFileAwareFileMovingPolicyTest.java @@ -0,0 +1,218 @@ +package fi.helsinki.cs.tmc.langs.sandbox; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.apache.commons.io.FileUtils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class ExtraStudentFileAwareFileMovingPolicyTest { + + private Path rootPath; + private Path sourceDir; + private Path targetDir; + + private SubmissionProcessor processor; + private FileMovingPolicy fileMovingPolicy; + + @Before + public void setUp() throws IOException { + + fileMovingPolicy = new ExtraStudentFileAwareFileMovingPolicy() { + @Override + public boolean shouldMoveFile(Path path) { + return false; + } + }; + processor = new SubmissionProcessor(fileMovingPolicy); + + rootPath = Files.createTempDirectory("tmc-test-submissionprocessortest"); + sourceDir = Files.createTempDirectory(rootPath, "source"); + targetDir = Files.createTempDirectory(rootPath, "target"); + } + + /** + * Delete files after tests are run. + */ + @After + public void tearDown() { + rootPath.toFile().delete(); + sourceDir.toFile().delete(); + targetDir.toFile().delete(); + } + + @Test + public void movesSingleExtraStudentFiles() throws IOException { + Path path = targetDir.resolve(".tmcproject.yml"); + Files.createFile(path); + FileUtils.write(path.toFile(), "extra_student_files: temp"); + + Path newFile = sourceDir.resolve("temp"); + Files.createFile(newFile); + FileUtils.write(newFile.toFile(), "Temporary"); + + assertTrue(fileMovingPolicy.shouldMove(newFile, sourceDir, targetDir)); + + processor.moveFiles(sourceDir, targetDir); + + Path targetFile = targetDir.resolve(sourceDir.relativize(newFile)); + + assertTrue(Files.exists(targetFile)); + assertEquals("Temporary", FileUtils.readFileToString(targetFile.toFile())); + + path.toFile().delete(); + newFile.toFile().delete(); + targetFile.toFile().delete(); + } + + @Test + public void movesMultipleExtraStudentFiles() throws IOException { + Path path = targetDir.resolve(".tmcproject.yml"); + Files.createFile(path); + FileUtils.write(path.toFile(), "extra_student_files:\n - temp\n - temporary.txt"); + + Path temp = sourceDir.resolve("temp"); + Files.createFile(temp); + FileUtils.write(temp.toFile(), "Temporary 1"); + Path temporary = sourceDir.resolve("temporary.txt"); + Files.createFile(temporary); + FileUtils.write(temporary.toFile(), "Temporary 2"); + + assertTrue(fileMovingPolicy.shouldMove(temp, sourceDir, targetDir)); + assertTrue(fileMovingPolicy.shouldMove(temporary, sourceDir, targetDir)); + + processor.moveFiles(sourceDir, targetDir); + + Path targetTemp = targetDir.resolve(sourceDir.relativize(temp)); + Path targetTemporary = targetDir.resolve(sourceDir.relativize(temporary)); + + assertTrue(Files.exists(targetTemp)); + assertTrue(Files.exists(targetTemporary)); + assertEquals("Temporary 1", FileUtils.readFileToString(targetTemp.toFile())); + assertEquals("Temporary 2", FileUtils.readFileToString(targetTemporary.toFile())); + + path.toFile().delete(); + temp.toFile().delete(); + temporary.toFile().delete(); + targetTemp.toFile().delete(); + targetTemporary.toFile().delete(); + } + + @Test + public void movesExtraStudentFilesInSubfolders() throws IOException { + Path path = targetDir.resolve(".tmcproject.yml"); + Files.createFile(path); + FileUtils.write(path.toFile(), "extra_student_files:\n - subdir/temp"); + + Path dir = sourceDir.resolve("subdir"); + Files.createDirectory(dir); + Path temp = dir.resolve("temp"); + Files.createFile(temp); + FileUtils.write(temp.toFile(), "Temporary"); + + assertTrue(fileMovingPolicy.shouldMove(temp, sourceDir, targetDir)); + + processor.moveFiles(sourceDir, targetDir); + + Path targetTemp = targetDir.resolve(sourceDir.relativize(temp)); + + assertTrue(Files.exists(targetTemp)); + assertEquals("Temporary", FileUtils.readFileToString(targetTemp.toFile())); + + path.toFile().delete(); + temp.toFile().delete(); + dir.toFile().delete(); + targetTemp.toFile().delete(); + } + + @Test + public void doesNotMoveTmcProjectYml() throws IOException { + Path path = targetDir.resolve(".tmcproject.yml"); + Files.createFile(path); + FileUtils.write(path.toFile(), "extra_student_files:\n - .tmcproject.yml"); + + Path temp = sourceDir.resolve(".tmcproject.yml"); + Files.createFile(temp); + FileUtils.write(temp.toFile(), "extra_student_files:\n - temp"); + + assertFalse(fileMovingPolicy.shouldMove(temp, sourceDir, targetDir)); + + processor.moveFiles(sourceDir, targetDir); + + Path targetTemp = targetDir.resolve(sourceDir.relativize(temp)); + + assertTrue(Files.exists(targetTemp)); + assertEquals( + "extra_student_files:\n - .tmcproject.yml", + FileUtils.readFileToString(targetTemp.toFile()) + ); + + path.toFile().delete(); + temp.toFile().delete(); + targetTemp.toFile().delete(); + } + + @Test + public void doesNotMoveDirectories() throws IOException { + Path dir = sourceDir.resolve("subdir"); + Files.createDirectory(dir); + + assertFalse(fileMovingPolicy.shouldMove(dir, sourceDir, targetDir)); + + processor.moveFiles(sourceDir, targetDir); + + Path targetSubdir = targetDir.resolve(sourceDir.relativize(dir)); + + assertFalse(Files.exists(targetSubdir)); + + dir.toFile().delete(); + targetSubdir.toFile().delete(); + } + + @Test + public void doesNotMoveNonexistentFiles() { + Path file = sourceDir.resolve("nonexistent"); + + assertFalse(fileMovingPolicy.shouldMove(file, sourceDir, targetDir)); + + processor.moveFiles(sourceDir, targetDir); + + Path targetFile = targetDir.resolve(sourceDir.relativize(file)); + + assertFalse(Files.exists(targetFile)); + + file.toFile().delete(); + targetFile.toFile().delete(); + } + + @Test + public void doesNotMoveFilesThatAreNotExtraStudentFiles() throws IOException { + Path path = targetDir.resolve(".tmcproject.yml"); + Files.createFile(path); + FileUtils.write(path.toFile(), "extra_student_files: nope"); + + Path newFile = sourceDir.resolve("temp"); + Files.createFile(newFile); + FileUtils.write(newFile.toFile(), "Temporary"); + + assertFalse(fileMovingPolicy.shouldMove(newFile, sourceDir, targetDir)); + + processor.moveFiles(sourceDir, targetDir); + + Path targetFile = targetDir.resolve(sourceDir.relativize(newFile)); + + assertFalse(Files.exists(targetFile)); + + path.toFile().delete(); + newFile.toFile().delete(); + targetFile.toFile().delete(); + } +} diff --git a/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/sandbox/SubmissionProcessorTest.java b/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/sandbox/SubmissionProcessorTest.java index 25afc661c..82b7c7715 100644 --- a/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/sandbox/SubmissionProcessorTest.java +++ b/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/sandbox/SubmissionProcessorTest.java @@ -3,6 +3,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import org.apache.commons.io.FileUtils; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -48,35 +50,51 @@ public void tearDown() { } @Test - public void getAbsoluteTargetPathSolvesCorrectTargetPathForDirectChildOfRoot() { - Path result = processor.getAbsoluteTargetPath(sourceDir, targetDir, sourceFile); - Path correct = targetDir.resolve(sourceFile.getFileName()); + public void moveFileMovesFiles() throws IOException { + processor.moveFile(sourceDir, sourceFile, targetDir); - assertEquals(correct.toAbsolutePath(), result.toAbsolutePath()); + Path targetFile = targetDir.resolve(sourceFile.getFileName()); + assertTrue(Files.exists(targetFile)); } @Test - public void getAbsoluteTargetPathSolvesCorrectTargetPathForSubPath() { - Path result = processor.getAbsoluteTargetPath(sourceDir, targetDir, subSourceFile); - Path correct = targetDir.resolve(subSourceDir.getFileName()) - .resolve(subSourceFile.getFileName()); + public void moveFileMovesFilesInSubfolders() throws IOException { + processor.moveFile(sourceDir, subSourceFile, targetDir); - assertEquals(correct.toAbsolutePath(), result.toAbsolutePath()); + Path targetFile = targetDir.resolve(sourceDir.relativize(subSourceFile)); + assertTrue(Files.exists(targetFile)); } @Test - public void moveFileMovesFiles() throws IOException { - processor.moveFile(sourceDir, sourceFile, targetDir); + public void moveFileReplacesExistingFiles() throws IOException { + Path path = targetDir.resolve("temp"); + Files.createFile(path); + FileUtils.write(path.toFile(), "Initial content"); - Path targetFile = targetDir.resolve(sourceFile.getFileName()); - assertTrue(Files.exists(targetFile)); + assertTrue(Files.exists(path)); + assertEquals("Initial content", FileUtils.readFileToString(path.toFile())); + + Path newFile = sourceDir.resolve("temp"); + Files.createFile(newFile); + FileUtils.write(newFile.toFile(), "New content"); + + processor.moveFile(sourceDir, newFile, targetDir); + + assertTrue(Files.exists(path)); + assertEquals("New content", FileUtils.readFileToString(path.toFile())); + + path.toFile().delete(); + newFile.toFile().delete(); } @Test - public void moveFileMovesFilesInSubfolders() throws IOException { - processor.moveFile(sourceDir, subSourceFile, targetDir); + public void moveFilesMovesAllFilesInDirectory() { + processor.moveFiles(sourceDir, targetDir); + + Path targetFile = targetDir.resolve(sourceFile.getFileName()); + Path targetSubFile = targetDir.resolve(sourceDir.relativize(subSourceFile)); - Path targetFile = targetDir.resolve(sourceDir.relativize(subSourceFile)); assertTrue(Files.exists(targetFile)); + assertTrue(Files.exists(targetSubFile)); } } diff --git a/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/utils/TestUtilsTest.java b/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/utils/TestUtilsTest.java index ed1538827..bb943b17f 100644 --- a/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/utils/TestUtilsTest.java +++ b/tmc-langs-framework/src/test/java/fi/helsinki/cs/tmc/langs/utils/TestUtilsTest.java @@ -1,14 +1,23 @@ package fi.helsinki.cs.tmc.langs.utils; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import fi.helsinki.cs.tmc.langs.sandbox.ExtraStudentFileAwareFileMovingPolicy; + +import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; public class TestUtilsTest { @@ -21,7 +30,7 @@ public class TestUtilsTest { @Before public void setUp() throws IOException { - dir = Files.createTempDirectory("tmc-test-resource"); + dir = Files.createTempDirectory("tmc-test-testutils"); subDir = Files.createTempDirectory(dir, "subDir"); subSubDir = Files.createTempDirectory(subDir, "subSubDir"); dirContent = Files.createTempFile(dir, "testFile", ".tmp"); @@ -29,6 +38,9 @@ public void setUp() throws IOException { subSubDirContent = Files.createTempFile(subSubDir, "subSubTestFile", ".tmp"); } + /** + * Delete files after tests are run. + */ @After public void tearDown() { subSubDirContent.toFile().delete(); @@ -72,4 +84,67 @@ public void removeDirRecursivelyRemovesDirAndSubDirs() throws IOException { assertFalse(subDirContent.toFile().exists()); assertFalse(subSubDirContent.toFile().exists()); } + + @Test + public void collectPathsCanCollectPaths() throws IOException { + List toBeMoved = new ArrayList<>(); + ExtraStudentFileAwareFileMovingPolicy fileMovingPolicy = + new ExtraStudentFileAwareFileMovingPolicy() { + @Override + public boolean shouldMoveFile(Path path) { + return true; + } + }; + + TestUtils.collectPaths(dir, toBeMoved, fileMovingPolicy); + + assertEquals(3, toBeMoved.size()); + assertTrue(toBeMoved.get(0).endsWith(".tmp")); + assertTrue(toBeMoved.get(1).endsWith(".tmp")); + assertTrue(toBeMoved.get(2).endsWith(".tmp")); + } + + @Test + public void collectPathsDoesNotCollectWrongPaths() throws IOException { + List toBeMoved = new ArrayList<>(); + ExtraStudentFileAwareFileMovingPolicy fileMovingPolicy = + new ExtraStudentFileAwareFileMovingPolicy() { + @Override + public boolean shouldMoveFile(Path path) { + return false; + } + }; + + TestUtils.collectPaths(dir, toBeMoved, fileMovingPolicy); + + assertEquals(0, toBeMoved.size()); + } + + @Test + public void initTempFileWithContent() throws IOException { + File file = TestUtils.initTempFileWithContent("temp", "tmp", "Temporary"); + + assertTrue(file.exists()); + assertTrue(file.toString().startsWith("/tmp/temp")); + assertTrue(file.toString().endsWith(".tmp")); + assertEquals("Temporary\n", FileUtils.readFileToString(file)); + + file.delete(); + } + + @Test + public void initTempFileWithContentInDirectory() throws IOException { + Path dirPath = Files.createTempDirectory("tempdir"); + File dir = dirPath.toFile(); + File file = TestUtils.initTempFileWithContent("temp", "tmp", dir, "Temporary"); + + assertTrue(file.exists()); + assertTrue(file.toString().startsWith("/tmp/temp")); + assertTrue(file.toString().endsWith(".tmp")); + assertEquals(file, dir.listFiles()[0]); + assertEquals("Temporary\n", FileUtils.readFileToString(file)); + + file.delete(); + dir.delete(); + } } diff --git a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/TestResultParser.java b/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/TestResultParser.java index 64024b115..316235c06 100644 --- a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/TestResultParser.java +++ b/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/TestResultParser.java @@ -1,8 +1,8 @@ package fi.helsinki.cs.tmc.langs.java; import fi.helsinki.cs.tmc.langs.RunResult; +import fi.helsinki.cs.tmc.langs.TestCase; import fi.helsinki.cs.tmc.langs.TestResult; -import fi.helsinki.cs.tmc.langs.java.testrunner.TestCase; import fi.helsinki.cs.tmc.langs.java.testrunner.TestCaseList; import com.google.common.base.Throwables; diff --git a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/ant/AntFileMovingPolicy.java b/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/ant/AntFileMovingPolicy.java index 3bb0cd844..1e3e863f4 100644 --- a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/ant/AntFileMovingPolicy.java +++ b/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/ant/AntFileMovingPolicy.java @@ -3,6 +3,7 @@ import fi.helsinki.cs.tmc.langs.sandbox.ExtraStudentFileAwareFileMovingPolicy; import java.nio.file.Path; +import java.nio.file.Paths; public class AntFileMovingPolicy extends ExtraStudentFileAwareFileMovingPolicy { @@ -15,7 +16,7 @@ public class AntFileMovingPolicy extends ExtraStudentFileAwareFileMovingPolicy { * decision to move them is made by {@link ExtraStudentFileAwareFileMovingPolicy}. */ @Override - protected boolean shouldMoveFile(Path path) { - throw new UnsupportedOperationException(); + public boolean shouldMoveFile(Path path) { + return path.startsWith(Paths.get("src")); } } diff --git a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/maven/MavenFileMovingPolicy.java b/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/maven/MavenFileMovingPolicy.java index 3d735d374..bebb81be3 100644 --- a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/maven/MavenFileMovingPolicy.java +++ b/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/maven/MavenFileMovingPolicy.java @@ -3,6 +3,7 @@ import fi.helsinki.cs.tmc.langs.sandbox.ExtraStudentFileAwareFileMovingPolicy; import java.nio.file.Path; +import java.nio.file.Paths; public class MavenFileMovingPolicy extends ExtraStudentFileAwareFileMovingPolicy { @@ -15,7 +16,7 @@ public class MavenFileMovingPolicy extends ExtraStudentFileAwareFileMovingPolicy * decision to move them is made by {@link ExtraStudentFileAwareFileMovingPolicy}. */ @Override - protected boolean shouldMoveFile(Path path) { - throw new UnsupportedOperationException(); + public boolean shouldMoveFile(Path path) { + return path.startsWith(Paths.get("src", "main")); } } diff --git a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseList.java b/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseList.java index e36d6dfb6..034dad29d 100644 --- a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseList.java +++ b/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseList.java @@ -1,6 +1,7 @@ package fi.helsinki.cs.tmc.langs.java.testrunner; import fi.helsinki.cs.tmc.langs.ExerciseDesc; +import fi.helsinki.cs.tmc.langs.TestCase; import fi.helsinki.cs.tmc.langs.TestDesc; import com.google.common.base.Optional; diff --git a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestRunner.java b/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestRunner.java index 44fba6357..8b7450fa1 100644 --- a/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestRunner.java +++ b/tmc-langs-java/src/main/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestRunner.java @@ -1,5 +1,8 @@ package fi.helsinki.cs.tmc.langs.java.testrunner; +import fi.helsinki.cs.tmc.langs.CaughtException; +import fi.helsinki.cs.tmc.langs.TestCase; + import org.junit.runner.Description; import org.junit.runner.Result; import org.junit.runner.Runner; diff --git a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/ant/AntFileMovingPolicyTest.java b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/ant/AntFileMovingPolicyTest.java new file mode 100644 index 000000000..40d37df94 --- /dev/null +++ b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/ant/AntFileMovingPolicyTest.java @@ -0,0 +1,75 @@ +package fi.helsinki.cs.tmc.langs.java.ant; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import fi.helsinki.cs.tmc.langs.utils.TestUtils; + +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public class AntFileMovingPolicyTest { + + private AntFileMovingPolicy antFileMovingPolicy; + + public AntFileMovingPolicyTest() { + antFileMovingPolicy = new AntFileMovingPolicy(); + } + + @Test + public void testItDoesNotMoveBuildXml() throws IOException { + Path build = Paths.get("build.xml"); + assertFalse(antFileMovingPolicy.shouldMoveFile(build)); + } + + @Test + public void testItMovesFilesInSrc() throws IOException { + final Path path = TestUtils.getPath(getClass(), "ant_arith_funcs"); + final List toBeMoved = new ArrayList<>(); + + TestUtils.collectPaths(path, toBeMoved, antFileMovingPolicy); + + assertEquals(1, toBeMoved.size()); + assertTrue(toBeMoved.contains("src" + File.separatorChar + "Arith.java")); + } + + @Test + public void testItDoesNotMoveFilesInTest() throws IOException { + final Path path = TestUtils.getPath(getClass(), "ant_arith_funcs"); + final List toBeMoved = new ArrayList<>(); + + TestUtils.collectPaths(path, toBeMoved, antFileMovingPolicy); + + assertEquals(1, toBeMoved.size()); + assertFalse(toBeMoved.contains("test" + File.separatorChar + "ArithTest.java")); + } + + @Test + public void testItDoesNotMoveFilesInLib() throws IOException { + final Path path = TestUtils.getPath(getClass(), "ant_arith_funcs"); + final List toBeMoved = new ArrayList<>(); + + TestUtils.collectPaths(path, toBeMoved, antFileMovingPolicy); + + assertEquals(1, toBeMoved.size()); + assertFalse(toBeMoved.contains("lib" + + File.separatorChar + "edu-test-utils-0.4.1.jar")); + assertFalse(toBeMoved.contains("lib" + + File.separatorChar + "junit-4.10.jar")); + assertFalse(toBeMoved.contains("lib" + File.separatorChar + "testrunner" + + File.separatorChar + "gson-2.2.4.jar")); + assertFalse(toBeMoved.contains("lib" + File.separatorChar + "testrunner" + + File.separatorChar + "hamcrest-core-1.3.jar")); + assertFalse(toBeMoved.contains("lib" + File.separatorChar + "testrunner" + + File.separatorChar + "junit-4.11.jar")); + assertFalse(toBeMoved.contains("lib" + File.separatorChar + "testrunner" + + File.separatorChar + "tmc-junit-runner.jar")); + } +} \ No newline at end of file diff --git a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/maven/MavenFileMovingPolicyTest.java b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/maven/MavenFileMovingPolicyTest.java new file mode 100644 index 000000000..2bd96af3e --- /dev/null +++ b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/maven/MavenFileMovingPolicyTest.java @@ -0,0 +1,85 @@ +package fi.helsinki.cs.tmc.langs.java.maven; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import fi.helsinki.cs.tmc.langs.utils.TestUtils; + +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public class MavenFileMovingPolicyTest { + + private MavenFileMovingPolicy mavenFileMovingPolicy; + + public MavenFileMovingPolicyTest() { + mavenFileMovingPolicy = new MavenFileMovingPolicy(); + } + + @Test + public void testItDoesNotMovePomXml() throws IOException { + Path pom = Paths.get("pom.xml"); + assertFalse(mavenFileMovingPolicy.shouldMoveFile(pom)); + } + + @Test + public void testItMovesFilesInSrcMain() throws IOException { + final Path path = TestUtils.getPath(getClass(), "maven_exercise"); + final List toBeMoved = new ArrayList<>(); + + TestUtils.collectPaths(path, toBeMoved, mavenFileMovingPolicy); + + assertEquals(1, toBeMoved.size()); + assertTrue(toBeMoved.contains("src" + + File.separatorChar + "main" + + File.separatorChar + "java" + + File.separatorChar + "fi" + + File.separatorChar + "helsinki" + + File.separatorChar + "cs" + + File.separatorChar + "maventest" + + File.separatorChar + "App.java")); + } + + @Test + public void testItDoesNotMoveFilesInSrcTest() throws IOException { + final Path path = TestUtils.getPath(getClass(), "maven_exercise"); + final List toBeMoved = new ArrayList<>(); + + TestUtils.collectPaths(path, toBeMoved, mavenFileMovingPolicy); + + assertEquals(1, toBeMoved.size()); + assertFalse(toBeMoved.contains("src" + + File.separatorChar + "test" + + File.separatorChar + "java" + + File.separatorChar + "fi" + + File.separatorChar + "helsinki" + + File.separatorChar + "cs" + + File.separatorChar + "maventest" + + File.separatorChar + "AppTest.java")); + } + + @Test + public void testItDoesNotMoveFilesInLib() throws IOException { + final Path path = TestUtils.getPath(getClass(), "maven_exercise"); + final List toBeMoved = new ArrayList<>(); + + TestUtils.collectPaths(path, toBeMoved, mavenFileMovingPolicy); + + assertEquals(1, toBeMoved.size()); + assertFalse(toBeMoved.contains("lib" + File.separatorChar + "testrunner" + + File.separatorChar + "gson-2.2.4.jar")); + assertFalse(toBeMoved.contains("lib" + File.separatorChar + "testrunner" + + File.separatorChar + "hamcrest-core-1.3.jar")); + assertFalse(toBeMoved.contains("lib" + File.separatorChar + "testrunner" + + File.separatorChar + "junit-4.11.jar")); + assertFalse(toBeMoved.contains("lib" + File.separatorChar + "testrunner" + + File.separatorChar + "tmc-junit-runner.jar")); + } +} \ No newline at end of file diff --git a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/maven/MavenPluginTest.java b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/maven/MavenPluginTest.java index c3361df86..9a7a85505 100644 --- a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/maven/MavenPluginTest.java +++ b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/maven/MavenPluginTest.java @@ -20,7 +20,7 @@ public class MavenPluginTest { - MavenPlugin mavenPlugin; + private MavenPlugin mavenPlugin; public MavenPluginTest() { mavenPlugin = new MavenPlugin(); diff --git a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseFailureMessageTest.java b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseFailureMessageTest.java index 3abad9e42..d1e738868 100644 --- a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseFailureMessageTest.java +++ b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseFailureMessageTest.java @@ -2,6 +2,8 @@ import static org.junit.Assert.assertEquals; +import fi.helsinki.cs.tmc.langs.TestCase; + import org.junit.Before; import org.junit.Test; import org.junit.runner.Description; diff --git a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseListTest.java b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseListTest.java index b1b880b0a..d26d792d5 100644 --- a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseListTest.java +++ b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestCaseListTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertEquals; import fi.helsinki.cs.tmc.langs.ExerciseDesc; +import fi.helsinki.cs.tmc.langs.TestCase; import fi.helsinki.cs.tmc.langs.TestDesc; import com.google.common.base.Optional; diff --git a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestRunnerTest.java b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestRunnerTest.java index f4cd284e8..d78119b1b 100644 --- a/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestRunnerTest.java +++ b/tmc-langs-java/src/test/java/fi/helsinki/cs/tmc/langs/java/testrunner/TestRunnerTest.java @@ -5,6 +5,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import fi.helsinki.cs.tmc.langs.TestCase; + import org.junit.Test; public class TestRunnerTest {