shoulda-matchers 2.6.2 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +6 -1
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +26 -22
  5. data/NEWS.md +52 -1
  6. data/README.md +8 -6
  7. data/Rakefile +1 -1
  8. data/doc_config/gh-pages/index.html.erb +1 -1
  9. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +1 -1
  10. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +26 -0
  11. data/features/rails_integration.feature +18 -3
  12. data/features/step_definitions/rails_steps.rb +21 -3
  13. data/gemfiles/3.0.gemfile +1 -1
  14. data/gemfiles/3.0.gemfile.lock +30 -24
  15. data/gemfiles/3.1.gemfile +1 -1
  16. data/gemfiles/3.1.gemfile.lock +32 -26
  17. data/gemfiles/3.1_1.9.2.gemfile +1 -1
  18. data/gemfiles/3.1_1.9.2.gemfile.lock +22 -19
  19. data/gemfiles/3.2.gemfile +1 -1
  20. data/gemfiles/3.2.gemfile.lock +32 -26
  21. data/gemfiles/3.2_1.9.2.gemfile +1 -1
  22. data/gemfiles/3.2_1.9.2.gemfile.lock +8 -8
  23. data/gemfiles/4.0.0.gemfile +2 -2
  24. data/gemfiles/4.0.0.gemfile.lock +35 -31
  25. data/gemfiles/4.0.1.gemfile +2 -2
  26. data/gemfiles/4.0.1.gemfile.lock +24 -22
  27. data/gemfiles/4.1.gemfile +1 -1
  28. data/gemfiles/4.1.gemfile.lock +26 -22
  29. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +10 -3
  30. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +24 -6
  31. data/lib/shoulda/matchers/active_model.rb +2 -2
  32. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +1 -1
  33. data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +1 -1
  34. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +5 -3
  35. data/lib/shoulda/matchers/active_model/{ensure_exclusion_of_matcher.rb → validate_exclusion_of_matcher.rb} +20 -10
  36. data/lib/shoulda/matchers/active_model/{ensure_inclusion_of_matcher.rb → validate_inclusion_of_matcher.rb} +52 -28
  37. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +28 -19
  38. data/lib/shoulda/matchers/active_record.rb +18 -16
  39. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +4 -4
  40. data/lib/shoulda/matchers/active_record/association_matcher.rb +17 -12
  41. data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +86 -0
  42. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +19 -0
  43. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +2 -1
  44. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +138 -0
  45. data/lib/shoulda/matchers/independent.rb +3 -2
  46. data/lib/shoulda/matchers/independent/{delegate_matcher.rb → delegate_method_matcher.rb} +69 -49
  47. data/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb +37 -0
  48. data/lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb +15 -0
  49. data/lib/shoulda/matchers/version.rb +1 -1
  50. data/lib/shoulda/matchers/warn.rb +30 -2
  51. data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +6 -0
  52. data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +67 -5
  53. data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +9 -9
  54. data/spec/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +30 -3
  55. data/spec/shoulda/matchers/active_model/{ensure_exclusion_of_matcher_spec.rb → validate_exclusion_of_matcher_spec.rb} +29 -13
  56. data/spec/shoulda/matchers/active_model/{ensure_inclusion_of_matcher_spec.rb → validate_inclusion_of_matcher_spec.rb} +34 -16
  57. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +35 -0
  58. data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +56 -1
  59. data/spec/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +101 -0
  60. data/spec/shoulda/matchers/doublespeak/object_double_spec.rb +6 -6
  61. data/spec/shoulda/matchers/independent/{delegate_matcher → delegate_method_matcher}/stubbed_target_spec.rb +1 -1
  62. data/spec/shoulda/matchers/independent/{delegate_matcher_spec.rb → delegate_method_matcher_spec.rb} +88 -29
  63. data/spec/spec_helper.rb +2 -3
  64. data/spec/support/fail_with_message_including_matcher.rb +14 -3
  65. data/spec/support/fail_with_message_matcher.rb +14 -2
  66. data/spec/support/rails_versions.rb +4 -0
  67. metadata +19 -14
  68. data/lib/shoulda/matchers/independent/delegate_matcher/stubbed_target.rb +0 -35
@@ -0,0 +1,37 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Independent
4
+ class DelegateMethodMatcher
5
+ # @private
6
+ class StubbedTarget
7
+ def initialize(method)
8
+ @received_method = false
9
+ @received_arguments = []
10
+ stub_method(method)
11
+ end
12
+
13
+ def has_received_method?
14
+ received_method
15
+ end
16
+
17
+ def has_received_arguments?(*args)
18
+ args == received_arguments
19
+ end
20
+
21
+ protected
22
+
23
+ def stub_method(method)
24
+ class_eval do
25
+ define_method method do |*args|
26
+ @received_method = true
27
+ @received_arguments = args
28
+ end
29
+ end
30
+ end
31
+
32
+ attr_reader :received_method, :received_arguments
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,15 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Independent
4
+ class DelegateMethodMatcher
5
+ # @private
6
+ class TargetNotDefinedError < StandardError
7
+ def message
8
+ 'Delegation needs a target. Use the #to method to define one, e.g.
9
+ `post_office.should delegate(:deliver_mail).to(:mailman)`'.squish
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,6 +1,6 @@
1
1
  module Shoulda
2
2
  module Matchers
3
3
  # @private
4
- VERSION = '2.6.2'.freeze
4
+ VERSION = '2.7.0'.freeze
5
5
  end
6
6
  end
@@ -1,8 +1,36 @@
1
1
  module Shoulda
2
2
  module Matchers
3
+ TERMINAL_MAX_WIDTH = 72
4
+
3
5
  # @private
