diff --git a/shortcuts/common/typed_shortcut.go b/shortcuts/common/typed_shortcut.go index 238f5fe0e..0b692fac7 100644 --- a/shortcuts/common/typed_shortcut.go +++ b/shortcuts/common/typed_shortcut.go @@ -97,12 +97,6 @@ func (s TypedShortcut[T]) DeclaredScopesForIdentity(identity string) []string { return out } -// Mount registers the typed shortcut on a parent command. Delegates to -// MountWithContext using a background context. -func (s TypedShortcut[T]) Mount(parent *cobra.Command, f *cmdutil.Factory) { - s.MountWithContext(context.Background(), parent, f) -} - // MountWithContext is implemented in Task 16's adapter section. func (s TypedShortcut[T]) MountWithContext(ctx context.Context, parent *cobra.Command, f *cmdutil.Factory) { mountTyped[T](ctx, parent, f, s) diff --git a/shortcuts/common/typed_shortcut_test.go b/shortcuts/common/typed_shortcut_test.go index b9c9f3042..b8328b03e 100644 --- a/shortcuts/common/typed_shortcut_test.go +++ b/shortcuts/common/typed_shortcut_test.go @@ -5,6 +5,7 @@ package common import ( "context" + "slices" "testing" "github.com/spf13/cobra" @@ -86,3 +87,76 @@ func TestMountTyped_HelpFuncInstalled(t *testing.T) { t.Fatal("expected typed help func installed on subcommand") } } + +func TestTypedShortcut_GetAuthTypes(t *testing.T) { + ts := TypedShortcut[*stubArgs]{AuthTypes: []string{"user", "bot"}} + if got := ts.GetAuthTypes(); !slices.Equal(got, []string{"user", "bot"}) { + t.Errorf("GetAuthTypes=%v", got) + } + if got := (TypedShortcut[*stubArgs]{}).GetAuthTypes(); got != nil { + t.Errorf("empty GetAuthTypes=%v, want nil", got) + } +} + +func TestTypedShortcut_ScopesForIdentity(t *testing.T) { + ts := TypedShortcut[*stubArgs]{ + Scopes: []string{"base"}, + UserScopes: []string{"u"}, + BotScopes: []string{"b"}, + } + cases := []struct { + identity string + want []string + }{ + {"user", []string{"u"}}, + {"bot", []string{"b"}}, + {"other", []string{"base"}}, + {"", []string{"base"}}, + } + for _, c := range cases { + if got := ts.ScopesForIdentity(c.identity); !slices.Equal(got, c.want) { + t.Errorf("ScopesForIdentity(%q)=%v, want %v", c.identity, got, c.want) + } + } + // Falls back to Scopes when the identity-specific list is empty. + fallback := TypedShortcut[*stubArgs]{Scopes: []string{"base"}} + if got := fallback.ScopesForIdentity("user"); !slices.Equal(got, []string{"base"}) { + t.Errorf("fallback user=%v", got) + } +} + +func TestTypedShortcut_ConditionalScopesForIdentity(t *testing.T) { + ts := TypedShortcut[*stubArgs]{ + ConditionalScopes: []string{"cbase"}, + ConditionalUserScopes: []string{"cu"}, + ConditionalBotScopes: []string{"cb"}, + } + cases := []struct { + identity string + want []string + }{ + {"user", []string{"cu"}}, + {"bot", []string{"cb"}}, + {"other", []string{"cbase"}}, + } + for _, c := range cases { + if got := ts.ConditionalScopesForIdentity(c.identity); !slices.Equal(got, c.want) { + t.Errorf("ConditionalScopesForIdentity(%q)=%v, want %v", c.identity, got, c.want) + } + } +} + +func TestTypedShortcut_DeclaredScopesForIdentity(t *testing.T) { + // Merges base + conditional, dedupes overlap, drops empty strings. + ts := TypedShortcut[*stubArgs]{ + UserScopes: []string{"a", "b", ""}, + ConditionalUserScopes: []string{"b", "c"}, + } + if got := ts.DeclaredScopesForIdentity("user"); !slices.Equal(got, []string{"a", "b", "c"}) { + t.Errorf("merge+dedupe got %v", got) + } + // Returns nil when nothing is declared on either side. + if got := (TypedShortcut[*stubArgs]{}).DeclaredScopesForIdentity("user"); got != nil { + t.Errorf("empty got %v, want nil", got) + } +}