🎨 Formatted exists repositories with dummy, stub and spy for entry

This commit is contained in:
Maxim Lebedev 2023-10-12 20:10:40 +06:00
parent 67c8df843d
commit c7dc4d027d
Signed by: toby3d
GPG Key ID: 1F14E25B7C119FC5
4 changed files with 151 additions and 21 deletions

View File

@ -17,9 +17,129 @@ type (
Update(ctx context.Context, path string, update UpdateFunc) (*domain.Entry, error)
Delete(ctx context.Context, path string) (bool, error)
}
dummyRepository struct{}
stubRepository struct {
outputs []domain.Entry
output *domain.Entry
err error
ok bool
}
spyRepository struct {
subRepository Repository
Calls int
Creates int
Deletes int
Fetches int
Gets int
Updates int
}
// NOTE(toby3d): fakeRepository is already provided by memory sub-package.
// NOTE(toby3d): mockRepository is complicated. Mocking too much is bad.
)
var (
ErrExist error = errors.New("this entry already exist")
ErrNotExist error = errors.New("this entry is not exist")
)
// NewDummyMediaRepository creates an empty repository to satisfy contracts.
// It is used in tests where repository working is not important.
func NewDummyEntryRepository() Repository {
return &dummyRepository{}
}
func (dummyRepository) Create(_ context.Context, _ string, _ domain.Entry) error { return nil }
func (dummyRepository) Delete(_ context.Context, _ string) (bool, error) { return false, nil }
func (dummyRepository) Get(_ context.Context, _ string) (*domain.Entry, error) { return nil, nil }
func (dummyRepository) Fetch(_ context.Context, _ string) ([]domain.Entry, int, error) {
return make([]domain.Entry, 0), 0, nil
}
func (dummyRepository) Update(_ context.Context, _ string, _ UpdateFunc) (*domain.Entry, error) {
return nil, nil
}
// NewStubEntryRepository creates a repository that always returns input as a
// output. It is used in tests where some dependency on the repository is
// required.
func NewStubEntryRepository(outputs []domain.Entry, output *domain.Entry, err error, ok bool) Repository {
return &stubRepository{
outputs: outputs,
output: output,
err: err,
ok: ok,
}
}
func (repo *stubRepository) Create(_ context.Context, _ string, _ domain.Entry) error {
return repo.err
}
func (repo *stubRepository) Delete(ctx context.Context, path string) (bool, error) {
return repo.ok, repo.err
}
func (repo *stubRepository) Fetch(ctx context.Context, path string) ([]domain.Entry, int, error) {
return repo.outputs, len(repo.outputs), repo.err
}
func (repo *stubRepository) Get(ctx context.Context, path string) (*domain.Entry, error) {
return repo.output, repo.err
}
func (repo *stubRepository) Update(ctx context.Context, path string, update UpdateFunc) (*domain.Entry, error) {
return repo.output, repo.err
}
// NewSpyEntryRepository creates a spy repository which count outside calls,
// based on provided subRepo. If subRepo is nil, then DummyRepository will be
// used.
func NewSpyEntryRepository(subRepo Repository) *spyRepository {
if subRepo == nil {
subRepo = NewDummyEntryRepository()
}
return &spyRepository{
subRepository: subRepo,
Creates: 0,
Updates: 0,
Gets: 0,
Fetches: 0,
Deletes: 0,
}
}
func (repo *spyRepository) Create(ctx context.Context, path string, e domain.Entry) error {
repo.Creates++
return repo.subRepository.Create(ctx, path, e)
}
func (repo *spyRepository) Delete(ctx context.Context, path string) (bool, error) {
repo.Deletes++
return repo.subRepository.Delete(ctx, path)
}
func (repo *spyRepository) Fetch(ctx context.Context, path string) ([]domain.Entry, int, error) {
repo.Fetches++
return repo.subRepository.Fetch(ctx, path)
}
func (repo *spyRepository) Get(ctx context.Context, path string) (*domain.Entry, error) {
repo.Gets++
return repo.subRepository.Get(ctx, path)
}
func (repo *spyRepository) Update(ctx context.Context, path string, update UpdateFunc) (*domain.Entry, error) {
repo.Updates++
return repo.subRepository.Update(ctx, path, update)
}

View File

@ -8,6 +8,12 @@ import (
)
type (
UpdateOptions struct {
Add *domain.Entry
Replace *domain.Entry
Delete *domain.Entry
}
UseCase interface {
// Create creates a new entry. Returns map or rel links, like Permalink
// or created post, shortcode and syndication.
@ -16,7 +22,7 @@ type (
// Update updates exist entry properties on provided u.
//
// TODO(toby3d): return Location header if entry updates their URL.
Update(ctx context.Context, u *url.URL, e domain.Entry) (*domain.Entry, error)
Update(ctx context.Context, u *url.URL, options UpdateOptions) (*domain.Entry, error)
// Delete destroy entry on provided URL.
Delete(ctx context.Context, u *url.URL) (bool, error)
@ -41,17 +47,17 @@ func NewDummyUseCase() *dummyUseCase {
return &dummyUseCase{}
}
func (dummyUseCase) Create(ctx context.Context, e domain.Entry) (map[string]*url.URL, error) {
func (dummyUseCase) Create(_ context.Context, _ domain.Entry) (map[string]*url.URL, error) {
return nil, nil
}
func (dummyUseCase) Update(ctx context.Context, u *url.URL, e domain.Entry) (*domain.Entry, error) {
func (dummyUseCase) Update(_ context.Context, _ *url.URL, _ UpdateOptions) (*domain.Entry, error) {
return nil, nil
}
func (dummyUseCase) Delete(ctx context.Context, u *url.URL) (bool, error) { return false, nil }
func (dummyUseCase) Undelete(ctx context.Context, u *url.URL) (*domain.Entry, error) { return nil, nil }
func (dummyUseCase) Source(ctx context.Context, u *url.URL) (*domain.Entry, error) { return nil, nil }
func (dummyUseCase) Delete(_ context.Context, _ *url.URL) (bool, error) { return false, nil }
func (dummyUseCase) Undelete(_ context.Context, _ *url.URL) (*domain.Entry, error) { return nil, nil }
func (dummyUseCase) Source(_ context.Context, _ *url.URL) (*domain.Entry, error) { return nil, nil }
func NewStubUseCase(err error, e *domain.Entry, ok bool) *stubUseCase {
return &stubUseCase{
@ -61,22 +67,22 @@ func NewStubUseCase(err error, e *domain.Entry, ok bool) *stubUseCase {
}
}
func (ucase *stubUseCase) Create(ctx context.Context, e domain.Entry) (*domain.Entry, error) {
func (ucase *stubUseCase) Create(_ context.Context, _ domain.Entry) (*domain.Entry, error) {
return ucase.entry, ucase.err
}
func (ucase *stubUseCase) Update(ctx context.Context, u *url.URL, e domain.Entry) (*domain.Entry, error) {
func (ucase *stubUseCase) Update(_ context.Context, _ *url.URL, _ UpdateOptions) (*domain.Entry, error) {
return ucase.entry, ucase.err
}
func (ucase *stubUseCase) Delete(ctx context.Context, u *url.URL) (bool, error) {
func (ucase *stubUseCase) Delete(_ context.Context, _ *url.URL) (bool, error) {
return ucase.ok, ucase.err
}
func (ucase *stubUseCase) Undelete(ctx context.Context, u *url.URL) (*domain.Entry, error) {
func (ucase *stubUseCase) Undelete(_ context.Context, _ *url.URL) (*domain.Entry, error) {
return ucase.entry, ucase.err
}
func (ucase *stubUseCase) Source(ctx context.Context, u *url.URL) (*domain.Entry, error) {
func (ucase *stubUseCase) Source(_ context.Context, _ *url.URL) (*domain.Entry, error) {
return ucase.entry, ucase.err
}

View File

@ -73,14 +73,18 @@ func (ucase *entryUseCase) Undelete(ctx context.Context, u *url.URL) (*domain.En
}
// Update implements entry.UseCase.
func (ucase *entryUseCase) Update(ctx context.Context, u *url.URL, e domain.Entry) (*domain.Entry, error) {
func (ucase *entryUseCase) Update(ctx context.Context, u *url.URL, opts entry.UpdateOptions) (*domain.Entry, error) {
result, err := ucase.entries.Update(ctx, u.RequestURI(), func(_ context.Context, e *domain.Entry) (
*domain.Entry, error,
) {
e.DeletedAt = time.Time{}
e.UpdatedAt = time.Now().UTC()
return nil, nil
// TODO(toby3d): add
// TODO(toby3d): update
// TODO(toby3d): delete
return e, nil
})
if err != nil {
return nil, fmt.Errorf("cannot update entry: %w", err)

View File

@ -107,26 +107,26 @@ func NewSpyMediaRepository(subRepo Repository) *spyRepository {
}
}
func (repo *spyRepository) Create(_ context.Context, _ string, _ domain.File) error {
func (repo *spyRepository) Create(ctx context.Context, path string, f domain.File) error {
repo.Creates++
return repo.subRepository.Create(context.TODO(), "", domain.File{})
return repo.subRepository.Create(ctx, path, f)
}
func (repo *spyRepository) Get(_ context.Context, _ string) (*domain.File, error) {
func (repo *spyRepository) Get(ctx context.Context, path string) (*domain.File, error) {
repo.Gets++
return repo.subRepository.Get(context.TODO(), "")
return repo.subRepository.Get(ctx, path)
}
func (repo *spyRepository) Update(_ context.Context, _ string, _ UpdateFunc) error {
func (repo *spyRepository) Update(ctx context.Context, path string, update UpdateFunc) error {
repo.Updates++
return repo.subRepository.Update(context.TODO(), "", nil)
return repo.subRepository.Update(ctx, path, update)
}
func (repo *spyRepository) Delete(_ context.Context, _ string) error {
func (repo *spyRepository) Delete(ctx context.Context, path string) error {
repo.Deletes++
return repo.subRepository.Delete(context.TODO(), "")
return repo.subRepository.Delete(ctx, path)
}