us_quality_core_test_kit 0.1.0 → 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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/NOTICE.md +12 -0
  3. data/config/presets/{localhost_preset.json → inferno_reference_server_preset.json.erb} +2 -2
  4. data/lib/us_quality_core_test_kit/client/generator/example_client_generator.rb +0 -1
  5. data/lib/us_quality_core_test_kit/client/generator/tags_generator.rb +0 -1
  6. data/lib/us_quality_core_test_kit/client/server_proxy.rb +2 -6
  7. data/lib/us_quality_core_test_kit/date_search_validation.rb +122 -0
  8. data/lib/us_quality_core_test_kit/fhir_resource_navigation.rb +9 -0
  9. data/lib/us_quality_core_test_kit/generated/v0.5.0/devicenotrequested/devicenotrequested_validation_test.rb +3 -0
  10. data/lib/us_quality_core_test_kit/generated/v0.5.0/devicerequest/devicerequest_validation_test.rb +3 -0
  11. data/lib/us_quality_core_test_kit/generated/v0.5.0/patient/patient_validation_test.rb +4 -0
  12. data/lib/us_quality_core_test_kit/generated/v0.5.0/us_quality_core_test_suite.rb +1 -2
  13. data/lib/us_quality_core_test_kit/generator/group_generator.rb +69 -3
  14. data/lib/us_quality_core_test_kit/generator/group_metadata.rb +100 -4
  15. data/lib/us_quality_core_test_kit/generator/group_metadata_extractor.rb +184 -8
  16. data/lib/us_quality_core_test_kit/generator/ig_loader.rb +47 -3
  17. data/lib/us_quality_core_test_kit/generator/ig_metadata.rb +51 -2
  18. data/lib/us_quality_core_test_kit/generator/ig_metadata_extractor.rb +25 -6
  19. data/lib/us_quality_core_test_kit/generator/ig_resources.rb +27 -3
  20. data/lib/us_quality_core_test_kit/generator/must_support_metadata_extractor.rb +366 -9
  21. data/lib/us_quality_core_test_kit/generator/must_support_test_generator.rb +54 -3
  22. data/lib/us_quality_core_test_kit/generator/provenance_revinclude_search_test_generator.rb +149 -3
  23. data/lib/us_quality_core_test_kit/generator/read_test_generator.rb +54 -3
  24. data/lib/us_quality_core_test_kit/generator/reference_resolution_test_generator.rb +57 -3
  25. data/lib/us_quality_core_test_kit/generator/search_definition_metadata_extractor.rb +181 -5
  26. data/lib/us_quality_core_test_kit/generator/search_metadata_extractor.rb +61 -3
  27. data/lib/us_quality_core_test_kit/generator/search_test_generator.rb +186 -3
  28. data/lib/us_quality_core_test_kit/generator/suite_generator.rb +35 -8
  29. data/lib/us_quality_core_test_kit/generator/terminology_binding_metadata_extractor.rb +107 -3
  30. data/lib/us_quality_core_test_kit/generator/validation_test_generator.rb +83 -4
  31. data/lib/us_quality_core_test_kit/generator/value_extractor.rb +147 -3
  32. data/lib/us_quality_core_test_kit/must_support_test.rb +15 -3
  33. data/lib/us_quality_core_test_kit/primitive_type.rb +7 -0
  34. data/lib/us_quality_core_test_kit/read_test.rb +99 -4
  35. data/lib/us_quality_core_test_kit/reference_resolution_test.rb +164 -3
  36. data/lib/us_quality_core_test_kit/resource_search_param_checker.rb +138 -0
  37. data/lib/us_quality_core_test_kit/search_test.rb +681 -46
  38. data/lib/us_quality_core_test_kit/search_test_properties.rb +53 -3
  39. data/lib/us_quality_core_test_kit/validation_test.rb +51 -4
  40. data/lib/us_quality_core_test_kit/version.rb +2 -2
  41. data/lib/us_quality_core_test_kit/well_known_code_systems.rb +23 -0
  42. metadata +8 -17
