Source File
fakeclock.go
Belonging Package
go.pact.im/x/clock/fakeclock
// Package fakeclock provides support for testing users of a clock.package fakeclockimport ()var _ interface {clock.Schedulerclock.NowSchedulerclock.TimerSchedulerclock.TickerScheduler} = (*Clock)(nil)// moment represents a scheduled event.type moment interface {// next returns the duration until the next occurrence of this event, or// false if it is the last event.next(now time.Time) (time.Duration, bool)}// Clock is a fake clock.Scheduler interface implementation that is safe for// concurrent use by multiple goroutines.//// Use Next, Set, Add and AddDate methods to change clock time. Advancing the// time triggers scheduled events, timers and tickers.//// Note that the order in which events scheduled for the same time are triggered// is undefined, but it is guaranteed that all events that are not after the new// current time are triggered on clock time change (even if old time is equal to// the next time value).//// The zero Clock defaults to zero time and is ready for use.type Clock struct {mu sync.Mutexnow time.Timesched map[moment]time.Time}// Unix returns a clock set to the Unix epoch time. That is, it is set to// 1970-01-01 00:00:00 UTC.func () *Clock {return Time(time.Unix(0, 0))}// Go returns a clock set to the Go initial release date. That is, it is set to// 2009-11-10 23:00:00 UTC.func () *Clock {return Time(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC))}// Y2038 returns a clock set to d duration after the Year 2038 problem time.// That is, it is set to the given duration after 2038-01-19 03:14:07 UTC, the// latest time that can be properly encoded as a 32-bit integer that is a number// of seconds after the Unix epoch.func ( time.Duration) *Clock {:= time.Unix(math.MaxInt32, 0)return Time(.Add())}// Time returns a clock set to the given now time.func ( time.Time) *Clock {return &Clock{now: ,sched: map[moment]time.Time{},}}// Now returns the current clock time.func ( *Clock) () time.Time {.mu.Lock()defer .mu.Unlock()return .now}// Next advances the time to the next timer or ticker event and returns the new// current time. If there are events in the past, the time is not changed. It// returns false if there are no scheduled events. Otherwise it returns true and// runs at least one scheduled event.func ( *Clock) () (time.Time, bool) {.mu.Lock()defer .mu.Unlock():= len(.sched) > 0.now = .next(.now).advance(.now)return .now,}// Set sets the given time to be the current clock time. It is possible to set// t that is before the current clock time.func ( *Clock) ( time.Time) {.mu.Lock()defer .mu.Unlock().now =.advance(.now)}// Add adds the given duration to the current time and returns the resulting// clock time. It is possible to add a negative duration.//// It is safe for concurrent use and is a shorthand for//// now := c.Now().Add(d)// c.Set(now)func ( *Clock) ( time.Duration) time.Time {.mu.Lock()defer .mu.Unlock().now = .now.Add().advance(.now)return .now}// AddDate adds the duration corresponding to the given number of years, months// and days relative to the current time and returns the resulting clock time.// It is possible to add negative values.//// It is safe for concurrent use and is a shorthand for//// now := c.Now().AddDate(years, months, days)// c.Set(now)func ( *Clock) (, , int) time.Time {.mu.Lock()defer .mu.Unlock().now = .now.AddDate(, , ).advance(.now)return .now}// Schedule implements the clock.Scheduler interface.func ( *Clock) ( time.Duration, func( time.Time)) clock.Event {:= &event{c: ,f: ,}.reset(, , nil)return}// Timer implements the clock.TimerScheduler interface.func ( *Clock) ( time.Duration) clock.Timer {:= &timer{c: ,ch: make(chan time.Time, 1),}.reset(, , nil)return}// Ticker implements the clock.TickerScheduler interface. Note that the returned// ticker does not adjust the time interval or drop ticks to make up for slow// receivers.func ( *Clock) ( time.Duration) clock.Ticker {if <= 0 {panic("non-positive interval for Ticker")}:= &ticker{c: ,ch: make(chan time.Time, 1),}.reset(, , &.d)return}// stop removes the given moment from the set of scheduled events. It returns// true if stop prevented the event from firing. Note that stop acquires the// underlying lock.func ( *Clock) ( moment) bool {.mu.Lock()defer .mu.Unlock(), := .sched[]delete(.sched, )return}// reset resets the given moment to run d duration after the current time.// Note that reset acquires the underlying lock. Reset returns true if it// rescheduled an event.func ( *Clock) ( moment, time.Duration, *time.Duration) bool {.mu.Lock()defer .mu.Unlock()if != nil {* =}return .schedule(, .now.Add())}// schedule schedules the given moment to run on next clock advance. It returns// true if an event was rescheduled.func ( *Clock) ( moment, time.Time) bool {if .sched == nil {.sched = map[moment]time.Time{}}, := .sched[].sched[] =return}// next returns the time of the next scheduled event. It returns the given now// time if there are no events or some of them are in the past.func ( *Clock) ( time.Time) time.Time {if len(.sched) == 0 {return}var time.Timefor , := range .sched {=break}for , := range .sched {if !.After() {return}if .After() {continue}=}return}// advance runs the scheduled events for the current clock time.func ( *Clock) ( time.Time) {for , := range .sched {if .After() {continue}, := .next()if ! {delete(.sched, )continue}_ = .schedule(, .Add())}}// event implements the moment and clock.Event interfaces.type event struct {c *Clockf func(time.Time)}// Stop implements the clock.Event interface.func ( *event) () bool {return .c.stop()}// Reset implements the clock.Event interface.func ( *event) ( time.Duration) bool {return .c.reset(, , nil)}// next implements the moment interface.func ( *event) ( time.Time) (time.Duration, bool) {go .f()return 0, false}// timer implements the moment and clock.Timer interfaces.type timer struct {c *Clockch chan time.Time}// C implements the clock.Timer interface.func ( *timer) () <-chan time.Time {return .ch}// Stop implements the clock.Timer interface.func ( *timer) () bool {return .c.stop()}// Reset implements the clock.Timer interface.func ( *timer) ( time.Duration) {_ = .c.reset(, , nil)}// next implements the moment interface.func ( *timer) ( time.Time) (time.Duration, bool) {select {case .ch <- :default:}return 0, false}// ticker implements the moment and clock.Ticker interfaces.type ticker struct {c *Clockch chan time.Timed time.Duration}// C implements the clock.Ticker interface.func ( *ticker) () <-chan time.Time {return .ch}// Stop implements the clock.Ticker interface.func ( *ticker) () {_ = .c.stop()}// Reset implements the clock.Ticker interface.func ( *ticker) ( time.Duration) {if <= 0 {panic("non-positive interval for Ticker.Reset")}_ = .c.reset(, , &.d)}// next implements the moment interface.func ( *ticker) ( time.Time) (time.Duration, bool) {select {case .ch <- :default:}return .d, true}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)