us_core_test_kit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (350) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/lib/us_core_test_kit/custom_groups/capability_statement/conformance_support_test.rb +41 -0
  4. data/lib/us_core_test_kit/custom_groups/capability_statement/fhir_version_test.rb +15 -0
  5. data/lib/us_core_test_kit/custom_groups/capability_statement/json_support_test.rb +40 -0
  6. data/lib/us_core_test_kit/custom_groups/capability_statement/profile_support_test.rb +90 -0
  7. data/lib/us_core_test_kit/custom_groups/capability_statement_group.rb +64 -0
  8. data/lib/us_core_test_kit/custom_groups/clinical_notes_guidance_group.rb +208 -0
  9. data/lib/us_core_test_kit/custom_groups/data_absent_reason_group.rb +59 -0
  10. data/lib/us_core_test_kit/date_search_validation.rb +101 -0
  11. data/lib/us_core_test_kit/ext/fhir_models.rb +59 -0
  12. data/lib/us_core_test_kit/fhir_resource_navigation.rb +63 -0
  13. data/lib/us_core_test_kit/generated/allergy_intolerance/allergy_intolerance_must_support_test.rb +40 -0
  14. data/lib/us_core_test_kit/generated/allergy_intolerance/allergy_intolerance_patient_clinical_status_search_test.rb +46 -0
  15. data/lib/us_core_test_kit/generated/allergy_intolerance/allergy_intolerance_patient_search_test.rb +60 -0
  16. data/lib/us_core_test_kit/generated/allergy_intolerance/allergy_intolerance_provenance_revinclude_search_test.rb +49 -0
  17. data/lib/us_core_test_kit/generated/allergy_intolerance/allergy_intolerance_read_test.rb +24 -0
  18. data/lib/us_core_test_kit/generated/allergy_intolerance/allergy_intolerance_reference_resolution_test.rb +28 -0
  19. data/lib/us_core_test_kit/generated/allergy_intolerance/allergy_intolerance_validation_test.rb +34 -0
  20. data/lib/us_core_test_kit/generated/allergy_intolerance_group.rb +85 -0
  21. data/lib/us_core_test_kit/generated/bodyheight/bodyheight_must_support_test.rb +49 -0
  22. data/lib/us_core_test_kit/generated/bodyheight/bodyheight_patient_category_date_search_test.rb +46 -0
  23. data/lib/us_core_test_kit/generated/bodyheight/bodyheight_patient_category_search_test.rb +45 -0
  24. data/lib/us_core_test_kit/generated/bodyheight/bodyheight_patient_category_status_search_test.rb +47 -0
  25. data/lib/us_core_test_kit/generated/bodyheight/bodyheight_patient_code_date_search_test.rb +48 -0
  26. data/lib/us_core_test_kit/generated/bodyheight/bodyheight_patient_code_search_test.rb +62 -0
  27. data/lib/us_core_test_kit/generated/bodyheight/bodyheight_provenance_revinclude_search_test.rb +51 -0
  28. data/lib/us_core_test_kit/generated/bodyheight/bodyheight_read_test.rb +24 -0
  29. data/lib/us_core_test_kit/generated/bodyheight/bodyheight_reference_resolution_test.rb +28 -0
  30. data/lib/us_core_test_kit/generated/bodyheight/bodyheight_validation_test.rb +34 -0
  31. data/lib/us_core_test_kit/generated/bodyheight_group.rb +93 -0
  32. data/lib/us_core_test_kit/generated/bodytemp/bodytemp_must_support_test.rb +49 -0
  33. data/lib/us_core_test_kit/generated/bodytemp/bodytemp_patient_category_date_search_test.rb +46 -0
  34. data/lib/us_core_test_kit/generated/bodytemp/bodytemp_patient_category_search_test.rb +45 -0
  35. data/lib/us_core_test_kit/generated/bodytemp/bodytemp_patient_category_status_search_test.rb +47 -0
  36. data/lib/us_core_test_kit/generated/bodytemp/bodytemp_patient_code_date_search_test.rb +48 -0
  37. data/lib/us_core_test_kit/generated/bodytemp/bodytemp_patient_code_search_test.rb +62 -0
  38. data/lib/us_core_test_kit/generated/bodytemp/bodytemp_provenance_revinclude_search_test.rb +51 -0
  39. data/lib/us_core_test_kit/generated/bodytemp/bodytemp_read_test.rb +24 -0
  40. data/lib/us_core_test_kit/generated/bodytemp/bodytemp_reference_resolution_test.rb +28 -0
  41. data/lib/us_core_test_kit/generated/bodytemp/bodytemp_validation_test.rb +34 -0
  42. data/lib/us_core_test_kit/generated/bodytemp_group.rb +93 -0
  43. data/lib/us_core_test_kit/generated/bodyweight/bodyweight_must_support_test.rb +49 -0
  44. data/lib/us_core_test_kit/generated/bodyweight/bodyweight_patient_category_date_search_test.rb +46 -0
  45. data/lib/us_core_test_kit/generated/bodyweight/bodyweight_patient_category_search_test.rb +45 -0
  46. data/lib/us_core_test_kit/generated/bodyweight/bodyweight_patient_category_status_search_test.rb +47 -0
  47. data/lib/us_core_test_kit/generated/bodyweight/bodyweight_patient_code_date_search_test.rb +48 -0
  48. data/lib/us_core_test_kit/generated/bodyweight/bodyweight_patient_code_search_test.rb +62 -0
  49. data/lib/us_core_test_kit/generated/bodyweight/bodyweight_provenance_revinclude_search_test.rb +51 -0
  50. data/lib/us_core_test_kit/generated/bodyweight/bodyweight_read_test.rb +24 -0
  51. data/lib/us_core_test_kit/generated/bodyweight/bodyweight_reference_resolution_test.rb +28 -0
  52. data/lib/us_core_test_kit/generated/bodyweight/bodyweight_validation_test.rb +34 -0
  53. data/lib/us_core_test_kit/generated/bodyweight_group.rb +93 -0
  54. data/lib/us_core_test_kit/generated/bp/bp_must_support_test.rb +52 -0
  55. data/lib/us_core_test_kit/generated/bp/bp_patient_category_date_search_test.rb +46 -0
  56. data/lib/us_core_test_kit/generated/bp/bp_patient_category_search_test.rb +45 -0
  57. data/lib/us_core_test_kit/generated/bp/bp_patient_category_status_search_test.rb +47 -0
  58. data/lib/us_core_test_kit/generated/bp/bp_patient_code_date_search_test.rb +48 -0
  59. data/lib/us_core_test_kit/generated/bp/bp_patient_code_search_test.rb +62 -0
  60. data/lib/us_core_test_kit/generated/bp/bp_provenance_revinclude_search_test.rb +51 -0
  61. data/lib/us_core_test_kit/generated/bp/bp_read_test.rb +24 -0
  62. data/lib/us_core_test_kit/generated/bp/bp_reference_resolution_test.rb +28 -0
  63. data/lib/us_core_test_kit/generated/bp/bp_validation_test.rb +34 -0
  64. data/lib/us_core_test_kit/generated/bp_group.rb +93 -0
  65. data/lib/us_core_test_kit/generated/care_plan/care_plan_must_support_test.rb +41 -0
  66. data/lib/us_core_test_kit/generated/care_plan/care_plan_patient_category_date_search_test.rb +48 -0
  67. data/lib/us_core_test_kit/generated/care_plan/care_plan_patient_category_search_test.rb +62 -0
  68. data/lib/us_core_test_kit/generated/care_plan/care_plan_patient_category_status_date_search_test.rb +48 -0
  69. data/lib/us_core_test_kit/generated/care_plan/care_plan_patient_category_status_search_test.rb +47 -0
  70. data/lib/us_core_test_kit/generated/care_plan/care_plan_provenance_revinclude_search_test.rb +51 -0
  71. data/lib/us_core_test_kit/generated/care_plan/care_plan_read_test.rb +24 -0
  72. data/lib/us_core_test_kit/generated/care_plan/care_plan_reference_resolution_test.rb +28 -0
  73. data/lib/us_core_test_kit/generated/care_plan/care_plan_validation_test.rb +34 -0
  74. data/lib/us_core_test_kit/generated/care_plan_group.rb +89 -0
  75. data/lib/us_core_test_kit/generated/care_team/care_team_must_support_test.rb +39 -0
  76. data/lib/us_core_test_kit/generated/care_team/care_team_patient_status_search_test.rb +62 -0
  77. data/lib/us_core_test_kit/generated/care_team/care_team_provenance_revinclude_search_test.rb +50 -0
  78. data/lib/us_core_test_kit/generated/care_team/care_team_read_test.rb +24 -0
  79. data/lib/us_core_test_kit/generated/care_team/care_team_reference_resolution_test.rb +28 -0
  80. data/lib/us_core_test_kit/generated/care_team/care_team_validation_test.rb +34 -0
  81. data/lib/us_core_test_kit/generated/care_team_group.rb +83 -0
  82. data/lib/us_core_test_kit/generated/condition/condition_must_support_test.rb +39 -0
  83. data/lib/us_core_test_kit/generated/condition/condition_patient_category_search_test.rb +47 -0
  84. data/lib/us_core_test_kit/generated/condition/condition_patient_clinical_status_search_test.rb +46 -0
  85. data/lib/us_core_test_kit/generated/condition/condition_patient_code_search_test.rb +47 -0
  86. data/lib/us_core_test_kit/generated/condition/condition_patient_onset_date_search_test.rb +47 -0
  87. data/lib/us_core_test_kit/generated/condition/condition_patient_search_test.rb +60 -0
  88. data/lib/us_core_test_kit/generated/condition/condition_provenance_revinclude_search_test.rb +49 -0
  89. data/lib/us_core_test_kit/generated/condition/condition_read_test.rb +24 -0
  90. data/lib/us_core_test_kit/generated/condition/condition_reference_resolution_test.rb +28 -0
  91. data/lib/us_core_test_kit/generated/condition/condition_validation_test.rb +34 -0
  92. data/lib/us_core_test_kit/generated/condition_group.rb +91 -0
  93. data/lib/us_core_test_kit/generated/device/device_must_support_test.rb +43 -0
  94. data/lib/us_core_test_kit/generated/device/device_patient_search_test.rb +65 -0
  95. data/lib/us_core_test_kit/generated/device/device_patient_type_search_test.rb +52 -0
  96. data/lib/us_core_test_kit/generated/device/device_provenance_revinclude_search_test.rb +49 -0
  97. data/lib/us_core_test_kit/generated/device/device_read_test.rb +24 -0
  98. data/lib/us_core_test_kit/generated/device/device_reference_resolution_test.rb +28 -0
  99. data/lib/us_core_test_kit/generated/device/device_validation_test.rb +34 -0
  100. data/lib/us_core_test_kit/generated/device_group.rb +85 -0
  101. data/lib/us_core_test_kit/generated/diagnostic_report_lab/diagnostic_report_lab_must_support_test.rb +43 -0
  102. data/lib/us_core_test_kit/generated/diagnostic_report_lab/diagnostic_report_lab_patient_category_date_search_test.rb +46 -0
  103. data/lib/us_core_test_kit/generated/diagnostic_report_lab/diagnostic_report_lab_patient_category_search_test.rb +63 -0
  104. data/lib/us_core_test_kit/generated/diagnostic_report_lab/diagnostic_report_lab_patient_code_date_search_test.rb +48 -0
  105. data/lib/us_core_test_kit/generated/diagnostic_report_lab/diagnostic_report_lab_patient_code_search_test.rb +45 -0
  106. data/lib/us_core_test_kit/generated/diagnostic_report_lab/diagnostic_report_lab_patient_search_test.rb +44 -0
  107. data/lib/us_core_test_kit/generated/diagnostic_report_lab/diagnostic_report_lab_patient_status_search_test.rb +46 -0
  108. data/lib/us_core_test_kit/generated/diagnostic_report_lab/diagnostic_report_lab_provenance_revinclude_search_test.rb +51 -0
  109. data/lib/us_core_test_kit/generated/diagnostic_report_lab/diagnostic_report_lab_read_test.rb +24 -0
  110. data/lib/us_core_test_kit/generated/diagnostic_report_lab/diagnostic_report_lab_reference_resolution_test.rb +28 -0
  111. data/lib/us_core_test_kit/generated/diagnostic_report_lab/diagnostic_report_lab_validation_test.rb +34 -0
  112. data/lib/us_core_test_kit/generated/diagnostic_report_lab_group.rb +96 -0
  113. data/lib/us_core_test_kit/generated/diagnostic_report_note/diagnostic_report_note_must_support_test.rb +43 -0
  114. data/lib/us_core_test_kit/generated/diagnostic_report_note/diagnostic_report_note_patient_category_date_search_test.rb +46 -0
  115. data/lib/us_core_test_kit/generated/diagnostic_report_note/diagnostic_report_note_patient_category_search_test.rb +63 -0
  116. data/lib/us_core_test_kit/generated/diagnostic_report_note/diagnostic_report_note_patient_code_date_search_test.rb +48 -0
  117. data/lib/us_core_test_kit/generated/diagnostic_report_note/diagnostic_report_note_patient_code_search_test.rb +45 -0
  118. data/lib/us_core_test_kit/generated/diagnostic_report_note/diagnostic_report_note_patient_search_test.rb +44 -0
  119. data/lib/us_core_test_kit/generated/diagnostic_report_note/diagnostic_report_note_patient_status_search_test.rb +46 -0
  120. data/lib/us_core_test_kit/generated/diagnostic_report_note/diagnostic_report_note_provenance_revinclude_search_test.rb +51 -0
  121. data/lib/us_core_test_kit/generated/diagnostic_report_note/diagnostic_report_note_read_test.rb +24 -0
  122. data/lib/us_core_test_kit/generated/diagnostic_report_note/diagnostic_report_note_reference_resolution_test.rb +28 -0
  123. data/lib/us_core_test_kit/generated/diagnostic_report_note/diagnostic_report_note_validation_test.rb +34 -0
  124. data/lib/us_core_test_kit/generated/diagnostic_report_note_group.rb +96 -0
  125. data/lib/us_core_test_kit/generated/document_reference/document_reference_id_search_test.rb +40 -0
  126. data/lib/us_core_test_kit/generated/document_reference/document_reference_must_support_test.rb +49 -0
  127. data/lib/us_core_test_kit/generated/document_reference/document_reference_patient_category_date_search_test.rb +46 -0
  128. data/lib/us_core_test_kit/generated/document_reference/document_reference_patient_category_search_test.rb +45 -0
  129. data/lib/us_core_test_kit/generated/document_reference/document_reference_patient_search_test.rb +61 -0
  130. data/lib/us_core_test_kit/generated/document_reference/document_reference_patient_status_search_test.rb +46 -0
  131. data/lib/us_core_test_kit/generated/document_reference/document_reference_patient_type_period_search_test.rb +48 -0
  132. data/lib/us_core_test_kit/generated/document_reference/document_reference_patient_type_search_test.rb +45 -0
  133. data/lib/us_core_test_kit/generated/document_reference/document_reference_provenance_revinclude_search_test.rb +50 -0
  134. data/lib/us_core_test_kit/generated/document_reference/document_reference_read_test.rb +24 -0
  135. data/lib/us_core_test_kit/generated/document_reference/document_reference_reference_resolution_test.rb +28 -0
  136. data/lib/us_core_test_kit/generated/document_reference/document_reference_validation_test.rb +34 -0
  137. data/lib/us_core_test_kit/generated/document_reference_group.rb +99 -0
  138. data/lib/us_core_test_kit/generated/encounter/encounter_class_patient_search_test.rb +47 -0
  139. data/lib/us_core_test_kit/generated/encounter/encounter_date_patient_search_test.rb +45 -0
  140. data/lib/us_core_test_kit/generated/encounter/encounter_id_search_test.rb +40 -0
  141. data/lib/us_core_test_kit/generated/encounter/encounter_identifier_search_test.rb +43 -0
  142. data/lib/us_core_test_kit/generated/encounter/encounter_must_support_test.rb +51 -0
  143. data/lib/us_core_test_kit/generated/encounter/encounter_patient_search_test.rb +61 -0
  144. data/lib/us_core_test_kit/generated/encounter/encounter_patient_status_search_test.rb +45 -0
  145. data/lib/us_core_test_kit/generated/encounter/encounter_patient_type_search_test.rb +47 -0
  146. data/lib/us_core_test_kit/generated/encounter/encounter_provenance_revinclude_search_test.rb +50 -0
  147. data/lib/us_core_test_kit/generated/encounter/encounter_read_test.rb +24 -0
  148. data/lib/us_core_test_kit/generated/encounter/encounter_reference_resolution_test.rb +28 -0
  149. data/lib/us_core_test_kit/generated/encounter/encounter_validation_test.rb +34 -0
  150. data/lib/us_core_test_kit/generated/encounter_group.rb +97 -0
  151. data/lib/us_core_test_kit/generated/goal/goal_must_support_test.rb +39 -0
  152. data/lib/us_core_test_kit/generated/goal/goal_patient_lifecycle_status_search_test.rb +45 -0
  153. data/lib/us_core_test_kit/generated/goal/goal_patient_search_test.rb +60 -0
  154. data/lib/us_core_test_kit/generated/goal/goal_patient_target_date_search_test.rb +47 -0
  155. data/lib/us_core_test_kit/generated/goal/goal_provenance_revinclude_search_test.rb +49 -0
  156. data/lib/us_core_test_kit/generated/goal/goal_read_test.rb +24 -0
  157. data/lib/us_core_test_kit/generated/goal/goal_reference_resolution_test.rb +28 -0
  158. data/lib/us_core_test_kit/generated/goal/goal_validation_test.rb +34 -0
  159. data/lib/us_core_test_kit/generated/goal_group.rb +87 -0
  160. data/lib/us_core_test_kit/generated/head_circumference/head_circumference_must_support_test.rb +49 -0
  161. data/lib/us_core_test_kit/generated/head_circumference/head_circumference_patient_category_date_search_test.rb +46 -0
  162. data/lib/us_core_test_kit/generated/head_circumference/head_circumference_patient_category_search_test.rb +45 -0
  163. data/lib/us_core_test_kit/generated/head_circumference/head_circumference_patient_category_status_search_test.rb +47 -0
  164. data/lib/us_core_test_kit/generated/head_circumference/head_circumference_patient_code_date_search_test.rb +48 -0
  165. data/lib/us_core_test_kit/generated/head_circumference/head_circumference_patient_code_search_test.rb +62 -0
  166. data/lib/us_core_test_kit/generated/head_circumference/head_circumference_provenance_revinclude_search_test.rb +51 -0
  167. data/lib/us_core_test_kit/generated/head_circumference/head_circumference_read_test.rb +24 -0
  168. data/lib/us_core_test_kit/generated/head_circumference/head_circumference_reference_resolution_test.rb +28 -0
  169. data/lib/us_core_test_kit/generated/head_circumference/head_circumference_validation_test.rb +34 -0
  170. data/lib/us_core_test_kit/generated/head_circumference_group.rb +93 -0
  171. data/lib/us_core_test_kit/generated/heartrate/heartrate_must_support_test.rb +49 -0
  172. data/lib/us_core_test_kit/generated/heartrate/heartrate_patient_category_date_search_test.rb +46 -0
  173. data/lib/us_core_test_kit/generated/heartrate/heartrate_patient_category_search_test.rb +45 -0
  174. data/lib/us_core_test_kit/generated/heartrate/heartrate_patient_category_status_search_test.rb +47 -0
  175. data/lib/us_core_test_kit/generated/heartrate/heartrate_patient_code_date_search_test.rb +48 -0
  176. data/lib/us_core_test_kit/generated/heartrate/heartrate_patient_code_search_test.rb +62 -0
  177. data/lib/us_core_test_kit/generated/heartrate/heartrate_provenance_revinclude_search_test.rb +51 -0
  178. data/lib/us_core_test_kit/generated/heartrate/heartrate_read_test.rb +24 -0
  179. data/lib/us_core_test_kit/generated/heartrate/heartrate_reference_resolution_test.rb +28 -0
  180. data/lib/us_core_test_kit/generated/heartrate/heartrate_validation_test.rb +34 -0
  181. data/lib/us_core_test_kit/generated/heartrate_group.rb +93 -0
  182. data/lib/us_core_test_kit/generated/immunization/immunization_must_support_test.rb +40 -0
  183. data/lib/us_core_test_kit/generated/immunization/immunization_patient_date_search_test.rb +47 -0
  184. data/lib/us_core_test_kit/generated/immunization/immunization_patient_search_test.rb +60 -0
  185. data/lib/us_core_test_kit/generated/immunization/immunization_patient_status_search_test.rb +45 -0
  186. data/lib/us_core_test_kit/generated/immunization/immunization_provenance_revinclude_search_test.rb +50 -0
  187. data/lib/us_core_test_kit/generated/immunization/immunization_read_test.rb +24 -0
  188. data/lib/us_core_test_kit/generated/immunization/immunization_reference_resolution_test.rb +28 -0
  189. data/lib/us_core_test_kit/generated/immunization/immunization_validation_test.rb +34 -0
  190. data/lib/us_core_test_kit/generated/immunization_group.rb +87 -0
  191. data/lib/us_core_test_kit/generated/medication_request/medication_request_must_support_test.rb +44 -0
  192. data/lib/us_core_test_kit/generated/medication_request/medication_request_patient_intent_authoredon_search_test.rb +53 -0
  193. data/lib/us_core_test_kit/generated/medication_request/medication_request_patient_intent_encounter_search_test.rb +52 -0
  194. data/lib/us_core_test_kit/generated/medication_request/medication_request_patient_intent_search_test.rb +68 -0
  195. data/lib/us_core_test_kit/generated/medication_request/medication_request_patient_intent_status_search_test.rb +49 -0
  196. data/lib/us_core_test_kit/generated/medication_request/medication_request_provenance_revinclude_search_test.rb +51 -0
  197. data/lib/us_core_test_kit/generated/medication_request/medication_request_read_test.rb +24 -0
  198. data/lib/us_core_test_kit/generated/medication_request/medication_request_reference_resolution_test.rb +28 -0
  199. data/lib/us_core_test_kit/generated/medication_request/medication_request_validation_test.rb +34 -0
  200. data/lib/us_core_test_kit/generated/medication_request/medication_validation_test.rb +34 -0
  201. data/lib/us_core_test_kit/generated/medication_request_group.rb +92 -0
  202. data/lib/us_core_test_kit/generated/observation_lab/observation_lab_must_support_test.rb +41 -0
  203. data/lib/us_core_test_kit/generated/observation_lab/observation_lab_patient_category_date_search_test.rb +46 -0
  204. data/lib/us_core_test_kit/generated/observation_lab/observation_lab_patient_category_search_test.rb +62 -0
  205. data/lib/us_core_test_kit/generated/observation_lab/observation_lab_patient_category_status_search_test.rb +47 -0
  206. data/lib/us_core_test_kit/generated/observation_lab/observation_lab_patient_code_date_search_test.rb +48 -0
  207. data/lib/us_core_test_kit/generated/observation_lab/observation_lab_patient_code_search_test.rb +45 -0
  208. data/lib/us_core_test_kit/generated/observation_lab/observation_lab_provenance_revinclude_search_test.rb +51 -0
  209. data/lib/us_core_test_kit/generated/observation_lab/observation_lab_read_test.rb +24 -0
  210. data/lib/us_core_test_kit/generated/observation_lab/observation_lab_reference_resolution_test.rb +28 -0
  211. data/lib/us_core_test_kit/generated/observation_lab/observation_lab_validation_test.rb +34 -0
  212. data/lib/us_core_test_kit/generated/observation_lab_group.rb +93 -0
  213. data/lib/us_core_test_kit/generated/organization/organization_address_search_test.rb +39 -0
  214. data/lib/us_core_test_kit/generated/organization/organization_must_support_test.rb +47 -0
  215. data/lib/us_core_test_kit/generated/organization/organization_name_search_test.rb +49 -0
  216. data/lib/us_core_test_kit/generated/organization/organization_read_test.rb +24 -0
  217. data/lib/us_core_test_kit/generated/organization/organization_reference_resolution_test.rb +28 -0
  218. data/lib/us_core_test_kit/generated/organization/organization_validation_test.rb +34 -0
  219. data/lib/us_core_test_kit/generated/organization_group.rb +84 -0
  220. data/lib/us_core_test_kit/generated/patient/patient_birthdate_family_search_test.rb +41 -0
  221. data/lib/us_core_test_kit/generated/patient/patient_birthdate_name_search_test.rb +39 -0
  222. data/lib/us_core_test_kit/generated/patient/patient_family_gender_search_test.rb +41 -0
  223. data/lib/us_core_test_kit/generated/patient/patient_gender_name_search_test.rb +39 -0
  224. data/lib/us_core_test_kit/generated/patient/patient_id_search_test.rb +53 -0
  225. data/lib/us_core_test_kit/generated/patient/patient_identifier_search_test.rb +40 -0
  226. data/lib/us_core_test_kit/generated/patient/patient_must_support_test.rb +57 -0
  227. data/lib/us_core_test_kit/generated/patient/patient_name_search_test.rb +39 -0
  228. data/lib/us_core_test_kit/generated/patient/patient_provenance_revinclude_search_test.rb +49 -0
  229. data/lib/us_core_test_kit/generated/patient/patient_read_test.rb +24 -0
  230. data/lib/us_core_test_kit/generated/patient/patient_reference_resolution_test.rb +28 -0
  231. data/lib/us_core_test_kit/generated/patient/patient_validation_test.rb +34 -0
  232. data/lib/us_core_test_kit/generated/patient_group.rb +99 -0
  233. data/lib/us_core_test_kit/generated/pediatric_bmi_for_age/pediatric_bmi_for_age_must_support_test.rb +49 -0
  234. data/lib/us_core_test_kit/generated/pediatric_bmi_for_age/pediatric_bmi_for_age_patient_category_date_search_test.rb +46 -0
  235. data/lib/us_core_test_kit/generated/pediatric_bmi_for_age/pediatric_bmi_for_age_patient_category_search_test.rb +45 -0
  236. data/lib/us_core_test_kit/generated/pediatric_bmi_for_age/pediatric_bmi_for_age_patient_category_status_search_test.rb +47 -0
  237. data/lib/us_core_test_kit/generated/pediatric_bmi_for_age/pediatric_bmi_for_age_patient_code_date_search_test.rb +48 -0
  238. data/lib/us_core_test_kit/generated/pediatric_bmi_for_age/pediatric_bmi_for_age_patient_code_search_test.rb +62 -0
  239. data/lib/us_core_test_kit/generated/pediatric_bmi_for_age/pediatric_bmi_for_age_provenance_revinclude_search_test.rb +51 -0
  240. data/lib/us_core_test_kit/generated/pediatric_bmi_for_age/pediatric_bmi_for_age_read_test.rb +24 -0
  241. data/lib/us_core_test_kit/generated/pediatric_bmi_for_age/pediatric_bmi_for_age_reference_resolution_test.rb +28 -0
  242. data/lib/us_core_test_kit/generated/pediatric_bmi_for_age/pediatric_bmi_for_age_validation_test.rb +34 -0
  243. data/lib/us_core_test_kit/generated/pediatric_bmi_for_age_group.rb +93 -0
  244. data/lib/us_core_test_kit/generated/pediatric_weight_for_height/pediatric_weight_for_height_must_support_test.rb +49 -0
  245. data/lib/us_core_test_kit/generated/pediatric_weight_for_height/pediatric_weight_for_height_patient_category_date_search_test.rb +46 -0
  246. data/lib/us_core_test_kit/generated/pediatric_weight_for_height/pediatric_weight_for_height_patient_category_search_test.rb +45 -0
  247. data/lib/us_core_test_kit/generated/pediatric_weight_for_height/pediatric_weight_for_height_patient_category_status_search_test.rb +47 -0
  248. data/lib/us_core_test_kit/generated/pediatric_weight_for_height/pediatric_weight_for_height_patient_code_date_search_test.rb +48 -0
  249. data/lib/us_core_test_kit/generated/pediatric_weight_for_height/pediatric_weight_for_height_patient_code_search_test.rb +62 -0
  250. data/lib/us_core_test_kit/generated/pediatric_weight_for_height/pediatric_weight_for_height_provenance_revinclude_search_test.rb +51 -0
  251. data/lib/us_core_test_kit/generated/pediatric_weight_for_height/pediatric_weight_for_height_read_test.rb +24 -0
  252. data/lib/us_core_test_kit/generated/pediatric_weight_for_height/pediatric_weight_for_height_reference_resolution_test.rb +28 -0
  253. data/lib/us_core_test_kit/generated/pediatric_weight_for_height/pediatric_weight_for_height_validation_test.rb +34 -0
  254. data/lib/us_core_test_kit/generated/pediatric_weight_for_height_group.rb +93 -0
  255. data/lib/us_core_test_kit/generated/practitioner/practitioner_identifier_search_test.rb +40 -0
  256. data/lib/us_core_test_kit/generated/practitioner/practitioner_must_support_test.rb +40 -0
  257. data/lib/us_core_test_kit/generated/practitioner/practitioner_name_search_test.rb +49 -0
  258. data/lib/us_core_test_kit/generated/practitioner/practitioner_read_test.rb +24 -0
  259. data/lib/us_core_test_kit/generated/practitioner/practitioner_reference_resolution_test.rb +28 -0
  260. data/lib/us_core_test_kit/generated/practitioner/practitioner_validation_test.rb +34 -0
  261. data/lib/us_core_test_kit/generated/practitioner_group.rb +84 -0
  262. data/lib/us_core_test_kit/generated/procedure/procedure_must_support_test.rb +38 -0
  263. data/lib/us_core_test_kit/generated/procedure/procedure_patient_code_date_search_test.rb +48 -0
  264. data/lib/us_core_test_kit/generated/procedure/procedure_patient_date_search_test.rb +45 -0
  265. data/lib/us_core_test_kit/generated/procedure/procedure_patient_search_test.rb +60 -0
  266. data/lib/us_core_test_kit/generated/procedure/procedure_patient_status_search_test.rb +46 -0
  267. data/lib/us_core_test_kit/generated/procedure/procedure_provenance_revinclude_search_test.rb +50 -0
  268. data/lib/us_core_test_kit/generated/procedure/procedure_read_test.rb +24 -0
  269. data/lib/us_core_test_kit/generated/procedure/procedure_reference_resolution_test.rb +28 -0
  270. data/lib/us_core_test_kit/generated/procedure/procedure_validation_test.rb +34 -0
  271. data/lib/us_core_test_kit/generated/procedure_group.rb +90 -0
  272. data/lib/us_core_test_kit/generated/provenance/provenance_must_support_test.rb +44 -0
  273. data/lib/us_core_test_kit/generated/provenance/provenance_read_test.rb +24 -0
  274. data/lib/us_core_test_kit/generated/provenance/provenance_reference_resolution_test.rb +28 -0
  275. data/lib/us_core_test_kit/generated/provenance/provenance_validation_test.rb +34 -0
  276. data/lib/us_core_test_kit/generated/provenance_group.rb +56 -0
  277. data/lib/us_core_test_kit/generated/pulse_oximetry/pulse_oximetry_must_support_test.rb +65 -0
  278. data/lib/us_core_test_kit/generated/pulse_oximetry/pulse_oximetry_patient_category_date_search_test.rb +46 -0
  279. data/lib/us_core_test_kit/generated/pulse_oximetry/pulse_oximetry_patient_category_search_test.rb +45 -0
  280. data/lib/us_core_test_kit/generated/pulse_oximetry/pulse_oximetry_patient_category_status_search_test.rb +47 -0
  281. data/lib/us_core_test_kit/generated/pulse_oximetry/pulse_oximetry_patient_code_date_search_test.rb +48 -0
  282. data/lib/us_core_test_kit/generated/pulse_oximetry/pulse_oximetry_patient_code_search_test.rb +62 -0
  283. data/lib/us_core_test_kit/generated/pulse_oximetry/pulse_oximetry_provenance_revinclude_search_test.rb +51 -0
  284. data/lib/us_core_test_kit/generated/pulse_oximetry/pulse_oximetry_read_test.rb +24 -0
  285. data/lib/us_core_test_kit/generated/pulse_oximetry/pulse_oximetry_reference_resolution_test.rb +28 -0
  286. data/lib/us_core_test_kit/generated/pulse_oximetry/pulse_oximetry_validation_test.rb +34 -0
  287. data/lib/us_core_test_kit/generated/pulse_oximetry_group.rb +93 -0
  288. data/lib/us_core_test_kit/generated/resource_list.rb +26 -0
  289. data/lib/us_core_test_kit/generated/resprate/resprate_must_support_test.rb +49 -0
  290. data/lib/us_core_test_kit/generated/resprate/resprate_patient_category_date_search_test.rb +46 -0
  291. data/lib/us_core_test_kit/generated/resprate/resprate_patient_category_search_test.rb +45 -0
  292. data/lib/us_core_test_kit/generated/resprate/resprate_patient_category_status_search_test.rb +47 -0
  293. data/lib/us_core_test_kit/generated/resprate/resprate_patient_code_date_search_test.rb +48 -0
  294. data/lib/us_core_test_kit/generated/resprate/resprate_patient_code_search_test.rb +62 -0
  295. data/lib/us_core_test_kit/generated/resprate/resprate_provenance_revinclude_search_test.rb +51 -0
  296. data/lib/us_core_test_kit/generated/resprate/resprate_read_test.rb +24 -0
  297. data/lib/us_core_test_kit/generated/resprate/resprate_reference_resolution_test.rb +28 -0
  298. data/lib/us_core_test_kit/generated/resprate/resprate_validation_test.rb +34 -0
  299. data/lib/us_core_test_kit/generated/resprate_group.rb +93 -0
  300. data/lib/us_core_test_kit/generated/smokingstatus/smokingstatus_must_support_test.rb +39 -0
  301. data/lib/us_core_test_kit/generated/smokingstatus/smokingstatus_patient_category_date_search_test.rb +48 -0
  302. data/lib/us_core_test_kit/generated/smokingstatus/smokingstatus_patient_category_search_test.rb +47 -0
  303. data/lib/us_core_test_kit/generated/smokingstatus/smokingstatus_patient_category_status_search_test.rb +47 -0
  304. data/lib/us_core_test_kit/generated/smokingstatus/smokingstatus_patient_code_date_search_test.rb +48 -0
  305. data/lib/us_core_test_kit/generated/smokingstatus/smokingstatus_patient_code_search_test.rb +62 -0
  306. data/lib/us_core_test_kit/generated/smokingstatus/smokingstatus_provenance_revinclude_search_test.rb +51 -0
  307. data/lib/us_core_test_kit/generated/smokingstatus/smokingstatus_read_test.rb +24 -0
  308. data/lib/us_core_test_kit/generated/smokingstatus/smokingstatus_reference_resolution_test.rb +28 -0
  309. data/lib/us_core_test_kit/generated/smokingstatus/smokingstatus_validation_test.rb +34 -0
  310. data/lib/us_core_test_kit/generated/smokingstatus_group.rb +93 -0
  311. data/lib/us_core_test_kit/generated/us_core_test_suite.rb +110 -0
  312. data/lib/us_core_test_kit/generator/group_generator.rb +171 -0
  313. data/lib/us_core_test_kit/generator/group_metadata.rb +98 -0
  314. data/lib/us_core_test_kit/generator/group_metadata_extractor.rb +281 -0
  315. data/lib/us_core_test_kit/generator/ig_loader.rb +63 -0
  316. data/lib/us_core_test_kit/generator/ig_metadata.rb +49 -0
  317. data/lib/us_core_test_kit/generator/ig_metadata_extractor.rb +56 -0
  318. data/lib/us_core_test_kit/generator/ig_resources.rb +48 -0
  319. data/lib/us_core_test_kit/generator/must_support_metadata_extractor.rb +221 -0
  320. data/lib/us_core_test_kit/generator/must_support_test_generator.rb +86 -0
  321. data/lib/us_core_test_kit/generator/naming.rb +58 -0
  322. data/lib/us_core_test_kit/generator/provenance_revinclude_search_test_generator.rb +186 -0
  323. data/lib/us_core_test_kit/generator/read_test_generator.rb +89 -0
  324. data/lib/us_core_test_kit/generator/reference_resolution_test_generator.rb +72 -0
  325. data/lib/us_core_test_kit/generator/resource_list_generator.rb +46 -0
  326. data/lib/us_core_test_kit/generator/search_definition_metadata_extractor.rb +181 -0
  327. data/lib/us_core_test_kit/generator/search_metadata_extractor.rb +74 -0
  328. data/lib/us_core_test_kit/generator/search_test_generator.rb +280 -0
  329. data/lib/us_core_test_kit/generator/special_cases.rb +17 -0
  330. data/lib/us_core_test_kit/generator/suite_generator.rb +67 -0
  331. data/lib/us_core_test_kit/generator/terminology_binding_metadata_extractor.rb +105 -0
  332. data/lib/us_core_test_kit/generator/validation_test_generator.rb +124 -0
  333. data/lib/us_core_test_kit/generator.rb +86 -0
  334. data/lib/us_core_test_kit/igs/StructureDefinition-bodyheight.json +3772 -0
  335. data/lib/us_core_test_kit/igs/StructureDefinition-bodytemp.json +3772 -0
  336. data/lib/us_core_test_kit/igs/StructureDefinition-bodyweight.json +3772 -0
  337. data/lib/us_core_test_kit/igs/StructureDefinition-bp.json +6034 -0
  338. data/lib/us_core_test_kit/igs/StructureDefinition-heartrate.json +3756 -0
  339. data/lib/us_core_test_kit/igs/StructureDefinition-resprate.json +3756 -0
  340. data/lib/us_core_test_kit/igs/package.tgz +0 -0
  341. data/lib/us_core_test_kit/must_support_test.rb +146 -0
  342. data/lib/us_core_test_kit/read_test.rb +62 -0
  343. data/lib/us_core_test_kit/reference_resolution_test.rb +111 -0
  344. data/lib/us_core_test_kit/request_logger.rb +46 -0
  345. data/lib/us_core_test_kit/search_test.rb +686 -0
  346. data/lib/us_core_test_kit/search_test_properties.rb +56 -0
  347. data/lib/us_core_test_kit/validation_test.rb +48 -0
  348. data/lib/us_core_test_kit/version.rb +3 -0
  349. data/lib/us_core_test_kit.rb +2 -0
  350. metadata +477 -0
