davinci_pas_test_kit 0.9.0

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 (168) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/lib/davinci_pas_test_kit/client_suite.rb +289 -0
  4. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/claim_status/pas_claim_status_test.rb +109 -0
  5. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_approval_submit_response_attest.rb +39 -0
  6. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_approval_submit_test.rb +38 -0
  7. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_denial_submit_response_attest.rb +38 -0
  8. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_denial_submit_test.rb +43 -0
  9. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_inquire_must_support_test.rb +51 -0
  10. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_inquire_response_attest.rb +39 -0
  11. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_inquire_test.rb +35 -0
  12. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_submit_response_attest.rb +39 -0
  13. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_submit_test.rb +43 -0
  14. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_submit_must_support_test.rb +57 -0
  15. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_token_request_test.rb +31 -0
  16. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_token_validation_test.rb +18 -0
  17. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/error_tests/nonconformant_pas_bundle.json +16 -0
  18. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/error_tests/pas_inquiry_error_test.rb +38 -0
  19. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/error_tests/pas_submission_error_test.rb +56 -0
  20. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/must_support/device_request_metadata.yml +112 -0
  21. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/must_support/medication_request_metadata.yml +183 -0
  22. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/must_support/nutrition_order_metadata.yml +109 -0
  23. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/must_support/pas_client_must_support_requirement_test.rb +117 -0
  24. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/must_support/pas_server_must_support_requirement_test.rb +116 -0
  25. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/must_support/service_request_metadata.yml +148 -0
  26. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_approval_group.rb +26 -0
  27. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_authentication_group.rb +49 -0
  28. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_denial_group.rb +41 -0
  29. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_pended_group.rb +56 -0
  30. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_error_group.rb +20 -0
  31. data/lib/davinci_pas_test_kit/ext/inferno_core/record_response_route.rb +98 -0
  32. data/lib/davinci_pas_test_kit/ext/inferno_core/request.rb +19 -0
  33. data/lib/davinci_pas_test_kit/ext/inferno_core/runnable.rb +18 -0
  34. data/lib/davinci_pas_test_kit/fhir_resource_navigation.rb +72 -0
  35. data/lib/davinci_pas_test_kit/generated/v2.0.1/beneficiary/client_inquiry_request_beneficiary_must_support_test.rb +75 -0
  36. data/lib/davinci_pas_test_kit/generated/v2.0.1/beneficiary/client_submit_request_beneficiary_must_support_test.rb +75 -0
  37. data/lib/davinci_pas_test_kit/generated/v2.0.1/beneficiary/metadata.yml +162 -0
  38. data/lib/davinci_pas_test_kit/generated/v2.0.1/beneficiary/server_inquiry_request_beneficiary_must_support_test.rb +75 -0
  39. data/lib/davinci_pas_test_kit/generated/v2.0.1/beneficiary/server_inquiry_response_beneficiary_must_support_test.rb +75 -0
  40. data/lib/davinci_pas_test_kit/generated/v2.0.1/beneficiary/server_submit_request_beneficiary_must_support_test.rb +75 -0
  41. data/lib/davinci_pas_test_kit/generated/v2.0.1/beneficiary/server_submit_response_beneficiary_must_support_test.rb +75 -0
  42. data/lib/davinci_pas_test_kit/generated/v2.0.1/claim/claim_operation_test.rb +67 -0
  43. data/lib/davinci_pas_test_kit/generated/v2.0.1/claim/metadata.yml +577 -0
  44. data/lib/davinci_pas_test_kit/generated/v2.0.1/claim_inquiry/claim_inquiry_operation_test.rb +57 -0
  45. data/lib/davinci_pas_test_kit/generated/v2.0.1/claim_inquiry/client_inquiry_request_claim_inquiry_must_support_test.rb +95 -0
  46. data/lib/davinci_pas_test_kit/generated/v2.0.1/claim_inquiry/metadata.yml +516 -0
  47. data/lib/davinci_pas_test_kit/generated/v2.0.1/claim_inquiry/server_inquiry_request_claim_inquiry_must_support_test.rb +95 -0
  48. data/lib/davinci_pas_test_kit/generated/v2.0.1/claim_update/client_submit_request_claim_update_must_support_test.rb +102 -0
  49. data/lib/davinci_pas_test_kit/generated/v2.0.1/claim_update/metadata.yml +591 -0
  50. data/lib/davinci_pas_test_kit/generated/v2.0.1/claim_update/server_submit_request_claim_update_must_support_test.rb +102 -0
  51. data/lib/davinci_pas_test_kit/generated/v2.0.1/claiminquiryresponse/metadata.yml +311 -0
  52. data/lib/davinci_pas_test_kit/generated/v2.0.1/claiminquiryresponse/server_inquiry_response_claiminquiryresponse_must_support_test.rb +73 -0
  53. data/lib/davinci_pas_test_kit/generated/v2.0.1/claimresponse/metadata.yml +318 -0
  54. data/lib/davinci_pas_test_kit/generated/v2.0.1/claimresponse/server_submit_response_claimresponse_must_support_test.rb +75 -0
  55. data/lib/davinci_pas_test_kit/generated/v2.0.1/client_tests/client_denial_pas_response_bundle_validation_test.rb +53 -0
  56. data/lib/davinci_pas_test_kit/generated/v2.0.1/client_tests/client_pas_request_bundle_validation_test.rb +55 -0
  57. data/lib/davinci_pas_test_kit/generated/v2.0.1/client_tests/client_pended_pas_inquiry_request_bundle_validation_test.rb +55 -0
  58. data/lib/davinci_pas_test_kit/generated/v2.0.1/client_tests/client_pended_pas_response_bundle_validation_test.rb +53 -0
  59. data/lib/davinci_pas_test_kit/generated/v2.0.1/communication_request/metadata.yml +130 -0
  60. data/lib/davinci_pas_test_kit/generated/v2.0.1/communication_request/server_submit_response_communication_request_must_support_test.rb +58 -0
  61. data/lib/davinci_pas_test_kit/generated/v2.0.1/coverage/client_inquiry_request_coverage_must_support_test.rb +55 -0
  62. data/lib/davinci_pas_test_kit/generated/v2.0.1/coverage/client_submit_request_coverage_must_support_test.rb +55 -0
  63. data/lib/davinci_pas_test_kit/generated/v2.0.1/coverage/metadata.yml +111 -0
  64. data/lib/davinci_pas_test_kit/generated/v2.0.1/coverage/server_inquiry_request_coverage_must_support_test.rb +55 -0
  65. data/lib/davinci_pas_test_kit/generated/v2.0.1/coverage/server_submit_request_coverage_must_support_test.rb +55 -0
  66. data/lib/davinci_pas_test_kit/generated/v2.0.1/device_request/client_submit_request_device_request_must_support_test.rb +51 -0
  67. data/lib/davinci_pas_test_kit/generated/v2.0.1/device_request/metadata.yml +112 -0
  68. data/lib/davinci_pas_test_kit/generated/v2.0.1/device_request/server_submit_request_device_request_must_support_test.rb +51 -0
  69. data/lib/davinci_pas_test_kit/generated/v2.0.1/encounter/client_submit_request_encounter_must_support_test.rb +67 -0
  70. data/lib/davinci_pas_test_kit/generated/v2.0.1/encounter/metadata.yml +213 -0
  71. data/lib/davinci_pas_test_kit/generated/v2.0.1/encounter/server_submit_request_encounter_must_support_test.rb +67 -0
  72. data/lib/davinci_pas_test_kit/generated/v2.0.1/insurer/client_inquiry_request_insurer_must_support_test.rb +60 -0
  73. data/lib/davinci_pas_test_kit/generated/v2.0.1/insurer/client_submit_request_insurer_must_support_test.rb +60 -0
  74. data/lib/davinci_pas_test_kit/generated/v2.0.1/insurer/metadata.yml +104 -0
  75. data/lib/davinci_pas_test_kit/generated/v2.0.1/insurer/server_inquiry_request_insurer_must_support_test.rb +60 -0
  76. data/lib/davinci_pas_test_kit/generated/v2.0.1/insurer/server_inquiry_response_insurer_must_support_test.rb +60 -0
  77. data/lib/davinci_pas_test_kit/generated/v2.0.1/insurer/server_submit_request_insurer_must_support_test.rb +60 -0
  78. data/lib/davinci_pas_test_kit/generated/v2.0.1/insurer/server_submit_response_insurer_must_support_test.rb +60 -0
  79. data/lib/davinci_pas_test_kit/generated/v2.0.1/medication_request/client_submit_request_medication_request_must_support_test.rb +61 -0
  80. data/lib/davinci_pas_test_kit/generated/v2.0.1/medication_request/metadata.yml +183 -0
  81. data/lib/davinci_pas_test_kit/generated/v2.0.1/medication_request/server_submit_request_medication_request_must_support_test.rb +61 -0
  82. data/lib/davinci_pas_test_kit/generated/v2.0.1/metadata.yml +5253 -0
  83. data/lib/davinci_pas_test_kit/generated/v2.0.1/nutrition_order/client_submit_request_nutrition_order_must_support_test.rb +53 -0
  84. data/lib/davinci_pas_test_kit/generated/v2.0.1/nutrition_order/metadata.yml +109 -0
  85. data/lib/davinci_pas_test_kit/generated/v2.0.1/nutrition_order/server_submit_request_nutrition_order_must_support_test.rb +53 -0
  86. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_client_inquiry_must_support_use_case_group.rb +51 -0
  87. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_client_submit_must_support_use_case_group.rb +61 -0
  88. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_request_bundle/client_inquiry_request_pas_inquiry_request_bundle_must_support_test.rb +53 -0
  89. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_request_bundle/metadata.yml +77 -0
  90. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_request_bundle/server_inquiry_request_pas_inquiry_request_bundle_must_support_test.rb +53 -0
  91. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_request_bundle/server_pas_inquiry_request_bundle_validation_test.rb +83 -0
  92. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_response_bundle/metadata.yml +67 -0
  93. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_response_bundle/server_inquiry_response_pas_inquiry_response_bundle_must_support_test.rb +52 -0
  94. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_response_bundle/server_pas_inquiry_response_bundle_validation_test.rb +80 -0
  95. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_request_bundle/client_submit_request_pas_request_bundle_must_support_test.rb +53 -0
  96. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_request_bundle/metadata.yml +77 -0
  97. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_request_bundle/server_pas_request_bundle_validation_test.rb +83 -0
  98. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_request_bundle/server_submit_request_pas_request_bundle_must_support_test.rb +53 -0
  99. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_response_bundle/metadata.yml +71 -0
  100. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_response_bundle/server_pas_response_bundle_validation_test.rb +80 -0
  101. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_response_bundle/server_submit_response_pas_response_bundle_must_support_test.rb +52 -0
  102. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_server_approval_use_case_group.rb +59 -0
  103. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_server_denial_use_case_group.rb +59 -0
  104. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_server_must_support_use_case_group.rb +265 -0
  105. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_server_pended_use_case_group.rb +84 -0
  106. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner/client_inquiry_request_practitioner_must_support_test.rb +53 -0
  107. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner/client_submit_request_practitioner_must_support_test.rb +53 -0
  108. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner/metadata.yml +74 -0
  109. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner/server_inquiry_request_practitioner_must_support_test.rb +53 -0
  110. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner/server_inquiry_response_practitioner_must_support_test.rb +53 -0
  111. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner/server_submit_request_practitioner_must_support_test.rb +53 -0
  112. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner/server_submit_response_practitioner_must_support_test.rb +53 -0
  113. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner_role/client_inquiry_request_practitioner_role_must_support_test.rb +49 -0
  114. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner_role/client_submit_request_practitioner_role_must_support_test.rb +49 -0
  115. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner_role/metadata.yml +81 -0
  116. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner_role/server_inquiry_request_practitioner_role_must_support_test.rb +49 -0
  117. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner_role/server_inquiry_response_practitioner_role_must_support_test.rb +49 -0
  118. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner_role/server_submit_request_practitioner_role_must_support_test.rb +49 -0
  119. data/lib/davinci_pas_test_kit/generated/v2.0.1/practitioner_role/server_submit_response_practitioner_role_must_support_test.rb +49 -0
  120. data/lib/davinci_pas_test_kit/generated/v2.0.1/requestor/client_inquiry_request_requestor_must_support_test.rb +63 -0
  121. data/lib/davinci_pas_test_kit/generated/v2.0.1/requestor/client_submit_request_requestor_must_support_test.rb +63 -0
  122. data/lib/davinci_pas_test_kit/generated/v2.0.1/requestor/metadata.yml +107 -0
  123. data/lib/davinci_pas_test_kit/generated/v2.0.1/requestor/server_inquiry_request_requestor_must_support_test.rb +63 -0
  124. data/lib/davinci_pas_test_kit/generated/v2.0.1/requestor/server_inquiry_response_requestor_must_support_test.rb +63 -0
  125. data/lib/davinci_pas_test_kit/generated/v2.0.1/requestor/server_submit_request_requestor_must_support_test.rb +63 -0
  126. data/lib/davinci_pas_test_kit/generated/v2.0.1/requestor/server_submit_response_requestor_must_support_test.rb +63 -0
  127. data/lib/davinci_pas_test_kit/generated/v2.0.1/resource_list.rb +54 -0
  128. data/lib/davinci_pas_test_kit/generated/v2.0.1/server_suite.rb +236 -0
  129. data/lib/davinci_pas_test_kit/generated/v2.0.1/service_request/client_submit_request_service_request_must_support_test.rb +53 -0
  130. data/lib/davinci_pas_test_kit/generated/v2.0.1/service_request/metadata.yml +148 -0
  131. data/lib/davinci_pas_test_kit/generated/v2.0.1/service_request/server_submit_request_service_request_must_support_test.rb +53 -0
  132. data/lib/davinci_pas_test_kit/generated/v2.0.1/subscriber/client_inquiry_request_subscriber_must_support_test.rb +74 -0
  133. data/lib/davinci_pas_test_kit/generated/v2.0.1/subscriber/client_submit_request_subscriber_must_support_test.rb +74 -0
  134. data/lib/davinci_pas_test_kit/generated/v2.0.1/subscriber/metadata.yml +159 -0
  135. data/lib/davinci_pas_test_kit/generated/v2.0.1/subscriber/server_inquiry_request_subscriber_must_support_test.rb +74 -0
  136. data/lib/davinci_pas_test_kit/generated/v2.0.1/subscriber/server_submit_request_subscriber_must_support_test.rb +74 -0
  137. data/lib/davinci_pas_test_kit/generated/v2.0.1/task/metadata.yml +192 -0
  138. data/lib/davinci_pas_test_kit/generated/v2.0.1/task/server_inquiry_response_task_must_support_test.rb +61 -0
  139. data/lib/davinci_pas_test_kit/generated/v2.0.1/task/server_submit_response_task_must_support_test.rb +61 -0
  140. data/lib/davinci_pas_test_kit/generator/group_generator.rb +440 -0
  141. data/lib/davinci_pas_test_kit/generator/group_metadata.rb +73 -0
  142. data/lib/davinci_pas_test_kit/generator/group_metadata_extractor.rb +244 -0
  143. data/lib/davinci_pas_test_kit/generator/ig_loader.rb +78 -0
  144. data/lib/davinci_pas_test_kit/generator/ig_metadata.rb +66 -0
  145. data/lib/davinci_pas_test_kit/generator/ig_metadata_extractor.rb +54 -0
  146. data/lib/davinci_pas_test_kit/generator/ig_resources.rb +74 -0
  147. data/lib/davinci_pas_test_kit/generator/must_support_check_profiles.rb +86 -0
  148. data/lib/davinci_pas_test_kit/generator/must_support_metadata_extractor.rb +327 -0
  149. data/lib/davinci_pas_test_kit/generator/must_support_test_generator.rb +155 -0
  150. data/lib/davinci_pas_test_kit/generator/naming.rb +50 -0
  151. data/lib/davinci_pas_test_kit/generator/operation_test_generator.rb +136 -0
  152. data/lib/davinci_pas_test_kit/generator/resource_list_generator.rb +59 -0
  153. data/lib/davinci_pas_test_kit/generator/suite_generator.rb +94 -0
  154. data/lib/davinci_pas_test_kit/generator/terminology_binding_metadata_extractor.rb +108 -0
  155. data/lib/davinci_pas_test_kit/generator/validation_test_generator.rb +181 -0
  156. data/lib/davinci_pas_test_kit/generator/value_extractor.rb +48 -0
  157. data/lib/davinci_pas_test_kit/generator.rb +80 -0
  158. data/lib/davinci_pas_test_kit/mock_server.rb +189 -0
  159. data/lib/davinci_pas_test_kit/must_support_test.rb +267 -0
  160. data/lib/davinci_pas_test_kit/pas_bundle_validation.rb +568 -0
  161. data/lib/davinci_pas_test_kit/tags.rb +7 -0
  162. data/lib/davinci_pas_test_kit/urls.rb +39 -0
  163. data/lib/davinci_pas_test_kit/user_input_response.rb +32 -0
  164. data/lib/davinci_pas_test_kit/validation_test.rb +58 -0
  165. data/lib/davinci_pas_test_kit/validator_suppressions.rb +143 -0
  166. data/lib/davinci_pas_test_kit/version.rb +5 -0
  167. data/lib/davinci_pas_test_kit.rb +2 -0
  168. metadata +281 -0
