us_core_test_kit 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/lib/us_core_test_kit/generated/v3.1.1/allergy_intolerance/metadata.yml +1 -24
  3. data/lib/us_core_test_kit/generated/v3.1.1/bodyheight/metadata.yml +0 -52
  4. data/lib/us_core_test_kit/generated/v3.1.1/bodytemp/metadata.yml +0 -52
  5. data/lib/us_core_test_kit/generated/v3.1.1/bodyweight/metadata.yml +0 -52
  6. data/lib/us_core_test_kit/generated/v3.1.1/bp/metadata.yml +0 -76
  7. data/lib/us_core_test_kit/generated/v3.1.1/care_plan/metadata.yml +0 -28
  8. data/lib/us_core_test_kit/generated/v3.1.1/care_team/metadata.yml +0 -16
  9. data/lib/us_core_test_kit/generated/v3.1.1/condition/metadata.yml +1 -39
  10. data/lib/us_core_test_kit/generated/v3.1.1/device/metadata.yml +1 -1013
  11. data/lib/us_core_test_kit/generated/v3.1.1/diagnostic_report_lab/metadata.yml +1 -1021
  12. data/lib/us_core_test_kit/generated/v3.1.1/diagnostic_report_note/metadata.yml +1 -1017
  13. data/lib/us_core_test_kit/generated/v3.1.1/document_reference/document_reference_must_support_test.rb +0 -1
  14. data/lib/us_core_test_kit/generated/v3.1.1/document_reference/document_reference_reference_resolution_test.rb +0 -1
  15. data/lib/us_core_test_kit/generated/v3.1.1/document_reference/metadata.yml +1 -81
  16. data/lib/us_core_test_kit/generated/v3.1.1/encounter/metadata.yml +2 -85
  17. data/lib/us_core_test_kit/generated/v3.1.1/goal/metadata.yml +1 -46
  18. data/lib/us_core_test_kit/generated/v3.1.1/head_circumference/metadata.yml +0 -52
  19. data/lib/us_core_test_kit/generated/v3.1.1/heartrate/metadata.yml +0 -52
  20. data/lib/us_core_test_kit/generated/v3.1.1/immunization/metadata.yml +0 -48
  21. data/lib/us_core_test_kit/generated/v3.1.1/medication_request/metadata.yml +0 -60
  22. data/lib/us_core_test_kit/generated/v3.1.1/metadata.yml +14 -6471
  23. data/lib/us_core_test_kit/generated/v3.1.1/observation_lab/metadata.yml +1 -1053
  24. data/lib/us_core_test_kit/generated/v3.1.1/organization/metadata.yml +0 -20
  25. data/lib/us_core_test_kit/generated/v3.1.1/patient/metadata.yml +1 -29
  26. data/lib/us_core_test_kit/generated/v3.1.1/pediatric_bmi_for_age/metadata.yml +0 -52
  27. data/lib/us_core_test_kit/generated/v3.1.1/pediatric_weight_for_height/metadata.yml +0 -52
  28. data/lib/us_core_test_kit/generated/v3.1.1/practitioner/metadata.yml +0 -16
  29. data/lib/us_core_test_kit/generated/v3.1.1/procedure/metadata.yml +1 -1049
  30. data/lib/us_core_test_kit/generated/v3.1.1/provenance/metadata.yml +0 -36
  31. data/lib/us_core_test_kit/generated/v3.1.1/pulse_oximetry/metadata.yml +0 -76
  32. data/lib/us_core_test_kit/generated/v3.1.1/resprate/metadata.yml +0 -52
  33. data/lib/us_core_test_kit/generated/v3.1.1/smokingstatus/metadata.yml +1 -62
  34. data/lib/us_core_test_kit/generated/v3.1.1/us_core_test_suite.rb +20 -1
  35. data/lib/us_core_test_kit/generated/v4.0.0/allergy_intolerance/metadata.yml +1 -24
  36. data/lib/us_core_test_kit/generated/v4.0.0/blood_pressure/metadata.yml +0 -80
  37. data/lib/us_core_test_kit/generated/v4.0.0/bmi/metadata.yml +0 -56
  38. data/lib/us_core_test_kit/generated/v4.0.0/body_height/metadata.yml +0 -56
  39. data/lib/us_core_test_kit/generated/v4.0.0/body_temperature/metadata.yml +0 -56
  40. data/lib/us_core_test_kit/generated/v4.0.0/body_weight/metadata.yml +0 -56
  41. data/lib/us_core_test_kit/generated/v4.0.0/care_plan/metadata.yml +0 -28
  42. data/lib/us_core_test_kit/generated/v4.0.0/care_team/metadata.yml +0 -16
  43. data/lib/us_core_test_kit/generated/v4.0.0/condition/metadata.yml +1 -39
  44. data/lib/us_core_test_kit/generated/v4.0.0/device/metadata.yml +1 -1013
  45. data/lib/us_core_test_kit/generated/v4.0.0/diagnostic_report_lab/metadata.yml +1 -1021
  46. data/lib/us_core_test_kit/generated/v4.0.0/diagnostic_report_note/metadata.yml +1 -1017
  47. data/lib/us_core_test_kit/generated/v4.0.0/document_reference/metadata.yml +1 -78
  48. data/lib/us_core_test_kit/generated/v4.0.0/encounter/metadata.yml +2 -85
  49. data/lib/us_core_test_kit/generated/v4.0.0/goal/metadata.yml +1 -46
  50. data/lib/us_core_test_kit/generated/v4.0.0/head_circumference/metadata.yml +0 -56
  51. data/lib/us_core_test_kit/generated/v4.0.0/head_circumference_percentile/metadata.yml +0 -56
  52. data/lib/us_core_test_kit/generated/v4.0.0/heart_rate/metadata.yml +0 -56
  53. data/lib/us_core_test_kit/generated/v4.0.0/immunization/metadata.yml +0 -48
  54. data/lib/us_core_test_kit/generated/v4.0.0/medication_request/metadata.yml +0 -60
  55. data/lib/us_core_test_kit/generated/v4.0.0/metadata.yml +13 -6618
  56. data/lib/us_core_test_kit/generated/v4.0.0/observation_lab/metadata.yml +1 -1053
  57. data/lib/us_core_test_kit/generated/v4.0.0/organization/metadata.yml +0 -20
  58. data/lib/us_core_test_kit/generated/v4.0.0/patient/metadata.yml +1 -29
  59. data/lib/us_core_test_kit/generated/v4.0.0/pediatric_bmi_for_age/metadata.yml +0 -56
  60. data/lib/us_core_test_kit/generated/v4.0.0/pediatric_weight_for_height/metadata.yml +0 -56
  61. data/lib/us_core_test_kit/generated/v4.0.0/practitioner/metadata.yml +0 -16
  62. data/lib/us_core_test_kit/generated/v4.0.0/procedure/metadata.yml +1 -1049
  63. data/lib/us_core_test_kit/generated/v4.0.0/provenance/metadata.yml +0 -40
  64. data/lib/us_core_test_kit/generated/v4.0.0/pulse_oximetry/metadata.yml +0 -80
  65. data/lib/us_core_test_kit/generated/v4.0.0/respiratory_rate/metadata.yml +0 -56
  66. data/lib/us_core_test_kit/generated/v4.0.0/smokingstatus/metadata.yml +0 -56
  67. data/lib/us_core_test_kit/generated/v4.0.0/us_core_test_suite.rb +20 -1
  68. data/lib/us_core_test_kit/generated/v5.0.1/allergy_intolerance/metadata.yml +1 -24
  69. data/lib/us_core_test_kit/generated/v5.0.1/blood_pressure/metadata.yml +0 -80
  70. data/lib/us_core_test_kit/generated/v5.0.1/bmi/metadata.yml +0 -56
  71. data/lib/us_core_test_kit/generated/v5.0.1/body_height/metadata.yml +0 -56
  72. data/lib/us_core_test_kit/generated/v5.0.1/body_temperature/metadata.yml +0 -56
  73. data/lib/us_core_test_kit/generated/v5.0.1/body_weight/metadata.yml +0 -56
  74. data/lib/us_core_test_kit/generated/v5.0.1/care_plan/metadata.yml +0 -28
  75. data/lib/us_core_test_kit/generated/v5.0.1/care_team/metadata.yml +0 -16
  76. data/lib/us_core_test_kit/generated/v5.0.1/condition_encounter_diagnosis/metadata.yml +1 -43
  77. data/lib/us_core_test_kit/generated/v5.0.1/condition_problems_health_concerns/metadata.yml +2 -44
  78. data/lib/us_core_test_kit/generated/v5.0.1/device/metadata.yml +1 -1013
  79. data/lib/us_core_test_kit/generated/v5.0.1/diagnostic_report_lab/metadata.yml +1 -1021
  80. data/lib/us_core_test_kit/generated/v5.0.1/diagnostic_report_note/metadata.yml +1 -1021
  81. data/lib/us_core_test_kit/generated/v5.0.1/document_reference/metadata.yml +1 -82
  82. data/lib/us_core_test_kit/generated/v5.0.1/encounter/metadata.yml +2 -85
  83. data/lib/us_core_test_kit/generated/v5.0.1/goal/metadata.yml +2 -1047
  84. data/lib/us_core_test_kit/generated/v5.0.1/head_circumference/metadata.yml +0 -56
  85. data/lib/us_core_test_kit/generated/v5.0.1/head_circumference_percentile/metadata.yml +0 -56
  86. data/lib/us_core_test_kit/generated/v5.0.1/heart_rate/metadata.yml +0 -56
  87. data/lib/us_core_test_kit/generated/v5.0.1/immunization/metadata.yml +0 -48
  88. data/lib/us_core_test_kit/generated/v5.0.1/medication_request/metadata.yml +5 -65
  89. data/lib/us_core_test_kit/generated/v5.0.1/metadata.yml +27 -11041
  90. data/lib/us_core_test_kit/generated/v5.0.1/observation_clinical_test/metadata.yml +0 -52
  91. data/lib/us_core_test_kit/generated/v5.0.1/observation_imaging/metadata.yml +1 -1053
  92. data/lib/us_core_test_kit/generated/v5.0.1/observation_lab/metadata.yml +1 -1053
  93. data/lib/us_core_test_kit/generated/v5.0.1/observation_sdoh_assessment/metadata.yml +0 -57
  94. data/lib/us_core_test_kit/generated/v5.0.1/observation_sexual_orientation/metadata.yml +1 -62
  95. data/lib/us_core_test_kit/generated/v5.0.1/observation_social_history/metadata.yml +1 -1058
  96. data/lib/us_core_test_kit/generated/v5.0.1/organization/metadata.yml +0 -20
  97. data/lib/us_core_test_kit/generated/v5.0.1/patient/metadata.yml +1 -29
  98. data/lib/us_core_test_kit/generated/v5.0.1/pediatric_bmi_for_age/metadata.yml +0 -56
  99. data/lib/us_core_test_kit/generated/v5.0.1/pediatric_weight_for_height/metadata.yml +0 -56
  100. data/lib/us_core_test_kit/generated/v5.0.1/practitioner/metadata.yml +0 -20
  101. data/lib/us_core_test_kit/generated/v5.0.1/procedure/metadata.yml +1 -1049
  102. data/lib/us_core_test_kit/generated/v5.0.1/provenance/metadata.yml +0 -40
  103. data/lib/us_core_test_kit/generated/v5.0.1/pulse_oximetry/metadata.yml +0 -80
  104. data/lib/us_core_test_kit/generated/v5.0.1/questionnaire_response/metadata.yml +0 -20
  105. data/lib/us_core_test_kit/generated/v5.0.1/related_person/metadata.yml +0 -12
  106. data/lib/us_core_test_kit/generated/v5.0.1/respiratory_rate/metadata.yml +0 -56
  107. data/lib/us_core_test_kit/generated/v5.0.1/service_request/metadata.yml +1 -1041
  108. data/lib/us_core_test_kit/generated/v5.0.1/smokingstatus/metadata.yml +0 -56
  109. data/lib/us_core_test_kit/generated/v5.0.1/us_core_test_suite.rb +20 -1
  110. data/lib/us_core_test_kit/generator/must_support_metadata_extractor.rb +17 -7
  111. data/lib/us_core_test_kit/generator/search_definition_metadata_extractor.rb +13 -93
  112. data/lib/us_core_test_kit/generator/suite_generator.rb +11 -0
  113. data/lib/us_core_test_kit/generator/terminology_binding_metadata_extractor.rb +15 -3
  114. data/lib/us_core_test_kit/generator/value_extractor.rb +101 -0
  115. data/lib/us_core_test_kit/provenance_validator.rb +37 -0
  116. data/lib/us_core_test_kit/version.rb +1 -1
  117. metadata +4 -2
@@ -168,66 +168,10 @@
168
168
  - Observation.value[x]
169
169
  - Observation.component.code
170
170
  :bindings:
171
- - :type: code
172
- :strength: preferred
173
- :system: http://hl7.org/fhir/ValueSet/languages
174
- :path: language
175
171
  - :type: code
176
172
  :strength: required
177
173
  :system: http://hl7.org/fhir/us/core/ValueSet/us-core-observation-smoking-status-status
178
174
  :path: status
179
- - :type: CodeableConcept
180
- :strength: preferred
181
- :system: http://hl7.org/fhir/ValueSet/observation-category
182
- :path: category
183
- - :type: CodeableConcept
184
- :strength: preferred
185
- :system: http://hl7.org/fhir/ValueSet/observation-category
186
- :path: category
187
- - :type: CodeableConcept
188
- :strength: extensible
189
- :system: http://hl7.org/fhir/us/core/ValueSet/us-core-smoking-status-observation-codes
190
- :path: code
191
- - :type: CodeableConcept
192
- :strength: preferred
193
- :system: http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.11.20.9.38
194
- :path: value
195
- - :type: CodeableConcept
196
- :strength: extensible
197
- :system: http://hl7.org/fhir/ValueSet/data-absent-reason
198
- :path: dataAbsentReason
199
- - :type: CodeableConcept
200
- :strength: extensible
201
- :system: http://hl7.org/fhir/ValueSet/observation-interpretation
202
- :path: interpretation
203
- - :type: CodeableConcept
204
- :strength: example
205
- :system: http://hl7.org/fhir/ValueSet/body-site
206
- :path: bodySite
207
- - :type: CodeableConcept
208
- :strength: example
209
- :system: http://hl7.org/fhir/ValueSet/observation-methods
210
- :path: method
211
- - :type: CodeableConcept
212
- :strength: preferred
213
- :system: http://hl7.org/fhir/ValueSet/referencerange-meaning
214
- :path: referenceRange.type
215
- - :type: CodeableConcept
216
- :strength: example
217
- :system: http://hl7.org/fhir/ValueSet/referencerange-appliesto
218
- :path: referenceRange.appliesTo
219
- - :type: CodeableConcept
220
- :strength: example
221
- :system: http://hl7.org/fhir/ValueSet/observation-codes
222
- :path: component.code
223
- - :type: CodeableConcept
224
- :strength: extensible
225
- :system: http://hl7.org/fhir/ValueSet/data-absent-reason
226
- :path: component.dataAbsentReason
227
- - :type: CodeableConcept
228
- :strength: extensible
229
- :system: http://hl7.org/fhir/ValueSet/observation-interpretation
230
- :path: component.interpretation
231
175
  :references:
