mirror of
https://github.com/lukaszraczylo/harness-sync.git
synced 2026-10-14 00:57:49 +00:00
feat(adapter): registry with detect filtering and duplicate guard
This commit is contained in:
@@ -3,6 +3,7 @@ package adapter
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/lukaszraczylo/harness-sync/internal/canonical"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -23,3 +24,37 @@ func TestKindString(t *testing.T) {
|
||||
assert.Equal(t, "rendered", RenderedFile.String())
|
||||
assert.Equal(t, "symlink-file", SymlinkFile.String())
|
||||
}
|
||||
|
||||
type fakeAdapter struct {
|
||||
name string
|
||||
detect bool
|
||||
}
|
||||
|
||||
func (f *fakeAdapter) Name() string { return f.name }
|
||||
func (f *fakeAdapter) Detect() bool { return f.detect }
|
||||
func (f *fakeAdapter) Render(_ *canonical.Bundle) (*FileSet, error) { return NewFileSet(), nil }
|
||||
func (f *fakeAdapter) Import(_ string) (*ImportResult, error) { return &ImportResult{}, nil }
|
||||
|
||||
func TestRegistry(t *testing.T) {
|
||||
r := NewRegistry()
|
||||
a := &fakeAdapter{name: "a", detect: true}
|
||||
b := &fakeAdapter{name: "b", detect: false}
|
||||
r.Register(a)
|
||||
r.Register(b)
|
||||
|
||||
assert.Equal(t, []string{"a", "b"}, r.Names())
|
||||
assert.Equal(t, []string{"a"}, r.DetectedNames())
|
||||
|
||||
got, ok := r.Get("a")
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "a", got.Name())
|
||||
|
||||
_, ok = r.Get("missing")
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
func TestRegistryDuplicatePanics(t *testing.T) {
|
||||
r := NewRegistry()
|
||||
r.Register(&fakeAdapter{name: "x"})
|
||||
assert.Panics(t, func() { r.Register(&fakeAdapter{name: "x"}) })
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package adapter
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Registry holds adapters in registration order.
|
||||
type Registry struct {
|
||||
byName map[string]Adapter
|
||||
order []string
|
||||
}
|
||||
|
||||
// NewRegistry returns an empty Registry.
|
||||
func NewRegistry() *Registry {
|
||||
return &Registry{byName: map[string]Adapter{}}
|
||||
}
|
||||
|
||||
// Register adds a to the registry. Panics on duplicate name.
|
||||
func (r *Registry) Register(a Adapter) {
|
||||
if _, exists := r.byName[a.Name()]; exists {
|
||||
panic(fmt.Sprintf("adapter %q already registered", a.Name()))
|
||||
}
|
||||
r.byName[a.Name()] = a
|
||||
r.order = append(r.order, a.Name())
|
||||
}
|
||||
|
||||
// Names returns adapter names in registration order.
|
||||
func (r *Registry) Names() []string {
|
||||
out := make([]string, len(r.order))
|
||||
copy(out, r.order)
|
||||
return out
|
||||
}
|
||||
|
||||
// DetectedNames returns names of adapters whose Detect() returns true.
|
||||
func (r *Registry) DetectedNames() []string {
|
||||
var out []string
|
||||
for _, n := range r.order {
|
||||
if r.byName[n].Detect() {
|
||||
out = append(out, n)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Get returns the adapter for name and whether it was found.
|
||||
func (r *Registry) Get(name string) (Adapter, bool) {
|
||||
a, ok := r.byName[name]
|
||||
return a, ok
|
||||
}
|
||||
|
||||
// All returns adapters in registration order.
|
||||
func (r *Registry) All() []Adapter {
|
||||
out := make([]Adapter, 0, len(r.order))
|
||||
for _, n := range r.order {
|
||||
out = append(out, r.byName[n])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Default is the process-global registry used by main(). Tests should
|
||||
// construct their own Registry via NewRegistry to avoid global state.
|
||||
var Default = NewRegistry()
|
||||
Reference in New Issue
Block a user