Bon test du service de fichiers
This commit is contained in:
parent
c6b3367cfa
commit
ee4385ccb4
|
@ -1,118 +1,293 @@
|
|||
package dev.fyloz.colorrecipesexplorer.service.files
|
||||
|
||||
import com.nhaarman.mockitokotlin2.*
|
||||
import dev.fyloz.colorrecipesexplorer.config.properties.CreProperties
|
||||
import io.mockk.*
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.slf4j.Logger
|
||||
import org.springframework.core.io.Resource
|
||||
import org.springframework.core.io.ResourceLoader
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import org.springframework.mock.web.MockMultipartFile
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.nio.file.Paths
|
||||
import java.nio.file.Path
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
private val creProperties = CreProperties().apply {
|
||||
workingDirectory = "data"
|
||||
deploymentUrl = "http://localhost"
|
||||
}
|
||||
private const val mockFilePath = "existingFile"
|
||||
private val mockFilePathPath = Path.of(mockFilePath)
|
||||
private val mockFileData = byteArrayOf(0x1, 0x8, 0xa, 0xf)
|
||||
|
||||
private class FileServiceTestContext {
|
||||
val fileService: FileService
|
||||
val mockFile: File
|
||||
val mockFileFullPath: FilePath
|
||||
val mockMultipartFile: MultipartFile
|
||||
|
||||
init {
|
||||
fileService = spyk(FileServiceImpl(creProperties, mockk {
|
||||
every { error(any(), any<Exception>()) } just Runs
|
||||
}))
|
||||
|
||||
mockFile = mockk {
|
||||
every { path } returns mockFilePath
|
||||
every { exists() } returns true
|
||||
every { isFile } returns true
|
||||
every { toPath() } returns mockFilePathPath
|
||||
}
|
||||
|
||||
mockFileFullPath = spyk(FilePath("${creProperties.workingDirectory}/$mockFilePath")) {
|
||||
every { file } returns mockFile
|
||||
|
||||
with(fileService) {
|
||||
every { mockFilePath.fullPath() } returns this@spyk
|
||||
}
|
||||
}
|
||||
|
||||
mockMultipartFile = spyk(MockMultipartFile(mockFilePath, mockFileData))
|
||||
}
|
||||
}
|
||||
|
||||
class FileServiceTest {
|
||||
private val resourcesLoader = mock<ResourceLoader>()
|
||||
private val logger = mock<Logger>()
|
||||
private val properties = CreProperties()
|
||||
|
||||
private val service = spy(FileService(resourcesLoader, properties, logger))
|
||||
|
||||
private val path = "/var/cre/file"
|
||||
|
||||
@AfterEach
|
||||
fun afterEach() {
|
||||
reset(resourcesLoader, logger, service)
|
||||
internal fun afterEach() {
|
||||
clearAllMocks()
|
||||
}
|
||||
|
||||
// readResource()
|
||||
// exists()
|
||||
|
||||
@Test
|
||||
fun `readResource() returns content of the resource at the given path`() {
|
||||
val resource = mock<Resource>()
|
||||
val resourceStream = mock<InputStream>()
|
||||
val resourceContent = """
|
||||
Line 1
|
||||
Line 2
|
||||
Line 3
|
||||
""".trimIndent()
|
||||
|
||||
whenever(resource.inputStream).doReturn(resourceStream)
|
||||
whenever(resourcesLoader.getResource("classpath:$path")).doReturn(resource)
|
||||
doReturn(resourceContent).whenever(service).readInputStreamAsString(resourceStream)
|
||||
|
||||
val found = service.readResource(path)
|
||||
|
||||
assertEquals(resourceContent, found)
|
||||
fun `exists() returns true when the file at the given path exists and is a file`() {
|
||||
fileServiceTest {
|
||||
assertTrue { fileService.exists(mockFilePath) }
|
||||
}
|
||||
}
|
||||
|
||||
// readInputStreamAsString()
|
||||
@Test
|
||||
fun `exists() returns false when the file at the given path does not exist`() {
|
||||
fileServiceTest {
|
||||
every { mockFile.exists() } returns false
|
||||
|
||||
assertFalse { fileService.exists(mockFilePath) }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `readInputStreamAsString() returns a String matching the given input stream's content`() {
|
||||
val stream = mock<InputStream>()
|
||||
val streamContent = """
|
||||
Line 1
|
||||
Line 2
|
||||
Line 3
|
||||
""".trimIndent()
|
||||
fun `exists() returns false when the file at the given path is not a file`() {
|
||||
fileServiceTest {
|
||||
every { mockFile.isFile } returns false
|
||||
|
||||
whenever(stream.readAllBytes()).doAnswer { streamContent.toByteArray() }
|
||||
assertFalse { fileService.exists(mockFilePath) }
|
||||
}
|
||||
}
|
||||
|
||||
val found = service.readInputStreamAsString(stream)
|
||||
// read()
|
||||
|
||||
assertEquals(streamContent, found)
|
||||
@Test
|
||||
fun `read() returns a valid ByteArrayResource`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists {
|
||||
mockkStatic(File::readBytes)
|
||||
every { mockFile.readBytes() } returns mockFileData
|
||||
|
||||
val redResource = fileService.read(mockFilePath)
|
||||
|
||||
assertEquals(mockFileData, redResource.byteArray)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read() throws FileNotFoundException when no file exists at the given path`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists(false) {
|
||||
with(assertThrows<FileNotFoundException> { fileService.read(mockFilePath) }) {
|
||||
assertEquals(mockFilePath, this.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read() throws FileReadException when an IOException is thrown`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists {
|
||||
mockkStatic(File::readBytes)
|
||||
every { mockFile.readBytes() } throws IOException()
|
||||
|
||||
with(assertThrows<FileReadException> { fileService.read(mockFilePath) }) {
|
||||
assertEquals(mockFilePath, this.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create()
|
||||
|
||||
@Test
|
||||
fun `create() creates a file at the given path`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists(false) {
|
||||
mockkStatic(File::create)
|
||||
every { mockFile.create() } just Runs
|
||||
|
||||
fileService.create(mockFilePath)
|
||||
|
||||
verify {
|
||||
mockFile.create()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `create() does nothing when a file already exists at the given path`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists {
|
||||
fileService.create(mockFilePath)
|
||||
|
||||
verify(exactly = 0) {
|
||||
mockFile.create()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `create() throws FileCreateException when the file creation throws an IOException`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists(false) {
|
||||
mockkStatic(File::create)
|
||||
every { mockFile.create() } throws IOException()
|
||||
|
||||
with(assertThrows<FileCreateException> { fileService.create(mockFilePath) }) {
|
||||
assertEquals(mockFilePath, this.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write()
|
||||
|
||||
private inline fun withMultipartFile(size: Long = 1000L, test: (MultipartFile) -> Unit) {
|
||||
val multipartFile = mock<MultipartFile>()
|
||||
whenever(multipartFile.size).doReturn(size)
|
||||
|
||||
test(multipartFile)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `write() transfers data from the given MultipartFile to the file at the given path and returns true`() {
|
||||
withMultipartFile { multipartFile ->
|
||||
val file = mock<File>()
|
||||
val filePath = Paths.get(path)
|
||||
fun `write() creates and writes the given MultipartFile to the file at the given path`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists(false) {
|
||||
every { fileService.create(mockFilePath) } just Runs
|
||||
every { mockMultipartFile.transferTo(mockFilePathPath) } just Runs
|
||||
|
||||
whenever(file.toPath()).doReturn(filePath)
|
||||
doAnswer { file }.whenever(service).create(path)
|
||||
fileService.write(mockMultipartFile, mockFilePath, false)
|
||||
|
||||
assertTrue { service.write(multipartFile, path) }
|
||||
|
||||
verify(multipartFile).transferTo(filePath)
|
||||
verify {
|
||||
fileService.create(mockFilePath)
|
||||
mockMultipartFile.transferTo(mockFilePathPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `write() returns true when given MultipartFile is empty`() {
|
||||
withMultipartFile(size = 0L) { multipartFile ->
|
||||
assertTrue { service.write(multipartFile, path) }
|
||||
|
||||
verify(multipartFile, never()).transferTo(any<File>())
|
||||
fun `write() throws FileExistsException when a file at the given path already exists and overwrite is disabled`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists {
|
||||
with(assertThrows<FileExistsException> { fileService.write(mockMultipartFile, mockFilePath, false) }) {
|
||||
assertEquals(mockFilePath, this.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `write() returns false when the data transfer throw an IOException`() {
|
||||
withMultipartFile { multipartFile ->
|
||||
val file = mock<File>()
|
||||
val filePath = Paths.get(path)
|
||||
fun `write() writes the given MultipartFile to an existing file when overwrite is enabled`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists {
|
||||
every { mockMultipartFile.transferTo(mockFilePathPath) } just Runs
|
||||
|
||||
whenever(file.toPath()).doReturn(filePath)
|
||||
whenever(multipartFile.transferTo(filePath)).doThrow(IOException())
|
||||
doAnswer { file }.whenever(service).create(path)
|
||||
fileService.write(mockMultipartFile, mockFilePath, true)
|
||||
|
||||
assertFalse { service.write(multipartFile, path) }
|
||||
verify {
|
||||
mockMultipartFile.transferTo(mockFilePathPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `write() throws FileWriteException when writing the given file throws an IOException`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists(false) {
|
||||
every { fileService.create(mockFilePath) } just Runs
|
||||
every { mockMultipartFile.transferTo(mockFilePathPath) } throws IOException()
|
||||
|
||||
with(assertThrows<FileWriteException> {
|
||||
fileService.write(mockMultipartFile, mockFilePath, false)
|
||||
}) {
|
||||
assertEquals(mockFilePath, this.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete()
|
||||
|
||||
@Test
|
||||
fun `delete() deletes the file at the given path`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists {
|
||||
every { mockFile.delete() } returns true
|
||||
|
||||
fileService.delete(mockFilePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `delete() throws FileNotFoundException when no file exists at the given path`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists(false) {
|
||||
with(assertThrows<FileNotFoundException> { fileService.delete(mockFilePath) }) {
|
||||
assertEquals(mockFilePath, this.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `delete() throws FileDeleteException when deleting throw and IOException`() {
|
||||
fileServiceTest {
|
||||
whenMockFilePathExists {
|
||||
every { mockFile.delete() } throws IOException()
|
||||
|
||||
with(assertThrows<FileDeleteException> { fileService.delete(mockFilePath) }) {
|
||||
assertEquals(mockFilePath, this.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String.fullPath()
|
||||
|
||||
@Test
|
||||
fun `fullPath() appends the given path to the given working directory`() {
|
||||
fileServiceTest {
|
||||
with(fileService) {
|
||||
val fullFilePath = mockFilePath.fullPath()
|
||||
|
||||
assertEquals("${creProperties.workingDirectory}/$mockFilePath", fullFilePath.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fileServiceTest(test: FileServiceTestContext.() -> Unit) {
|
||||
FileServiceTestContext().test()
|
||||
}
|
||||
|
||||
private fun FileServiceTestContext.whenMockFilePathExists(exists: Boolean = true, test: () -> Unit) {
|
||||
every { fileService.exists(mockFilePath) } returns exists
|
||||
test()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue