Skip to content

Commit

Permalink
add some tests for time parsing, fix some time parsing bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
nickelser committed Jun 2, 2015
1 parent 9c90ebc commit 274e0ff
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 18 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,8 @@
## 0.1.4

- Fix several bugs related to time parsing.
- In a totally unrelated change, add some tests around time parsing.

## 0.1.3

- Fix several memory leaks.
Expand Down
37 changes: 28 additions & 9 deletions lib/zhong/at.rb
Expand Up @@ -17,22 +17,35 @@ class FailedToParse < StandardError; end

attr_accessor :minute, :hour, :wday

def initialize(minute: nil, hour: nil, wday: nil, grace: 0.minutes)
def initialize(minute: nil, hour: nil, wday: nil, grace: 0.seconds)
@minute = minute
@hour = hour
@wday = wday
@grace = grace

fail ArgumentError unless valid?
end

def next_at(time = Time.now)
at_time = @wday.nil? ? time.dup : (time + (@wday - time.wday).days)

at_time = at_time.change(min: @minute)
at_time = at_time.change(hour: @hour) if @hour
at_time = if !@minute.nil? && !@hour.nil?
at_time.change(hour: @hour, min: @minute)
elsif !@minute.nil?
at_time.change(min: @minute)
elsif !@hour.nil? && @hour != time.hour
at_time.change(hour: @hour)
else
at_time.change(sec: 0)
end

if at_time < @grace.ago
if at_time < (time.change(sec: 0) - @grace)
if @wday.nil?
at_time += 1.day
if @hour.nil?
at_time += 1.hour
else
at_time += 1.day
end
else
at_time += 1.week
end
Expand All @@ -41,7 +54,13 @@ def next_at(time = Time.now)
end
end

def self.parse(at, grace: 0)
private def valid?
(@minute.nil? || (0..59).cover?(@minute)) &&
(@hour.nil? || (0..23).cover?(@hour)) &&
(@wday.nil? || (0..6).cover?(@wday))
end

def self.parse(at, grace: 0.seconds)
return unless at

# TODO: refactor this mess
Expand All @@ -51,7 +70,7 @@ def self.parse(at, grace: 0)

case at
when /\A([[:alpha:]]+)\s+(.*)\z/
wday = WDAYS[$1]
wday = WDAYS[$1.downcase]

if wday
parsed_time = parse($2, grace: grace)
Expand All @@ -65,12 +84,12 @@ def self.parse(at, grace: 0)
when /\A\*{1,2}:(\d\d)\z/
new(minute: $1.to_i, grace: grace)
when /\A(\d{1,2}):\*{1,2}\z/
new(hour: $1, grace: grace)
new(hour: $1.to_i, grace: grace)
else
fail FailedToParse, at
end
rescue ArgumentError
throw FailedToParse, at
fail FailedToParse, at
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/zhong/every.rb
Expand Up @@ -8,7 +8,7 @@ class FailedToParse < StandardError; end
month: 1.month,
semiannual: 6.months, # enterprise!
year: 1.year,
decade: 10.year
decade: 10.years
}.freeze

def initialize(period)
Expand Down
2 changes: 1 addition & 1 deletion lib/zhong/version.rb
@@ -1,3 +1,3 @@
module Zhong
VERSION = "0.1.3"
VERSION = "0.1.4"
end
4 changes: 0 additions & 4 deletions test/minitest_helper.rb

This file was deleted.

11 changes: 11 additions & 0 deletions test/test_helper.rb
@@ -0,0 +1,11 @@
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)

if ENV["CODECLIMATE_REPO_TOKEN"]
require "codeclimate-test-reporter"
CodeClimate::TestReporter.start
end

require "zhong"
require "minitest/autorun"

ENV["ZHONG_TEST"] = "true"
144 changes: 142 additions & 2 deletions test/zhong_test.rb
@@ -1,6 +1,146 @@
require 'minitest_helper'
require "test_helper"

class TestZhong < Minitest::Test
# Many At tests lifted from Clockwork (thanks Clockwork!)
class TestAt < Minitest::Test
def time_in_day(hour, minute, day = 0, sec = 0)
Time.new.beginning_of_week(:monday).change(hour: hour, min: minute, sec: sec) + day.days
end

def test_16_20
at = Zhong::At.parse("16:20", grace: 0)

assert_equal time_in_day(16, 20), at.next_at(time_in_day(16, 15))
assert_equal time_in_day(16, 20), at.next_at(time_in_day(16, 20))
assert_equal time_in_day(16, 20), at.next_at(time_in_day(16, 20, 0, 10))
assert_equal time_in_day(16, 20), at.next_at(time_in_day(16, 20, 0, 59))
assert_equal time_in_day(16, 20, 1), at.next_at(time_in_day(16, 21))
assert_equal time_in_day(16, 20, 1), at.next_at(time_in_day(16, 21, 0, 01))
assert_equal time_in_day(16, 20, 2), at.next_at(time_in_day(16, 21, 1, 30))
end

def test_16_20_with_grace
at = Zhong::At.parse("16:20", grace: 5.minutes)

assert_equal time_in_day(16, 20), at.next_at(time_in_day(16, 21))
assert_equal time_in_day(16, 20), at.next_at(time_in_day(16, 25))
assert_equal time_in_day(16, 20, 1), at.next_at(time_in_day(16, 26))
end

def test_8_20_before
at = Zhong::At.parse("8:20")

assert_equal time_in_day(8, 20), at.next_at(time_in_day(8, 15))
assert_equal time_in_day(8, 20, 1), at.next_at(time_in_day(8, 21))
end

def test_two_star_20
at = Zhong::At.parse("**:20")

assert_equal time_in_day(8, 20), at.next_at(time_in_day(8, 15))
assert_equal time_in_day(9, 20), at.next_at(time_in_day(9, 15))
assert_equal time_in_day(10, 20), at.next_at(time_in_day(9, 45))
end

def test_one_star_20
at = Zhong::At.parse("*:45")

assert_equal time_in_day(8, 45), at.next_at(time_in_day(8, 35))
assert_equal time_in_day(9, 45), at.next_at(time_in_day(9, 35))
assert_equal time_in_day(10, 45), at.next_at(time_in_day(9, 50))
end

def test_one_star_20_with_grace
at = Zhong::At.parse("*:45", grace: 5.minutes)

assert_equal time_in_day(8, 45), at.next_at(time_in_day(8, 35))
assert_equal time_in_day(8, 45), at.next_at(time_in_day(8, 50))
assert_equal time_in_day(9, 45), at.next_at(time_in_day(8, 51))
assert_equal time_in_day(9, 45), at.next_at(time_in_day(9, 35))
assert_equal time_in_day(10, 45), at.next_at(time_in_day(9, 55))
end

def test_16_two_stars
at = Zhong::At.parse("16:**")

assert_equal time_in_day(16, 00), at.next_at(time_in_day(8, 45))
assert_equal time_in_day(16, 00), at.next_at(time_in_day(10, 00))
assert_equal time_in_day(16, 00), at.next_at(time_in_day(16, 00))
assert_equal time_in_day(16, 01), at.next_at(time_in_day(16, 01))
assert_equal time_in_day(16, 30), at.next_at(time_in_day(16, 30))
assert_equal time_in_day(16, 59), at.next_at(time_in_day(16, 59))
assert_equal time_in_day(16, 00, 1), at.next_at(time_in_day(17, 00))
assert_equal time_in_day(16, 00, 1), at.next_at(time_in_day(23, 59))
end

def test_8_two_stars
at = Zhong::At.parse("8:**")

assert_equal time_in_day(8, 00), at.next_at(time_in_day(3, 45))
assert_equal time_in_day(8, 00), at.next_at(time_in_day(5, 00))
assert_equal time_in_day(8, 00), at.next_at(time_in_day(8, 00))
assert_equal time_in_day(8, 01), at.next_at(time_in_day(8, 01))
assert_equal time_in_day(8, 30), at.next_at(time_in_day(8, 30))
assert_equal time_in_day(8, 59), at.next_at(time_in_day(8, 59))
assert_equal time_in_day(8, 00, 1), at.next_at(time_in_day(9, 00))
assert_equal time_in_day(8, 00, 1), at.next_at(time_in_day(12, 59))
end

def test_saturday_12
at = Zhong::At.parse("Saturday 12:00")

assert_equal time_in_day(12, 00, 5), at.next_at(time_in_day(12, 00))
assert_equal time_in_day(12, 00, 5), at.next_at(time_in_day(13, 00, 1))
assert_equal time_in_day(12, 00, 5), at.next_at(time_in_day(23, 59, 3))
assert_equal time_in_day(12, 00, 5), at.next_at(time_in_day(12, 00, 5))
assert_equal time_in_day(12, 00, 12), at.next_at(time_in_day(12, 01, 5))
assert_equal time_in_day(12, 00, 12), at.next_at(time_in_day(13, 01, 6, 01))
end

def test_sat_12
at = Zhong::At.parse("sat 12:00")

assert_equal time_in_day(12, 00, 5), at.next_at(time_in_day(12, 00))
assert_equal time_in_day(12, 00, 5), at.next_at(time_in_day(13, 00, 1))
assert_equal time_in_day(12, 00, 5), at.next_at(time_in_day(23, 59, 3))
assert_equal time_in_day(12, 00, 5), at.next_at(time_in_day(12, 00, 5))
assert_equal time_in_day(12, 00, 12), at.next_at(time_in_day(12, 01, 5))
assert_equal time_in_day(12, 00, 12), at.next_at(time_in_day(13, 01, 6, 01))
end

def test_tue_12_59
at = Zhong::At.parse("tue 12:59")

assert_equal time_in_day(12, 59, 1), at.next_at(time_in_day(7, 00))
assert_equal time_in_day(12, 59, 1), at.next_at(time_in_day(12, 00, 1))
assert_equal time_in_day(12, 59, 1), at.next_at(time_in_day(12, 59, 1))
assert_equal time_in_day(12, 59, 8), at.next_at(time_in_day(13, 00, 1))
assert_equal time_in_day(12, 59, 8), at.next_at(time_in_day(13, 01, 6, 01))
end

def test_thr_12_59
at = Zhong::At.parse("thr 12:59")

assert_equal time_in_day(12, 59, 3), at.next_at(time_in_day(7, 00))
assert_equal time_in_day(12, 59, 3), at.next_at(time_in_day(12, 00, 3))
assert_equal time_in_day(12, 59, 3), at.next_at(time_in_day(12, 59, 3))
assert_equal time_in_day(12, 59, 10), at.next_at(time_in_day(13, 00, 3))
assert_equal time_in_day(12, 59, 10), at.next_at(time_in_day(13, 01, 6, 01))
end

def test_invalid_time_32
assert_raises Zhong::At::FailedToParse do
Zhong::At.parse("32:00")
end
end

def test_invalid_multi_line_time_sat_12
assert_raises Zhong::At::FailedToParse do
Zhong::At.parse("sat 12:00\nreally invalid time")
end
end
end

class TestLibrary < Minitest::Test
def test_that_it_has_a_version_number
refute_nil ::Zhong::VERSION
end
Expand Down
2 changes: 1 addition & 1 deletion zhong.gemspec
Expand Up @@ -31,5 +31,5 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rubocop", "~> 0.30.0"
spec.add_development_dependency "minitest", "~> 5.5.0"
# spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4.7"
spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4.7"
end

0 comments on commit 274e0ff

Please sign in to comment.