4
- def self.warn(msg)
5
- Kernel.warn "Warning from shoulda-matchers:\n\n#{msg}"
6
+ def self.warn(message)
7
+ header = "Warning from shoulda-matchers:"
8
+ divider = "*" * TERMINAL_MAX_WIDTH
9
+ wrapped_message = word_wrap(message, TERMINAL_MAX_WIDTH)
10
+ full_message = [
11
+ divider,
12
+ [header, wrapped_message.strip].join("\n\n"),
13
+ divider
14
+ ].join("\n")
15
+
16
+ Kernel.warn(full_message)
17
+ end
18
+
19
+ # @private
20
+ def self.warn_about_deprecated_method(old_method, new_method)
21
+ warn <<EOT
22
+ #{old_method} is deprecated and will be removed in the next major
23
+ release. Please use #{new_method} instead.
24
+ EOT
25
+ end
26
+
27
+ # Source: <https://www.ruby-forum.com/topic/57805>
28
+ # @private
29
+ def self.word_wrap(text, width=80)
30
+ text.
31
+ gsub(/\n+/, " ").
32
+ gsub( /(\S{#{width}})(?=\S)/, '\1 ' ).
33
+ gsub( /(.{1,#{width}})(?:\s+|$)/, "\\1\n" )
6
34
  end
7
35
  end
8
36
  end
@@ -7,6 +7,12 @@ describe Shoulda::Matchers::ActionController::FilterParamMatcher do
7
7
  expect(nil).to filter_param(:secret)
8
8
  end
9
9
 
10
+ it 'accepts filtering a parameter matching a filtered regex' do
11
+ filter(/(?!tip)pin(?!g)/)
12
+
13
+ expect(nil).to filter_param(:pin)
14
+ end
15
+
10
16
  it 'rejects filtering an unfiltered parameter' do
11
17
  filter(:secret)
12
18
  matcher = filter_param(:other)
@@ -6,6 +6,10 @@ describe Shoulda::Matchers::ActionController::SetSessionMatcher do
6
6
  expect(controller_with_session(var: 'hi')).to set_session(:var)
7
7
  end
8
8
 
9
+ it 'accepts assigning to that variable with specifying the key by string' do
10
+ expect(controller_with_session(var: 'hi')).to set_session('var')
11
+ end
12
+
9
13
  it 'accepts assigning the correct value to that variable' do
10
14
  expect(controller_with_session(var: 'hi')).to set_session(:var).to('hi')
11
15
  end
@@ -22,22 +26,80 @@ describe Shoulda::Matchers::ActionController::SetSessionMatcher do
22
26
  expect(controller_with_session(var: 'hi')).to set_session(:other).to(nil)
23
27
  end
24
28
 
29
+ it 'rejects assigning nil to that variable' do
30
+ expect(controller_with_session(var: 'hi')).not_to set_session(:var).to(nil)
31
+ end
32
+
33
+ it 'accepts assigning nil to cleared variable' do
34
+ expect(controller_with_session(var: nil)).to set_session(:var).to(nil)
35
+ end
36
+
25
37
  it 'accepts assigning false to that variable' do
26
38
  expect(controller_with_session(var: false)).to set_session(:var).to(false)
27
39
  end
28
40
 
41
+ it 'rejects assigning false to other variable' do
42
+ expect(controller_with_session(var: false)).not_to set_session(:other).to(false)
43
+ end
44
+
45
+ it 'rejects assigning false to a variable with value' do
46
+ expect(controller_with_session(var: 'hi')).not_to set_session(:other).to(false)
47
+ end
48
+
29
49
  it 'accepts assigning to the same value in the test context' do
30
- expected = 'value'
50
+ context = stub(expected: 'value')
31
51
 
32
- expect(controller_with_session(var: expected)).
33
- to set_session(:var).in_context(self).to { expected }
52
+ expect(controller_with_session(var: 'value')).
53
+ to set_session(:var).in_context(context).to { expected }
34
54
  end
35
55
 
36
56
  it 'rejects assigning to the another value in the test context' do
37
- expected = 'other'
57
+ context = stub(expected: 'other')
38
58
 
39
59
  expect(controller_with_session(var: 'unexpected')).
40
- not_to set_session(:var).in_context(self).to { expected }
60
+ not_to set_session(:var).in_context(context).to { expected }
61
+ end
62
+
63
+ it 'accepts assigning nil to another variable in the test context' do
64
+ context = stub(expected: nil)
65
+
66
+ expect(controller_with_session(var: 'hi')).
67
+ to set_session(:other).in_context(context).to { expected }
68
+ end
69
+
70
+ it 'rejects assigning nil to that variable in the test context' do
71
+ context = stub(expected: nil)
72
+
73
+ expect(controller_with_session(var: 'hi')).
74
+ not_to set_session(:var).in_context(context).to { expected }
75
+ end
76
+
77
+ it 'accepts assigning nil to a cleared variable in the test context' do
78
+ context = stub(expected: nil)
79
+
80
+ expect(controller_with_session(var: nil)).
81
+ to set_session(:var).in_context(context).to { expected }
82
+ end
83
+
84
+ it 'accepts assigning false to that variable in the test context' do
85
+ context = stub(expected: false)
86
+
87
+ expect(controller_with_session(var: false)).
88
+ to set_session(:var).in_context(context).to { expected }
89
+ end
90
+
91
+ it 'accepts assigning false to other variable in the test context' do
92
+ context = stub(expected: false)
93
+
94
+ expect(controller_with_session(var: false)).
95
+ not_to set_session(:other).in_context(context).to { expected }
96
+ end
97
+
98
+ it 'accepts assigning false to other variable in the test context' do
99
+ context = stub(expected: false)
100
+
101
+ expect(controller_with_session(var: 'hi')).
102
+ not_to set_session(:var).in_context(context).to { expected }
41
103
  end
42
104
 
43
105
  def controller_with_session(session_hash)
@@ -72,7 +72,7 @@ describe Shoulda::Matchers::ActionController::StrongParametersMatcher do
72
72
  end
73
73
 
74
74
  matcher = described_class.new([:name]).in_context(self).for(:create)
75
- expect(matcher.matches?(@controller)).to be_true
75
+ expect(matcher.matches?(@controller)).to be true
76
76
  end
77
77
 
78
78
  it 'is true for all the allowable attributes' do
@@ -81,7 +81,7 @@ describe Shoulda::Matchers::ActionController::StrongParametersMatcher do
81
81
  end
82
82
 
83
83
  matcher = described_class.new([:name, :age]).in_context(self).for(:create)
84
- expect(matcher.matches?(@controller)).to be_true
84
+ expect(matcher.matches?(@controller)).to be true
85
85
  end
86
86
 
87
87
  it 'is false when any attributes are not allowed' do
@@ -90,14 +90,14 @@ describe Shoulda::Matchers::ActionController::StrongParametersMatcher do
90
90
  end
91
91
 
92
92
  matcher = described_class.new([:name, :admin]).in_context(self).for(:create)
93
- expect(matcher.matches?(@controller)).to be_false
93
+ expect(matcher.matches?(@controller)).to be false
94
94
  end
95
95
 
96
96
  it 'is false when permit is not called' do
97
97
  controller_for_resource_with_strong_parameters(action: :create)
98
98
 
99
99
  matcher = described_class.new([:name]).in_context(self).for(:create)
100
- expect(matcher.matches?(@controller)).to be_false
100
+ expect(matcher.matches?(@controller)).to be false
101
101
  end
102
102
 
103
103
  it 'requires an action' do
@@ -129,7 +129,7 @@ describe Shoulda::Matchers::ActionController::StrongParametersMatcher do
129
129
  matcher = described_class.new([:name]).
130
130
  in_context(self).
131
131
  for(:show, verb: :get, params: { slug: 'foo' })
132
- expect(matcher.matches?(@controller)).to be_true
132
+ expect(matcher.matches?(@controller)).to be true
133
133
  end
134
134
 
135
135
  it 'works with #update specifically' do
@@ -140,7 +140,7 @@ describe Shoulda::Matchers::ActionController::StrongParametersMatcher do
140
140
  matcher = described_class.new([:name]).
141
141
  in_context(self).
142
142
  for(:update, params: { id: 1 })
143
- expect(matcher.matches?(@controller)).to be_true
143
+ expect(matcher.matches?(@controller)).to be true
144
144
  end
145
145
 
146
146
  it 'does not raise an error when #fetch was used instead of #require (issue #495)' do
@@ -151,7 +151,7 @@ describe Shoulda::Matchers::ActionController::StrongParametersMatcher do
151
151
  matcher = described_class.new([:eta, :diner_id]).
152
152
  in_context(self).
153
153
  for(:create)
154
- expect(matcher.matches?(@controller)).to be_true
154
+ expect(matcher.matches?(@controller)).to be true
155
155
  end
156
156
 
157
157
  it 'tracks multiple calls to #permit' do
@@ -167,12 +167,12 @@ describe Shoulda::Matchers::ActionController::StrongParametersMatcher do
167
167
  matcher = described_class.new(sets_of_attributes[0]).
168
168
  in_context(self).
169
169
  for(:create)
170
- expect(matcher.matches?(@controller)).to be_true
170
+ expect(matcher.matches?(@controller)).to be true
171
171
 
172
172
  matcher = described_class.new(sets_of_attributes[1]).
173
173
  in_context(self).
174
174
  for(:create)
175
- expect(matcher.matches?(@controller)).to be_true
175
+ expect(matcher.matches?(@controller)).to be true
176
176
  end
177
177
 
178
178
  context 'stubbing params on the controller' do
@@ -2,6 +2,21 @@ require 'spec_helper'
2
2
 
3
3
  describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher do
4
4
  if active_model_4_0?
5
+ def self.available_column_types
6
+ [
7
+ :string,
8
+ :text,
9
+ :integer,
10
+ :float,
11
+ :decimal,
12
+ :datetime,
13
+ :timestamp,
14
+ :time,
15
+ :date,
16
+ :binary
17
+ ]
18
+ end
19
+
5
20
  context 'a model with an absence validation' do
6
21
  it 'accepts' do
7
22
  expect(validating_absence_of(:attr)).to validate_absence_of(:attr)
@@ -10,6 +25,15 @@ describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher do
10
25
  it 'does not override the default message with a present' do
11
26
  expect(validating_absence_of(:attr)).to validate_absence_of(:attr).with_message(nil)
12
27
  end
28
+
29
+ available_column_types.each do |type|
30
+ context "when column is of type #{type}" do
31
+ it "accepts" do
32
+ expect(validating_absence_of(:attr, {}, type: type)).
33
+ to validate_absence_of(:attr)
34
+ end
35
+ end
36
+ end
13
37
  end
14
38
 
15
39
  context 'a model without an absence validation' do
@@ -95,9 +119,12 @@ describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher do
95
119
  end
96
120
  end
97
121
 
98
- def validating_absence_of(attr, options = {})
99
- define_model :example, attr => :string do
100
- validates_absence_of attr, options
122
+ def validating_absence_of(attr, validation_options = {}, given_column_options = {})
123
+ default_column_options = { type: :string, options: {} }
124
+ column_options = default_column_options.merge(given_column_options)
125
+
126
+ define_model :example, attr => column_options do
127
+ validates_absence_of attr, validation_options
101
128
  end.new
102
129
  end
103
130
 
@@ -1,39 +1,55 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Shoulda::Matchers::ActiveModel::EnsureExclusionOfMatcher do
3
+ describe Shoulda::Matchers::ActiveModel do
4
+ describe '#ensure_exclusion_of' do
5
+ it 'is aliased to #validate_exclusion_of' do
6
+ matchers.expects(:validate_exclusion_of).with(:attr)
7
+
8
+ silence_warnings do
9
+ matchers.ensure_exclusion_of(:attr)
10
+ end
11
+ end
12
+ end
13
+
14
+ def matchers
15
+ @_matchers ||= Object.new.extend(described_class)
16
+ end
17
+ end
18
+
19
+ describe Shoulda::Matchers::ActiveModel::ValidateExclusionOfMatcher do
4
20
  context 'an attribute which must be excluded from a range' do
5
21
  it 'accepts ensuring the correct range' do
6
22
  expect(validating_exclusion(in: 2..5)).
7
- to ensure_exclusion_of(:attr).in_range(2..5)
23
+ to validate_exclusion_of(:attr).in_range(2..5)
8
24
  end
9
25
 
10
26
  it 'rejects ensuring excluded value' do
11
27
  expect(validating_exclusion(in: 2..5)).
12
- not_to ensure_exclusion_of(:attr).in_range(2..6)
28
+ not_to validate_exclusion_of(:attr).in_range(2..6)
13
29
  end
14
30
 
15
31
  it 'does not override the default message with a blank' do
16
32
  expect(validating_exclusion(in: 2..5)).
17
- to ensure_exclusion_of(:attr).in_range(2..5).with_message(nil)
33
+ to validate_exclusion_of(:attr).in_range(2..5).with_message(nil)
18
34
  end
19
35
  end
20
36
 
21
37
  context 'an attribute which must be excluded from a range with excluded end' do
22
38
  it 'accepts ensuring the correct range' do
23
39
  expect(validating_exclusion(in: 2...5)).
24
- to ensure_exclusion_of(:attr).in_range(2...5)
40
+ to validate_exclusion_of(:attr).in_range(2...5)
25
41
  end
26
42
 
27
43
  it 'rejects ensuring excluded value' do
28
44
  expect(validating_exclusion(in: 2...5)).
29
- not_to ensure_exclusion_of(:attr).in_range(2...4)
45
+ not_to validate_exclusion_of(:attr).in_range(2...4)
30
46
  end
31
47
  end
32
48
 
33
49
  context 'an attribute with a custom validation message' do
34
50
  it 'accepts ensuring the correct range' do
35
51
  expect(validating_exclusion(in: 2..4, message: 'not good')).
36
- to ensure_exclusion_of(:attr).in_range(2..4).with_message(/not good/)
52
+ to validate_exclusion_of(:attr).in_range(2..4).with_message(/not good/)
37
53
  end
38
54
  end
39
55
 
@@ -45,7 +61,7 @@ describe Shoulda::Matchers::ActiveModel::EnsureExclusionOfMatcher do
45
61
  end
46
62
  end
47
63
 
48
- expect(model).to ensure_exclusion_of(:attr).in_range(2..5).
64
+ expect(model).to validate_exclusion_of(:attr).in_range(2..5).
49
65
  with_message(/should be out of this range/)
50
66
 
51
67
  model = custom_validation do
@@ -54,7 +70,7 @@ describe Shoulda::Matchers::ActiveModel::EnsureExclusionOfMatcher do
54
70
  end
55
71
  end
56
72
 
57
- expect(model).to ensure_exclusion_of(:attr).in_range(2...5).
73
+ expect(model).to validate_exclusion_of(:attr).in_range(2...5).
58
74
  with_message(/should be out of this range/)
59
75
  end
60
76
  end
@@ -62,21 +78,21 @@ describe Shoulda::Matchers::ActiveModel::EnsureExclusionOfMatcher do
62
78
  context 'an attribute which must be excluded from an array' do
63
79
  it 'accepts with correct array' do
64
80
  expect(validating_exclusion(in: %w(one two))).
65
- to ensure_exclusion_of(:attr).in_array(%w(one two))
81
+ to validate_exclusion_of(:attr).in_array(%w(one two))
66
82
  end
67
83
 
68
84
  it 'rejects when only part of array matches' do
69
85
  expect(validating_exclusion(in: %w(one two))).
70
- not_to ensure_exclusion_of(:attr).in_array(%w(one wrong_value))
86
+ not_to validate_exclusion_of(:attr).in_array(%w(one wrong_value))
71
87
  end
72
88
 
73
89
  it 'rejects when array does not match at all' do
74
90
  expect(validating_exclusion(in: %w(one two))).
75
- not_to ensure_exclusion_of(:attr).in_array(%w(cat dog))
91
+ not_to validate_exclusion_of(:attr).in_array(%w(cat dog))
76
92
  end
77
93
 
78
94
  it 'has correct description' do
79
- expect(ensure_exclusion_of(:attr).in_array([true, 'dog']).description).
95
+ expect(validate_exclusion_of(:attr).in_array([true, 'dog']).description).
80
96
  to eq 'ensure exclusion of attr in [true, "dog"]'
81
97
  end
82
98