@@ -1,13 +1,64 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'us_core_test_kit/generator/read_test_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 ReadTestGenerator < USCoreTestKit::Generator::ReadTestGenerator
8
+ class ReadTestGenerator
9
+ attr_accessor :group_metadata, :base_output_dir
10
+
11
+ def initialize(group_metadata, base_output_dir)
12
+ self.group_metadata = group_metadata
13
+ self.base_output_dir = base_output_dir
14
+ end
15
+
16
+ def output
17
+ @output ||= ERB.new(template).result(binding)
18
+ end
19
+
20
+ def base_output_file_name
21
+ "#{class_name.underscore}.rb"
22
+ end
23
+
24
+ def output_file_directory
25
+ File.join(base_output_dir, profile_identifier)
26
+ end
27
+
28
+ def output_file_name
29
+ File.join(output_file_directory, base_output_file_name)
30
+ end
31
+
32
+ def read_interaction
33
+ self.class.read_interaction(group_metadata)
34
+ end
35
+
36
+ def resource_type
37
+ group_metadata.resource
38
+ end
39
+
40
+ def resource_collection_string
41
+ if group_metadata.delayed? && resource_type != 'Provenance'
42
+ "scratch.dig(:references, '#{resource_type}'), delayed_reference: true"
43
+ else
44
+ 'all_scratch_resources'
45
+ end
46
+ end
47
+
48
+ def conformance_expectation
49
+ read_interaction[:expectation]
50
+ end
51
+
52
+ def generate
53
+ FileUtils.mkdir_p(output_file_directory)
54
+ File.write(output_file_name, output)
55
+
56
+ group_metadata.add_test(
57
+ id: test_id,
58
+ file_name: base_output_file_name
59
+ )
60
+ end
61
+
11
62
  class << self
12
63
  def generate(ig_metadata, base_output_dir)
13
64
  ig_metadata.groups
@@ -1,13 +1,67 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'us_core_test_kit/generator/reference_resolution_test_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 ReferenceResolutionTestGenerator < USCoreTestKit::Generator::ReferenceResolutionTestGenerator
8
+ class ReferenceResolutionTestGenerator
9
+ attr_accessor :group_metadata, :base_output_dir
10
+
11
+ def initialize(group_metadata, base_output_dir)
12
+ self.group_metadata = group_metadata
13
+ self.base_output_dir = base_output_dir
14
+ end
15
+
16
+ def output
17
+ @output ||= ERB.new(template, trim_mode: '-').result(binding)
18
+ end
19
+
20
+ def base_output_file_name
21
+ "#{class_name.underscore}.rb"
22
+ end
23
+
24
+ def output_file_directory
25
+ File.join(base_output_dir, profile_identifier)
26
+ end
27
+
28
+ def output_file_name
29
+ File.join(output_file_directory, base_output_file_name)
30
+ end
31
+
32
+ def resource_type
33
+ group_metadata.resource
34
+ end
35
+
36
+ def resource_collection_string
37
+ 'scratch_resources[:all]'
38
+ end
39
+
40
+ def must_support_references
41
+ group_metadata.must_supports[:elements]
42
+ .select { |element| element[:types]&.include?('Reference') }
43
+ end
44
+
45
+ def must_support_reference_list_string
46
+ must_support_references
47
+ .map { |element| "#{' ' * 8}* #{resource_type}.#{element[:path]}" }
48
+ .uniq
49
+ .sort
50
+ .join("\n")
51
+ end
52
+
53
+ def generate
54
+ return if must_support_references.empty?
55
+
56
+ FileUtils.mkdir_p(output_file_directory)
57
+ File.write(output_file_name, output)
58
+
59
+ group_metadata.add_test(
60
+ id: test_id,
61
+ file_name: base_output_file_name
62
+ )
63
+ end
64
+
11
65
  class << self
