Files
dingtalk-workspace-cli/internal/cli/param_aliases_test.go

687 lines
26 KiB
Go

// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
package cli
import (
"errors"
"reflect"
"strings"
"testing"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/testseam"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/cmdutil"
"github.com/spf13/cobra"
)
// realMap builds a per-leaf real-flag table keyed by the shared Morph so the
// tests exercise exactly the same intersection the generator performs.
func realMap(flags ...realFlag) map[string][]realFlag {
m := make(map[string][]realFlag)
for _, f := range flags {
k := cmdutil.Morph(f.name)
m[k] = appendRealFlag(m[k], f)
}
return m
}
// conceptFixture is a small synthetic concept set; reduceLeafParamAliases is
// deliberately pure so it can be tested without the whole Cobra tree.
func conceptFixture() []Concept {
return []Concept{
{ID: "pagination_size", CanonicalHint: "limit", Members: []string{"limit", "size", "page-size", "max-results"}},
{ID: "base_id", CanonicalHint: "base-id", Members: []string{"base", "base-id", "base-token"}},
{ID: "user_id", CanonicalHint: "user-id", Members: []string{"user", "users", "user-id", "uid"}},
}
}
func useParamConceptLoader(t *testing.T, concepts ParamConcepts, err error) {
t.Helper()
testseam.Swap(t, &loadReviewedParamConcepts, func() (ParamConcepts, error) { return concepts, err })
}
func TestReduceParamAliasesLoadsAndValidatesSourceTree(t *testing.T) {
t.Run("load failure", func(t *testing.T) {
useParamConceptLoader(t, ParamConcepts{}, errors.New("fixture load"))
if _, err := ReduceParamAliases(&cobra.Command{Use: "dws"}); err == nil || !strings.Contains(err.Error(), "fixture load") {
t.Fatalf("ReduceParamAliases() error = %v", err)
}
})
t.Run("nil root", func(t *testing.T) {
useParamConceptLoader(t, ParamConcepts{Version: 1}, nil)
if _, err := ReduceParamAliases(nil); err == nil || !strings.Contains(err.Error(), "root is nil") {
t.Fatalf("ReduceParamAliases(nil) error = %v", err)
}
})
t.Run("real tree", func(t *testing.T) {
concepts := ParamConcepts{
Version: 1,
Concepts: []Concept{
{ID: "query", Members: []string{"query", "keyword"}, Commands: []string{"demo run"}},
{ID: "user_id", Members: []string{"user-id", "uid"}, Commands: []string{"demo run"}},
},
Overrides: []CommandOverride{
{CommandPath: "alpha", Block: []string{"unsafe"}},
{CommandPath: "demo run", Bind: map[string]string{"id": "user_id"}},
},
}
useParamConceptLoader(t, concepts, nil)
root := &cobra.Command{Use: "dws"}
alpha := &cobra.Command{Use: "alpha", Run: func(*cobra.Command, []string) {}}
alpha.Flags().String("name", "", "name")
demo := &cobra.Command{Use: "demo", Run: func(*cobra.Command, []string) {}}
run := &cobra.Command{Use: "run", Run: func(*cobra.Command, []string) {}}
run.Flags().String("query", "", "query")
run.Flags().String("id", "", "id")
demo.AddCommand(run)
root.AddCommand(alpha, demo)
root.AddCommand(&cobra.Command{Use: "help", Run: func(*cobra.Command, []string) {}})
root.AddCommand(&cobra.Command{Use: "hidden", Hidden: true, Run: func(*cobra.Command, []string) {}})
entries, err := ReduceParamAliases(root)
if err != nil {
t.Fatalf("ReduceParamAliases() error = %v", err)
}
if len(entries) != 2 || entries[0].CLIPath != "alpha" || entries[1].CLIPath != "demo run" {
t.Fatalf("entries = %#v", entries)
}
if entries[1].Aliases["keyword"] != "query" || entries[1].Aliases["uid"] != "id" {
t.Fatalf("demo aliases = %#v", entries[1].Aliases)
}
})
t.Run("stale and unbound review inputs", func(t *testing.T) {
concepts := ParamConcepts{
Version: 1,
Concepts: []Concept{
{ID: "missing", Members: []string{"missing"}, Commands: []string{"demo run"}},
{ID: "stale", Members: []string{"stale"}, Commands: []string{"ghost run"}},
},
Overrides: []CommandOverride{{CommandPath: "ghost run", Block: []string{"unsafe"}}},
}
useParamConceptLoader(t, concepts, nil)
root := &cobra.Command{Use: "dws"}
demo := &cobra.Command{Use: "demo"}
run := &cobra.Command{Use: "run", Run: func(*cobra.Command, []string) {}}
run.Flags().String("query", "", "query")
demo.AddCommand(run)
root.AddCommand(demo)
_, err := ReduceParamAliases(root)
for _, want := range []string{"has no matching real flag", "does not match any runnable Cobra leaf", "does not match any runnable Cobra command"} {
if err == nil || !strings.Contains(err.Error(), want) {
t.Fatalf("ReduceParamAliases() error = %v, want %q", err, want)
}
}
})
}
func TestParamAliasHelperEdges(t *testing.T) {
walkRunnableParamCommands(nil, func(*cobra.Command) { t.Fatal("nil root was visited") })
helpOnly := &cobra.Command{Use: "demo"}
helpOnly.Flags().String("help", "", "help")
if got := realFlagsByMorph(helpOnly); len(got) != 0 {
t.Fatalf("help flag entered the real parameter table: %#v", got)
}
flags := []realFlag{{name: "same", hidden: true}}
flags = appendRealFlag(flags, realFlag{name: "same"})
if len(flags) != 1 || flags[0].hidden {
t.Fatalf("visible duplicate did not replace hidden registration: %#v", flags)
}
flags = appendRealFlag(flags, realFlag{name: "same", hidden: true})
if len(flags) != 1 || flags[0].hidden {
t.Fatalf("hidden duplicate replaced visible registration: %#v", flags)
}
flags = appendRealFlag(flags, realFlag{name: "alpha"})
if !reflect.DeepEqual([]string{flags[0].name, flags[1].name}, []string{"alpha", "same"}) {
t.Fatalf("new real flags are not sorted: %#v", flags)
}
candidates := []realFlag{{name: "hidden", hidden: true}, {name: "visible"}, {name: "visible"}}
if got := distinctRealNames(candidates, true); !reflect.DeepEqual(got, []string{"visible"}) {
t.Fatalf("visible names = %v", got)
}
if got := canonicalRealName([]realFlag{{name: "hidden", hidden: true}}); got != "hidden" {
t.Fatalf("hidden-only canonical = %q", got)
}
if got := canonicalRealName(nil); got != "" {
t.Fatalf("empty canonical = %q", got)
}
if got := sortedUnique(nil); got != nil {
t.Fatalf("sortedUnique(nil) = %#v", got)
}
if got := sortedUnique([]string{"b", "a", "b"}); !reflect.DeepEqual(got, []string{"a", "b"}) {
t.Fatalf("sortedUnique() = %v", got)
}
real := realMap(realFlag{name: "query"}, realFlag{name: "id"})
if !conceptHasRealFlag(Concept{ID: "query", Members: []string{"query"}}, CommandOverride{}, real) {
t.Fatal("concept member did not match a real flag")
}
if !conceptHasRealFlag(Concept{ID: "user", Members: []string{"user-id"}}, CommandOverride{Bind: map[string]string{"id": "user"}}, real) {
t.Fatal("reviewed bind did not match a real flag")
}
if conceptHasRealFlag(Concept{ID: "user", Members: []string{"user-id"}}, CommandOverride{Bind: map[string]string{"missing": "user"}}, real) {
t.Fatal("missing reviewed bind matched a real flag")
}
}
func TestReduceLeafParamAliasesRemainingEdges(t *testing.T) {
t.Run("pending reviewed bind blocks non-real members", func(t *testing.T) {
entry, problems := reduceLeafParamAliases(
"demo cmd",
realMap(realFlag{name: "id"}),
[]Concept{{ID: "user_id", Members: []string{"user-id", "uid"}}},
CommandOverride{Bind: map[string]string{"id": "user_id"}, Investigate: true},
)
if len(problems) != 0 || entry == nil ||
!containsParamAlias(entry.Blocked, "user-id") || !containsParamAlias(entry.Blocked, "uid") {
t.Fatalf("pending bind entry = %#v, problems = %v", entry, problems)
}
})
t.Run("hidden-only canonical", func(t *testing.T) {
entry, problems := reduceLeafParamAliases(
"demo cmd",
realMap(realFlag{name: "query", hidden: true}),
[]Concept{{ID: "query", Members: []string{"query", "keyword"}}},
CommandOverride{},
)
if len(problems) != 0 || entry == nil || entry.Aliases["keyword"] != "query" {
t.Fatalf("hidden-only entry = %#v, problems = %v", entry, problems)
}
})
t.Run("multiple hidden candidates stay unresolved", func(t *testing.T) {
entry, problems := reduceLeafParamAliases(
"demo cmd",
realMap(realFlag{name: "first", hidden: true}, realFlag{name: "second", hidden: true}),
[]Concept{{ID: "choice", Members: []string{"first", "second", "choice"}}},
CommandOverride{},
)
if len(problems) != 0 || entry != nil {
t.Fatalf("multiple hidden candidates entry = %#v, problems = %v", entry, problems)
}
})
t.Run("two concepts cannot claim one emitted spelling", func(t *testing.T) {
_, problems := reduceLeafParamAliases(
"demo cmd",
realMap(realFlag{name: "first"}, realFlag{name: "second"}),
[]Concept{
{ID: "first", Members: []string{"first", "shared"}},
{ID: "second", Members: []string{"second", "shared"}},
},
CommandOverride{},
)
if len(problems) == 0 || !strings.Contains(strings.Join(problems, "\n"), "reduces to both") {
t.Fatalf("alias collision problems = %v", problems)
}
})
t.Run("unclaimed exclude becomes blocked", func(t *testing.T) {
entry, problems := reduceLeafParamAliases(
"demo cmd",
realMap(realFlag{name: "query"}),
[]Concept{{ID: "query", Members: []string{"query", "keyword"}, Excludes: []string{"name"}}},
CommandOverride{},
)
if len(problems) != 0 || entry == nil || !containsParamAlias(entry.Blocked, "name") {
t.Fatalf("exclude entry = %#v, problems = %v", entry, problems)
}
})
}
func TestCrossPlatformCoverageReduceLeafParamAliasesBindExcludesRealFlags(t *testing.T) {
entry, problems := reduceLeafParamAliases(
"demo cmd",
realMap(realFlag{name: "id"}, realFlag{name: "name"}, realFlag{name: "query"}),
[]Concept{
{ID: "base_id", Members: []string{"base-id", "base-token"}, Excludes: []string{"keyword", "name", "query", "unsafe"}},
{ID: "query", Members: []string{"query", "keyword"}},
},
CommandOverride{Bind: map[string]string{"id": "base_id"}},
)
if len(problems) != 0 {
t.Fatalf("reduceLeafParamAliases() problems = %v", problems)
}
if entry == nil {
t.Fatal("reduceLeafParamAliases() entry = nil")
}
if entry.Aliases["base-id"] != "id" || entry.Aliases["base-token"] != "id" {
t.Fatalf("bound aliases = %#v, want base-id/base-token -> id", entry.Aliases)
}
if entry.Aliases["keyword"] != "query" {
t.Fatalf("query alias = %#v, want keyword -> query", entry.Aliases)
}
if containsParamAlias(entry.Blocked, "keyword") {
t.Fatalf("excluded alias entered blocked list: %#v", entry.Blocked)
}
if containsParamAlias(entry.Blocked, "name") {
t.Fatalf("real excluded flag entered blocked list: %#v", entry.Blocked)
}
if containsParamAlias(entry.Blocked, "query") {
t.Fatalf("claimed real excluded flag entered blocked list: %#v", entry.Blocked)
}
if !containsParamAlias(entry.Blocked, "unsafe") {
t.Fatalf("non-real excluded flag was not blocked: %#v", entry.Blocked)
}
}
func TestParamAliasEntryLookupMethods(t *testing.T) {
entry := ParamAliasEntry{
Aliases: map[string]string{"uid": "user"},
Blocked: []string{"count"},
Ambiguous: []string{"user-id"},
}
if got, ok := entry.ResolveAlias("uid"); !ok || got != "user" {
t.Fatalf("ResolveAlias(uid) = %q, %v", got, ok)
}
if _, ok := entry.ResolveAlias("missing"); ok {
t.Fatal("ResolveAlias(missing) unexpectedly matched")
}
if !entry.IsBlocked("count") || entry.IsBlocked("missing") {
t.Fatalf("blocked lookup mismatch: %#v", entry.Blocked)
}
if !entry.IsAmbiguous("user-id") || entry.IsAmbiguous("missing") {
t.Fatalf("ambiguous lookup mismatch: %#v", entry.Ambiguous)
}
}
func TestReduceLeafParamAliasesAutoReduction(t *testing.T) {
entry, problems := reduceLeafParamAliases("demo cmd", realMap(realFlag{name: "limit"}), conceptFixture(), CommandOverride{})
if len(problems) != 0 {
t.Fatalf("unexpected problems: %v", problems)
}
if entry == nil {
t.Fatal("expected a reduced entry")
}
for _, emitted := range []string{"size", "page-size", "max-results"} {
if entry.Aliases[emitted] != "limit" {
t.Fatalf("alias %q = %q, want limit", emitted, entry.Aliases[emitted])
}
}
if _, ok := entry.Aliases["limit"]; ok {
t.Fatal("the real flag limit must never be an alias key")
}
}
func TestReduceLeafParamAliasesCoOccurrenceRequiresReview(t *testing.T) {
_, problems := reduceLeafParamAliases("demo cmd",
realMap(realFlag{name: "user"}, realFlag{name: "users"}), conceptFixture(), CommandOverride{})
if len(problems) == 0 {
t.Fatal("two visible real flags for one concept must fail without a reviewed ambiguous whitelist")
}
}
func TestReduceLeafParamAliasesAmbiguousWhitelist(t *testing.T) {
entry, problems := reduceLeafParamAliases("demo cmd",
realMap(realFlag{name: "user"}, realFlag{name: "users"}), conceptFixture(),
CommandOverride{CommandPath: "demo cmd", Ambiguous: []string{"user-id", "uid"}})
if len(problems) != 0 {
t.Fatalf("unexpected problems: %v", problems)
}
if entry == nil {
t.Fatal("expected a reduced entry")
}
if _, ok := entry.Aliases["user-id"]; ok {
t.Fatal("a reviewed co-occurrence must not auto-reduce its concept members")
}
if len(entry.Ambiguous) != 2 || entry.Ambiguous[0] != "uid" || entry.Ambiguous[1] != "user-id" {
t.Fatalf("ambiguous = %v, want sorted [uid user-id]", entry.Ambiguous)
}
}
// TestReduceLeafParamAliasesCoOccurrencePerConcept locks the per-concept guard:
// reviewing one concept's co-occurrence must not silently vouch for a second,
// unreviewed co-occurring concept on the same command. Here user_id (user +
// users) is whitelisted while base_id (base + base-id) is not, so base_id's
// unreviewed emittable member base-token must still fail generation.
func TestReduceLeafParamAliasesCoOccurrencePerConcept(t *testing.T) {
real := realMap(
realFlag{name: "user"}, realFlag{name: "users"},
realFlag{name: "base"}, realFlag{name: "base-id"},
)
_, problems := reduceLeafParamAliases("demo cmd", real, conceptFixture(),
CommandOverride{CommandPath: "demo cmd", Ambiguous: []string{"user-id", "uid"}})
if len(problems) == 0 {
t.Fatal("an unreviewed second co-occurring concept must fail even when another concept is whitelisted")
}
found := false
for _, p := range problems {
if strings.Contains(p, `concept "base_id"`) {
found = true
}
}
if !found {
t.Fatalf("expected a problem naming the unreviewed base_id concept, got: %v", problems)
}
}
// TestReduceLeafParamAliasesCoOccurrenceBothReviewed confirms the per-concept
// guard passes once every co-occurring concept's emittable members are listed.
func TestReduceLeafParamAliasesCoOccurrenceBothReviewed(t *testing.T) {
real := realMap(
realFlag{name: "user"}, realFlag{name: "users"},
realFlag{name: "base"}, realFlag{name: "base-id"},
)
_, problems := reduceLeafParamAliases("demo cmd", real, conceptFixture(),
CommandOverride{CommandPath: "demo cmd", Ambiguous: []string{"user-id", "uid", "base-token"}})
if len(problems) != 0 {
t.Fatalf("both concepts reviewed should pass: %v", problems)
}
}
// TestReduceLeafParamAliasesRejectsAliasAmbiguousOverlap locks the guard that a
// single name cannot be both auto-reduced and marked ambiguous. Here only
// --users is real, so user_id auto-reduces user-id to users; hand-listing
// user-id as ambiguous would produce a self-contradictory entry.
func TestReduceLeafParamAliasesRejectsAliasAmbiguousOverlap(t *testing.T) {
_, problems := reduceLeafParamAliases("demo cmd",
realMap(realFlag{name: "users"}), conceptFixture(),
CommandOverride{CommandPath: "demo cmd", Ambiguous: []string{"user-id"}})
if len(problems) == 0 {
t.Fatal("a name that both auto-reduces and is listed ambiguous must fail")
}
}
func TestReduceLeafParamAliasesAbsorbsHiddenLegacyAlias(t *testing.T) {
entry, problems := reduceLeafParamAliases("demo cmd",
realMap(realFlag{name: "base-id"}, realFlag{name: "base", hidden: true}), conceptFixture(), CommandOverride{})
if len(problems) != 0 {
t.Fatalf("a hidden legacy alias flag must not be a co-occurrence: %v", problems)
}
if entry == nil {
t.Fatal("expected a reduced entry")
}
if entry.Aliases["base-token"] != "base-id" {
t.Fatalf("base-token = %q, want base-id", entry.Aliases["base-token"])
}
if _, ok := entry.Aliases["base"]; ok {
t.Fatal("a real (hidden) flag must never be an alias key")
}
}
func TestReduceLeafParamAliasesBindGenericFlag(t *testing.T) {
entry, problems := reduceLeafParamAliases("demo cmd", realMap(realFlag{name: "id"}), conceptFixture(),
CommandOverride{CommandPath: "demo cmd", Bind: map[string]string{"id": "base_id"}})
if len(problems) != 0 {
t.Fatalf("unexpected problems: %v", problems)
}
if entry.Aliases["base"] != "id" || entry.Aliases["base-id"] != "id" || entry.Aliases["base-token"] != "id" {
t.Fatalf("bind reduction wrong: %#v", entry.Aliases)
}
}
func TestReduceLeafParamAliasesBindRejectsNonRealFlag(t *testing.T) {
_, problems := reduceLeafParamAliases("demo cmd", realMap(realFlag{name: "id"}), conceptFixture(),
CommandOverride{CommandPath: "demo cmd", Bind: map[string]string{"missing": "base_id"}})
if len(problems) == 0 {
t.Fatal("binding a non-real flag must fail")
}
}
func TestReduceLeafParamAliasesScopedAlias(t *testing.T) {
entry, problems := reduceLeafParamAliases("demo cmd", realMap(realFlag{name: "id"}), conceptFixture(),
CommandOverride{CommandPath: "demo cmd", ScopedAliases: map[string]string{"ding-id": "id"}})
if len(problems) != 0 {
t.Fatalf("unexpected problems: %v", problems)
}
if entry == nil || entry.Aliases[cmdutil.Morph("ding-id")] != "id" {
t.Fatalf("scoped alias not applied: %#v", entry)
}
}
func TestReduceLeafParamAliasesScopedAliasRejectsNonRealTarget(t *testing.T) {
_, problems := reduceLeafParamAliases("demo cmd", realMap(realFlag{name: "id"}), conceptFixture(),
CommandOverride{CommandPath: "demo cmd", ScopedAliases: map[string]string{"foo": "nonexistent"}})
if len(problems) == 0 {
t.Fatal("a scoped alias onto a non-real flag must fail")
}
}
func TestReduceLeafParamAliasesBlockRemovesAndRecords(t *testing.T) {
entry, problems := reduceLeafParamAliases("demo cmd", realMap(realFlag{name: "limit"}), conceptFixture(),
CommandOverride{CommandPath: "demo cmd", Block: []string{"size"}})
if len(problems) != 0 {
t.Fatalf("unexpected problems: %v", problems)
}
if entry == nil {
t.Fatal("expected a reduced entry")
}
if _, ok := entry.Aliases["size"]; ok {
t.Fatal("a blocked emitted name must be removed from the alias map")
}
found := false
for _, b := range entry.Blocked {
if b == "size" {
found = true
}
}
if !found {
t.Fatalf("size not recorded in blocked: %v", entry.Blocked)
}
}
func TestReduceLeafParamAliasesPendingReviewDoesNotEmit(t *testing.T) {
entry, problems := reduceLeafParamAliases("demo cmd", realMap(realFlag{name: "query"}), nil,
CommandOverride{CommandPath: "demo cmd", ScopedAliases: map[string]string{"keyword": "query"}, Confirm: true})
if len(problems) != 0 {
t.Fatalf("unexpected problems: %v", problems)
}
if entry == nil || entry.Aliases["keyword"] != "" || !containsParamAlias(entry.Blocked, "keyword") {
t.Fatalf("pending mapping entered automatic aliases: %#v", entry)
}
}
func TestReduceLeafParamAliasesExcludesProtectFuzzyButDoNotOverrideAnotherConcept(t *testing.T) {
concepts := []Concept{
{ID: "page_number", Members: []string{"page", "page-no"}, Excludes: []string{"page-size"}},
{ID: "page_size", Members: []string{"limit", "page-size"}},
}
entry, problems := reduceLeafParamAliases("demo cmd", realMap(realFlag{name: "page"}, realFlag{name: "limit"}), concepts, CommandOverride{})
if len(problems) != 0 {
t.Fatalf("unexpected problems: %v", problems)
}
if entry.Aliases["page-size"] != "limit" || containsParamAlias(entry.Blocked, "page-size") {
t.Fatalf("another reviewed concept alias was overridden by an exclude: %#v", entry)
}
}
func TestReduceLeafParamAliasesExcludesDoNotBlockRealFlag(t *testing.T) {
concepts := []Concept{
{ID: "single_id", Members: []string{"id", "item-id"}, Excludes: []string{"item-ids"}},
}
entry, problems := reduceLeafParamAliases("demo cmd", realMap(realFlag{name: "id"}, realFlag{name: "item-ids"}), concepts, CommandOverride{})
if len(problems) != 0 {
t.Fatalf("unexpected problems: %v", problems)
}
if entry == nil {
t.Fatal("expected a reduced entry")
}
if containsParamAlias(entry.Blocked, "item-ids") {
t.Fatalf("real exclude was blocked: %#v", entry)
}
}
func TestReduceLeafParamAliasesRejectsProtectionOrScopedAliasOnRealFlag(t *testing.T) {
real := realMap(realFlag{name: "user-id"}, realFlag{name: "user"})
for name, override := range map[string]CommandOverride{
"block": {CommandPath: "demo cmd", Block: []string{"user-id"}},
"ambiguous": {CommandPath: "demo cmd", Ambiguous: []string{"user-id"}},
"scoped": {CommandPath: "demo cmd", ScopedAliases: map[string]string{"user-id": "user"}},
} {
t.Run(name, func(t *testing.T) {
if _, problems := reduceLeafParamAliases("demo cmd", real, nil, override); len(problems) == 0 {
t.Fatal("real native flag was allowed to be reclassified")
}
})
}
}
func TestGeneratedParamAliasesBlockPluralListSpellingsOnSingleIDCommands(t *testing.T) {
entries := make(map[string]ParamAliasEntry, len(generatedParamAliases))
for _, entry := range generatedParamAliases {
entries[entry.CLIPath] = entry
}
assertBlocked := func(path string, names ...string) {
t.Helper()
entry, ok := entries[path]
if !ok {
t.Fatalf("missing generated alias entry for %q", path)
}
for _, name := range names {
if !entry.IsBlocked(cmdutil.Morph(name)) {
t.Fatalf("%s: %q not blocked; entry = %#v", path, name, entry)
}
}
}
for _, path := range []string{
"chat message add-emoji",
"chat message remove-emoji",
"chat message add-text-emotion",
"chat message remove-text-emotion",
} {
assertBlocked(path, "msg-ids", "message-ids")
}
for _, path := range []string{
"chat message send",
"chat conversation-info",
"chat category add-conv",
"chat category remove-conv",
"chat message list",
"chat message list-mentions",
"chat message recall-by-bot",
"chat message search",
} {
assertBlocked(path, "conversation-ids")
}
}
func TestGeneratedParamAliasesKeepAuditJoinUserRoleAmbiguous(t *testing.T) {
entry, ok := LookupParamAlias("chat group audit-join-validation")
if !ok {
t.Fatal("missing generated alias entry for chat group audit-join-validation")
}
for _, name := range []string{"user", "user-id", "userid", "uid", "staff-id"} {
if !entry.IsAmbiguous(cmdutil.Morph(name)) {
t.Fatalf("%q not ambiguous; entry = %#v", name, entry)
}
}
}
// TestGeneratedParamAliasesAreWellFormed guards the committed generated table
// at the Go level, complementing the byte-identity drift gate.
func TestGeneratedParamAliasesAreWellFormed(t *testing.T) {
if len(generatedParamAliases) == 0 {
t.Fatal("generated parameter alias table is empty")
}
seen := make(map[string]bool, len(generatedParamAliases))
for _, e := range generatedParamAliases {
if e.CLIPath == "" {
t.Fatal("generated entry has an empty CLIPath")
}
if seen[e.CLIPath] {
t.Fatalf("duplicate CLIPath %q in generated table", e.CLIPath)
}
seen[e.CLIPath] = true
for emitted, canon := range e.Aliases {
if emitted != cmdutil.Morph(emitted) {
t.Fatalf("%s: alias key %q is not morph-normalized", e.CLIPath, emitted)
}
if canon == "" {
t.Fatalf("%s: alias %q has an empty target", e.CLIPath, emitted)
}
if emitted == canon {
t.Fatalf("%s: alias %q maps to itself", e.CLIPath, emitted)
}
}
classified := make(map[string]string, len(e.Aliases)+len(e.Blocked)+len(e.Ambiguous))
for emitted := range e.Aliases {
classified[emitted] = "alias"
}
for kind, values := range map[string][]string{"blocked": e.Blocked, "ambiguous": e.Ambiguous} {
for _, name := range values {
if name != cmdutil.Morph(name) {
t.Fatalf("%s: %s name %q is not morph-normalized", e.CLIPath, kind, name)
}
if previous := classified[name]; previous != "" {
t.Fatalf("%s: %q is classified as both %s and %s", e.CLIPath, name, previous, kind)
}
classified[name] = kind
}
}
}
}
func TestCrossPlatformCoveragePublishedSpaceWorkspaceAliasesRemainExecutable(t *testing.T) {
docCommands := []string{
"doc +access-change",
"doc +access-grant",
"doc +access-revoke",
"doc +copy",
"doc +create",
"doc +create-from-template",
"doc +grant-and-share",
"doc +import",
"doc +list",
"doc +move",
"doc create",
"doc file create",
"doc import",
"doc template apply",
}
for _, command := range docCommands {
entry, ok := LookupParamAlias(command)
if !ok {
t.Errorf("published Doc command %q has no generated parameter-alias entry", command)
continue
}
for _, emitted := range []string{"space", "space-id"} {
target, active := entry.ResolveAlias(emitted)
if !active || target != "workspace" {
t.Errorf("%s --%s resolution = active:%v target:%q, want --workspace", command, emitted, active, target)
}
if entry.IsBlocked(emitted) || entry.IsAmbiguous(emitted) {
t.Errorf("%s --%s remains protected after restoring its published alias", command, emitted)
}
}
}
driveInfo, ok := LookupParamAlias("drive info")
if !ok {
t.Fatal("published drive info command has no generated parameter-alias entry")
}
for _, emitted := range []string{"space", "workspace", "workspace-id"} {
target, active := driveInfo.ResolveAlias(emitted)
if !active || target != "space-id" {
t.Errorf("drive info --%s resolution = active:%v target:%q, want --space-id", emitted, active, target)
}
if driveInfo.IsBlocked(emitted) || driveInfo.IsAmbiguous(emitted) {
t.Errorf("drive info --%s remains protected after restoring its published alias", emitted)
}
}
// Compatibility remains exact-path scoped. Strong type spellings introduced
// after the split continue to guard the two value domains elsewhere.
for _, test := range []struct {
command string
emitted string
}{
{command: "doc create", emitted: "storage-space-id"},
{command: "drive +upload", emitted: "workspace-id"},
{command: "drive info", emitted: "knowledge-base-id"},
} {
entry, ok := LookupParamAlias(test.command)
if !ok || !entry.IsBlocked(test.emitted) {
t.Errorf("%s --%s must remain blocked outside the published compatibility set", test.command, test.emitted)
}
}
}