@@ -0,0 +1,327 @@
1
+ require 'pry'
2
+ require_relative 'value_extractor'
3
+
4
+ module DaVinciPASTestKit
5
+ class Generator
6
+ class MustSupportMetadataExtractor
7
+ attr_accessor :profile_elements, :profile, :resource, :ig_resources
8
+
9
+ def initialize(profile_elements, profile, resource, ig_resources)
10
+ self.profile_elements = profile_elements
11
+ self.profile = profile
12
+ self.resource = resource
13
+ self.ig_resources = ig_resources
14
+ end
15
+
16
+ def must_supports
17
+ @must_supports = {
18
+ extensions: must_support_extensions,
19
+ slices: must_support_slices,
20
+ elements: must_support_elements
21
+ }
22
+
23
+ @must_supports
24
+ end
25
+
26
+ def all_must_support_elements
27
+ profile_elements.select(&:mustSupport)
28
+ end
29
+
30
+ def must_support_extension_elements
31
+ all_must_support_elements.select { |element| element.path.end_with? 'extension' }
32
+ end
33
+
34
+ def must_support_extensions
35
+ must_support_extension_elements.map do |element|
36
+ {
37
+ id: element.id,
38
+ path: element.path.gsub("#{resource}.", ''),
39
+ url: element.type.first.profile.first
40
+ }
41
+ end
42
+ end
43
+
44
+ def must_support_slice_elements
45
+ all_must_support_elements.select do |element|
46
+ !element.path.end_with?('extension') && element.sliceName.present?
47
+ end
48
+ end
49
+
50
+ def sliced_element(slice)
51
+ profile_elements.find { |element| element.id == slice.path }
52
+ end
53
+
54
+ def discriminators(slice)
55
+ slice.slicing.discriminator
56
+ end
57
+
58
+ def must_support_pattern_slice_elements
59
+ must_support_slice_elements.select do |element|
60
+ discriminators(sliced_element(element)).first.type == 'pattern' unless sliced_element(element).slicing.nil?
61
+ end
62
+ end
63
+
64
+ def pattern_slices
65
+ must_support_pattern_slice_elements.map do |current_element|
66
+ {
67
+ name: current_element.id,
68
+ path: current_element.path.gsub("#{resource}.", '')
69
+ }.tap do |metadata|
70
+ discriminator = discriminators(sliced_element(current_element)).first
71
+ discriminator_path = discriminator.path
72
+ discriminator_path = '' if discriminator_path == '$this'
73
+ pattern_element =
74
+ if discriminator_path.present?
75
+ profile_elements.find { |element| element.id == "#{current_element.id}.#{discriminator_path}" }
76
+ else
77
+ current_element
78
+ end
79
+
80
+ metadata[:discriminator] =
81
+ if pattern_element.patternCodeableConcept.present?
82
+ {
83
+ type: 'patternCodeableConcept',
84
+ path: discriminator_path,
85
+ code: pattern_element.patternCodeableConcept.coding.first.code,
86
+ system: pattern_element.patternCodeableConcept.coding.first.system
87
+ }
88
+ elsif pattern_element.patternCoding.present?
89
+ {
90
+ type: 'patternCoding',
91
+ path: discriminator_path,
92
+ code: pattern_element.patternCoding.code,
93
+ system: pattern_element.patternCoding.system
94
+ }
95
+ elsif pattern_element.patternIdentifier.present?
96
+ {
97
+ type: 'patternIdentifier',
98
+ path: discriminator_path,
99
+ system: pattern_element.patternIdentifier.system
100
+ }
101
+ elsif pattern_element.binding&.strength == 'required' &&
102
+ pattern_element.binding&.valueSet.present?
103
+
104
+ value_extractor = ValueExactor.new(ig_resources, resource)
105
+
106
+ values = value_extractor.values_from_value_set_binding(pattern_element).presence ||
107
+ value_extractor.values_from_resource_metadata([metadata[:path]]).presence || []
108
+
109
+ {
110
+ type: 'requiredBinding',
111
+ path: discriminator_path,
112
+ values:
113
+ }
114
+ else
115
+ raise StandardError, 'Unsupported discriminator pattern type'
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ def must_support_type_slice_elements
122
+ must_support_slice_elements.select do |element|
123
+ discriminators(sliced_element(element)).first.type == 'type' unless sliced_element(element).slicing.nil?
124
+ end
125
+ end
126
+
127
+ def type_slices
128
+ must_support_type_slice_elements.map do |current_element|
129
+ discriminator = discriminators(sliced_element(current_element)).first
130
+ type_path = discriminator.path
131
+ type_path = '' if type_path == '$this'
132
+ type_element =
133
+ if type_path.present?
134
+ profile_elements.find { |element| element.id == "#{current_element.id}.#{type_path}" }
135
+ else
136
+ current_element
137
+ end
138
+
139
+ type_code = type_element.type.first.code
140
+
141
+ {
142
+ name: current_element.id,
143
+ path: current_element.path.gsub("#{resource}.", ''),
144
+ discriminator: {
145
+ type: 'type',
146
+ code: type_code.upcase_first
147
+ }
148
+ }
149
+ end
150
+ end
151
+
152
+ def must_support_value_slice_elements
153
+ must_support_slice_elements.select do |element|
154
+ discriminators(sliced_element(element)).first.type == 'value' unless sliced_element(element).slicing.nil?
155
+ end
156
+ end
157
+
158
+ def value_slices
159
+ must_support_value_slice_elements.map do |current_element|
160
+ {
161
+ name: current_element.id,
162
+ path: current_element.path.gsub("#{resource}.", ''),
163
+ discriminator: {
164
+ type: 'value'
165
+ }
166
+ }.tap do |metadata|
167
+ metadata[:discriminator][:values] = discriminators(sliced_element(current_element)).map do |discriminator|
168
+ fixed_element = profile_elements.find do |element|
169
+ element.id.starts_with?(current_element.id) &&
170
+ element.path == "#{current_element.path}.#{discriminator.path}"
171
+ end
172
+
173
+ {
174
+ path: discriminator.path,
175
+ value: fixed_element&.fixedUri || fixed_element&.fixedCode
176
+ }
177
+ end
178
+ end
179
+ end
180
+ end
181
+
182
+ def must_support_slices
183
+ pattern_slices + type_slices + value_slices
184
+ end
185
+
186
+ def plain_must_support_elements
187
+ all_must_support_elements - must_support_extension_elements - must_support_slice_elements
188
+ end
189
+
190
+ def handle_fixed_values(metadata, element)
191
+ if element.fixedUri.present?
192
+ metadata[:fixed_value] = element.fixedUri
193
+ elsif element.patternCodeableConcept.present?
194
+ metadata[:fixed_value] = element.patternCodeableConcept.coding.first.code
195
+ metadata[:path] += '.coding.code'
196
+ elsif element.fixedCode.present?
197
+ metadata[:fixed_value] = element.fixedCode
198
+ elsif element.patternIdentifier.present?
199
+ metadata[:fixed_value] = element.patternIdentifier.system
200
+ metadata[:path] += '.system'
201
+ end
202
+ end
203
+
204
+ def type_must_support_extension?(extensions)
205
+ extensions&.any? do |extension|
206
+ extension.url == 'http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support' &&
207
+ extension.valueBoolean
208
+ end
209
+ end
210
+
211
+ def save_type_code?(type)
212
+ type.code == 'Reference'
213
+ end
214
+
215
+ def get_type_must_support_metadata(current_metadata, current_element)
216
+ current_element.type.map do |type|
217
+ next unless type_must_support_extension?(type.extension)
218
+
219
+ metadata =
220
+ {
221
+ path: "#{current_metadata[:path].delete_suffix('[x]')}#{type.code.upcase_first}",
222
+ original_path: current_metadata[:path]
223
+ }
224
+ metadata[:type] = [type.code] if save_type_code?(type)
225
+ handle_type_must_support_target_profiles(type, metadata) if type.code == 'Reference'
226
+
227
+ metadata
228
+ end.compact
229
+ end
230
+
231
+ def handle_type_must_support_target_profiles(type, metadata)
232
+ index = 0
233
+ target_profiles = []
234
+
235
+ type.source_hash['_targetProfile']&.each do |hash|
236
+ if hash.present?
237
+ element = FHIR::Element.new(hash)
238
+ target_profiles << type.targetProfile[index] if type_must_support_extension?(element.extension)
239
+ end
240
+ index += 1
241
+ end
242
+
243
+ metadata[:target_profiles] = target_profiles if target_profiles.present?
244
+ end
245
+
246
+ def handle_choice_type_in_sliced_element(current_metadata, must_support_elements_metadata)
247
+ choice_element_metadata = must_support_elements_metadata.find do |metadata|
248
+ metadata[:original_path].present? &&
249
+ current_metadata[:path].include?(metadata[:original_path])
250
+ end
251
+
252
+ return unless choice_element_metadata.present?
253
+
254
+ current_metadata[:original_path] = current_metadata[:path]
255
+ current_metadata[:path] =
256
+ current_metadata[:path].sub(choice_element_metadata[:original_path], choice_element_metadata[:path])
257
+ end
258
+
259
+ def must_support_elements
260
+ plain_must_support_elements.each_with_object([]) do |current_element, must_support_elements_metadata|
261
+ {
262
+ path: current_element.path.gsub("#{resource}.", '')
263
+ }.tap do |current_metadata|
264
+ type_must_support_metadata = get_type_must_support_metadata(current_metadata, current_element)
265
+
266
+ if type_must_support_metadata.any?
267
+ must_support_elements_metadata.concat(type_must_support_metadata)
268
+ else
269
+ handle_choice_type_in_sliced_element(current_metadata, must_support_elements_metadata)
270
+
271
+ supported_types = current_element.type.select { |type| save_type_code?(type) }.map(&:code)
272
+ current_metadata[:types] = supported_types if supported_types.present?
273
+
274
+ if current_element.type.first&.code == 'Reference'
275
+ handle_type_must_support_target_profiles(current_element.type.first,
276
+ current_metadata)
277
+ end
278
+
279
+ handle_fixed_values(current_metadata, current_element)
280
+
281
+ must_support_elements_metadata.delete_if do |metadata|
282
+ metadata[:path] == current_metadata[:path] && metadata[:fixed_value].blank?
283
+ end
284
+
285
+ must_support_elements_metadata << current_metadata
286
+ end
287
+ end
288
+ end.uniq
289
+ end
290
+
291
+ #### SPECIAL CASE ####
292
+
293
+ def vital_sign?
294
+ [
295
+ 'http://hl7.org/fhir/StructureDefinition/vitalsigns',
296
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-vital-signs'
297
+ ].include?(profile.baseDefinition)
298
+ end
299
+
300
+ def blood_pressure?
301
+ ['observation-bp', 'USCoreBloodPressureProfile'].include?(profile.name)
302
+ end
303
+
304
+ # ONC and US Core 4.0.0 both clarified that health IT developers that always provide HL7 FHIR "observation" values
305
+ # are not required to demonstrate Health IT Module support for "dataAbsentReason" elements.
306
+ # Remove MS check for dataAbsentReason and component.dataAbsentReason from vital sign profiles and observation lab
307
+ # profile.
308
+ # Smoking status profile does not have MS on dataAbsentReason. It is safe to use profile.type == 'Observation'
309
+
310
+ def remove_device_carrier
311
+ return unless profile.type == 'Device'
312
+
313
+ @must_supports[:elements].delete_if do |element|
314
+ ['udiCarrier.carrierAIDC', 'udiCarrier.carrierHRF'].include?(element[:path])
315
+ end
316
+ end
317
+
318
+ def remove_document_reference_attachment_data_url
319
+ return unless profile.type == 'DocumentReference'
320
+
321
+ @must_supports[:elements].delete_if do |element|
322
+ ['content.attachment.data', 'content.attachment.url'].include?(element[:path])
323
+ end
324
+ end
325
+ end
326
+ end
327
+ end
@@ -0,0 +1,155 @@
1
+ require 'pry'
2
+ require_relative 'naming'
3
+ require_relative 'must_support_check_profiles'
4
+
5
+ module DaVinciPASTestKit
6
+ class Generator
7
+ class MustSupportTestGenerator
8
+ class << self
9
+ def generate(ig_metadata, base_output_dir)
10
+ submit_request_groups = ig_metadata.groups.select do |group|
11
+ MustSupportCheckProfiles.submit_request_group?(group)
12
+ end
13
+ submit_response_groups = ig_metadata.groups.select do |group|
14
+ MustSupportCheckProfiles.submit_response_group?(group)
15
+ end
16
+ inquiry_request_groups = ig_metadata.groups.select do |group|
17
+ MustSupportCheckProfiles.inquiry_request_group?(group)
18
+ end
19
+ inquiry_response_groups = ig_metadata.groups.select do |group|
20
+ MustSupportCheckProfiles.inquiry_response_group?(group)
21
+ end
22
+
23
+ submit_request_groups.each do |group|
24
+ new(group, base_output_dir, 'submit_request').generate
25
+ new(group, base_output_dir, 'submit_request', 'client').generate
26
+ end
27
+ submit_response_groups.each { |group| new(group, base_output_dir, 'submit_response').generate }
28
+
29
+ inquiry_request_groups.each do |group|
30
+ new(group, base_output_dir, 'inquiry_request').generate
31
+ new(group, base_output_dir, 'inquiry_request', 'client').generate
32
+ end
33
+ inquiry_response_groups.each { |group| new(group, base_output_dir, 'inquiry_response').generate }
34
+ end
35
+ end
36
+
37
+ attr_accessor :group_metadata, :base_output_dir, :request_type, :system
38
+
39
+ def initialize(group_metadata, base_output_dir, request_type, system = 'server')
40
+ self.group_metadata = group_metadata
41
+ self.base_output_dir = base_output_dir
42
+ self.request_type = request_type
43
+ self.system = system
44
+ end
45
+
46
+ def template
47
+ @template ||= File.read(File.join(__dir__, 'templates', 'must_support.rb.erb'))
48
+ end
49
+
50
+ def output
51
+ @output ||= ERB.new(template).result(binding)
52
+ end
53
+
54
+ def base_output_file_name
55
+ "#{class_name.underscore}.rb"
56
+ end
57
+
58
+ def output_file_directory
59
+ File.join(base_output_dir, profile_identifier)
60
+ end
61
+
62
+ def output_file_name
63
+ File.join(output_file_directory, base_output_file_name)
64
+ end
65
+
66
+ def read_interaction
67
+ self.class.read_interaction(group_metadata)
68
+ end
69
+
70
+ def profile_identifier
71
+ Naming.snake_case_for_profile(group_metadata)
72
+ end
73
+
74
+ def test_id
75
+ "pas_#{system}_#{request_type}_#{group_metadata.reformatted_version}_#{profile_identifier}_must_support_test"
76
+ end
77
+
78
+ def class_name
79
+ # rubocop:disable Layout/LineLength
80
+ "#{system.capitalize}#{request_type.camelize}#{Naming.upper_camel_case_for_profile(group_metadata)}MustSupportTest"
81
+ # rubocop:enable Layout/LineLength
82
+ end
83
+
84
+ def module_name
85
+ "DaVinciPAS#{group_metadata.reformatted_version.upcase}"
86
+ end
87
+
88
+ def resource_type
89
+ group_metadata.resource
90
+ end
91
+
92
+ def profile_name
93
+ group_metadata.profile_name
94
+ end
95
+
96
+ def resource_collection_string
97
+ 'all_scratch_resources'
98
+ end
99
+
100
+ def must_support_list_string
101
+ build_must_support_list_string(false)
102
+ end
103
+
104
+ def uscdi_list_string
105
+ build_must_support_list_string(true)
106
+ end
107
+
108
+ def build_must_support_list_string(uscdi_only)
109
+ slice_names = group_metadata.must_supports[:slices]
110
+ .select { |slice| slice[:uscdi_only].presence == uscdi_only.presence }
111
+ .map { |slice| slice[:name] }
112
+
113
+ element_names = group_metadata.must_supports[:elements]
114
+ .select { |element| element[:uscdi_only].presence == uscdi_only.presence }
115
+ .map { |element| "#{resource_type}.#{element[:path]}" }
116
+
117
+ extension_names = group_metadata.must_supports[:extensions]
118
+ .select { |extension| extension[:uscdi_only].presence == uscdi_only.presence }
119
+ .map { |extension| extension[:id] }
120
+
121
+ group_metadata.must_supports[:choices]&.each do |choice|
122
+ next unless choice[:uscdi_only].presence == uscdi_only.presence && choice.key?(:paths)
123
+
124
+ choice[:paths].each { |path| element_names.delete("#{resource_type}.#{path}") }
125
+ choice[:extension_ids].each { |id| extension_names.delete(id.to_s) } if choice[:extension_ids].present?
126
+
127
+ element_paths = choice[:paths].map { |path| "#{resource_type}.#{path}" }.join(' or ')
128
+ extension_ids = choice[:extension_ids].map(&:to_s).join(' or ')
129
+
130
+ element_names << ("#{element_paths} or #{extension_ids}")
131
+ end
132
+
133
+ (slice_names + element_names + extension_names)
134
+ .uniq
135
+ .sort
136
+ .map { |name| "#{' ' * 8}* #{name}" }
137
+ .join("\n")
138
+ end
139
+
140
+ def optional?
141
+ MustSupportCheckProfiles.optional_group?(group_metadata)
142
+ end
143
+
144
+ def generate
145
+ FileUtils.mkdir_p(output_file_directory)
146
+ File.write(output_file_name, output)
147
+
148
+ group_metadata.add_test(
149
+ id: test_id,
150
+ file_name: base_output_file_name
151
+ )
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,50 @@
1
+ require 'pry'
2
+ require_relative '../generated/v2.0.1/resource_list'
3
+
4
+ module DaVinciPASTestKit
5
+ class Generator
6
+ module Naming
7
+ class << self
8
+ include DaVinciPASTestKit::PASV201::ResourceList
9
+ def resources_with_multiple_profiles
10
+ resources = []
11
+ RESOURCE_SUPPORTED_PROFILES.each do |resource, profile_list|
12
+ resources << resource.to_s if profile_list.length > 1
13
+ end
14
+ resources
15
+ end
16
+
17
+ def resource_has_multiple_profiles?(resource)
18
+ resources_with_multiple_profiles.include? resource
19
+ end
20
+
21
+ def request_type_for_bundle_or_claim
22
+ {
23
+ 'PAS Request Bundle' => 'submit_request',
24
+ 'PAS Response Bundle' => 'submit_response',
25
+ 'PAS Inquiry Request Bundle' => 'inquire_request',
26
+ 'PAS Inquiry Response Bundle' => 'inquire_response',
27
+ 'PAS Claim' => 'submit_request',
28
+ 'PAS Claim Response' => 'submit_response',
29
+ 'PAS Claim Inquiry' => 'inquire_request',
30
+ 'PAS Claim Inquiry Response' => 'inquire_response',
31
+ 'PAS Claim Update' => 'update_request'
32
+ }
33
+ end
34
+
35
+ def snake_case_for_profile(group_metadata)
36
+ resource = group_metadata.resource
37
+ return resource.underscore unless resource_has_multiple_profiles?(resource)
38
+
39
+ group_metadata.name
40
+ .delete_prefix('profile_')
41
+ .underscore
42
+ end
43
+
44
+ def upper_camel_case_for_profile(group_metadata)
45
+ snake_case_for_profile(group_metadata).camelize
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,136 @@
1
+ require 'pry'
2
+ require_relative 'naming'
3
+
4
+ module DaVinciPASTestKit
5
+ class Generator
6
+ class OperationTestGenerator
7
+ class << self
8
+ def generate(ig_metadata, base_output_dir)
9
+ ig_metadata.claim_groups
10
+ .reject { |group| group.name.include?('update') }
11
+ .each do |group|
12
+ new(group, base_output_dir:).generate
13
+ end
14
+ end
15
+ end
16
+
17
+ attr_accessor :group_metadata, :medication_request_metadata, :base_output_dir
18
+
19
+ def initialize(group_metadata, medication_request_metadata = nil, base_output_dir:)
20
+ self.group_metadata = group_metadata
21
+ self.medication_request_metadata = medication_request_metadata
22
+ self.base_output_dir = base_output_dir
23
+ end
24
+
25
+ def template
26
+ @template ||= File.read(File.join(__dir__, 'templates', 'operation.rb.erb'))
27
+ end
28
+
29
+ def output
30
+ @output ||= ERB.new(template).result(binding)
31
+ end
32
+
33
+ def base_output_file_name
34
+ "#{class_name.underscore}.rb"
35
+ end
36
+
37
+ def output_file_directory
38
+ File.join(base_output_dir, directory_name)
39
+ end
40
+
41
+ def output_file_name
42
+ File.join(output_file_directory, base_output_file_name)
43
+ end
44
+
45
+ def directory_name
46
+ Naming.snake_case_for_profile(medication_request_metadata || group_metadata)
47
+ end
48
+
49
+ def profile_identifier
50
+ Naming.snake_case_for_profile(group_metadata)
51
+ end
52
+
53
+ def profile_url
54
+ group_metadata.profile_url
55
+ end
56
+
57
+ def profile_name
58
+ group_metadata.profile_name
59
+ end
60
+
61
+ def profile_version
62
+ group_metadata.profile_version
63
+ end
64
+
65
+ def test_id
66
+ "pas_#{group_metadata.reformatted_version}_#{profile_identifier}_operation_test"
67
+ end
68
+
69
+ def class_name
70
+ "#{Naming.upper_camel_case_for_profile(group_metadata)}OperationTest"
71
+ end
72
+
73
+ def module_name
74
+ "DaVinciPAS#{group_metadata.reformatted_version.upcase}"
75
+ end
76
+
77
+ def resource_type
78
+ group_metadata.resource
79
+ end
80
+
81
+ def conformance_expectation
82
+ read_interaction[:expectation]
83
+ end
84
+
85
+ def skip_if_empty
86
+ # Return true if a system must demonstrate at least one example of the resource type.
87
+ # This drives omit vs. skip result statuses in this test.
88
+ resource_type != 'Medication'
89
+ end
90
+
91
+ def request_type
92
+ Naming.request_type_for_bundle_or_claim[profile_name]
93
+ end
94
+
95
+ def operation
96
+ operations = group_metadata.operations.map { |op| op[:code] }
97
+ operations.find { |op| request_type.include?(op.delete_prefix('$')) }
98
+ .to_s.delete_prefix('$')
99
+ end
100
+
101
+ def operation_name
102
+ case operation
103
+ when 'inquire'
104
+ 'Inquiry'
105
+ when 'submit'
106
+ 'Submit'
107
+ end
108
+ end
109
+
110
+ def generate
111
+ FileUtils.mkdir_p(output_file_directory)
112
+ File.write(output_file_name, output)
113
+
114
+ test_metadata = {
115
+ id: test_id,
116
+ file_name: base_output_file_name
117
+ }
118
+ group_metadata.add_test(**test_metadata)
119
+ end
120
+
121
+ def title
122
+ "Claim/$#{operation} Operation Test"
123
+ end
124
+
125
+ def description
126
+ <<~DESCRIPTION
127
+ Server SHALL support PAS #{operation_name} requests: a POST interaction to
128
+ the /Claim/$#{operation} endpoint.
129
+ This test submits a Prior Authorization #{operation_name} request to the server and verifies that a
130
+ response is returned with HTTP status 2XX.
131
+ #{operation == 'submit' ? 'The server SHOULD respond within 15 seconds.' : ''}
132
+ DESCRIPTION
133
+ end
134
+ end
135
+ end
136
+ end