Bon test du service de fichiers

This commit is contained in:
FyloZ 2021-04-26 23:31:58 -04:00
parent c6b3367cfa
commit ee4385ccb4
1 changed files with 248 additions and 73 deletions

View File

@ -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()
}
}