Files

185 lines
6.3 KiB
Go

// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0 (the "License");
package main
import (
"context"
"errors"
"flag"
"go/format"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/app"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/cli"
"github.com/spf13/cobra"
)
func TestParamAliasGeneratorUsesDistributionOwnedCommandTree(t *testing.T) {
got := reflect.ValueOf(newParamAliasRoot).Pointer()
want := reflect.ValueOf(app.NewSchemaSourceRootCommand).Pointer()
if got != want {
t.Fatal("parameter alias generator must use the distribution-owned Schema source command tree")
}
}
func preserveParamAliasGeneratorGlobals(t *testing.T) {
t.Helper()
oldArgs, oldFlags := os.Args, flag.CommandLine
oldRoot := newParamAliasRoot
oldReduce := reduceParamAliasEntries
oldFormat := formatParamAliasSource
oldWrite := writeParamAliasFile
oldExit := exitParamAliasProcess
t.Cleanup(func() {
os.Args, flag.CommandLine = oldArgs, oldFlags
newParamAliasRoot = oldRoot
reduceParamAliasEntries = oldReduce
formatParamAliasSource = oldFormat
writeParamAliasFile = oldWrite
exitParamAliasProcess = oldExit
})
}
func repositoryRoot(t *testing.T) string {
t.Helper()
root, err := filepath.Abs(filepath.Join("..", "..", ".."))
if err != nil {
t.Fatal(err)
}
return root
}
func TestCrossPlatformCoverageParamAliasMainWritesGeneratedFile(t *testing.T) {
preserveParamAliasGeneratorGlobals(t)
output := filepath.Join(t.TempDir(), "param_aliases_generated.go")
flag.CommandLine = flag.NewFlagSet("param-alias-success", flag.ContinueOnError)
os.Args = []string{"cmd_param_aliases", "-root", repositoryRoot(t), "-output", output}
newParamAliasRoot = func(...context.Context) *cobra.Command { return &cobra.Command{Use: "dws"} }
reduceParamAliasEntries = func(*cobra.Command) ([]cli.ParamAliasEntry, error) {
return []cli.ParamAliasEntry{{CLIPath: "demo get", Aliases: map[string]string{"uid": "user"}}}, nil
}
main()
data, err := os.ReadFile(output)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(data), "func loadGeneratedParamAliases() []ParamAliasEntry") ||
!strings.Contains(string(data), `"uid": "user"`) {
t.Fatalf("generated source missing runtime table:\n%s", data)
}
}
func TestCrossPlatformCoverageParamAliasMainReportsFailure(t *testing.T) {
preserveParamAliasGeneratorGlobals(t)
flag.CommandLine = flag.NewFlagSet("param-alias-failure", flag.ContinueOnError)
os.Args = []string{
"cmd_param_aliases",
"-root", repositoryRoot(t),
"-output", filepath.Join(repositoryRoot(t), "internal", "cli", "param_concepts.json"),
}
exitParamAliasProcess = func(code int) { panic(code) }
defer func() {
if recovered := recover(); recovered != 1 {
t.Fatalf("main exit = %#v, want 1", recovered)
}
}()
main()
}
func TestGenerateParamAliasesFailurePaths(t *testing.T) {
preserveParamAliasGeneratorGlobals(t)
root := repositoryRoot(t)
output := filepath.Join(t.TempDir(), "param_aliases_generated.go")
newParamAliasRoot = func(...context.Context) *cobra.Command { return &cobra.Command{Use: "dws"} }
if err := generateParamAliases(root, filepath.Join(root, "internal", "cli", "param_concepts.json")); err == nil {
t.Fatal("generateParamAliases accepted an output that overlaps a reviewed input")
}
reduceParamAliasEntries = func(*cobra.Command) ([]cli.ParamAliasEntry, error) {
return nil, errors.New("reduce")
}
if err := generateParamAliases(root, output); err == nil || !strings.Contains(err.Error(), "reduce") {
t.Fatalf("reduction error = %v", err)
}
reduceParamAliasEntries = func(*cobra.Command) ([]cli.ParamAliasEntry, error) { return nil, nil }
formatParamAliasSource = func([]byte) ([]byte, error) { return nil, errors.New("format") }
if err := generateParamAliases(root, output); err == nil || !strings.Contains(err.Error(), "format generated") {
t.Fatalf("format error = %v", err)
}
formatParamAliasSource = format.Source
writeParamAliasFile = func(string, []byte, os.FileMode) error { return errors.New("write") }
if err := generateParamAliases(root, output); err == nil || !strings.Contains(err.Error(), "write generated") {
t.Fatalf("write error = %v", err)
}
}
func TestValidateParamAliasOutputIsolation(t *testing.T) {
root := repositoryRoot(t)
if err := validateOutputIsolation(root, filepath.Join(t.TempDir(), "aliases.go")); err != nil {
t.Fatalf("temporary output rejected: %v", err)
}
if err := validateOutputIsolation(root, filepath.Join(root, "internal", "cli", "not_a_delivery_target.go")); err == nil ||
!strings.Contains(err.Error(), "not a canonical generated delivery target") {
t.Fatalf("non-canonical repository output error = %v", err)
}
}
func TestRenderParamAliasesDeterministicShape(t *testing.T) {
preserveParamAliasGeneratorGlobals(t)
entries := []cli.ParamAliasEntry{
{
CLIPath: "demo get",
Aliases: map[string]string{"z-name": "name", "a-name": "name"},
Blocked: []string{"page", "count"},
Ambiguous: []string{"user-id"},
},
{CLIPath: "demo empty"},
}
data, err := renderParamAliases(entries)
if err != nil {
t.Fatal(err)
}
text := string(data)
if strings.Index(text, `"a-name": "name"`) > strings.Index(text, `"z-name": "name"`) {
t.Fatalf("alias keys are not sorted:\n%s", text)
}
for _, want := range []string{
"func loadGeneratedParamAliases() []ParamAliasEntry",
`Blocked: []string{"page", "count"}`,
`Ambiguous: []string{"user-id"}`,
`CLIPath: "demo empty"`,
} {
if !strings.Contains(text, want) {
t.Fatalf("generated source missing %q:\n%s", want, text)
}
}
empty, err := renderParamAliases(nil)
if err != nil || !strings.Contains(string(empty), "var generatedParamAliases = []ParamAliasEntry{") {
t.Fatalf("empty render = %q, error = %v", empty, err)
}
if got := renderStringSlice(nil); got != "[]string{}" {
t.Fatalf("renderStringSlice(nil) = %q", got)
}
if got := sortedKeys(nil); len(got) != 0 {
t.Fatalf("sortedKeys(nil) = %v", got)
}
if got := sortedKeys(map[string]string{"b": "2", "a": "1"}); !reflect.DeepEqual(got, []string{"a", "b"}) {
t.Fatalf("sortedKeys() = %v", got)
}
formatParamAliasSource = func([]byte) ([]byte, error) { return nil, errors.New("broken formatter") }
if _, err := renderParamAliases(entries); err == nil || !strings.Contains(err.Error(), "broken formatter") {
t.Fatalf("formatter error = %v", err)
}
}