active_storage_validations 1.1.1 → 1.2.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.
- checksums.yaml +4 -4
- data/README.md +145 -73
- data/config/locales/da.yml +33 -0
- data/config/locales/de.yml +6 -0
- data/config/locales/en.yml +5 -0
- data/config/locales/es.yml +6 -0
- data/config/locales/fr.yml +6 -0
- data/config/locales/it.yml +6 -0
- data/config/locales/ja.yml +6 -0
- data/config/locales/nl.yml +6 -0
- data/config/locales/pl.yml +6 -0
- data/config/locales/pt-BR.yml +5 -0
- data/config/locales/ru.yml +7 -1
- data/config/locales/sv.yml +10 -1
- data/config/locales/tr.yml +6 -0
- data/config/locales/uk.yml +6 -0
- data/config/locales/vi.yml +6 -0
- data/config/locales/zh-CN.yml +6 -0
- data/lib/active_storage_validations/aspect_ratio_validator.rb +49 -22
- data/lib/active_storage_validations/attached_validator.rb +18 -4
- data/lib/active_storage_validations/base_size_validator.rb +66 -0
- data/lib/active_storage_validations/concerns/errorable.rb +38 -0
- data/lib/active_storage_validations/concerns/symbolizable.rb +12 -0
- data/lib/active_storage_validations/content_type_validator.rb +47 -8
- data/lib/active_storage_validations/dimension_validator.rb +30 -15
- data/lib/active_storage_validations/limit_validator.rb +48 -8
- data/lib/active_storage_validations/matchers/aspect_ratio_validator_matcher.rb +119 -0
- data/lib/active_storage_validations/matchers/attached_validator_matcher.rb +46 -33
- data/lib/active_storage_validations/matchers/base_size_validator_matcher.rb +134 -0
- data/lib/active_storage_validations/matchers/concerns/active_storageable.rb +17 -0
- data/lib/active_storage_validations/matchers/concerns/allow_blankable.rb +26 -0
- data/lib/active_storage_validations/matchers/concerns/attachable.rb +48 -0
- data/lib/active_storage_validations/matchers/concerns/contextable.rb +47 -0
- data/lib/active_storage_validations/matchers/concerns/messageable.rb +26 -0
- data/lib/active_storage_validations/matchers/concerns/rspecable.rb +25 -0
- data/lib/active_storage_validations/matchers/concerns/validatable.rb +54 -0
- data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +76 -52
- data/lib/active_storage_validations/matchers/dimension_validator_matcher.rb +93 -55
- data/lib/active_storage_validations/matchers/processable_image_validator_matcher.rb +78 -0
- data/lib/active_storage_validations/matchers/size_validator_matcher.rb +9 -88
- data/lib/active_storage_validations/matchers/total_size_validator_matcher.rb +40 -0
- data/lib/active_storage_validations/matchers.rb +3 -0
- data/lib/active_storage_validations/metadata.rb +60 -28
- data/lib/active_storage_validations/processable_image_validator.rb +16 -5
- data/lib/active_storage_validations/size_validator.rb +18 -43
- data/lib/active_storage_validations/total_size_validator.rb +49 -0
- data/lib/active_storage_validations/version.rb +1 -1
- data/lib/active_storage_validations.rb +3 -2
- metadata +42 -26
- data/lib/active_storage_validations/error_handler.rb +0 -18
@@ -2,20 +2,47 @@
|
|
2
2
|
|
3
3
|
# Big thank you to the paperclip validation matchers:
|
4
4
|
# https://github.com/thoughtbot/paperclip/blob/v6.1.0/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb
|
5
|
+
|
6
|
+
require_relative 'concerns/active_storageable.rb'
|
7
|
+
require_relative 'concerns/allow_blankable.rb'
|
8
|
+
require_relative 'concerns/attachable.rb'
|
9
|
+
require_relative 'concerns/contextable.rb'
|
10
|
+
require_relative 'concerns/messageable.rb'
|
11
|
+
require_relative 'concerns/rspecable.rb'
|
12
|
+
require_relative 'concerns/validatable.rb'
|
13
|
+
|
5
14
|
module ActiveStorageValidations
|
6
15
|
module Matchers
|
7
|
-
def validate_content_type_of(
|
8
|
-
ContentTypeValidatorMatcher.new(
|
16
|
+
def validate_content_type_of(attribute_name)
|
17
|
+
ContentTypeValidatorMatcher.new(attribute_name)
|
9
18
|
end
|
10
19
|
|
11
20
|
class ContentTypeValidatorMatcher
|
21
|
+
include ActiveStorageable
|
22
|
+
include AllowBlankable
|
23
|
+
include Attachable
|
24
|
+
include Contextable
|
25
|
+
include Messageable
|
26
|
+
include Rspecable
|
27
|
+
include Validatable
|
28
|
+
|
12
29
|
def initialize(attribute_name)
|
30
|
+
initialize_allow_blankable
|
31
|
+
initialize_contextable
|
32
|
+
initialize_messageable
|
33
|
+
initialize_rspecable
|
13
34
|
@attribute_name = attribute_name
|
14
|
-
@
|
35
|
+
@allowed_types = @rejected_types = []
|
15
36
|
end
|
16
37
|
|
17
38
|
def description
|
18
|
-
"validate the content types allowed on
|
39
|
+
"validate the content types allowed on :#{@attribute_name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def failure_message
|
43
|
+
message = ["is expected to validate the content types of :#{@attribute_name}"]
|
44
|
+
build_failure_message(message)
|
45
|
+
message.join("\n")
|
19
46
|
end
|
20
47
|
|
21
48
|
def allowing(*types)
|
@@ -28,83 +55,80 @@ module ActiveStorageValidations
|
|
28
55
|
self
|
29
56
|
end
|
30
57
|
|
31
|
-
def with_message(message)
|
32
|
-
@custom_message = message
|
33
|
-
self
|
34
|
-
end
|
35
|
-
|
36
58
|
def matches?(subject)
|
37
59
|
@subject = subject.is_a?(Class) ? subject.new : subject
|
38
|
-
|
60
|
+
|
61
|
+
is_a_valid_active_storage_attribute? &&
|
62
|
+
is_context_valid? &&
|
63
|
+
is_allowing_blank? &&
|
64
|
+
is_custom_message_valid? &&
|
65
|
+
all_allowed_types_allowed? &&
|
66
|
+
all_rejected_types_rejected?
|
39
67
|
end
|
40
68
|
|
41
|
-
|
42
|
-
message = ["Expected #{@attribute_name}"]
|
69
|
+
protected
|
43
70
|
|
44
|
-
|
45
|
-
|
46
|
-
message << "#{@
|
71
|
+
def build_failure_message(message)
|
72
|
+
if @allowed_types_not_allowed.present?
|
73
|
+
message << " the following content type#{'s' if @allowed_types.count > 1} should be allowed: :#{@allowed_types.join(", :")}"
|
74
|
+
message << " but #{pluralize(@allowed_types_not_allowed)} rejected"
|
47
75
|
end
|
48
76
|
|
49
|
-
if @
|
50
|
-
message << "
|
51
|
-
message << "#{@
|
77
|
+
if @rejected_types_not_rejected.present?
|
78
|
+
message << " the following content type#{'s' if @rejected_types.count > 1} should be rejected: :#{@rejected_types.join(", :")}"
|
79
|
+
message << " but #{pluralize(@rejected_types_not_rejected)} accepted"
|
52
80
|
end
|
53
|
-
|
54
|
-
message.join("\n")
|
55
81
|
end
|
56
82
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
def allowed_types
|
66
|
-
@allowed_types || []
|
83
|
+
def pluralize(types)
|
84
|
+
if types.count == 1
|
85
|
+
":#{types[0]} was"
|
86
|
+
else
|
87
|
+
":#{types.join(", :")} were"
|
88
|
+
end
|
67
89
|
end
|
68
90
|
|
69
|
-
def
|
70
|
-
@
|
91
|
+
def all_allowed_types_allowed?
|
92
|
+
@allowed_types_not_allowed ||= @allowed_types.reject { |type| type_allowed?(type) }
|
93
|
+
@allowed_types_not_allowed.empty?
|
71
94
|
end
|
72
95
|
|
73
|
-
def
|
74
|
-
@
|
75
|
-
@
|
96
|
+
def all_rejected_types_rejected?
|
97
|
+
@rejected_types_not_rejected ||= @rejected_types.select { |type| type_allowed?(type) }
|
98
|
+
@rejected_types_not_rejected.empty?
|
76
99
|
end
|
77
100
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
101
|
+
def type_allowed?(type)
|
102
|
+
attach_file_of_type(type)
|
103
|
+
validate
|
104
|
+
detach_file
|
105
|
+
is_valid?
|
81
106
|
end
|
82
107
|
|
83
|
-
def
|
108
|
+
def attach_file_of_type(type)
|
84
109
|
@subject.public_send(@attribute_name).attach(attachment_for(type))
|
85
|
-
@subject.validate
|
86
|
-
@subject.errors.details[@attribute_name].none? do |error|
|
87
|
-
error[:error].to_s.include?(error_message)
|
88
|
-
end
|
89
110
|
end
|
90
111
|
|
91
|
-
def
|
112
|
+
def is_custom_message_valid?
|
92
113
|
return true unless @custom_message
|
93
114
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
error[:error].to_s.include?(error_message)
|
98
|
-
end
|
115
|
+
attach_invalid_content_type_file
|
116
|
+
validate
|
117
|
+
has_an_error_message_which_is_custom_message?
|
99
118
|
end
|
100
119
|
|
101
|
-
def
|
102
|
-
@
|
120
|
+
def attach_invalid_content_type_file
|
121
|
+
@subject.public_send(@attribute_name).attach(attachment_for('fake/fake'))
|
103
122
|
end
|
104
123
|
|
105
124
|
def attachment_for(type)
|
106
125
|
suffix = type.to_s.split('/').last
|
107
|
-
|
126
|
+
|
127
|
+
{
|
128
|
+
io: Tempfile.new('.'),
|
129
|
+
filename: "test.#{suffix}",
|
130
|
+
content_type: type
|
131
|
+
}
|
108
132
|
end
|
109
133
|
end
|
110
134
|
end
|
@@ -1,20 +1,50 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'concerns/active_storageable.rb'
|
4
|
+
require_relative 'concerns/allow_blankable.rb'
|
5
|
+
require_relative 'concerns/attachable'
|
6
|
+
require_relative 'concerns/contextable.rb'
|
7
|
+
require_relative 'concerns/messageable.rb'
|
8
|
+
require_relative 'concerns/rspecable.rb'
|
9
|
+
require_relative 'concerns/validatable.rb'
|
10
|
+
|
3
11
|
module ActiveStorageValidations
|
4
12
|
module Matchers
|
5
|
-
def validate_dimensions_of(
|
6
|
-
DimensionValidatorMatcher.new(
|
13
|
+
def validate_dimensions_of(attribute_name)
|
14
|
+
DimensionValidatorMatcher.new(attribute_name)
|
7
15
|
end
|
8
16
|
|
9
17
|
class DimensionValidatorMatcher
|
18
|
+
include ActiveStorageable
|
19
|
+
include AllowBlankable
|
20
|
+
include Attachable
|
21
|
+
include Contextable
|
22
|
+
include Messageable
|
23
|
+
include Rspecable
|
24
|
+
include Validatable
|
25
|
+
|
10
26
|
def initialize(attribute_name)
|
27
|
+
initialize_allow_blankable
|
28
|
+
initialize_contextable
|
29
|
+
initialize_messageable
|
30
|
+
initialize_rspecable
|
11
31
|
@attribute_name = attribute_name
|
12
32
|
@width_min = @width_max = @height_min = @height_max = nil
|
13
|
-
@custom_message = nil
|
14
33
|
end
|
15
34
|
|
16
35
|
def description
|
17
|
-
"validate image dimensions of
|
36
|
+
"validate the image dimensions of :#{@attribute_name}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def failure_message
|
40
|
+
message = ["is expected to validate dimensions of :#{@attribute_name}"]
|
41
|
+
build_failure_message(message)
|
42
|
+
message.join("\n")
|
43
|
+
end
|
44
|
+
|
45
|
+
def width(width)
|
46
|
+
@width_min = @width_max = width
|
47
|
+
self
|
18
48
|
end
|
19
49
|
|
20
50
|
def width_min(width)
|
@@ -27,13 +57,13 @@ module ActiveStorageValidations
|
|
27
57
|
self
|
28
58
|
end
|
29
59
|
|
30
|
-
def
|
31
|
-
@
|
60
|
+
def width_between(range)
|
61
|
+
@width_min, @width_max = range.first, range.last
|
32
62
|
self
|
33
63
|
end
|
34
64
|
|
35
|
-
def
|
36
|
-
@
|
65
|
+
def height(height)
|
66
|
+
@height_min = @height_max = height
|
37
67
|
self
|
38
68
|
end
|
39
69
|
|
@@ -47,42 +77,40 @@ module ActiveStorageValidations
|
|
47
77
|
self
|
48
78
|
end
|
49
79
|
|
50
|
-
def width_between(range)
|
51
|
-
@width_min, @width_max = range.first, range.last
|
52
|
-
self
|
53
|
-
end
|
54
|
-
|
55
80
|
def height_between(range)
|
56
81
|
@height_min, @height_max = range.first, range.last
|
57
82
|
self
|
58
83
|
end
|
59
84
|
|
60
|
-
def height(height)
|
61
|
-
@height_min = @height_max = height
|
62
|
-
self
|
63
|
-
end
|
64
|
-
|
65
85
|
def matches?(subject)
|
66
86
|
@subject = subject.is_a?(Class) ? subject.new : subject
|
67
|
-
responds_to_methods &&
|
68
|
-
width_not_smaller_than_min? && width_larger_than_min? && width_smaller_than_max? && width_not_larger_than_max? && width_equals? &&
|
69
|
-
height_not_smaller_than_min? && height_larger_than_min? && height_smaller_than_max? && height_not_larger_than_max? && height_equals?
|
70
|
-
end
|
71
87
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
88
|
+
is_a_valid_active_storage_attribute? &&
|
89
|
+
is_context_valid? &&
|
90
|
+
is_allowing_blank? &&
|
91
|
+
is_custom_message_valid? &&
|
92
|
+
width_not_smaller_than_min? &&
|
93
|
+
width_larger_than_min? &&
|
94
|
+
width_smaller_than_max? &&
|
95
|
+
width_not_larger_than_max? &&
|
96
|
+
width_equals? &&
|
97
|
+
height_not_smaller_than_min? &&
|
98
|
+
height_larger_than_min? &&
|
99
|
+
height_smaller_than_max? &&
|
100
|
+
height_not_larger_than_max? &&
|
101
|
+
height_equals?
|
78
102
|
end
|
79
103
|
|
80
104
|
protected
|
81
105
|
|
82
|
-
def
|
83
|
-
@
|
84
|
-
|
85
|
-
|
106
|
+
def build_failure_message(message)
|
107
|
+
return unless @failure_message_artefacts.present?
|
108
|
+
|
109
|
+
message << " but there seem to have issues with the matcher methods you used, since:"
|
110
|
+
@failure_message_artefacts.each do |error_case|
|
111
|
+
message << " validation failed when provided with a #{error_case[:width]}x#{error_case[:height]}px test image"
|
112
|
+
end
|
113
|
+
message << " whereas it should have passed"
|
86
114
|
end
|
87
115
|
|
88
116
|
def valid_width
|
@@ -94,62 +122,72 @@ module ActiveStorageValidations
|
|
94
122
|
end
|
95
123
|
|
96
124
|
def width_not_smaller_than_min?
|
97
|
-
@width_min.nil? || !passes_validation_with_dimensions(@width_min - 1, valid_height
|
125
|
+
@width_min.nil? || !passes_validation_with_dimensions(@width_min - 1, valid_height)
|
98
126
|
end
|
99
127
|
|
100
128
|
def width_larger_than_min?
|
101
|
-
@width_min.nil? || @width_min == @width_max || passes_validation_with_dimensions(@width_min + 1, valid_height
|
129
|
+
@width_min.nil? || @width_min == @width_max || passes_validation_with_dimensions(@width_min + 1, valid_height)
|
102
130
|
end
|
103
131
|
|
104
132
|
def width_smaller_than_max?
|
105
|
-
@width_max.nil? || @width_min == @width_max || passes_validation_with_dimensions(@width_max - 1, valid_height
|
133
|
+
@width_max.nil? || @width_min == @width_max || passes_validation_with_dimensions(@width_max - 1, valid_height)
|
106
134
|
end
|
107
135
|
|
108
136
|
def width_not_larger_than_max?
|
109
|
-
@width_max.nil? || !passes_validation_with_dimensions(@width_max + 1, valid_height
|
137
|
+
@width_max.nil? || !passes_validation_with_dimensions(@width_max + 1, valid_height)
|
110
138
|
end
|
111
139
|
|
112
140
|
def width_equals?
|
113
|
-
@width_min.nil? || @width_min != @width_max || passes_validation_with_dimensions(@width_min, valid_height
|
141
|
+
@width_min.nil? || @width_min != @width_max || passes_validation_with_dimensions(@width_min, valid_height)
|
114
142
|
end
|
115
143
|
|
116
144
|
def height_not_smaller_than_min?
|
117
|
-
@height_min.nil? || !passes_validation_with_dimensions(valid_width, @height_min - 1
|
145
|
+
@height_min.nil? || !passes_validation_with_dimensions(valid_width, @height_min - 1)
|
118
146
|
end
|
119
147
|
|
120
148
|
def height_larger_than_min?
|
121
|
-
@height_min.nil? || @height_min == @height_max || passes_validation_with_dimensions(valid_width, @height_min + 1
|
149
|
+
@height_min.nil? || @height_min == @height_max || passes_validation_with_dimensions(valid_width, @height_min + 1)
|
122
150
|
end
|
123
151
|
|
124
152
|
def height_smaller_than_max?
|
125
|
-
@height_max.nil? || @height_min == @height_max || passes_validation_with_dimensions(valid_width, @height_max - 1
|
153
|
+
@height_max.nil? || @height_min == @height_max || passes_validation_with_dimensions(valid_width, @height_max - 1)
|
126
154
|
end
|
127
155
|
|
128
156
|
def height_not_larger_than_max?
|
129
|
-
@height_max.nil? || !passes_validation_with_dimensions(valid_width, @height_max + 1
|
157
|
+
@height_max.nil? || !passes_validation_with_dimensions(valid_width, @height_max + 1)
|
130
158
|
end
|
131
159
|
|
132
160
|
def height_equals?
|
133
|
-
@height_min.nil? || @height_min != @height_max || passes_validation_with_dimensions(valid_width, @height_min
|
161
|
+
@height_min.nil? || @height_min != @height_max || passes_validation_with_dimensions(valid_width, @height_min)
|
134
162
|
end
|
135
163
|
|
136
|
-
def passes_validation_with_dimensions(width, height
|
137
|
-
|
164
|
+
def passes_validation_with_dimensions(width, height)
|
165
|
+
mock_dimensions_for(attach_file, width, height) do
|
166
|
+
validate
|
167
|
+
detach_file
|
168
|
+
is_valid? || add_failure_message_artefact(width, height)
|
169
|
+
end
|
170
|
+
end
|
138
171
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
172
|
+
def add_failure_message_artefact(width, height)
|
173
|
+
@failure_message_artefacts << { width: width, height: height }
|
174
|
+
false
|
175
|
+
end
|
176
|
+
|
177
|
+
def is_custom_message_valid?
|
178
|
+
return true unless @custom_message
|
179
|
+
|
180
|
+
mock_dimensions_for(attach_file, -1, -1) do
|
181
|
+
validate
|
182
|
+
detach_file
|
183
|
+
has_an_error_message_which_is_custom_message?
|
148
184
|
end
|
149
185
|
end
|
150
186
|
|
151
|
-
def
|
152
|
-
|
187
|
+
def mock_dimensions_for(attachment, width, height)
|
188
|
+
Matchers.mock_metadata(attachment, width, height) do
|
189
|
+
yield
|
190
|
+
end
|
153
191
|
end
|
154
192
|
end
|
155
193
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'concerns/active_storageable.rb'
|
4
|
+
require_relative 'concerns/allow_blankable.rb'
|
5
|
+
require_relative 'concerns/attachable.rb'
|
6
|
+
require_relative 'concerns/contextable.rb'
|
7
|
+
require_relative 'concerns/messageable.rb'
|
8
|
+
require_relative 'concerns/rspecable.rb'
|
9
|
+
require_relative 'concerns/validatable.rb'
|
10
|
+
|
11
|
+
module ActiveStorageValidations
|
12
|
+
module Matchers
|
13
|
+
def validate_processable_image_of(name)
|
14
|
+
ProcessableImageValidatorMatcher.new(name)
|
15
|
+
end
|
16
|
+
|
17
|
+
class ProcessableImageValidatorMatcher
|
18
|
+
include ActiveStorageable
|
19
|
+
include AllowBlankable
|
20
|
+
include Attachable
|
21
|
+
include Contextable
|
22
|
+
include Messageable
|
23
|
+
include Rspecable
|
24
|
+
include Validatable
|
25
|
+
|
26
|
+
def initialize(attribute_name)
|
27
|
+
initialize_allow_blankable
|
28
|
+
initialize_contextable
|
29
|
+
initialize_messageable
|
30
|
+
initialize_rspecable
|
31
|
+
@attribute_name = attribute_name
|
32
|
+
end
|
33
|
+
|
34
|
+
def description
|
35
|
+
"validate that :#{@attribute_name} is a processable image"
|
36
|
+
end
|
37
|
+
|
38
|
+
def failure_message
|
39
|
+
"is expected to validate the processable image of :#{@attribute_name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def matches?(subject)
|
43
|
+
@subject = subject.is_a?(Class) ? subject.new : subject
|
44
|
+
|
45
|
+
is_a_valid_active_storage_attribute? &&
|
46
|
+
is_context_valid? &&
|
47
|
+
is_custom_message_valid? &&
|
48
|
+
is_valid_when_image_processable? &&
|
49
|
+
is_invalid_when_image_not_processable?
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def is_valid_when_image_processable?
|
55
|
+
attach_file(processable_image)
|
56
|
+
validate
|
57
|
+
detach_file
|
58
|
+
is_valid?
|
59
|
+
end
|
60
|
+
|
61
|
+
def is_invalid_when_image_not_processable?
|
62
|
+
attach_file(not_processable_image)
|
63
|
+
validate
|
64
|
+
detach_file
|
65
|
+
!is_valid?
|
66
|
+
end
|
67
|
+
|
68
|
+
def is_custom_message_valid?
|
69
|
+
return true unless @custom_message
|
70
|
+
|
71
|
+
attach_file(not_processable_image)
|
72
|
+
validate
|
73
|
+
detach_file
|
74
|
+
has_an_error_message_which_is_custom_message?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -1,101 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require_relative 'base_size_validator_matcher'
|
4
|
+
|
5
5
|
module ActiveStorageValidations
|
6
6
|
module Matchers
|
7
|
-
def validate_size_of(
|
8
|
-
SizeValidatorMatcher.new(
|
7
|
+
def validate_size_of(attribute_name)
|
8
|
+
SizeValidatorMatcher.new(attribute_name)
|
9
9
|
end
|
10
10
|
|
11
|
-
class SizeValidatorMatcher
|
12
|
-
def initialize(attribute_name)
|
13
|
-
@attribute_name = attribute_name
|
14
|
-
@min = @max = nil
|
15
|
-
@custom_message = nil
|
16
|
-
end
|
17
|
-
|
11
|
+
class SizeValidatorMatcher < BaseSizeValidatorMatcher
|
18
12
|
def description
|
19
|
-
"validate file size of
|
20
|
-
end
|
21
|
-
|
22
|
-
def less_than(size)
|
23
|
-
@max = size - 1.byte
|
24
|
-
self
|
25
|
-
end
|
26
|
-
|
27
|
-
def less_than_or_equal_to(size)
|
28
|
-
@max = size
|
29
|
-
self
|
30
|
-
end
|
31
|
-
|
32
|
-
def greater_than(size)
|
33
|
-
@min = size + 1.byte
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
|
-
def greater_than_or_equal_to(size)
|
38
|
-
@min = size
|
39
|
-
self
|
40
|
-
end
|
41
|
-
|
42
|
-
def between(range)
|
43
|
-
@min, @max = range.first, range.last
|
44
|
-
self
|
45
|
-
end
|
46
|
-
|
47
|
-
def with_message(message)
|
48
|
-
@custom_message = message
|
49
|
-
self
|
50
|
-
end
|
51
|
-
|
52
|
-
def matches?(subject)
|
53
|
-
@subject = subject.is_a?(Class) ? subject.new : subject
|
54
|
-
responds_to_methods && not_lower_than_min? && higher_than_min? && lower_than_max? && not_higher_than_max?
|
13
|
+
"validate file size of :#{@attribute_name}"
|
55
14
|
end
|
56
15
|
|
57
16
|
def failure_message
|
58
|
-
"is expected to validate file size of
|
59
|
-
|
60
|
-
|
61
|
-
def failure_message_when_negated
|
62
|
-
"is expected to not validate file size of #{@attribute_name} to be between #{@min} and #{@max} bytes"
|
63
|
-
end
|
64
|
-
|
65
|
-
protected
|
66
|
-
|
67
|
-
def responds_to_methods
|
68
|
-
@subject.respond_to?(@attribute_name) &&
|
69
|
-
@subject.public_send(@attribute_name).respond_to?(:attach) &&
|
70
|
-
@subject.public_send(@attribute_name).respond_to?(:detach)
|
71
|
-
end
|
72
|
-
|
73
|
-
def not_lower_than_min?
|
74
|
-
@min.nil? || !passes_validation_with_size(@min - 1)
|
75
|
-
end
|
76
|
-
|
77
|
-
def higher_than_min?
|
78
|
-
@min.nil? || passes_validation_with_size(@min + 1)
|
79
|
-
end
|
80
|
-
|
81
|
-
def lower_than_max?
|
82
|
-
@max.nil? || @max == Float::INFINITY || passes_validation_with_size(@max - 1)
|
83
|
-
end
|
84
|
-
|
85
|
-
def not_higher_than_max?
|
86
|
-
@max.nil? || @max == Float::INFINITY || !passes_validation_with_size(@max + 1)
|
87
|
-
end
|
88
|
-
|
89
|
-
def passes_validation_with_size(new_size)
|
90
|
-
io = Tempfile.new('Hello world!')
|
91
|
-
Matchers.stub_method(io, :size, new_size) do
|
92
|
-
@subject.public_send(@attribute_name).attach(io: io, filename: 'test.png', content_type: 'image/pg')
|
93
|
-
@subject.validate
|
94
|
-
exclude_error_message = @custom_message || "file_size_not_"
|
95
|
-
@subject.errors.details[@attribute_name].none? do |error|
|
96
|
-
error[:error].to_s.include?(exclude_error_message)
|
97
|
-
end
|
98
|
-
end
|
17
|
+
message = ["is expected to validate file size of :#{@attribute_name}"]
|
18
|
+
build_failure_message(message)
|
19
|
+
message.join("\n")
|
99
20
|
end
|
100
21
|
end
|
101
22
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_size_validator_matcher'
|
4
|
+
|
5
|
+
module ActiveStorageValidations
|
6
|
+
module Matchers
|
7
|
+
def validate_total_size_of(attribute_name)
|
8
|
+
TotalSizeValidatorMatcher.new(attribute_name)
|
9
|
+
end
|
10
|
+
|
11
|
+
class TotalSizeValidatorMatcher < BaseSizeValidatorMatcher
|
12
|
+
def description
|
13
|
+
"validate total file size of :#{@attribute_name}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def failure_message
|
17
|
+
message = ["is expected to validate total file size of :#{@attribute_name}"]
|
18
|
+
build_failure_message(message)
|
19
|
+
message.join("\n")
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def attach_file
|
25
|
+
# We attach blobs instead of io for has_many_attached relation
|
26
|
+
@subject.public_send(@attribute_name).attach([dummy_blob])
|
27
|
+
@subject.public_send(@attribute_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def dummy_blob
|
31
|
+
ActiveStorage::Blob.create_and_upload!(
|
32
|
+
io: io,
|
33
|
+
filename: 'test.png',
|
34
|
+
content_type: 'image/png',
|
35
|
+
service_name: 'test'
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_storage_validations/matchers/aspect_ratio_validator_matcher'
|
3
4
|
require 'active_storage_validations/matchers/attached_validator_matcher'
|
5
|
+
require 'active_storage_validations/matchers/processable_image_validator_matcher'
|
4
6
|
require 'active_storage_validations/matchers/content_type_validator_matcher'
|
5
7
|
require 'active_storage_validations/matchers/dimension_validator_matcher'
|
6
8
|
require 'active_storage_validations/matchers/size_validator_matcher'
|
9
|
+
require 'active_storage_validations/matchers/total_size_validator_matcher'
|
7
10
|
|
8
11
|
module ActiveStorageValidations
|
9
12
|
module Matchers
|