shoulda-matchers 1.1.0 → 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.
- data/.travis.yml +5 -0
- data/Appraisals +6 -0
- data/Gemfile.lock +15 -15
- data/NEWS.md +20 -1
- data/README.md +6 -1
- data/features/step_definitions/rails_steps.rb +3 -3
- data/gemfiles/3.0.gemfile.lock +23 -27
- data/gemfiles/3.1.gemfile.lock +26 -30
- data/gemfiles/3.2.gemfile +16 -0
- data/gemfiles/3.2.gemfile.lock +157 -0
- data/lib/shoulda/matchers/action_controller/assign_to_matcher.rb +46 -29
- data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +6 -2
- data/lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb +12 -7
- data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +28 -15
- data/lib/shoulda/matchers/action_mailer/have_sent_email_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +13 -9
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +9 -8
- data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +8 -6
- data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +63 -8
- data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +67 -34
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +3 -3
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +9 -5
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +6 -3
- data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +27 -23
- data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +38 -25
- data/lib/shoulda/matchers/active_record/association_matcher.rb +49 -33
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +42 -35
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +15 -13
- data/lib/shoulda/matchers/active_record/query_the_database_matcher.rb +24 -23
- data/lib/shoulda/matchers/active_record/serialize_matcher.rb +13 -12
- data/lib/shoulda/matchers/version.rb +1 -1
- data/shoulda-matchers.gemspec +1 -1
- data/spec/shoulda/action_controller/assign_to_matcher_spec.rb +5 -3
- data/spec/shoulda/action_mailer/have_sent_email_spec.rb +40 -0
- data/spec/shoulda/active_model/allow_mass_assignment_of_matcher_spec.rb +12 -10
- data/spec/shoulda/active_model/ensure_inclusion_of_matcher_spec.rb +52 -0
- data/spec/shoulda/active_model/helpers_spec.rb +35 -6
- data/spec/shoulda/active_model/validate_presence_of_matcher_spec.rb +0 -1
- data/spec/shoulda/active_model/validate_uniqueness_of_matcher_spec.rb +8 -1
- data/spec/shoulda/active_record/serialize_matcher_spec.rb +1 -1
- data/spec/support/active_model_versions.rb +9 -0
- data/spec/support/model_builder.rb +15 -7
- metadata +123 -128
@@ -24,30 +24,35 @@ module Shoulda # :nodoc:
|
|
24
24
|
|
25
25
|
def initialize(variable)
|
26
26
|
@variable = variable.to_s
|
27
|
-
@
|
27
|
+
@options = {}
|
28
|
+
@options[:check_value] = false
|
28
29
|
end
|
29
30
|
|
30
31
|
def with_kind_of(expected_class)
|
31
|
-
@expected_class = expected_class
|
32
|
+
@options[:expected_class] = expected_class
|
32
33
|
self
|
33
34
|
end
|
34
35
|
|
35
36
|
def with(expected_value = nil, &block)
|
36
|
-
@check_value
|
37
|
-
@expected_value
|
38
|
-
@expectation_block = block
|
37
|
+
@options[:check_value] = true
|
38
|
+
@options[:expected_value] = expected_value
|
39
|
+
@options[:expectation_block] = block
|
39
40
|
self
|
40
41
|
end
|
41
42
|
|
42
43
|
def matches?(controller)
|
43
44
|
@controller = controller
|
44
|
-
|
45
|
-
assigned_value? &&
|
45
|
+
normalize_expected_value!
|
46
|
+
assigned_value? &&
|
47
|
+
kind_of_expected_class? &&
|
48
|
+
equal_to_expected_value?
|
46
49
|
end
|
47
50
|
|
48
51
|
def description
|
49
52
|
description = "assign @#{@variable}"
|
50
|
-
|
53
|
+
if @options.key?(:expected_class)
|
54
|
+
description << " with a kind of #{@options[:expected_class]}"
|
55
|
+
end
|
51
56
|
description
|
52
57
|
end
|
53
58
|
|
@@ -72,33 +77,45 @@ module Shoulda # :nodoc:
|
|
72
77
|
end
|
73
78
|
|
74
79
|
def kind_of_expected_class?
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
80
|
+
if @options.key?(:expected_class)
|
81
|
+
if assigned_value.kind_of?(@options[:expected_class])
|
82
|
+
@negative_failure_message =
|
83
|
+
"Didn't expect action to assign a kind of #{@options[:expected_class]} " <<
|
84
|
+
"for #{@variable}, but got one anyway"
|
85
|
+
true
|
86
|
+
else
|
87
|
+
@failure_message =
|
88
|
+
"Expected action to assign a kind of #{@options[:expected_class]} " <<
|
89
|
+
"for #{@variable}, but got #{assigned_value.inspect} " <<
|
90
|
+
"(#{assigned_value.class.name})"
|
91
|
+
false
|
92
|
+
end
|
81
93
|
else
|
82
|
-
|
83
|
-
"Expected action to assign a kind of #{@expected_class} " <<
|
84
|
-
"for #{@variable}, but got #{assigned_value.inspect} " <<
|
85
|
-
"(#{assigned_value.class.name})"
|
86
|
-
false
|
94
|
+
true
|
87
95
|
end
|
88
96
|
end
|
89
97
|
|
90
98
|
def equal_to_expected_value?
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
99
|
+
if @options[:check_value]
|
100
|
+
if @options[:expected_value] == assigned_value
|
101
|
+
@negative_failure_message =
|
102
|
+
"Didn't expect action to assign #{@options[:expected_value].inspect} " <<
|
103
|
+
"for #{@variable}, but got it anyway"
|
104
|
+
true
|
105
|
+
else
|
106
|
+
@failure_message =
|
107
|
+
"Expected action to assign #{@options[:expected_value].inspect} " <<
|
108
|
+
"for #{@variable}, but got #{assigned_value.inspect}"
|
109
|
+
false
|
110
|
+
end
|
97
111
|
else
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
112
|
+
true
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def normalize_expected_value!
|
117
|
+
if @options[:expectation_block]
|
118
|
+
@options[:expected_value] = @context.instance_eval(&@options[:expectation_block])
|
102
119
|
end
|
103
120
|
end
|
104
121
|
|
@@ -16,7 +16,9 @@ module Shoulda # :nodoc:
|
|
16
16
|
class RenderWithLayoutMatcher # :nodoc:
|
17
17
|
|
18
18
|
def initialize(expected_layout)
|
19
|
-
|
19
|
+
unless expected_layout.nil?
|
20
|
+
@expected_layout = expected_layout.to_s
|
21
|
+
end
|
20
22
|
end
|
21
23
|
|
22
24
|
# Used to provide access to layouts recorded by
|
@@ -64,7 +66,7 @@ module Shoulda # :nodoc:
|
|
64
66
|
end
|
65
67
|
|
66
68
|
def rendered_layouts
|
67
|
-
if recorded_layouts
|
69
|
+
if recorded_layouts.size > 0
|
68
70
|
recorded_layouts.keys.compact.map { |layout| layout.sub(%r{^layouts/}, '') }
|
69
71
|
else
|
70
72
|
layout = @controller.response.layout
|
@@ -79,6 +81,8 @@ module Shoulda # :nodoc:
|
|
79
81
|
def recorded_layouts
|
80
82
|
if @context
|
81
83
|
@context.instance_variable_get('@layouts')
|
84
|
+
else
|
85
|
+
{}
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
@@ -32,11 +32,7 @@ module Shoulda # :nodoc:
|
|
32
32
|
|
33
33
|
def matches?(controller)
|
34
34
|
@controller = controller
|
35
|
-
|
36
|
-
response_content_type =~ @content_type
|
37
|
-
else
|
38
|
-
response_content_type == @content_type
|
39
|
-
end
|
35
|
+
content_type_matches_regexp? || content_type_matches_string?
|
40
36
|
end
|
41
37
|
|
42
38
|
def failure_message
|
@@ -49,6 +45,16 @@ module Shoulda # :nodoc:
|
|
49
45
|
|
50
46
|
protected
|
51
47
|
|
48
|
+
def content_type_matches_regexp?
|
49
|
+
if @content_type.is_a?(Regexp)
|
50
|
+
response_content_type =~ @content_type
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def content_type_matches_string?
|
55
|
+
response_content_type == @content_type
|
56
|
+
end
|
57
|
+
|
52
58
|
def response_content_type
|
53
59
|
@controller.response.content_type.to_s
|
54
60
|
end
|
@@ -66,8 +72,7 @@ module Shoulda # :nodoc:
|
|
66
72
|
end
|
67
73
|
|
68
74
|
def expectation
|
69
|
-
"content type to be #{@content_type}, "
|
70
|
-
"but was #{response_content_type}"
|
75
|
+
"content type to be #{@content_type}, but was #{response_content_type}"
|
71
76
|
end
|
72
77
|
end
|
73
78
|
end
|
@@ -18,6 +18,10 @@ module Shoulda # :nodoc:
|
|
18
18
|
end
|
19
19
|
|
20
20
|
class SetTheFlashMatcher # :nodoc:
|
21
|
+
def initialize
|
22
|
+
@options = {}
|
23
|
+
end
|
24
|
+
|
21
25
|
attr_reader :failure_message, :negative_failure_message
|
22
26
|
|
23
27
|
def to(value)
|
@@ -26,12 +30,12 @@ module Shoulda # :nodoc:
|
|
26
30
|
end
|
27
31
|
|
28
32
|
def now
|
29
|
-
@now = true
|
33
|
+
@options[:now] = true
|
30
34
|
self
|
31
35
|
end
|
32
36
|
|
33
37
|
def [](key)
|
34
|
-
@key = key
|
38
|
+
@options[:key] = key
|
35
39
|
self
|
36
40
|
end
|
37
41
|
|
@@ -77,8 +81,8 @@ module Shoulda # :nodoc:
|
|
77
81
|
end
|
78
82
|
|
79
83
|
def flash_values
|
80
|
-
if @key
|
81
|
-
[flash.to_hash[@key]]
|
84
|
+
if @options.key?(:key)
|
85
|
+
[flash.to_hash[@options[:key]]]
|
82
86
|
else
|
83
87
|
flash.to_hash.values
|
84
88
|
end
|
@@ -90,13 +94,17 @@ module Shoulda # :nodoc:
|
|
90
94
|
else
|
91
95
|
@flash = @controller.flash.dup
|
92
96
|
@flash.instance_variable_set(:@used, @controller.flash.instance_variable_get(:@used).dup)
|
93
|
-
|
94
|
-
@flash.sweep
|
95
|
-
end
|
97
|
+
sweep_flash_if_necessary
|
96
98
|
@flash
|
97
99
|
end
|
98
100
|
end
|
99
101
|
|
102
|
+
def sweep_flash_if_necessary
|
103
|
+
unless @options[:now]
|
104
|
+
@flash.sweep
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
100
108
|
def expectation
|
101
109
|
expectation = "the #{expected_flash_invocation} to be set"
|
102
110
|
expectation << " to #{@value.inspect}" unless @value.nil?
|
@@ -113,18 +121,23 @@ module Shoulda # :nodoc:
|
|
113
121
|
end
|
114
122
|
|
115
123
|
def expected_flash_invocation
|
116
|
-
|
117
|
-
|
124
|
+
"flash#{pretty_now}#{pretty_key}"
|
125
|
+
end
|
118
126
|
|
119
|
-
|
120
|
-
|
127
|
+
def pretty_now
|
128
|
+
if @options[:now]
|
129
|
+
".now"
|
130
|
+
else
|
131
|
+
""
|
121
132
|
end
|
133
|
+
end
|
122
134
|
|
123
|
-
|
124
|
-
|
135
|
+
def pretty_key
|
136
|
+
if @options[:key]
|
137
|
+
"[:#{@key}]"
|
138
|
+
else
|
139
|
+
""
|
125
140
|
end
|
126
|
-
|
127
|
-
"flash#{now}#{key}"
|
128
141
|
end
|
129
142
|
end
|
130
143
|
end
|
@@ -20,19 +20,19 @@ module Shoulda # :nodoc:
|
|
20
20
|
|
21
21
|
def initialize(attribute)
|
22
22
|
@attribute = attribute.to_s
|
23
|
+
@options = {}
|
23
24
|
end
|
24
25
|
|
25
26
|
def as(role)
|
26
|
-
|
27
|
-
raise "You can specify role only in Rails 3.1 or greater"
|
27
|
+
if active_model_less_than_3_1?
|
28
|
+
raise "You can specify role only in Rails 3.1 or greater"
|
28
29
|
end
|
29
|
-
@role = role
|
30
|
+
@options[:role] = role
|
30
31
|
self
|
31
32
|
end
|
32
33
|
|
33
34
|
def matches?(subject)
|
34
35
|
@subject = subject
|
35
|
-
@role ||= :default
|
36
36
|
if attr_mass_assignable?
|
37
37
|
if whitelisting?
|
38
38
|
@negative_failure_message = "#{@attribute} was made accessible"
|
@@ -62,6 +62,10 @@ module Shoulda # :nodoc:
|
|
62
62
|
|
63
63
|
private
|
64
64
|
|
65
|
+
def role
|
66
|
+
@options[:role] || :default
|
67
|
+
end
|
68
|
+
|
65
69
|
def protected_attributes
|
66
70
|
@protected_attributes ||= (@subject.class.protected_attributes || [])
|
67
71
|
end
|
@@ -79,10 +83,10 @@ module Shoulda # :nodoc:
|
|
79
83
|
end
|
80
84
|
|
81
85
|
def authorizer
|
82
|
-
if
|
83
|
-
@subject.class.active_authorizer[@role]
|
84
|
-
else
|
86
|
+
if active_model_less_than_3_1?
|
85
87
|
@subject.class.active_authorizer
|
88
|
+
else
|
89
|
+
@subject.class.active_authorizer[role]
|
86
90
|
end
|
87
91
|
end
|
88
92
|
|
@@ -90,8 +94,8 @@ module Shoulda # :nodoc:
|
|
90
94
|
@subject.class.name
|
91
95
|
end
|
92
96
|
|
93
|
-
def
|
94
|
-
::ActiveModel::VERSION::
|
97
|
+
def active_model_less_than_3_1?
|
98
|
+
::ActiveModel::VERSION::STRING.to_f < 3.1
|
95
99
|
end
|
96
100
|
end
|
97
101
|
end
|
@@ -29,6 +29,7 @@ module Shoulda # :nodoc:
|
|
29
29
|
|
30
30
|
def initialize(*values)
|
31
31
|
@values_to_match = values
|
32
|
+
@options = {}
|
32
33
|
end
|
33
34
|
|
34
35
|
def for(attribute)
|
@@ -37,7 +38,7 @@ module Shoulda # :nodoc:
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def with_message(message)
|
40
|
-
@expected_message = message
|
41
|
+
@options[:expected_message] = message
|
41
42
|
self
|
42
43
|
end
|
43
44
|
|
@@ -69,7 +70,7 @@ module Shoulda # :nodoc:
|
|
69
70
|
false
|
70
71
|
else
|
71
72
|
if expected_message
|
72
|
-
errors_match_regexp? || errors_match_string?
|
73
|
+
@matched_error = errors_match_regexp? || errors_match_string?
|
73
74
|
else
|
74
75
|
errors_for_attribute.compact.any?
|
75
76
|
end
|
@@ -87,13 +88,13 @@ module Shoulda # :nodoc:
|
|
87
88
|
|
88
89
|
def errors_match_regexp?
|
89
90
|
if Regexp === expected_message
|
90
|
-
|
91
|
+
errors_for_attribute.detect { |e| e =~ expected_message }
|
91
92
|
end
|
92
93
|
end
|
93
94
|
|
94
95
|
def errors_match_string?
|
95
96
|
if errors_for_attribute.include?(expected_message)
|
96
|
-
|
97
|
+
expected_message
|
97
98
|
end
|
98
99
|
end
|
99
100
|
|
@@ -119,11 +120,11 @@ module Shoulda # :nodoc:
|
|
119
120
|
end
|
120
121
|
|
121
122
|
def expected_message
|
122
|
-
if @expected_message
|
123
|
-
if Symbol === @expected_message
|
124
|
-
default_error_message(@expected_message, :model_name => model_name, :attribute => @attribute)
|
123
|
+
if @options.key?(:expected_message)
|
124
|
+
if Symbol === @options[:expected_message]
|
125
|
+
default_error_message(@options[:expected_message], :model_name => model_name, :attribute => @attribute)
|
125
126
|
else
|
126
|
-
@expected_message
|
127
|
+
@options[:expected_message]
|
127
128
|
end
|
128
129
|
end
|
129
130
|
end
|
@@ -38,8 +38,6 @@ module Shoulda # :nodoc:
|
|
38
38
|
def matches?(subject)
|
39
39
|
super(subject)
|
40
40
|
|
41
|
-
@expected_message ||= :exclusion
|
42
|
-
|
43
41
|
allows_lower_value &&
|
44
42
|
disallows_minimum_value &&
|
45
43
|
allows_higher_value &&
|
@@ -49,19 +47,23 @@ module Shoulda # :nodoc:
|
|
49
47
|
private
|
50
48
|
|
51
49
|
def allows_lower_value
|
52
|
-
@minimum == 0 || allows_value_of(@minimum - 1,
|
50
|
+
@minimum == 0 || allows_value_of(@minimum - 1, expected_message)
|
53
51
|
end
|
54
52
|
|
55
53
|
def allows_higher_value
|
56
|
-
allows_value_of(@maximum + 1,
|
54
|
+
allows_value_of(@maximum + 1, expected_message)
|
57
55
|
end
|
58
56
|
|
59
57
|
def disallows_minimum_value
|
60
|
-
disallows_value_of(@minimum,
|
58
|
+
disallows_value_of(@minimum, expected_message)
|
61
59
|
end
|
62
60
|
|
63
61
|
def disallows_maximum_value
|
64
|
-
disallows_value_of(@maximum,
|
62
|
+
disallows_value_of(@maximum, expected_message)
|
63
|
+
end
|
64
|
+
|
65
|
+
def expected_message
|
66
|
+
@expected_message || :exclusion
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
@@ -5,6 +5,7 @@ module Shoulda # :nodoc:
|
|
5
5
|
# Ensure that the attribute's value is in the range specified
|
6
6
|
#
|
7
7
|
# Options:
|
8
|
+
# * <tt>in_array</tt> - the range of allowed values for this attribute
|
8
9
|
# * <tt>in_range</tt> - the range of allowed values for this attribute
|
9
10
|
# * <tt>with_low_message</tt> - value the test expects to find in
|
10
11
|
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
@@ -21,6 +22,15 @@ module Shoulda # :nodoc:
|
|
21
22
|
end
|
22
23
|
|
23
24
|
class EnsureInclusionOfMatcher < ValidationMatcher # :nodoc:
|
25
|
+
def initialize(attribute)
|
26
|
+
super(attribute)
|
27
|
+
@options = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def in_array(array)
|
31
|
+
@array = array
|
32
|
+
self
|
33
|
+
end
|
24
34
|
|
25
35
|
def in_range(range)
|
26
36
|
@range = range
|
@@ -29,6 +39,16 @@ module Shoulda # :nodoc:
|
|
29
39
|
self
|
30
40
|
end
|
31
41
|
|
42
|
+
def allow_blank(allow_blank = true)
|
43
|
+
@options[:allow_blank] = allow_blank
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def allow_nil(allow_nil = true)
|
48
|
+
@options[:allow_nil] = allow_nil
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
32
52
|
def with_message(message)
|
33
53
|
if message
|
34
54
|
@low_message = message
|
@@ -48,23 +68,58 @@ module Shoulda # :nodoc:
|
|
48
68
|
end
|
49
69
|
|
50
70
|
def description
|
51
|
-
"ensure inclusion of #{@attribute} in #{
|
71
|
+
"ensure inclusion of #{@attribute} in #{inspect_message}"
|
52
72
|
end
|
53
73
|
|
54
74
|
def matches?(subject)
|
55
75
|
super(subject)
|
56
76
|
|
57
|
-
@
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
77
|
+
if @range
|
78
|
+
@low_message ||= :inclusion
|
79
|
+
@high_message ||= :inclusion
|
80
|
+
|
81
|
+
disallows_lower_value &&
|
82
|
+
allows_minimum_value &&
|
83
|
+
disallows_higher_value &&
|
84
|
+
allows_maximum_value
|
85
|
+
elsif @array
|
86
|
+
if allows_all_values_in_array? && allows_blank_value? && allows_nil_value?
|
87
|
+
true
|
88
|
+
else
|
89
|
+
@failure_message = "#{@array} doesn't match array in validation"
|
90
|
+
false
|
91
|
+
end
|
92
|
+
end
|
64
93
|
end
|
65
94
|
|
66
95
|
private
|
67
96
|
|
97
|
+
def allows_blank_value?
|
98
|
+
if @options.key?(:allow_blank)
|
99
|
+
@options[:allow_blank] == allows_value_of('')
|
100
|
+
else
|
101
|
+
true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def allows_nil_value?
|
106
|
+
if @options.key?(:allow_nil)
|
107
|
+
@options[:allow_nil] == allows_value_of(nil)
|
108
|
+
else
|
109
|
+
true
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def inspect_message
|
114
|
+
@range.nil? ? @array.inspect : @range.inspect
|
115
|
+
end
|
116
|
+
|
117
|
+
def allows_all_values_in_array?
|
118
|
+
@array.all? do |value|
|
119
|
+
allows_value_of(value, @low_message)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
68
123
|
def disallows_lower_value
|
69
124
|
@minimum == 0 || disallows_value_of(@minimum - 1, @low_message)
|
70
125
|
end
|