us_quality_core_test_kit 0.1.1 → 0.1.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.
- checksums.yaml +4 -4
- data/NOTICE.md +12 -0
- data/config/presets/{localhost_preset.json → inferno_reference_server_preset.json.erb} +2 -2
- data/lib/us_quality_core_test_kit/client/generator/example_client_generator.rb +0 -1
- data/lib/us_quality_core_test_kit/client/generator/tags_generator.rb +0 -1
- data/lib/us_quality_core_test_kit/client/server_proxy.rb +2 -6
- data/lib/us_quality_core_test_kit/date_search_validation.rb +122 -0
- data/lib/us_quality_core_test_kit/fhir_resource_navigation.rb +9 -0
- data/lib/us_quality_core_test_kit/generated/v0.5.0/devicenotrequested/devicenotrequested_validation_test.rb +3 -0
- data/lib/us_quality_core_test_kit/generated/v0.5.0/devicerequest/devicerequest_validation_test.rb +3 -0
- data/lib/us_quality_core_test_kit/generated/v0.5.0/patient/patient_validation_test.rb +4 -0
- data/lib/us_quality_core_test_kit/generated/v0.5.0/us_quality_core_test_suite.rb +1 -2
- data/lib/us_quality_core_test_kit/generator/group_generator.rb +69 -3
- data/lib/us_quality_core_test_kit/generator/group_metadata.rb +100 -4
- data/lib/us_quality_core_test_kit/generator/group_metadata_extractor.rb +184 -8
- data/lib/us_quality_core_test_kit/generator/ig_loader.rb +47 -3
- data/lib/us_quality_core_test_kit/generator/ig_metadata.rb +51 -2
- data/lib/us_quality_core_test_kit/generator/ig_metadata_extractor.rb +25 -6
- data/lib/us_quality_core_test_kit/generator/ig_resources.rb +27 -3
- data/lib/us_quality_core_test_kit/generator/must_support_metadata_extractor.rb +366 -9
- data/lib/us_quality_core_test_kit/generator/must_support_test_generator.rb +54 -3
- data/lib/us_quality_core_test_kit/generator/provenance_revinclude_search_test_generator.rb +149 -3
- data/lib/us_quality_core_test_kit/generator/read_test_generator.rb +54 -3
- data/lib/us_quality_core_test_kit/generator/reference_resolution_test_generator.rb +57 -3
- data/lib/us_quality_core_test_kit/generator/search_definition_metadata_extractor.rb +181 -5
- data/lib/us_quality_core_test_kit/generator/search_metadata_extractor.rb +61 -3
- data/lib/us_quality_core_test_kit/generator/search_test_generator.rb +186 -3
- data/lib/us_quality_core_test_kit/generator/suite_generator.rb +35 -8
- data/lib/us_quality_core_test_kit/generator/terminology_binding_metadata_extractor.rb +107 -3
- data/lib/us_quality_core_test_kit/generator/validation_test_generator.rb +83 -4
- data/lib/us_quality_core_test_kit/generator/value_extractor.rb +147 -3
- data/lib/us_quality_core_test_kit/must_support_test.rb +15 -3
- data/lib/us_quality_core_test_kit/primitive_type.rb +7 -0
- data/lib/us_quality_core_test_kit/read_test.rb +99 -4
- data/lib/us_quality_core_test_kit/reference_resolution_test.rb +164 -3
- data/lib/us_quality_core_test_kit/resource_search_param_checker.rb +138 -0
- data/lib/us_quality_core_test_kit/search_test.rb +681 -46
- data/lib/us_quality_core_test_kit/search_test_properties.rb +53 -3
- data/lib/us_quality_core_test_kit/validation_test.rb +51 -4
- data/lib/us_quality_core_test_kit/version.rb +2 -2
- data/lib/us_quality_core_test_kit/well_known_code_systems.rb +23 -0
- metadata +8 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0297423f25d4655d95c5d963fb2363bdef89197c13c082b63ee2bc339a9780fe'
|
|
4
|
+
data.tar.gz: 614f8a0f368729af2383e877bff720b9784ece107bef849cf887966dec2e73e0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 10673556b891c029d3c94779d7439412f633dcc9c6dfe033fce3deeb64da61e1d29a96f953cdaf8dd8338db314eb7f6217d9b1518d356d702dd397b8daaf34e9
|
|
7
|
+
data.tar.gz: 8c8e669cebe8ff4a3b1fcb49ed3023c32f7546b27116ad21c965beb716017cc488694cb6ca225f1f17380cd7bb31f13ffa6273a777647de75ebb9790b57a2a5e
|
data/NOTICE.md
CHANGED
|
@@ -11,3 +11,15 @@ For further information, please contact The MITRE Corporation, Contracts Managem
|
|
|
11
11
|
Approved for Public Release; Distribution Unlimited. Public Release Case Number: 25-3234
|
|
12
12
|
|
|
13
13
|
### <p align='center'>**ⓒ2026 The MITRE Corporation.**</p>
|
|
14
|
+
|
|
15
|
+
Portions of this software include code from the US Core Test Kit.
|
|
16
|
+
|
|
17
|
+
That software was produced for the U. S. Government under Contract Number 75FCMC18D0047, and is subject to Federal Acquisition Regulation Clause 52.227-14, Rights in Data-General.
|
|
18
|
+
|
|
19
|
+
No other use other than that granted to the U. S. Government, or to those acting on behalf of the U. S. Government under that Clause is authorized without the express written permission of The MITRE Corporation.
|
|
20
|
+
|
|
21
|
+
To the extent necessary MITRE hereby grants express written permission to use, reproduce, distribute, modify, and otherwise leverage this software to the extent permitted by the Apache 2.0 license.
|
|
22
|
+
|
|
23
|
+
For further information, please contact The MITRE Corporation, Contracts Management Office, 7515 Colshire Drive, McLean, VA 22102-7539, (703) 983-6000.
|
|
24
|
+
|
|
25
|
+
### <p align='center'>**ⓒ2024 The MITRE Corporation.**</p>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"title": "
|
|
2
|
+
"title": "Inferno Reference Server",
|
|
3
3
|
"id": null,
|
|
4
4
|
"test_suite_id": "us_quality_core_v050",
|
|
5
5
|
"inputs": [
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"type": "text",
|
|
9
9
|
"title": "FHIR Endpoint",
|
|
10
10
|
"description": "URL of the FHIR endpoint",
|
|
11
|
-
"value": "
|
|
11
|
+
"value": "<%= ENV.fetch('FHIR_REFERENCE_SERVER', 'https://inferno.healthit.gov/reference-server/r4') %>"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"name": "smart_auth_info",
|
|
@@ -58,12 +58,8 @@ module USQualityCoreTestKit
|
|
|
58
58
|
|
|
59
59
|
def replace_bundle_urls(bundle)
|
|
60
60
|
reference_server_base = ENV.fetch('FHIR_REFERENCE_SERVER')
|
|
61
|
-
bundle&.link&.
|
|
62
|
-
bundle&.entry&.
|
|
63
|
-
{ fullUrl: bundled_resource.fullUrl.gsub(reference_server_base, new_link),
|
|
64
|
-
resource: bundled_resource.resource,
|
|
65
|
-
search: bundled_resource.search }
|
|
66
|
-
end
|
|
61
|
+
bundle&.link&.each { |link| link.url = link.url.gsub(reference_server_base, new_link) }
|
|
62
|
+
bundle&.entry&.each { |entry| entry.fullUrl = entry.fullUrl.gsub(reference_server_base, new_link) }
|
|
67
63
|
bundle
|
|
68
64
|
end
|
|
69
65
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module USQualityCoreTestKit
|
|
4
|
+
module DateSearchValidation
|
|
5
|
+
def get_fhir_datetime_range(datetime)
|
|
6
|
+
range = { start: DateTime.xmlschema(datetime), end: nil }
|
|
7
|
+
range[:end] =
|
|
8
|
+
case datetime
|
|
9
|
+
when /^\d{4}$/ # YYYY
|
|
10
|
+
range[:start].next_year - 1.seconds
|
|
11
|
+
when /^\d{4}-\d{2}$/ # YYYY-MM
|
|
12
|
+
range[:start].next_month - 1.seconds
|
|
13
|
+
when /^\d{4}-\d{2}-\d{2}$/ # YYYY-MM-DD
|
|
14
|
+
range[:start].next_day - 1.seconds
|
|
15
|
+
else # YYYY-MM-DDThh:mm:ss+zz:zz
|
|
16
|
+
range[:start]
|
|
17
|
+
end
|
|
18
|
+
range
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def get_fhir_period_range(period)
|
|
22
|
+
range = { start: nil, end: nil }
|
|
23
|
+
range[:start] = DateTime.xmlschema(period.start) unless period.start.nil?
|
|
24
|
+
return range if period.end.nil?
|
|
25
|
+
|
|
26
|
+
period_end_beginning = DateTime.xmlschema(period.end)
|
|
27
|
+
range[:end] =
|
|
28
|
+
case period.end
|
|
29
|
+
when /^\d{4}$/ # YYYY
|
|
30
|
+
period_end_beginning.next_year - 1.seconds
|
|
31
|
+
when /^\d{4}-\d{2}$/ # YYYY-MM
|
|
32
|
+
period_end_beginning.next_month - 1.seconds
|
|
33
|
+
when /^\d{4}-\d{2}-\d{2}$/ # YYYY-MM-DD
|
|
34
|
+
period_end_beginning.next_day - 1.seconds
|
|
35
|
+
else # YYYY-MM-DDThh:mm:ss+zz:zz
|
|
36
|
+
period_end_beginning
|
|
37
|
+
end
|
|
38
|
+
range
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def fhir_date_comparer(search_range, target_range, comparator, extend_start: false, extend_end: false)
|
|
42
|
+
# Implicitly, a missing lower boundary is "less than" any actual date. A missing upper boundary is "greater than" any actual date.
|
|
43
|
+
case comparator
|
|
44
|
+
when 'eq' # the range of the search value fully contains the range of the target value
|
|
45
|
+
!target_range[:start].nil? && !target_range[:end].nil? && search_range[:start] <= target_range[:start] && search_range[:end] >= target_range[:end]
|
|
46
|
+
when 'ne' # the range of the search value does not fully contain the range of the target value
|
|
47
|
+
target_range[:start].nil? || target_range[:end].nil? || search_range[:start] > target_range[:start] || search_range[:end] < target_range[:end]
|
|
48
|
+
when 'gt' # the range above the search value intersects (i.e. overlaps) with the range of the target value
|
|
49
|
+
target_range[:end].nil? || search_range[:end] < target_range[:end] || (search_range[:end] < (target_range[:end] + 1) && extend_end)
|
|
50
|
+
when 'lt' # the range below the search value intersects (i.e. overlaps) with the range of the target value
|
|
51
|
+
target_range[:start].nil? || search_range[:start] > target_range[:start] || (search_range[:start] > (target_range[:start] - 1) && extend_start)
|
|
52
|
+
when 'ge'
|
|
53
|
+
fhir_date_comparer(search_range, target_range, 'gt', extend_start:, extend_end:) || fhir_date_comparer(search_range, target_range, 'eq')
|
|
54
|
+
when 'le'
|
|
55
|
+
fhir_date_comparer(search_range, target_range, 'lt', extend_start:, extend_end:) || fhir_date_comparer(search_range, target_range, 'eq')
|
|
56
|
+
when 'sa' # the range above the search value contains the range of the target value
|
|
57
|
+
!target_range[:start].nil? && search_range[:end] < target_range[:start]
|
|
58
|
+
when 'eb' # the range below the search value contains the range of the target value
|
|
59
|
+
!target_range[:end].nil? && search_range[:start] > target_range[:end]
|
|
60
|
+
when 'ap' # the range of the search value overlaps with the range of the target value
|
|
61
|
+
if target_range[:start].nil? || target_range[:end].nil?
|
|
62
|
+
(target_range[:start].nil? && search_range[:start] < target_range[:end]) ||
|
|
63
|
+
(target_range[:end].nil? && search_range[:end] > target_range[:start])
|
|
64
|
+
else
|
|
65
|
+
(search_range[:start] >= target_range[:start] && search_range[:start] <= target_range[:end]) ||
|
|
66
|
+
(search_range[:end] >= target_range[:start] && search_range[:end] <= target_range[:end])
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def validate_date_search(search_value, target_value)
|
|
72
|
+
if target_value.instance_of? FHIR::Period
|
|
73
|
+
validate_period_search(search_value, target_value)
|
|
74
|
+
else
|
|
75
|
+
validate_datetime_search(search_value, target_value)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def validate_datetime_search(search_value, target_value)
|
|
80
|
+
comparator = search_value[0..1]
|
|
81
|
+
if %w[eq ge gt le lt ne sa eb ap].include? comparator
|
|
82
|
+
search_value = search_value[2..]
|
|
83
|
+
else
|
|
84
|
+
comparator = 'eq'
|
|
85
|
+
end
|
|
86
|
+
search_is_date = date?(search_value)
|
|
87
|
+
target_is_date = date?(target_value)
|
|
88
|
+
search_range = get_fhir_datetime_range(search_value)
|
|
89
|
+
target_range = get_fhir_datetime_range(target_value)
|
|
90
|
+
fhir_date_comparer(
|
|
91
|
+
search_range,
|
|
92
|
+
target_range,
|
|
93
|
+
comparator,
|
|
94
|
+
extend_start: !search_is_date && target_is_date,
|
|
95
|
+
extend_end: !search_is_date && target_is_date
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def validate_period_search(search_value, target_value)
|
|
100
|
+
comparator = search_value[0..1]
|
|
101
|
+
if %w[eq ge gt le lt ne sa eb ap].include? comparator
|
|
102
|
+
search_value = search_value[2..]
|
|
103
|
+
else
|
|
104
|
+
comparator = 'eq'
|
|
105
|
+
end
|
|
106
|
+
search_is_date = date?(search_value)
|
|
107
|
+
search_range = get_fhir_datetime_range(search_value)
|
|
108
|
+
target_range = get_fhir_period_range(target_value)
|
|
109
|
+
fhir_date_comparer(
|
|
110
|
+
search_range,
|
|
111
|
+
target_range,
|
|
112
|
+
comparator,
|
|
113
|
+
extend_start: !search_is_date && date?(target_value.start),
|
|
114
|
+
extend_end: !search_is_date && date?(target_value.end)
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def date?(value)
|
|
119
|
+
/^\d{4}(-\d{2})?(-\d{2})?$/.match?(value) # YYYY or YYYY-MM or YYYY-MM-DD
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'primitive_type'
|
|
4
|
+
|
|
5
|
+
module USQualityCoreTestKit
|
|
6
|
+
# This functionality has been moved to Inferno Core, but this reference is
|
|
7
|
+
# retained to avoid a breaking change.
|
|
8
|
+
FHIRResourceNavigation = Inferno::DSL::FHIRResourceNavigation
|
|
9
|
+
end
|
|
@@ -20,6 +20,9 @@ bindings will fail if none of their codings have a code/system belonging
|
|
|
20
20
|
to the bound ValueSet. Quantity, Coding, and code element bindings will
|
|
21
21
|
fail if their code/system are not found in the valueset.
|
|
22
22
|
|
|
23
|
+
Note: This test ignores a known validator slicing resolution message for
|
|
24
|
+
`DeviceRequest.modifierExtension`.
|
|
25
|
+
|
|
23
26
|
)
|
|
24
27
|
|
|
25
28
|
output :dar_code_found, :dar_extension_found
|
data/lib/us_quality_core_test_kit/generated/v0.5.0/devicerequest/devicerequest_validation_test.rb
CHANGED
|
@@ -20,6 +20,9 @@ bindings will fail if none of their codings have a code/system belonging
|
|
|
20
20
|
to the bound ValueSet. Quantity, Coding, and code element bindings will
|
|
21
21
|
fail if their code/system are not found in the valueset.
|
|
22
22
|
|
|
23
|
+
Note: This test ignores a known validator slicing resolution message for
|
|
24
|
+
`DeviceRequest.modifierExtension`.
|
|
25
|
+
|
|
23
26
|
)
|
|
24
27
|
|
|
25
28
|
output :dar_code_found, :dar_extension_found
|
|
@@ -20,6 +20,10 @@ bindings will fail if none of their codings have a code/system belonging
|
|
|
20
20
|
to the bound ValueSet. Quantity, Coding, and code element bindings will
|
|
21
21
|
fail if their code/system are not found in the valueset.
|
|
22
22
|
|
|
23
|
+
Note: This test ignores validator messages for `Patient.extension`. This is a workaround for
|
|
24
|
+
a known validator package interaction where CQL can load US Core 7 definitions into the
|
|
25
|
+
validator session even though US Quality Core 0.5.0 is based on US Core 6.1.0.
|
|
26
|
+
|
|
23
27
|
)
|
|
24
28
|
|
|
25
29
|
output :dar_code_found, :dar_extension_found
|
|
@@ -98,8 +98,7 @@ module USQualityCoreTestKit
|
|
|
98
98
|
|
|
99
99
|
|
|
100
100
|
VERSION_SPECIFIC_MESSAGE_FILTERS = [
|
|
101
|
-
%r{
|
|
102
|
-
%r{Patient.*Patient\.extension\[\d+\]\.url:\s*Value is 'http://hl7\.org/fhir/us/core/StructureDefinition/us-core-(race|ethnicity|tribal-affiliation)\|\d+\.\d+(?:\.\d+)?'\s*but is fixed to 'http://hl7\.org/fhir/us/core/StructureDefinition/us-core-(race|ethnicity|tribal-affiliation)'\s*in the profile http://hl7\.org/fhir/us/core/StructureDefinition/us-core-(race|ethnicity|tribal-affiliation)\|\d+\.\d+(?:\.\d+)?#Extension\.url},
|
|
101
|
+
%r{\bPatient\.extension},
|
|
103
102
|
%r{DeviceRequest.*DeviceRequest\.modifierExtension\[\d+\]:\s*Slicing cannot be evaluated:\s*Unable to resolve profile CanonicalType\[http://hl7\.org/fhir/5\.0/StructureDefinition/extension-DeviceRequest\.doNotPerform\]}
|
|
104
103
|
].freeze
|
|
105
104
|
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'us_core_test_kit/generator/group_generator'
|
|
4
|
-
|
|
5
3
|
require_relative 'naming'
|
|
6
4
|
require_relative 'special_cases'
|
|
7
5
|
|
|
8
6
|
module USQualityCoreTestKit
|
|
9
7
|
class Generator
|
|
10
|
-
class GroupGenerator
|
|
8
|
+
class GroupGenerator
|
|
11
9
|
class << self
|
|
12
10
|
def generate(ig_metadata, base_output_dir)
|
|
13
11
|
ig_metadata.ordered_groups
|
|
@@ -16,10 +14,29 @@ module USQualityCoreTestKit
|
|
|
16
14
|
end
|
|
17
15
|
end
|
|
18
16
|
|
|
17
|
+
attr_accessor :group_metadata, :base_output_dir
|
|
18
|
+
|
|
19
|
+
def initialize(group_metadata, base_output_dir)
|
|
20
|
+
self.group_metadata = group_metadata
|
|
21
|
+
self.base_output_dir = base_output_dir
|
|
22
|
+
end
|
|
23
|
+
|
|
19
24
|
def template
|
|
20
25
|
@template ||= File.read(File.join(__dir__, 'templates', 'group.rb.erb'))
|
|
21
26
|
end
|
|
22
27
|
|
|
28
|
+
def output
|
|
29
|
+
@output ||= ERB.new(template, trim_mode: '-').result(binding)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def base_output_file_name
|
|
33
|
+
"#{class_name.underscore}.rb"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def base_metadata_file_name
|
|
37
|
+
'metadata.yml'
|
|
38
|
+
end
|
|
39
|
+
|
|
23
40
|
def class_name
|
|
24
41
|
"#{Naming.upper_camel_case_for_profile(group_metadata)}Group"
|
|
25
42
|
end
|
|
@@ -28,6 +45,22 @@ module USQualityCoreTestKit
|
|
|
28
45
|
"USQualityCore#{group_metadata.reformatted_version.upcase}"
|
|
29
46
|
end
|
|
30
47
|
|
|
48
|
+
def title
|
|
49
|
+
group_metadata.title
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def short_description
|
|
53
|
+
group_metadata.short_description
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def output_file_name
|
|
57
|
+
File.join(base_output_dir, base_output_file_name)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def metadata_file_name
|
|
61
|
+
File.join(base_output_dir, profile_identifier, base_metadata_file_name)
|
|
62
|
+
end
|
|
63
|
+
|
|
31
64
|
def profile_identifier
|
|
32
65
|
Naming.snake_case_for_profile(group_metadata)
|
|
33
66
|
end
|
|
@@ -36,16 +69,49 @@ module USQualityCoreTestKit
|
|
|
36
69
|
"us_quality_core_#{group_metadata.reformatted_version}_#{profile_identifier}"
|
|
37
70
|
end
|
|
38
71
|
|
|
72
|
+
def resource_type
|
|
73
|
+
group_metadata.resource
|
|
74
|
+
end
|
|
75
|
+
|
|
39
76
|
def search_validation_resource_type
|
|
40
77
|
"#{resource_type} resources"
|
|
41
78
|
end
|
|
42
79
|
|
|
80
|
+
def profile_name
|
|
81
|
+
group_metadata.profile_name
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def profile_url
|
|
85
|
+
group_metadata.profile_url
|
|
86
|
+
end
|
|
87
|
+
|
|
43
88
|
def optional?
|
|
44
89
|
SpecialCases::OPTIONAL_RESOURCES.include?(resource_type) || group_metadata.optional_profile?
|
|
45
90
|
end
|
|
46
91
|
|
|
92
|
+
def generate
|
|
93
|
+
add_special_tests
|
|
94
|
+
File.write(output_file_name, output)
|
|
95
|
+
group_metadata.id = group_id
|
|
96
|
+
group_metadata.file_name = base_output_file_name
|
|
97
|
+
File.write(metadata_file_name, YAML.dump(group_metadata.to_hash))
|
|
98
|
+
end
|
|
99
|
+
|
|
47
100
|
def add_special_tests; end
|
|
48
101
|
|
|
102
|
+
def test_id_list
|
|
103
|
+
@test_id_list ||=
|
|
104
|
+
group_metadata.tests.map { |test| test[:id] }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def test_file_list
|
|
108
|
+
@test_file_list ||=
|
|
109
|
+
group_metadata.tests.map do |test|
|
|
110
|
+
name_without_suffix = test[:file_name].delete_suffix('.rb')
|
|
111
|
+
name_without_suffix.start_with?('..') ? name_without_suffix : "#{profile_identifier}/#{name_without_suffix}"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
49
115
|
def required_searches
|
|
50
116
|
group_metadata.searches.select { |search| search[:expectation] == 'SHALL' }
|
|
51
117
|
end
|
|
@@ -2,14 +2,110 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'special_cases'
|
|
4
4
|
|
|
5
|
-
require 'us_core_test_kit/generator/group_metadata'
|
|
6
|
-
|
|
7
5
|
module USQualityCoreTestKit
|
|
8
6
|
class Generator
|
|
9
|
-
class GroupMetadata
|
|
7
|
+
class GroupMetadata
|
|
8
|
+
ATTRIBUTES = %i[
|
|
9
|
+
name
|
|
10
|
+
class_name
|
|
11
|
+
version
|
|
12
|
+
reformatted_version
|
|
13
|
+
resource
|
|
14
|
+
profile_url
|
|
15
|
+
profile_name
|
|
16
|
+
profile_version
|
|
17
|
+
title
|
|
18
|
+
short_description
|
|
19
|
+
is_delayed
|
|
20
|
+
interactions
|
|
21
|
+
operations
|
|
22
|
+
searches
|
|
23
|
+
search_definitions
|
|
24
|
+
include_params
|
|
25
|
+
revincludes
|
|
26
|
+
required_concepts
|
|
27
|
+
must_supports
|
|
28
|
+
mandatory_elements
|
|
29
|
+
bindings
|
|
30
|
+
references
|
|
31
|
+
tests
|
|
32
|
+
granular_scope_tests
|
|
33
|
+
id
|
|
34
|
+
file_name
|
|
35
|
+
delayed_references
|
|
36
|
+
resource_conformance_expectation
|
|
37
|
+
].freeze
|
|
38
|
+
|
|
39
|
+
ATTRIBUTES.each { |name| attr_accessor name }
|
|
40
|
+
|
|
41
|
+
def initialize(metadata)
|
|
42
|
+
metadata.each do |key, value|
|
|
43
|
+
raise "Unknown attribute #{key}" unless ATTRIBUTES.include? key
|
|
44
|
+
|
|
45
|
+
instance_variable_set(:"@#{key}", value)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def exclude_search_tests?
|
|
50
|
+
delayed? && !searchable_delayed_resource?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def non_uscdi_resource?
|
|
54
|
+
SpecialCases::NON_USCDI_RESOURCES.key?(resource) && SpecialCases::NON_USCDI_RESOURCES[resource].include?(reformatted_version)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def optional_profile?
|
|
58
|
+
SpecialCases::OPTIONAL_PROFILES.key?(profile_url) && SpecialCases::OPTIONAL_PROFILES[profile_url].include?(reformatted_version)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def searchable_delayed_resource?
|
|
62
|
+
SpecialCases::SEARCHABLE_DELAYED_RESOURCES.key?(resource) && SpecialCases::SEARCHABLE_DELAYED_RESOURCES[resource].include?(reformatted_version)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def add_test(id:, file_name:)
|
|
66
|
+
self.tests ||= []
|
|
67
|
+
|
|
68
|
+
test_metadata = {
|
|
69
|
+
id: id,
|
|
70
|
+
file_name: file_name
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if delayed? && id.include?('read')
|
|
74
|
+
self.tests.unshift(test_metadata)
|
|
75
|
+
else
|
|
76
|
+
self.tests << test_metadata
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def add_granular_scope_test(id:, file_name:)
|
|
81
|
+
self.granular_scope_tests ||= []
|
|
82
|
+
|
|
83
|
+
self.granular_scope_tests << {
|
|
84
|
+
id:,
|
|
85
|
+
file_name:
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def to_hash
|
|
90
|
+
ATTRIBUTES.each_with_object({}) { |key, hash| hash[key] = send(key) unless send(key).nil? }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def add_delayed_references(delayed_profiles, ig_resources)
|
|
94
|
+
self.delayed_references =
|
|
95
|
+
references
|
|
96
|
+
.select { |reference| (reference[:profiles] & delayed_profiles).present? }
|
|
97
|
+
.map do |reference|
|
|
98
|
+
profile_urls = (reference[:profiles] & delayed_profiles)
|
|
99
|
+
delayed_resources = profile_urls.map { |url| ig_resources.resource_for_profile(url) }
|
|
100
|
+
{
|
|
101
|
+
path: reference[:path].gsub("#{resource}.", ''),
|
|
102
|
+
resources: delayed_resources
|
|
103
|
+
}
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
10
107
|
def delayed?
|
|
11
108
|
# rubocop:disable Naming/MemoizedInstanceVariableName
|
|
12
|
-
# @is_delayed is used in USCoreTestKit::Generator::GroupMetadata
|
|
13
109
|
@is_delayed ||= if resource == 'Patient'
|
|
14
110
|
false
|
|
15
111
|
else
|