servactory 2.16.1 → 3.0.0.rc1

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -9
  3. data/config/locales/de.yml +134 -0
  4. data/config/locales/en.yml +15 -0
  5. data/config/locales/es.yml +134 -0
  6. data/config/locales/fr.yml +134 -0
  7. data/config/locales/it.yml +134 -0
  8. data/config/locales/ru.yml +15 -0
  9. data/lib/generators/README.md +45 -0
  10. data/lib/generators/servactory/base.rb +82 -0
  11. data/lib/generators/servactory/extension/USAGE +54 -0
  12. data/lib/generators/servactory/extension/extension_generator.rb +41 -0
  13. data/lib/generators/servactory/extension/templates/extension.rb.tt +62 -0
  14. data/lib/generators/servactory/install/USAGE +27 -0
  15. data/lib/generators/servactory/install/install_generator.rb +94 -0
  16. data/lib/generators/servactory/{templates/services/application_service/base.rb → install/templates/application_service/base.rb.tt} +29 -19
  17. data/lib/generators/servactory/{templates/services/application_service/exceptions.rb → install/templates/application_service/exceptions.rb.tt} +1 -1
  18. data/lib/generators/servactory/{templates/services/application_service/result.rb → install/templates/application_service/result.rb.tt} +1 -1
  19. data/lib/generators/servactory/rspec/USAGE +46 -0
  20. data/lib/generators/servactory/rspec/rspec_generator.rb +95 -0
  21. data/lib/generators/servactory/rspec/templates/service_spec.rb.tt +58 -0
  22. data/lib/generators/servactory/service/USAGE +51 -0
  23. data/lib/generators/servactory/service/service_generator.rb +56 -0
  24. data/lib/generators/servactory/service/templates/service.rb.tt +22 -0
  25. data/lib/servactory/actions/collection.rb +56 -1
  26. data/lib/servactory/actions/dsl.rb +11 -11
  27. data/lib/servactory/actions/tools/rules.rb +1 -1
  28. data/lib/servactory/actions/tools/runner.rb +111 -28
  29. data/lib/servactory/base.rb +1 -7
  30. data/lib/servactory/configuration/actions/aliases/collection.rb +5 -0
  31. data/lib/servactory/configuration/actions/rescue_handlers/collection.rb +5 -0
  32. data/lib/servactory/configuration/actions/shortcuts/collection.rb +5 -0
  33. data/lib/servactory/configuration/collection_mode/class_names_collection.rb +5 -0
  34. data/lib/servactory/configuration/config.rb +36 -0
  35. data/lib/servactory/configuration/configurable.rb +95 -0
  36. data/lib/servactory/configuration/dsl.rb +3 -27
  37. data/lib/servactory/configuration/factory.rb +20 -20
  38. data/lib/servactory/configuration/hash_mode/class_names_collection.rb +5 -0
  39. data/lib/servactory/configuration/option_helpers/option_helpers_collection.rb +5 -0
  40. data/lib/servactory/context/warehouse/inputs.rb +2 -2
  41. data/lib/servactory/context/workspace/inputs.rb +2 -2
  42. data/lib/servactory/context/workspace/internals.rb +2 -2
  43. data/lib/servactory/context/workspace/outputs.rb +2 -2
  44. data/lib/servactory/context/workspace.rb +11 -7
  45. data/lib/servactory/dsl.rb +10 -8
  46. data/lib/servactory/maintenance/attributes/tools/validation.rb +1 -1
  47. data/lib/servactory/result.rb +2 -2
  48. data/lib/servactory/stroma/dsl.rb +118 -0
  49. data/lib/servactory/stroma/entry.rb +32 -0
  50. data/lib/servactory/stroma/exceptions/base.rb +45 -0
  51. data/lib/servactory/stroma/exceptions/invalid_hook_type.rb +29 -0
  52. data/lib/servactory/stroma/exceptions/key_already_registered.rb +32 -0
  53. data/lib/servactory/stroma/exceptions/registry_frozen.rb +33 -0
  54. data/lib/servactory/stroma/exceptions/registry_not_finalized.rb +33 -0
  55. data/lib/servactory/stroma/exceptions/unknown_hook_target.rb +39 -0
  56. data/lib/servactory/stroma/hooks/applier.rb +63 -0
  57. data/lib/servactory/stroma/hooks/collection.rb +103 -0
  58. data/lib/servactory/stroma/hooks/factory.rb +80 -0
  59. data/lib/servactory/stroma/hooks/hook.rb +74 -0
  60. data/lib/servactory/stroma/registry.rb +94 -0
  61. data/lib/servactory/stroma/settings/collection.rb +90 -0
  62. data/lib/servactory/stroma/settings/registry_settings.rb +88 -0
  63. data/lib/servactory/stroma/settings/setting.rb +113 -0
  64. data/lib/servactory/stroma/state.rb +59 -0
  65. data/lib/servactory/test_kit/fake_type.rb +23 -0
  66. data/lib/servactory/test_kit/result.rb +45 -0
  67. data/lib/servactory/test_kit/rspec/helpers/argument_matchers.rb +97 -0
  68. data/lib/servactory/test_kit/rspec/helpers/concerns/error_messages.rb +179 -0
  69. data/lib/servactory/test_kit/rspec/helpers/concerns/service_class_validation.rb +74 -0
  70. data/lib/servactory/test_kit/rspec/helpers/fluent.rb +110 -0
  71. data/lib/servactory/test_kit/rspec/helpers/input_validator.rb +149 -0
  72. data/lib/servactory/test_kit/rspec/helpers/legacy.rb +228 -0
  73. data/lib/servactory/test_kit/rspec/helpers/mock_executor.rb +256 -0
  74. data/lib/servactory/test_kit/rspec/helpers/output_validator.rb +121 -0
  75. data/lib/servactory/test_kit/rspec/helpers/service_mock_builder.rb +422 -0
  76. data/lib/servactory/test_kit/rspec/helpers/service_mock_config.rb +129 -0
  77. data/lib/servactory/test_kit/rspec/helpers.rb +51 -84
  78. data/lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb +324 -0
  79. data/lib/servactory/test_kit/rspec/matchers/base/submatcher.rb +133 -0
  80. data/lib/servactory/test_kit/rspec/matchers/base/submatcher_context.rb +101 -0
  81. data/lib/servactory/test_kit/rspec/matchers/base/submatcher_registry.rb +205 -0
  82. data/lib/servactory/test_kit/rspec/matchers/concerns/attribute_data_access.rb +100 -0
  83. data/lib/servactory/test_kit/rspec/matchers/concerns/error_message_builder.rb +106 -0
  84. data/lib/servactory/test_kit/rspec/matchers/concerns/value_comparison.rb +97 -0
  85. data/lib/servactory/test_kit/rspec/matchers/have_service_input_matcher.rb +89 -219
  86. data/lib/servactory/test_kit/rspec/matchers/have_service_internal_matcher.rb +74 -166
  87. data/lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb +238 -0
  88. data/lib/servactory/test_kit/rspec/matchers/result/be_failure_service_matcher.rb +257 -0
  89. data/lib/servactory/test_kit/rspec/matchers/result/be_success_service_matcher.rb +185 -0
  90. data/lib/servactory/test_kit/rspec/matchers/submatchers/input/default_submatcher.rb +81 -0
  91. data/lib/servactory/test_kit/rspec/matchers/submatchers/input/optional_submatcher.rb +62 -0
  92. data/lib/servactory/test_kit/rspec/matchers/submatchers/input/required_submatcher.rb +93 -0
  93. data/lib/servactory/test_kit/rspec/matchers/submatchers/input/valid_with_submatcher.rb +271 -0
  94. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/consists_of_submatcher.rb +85 -0
  95. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/inclusion_submatcher.rb +120 -0
  96. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/message_submatcher.rb +115 -0
  97. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/must_submatcher.rb +82 -0
  98. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/schema_submatcher.rb +102 -0
  99. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/target_submatcher.rb +125 -0
  100. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/types_submatcher.rb +77 -0
  101. data/lib/servactory/test_kit/rspec/matchers.rb +126 -285
  102. data/lib/servactory/test_kit/utils/faker.rb +62 -2
  103. data/lib/servactory/tool_kit/dynamic_options/consists_of.rb +166 -0
  104. data/lib/servactory/tool_kit/dynamic_options/format.rb +195 -8
  105. data/lib/servactory/tool_kit/dynamic_options/inclusion.rb +219 -17
  106. data/lib/servactory/tool_kit/dynamic_options/max.rb +143 -0
  107. data/lib/servactory/tool_kit/dynamic_options/min.rb +143 -0
  108. data/lib/servactory/tool_kit/dynamic_options/multiple_of.rb +157 -8
  109. data/lib/servactory/tool_kit/dynamic_options/must.rb +194 -0
  110. data/lib/servactory/tool_kit/dynamic_options/schema.rb +226 -2
  111. data/lib/servactory/tool_kit/dynamic_options/target.rb +252 -0
  112. data/lib/servactory/version.rb +4 -4
  113. data/lib/servactory.rb +4 -0
  114. metadata +73 -19
  115. data/lib/generators/servactory/install_generator.rb +0 -21
  116. data/lib/generators/servactory/rspec_generator.rb +0 -88
  117. data/lib/generators/servactory/service_generator.rb +0 -49
  118. data/lib/servactory/configuration/setup.rb +0 -97
  119. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/consists_of_matcher.rb +0 -68
  120. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/inclusion_matcher.rb +0 -73
  121. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/message_matcher.rb +0 -91
  122. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/must_matcher.rb +0 -72
  123. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/schema_matcher.rb +0 -92
  124. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/types_matcher.rb +0 -72
  125. data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/default_matcher.rb +0 -69
  126. data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/optional_matcher.rb +0 -63
  127. data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/required_matcher.rb +0 -81
  128. data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/valid_with_matcher.rb +0 -199
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module TestKit
5
- module Rspec
6
- module Matchers
7
- module HaveServiceAttributeMatchers
8
- class MustMatcher
9
- attr_reader :missing_option
10
-
11
- def initialize(described_class, attribute_type, attribute_name, must_names)
12
- @described_class = described_class
13
- @attribute_type = attribute_type
14
- @attribute_type_plural = attribute_type.to_s.pluralize.to_sym
15
- @attribute_name = attribute_name
16
- @must_names = must_names
17
-
18
- @attribute_data = described_class.info.public_send(attribute_type_plural).fetch(attribute_name)
19
-
20
- @missing_option = ""
21
- end
22
-
23
- def description
24
- "must: #{must_names.join(', ')}"
25
- end
26
-
27
- def matches?(subject)
28
- if submatcher_passes?(subject)
29
- true
30
- else
31
- @missing_option = build_missing_option
32
-
33
- false
34
- end
35
- end
36
-
37
- private
38
-
39
- attr_reader :described_class,
40
- :attribute_type,
41
- :attribute_type_plural,
42
- :attribute_name,
43
- :must_names,
44
- :attribute_data
45
-
46
- def submatcher_passes?(_subject)
47
- attribute_must = attribute_data.fetch(:must)
48
-
49
- attribute_must_keys = attribute_must.keys
50
-
51
- # NOTE: Even though the dynamic option `consists_of` is a `must`, here we are testing explicit `must`.
52
- attribute_must_keys.delete(:consists_of)
53
-
54
- # NOTE: Even though the dynamic option `schema` is a `must`, here we are testing explicit `must`.
55
- attribute_must_keys.delete(:schema)
56
-
57
- # NOTE: Even though the dynamic option `inclusion` is a `must`, here we are testing explicit `must`.
58
- attribute_must_keys.delete(:inclusion)
59
-
60
- attribute_must_keys.difference(must_names).empty? &&
61
- must_names.difference(attribute_must_keys).empty?
62
- end
63
-
64
- def build_missing_option
65
- "should #{must_names.join(', ')}"
66
- end
67
- end
68
- end
69
- end
70
- end
71
- end
72
- end
@@ -1,92 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module TestKit
5
- module Rspec
6
- module Matchers
7
- module HaveServiceAttributeMatchers
8
- class SchemaMatcher
9
- OPTION_NAME = :schema
10
- OPTION_BODY_KEY = :is
11
-
12
- attr_reader :missing_option
13
-
14
- def initialize(described_class, attribute_type, attribute_name, option_types, schema_data) # rubocop:disable Metrics/MethodLength
15
- @described_class = described_class
16
- @attribute_type = attribute_type
17
- @attribute_type_plural = attribute_type.to_s.pluralize.to_sym
18
- @attribute_name = attribute_name
19
- @option_types = option_types
20
- @schema_data = schema_data
21
-
22
- attribute_data = described_class.info.public_send(attribute_type_plural).fetch(attribute_name)
23
-
24
- attribute_schema = attribute_data.fetch(OPTION_NAME)
25
- @attribute_schema_is = attribute_schema.fetch(OPTION_BODY_KEY)
26
- @attribute_schema_message = attribute_schema.fetch(:message)
27
-
28
- @missing_option = ""
29
- end
30
-
31
- def description
32
- "schema: #{schema_data}"
33
- end
34
-
35
- def matches?(subject)
36
- if submatcher_passes?(subject)
37
- true
38
- else
39
- @missing_option = build_missing_option
40
-
41
- false
42
- end
43
- end
44
-
45
- private
46
-
47
- attr_reader :described_class,
48
- :attribute_type,
49
- :attribute_type_plural,
50
- :attribute_name,
51
- :option_types,
52
- :schema_data,
53
- :attribute_schema_is,
54
- :attribute_schema_message
55
-
56
- def submatcher_passes?(_subject)
57
- schema_data_equal?
58
- end
59
-
60
- def schema_data_equal? # rubocop:disable Metrics/MethodLength
61
- matcher_result =
62
- RSpec::Expectations::ExpectationHelper
63
- .with_matcher(
64
- RSpec::Expectations::PositiveExpectationHandler,
65
- RSpec::Matchers::BuiltIn::Match.new(schema_data),
66
- nil
67
- ) do |matcher|
68
- matcher.matches?(attribute_schema_is)
69
- end
70
-
71
- @schema_data_equal ||=
72
- (
73
- schema_data.present? && matcher_result
74
- ) || schema_data.blank?
75
- end
76
-
77
- def build_missing_option
78
- return if schema_data_equal?
79
-
80
- <<~MESSAGE
81
- should be schema with corresponding template
82
-
83
- expected #{attribute_schema_is.inspect}
84
- got #{schema_data.inspect}
85
- MESSAGE
86
- end
87
- end
88
- end
89
- end
90
- end
91
- end
92
- end
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module TestKit
5
- module Rspec
6
- module Matchers
7
- module HaveServiceAttributeMatchers
8
- class TypesMatcher
9
- attr_reader :missing_option
10
-
11
- def initialize(described_class, attribute_type, attribute_name, types)
12
- @described_class = described_class
13
- @attribute_type = attribute_type
14
- @attribute_type_plural = attribute_type.to_s.pluralize.to_sym
15
- @attribute_name = attribute_name
16
- @types = types
17
-
18
- @attribute_data = described_class.info.public_send(attribute_type_plural).fetch(attribute_name)
19
-
20
- @missing_option = ""
21
- end
22
-
23
- def description
24
- result = "type"
25
- result += types.size > 1 ? "s: " : ": "
26
- result + types.join(", ")
27
- end
28
-
29
- def matches?(subject)
30
- if submatcher_passes?(subject)
31
- true
32
- else
33
- @missing_option = build_missing_option
34
-
35
- false
36
- end
37
- end
38
-
39
- private
40
-
41
- attr_reader :described_class,
42
- :attribute_type,
43
- :attribute_type_plural,
44
- :attribute_name,
45
- :types,
46
- :attribute_data
47
-
48
- def submatcher_passes?(_subject)
49
- option_types = attribute_data.fetch(:types)
50
-
51
- option_types.difference(types).empty? &&
52
- types.difference(option_types).empty?
53
- end
54
-
55
- def build_missing_option
56
- option_types = attribute_data.fetch(:types)
57
-
58
- text_about_types = types.size > 1 ? "with one of the following types" : "type"
59
-
60
- <<~MESSAGE
61
- should be a value with #{text_about_types}
62
-
63
- expected #{types.inspect}
64
- got #{option_types.inspect}
65
- MESSAGE
66
- end
67
- end
68
- end
69
- end
70
- end
71
- end
72
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module TestKit
5
- module Rspec
6
- module Matchers
7
- module HaveServiceInputMatchers
8
- class DefaultMatcher
9
- attr_reader :missing_option
10
-
11
- def initialize(described_class, attribute_type, attribute_name, default_value)
12
- @described_class = described_class
13
- @attribute_type = attribute_type
14
- @attribute_type_plural = attribute_type.to_s.pluralize.to_sym
15
- @attribute_name = attribute_name
16
- @default_value = default_value
17
-
18
- @attribute_data = described_class.info.public_send(attribute_type_plural).fetch(attribute_name)
19
-
20
- @missing_option = ""
21
- end
22
-
23
- def description
24
- "default: #{default_value.inspect}"
25
- end
26
-
27
- def matches?(subject)
28
- if submatcher_passes?(subject)
29
- true
30
- else
31
- @missing_option = build_missing_option
32
-
33
- false
34
- end
35
- end
36
-
37
- private
38
-
39
- attr_reader :described_class,
40
- :attribute_type,
41
- :attribute_type_plural,
42
- :attribute_name,
43
- :default_value,
44
- :attribute_data
45
-
46
- def submatcher_passes?(_subject)
47
- attribute_default_value = attribute_data.fetch(:default)
48
-
49
- return default_value.nil? if attribute_default_value.is_a?(NilClass)
50
-
51
- attribute_default_value.to_s.casecmp(default_value.to_s).zero?
52
- end
53
-
54
- def build_missing_option
55
- attribute_default_value = attribute_data.fetch(:default)
56
-
57
- <<~MESSAGE
58
- should have a default value
59
-
60
- expected #{default_value.inspect}
61
- got #{attribute_default_value.inspect}
62
- MESSAGE
63
- end
64
- end
65
- end
66
- end
67
- end
68
- end
69
- end
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module TestKit
5
- module Rspec
6
- module Matchers
7
- module HaveServiceInputMatchers
8
- class OptionalMatcher
9
- attr_reader :missing_option
10
-
11
- def initialize(described_class, attribute_type, attribute_name)
12
- @described_class = described_class
13
- @attribute_type = attribute_type
14
- @attribute_type_plural = attribute_type.to_s.pluralize.to_sym
15
- @attribute_name = attribute_name
16
-
17
- @attribute_data = described_class.info.public_send(attribute_type_plural).fetch(attribute_name)
18
-
19
- @missing_option = ""
20
- end
21
-
22
- def description
23
- "required: false"
24
- end
25
-
26
- def matches?(subject)
27
- if submatcher_passes?(subject)
28
- true
29
- else
30
- @missing_option = build_missing_option
31
-
32
- false
33
- end
34
- end
35
-
36
- private
37
-
38
- attr_reader :described_class,
39
- :attribute_type,
40
- :attribute_type_plural,
41
- :attribute_name,
42
- :attribute_data
43
-
44
- def submatcher_passes?(_subject)
45
- input_required = attribute_data.fetch(:required).fetch(:is)
46
-
47
- input_required == false
48
- end
49
-
50
- def build_missing_option
51
- <<~MESSAGE
52
- should be optional
53
-
54
- expected required: false
55
- got required: true
56
- MESSAGE
57
- end
58
- end
59
- end
60
- end
61
- end
62
- end
63
- end
@@ -1,81 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module TestKit
5
- module Rspec
6
- module Matchers
7
- module HaveServiceInputMatchers
8
- class RequiredMatcher
9
- attr_reader :missing_option
10
-
11
- def initialize(described_class, attribute_type, attribute_name, custom_message)
12
- @described_class = described_class
13
- @attribute_type = attribute_type
14
- @attribute_type_plural = attribute_type.to_s.pluralize.to_sym
15
- @attribute_name = attribute_name
16
- @custom_message = custom_message
17
-
18
- @attribute_data = described_class.info.public_send(attribute_type_plural).fetch(attribute_name)
19
-
20
- @i18n_root_key = described_class.config.i18n_root_key
21
-
22
- @missing_option = ""
23
- end
24
-
25
- def description
26
- "required: true"
27
- end
28
-
29
- def matches?(subject)
30
- if submatcher_passes?(subject)
31
- true
32
- else
33
- @missing_option = build_missing_option
34
-
35
- false
36
- end
37
- end
38
-
39
- private
40
-
41
- attr_reader :described_class,
42
- :attribute_type,
43
- :attribute_type_plural,
44
- :attribute_name,
45
- :custom_message,
46
- :attribute_data,
47
- :i18n_root_key
48
-
49
- def submatcher_passes?(_subject) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
50
- attribute_required = attribute_data.fetch(:required).fetch(:is)
51
- attribute_required_message = attribute_data.fetch(:required).fetch(:message)
52
-
53
- matched = attribute_required == true
54
-
55
- if attribute_required_message.nil?
56
- attribute_required_message = I18n.t(
57
- "#{i18n_root_key}.#{attribute_type_plural}.validations.required.default_error.default",
58
- service_class_name: described_class.name,
59
- "#{attribute_type}_name": attribute_name
60
- )
61
- end
62
-
63
- matched &&= attribute_required_message.casecmp(custom_message).zero? if custom_message.present?
64
-
65
- matched
66
- end
67
-
68
- def build_missing_option
69
- <<~MESSAGE
70
- should be required
71
-
72
- expected required: true
73
- got required: false
74
- MESSAGE
75
- end
76
- end
77
- end
78
- end
79
- end
80
- end
81
- end
@@ -1,199 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module TestKit
5
- module Rspec
6
- module Matchers
7
- module HaveServiceInputMatchers
8
- # DEPRECATED: This chain is planned to be decommissioned.
9
- class ValidWithMatcher # rubocop:disable Metrics/ClassLength
10
- attr_reader :missing_option
11
-
12
- def initialize(described_class, attribute_type, attribute_name, attributes)
13
- @described_class = described_class
14
- @attribute_type = attribute_type
15
- @attribute_type_plural = attribute_type.to_s.pluralize.to_sym
16
- @attribute_name = attribute_name
17
- @attributes = attributes.is_a?(FalseClass) ? attributes : Servactory::Utils.adapt(attributes)
18
-
19
- @attribute_data = described_class.info.public_send(attribute_type_plural).fetch(attribute_name)
20
-
21
- @i18n_root_key = described_class.config.i18n_root_key
22
-
23
- @missing_option = ""
24
- end
25
-
26
- def description
27
- "valid_with attribute checking"
28
- end
29
-
30
- def matches?(subject)
31
- if attributes.is_a?(FalseClass) || submatcher_passes?(subject)
32
- true
33
- else
34
- @missing_option = build_missing_option
35
-
36
- false
37
- end
38
- end
39
-
40
- private
41
-
42
- attr_reader :described_class,
43
- :attribute_type,
44
- :attribute_type_plural,
45
- :attribute_name,
46
- :attributes,
47
- :attribute_data,
48
- :i18n_root_key
49
-
50
- def submatcher_passes?(_subject) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
51
- success_passes? &&
52
- failure_type_passes? &&
53
- failure_required_passes? &&
54
- failure_optional_passes? &&
55
- failure_consists_of_passes? &&
56
- failure_schema_passes? &&
57
- failure_format_passes? &&
58
- failure_inclusion_passes? &&
59
- failure_must_passes?
60
- end
61
-
62
- def success_passes?
63
- expect_success_with!(attributes)
64
- end
65
-
66
- def failure_type_passes? # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
67
- option_types = attribute_data.fetch(:types)
68
-
69
- prepared_attributes = attributes.dup
70
- prepared_attributes[attribute_name] = Servactory::TestKit::FakeType.new
71
-
72
- input_required_message =
73
- I18n.t(
74
- "#{i18n_root_key}.#{attribute_type_plural}.validations.type.default_error.default",
75
- service_class_name: described_class.name,
76
- "#{attribute_type}_name": attribute_name,
77
- expected_type: option_types.join(", "),
78
- given_type: Servactory::TestKit::FakeType.new.class.name
79
- )
80
-
81
- expect_failure_with!(prepared_attributes, input_required_message)
82
- end
83
-
84
- def failure_required_passes? # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
85
- input_required = attribute_data.fetch(:required).fetch(:is)
86
-
87
- return true unless input_required
88
-
89
- prepared_attributes = attributes.dup
90
- prepared_attributes[attribute_name] = nil
91
-
92
- input_required_message = attribute_data.fetch(:required).fetch(:message)
93
-
94
- if input_required_message.nil?
95
- input_required_message = I18n.t(
96
- "#{i18n_root_key}.#{attribute_type_plural}.validations.required.default_error.default",
97
- service_class_name: described_class.name,
98
- "#{attribute_type}_name": attribute_name
99
- )
100
- end
101
-
102
- expect_failure_with!(prepared_attributes, input_required_message)
103
- end
104
-
105
- def failure_optional_passes?
106
- input_required = attribute_data.fetch(:required).fetch(:is)
107
-
108
- return true if input_required
109
-
110
- prepared_attributes = attributes.dup
111
- prepared_attributes[attribute_name] = nil
112
-
113
- expect_failure_with!(prepared_attributes, nil)
114
- end
115
-
116
- def failure_consists_of_passes?
117
- # NOTE: Checking for negative cases is not implemented for `consists_of`
118
- true
119
- end
120
-
121
- def failure_schema_passes?
122
- # NOTE: Checking for negative cases is not implemented for `schema`
123
- true
124
- end
125
-
126
- def failure_format_passes?
127
- # NOTE: Checking for negative cases is not implemented for `format`
128
- true
129
- end
130
-
131
- def failure_inclusion_passes? # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
132
- input_inclusion_in = attribute_data.dig(:inclusion, :in)
133
-
134
- return true if input_inclusion_in.blank?
135
-
136
- wrong_value = Servactory::TestKit::Utils::Faker.fetch_value_for(input_inclusion_in.first.class)
137
-
138
- prepared_attributes = attributes.dup
139
- prepared_attributes[attribute_name] = wrong_value
140
-
141
- input_required_message = attribute_data.fetch(:inclusion).fetch(:message)
142
-
143
- if input_required_message.nil?
144
- input_required_message = I18n.t(
145
- "#{i18n_root_key}.#{attribute_type_plural}.validations.must.dynamic_options.inclusion.default",
146
- service_class_name: described_class.name,
147
- "#{attribute_type}_name": attribute_name,
148
- "#{attribute_type}_inclusion": input_inclusion_in.inspect,
149
- value: wrong_value.inspect
150
- )
151
- elsif input_required_message.is_a?(Proc)
152
- service_class = Struct.new(:class_name, keyword_init: true)
153
- service = service_class.new(class_name: described_class.name)
154
-
155
- input_actor = attribute_data.fetch(:actor)
156
-
157
- input_required_message = input_required_message.call(
158
- service:,
159
- input: input_actor,
160
- value: wrong_value
161
- )
162
- end
163
-
164
- expect_failure_with!(prepared_attributes, input_required_message)
165
- end
166
-
167
- def failure_must_passes?
168
- # NOTE: Checking for negative cases is not implemented for `must`
169
- true
170
- end
171
-
172
- def expect_success_with!(prepared_attributes)
173
- described_class.call!(prepared_attributes).success?
174
- rescue Servactory::Exceptions::Input
175
- false
176
- rescue StandardError
177
- true
178
- end
179
-
180
- def expect_failure_with!(prepared_attributes, expected_message)
181
- described_class.call!(prepared_attributes).success?
182
- rescue Servactory::Exceptions::Input => e
183
- return false if expected_message.blank?
184
-
185
- expected_message.casecmp(e.message).zero?
186
- rescue Servactory::Exceptions::Internal, Servactory::Exceptions::Output
187
- # NOTE: Skips the fall of validations inside the service, which are not important in this place.
188
- true
189
- end
190
-
191
- def build_missing_option
192
- "should work as expected on the specified attributes based on its options"
193
- end
194
- end
195
- end
196
- end
197
- end
198
- end
199
- end