us_core_test_kit 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
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