ultra-fast-box 0.0.1
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 +7 -0
- data/shoulda-matchers-8.0.1/LICENSE +22 -0
- data/shoulda-matchers-8.0.1/README.md +567 -0
- data/shoulda-matchers-8.0.1/docs/errors/NonCaseSwappableValueError.md +111 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/callback_matcher.rb +121 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +70 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/flash_store.rb +86 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/permit_matcher.rb +445 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +96 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/render_template_matcher.rb +84 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +145 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +115 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +148 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/route_matcher.rb +207 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/route_params.rb +62 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/session_store.rb +34 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +228 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_session_matcher.rb +163 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +107 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller.rb +24 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +45 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_does_not_exist_error.rb +23 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +232 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +62 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +40 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +48 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb +14 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb +14 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher.rb +695 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/comparison_matcher.rb +157 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +78 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/errors.rb +52 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +125 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/helpers.rb +37 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +45 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +67 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +45 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +44 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/range_matcher.rb +71 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +53 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb +26 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb +26 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb +101 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +21 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers.rb +14 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +180 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +128 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +567 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +185 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +272 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +664 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +575 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +711 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +428 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +62 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_matcher.rb +195 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_message_finder.rb +63 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validator.rb +127 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model.rb +96 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +217 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matcher.rb +2134 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +74 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +62 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +41 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +105 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +101 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +89 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +142 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +71 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +41 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +76 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +42 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +65 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +784 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/encrypt_matcher.rb +174 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_attached_matcher.rb +343 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +366 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +287 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +104 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +95 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +83 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +132 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/normalize_matcher.rb +151 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/serialize_matcher.rb +203 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/model.rb +58 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/namespace.rb +39 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +49 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +55 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness.rb +14 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +1197 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record.rb +37 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/configuration.rb +31 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double.rb +103 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double_collection.rb +60 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +31 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/method_call.rb +44 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/object_double.rb +43 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +32 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/stub_implementation.rb +31 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/world.rb +63 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak.rb +38 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/error.rb +29 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb +15 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent/delegate_method_matcher.rb +540 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent.rb +11 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/configuration.rb +70 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/configuration_error.rb +9 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/inclusion.rb +20 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/action_controller.rb +33 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/active_model.rb +26 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/active_record.rb +26 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/missing_library.rb +19 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/rails.rb +31 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/routing.rb +29 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries.rb +16 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/rails.rb +12 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/registry.rb +28 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +37 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +36 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +37 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +40 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb +29 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +36 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks.rb +16 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations.rb +43 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/matcher_collection.rb +99 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/matcher_context.rb +36 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/rails_shim.rb +190 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/routing.rb +10 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/util/word_wrap.rb +211 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/util.rb +110 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/version.rb +6 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/warn.rb +28 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers.rb +25 -0
- data/shoulda-matchers-8.0.1/lib/shoulda-matchers.rb +1 -0
- data/shoulda-matchers-8.0.1/shoulda-matchers.gemspec +43 -0
- data/ultra-fast-box.gemspec +12 -0
- metadata +179 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
# The `have_implicit_order_column` matcher tests that the model has `implicit_order_column`
|
|
5
|
+
# assigned to one of the table columns.
|
|
6
|
+
#
|
|
7
|
+
# class Product < ApplicationRecord
|
|
8
|
+
# self.implicit_order_column = :created_at
|
|
9
|
+
# end
|
|
10
|
+
#
|
|
11
|
+
# # RSpec
|
|
12
|
+
# RSpec.describe Product, type: :model do
|
|
13
|
+
# it { should have_implicit_order_column(:created_at) }
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# # Minitest (Shoulda)
|
|
17
|
+
# class ProductTest < ActiveSupport::TestCase
|
|
18
|
+
# should have_implicit_order_column(:created_at)
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# @return [HaveImplicitOrderColumnMatcher]
|
|
22
|
+
#
|
|
23
|
+
def have_implicit_order_column(column_name)
|
|
24
|
+
HaveImplicitOrderColumnMatcher.new(column_name)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @private
|
|
28
|
+
class HaveImplicitOrderColumnMatcher
|
|
29
|
+
attr_reader :failure_message
|
|
30
|
+
|
|
31
|
+
def initialize(column_name)
|
|
32
|
+
@column_name = column_name
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def matches?(subject)
|
|
36
|
+
@subject = subject
|
|
37
|
+
check_column_exists!
|
|
38
|
+
check_implicit_order_column_matches!
|
|
39
|
+
true
|
|
40
|
+
rescue SecondaryCheckFailedError => e
|
|
41
|
+
@failure_message = Shoulda::Matchers.word_wrap(
|
|
42
|
+
"Expected #{model.name} to #{expectation}, " +
|
|
43
|
+
"but that could not be proved: #{e.message}.",
|
|
44
|
+
)
|
|
45
|
+
false
|
|
46
|
+
rescue PrimaryCheckFailedError => e
|
|
47
|
+
@failure_message = Shoulda::Matchers.word_wrap(
|
|
48
|
+
"Expected #{model.name} to #{expectation}, but #{e.message}.",
|
|
49
|
+
)
|
|
50
|
+
false
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def failure_message_when_negated
|
|
54
|
+
Shoulda::Matchers.word_wrap(
|
|
55
|
+
"Expected #{model.name} not to #{expectation}, but it did.",
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def description
|
|
60
|
+
expectation
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
attr_reader :column_name, :subject
|
|
66
|
+
|
|
67
|
+
def check_column_exists!
|
|
68
|
+
matcher = HaveDbColumnMatcher.new(column_name)
|
|
69
|
+
|
|
70
|
+
if !matcher.matches?(@subject)
|
|
71
|
+
raise SecondaryCheckFailedError.new(
|
|
72
|
+
"The :#{model.table_name} table does not have a " +
|
|
73
|
+
":#{column_name} column",
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def check_implicit_order_column_matches!
|
|
79
|
+
if model.implicit_order_column.to_s != column_name.to_s
|
|
80
|
+
message =
|
|
81
|
+
if model.implicit_order_column.nil?
|
|
82
|
+
'implicit_order_column is not set'
|
|
83
|
+
else
|
|
84
|
+
"it is :#{model.implicit_order_column}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
raise PrimaryCheckFailedError.new(message)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def model
|
|
92
|
+
subject.class
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def expectation
|
|
96
|
+
"have an implicit_order_column of :#{column_name}"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class SecondaryCheckFailedError < StandardError; end
|
|
100
|
+
class PrimaryCheckFailedError < StandardError; end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
# The `have_readonly_attribute` matcher tests usage of the
|
|
5
|
+
# `attr_readonly` macro.
|
|
6
|
+
#
|
|
7
|
+
# class User < ActiveRecord::Base
|
|
8
|
+
# attr_readonly :password
|
|
9
|
+
# end
|
|
10
|
+
#
|
|
11
|
+
# # RSpec
|
|
12
|
+
# RSpec.describe User, type: :model do
|
|
13
|
+
# it { should have_readonly_attribute(:password) }
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# # Minitest (Shoulda)
|
|
17
|
+
# class UserTest < ActiveSupport::TestCase
|
|
18
|
+
# should have_readonly_attribute(:password)
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# #### Multiple attributes
|
|
22
|
+
#
|
|
23
|
+
# You can pass multiple attributes to assert that each one has the
|
|
24
|
+
# validation. Any qualifier chained on the matcher is applied to
|
|
25
|
+
# every attribute uniformly.
|
|
26
|
+
#
|
|
27
|
+
# class User < ActiveRecord::Base
|
|
28
|
+
# attr_readonly :name, :email
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# # RSpec
|
|
32
|
+
# RSpec.describe User, type: :model do
|
|
33
|
+
# it { should have_readonly_attribute(:name, :email) }
|
|
34
|
+
# end
|
|
35
|
+
#
|
|
36
|
+
# # Minitest (Shoulda)
|
|
37
|
+
# class UserTest < ActiveSupport::TestCase
|
|
38
|
+
# should have_readonly_attribute(:name, :email)
|
|
39
|
+
# end
|
|
40
|
+
#
|
|
41
|
+
# @return [HaveReadonlyAttributeMatcher]
|
|
42
|
+
#
|
|
43
|
+
def have_readonly_attribute(*values)
|
|
44
|
+
MatcherCollection.build(values) { |value| HaveReadonlyAttributeMatcher.new(value) }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @private
|
|
48
|
+
class HaveReadonlyAttributeMatcher
|
|
49
|
+
def initialize(attribute)
|
|
50
|
+
@attribute = attribute.to_s
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
attr_reader :failure_message, :failure_message_when_negated
|
|
54
|
+
|
|
55
|
+
def failure_reason
|
|
56
|
+
@failure_message
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def matches?(subject)
|
|
60
|
+
@subject = subject
|
|
61
|
+
if readonly_attributes.include?(@attribute)
|
|
62
|
+
@failure_message_when_negated = "Did not expect #{@attribute}"\
|
|
63
|
+
' to be read-only'
|
|
64
|
+
true
|
|
65
|
+
else
|
|
66
|
+
@failure_message =
|
|
67
|
+
if readonly_attributes.empty?
|
|
68
|
+
"#{class_name} attribute #{@attribute} " <<
|
|
69
|
+
'is not read-only'
|
|
70
|
+
else
|
|
71
|
+
"#{class_name} is making " <<
|
|
72
|
+
"#{readonly_attributes.to_a.to_sentence} " <<
|
|
73
|
+
"read-only, but not #{@attribute}."
|
|
74
|
+
end
|
|
75
|
+
false
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def description
|
|
80
|
+
"make #{@attribute} read-only"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def readonly_attributes
|
|
86
|
+
@_readonly_attributes ||= @subject.class.readonly_attributes || []
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def class_name
|
|
90
|
+
@subject.class.name
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
# The `have_rich_text` matcher tests usage of the
|
|
5
|
+
# `has_rich_text` macro.
|
|
6
|
+
#
|
|
7
|
+
# #### Example
|
|
8
|
+
#
|
|
9
|
+
# class Post < ActiveRecord
|
|
10
|
+
# has_rich_text :content
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# # RSpec
|
|
14
|
+
# RSpec.describe Post, type: :model do
|
|
15
|
+
# it { should have_rich_text(:content) }
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# # Minitest (Shoulda)
|
|
19
|
+
# class PostTest < ActiveSupport::TestCase
|
|
20
|
+
# should have_rich_text(:content)
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# @return [HaveRichTextMatcher]
|
|
24
|
+
#
|
|
25
|
+
def have_rich_text(rich_text_attribute)
|
|
26
|
+
HaveRichTextMatcher.new(rich_text_attribute)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @private
|
|
30
|
+
class HaveRichTextMatcher
|
|
31
|
+
def initialize(rich_text_attribute)
|
|
32
|
+
@rich_text_attribute = rich_text_attribute
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def description
|
|
36
|
+
"have configured :#{rich_text_attribute} as a "\
|
|
37
|
+
'ActionText::RichText association'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def failure_message
|
|
41
|
+
"Expected #{subject.class} to #{error_description}"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def failure_message_when_negated
|
|
45
|
+
"Did not expect #{subject.class} to have ActionText::RichText"\
|
|
46
|
+
" :#{rich_text_attribute}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def matches?(subject)
|
|
50
|
+
@subject = subject
|
|
51
|
+
@error = run_checks
|
|
52
|
+
@error.nil?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
attr_reader :error, :rich_text_attribute, :subject
|
|
58
|
+
|
|
59
|
+
def run_checks
|
|
60
|
+
if !has_attribute?
|
|
61
|
+
":#{rich_text_attribute} does not exist"
|
|
62
|
+
elsif !has_expected_action_text?
|
|
63
|
+
:default
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def has_attribute?
|
|
68
|
+
@subject.respond_to?(rich_text_attribute.to_s)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def has_expected_action_text?
|
|
72
|
+
defined?(ActionText::RichText) &&
|
|
73
|
+
@subject.send(rich_text_attribute).
|
|
74
|
+
is_a?(ActionText::RichText)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def error_description
|
|
78
|
+
error == :default ? description : "#{description} but #{error}"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
# The `have_secure_token` matcher tests usage of the
|
|
5
|
+
# `has_secure_token` macro.
|
|
6
|
+
#
|
|
7
|
+
# class User < ActiveRecord
|
|
8
|
+
# has_secure_token
|
|
9
|
+
# has_secure_token :auth_token
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# # RSpec
|
|
13
|
+
# RSpec.describe User, type: :model do
|
|
14
|
+
# it { should have_secure_token }
|
|
15
|
+
# it { should have_secure_token(:auth_token) }
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# # Minitest (Shoulda)
|
|
19
|
+
# class UserTest < ActiveSupport::TestCase
|
|
20
|
+
# should have_secure_token
|
|
21
|
+
# should have_secure_token(:auth_token)
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# #### Qualifiers
|
|
25
|
+
#
|
|
26
|
+
# ##### ignoring_check_for_db_index
|
|
27
|
+
#
|
|
28
|
+
# By default, this matcher tests that an index is defined on your token
|
|
29
|
+
# column. Use `ignoring_check_for_db_index` if this is not the case.
|
|
30
|
+
#
|
|
31
|
+
# class User < ActiveRecord
|
|
32
|
+
# has_secure_token :auth_token
|
|
33
|
+
# end
|
|
34
|
+
#
|
|
35
|
+
# # RSpec
|
|
36
|
+
# RSpec.describe User, type: :model do
|
|
37
|
+
# it { should have_secure_token(:auth_token).ignoring_check_for_db_index }
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# # Minitest (Shoulda)
|
|
41
|
+
# class UserTest < ActiveSupport::TestCase
|
|
42
|
+
# should have_secure_token(:auth_token).ignoring_check_for_db_index
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# @return [HaveSecureToken]
|
|
46
|
+
#
|
|
47
|
+
def have_secure_token(token_attribute = :token)
|
|
48
|
+
HaveSecureTokenMatcher.new(token_attribute)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @private
|
|
52
|
+
class HaveSecureTokenMatcher
|
|
53
|
+
attr_reader :token_attribute
|
|
54
|
+
|
|
55
|
+
def initialize(token_attribute)
|
|
56
|
+
@token_attribute = token_attribute
|
|
57
|
+
@options = { ignore_check_for_db_index: false }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def description
|
|
61
|
+
"have :#{token_attribute} as a secure token"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def failure_message
|
|
65
|
+
return if !@errors
|
|
66
|
+
|
|
67
|
+
"Expected #{@subject.class} to #{description} but the following " \
|
|
68
|
+
"errors were found: #{@errors.join(', ')}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def failure_message_when_negated
|
|
72
|
+
return if !@errors
|
|
73
|
+
|
|
74
|
+
"Did not expect #{@subject.class} to have secure token " \
|
|
75
|
+
":#{token_attribute}"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def matches?(subject)
|
|
79
|
+
@subject = subject
|
|
80
|
+
@errors = run_checks
|
|
81
|
+
@errors.empty?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def ignoring_check_for_db_index
|
|
85
|
+
@options[:ignore_check_for_db_index] = true
|
|
86
|
+
self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def run_checks
|
|
92
|
+
@errors = []
|
|
93
|
+
if !has_expected_instance_methods?
|
|
94
|
+
@errors << 'missing expected class and instance methods'
|
|
95
|
+
end
|
|
96
|
+
if !has_expected_db_column?
|
|
97
|
+
@errors << "missing correct column #{token_attribute}:string"
|
|
98
|
+
end
|
|
99
|
+
if !@options[:ignore_check_for_db_index] && !has_expected_db_index?
|
|
100
|
+
@errors << "missing unique index for #{table_and_column}"
|
|
101
|
+
end
|
|
102
|
+
@errors
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def has_expected_instance_methods?
|
|
106
|
+
@subject.respond_to?(token_attribute.to_s) &&
|
|
107
|
+
@subject.respond_to?("#{token_attribute}=") &&
|
|
108
|
+
@subject.respond_to?("regenerate_#{token_attribute}") &&
|
|
109
|
+
@subject.class.respond_to?(:generate_unique_secure_token)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def has_expected_db_column?
|
|
113
|
+
matcher = HaveDbColumnMatcher.new(token_attribute).of_type(:string)
|
|
114
|
+
matcher.matches?(@subject)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def has_expected_db_index?
|
|
118
|
+
matcher = HaveDbIndexMatcher.new(token_attribute).unique(true)
|
|
119
|
+
matcher.matches?(@subject)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def table_and_column
|
|
123
|
+
"#{table_name}.#{token_attribute}"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def table_name
|
|
127
|
+
@subject.class.table_name
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
# The `normalize` matcher is used to ensure attribute normalizations
|
|
5
|
+
# are transforming attribute values as expected.
|
|
6
|
+
#
|
|
7
|
+
# Take this model for example:
|
|
8
|
+
#
|
|
9
|
+
# class User < ActiveRecord::Base
|
|
10
|
+
# normalizes :email, with: -> email { email.strip.downcase }
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# You can use `normalize` providing an input and defining the expected
|
|
14
|
+
# normalization output:
|
|
15
|
+
#
|
|
16
|
+
# # RSpec
|
|
17
|
+
# RSpec.describe User, type: :model do
|
|
18
|
+
# it do
|
|
19
|
+
# should normalize(:email).from(" ME@XYZ.COM\n").to("me@xyz.com")
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# # Minitest (Shoulda)
|
|
24
|
+
# class User < ActiveSupport::TestCase
|
|
25
|
+
# should normalize(:email).from(" ME@XYZ.COM\n").to("me@xyz.com")
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# You can use `normalize` to test multiple attributes at once:
|
|
29
|
+
#
|
|
30
|
+
# class User < ActiveRecord::Base
|
|
31
|
+
# normalizes :email, :handle, with: -> value { value.strip.downcase }
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# # RSpec
|
|
35
|
+
# RSpec.describe User, type: :model do
|
|
36
|
+
# it do
|
|
37
|
+
# should normalize(:email, :handle).from(" Example\n").to("example")
|
|
38
|
+
# end
|
|
39
|
+
# end
|
|
40
|
+
#
|
|
41
|
+
# # Minitest (Shoulda)
|
|
42
|
+
# class User < ActiveSupport::TestCase
|
|
43
|
+
# should normalize(:email, :handle).from(" Example\n").to("example")
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# If the normalization accepts nil values with the `apply_to_nil` option,
|
|
47
|
+
# you just need to use `.from(nil).to("Your expected value here")`.
|
|
48
|
+
#
|
|
49
|
+
# class User < ActiveRecord::Base
|
|
50
|
+
# normalizes :name, with: -> name { name&.titleize || 'Untitled' },
|
|
51
|
+
# apply_to_nil: true
|
|
52
|
+
# end
|
|
53
|
+
#
|
|
54
|
+
# # RSpec
|
|
55
|
+
# RSpec.describe User, type: :model do
|
|
56
|
+
# it { should normalize(:name).from("jane doe").to("Jane Doe") }
|
|
57
|
+
# it { should normalize(:name).from(nil).to("Untitled") }
|
|
58
|
+
# end
|
|
59
|
+
#
|
|
60
|
+
# # Minitest (Shoulda)
|
|
61
|
+
# class User < ActiveSupport::TestCase
|
|
62
|
+
# should normalize(:name).from("jane doe").to("Jane Doe")
|
|
63
|
+
# should normalize(:name).from(nil).to("Untitled")
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# @return [NormalizeMatcher]
|
|
67
|
+
#
|
|
68
|
+
def normalize(*attributes)
|
|
69
|
+
if attributes.empty?
|
|
70
|
+
raise ArgumentError, 'need at least one attribute'
|
|
71
|
+
else
|
|
72
|
+
NormalizeMatcher.new(*attributes)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @private
|
|
77
|
+
class NormalizeMatcher
|
|
78
|
+
attr_reader :attributes, :from_value, :to_value, :failure_message,
|
|
79
|
+
:failure_message_when_negated
|
|
80
|
+
|
|
81
|
+
def initialize(*attributes)
|
|
82
|
+
@attributes = attributes
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def description
|
|
86
|
+
%(
|
|
87
|
+
normalize #{attributes.to_sentence(last_word_connector: ' and ')} from
|
|
88
|
+
‹#{from_value.inspect}› to ‹#{to_value.inspect}›
|
|
89
|
+
).squish
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def from(value)
|
|
93
|
+
@from_value = value
|
|
94
|
+
|
|
95
|
+
self
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def to(value)
|
|
99
|
+
@to_value = value
|
|
100
|
+
|
|
101
|
+
self
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def matches?(subject)
|
|
105
|
+
attributes.all? { |attribute| attribute_matches?(subject, attribute) }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def does_not_match?(subject)
|
|
109
|
+
attributes.all? { |attribute| attribute_does_not_match?(subject, attribute) }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
|
|
114
|
+
def attribute_matches?(subject, attribute)
|
|
115
|
+
return true if normalize_attribute?(subject, attribute)
|
|
116
|
+
|
|
117
|
+
@failure_message = build_failure_message(
|
|
118
|
+
attribute,
|
|
119
|
+
subject.class.normalize_value_for(attribute, from_value),
|
|
120
|
+
)
|
|
121
|
+
false
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def attribute_does_not_match?(subject, attribute)
|
|
125
|
+
return true unless normalize_attribute?(subject, attribute)
|
|
126
|
+
|
|
127
|
+
@failure_message_when_negated = build_failure_message_when_negated(attribute)
|
|
128
|
+
false
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def normalize_attribute?(subject, attribute)
|
|
132
|
+
subject.class.normalize_value_for(attribute, from_value) == to_value
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def build_failure_message(attribute, attribute_value)
|
|
136
|
+
%(
|
|
137
|
+
Expected to normalize #{attribute.inspect} from ‹#{from_value.inspect}› to
|
|
138
|
+
‹#{to_value.inspect}› but it was normalized to ‹#{attribute_value.inspect}›
|
|
139
|
+
).squish
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def build_failure_message_when_negated(attribute)
|
|
143
|
+
%(
|
|
144
|
+
Expected to not normalize #{attribute.inspect} from ‹#{from_value.inspect}› to
|
|
145
|
+
‹#{to_value.inspect}› but it was normalized
|
|
146
|
+
).squish
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|