-
Notifications
You must be signed in to change notification settings - Fork 288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Launch and Submission Timestamps to QR #2672
base: master
Are you sure you want to change the base?
Changes from 5 commits
cd27970
dc8c138
71d6c3d
5b0983e
cfdff4c
3156fdd
86bb30d
fea4e20
9266784
98cb866
dfec10d
809a27b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,7 @@ import com.google.android.fhir.datacapture.extensions.isHelpCode | |
import com.google.android.fhir.datacapture.extensions.isHidden | ||
import com.google.android.fhir.datacapture.extensions.isPaginated | ||
import com.google.android.fhir.datacapture.extensions.isRepeatedGroup | ||
import com.google.android.fhir.datacapture.extensions.launchTimestamp | ||
import com.google.android.fhir.datacapture.extensions.localizedTextSpanned | ||
import com.google.android.fhir.datacapture.extensions.maxValue | ||
import com.google.android.fhir.datacapture.extensions.maxValueCqfCalculatedValueExpression | ||
|
@@ -64,6 +65,7 @@ import com.google.android.fhir.datacapture.validation.Valid | |
import com.google.android.fhir.datacapture.validation.ValidationResult | ||
import com.google.android.fhir.datacapture.views.QuestionTextConfiguration | ||
import com.google.android.fhir.datacapture.views.QuestionnaireViewItem | ||
import java.util.Date | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.SharingStarted | ||
import kotlinx.coroutines.flow.StateFlow | ||
|
@@ -74,6 +76,7 @@ import kotlinx.coroutines.flow.stateIn | |
import kotlinx.coroutines.flow.update | ||
import kotlinx.coroutines.flow.withIndex | ||
import kotlinx.coroutines.launch | ||
import org.hl7.fhir.r4.model.DateTimeType | ||
import org.hl7.fhir.r4.model.Questionnaire | ||
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent | ||
import org.hl7.fhir.r4.model.QuestionnaireResponse | ||
|
@@ -160,6 +163,8 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat | |
.forEach { questionnaireResponse.addItem(it.createQuestionnaireResponseItem()) } | ||
} | ||
} | ||
// Add extension for questionnaire launch time stamp | ||
questionnaireResponse.launchTimestamp = DateTimeType(Date()) | ||
questionnaireResponse.packRepeatedGroups(questionnaire) | ||
} | ||
|
||
|
@@ -475,6 +480,8 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat | |
) | ||
.map { it.copy() } | ||
unpackRepeatedGroups([email protected]) | ||
// Use authored as a submission time stamp | ||
authored = Date() | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,7 @@ import com.google.android.fhir.datacapture.QuestionnaireFragment.Companion.EXTRA | |
import com.google.android.fhir.datacapture.QuestionnaireFragment.Companion.EXTRA_QUESTIONNAIRE_RESPONSE_JSON_STRING | ||
import com.google.android.fhir.datacapture.QuestionnaireFragment.Companion.EXTRA_QUESTIONNAIRE_RESPONSE_JSON_URI | ||
import com.google.android.fhir.datacapture.QuestionnaireFragment.Companion.EXTRA_SHOW_REVIEW_PAGE_FIRST | ||
import com.google.android.fhir.datacapture.extensions.EXTENSION_LAST_LAUNCHED_TIMESTAMP | ||
import com.google.android.fhir.datacapture.testing.DataCaptureTestApplication | ||
import com.google.common.truth.Truth.assertThat | ||
import java.io.File | ||
|
@@ -183,8 +184,23 @@ class QuestionnaireViewModelParameterizedTest( | |
val printer: IParser = FhirContext.forR4().newJsonParser() | ||
|
||
fun <T : IBaseResource> assertResourceEquals(actual: T, expected: T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as @ndegwamartin pointed out, might as well split this assert function into two to make it clearer and use the right one in the relevant tests... i think at the moment this code might hide errors and make debugging difficult in the future. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ndegwamartin can you please elaborate further on how can we split the assertion here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. create a new function to assert two questionnaire responses in which you fiddle with the timestamps. this assertion is used by a lot of tests. seems at least inefficient to do this operation for all resource types. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jingtang10 @ndegwamartin cc: @qiarie The updates I made to this method were not to test my own code, but to ensure the failing tests would pass. You can find the tests for my implementation here. After adding timestamps to the QuestionnaireResponses, many tests that asserted response equality started failing due to mismatching timestamps. Although the difference was only in milliseconds, it still caused the checks to fail. This left me with two options:
I chose the second approach as it was more time-efficient, and we already have separate tests for timestamp functionality. I hope this makes sense. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is that the function is now doing things that is quite specific to questionnaire responses and someone in the future is going to call the Please create a function called I think this change shouldn't be too big - it should be easy to find and replace usage of this function with questionnaire responses and use the new funciton. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also make sure you don't mutate the resources - make a copy and then remove the timestamp. |
||
assertThat(printer.encodeResourceToString(actual)) | ||
.isEqualTo(printer.encodeResourceToString(expected)) | ||
if (actual is QuestionnaireResponse && expected is QuestionnaireResponse) { | ||
val actualResponse = (actual as QuestionnaireResponse) | ||
val expectedResponse = | ||
(expected as QuestionnaireResponse).apply { | ||
extension.add( | ||
actualResponse.extension.firstOrNull { extension -> | ||
extension.url == EXTENSION_LAST_LAUNCHED_TIMESTAMP | ||
}, | ||
) | ||
authored = actualResponse.authored | ||
} | ||
assertThat(printer.encodeResourceToString(actualResponse)) | ||
.isEqualTo(printer.encodeResourceToString(expectedResponse)) | ||
} else { | ||
assertThat(printer.encodeResourceToString(actual)) | ||
.isEqualTo(printer.encodeResourceToString(expected)) | ||
} | ||
} | ||
|
||
@JvmStatic | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,6 +48,7 @@ import com.google.android.fhir.datacapture.extensions.EXTENSION_ENTRY_MODE_URL | |
import com.google.android.fhir.datacapture.extensions.EXTENSION_HIDDEN_URL | ||
import com.google.android.fhir.datacapture.extensions.EXTENSION_ITEM_CONTROL_SYSTEM | ||
import com.google.android.fhir.datacapture.extensions.EXTENSION_ITEM_CONTROL_URL | ||
import com.google.android.fhir.datacapture.extensions.EXTENSION_LAST_LAUNCHED_TIMESTAMP | ||
import com.google.android.fhir.datacapture.extensions.EXTENSION_SDC_QUESTIONNAIRE_LAUNCH_CONTEXT | ||
import com.google.android.fhir.datacapture.extensions.EXTENSION_VARIABLE_URL | ||
import com.google.android.fhir.datacapture.extensions.EntryMode | ||
|
@@ -651,7 +652,7 @@ class QuestionnaireViewModelTest { | |
|
||
val viewModel = createQuestionnaireViewModel(questionnaire, questionnaireResponse) | ||
|
||
runTest { assertResourceEquals(questionnaireResponse, viewModel.getQuestionnaireResponse()) } | ||
runTest { assertResourceEquals(viewModel.getQuestionnaireResponse(), questionnaireResponse) } | ||
} | ||
|
||
@Test | ||
|
@@ -7514,8 +7515,23 @@ class QuestionnaireViewModelTest { | |
val printer: IParser = FhirContext.forR4().newJsonParser() | ||
|
||
fun <T : IBaseResource> assertResourceEquals(actual: T, expected: T) { | ||
assertThat(printer.encodeResourceToString(actual)) | ||
.isEqualTo(printer.encodeResourceToString(expected)) | ||
if (actual is QuestionnaireResponse && expected is QuestionnaireResponse) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here. |
||
val actualResponse = (actual as QuestionnaireResponse) | ||
val expectedResponse = | ||
(expected as QuestionnaireResponse).apply { | ||
extension.add( | ||
actualResponse.extension.firstOrNull { extension -> | ||
extension.url == EXTENSION_LAST_LAUNCHED_TIMESTAMP | ||
}, | ||
) | ||
authored = actualResponse.authored | ||
} | ||
assertThat(printer.encodeResourceToString(actualResponse)) | ||
.isEqualTo(printer.encodeResourceToString(expectedResponse)) | ||
} else { | ||
assertThat(printer.encodeResourceToString(actual)) | ||
.isEqualTo(printer.encodeResourceToString(expected)) | ||
} | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we just overwrite the value here?
the whole operation of this
this.extension[this.extension.indexOf(it)]
seems to negate the benefit of using scope functions... looks a bit more clumsy in my opinion.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jingtang10 this is because we need to keep the previous extensions intact and only update the url for a specific extension. The url in extension is a immutable property so I had to assign a new one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i mean can you just overwrite th value without changeing the url? the url is already the same (as it has been checked in line 174).
so do somethign like this.extension.setValue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated