clock

package
v0.30.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 20, 2026 License: Apache-2.0 Imports: 2 Imported by: 0

README

Clock Package

A simple and testable time abstraction package for Go applications.

Overview

The clock package provides a clean abstraction over Go's time package, making it easier to write testable code that depends on time operations. By using an interface-based approach, you can easily mock time operations in your tests while using the real system time in production.

Features

  • Simple Interface: Clean abstraction with minimal API surface
  • Testable: Easy to mock for unit testing
  • Production Ready: Uses actual system time in production
  • Zero Dependencies: Only depends on Go's standard library
  • Mock Generation: Includes generated mocks using testify/mock

Installation

go get github.com/zondax/golem/pkg/clock

Usage

Basic Usage
package main

import (
    "fmt"
    "github.com/zondax/golem/pkg/clock"
)

func main() {
    // Create a new clock instance
    clk := clock.New()
    
    // Get current time
    now := clk.Now()
    fmt.Printf("Current time: %v\n", now)
}
Dependency Injection
type Service struct {
    clock clock.Clock
}

func NewService(clk clock.Clock) *Service {
    return &Service{
        clock: clk,
    }
}

func (s *Service) ProcessWithTimestamp() {
    timestamp := s.clock.Now()
    // Process with timestamp...
}

// In production
func main() {
    clk := clock.New()
    service := NewService(clk)
    service.ProcessWithTimestamp()
}
Testing with Mocks
package main

import (
    "testing"
    "time"
    
    "github.com/stretchr/testify/assert"
    "github.com/zondax/golem/pkg/clock"
)

func TestServiceWithMockClock(t *testing.T) {
    // Create mock clock
    mockClock := clock.NewMockClock(t)
    
    // Set up expectations
    fixedTime := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC)
    mockClock.EXPECT().Now().Return(fixedTime).Once()
    
    // Create service with mock
    service := NewService(mockClock)
    
    // Test with predictable time
    result := service.ProcessWithTimestamp()
    
    // Verify behavior with known time
    assert.Equal(t, fixedTime, result.Timestamp)
}

API Reference

Interface
type Clock interface {
    // Now returns the current time
    Now() time.Time
}
Functions
New() Clock

Creates a new clock instance that uses the actual system time.

Returns:

  • Clock: A clock implementation using time.Now()

Example:

clk := clock.New()
currentTime := clk.Now()
Mock

The package includes a generated mock (MockClock) that implements the Clock interface using testify/mock.

NewMockClock(t *testing.T) *MockClock

Creates a new mock clock for testing.

Parameters:

  • t *testing.T: The testing context

Returns:

  • *MockClock: A mock implementation of the Clock interface

Example:

func TestWithMockClock(t *testing.T) {
    mockClock := clock.NewMockClock(t)
    
    // Set up expectations
    expectedTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
    mockClock.EXPECT().Now().Return(expectedTime).Times(2)
    
    // Use mock in tests
    assert.Equal(t, expectedTime, mockClock.Now())
    assert.Equal(t, expectedTime, mockClock.Now())
}

Testing Patterns

Fixed Time Testing
func TestWithFixedTime(t *testing.T) {
    mockClock := clock.NewMockClock(t)
    fixedTime := time.Date(2024, 6, 14, 12, 0, 0, 0, time.UTC)
    
    mockClock.EXPECT().Now().Return(fixedTime).Once()
    
    service := NewService(mockClock)
    result := service.GetTimestamp()
    
    assert.Equal(t, fixedTime, result)
}
Time Progression Testing
func TestWithTimeProgression(t *testing.T) {
    mockClock := clock.NewMockClock(t)
    baseTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
    
    // Set up time progression
    mockClock.EXPECT().Now().Return(baseTime).Once()
    mockClock.EXPECT().Now().Return(baseTime.Add(time.Hour)).Once()
    mockClock.EXPECT().Now().Return(baseTime.Add(2 * time.Hour)).Once()
    
    service := NewService(mockClock)
    
    // Test time progression
    t1 := service.GetTimestamp()
    t2 := service.GetTimestamp()
    t3 := service.GetTimestamp()
    
    assert.Equal(t, baseTime, t1)
    assert.Equal(t, baseTime.Add(time.Hour), t2)
    assert.Equal(t, baseTime.Add(2*time.Hour), t3)
}

