rspec-validates_timeliness 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +67 -0
- data/Rakefile +6 -0
- data/bin/console +10 -0
- data/bin/setup +8 -0
- data/lib/rspec-validates_timeliness.rb +7 -0
- data/lib/rspec-validates_timeliness/matchers.rb +15 -0
- data/lib/rspec-validates_timeliness/matchers/expected_value.rb +44 -0
- data/lib/rspec-validates_timeliness/matchers/message_builder.rb +28 -0
- data/lib/rspec-validates_timeliness/matchers/validation_matcher.rb +143 -0
- data/lib/rspec-validates_timeliness/matchers/validator_proxy.rb +36 -0
- data/lib/rspec-validates_timeliness/version.rb +5 -0
- data/rspec-validates_timeliness.gemspec +31 -0
- data/spec/acceptance/validates_date_spec.rb +19 -0
- data/spec/acceptance/validates_date_time_spec.rb +19 -0
- data/spec/acceptance/validates_time_spec.rb +19 -0
- data/spec/lib/rspec-validates_timeliness/matchers/expected_value_spec.rb +103 -0
- data/spec/lib/rspec-validates_timeliness/matchers/message_builder_spec.rb +35 -0
- data/spec/lib/rspec-validates_timeliness/matchers/validation_matcher_spec.rb +97 -0
- data/spec/lib/rspec-validates_timeliness/matchers/validator_proxy_spec.rb +47 -0
- data/spec/lib/rspec-validates_timeliness/matchers_spec.rb +18 -0
- data/spec/lib/rspec-validates_timeliness_spec.rb +6 -0
- data/spec/spec_helper.rb +12 -0
- metadata +180 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e33418e0bc1ca0d9159d7261d703e400d64c5580
|
4
|
+
data.tar.gz: d07b63180655408b4919558a75bf3e001ab186bc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 533b1d9f4d0737feaee37c26ef12a0d66d67c28e213b743c7fb11a697af7d0affc1b33a92a6f044a152ab1f510b6c265e2b595045f92d6a33252a0d6cb4ee945
|
7
|
+
data.tar.gz: 1898aba67ad2dcc7ba31da36cee42b726efa18a88aedfa6e51a876e81c51d90960b4fcdc90b3d95fd860a6f855b295e4c7234cfc6480af135526c63a09d1804d
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Yoshiyuki Hirano
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# RSpec::ValidatesTimeliness
|
2
|
+
|
3
|
+
Simple RSpec matchers for [validates_timeliness](https://github.com/adzap/validates_timeliness)
|
4
|
+
|
5
|
+
## Matchers
|
6
|
+
|
7
|
+
- **validates_timeliness_of** tests usage of validates_timeliness
|
8
|
+
- **validates_datetime** tests usage of `validates_datetime` (alias of `validates_timeliness_of`).
|
9
|
+
- **validates_date** tests usage of `validates_date` (alias of `validates_timeliness_of`).
|
10
|
+
- **validates_time** tests usage of `validate_time` (alias of `validates_timeliness_of`).
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'rspec-validates_timeliness'
|
18
|
+
```
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install rspec-validates_timeliness
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
Here is model:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
class Person
|
34
|
+
include ActiveModel::model
|
35
|
+
|
36
|
+
validates_date :date_of_birth, before: lambda { 18.years.ago }
|
37
|
+
validates_time :breakfast_time, is_at: '7:00am'
|
38
|
+
validates_time :updated_at, between: ['9:00am', '5:00pm']
|
39
|
+
|
40
|
+
# validates_datetime :start_time, before: :finish_time **[CAUTION] Method symbol is not support**
|
41
|
+
# validates_date :created_at, on_or_after: :today **[CAUTION] Shorthand is not support**
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
And with `rspec-validates_timeliness` we can now make simple assertions about those models:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
require 'spec_helper'
|
49
|
+
|
50
|
+
describe Person, type: :model do
|
51
|
+
it { is_expected.to validates_date(:date_of_birth).before { 18.years.ago.to_date } }
|
52
|
+
it { is_expected.to validates_time(:breakfast_time).is_at('7:00am') }
|
53
|
+
it { is_expected.to validates_time(:updated_at).between(['9:00am', '5:00pm']) }
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
## Contributing
|
58
|
+
|
59
|
+
1. Fork it
|
60
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
61
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
62
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
63
|
+
5. Create new Pull Request
|
64
|
+
|
65
|
+
## Changelog
|
66
|
+
|
67
|
+
* Release 0.0.1 (Jun 12, 2016)
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "rspec-validates_timeliness"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
require "pry"
|
10
|
+
Pry.start
|
data/bin/setup
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
require 'timecop'
|
4
|
+
|
5
|
+
require 'rspec-validates_timeliness/matchers/expected_value'
|
6
|
+
require 'rspec-validates_timeliness/matchers/message_builder'
|
7
|
+
require 'rspec-validates_timeliness/matchers/validation_matcher'
|
8
|
+
require 'rspec-validates_timeliness/matchers/validator_proxy'
|
9
|
+
|
10
|
+
module RSpec
|
11
|
+
module ValidatesTimeliness
|
12
|
+
module Matchers
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module RSpec::ValidatesTimeliness
|
2
|
+
module Matchers
|
3
|
+
class ExpectedValue
|
4
|
+
def initialize(value)
|
5
|
+
@value = evaluate(value)
|
6
|
+
end
|
7
|
+
|
8
|
+
def equal
|
9
|
+
@equal ||= value
|
10
|
+
end
|
11
|
+
|
12
|
+
def over
|
13
|
+
case value
|
14
|
+
when Time, DateTime
|
15
|
+
value + 1.second
|
16
|
+
when Date
|
17
|
+
value + 1.day
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def under
|
22
|
+
case value
|
23
|
+
when Time, DateTime
|
24
|
+
value - 1.second
|
25
|
+
when Date
|
26
|
+
value - 1.day
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :value
|
33
|
+
|
34
|
+
def evaluate(value)
|
35
|
+
case value
|
36
|
+
when Proc then value.call
|
37
|
+
when Time, DateTime, Date then value
|
38
|
+
when String then value.to_time
|
39
|
+
else nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RSpec::ValidatesTimeliness
|
2
|
+
module Matchers
|
3
|
+
class MessageBuilder
|
4
|
+
def initialize(base_message)
|
5
|
+
@base_message = base_message
|
6
|
+
@option_messages = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def full_message
|
10
|
+
[base_message, option_message].join(' ')
|
11
|
+
end
|
12
|
+
|
13
|
+
alias to_s full_message
|
14
|
+
|
15
|
+
def <<(text)
|
16
|
+
option_messages << text
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :base_message, :option_messages
|
22
|
+
|
23
|
+
def option_message
|
24
|
+
option_messages.join(' and ')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module RSpec::ValidatesTimeliness
|
2
|
+
module Matchers
|
3
|
+
def validates_timeliness_of(attr_name)
|
4
|
+
ValidationMatcher.new(attr_name)
|
5
|
+
end
|
6
|
+
|
7
|
+
alias validates_date validates_timeliness_of
|
8
|
+
alias validates_time validates_timeliness_of
|
9
|
+
alias validates_datetime validates_timeliness_of
|
10
|
+
|
11
|
+
class ValidationMatcher
|
12
|
+
attr_reader :description
|
13
|
+
|
14
|
+
def initialize(attr_name)
|
15
|
+
@attr_name = attr_name
|
16
|
+
@options = {}
|
17
|
+
@description = MessageBuilder.new(base_description)
|
18
|
+
end
|
19
|
+
|
20
|
+
def is_at(value = nil, &block)
|
21
|
+
options[__method__] = block_given? ? block : value
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def after(value = nil, &block)
|
26
|
+
options[__method__] = block_given? ? block : value
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_or_after(value = nil, &block)
|
31
|
+
options[__method__] = block_given? ? block : value
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def before(value = nil, &block)
|
36
|
+
options[__method__] = block_given? ? block : value
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_or_before(value = nil, &block)
|
41
|
+
options[__method__] = block_given? ? block : value
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def between(value)
|
46
|
+
case value
|
47
|
+
when Array, Range
|
48
|
+
options[:on_or_after] = value.first
|
49
|
+
options[value.is_a?(Range) && value.exclude_end? ? :before : :on_or_before] = value.last
|
50
|
+
end
|
51
|
+
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def matches?(subject)
|
56
|
+
@subject = subject
|
57
|
+
|
58
|
+
attribute_exist? && all_options_correct?
|
59
|
+
end
|
60
|
+
|
61
|
+
def failure_message
|
62
|
+
"Expected #{description}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def failure_message_when_negated
|
66
|
+
"Did not expect #{description}"
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
attr_reader :attr_name, :options, :subject
|
72
|
+
|
73
|
+
def base_description
|
74
|
+
"validate that :#{attr_name} must be"
|
75
|
+
end
|
76
|
+
|
77
|
+
def attribute_exist?
|
78
|
+
subject.respond_to?(attr_name)
|
79
|
+
end
|
80
|
+
|
81
|
+
def all_options_correct?
|
82
|
+
options.compact.keys.all? do |option_name|
|
83
|
+
send(:"#{option_name}_correct?")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def run_correct
|
88
|
+
Timecop.freeze
|
89
|
+
yield
|
90
|
+
ensure
|
91
|
+
Timecop.return
|
92
|
+
end
|
93
|
+
|
94
|
+
def is_at_correct?
|
95
|
+
run_correct do
|
96
|
+
value = ExpectedValue.new(options[:is_at])
|
97
|
+
description << "at #{value.equal}"
|
98
|
+
valid?(value.equal) && invalid?(value.over) && invalid?(value.under)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def after_correct?
|
103
|
+
run_correct do
|
104
|
+
value = ExpectedValue.new(options[:after])
|
105
|
+
description << "after #{value.equal}"
|
106
|
+
valid?(value.over) && invalid?(value.equal) && invalid?(value.under)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def on_or_after_correct?
|
111
|
+
run_correct do
|
112
|
+
value = ExpectedValue.new(options[:on_or_after])
|
113
|
+
description << "on or after #{value.equal}"
|
114
|
+
valid?(value.equal) && valid?(value.over) && invalid?(value.under)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def before_correct?
|
119
|
+
run_correct do
|
120
|
+
value = ExpectedValue.new(options[:before])
|
121
|
+
description << "before #{value.equal}"
|
122
|
+
valid?(value.under) && invalid?(value.equal) && invalid?(value.over)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def on_or_before_correct?
|
127
|
+
run_correct do
|
128
|
+
value = ExpectedValue.new(options[:on_or_before])
|
129
|
+
description << "on or before #{value.equal}"
|
130
|
+
valid?(value.equal) && valid?(value.under) && invalid?(value.over)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def validator_proxy
|
135
|
+
@validator_proxy ||= ValidatorProxy.new(subject, attr_name)
|
136
|
+
end
|
137
|
+
|
138
|
+
delegate :valid?, to: :validator_proxy
|
139
|
+
delegate :invalid?, to: :validator_proxy
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RSpec::ValidatesTimeliness
|
2
|
+
module Matchers
|
3
|
+
class ValidatorProxy
|
4
|
+
def initialize(model, attr_name)
|
5
|
+
@model = model
|
6
|
+
@attr_name = attr_name
|
7
|
+
end
|
8
|
+
|
9
|
+
def valid?(value)
|
10
|
+
set_value(value)
|
11
|
+
validate!
|
12
|
+
error_message.blank?
|
13
|
+
end
|
14
|
+
|
15
|
+
def invalid?(value)
|
16
|
+
!valid?(value)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :model, :attr_name
|
22
|
+
|
23
|
+
def set_value(value)
|
24
|
+
model.instance_variable_set(:"@#{attr_name}", value)
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate!
|
28
|
+
model.validate
|
29
|
+
end
|
30
|
+
|
31
|
+
def error_message
|
32
|
+
model.errors.messages[attr_name]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'rspec-validates_timeliness/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.platform = Gem::Platform::RUBY
|
7
|
+
gem.name = "rspec-validates_timeliness"
|
8
|
+
gem.version = RSpec::ValidatesTimeliness::VERSION
|
9
|
+
gem.summary = %q{Simple RSpec matchers for validates_timeliness}
|
10
|
+
gem.description = %q{Simple RSpec matchers for validates_timeliness}
|
11
|
+
|
12
|
+
gem.required_ruby_version = ">= 2.1.0"
|
13
|
+
|
14
|
+
gem.authors = ["Yoshiyuki Hirano"]
|
15
|
+
gem.email = ["yhirano@aiming-inc.com"]
|
16
|
+
gem.homepage = "https://github.com/yhirano55/rspec-validates_timeliness"
|
17
|
+
|
18
|
+
gem.files = `git ls-files`.split($/)
|
19
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
21
|
+
gem.require_paths = ["lib"]
|
22
|
+
|
23
|
+
gem.add_dependency "rspec", ">= 3.0"
|
24
|
+
gem.add_dependency "validates_timeliness", "~> 4.0"
|
25
|
+
gem.add_dependency "timecop", ">= 0.8.0"
|
26
|
+
gem.add_dependency "activesupport", ">= 4.0"
|
27
|
+
|
28
|
+
gem.add_development_dependency "rake", "~> 10.0"
|
29
|
+
gem.add_development_dependency "pry"
|
30
|
+
gem.add_development_dependency "activemodel", ">= 4.0"
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class ValidatesDate
|
4
|
+
include ActiveModel::Model
|
5
|
+
|
6
|
+
attr_reader :date_of_birth, :date_of_start, :date_of_finish, :date_of_expiry
|
7
|
+
|
8
|
+
validates_date :date_of_birth, is_at: lambda { Date.current }
|
9
|
+
validates_date :date_of_start, after: lambda { 1.week.ago }, before: lambda { 1.week.since }
|
10
|
+
validates_date :date_of_finish, on_or_after: lambda { 1.year.ago }, on_or_before: lambda { 1.year.since }
|
11
|
+
validates_date :date_of_expiry, between: [3.days.ago, 3.days.since]
|
12
|
+
end
|
13
|
+
|
14
|
+
describe ValidatesDate do
|
15
|
+
it { is_expected.to validates_date(:date_of_birth).is_at { Date.current } }
|
16
|
+
it { is_expected.to validates_date(:date_of_start).after { 1.week.ago.to_date }.before { 1.week.since.to_date } }
|
17
|
+
it { is_expected.to validates_date(:date_of_finish).on_or_after { 1.year.ago.to_date }.on_or_before { 1.year.since.to_date } }
|
18
|
+
it { is_expected.to validates_date(:date_of_expiry).between([3.days.ago.to_date, 3.days.since.to_date]) }
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class ValidatesDateTime
|
4
|
+
include ActiveModel::Model
|
5
|
+
|
6
|
+
attr_reader :started_at, :finished_at, :created_at, :updated_at
|
7
|
+
|
8
|
+
validates_datetime :started_at, is_at: lambda { DateTime.current }
|
9
|
+
validates_datetime :finished_at, after: lambda { 1.week.ago.to_datetime }, before: lambda { 1.week.since.to_datetime }
|
10
|
+
validates_datetime :created_at, on_or_after: lambda { 1.year.ago.to_datetime }, on_or_before: lambda { 1.year.since.to_datetime }
|
11
|
+
validates_datetime :updated_at, between: [DateTime.new(2008, 9, 1, 10, 5, 0), DateTime.new(2009, 4, 1, 0, 30, 0)]
|
12
|
+
end
|
13
|
+
|
14
|
+
describe ValidatesDateTime do
|
15
|
+
it { is_expected.to validates_datetime(:started_at).is_at { DateTime.current } }
|
16
|
+
it { is_expected.to validates_datetime(:finished_at).after { 1.week.ago.to_datetime }.before { 1.week.since.to_datetime } }
|
17
|
+
it { is_expected.to validates_datetime(:created_at).on_or_after { 1.year.ago.to_datetime }.on_or_before { 1.year.since.to_datetime } }
|
18
|
+
it { is_expected.to validates_datetime(:updated_at).between([DateTime.new(2008, 9, 1, 10, 5, 0), DateTime.new(2009, 4, 1, 0, 30, 0)]) }
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class ValidatesTime
|
4
|
+
include ActiveModel::Model
|
5
|
+
|
6
|
+
attr_reader :started_at, :finished_at, :created_at, :updated_at
|
7
|
+
|
8
|
+
validates_time :started_at, is_at: '9:00am'
|
9
|
+
validates_time :finished_at, after: '11:00am', before: '1:00pm'
|
10
|
+
validates_time :created_at, on_or_after: '6:00am', on_or_before: '8:00am'
|
11
|
+
validates_time :updated_at, between: ['10:00am', '5:00pm']
|
12
|
+
end
|
13
|
+
|
14
|
+
describe ValidatesTime do
|
15
|
+
it { is_expected.to validates_time(:started_at).is_at('9:00am') }
|
16
|
+
it { is_expected.to validates_time(:finished_at).after('11:00am').before('1:00pm') }
|
17
|
+
it { is_expected.to validates_time(:created_at).on_or_after('6:00am').on_or_before('8:00am') }
|
18
|
+
it { is_expected.to validates_time(:updated_at).between(['10:00am', '5:00pm']) }
|
19
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RSpec::ValidatesTimeliness::Matchers::ExpectedValue do
|
4
|
+
describe '#equal' do
|
5
|
+
let(:result) { Date.current }
|
6
|
+
let(:model) { described_class.new(result) }
|
7
|
+
|
8
|
+
subject { model.equal }
|
9
|
+
|
10
|
+
it { is_expected.to eq result }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#over' do
|
14
|
+
let(:model) { described_class.new(value) }
|
15
|
+
|
16
|
+
subject { model.over }
|
17
|
+
|
18
|
+
context 'value is kind of Date' do
|
19
|
+
let(:value) { Date.current }
|
20
|
+
let(:result) { value + 1.day }
|
21
|
+
|
22
|
+
it 'returns value + 1.day (tomorrow)' do
|
23
|
+
is_expected.to eq result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'value is not kind of Date' do
|
28
|
+
let(:value) { DateTime.current }
|
29
|
+
let(:result) { value + 1.second }
|
30
|
+
|
31
|
+
it 'returns value + 1.second' do
|
32
|
+
is_expected.to eq result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#under' do
|
38
|
+
let(:model) { described_class.new(value) }
|
39
|
+
|
40
|
+
subject { model.under }
|
41
|
+
|
42
|
+
context 'value is kind of Date' do
|
43
|
+
let(:value) { Date.current }
|
44
|
+
let(:result) { value - 1.day }
|
45
|
+
|
46
|
+
it 'returns value - 1.day (yesterday)' do
|
47
|
+
is_expected.to eq result
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'value is not kind of Date' do
|
52
|
+
let(:value) { DateTime.current }
|
53
|
+
let(:result) { value - 1.second }
|
54
|
+
|
55
|
+
it 'returns value - 1.second' do
|
56
|
+
is_expected.to eq result
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#evaluate' do
|
62
|
+
let(:model) { described_class.new(nil) }
|
63
|
+
|
64
|
+
subject { model.send(:evaluate, value) }
|
65
|
+
|
66
|
+
context 'velue is kind of Proc' do
|
67
|
+
let(:value) { proc { Date.today } }
|
68
|
+
|
69
|
+
it { is_expected.to eq value.call }
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'value is kind of Time' do
|
73
|
+
let(:value) { Time.now }
|
74
|
+
|
75
|
+
it { is_expected.to eq value }
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'value is kind of DateTime' do
|
79
|
+
let(:value) { DateTime.current }
|
80
|
+
|
81
|
+
it { is_expected.to eq value }
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'value is kind of Date' do
|
85
|
+
let(:value) { Date.current }
|
86
|
+
|
87
|
+
it { is_expected.to eq value }
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'value is kind of String' do
|
91
|
+
let(:value) { '9:00am' }
|
92
|
+
let(:result) { value.to_time }
|
93
|
+
|
94
|
+
it { is_expected.to eq result }
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'value is not kind of Proc, Time, DateTime, Date' do
|
98
|
+
let(:value) { 12345 }
|
99
|
+
|
100
|
+
it { is_expected.to be_nil }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RSpec::ValidatesTimeliness::Matchers::MessageBuilder do
|
4
|
+
describe '#full_message' do
|
5
|
+
let(:model) { described_class.new(base_message) }
|
6
|
+
let(:base_message) { 'abc' }
|
7
|
+
let(:option_messages) { %w(123 456 789) }
|
8
|
+
let(:result) { 'abc 123 and 456 and 789' }
|
9
|
+
|
10
|
+
before do
|
11
|
+
option_messages.each do |text|
|
12
|
+
model << text
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
subject { model.full_message }
|
17
|
+
|
18
|
+
it 'returns exactly full message' do
|
19
|
+
is_expected.to eq result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#<<' do
|
24
|
+
let(:model) { described_class.new(nil) }
|
25
|
+
let(:text) { 'abc' }
|
26
|
+
|
27
|
+
before { model << text }
|
28
|
+
|
29
|
+
subject { model.instance_variable_get(:@option_messages) }
|
30
|
+
|
31
|
+
it 'pushes text to @option_messages' do
|
32
|
+
is_expected.to eq [text]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RSpec::ValidatesTimeliness::Matchers::ValidationMatcher do
|
4
|
+
let(:attr_name) { :one }
|
5
|
+
let(:model) { described_class.new(attr_name) }
|
6
|
+
|
7
|
+
%i(is_at after on_or_after before on_or_before).each do |option_name|
|
8
|
+
describe "##{option_name}" do
|
9
|
+
shared_examples 'exactly chain' do
|
10
|
+
it 'returns itself' do
|
11
|
+
is_expected.to eq model
|
12
|
+
options = model.instance_variable_get(:@options)
|
13
|
+
expect(options[option_name]).to eq value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
subject { model.try(option_name, value) }
|
18
|
+
|
19
|
+
context 'with not block given' do
|
20
|
+
let(:value) { Date.current }
|
21
|
+
|
22
|
+
it_behaves_like 'exactly chain'
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with block given' do
|
26
|
+
let(:value) { proc { Date.current } }
|
27
|
+
|
28
|
+
it_behaves_like 'exactly chain'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#between' do
|
34
|
+
shared_examples 'exactly chain' do
|
35
|
+
it 'returns itself' do
|
36
|
+
is_expected.to eq model
|
37
|
+
options = model.instance_variable_get(:@options)
|
38
|
+
expect(options[:on_or_after]).to eq value.first
|
39
|
+
key = value.is_a?(Range) && value.exclude_end? ? :before : :on_or_before
|
40
|
+
expect(options[key]).to eq value.last
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
subject { model.between(value) }
|
45
|
+
|
46
|
+
context 'value is kind of Array' do
|
47
|
+
let(:value) { [1.week.ago.to_date, 1.week.since.to_date] }
|
48
|
+
|
49
|
+
it_behaves_like 'exactly chain'
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'value is kind of Range' do
|
53
|
+
context 'with exclude_end' do
|
54
|
+
let(:value) { 1.week.ago.to_date..1.week.since.to_date }
|
55
|
+
|
56
|
+
it_behaves_like 'exactly chain'
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'with not exclude_end' do
|
60
|
+
let(:value) { 1.week.ago.to_date...1.week.since.to_date }
|
61
|
+
|
62
|
+
it_behaves_like 'exactly chain'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#matches' do
|
68
|
+
let(:expected) { nil }
|
69
|
+
|
70
|
+
before do
|
71
|
+
expect(model).to receive(:attribute_exist?).and_return(true)
|
72
|
+
expect(model).to receive(:all_options_correct?).and_return(true)
|
73
|
+
end
|
74
|
+
|
75
|
+
subject { model.matches?(expected) }
|
76
|
+
|
77
|
+
it { is_expected.to be_truthy }
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#failure_message' do
|
81
|
+
let(:base_description) { "validate that :#{attr_name} must be" }
|
82
|
+
let(:result) { "Expected #{base_description}" }
|
83
|
+
|
84
|
+
subject { model.failure_message }
|
85
|
+
|
86
|
+
it { is_expected.to match result }
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#failure_message_when_negated' do
|
90
|
+
let(:base_description) { "validate that :#{attr_name} must be" }
|
91
|
+
let(:result) { "Did not expect #{base_description}" }
|
92
|
+
|
93
|
+
subject { model.failure_message_when_negated }
|
94
|
+
|
95
|
+
it { is_expected.to match result }
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RSpec::ValidatesTimeliness::Matchers::ValidatorProxy do
|
4
|
+
before do
|
5
|
+
class DummyModel
|
6
|
+
include ActiveModel::Model
|
7
|
+
attr_reader :one
|
8
|
+
validates :one, presence: true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:model) { DummyModel.new }
|
13
|
+
let(:attr_name) { :one }
|
14
|
+
let(:proxy) { described_class.new(model, attr_name) }
|
15
|
+
|
16
|
+
describe '#valid?' do
|
17
|
+
subject { proxy.valid?(value) }
|
18
|
+
|
19
|
+
context 'with valid' do
|
20
|
+
let(:value) { true }
|
21
|
+
|
22
|
+
it { is_expected.to be_truthy }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with invalid' do
|
26
|
+
let(:value) { nil }
|
27
|
+
|
28
|
+
it { is_expected.to be_falsey }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#invalid?' do
|
33
|
+
subject { proxy.invalid?(value) }
|
34
|
+
|
35
|
+
context 'with invalid' do
|
36
|
+
let(:value) { nil }
|
37
|
+
|
38
|
+
it { is_expected.to be_truthy }
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with valid' do
|
42
|
+
let(:value) { true }
|
43
|
+
|
44
|
+
it { is_expected.to be_falsey }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RSpec::ValidatesTimeliness::Matchers do
|
4
|
+
describe '#validates_timeliness_of' do
|
5
|
+
before do
|
6
|
+
class DummyModel
|
7
|
+
include RSpec::ValidatesTimeliness::Matchers
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:model) { DummyModel.new }
|
12
|
+
let(:attr_name) { :one }
|
13
|
+
|
14
|
+
subject { model.validates_timeliness_of(attr_name) }
|
15
|
+
|
16
|
+
it { is_expected.to be_kind_of(RSpec::ValidatesTimeliness::Matchers::ValidationMatcher) }
|
17
|
+
end
|
18
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rspec-validates_timeliness
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yoshiyuki Hirano
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-12 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.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: validates_timeliness
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: timecop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.8.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: activemodel
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '4.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '4.0'
|
111
|
+
description: Simple RSpec matchers for validates_timeliness
|
112
|
+
email:
|
113
|
+
- yhirano@aiming-inc.com
|
114
|
+
executables:
|
115
|
+
- console
|
116
|
+
- setup
|
117
|
+
extensions: []
|
118
|
+
extra_rdoc_files: []
|
119
|
+
files:
|
120
|
+
- ".gitignore"
|
121
|
+
- ".rspec"
|
122
|
+
- ".travis.yml"
|
123
|
+
- Gemfile
|
124
|
+
- LICENSE.txt
|
125
|
+
- README.md
|
126
|
+
- Rakefile
|
127
|
+
- bin/console
|
128
|
+
- bin/setup
|
129
|
+
- lib/rspec-validates_timeliness.rb
|
130
|
+
- lib/rspec-validates_timeliness/matchers.rb
|
131
|
+
- lib/rspec-validates_timeliness/matchers/expected_value.rb
|
132
|
+
- lib/rspec-validates_timeliness/matchers/message_builder.rb
|
133
|
+
- lib/rspec-validates_timeliness/matchers/validation_matcher.rb
|
134
|
+
- lib/rspec-validates_timeliness/matchers/validator_proxy.rb
|
135
|
+
- lib/rspec-validates_timeliness/version.rb
|
136
|
+
- rspec-validates_timeliness.gemspec
|
137
|
+
- spec/acceptance/validates_date_spec.rb
|
138
|
+
- spec/acceptance/validates_date_time_spec.rb
|
139
|
+
- spec/acceptance/validates_time_spec.rb
|
140
|
+
- spec/lib/rspec-validates_timeliness/matchers/expected_value_spec.rb
|
141
|
+
- spec/lib/rspec-validates_timeliness/matchers/message_builder_spec.rb
|
142
|
+
- spec/lib/rspec-validates_timeliness/matchers/validation_matcher_spec.rb
|
143
|
+
- spec/lib/rspec-validates_timeliness/matchers/validator_proxy_spec.rb
|
144
|
+
- spec/lib/rspec-validates_timeliness/matchers_spec.rb
|
145
|
+
- spec/lib/rspec-validates_timeliness_spec.rb
|
146
|
+
- spec/spec_helper.rb
|
147
|
+
homepage: https://github.com/yhirano55/rspec-validates_timeliness
|
148
|
+
licenses: []
|
149
|
+
metadata: {}
|
150
|
+
post_install_message:
|
151
|
+
rdoc_options: []
|
152
|
+
require_paths:
|
153
|
+
- lib
|
154
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: 2.1.0
|
159
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - ">="
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
requirements: []
|
165
|
+
rubyforge_project:
|
166
|
+
rubygems_version: 2.5.1
|
167
|
+
signing_key:
|
168
|
+
specification_version: 4
|
169
|
+
summary: Simple RSpec matchers for validates_timeliness
|
170
|
+
test_files:
|
171
|
+
- spec/acceptance/validates_date_spec.rb
|
172
|
+
- spec/acceptance/validates_date_time_spec.rb
|
173
|
+
- spec/acceptance/validates_time_spec.rb
|
174
|
+
- spec/lib/rspec-validates_timeliness/matchers/expected_value_spec.rb
|
175
|
+
- spec/lib/rspec-validates_timeliness/matchers/message_builder_spec.rb
|
176
|
+
- spec/lib/rspec-validates_timeliness/matchers/validation_matcher_spec.rb
|
177
|
+
- spec/lib/rspec-validates_timeliness/matchers/validator_proxy_spec.rb
|
178
|
+
- spec/lib/rspec-validates_timeliness/matchers_spec.rb
|
179
|
+
- spec/lib/rspec-validates_timeliness_spec.rb
|
180
|
+
- spec/spec_helper.rb
|