Initial implementations

This commit is contained in:
Gleb Koval 2023-12-20 13:12:52 +00:00
parent 9489e6048c
commit f9ab02c68d
Signed by: cyclane
GPG Key ID: 15E168A8B332382C
6 changed files with 117 additions and 5 deletions

3
.gitignore vendored
View File

@ -40,3 +40,6 @@ bin/
### Mac OS ### ### Mac OS ###
.DS_Store .DS_Store
### Custom ###
_tmp/

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>

View File

@ -4,7 +4,7 @@
<component name="FrameworkDetectionExcludesConfiguration"> <component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" /> <file type="web" url="file://$PROJECT_DIR$" />
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="corretto-19" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="corretto-19" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View File

@ -18,5 +18,5 @@ tasks.test {
} }
kotlin { kotlin {
jvmToolchain(8) jvmToolchain(11)
} }

View File

@ -1,9 +1,13 @@
package filesystem package filesystem
import java.nio.file.FileAlreadyExistsException
import java.nio.file.FileSystemException
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
class FSCreator { class FSCreator {
// Create entry, leaving existing folders' contents, but overwriting existing files.
@Throws(FileSystemException::class)
fun create(entryToCreate: FSEntry, destination: String) { fun create(entryToCreate: FSEntry, destination: String) {
val queue = ArrayDeque<Pair<FSEntry, Path>>() val queue = ArrayDeque<Pair<FSEntry, Path>>()
queue.add(entryToCreate to Path.of(destination)) queue.add(entryToCreate to Path.of(destination))
@ -17,8 +21,9 @@ class FSCreator {
is FSFolder -> Files.createDirectory(path) is FSFolder -> Files.createDirectory(path)
} }
} catch (_: FileAlreadyExistsException) {} // Allow files/folders to already exist. } catch (_: FileAlreadyExistsException) {} // Allow files/folders to already exist.
if (entry is FSFolder) { when (entry) {
queue.addAll(entry.entries.map { it to path }) is FSFile -> Files.write(path, entry.content.toByteArray())
is FSFolder -> queue.addAll(entry.entries.map { it to path })
} }
} }
} }

View File

@ -0,0 +1,103 @@
package filesystem
import org.junit.jupiter.api.*
import java.nio.file.FileSystemException
import java.nio.file.Files
import java.nio.file.Path
import java.util.concurrent.TimeUnit
import kotlin.test.Test
import kotlin.test.assertEquals
class FSCreatorTest {
private val creator = FSCreator()
@BeforeEach
fun `before each`() {
assertDoesNotThrow("should create _tmp directory") {
Files.createDirectory(Path.of("_tmp"))
}
}
@AfterEach
fun `after each`() {
assertDoesNotThrow("should delete _tmp directory") {
deleteRecursive(Path.of("_tmp"))
}
}
@Test
fun `create entries`() {
val readme = FSFile("README", "Hello World!")
val gomod = FSFile("go.mod", "module example.com/hello-world\n\ngo1.21.5")
val maingo = FSFile("main.go", "package main\n\nimport \"example.com/hello-world/utils\"\n\n" +
"func main() {\n\tprintln(\"Hello World!\")\n}")
val helloworldgo = FSFile("hello-world.go", "package utils\n\nfunc PrintHelloWorld() {\n" +
"\tprintln(\"Hello World!\")\n}")
assertDoesNotThrow("should create entries") {
creator.create(FSFolder("folder", listOf(
readme,
gomod,
maingo,
FSFolder("utils", listOf(
helloworldgo
))
)), "_tmp")
}
// If objects don't exist, these functions will throw anyway, so don't explicitly check for existence.
// Similarly, don't explicitly check if an object is a directory.
assertEquals(readme.content, Files.readString(Path.of("_tmp/folder", readme.name)))
assertEquals(gomod.content, Files.readString(Path.of("_tmp/folder", gomod.name)))
assertEquals(maingo.content, Files.readString(Path.of("_tmp/folder", maingo.name)))
assertEquals(helloworldgo.content, Files.readString(Path.of("_tmp/folder/utils", helloworldgo.name)))
}
@Test
fun `create existing entries`() {
assertDoesNotThrow("creation one") {
creator.create(FSFolder("folder", listOf(
FSFolder("sub-folder", listOf(
FSFile("hi", "hi")
)),
FSFolder("another-folder", listOf()),
FSFile("1.txt", "One!"),
FSFile("2.txt", "Two!")
)), "_tmp")
}
assertDoesNotThrow("creation two") {
creator.create(FSFolder("folder", listOf(
FSFolder("another-folder", listOf(
FSFolder("secrets", listOf(
FSFile("secret", "P4ssW0rd")
))
)),
FSFile("1.txt", "One is a good number"),
FSFile("3.txt", "Three!")
)), "_tmp")
}
assertEquals("hi", Files.readString(Path.of("_tmp/folder/sub-folder/hi")))
assertEquals("P4ssW0rd", Files.readString(Path.of("_tmp/folder/another-folder/secrets/secret")))
assertEquals("One is a good number", Files.readString(Path.of("_tmp/folder/1.txt")))
assertEquals("Two!", Files.readString(Path.of("_tmp/folder/2.txt")))
assertEquals("Three!", Files.readString(Path.of("_tmp/folder/3.txt")))
}
@Test
@Timeout(500, unit = TimeUnit.MILLISECONDS) // in case implementation starts trying to handle recursion
fun `create throws on recursive folder`() {
val files = mutableListOf<FSEntry>()
val folder = FSFolder("folder", files)
files.add(folder)
assertThrows<FileSystemException> {
creator.create(folder, "_tmp")
}
}
}
fun deleteRecursive(path: Path) {
if (Files.isDirectory(path)) {
for (child in Files.list(path)) {
deleteRecursive(child)
}
}
Files.delete(path)
}