Best Practices

1. Use Dependency Injection

Always inject the clock as a dependency rather than creating it directly in your business logic:

// ✅ Good - Testable
type Service struct {
    clock clock.Clock
}

func NewService(clk clock.Clock) *Service {
    return &Service{clock: clk}
}

// ❌ Bad - Hard to test
type Service struct{}

func (s *Service) Process() {
    now := time.Now() // Hard to mock
}
2. Use Interface Types

Always use the clock.Clock interface type in your function signatures:

// ✅ Good - Flexible
func ProcessData(clk clock.Clock, data []byte) error {
    timestamp := clk.Now()
    // ...
}

// ❌ Bad - Tightly coupled
func ProcessData(clk *clock.clock, data []byte) error {
    // ...
}
3. Set Clear Mock Expectations

Always set up your mock expectations clearly and verify they're met:

func TestProcess(t *testing.T) {
    mockClock := clock.NewMockClock(t)
    expectedTime := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC)
    
    // Clear expectation
    mockClock.EXPECT().Now().Return(expectedTime).Once()
    
    result := ProcessData(mockClock, []byte("test"))
    
    assert.NoError(t, result)
    // Mock expectations are automatically verified by testify
}

File Structure

pkg/clock/
├── README.md           # This documentation
├── clock.go           # Main implementation
├── clock_mock.go      # Generated mock (DO NOT EDIT)
└── clock_test.go      # Unit tests

Mock Generation

The mock is generated using mockery. To regenerate the mock:

# Install mockery if not already installed
go install github.com/vektra/mockery/v2@latest

# Generate mocks (run from project root)
mockery --name=Clock --dir=pkg/clock --output=pkg/clock --filename=clock_mock.go

Contributing

When contributing to this package:

  1. Keep it simple: The clock package should remain minimal and focused
  2. Maintain backward compatibility: Any changes should not break existing code
  3. Update tests: Ensure all tests pass and add new tests for new functionality
  4. Update documentation: Keep this README up to date with any changes
  5. Don't edit generated files: Never manually edit clock_mock.go

License

This package is part of the Zondax Golem project and follows the same licensing terms.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Clock

type Clock interface {
	// Now returns the current time
	Now() time.Time
}

Clock abstracts time operations for better testing and flexibility

func New

func New() Clock

type MockClock

type MockClock struct {
	mock.Mock
}

MockClock is an autogenerated mock type for the Clock type

func NewMockClock

func NewMockClock(t interface {
	mock.TestingT
	Cleanup(func())
}) *MockClock

NewMockClock creates a new instance of MockClock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. The first argument is typically a *testing.T value.

func (*MockClock) EXPECT

func (_m *MockClock) EXPECT() *MockClock_Expecter

func (*MockClock) Now

func (_m *MockClock) Now() time.Time

Now provides a mock function with no fields

type MockClock_Expecter

type MockClock_Expecter struct {
	// contains filtered or unexported fields
}

func (*MockClock_Expecter) Now

Now is a helper method to define mock.On call

type MockClock_Now_Call

type MockClock_Now_Call struct {
	*mock.Call
}

MockClock_Now_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Now'

func (*MockClock_Now_Call) Return

func (*MockClock_Now_Call) Run

func (_c *MockClock_Now_Call) Run(run func()) *MockClock_Now_Call

func (*MockClock_Now_Call) RunAndReturn

func (_c *MockClock_Now_Call) RunAndReturn(run func() time.Time) *MockClock_Now_Call

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL