us_core_test_kit 0.7.0 → 0.7.1

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 (106) hide show
  1. checksums.yaml +4 -4
  2. data/lib/us_core_test_kit/custom_groups/base_smart_granular_scopes_group.rb +2 -1
  3. data/lib/us_core_test_kit/custom_groups/screening_assessment_category_test.rb +75 -0
  4. data/lib/us_core_test_kit/custom_groups/v6.1.0/screening_assessment_group.rb +45 -0
  5. data/lib/us_core_test_kit/custom_groups/v7.0.0-ballot/screening_assessment_group.rb +48 -0
  6. data/lib/us_core_test_kit/fhir_resource_navigation.rb +11 -6
  7. data/lib/us_core_test_kit/generated/v6.1.0/condition_encounter_diagnosis/metadata.yml +22 -20
  8. data/lib/us_core_test_kit/generated/v6.1.0/condition_granular_scope1_group.rb +22 -20
  9. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/condition_granular_scope_read_test.rb +32 -0
  10. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/{condition_patient_abatement_date_granular_scope_test.rb → condition_patient_abatement_date_granular_scope_search_test.rb} +5 -5
  11. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/{condition_patient_asserted_date_granular_scope_test.rb → condition_patient_asserted_date_granular_scope_search_test.rb} +5 -5
  12. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/{condition_patient_category_clinical_status_granular_scope_test.rb → condition_patient_category_clinical_status_granular_scope_search_test.rb} +5 -5
  13. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/{condition_patient_category_encounter_granular_scope_test.rb → condition_patient_category_encounter_granular_scope_search_test.rb} +5 -5
  14. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/{condition_patient_category_granular_scope_test.rb → condition_patient_category_granular_scope_search_test.rb} +5 -5
  15. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/{condition_patient_clinical_status_granular_scope_test.rb → condition_patient_clinical_status_granular_scope_search_test.rb} +5 -5
  16. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/{condition_patient_code_granular_scope_test.rb → condition_patient_code_granular_scope_search_test.rb} +5 -5
  17. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/{condition_patient_granular_scope_test.rb → condition_patient_granular_scope_search_test.rb} +5 -5
  18. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/{condition_patient_onset_date_granular_scope_test.rb → condition_patient_onset_date_granular_scope_search_test.rb} +5 -5
  19. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/{condition_patient_recorded_date_granular_scope_test.rb → condition_patient_recorded_date_granular_scope_search_test.rb} +5 -5
  20. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/condition/metadata.yml +22 -20
  21. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/observation/metadata.yml +12 -10
  22. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/observation/observation_granular_scope_read_test.rb +32 -0
  23. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/observation/{observation_patient_category_date_granular_scope_test.rb → observation_patient_category_date_granular_scope_search_test.rb} +5 -5
  24. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/observation/{observation_patient_category_granular_scope_test.rb → observation_patient_category_granular_scope_search_test.rb} +5 -5
  25. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/observation/{observation_patient_category_status_granular_scope_test.rb → observation_patient_category_status_granular_scope_search_test.rb} +5 -5
  26. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/observation/{observation_patient_code_date_granular_scope_test.rb → observation_patient_code_date_granular_scope_search_test.rb} +5 -5
  27. data/lib/us_core_test_kit/generated/v6.1.0/granular_scope_tests/observation/{observation_patient_code_granular_scope_test.rb → observation_patient_code_granular_scope_search_test.rb} +5 -5
  28. data/lib/us_core_test_kit/generated/v6.1.0/metadata.yml +34 -30
  29. data/lib/us_core_test_kit/generated/v6.1.0/observation_granular_scope1_group.rb +12 -10
  30. data/lib/us_core_test_kit/generated/v6.1.0/observation_lab/metadata.yml +12 -10
  31. data/lib/us_core_test_kit/generated/v6.1.0/us_core_test_suite.rb +2 -0
  32. data/lib/us_core_test_kit/generated/v7.0.0-ballot/condition_encounter_diagnosis/metadata.yml +22 -20
  33. data/lib/us_core_test_kit/generated/v7.0.0-ballot/condition_granular_scope1_group.rb +22 -20
  34. data/lib/us_core_test_kit/generated/v7.0.0-ballot/condition_granular_scope2_group.rb +22 -20
  35. data/lib/us_core_test_kit/generated/v7.0.0-ballot/diagnostic_report_granular_scope1_group.rb +14 -12
  36. data/lib/us_core_test_kit/generated/v7.0.0-ballot/diagnostic_report_granular_scope2_group.rb +14 -12
  37. data/lib/us_core_test_kit/generated/v7.0.0-ballot/diagnostic_report_note/metadata.yml +14 -12
  38. data/lib/us_core_test_kit/generated/v7.0.0-ballot/document_reference/metadata.yml +16 -14
  39. data/lib/us_core_test_kit/generated/v7.0.0-ballot/document_reference_granular_scope1_group.rb +16 -14
  40. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/condition_granular_scope_read_test.rb +32 -0
  41. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/{condition_patient_abatement_date_granular_scope_test.rb → condition_patient_abatement_date_granular_scope_search_test.rb} +5 -5
  42. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/{condition_patient_asserted_date_granular_scope_test.rb → condition_patient_asserted_date_granular_scope_search_test.rb} +5 -5
  43. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/{condition_patient_category_clinical_status_granular_scope_test.rb → condition_patient_category_clinical_status_granular_scope_search_test.rb} +5 -5
  44. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/{condition_patient_category_encounter_granular_scope_test.rb → condition_patient_category_encounter_granular_scope_search_test.rb} +5 -5
  45. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/{condition_patient_category_granular_scope_test.rb → condition_patient_category_granular_scope_search_test.rb} +5 -5
  46. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/{condition_patient_clinical_status_granular_scope_test.rb → condition_patient_clinical_status_granular_scope_search_test.rb} +5 -5
  47. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/{condition_patient_code_granular_scope_test.rb → condition_patient_code_granular_scope_search_test.rb} +5 -5
  48. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/{condition_patient_granular_scope_test.rb → condition_patient_granular_scope_search_test.rb} +5 -5
  49. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/{condition_patient_onset_date_granular_scope_test.rb → condition_patient_onset_date_granular_scope_search_test.rb} +5 -5
  50. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/{condition_patient_recorded_date_granular_scope_test.rb → condition_patient_recorded_date_granular_scope_search_test.rb} +5 -5
  51. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/condition/metadata.yml +22 -20
  52. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/diagnostic_report/diagnostic_report_granular_scope_read_test.rb +32 -0
  53. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/diagnostic_report/{diagnostic_report_patient_category_date_granular_scope_test.rb → diagnostic_report_patient_category_date_granular_scope_search_test.rb} +5 -5
  54. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/diagnostic_report/{diagnostic_report_patient_category_granular_scope_test.rb → diagnostic_report_patient_category_granular_scope_search_test.rb} +5 -5
  55. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/diagnostic_report/{diagnostic_report_patient_code_date_granular_scope_test.rb → diagnostic_report_patient_code_date_granular_scope_search_test.rb} +5 -5
  56. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/diagnostic_report/{diagnostic_report_patient_code_granular_scope_test.rb → diagnostic_report_patient_code_granular_scope_search_test.rb} +5 -5
  57. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/diagnostic_report/{diagnostic_report_patient_granular_scope_test.rb → diagnostic_report_patient_granular_scope_search_test.rb} +5 -5
  58. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/diagnostic_report/{diagnostic_report_patient_status_granular_scope_test.rb → diagnostic_report_patient_status_granular_scope_search_test.rb} +5 -5
  59. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/diagnostic_report/metadata.yml +14 -12
  60. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/document_reference/document_reference_granular_scope_read_test.rb +32 -0
  61. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/document_reference/{document_reference_id_granular_scope_test.rb → document_reference_id_granular_scope_search_test.rb} +5 -5
  62. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/document_reference/{document_reference_patient_category_date_granular_scope_test.rb → document_reference_patient_category_date_granular_scope_search_test.rb} +5 -5
  63. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/document_reference/{document_reference_patient_category_granular_scope_test.rb → document_reference_patient_category_granular_scope_search_test.rb} +5 -5
  64. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/document_reference/{document_reference_patient_granular_scope_test.rb → document_reference_patient_granular_scope_search_test.rb} +5 -5
  65. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/document_reference/{document_reference_patient_status_granular_scope_test.rb → document_reference_patient_status_granular_scope_search_test.rb} +5 -5
  66. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/document_reference/{document_reference_patient_type_granular_scope_test.rb → document_reference_patient_type_granular_scope_search_test.rb} +5 -5
  67. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/document_reference/{document_reference_patient_type_period_granular_scope_test.rb → document_reference_patient_type_period_granular_scope_search_test.rb} +5 -5
  68. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/document_reference/metadata.yml +16 -14
  69. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/observation/metadata.yml +12 -10
  70. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/observation/observation_granular_scope_read_test.rb +32 -0
  71. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/observation/{observation_patient_category_date_granular_scope_test.rb → observation_patient_category_date_granular_scope_search_test.rb} +5 -5
  72. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/observation/{observation_patient_category_granular_scope_test.rb → observation_patient_category_granular_scope_search_test.rb} +5 -5
  73. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/observation/{observation_patient_category_status_granular_scope_test.rb → observation_patient_category_status_granular_scope_search_test.rb} +5 -5
  74. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/observation/{observation_patient_code_date_granular_scope_test.rb → observation_patient_code_date_granular_scope_search_test.rb} +5 -5
  75. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/observation/{observation_patient_code_granular_scope_test.rb → observation_patient_code_granular_scope_search_test.rb} +5 -5
  76. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/service_request/metadata.yml +16 -14
  77. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/service_request/service_request_granular_scope_read_test.rb +32 -0
  78. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/service_request/{service_request_id_granular_scope_test.rb → service_request_id_granular_scope_search_test.rb} +5 -5
  79. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/service_request/{service_request_patient_category_authored_granular_scope_test.rb → service_request_patient_category_authored_granular_scope_search_test.rb} +5 -5
  80. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/service_request/{service_request_patient_category_granular_scope_test.rb → service_request_patient_category_granular_scope_search_test.rb} +5 -5
  81. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/service_request/{service_request_patient_code_authored_granular_scope_test.rb → service_request_patient_code_authored_granular_scope_search_test.rb} +5 -5
  82. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/service_request/{service_request_patient_code_granular_scope_test.rb → service_request_patient_code_granular_scope_search_test.rb} +5 -5
  83. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/service_request/{service_request_patient_granular_scope_test.rb → service_request_patient_granular_scope_search_test.rb} +5 -5
  84. data/lib/us_core_test_kit/generated/v7.0.0-ballot/granular_scope_tests/service_request/{service_request_patient_status_granular_scope_test.rb → service_request_patient_status_granular_scope_search_test.rb} +5 -5
  85. data/lib/us_core_test_kit/generated/v7.0.0-ballot/metadata.yml +80 -70
  86. data/lib/us_core_test_kit/generated/v7.0.0-ballot/observation_granular_scope1_group.rb +12 -10
  87. data/lib/us_core_test_kit/generated/v7.0.0-ballot/observation_granular_scope2_group.rb +12 -10
  88. data/lib/us_core_test_kit/generated/v7.0.0-ballot/observation_lab/metadata.yml +12 -10
  89. data/lib/us_core_test_kit/generated/v7.0.0-ballot/service_request/metadata.yml +16 -14
  90. data/lib/us_core_test_kit/generated/v7.0.0-ballot/service_request_granular_scope1_group.rb +16 -14
  91. data/lib/us_core_test_kit/generated/v7.0.0-ballot/service_request_granular_scope2_group.rb +16 -14
  92. data/lib/us_core_test_kit/generated/v7.0.0-ballot/us_core_test_suite.rb +2 -0
  93. data/lib/us_core_test_kit/generator/granular_scope_read_test_generator.rb +102 -0
  94. data/lib/us_core_test_kit/generator/granular_scope_test_generator.rb +2 -2
  95. data/lib/us_core_test_kit/generator/suite_generator.rb +9 -1
  96. data/lib/us_core_test_kit/generator.rb +2 -0
  97. data/lib/us_core_test_kit/granular_scope.rb +63 -0
  98. data/lib/us_core_test_kit/granular_scope_read_test.rb +71 -0
  99. data/lib/us_core_test_kit/{granular_scope_checker.rb → granular_scope_search_test.rb} +8 -47
  100. data/lib/us_core_test_kit/must_support_test.rb +3 -2
  101. data/lib/us_core_test_kit/primitive_type.rb +5 -0
  102. data/lib/us_core_test_kit/provenance_validator.rb +3 -4
  103. data/lib/us_core_test_kit/resource_search_param_checker.rb +139 -0
  104. data/lib/us_core_test_kit/search_test.rb +6 -2
  105. data/lib/us_core_test_kit/version.rb +1 -1
  106. metadata +70 -55
@@ -0,0 +1,63 @@
1
+ module USCoreTestKit
2
+ module GranularScope
3
+
4
+ def granular_scopes
5
+ @granular_scopes ||=
6
+ received_scopes
7
+ .split(' ')
8
+ .select do |scope|
9
+ (scope.start_with?("patient/#{resource_type}") || scope.start_with?("user/#{resource_type}")) &&
10
+ scope.include?('?')
11
+ end
12
+ end
13
+
14
+ def granular_scope_search_params
15
+ @granular_scope_search_params ||=
16
+ granular_scopes.map do |scope|
17
+ _, granular_scope = scope.split('?')
18
+ name, value = granular_scope.split('=')
19
+
20
+ {
21
+ name:,
22
+ value:
23
+ }
24
+ end
25
+ end
26
+
27
+ def resource_specific_granular_scope_search_params
28
+ @resource_specific_granular_scope_search_params ||=
29
+ granular_scopes.select {|scope| scope.include?(resource_type)}.map do |scope|
30
+ _, granular_scope = scope.split('?')
31
+ name, value = granular_scope.split('=')
32
+ _, value = value.split('|')
33
+ {
34
+ name:,
35
+ value:
36
+ }
37
+ end
38
+ end
39
+
40
+ def previous_request_resources
41
+ first_request = previous_requests.first
42
+ next_page_url = nil
43
+ hash = Hash.new { |hash, key| hash[key] = [] }
44
+ previous_requests.each_with_object(hash) do |request, request_resource_hash|
45
+ request_resources =
46
+ if request.status == 200
47
+ request.resource.entry.map(&:resource).select { |resource| resource.resourceType == resource_type }
48
+ else
49
+ []
50
+ end
51
+
52
+ first_request = request if request.url != next_page_url
53
+
54
+ request_resource_hash[first_request].concat(request_resources)
55
+
56
+ next if request.resource&.resourceType != 'Bundle'
57
+
58
+ next_page_url = request.resource&.link&.find { |link| link.relation == 'next' }&.url
59
+ end
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,71 @@
1
+ require_relative 'resource_search_param_checker'
2
+ require_relative 'granular_scope'
3
+
4
+ module USCoreTestKit
5
+ module GranularScopeReadTest
6
+ extend Forwardable
7
+ include ResourceSearchParamChecker
8
+ include GranularScope
9
+
10
+ def_delegators 'self.class', :metadata
11
+ def self.included(klass)
12
+ klass.input(:received_scopes)
13
+ klass.attr_accessor :previous_requests
14
+ end
15
+
16
+ def run_scope_read_test
17
+ assert granular_scopes.present?, "No granular scopes were received for #{resource_type} resources"
18
+ resource_scopes = granular_scopes.select {|scope| scope.include?(resource_type)}
19
+
20
+ load_previous_requests
21
+ skip_if previous_requests.blank?,
22
+ "No #{resource_type} reads found"
23
+ previous_resources_for_reads = previous_request_resources.values.flatten
24
+
25
+ resource_specific_granular_scope_search_params.each do |scope|
26
+ current_scope = granular_scopes.find {|granular| granular.include?(scope[:name]) && granular.include?(scope[:value])}
27
+
28
+ resource_matching_scope = previous_resources_for_reads.find do |prev_resource|
29
+ resource_matches_param?(prev_resource, scope[:name], scope[:value])
30
+ end
31
+ skip_if resource_matching_scope.nil?, "Unable to find any resources to match scope #{current_scope}"
32
+
33
+ fhir_read resource_type, resource_matching_scope.id
34
+
35
+ assert_response_status(200)
36
+ assert_resource_type(resource_type)
37
+ end
38
+
39
+ nonmatching_resource = previous_resources_for_reads.find do |prev_resource|
40
+ resource_specific_granular_scope_search_params.none? do |scope|
41
+ resource_matches_param?(prev_resource, scope[:name], scope[:value])
42
+ end
43
+ end
44
+ if nonmatching_resource
45
+ fhir_read resource_type, nonmatching_resource.id
46
+ assert (response && response[:status]) != 200, "Server incorrectly responded with a successful status, read should fail due to scopes."
47
+ assert (resource && resource.resourceType != resource_type), "Server incorrectly returned a #{resource_type}, read should fail due to scopes"
48
+ else
49
+ info "Unable to find a resource that does not match scopes."
50
+ end
51
+ end
52
+
53
+ def load_previous_requests
54
+ params = metadata.searches.first[:names]
55
+ search_params_as_hash = params.each_with_object({}) do |name, hash|
56
+ hash[name] = nil
57
+ end
58
+ @previous_requests ||=
59
+ load_tagged_requests(search_params_tag(search_params_as_hash))
60
+ .sort_by { |request| request.index }
61
+ end
62
+
63
+ def unescape_search_value(value)
64
+ value&.gsub('\\,', ',')
65
+ end
66
+
67
+ def search_params_tag(params)
68
+ "#{resource_type}?#{params.keys.join('&')}"
69
+ end
70
+ end
71
+ end
@@ -1,11 +1,17 @@
1
+ require_relative 'resource_search_param_checker'
2
+ require_relative 'granular_scope'
3
+
1
4
  module USCoreTestKit
