diff --git a/lib/resource_generator.rb b/lib/resource_generator.rb index 86faade..276e4eb 100644 --- a/lib/resource_generator.rb +++ b/lib/resource_generator.rb @@ -28,6 +28,7 @@ class RequiredElementGenerationError < StandardError; end }.freeze }.freeze SIMPLE_QUANTITY_FIELDS = { + 'Observation' => [:valueQuantity], 'Range' => [:low, :high], 'SampledData' => [:origin], 'Observation::ReferenceRange' => [:low, :high] @@ -642,15 +643,7 @@ def self.relative_fhir_class_name(model) def self.apply_r5_invariants!(resource) case resource when FHIR::R5::UsageContext - ensure_serializable_choice!( - resource, - 'value', - 'valueCodeableConcept', - textonly_codeableconcept( - 'Generated usage context', - namespace: FHIR::R5 - ) - ) + apply_usage_context_invariant!(resource, namespace: FHIR::R5) when FHIR::R5::BiologicallyDerivedProduct::Property ensure_serializable_choice!( resource, @@ -737,6 +730,18 @@ def self.apply_r5_invariants!(resource) resource end + def self.apply_usage_context_invariant!(resource, namespace:) + ensure_serializable_choice!( + resource, + 'value', + 'valueCodeableConcept', + textonly_codeableconcept( + 'Generated usage context', + namespace: namespace + ) + ) + end + def self.ensure_serializable_choice!(resource, prefix, selected_field, value) fields = multiple_type_fields(resource.class).fetch(prefix).values populated_fields = fields.select do |field| @@ -794,6 +799,10 @@ def self.ensure_r5_test_script_action!(test) def self.apply_invariants!(resource) fix_codeable_reference(resource) clear_prohibited_observation_quantity_comparators!(resource) + apply_usage_context_invariant!(resource, namespace: FHIR) if + resource.is_a?(FHIR::UsageContext) + apply_usage_context_invariant!(resource, namespace: FHIR::R4B) if + resource.is_a?(FHIR::R4B::UsageContext) apply_r5_invariants!(resource) if Crucible::FHIRVersion.for_class(resource) == :r5 diff --git a/test/unit/observation_generation_test.rb b/test/unit/observation_generation_test.rb index 76d1906..98348ed 100644 --- a/test/unit/observation_generation_test.rb +++ b/test/unit/observation_generation_test.rb @@ -35,15 +35,22 @@ def test_observation_simple_quantities_have_no_comparator_across_namespaces end end - def test_r4_and_r4b_observation_quantities_that_allow_comparators_are_unchanged + def test_r4_and_r4b_observation_quantity_comparators_are_selectively_cleared VERSIONS.each do |version, namespace| observation = observation_with_allowed_comparators(namespace) - expected = allowed_quantities(observation).map { |path, quantity| [path, quantity.comparator] } Crucible::Tests::ResourceGenerator.apply_invariants!(observation) actual = allowed_quantities(observation).map { |path, quantity| [path, quantity.comparator] } - assert_equal expected, actual, "#{version} cleared an allowed Quantity comparator" + expected = [ + ["valueQuantity", nil], + ["valueRatio.numerator", ">"], + ["valueRatio.denominator", "<="], + ["component[0].valueQuantity", ">="], + ["component[0].valueRatio.numerator", "<="], + ["component[0].valueRatio.denominator", ">"] + ] + assert_equal expected, actual, "#{version} applied the wrong Quantity comparator invariant" end end diff --git a/test/unit/resource_generator_test.rb b/test/unit/resource_generator_test.rb index dbd68f8..2bcc71d 100644 --- a/test/unit/resource_generator_test.rb +++ b/test/unit/resource_generator_test.rb @@ -47,6 +47,47 @@ def test_empty_r4b_codeable_reference_gets_a_concept assert_nil reference.reference end + def test_empty_r4_usage_context_gets_a_value + context = FHIR::UsageContext.new + + Crucible::Tests::ResourceGenerator.apply_invariants!(context) + + assert_instance_of FHIR::CodeableConcept, context.valueCodeableConcept + assert_not_empty context.valueCodeableConcept.text + assert_nil context.valueQuantity + assert_nil context.valueRange + assert_nil context.valueReference + end + + def test_empty_r4b_usage_context_gets_a_value + context = FHIR::R4B::UsageContext.new + + Crucible::Tests::ResourceGenerator.apply_invariants!(context) + + assert_instance_of FHIR::R4B::CodeableConcept, context.valueCodeableConcept + assert_not_empty context.valueCodeableConcept.text + assert_nil context.valueQuantity + assert_nil context.valueRange + assert_nil context.valueReference + end + + def test_observation_value_quantity_comparator_is_cleared_for_supported_versions + [ + [FHIR::Observation, FHIR::Quantity], + [FHIR::R4B::Observation, FHIR::R4B::Quantity], + [FHIR::R5::Observation, FHIR::R5::Quantity] + ].each do |observation_class, quantity_class| + quantity = quantity_class.new(value: 10, comparator: '>') + observation = observation_class.new(valueQuantity: quantity) + + Crucible::Tests::ResourceGenerator.apply_invariants!(observation) + + assert_instance_of quantity_class, observation.valueQuantity + assert_equal 10, observation.valueQuantity.value + assert_nil observation.valueQuantity.comparator + end + end + def test_populated_r4b_codeable_reference_is_preserved reference = FHIR::R4B::CodeableReference.new reference.reference = FHIR::R4B::Reference.new(display: 'Existing reference')