servactory 2.5.0.rc2 → 2.5.0.rc4
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/generators/servactory/install_generator.rb +21 -0
- data/lib/generators/servactory/rspec_generator.rb +88 -0
- data/lib/generators/servactory/service_generator.rb +49 -0
- data/lib/generators/servactory/templates/services/application_service/base.rb +60 -0
- data/lib/generators/servactory/templates/services/application_service/exceptions.rb +11 -0
- data/lib/generators/servactory/templates/services/application_service/result.rb +5 -0
- data/lib/servactory/context/workspace/internals.rb +1 -1
- data/lib/servactory/info/dsl.rb +56 -4
- data/lib/servactory/maintenance/attributes/options/registrar.rb +1 -1
- data/lib/servactory/result.rb +1 -1
- data/lib/servactory/test_kit/rspec/helpers.rb +95 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/consists_of_matcher.rb +121 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/inclusion_matcher.rb +70 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/must_matcher.rb +61 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/types_matcher.rb +72 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_input_matcher.rb +203 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/default_matcher.rb +67 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/optional_matcher.rb +63 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/required_matcher.rb +78 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/valid_with_matcher.rb +233 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_internal_matcher.rb +148 -0
- data/lib/servactory/test_kit/rspec/matchers.rb +295 -0
- data/lib/servactory/test_kit/utils/faker.rb +78 -0
- data/lib/servactory/tool_kit/dynamic_options/format.rb +16 -12
- data/lib/servactory/version.rb +1 -1
- data/lib/servactory.rb +1 -0
- metadata +26 -7
@@ -0,0 +1,233 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module TestKit
|
5
|
+
module Rspec
|
6
|
+
module Matchers
|
7
|
+
module HaveServiceInputMatchers
|
8
|
+
class ValidWithMatcher # rubocop:disable Metrics/ClassLength
|
9
|
+
attr_reader :missing_option
|
10
|
+
|
11
|
+
def initialize(described_class, attribute_type, attribute_name, attributes)
|
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
|
+
@attributes = attributes
|
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
|
+
"valid_with attribute checking"
|
25
|
+
end
|
26
|
+
|
27
|
+
def matches?(subject)
|
28
|
+
if attributes.is_a?(FalseClass) || 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
|
+
:attributes,
|
44
|
+
:attribute_data
|
45
|
+
|
46
|
+
def submatcher_passes?(_subject) # rubocop:disable Metrics/CyclomaticComplexity
|
47
|
+
success_passes? &&
|
48
|
+
failure_type_passes? &&
|
49
|
+
failure_required_passes? &&
|
50
|
+
failure_optional_passes? &&
|
51
|
+
failure_consists_of_passes? &&
|
52
|
+
failure_format_passes? &&
|
53
|
+
failure_inclusion_passes? &&
|
54
|
+
failure_must_passes?
|
55
|
+
end
|
56
|
+
|
57
|
+
def success_passes?
|
58
|
+
expect_success_with!(attributes)
|
59
|
+
end
|
60
|
+
|
61
|
+
def failure_type_passes? # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
62
|
+
option_types = attribute_data.fetch(:types)
|
63
|
+
input_first_type = option_types.first
|
64
|
+
input_required = attribute_data.fetch(:required).fetch(:is)
|
65
|
+
attribute_consists_of_types = Array(attribute_data.fetch(:consists_of).fetch(:type))
|
66
|
+
attribute_consists_of_first_type = attribute_consists_of_types.first
|
67
|
+
|
68
|
+
prepared_attributes = attributes.dup
|
69
|
+
prepared_attributes[attribute_name] = Servactory::TestKit::FakeType.new
|
70
|
+
|
71
|
+
input_required_message =
|
72
|
+
if described_class.config.collection_mode_class_names.include?(input_first_type) &&
|
73
|
+
attribute_consists_of_first_type != false
|
74
|
+
if input_required
|
75
|
+
I18n.t(
|
76
|
+
"servactory.#{attribute_type_plural}.validations.required.default_error.for_collection",
|
77
|
+
service_class_name: described_class.name,
|
78
|
+
"#{attribute_type}_name": attribute_name
|
79
|
+
)
|
80
|
+
else
|
81
|
+
I18n.t(
|
82
|
+
"servactory.#{attribute_type_plural}.validations.type.default_error.for_collection.wrong_type",
|
83
|
+
service_class_name: described_class.name,
|
84
|
+
"#{attribute_type}_name": attribute_name,
|
85
|
+
expected_type: option_types.join(", "),
|
86
|
+
given_type: Servactory::TestKit::FakeType.new.class.name
|
87
|
+
)
|
88
|
+
end
|
89
|
+
else
|
90
|
+
I18n.t(
|
91
|
+
"servactory.#{attribute_type_plural}.validations.type.default_error.default",
|
92
|
+
service_class_name: described_class.name,
|
93
|
+
"#{attribute_type}_name": attribute_name,
|
94
|
+
expected_type: option_types.join(", "),
|
95
|
+
given_type: Servactory::TestKit::FakeType.new.class.name
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
expect_failure_with!(prepared_attributes, input_required_message)
|
100
|
+
end
|
101
|
+
|
102
|
+
def failure_required_passes? # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
103
|
+
input_required = attribute_data.fetch(:required).fetch(:is)
|
104
|
+
|
105
|
+
return true unless input_required
|
106
|
+
|
107
|
+
prepared_attributes = attributes.dup
|
108
|
+
prepared_attributes[attribute_name] = nil
|
109
|
+
|
110
|
+
input_required_message = attribute_data.fetch(:required).fetch(:message)
|
111
|
+
|
112
|
+
if input_required_message.nil?
|
113
|
+
input_required_message = I18n.t(
|
114
|
+
"servactory.#{attribute_type_plural}.validations.required.default_error.default",
|
115
|
+
service_class_name: described_class.name,
|
116
|
+
"#{attribute_type}_name": attribute_name
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
expect_failure_with!(prepared_attributes, input_required_message)
|
121
|
+
end
|
122
|
+
|
123
|
+
def failure_optional_passes?
|
124
|
+
input_required = attribute_data.fetch(:required).fetch(:is)
|
125
|
+
|
126
|
+
return true if input_required
|
127
|
+
|
128
|
+
prepared_attributes = attributes.dup
|
129
|
+
prepared_attributes[attribute_name] = nil
|
130
|
+
|
131
|
+
expect_failure_with!(prepared_attributes, nil)
|
132
|
+
end
|
133
|
+
|
134
|
+
def failure_format_passes?
|
135
|
+
# NOTE: Checking for negative cases is not implemented for `format`
|
136
|
+
true
|
137
|
+
end
|
138
|
+
|
139
|
+
def failure_consists_of_passes? # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
140
|
+
option_types = attribute_data.fetch(:types)
|
141
|
+
input_first_type = option_types.first
|
142
|
+
|
143
|
+
return true unless described_class.config.collection_mode_class_names.include?(input_first_type)
|
144
|
+
|
145
|
+
prepared_attributes = attributes.dup
|
146
|
+
prepared_attributes[attribute_name] = input_first_type[Servactory::TestKit::FakeType.new]
|
147
|
+
|
148
|
+
attribute_consists_of_types = Array(attribute_data.fetch(:consists_of).fetch(:type))
|
149
|
+
attribute_consists_of_first_type = attribute_consists_of_types.first
|
150
|
+
|
151
|
+
return true if attribute_consists_of_first_type == false
|
152
|
+
|
153
|
+
attribute_consists_of_message = attribute_data.fetch(:consists_of).fetch(:message)
|
154
|
+
|
155
|
+
if attribute_consists_of_message.nil?
|
156
|
+
attribute_consists_of_message = I18n.t(
|
157
|
+
"servactory.#{attribute_type_plural}.validations.type.default_error.for_collection.wrong_element_type", # rubocop:disable Layout/LineLength
|
158
|
+
service_class_name: described_class.name,
|
159
|
+
"#{attribute_type}_name": attribute_name,
|
160
|
+
expected_type: attribute_consists_of_types.join(", "),
|
161
|
+
given_type: prepared_attributes[attribute_name].map { _1.class.name }.join(", ")
|
162
|
+
)
|
163
|
+
end
|
164
|
+
|
165
|
+
expect_failure_with!(prepared_attributes, attribute_consists_of_message)
|
166
|
+
end
|
167
|
+
|
168
|
+
def failure_inclusion_passes? # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
169
|
+
input_inclusion_in = attribute_data.fetch(:inclusion).fetch(:in)
|
170
|
+
|
171
|
+
return true if input_inclusion_in.blank?
|
172
|
+
|
173
|
+
wrong_value = Servactory::TestKit::Utils::Faker.fetch_value_for(input_inclusion_in.first.class)
|
174
|
+
|
175
|
+
prepared_attributes = attributes.dup
|
176
|
+
prepared_attributes[attribute_name] = wrong_value
|
177
|
+
|
178
|
+
input_required_message = attribute_data.fetch(:inclusion).fetch(:message)
|
179
|
+
|
180
|
+
if input_required_message.nil?
|
181
|
+
input_required_message = I18n.t(
|
182
|
+
"servactory.#{attribute_type_plural}.validations.inclusion.default_error",
|
183
|
+
service_class_name: described_class.name,
|
184
|
+
"#{attribute_type}_name": attribute_name,
|
185
|
+
"#{attribute_type}_inclusion": input_inclusion_in,
|
186
|
+
value: wrong_value
|
187
|
+
)
|
188
|
+
elsif input_required_message.is_a?(Proc)
|
189
|
+
input_work = attribute_data.fetch(:work)
|
190
|
+
|
191
|
+
input_required_message = input_required_message.call(
|
192
|
+
service_class_name: described_class.name,
|
193
|
+
input: input_work,
|
194
|
+
value: wrong_value
|
195
|
+
)
|
196
|
+
end
|
197
|
+
|
198
|
+
expect_failure_with!(prepared_attributes, input_required_message)
|
199
|
+
end
|
200
|
+
|
201
|
+
def failure_must_passes?
|
202
|
+
# NOTE: Checking for negative cases is not implemented for `must`
|
203
|
+
true
|
204
|
+
end
|
205
|
+
|
206
|
+
def expect_success_with!(prepared_attributes)
|
207
|
+
described_class.call!(prepared_attributes).success?
|
208
|
+
rescue Servactory::Exceptions::Input
|
209
|
+
false
|
210
|
+
rescue StandardError
|
211
|
+
true
|
212
|
+
end
|
213
|
+
|
214
|
+
def expect_failure_with!(prepared_attributes, expected_message)
|
215
|
+
described_class.call!(prepared_attributes).success?
|
216
|
+
rescue Servactory::Exceptions::Input => e
|
217
|
+
return false if expected_message.blank?
|
218
|
+
|
219
|
+
expected_message.casecmp(e.message).zero?
|
220
|
+
rescue Servactory::Exceptions::Internal, Servactory::Exceptions::Output
|
221
|
+
# NOTE: Skips the fall of validations inside the service, which are not important in this place.
|
222
|
+
true
|
223
|
+
end
|
224
|
+
|
225
|
+
def build_missing_option
|
226
|
+
"should work as expected on the specified attributes based on its options"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module TestKit
|
5
|
+
module Rspec
|
6
|
+
module Matchers
|
7
|
+
class HaveServiceInternalMatcher # rubocop:disable Metrics/ClassLength
|
8
|
+
attr_reader :described_class, :internal_name, :options
|
9
|
+
|
10
|
+
def initialize(described_class, internal_name)
|
11
|
+
@described_class = described_class
|
12
|
+
@internal_name = internal_name
|
13
|
+
|
14
|
+
@options = {}
|
15
|
+
@submatchers = []
|
16
|
+
|
17
|
+
@missing = ""
|
18
|
+
end
|
19
|
+
|
20
|
+
def supports_block_expectations?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def type(type)
|
25
|
+
@option_types = Array(type)
|
26
|
+
add_submatcher(
|
27
|
+
HaveServiceAttributeMatchers::TypesMatcher,
|
28
|
+
described_class,
|
29
|
+
:internal,
|
30
|
+
internal_name,
|
31
|
+
@option_types
|
32
|
+
)
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def types(*types)
|
37
|
+
@option_types = types
|
38
|
+
add_submatcher(
|
39
|
+
HaveServiceAttributeMatchers::TypesMatcher,
|
40
|
+
described_class,
|
41
|
+
:internal,
|
42
|
+
internal_name,
|
43
|
+
@option_types
|
44
|
+
)
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
def consists_of(*types) # rubocop:disable Metrics/MethodLength
|
49
|
+
message = block_given? ? yield : nil
|
50
|
+
|
51
|
+
add_submatcher(
|
52
|
+
HaveServiceAttributeMatchers::ConsistsOfMatcher,
|
53
|
+
described_class,
|
54
|
+
:internal,
|
55
|
+
internal_name,
|
56
|
+
@option_types,
|
57
|
+
Array(types),
|
58
|
+
message
|
59
|
+
)
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
def inclusion(values)
|
64
|
+
add_submatcher(
|
65
|
+
HaveServiceAttributeMatchers::InclusionMatcher,
|
66
|
+
described_class,
|
67
|
+
:internal,
|
68
|
+
internal_name,
|
69
|
+
Array(values)
|
70
|
+
)
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
def must(*must_names)
|
75
|
+
add_submatcher(
|
76
|
+
HaveServiceAttributeMatchers::MustMatcher,
|
77
|
+
described_class,
|
78
|
+
:internal,
|
79
|
+
internal_name,
|
80
|
+
Array(must_names)
|
81
|
+
)
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
def description
|
86
|
+
"#{internal_name} with #{submatchers.map(&:description).join(', ')}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def failure_message
|
90
|
+
"Expected #{expectation}, which #{missing_options}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def failure_message_when_negated
|
94
|
+
"Did not expect #{expectation} with specified options"
|
95
|
+
end
|
96
|
+
|
97
|
+
def matches?(subject)
|
98
|
+
@subject = subject
|
99
|
+
|
100
|
+
submatchers_match?
|
101
|
+
end
|
102
|
+
|
103
|
+
protected
|
104
|
+
|
105
|
+
attr_reader :submatchers, :missing, :subject
|
106
|
+
|
107
|
+
def add_submatcher(matcher_class, *args)
|
108
|
+
remove_submatcher(matcher_class)
|
109
|
+
submatchers << matcher_class.new(*args)
|
110
|
+
end
|
111
|
+
|
112
|
+
def remove_submatcher(matcher_class)
|
113
|
+
submatchers.delete_if do |submatcher|
|
114
|
+
submatcher.is_a?(matcher_class)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def expectation
|
119
|
+
"#{described_class.name} to have a service internal attribute named #{internal_name}"
|
120
|
+
end
|
121
|
+
|
122
|
+
def missing_options
|
123
|
+
missing_options = [missing, missing_options_for_failing_submatchers]
|
124
|
+
missing_options.flatten.select(&:present?).join(", ")
|
125
|
+
end
|
126
|
+
|
127
|
+
def failing_submatchers
|
128
|
+
@failing_submatchers ||= submatchers.reject do |matcher|
|
129
|
+
matcher.matches?(subject)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def missing_options_for_failing_submatchers
|
134
|
+
if defined?(failing_submatchers)
|
135
|
+
failing_submatchers.map(&:missing_option)
|
136
|
+
else
|
137
|
+
[]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def submatchers_match?
|
142
|
+
failing_submatchers.empty?
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,295 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module TestKit
|
5
|
+
module Rspec
|
6
|
+
module Matchers # rubocop:disable Metrics/ModuleLength
|
7
|
+
def have_service_input(input_name) # rubocop:disable Naming/PredicateName
|
8
|
+
HaveServiceInputMatcher.new(described_class, input_name)
|
9
|
+
end
|
10
|
+
|
11
|
+
RSpec::Matchers.alias_matcher :have_input, :have_service_input
|
12
|
+
|
13
|
+
def have_service_internal(internal_name) # rubocop:disable Naming/PredicateName
|
14
|
+
HaveServiceInternalMatcher.new(described_class, internal_name)
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec::Matchers.alias_matcher :have_internal, :have_service_internal
|
18
|
+
|
19
|
+
########################################################################
|
20
|
+
########################################################################
|
21
|
+
########################################################################
|
22
|
+
|
23
|
+
RSpec::Matchers.define :have_service_output do |output_name| # rubocop:disable Metrics/BlockLength
|
24
|
+
description { "service output" }
|
25
|
+
|
26
|
+
match do |actual|
|
27
|
+
match_for(actual, output_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
chain :instance_of do |class_or_name|
|
31
|
+
@instance_of = Servactory::Utils.constantize_class(class_or_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
chain :nested do |*values|
|
35
|
+
@nested = values
|
36
|
+
end
|
37
|
+
|
38
|
+
chain :with do |value|
|
39
|
+
@value = value
|
40
|
+
end
|
41
|
+
|
42
|
+
failure_message do |actual|
|
43
|
+
match_for(actual, output_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
47
|
+
def match_for(actual, output_name)
|
48
|
+
given_value = actual.public_send(output_name)
|
49
|
+
|
50
|
+
if defined?(@nested) && @nested.present?
|
51
|
+
@nested.each do |method_name|
|
52
|
+
next unless given_value.respond_to?(method_name)
|
53
|
+
|
54
|
+
given_value = given_value.public_send(method_name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
expect(given_value).to(
|
59
|
+
if defined?(@instance_of)
|
60
|
+
RSpec::Matchers::BuiltIn::BeAnInstanceOf.new(@instance_of)
|
61
|
+
elsif @value.is_a?(Array)
|
62
|
+
RSpec::Matchers::BuiltIn::ContainExactly.new(@value)
|
63
|
+
elsif @value.is_a?(Hash)
|
64
|
+
RSpec::Matchers::BuiltIn::Match.new(@value)
|
65
|
+
elsif @value.is_a?(TrueClass) || @value.is_a?(FalseClass)
|
66
|
+
RSpec::Matchers::BuiltIn::Equal.new(@value)
|
67
|
+
elsif @value.is_a?(NilClass)
|
68
|
+
RSpec::Matchers::BuiltIn::BeNil.new(@value)
|
69
|
+
else
|
70
|
+
RSpec::Matchers::BuiltIn::Eq.new(@value)
|
71
|
+
end
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
76
|
+
|
77
|
+
RSpec::Matchers.alias_matcher :have_output, :have_service_output
|
78
|
+
|
79
|
+
RSpec::Matchers.define :be_success_service do # rubocop:disable Metrics/BlockLength
|
80
|
+
description { "service success" }
|
81
|
+
|
82
|
+
def expected_data
|
83
|
+
@expected_data ||= {}
|
84
|
+
end
|
85
|
+
|
86
|
+
match do |actual|
|
87
|
+
matched = actual.is_a?(Servactory::Result)
|
88
|
+
matched &&= actual.success?
|
89
|
+
matched &&= !actual.failure?
|
90
|
+
|
91
|
+
if defined?(expected_data)
|
92
|
+
matched &&= expected_data.all? do |key, value|
|
93
|
+
if actual.respond_to?(key)
|
94
|
+
actual.public_send(key) == value
|
95
|
+
else
|
96
|
+
false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
matched
|
102
|
+
end
|
103
|
+
|
104
|
+
chain :with_output do |key, value|
|
105
|
+
expected_data[key] = value
|
106
|
+
end
|
107
|
+
|
108
|
+
chain :with_outputs do |attributes|
|
109
|
+
attributes.each do |key, value|
|
110
|
+
expected_data[key] = value
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
failure_message do |actual| # rubocop:disable Metrics/BlockLength
|
115
|
+
unless actual.instance_of?(Servactory::Result)
|
116
|
+
break <<~MESSAGE
|
117
|
+
Incorrect service result:
|
118
|
+
|
119
|
+
expected Servactory::Result
|
120
|
+
got #{actual.class.name}
|
121
|
+
MESSAGE
|
122
|
+
end
|
123
|
+
|
124
|
+
if actual.failure?
|
125
|
+
break <<~MESSAGE
|
126
|
+
Incorrect service result:
|
127
|
+
|
128
|
+
expected success
|
129
|
+
got failure
|
130
|
+
MESSAGE
|
131
|
+
end
|
132
|
+
|
133
|
+
if defined?(expected_data)
|
134
|
+
message = expected_data.each do |key, value|
|
135
|
+
unless actual.respond_to?(key)
|
136
|
+
break <<~MESSAGE
|
137
|
+
Non-existent value key in result:
|
138
|
+
|
139
|
+
expected #{actual.inspect}
|
140
|
+
got #{key}
|
141
|
+
MESSAGE
|
142
|
+
end
|
143
|
+
|
144
|
+
expected_value = actual.public_send(key)
|
145
|
+
next if actual.public_send(key) == value
|
146
|
+
|
147
|
+
break <<~MESSAGE
|
148
|
+
Incorrect result value for #{key}:
|
149
|
+
|
150
|
+
expected #{expected_value.inspect}
|
151
|
+
got #{value.inspect}
|
152
|
+
MESSAGE
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
break message if message.present?
|
157
|
+
|
158
|
+
<<~MESSAGE
|
159
|
+
Unexpected case when using `be_success_service`.
|
160
|
+
|
161
|
+
Please try to build an example based on the documentation.
|
162
|
+
Or report your problem to us:
|
163
|
+
|
164
|
+
https://github.com/servactory/servactory/issues
|
165
|
+
MESSAGE
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
RSpec::Matchers.define :be_failure_service do # rubocop:disable Metrics/BlockLength
|
170
|
+
description { "service failure" }
|
171
|
+
|
172
|
+
match do |actual|
|
173
|
+
expected_failure_class =
|
174
|
+
defined?(@expected_failure_class) ? @expected_failure_class : Servactory::Exceptions::Failure
|
175
|
+
|
176
|
+
expected_type = defined?(@expected_type) ? @expected_type : :base
|
177
|
+
expected_message = defined?(@expected_message) ? @expected_message : nil
|
178
|
+
expected_meta = defined?(@expected_meta) ? @expected_meta : nil
|
179
|
+
|
180
|
+
matched = actual.is_a?(Servactory::Result)
|
181
|
+
matched &&= !actual.success?
|
182
|
+
matched &&= actual.failure?
|
183
|
+
matched &&= actual.error.is_a?(Servactory::Exceptions::Failure)
|
184
|
+
matched &&= actual.error.instance_of?(expected_failure_class)
|
185
|
+
matched &&= actual.error.type == expected_type
|
186
|
+
matched &&= actual.error.message == expected_message
|
187
|
+
matched &&= actual.error.meta == expected_meta
|
188
|
+
matched
|
189
|
+
end
|
190
|
+
|
191
|
+
chain :with do |expected_failure_class|
|
192
|
+
@expected_failure_class = expected_failure_class
|
193
|
+
end
|
194
|
+
|
195
|
+
chain :type do |expected_type|
|
196
|
+
@expected_type = expected_type
|
197
|
+
end
|
198
|
+
|
199
|
+
chain :message do |expected_message|
|
200
|
+
@expected_message = expected_message
|
201
|
+
end
|
202
|
+
|
203
|
+
chain :meta do |expected_meta|
|
204
|
+
@expected_meta = expected_meta
|
205
|
+
end
|
206
|
+
|
207
|
+
failure_message do |actual| # rubocop:disable Metrics/BlockLength
|
208
|
+
unless actual.instance_of?(Servactory::Result)
|
209
|
+
break <<~MESSAGE
|
210
|
+
Incorrect service result:
|
211
|
+
|
212
|
+
expected Servactory::Result
|
213
|
+
got #{actual.class.name}
|
214
|
+
MESSAGE
|
215
|
+
end
|
216
|
+
|
217
|
+
if actual.success?
|
218
|
+
break <<~MESSAGE
|
219
|
+
Incorrect service result:
|
220
|
+
|
221
|
+
expected failure
|
222
|
+
got success
|
223
|
+
MESSAGE
|
224
|
+
end
|
225
|
+
|
226
|
+
unless actual.error.is_a?(Servactory::Exceptions::Failure)
|
227
|
+
break <<~MESSAGE
|
228
|
+
Incorrect error object:
|
229
|
+
|
230
|
+
expected Servactory::Exceptions::Failure
|
231
|
+
got #{actual.error.class.name}
|
232
|
+
MESSAGE
|
233
|
+
end
|
234
|
+
|
235
|
+
if defined?(@expected_failure_class)
|
236
|
+
unless actual.error.instance_of?(@expected_failure_class)
|
237
|
+
break <<~MESSAGE
|
238
|
+
Incorrect instance error:
|
239
|
+
|
240
|
+
expected #{@expected_failure_class}
|
241
|
+
got #{actual.error.class.name}
|
242
|
+
MESSAGE
|
243
|
+
end
|
244
|
+
else
|
245
|
+
unless actual.error.instance_of?(Servactory::Exceptions::Failure)
|
246
|
+
break <<~MESSAGE
|
247
|
+
Incorrect error object:
|
248
|
+
|
249
|
+
expected Servactory::Exceptions::Failure
|
250
|
+
got #{actual.error.class.name}
|
251
|
+
MESSAGE
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
if defined?(@expected_type) && actual.error.type != @expected_type
|
256
|
+
break <<~MESSAGE
|
257
|
+
Incorrect error type:
|
258
|
+
|
259
|
+
expected #{actual.error.type.inspect}
|
260
|
+
got #{@expected_type.inspect}
|
261
|
+
MESSAGE
|
262
|
+
end
|
263
|
+
|
264
|
+
if defined?(@expected_message) && actual.error.message != @expected_message
|
265
|
+
break <<~MESSAGE
|
266
|
+
Incorrect error message:
|
267
|
+
|
268
|
+
expected #{actual.error.message.inspect}
|
269
|
+
got #{@expected_message.inspect}
|
270
|
+
MESSAGE
|
271
|
+
end
|
272
|
+
|
273
|
+
if defined?(@expected_meta) && actual.error.meta != @expected_meta
|
274
|
+
break <<~MESSAGE
|
275
|
+
Incorrect error meta:
|
276
|
+
|
277
|
+
expected #{actual.error.meta.inspect}
|
278
|
+
got #{@expected_meta.inspect}
|
279
|
+
MESSAGE
|
280
|
+
end
|
281
|
+
|
282
|
+
<<~MESSAGE
|
283
|
+
Unexpected case when using `be_failure_service`.
|
284
|
+
|
285
|
+
Please try to build an example based on the documentation.
|
286
|
+
Or report your problem to us:
|
287
|
+
|
288
|
+
https://github.com/servactory/servactory/issues
|
289
|
+
MESSAGE
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|