quando/clock.go
Oliver Jakoubek d0cbff9ff8 feat(quando-vih): implement Clock abstraction for testability
- Add Clock interface with Now() and From(t time.Time) methods
- Implement DefaultClock using time.Now() for production code
- Implement FixedClock with fixed time for deterministic testing
- Add factory functions NewClock() and NewFixedClock(time.Time)
- Comprehensive unit tests demonstrating deterministic test patterns
- Edge case testing (epoch, year 0001, year 9999, nanoseconds)
- Timezone preservation tests
- Example tests showing test usage patterns
- Performance benchmarks for both clock implementations
- 100% test coverage (exceeds 95% requirement)

All acceptance criteria met:
✓ Clock interface defined
✓ DefaultClock implementation using time.Now()
✓ FixedClock implementation with fixed time
✓ NewClock() factory function
✓ NewFixedClock(time.Time) factory function
✓ Unit tests demonstrating deterministic test patterns
✓ Godoc comments
✓ Example test showing test usage pattern
2026-02-11 16:33:23 +01:00

79 lines
2.1 KiB
Go

package quando
import "time"
// Clock provides an abstraction for time operations to enable deterministic testing.
// Use DefaultClock in production and FixedClock in tests.
//
// Example production code:
//
// clock := quando.NewClock()
// date := clock.Now()
//
// Example test code:
//
// fixedTime := time.Date(2026, 2, 9, 12, 0, 0, 0, time.UTC)
// clock := quando.NewFixedClock(fixedTime)
// date := clock.Now() // Always returns Feb 9, 2026
type Clock interface {
// Now returns the current date according to this clock.
Now() Date
// From converts a time.Time to a Date using this clock's configuration.
From(t time.Time) Date
}
// DefaultClock is the standard clock implementation that uses the system time.
// It returns the actual current time when Now() is called.
type DefaultClock struct{}
// NewClock returns a new DefaultClock that uses the system time.
// This is the clock to use in production code.
//
// Example:
//
// clock := quando.NewClock()
// now := clock.Now()
func NewClock() Clock {
return &DefaultClock{}
}
// Now returns the current date using the system time.
func (c *DefaultClock) Now() Date {
return Now()
}
// From converts a time.Time to a Date.
func (c *DefaultClock) From(t time.Time) Date {
return From(t)
}
// FixedClock is a clock implementation that always returns the same time.
// This is useful for deterministic testing.
type FixedClock struct {
fixedTime time.Time
}
// NewFixedClock returns a new FixedClock that always returns the specified time.
// This is primarily intended for testing.
//
// Example:
//
// // In tests
// fixedTime := time.Date(2026, 2, 9, 12, 0, 0, 0, time.UTC)
// clock := quando.NewFixedClock(fixedTime)
// date := clock.Now() // Always returns Feb 9, 2026 12:00:00
func NewFixedClock(t time.Time) Clock {
return &FixedClock{fixedTime: t}
}
// Now returns the fixed time configured for this clock.
func (c *FixedClock) Now() Date {
return From(c.fixedTime)
}
// From converts a time.Time to a Date.
// For FixedClock, this behaves the same as the DefaultClock.
func (c *FixedClock) From(t time.Time) Date {
return From(t)
}