shoulda-matchers 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +3 -1
- data/Gemfile +1 -2
- data/Gemfile.lock +8 -2
- data/NEWS.md +29 -1
- data/README.md +3 -11
- data/doc_config/yard/templates/default/fulldoc/html/css/global.css +17 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/style.css +3 -4
- data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +1 -1
- data/doc_config/yard/templates/default/layout/html/footer.erb +6 -0
- data/docs/errors/NonCaseSwappableValueError.md +111 -0
- data/gemfiles/4.0.0.gemfile +1 -2
- data/gemfiles/4.0.0.gemfile.lock +5 -2
- data/gemfiles/4.0.1.gemfile +1 -2
- data/gemfiles/4.0.1.gemfile.lock +5 -2
- data/gemfiles/4.1.gemfile +1 -2
- data/gemfiles/4.1.gemfile.lock +5 -2
- data/gemfiles/4.2.gemfile +1 -2
- data/gemfiles/4.2.gemfile.lock +5 -2
- data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +1 -5
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +26 -4
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +9 -8
- data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +14 -8
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +47 -12
- data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +15 -9
- data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +14 -7
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +16 -4
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +67 -5
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +35 -0
- data/lib/shoulda/matchers/util.rb +2 -0
- data/lib/shoulda/matchers/util/word_wrap.rb +178 -0
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers/warn.rb +1 -10
- data/spec/acceptance_spec_helper.rb +2 -10
- data/spec/doublespeak_spec_helper.rb +1 -17
- data/spec/spec_helper.rb +23 -0
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +1 -1
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +5 -2
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +5 -2
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +5 -1
- data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +91 -4
- data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +292 -2
- data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +16 -2
- data/spec/unit/shoulda/matchers/util/word_wrap_spec.rb +197 -0
- data/spec/unit_spec_helper.rb +1 -16
- data/tasks/documentation.rb +10 -17
- metadata +9 -2
@@ -412,6 +412,14 @@ module Shoulda
|
|
412
412
|
if @options[:case_insensitive]
|
413
413
|
disallows_value_of(swapcased_value, @expected_message)
|
414
414
|
else
|
415
|
+
if value == swapcased_value
|
416
|
+
raise NonCaseSwappableValueError.create(
|
417
|
+
model: @subject.class,
|
418
|
+
attribute: @attribute,
|
419
|
+
value: value
|
420
|
+
)
|
421
|
+
end
|
422
|
+
|
415
423
|
allows_value_of(swapcased_value, @expected_message)
|
416
424
|
end
|
417
425
|
else
|
@@ -551,6 +559,33 @@ module Shoulda
|
|
551
559
|
def column_for(scope)
|
552
560
|
@subject.class.columns_hash[scope.to_s]
|
553
561
|
end
|
562
|
+
|
563
|
+
# @private
|
564
|
+
class NonCaseSwappableValueError < Shoulda::Matchers::Error
|
565
|
+
attr_accessor :model, :attribute, :value
|
566
|
+
|
567
|
+
def message
|
568
|
+
Shoulda::Matchers.word_wrap <<-MESSAGE
|
569
|
+
Your #{model.name} model has a uniqueness validation on :#{attribute} which is
|
570
|
+
declared to be case-sensitive, but the value the uniqueness matcher used,
|
571
|
+
#{value.inspect}, doesn't contain any alpha characters, so using it to
|
572
|
+
to test the case-sensitivity part of the validation is ineffective. There are
|
573
|
+
two possible solutions for this depending on what you're trying to do here:
|
574
|
+
|
575
|
+
a) If you meant for the validation to be case-sensitive, then you need to give
|
576
|
+
the uniqueness matcher a saved instance of #{model.name} with a value for
|
577
|
+
:#{attribute} that contains alpha characters.
|
578
|
+
|
579
|
+
b) If you meant for the validation to be case-insensitive, then you need to
|
580
|
+
add `case_sensitive: false` to the validation and add `case_insensitive` to
|
581
|
+
the matcher.
|
582
|
+
|
583
|
+
For more information, please see:
|
584
|
+
|
585
|
+
http://matchers.shoulda.io/docs/v#{Shoulda::Matchers::VERSION}/file.NonCaseSwappableValueError.html
|
586
|
+
MESSAGE
|
587
|
+
end
|
588
|
+
end
|
554
589
|
end
|
555
590
|
end
|
556
591
|
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
# @private
|
4
|
+
def self.word_wrap(document)
|
5
|
+
Document.new(document).wrap
|
6
|
+
end
|
7
|
+
|
8
|
+
# @private
|
9
|
+
class Document
|
10
|
+
def initialize(document)
|
11
|
+
@document = document
|
12
|
+
end
|
13
|
+
|
14
|
+
def wrap
|
15
|
+
wrapped_paragraphs.map { |lines| lines.join("\n") }.join("\n\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
attr_reader :document
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def paragraphs
|
25
|
+
document.split(/\n{2,}/)
|
26
|
+
end
|
27
|
+
|
28
|
+
def wrapped_paragraphs
|
29
|
+
paragraphs.map do |paragraph|
|
30
|
+
Paragraph.new(paragraph).wrap
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# @private
|
36
|
+
class Text < ::String
|
37
|
+
LIST_ITEM_REGEXP = /\A((?:[a-z0-9]+(?:\)|\.)|\*) )/
|
38
|
+
|
39
|
+
def indented?
|
40
|
+
self =~ /\A[ ]+/
|
41
|
+
end
|
42
|
+
|
43
|
+
def list_item?
|
44
|
+
self =~ LIST_ITEM_REGEXP
|
45
|
+
end
|
46
|
+
|
47
|
+
def match_as_list_item
|
48
|
+
match(LIST_ITEM_REGEXP)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# @private
|
53
|
+
class Paragraph
|
54
|
+
def initialize(paragraph)
|
55
|
+
@paragraph = Text.new(paragraph)
|
56
|
+
end
|
57
|
+
|
58
|
+
def wrap
|
59
|
+
if paragraph.indented?
|
60
|
+
lines
|
61
|
+
elsif paragraph.list_item?
|
62
|
+
wrap_list_item
|
63
|
+
else
|
64
|
+
wrap_generic_paragraph
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
attr_reader :paragraph
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def wrap_list_item
|
75
|
+
wrap_lines(combine_list_item_lines(lines))
|
76
|
+
end
|
77
|
+
|
78
|
+
def lines
|
79
|
+
paragraph.split("\n").map { |line| Text.new(line) }
|
80
|
+
end
|
81
|
+
|
82
|
+
def combine_list_item_lines(lines)
|
83
|
+
lines.reduce([]) do |combined_lines, line|
|
84
|
+
if line.list_item?
|
85
|
+
combined_lines << line
|
86
|
+
else
|
87
|
+
combined_lines.last << (' ' + line).squeeze(' ')
|
88
|
+
end
|
89
|
+
|
90
|
+
combined_lines
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def wrap_lines(lines)
|
95
|
+
lines.map { |line| Line.new(line).wrap }
|
96
|
+
end
|
97
|
+
|
98
|
+
def wrap_generic_paragraph
|
99
|
+
Line.new(combine_paragraph_into_one_line).wrap
|
100
|
+
end
|
101
|
+
|
102
|
+
def combine_paragraph_into_one_line
|
103
|
+
paragraph.gsub(/\n/, ' ')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# @private
|
108
|
+
class Line
|
109
|
+
TERMINAL_WIDTH = 72
|
110
|
+
|
111
|
+
def initialize(line)
|
112
|
+
@original_line = @line_to_wrap = Text.new(line)
|
113
|
+
@indentation = nil
|
114
|
+
end
|
115
|
+
|
116
|
+
def wrap
|
117
|
+
lines = []
|
118
|
+
|
119
|
+
if line_to_wrap.indented?
|
120
|
+
lines << line_to_wrap
|
121
|
+
else
|
122
|
+
loop do
|
123
|
+
new_line = (indentation || '') + line_to_wrap
|
124
|
+
result = wrap_line(new_line)
|
125
|
+
lines << result[:fitted_line].rstrip
|
126
|
+
@indentation ||= read_indentation
|
127
|
+
@line_to_wrap = result[:leftover]
|
128
|
+
|
129
|
+
if line_to_wrap.empty? || @original_line == @line_to_wrap
|
130
|
+
break
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
lines
|
136
|
+
end
|
137
|
+
|
138
|
+
protected
|
139
|
+
|
140
|
+
attr_reader :original_line, :line_to_wrap, :indentation
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def read_indentation
|
145
|
+
match = line_to_wrap.match_as_list_item
|
146
|
+
|
147
|
+
if match
|
148
|
+
' ' * match[1].length
|
149
|
+
else
|
150
|
+
''
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def wrap_line(line)
|
155
|
+
if line.length > TERMINAL_WIDTH
|
156
|
+
index = determine_where_to_break_line(line)
|
157
|
+
fitted_line = line[0 .. index].rstrip
|
158
|
+
leftover = line[index + 1 .. -1]
|
159
|
+
else
|
160
|
+
fitted_line = line
|
161
|
+
leftover = ''
|
162
|
+
end
|
163
|
+
|
164
|
+
{ fitted_line: fitted_line, leftover: leftover }
|
165
|
+
end
|
166
|
+
|
167
|
+
def determine_where_to_break_line(line)
|
168
|
+
index = TERMINAL_WIDTH - 1
|
169
|
+
|
170
|
+
while line[index] !~ /\s/
|
171
|
+
index -= 1
|
172
|
+
end
|
173
|
+
|
174
|
+
index
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -6,7 +6,7 @@ module Shoulda
|
|
6
6
|
def self.warn(message)
|
7
7
|
header = "Warning from shoulda-matchers:"
|
8
8
|
divider = "*" * TERMINAL_MAX_WIDTH
|
9
|
-
wrapped_message = word_wrap(message
|
9
|
+
wrapped_message = word_wrap(message)
|
10
10
|
full_message = [
|
11
11
|
divider,
|
12
12
|
[header, wrapped_message.strip].join("\n\n"),
|
@@ -23,14 +23,5 @@ module Shoulda
|
|
23
23
|
release. Please use #{new_method} instead.
|
24
24
|
EOT
|
25
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" )
|
34
|
-
end
|
35
26
|
end
|
36
27
|
end
|
@@ -5,20 +5,14 @@ Tests::CurrentBundle.instance.assert_appraisal!
|
|
5
5
|
#---
|
6
6
|
|
7
7
|
require 'rspec/core'
|
8
|
-
|
9
|
-
require '
|
8
|
+
|
9
|
+
require 'spec_helper'
|
10
10
|
|
11
11
|
Dir[ File.join(File.expand_path('../support/acceptance/**/*.rb', __FILE__)) ].sort.each do |file|
|
12
12
|
require file
|
13
13
|
end
|
14
14
|
|
15
15
|
RSpec.configure do |config|
|
16
|
-
config.order = :random
|
17
|
-
|
18
|
-
config.expect_with :rspec do |c|
|
19
|
-
c.syntax = :expect
|
20
|
-
end
|
21
|
-
|
22
16
|
if config.respond_to?(:infer_spec_type_from_file_location!)
|
23
17
|
config.infer_spec_type_from_file_location!
|
24
18
|
end
|
@@ -27,5 +21,3 @@ RSpec.configure do |config|
|
|
27
21
|
|
28
22
|
config.include AcceptanceTests::Matchers
|
29
23
|
end
|
30
|
-
|
31
|
-
$VERBOSE = true
|
@@ -1,18 +1,2 @@
|
|
1
1
|
require 'shoulda/matchers/doublespeak'
|
2
|
-
|
3
|
-
PROJECT_ROOT = File.expand_path('../..', __FILE__)
|
4
|
-
$LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
|
5
|
-
|
6
|
-
RSpec.configure do |config|
|
7
|
-
config.order = :random
|
8
|
-
|
9
|
-
config.expect_with :rspec do |c|
|
10
|
-
c.syntax = :expect
|
11
|
-
end
|
12
|
-
|
13
|
-
if config.files_to_run.one?
|
14
|
-
config.default_formatter = 'doc'
|
15
|
-
end
|
16
|
-
|
17
|
-
config.mock_with :rspec
|
18
|
-
end
|
2
|
+
require 'spec_helper'
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
PROJECT_ROOT = File.expand_path('../..', __FILE__)
|
2
|
+
$LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
|
3
|
+
|
4
|
+
require 'pry'
|
5
|
+
require 'pry-byebug'
|
6
|
+
|
7
|
+
require 'rspec'
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.order = :random
|
11
|
+
|
12
|
+
config.expect_with :rspec do |c|
|
13
|
+
c.syntax = :expect
|
14
|
+
end
|
15
|
+
|
16
|
+
if config.files_to_run.one?
|
17
|
+
config.default_formatter = 'doc'
|
18
|
+
end
|
19
|
+
|
20
|
+
config.mock_with :rspec
|
21
|
+
end
|
22
|
+
|
23
|
+
$VERBOSE = true
|
data/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'unit_spec_helper'
|
2
2
|
|
3
3
|
describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::EvenNumberMatcher do
|
4
|
-
subject { described_class.new(:attr) }
|
4
|
+
subject { described_class.new(numericality_matcher, :attr) }
|
5
5
|
|
6
6
|
it_behaves_like 'a numerical submatcher'
|
7
7
|
it_behaves_like 'a numerical type submatcher'
|
@@ -84,6 +84,10 @@ describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::EvenNumberMatcher
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
+
def numericality_matcher
|
88
|
+
double(:numericality_matcher, given_numeric_column?: nil)
|
89
|
+
end
|
90
|
+
|
87
91
|
def validating_even_number(options = {})
|
88
92
|
define_model :example, attr: :string do
|
89
93
|
validates_numericality_of :attr, { even: true }.merge(options)
|
@@ -93,5 +97,4 @@ describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::EvenNumberMatcher
|
|
93
97
|
def not_validating_even_number
|
94
98
|
define_model(:example, attr: :string).new
|
95
99
|
end
|
96
|
-
|
97
100
|
end
|
data/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'unit_spec_helper'
|
2
2
|
|
3
3
|
describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::OddNumberMatcher do
|
4
|
-
subject { described_class.new(:attr) }
|
4
|
+
subject { described_class.new(numericality_matcher, :attr) }
|
5
5
|
|
6
6
|
it_behaves_like 'a numerical submatcher'
|
7
7
|
it_behaves_like 'a numerical type submatcher'
|
@@ -84,6 +84,10 @@ describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::OddNumberMatcher
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
+
def numericality_matcher
|
88
|
+
double(:numericality_matcher, given_numeric_column?: nil)
|
89
|
+
end
|
90
|
+
|
87
91
|
def validating_odd_number(options = {})
|
88
92
|
define_model :example, attr: :string do
|
89
93
|
validates_numericality_of :attr, { odd: true }.merge(options)
|
@@ -93,5 +97,4 @@ describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::OddNumberMatcher
|
|
93
97
|
def not_validating_odd_number
|
94
98
|
define_model(:example, attr: :string).new
|
95
99
|
end
|
96
|
-
|
97
100
|
end
|
data/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'unit_spec_helper'
|
2
2
|
|
3
3
|
describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::OnlyIntegerMatcher do
|
4
|
-
subject { described_class.new(:attr) }
|
4
|
+
subject { described_class.new(numericality_matcher, :attr) }
|
5
5
|
|
6
6
|
it_behaves_like 'a numerical submatcher'
|
7
7
|
it_behaves_like 'a numerical type submatcher'
|
@@ -84,6 +84,10 @@ describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::OnlyIntegerMatche
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
+
def numericality_matcher
|
88
|
+
double(:numericality_matcher, given_numeric_column?: nil)
|
89
|
+
end
|
90
|
+
|
87
91
|
def validating_only_integer(options = {})
|
88
92
|
define_model :example, attr: :string do
|
89
93
|
validates_numericality_of :attr, { only_integer: true }.merge(options)
|
@@ -75,7 +75,7 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
context
|
78
|
+
context 'against a float attribute' do
|
79
79
|
it_behaves_like 'it supports in_array',
|
80
80
|
possible_values: [1.0, 2.0, 3.0, 4.0, 5.0],
|
81
81
|
zero: 0.0,
|
@@ -97,7 +97,7 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
|
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
-
context
|
100
|
+
context 'against a decimal attribute' do
|
101
101
|
it_behaves_like 'it supports in_array',
|
102
102
|
possible_values: [1.0, 2.0, 3.0, 4.0, 5.0].map { |number|
|
103
103
|
BigDecimal.new(number.to_s)
|
@@ -121,6 +121,72 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
|
+
context 'against a date attribute' do
|
125
|
+
today = Date.today
|
126
|
+
|
127
|
+
it_behaves_like 'it supports in_array',
|
128
|
+
possible_values: (1..5).map { |n| today + n },
|
129
|
+
reserved_outside_value: described_class::ARBITRARY_OUTSIDE_DATE
|
130
|
+
|
131
|
+
it_behaves_like 'it supports in_range',
|
132
|
+
possible_values: (today .. today + 5)
|
133
|
+
|
134
|
+
define_method :build_object do |options = {}, &block|
|
135
|
+
build_object_with_generic_attribute(
|
136
|
+
options.merge(column_type: :date, value: today),
|
137
|
+
&block
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
def add_outside_value_to(values)
|
142
|
+
values + [values.last + 1]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'against a datetime attribute' do
|
147
|
+
now = DateTime.now
|
148
|
+
|
149
|
+
it_behaves_like 'it supports in_array',
|
150
|
+
possible_values: (1..5).map { |n| now + n },
|
151
|
+
reserved_outside_value: described_class::ARBITRARY_OUTSIDE_DATETIME
|
152
|
+
|
153
|
+
it_behaves_like 'it supports in_range',
|
154
|
+
possible_values: (now .. now + 5)
|
155
|
+
|
156
|
+
define_method :build_object do |options = {}, &block|
|
157
|
+
build_object_with_generic_attribute(
|
158
|
+
options.merge(column_type: :datetime, value: now),
|
159
|
+
&block
|
160
|
+
)
|
161
|
+
end
|
162
|
+
|
163
|
+
def add_outside_value_to(values)
|
164
|
+
values + [values.last + 1]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context 'against a time attribute' do
|
169
|
+
now = Time.now
|
170
|
+
|
171
|
+
it_behaves_like 'it supports in_array',
|
172
|
+
possible_values: (1..5).map { |n| now + n },
|
173
|
+
reserved_outside_value: described_class::ARBITRARY_OUTSIDE_TIME
|
174
|
+
|
175
|
+
it_behaves_like 'it supports in_range',
|
176
|
+
possible_values: (now .. now + 5)
|
177
|
+
|
178
|
+
define_method :build_object do |options = {}, &block|
|
179
|
+
build_object_with_generic_attribute(
|
180
|
+
options.merge(column_type: :time, value: now),
|
181
|
+
&block
|
182
|
+
)
|
183
|
+
end
|
184
|
+
|
185
|
+
def add_outside_value_to(values)
|
186
|
+
values + [values.last + 1]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
124
190
|
context 'against a string attribute' do
|
125
191
|
it_behaves_like 'it supports in_array',
|
126
192
|
possible_values: %w(foo bar baz),
|
@@ -270,7 +336,7 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
|
|
270
336
|
end
|
271
337
|
|
272
338
|
if zero
|
273
|
-
it 'matches when one of the given values is a
|
339
|
+
it 'matches when one of the given values is a zero' do
|
274
340
|
valid_values = possible_values + [zero]
|
275
341
|
builder = build_object_allowing(valid_values)
|
276
342
|
expect_to_match_on_values(builder, valid_values)
|
@@ -468,6 +534,28 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
|
|
468
534
|
context 'for a database column' do
|
469
535
|
include_context 'for a generic attribute'
|
470
536
|
|
537
|
+
context 'against a timestamp column' do
|
538
|
+
now = DateTime.now
|
539
|
+
|
540
|
+
it_behaves_like 'it supports in_array',
|
541
|
+
possible_values: (1..5).map { |n| now + n },
|
542
|
+
reserved_outside_value: described_class::ARBITRARY_OUTSIDE_DATETIME
|
543
|
+
|
544
|
+
it_behaves_like 'it supports in_range',
|
545
|
+
possible_values: (now .. now + 5)
|
546
|
+
|
547
|
+
define_method :build_object do |options = {}, &block|
|
548
|
+
build_object_with_generic_attribute(
|
549
|
+
options.merge(column_type: :timestamp, value: now),
|
550
|
+
&block
|
551
|
+
)
|
552
|
+
end
|
553
|
+
|
554
|
+
def add_outside_value_to(values)
|
555
|
+
values + [values.last + 1]
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
471
559
|
context 'against a boolean attribute' do
|
472
560
|
context 'which is nullable' do
|
473
561
|
include_context 'against a boolean attribute for true and false'
|
@@ -527,7 +615,6 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
|
|
527
615
|
end
|
528
616
|
end
|
529
617
|
|
530
|
-
|
531
618
|
def build_object_with_generic_attribute(options = {}, &block)
|
532
619
|
attribute_name = :attr
|
533
620
|
column_type = options.fetch(:column_type)
|