easmock

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: May 10, 2026 License: MIT Imports: 3 Imported by: 0

README

easmock — hand-written test doubles for the eas interfaces

easmock provides drop-in fakes for every interface eas declares. Each interface in eas (the umbrella Client plus ten feature-area sub-interfaces) has a sibling struct here with one func-typed field per method.

Why

The eas package's NewClient returns the eas.Client interface so callers can swap in a fake during unit tests. easmock is the fake they swap in — already written, zero codegen, zero deps.

Compared to standing up an httptest.Server plus a real StateStore, an easmock-based test:

  • has no goroutines and no network sockets;
  • runs in microseconds;
  • exposes call arguments directly to test assertions;
  • fails loudly with a sentinel error when the code under test calls a method the test didn't configure (instead of silently 200-OK).

How

Each method's behavior is controlled by a *Func field on the mock struct. Set the Func to return what your scenario needs; leave it nil and the method returns errors.New("easmock: <Method> not implemented").

import (
    "context"
    "testing"

    "github.com/hstern/go-activesync/eas"
    "github.com/hstern/go-activesync/eas/easmock"
)

func TestInboxSummary(t *testing.T) {
    var c eas.Client = &easmock.Client{
        EmailClient: easmock.EmailClient{
            SyncEmailFunc: func(_ context.Context, fid string, _ eas.EmailSyncOptions) (*eas.EmailSyncResult, error) {
                if fid != "inbox" {
                    t.Errorf("unexpected folder %q", fid)
                }
                return &eas.EmailSyncResult{
                    SyncKey: "S2",
                    Added:   []eas.EmailItem{{Subject: "hello"}},
                }, nil
            },
        },
    }

    // Pass c to your code under test.
    summary := codeUnderTest(c)
    if summary != "1 new: hello" {
        t.Errorf("got %q", summary)
    }
}

Sub-interfaces compose into the umbrella the same way the real eas.Client does:

mock := &easmock.Client{
    EmailClient:  easmock.EmailClient{ /* … */ },
    FolderClient: easmock.FolderClient{ /* … */ },
}
var _ eas.Client = mock // compile-time conformance check

If your code only depends on a slice of the protocol (e.g. an inbox-summarising function that needs EmailClient + FolderClient), declare the narrower interface in your code and pass the matching sub-mock directly — you don't have to wrap it in easmock.Client.

What's covered

eas interface easmock mock Methods
eas.Client easmock.Client umbrella, embeds the sub-mocks below
eas.EmailClient easmock.EmailClient 9
eas.CalendarClient easmock.CalendarClient 5
eas.ContactsClient easmock.ContactsClient 4
eas.TasksClient easmock.TasksClient 5
eas.NotesClient easmock.NotesClient 4
eas.FolderClient easmock.FolderClient 10
eas.SettingsClient easmock.SettingsClient 6
eas.SearchClient easmock.SearchClient 3
eas.ProvisionClient easmock.ProvisionClient 4
eas.PingClient easmock.PingClient 1

Each file ends with var _ eas.X = (*X)(nil) so a missing method on the mock fails the package build immediately — drift between eas and easmock can't sneak in unnoticed.

What's not covered

  • eas.Autodiscover is a package function, not a method, so it has no mock. Wrap it in your own indirection if you need to fake autodiscovery.
  • eas.StateStore already lives in the eas package as an interface; eas.NewMemoryState is the in-memory implementation suitable for tests. There's no easmock equivalent because MemoryState already is the test double.

See also

  • eas — the main package and its interfaces
  • godoc — full API reference

Documentation

Overview

Package easmock provides hand-written test doubles for the github.com/hstern/go-activesync/eas interface set.

Each interface in eas has a sibling struct here with one func-typed field per method. Tests set the fields they care about; methods whose Func is nil return a sentinel error so a misbehaving handler fails loudly rather than silently calling a no-op.

mock := &easmock.Client{
    EmailClient: easmock.EmailClient{
        SyncEmailFunc: func(ctx context.Context, fid string, opts eas.EmailSyncOptions) (*eas.EmailSyncResult, error) {
            return &eas.EmailSyncResult{SyncKey: "1", Added: []eas.EmailItem{{Subject: "hi"}}}, nil
        },
    },
}

// mock implements eas.Client; pass it where the consumer expects
// an eas.Client.

The mocks are intentionally hand-written: zero codegen, zero deps, and easy to extend when eas adds methods (the only edits are an extra Func field and a one-method stub).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CalendarClient

type CalendarClient struct {
	SyncCalendarFunc  func(ctx context.Context, folderID string, opts eas.CalendarSyncOptions) (*eas.CalendarSyncResult, error)
	CreateEventFunc   func(ctx context.Context, folderID string, draft eas.EventDraft) (string, error)
	UpdateEventFunc   func(ctx context.Context, folderID, serverID string, draft eas.EventDraft) error
	DeleteEventFunc   func(ctx context.Context, folderID, serverID string) error
	RespondInviteFunc func(ctx context.Context, folderID, serverID string, choice eas.MeetingResponseChoice) (*eas.MeetingResponseResult, error)
}

CalendarClient is a hand-written test double for eas.CalendarClient.

func (*CalendarClient) CreateEvent

func (m *CalendarClient) CreateEvent(ctx context.Context, folderID string, draft eas.EventDraft) (string, error)

func (*CalendarClient) DeleteEvent

func (m *CalendarClient) DeleteEvent(ctx context.Context, folderID, serverID string) error

func (*CalendarClient) RespondInvite

func (m *CalendarClient) RespondInvite(ctx context.Context, folderID, serverID string, choice eas.MeetingResponseChoice) (*eas.MeetingResponseResult, error)

func (*CalendarClient) SyncCalendar

func (m *CalendarClient) SyncCalendar(ctx context.Context, folderID string, opts eas.CalendarSyncOptions) (*eas.CalendarSyncResult, error)

func (*CalendarClient) UpdateEvent

func (m *CalendarClient) UpdateEvent(ctx context.Context, folderID, serverID string, draft eas.EventDraft) error

type Client

Client is the umbrella mock for eas.Client. Embed and override only the sub-mocks (or specific Func fields on them) the test cares about. Methods not configured return a sentinel error.

mock := &easmock.Client{
    EmailClient: easmock.EmailClient{
        SyncEmailFunc: func(ctx context.Context, fid string, opts eas.EmailSyncOptions) (*eas.EmailSyncResult, error) {
            return &eas.EmailSyncResult{SyncKey: "1"}, nil
        },
    },
}
var _ eas.Client = mock

func (*Client) LastPolicy

func (m *Client) LastPolicy() *eas.Policy

LastPolicy returns the canned Policy from LastPolicyFunc, or nil if unset.

type ContactsClient

type ContactsClient struct {
	SyncContactsFunc  func(ctx context.Context, folderID string) (*eas.ContactsSyncResult, error)
	CreateContactFunc func(ctx context.Context, folderID string, draft eas.ContactDraft) (string, error)
	UpdateContactFunc func(ctx context.Context, folderID, serverID string, draft eas.ContactDraft) error
	DeleteContactFunc func(ctx context.Context, folderID, serverID string) error
}

ContactsClient is a hand-written test double for eas.ContactsClient.

func (*ContactsClient) CreateContact

func (m *ContactsClient) CreateContact(ctx context.Context, folderID string, draft eas.ContactDraft) (string, error)

func (*ContactsClient) DeleteContact

func (m *ContactsClient) DeleteContact(ctx context.Context, folderID, serverID string) error

func (*ContactsClient) SyncContacts

func (m *ContactsClient) SyncContacts(ctx context.Context, folderID string) (*eas.ContactsSyncResult, error)

func (*ContactsClient) UpdateContact

func (m *ContactsClient) UpdateContact(ctx context.Context, folderID, serverID string, draft eas.ContactDraft) error

type EmailClient

type EmailClient struct {
	SyncEmailFunc         func(ctx context.Context, folderID string, opts eas.EmailSyncOptions) (*eas.EmailSyncResult, error)
	ApplyEmailChangesFunc func(ctx context.Context, folderID string, changes []eas.EmailChange) ([]eas.EmailChangeResult, error)
	FetchEmailFunc        func(ctx context.Context, folderID, serverID string, opts eas.FetchEmailOptions) (*eas.EmailItem, error)
	SendMailFunc          func(ctx context.Context, opts eas.SendMailOptions) error
	SmartReplyFunc        func(ctx context.Context, opts eas.ReplyForwardOptions) error
	SmartForwardFunc      func(ctx context.Context, opts eas.ReplyForwardOptions) error
	SearchEmailFunc       func(ctx context.Context, query string, opts eas.EmailSearchOptions) (*eas.EmailSearchResult, error)
	SearchEmailQueryFunc  func(ctx context.Context, q eas.Query, opts eas.EmailSearchOptions) (*eas.EmailSearchResult, error)
	FindEmailFunc         func(ctx context.Context, query string, opts eas.FindOptions) (*eas.FindResult, error)
}

EmailClient is a hand-written test double for eas.EmailClient.

func (*EmailClient) ApplyEmailChanges

func (m *EmailClient) ApplyEmailChanges(ctx context.Context, folderID string, changes []eas.EmailChange) ([]eas.EmailChangeResult, error)

func (*EmailClient) FetchEmail

func (m *EmailClient) FetchEmail(ctx context.Context, folderID, serverID string, opts eas.FetchEmailOptions) (*eas.EmailItem, error)

func (*EmailClient) FindEmail

func (m *EmailClient) FindEmail(ctx context.Context, query string, opts eas.FindOptions) (*eas.FindResult, error)

func (*EmailClient) SearchEmail

func (m *EmailClient) SearchEmail(ctx context.Context, query string, opts eas.EmailSearchOptions) (*eas.EmailSearchResult, error)

func (*EmailClient) SearchEmailQuery

func (m *EmailClient) SearchEmailQuery(ctx context.Context, q eas.Query, opts eas.EmailSearchOptions) (*eas.EmailSearchResult, error)

func (*EmailClient) SendMail

func (m *EmailClient) SendMail(ctx context.Context, opts eas.SendMailOptions) error

func (*EmailClient) SmartForward

func (m *EmailClient) SmartForward(ctx context.Context, opts eas.ReplyForwardOptions) error

func (*EmailClient) SmartReply

func (m *EmailClient) SmartReply(ctx context.Context, opts eas.ReplyForwardOptions) error

func (*EmailClient) SyncEmail

func (m *EmailClient) SyncEmail(ctx context.Context, folderID string, opts eas.EmailSyncOptions) (*eas.EmailSyncResult, error)

type FolderClient

type FolderClient struct {
	FolderSyncFunc            func(ctx context.Context) (*eas.FolderSyncResult, error)
	FolderCreateFunc          func(ctx context.Context, parentID, displayName string, folderType eas.FolderType) (*eas.FolderCreateResult, error)
	FolderUpdateFunc          func(ctx context.Context, serverID, newParentID, newDisplayName string) error
	FolderDeleteFunc          func(ctx context.Context, serverID string) error
	GetItemEstimateFunc       func(ctx context.Context, folderIDs []string) ([]eas.ItemEstimate, error)
	MoveItemsFunc             func(ctx context.Context, srcFolder, dstFolder string, ids []string) ([]eas.MoveItemResult, error)
	MoveViaItemOperationsFunc func(ctx context.Context, srcFolder, srcID, dstFolder string, moveAlways bool) (string, error)
	EmptyFolderContentsFunc   func(ctx context.Context, folderID string, deleteSubfolders bool) error
	FetchAttachmentFunc       func(ctx context.Context, fileReference string, rangeStart, rangeEnd int64) (*eas.FetchAttachmentResult, error)
	FetchDocumentLibraryFunc  func(ctx context.Context, linkID string, rangeStart, rangeEnd int64) ([]byte, error)
}

FolderClient is a hand-written test double for eas.FolderClient.

func (*FolderClient) EmptyFolderContents

func (m *FolderClient) EmptyFolderContents(ctx context.Context, folderID string, deleteSubfolders bool) error

func (*FolderClient) FetchAttachment

func (m *FolderClient) FetchAttachment(ctx context.Context, fileReference string, rangeStart, rangeEnd int64) (*eas.FetchAttachmentResult, error)

func (*FolderClient) FetchDocumentLibrary

func (m *FolderClient) FetchDocumentLibrary(ctx context.Context, linkID string, rangeStart, rangeEnd int64) ([]byte, error)

func (*FolderClient) FolderCreate

func (m *FolderClient) FolderCreate(ctx context.Context, parentID, displayName string, folderType eas.FolderType) (*eas.FolderCreateResult, error)

func (*FolderClient) FolderDelete

func (m *FolderClient) FolderDelete(ctx context.Context, serverID string) error

func (*FolderClient) FolderSync

func (m *FolderClient) FolderSync(ctx context.Context) (*eas.FolderSyncResult, error)

func (*FolderClient) FolderUpdate

func (m *FolderClient) FolderUpdate(ctx context.Context, serverID, newParentID, newDisplayName string) error

func (*FolderClient) GetItemEstimate

func (m *FolderClient) GetItemEstimate(ctx context.Context, folderIDs []string) ([]eas.ItemEstimate, error)

func (*FolderClient) MoveItems

func (m *FolderClient) MoveItems(ctx context.Context, srcFolder, dstFolder string, ids []string) ([]eas.MoveItemResult, error)

func (*FolderClient) MoveViaItemOperations

func (m *FolderClient) MoveViaItemOperations(ctx context.Context, srcFolder, srcID, dstFolder string, moveAlways bool) (string, error)

type NotesClient

type NotesClient struct {
	SyncNotesFunc  func(ctx context.Context, folderID string) (*eas.NotesSyncResult, error)
	CreateNoteFunc func(ctx context.Context, folderID string, draft eas.NoteDraft) (string, error)
	UpdateNoteFunc func(ctx context.Context, folderID, serverID string, draft eas.NoteDraft) error
	DeleteNoteFunc func(ctx context.Context, folderID, serverID string) error
}

NotesClient is a hand-written test double for eas.NotesClient.

func (*NotesClient) CreateNote

func (m *NotesClient) CreateNote(ctx context.Context, folderID string, draft eas.NoteDraft) (string, error)

func (*NotesClient) DeleteNote

func (m *NotesClient) DeleteNote(ctx context.Context, folderID, serverID string) error

func (*NotesClient) SyncNotes

func (m *NotesClient) SyncNotes(ctx context.Context, folderID string) (*eas.NotesSyncResult, error)

func (*NotesClient) UpdateNote

func (m *NotesClient) UpdateNote(ctx context.Context, folderID, serverID string, draft eas.NoteDraft) error

type PingClient

type PingClient struct {
	PingFunc func(ctx context.Context, heartbeatSeconds int, folders []eas.PingFolder) (*eas.PingResult, error)
}

PingClient is a hand-written test double for eas.PingClient.

func (*PingClient) Ping

func (m *PingClient) Ping(ctx context.Context, heartbeatSeconds int, folders []eas.PingFolder) (*eas.PingResult, error)

type ProvisionClient

type ProvisionClient struct {
	ProvisionFunc             func(ctx context.Context) error
	AcknowledgeRemoteWipeFunc func(ctx context.Context, status int) error
	NegotiateVersionFunc      func(ctx context.Context) (string, error)
	OptionsFunc               func(ctx context.Context) (*eas.OptionsResult, error)
}

ProvisionClient is a hand-written test double for eas.ProvisionClient.

func (*ProvisionClient) AcknowledgeRemoteWipe

func (m *ProvisionClient) AcknowledgeRemoteWipe(ctx context.Context, status int) error

func (*ProvisionClient) NegotiateVersion

func (m *ProvisionClient) NegotiateVersion(ctx context.Context) (string, error)

func (*ProvisionClient) Options

func (m *ProvisionClient) Options(ctx context.Context) (*eas.OptionsResult, error)

func (*ProvisionClient) Provision

func (m *ProvisionClient) Provision(ctx context.Context) error

type SearchClient

type SearchClient struct {
	GALSearchFunc         func(ctx context.Context, query string, limit int) (*eas.GALSearchResult, error)
	ResolveRecipientsFunc func(ctx context.Context, recipients []string, opts eas.ResolveOptions) ([]eas.ResolveResponse, error)
	ValidateCertFunc      func(ctx context.Context, certs, chain [][]byte, checkCRL bool) ([]eas.CertValidation, error)
}

SearchClient is a hand-written test double for eas.SearchClient.

func (*SearchClient) GALSearch

func (m *SearchClient) GALSearch(ctx context.Context, query string, limit int) (*eas.GALSearchResult, error)

func (*SearchClient) ResolveRecipients

func (m *SearchClient) ResolveRecipients(ctx context.Context, recipients []string, opts eas.ResolveOptions) ([]eas.ResolveResponse, error)

func (*SearchClient) ValidateCert

func (m *SearchClient) ValidateCert(ctx context.Context, certs, chain [][]byte, checkCRL bool) ([]eas.CertValidation, error)

type SettingsClient

type SettingsClient struct {
	GetOofFunc                       func(ctx context.Context) (*eas.OofConfig, error)
	SetOofFunc                       func(ctx context.Context, cfg eas.OofConfig) error
	SetDevicePasswordFunc            func(ctx context.Context, newPassword string) error
	GetUserInformationFunc           func(ctx context.Context) (*eas.UserInformation, error)
	SettingsDeviceInformationFunc    func(ctx context.Context, info eas.DeviceInformation) error
	GetRightsManagementTemplatesFunc func(ctx context.Context) ([]eas.RightsTemplate, error)
}

SettingsClient is a hand-written test double for eas.SettingsClient.

func (*SettingsClient) GetOof

func (m *SettingsClient) GetOof(ctx context.Context) (*eas.OofConfig, error)

func (*SettingsClient) GetRightsManagementTemplates

func (m *SettingsClient) GetRightsManagementTemplates(ctx context.Context) ([]eas.RightsTemplate, error)

func (*SettingsClient) GetUserInformation

func (m *SettingsClient) GetUserInformation(ctx context.Context) (*eas.UserInformation, error)

func (*SettingsClient) SetDevicePassword

func (m *SettingsClient) SetDevicePassword(ctx context.Context, newPassword string) error

func (*SettingsClient) SetOof

func (m *SettingsClient) SetOof(ctx context.Context, cfg eas.OofConfig) error

func (*SettingsClient) SettingsDeviceInformation

func (m *SettingsClient) SettingsDeviceInformation(ctx context.Context, info eas.DeviceInformation) error

type TasksClient

type TasksClient struct {
	SyncTasksFunc    func(ctx context.Context, folderID string) (*eas.TasksSyncResult, error)
	CreateTaskFunc   func(ctx context.Context, folderID string, draft eas.TaskDraft) (string, error)
	UpdateTaskFunc   func(ctx context.Context, folderID, serverID string, draft eas.TaskDraft) error
	CompleteTaskFunc func(ctx context.Context, folderID, serverID string) error
	DeleteTaskFunc   func(ctx context.Context, folderID, serverID string) error
}

TasksClient is a hand-written test double for eas.TasksClient.

func (*TasksClient) CompleteTask

func (m *TasksClient) CompleteTask(ctx context.Context, folderID, serverID string) error

func (*TasksClient) CreateTask

func (m *TasksClient) CreateTask(ctx context.Context, folderID string, draft eas.TaskDraft) (string, error)

func (*TasksClient) DeleteTask

func (m *TasksClient) DeleteTask(ctx context.Context, folderID, serverID string) error

func (*TasksClient) SyncTasks

func (m *TasksClient) SyncTasks(ctx context.Context, folderID string) (*eas.TasksSyncResult, error)

func (*TasksClient) UpdateTask

func (m *TasksClient) UpdateTask(ctx context.Context, folderID, serverID string, draft eas.TaskDraft) error

Jump to

Keyboard shortcuts

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