rspec-be_valid_when_matcher 0.1.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 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: