Skip to content

Commit b3e1a38

Browse files
committed
Add sophisticated date matchers
This commit adds date matchers with the following modifiers: - beginning/end of day/month/year - X days/months/years ago/from now - (as day/month/year/custom) Which can be combined freely to e.g.: - beginning of month 7 years from now (as day) - end of year 10 months ago (as custom '%Y/%m/%d') The custom formatter uses Ruby formatting: https://apidock.com/ruby/DateTime/strftime
1 parent cbc5e86 commit b3e1a38

File tree

2 files changed

+232
-15
lines changed

2 files changed

+232
-15
lines changed

lib/squcumber-postgres/support/matchers.rb

Lines changed: 119 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,127 @@ def timetravel(date, i, method); i > 0 ? timetravel(date.send(method.to_sym), i
2323
def convert_mock_values(mock_data)
2424
mock_data.map do |entry|
2525
entry.each do |key, value|
26-
entry[key] = case value
27-
when /today/
28-
Date.today.to_s
29-
when /yesterday/
30-
Date.today.prev_day.to_s
31-
when /\s*\d+\s+month(s)?\s+ago\s*/
32-
number_of_months = value.match(/\d+/)[0].to_i
33-
timetravel(Date.today, number_of_months, :prev_month).to_s
34-
when /\s*\d+\s+day(s)?\s+ago\s*/
35-
number_of_days = value.match(/\d+/)[0].to_i
36-
timetravel(Date.today, number_of_days, :prev_day).to_s
37-
else
38-
value
39-
end
26+
# Examples of valid values; all examples assume that today is 30th July 2017
27+
#
28+
# 1 month ago
29+
# => '2017-06-30'
30+
#
31+
# 40 days ago (as month)
32+
# => '6'
33+
#
34+
# 2 years ago (as year)
35+
# => '2015'
36+
#
37+
# beginning of last month
38+
# => '2017-06-01'
39+
#
40+
# end of last year
41+
# => '2016-12-31'
42+
#
43+
# today (as custom '%Y-%m')
44+
# => '2017-07'
45+
#
46+
entry[key] = convert_mock_value(value)
4047
end
4148
end
4249
end
50+
51+
def convert_mock_value(value)
52+
value_parser_regexp = /\s*((?<modifier>(beginning|end))\s+of\s+(?<modifier_base>day|month|year))?\s*(?<placeholder>[^\(\)]+)\s*(\(as (?<format>day|month|year|(custom '[^']+'))\))?\s*/
53+
54+
parsed_value = value.match(value_parser_regexp)
55+
placeholder = parsed_value[:placeholder]
56+
format = parsed_value[:format]
57+
modifier = parsed_value[:modifier]
58+
modifier_base = parsed_value[:modifier_base]
59+
60+
new_value = case placeholder
61+
when /today/
62+
Date.today
63+
when /yesterday/
64+
timetravel(Date.today, 1, :prev_day)
65+
when /tomorrow/
66+
timetravel(Date.today, 1, :next_day)
67+
when /last month/
68+
timetravel(Date.today, 1, :prev_month)
69+
when /next month/
70+
timetravel(Date.today, 1, :next_month)
71+
when /last year/
72+
timetravel(Date.today, 1, :prev_year)
73+
when /next year/
74+
timetravel(Date.today, 1, :next_year)
75+
when /\s*\d+\s+month(s)?\s+ago\s*?/
76+
number_of_months = value.match(/\d+/)[0].to_i
77+
timetravel(Date.today, number_of_months, :prev_month)
78+
when /\s*\d+\s+day(s)?\s+ago\s*/
79+
number_of_days = value.match(/\d+/)[0].to_i
80+
timetravel(Date.today, number_of_days, :prev_day)
81+
when /\s*\d+\s+year(s)?\s+ago\s*/
82+
number_of_years = value.match(/\d+/)[0].to_i
83+
timetravel(Date.today, number_of_years, :prev_year)
84+
when /\s*\d+\s+month(s)?\s+from now\s*?/
85+
number_of_months = value.match(/\d+/)[0].to_i
86+
timetravel(Date.today, number_of_months, :next_month)
87+
when /\s*\d+\s+day(s)?\s+from now\s*/
88+
number_of_days = value.match(/\d+/)[0].to_i
89+
timetravel(Date.today, number_of_days, :next_day)
90+
when /\s*\d+\s+year(s)?\s+from now\s*/
91+
number_of_years = value.match(/\d+/)[0].to_i
92+
timetravel(Date.today, number_of_years, :next_year)
93+
else
94+
placeholder
95+
end
96+
97+
if new_value.is_a?(Date)
98+
modified_new_value = case modifier
99+
when nil
100+
new_value
101+
when 'beginning'
102+
case modifier_base
103+
when 'day'
104+
new_value
105+
when 'month'
106+
Date.new(new_value.year, new_value.month, 1)
107+
when 'year'
108+
Date.new(new_value.year, 1, 1)
109+
else
110+
raise "Invalid date modifier provided: #{modifier} #{modifier_base}"
111+
end
112+
when 'end'
113+
case modifier_base
114+
when 'day'
115+
new_value
116+
when 'month'
117+
Date.new(new_value.next_month.year, new_value.next_month.month, 1).prev_day
118+
when 'year'
119+
Date.new(new_value.next_year.year, 1, 1).prev_day
120+
else
121+
raise "Invalid date modifier provided: #{modifier} #{modifier_base}"
122+
end
123+
else
124+
raise "Invalid date modifier provided: #{modifier} #{modifier_base}"
125+
end
126+
127+
formatted_new_value = case format
128+
when nil
129+
puts "NO FORMAT"
130+
modified_new_value.to_s
131+
when 'day', 'month', 'year'
132+
modified_new_value.send(format.to_sym)
133+
when /custom '[^']+'/
134+
parsed_format = format.match(/custom '(?<format_string>[^']+)'/)
135+
modified_new_value.strftime(parsed_format[:format_string])
136+
else
137+
raise "Invalid date format provided: #{format}"
138+
end
139+
140+
formatted_new_value
141+
else
142+
new_value
143+
end
144+
end
43145
end
44146

45-
World(MatcherHelpers)
147+
if defined?(World)
148+
World(MatcherHelpers)
149+
end
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
require_relative '../../spec_helper'
2+
require_relative '../../../lib/squcumber-postgres/support/matchers'
3+
4+
module Squcumber
5+
describe 'MatcherHelpers' do
6+
let(:dummy_class) { Class.new { include MatcherHelpers } }
7+
8+
before(:each) do
9+
allow(Date).to receive(:today).and_return Date.new(2017, 7, 15)
10+
end
11+
12+
describe '#convert_mock_values' do
13+
context 'with day placeholders' do
14+
it 'sets today' do
15+
expect(dummy_class.new.convert_mock_value('today')).to eql('2017-07-15')
16+
end
17+
it 'sets tomorrow' do
18+
expect(dummy_class.new.convert_mock_value('tomorrow')).to eql('2017-07-16')
19+
end
20+
it 'sets yesterday' do
21+
expect(dummy_class.new.convert_mock_value('yesterday')).to eql('2017-07-14')
22+
end
23+
it 'travels into the past' do
24+
expect(dummy_class.new.convert_mock_value('10 days ago')).to eql('2017-07-05')
25+
end
26+
it 'travels into the future' do
27+
expect(dummy_class.new.convert_mock_value('30 days from now')).to eql('2017-08-14')
28+
end
29+
it 'converts to day' do
30+
expect(dummy_class.new.convert_mock_value('10 days from now (as day)')).to eql(25)
31+
end
32+
it 'converts to month' do
33+
expect(dummy_class.new.convert_mock_value('30 days from now (as month)')).to eql(8)
34+
end
35+
it 'converts to year' do
36+
expect(dummy_class.new.convert_mock_value('30 days from now (as year)')).to eql(2017)
37+
end
38+
it 'sets beginning of day' do
39+
expect(dummy_class.new.convert_mock_value('beginning of day 10 days from now')).to eql('2017-07-25')
40+
end
41+
it 'sets end of day' do
42+
expect(dummy_class.new.convert_mock_value('end of day 10 days from now')).to eql('2017-07-25')
43+
end
44+
end
45+
46+
context 'with month placeholders' do
47+
it 'sets last month' do
48+
expect(dummy_class.new.convert_mock_value('last month')).to eql('2017-06-15')
49+
end
50+
it 'sets next month' do
51+
expect(dummy_class.new.convert_mock_value('next month')).to eql('2017-08-15')
52+
end
53+
it 'travels into the past' do
54+
expect(dummy_class.new.convert_mock_value('10 months ago')).to eql('2016-09-15')
55+
end
56+
it 'travels into the future' do
57+
expect(dummy_class.new.convert_mock_value('10 months from now')).to eql('2018-05-15')
58+
end
59+
it 'converts to day' do
60+
expect(dummy_class.new.convert_mock_value('10 months from now (as day)')).to eql(15)
61+
end
62+
it 'converts to month' do
63+
expect(dummy_class.new.convert_mock_value('10 months from now (as month)')).to eql(5)
64+
end
65+
it 'converts to year' do
66+
expect(dummy_class.new.convert_mock_value('10 months from now (as year)')).to eql(2018)
67+
end
68+
it 'sets beginning of month' do
69+
expect(dummy_class.new.convert_mock_value('beginning of month 10 months from now')).to eql('2018-05-01')
70+
end
71+
it 'sets end of month' do
72+
expect(dummy_class.new.convert_mock_value('end of month 10 months from now')).to eql('2018-05-31')
73+
end
74+
end
75+
76+
context 'with year placeholders' do
77+
it 'sets last year' do
78+
expect(dummy_class.new.convert_mock_value('last year')).to eql('2016-07-15')
79+
end
80+
it 'sets next year' do
81+
expect(dummy_class.new.convert_mock_value('next year')).to eql('2018-07-15')
82+
end
83+
it 'travels into the past' do
84+
expect(dummy_class.new.convert_mock_value('10 years ago')).to eql('2007-07-15')
85+
end
86+
it 'travels into the future' do
87+
expect(dummy_class.new.convert_mock_value('10 years from now')).to eql('2027-07-15')
88+
end
89+
it 'converts to day' do
90+
expect(dummy_class.new.convert_mock_value('10 years from now (as day)')).to eql(15)
91+
end
92+
it 'converts to month' do
93+
expect(dummy_class.new.convert_mock_value('10 years from now (as month)')).to eql(7)
94+
end
95+
it 'converts to year' do
96+
expect(dummy_class.new.convert_mock_value('10 years from now (as year)')).to eql(2027)
97+
end
98+
it 'sets beginning of year' do
99+
expect(dummy_class.new.convert_mock_value('beginning of year 10 months from now')).to eql('2018-01-01')
100+
end
101+
it 'sets end of year' do
102+
expect(dummy_class.new.convert_mock_value('end of year 10 months from now')).to eql('2018-12-31')
103+
end
104+
end
105+
106+
context 'with custom format' do
107+
it 'sets the date format' do
108+
expect(dummy_class.new.convert_mock_value('today (as custom \'%Y/%m/%d\')')).to eql('2017/07/15')
109+
end
110+
end
111+
end
112+
end
113+
end

0 commit comments

Comments
 (0)