rspec-be_valid_when_matcher 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dbf10b740ed23ee52f1dcd04f21344f1b80ce0fb
4
+ data.tar.gz: 2fa1b2a7c0177523425e1e3d94170a0c9dbf3dd4
5
+ SHA512:
6
+ metadata.gz: 1365c63d51fe47a3013da2c205be06edc2a3a15ff799d831191a17ea914db8eb4d3923ecb10e1b38a2f10eb8fb6a9222182ebdeb511e0c739b70babef8a30782
7
+ data.tar.gz: 4543a03621ee16fab142d3d26a97bc60c7ff03e0e93072c762c0d38fe8c988c638d11f204e9fd599059f65a28f547587f27a29915225445c4bf48b5eef8539aa
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2015 Marek Tuchowski
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # rspec-be_valid_when_matcher
2
+
3
+ RSpec matcher for testing ActiveRecord models with a fluent and clear language.
4
+
5
+ ## Install
6
+
7
+ First, add to your `Gemfile` (preferably in the `:test` group):
8
+
9
+ ```ruby
10
+ gem 'rspec-be_valid_when_matcher'
11
+ ```
12
+
13
+ Then, include `RSpec::BeValidWhenMatcher` in RSpec configuration:
14
+
15
+ ```ruby
16
+ RSpec.configure do |config|
17
+ config.include RSpec::BeValidWhenMatcher
18
+ end
19
+ ```
20
+
21
+ Or, directly in your model spec(s):
22
+
23
+ ```ruby
24
+ describe MyModel do
25
+ include RSpec::BeValidWhenMatcher
26
+
27
+ subject { build(:my_model) }
28
+
29
+ describe '#header' do
30
+ it { is_expected.not_to be_valid_when :header, nil }
31
+ end
32
+ end
33
+ ```
34
+
35
+ ## Basic usage
36
+
37
+ Here's an example using rspec-be_valid_when_matcher:
38
+
39
+ ```ruby
40
+ RSpec.describe Person do
41
+ subject { Person.new }
42
+
43
+ it { is_expected.to be_valid_when :name, 'Frank', 'some text' }
44
+ it { is_expected.to be_valid_when :age, 42, 'positive number' }
45
+ it { is_expected.not_to be_valid_when :age, -1, 'negative number' }
46
+ end
47
+ ```
48
+
49
+ The `:name` and `:age` are names of fields belonging to `Person` instance. If the matcher will fail,
50
+ say for negative number check, it'll display the following message:
51
+
52
+ ```console
53
+ Failures:
54
+
55
+ 1) Person should not be valid when #age is negative number (-1)
56
+ Failure/Error: it { is_expected.not_to be_valid_when :age, -1, 'negative number' }
57
+ ```
58
+
59
+ To keep the specs more readable `#is(value, message)` method can be used to separate `field`
60
+ from expected `value` and optional `message` declaration like so:
61
+
62
+ ```ruby
63
+ RSpec.describe Person do
64
+ subject { Person.new }
65
+
66
+ it { is_expected.to be_valid_when(:name).is('Frank', 'some text') }
67
+ it { is_expected.to be_valid_when(:age).is(42, 'positive number') }
68
+ it { is_expected.not_to be_valid_when(:age).is(-1, 'negative number') }
69
+ end
70
+ ```
71
+
72
+ ### Built-in checks
73
+
74
+ #### Presence
75
+
76
+ Test field validity with the `nil` value:
77
+
78
+ ```ruby
79
+ be_valid_when(:field).is_not_present # Uses nil value
80
+ ```
81
+
82
+ #### Type
83
+
84
+ Test field validity with specific type values:
85
+
86
+ ```ruby
87
+ be_valid_when(:field).is_number 2 # Defaults to 42
88
+ be_valid_when(:field).is_fixnum 2 # Defaults to 42
89
+ be_valid_when(:field).is_bignum 1024**32 # Defaults to 42**13
90
+ be_valid_when(:field).is_float 0.1 # Defaults to 3.14
91
+ be_valid_when(:field).is_complex 2.to_c # Defaults to 42+0i
92
+ be_valid_when(:field).is_rational 2.to_r # Defaults to 42/1
93
+ be_valid_when(:field).is_bigdecimal BigDecimal('2') # Defaults to BigDecimal('42')
94
+ be_valid_when(:field).is_string 'a' # Defaults to 'value'
95
+ be_valid_when(:field).is_regex /abc/ # Defaults to /^value$/
96
+ be_valid_when(:field).is_array [1,2] # Defaults to [42]
97
+ be_valid_when(:field).is_hash { a: 1 } # Defaults to { value: 42 }
98
+ be_valid_when(:field).is_symbol :a # Defaults to :value
99
+ ```
100
+
101
+ ## MIT Licensed
102
+
103
+ See [LICENSE](https://github.com/mtuchowski/rspec-be_valid_when_matcher/blob/master/LICENSE) file
104
+ for full license text.
@@ -0,0 +1,192 @@
1
+ # encoding: UTF-8
2
+ require 'rspec'
3
+
4
+ # RSpec's top level namespace.
5
+ module RSpec
6
+ # Container module for be_valid_when matcher definition and implementation.
7
+ module BeValidWhenMatcher
8
+ # rubocop:disable Style/PredicateName
9
+
10
+ # Provides the implementation for `be_valid_when` matcher.
11
+ # Not intended to be instantiated directly.
12
+ # @api private
13
+ class BeValidWhen
14
+ # Returns a new instance of matcher.
15
+ # @param field (Symbol) field name to use.
16
+ # @raise ArgumentError if field name is not a symbol.
17
+ def initialize(field)
18
+ unless field.instance_of? Symbol
19
+ fail ArgumentError, "field name should be symbol (#{field.inspect})"
20
+ end
21
+
22
+ @field = field
23
+ @value_set = false
24
+ @value = nil
25
+ @model = nil
26
+ end
27
+
28
+ # Passes if given `model` instance is valid.
29
+ #
30
+ # More specifically if it doesn't have any
31
+ # {http://api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-errors `errors`}
32
+ # on specified `field` after setting it's `value` and validating it. Does not take into
33
+ # account other fields and the validity of the whole object.
34
+ # @api private
35
+ # @param model [Object] an Object implementing `ActiveModel::Validations`.
36
+ # @return [Boolean] `true` if there are no errors on `field`, `false` otherwise.
37
+ def matches?(model)
38
+ setup_model model
39
+ @model.errors[@field].empty?
40
+ end
41
+
42
+ # Passes if given `model` instance is invalid.
43
+ #
44
+ # More specifically if it does have
45
+ # {http://api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-errors `errors`}
46
+ # on specified `field` after setting it's `value` and validating it. Does not take into
47
+ # account other fields.
48
+ # @api private
49
+ # @param model [Object] an Object implementing `ActiveModel::Validations`.
50
+ # @return [Boolean] `true` if there are errors on `field`, `false` otherwise.
51
+ def does_not_match?(model)
52
+ setup_model model
53
+ !@model.errors[@field].empty?
54
+ end
55
+
56
+ # Called when {#matches?} returns false.
57
+ # @api private
58
+ # @return [String] explaining what was expected.
59
+ def failure_message
60
+ assert_value_existence
61
+ assert_model_existance
62
+
63
+ "expected #{@model.inspect} to be valid when #{format_message}"
64
+ end
65
+
66
+ # Called when {#does_not_match?} returns false.
67
+ # @api private
68
+ # @return [String] explaining what was expected.
69
+ def failure_message_when_negated
70
+ assert_value_existence
71
+ assert_model_existance
72
+
73
+ "expected #{@model.inspect} not to be valid when #{format_message}"
74
+ end
75
+
76
+ # Used to generate the example's doc string in one-liner syntax.
77
+ # @api private
78
+ # @return [String] short description of what is expected.
79
+ def description
80
+ assert_value_existence
81
+
82
+ "be valid when #{format_message}"
83
+ end
84
+
85
+ # Indicates that this matcher doesn't provide actual and expected attributes.
86
+ # @api private
87
+ # @return [FalseClass]
88
+ def diffable?
89
+ false
90
+ end
91
+
92
+ # Indicates that this matcher cannot be used in a block expectation expression.
93
+ # @api private
94
+ # @return [FalseClass]
95
+ def supports_block_expectations?
96
+ false
97
+ end
98
+
99
+ # Used to set field `value` and optional custom failure `message`.
100
+ # @overload is(value)
101
+ # Sets the field `value`.
102
+ # @param value [Any] field `value` to use in matching.
103
+ # @overload is(value, message)
104
+ # Sets the field `value` and custom failure `message`.
105
+ # @param value [Any] field `value` to use in matching.
106
+ # @param message [String] a `message` used for {#failure_message},
107
+ # {#failure_message_when_negated} and {#description}.
108
+ # @return [self]
109
+ def is(*args)
110
+ number_of_arguments = args.size
111
+
112
+ if number_of_arguments > 2 || number_of_arguments == 0
113
+ fail ArgumentError, "wrong number of arguments (#{number_of_arguments} insted of 1 or 2)"
114
+ else
115
+ self.value = args.shift
116
+ @message = args.first
117
+ end
118
+
119
+ self
120
+ end
121
+
122
+ # Used to setup matcher for checking `nil` `value`.
123
+ def is_not_present
124
+ is(nil, 'not present')
125
+ end
126
+
127
+ # Used to setup matcher for checking for numeric values.
128
+ def is_number(number = 42)
129
+ fail ArgumentError, 'should be number' unless number.is_a? Numeric
130
+
131
+ is(number, 'number')
132
+ end
133
+
134
+ # Used to setup matcher for checking for fixnum values.
135
+ def is_fixnum(number = 42)
136
+ fail ArgumentError, 'should be a fixnum' unless number.is_a? Fixnum
137
+
138
+ is(number, 'a fixnum')
139
+ end
140
+
141
+ # Used to setup matcher for checking for bignum values.
142
+ def is_bignum(number = 42**13)
143
+ fail ArgumentError, 'should be a bignum' unless number.is_a? Bignum
144
+
145
+ is(number, 'a bignum')
146
+ end
147
+
148
+ private
149
+
150
+ attr_writer :message
151
+
152
+ def value=(value)
153
+ @value = value
154
+ @value_set = true
155
+ end
156
+
157
+ def assert_value_existence
158
+ fail ArgumentError, 'missing value' unless @value_set
159
+ end
160
+
161
+ def assert_model_existance
162
+ fail ArgumentError, 'missing model' if @model.nil?
163
+ end
164
+
165
+ def setup_model(model)
166
+ assert_value_existence
167
+
168
+ @model = model
169
+ @model.send "#{@field}=", @value
170
+ @model.validate
171
+ end
172
+
173
+ def format_message
174
+ value = @value.inspect
175
+ message = @message.nil? ? "is #{value}" : "is #{@message} (#{value})"
176
+ "##{@field} #{message}"
177
+ end
178
+ end
179
+
180
+ # Model validity assertion.
181
+ def be_valid_when(*args)
182
+ number_of_arguments = args.size
183
+ field_name = args.shift
184
+
185
+ if number_of_arguments == 1
186
+ BeValidWhen.new(field_name)
187
+ else
188
+ BeValidWhen.new(field_name).is(*args)
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,59 @@
1
+ example_id | status | run_time |
2
+ ------------------------------------------------------ | ------ | --------------- |
3
+ ./spec/rspec/be_valid_when/is_bignum_spec.rb[1:1:1] | passed | 0.00026 seconds |
4
+ ./spec/rspec/be_valid_when/is_bignum_spec.rb[1:1:2] | passed | 0.0123 seconds |
5
+ ./spec/rspec/be_valid_when/is_bignum_spec.rb[1:2:1] | passed | 0.00012 seconds |
6
+ ./spec/rspec/be_valid_when/is_bignum_spec.rb[1:2:2] | passed | 0.01276 seconds |
7
+ ./spec/rspec/be_valid_when/is_bignum_spec.rb[1:2:3] | passed | 0.00017 seconds |
8
+ ./spec/rspec/be_valid_when/is_fixnum_spec.rb[1:1:1] | passed | 0.0005 seconds |
9
+ ./spec/rspec/be_valid_when/is_fixnum_spec.rb[1:1:2] | passed | 0.06739 seconds |
10
+ ./spec/rspec/be_valid_when/is_fixnum_spec.rb[1:2:1] | passed | 0.00014 seconds |
11
+ ./spec/rspec/be_valid_when/is_fixnum_spec.rb[1:2:2] | passed | 0.0176 seconds |
12
+ ./spec/rspec/be_valid_when/is_fixnum_spec.rb[1:2:3] | passed | 0.00139 seconds |
13
+ ./spec/rspec/be_valid_when/is_not_present_spec.rb[1:1] | passed | 0.00011 seconds |
14
+ ./spec/rspec/be_valid_when/is_not_present_spec.rb[1:2] | passed | 0.01358 seconds |
15
+ ./spec/rspec/be_valid_when/is_number_spec.rb[1:1:1] | passed | 0.00013 seconds |
16
+ ./spec/rspec/be_valid_when/is_number_spec.rb[1:1:2] | passed | 0.01096 seconds |
17
+ ./spec/rspec/be_valid_when/is_number_spec.rb[1:2:1] | passed | 0.00012 seconds |
18
+ ./spec/rspec/be_valid_when/is_number_spec.rb[1:2:2] | passed | 0.01177 seconds |
19
+ ./spec/rspec/be_valid_when/is_number_spec.rb[1:2:3] | passed | 0.00013 seconds |
20
+ ./spec/rspec/be_valid_when/is_spec.rb[1:1] | passed | 0.00015 seconds |
21
+ ./spec/rspec/be_valid_when/is_spec.rb[1:2:1] | passed | 0.01055 seconds |
22
+ ./spec/rspec/be_valid_when/is_spec.rb[1:3:1] | passed | 0.01142 seconds |
23
+ ./spec/rspec/be_valid_when/is_spec.rb[1:3:2] | passed | 0.00298 seconds |
24
+ ./spec/rspec/be_valid_when/is_spec.rb[1:4] | passed | 0.00011 seconds |
25
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:1:1] | passed | 0.00031 seconds |
26
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:1:2] | passed | 0.00008 seconds |
27
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:1:3] | passed | 0.00008 seconds |
28
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:1:4] | passed | 0.0001 seconds |
29
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:1:5] | passed | 0.00009 seconds |
30
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:1:6] | passed | 0.00067 seconds |
31
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:1:7] | passed | 0.00009 seconds |
32
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:1:8] | passed | 0.0001 seconds |
33
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:1:9] | passed | 0.00008 seconds |
34
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:1:10] | passed | 0.00011 seconds |
35
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:2:1] | passed | 0.00012 seconds |
36
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:2:2] | passed | 0.0001 seconds |
37
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:2:3:1] | passed | 0.0001 seconds |
38
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:2:3:2] | passed | 0.00011 seconds |
39
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:2:3:3] | passed | 0.0001 seconds |
40
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:2:3:4] | passed | 0.00011 seconds |
41
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:2:3:5] | passed | 0.00011 seconds |
42
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:3:1] | passed | 0.00009 seconds |
43
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:3:2:1] | passed | 0.0028 seconds |
44
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:3:2:2] | passed | 0.00367 seconds |
45
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:4:1] | passed | 0.00012 seconds |
46
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:4:2:1] | passed | 0.00286 seconds |
47
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:4:2:2] | passed | 0.00272 seconds |
48
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:5] | passed | 0.00014 seconds |
49
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:6:1] | passed | 0.00014 seconds |
50
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:6:2] | passed | 0.00018 seconds |
51
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:6:3] | passed | 0.00012 seconds |
52
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:6:4] | passed | 0.0001 seconds |
53
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:7:1:1] | passed | 0.00278 seconds |
54
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:7:1:2] | passed | 0.00602 seconds |
55
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:7:2:1] | passed | 0.00285 seconds |
56
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:7:2:2] | passed | 0.00613 seconds |
57
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:8:1] | passed | 0.00287 seconds |
58
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:8:2:1] | passed | 0.00286 seconds |
59
+ ./spec/rspec/be_valid_when_matcher_spec.rb[1:9:1] | passed | 0.00012 seconds |
@@ -0,0 +1,60 @@
1
+ require 'active_model'
2
+
3
+ # @private
4
+ class FakeModel
5
+ include ActiveModel::Validations
6
+
7
+ attr_accessor :bignum_field
8
+ attr_accessor :not_bignum_field
9
+
10
+ validates_numericality_of :bignum_field, greater_than: 30129469486639681537
11
+ validates_length_of :not_bignum_field, minimum: 31
12
+ end
13
+
14
+ describe 'be_valid_when#is_bignum' do
15
+ let(:model) { FakeModel.new }
16
+
17
+ context 'with no arguments' do
18
+ let(:description) { /^be valid when #bignum_field is a bignum \(1265437718438866624512\)$/ }
19
+
20
+ let(:passing_matcher) { be_valid_when(:bignum_field).is_bignum }
21
+ let(:failing_matcher) { be_valid_when(:not_bignum_field).is_bignum }
22
+
23
+ it 'has the correct description' do
24
+ expect(passing_matcher.description).to match description
25
+ end
26
+
27
+ it 'returns proper result' do
28
+ expect(passing_matcher.matches? model).to eq true
29
+ expect(passing_matcher.does_not_match? model).to eq false
30
+ expect(failing_matcher.matches? model).to eq false
31
+ expect(failing_matcher.does_not_match? model).to eq true
32
+ end
33
+ end
34
+
35
+ context 'with one argument' do
36
+ let(:description) { /^be valid when #bignum_field is a bignum \(2232232135326160725639168\)$/ }
37
+
38
+ let(:passing_matcher) { be_valid_when(:bignum_field).is_bignum 2232232135326160725639168 }
39
+ let(:failing_matcher) { be_valid_when(:bignum_field).is_bignum 30129469486639681536 }
40
+
41
+ it 'has the correct description' do
42
+ expect(passing_matcher.description).to match description
43
+ end
44
+
45
+ it 'returns proper result' do
46
+ expect(passing_matcher.matches? model).to eq true
47
+ expect(passing_matcher.does_not_match? model).to eq false
48
+ expect(failing_matcher.matches? model).to eq false
49
+ expect(failing_matcher.does_not_match? model).to eq true
50
+ end
51
+
52
+ it 'should fail if passed non bignum' do
53
+ expect { be_valid_when(:bignum_field).is_bignum 'value' }.to raise_error ArgumentError
54
+ expect { be_valid_when(:bignum_field).is_bignum '42' }.to raise_error ArgumentError
55
+ expect { be_valid_when(:bignum_field).is_bignum 42 }.to raise_error ArgumentError
56
+ expect { be_valid_when(:bignum_field).is_bignum 3.14 }.to raise_error ArgumentError
57
+ expect { be_valid_when(:bignum_field).is_bignum :value }.to raise_error ArgumentError
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,59 @@
1
+ require 'active_model'
2
+
3
+ # @private
4
+ class FakeModel
5
+ include ActiveModel::Validations
6
+
7
+ attr_accessor :fixnum_field
8
+ attr_accessor :not_fixnum_field
9
+
10
+ validates_numericality_of :fixnum_field, greater_than: 40
11
+ validates_length_of :not_fixnum_field, minimum: 31
12
+ end
13
+
14
+ describe 'be_valid_when#is_fixnum' do
15
+ let(:model) { FakeModel.new }
16
+
17
+ context 'with no arguments' do
18
+ let(:description) { /^be valid when #fixnum_field is a fixnum \(42\)$/ }
19
+
20
+ let(:passing_matcher) { be_valid_when(:fixnum_field).is_fixnum }
21
+ let(:failing_matcher) { be_valid_when(:not_fixnum_field).is_fixnum }
22
+
23
+ it 'has the correct description' do
24
+ expect(passing_matcher.description).to match description
25
+ end
26
+
27
+ it 'returns proper result' do
28
+ expect(passing_matcher.matches? model).to eq true
29
+ expect(passing_matcher.does_not_match? model).to eq false
30
+ expect(failing_matcher.matches? model).to eq false
31
+ expect(failing_matcher.does_not_match? model).to eq true
32
+ end
33
+ end
34
+
35
+ context 'with one argument' do
36
+ let(:description) { /^be valid when #fixnum_field is a fixnum \(50\)$/ }
37
+
38
+ let(:passing_matcher) { be_valid_when(:fixnum_field).is_fixnum 50 }
39
+ let(:failing_matcher) { be_valid_when(:fixnum_field).is_fixnum 30 }
40
+
41
+ it 'has the correct description' do
42
+ expect(passing_matcher.description).to match description
43
+ end
44
+
45
+ it 'returns proper result' do
46
+ expect(passing_matcher.matches? model).to eq true
47
+ expect(passing_matcher.does_not_match? model).to eq false
48
+ expect(failing_matcher.matches? model).to eq false
49
+ expect(failing_matcher.does_not_match? model).to eq true
50
+ end
51
+
52
+ it 'should fail if passed non fixnum' do
53
+ expect { be_valid_when(:fixnum_field).is_fixnum 'value' }.to raise_error ArgumentError
54
+ expect { be_valid_when(:fixnum_field).is_fixnum '42' }.to raise_error ArgumentError
55
+ expect { be_valid_when(:fixnum_field).is_fixnum 3.14 }.to raise_error ArgumentError
56
+ expect { be_valid_when(:fixnum_field).is_fixnum :value }.to raise_error ArgumentError
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,32 @@
1
+ require 'active_model'
2
+
3
+ # @private
4
+ class FakeModel
5
+ include ActiveModel::Validations
6
+
7
+ attr_accessor :nil_field
8
+ attr_accessor :not_nil_field
9
+
10
+ validates_absence_of :nil_field
11
+ validates_presence_of :not_nil_field
12
+ end
13
+
14
+ describe 'be_valid_when#is_not_present' do
15
+ let(:model) { FakeModel.new }
16
+
17
+ let(:passing_matcher) { be_valid_when(:nil_field).is_not_present }
18
+ let(:failing_matcher) { be_valid_when(:not_nil_field).is_not_present }
19
+
20
+ let(:description) { /^be valid when #nil_field is not present \(nil\)$/ }
21
+
22
+ it 'has the correct description' do
23
+ expect(passing_matcher.description).to match description
24
+ end
25
+
26
+ it 'returns proper result' do
27
+ expect(passing_matcher.matches? model).to eq true
28
+ expect(passing_matcher.does_not_match? model).to eq false
29
+ expect(failing_matcher.matches? model).to eq false
30
+ expect(failing_matcher.does_not_match? model).to eq true
31
+ end
32
+ end
@@ -0,0 +1,58 @@
1
+ require 'active_model'
2
+
3
+ # @private
4
+ class FakeModel
5
+ include ActiveModel::Validations
6
+
7
+ attr_accessor :number_field
8
+ attr_accessor :not_number_field
9
+
10
+ validates_numericality_of :number_field, greater_than: 40
11
+ validates_length_of :not_number_field, minimum: 31
12
+ end
13
+
14
+ describe 'be_valid_when#is_number' do
15
+ let(:model) { FakeModel.new }
16
+
17
+ context 'with no arguments' do
18
+ let(:description) { /^be valid when #number_field is number \(42\)$/ }
19
+
20
+ let(:passing_matcher) { be_valid_when(:number_field).is_number }
21
+ let(:failing_matcher) { be_valid_when(:not_number_field).is_number }
22
+
23
+ it 'has the correct description' do
24
+ expect(passing_matcher.description).to match description
25
+ end
26
+
27
+ it 'returns proper result' do
28
+ expect(passing_matcher.matches? model).to eq true
29
+ expect(passing_matcher.does_not_match? model).to eq false
30
+ expect(failing_matcher.matches? model).to eq false
31
+ expect(failing_matcher.does_not_match? model).to eq true
32
+ end
33
+ end
34
+
35
+ context 'with one argument' do
36
+ let(:description) { /^be valid when #number_field is number \(50\)$/ }
37
+
38
+ let(:passing_matcher) { be_valid_when(:number_field).is_number 50 }
39
+ let(:failing_matcher) { be_valid_when(:number_field).is_number 30 }
40
+
41
+ it 'has the correct description' do
42
+ expect(passing_matcher.description).to match description
43
+ end
44
+
45
+ it 'returns proper result' do
46
+ expect(passing_matcher.matches? model).to eq true
47
+ expect(passing_matcher.does_not_match? model).to eq false
48
+ expect(failing_matcher.matches? model).to eq false
49
+ expect(failing_matcher.does_not_match? model).to eq true
50
+ end
51
+
52
+ it 'should fail if passed non number' do
53
+ expect { be_valid_when(:number_field).is_number 'value' }.to raise_error ArgumentError
54
+ expect { be_valid_when(:number_field).is_number '42' }.to raise_error ArgumentError
55
+ expect { be_valid_when(:number_field).is_number :value }.to raise_error ArgumentError
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,62 @@
1
+ require 'active_model'
2
+
3
+ # @private
4
+ class FakeModel
5
+ include ActiveModel::Validations
6
+
7
+ attr_accessor :field
8
+
9
+ validates_presence_of :field
10
+ end
11
+
12
+ RSpec.shared_examples 'sets the field value' do
13
+ it 'sets the field value' do
14
+ expect { subject.matches? model }.not_to raise_error
15
+ expect { subject.does_not_match? model }.not_to raise_error
16
+
17
+ expect(subject.matches? model).to eq true
18
+ expect(subject.does_not_match? model).to eq false
19
+
20
+ expect { subject.description }.not_to raise_error
21
+ end
22
+ end
23
+
24
+ describe 'be_valid_when#is' do
25
+ let(:model) { FakeModel.new }
26
+
27
+ it 'should fail if no arguments given' do
28
+ expect { be_valid_when(:field).is }.to raise_error ArgumentError
29
+ end
30
+
31
+ context 'when given one argument' do
32
+ subject { be_valid_when(:field).is('value') }
33
+
34
+ include_examples 'sets the field value'
35
+ end
36
+
37
+ context 'when given two arguments' do
38
+ subject { be_valid_when(:field).is('value', 'some text') }
39
+
40
+ let(:description_regex) { /^be valid when #field is some text \("value"\)$/ }
41
+ let(:message_regex) do
42
+ /^expected #<.*> to be valid when #field is some text \("value"\)$/
43
+ end
44
+ let(:negated_message_regex) do
45
+ /^expected #<.*> not to be valid when #field is some text \("value"\)$/
46
+ end
47
+
48
+ include_examples 'sets the field value'
49
+
50
+ it 'sets the custom message with second argument' do
51
+ subject.matches? model
52
+
53
+ expect(subject.description).to match description_regex
54
+ expect(subject.failure_message).to match message_regex
55
+ expect(subject.failure_message_when_negated).to match negated_message_regex
56
+ end
57
+ end
58
+
59
+ it 'should fail if more that two arguments given' do
60
+ expect { be_valid_when(:field).is('one', 'two', 'three') }.to raise_error ArgumentError
61
+ end
62
+ end
@@ -0,0 +1,209 @@
1
+ require 'active_model'
2
+
3
+ # @private
4
+ class FakeModel
5
+ include ActiveModel::Validations
6
+
7
+ attr_accessor :field
8
+ attr_accessor :other_field
9
+
10
+ validates :field, presence: true
11
+ validates :other_field, presence: true
12
+ end
13
+
14
+ describe 'be_valid_when' do
15
+ # Declarations
16
+
17
+ let(:model) { FakeModel.new }
18
+
19
+ # General specs
20
+
21
+ context 'matcher' do
22
+ subject { be_valid_when :field }
23
+
24
+ it 'is expected to be of proper type' do
25
+ expect(subject).to be_an_instance_of RSpec::BeValidWhenMatcher::BeValidWhen
26
+ end
27
+
28
+ it { is_expected.to respond_to :matches? }
29
+ it { is_expected.to respond_to :does_not_match? }
30
+ it { is_expected.to respond_to :failure_message }
31
+ it { is_expected.to respond_to :failure_message_when_negated }
32
+ it { is_expected.to respond_to :description }
33
+ it { is_expected.to respond_to :diffable? }
34
+ it { is_expected.to respond_to :supports_block_expectations? }
35
+
36
+ it 'does not support diffing' do
37
+ expect(subject.diffable?).to eq false
38
+ end
39
+
40
+ it 'does not support block expectations' do
41
+ expect(subject.supports_block_expectations?).to eq false
42
+ end
43
+ end
44
+
45
+ # Matcher arguments specs
46
+
47
+ context 'field name argument' do
48
+ it 'is expected to be provided' do
49
+ expect { be_valid_when }.to raise_error ArgumentError
50
+ end
51
+
52
+ it 'is expected to bo a symbol' do
53
+ expect { be_valid_when 42 }.to raise_error ArgumentError
54
+ expect { be_valid_when :field }.not_to raise_error
55
+ end
56
+
57
+ context 'when is the only argument provided' do
58
+ subject { be_valid_when :field }
59
+
60
+ it 'should fail on #matches?' do
61
+ expect { subject.matches? model }.to raise_error ArgumentError
62
+ end
63
+
64
+ it 'should fail on #does_not_match?' do
65
+ expect { subject.does_not_match? model }.to raise_error ArgumentError
66
+ end
67
+
68
+ it 'should fail on #failure_message' do
69
+ expect { subject.failure_message }.to raise_error ArgumentError
70
+ end
71
+
72
+ it 'should fail on #failure_message_when_negated' do
73
+ expect { subject.failure_message_when_negated }.to raise_error ArgumentError
74
+ end
75
+
76
+ it 'should fail on #description' do
77
+ expect { subject.description }.to raise_error ArgumentError
78
+ end
79
+ end
80
+ end
81
+
82
+ context 'field value argument' do
83
+ it 'can be specified when declating matcher' do
84
+ expect { be_valid_when :field, 'value' }.not_to raise_error
85
+ end
86
+
87
+ context 'if provided' do
88
+ subject { be_valid_when :field, 'value' }
89
+
90
+ it 'should not fail on #matches?' do
91
+ expect { subject.matches? model }.not_to raise_error
92
+ end
93
+
94
+ it 'should not fail on #does_not_match?' do
95
+ expect { subject.does_not_match? model }.not_to raise_error
96
+ end
97
+ end
98
+ end
99
+
100
+ context 'custom message argument' do
101
+ it 'can be specified when declating matcher' do
102
+ expect { be_valid_when :field, 'value', 'some text' }.not_to raise_error
103
+ end
104
+
105
+ context 'if provided' do
106
+ subject { be_valid_when :field, 'value', 'some text' }
107
+
108
+ it 'should not fail on #matches?' do
109
+ expect { subject.matches? model }.not_to raise_error
110
+ end
111
+
112
+ it 'should not fail on #does_not_match?' do
113
+ expect { subject.does_not_match? model }.not_to raise_error
114
+ end
115
+ end
116
+ end
117
+
118
+ it 'should not accept more arguments than field symbol, field value and custom message' do
119
+ expect { be_valid_when :field, 'value', 'some text', 'other arg' }.to raise_error ArgumentError
120
+ end
121
+
122
+ # General matching interface specs
123
+
124
+ context 'if not provided with model to match' do
125
+ subject { be_valid_when :field, 'value' }
126
+
127
+ it 'should fail on #matches?' do
128
+ expect { subject.matches? }.to raise_error ArgumentError
129
+ end
130
+
131
+ it 'should fail on #does_not_match?' do
132
+ expect { subject.does_not_match? }.to raise_error ArgumentError
133
+ end
134
+
135
+ it 'should fail on #failure_message' do
136
+ expect { subject.failure_message }.to raise_error ArgumentError
137
+ end
138
+
139
+ it 'should fail on #failure_message_when_negated' do
140
+ expect { subject.failure_message_when_negated }.to raise_error ArgumentError
141
+ end
142
+ end
143
+
144
+ context 'when asserting validity of model' do
145
+ subject { be_valid_when :field }
146
+
147
+ context 'using #matches?' do
148
+ it 'is setting the proper field using the provided value' do
149
+ model.field = nil
150
+ subject.is('value').matches? model
151
+ expect(model.field).to eq 'value'
152
+ end
153
+
154
+ it 'returns proper result' do
155
+ expect(subject.is('value').matches? model).to eq true
156
+ expect(subject.is(nil).matches? model).to eq false
157
+ end
158
+ end
159
+
160
+ context 'using #does_not_match?' do
161
+ it 'is setting the proper field using the provided value' do
162
+ model.field = nil
163
+ subject.is('value').does_not_match? model
164
+ expect(model.field).to eq 'value'
165
+ end
166
+
167
+ it 'returns proper result' do
168
+ expect(subject.is('value').does_not_match? model).to eq false
169
+ expect(subject.is(nil).does_not_match? model).to eq true
170
+ end
171
+ end
172
+ end
173
+
174
+ # Message methods specs
175
+
176
+ context 'failure message' do
177
+ subject { be_valid_when :field, 'value' }
178
+
179
+ let(:message_regex) do
180
+ /^expected #<.*> to be valid when #field is "value"$/
181
+ end
182
+
183
+ it 'provides subject model, field name and field value' do
184
+ subject.matches?(model)
185
+ expect(subject.failure_message).to match message_regex
186
+ end
187
+
188
+ context 'when negated' do
189
+ let(:negated_message_regex) do
190
+ /^expected #<.*> not to be valid when #field is "value"$/
191
+ end
192
+
193
+ it 'provides subject model, field name and field value' do
194
+ subject.does_not_match?(model)
195
+ expect(subject.failure_message_when_negated).to match negated_message_regex
196
+ end
197
+ end
198
+ end
199
+
200
+ context 'description' do
201
+ subject { be_valid_when :field, 'value' }
202
+
203
+ let(:description_regex) { /^be valid when #field is "value"$/ }
204
+
205
+ it 'provides field name and field value' do
206
+ expect(subject.description).to match description_regex
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,55 @@
1
+ # Conventionally, all specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
2
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this file to always
3
+ # be loaded, without a need to explicitly require it in any files.
4
+ #
5
+ # Given that it is always loaded, keep this file as light-weight as possible. Requiring heavyweight
6
+ # dependencies from this file will add to the boot time of test suite on EVERY test run, even for
7
+ # an individual file that may not need all of that loaded. Instead, consider making a separate
8
+ # helper file that requires the additional dependencies and performs the additional setup,
9
+ # and require it from the spec files that actually need it.
10
+ #
11
+ # The `.rspec` file also contains a few flags that are not defaults but that are commonly wanted.
12
+ #
13
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
14
+
15
+ require 'rspec/be_valid_when_matcher'
16
+
17
+ RSpec.configure do |config|
18
+ config.include RSpec::BeValidWhenMatcher
19
+
20
+ # rspec-expectations config goes here.
21
+ config.expect_with :rspec do |expectations|
22
+ # This option will default to `true` in RSpec 4. It makes the `description` and
23
+ # `failure_message` of custom matchers include text for helper methods defined using
24
+ # `chain`, e.g.:
25
+ # be_bigger_than(2).and_smaller_than(4).description
26
+ # # => "be bigger than 2 and smaller than 4"
27
+ # ...rather than:
28
+ # # => "be bigger than 2"
29
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
30
+
31
+ # Only allow expect syntax.
32
+ expectations.syntax = :expect
33
+ end
34
+
35
+ # rspec-mocks config goes here.
36
+ config.mock_with :rspec do |mocks|
37
+ # Prevents from mocking or stubbing a method that does not exist on a real object.
38
+ # This is generally recommended, and will default to `true` in RSpec 4.
39
+ mocks.verify_partial_doubles = true
40
+ end
41
+
42
+ # Allows RSpec to persist some state between runs in order to support the `--only-failures` and
43
+ # `--next-failure` CLI options. Source control system should be configured to ignore this file.
44
+ config.example_status_persistence_file_path = 'spec/examples.cache'
45
+
46
+ # Run specs in random order to surface order dependencies. To debug an order dependency after
47
+ # finding one, fix the order by providing the seed, which is printed after each run.
48
+ # --seed 1234
49
+ config.order = :random
50
+
51
+ # Seed global randomization in this process using the `--seed` CLI option. Setting this allows
52
+ # to use `--seed` to deterministically reproduce test failures related to randomization
53
+ # by passing the same `--seed` value as the one that triggered the failure.
54
+ Kernel.srand config.seed
55
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-be_valid_when_matcher
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Marek Tuchowski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activemodel
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4'
41
+ description: RSpec matcher for testing ActiveRecord models with a fluent language.
42
+ email: marek@tuchowski.com.pl
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files:
46
+ - README.md
47
+ - LICENSE
48
+ files:
49
+ - LICENSE
50
+ - README.md
51
+ - lib/rspec/be_valid_when_matcher.rb
52
+ - spec/examples.cache
53
+ - spec/rspec/be_valid_when/is_bignum_spec.rb
54
+ - spec/rspec/be_valid_when/is_fixnum_spec.rb
55
+ - spec/rspec/be_valid_when/is_not_present_spec.rb
56
+ - spec/rspec/be_valid_when/is_number_spec.rb
57
+ - spec/rspec/be_valid_when/is_spec.rb
58
+ - spec/rspec/be_valid_when_matcher_spec.rb
59
+ - spec/spec_helper.rb
60
+ homepage: https://github.com/mtuchowski/rspec-be_valid_when_matcher
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options:
66
+ - "--charset"
67
+ - UTF-8
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.4.8
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: RSpec be_valid_when matcher for ActiveRecord models.
86
+ test_files:
87
+ - spec/spec_helper.rb
88
+ - spec/rspec/be_valid_when_matcher_spec.rb
89
+ - spec/rspec/be_valid_when/is_number_spec.rb
90
+ - spec/rspec/be_valid_when/is_bignum_spec.rb
91
+ - spec/rspec/be_valid_when/is_spec.rb
92
+ - spec/rspec/be_valid_when/is_not_present_spec.rb
93
+ - spec/rspec/be_valid_when/is_fixnum_spec.rb
94
+ - spec/examples.cache
95
+ has_rdoc: