From e6b1ba3b451de958bd5e36c8629358c9cade6036 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Mon, 3 Jan 2022 13:44:23 -0500 Subject: [PATCH] #18 Add FileCache --- .../service/RecipeService.kt | 32 ++-- .../service/files/FileCache.kt | 150 ++++++++++++++++++ .../service/files/FileExistCache.kt | 32 ---- .../service/files/FileService.kt | 61 +++++-- .../service/files/ResourceFileService.kt | 17 +- .../fyloz/colorrecipesexplorer/utils/Files.kt | 9 ++ src/main/resources/logback.xml | 6 +- .../service/RecipeServiceTest.kt | 41 +++-- .../service/files/FileServiceTest.kt | 36 ++--- .../service/files/ResourceFileServiceTest.kt | 10 +- 10 files changed, 276 insertions(+), 118 deletions(-) create mode 100644 src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileCache.kt delete mode 100644 src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileExistCache.kt diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeService.kt index dd9eccd..d900aef 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeService.kt @@ -1,5 +1,6 @@ package dev.fyloz.colorrecipesexplorer.service +import dev.fyloz.colorrecipesexplorer.config.annotations.RequireDatabase import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.model.account.Group import dev.fyloz.colorrecipesexplorer.model.validation.or @@ -9,10 +10,8 @@ import dev.fyloz.colorrecipesexplorer.service.files.WriteableFileService import dev.fyloz.colorrecipesexplorer.service.users.GroupService import dev.fyloz.colorrecipesexplorer.utils.setAll import org.springframework.context.annotation.Lazy -import org.springframework.context.annotation.Profile import org.springframework.stereotype.Service import org.springframework.web.multipart.MultipartFile -import java.io.File import java.time.LocalDate import java.time.Period import javax.transaction.Transactional @@ -45,7 +44,7 @@ interface RecipeService : } @Service -@Profile("!emergency") +@RequireDatabase class RecipeServiceImpl( recipeRepository: RecipeRepository, val companyService: CompanyService, @@ -213,29 +212,20 @@ interface RecipeImageService { /** Deletes the image with the given [name] for the given [recipe]. */ fun delete(recipe: Recipe, name: String) - - /** Gets the directory containing all images of the given [Recipe]. */ - fun Recipe.getDirectory(): File } const val RECIPE_IMAGE_ID_DELIMITER = "_" const val RECIPE_IMAGE_EXTENSION = ".jpg" @Service -@Profile("!emergency") +@RequireDatabase class RecipeImageServiceImpl( val fileService: WriteableFileService ) : RecipeImageService { - override fun getAllImages(recipe: Recipe): Set { - val recipeDirectory = recipe.getDirectory() - if (!recipeDirectory.exists() || !recipeDirectory.isDirectory) { - return setOf() - } - return recipeDirectory.listFiles()!! // Should never be null because we check if recipeDirectory exists and is a directory before - .filterNotNull() + override fun getAllImages(recipe: Recipe) = + fileService.listDirectoryFiles(recipe.imagesDirectoryPath) .map { it.name } .toSet() - } override fun download(image: MultipartFile, recipe: Recipe): String { /** Gets the next id available for a new image for the given [recipe]. */ @@ -252,17 +242,15 @@ class RecipeImageServiceImpl( } + 1L } - return getImageFileName(recipe, getNextAvailableId()).apply { - fileService.write(image, getImagePath(recipe, this), true) + return getImageFileName(recipe, getNextAvailableId()).also { + with(getImagePath(recipe, it)) { + fileService.writeToDirectory(image, this, recipe.imagesDirectoryPath, true) + } } } override fun delete(recipe: Recipe, name: String) = - fileService.delete(getImagePath(recipe, name)) - - override fun Recipe.getDirectory(): File = File(with(fileService) { - this@getDirectory.imagesDirectoryPath.fullPath().path - }) + fileService.deleteFromDirectory(getImagePath(recipe, name), recipe.imagesDirectoryPath) private fun getImageFileName(recipe: Recipe, id: Long) = "${recipe.name}$RECIPE_IMAGE_ID_DELIMITER$id" diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileCache.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileCache.kt new file mode 100644 index 0000000..4ee0260 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileCache.kt @@ -0,0 +1,150 @@ +package dev.fyloz.colorrecipesexplorer.service.files + +import dev.fyloz.colorrecipesexplorer.JavaFile +import dev.fyloz.colorrecipesexplorer.utils.File +import dev.fyloz.colorrecipesexplorer.utils.FilePath +import mu.KotlinLogging + +object FileCache { + private val logger = KotlinLogging.logger {} + private val cache = hashMapOf() + + operator fun contains(filePath: FilePath) = + filePath.path in cache + + operator fun get(filePath: FilePath) = + cache[filePath.path] + + fun getDirectory(filePath: FilePath) = + if (directoryExists(filePath)) { + this[filePath] as CachedDirectory + } else { + null + } + + fun getFile(filePath: FilePath) = + if (fileExists(filePath)) { + this[filePath] as CachedFile + } else { + null + } + + private operator fun set(filePath: FilePath, item: CachedFileSystemItem) { + cache[filePath.path] = item + } + + fun exists(filePath: FilePath) = + filePath in this && cache[filePath.path]!!.exists + + fun directoryExists(filePath: FilePath) = + exists(filePath) && this[filePath] is CachedDirectory + + fun fileExists(filePath: FilePath) = + exists(filePath) && this[filePath] is CachedFile + + fun setExists(filePath: FilePath, exists: Boolean = true) { + if (filePath !in this) { + load(filePath) + } + + this[filePath] = this[filePath]!!.clone(exists) + logger.debug("Updated FileCache state: ${filePath.path} exists -> $exists") + } + + fun setDoesNotExists(filePath: FilePath) = + setExists(filePath, false) + + fun load(filePath: FilePath) = + with(JavaFile(filePath.path).toFileSystemItem()) { + cache[filePath.path] = this + + logger.debug("Loaded file at ${filePath.path} into FileCache") + } + + fun addContent(filePath: FilePath, childFilePath: FilePath) { + val directory = prepareDirectory(filePath) ?: return + + val updatedContent = setOf( + *directory.content.toTypedArray(), + JavaFile(childFilePath.path).toFileSystemItem() + ) + + this[filePath] = directory.copy(content = updatedContent) + logger.debug("Added child ${childFilePath.path} to ${filePath.path} in FileCache") + } + + fun removeContent(filePath: FilePath, childFilePath: FilePath) { + val directory = prepareDirectory(filePath) ?: return + + val updatedContent = directory.content + .filter { it.path.path != childFilePath.path } + .toSet() + + this[filePath] = directory.copy(content = updatedContent) + logger.debug("Removed child ${childFilePath.path} from ${filePath.path} in FileCache") + } + + private fun prepareDirectory(filePath: FilePath): CachedDirectory? { + if (!directoryExists(filePath)) { + logger.warn("Cannot add child to ${filePath.path} because it is not in the cache") + return null + } + + val directory = getDirectory(filePath) + if (directory == null) { + logger.warn("Cannot add child to ${filePath.path} because it is not a directory") + return null + } + + return directory + } +} + +interface CachedFileSystemItem { + val name: String + val path: FilePath + val exists: Boolean + + fun clone(exists: Boolean): CachedFileSystemItem +} + +data class CachedFile( + override val name: String, + override val path: FilePath, + override val exists: Boolean +) : CachedFileSystemItem { + constructor(file: File) : this(file.name, file.toFilePath(), file.exists() && file.isFile) + + override fun clone(exists: Boolean) = + this.copy(exists = exists) +} + +data class CachedDirectory( + override val name: String, + override val path: FilePath, + override val exists: Boolean, + val content: Set = setOf() +) : CachedFileSystemItem { + constructor(file: File) : this(file.name, file.toFilePath(), file.exists() && file.isDirectory, file.fetchContent()) + + val contentFiles: Collection + get() = content.filterIsInstance() + + override fun clone(exists: Boolean) = + this.copy(exists = exists) + + companion object { + private fun File.fetchContent() = + (this.file.listFiles() ?: arrayOf()) + .filterNotNull() + .map { it.toFileSystemItem() } + .toSet() + } +} + +fun JavaFile.toFileSystemItem() = + if (this.isDirectory) { + CachedDirectory(File(this)) + } else { + CachedFile(File(this)) + } \ No newline at end of file diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileExistCache.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileExistCache.kt deleted file mode 100644 index 783262b..0000000 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileExistCache.kt +++ /dev/null @@ -1,32 +0,0 @@ -package dev.fyloz.colorrecipesexplorer.service.files - -import dev.fyloz.colorrecipesexplorer.utils.FilePath -import mu.KotlinLogging - -object FileExistCache { - private val logger = KotlinLogging.logger {} - private val map = hashMapOf() - - /** Checks if the given [path] is in the cache. */ - operator fun contains(path: FilePath) = - path.path in map - - /** Checks if the file at the given [path] exists. */ - fun exists(path: FilePath) = - map[path.path] ?: false - - /** Sets the file at the given [path] as existing. */ - fun setExists(path: FilePath) = - set(path, true) - - /** Sets the file at the given [path] as not existing. */ - fun setDoesNotExists(path: FilePath) = - set(path, false) - - /** Sets if the file at the given [path] [exists]. */ - fun set(path: FilePath, exists: Boolean) { - map[path.path] = exists - - logger.debug("Updated FileExistCache state: ${path.path} -> $exists") - } -} \ No newline at end of file diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileService.kt index 0179a47..aa5abd2 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileService.kt @@ -28,8 +28,11 @@ interface FileService { /** Reads the file at the given [path]. */ fun read(path: String): Resource + /** List the files contained in the folder at the given [path]. Returns an empty collection if the directory does not exist. */ + fun listDirectoryFiles(path: String): Collection + /** Completes the path of the given [String] by adding the working directory. */ - fun String.fullPath(): FilePath + fun fullPath(path: String): FilePath } interface WriteableFileService : FileService { @@ -42,8 +45,14 @@ interface WriteableFileService : FileService { /** Writes the given [data] to the given [path]. If the file at the path already exists, it will be overwritten if [overwrite] is enabled. */ fun write(data: ByteArrayResource, path: String, overwrite: Boolean) + /** Writes the given [data] to the given [path], and specify the [parentPath]. If the file at the path already exists, it will be overwritten if [overwrite] is enabled. */ + fun writeToDirectory(data: MultipartFile, path: String, parentPath: String, overwrite: Boolean) + /** Deletes the file at the given [path]. */ fun delete(path: String) + + /** Deletes the file at the given [path], and specify the [parentPath]. */ + fun deleteFromDirectory(path: String, parentPath: String) } @Service @@ -53,20 +62,20 @@ class FileServiceImpl( private val logger = KotlinLogging.logger {} override fun exists(path: String): Boolean { - val fullPath = path.fullPath() - return if (fullPath in FileExistCache) { - FileExistCache.exists(fullPath) + val fullPath = fullPath(path) + return if (fullPath in FileCache) { + FileCache.exists(fullPath) } else { withFileAt(fullPath) { (this.exists() && this.isFile).also { - FileExistCache.set(fullPath, it) + FileCache.setExists(fullPath, it) } } } } override fun read(path: String) = ByteArrayResource( - withFileAt(path.fullPath()) { + withFileAt(fullPath(path)) { if (!exists(path)) throw FileNotFoundException(path) try { readBytes() @@ -76,13 +85,23 @@ class FileServiceImpl( } ) + override fun listDirectoryFiles(path: String): Collection = + with(fullPath(path)) { + if (this !in FileCache) { + FileCache.load(this) + } + + (FileCache.getDirectory(this) ?: return setOf()) + .contentFiles + } + override fun create(path: String) { - val fullPath = path.fullPath() + val fullPath = fullPath(path) if (!exists(path)) { try { withFileAt(fullPath) { this.create() - FileExistCache.setExists(fullPath) + FileCache.setExists(fullPath) logger.info("Created file at '${fullPath.path}'") } @@ -104,14 +123,19 @@ class FileServiceImpl( this.writeBytes(data.byteArray) } + override fun writeToDirectory(data: MultipartFile, path: String, parentPath: String, overwrite: Boolean) { + FileCache.addContent(fullPath(parentPath), fullPath(path)) + write(data, path, overwrite) + } + override fun delete(path: String) { try { - val fullPath = path.fullPath() + val fullPath = fullPath(path) withFileAt(fullPath) { if (!exists(path)) throw FileNotFoundException(path) this.delete() - FileExistCache.setDoesNotExists(fullPath) + FileCache.setDoesNotExists(fullPath) logger.info("Deleted file at '${fullPath.path}'") } @@ -120,16 +144,21 @@ class FileServiceImpl( } } - override fun String.fullPath(): FilePath { - BANNED_FILE_PATH_SHARDS - .firstOrNull { this.contains(it) } - ?.let { throw InvalidFilePathException(this, it) } + override fun deleteFromDirectory(path: String, parentPath: String) { + FileCache.removeContent(fullPath(parentPath), fullPath(path)) + delete(path) + } - return FilePath("${creProperties.dataDirectory}/$this") + override fun fullPath(path: String): FilePath { + BANNED_FILE_PATH_SHARDS + .firstOrNull { path.contains(it) } + ?.let { throw InvalidFilePathException(path, it) } + + return FilePath("${creProperties.dataDirectory}/$path") } private fun prepareWrite(path: String, overwrite: Boolean, op: File.() -> Unit) { - val fullPath = path.fullPath() + val fullPath = fullPath(path) if (exists(path)) { if (!overwrite) throw FileExistsException(path) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/ResourceFileService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/ResourceFileService.kt index d33bc9e..5c4d116 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/ResourceFileService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/ResourceFileService.kt @@ -10,17 +10,26 @@ class ResourceFileService( private val resourceLoader: ResourceLoader ) : FileService { override fun exists(path: String) = - path.fullPath().resource.exists() + fullPath(path).resource.exists() override fun read(path: String): Resource = - path.fullPath().resource.also { + fullPath(path).resource.also { if (!it.exists()) { throw FileNotFoundException(path) } } - override fun String.fullPath() = - FilePath("classpath:${this}") + override fun listDirectoryFiles(path: String): Collection { + val content = fullPath(path).resource.file.listFiles() ?: return setOf() + + return content + .filterNotNull() + .filter { it.isFile } + .map { it.toFileSystemItem() as CachedFile } + } + + override fun fullPath(path: String) = + FilePath("classpath:${path}") val FilePath.resource: Resource get() = resourceLoader.getResource(this.path) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/utils/Files.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/utils/Files.kt index 6efb4fb..d336667 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/utils/Files.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/utils/Files.kt @@ -6,12 +6,21 @@ import java.nio.file.Path /** Mockable file wrapper, to prevent issues when mocking [java.io.File]. */ class File(val file: JavaFile) { + val name: String + get() = file.name + val isFile: Boolean get() = file.isFile + val isDirectory: Boolean + get() = file.isDirectory + fun toPath(): Path = file.toPath() + fun toFilePath(): FilePath = + FilePath(file.path) + fun exists() = file.exists() diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index a338b2c..1ecd253 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -8,9 +8,9 @@ %green(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{36}): %msg%n%throwable - - - + + INFO + diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeServiceTest.kt index ede2dce..0e51c72 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeServiceTest.kt @@ -6,8 +6,10 @@ import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.model.account.group import dev.fyloz.colorrecipesexplorer.repository.RecipeRepository import dev.fyloz.colorrecipesexplorer.service.config.ConfigurationService +import dev.fyloz.colorrecipesexplorer.service.files.CachedFile import dev.fyloz.colorrecipesexplorer.service.files.WriteableFileService import dev.fyloz.colorrecipesexplorer.service.users.GroupService +import dev.fyloz.colorrecipesexplorer.utils.FilePath import io.mockk.* import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test @@ -15,7 +17,6 @@ import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.assertThrows import org.springframework.mock.web.MockMultipartFile import org.springframework.web.multipart.MultipartFile -import java.io.File import java.time.LocalDate import java.time.Period import kotlin.test.* @@ -30,7 +31,17 @@ class RecipeServiceTest : private val recipeStepService: RecipeStepService = mock() private val configService: ConfigurationService = mock() override val service: RecipeService = - spy(RecipeServiceImpl(repository, companyService, mixService, recipeStepService, groupService, mock(), configService)) + spy( + RecipeServiceImpl( + repository, + companyService, + mixService, + recipeStepService, + groupService, + mock(), + configService + ) + ) private val company: Company = company(id = 0L) override val entity: Recipe = recipe(id = 0L, name = "recipe", company = company) @@ -273,18 +284,7 @@ private class RecipeImageServiceTestContext { val recipe = spyk(recipe()) val recipeImagesIds = setOf(1L, 10L, 21L) val recipeImagesNames = recipeImagesIds.map { it.imageName }.toSet() - val recipeImagesFiles = recipeImagesNames.map { File(it) }.toTypedArray() - val recipeDirectory = mockk { - every { exists() } returns true - every { isDirectory } returns true - every { listFiles() } returns recipeImagesFiles - } - - init { - with(recipeImageService) { - every { recipe.getDirectory() } returns recipeDirectory - } - } + val recipeImagesFiles = recipeImagesNames.map { CachedFile(it, FilePath(it), true) } val Long.imageName get() = "${recipe.name}$RECIPE_IMAGE_ID_DELIMITER$this" @@ -308,6 +308,8 @@ class RecipeImageServiceTest { @Test fun `getAllImages() returns a Set containing the name of every files in the recipe's directory`() { test { + every { fileService.listDirectoryFiles(any()) } returns recipeImagesFiles + val foundImagesNames = recipeImageService.getAllImages(recipe) assertEquals(recipeImagesNames, foundImagesNames) @@ -317,7 +319,7 @@ class RecipeImageServiceTest { @Test fun `getAllImages() returns an empty Set when the recipe's directory does not exists`() { test { - every { recipeDirectory.exists() } returns false + every { fileService.listDirectoryFiles(any()) } returns emptySet() assertTrue { recipeImageService.getAllImages(recipe).isEmpty() @@ -335,12 +337,15 @@ class RecipeImageServiceTest { val expectedImageName = expectedImageId.imageName val expectedImagePath = expectedImageName.imagePath + every { fileService.listDirectoryFiles(any()) } returns recipeImagesFiles + every { fileService.writeToDirectory(any(), any(), any(), any()) } just runs + val foundImageName = recipeImageService.download(mockImage, recipe) assertEquals(expectedImageName, foundImageName) verify { - fileService.write(mockImage, expectedImagePath, true) + fileService.writeToDirectory(mockImage, expectedImagePath, any(), true) } } } @@ -353,10 +358,12 @@ class RecipeImageServiceTest { val imageName = recipeImagesIds.first().imageName val imagePath = imageName.imagePath + every { fileService.deleteFromDirectory(any(), any()) } just runs + recipeImageService.delete(recipe, imageName) verify { - fileService.delete(imagePath) + fileService.deleteFromDirectory(imagePath, any()) } } } diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileServiceTest.kt index 355e949..44a6990 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileServiceTest.kt @@ -43,8 +43,8 @@ class FileServiceTest { } private fun whenFileCached(cached: Boolean = true, test: () -> Unit) { - mockkObject(FileExistCache) { - every { FileExistCache.contains(any()) } returns cached + mockkObject(FileCache) { + every { FileCache.contains(any()) } returns cached test() } @@ -106,34 +106,34 @@ class FileServiceTest { @Test fun `exists() returns true when the file at the given path is cached as existing`() { whenFileCached { - every { FileExistCache.exists(any()) } returns true + every { FileCache.exists(any()) } returns true assertTrue { fileService.exists(mockFilePath) } verify { - FileExistCache.contains(any()) - FileExistCache.exists(any()) + FileCache.contains(any()) + FileCache.exists(any()) mockFile wasNot called } - confirmVerified(FileExistCache, mockFile) + confirmVerified(FileCache, mockFile) } } @Test fun `exists() returns false when the file at the given path is cached as not existing`() { whenFileCached { - every { FileExistCache.exists(any()) } returns false + every { FileCache.exists(any()) } returns false assertFalse { fileService.exists(mockFilePath) } verify { - FileExistCache.contains(any()) - FileExistCache.exists(any()) + FileCache.contains(any()) + FileCache.exists(any()) mockFile wasNot called } - confirmVerified(FileExistCache, mockFile) + confirmVerified(FileCache, mockFile) } } @@ -180,16 +180,16 @@ class FileServiceTest { whenFileNotCached { mockkStatic(File::create) { every { mockFile.create() } just Runs - every { FileExistCache.setExists(any()) } just Runs + every { FileCache.setExists(any()) } just Runs fileService.create(mockFilePath) verify { mockFile.create() - FileExistCache.setExists(any()) + FileCache.setExists(any()) } - confirmVerified(mockFile, FileExistCache) + confirmVerified(mockFile, FileCache) } } } @@ -278,16 +278,16 @@ class FileServiceTest { whenMockFilePathExists { whenFileCached { every { mockFile.delete() } returns true - every { FileExistCache.setDoesNotExists(any()) } just Runs + every { FileCache.setDoesNotExists(any()) } just Runs fileService.delete(mockFilePath) verify { mockFile.delete() - FileExistCache.setDoesNotExists(any()) + FileCache.setDoesNotExists(any()) } - confirmVerified(mockFile, FileExistCache) + confirmVerified(mockFile, FileCache) } } } @@ -317,7 +317,7 @@ class FileServiceTest { @Test fun `fullPath() appends the given path to the given working directory`() { with(fileService) { - val fullFilePath = mockFilePath.fullPath() + val fullFilePath = fullPath(mockFilePath) assertEquals("${creProperties.dataDirectory}/$mockFilePath", fullFilePath.path) } @@ -329,7 +329,7 @@ class FileServiceTest { BANNED_FILE_PATH_SHARDS.forEach { val maliciousPath = "$it/$mockFilePath" - with(assertThrows { maliciousPath.fullPath() }) { + with(assertThrows { fullPath(maliciousPath) }) { assertEquals(maliciousPath, this.path) assertEquals(it, this.fragment) } diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/ResourceFileServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/ResourceFileServiceTest.kt index 9aafde9..55bcac2 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/ResourceFileServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/ResourceFileServiceTest.kt @@ -27,7 +27,7 @@ class ResourceFileServiceTest { private fun existsTest(shouldExists: Boolean, test: (String) -> Unit) { val path = "unit_test_resource" with(service) { - every { path.fullPath() } returns mockk { + every { fullPath(path) } returns mockk { every { resource } returns mockk { every { exists() } returns shouldExists } @@ -61,7 +61,7 @@ class ResourceFileServiceTest { } val path = "unit_test_path" with(service) { - every { path.fullPath() } returns mockk { + every { fullPath(path) } returns mockk { every { resource } returns mockResource } @@ -92,11 +92,9 @@ class ResourceFileServiceTest { val path = "unit_test_path" val expectedPath = "classpath:$path" - with(service) { - val found = path.fullPath() + val found = service.fullPath(path) - assertEquals(expectedPath, found.path) - } + assertEquals(expectedPath, found.path) } @Test