diff --git a/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolStageService.kt b/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolStageService.kt index 09966a5e..bc30d408 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolStageService.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolStageService.kt @@ -19,14 +19,18 @@ interface FindProtocolStageService { ) enum class ProtocolStage { - PROTOCOL_PART_I, + GENERAL_DEFINITION, + RESEARCH_QUESTIONS, PICOC, - PROTOCOL_PART_II, - PROTOCOL_PART_III, + ELIGIBILITY_CRITERIA, + INFORMATION_SOURCES_AND_SEARCH_STRATEGY, + SELECTION_AND_EXTRACTION, + RISK_OF_BIAS, + ANALYSIS_AND_SYNTHESIS_METHOD, + IDENTIFICATION, SELECTION, EXTRACTION, - GRAPHICS, - FINALIZATION + GRAPHICS } } \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolStageServiceImpl.kt index c900bf90..7eaaf15c 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolStageServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolStageServiceImpl.kt @@ -8,6 +8,7 @@ import br.all.application.protocol.find.FindProtocolStageService.ResponseModel import br.all.application.protocol.find.FindProtocolStageService.ProtocolStage import br.all.application.protocol.repository.ProtocolDto import br.all.application.question.repository.QuestionRepository +import br.all.application.review.repository.SystematicStudyDto import br.all.application.review.repository.fromDto import br.all.domain.shared.exception.EntityNotFoundException import br.all.application.shared.presenter.prepareIfFailsPreconditions @@ -27,40 +28,41 @@ class FindProtocolStageServiceImpl( override fun getStage(presenter: FindProtocolStagePresenter, request: RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) - val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + + val systematicStudy = runCatching { + systematicStudyDto?.let { SystematicStudy.fromDto(it) } + }.getOrNull() presenter.prepareIfFailsPreconditions(user, systematicStudy) if (presenter.isDone()) return val protocolDto = protocolRepository.findById(request.systematicStudyId) - if (protocolDto == null) { - val message = "Protocol not found for systematic study ${request.systematicStudyId}" + if (protocolDto == null || systematicStudyDto == null) { + val message = "Protocol or Systematic Study not found for id ${request.systematicStudyId}" presenter.prepareFailView(EntityNotFoundException(message)) return } val allStudies = studyReviewRepository.findAllFromReview(request.systematicStudyId) - val robQuestions = questionRepository.findAllBySystematicStudyId(systematicStudyDto!!.id, QuestionContextEnum.ROB).size - val extractionQuestions = questionRepository.findAllBySystematicStudyId(systematicStudyDto.id, QuestionContextEnum.EXTRACTION).size - - val totalStudiesCount = allStudies.size - val includedStudiesCount = allStudies.count { it.selectionStatus == "INCLUDED" } - val extractedStudiesCount = allStudies.count { it.extractionStatus == "INCLUDED" } + val robQuestionsCount = questionRepository.findAllBySystematicStudyId(systematicStudyDto.id, QuestionContextEnum.ROB).size + val extractionQuestionsCount = questionRepository.findAllBySystematicStudyId(systematicStudyDto.id, QuestionContextEnum.EXTRACTION).size val stage = evaluateStage( protocolDto, - totalStudiesCount, - includedStudiesCount, - extractedStudiesCount, - robQuestions, - extractionQuestions, + systematicStudyDto, + allStudies.size, + allStudies.count { it.selectionStatus == "INCLUDED" }, + allStudies.count { it.extractionStatus == "INCLUDED" }, + robQuestionsCount, + extractionQuestionsCount ) presenter.prepareSuccessView(ResponseModel(request.userId, request.systematicStudyId, stage)) } private fun evaluateStage( - dto: ProtocolDto, + protocolDto: ProtocolDto, + studyDto: SystematicStudyDto, totalStudiesCount: Int, includedStudiesCount: Int, extractedStudiesCount: Int, @@ -68,10 +70,17 @@ class FindProtocolStageServiceImpl( extractionQuestionsCount: Int ): ProtocolStage { return when { - isProtocolPartI(dto) -> ProtocolStage.PROTOCOL_PART_I - picocStage(dto) -> ProtocolStage.PICOC - isProtocolPartII(dto) -> ProtocolStage.PROTOCOL_PART_II - !isProtocolPartIIICompleted(dto, robQuestionCount, extractionQuestionsCount) -> ProtocolStage.PROTOCOL_PART_III + !isT1Complete(studyDto, protocolDto) -> ProtocolStage.GENERAL_DEFINITION + !isT2Complete(protocolDto) -> ProtocolStage.RESEARCH_QUESTIONS + + isPicocStarted(protocolDto) && !isT3Complete(protocolDto) -> ProtocolStage.PICOC + + !isT4Complete(protocolDto) -> ProtocolStage.ELIGIBILITY_CRITERIA + !isT5Complete(protocolDto) -> ProtocolStage.INFORMATION_SOURCES_AND_SEARCH_STRATEGY + !isT6Complete(protocolDto, extractionQuestionsCount) -> ProtocolStage.SELECTION_AND_EXTRACTION + + !isT8Complete(protocolDto) -> ProtocolStage.ANALYSIS_AND_SYNTHESIS_METHOD + totalStudiesCount == 0 -> ProtocolStage.IDENTIFICATION includedStudiesCount == 0 -> ProtocolStage.SELECTION extractedStudiesCount == 0 -> ProtocolStage.EXTRACTION @@ -79,51 +88,62 @@ class FindProtocolStageServiceImpl( } } - private fun isProtocolPartI(dto: ProtocolDto): Boolean { - return dto.goal.isNullOrBlank() && dto.justification.isNullOrBlank() - } - private fun isProtocolPartII(dto: ProtocolDto): Boolean { - return dto.studiesLanguages.isEmpty() && - dto.eligibilityCriteria.isEmpty() && - dto.informationSources.isEmpty() && - dto.keywords.isEmpty() && - dto.sourcesSelectionCriteria.isNullOrBlank() && - dto.searchMethod.isNullOrBlank() && - dto.selectionProcess.isNullOrBlank() + private fun isT1Complete(studyDto: SystematicStudyDto, protocolDto: ProtocolDto): Boolean { + val isStudyInfoComplete = studyDto.title.isNotBlank() && studyDto.description.isNotBlank() + val isProtocolGoalComplete = !protocolDto.goal.isNullOrBlank() + return isStudyInfoComplete && isProtocolGoalComplete } - private fun isProtocolPartIIICompleted(dto: ProtocolDto, robQuestionCount: Int, extractionQuestionsCount: Int): Boolean { - val hasInclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("INCLUSION", ignoreCase = true) } - val hasExclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("EXCLUSION", ignoreCase = true) } + private fun isT2Complete(dto: ProtocolDto): Boolean { + return dto.researchQuestions.isNotEmpty() + } - val hasExtractionAndRob = robQuestionCount > 0 && extractionQuestionsCount > 0 + private fun isPicocStarted(dto: ProtocolDto): Boolean { + val picoc = dto.picoc ?: return false + return !picoc.population.isNullOrBlank() || !picoc.intervention.isNullOrBlank() || + !picoc.control.isNullOrBlank() || !picoc.outcome.isNullOrBlank() || !picoc.context.isNullOrBlank() + } - val hasDatabases = dto.informationSources.isNotEmpty() - val hasResearchQuestions = dto.researchQuestions.isNotEmpty() - val hasAnalysisProcess = !dto.analysisAndSynthesisProcess.isNullOrBlank() + private fun isT3Complete(dto: ProtocolDto): Boolean { + val picoc = dto.picoc ?: return false - return hasInclusionCriteria && hasExclusionCriteria && - hasExtractionAndRob && hasDatabases && - hasResearchQuestions && hasAnalysisProcess + return !picoc.population.isNullOrBlank() && + !picoc.intervention.isNullOrBlank() && + !picoc.control.isNullOrBlank() && + !picoc.outcome.isNullOrBlank() } - private fun picocStage(dto: ProtocolDto): Boolean { - val picoc = dto.picoc - if (picoc == null) return false + private fun isT4Complete(dto: ProtocolDto): Boolean { + val hasInclusion = dto.eligibilityCriteria.any { it.type.equals("INCLUSION", ignoreCase = true) } + val hasExclusion = dto.eligibilityCriteria.any { it.type.equals("EXCLUSION", ignoreCase = true) } - val picocIsStarted = !picoc.population.isNullOrBlank() || !picoc.intervention.isNullOrBlank() || - !picoc.control.isNullOrBlank() || !picoc.outcome.isNullOrBlank() || !picoc.context.isNullOrBlank() + val hasStudyType = !dto.studyTypeDefinition.isNullOrBlank() + val hasLanguage = dto.studiesLanguages.isNotEmpty() - if (picocIsStarted) { - val picocIsCompleted = !picoc.population.isNullOrBlank() && !picoc.intervention.isNullOrBlank() && - !picoc.control.isNullOrBlank() && !picoc.outcome.isNullOrBlank() && !picoc.context.isNullOrBlank() + return hasInclusion && hasExclusion && hasStudyType && hasLanguage + } - if (!picocIsCompleted) { - return true - } - } + private fun isT5Complete(dto: ProtocolDto): Boolean { + return !dto.sourcesSelectionCriteria.isNullOrBlank() && + dto.informationSources.isNotEmpty() && + !dto.searchMethod.isNullOrBlank() && + dto.keywords.isNotEmpty() && + !dto.searchString.isNullOrBlank() + } + + private fun isT6Complete(dto: ProtocolDto, extractionQuestionsCount: Int): Boolean { + return !dto.selectionProcess.isNullOrBlank() && + !dto.dataCollectionProcess.isNullOrBlank() && + extractionQuestionsCount > 0 + } + + // T7 - Risk Of Bias + // Não é necessária uma função 'isT7Complete' na lógica principal, pois + // a regra é: se não houver questões, o sistema avança para T8. + // A presença de questões (robQuestionCount > 0) simplesmente marca a tarefa como feita. - return false + private fun isT8Complete(dto: ProtocolDto): Boolean { + return !dto.analysisAndSynthesisProcess.isNullOrBlank() } -} +} \ No newline at end of file diff --git a/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolStageServiceImplTest.kt b/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolStageServiceImplTest.kt index d803ac57..7b2fb280 100644 --- a/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolStageServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolStageServiceImplTest.kt @@ -21,10 +21,13 @@ import java.util.UUID import kotlin.test.Test import br.all.application.protocol.find.FindProtocolStageService.RequestModel import br.all.application.protocol.find.FindProtocolStageService.ResponseModel -import br.all.application.protocol.find.FindProtocolStageService.ProtocolStage +import br.all.application.protocol.find.FindProtocolStageService.ProtocolStage // Assuming this enum is updated import br.all.application.protocol.repository.CriterionDto import br.all.application.protocol.repository.PicocDto +import br.all.application.protocol.repository.ProtocolDto import br.all.application.question.repository.QuestionRepository +import br.all.application.review.repository.SystematicStudyDto +import br.all.application.study.repository.StudyReviewDto import br.all.domain.model.question.QuestionContextEnum import io.mockk.verify @@ -80,125 +83,118 @@ class FindProtocolStageServiceImplTest { ) precondition.makeEverythingWork() + + every { systematicStudyRepository.findById(systematicStudyId) } returns createFullSystematicStudyDto() + + every { studyReviewRepository.findAllFromReview(any()) } returns emptyList() + every { questionRepository.findAllBySystematicStudyId(any(), any()) } returns emptyList() } @Nested - @DisplayName("When successfully getting protocol's current stage") + @DisplayName("When getting protocol stage") inner class SuccessfullyGettingProtocolStage { + @Test - fun `should return PROTOCOL_PART_I stage when goal and justification are empty`() { - val protocolDto = protocolFactory.protocolDto( - systematicStudy = systematicStudyId, - goal = null, - justification = null - ) + fun `should return GENERAL_DEFINITION stage (T1) when systematic study name is blank`() { + val incompleteStudyDto = createFullSystematicStudyDto(title = "") + val protocolDto = protocolFactory.protocolDto(systematicStudy = systematicStudyId) + every { systematicStudyRepository.findById(systematicStudyId) } returns incompleteStudyDto every { protocolRepository.findById(systematicStudyId) } returns protocolDto - every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns emptyList() - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns emptyList() - val request = RequestModel(researcherId, systematicStudyId) + sut.getStage(presenter, RequestModel(researcherId, systematicStudyId)) + + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.GENERAL_DEFINITION) + verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } + } + + @Test + fun `should return RESEARCH_QUESTIONS stage (T2) when T1 is complete but no research questions exist`() { + val protocolDto = createFullProtocolDto(researchQuestions = emptySet()) - sut.getStage(presenter, request) + every { protocolRepository.findById(systematicStudyId) } returns protocolDto + + sut.getStage(presenter, RequestModel(researcherId, systematicStudyId)) - val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.PROTOCOL_PART_I) + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.RESEARCH_QUESTIONS) verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } } @Test - fun `should return PICOC stage when it is not filled`() { - val protocolDto = protocolFactory.protocolDto( - systematicStudy = systematicStudyId, - goal = "A goal", - justification = "A justification", - picoc = PicocDto( - population = "P", - intervention = null, - control = null, - outcome = null, - context = null - ) + fun `should return PICOC stage (T3) when it is started but not complete`() { + val protocolDto = createFullProtocolDto( + picoc = PicocDto(population = "P", intervention = "I", control = null, outcome = null, context = null) ) every { protocolRepository.findById(systematicStudyId) } returns protocolDto - every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns emptyList() - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns emptyList() - - val request = RequestModel(researcherId, systematicStudyId) - sut.getStage(presenter, request) + sut.getStage(presenter, RequestModel(researcherId, systematicStudyId)) val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.PICOC) verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } } @Test - fun `should return PROTOCOL_PART_II stage when its fields are empty`() { - val protocolDto = protocolFactory.protocolDto( - systematicStudy = systematicStudyId, - goal = "A goal", - justification = "A justification", - picoc = PicocDto(population = "P", intervention = "I", control = "C", outcome = "O", context = "C"), - studiesLanguages = emptySet(), - eligibilityCriteria = emptySet(), - informationSources = emptySet(), - keywords = emptySet() + fun `should return ELIGIBILITY_CRITERIA stage (T4) when T3 (PICOC) is skipped and T4 is incomplete`() { + val protocolDto = createFullProtocolDto( + picoc = PicocDto(null, null, null, null, null), + eligibilityCriteria = emptySet() ) every { protocolRepository.findById(systematicStudyId) } returns protocolDto - every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns emptyList() - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns emptyList() - - val request = RequestModel(researcherId, systematicStudyId) - sut.getStage(presenter, request) + sut.getStage(presenter, RequestModel(researcherId, systematicStudyId)) - val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.PROTOCOL_PART_II) + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.ELIGIBILITY_CRITERIA) verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } } @Test - fun `should return PROTOCOL_PART_III stage when its conditions are not met`() { - val protocolDto = protocolFactory.protocolDto( - systematicStudy = systematicStudyId, - goal = "A goal", - justification = "A justification", - picoc = PicocDto(population = "P", intervention = "I", control = "C", outcome = "O", context = "C"), - keywords = setOf("test"), - extractionQuestions = emptySet() - ) + fun `should return INFORMATION_SOURCES_AND_SEARCH_STRATEGY stage (T5) when T4 is complete but T5 is not`() { + val protocolDto = createFullProtocolDto(searchString = "") every { protocolRepository.findById(systematicStudyId) } returns protocolDto - every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns emptyList() + + sut.getStage(presenter, RequestModel(researcherId, systematicStudyId)) + + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.INFORMATION_SOURCES_AND_SEARCH_STRATEGY) + verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } + } + + @Test + fun `should return SELECTION_AND_EXTRACTION stage (T6) when T5 is complete but T6 is not (no extraction questions)`() { + val protocolDto = createFullProtocolDto() + every { protocolRepository.findById(systematicStudyId) } returns protocolDto every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns emptyList() - val request = RequestModel(researcherId, systematicStudyId) + sut.getStage(presenter, RequestModel(researcherId, systematicStudyId)) + + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.SELECTION_AND_EXTRACTION) + verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } + } + + @Test + fun `should return ANALYSIS_AND_SYNTHESIS_METHOD stage (T8) when T6 is complete but T8 is not`() { + val protocolDto = createFullProtocolDto(analysisAndSynthesisProcess = "") + every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns listOf(questionFactory.generateTextualDto()) + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns emptyList() - sut.getStage(presenter, request) + sut.getStage(presenter, RequestModel(researcherId, systematicStudyId)) - val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.PROTOCOL_PART_III) + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.ANALYSIS_AND_SYNTHESIS_METHOD) verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } } @Test - fun `should return IDENTIFICATION stage when no studies have been submitted`() { + fun `should return IDENTIFICATION stage when protocol is complete and no studies are imported`() { val protocolDto = createFullProtocolDto() - val questions = listOf( - questionFactory.generateTextualDto() - ) - every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns listOf(questionFactory.generateTextualDto()) + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns listOf(questionFactory.generateTextualDto()) every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns questions - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns questions - - val request = RequestModel(researcherId, systematicStudyId) - sut.getStage(presenter, request) + sut.getStage(presenter, RequestModel(researcherId, systematicStudyId)) val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.IDENTIFICATION) verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } @@ -207,116 +203,108 @@ class FindProtocolStageServiceImplTest { @Test fun `should return SELECTION stage when studies exist but none are included`() { val protocolDto = createFullProtocolDto() - val studies = listOf( - createFullStudyReviewDto(selectionStatus = "", extractionStatus = "") - ) - val questions = listOf( - questionFactory.generateTextualDto() - ) - + val studies = listOf(createFullStudyReviewDto(selectionStatus = "EXCLUDED")) every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns listOf(questionFactory.generateTextualDto()) + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns listOf(questionFactory.generateTextualDto()) every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns studies - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns questions - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns questions - - val request = RequestModel(researcherId, systematicStudyId) - sut.getStage(presenter, request) + sut.getStage(presenter, RequestModel(researcherId, systematicStudyId)) val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.SELECTION) verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } } @Test - fun `should return EXTRACTION stage when studies are included but none are extracted`() { + fun `should return EXTRACTION stage when studies are included but not extracted`() { val protocolDto = createFullProtocolDto() - val studies = listOf( - createFullStudyReviewDto(selectionStatus = "INCLUDED", extractionStatus = "") - ) - val questions = listOf( - questionFactory.generateTextualDto() - ) - + val studies = listOf(createFullStudyReviewDto(selectionStatus = "INCLUDED", extractionStatus = "PENDING")) every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns listOf(questionFactory.generateTextualDto()) + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns listOf(questionFactory.generateTextualDto()) every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns studies - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns questions - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns questions - - val request = RequestModel(researcherId, systematicStudyId) - sut.getStage(presenter, request) + sut.getStage(presenter, RequestModel(researcherId, systematicStudyId)) val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.EXTRACTION) verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } } @Test - fun `should return GRAPHICS stage when studies have been extracted`() { + fun `should return GRAPHICS stage when at least one study has been fully extracted`() { val protocolDto = createFullProtocolDto() - val studies = listOf( - createFullStudyReviewDto(selectionStatus = "INCLUDED", extractionStatus = "INCLUDED") - ) - val questions = listOf( - questionFactory.generateTextualDto() - ) - + val studies = listOf(createFullStudyReviewDto(selectionStatus = "INCLUDED", extractionStatus = "INCLUDED")) every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns listOf(questionFactory.generateTextualDto()) + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns listOf(questionFactory.generateTextualDto()) every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns studies - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns questions - every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns questions - - val request = RequestModel(researcherId, systematicStudyId) - sut.getStage(presenter, request) + sut.getStage(presenter, RequestModel(researcherId, systematicStudyId)) val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.GRAPHICS) verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } } } + private fun createFullSystematicStudyDto( + id: UUID = systematicStudyId, + title: String = "A complete systematic study", + description: String = "A complete description" + ) = SystematicStudyDto( + id = id, + title = title, + description = description, + owner = UUID.randomUUID(), + collaborators = emptySet() + ) - private fun createFullProtocolDto() = protocolFactory.protocolDto( - systematicStudy = systematicStudyId, - goal = "A goal", - justification = "A justification", - picoc = PicocDto(population = "P", intervention = "I", control = "C", outcome = "O", context = "C"), - studiesLanguages = setOf("English"), - eligibilityCriteria = setOf( - CriterionDto("test description", "INCLUSION"), - CriterionDto("test description", "EXCLUSION") + private fun createFullProtocolDto( + goal: String? = "A complete goal", + researchQuestions: Set = setOf("RQ1?"), + picoc: PicocDto? = PicocDto("P", "I", "C", "O", "Context"), + eligibilityCriteria: Set = setOf( + CriterionDto("Inclusion", "INCLUSION"), + CriterionDto("Exclusion", "EXCLUSION") ), - informationSources = setOf("IEEE"), - keywords = setOf("test"), - sourcesSelectionCriteria = "criteria", - searchMethod = "method", - selectionProcess = "process", - extractionQuestions = setOf(UUID.randomUUID()), - robQuestions = setOf(UUID.randomUUID()), - researchQuestions = setOf("RQ1?"), - analysisAndSynthesisProcess = "process" - ) + studyTypeDefinition: String? = "Randomized Controlled Trial", + studiesLanguages: Set = setOf("English"), + sourcesSelectionCriteria: String? = "Selection criteria", + informationSources: Set = setOf("Scopus"), + searchMethod: String? = "A valid search method", + keywords: Set = setOf("keyword1"), + searchString: String? = "((keyword1) AND (keyword2))", + selectionProcess: String? = "A valid selection process", + dataCollectionProcess: String? = "A valid data collection process", + analysisAndSynthesisProcess: String? = "A final analysis process" + ): ProtocolDto { + val baseDto = protocolFactory.protocolDto( + systematicStudy = systematicStudyId, + goal = goal, + justification = "A justification", + researchQuestions = researchQuestions, + picoc = picoc, + eligibilityCriteria = eligibilityCriteria, + studiesLanguages = studiesLanguages, + sourcesSelectionCriteria = sourcesSelectionCriteria, + informationSources = informationSources, + searchMethod = searchMethod, + keywords = keywords, + selectionProcess = selectionProcess, + analysisAndSynthesisProcess = analysisAndSynthesisProcess + ) + return baseDto.copy( + studyTypeDefinition = studyTypeDefinition, + searchString = searchString, + dataCollectionProcess = dataCollectionProcess + ) + } - private fun createFullStudyReviewDto(selectionStatus: String, extractionStatus: String) = studyReviewFactory.generateDto( - studyReviewId = 1L, + private fun createFullStudyReviewDto( + selectionStatus: String, + extractionStatus: String = "PENDING" + ) = studyReviewFactory.generateDto( systematicStudyId = systematicStudyId, - searchSessionId = UUID.randomUUID(), - type = "type", - title = "title", - year = 2025, - authors = "authors", - venue = "venue", - abstract = "abstract", - keywords = emptySet(), - references = emptyList(), - doi = "doi", - sources = emptySet(), - criteria = emptySet(), - formAnswers = emptyMap(), - robAnswers = emptyMap(), - comments = "comments", - readingPriority = "HIGH", - extractionStatus = extractionStatus, selectionStatus = selectionStatus, - score = 10 + extractionStatus = extractionStatus, ) -} +} \ No newline at end of file