2
- module GranularScopeChecker
5
+ module GranularScopeSearchTest
6
+ include ResourceSearchParamChecker
7
+ include GranularScope
8
+
3
9
  def self.included(klass)
4
10
  klass.input(:received_scopes)
5
11
  klass.attr_accessor :previous_requests
6
12
  end
7
13
 
8
- def run_scope_check_test
14
+ def run_scope_search_test
9
15
  assert granular_scopes.present?, "No granular scopes were received for #{resource_type} resources"
10
16
 
11
17
  load_previous_requests
@@ -47,51 +53,6 @@ module USCoreTestKit
47
53
  end
48
54
  end
49
55
 
50
- def previous_request_resources
51
- first_request = previous_requests.first
52
- next_page_url = nil
53
- hash = Hash.new { |hash, key| hash[key] = [] }
54
- previous_requests.each_with_object(hash) do |request, request_resource_hash|
55
- request_resources =
56
- if request.status == 200
57
- request.resource.entry.map(&:resource).select { |resource| resource.resourceType == resource_type }
58
- else
59
- []
60
- end
61
-
62
- first_request = request if request.url != next_page_url
63
-
64
- request_resource_hash[first_request].concat(request_resources)
65
-
66
- next if request.resource&.resourceType != 'Bundle'
67
-
68
- next_page_url = request.resource&.link&.find { |link| link.relation == 'next' }&.url
69
- end
70
- end
71
-
72
- def granular_scopes
73
- @granular_scopes ||=
74
- received_scopes
75
- .split(' ')
76
- .select do |scope|
77
- (scope.start_with?("patient/#{resource_type}") || scope.start_with?("user/#{resource_type}")) &&
78
- scope.include?('?')
79
- end
80
- end
81
-
82
- def granular_scope_search_params
83
- @granular_scope_search_params ||=
84
- granular_scopes.map do |scope|
85
- _, granular_scope = scope.split('?')
86
- name, value = granular_scope.split('=')
87
-
88
- {
89
- name:,
90
- value:
91
- }
92
- end
93
- end
94
-
95
56
  def load_previous_requests
