feature/#25-dtos #28
|
@ -0,0 +1,15 @@
|
|||
package dev.fyloz.colorrecipesexplorer.dtos
|
||||
|
||||
data class RecipeStepDto(
|
||||
override val id: Long = 0L,
|
||||
|
||||
val position: Int,
|
||||
|
||||
val message: String
|
||||
) : EntityDto {
|
||||
companion object {
|
||||
const val VALIDATION_ERROR_CODE_INVALID_FIRST_STEP = "first"
|
||||
const val VALIDATION_ERROR_CODE_DUPLICATED_STEPS_POSITION = "duplicated"
|
||||
const val VALIDATION_ERROR_CODE_GAP_BETWEEN_STEPS_POSITIONS = "gap"
|
||||
}
|
||||
}
|
|
@ -61,7 +61,7 @@ abstract class BaseLogic<D : EntityDto, S : Service<D, *, *>>(
|
|||
override fun deleteById(id: Long) =
|
||||
service.deleteById(id)
|
||||
|
||||
protected fun notFoundException(identifierName: String = idIdentifierName, value: Any) =
|
||||
protected fun notFoundException(identifierName: String = ID_IDENTIFIER_NAME, value: Any) =
|
||||
NotFoundException(
|
||||
typeNameLowerCase,
|
||||
"$typeName not found",
|
||||
|
@ -70,7 +70,7 @@ abstract class BaseLogic<D : EntityDto, S : Service<D, *, *>>(
|
|||
identifierName
|
||||
)
|
||||
|
||||
protected fun alreadyExistsException(identifierName: String = nameIdentifierName, value: Any) =
|
||||
protected fun alreadyExistsException(identifierName: String = NAME_IDENTIFIER_NAME, value: Any) =
|
||||
AlreadyExistsException(
|
||||
typeNameLowerCase,
|
||||
"$typeName already exists",
|
||||
|
@ -87,7 +87,7 @@ abstract class BaseLogic<D : EntityDto, S : Service<D, *, *>>(
|
|||
)
|
||||
|
||||
companion object {
|
||||
const val idIdentifierName = "id"
|
||||
const val nameIdentifierName = "name"
|
||||
const val ID_IDENTIFIER_NAME = "id"
|
||||
const val NAME_IDENTIFIER_NAME = "name"
|
||||
}
|
||||
}
|
|
@ -1,19 +1,18 @@
|
|||
package dev.fyloz.colorrecipesexplorer.logic
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.config.annotations.RequireDatabase
|
||||
import dev.fyloz.colorrecipesexplorer.config.annotations.LogicComponent
|
||||
import dev.fyloz.colorrecipesexplorer.dtos.RecipeStepDto
|
||||
import dev.fyloz.colorrecipesexplorer.exception.RestException
|
||||
import dev.fyloz.colorrecipesexplorer.model.RecipeGroupInformation
|
||||
import dev.fyloz.colorrecipesexplorer.model.RecipeStep
|
||||
import dev.fyloz.colorrecipesexplorer.model.account.Group
|
||||
import dev.fyloz.colorrecipesexplorer.model.recipeStepIdAlreadyExistsException
|
||||
import dev.fyloz.colorrecipesexplorer.model.recipeStepIdNotFoundException
|
||||
import dev.fyloz.colorrecipesexplorer.repository.RecipeStepRepository
|
||||
import dev.fyloz.colorrecipesexplorer.model.recipeStepDto
|
||||
import dev.fyloz.colorrecipesexplorer.service.RecipeStepService
|
||||
import dev.fyloz.colorrecipesexplorer.utils.findDuplicated
|
||||
import dev.fyloz.colorrecipesexplorer.utils.hasGaps
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
interface RecipeStepLogic : ModelService<RecipeStep, RecipeStepRepository> {
|
||||
interface RecipeStepLogic : Logic<RecipeStepDto, RecipeStepService> {
|
||||
/** Validates the steps of the given [groupInformation], according to the criteria of [validateSteps]. */
|
||||
fun validateGroupInformationSteps(groupInformation: RecipeGroupInformation)
|
||||
|
||||
|
@ -22,106 +21,112 @@ interface RecipeStepLogic : ModelService<RecipeStep, RecipeStepRepository> {
|
|||
* There must also be no gap between the positions.
|
||||
* If any of those criteria are not met, an [InvalidGroupStepsPositionsException] will be thrown.
|
||||
*/
|
||||
fun validateSteps(steps: Set<RecipeStep>)
|
||||
fun validateSteps(steps: Set<RecipeStepDto>)
|
||||
}
|
||||
|
||||
@Service
|
||||
@RequireDatabase
|
||||
class DefaultRecipeStepLogic(recipeStepRepository: RecipeStepRepository) :
|
||||
AbstractModelService<RecipeStep, RecipeStepRepository>(recipeStepRepository),
|
||||
RecipeStepLogic {
|
||||
override fun idNotFoundException(id: Long) = recipeStepIdNotFoundException(id)
|
||||
override fun idAlreadyExistsException(id: Long) = recipeStepIdAlreadyExistsException(id)
|
||||
|
||||
@LogicComponent
|
||||
class DefaultRecipeStepLogic(recipeStepService: RecipeStepService) :
|
||||
BaseLogic<RecipeStepDto, RecipeStepService>(recipeStepService, RecipeStep::class.simpleName!!), RecipeStepLogic {
|
||||
override fun validateGroupInformationSteps(groupInformation: RecipeGroupInformation) {
|
||||
if (groupInformation.steps == null) return
|
||||
|
||||
try {
|
||||
validateSteps(groupInformation.steps!!)
|
||||
validateSteps(groupInformation.steps!!.map { recipeStepDto(it) }.toSet())
|
||||
} catch (validationException: InvalidStepsPositionsException) {
|
||||
throw InvalidGroupStepsPositionsException(groupInformation.group, validationException)
|
||||
}
|
||||
}
|
||||
|
||||
override fun validateSteps(steps: Set<RecipeStep>) {
|
||||
override fun validateSteps(steps: Set<RecipeStepDto>) {
|
||||
if (steps.isEmpty()) return
|
||||
|
||||
val sortedSteps = steps.sortedBy { it.position }
|
||||
val errors = mutableSetOf<InvalidStepsPositionsError>()
|
||||
|
||||
// Check if the first step position is 1
|
||||
fun isFirstStepPositionInvalid() =
|
||||
sortedSteps[0].position != 1
|
||||
validateFirstStepPosition(sortedSteps, errors)
|
||||
|
||||
// Check if any position is duplicated
|
||||
fun getDuplicatedPositionsErrors() =
|
||||
sortedSteps
|
||||
.findDuplicated { it.position }
|
||||
.map { duplicatedStepsPositions(it) }
|
||||
validateDuplicatedStepsPositions(sortedSteps, errors)
|
||||
|
||||
// Check for gaps between positions
|
||||
validateGapsInStepsPositions(sortedSteps, errors)
|
||||
|
||||
// Find all errors and throw if there is any
|
||||
if (isFirstStepPositionInvalid()) errors += invalidFirstStepPosition(sortedSteps[0])
|
||||
errors += getDuplicatedPositionsErrors()
|
||||
if (errors.isEmpty() && steps.hasGaps { it.position }) errors += gapBetweenStepsPositions()
|
||||
if (errors.isNotEmpty()) {
|
||||
throw InvalidStepsPositionsException(errors)
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateFirstStepPosition(
|
||||
steps: List<RecipeStepDto>,
|
||||
errors: MutableSet<InvalidStepsPositionsError>
|
||||
) {
|
||||
if (steps[0].position != 1) {
|
||||
errors += InvalidStepsPositionsError(
|
||||
RecipeStepDto.VALIDATION_ERROR_CODE_INVALID_FIRST_STEP,
|
||||
"The first step must be at position 1"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateDuplicatedStepsPositions(
|
||||
steps: List<RecipeStepDto>,
|
||||
errors: MutableSet<InvalidStepsPositionsError>
|
||||
) {
|
||||
errors += steps
|
||||
.findDuplicated { it.position }
|
||||
.map {
|
||||
InvalidStepsPositionsError(
|
||||
RecipeStepDto.VALIDATION_ERROR_CODE_DUPLICATED_STEPS_POSITION,
|
||||
"The position $it is duplicated"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateGapsInStepsPositions(
|
||||
steps: List<RecipeStepDto>,
|
||||
errors: MutableSet<InvalidStepsPositionsError>
|
||||
) {
|
||||
if (errors.isEmpty() && steps.hasGaps { it.position }) {
|
||||
errors += InvalidStepsPositionsError(
|
||||
RecipeStepDto.VALIDATION_ERROR_CODE_GAP_BETWEEN_STEPS_POSITIONS,
|
||||
"There is a gap between steps positions"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class InvalidStepsPositionsError(
|
||||
val type: String,
|
||||
val details: String
|
||||
val type: String,
|
||||
val details: String
|
||||
)
|
||||
|
||||
class InvalidStepsPositionsException(
|
||||
val errors: Set<InvalidStepsPositionsError>
|
||||
val errors: Set<InvalidStepsPositionsError>
|
||||
) : RestException(
|
||||
"invalid-recipestep-position",
|
||||
"Invalid steps positions",
|
||||
HttpStatus.BAD_REQUEST,
|
||||
"The position of steps are invalid",
|
||||
mapOf(
|
||||
"invalidSteps" to errors
|
||||
)
|
||||
"invalid-recipestep-position",
|
||||
"Invalid steps positions",
|
||||
HttpStatus.BAD_REQUEST,
|
||||
"The position of steps are invalid",
|
||||
mapOf(
|
||||
"invalidSteps" to errors
|
||||
)
|
||||
)
|
||||
|
||||
class InvalidGroupStepsPositionsException(
|
||||
val group: Group,
|
||||
val exception: InvalidStepsPositionsException
|
||||
) : RestException(
|
||||
"invalid-groupinformation-recipestep-position",
|
||||
"Invalid steps positions",
|
||||
HttpStatus.BAD_REQUEST,
|
||||
"The position of steps for the group ${group.name} are invalid",
|
||||
mapOf(
|
||||
"group" to group.name,
|
||||
"groupId" to group.id!!,
|
||||
"invalidSteps" to exception.errors
|
||||
)
|
||||
"invalid-groupinformation-recipestep-position",
|
||||
"Invalid steps positions",
|
||||
HttpStatus.BAD_REQUEST,
|
||||
"The position of steps for the group ${group.name} are invalid",
|
||||
mapOf(
|
||||
"group" to group.name,
|
||||
"groupId" to group.id!!,
|
||||
"invalidSteps" to exception.errors
|
||||
)
|
||||
) {
|
||||
val errors: Set<InvalidStepsPositionsError>
|
||||
get() = exception.errors
|
||||
}
|
||||
|
||||
const val INVALID_FIRST_STEP_POSITION_ERROR_CODE = "first"
|
||||
const val DUPLICATED_STEPS_POSITIONS_ERROR_CODE = "duplicated"
|
||||
const val GAP_BETWEEN_STEPS_POSITIONS_ERROR_CODE = "gap"
|
||||
|
||||
private fun invalidFirstStepPosition(step: RecipeStep) =
|
||||
InvalidStepsPositionsError(
|
||||
INVALID_FIRST_STEP_POSITION_ERROR_CODE,
|
||||
"The position ${step.position} is under the minimum of 1"
|
||||
)
|
||||
|
||||
private fun duplicatedStepsPositions(position: Int) =
|
||||
InvalidStepsPositionsError(
|
||||
DUPLICATED_STEPS_POSITIONS_ERROR_CODE,
|
||||
"The position $position is duplicated"
|
||||
)
|
||||
|
||||
private fun gapBetweenStepsPositions() =
|
||||
InvalidStepsPositionsError(
|
||||
GAP_BETWEEN_STEPS_POSITIONS_ERROR_CODE,
|
||||
"There is a gap between steps positions"
|
||||
)
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package dev.fyloz.colorrecipesexplorer.model
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
|
||||
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
|
||||
import dev.fyloz.colorrecipesexplorer.dtos.RecipeStepDto
|
||||
import javax.persistence.*
|
||||
|
||||
@Entity
|
||||
|
@ -16,31 +15,7 @@ data class RecipeStep(
|
|||
val message: String
|
||||
) : ModelEntity
|
||||
|
||||
// ==== DSL ====
|
||||
fun recipeStep(
|
||||
id: Long? = null,
|
||||
position: Int = 0,
|
||||
message: String = "message",
|
||||
op: RecipeStep.() -> Unit = {}
|
||||
) = RecipeStep(id, position, message).apply(op)
|
||||
|
||||
// ==== Exceptions ====
|
||||
private const val RECIPE_STEP_NOT_FOUND_EXCEPTION_TITLE = "Recipe step not found"
|
||||
private const val RECIPE_STEP_ALREADY_EXISTS_EXCEPTION_TITLE = "Recipe step already exists"
|
||||
private const val RECIPE_STEP_EXCEPTION_ERROR_CODE = "recipestep"
|
||||
|
||||
fun recipeStepIdNotFoundException(id: Long) =
|
||||
NotFoundException(
|
||||
RECIPE_STEP_EXCEPTION_ERROR_CODE,
|
||||
RECIPE_STEP_NOT_FOUND_EXCEPTION_TITLE,
|
||||
"A recipe step with the id $id could not be found",
|
||||
id
|
||||
)
|
||||
|
||||
fun recipeStepIdAlreadyExistsException(id: Long) =
|
||||
AlreadyExistsException(
|
||||
RECIPE_STEP_EXCEPTION_ERROR_CODE,
|
||||
RECIPE_STEP_ALREADY_EXISTS_EXCEPTION_TITLE,
|
||||
"A recipe step with the id $id already exists",
|
||||
id
|
||||
)
|
||||
@Deprecated("Temporary DSL for transition")
|
||||
fun recipeStepDto(
|
||||
entity: RecipeStep
|
||||
) = RecipeStepDto(entity.id!!, entity.position, entity.message)
|
|
@ -0,0 +1,18 @@
|
|||
package dev.fyloz.colorrecipesexplorer.service
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.config.annotations.ServiceComponent
|
||||
import dev.fyloz.colorrecipesexplorer.dtos.RecipeStepDto
|
||||
import dev.fyloz.colorrecipesexplorer.model.RecipeStep
|
||||
import dev.fyloz.colorrecipesexplorer.repository.RecipeStepRepository
|
||||
|
||||
interface RecipeStepService : Service<RecipeStepDto, RecipeStep, RecipeStepRepository>
|
||||
|
||||
@ServiceComponent
|
||||
class DefaultRecipeStepService(repository: RecipeStepRepository) :
|
||||
BaseService<RecipeStepDto, RecipeStep, RecipeStepRepository>(repository), RecipeStepService {
|
||||
override fun toDto(entity: RecipeStep) =
|
||||
RecipeStepDto(entity.id!!, entity.position, entity.message)
|
||||
|
||||
override fun toEntity(dto: RecipeStepDto) =
|
||||
RecipeStep(dto.id, dto.position, dto.message)
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
package dev.fyloz.colorrecipesexplorer.logic
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.dtos.RecipeStepDto
|
||||
import dev.fyloz.colorrecipesexplorer.model.RecipeGroupInformation
|
||||
import dev.fyloz.colorrecipesexplorer.model.RecipeStep
|
||||
import dev.fyloz.colorrecipesexplorer.model.account.Group
|
||||
import dev.fyloz.colorrecipesexplorer.service.RecipeStepService
|
||||
import io.mockk.*
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertDoesNotThrow
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class DefaultRecipeStepLogicTest {
|
||||
private val recipeStepServiceMock = mockk<RecipeStepService>()
|
||||
|
||||
private val recipeStepLogic = spyk(DefaultRecipeStepLogic(recipeStepServiceMock))
|
||||
|
||||
@AfterEach
|
||||
internal fun afterEach() {
|
||||
clearAllMocks()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateGroupInformationSteps_normalBehavior_callsValidateSteps() {
|
||||
// Arrange
|
||||
every { recipeStepLogic.validateSteps(any()) } just runs
|
||||
|
||||
val group = Group(1L, "Unit test group")
|
||||
val steps = mutableSetOf(RecipeStep(1L, 1, "A message"))
|
||||
val groupInfo = RecipeGroupInformation(1L, group, "A note", steps)
|
||||
|
||||
// Act
|
||||
recipeStepLogic.validateGroupInformationSteps(groupInfo)
|
||||
|
||||
// Assert
|
||||
verify {
|
||||
recipeStepLogic.validateSteps(any()) // TODO replace with actual steps dtos when RecipeGroupInformation updated
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateGroupInformationSteps_stepSetIsNull_doesNothing() {
|
||||
// Arrange
|
||||
every { recipeStepLogic.validateSteps(any()) } just runs
|
||||
|
||||
val group = Group(1L, "Unit test group")
|
||||
val groupInfo = RecipeGroupInformation(1L, group, "A note", null)
|
||||
|
||||
// Act
|
||||
recipeStepLogic.validateGroupInformationSteps(groupInfo)
|
||||
|
||||
// Assert
|
||||
verify(exactly = 0) {
|
||||
recipeStepLogic.validateSteps(any()) // TODO replace with actual steps dtos when RecipeGroupInformation updated
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateGroupInformationSteps_invalidSteps_throwsInvalidGroupStepsPositionsException() {
|
||||
// Arrange
|
||||
val errors = setOf(InvalidStepsPositionsError("error", "An unit test error"))
|
||||
every { recipeStepLogic.validateSteps(any()) } throws InvalidStepsPositionsException(errors)
|
||||
|
||||
val group = Group(1L, "Unit test group")
|
||||
val steps = mutableSetOf(RecipeStep(1L, 1, "A message"))
|
||||
val groupInfo = RecipeGroupInformation(1L, group, "A note", steps)
|
||||
|
||||
// Act
|
||||
// Assert
|
||||
assertThrows<InvalidGroupStepsPositionsException> { recipeStepLogic.validateGroupInformationSteps(groupInfo) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateSteps_normalBehavior_doesNothing() {
|
||||
// Arrange
|
||||
val recipeSteps = setOf(
|
||||
RecipeStepDto(1L, 1, "A message"),
|
||||
RecipeStepDto(2L, 2, "Another message")
|
||||
)
|
||||
|
||||
// Act
|
||||
// Assert
|
||||
assertDoesNotThrow { recipeStepLogic.validateSteps(recipeSteps) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateSteps_emptyStepSet_doesNothing() {
|
||||
// Arrange
|
||||
val recipeSteps = setOf<RecipeStepDto>()
|
||||
|
||||
// Act
|
||||
// Assert
|
||||
assertDoesNotThrow { recipeStepLogic.validateSteps(recipeSteps) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateSteps_hasInvalidPositions_throwsInvalidStepsPositionsException() {
|
||||
// Arrange
|
||||
val recipeSteps = setOf(
|
||||
RecipeStepDto(1L, 2, "A message"),
|
||||
RecipeStepDto(2L, 3, "Another message")
|
||||
)
|
||||
|
||||
// Act
|
||||
// Assert
|
||||
assertThrows<InvalidStepsPositionsException> { recipeStepLogic.validateSteps(recipeSteps) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateSteps_firstStepPositionInvalid_returnsInvalidStepValidationError() {
|
||||
// Arrange
|
||||
val recipeSteps = setOf(
|
||||
RecipeStepDto(1L, 2, "A message"),
|
||||
RecipeStepDto(2L, 3, "Another message")
|
||||
)
|
||||
|
||||
// Act
|
||||
val exception = assertThrows<InvalidStepsPositionsException> { recipeStepLogic.validateSteps(recipeSteps) }
|
||||
|
||||
// Assert
|
||||
assertTrue {
|
||||
exception.errors.any { it.type == RecipeStepDto.VALIDATION_ERROR_CODE_INVALID_FIRST_STEP }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateSteps_duplicatedPositions_returnsInvalidStepValidationError() {
|
||||
// Arrange
|
||||
val recipeSteps = setOf(
|
||||
RecipeStepDto(1L, 1, "A message"),
|
||||
RecipeStepDto(2L, 1, "Another message")
|
||||
)
|
||||
|
||||
// Act
|
||||
val exception = assertThrows<InvalidStepsPositionsException> { recipeStepLogic.validateSteps(recipeSteps) }
|
||||
|
||||
// Assert
|
||||
assertTrue {
|
||||
exception.errors.any { it.type == RecipeStepDto.VALIDATION_ERROR_CODE_DUPLICATED_STEPS_POSITION }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateSteps_gapsInPositions_returnsInvalidStepValidationError() {
|
||||
// Arrange
|
||||
val recipeSteps = setOf(
|
||||
RecipeStepDto(1L, 1, "A message"),
|
||||
RecipeStepDto(2L, 3, "Another message")
|
||||
)
|
||||
|
||||
// Act
|
||||
val exception = assertThrows<InvalidStepsPositionsException> { recipeStepLogic.validateSteps(recipeSteps) }
|
||||
|
||||
// Assert
|
||||
assertTrue {
|
||||
exception.errors.any { it.type == RecipeStepDto.VALIDATION_ERROR_CODE_GAP_BETWEEN_STEPS_POSITIONS }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
//class RecipeStepLogicTest :
|
||||
// AbstractModelServiceTest<RecipeStep, RecipeStepLogic, RecipeStepRepository>() {
|
||||
// override val repository: RecipeStepRepository = mock()
|
||||
// override val logic: RecipeStepLogic = spy(DefaultRecipeStepLogic(repository))
|
||||
//
|
||||
// override val entity: RecipeStep = recipeStep(id = 0L, message = "message")
|
||||
// override val anotherEntity: RecipeStep = recipeStep(id = 1L, message = "another message")
|
||||
//
|
||||
// // validateGroupInformationSteps()
|
||||
//
|
||||
// @Test
|
||||
// fun `validateGroupInformationSteps() calls validateSteps() with the given RecipeGroupInformation steps`() {
|
||||
// withGroupInformation {
|
||||
// logic.validateGroupInformationSteps(this)
|
||||
//
|
||||
// verify(logic).validateSteps(this.steps!!)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// fun `validateGroupInformationSteps() throws InvalidGroupStepsPositionsException when validateSteps() throws an InvalidStepsPositionsException`() {
|
||||
// withGroupInformation {
|
||||
// doAnswer { throw InvalidStepsPositionsException(setOf()) }.whenever(logic).validateSteps(this.steps!!)
|
||||
//
|
||||
// assertThrows<InvalidGroupStepsPositionsException> {
|
||||
// logic.validateGroupInformationSteps(this)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // validateSteps()
|
||||
//
|
||||
// @Test
|
||||
// fun `validateSteps() throws an InvalidStepsPositionsException when the position of the first step of the given groupInformation is not 1`() {
|
||||
// assertInvalidStepsPositionsException(
|
||||
// mutableSetOf(
|
||||
// recipeStep(id = 0L, position = 0),
|
||||
// recipeStep(id = 1L, position = 1),
|
||||
// recipeStep(id = 2L, position = 2),
|
||||
// recipeStep(id = 3L, position = 3)
|
||||
// ),
|
||||
// INVALID_FIRST_STEP_POSITION_ERROR_CODE
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// fun `validateSteps() throws an InvalidStepsPositionsException when steps positions are duplicated in the given groupInformation`() {
|
||||
// assertInvalidStepsPositionsException(
|
||||
// mutableSetOf(
|
||||
// recipeStep(id = 0L, position = 1),
|
||||
// recipeStep(id = 1L, position = 2),
|
||||
// recipeStep(id = 2L, position = 2),
|
||||
// recipeStep(id = 3L, position = 3)
|
||||
// ),
|
||||
// DUPLICATED_STEPS_POSITIONS_ERROR_CODE
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// fun `validateSteps() throws an InvalidStepsPositionsException when there is a gap between steps positions in the given groupInformation`() {
|
||||
// assertInvalidStepsPositionsException(
|
||||
// mutableSetOf(
|
||||
// recipeStep(id = 0L, position = 1),
|
||||
// recipeStep(id = 1L, position = 2),
|
||||
// recipeStep(id = 2L, position = 4),
|
||||
// recipeStep(id = 3L, position = 5)
|
||||
// ),
|
||||
// GAP_BETWEEN_STEPS_POSITIONS_ERROR_CODE
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// private fun withGroupInformation(steps: MutableSet<RecipeStep>? = null, test: RecipeGroupInformation.() -> Unit) {
|
||||
// recipeGroupInformation(
|
||||
// group = group(id = 0L),
|
||||
// steps = steps ?: mutableSetOf(
|
||||
// recipeStep(id = 0L, position = 1),
|
||||
// recipeStep(id = 1L, position = 2),
|
||||
// recipeStep(id = 2L, position = 3),
|
||||
// recipeStep(id = 3L, position = 4)
|
||||
// )
|
||||
// ) {
|
||||
// test()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun assertInvalidStepsPositionsException(steps: MutableSet<RecipeStep>, errorType: String) {
|
||||
// val exception = assertThrows<InvalidStepsPositionsException> {
|
||||
// logic.validateSteps(steps)
|
||||
// }
|
||||
//
|
||||
// assertTrue { exception.errors.size == 1 }
|
||||
// assertTrue { exception.errors.first().type == errorType }
|
||||
// }
|
||||
//}
|
|
@ -1,109 +0,0 @@
|
|||
package dev.fyloz.colorrecipesexplorer.logic
|
||||
|
||||
import com.nhaarman.mockitokotlin2.*
|
||||
import dev.fyloz.colorrecipesexplorer.model.RecipeGroupInformation
|
||||
import dev.fyloz.colorrecipesexplorer.model.RecipeStep
|
||||
import dev.fyloz.colorrecipesexplorer.model.account.group
|
||||
import dev.fyloz.colorrecipesexplorer.model.recipeGroupInformation
|
||||
import dev.fyloz.colorrecipesexplorer.model.recipeStep
|
||||
import dev.fyloz.colorrecipesexplorer.repository.RecipeStepRepository
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class RecipeStepLogicTest :
|
||||
AbstractModelServiceTest<RecipeStep, RecipeStepLogic, RecipeStepRepository>() {
|
||||
override val repository: RecipeStepRepository = mock()
|
||||
override val logic: RecipeStepLogic = spy(DefaultRecipeStepLogic(repository))
|
||||
|
||||
override val entity: RecipeStep = recipeStep(id = 0L, message = "message")
|
||||
override val anotherEntity: RecipeStep = recipeStep(id = 1L, message = "another message")
|
||||
|
||||
// validateGroupInformationSteps()
|
||||
|
||||
@Test
|
||||
fun `validateGroupInformationSteps() calls validateSteps() with the given RecipeGroupInformation steps`() {
|
||||
withGroupInformation {
|
||||
logic.validateGroupInformationSteps(this)
|
||||
|
||||
verify(logic).validateSteps(this.steps!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validateGroupInformationSteps() throws InvalidGroupStepsPositionsException when validateSteps() throws an InvalidStepsPositionsException`() {
|
||||
withGroupInformation {
|
||||
doAnswer { throw InvalidStepsPositionsException(setOf()) }.whenever(logic).validateSteps(this.steps!!)
|
||||
|
||||
assertThrows<InvalidGroupStepsPositionsException> {
|
||||
logic.validateGroupInformationSteps(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validateSteps()
|
||||
|
||||
@Test
|
||||
fun `validateSteps() throws an InvalidStepsPositionsException when the position of the first step of the given groupInformation is not 1`() {
|
||||
assertInvalidStepsPositionsException(
|
||||
mutableSetOf(
|
||||
recipeStep(id = 0L, position = 0),
|
||||
recipeStep(id = 1L, position = 1),
|
||||
recipeStep(id = 2L, position = 2),
|
||||
recipeStep(id = 3L, position = 3)
|
||||
),
|
||||
INVALID_FIRST_STEP_POSITION_ERROR_CODE
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validateSteps() throws an InvalidStepsPositionsException when steps positions are duplicated in the given groupInformation`() {
|
||||
assertInvalidStepsPositionsException(
|
||||
mutableSetOf(
|
||||
recipeStep(id = 0L, position = 1),
|
||||
recipeStep(id = 1L, position = 2),
|
||||
recipeStep(id = 2L, position = 2),
|
||||
recipeStep(id = 3L, position = 3)
|
||||
),
|
||||
DUPLICATED_STEPS_POSITIONS_ERROR_CODE
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validateSteps() throws an InvalidStepsPositionsException when there is a gap between steps positions in the given groupInformation`() {
|
||||
assertInvalidStepsPositionsException(
|
||||
mutableSetOf(
|
||||
recipeStep(id = 0L, position = 1),
|
||||
recipeStep(id = 1L, position = 2),
|
||||
recipeStep(id = 2L, position = 4),
|
||||
recipeStep(id = 3L, position = 5)
|
||||
),
|
||||
GAP_BETWEEN_STEPS_POSITIONS_ERROR_CODE
|
||||
)
|
||||
}
|
||||
|
||||
private fun withGroupInformation(steps: MutableSet<RecipeStep>? = null, test: RecipeGroupInformation.() -> Unit) {
|
||||
recipeGroupInformation(
|
||||
group = group(id = 0L),
|
||||
steps = steps ?: mutableSetOf(
|
||||
recipeStep(id = 0L, position = 1),
|
||||
recipeStep(id = 1L, position = 2),
|
||||
recipeStep(id = 2L, position = 3),
|
||||
recipeStep(id = 3L, position = 4)
|
||||
)
|
||||
) {
|
||||
test()
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertInvalidStepsPositionsException(steps: MutableSet<RecipeStep>, errorType: String) {
|
||||
val exception = assertThrows<InvalidStepsPositionsException> {
|
||||
logic.validateSteps(steps)
|
||||
}
|
||||
|
||||
assertTrue { exception.errors.size == 1 }
|
||||
assertTrue { exception.errors.first().type == errorType }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue