Skip to content

Commit

Permalink
Implemented all remaining time assertions.
Browse files Browse the repository at this point in the history
  • Loading branch information
mdwhatcott committed Sep 17, 2013
1 parent 5084637 commit bbcf475
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 61 deletions.
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,16 @@ Here's the listing of assertions that this project aims to implement
X | __Type checking__
X | So(1, ShouldHaveSameTypeAs, 0)
X | So(1, ShouldNotHaveSameTypeAs, "asdf")
| __time__
X | __time__
X | So(time.Now(), ShouldHappenBefore, time.Now())
| So(time.Now(), ShouldHappenOnOrBefore, time.Now())
| So(time.Now(), ShouldHappenAfter, time.Now())
| So(time.Now(), ShouldHappenOnOrAfter, time.Now())
| So(time.Now(), ShouldHappenBetween, time.Now(), time.Now())
| So(time.Now(), ShouldHappenOnOrBetween, time.Now(), time.Now())
| So(time.New(), ShouldHappenWithin, duration, time.Now())
X | So(time.Now(), ShouldHappenOnOrBefore, time.Now())
X | So(time.Now(), ShouldHappenAfter, time.Now())
X | So(time.Now(), ShouldHappenOnOrAfter, time.Now())
X | So(time.Now(), ShouldHappenBetween, time.Now(), time.Now())
X | So(time.Now(), ShouldHappenOnOrBetween, time.Now(), time.Now())
X | So(time.Now(), ShouldNotHappenOnOrBetween, time.Now(), time.Now())
X | So(time.New(), ShouldHappenWithin, duration, time.Now())
X | So(time.New(), ShouldNotHappenWithin, duration, time.Now())

Thanks to [github.com/jacobsa](https://github.com/jacobsa/oglematchers) for his excellent
[oglematchers](https://github.com/smartystreets/oglmatchers) library, which
Expand Down
14 changes: 6 additions & 8 deletions assertions/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,10 @@ const ( // type checking
)

const ( // time comparisons
shouldUseTimes = "You must provide time instances as arguments to this assertion."
shouldHaveHappenedBefore = "Expected '%v' to happen before '%v' (it happened '%v' after)!"
shouldHaveHappenedOneOrBefore = "Expected '%v' to happen on or before '%v' (it happened '%v' after)!"
shouldHaveHappenedAfter = "Expected '%v' to happen after '%v' (it happened '%v' before)!"
shouldHaveHappenedOnOrAfter = "Expected '%v' to happen on or after '%v' (it happened '%v' before)!"
shouldHaveHappenedBetween = "Expected '%v' to happen between '%v' and '%v' (it happened '%v' outside threshold)!"
shouldHaveHappenedOnOrBetween = "Expected '%v' to happen on or between '%v' (it happened '%v' outside threshold)!"
shouldHaveHappenedWithin = "Expected '%v' to happen within '%v' (it happened within '%v')!"
shouldUseTimes = "You must provide time instances as arguments to this assertion."
shouldUseDurationAndTime = "You must provide a duration and a time as arguments to this assertion."
shouldHaveHappenedBefore = "Expected '%v' to happen before '%v' (it happened '%v' after)!"
shouldHaveHappenedAfter = "Expected '%v' to happen after '%v' (it happened '%v' before)!"
shouldHaveHappenedBetween = "Expected '%v' to happen between '%v' and '%v' (it happened '%v' outside threshold)!"
shouldNotHaveHappenedOnOrBetween = "Expected '%v' to NOT happen on or between '%v' and '%v' (but it did)!"
)
109 changes: 93 additions & 16 deletions assertions/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"
)

// ShouldHappenBefore receives exactly 2 time.Time arguments and asserts that the first happens before the second.
func ShouldHappenBefore(actual interface{}, expected ...interface{}) string {
if fail := need(1, expected); fail != success {
return fail
Expand All @@ -23,6 +24,7 @@ func ShouldHappenBefore(actual interface{}, expected ...interface{}) string {
return success
}

// ShouldHappenOnOrBefore receives exactly 2 time.Time arguments and asserts that the first happens on or before the second.
func ShouldHappenOnOrBefore(actual interface{}, expected ...interface{}) string {
if fail := need(1, expected); fail != success {
return fail
Expand All @@ -33,9 +35,14 @@ func ShouldHappenOnOrBefore(actual interface{}, expected ...interface{}) string
if !firstOk || !secondOk {
return shouldUseTimes
}
return fmt.Sprintf("%v %v", actualTime, expectedTime) // TODO

if actualTime.Equal(expectedTime) {
return success
}
return ShouldHappenBefore(actualTime, expectedTime)
}

// ShouldHappenAfter receives exactly 2 time.Time arguments and asserts that the first happens after the second.
func ShouldHappenAfter(actual interface{}, expected ...interface{}) string {
if fail := need(1, expected); fail != success {
return fail
Expand All @@ -46,9 +53,13 @@ func ShouldHappenAfter(actual interface{}, expected ...interface{}) string {
if !firstOk || !secondOk {
return shouldUseTimes
}
return fmt.Sprintf("%v %v", actualTime, expectedTime) // TODO
if !actualTime.After(expectedTime) {
return fmt.Sprintf(shouldHaveHappenedAfter, actualTime, expectedTime, expectedTime.Sub(actualTime))
}
return success
}

// ShouldHappenOnOrAfter receives exactly 2 time.Time arguments and asserts that the first happens on or after the second.
func ShouldHappenOnOrAfter(actual interface{}, expected ...interface{}) string {
if fail := need(1, expected); fail != success {
return fail
Expand All @@ -59,44 +70,110 @@ func ShouldHappenOnOrAfter(actual interface{}, expected ...interface{}) string {
if !firstOk || !secondOk {
return shouldUseTimes
}
return fmt.Sprintf("%v %v", actualTime, expectedTime) // TODO
if actualTime.Equal(expectedTime) {
return success
}
return ShouldHappenAfter(actualTime, expectedTime)
}

// ShouldHappenBetween receives exactly 3 time.Time arguments and asserts that the first happens between (not on) the second and third.
func ShouldHappenBetween(actual interface{}, expected ...interface{}) string {
if fail := need(1, expected); fail != success {
if fail := need(2, expected); fail != success {
return fail
}
actualTime, firstOk := actual.(time.Time)
expectedTime, secondOk := expected[0].(time.Time)
min, secondOk := expected[0].(time.Time)
max, thirdOk := expected[1].(time.Time)

if !firstOk || !secondOk {
if !firstOk || !secondOk || !thirdOk {
return shouldUseTimes
}
return fmt.Sprintf("%v %v", actualTime, expectedTime) // TODO

if !actualTime.After(min) {
return fmt.Sprintf(shouldHaveHappenedBetween, actualTime, min, max, min.Sub(actualTime))
}
if !actualTime.Before(max) {
return fmt.Sprintf(shouldHaveHappenedBetween, actualTime, min, max, actualTime.Sub(max))
}
return success
}

// ShouldHappenOnOrBetween receives exactly 3 time.Time arguments and asserts that the first happens between or on the second and third.
func ShouldHappenOnOrBetween(actual interface{}, expected ...interface{}) string {
if fail := need(1, expected); fail != success {
if fail := need(2, expected); fail != success {
return fail
}
actualTime, firstOk := actual.(time.Time)
expectedTime, secondOk := expected[0].(time.Time)
min, secondOk := expected[0].(time.Time)
max, thirdOk := expected[1].(time.Time)

if !firstOk || !secondOk {
if !firstOk || !secondOk || !thirdOk {
return shouldUseTimes
}
return fmt.Sprintf("%v %v", actualTime, expectedTime) // TODO
if actualTime.Equal(min) || actualTime.Equal(max) {
return success
}
return ShouldHappenBetween(actualTime, min, max)
}

func ShouldHappenWithin(actual interface{}, expected ...interface{}) string {
if fail := need(1, expected); fail != success {
// ShouldNotHappenOnOrBetween receives exactly 3 time.Time arguments and asserts that the first
// does NOT happen between or on the second or third.
func ShouldNotHappenOnOrBetween(actual interface{}, expected ...interface{}) string {
if fail := need(2, expected); fail != success {
return fail
}
actualTime, firstOk := actual.(time.Time)
expectedTime, secondOk := expected[0].(time.Time)
min, secondOk := expected[0].(time.Time)
max, thirdOk := expected[1].(time.Time)

if !firstOk || !secondOk {
if !firstOk || !secondOk || !thirdOk {
return shouldUseTimes
}
return fmt.Sprintf("%v %v", actualTime, expectedTime) // TODO
if actualTime.Equal(min) || actualTime.Equal(max) {
return fmt.Sprintf(shouldNotHaveHappenedOnOrBetween, actualTime, min, max)
}
if actualTime.After(min) && actualTime.Before(max) {
return fmt.Sprintf(shouldNotHaveHappenedOnOrBetween, actualTime, min, max)
}
return success
}

// ShouldHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 arguments)
// and asserts that the first time.Time happens within or on the duration specified relative to
// the other time.Time.
func ShouldHappenWithin(actual interface{}, expected ...interface{}) string {
if fail := need(2, expected); fail != success {
return fail
}
actualTime, firstOk := actual.(time.Time)
tolerance, secondOk := expected[0].(time.Duration)
threshold, thirdOk := expected[1].(time.Time)

if !firstOk || !secondOk || !thirdOk {
return shouldUseDurationAndTime
}

min := threshold.Add(-tolerance)
max := threshold.Add(tolerance)
return ShouldHappenOnOrBetween(actualTime, min, max)
}

// ShouldNotHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 arguments)
// and asserts that the first time.Time does NOT happen within or on the duration specified relative to
// the other time.Time.
func ShouldNotHappenWithin(actual interface{}, expected ...interface{}) string {
if fail := need(2, expected); fail != success {
return fail
}
actualTime, firstOk := actual.(time.Time)
tolerance, secondOk := expected[0].(time.Duration)
threshold, thirdOk := expected[1].(time.Time)

if !firstOk || !secondOk || !thirdOk {
return shouldUseDurationAndTime
}

min := threshold.Add(-tolerance)
max := threshold.Add(tolerance)
return ShouldNotHappenOnOrBetween(actualTime, min, max)
}
106 changes: 76 additions & 30 deletions assertions/time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ func TestShouldHappenOnOrBefore(t *testing.T) {
fail(t, so(0, ShouldHappenOnOrBefore, time.Now()), shouldUseTimes)
fail(t, so(time.Now(), ShouldHappenOnOrBefore, 0), shouldUseTimes)

// TODO: test actual logic
fail(t, so(january3, ShouldHappenOnOrBefore, january1), fmt.Sprintf("Expected '%s' to happen before '%s' (it happened '48h0m0s' after)!", pretty(january3), pretty(january1)))
pass(t, so(january3, ShouldHappenOnOrBefore, january3))
pass(t, so(january1, ShouldHappenOnOrBefore, january3))
}

func TestShouldHappenAfter(t *testing.T) {
Expand All @@ -38,7 +40,9 @@ func TestShouldHappenAfter(t *testing.T) {
fail(t, so(0, ShouldHappenAfter, time.Now()), shouldUseTimes)
fail(t, so(time.Now(), ShouldHappenAfter, 0), shouldUseTimes)

// TODO: test actual logic
fail(t, so(january1, ShouldHappenAfter, january2), fmt.Sprintf("Expected '%s' to happen after '%s' (it happened '24h0m0s' before)!", pretty(january1), pretty(january2)))
fail(t, so(january1, ShouldHappenAfter, january1), fmt.Sprintf("Expected '%s' to happen after '%s' (it happened '0' before)!", pretty(january1), pretty(january1)))
pass(t, so(january3, ShouldHappenAfter, january1))
}

func TestShouldHappenOnOrAfter(t *testing.T) {
Expand All @@ -49,55 +53,97 @@ func TestShouldHappenOnOrAfter(t *testing.T) {
fail(t, so(0, ShouldHappenOnOrAfter, time.Now()), shouldUseTimes)
fail(t, so(time.Now(), ShouldHappenOnOrAfter, 0), shouldUseTimes)

// TODO: test actual logic
fail(t, so(january1, ShouldHappenOnOrAfter, january2), fmt.Sprintf("Expected '%s' to happen after '%s' (it happened '24h0m0s' before)!", pretty(january1), pretty(january2)))
pass(t, so(january1, ShouldHappenOnOrAfter, january1))
pass(t, so(january3, ShouldHappenOnOrAfter, january1))
}

func TestShouldHappenBetween(t *testing.T) {
fail(t, so(0, ShouldHappenBetween), "This assertion requires exactly 1 comparison values (you provided 0).")
fail(t, so(0, ShouldHappenBetween, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")

fail(t, so(0, ShouldHappenBetween, 1), shouldUseTimes)
fail(t, so(0, ShouldHappenBetween, time.Now()), shouldUseTimes)
fail(t, so(time.Now(), ShouldHappenBetween, 0), shouldUseTimes)

// TODO: test actual logic
fail(t, so(0, ShouldHappenBetween), "This assertion requires exactly 2 comparison values (you provided 0).")
fail(t, so(0, ShouldHappenBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")

fail(t, so(0, ShouldHappenBetween, 1, 2), shouldUseTimes)
fail(t, so(0, ShouldHappenBetween, time.Now(), time.Now()), shouldUseTimes)
fail(t, so(time.Now(), ShouldHappenBetween, 0, time.Now()), shouldUseTimes)
fail(t, so(time.Now(), ShouldHappenBetween, time.Now(), 9), shouldUseTimes)

fail(t, so(january1, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january1), pretty(january2), pretty(january4)))
fail(t, so(january2, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '0' outside threshold)!", pretty(january2), pretty(january2), pretty(january4)))
pass(t, so(january3, ShouldHappenBetween, january2, january4))
fail(t, so(january4, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '0' outside threshold)!", pretty(january4), pretty(january2), pretty(january4)))
fail(t, so(january5, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january5), pretty(january2), pretty(january4)))
}

func TestShouldHappenOnOrBetween(t *testing.T) {
fail(t, so(0, ShouldHappenOnOrBetween), "This assertion requires exactly 1 comparison values (you provided 0).")
fail(t, so(0, ShouldHappenOnOrBetween, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
fail(t, so(0, ShouldHappenOnOrBetween), "This assertion requires exactly 2 comparison values (you provided 0).")
fail(t, so(0, ShouldHappenOnOrBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")

fail(t, so(0, ShouldHappenOnOrBetween, 1, time.Now()), shouldUseTimes)
fail(t, so(0, ShouldHappenOnOrBetween, time.Now(), 1), shouldUseTimes)
fail(t, so(time.Now(), ShouldHappenOnOrBetween, 0, 1), shouldUseTimes)

fail(t, so(january1, ShouldHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january1), pretty(january2), pretty(january4)))
pass(t, so(january2, ShouldHappenOnOrBetween, january2, january4))
pass(t, so(january3, ShouldHappenOnOrBetween, january2, january4))
pass(t, so(january4, ShouldHappenOnOrBetween, january2, january4))
fail(t, so(january5, ShouldHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january5), pretty(january2), pretty(january4)))
}

func TestShouldNotHappenOnOrBetween(t *testing.T) {
fail(t, so(0, ShouldNotHappenOnOrBetween), "This assertion requires exactly 2 comparison values (you provided 0).")
fail(t, so(0, ShouldNotHappenOnOrBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")

fail(t, so(0, ShouldHappenOnOrBetween, 1), shouldUseTimes)
fail(t, so(0, ShouldHappenOnOrBetween, time.Now()), shouldUseTimes)
fail(t, so(time.Now(), ShouldHappenOnOrBetween, 0), shouldUseTimes)
fail(t, so(0, ShouldNotHappenOnOrBetween, 1, time.Now()), shouldUseTimes)
fail(t, so(0, ShouldNotHappenOnOrBetween, time.Now(), 1), shouldUseTimes)
fail(t, so(time.Now(), ShouldNotHappenOnOrBetween, 0, 1), shouldUseTimes)

// TODO: test actual logic
pass(t, so(january1, ShouldNotHappenOnOrBetween, january2, january4))
fail(t, so(january2, ShouldNotHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january2), pretty(january2), pretty(january4)))
fail(t, so(january3, ShouldNotHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january3), pretty(january2), pretty(january4)))
fail(t, so(january4, ShouldNotHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january4), pretty(january2), pretty(january4)))
pass(t, so(january5, ShouldNotHappenOnOrBetween, january2, january4))
}

func TestShouldHappenWithin(t *testing.T) {
fail(t, so(0, ShouldHappenWithin), "This assertion requires exactly 1 comparison values (you provided 0).")
fail(t, so(0, ShouldHappenWithin, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
fail(t, so(0, ShouldHappenWithin), "This assertion requires exactly 2 comparison values (you provided 0).")
fail(t, so(0, ShouldHappenWithin, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")

fail(t, so(0, ShouldHappenWithin, 1, 2), shouldUseDurationAndTime)
fail(t, so(0, ShouldHappenWithin, oneDay, time.Now()), shouldUseDurationAndTime)
fail(t, so(time.Now(), ShouldHappenWithin, 0, time.Now()), shouldUseDurationAndTime)

fail(t, so(january1, ShouldHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january1), pretty(january2), pretty(january4)))
pass(t, so(january2, ShouldHappenWithin, oneDay, january3))
pass(t, so(january3, ShouldHappenWithin, oneDay, january3))
pass(t, so(january4, ShouldHappenWithin, oneDay, january3))
fail(t, so(january5, ShouldHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january5), pretty(january2), pretty(january4)))
}

func TestShouldNotHappenWithin(t *testing.T) {
fail(t, so(0, ShouldNotHappenWithin), "This assertion requires exactly 2 comparison values (you provided 0).")
fail(t, so(0, ShouldNotHappenWithin, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")

fail(t, so(0, ShouldHappenWithin, 1), shouldUseTimes)
fail(t, so(0, ShouldHappenWithin, time.Now()), shouldUseTimes)
fail(t, so(time.Now(), ShouldHappenWithin, 0), shouldUseTimes)
fail(t, so(0, ShouldNotHappenWithin, 1, 2), shouldUseDurationAndTime)
fail(t, so(0, ShouldNotHappenWithin, oneDay, time.Now()), shouldUseDurationAndTime)
fail(t, so(time.Now(), ShouldNotHappenWithin, 0, time.Now()), shouldUseDurationAndTime)

// TODO: test actual logic
pass(t, so(january1, ShouldNotHappenWithin, oneDay, january3))
fail(t, so(january2, ShouldNotHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january2), pretty(january2), pretty(january4)))
fail(t, so(january3, ShouldNotHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january3), pretty(january2), pretty(january4)))
fail(t, so(january4, ShouldNotHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january4), pretty(january2), pretty(january4)))
pass(t, so(january5, ShouldNotHappenWithin, oneDay, january3))
}

const layout = "2006-01-02 15:04"

var january1, _ = time.Parse(layout, "2013-01-01 00:00")
var january2, _ = time.Parse(layout, "2013-01-02 00:00")
var january3, _ = time.Parse(layout, "2013-01-03 00:00")
var january4, _ = time.Parse(layout, "2013-01-04 00:00")
var january5, _ = time.Parse(layout, "2013-01-05 00:00")

var february1, _ = time.Parse(layout, "2013-02-01 00:00")
var february2, _ = time.Parse(layout, "2013-02-02 00:00")
var february3, _ = time.Parse(layout, "2013-02-03 00:00")

var march1, _ = time.Parse(layout, "2013-03-01 00:00")
var march2, _ = time.Parse(layout, "2013-03-02 00:00")
var march3, _ = time.Parse(layout, "2013-03-03 00:00")
var oneDay, _ = time.ParseDuration("24h0m0s")
var twoDays, _ = time.ParseDuration("48h0m0s")

func pretty(t time.Time) string {
return fmt.Sprintf("%v", t)
Expand Down

0 comments on commit bbcf475

Please sign in to comment.