96
57
  search_params_as_hash = search_param_names.each_with_object({}) do |name, hash|
97
58
  hash[name] = nil
@@ -115,12 +115,13 @@ module USCoreTestKit
115
115
  .map { |ex| ex[:url] }
116
116
 
117
117
  value_found = find_a_value_at(resource, path) do |value|
118
- if value.respond_to?(:extension) && ms_extension_urls.present?
119
- urls = value.extension.map(&:url)
118
+ if value.instance_of?(USCoreTestKit::PrimitiveType) && ms_extension_urls.present?
119
+ urls = value.extension&.map(&:url)
120
120
  has_ms_extension = (urls & ms_extension_urls).present?
121
121
  end
122
122
 
123
123
  unless has_ms_extension
124
+ value = value.value if value.instance_of?(USCoreTestKit::PrimitiveType)
124
125
  value_without_extensions =
125
126
  value.respond_to?(:to_hash) ? value.to_hash.reject { |key, _| key == 'extension' } : value
126
127
  end
@@ -0,0 +1,5 @@
1
+ module USCoreTestKit
2
+ class PrimitiveType < FHIR::Element
3
+ attr_accessor :value
4
+ end
5
+ end
@@ -19,11 +19,10 @@ module USCoreTestKit
19
19
 
20
20
  failed_provenance =
21
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?
22
+ ['Practitioner', 'Device'].any? { |resource_type| agent.who&.reference&.include?(resource_type) } &&
23
+ agent.onBehalfOf.nil?
24
24
  end
25
25
 
26
-
27
26
  if failed_provenance.present?
28
27
  validation_messages << {
29
28
  type: 'error',
@@ -34,4 +33,4 @@ module USCoreTestKit
34
33
  validation_messages
35
34
  end
36
35
  end
37
- end
36
+ end
@@ -0,0 +1,139 @@
1
+ require_relative 'fhir_resource_navigation'
2
+
3
+ module USCoreTestKit
4
+ module ResourceSearchParamChecker
5
+ include FHIRResourceNavigation
6
+
7
+ def search_param_paths(name)
8
+ paths = metadata.search_definitions[name.to_sym][:paths]
9
+ if paths.first =='class'
10
+ paths[0] = 'local_class'
11
+ end
12
+
13
+ paths
14
+ end
15
+
16
+ def element_has_valid_value?(element, include_system)
17
+ case element
18
+ when FHIR::Reference
19
+ element.reference.present?
20
+ when FHIR::CodeableConcept
21
+ if include_system
22
+ coding =
23
+ find_a_value_at(element, 'coding') { |coding| coding.code.present? && coding.system.present? }
24
+ coding.present?
25
+ else
26
+ find_a_value_at(element, 'coding.code').present?
27
+ end
28
+ when FHIR::Identifier
29
+ include_system ? element.value.present? && element.system.present? : element.value.present?
30
+ when FHIR::Coding
31
+ include_system ? element.code.present? && element.system.present? : element.code.present?
32
+ when FHIR::HumanName
33
+ (element.family || element.given&.first || element.text).present?
34
+ when FHIR::Address
35
+ (element.text || element.city || element.state || element.postalCode || element.country).present?
36
+ when FHIR::Element
37
+ false
38
+ else
39
+ true
40
+ end
41
+ end
42
+
43
+ def resource_matches_param?(resource, search_param_name, escaped_search_value, values_found = [])
44
+ search_value = unescape_search_value(escaped_search_value)
45
+ paths = search_param_paths(search_param_name)
46
+
47
+ match_found = false
48
+
49
+ paths.each do |path|
50
+ type = metadata.search_definitions[search_param_name.to_sym][:type]
51
+ values_found =
52
+ resolve_path(resource, path)
53
+ .map do |value|
54
+ if value.is_a? FHIR::Reference
55
+ value.reference
56
+ else
57
+ value
58
+ end
59
+ end
60
+
61
+ match_found =
62
+ case type
63
+ when 'Period', 'date', 'instant', 'dateTime'
64
+ values_found.any? { |date| validate_date_search(search_value, date) }
65
+ when 'HumanName'
66
+ # When a string search parameter refers to the types HumanName and Address,
67
+ # the search covers the elements of type string, and does not cover elements such as use and period
68
+ # https://www.hl7.org/fhir/search.html#string
69
+ search_value_downcase = search_value.downcase
70
+ values_found.any? do |name|
71
+ name&.text&.downcase&.start_with?(search_value_downcase) ||
72
+ name&.family&.downcase&.start_with?(search_value_downcase) ||
73
+ name&.given&.any? { |given| given.downcase.start_with?(search_value_downcase) } ||
74
+ name&.prefix&.any? { |prefix| prefix.downcase.start_with?(search_value_downcase) } ||
75
+ name&.suffix&.any? { |suffix| suffix.downcase.start_with?(search_value_downcase) }
76
+ end
77
+ when 'Address'
78
+ search_value_downcase = search_value.downcase
79
+ values_found.any? do |address|
80
+ address&.text&.downcase&.start_with?(search_value_downcase) ||
81
+ address&.city&.downcase&.start_with?(search_value_downcase) ||
82
+ address&.state&.downcase&.start_with?(search_value_downcase) ||
83
+ address&.postalCode&.downcase&.start_with?(search_value_downcase) ||
84
+ address&.country&.downcase&.start_with?(search_value_downcase)
85
+ end
86
+ when 'CodeableConcept'
87
+ # FHIR token search (https://www.hl7.org/fhir/search.html#token): "When in doubt, servers SHOULD
88
+ # treat tokens in a case-insensitive manner, on the grounds that including undesired data has
89
+ # less safety implications than excluding desired behavior".
90
+ codings = values_found.flat_map(&:coding)
91
+ if search_value.include? '|'
92
+ system = search_value.split('|').first
93
+ code = search_value.split('|').last
94
+ codings&.any? { |coding| coding.system == system && coding.code&.casecmp?(code) }
95
+ else
96
+ codings&.any? { |coding| coding.code&.casecmp?(search_value) }
97
+ end
98
+ when 'Coding'
99
+ if search_value.include? '|'
100
+ system = search_value.split('|').first
101
+ code = search_value.split('|').last
102
+ values_found.any? { |coding| coding.system == system && coding.code&.casecmp?(code) }
103
+ else
104
+ values_found.any? { |coding| coding.code&.casecmp?(search_value) }
105
+ end
106
+ when 'Identifier'
107
+ if search_value.include? '|'
108
+ values_found.any? { |identifier| "#{identifier.system}|#{identifier.value}" == search_value }
109
+ else
110
+ values_found.any? { |identifier| identifier.value == search_value }
111
+ end
112
+ when 'string'
113
+ searched_values = search_value.downcase.split(/(?<!\\\\),/).map{ |string| string.gsub('\\,', ',') }
114
+ values_found.any? do |value_found|
115
+ searched_values.any? { |searched_value| value_found.downcase.starts_with? searched_value }
116
+ end
117
+ else
118
+ # searching by patient requires special case because we are searching by a resource identifier
119
+ # references can also be URLs, so we may need to resolve those URLs
120
+ if ['subject', 'patient'].include? search_param_name.to_s
121
+ id = search_value.split('Patient/').last
122
+ possible_values = [id, "Patient/#{id}", "#{url}/Patient/#{id}"]
123
+ values_found.any? do |reference|
124
+ possible_values.include? reference
125
+ end
126
+ else
127
+ search_values = search_value.split(/(?<!\\\\),/).map { |string| string.gsub('\\,', ',') }
128
+ values_found.any? { |value_found| search_values.include? value_found }
129
+ end
130
+ end
131
+
132
+ break if match_found
133
+ end
134
+
135
+ match_found
136
+ end
137
+
138
+ end
139
+ end
@@ -1,5 +1,6 @@
1
1
  require_relative 'date_search_validation'
2
2
  require_relative 'fhir_resource_navigation'
3
+ require_relative 'resource_search_param_checker'
3
4
  require_relative 'search_test_properties'
4
5
 
5
6
  module USCoreTestKit
@@ -7,6 +8,7 @@ module USCoreTestKit
7
8
  extend Forwardable
8
9
  include DateSearchValidation
9
10
  include FHIRResourceNavigation
11
+ include ResourceSearchParamChecker
10
12
 
11
13
  def_delegators 'self.class', :metadata, :provenance_metadata, :properties
12
14
  def_delegators 'properties',
@@ -629,6 +631,8 @@ module USCoreTestKit
629
631
  element.family || element.given&.first || element.text
630
632
  when FHIR::Address
631
633
  element.text || element.city || element.state || element.postalCode || element.country
634
+ when USCoreTestKit::PrimitiveType
635
+ element.value
632
636
  else
633
637
  if metadata.version != 'v3.1.1' &&
634
638
  metadata.search_definitions[name.to_sym][:type] == 'date' &&
@@ -676,8 +680,8 @@ module USCoreTestKit
676
680
  (element.family || element.given&.first || element.text).present?
677
681
  when FHIR::Address
678
682
  (element.text || element.city || element.state || element.postalCode || element.country).present?
679
- when FHIR::Element
680
- false
683
+ when USCoreTestKit::PrimitiveType
684
+ element.value.present?
681
685
  else
682
686
  true
683
687
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USCoreTestKit
4
- VERSION = '0.7.0'
4
+ VERSION = '0.7.1'
5
5
  end