Skip to content

Commit 5e59ef5

Browse files
committed
Refactor to just send FhirValidator error messages to logcat
1 parent 73d4d6e commit 5e59ef5

File tree

6 files changed

+84
-167
lines changed

6 files changed

+84
-167
lines changed

android/engine/src/main/java/org/smartregister/fhircore/engine/di/FhirValidatorModule.kt

+1-3
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@ class FhirValidatorModule {
3737

3838
@Provides
3939
@Singleton
40-
fun provideFhirValidator(): FhirValidator {
41-
val fhirContext = FhirContext.forR4()
42-
40+
fun provideFhirValidator(fhirContext: FhirContext): FhirValidator {
4341
val validationSupportChain =
4442
ValidationSupportChain(
4543
DefaultProfileValidationSupport(fhirContext),

android/engine/src/main/java/org/smartregister/fhircore/engine/util/extension/FhirValidatorExtension.kt

+41-11
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,54 @@ import kotlin.coroutines.coroutineContext
2323
import kotlinx.coroutines.withContext
2424
import org.hl7.fhir.r4.model.Resource
2525
import org.smartregister.fhircore.engine.BuildConfig
26+
import timber.log.Timber
27+
28+
data class ResourceValidationResult(
29+
val resource: Resource,
30+
val validationResult: ValidationResult,
31+
) {
32+
val errorMessages
33+
get() = buildString {
34+
val messages =
35+
validationResult.messages.filter {
36+
it.severity.ordinal >= ResultSeverityEnum.WARNING.ordinal
37+
}
38+
39+
for (validationMsg in messages) {
40+
appendLine(
41+
"${validationMsg.message} - ${validationMsg.locationString} -- (${validationMsg.severity})",
42+
)
43+
}
44+
}
45+
}
46+
47+
data class FhirValidatorResultsWrapper(val results: List<ResourceValidationResult> = emptyList()) {
48+
val errorMessages = results.map { it.errorMessages }
49+
}
2650

2751
suspend fun FhirValidator.checkResourceValid(
2852
vararg resource: Resource,
29-
isDebug: Boolean = BuildConfig.BUILD_TYPE.contains("debug", ignoreCase = true),
30-
): List<ValidationResult> {
31-
if (!isDebug) return emptyList()
53+
isDebug: Boolean = BuildConfig.DEBUG,
54+
): FhirValidatorResultsWrapper {
55+
if (!isDebug) return FhirValidatorResultsWrapper()
3256

3357
return withContext(coroutineContext) {
34-
resource.map { this@checkResourceValid.validateWithResult(it) }
58+
FhirValidatorResultsWrapper(
59+
results =
60+
resource.map {
61+
val result = this@checkResourceValid.validateWithResult(it)
62+
ResourceValidationResult(it, result)
63+
},
64+
)
3565
}
3666
}
3767

38-
val ValidationResult.errorMessages
39-
get() = buildString {
40-
for (validationMsg in
41-
messages.filter { it.severity.ordinal >= ResultSeverityEnum.WARNING.ordinal }) {
42-
appendLine(
43-
"${validationMsg.message} - ${validationMsg.locationString} -- (${validationMsg.severity})",
44-
)
68+
fun FhirValidatorResultsWrapper.logErrorMessages() {
69+
results.forEach {
70+
if (it.errorMessages.isNotBlank()) {
71+
Timber.tag("$TAG (${it.resource.referenceValue()})").e(it.errorMessages)
4572
}
4673
}
74+
}
75+
76+
private const val TAG = "FhirValidator"

android/engine/src/test/java/org/smartregister/fhircore/engine/util/extension/FhirValidatorExtensionTest.kt

+16-22
Original file line numberDiff line numberDiff line change
@@ -49,28 +49,27 @@ class FhirValidatorExtensionTest : RobolectricTest() {
4949
fun testCheckResourceValidRunsNoValidationWhenBuildTypeIsNotDebug() = runTest {
5050
val basicResource = CarePlan()
5151
val fhirValidatorSpy = spyk(validator)
52-
val results = fhirValidatorSpy.checkResourceValid(basicResource, isDebug = false)
53-
Assert.assertTrue(results.isEmpty())
52+
val resultsWrapper = fhirValidatorSpy.checkResourceValid(basicResource, isDebug = false)
53+
Assert.assertTrue(resultsWrapper.results.isEmpty())
5454
verify(exactly = 0) { fhirValidatorSpy.validateWithResult(any<IBaseResource>()) }
5555
verify(exactly = 0) { fhirValidatorSpy.validateWithResult(any<String>()) }
5656
}
5757

5858
@Test
5959
fun testCheckResourceValidValidatesResourceStructureWhenCarePlanResourceInvalid() = runTest {
6060
val basicCarePlan = CarePlan()
61-
val results = validator.checkResourceValid(basicCarePlan)
62-
Assert.assertFalse(results.isEmpty())
61+
val resultsWrapper = validator.checkResourceValid(basicCarePlan)
6362
Assert.assertTrue(
64-
results.any {
65-
it.errorMessages.contains(
63+
resultsWrapper.errorMessages.any {
64+
it.contains(
6665
"CarePlan.status: minimum required = 1, but only found 0",
6766
ignoreCase = true,
6867
)
6968
},
7069
)
7170
Assert.assertTrue(
72-
results.any {
73-
it.errorMessages.contains(
71+
resultsWrapper.errorMessages.any {
72+
it.contains(
7473
"CarePlan.intent: minimum required = 1, but only found 0",
7574
ignoreCase = true,
7675
)
@@ -86,13 +85,11 @@ class FhirValidatorExtensionTest : RobolectricTest() {
8685
intent = CarePlan.CarePlanIntent.PLAN
8786
subject = Reference("Task/unknown")
8887
}
89-
val results = validator.checkResourceValid(carePlan)
90-
Assert.assertFalse(results.isEmpty())
91-
Assert.assertEquals(1, results.size)
88+
val resultsWrapper = validator.checkResourceValid(carePlan)
89+
Assert.assertEquals(1, resultsWrapper.errorMessages.size)
9290
Assert.assertTrue(
93-
results
91+
resultsWrapper.errorMessages
9492
.first()
95-
.errorMessages
9693
.contains(
9794
"The type 'Task' implied by the reference URL Task/unknown is not a valid Target for this element (must be one of [Group, Patient]) - CarePlan.subject",
9895
ignoreCase = true,
@@ -108,13 +105,11 @@ class FhirValidatorExtensionTest : RobolectricTest() {
108105
intent = CarePlan.CarePlanIntent.PLAN
109106
subject = Reference("unknown")
110107
}
111-
val results = validator.checkResourceValid(carePlan)
112-
Assert.assertFalse(results.isEmpty())
113-
Assert.assertEquals(1, results.size)
108+
val resultsWrapper = validator.checkResourceValid(carePlan)
109+
Assert.assertEquals(1, resultsWrapper.errorMessages.size)
114110
Assert.assertTrue(
115-
results
111+
resultsWrapper.errorMessages
116112
.first()
117-
.errorMessages
118113
.contains(
119114
"The syntax of the reference 'unknown' looks incorrect, and it should be checked - CarePlan.subject",
120115
ignoreCase = true,
@@ -131,9 +126,8 @@ class FhirValidatorExtensionTest : RobolectricTest() {
131126
intent = CarePlan.CarePlanIntent.PLAN
132127
subject = Reference(patient)
133128
}
134-
val results = validator.checkResourceValid(carePlan)
135-
Assert.assertFalse(results.isEmpty())
136-
Assert.assertEquals(1, results.size)
137-
Assert.assertTrue(results.first().errorMessages.isBlank())
129+
val resultsWrapper = validator.checkResourceValid(carePlan)
130+
Assert.assertEquals(1, resultsWrapper.errorMessages.size)
131+
Assert.assertTrue(resultsWrapper.errorMessages.first().isBlank())
138132
}
139133
}

android/quest/src/main/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireActivity.kt

+10-62
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import dagger.hilt.android.AndroidEntryPoint
3939
import java.io.Serializable
4040
import javax.inject.Inject
4141
import kotlinx.coroutines.launch
42-
import org.hl7.fhir.r4.model.IdType
4342
import org.hl7.fhir.r4.model.Questionnaire
4443
import org.hl7.fhir.r4.model.QuestionnaireResponse
4544
import org.hl7.fhir.r4.model.Resource
@@ -53,11 +52,9 @@ import org.smartregister.fhircore.engine.util.DispatcherProvider
5352
import org.smartregister.fhircore.engine.util.extension.encodeResourceToString
5453
import org.smartregister.fhircore.engine.util.extension.parcelable
5554
import org.smartregister.fhircore.engine.util.extension.parcelableArrayList
56-
import org.smartregister.fhircore.engine.util.extension.referenceValue
5755
import org.smartregister.fhircore.engine.util.extension.showToast
5856
import org.smartregister.fhircore.engine.util.location.LocationUtils
5957
import org.smartregister.fhircore.engine.util.location.PermissionUtils
60-
import org.smartregister.fhircore.quest.BuildConfig
6158
import org.smartregister.fhircore.quest.R
6259
import org.smartregister.fhircore.quest.databinding.QuestionnaireActivityBinding
6360
import org.smartregister.fhircore.quest.util.ResourceUtils
@@ -339,75 +336,26 @@ class QuestionnaireActivity : BaseMultiLanguageActivity() {
339336
questionnaireConfig = questionnaireConfig,
340337
actionParameters = actionParameters,
341338
context = this@QuestionnaireActivity,
342-
) { idTypes, questionnaireResponse, extractedValidationErrors ->
339+
) { idTypes, questionnaireResponse ->
343340
// Dismiss progress indicator dialog, submit result then finish activity
344341
// TODO Ensure this dialog is dismissed even when an exception is encountered
345342
setProgressState(QuestionnaireProgressState.ExtractionInProgress(false))
346-
347-
if (BuildConfig.BUILD_TYPE.contains("debug", ignoreCase = true)) {
348-
val message =
349-
if (extractedValidationErrors.isEmpty()) {
350-
"Questionnaire submitted and saved successfully with no validation errors"
351-
} else {
352-
"""
353-
Questionnaire `${questionnaire?.referenceValue()}` was submitted but had the following validation errors
354-
355-
${
356-
buildString {
357-
extractedValidationErrors.forEach {
358-
appendLine("${it.key}: ")
359-
append(it.value)
360-
appendLine()
361-
}
362-
}
363-
}
364-
"""
365-
.trimIndent()
366-
}
367-
368-
AlertDialogue.showInfoAlert(
369-
this@QuestionnaireActivity,
370-
message,
371-
"Questionnaire submitted",
372-
{
373-
it.dismiss()
374-
finishOnQuestionnaireSubmission(
375-
questionnaireResponse,
376-
idTypes,
377-
questionnaireConfig,
378-
)
379-
},
380-
)
381-
} else {
382-
finishOnQuestionnaireSubmission(
383-
questionnaireResponse,
384-
idTypes,
385-
questionnaireConfig,
386-
)
387-
}
343+
setResult(
344+
Activity.RESULT_OK,
345+
Intent().apply {
346+
putExtra(QUESTIONNAIRE_RESPONSE, questionnaireResponse as Serializable)
347+
putExtra(QUESTIONNAIRE_SUBMISSION_EXTRACTED_RESOURCE_IDS, idTypes as Serializable)
348+
putExtra(QUESTIONNAIRE_CONFIG, questionnaireConfig as Parcelable)
349+
},
350+
)
351+
finish()
388352
}
389353
}
390354
}
391355
}
392356
}
393357
}
394358

395-
private fun finishOnQuestionnaireSubmission(
396-
questionnaireResponse: QuestionnaireResponse,
397-
idTypes: List<IdType>,
398-
questionnaireConfig: QuestionnaireConfig,
399-
) {
400-
setResult(
401-
Activity.RESULT_OK,
402-
Intent().apply {
403-
putExtra(QUESTIONNAIRE_RESPONSE, questionnaireResponse as Serializable)
404-
putExtra(QUESTIONNAIRE_SUBMISSION_EXTRACTED_RESOURCE_IDS, idTypes as Serializable)
405-
putExtra(QUESTIONNAIRE_CONFIG, questionnaireConfig as Parcelable)
406-
},
407-
)
408-
finish()
409-
}
410-
411359
private fun handleBackPress() {
412360
if (questionnaireConfig.isReadOnly()) {
413361
finish()

0 commit comments

Comments
 (0)