232
176
  - :path: Observation.basedOn
233
177
  :profiles:
@@ -3,6 +3,7 @@ require_relative '../../version'
3
3
  require_relative '../../custom_groups/v5.0.1/capability_statement_group'
4
4
  require_relative '../../custom_groups/v4.0.0/clinical_notes_guidance_group'
5
5
  require_relative '../../custom_groups/data_absent_reason_group'
6
+ require_relative '../../provenance_validator'
6
7
  require_relative 'patient_group'
7
8
  require_relative 'allergy_intolerance_group'
8
9
  require_relative 'care_plan_group'
@@ -48,13 +49,27 @@ module USCoreTestKit
48
49
  module USCoreV501
49
50
  class USCoreTestSuite < Inferno::TestSuite
50
51
  title 'US Core v5.0.1'
52
+ description %(
53
+ The US Core Test Kit tests systems for their conformance to the [US Core
54
+ Implementation Guide](http://hl7.org/fhir/us/core/STU5.0.1).
55
+
56
+ Resources are validated with the FHIR Java validator using `tx.fhir.org`
57
+ as the terminology server. Users should note that the although the ONC
58
+ Certification (g)(10) Standardized API Test Suite includes tests from
59
+ this suite, [it uses a different method to perform terminology
60
+ validation](https://github.com/onc-healthit/onc-certification-g10-test-kit/wiki/FAQ#q-why-do-some-resources-fail-in-us-core-test-kit-with-terminology-validation-errors).
61
+ As a result, resource validation results may not be consistent between
62
+ the US Core Test Suite and the ONC Certification (g)(10) Standardized
63
+ API Test Suite.
64
+ )
51
65
  version VERSION
52
66
 
53
67
  VALIDATION_MESSAGE_FILTERS = [
54
68
  %r{Sub-extension url 'introspect' is not defined by the Extension http://fhir-registry\.smarthealthit\.org/StructureDefinition/oauth-uris$},
55
69
  %r{Sub-extension url 'revoke' is not defined by the Extension http://fhir-registry\.smarthealthit\.org/StructureDefinition/oauth-uris$},
56
70
  /Observation\.effective\.ofType\(Period\): .*vs-1:/, # Invalid invariant in FHIR v4.0.1
57
- /Observation\.effective\.ofType\(Period\): .*us-core-1:/ # Invalid invariant in US Core v3.1.1
71
+ /Observation\.effective\.ofType\(Period\): .*us-core-1:/, # Invalid invariant in US Core v3.1.1
72
+ /Provenance.agent\[\d*\]: Rule provenance-1/ #Invalid invariant in US Core v5.0.1
58
73
  ].freeze
59
74
 
60
75
  def self.metadata
@@ -68,6 +83,10 @@ module USCoreTestKit
68
83
  exclude_message do |message|
69
84
  VALIDATION_MESSAGE_FILTERS.any? { |filter| filter.match? message.message }
70
85
  end
86
+
87
+ perform_additional_validation do |resource, profile_url|
88
+ ProvenanceValidator.validate(resource) if resource.instance_of?(FHIR::Provenance)
89
+ end
71
90
  end
72
91
 
73
92
  id :us_core_v501
@@ -1,3 +1,5 @@
1
+ require_relative 'value_extractor'
2
+
1
3
  module USCoreTestKit
2
4
  class Generator
3
5
  class MustSupportMetadataExtractor
@@ -97,13 +99,10 @@ module USCoreTestKit
97
99
  elsif pattern_element.binding&.strength == 'required' &&
98
100
  pattern_element.binding&.valueSet.present?
99
101
 
100
- value_set = ig_resources.value_set_by_url(pattern_element.binding.valueSet)
101
- bound_systems = value_set&.compose&.include&.reject { |code| code.concept.blank? }
102
- values = []
102
+ value_extractor = ValueExactor.new(ig_resources, resource, profile_elements)
103
103
 
104
- if bound_systems.present?
105
- values = bound_systems&.flat_map { |system| system.concept.map { |code| code.code } }.uniq
106
- end
104
+ values = value_extractor.values_from_value_set_binding(pattern_element).presence ||
105
+ value_extractor.values_from_resource_metadata([metadata[:path]]).presence || []
107
106
 
108
107
  {
109
108
  type: 'requiredBinding',
@@ -292,6 +291,8 @@ module USCoreTestKit
292
291
  add_must_support_choices
293
292
 
294
293
  case profile.version
294
+ when '3.1.1'
295
+ remove_document_reference_custodian
295
296
  when '4.0.0'
296
297
  add_device_distinct_identifier
297
298
  add_patient_uscdi_elements
@@ -354,6 +355,15 @@ module USCoreTestKit
354
355
  end
355
356
  end
356
357
 
358
+ # US Core clarified that server implmentation is not required to support DocumentReference.custodian (FHIR-28393)
359
+ def remove_document_reference_custodian
360
+ if profile.type == 'DocumentReference'
361
+ @must_supports[:elements].delete_if do |element|
362
+ element[:path] == 'custodian'
363
+ end
364
+ end
365
+ end
366
+
357
367
  def remove_document_reference_attachment_data_url
358
368
  if profile.type == 'DocumentReference'
359
369
  @must_supports[:elements].delete_if do |element|
@@ -482,7 +492,7 @@ module USCoreTestKit
482
492
 
483
493
  slice = @must_supports[:slices].find{|slice| slice[:path] == 'category'}
484
494
 
485
- slice[:discriminator][:values] << 'clinical-note' if slice.present?
495
+ slice[:discriminator][:values] = ['clinical-note'] if slice.present?
486
496
  end
487
497
 
488
498
  # FHIR-37794 Server systems are not required to support US Core QuestionnaireResponse
@@ -1,3 +1,5 @@
1
+ require_relative 'value_extractor'
2
+
1
3
  module USCoreTestKit
2
4
  class Generator
3
5
  class SearchDefinitionMetadataExtractor
@@ -112,103 +114,21 @@ module USCoreTestKit
112
114
  end
113
115
 
114
116
  def values
115
- values = (
116
- (
117
- values_from_pattern_codeable_concept_slices +
118
- values_from_required_binding_slices +
119
- values_from_fixed_codes +
120
- values_from_pattern_coding +
121
- values_from_pattern_codeable_concept
122
- ).uniq.presence || values_from_value_set_binding(profile_element)
123
- ).presence || values_from_resource_metadata
124
- values
125
- end
126
-
127
- def slices
128
- return [] unless contains_multiple?
129
-
130
- profile_elements.select do |element|
131
- full_paths.include?(element.path) &&
132
- element.sliceName.present? &&
133
- (
134
- element.patternCodeableConcept.present? ||
135
- element.binding.present? && element.binding.strength == 'required'
136
- )
137
- end
117
+ value_extractor.values_from_slicing(profile_element, type).presence ||
118
+ value_extractor.values_from_value_set_binding(profile_element).presence ||
119
+ values_from_resource_metadata(paths).presence || []
138
120
  end
139
121
 
140
- def values_from_pattern_codeable_concept_slices
141
- slices.map do |slice|
142
- slice.patternCodeableConcept.coding.first.code if slice.patternCodeableConcept.present?
143
- end.compact
144
- end
145
-
146
- def values_from_required_binding_slices
147
- slices.map do |slice|
148
- if slice.binding.present? && slice.binding.strength == 'required'
149
- values_from_value_set_binding(slice)
150
- end
151
- end.flatten.compact
152
- end
153
-
154
- def values_from_fixed_codes
155
- return [] unless type == 'CodeableConcept'
156
-
157
- profile_elements
158
- .select { |element| element.path == "#{profile_element.path}.coding.code" && element.fixedCode.present? }
159
- .map { |element| element.fixedCode }
160
- end
161
-
162
- def values_from_pattern_coding
163
- return [] unless type == 'CodeableConcept'
164
-
165
- profile_elements
166
- .select { |element| element.path == "#{profile_element.path}.coding" && element.patternCoding.present? }
167
- .map { |element| element.patternCoding.code }
168
- end
169
-
170
- def values_from_pattern_codeable_concept
171
- return [] if type != 'CodeableConcept' || profile_element.patternCodeableConcept.blank?
172
-
173
- [profile_element.patternCodeableConcept.coding.first.code]
174
- end
175
-
176
- def value_set_binding(the_element)
177
- the_element&.binding
178
- end
179
-
180
- def value_set(the_element)
181
- ig_resources.value_set_by_url(value_set_binding(the_element)&.valueSet)
182
- end
183
-
184
- def bound_systems(the_element)
185
- value_set(the_element)&.compose&.include&.reject { |code| code.concept.nil? }
186
- end
187
-
188
- def values_from_value_set_binding(the_element)
189
- bound_systems = bound_systems(the_element)
190
-
191
- return [] if bound_systems.blank?
192
-
193
- bound_systems.flat_map { |system| system.concept.map { |code| code.code } }.uniq
194
- end
195
-
196
- def fhir_metadata(current_path)
197
- FHIR.const_get(resource)::METADATA[current_path]
198
- end
199
-
200
- def values_from_resource_metadata
201
- values = []
202
-
203
- paths.each do |current_path|
204
- current_metadata = fhir_metadata(current_path)
205
-
206
- if current_metadata&.dig('valid_codes').present?
207
- values = values + current_metadata['valid_codes'].values.flatten
208
- end
122
+ def values_from_resource_metadata(paths)
123
+ if multiple_or_expectation == 'SHALL' || paths.include?('status')
124
+ value_extractor.values_from_resource_metadata(paths)
125
+ else
126
+ []
209
127
  end
128
+ end
210
129
 
211
- values
130
+ def value_extractor
131
+ @value_extractor ||= ValueExactor.new(ig_resources, resource, profile_elements)
212
132
  end
213
133
  end
214
134
  end
@@ -53,6 +53,17 @@ module USCoreTestKit
53
53
  "#{ig_metadata.reformatted_version.upcase}_VALIDATOR_URL"
54
54
  end
55
55
 
56
+ def ig_link
57
+ case ig_metadata.ig_version
58
+ when 'v5.0.1'
59
+ 'http://hl7.org/fhir/us/core/STU5.0.1'
60
+ when 'v4.0.0'
61
+ 'http://hl7.org/fhir/us/core/STU4'
62
+ when 'v3.1.1'
63
+ 'http://hl7.org/fhir/us/core/STU3.1.1'
64
+ end
65
+ end
66
+
56
67
  def generate
57
68
  File.open(output_file_name, 'w') { |f| f.write(output) }
58
69
  end
@@ -27,21 +27,33 @@ module USCoreTestKit
27
27
  end
28
28
  end
29
29
 
30
+ def element_has_optional_binding_slice?(element)
31
+ element.sliceName.present? && element.min == 0
32
+ end
33
+
30
34
  def profile_elements_with_bindings
31
35
  profile_elements
32
- .select { |element| element.binding.present? }
33
- .reject { |element| element_has_fixed_value? element }
36
+ .select { |element| element.binding.present? && element.binding.strength == 'required'}
37
+ .reject { |element| element_has_fixed_value?(element) || element_has_optional_binding_slice?(element) }
34
38
  end
35
39
 
40
+
41
+
36
42
  def element_terminology_bindings
37
43
  profile_elements_with_bindings.map do |element|
38
- {
44
+ binding = {
39
45
  type: element.type.first.code,
40
46
  strength: element.binding.strength,
41
47
  # Goal.target.detail has an unbound binding
42
48
  system: element.binding.valueSet&.split('|')&.first,
43
49
  path: element.path.gsub('[x]', '').gsub("#{resource}.", '')
44
50
  }
51
+
52
+ if element.sliceName.present? && element.min > 0
53
+ binding[:required_binding_slice] = true
54
+ end
55
+
56
+ binding
45
57
  end
46
58
  end
47
59
 
@@ -0,0 +1,101 @@
1
+ module USCoreTestKit
2
+ class Generator
3
+ class ValueExactor
4
+ attr_accessor :ig_resources, :resource, :profile_elements
5
+
6
+ def initialize(ig_resources, resource, profile_elements)
7
+ self.ig_resources = ig_resources
8
+ self.resource = resource
9
+ self.profile_elements = profile_elements
10
+ end
11
+
12
+ def values_from_slicing(profile_element, type)
13
+ (
14
+ values_from_required_binding(profile_element) +
15
+ values_from_fixed_codes(profile_element, type) +
16
+ values_from_pattern_coding(profile_element, type) +
17
+ values_from_pattern_codeable_concept(profile_element, type)
18
+ ).uniq
19
+ end
20
+
21
+ def values_from_required_binding(profile_element)
22
+ return [] unless profile_element&.max == '*'
23
+
24
+ profile_elements
25
+ .select do |element|
26
+ element.path == profile_element.path && element.binding&.strength == 'required'
27
+ end
28
+ .map { |element| values_from_value_set_binding(element) }
29
+ .flatten.compact
30
+ end
31
+
32
+ def values_from_fixed_codes(profile_element, type)
33
+ return [] unless type == 'CodeableConcept'
34
+
35
+ profile_elements
36
+ .select do
37
+ |element| element.path == "#{profile_element.path}.coding.code" && element.fixedCode.present?
38
+ end
39
+ .map { |element| element.fixedCode }
40
+ end
41
+
42
+ def values_from_pattern_coding(profile_element, type)
43
+ return [] unless type == 'CodeableConcept'
44
+
45
+ profile_elements
46
+ .select do |element|
47
+ element.path == "#{profile_element.path}.coding" && element.patternCoding.present?
48
+ end
49
+ .map { |element| element.patternCoding.code }
50
+ end
51
+
52
+ def values_from_pattern_codeable_concept(profile_element, type)
53
+ return [] unless type == 'CodeableConcept'
54
+
55
+ profile_elements
56
+ .select do |element|
57
+ element.path == profile_element.path && element.patternCodeableConcept.present? && element.min > 0
58
+ end
59
+ .map { |element| element.patternCodeableConcept.coding.first.code }
60
+ end
61
+
62
+ def value_set_binding(the_element)
63
+ the_element&.binding
64
+ end
65
+
66
+ def value_set(the_element)
67
+ ig_resources.value_set_by_url(value_set_binding(the_element)&.valueSet)
68
+ end
69
+
70
+ def bound_systems(the_element)
71
+ value_set(the_element)&.compose&.include&.reject { |code| code.concept.nil? }
72
+ end
73
+
74
+ def values_from_value_set_binding(the_element)
75
+ bound_systems = bound_systems(the_element)
76
+
77
+ return [] if bound_systems.blank?
78
+
79
+ bound_systems.flat_map { |system| system.concept.map { |code| code.code } }.uniq
80
+ end
81
+
82
+ def fhir_metadata(current_path)
83
+ FHIR.const_get(resource)::METADATA[current_path]
84
+ end
85
+
86
+ def values_from_resource_metadata(paths)
87
+ values = []
88
+
89
+ paths.each do |current_path|
90
+ current_metadata = fhir_metadata(current_path)
91
+
92
+ if current_metadata&.dig('valid_codes').present?
93
+ values = values + current_metadata['valid_codes'].values.flatten
94
+ end
95
+ end
96
+
97
+ values
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,37 @@
1
+ module USCoreTestKit
2
+ class ProvenanceValidator
3
+ include FHIRResourceNavigation
4
+
5
+ def self.validate(...)
6
+ new(...).validate
7
+ end
8
+
9
+ attr_reader :resource, :validation_messages
10
+
11
+ def initialize(resource)
12
+ @resource = resource
13
+ @validation_messages = []
14
+ end
15
+
16
+ def validate
17
+ # Invariant provenance-1 in US Core 5 causes validation error. See FHIR-39518
18
+ return validation_messages unless resource.instance_of?(FHIR::Provenance)
19
+
20
+ failed_provenance =
21
+ find_a_value_at(resource, 'agent') do |agent|
22
+ ['Practitioner', 'Device'].any? { |resource_type| agent.who.reference&.include?(resource_type) } &&
23
+ agent.onBehalfOf.nil?
24
+ end
25
+
26
+
27
+ if failed_provenance.present?
28
+ validation_messages << {
29
+ type: 'error',
30
+ message: "#{resource.resourceType}/#{resource.id}: Rule provenance-1: 'onBehalfOf SHALL be present when Provenance.agent.who is a Practitioner or Device' Failed"
31
+ }
32
+ end
33
+
34
+ validation_messages
35
+ end
36
+ end
37
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USCoreTestKit
4
- VERSION = '0.4.0'
4
+ VERSION = '0.4.2'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: us_core_test_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen MacVicar
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-31 00:00:00.000000000 Z
11
+ date: 2022-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: inferno_core
@@ -1292,6 +1292,7 @@ files:
1292
1292
  - lib/us_core_test_kit/generator/suite_generator.rb
1293
1293
  - lib/us_core_test_kit/generator/terminology_binding_metadata_extractor.rb
1294
1294
  - lib/us_core_test_kit/generator/validation_test_generator.rb
1295
+ - lib/us_core_test_kit/generator/value_extractor.rb
1295
1296
  - lib/us_core_test_kit/igs/us_core_311.tgz
1296
1297
  - lib/us_core_test_kit/igs/us_core_311/StructureDefinition-bodyheight.json
1297
1298
  - lib/us_core_test_kit/igs/us_core_311/StructureDefinition-bodytemp.json
@@ -1302,6 +1303,7 @@ files:
1302
1303
  - lib/us_core_test_kit/igs/us_core_400.tgz
1303
1304
  - lib/us_core_test_kit/igs/us_core_501.tgz
1304
1305
  - lib/us_core_test_kit/must_support_test.rb
1306
+ - lib/us_core_test_kit/provenance_validator.rb
1305
1307
  - lib/us_core_test_kit/read_test.rb
1306
1308
  - lib/us_core_test_kit/reference_resolution_test.rb
1307
1309
  - lib/us_core_test_kit/request_logger.rb