12
66
  def generate(ig_metadata, base_output_dir)
13
67
  ig_metadata.groups
@@ -1,13 +1,183 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'us_core_test_kit/generator/search_definition_metadata_extractor'
4
-
5
- require_relative 'special_cases'
6
3
  require_relative 'value_extractor'
4
+ require_relative 'special_cases'
7
5
 
8
6
  module USQualityCoreTestKit
9
7
  class Generator
10
- class SearchDefinitionMetadataExtractor < USCoreTestKit::Generator::SearchDefinitionMetadataExtractor
8
+ class SearchDefinitionMetadataExtractor
9
+ attr_accessor :ig_resources, :name, :profile_elements, :group_metadata
10
+
11
+ def initialize(name, ig_resources, profile_elements, group_metadata)
12
+ self.name = name
13
+ self.ig_resources = ig_resources
14
+ self.profile_elements = profile_elements
15
+ self.group_metadata = group_metadata
16
+ end
17
+
18
+ def search_definition
19
+ @search_definition ||=
20
+ {
21
+ paths: paths,
22
+ full_paths: full_paths,
23
+ comparators: comparators,
24
+ values: values,
25
+ type: type,
26
+ contains_multiple: contains_multiple?,
27
+ multiple_or: multiple_or_expectation,
28
+ chain: chain
29
+ }.compact
30
+ end
31
+
32
+ def resource
33
+ group_metadata[:resource]
34
+ end
35
+
36
+ def param
37
+ @param ||= ig_resources.search_param_by_resource_and_name(resource, name)
38
+ end
39
+
40
+ def param_hash
41
+ param.source_hash
42
+ end
43
+
44
+ def full_paths
45
+ @full_paths ||=
46
+ begin
47
+ path = param.expression.gsub(/.where\(resolve\((.*)/, '').gsub('url = \'', 'url=\'')
48
+ path = path[1..-2] if path.start_with?('(') && path.end_with?(')')
49
+ path.scan(/[. ]as[( ]([^)]*)[)]?/).flatten.map do |as_type|
50
+ path.gsub!(/[. ]as[( ](#{as_type}[^)]*)[)]?/, as_type.upcase_first) if as_type.present?
51
+ end
52
+
53
+ path.gsub!('Resource.', "#{resource}.") if path.start_with?('Resource.')
54
+
55
+ full_paths = path.split('|')
56
+
57
+ full_paths
58
+ end
59
+ end
60
+
61
+ def remove_additional_extension_from_asserted_date(full_paths)
62
+ full_paths.each do |full_path|
63
+ next unless full_path.include?('http://hl7.org/fhir/StructureDefinition/condition-assertedDate')
64
+
65
+ full_path.gsub!(/\).extension./, ').')
66
+ end
67
+ end
68
+
69
+ def extension_definition
70
+ @extension_definition ||=
71
+ begin
72
+ ext_definition = nil
73
+ extensions&.each do |ext_metadata|
74
+ ext_definition = ig_resources.profile_by_url(ext_metadata[:url])
75
+ break if ext_definition.present?
76
+ end
77
+ ext_definition
78
+ end
79
+ end
80
+
81
+ def comparator_expectation_extensions
82
+ @comparator_expectation_extensions ||= param_hash['_comparator'] || []
83
+ end
84
+
85
+ def support_expectation(extension)
86
+ extension['extension'].first['valueCode']
87
+ end
88
+
89
+ def comparator_expectation(extension)
90
+ if extension.nil?
91
+ 'MAY'
92
+ else
93
+ support_expectation(extension)
94
+ end
95
+ end
96
+
97
+ def comparators
98
+ {}.tap do |comparators|
99
+ param.comparator&.each_with_index do |comparator, index|
100
+ comparators[comparator.to_sym] = comparator_expectation(comparator_expectation_extensions[index])
101
+ end
102
+ end
103
+ end
104
+
105
+ def contains_multiple?
106
+ if profile_element.present?
107
+ if profile_element.id.start_with?('Extension') && extension_definition.present?
108
+ # Find the extension instance in a US Core profile
109
+ target_element = profile_elements.find do |element|
110
+ element.type.any? { |type| type.code == 'Extension' && type.profile.include?(extension_definition.url) }
111
+ end
112
+ target_element&.max == '*'
113
+ else
114
+ profile_element.max == '*'
115
+ end
116
+ else
117
+ false
118
+ end
119
+ end
120
+
121
+ def chain_extensions
122
+ param_hash['_chain']
123
+ end
124
+
125
+ def chain_expectations
126
+ chain_extensions.map { |extension| support_expectation(extension) }
127
+ end
128
+
129
+ def chain
130
+ return nil if param.chain.blank?
131
+
132
+ param.chain
133
+ .zip(chain_expectations)
134
+ .map { |chain, expectation| { chain: chain, expectation: expectation } }
135
+ end
136
+
137
+ def multiple_or_expectation
138
+ param_hash['_multipleOr'] ? param_hash['_multipleOr']['extension'].first['valueCode'] : 'MAY'
139
+ end
140
+
141
+ def values_from_must_supports(profile_element)
142
+ return if profile_element.nil?
143
+
144
+ short_path = profile_element.path.split('.', 2)[1]
145
+
146
+ values_from_must_support_slices(profile_element, short_path, true).presence ||
147
+ values_from_must_support_slices(profile_element, short_path, false).presence ||
148
+ values_from_must_support_elements(short_path).presence ||
149
+ []
150
+ end
151
+
152
+ def values_from_must_support_slices(profile_element, short_path, mandatory_slice_only)
153
+ group_metadata[:must_supports][:slices]
154
+ .select { |slice| [short_path, "#{short_path}.coding"].include?(slice[:path]) }
155
+ .map do |slice|
156
+ slice_element = profile_elements.find { |element| slice[:slice_id] == element.id }
157
+ next if profile_element.min.positive? && slice_element.min.zero? && mandatory_slice_only
158
+
159
+ case slice[:discriminator][:type]
160
+ when 'patternCoding', 'patternCodeableConcept'
161
+ slice[:discriminator][:code]
162
+ when 'requiredBinding'
163
+ value_extractor.codes_from_system_code_pair(slice[:discriminator][:values])
164
+ when 'value'
165
+ slice[:discriminator][:values]
166
+ .select { |value| value[:path] == 'coding.code' }
167
+ .map { |value| value[:value] }
168
+ end
169
+ end
170
+ .compact.flatten
171
+ end
172
+
173
+ def values_from_resource_metadata(paths)
174
+ if multiple_or_expectation == 'SHALL' || paths.any? { |path| path.downcase.include?('status') }
175
+ value_extractor.codes_from_system_code_pair(value_extractor.values_from_resource_metadata(paths))
176
+ else
177
+ []
178
+ end
179
+ end
180
+
11
181
  EXTENSION_URL_REGEX = /(?:modifierExtension|extension)\.where\(url='([^']+)'\)/
12
182
  EXTENSION_VALUE_PATH_REGEX = /\.(?:value(?:[A-Z]\w*|\[x\])?)\z/
13
183
 
@@ -71,10 +241,16 @@ module USQualityCoreTestKit
71
241
  category_search = paths.any? { |path| path.split('.').first == 'category' }
72
242
  fixed_boolean = profile_element.fixedBoolean if profile_element.respond_to?(:fixedBoolean)
73
243
  fixed_boolean_value = [fixed_boolean.to_s] unless fixed_boolean.nil?
244
+ base_values =
245
+ values_from_must_supports(profile_element).presence ||
246
+ value_extractor.values_from_fixed_codes(profile_element, type).presence ||
247
+ value_extractor.codes_from_value_set_binding(profile_element).presence ||
248
+ values_from_resource_metadata(paths).presence ||
249
+ []
74
250
 
75
251
  fixed_boolean_value.presence ||
76
252
  (SpecialCases::PROFILE_CATEGORY_SEARCH_VALUES[group_metadata[:profile_url]] if category_search).presence ||
77
- super.presence ||
253
+ base_values.presence ||
78
254
  (value_extractor.codes_from_system_code_pair(value_extractor.values_from_resource_metadata(paths)) if category_search).presence ||
79
255
  []
80
256
  end
@@ -1,12 +1,70 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'us_core_test_kit/generator/search_metadata_extractor'
4
-
5
3
  require_relative 'search_definition_metadata_extractor'
6
4
 
7
5
  module USQualityCoreTestKit
8
6
  class Generator
9
- class SearchMetadataExtractor < USCoreTestKit::Generator::SearchMetadataExtractor
7
+ class SearchMetadataExtractor
8
+ COMBO_EXTENSION_URL =
9
+ 'http://hl7.org/fhir/StructureDefinition/capabilitystatement-search-parameter-combination'
10
+
11
+ attr_accessor :resource_capabilities, :ig_resources, :profile_elements, :group_metadata
12
+
13
+ def initialize(resource_capabilities, ig_resources, profile_elements, group_metadata)
14
+ self.resource_capabilities = resource_capabilities
15
+ self.ig_resources = ig_resources
16
+ self.profile_elements = profile_elements
17
+ self.group_metadata = group_metadata
18
+ end
19
+
20
+ def searches
21
+ @searches ||= basic_searches + combo_searches
22
+ end
23
+
24
+ def conformance_expectation(search_param)
25
+ search_param.extension.first.valueCode # TODO: fix expectation extension finding
26
+ end
27
+
28
+ def no_search_params?
29
+ resource_capabilities.searchParam.blank?
30
+ end
31
+
32
+ def basic_searches
33
+ return [] if no_search_params?
34
+
35
+ resource_capabilities.searchParam
36
+ .select { |search_param| %w[SHALL SHOULD].include? conformance_expectation(search_param) }
37
+ .map do |search_param|
38
+ {
39
+ names: [search_param.name],
40
+ expectation: conformance_expectation(search_param)
41
+ }
42
+ end
43
+ end
44
+
45
+ def search_extensions
46
+ resource_capabilities.extension
47
+ end
48
+
49
+ def combo_searches
50
+ return [] if search_extensions.blank?
51
+
52
+ search_extensions
53
+ .select { |extension| extension.url == COMBO_EXTENSION_URL }
54
+ .select { |extension| %w[SHALL SHOULD].include? conformance_expectation(extension) }
55
+ .map do |extension|
56
+ names = extension.extension.select { |param| param.valueString.present? }.map(&:valueString)
57
+ {
58
+ expectation: conformance_expectation(extension),
59
+ names: names
60
+ }
61
+ end
62
+ end
63
+
64
+ def search_param_names
65
+ searches.flat_map { |search| search[:names] }.uniq
66
+ end
67
+
10
68
  def search_definitions
11
69
  search_param_names.each_with_object({}) do |name, definitions|
12
70
  definitions[name.to_sym] =
@@ -1,13 +1,196 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'us_core_test_kit/generator/search_test_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 SearchTestGenerator < USCoreTestKit::Generator::SearchTestGenerator
8
+ class SearchTestGenerator
9
+ attr_accessor :group_metadata, :search_metadata, :base_output_dir
10
+
11
+ def initialize(group_metadata, search_metadata, base_output_dir)
12
+ self.group_metadata = group_metadata
13
+ self.search_metadata = search_metadata
14
+ self.base_output_dir = base_output_dir
15
+ end
16
+
17
+ def output
18
+ @output ||= ERB.new(template, trim_mode: '-').result(binding)
19
+ end
20
+
21
+ def base_output_file_name
22
+ "#{class_name.underscore}.rb"
23
+ end
24
+
25
+ def output_file_directory
26
+ File.join(base_output_dir, profile_identifier)
27
+ end
28
+
29
+ def output_file_name
30
+ File.join(output_file_directory, base_output_file_name)
31
+ end
32
+
33
+ def search_identifier
34
+ search_metadata[:names].join('_').tr('-', '_')
35
+ end
36
+
37
+ def search_title
38
+ search_identifier.camelize
39
+ end
40
+
41
+ def resource_type
42
+ group_metadata.resource
43
+ end
44
+
45
+ def conformance_expectation
46
+ search_metadata[:expectation]
47
+ end
48
+
49
+ def search_params
50
+ @search_params ||=
51
+ search_metadata[:names].map do |name|
52
+ {
53
+ name: name,
54
+ path: search_definition(name)[:path]
55
+ }
56
+ end
57
+ end
58
+
59
+ def first_search?
60
+ group_metadata.searches.first == search_metadata
61
+ end
62
+
63
+ def fixed_value_search_param_name
64
+ (search_metadata[:names] - [:patient]).first
65
+ end
66
+
67
+ def search_param_name_string
68
+ search_metadata[:names].join(' + ')
69
+ end
70
+
71
+ def search_param_names
72
+ search_params.map { |param| param[:name] }
73
+ end
74
+
75
+ def search_param_names_array
76
+ array_of_strings(search_param_names)
77
+ end
78
+
79
+ def path_for_value(path)
80
+ path == 'class' ? 'local_class' : path
81
+ end
82
+
83
+ def required_comparators_for_param(name)
84
+ search_definition(name)[:comparators].select { |_comparator, expectation| expectation == 'SHALL' }
85
+ end
86
+
87
+ def required_comparators
88
+ @required_comparators ||=
89
+ search_param_names.each_with_object({}) do |name, comparators|
90
+ required_comparators = required_comparators_for_param(name)
91
+ comparators[name] = required_comparators if required_comparators.present?
92
+ end
93
+ end
94
+
95
+ def optional?
96
+ conformance_expectation != 'SHALL' || !search_metadata[:must_support_or_mandatory]
97
+ end
98
+
99
+ def search_definition(name)
100
+ group_metadata.search_definitions[name.to_sym]
101
+ end
102
+
103
+ def saves_delayed_references?
104
+ first_search? && group_metadata.delayed_references.present?
105
+ end
106
+
107
+ def possible_status_search?
108
+ search_metadata[:names].none? { |name| name.include? 'status' } &&
109
+ group_metadata.search_definitions.keys.any? { |key| key.to_s.include? 'status' }
110
+ end
111
+
112
+ def token_search_params
113
+ @token_search_params ||=
114
+ search_param_names.select do |name|
115
+ %w[Identifier CodeableConcept Coding].include? group_metadata.search_definitions[name.to_sym][:type]
116
+ end
117
+ end
118
+
119
+ def token_search_params_string
120
+ array_of_strings(token_search_params)
121
+ end
122
+
123
+ def required_multiple_or_search_params
124
+ @required_multiple_or_search_params ||=
125
+ search_param_names.select do |name|
126
+ search_definition(name)[:multiple_or] == 'SHALL'
127
+ end
128
+ end
129
+
130
+ def required_multiple_or_search_params_string
131
+ array_of_strings(required_multiple_or_search_params)
132
+ end
133
+
134
+ def required_comparators_string
135
+ array_of_strings(required_comparators.keys)
136
+ end
137
+
138
+ def array_of_strings(array)
139
+ quoted_strings = array.map { |element| "'#{element}'" }
140
+ "[#{quoted_strings.join(', ')}]"
141
+ end
142
+
143
+ def test_reference_variants?
144
+ first_search? && search_param_names.include?('patient')
145
+ end
146
+
147
+ def test_post_search?
148
+ first_search?
149
+ end
150
+
151
+ def search_properties
152
+ {}.tap do |properties|
153
+ properties[:first_search] = 'true' if first_search?
154
+ properties[:fixed_value_search] = 'true' if fixed_value_search?
155
+ properties[:resource_type] = "'#{resource_type}'"
156
+ properties[:search_param_names] = search_param_names_array
157
+ properties[:saves_delayed_references] = 'true' if saves_delayed_references?
158
+ properties[:possible_status_search] = 'true' if possible_status_search?
159
+ properties[:test_medication_inclusion] = 'true' if test_medication_inclusion?
160
+ properties[:token_search_params] = token_search_params_string if token_search_params.present?
161
+ properties[:test_reference_variants] = 'true' if test_reference_variants?
162
+ properties[:params_with_comparators] = required_comparators_string if required_comparators.present?
163
+ properties[:multiple_or_search_params] = required_multiple_or_search_params_string if required_multiple_or_search_params.present?
164
+ properties[:test_post_search] = 'true' if first_search?
165
+ end
166
+ end
167
+
168
+ def search_test_properties_string
169
+ search_properties
170
+ .map { |key, value| "#{' ' * 8}#{key}: #{value}" }
171
+ .join(",\n")
172
+ end
173
+
174
+ def generate
175
+ FileUtils.mkdir_p(output_file_directory)
176
+ File.write(output_file_name, output)
177
+
178
+ group_metadata.add_test(
179
+ id: test_id,
180
+ file_name: base_output_file_name
181
+ )
182
+ end
183
+
184
+ def medication_inclusion_description
185
+ return '' unless test_medication_inclusion?
186
+
187
+ <<~MEDICATION_INCLUSION_DESCRIPTION
188
+ If any #{resource_type} resources use external references to
189
+ Medications, the search will be repeated with
190
+ `_include=#{resource_type}:medication`.
191
+ MEDICATION_INCLUSION_DESCRIPTION
192
+ end
193
+
11
194
  class << self
12
195
  def generate(ig_metadata, base_output_dir)
13
196
  ig_metadata.groups
@@ -1,20 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'us_core_test_kit/generator/suite_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 SuiteGenerator < USCoreTestKit::Generator::SuiteGenerator
8
+ class SuiteGenerator
9
+ class << self
10
+ def generate(ig_metadata, base_output_dir)
11
+ new(ig_metadata, base_output_dir).generate
12
+ end
13
+ end
14
+
15
+ attr_accessor :ig_metadata, :base_output_dir
16
+
17
+ def initialize(ig_metadata, base_output_dir)
18
+ self.ig_metadata = ig_metadata
19
+ self.base_output_dir = base_output_dir
20
+ end
21
+
22
+ def output
23
+ @output ||= ERB.new(template, trim_mode: '-').result(binding)
24
+ end
25
+
26
+ def output_file_name
27
+ File.join(base_output_dir, base_output_file_name)
28
+ end
29
+
30
+ def generate
31
+ File.write(output_file_name, output)
32
+ end
33
+
34
+ def group_file_list
35
+ @group_file_list ||=
36
+ groups.map { |group| group.file_name.delete_suffix('.rb') }
37
+ end
38
+
11
39
  def version_specific_message_filters
12
40
  [
13
- # Patient validation warnings suppressed for US Core extensions because
14
- # validator tries to validate against different US Core version than we require
15
- %r{Patient.*Patient\.extension\[\d+\]\[url='http://hl7\.org/fhir/us/core/StructureDefinition/us-core-(race|ethnicity|tribal-affiliation)\|\d+\.\d+(?:\.\d+)?'\]:\s*The extension URL must not contain a version\.},
16
- %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},
17
- # This extension is correct but is not yet correctly passing in the validator
41
+ # Patient extension messages are suppressed because the CQL package can load US Core 7 into
42
+ # the validator session while US Quality Core 0.5.0 uses US Core 6.1.0.
43
+ /\bPatient\.extension/,
44
+ # This extension is correct but is not yet correctly passing in the validator.
18
45
  %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\]}
19
46
  ]
20
47
  end