package channel_test import ( "fmt" "testing" "github.com/memohai/memoh/internal/channel" ) const testChannelType = channel.ChannelType("test-config") // testConfigAdapter implements Adapter, ConfigNormalizer, TargetResolver, BindingMatcher for tests. type testConfigAdapter struct{} func (a *testConfigAdapter) Type() channel.ChannelType { return testChannelType } func (a *testConfigAdapter) Descriptor() channel.Descriptor { return channel.Descriptor{ Type: testChannelType, DisplayName: "Test", Capabilities: channel.ChannelCapabilities{ Text: true, }, ConfigSchema: channel.ConfigSchema{ Version: 1, Fields: map[string]channel.FieldSchema{ "value": {Type: channel.FieldString, Required: true}, }, }, UserConfigSchema: channel.ConfigSchema{ Version: 1, Fields: map[string]channel.FieldSchema{ "user": {Type: channel.FieldString, Required: true}, }, }, } } func (a *testConfigAdapter) NormalizeConfig(raw map[string]any) (map[string]any, error) { value := channel.ReadString(raw, "value") if value == "" { return nil, fmt.Errorf("value is required") } return map[string]any{"value": value}, nil } func (a *testConfigAdapter) NormalizeUserConfig(raw map[string]any) (map[string]any, error) { value := channel.ReadString(raw, "user") if value == "" { return nil, fmt.Errorf("user is required") } return map[string]any{"user": value}, nil } func (a *testConfigAdapter) NormalizeTarget(raw string) string { return raw } func (a *testConfigAdapter) ResolveTarget(raw map[string]any) (string, error) { value := channel.ReadString(raw, "target") if value == "" { return "", fmt.Errorf("target is required") } return "resolved:" + value, nil } func (a *testConfigAdapter) MatchBinding(raw map[string]any, criteria channel.BindingCriteria) bool { value := channel.ReadString(raw, "user") return value != "" && value == criteria.SubjectID } func (a *testConfigAdapter) BuildUserConfig(identity channel.Identity) map[string]any { return map[string]any{} } func newTestConfigRegistry() *channel.Registry { reg := channel.NewRegistry() reg.MustRegister(&testConfigAdapter{}) return reg } func TestParseChannelType(t *testing.T) { t.Parallel() reg := newTestConfigRegistry() got, err := reg.ParseChannelType(" test-config ") if err != nil { t.Fatalf("expected no error, got %v", err) } if got != testChannelType { t.Fatalf("unexpected channel type: %s", got) } if _, err := reg.ParseChannelType("unknown"); err == nil { t.Fatalf("expected error, got nil") } } func TestNormalizeChannelConfig(t *testing.T) { t.Parallel() reg := newTestConfigRegistry() got, err := reg.NormalizeConfig(testChannelType, map[string]any{"value": "ok"}) if err != nil { t.Fatalf("expected no error, got %v", err) } if got["value"] != "ok" { t.Fatalf("unexpected value: %#v", got["value"]) } } func TestNormalizeChannelConfigRequiresValue(t *testing.T) { t.Parallel() reg := newTestConfigRegistry() _, err := reg.NormalizeConfig(testChannelType, map[string]any{}) if err == nil { t.Fatalf("expected error, got nil") } } func TestNormalizeChannelUserConfig(t *testing.T) { t.Parallel() reg := newTestConfigRegistry() got, err := reg.NormalizeUserConfig(testChannelType, map[string]any{"user": "alice"}) if err != nil { t.Fatalf("expected no error, got %v", err) } if got["user"] != "alice" { t.Fatalf("unexpected user: %#v", got["user"]) } } func TestNormalizeChannelUserConfigRequiresUser(t *testing.T) { t.Parallel() reg := newTestConfigRegistry() _, err := reg.NormalizeUserConfig(testChannelType, map[string]any{}) if err == nil { t.Fatalf("expected error, got nil") } }