@@ -0,0 +1,686 @@
1
+ require_relative 'date_search_validation'
2
+ require_relative 'fhir_resource_navigation'
3
+ require_relative 'search_test_properties'
4
+
5
+ module USCoreTestKit
6
+ module SearchTest
7
+ extend Forwardable
8
+ include DateSearchValidation
9
+ include FHIRResourceNavigation
10
+
11
+ def_delegators 'self.class', :metadata, :provenance_metadata, :properties
12
+ def_delegators 'properties',
13
+ :resource_type,
14
+ :search_param_names,
15
+ :saves_delayed_references?,
16
+ :first_search?,
17
+ :fixed_value_search?,
18
+ :possible_status_search?,
19
+ :test_medication_inclusion?,
20
+ :test_post_search?,
21
+ :token_search_params,
22
+ :test_reference_variants?,
23
+ :params_with_comparators,
24
+ :multiple_or_search_params
25
+
26
+ def all_search_params
27
+ @all_search_params ||=
28
+ patient_id_list.each_with_object({}) do |patient_id, params|
29
+ params[patient_id] ||= []
30
+ new_params =
31
+ if fixed_value_search?
32
+ fixed_value_search_param_values.map { |value| fixed_value_search_params(value, patient_id) }
33
+ else
34
+ [search_params_with_values(patient_id)]
35
+ end
36
+ new_params.reject! do |params|
37
+ params.any? { |_key, value| value.blank? }
38
+ end
39
+
40
+ params[patient_id].concat(new_params)
41
+ end
42
+ end
43
+
44
+ def all_provenance_revinclude_search_params
45
+ @all_provenance_revinclude_search_params ||=
46
+ all_search_params.transform_values! do |params_list|
47
+ params_list.map { |params| params.merge(_revinclude: 'Provenance:target') }
48
+ end
49
+ end
50
+
51
+ def any_valid_search_params?(search_params)
52
+ search_params.any? { |_patient_id, params| params.present? }
53
+ end
54
+
55
+ def run_provenance_revinclude_search_test
56
+ # TODO: skip if not supported?
57
+ skip_if !any_valid_search_params?(all_provenance_revinclude_search_params), unable_to_resolve_params_message
58
+
59
+ provenance_resources =
60
+ all_provenance_revinclude_search_params.flat_map do |_patient_id, params_list|
61
+ params_list.flat_map do |params|
62
+ fhir_search resource_type, params: params
63
+
64
+ perform_search_with_status(params, patient_id) if response[:status] == 400 && possible_status_search?
65
+
66
+ check_search_response
67
+
68
+ fetch_all_bundled_resources(additional_resource_types: ['Provenance'])
69
+ .select { |resource| resource.resourceType == 'Provenance' }
70
+ end
71
+ end
72
+
73
+ scratch_provenance_resources[:all] ||= []
74
+ scratch_provenance_resources[:all].concat(provenance_resources)
75
+
76
+ save_delayed_references(provenance_resources, 'Provenance')
77
+
78
+ skip_if provenance_resources.empty?, no_resources_skip_message('Provenance')
79
+ end
80
+
81
+ def run_search_test
82
+ # TODO: skip if not supported?
83
+ skip_if !any_valid_search_params?(all_search_params), unable_to_resolve_params_message
84
+
85
+ resources_returned =
86
+ all_search_params.flat_map do |patient_id, params_list|
87
+ params_list.flat_map { |params| perform_search(params, patient_id) }
88
+ end
89
+
90
+ skip_if resources_returned.empty?, no_resources_skip_message
91
+
92
+ perform_multiple_or_search_test if multiple_or_search_params.present?
93
+ end
94
+
95
+ def perform_search(params, patient_id)
96
+ fhir_search resource_type, params: params
97
+
98
+ perform_search_with_status(params, patient_id) if response[:status] == 400 && possible_status_search?
99
+
100
+ check_search_response
101
+
102
+ resources_returned =
103
+ fetch_all_bundled_resources.select { |resource| resource.resourceType == resource_type }
104
+
105
+ return [] if resources_returned.blank?
106
+
107
+ perform_comparator_searches(params, patient_id) if params_with_comparators.present?
108
+
109
+ filter_devices(resources_returned) if resource_type == 'Device'
110
+
111
+ if first_search?
112
+ all_scratch_resources.concat(resources_returned).uniq!
113
+ scratch_resources_for_patient(patient_id).concat(resources_returned).uniq!
114
+ end
115
+
116
+ resources_returned.each do |resource|
117
+ check_resource_against_params(resource, params)
118
+ end
119
+
120
+ save_delayed_references(resources_returned) if saves_delayed_references?
121
+
122
+ return resources_returned if all_search_variants_tested?
123
+
124
+ perform_post_search(resources_returned, params) if test_post_search?
125
+ test_medication_inclusion(resources_returned, params, patient_id) if test_medication_inclusion?
126
+ perform_reference_with_type_search(params, resources_returned.count) if test_reference_variants?
127
+ perform_search_with_system(params, patient_id) if token_search_params.present?
128
+
129
+ resources_returned
130
+ end
131
+
132
+ def perform_post_search(get_search_resources, params)
133
+ fhir_search resource_type, params: params, search_method: :post
134
+
135
+ check_search_response
136
+
137
+ post_search_resources = fetch_all_bundled_resources.select { |resource| resource.resourceType == resource_type }
138
+ get_resource_count = get_search_resources.length
139
+ post_resource_count = post_search_resources.length
140
+
141
+ search_variant_test_records[:post_variant] = true
142
+
143
+ assert get_resource_count == post_resource_count,
144
+ "Expected search by POST to return the same results as search by GET, " \
145
+ "but GET search returned #{get_resource_count} resources, and POST search " \
146
+ "returned #{post_resource_count} resources."
147
+ end
148
+
149
+ def filter_devices(resources)
150
+ codes_to_include = implantable_device_codes&.split(',')&.map(&:strip)
151
+ return resources if codes_to_include.blank?
152
+
153
+ resources.select! do |resource|
154
+ resource&.type&.coding&.any? { |coding| codes_to_include.include?(coding.code) }
155
+ end
156
+ end
157
+
158
+ def search_and_check_response(params, resource_type = self.resource_type)
159
+ fhir_search resource_type, params: params
160
+
161
+ check_search_response
162
+ end
163
+
164
+ def check_search_response
165
+ assert_response_status(200)
166
+ assert_resource_type(:bundle)
167
+ # NOTE: how do we want to handle validating Bundles?
168
+ end
169
+
170
+ def search_variant_test_records
171
+ @search_variant_test_records ||= initial_search_variant_test_records
172
+ end
173
+
174
+ def initial_search_variant_test_records
175
+ {}.tap do |records|
176
+ records[:post_variant] = false if test_post_search?
177
+ records[:medication_inclusion] = false if test_medication_inclusion?
178
+ records[:reference_variants] = false if test_reference_variants?
179
+ records[:token_variants] = false if token_search_params.present?
180
+ records[:comparator_searches] = Set.new if params_with_comparators.present?
181
+ end
182
+ end
183
+
184
+ def all_search_variants_tested?
185
+ search_variant_test_records.all? { |_variant, tested| tested.present? } &&
186
+ all_comparator_searches_tested?
187
+ end
188
+
189
+ def all_comparator_searches_tested?
190
+ return true if params_with_comparators.blank?
191
+
192
+ Set.new(params_with_comparators) == search_variant_test_records[:comparator_searches]
193
+ end
194
+
195
+ def date_comparator_value(comparator, date)
196
+ date = date.start || date.end if date.is_a? FHIR::Period
197
+ case comparator
198
+ when 'lt', 'le'
199
+ comparator + (DateTime.xmlschema(date) + 1).xmlschema
200
+ when 'gt', 'ge'
201
+ comparator + (DateTime.xmlschema(date) - 1).xmlschema
202
+ else
203
+ # ''
204
+ raise "Unsupported comparator '#{comparator}'"
205
+ end
206
+ end
207
+
208
+ def required_comparators(name)
209
+ metadata
210
+ .search_definitions
211
+ .dig(name.to_sym, :comparators)
212
+ .select { |_comparator, expectation| expectation == 'SHALL' }
213
+ .keys
214
+ .map(&:to_s)
215
+ end
216
+
217
+ def perform_comparator_searches(params, patient_id)
218
+ params_with_comparators.each do |name|
219
+ next if search_variant_test_records[:comparator_searches].include? name
220
+
221
+ required_comparators(name).each do |comparator|
222
+ path = search_param_path(name)
223
+ date_element = find_a_value_at(scratch_resources_for_patient(patient_id), path)
224
+ params_with_comparator = params.merge(name => date_comparator_value(comparator, date_element))
225
+
226
+ search_and_check_response(params_with_comparator)
227
+
228
+ fetch_all_bundled_resources
229
+ .each { |resource| check_resource_against_params(resource, params_with_comparator) }
230
+ end
231
+
232
+ search_variant_test_records[:comparator_searches] << name
233
+ end
234
+ end
235
+
236
+ def perform_reference_with_type_search(params, resource_count)
237
+ return if resource_count == 0
238
+ return if search_variant_test_records[:reference_variants]
239
+
240
+ new_search_params = params.merge('patient' => "Patient/#{params['patient']}")
241
+ search_and_check_response(new_search_params)
242
+
243
+ new_resource_count =
244
+ fetch_all_bundled_resources
245
+ .select { |resource| resource.resourceType == resource_type }
246
+ .count
247
+
248
+ assert new_resource_count == resource_count,
249
+ "Expected search by `#{params['patient']}` to to return the same results as searching " \
250
+ "by `#{new_search_params['patient']}`, but found #{resource_count} resources with " \
251
+ "`#{params['patient']}` and #{new_resource_count} with `#{new_search_params['patient']}`"
252
+
253
+ search_variant_test_records[:reference_variants] = true
254
+ end
255
+
256
+ def perform_search_with_system(params, patient_id)
257
+ return if search_variant_test_records[:token_variants]
258
+
259
+ new_search_params = token_search_params.each_with_object({}) do |name, search_params|
260
+ search_params[name] = search_param_value(name, patient_id, include_system: true)
261
+ end
262
+ return if new_search_params.any? { |_name, value| value.blank? }
263
+
264
+ search_params = params.merge(new_search_params)
265
+ search_and_check_response(search_params)
266
+
267
+ resources_returned =
268
+ fetch_all_bundled_resources
269
+ .select { |resource| resource.resourceType == resource_type }
270
+
271
+ assert resources_returned.present?, "No resources were returned when searching by `system|code`"
272
+
273
+ search_variant_test_records[:token_variants] = true
274
+ end
275
+
276
+ def perform_search_with_status(
277
+ original_params,
278
+ patient_id,
279
+ status_search_values: self.status_search_values,
280
+ resource_type: self.resource_type
281
+ )
282
+ assert resource.is_a?(FHIR::OperationOutcome), "Server returned a status of 400 without an OperationOutcome"
283
+ # TODO: warn about documenting status requirements
284
+ status_search_values.flat_map do |status_value|
285
+ search_params = original_params.merge("#{status_search_param_name}": status_value)
286
+
287
+ search_and_check_response(search_params)
288
+
289
+ entries = resource.entry.select { |entry| entry.resource.resourceType == resource_type }
290
+
291
+ if entries.present?
292
+ original_params.merge!("#{status_search_param_name}": status_value)
293
+ break
294
+ end
295
+ end
296
+ end
297
+
298
+ def status_search_param_name
299
+ @status_search_param_name ||=
300
+ metadata.search_definitions.keys.find { |key| key.to_s.include? 'status' }
301
+ end
302
+
303
+ def status_search_values
304
+ default_search_values(status_search_param_name)
305
+ end
306
+
307
+ def default_search_values(param_name)
308
+ definition = metadata.search_definitions[param_name]
309
+ return [] if definition.blank?
310
+
311
+ definition[:multiple_or] == 'SHALL' ? [definition[:values].join(',')] : [definition[:values]]
312
+ end
313
+
314
+
315
+ def perform_multiple_or_search_test
316
+ resolved_one = false
317
+
318
+ all_search_params.each do |patient_id, params_list|
319
+ next unless params_list.present?
320
+
321
+ search_params = params_list.first
322
+ existing_values = {}
323
+ missing_values = {}
324
+
325
+ multiple_or_search_params.each do |param_name|
326
+ search_value = default_search_values(param_name.to_sym)
327
+ search_params = search_params.merge("#{param_name}" => search_value)
328
+ existing_values[param_name.to_sym] = scratch_resources_for_patient(patient_id).map(&param_name.to_sym).compact.uniq
329
+ end
330
+
331
+ # skip patient without multiple-or values
332
+ next if existing_values.values.any?(&:empty?)
333
+
334
+ resolved_one = true
335
+
336
+ search_and_check_response(search_params)
337
+
338
+ resources_returned =
339
+ fetch_all_bundled_resources
340
+ .select { |resource| resource.resourceType == resource_type }
341
+
342
+ multiple_or_search_params.each do |param_name|
343
+ missing_values[param_name.to_sym] = existing_values[param_name.to_sym] - resources_returned.map(&param_name.to_sym)
344
+ end
345
+
346
+ missing_value_message = missing_values
347
+ .reject { |_param_name, missing_value| missing_value.empty? }
348
+ .map { |param_name, missing_value| "#{missing_value.join(',')} values from #{param_name}" }
349
+ .join(' and ')
350
+
351
+ assert missing_value_message.blank?, "Could not find #{missing_value_message} in any of the resources returned for Patient/#{patient_id}"
352
+
353
+ break if resolved_one
354
+ end
355
+ end
356
+
357
+ def test_medication_inclusion(medication_requests, params, patient_id)
358
+ return if search_variant_test_records[:medication_inclusion]
359
+
360
+ scratch[:medication_resources] ||= {}
361
+ scratch[:medication_resources][:all] ||= []
362
+ scratch[:medication_resources][patient_id] ||= []
363
+ scratch[:medication_resources][:contained] ||= []
364
+
365
+ requests_with_external_references =
366
+ medication_requests
367
+ .select { |request| request&.medicationReference&.present? }
368
+ .reject { |request| request&.medicationReference&.reference&.start_with? '#' }
369
+
370
+ contained_medications =
371
+ medication_requests
372
+ .select { |request| request&.medicationReference&.reference&.start_with? '#' }
373
+ .flat_map(&:contained)
374
+ .select { |resource| resource.resourceType == 'Medication' }
375
+
376
+ scratch[:medication_resources][:all] += contained_medications
377
+ scratch[:medication_resources][patient_id] += contained_medications
378
+ scratch[:medication_resources][:contained] += contained_medications
379
+
380
+ return if requests_with_external_references.blank?
381
+
382
+ search_params = params.merge(_include: 'MedicationRequest:medication')
383
+
384
+ search_and_check_response(search_params)
385
+
386
+ medications = fetch_all_bundled_resources.select { |resource| resource.resourceType == 'Medication' }
387
+ assert medications.present?, 'No Medications were included in the search results'
388
+
389
+ medications.uniq!(&:id)
390
+
391
+ scratch[:medication_resources][:all] += medications
392
+ scratch[:medication_resources][patient_id] += medications
393
+
394
+ search_variant_test_records[:medication_inclusion] = true
395
+ end
396
+
397
+ def all_scratch_resources
398
+ scratch_resources[:all] ||= []
399
+ end
400
+
401
+ def scratch_resources_for_patient(patient_id)
402
+ return all_scratch_resources if patient_id.nil?
403
+
404
+ scratch_resources[patient_id] ||= []
405
+ end
406
+
407
+ def references_to_save(resource_type = nil)
408
+ reference_metadata = resource_type == 'Provenance' ? provenance_metadata : metadata
409
+ reference_metadata.delayed_references
410
+ end
411
+
412
+ def fixed_value_search_param_name
413
+ (search_param_names - ['patient']).first
414
+ end
415
+
416
+ def fixed_value_search_param_values
417
+ metadata.search_definitions[fixed_value_search_param_name.to_sym][:values]
418
+ end
419
+
420
+ def fixed_value_search_params(value, patient_id)
421
+ search_param_names.each_with_object({}) do |name, params|
422
+ patient_id_param?(name) ? params[name] = patient_id : params[name] = value
423
+ end
424
+ end
425
+
426
+ def search_params_with_values(patient_id)
427
+ search_param_names.each_with_object({}) do |name, params|
428
+ value = patient_id_param?(name) ? patient_id : search_param_value(name, patient_id)
429
+ params[name] = value
430
+ end
431
+ end
432
+
433
+ def patient_id_list
434
+ return [nil] unless respond_to? :patient_ids
435
+
436
+ patient_ids.split(',').map(&:strip)
437
+ end
438
+
439
+ def patient_search?
440
+ search_param_names.any? { |name| patient_id_param? name }
441
+ end
442
+
443
+ def patient_id_param?(name)
444
+ name == 'patient' || (name == '_id' && resource_type == 'Patient')
445
+ end
446
+
447
+ def search_param_path(name)
448
+ path = metadata.search_definitions[name.to_sym][:path]
449
+ path == 'class' ? 'local_class' : path
450
+ end
451
+
452
+ def all_search_params_present?(params)
453
+ params.all? { |_name, value| value.present? }
454
+ end
455
+
456
+ def array_of_codes(array)
457
+ array.map { |name| "`#{name}`" }.join(', ')
458
+ end
459
+
460
+ def unable_to_resolve_params_message
461
+ "Could not find values for all search params #{array_of_codes(search_param_names)}"
462
+ end
463
+
464
+ def empty_search_params_message(empty_search_params)
465
+ "Could not find values for the search parameters #{array_of_codes(empty_search_params.keys)}"
466
+ end
467
+
468
+ def no_resources_skip_message(resource_type = self.resource_type)
469
+ "No #{resource_type} resources appear to be available. " \
470
+ "Please use patients with more information"
471
+ end
472
+
473
+ def fetch_all_bundled_resources(
474
+ reply_handler: nil,
475
+ max_pages: 20,
476
+ additional_resource_types: [],
477
+ resource_type: self.resource_type
478
+ )
479
+ page_count = 1
480
+ resources = []
481
+ bundle = resource
482
+
483
+ until bundle.nil? || page_count == max_pages
484
+ resources += bundle&.entry&.map { |entry| entry&.resource }
485
+ next_bundle_link = bundle&.link&.find { |link| link.relation == 'next' }&.url
486
+ reply_handler&.call(response)
487
+
488
+ break if next_bundle_link.blank?
489
+
490
+ reply = fhir_client.raw_read_url(next_bundle_link)
491
+
492
+ store_request('outgoing') { reply }
493
+ error_message = cant_resolve_next_bundle_message(next_bundle_link)
494
+
495
+ assert_response_status(200)
496
+ assert_valid_json(reply.body, error_message)
497
+
498
+ bundle = fhir_client.parse_reply(FHIR::Bundle, fhir_client.default_format, reply)
499
+
500
+ page_count += 1
501
+ end
502
+
503
+ valid_resource_types = [resource_type, 'OperationOutcome'].concat(additional_resource_types)
504
+ valid_resource_types << 'Medication' if resource_type == 'MedicationRequest'
505
+
506
+ all_valid_resource_types =
507
+ resources.all? { |entry| valid_resource_types.include? entry.resourceType }
508
+
509
+ assert all_valid_resource_types,
510
+ "All resources returned must be of the type: #{valid_resource_types.join(', ')}"
511
+
512
+ resources
513
+ end
514
+
515
+ def cant_resolve_next_bundle_message(link)
516
+ "Could not resolve next bundle: #{link}"
517
+ end
518
+
519
+ def search_param_value(name, patient_id, include_system: false)
520
+ path = search_param_path(name)
521
+ element = find_a_value_at(scratch_resources_for_patient(patient_id), path)
522
+ search_value =
523
+ case element
524
+ when FHIR::Period
525
+ if element.start.present?
526
+ 'gt' + (DateTime.xmlschema(element.start) - 1).xmlschema
527
+ else
528
+ end_datetime = get_fhir_datetime_range(element.end)[:end]
529
+ 'lt' + (end_datetime + 1).xmlschema
530
+ end
531
+ when FHIR::Reference
532
+ element.reference
533
+ when FHIR::CodeableConcept
534
+ if include_system
535
+ coding =
536
+ find_a_value_at(element, 'coding') { |coding| coding.code.present? && coding.system.present? }
537
+ coding.present? ? "#{coding.system}|#{coding.code}" : nil
538
+ else
539
+ find_a_value_at(element, 'coding.code')
540
+ end
541
+ when FHIR::Identifier
542
+ if include_system
543
+ identifier = find_a_value_at(scratch_resources_for_patient(patient_id), path) do |identifier|
544
+ identifier.value.present? && identifier.system.present?
545
+ end
546
+ identifier.present? ? "#{identifier.system}|#{identifier.value}" : nil
547
+ else
548
+ element.value
549
+ end
550
+ when FHIR::Coding
551
+ if include_system
552
+ coding = find_a_value_at(scratch_resources_for_patient(patient_id), path) do |coding|
553
+ coding.code.present? && coding.system.present?
554
+ end
555
+ coding.present? ? "#{coding.system}|#{coding.code}" : nil
556
+ else
557
+ element.code
558
+ end
559
+ when FHIR::HumanName
560
+ element.family || element.given&.first || element.text
561
+ when FHIR::Address
562
+ element.text || element.city || element.state || element.postalCode || element.country
563
+ else
564
+ element
565
+ end
566
+ escaped_value = search_value&.gsub(',', '\\,')
567
+ escaped_value
568
+ end
569
+
570
+ def save_resource_reference(resource_type, reference)
571
+ scratch[:references] ||= {}
572
+ scratch[:references][resource_type] ||= Set.new
573
+ scratch[:references][resource_type] << reference
574
+ end
575
+
576
+ def save_delayed_references(resources, containing_resource_type = self.resource_type)
577
+ resources.each do |resource|
578
+ references_to_save(containing_resource_type).each do |reference_to_save|
579
+ resolve_path(resource, reference_to_save[:path])
580
+ .select { |reference| reference.is_a?(FHIR::Reference) && !reference.contained? }
581
+ .each do |reference|
582
+ resource_type = reference.resource_class.name.demodulize
583
+ need_to_save = reference_to_save[:resources].include?(resource_type)
584
+ next unless need_to_save
585
+
586
+ save_resource_reference(resource_type, reference)
587
+ end
588
+ end
589
+ end
590
+ end
591
+
592
+ #### RESULT CHECKING ####
593
+
594
+ def check_resource_against_params(resource, params)
595
+ params.each do |name, search_value|
596
+ path = search_param_path(name)
597
+ type = metadata.search_definitions[name.to_sym][:type]
598
+ values_found =
599
+ resolve_path(resource, path)
600
+ .map do |value|
601
+ if value.is_a? FHIR::Reference
602
+ value.reference
603
+ else
604
+ value
605
+ end
606
+ end
607
+
608
+ match_found =
609
+ case type
610
+ when 'Period', 'date', 'instant', 'dateTime'
611
+ values_found.any? { |date| validate_date_search(search_value, date) }
612
+ when 'HumanName'
613
+ # When a string search parameter refers to the types HumanName and Address,
614
+ # the search covers the elements of type string, and does not cover elements such as use and period
615
+ # https://www.hl7.org/fhir/search.html#string
616
+ search_value_downcase = search_value.downcase
617
+ values_found.any? do |name|
618
+ name&.text&.downcase&.start_with?(search_value_downcase) ||
619
+ name&.family&.downcase&.start_with?(search_value_downcase) ||
620
+ name&.given&.any? { |given| given.downcase.start_with?(search_value_downcase) } ||
621
+ name&.prefix&.any? { |prefix| prefix.downcase.start_with?(search_value_downcase) } ||
622
+ name&.suffix&.any? { |suffix| suffix.downcase.start_with?(search_value_downcase) }
623
+ end
624
+ when 'Address'
625
+ search_value_downcase = search_value.downcase
626
+ values_found.any? do |address|
627
+ address&.text&.downcase&.start_with?(search_value_downcase) ||
628
+ address&.city&.downcase&.start_with?(search_value_downcase) ||
629
+ address&.state&.downcase&.start_with?(search_value_downcase) ||
630
+ address&.postalCode&.downcase&.start_with?(search_value_downcase) ||
631
+ address&.country&.downcase&.start_with?(search_value_downcase)
632
+ end
633
+ when 'CodeableConcept'
634
+ # FHIR token search (https://www.hl7.org/fhir/search.html#token): "When in doubt, servers SHOULD
635
+ # treat tokens in a case-insensitive manner, on the grounds that including undesired data has
636
+ # less safety implications than excluding desired behavior".
637
+ codings = values_found.flat_map(&:coding)
638
+ if search_value.include? '|'
639
+ system = search_value.split('|').first
640
+ code = search_value.split('|').last
641
+ codings&.any? { |coding| coding.system == system && coding.code&.casecmp?(code) }
642
+ else
643
+ codings&.any? { |coding| coding.code&.casecmp?(search_value) }
644
+ end
645
+ when 'Coding'
646
+ if search_value.include? '|'
647
+ system = search_value.split('|').first
648
+ code = search_value.split('|').last
649
+ values_found.any? { |coding| coding.system == system && coding.code&.casecmp?(code) }
650
+ else
651
+ values_found.any? { |coding| coding.code&.casecmp?(search_value) }
652
+ end
653
+ when 'Identifier'
654
+ if search_value.include? '|'
655
+ values_found.any? { |identifier| "#{identifier.system}|#{identifier.value}" == search_value }
656
+ else
657
+ values_found.any? { |identifier| identifier.value == search_value }
658
+ end
659
+ when 'string'
660
+ searched_values = search_value.downcase.split(/(?<!\\\\),/).map{ |string| string.gsub('\\,', ',') }
661
+ values_found.any? do |value_found|
662
+ searched_values.any? { |searched_value| value_found.downcase.starts_with? searched_value }
663
+ end
664
+ else
665
+ # searching by patient requires special case because we are searching by a resource identifier
666
+ # references can also be URL's, so we made need to resolve those url's
667
+ if ['subject', 'patient'].include? name.to_s
668
+ id = search_value.split('Patient/').last
669
+ possible_values = [id, 'Patient/' + id, "#{url}/Patient/\#{id}"]
670
+ values_found.any? do |reference|
671
+ possible_values.include? reference
672
+ end
673
+ else
674
+ search_values = search_value.split(/(?<!\\\\),/).map { |string| string.gsub('\\,', ',') }
675
+ values_found.any? { |value_found| search_values.include? value_found }
676
+ end
677
+ end
678
+
679
+ assert match_found,
680
+ "#{resource_type}/#{resource.id} did not match the search parameters:\n" \
681
+ "* Expected: #{search_value}\n" \
682
+ "* Found: #{values_found.map(&:inspect).join(', ')}"
683
+ end
684
+ end
685
+ end
686
+ end