180 lines
6.4 KiB
Go
180 lines
6.4 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
package helpers
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/output"
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func TestCrossPlatformCoverageFramework2HelperOutputEdges(t *testing.T) {
|
|
if err := writeCommandPayload(nil, map[string]any{"ok": true}); err != nil {
|
|
t.Fatalf("nil command payload: %v", err)
|
|
}
|
|
|
|
cmd := &cobra.Command{Use: "output"}
|
|
var stdout, stderr bytes.Buffer
|
|
cmd.SetOut(&stdout)
|
|
cmd.SetErr(&stderr)
|
|
if err := writeEnvelope(cmd, output.NewSuccessEnvelope(map[string]any{"id": "x"})); err != nil {
|
|
t.Fatalf("success envelope: %v", err)
|
|
}
|
|
if !strings.Contains(stdout.String(), `"outcome": "success"`) {
|
|
t.Fatalf("stdout=%q", stdout.String())
|
|
}
|
|
if err := writeEnvelope(nil, nil); err != nil {
|
|
t.Fatalf("nil failure envelope: %v", err)
|
|
}
|
|
|
|
f := NewFormatterWithWriters(nil, nil)
|
|
if f.w != os.Stdout || f.errW != os.Stderr {
|
|
t.Fatalf("nil writers did not use process defaults")
|
|
}
|
|
var nextOut, nextErr bytes.Buffer
|
|
f.SetWriters(&nextOut, nil)
|
|
f.SetWriters(nil, &nextErr)
|
|
if f.w != &nextOut || f.errW != &nextErr {
|
|
t.Fatalf("SetWriters did not replace each non-nil side")
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageFramework2MCPDataEdges(t *testing.T) {
|
|
original := deps
|
|
t.Cleanup(func() { deps = original })
|
|
|
|
InitDeps(&coverageErrorCaller{result: &edition.ToolResult{Content: []edition.ContentBlock{{Type: "text", Text: `{"id":"x"}`}}}})
|
|
data, err := CallMCPToolDataOnServer(nil, "dev", "get_thing", nil)
|
|
if err != nil || data.(map[string]any)["id"] != "x" {
|
|
t.Fatalf("decoded data=%#v err=%v", data, err)
|
|
}
|
|
|
|
InitDeps(&coverageErrorCaller{result: &edition.ToolResult{Content: []edition.ContentBlock{{Type: "text", Text: `{"count":7}`}}}})
|
|
data, err = CallMCPToolDataOnServer(context.Background(), "dev", "get_thing", nil)
|
|
if err != nil || data.(map[string]any)["count"] != float64(7) {
|
|
t.Fatalf("legacy float64 number data=%#v err=%v", data, err)
|
|
}
|
|
|
|
InitDeps(&coverageErrorCaller{err: errors.New("transport failed")})
|
|
if _, err := CallMCPToolDataOnServer(context.Background(), "dev", "get_thing", nil); err == nil {
|
|
t.Fatal("expected transport error")
|
|
}
|
|
|
|
InitDeps(&coverageErrorCaller{result: &edition.ToolResult{Content: []edition.ContentBlock{{Type: "text", Text: " "}}}})
|
|
data, err = CallMCPToolDataOnServer(context.Background(), "dev", "get_thing", nil)
|
|
if err != nil || len(data.(map[string]any)) != 0 {
|
|
t.Fatalf("empty response data=%#v err=%v", data, err)
|
|
}
|
|
|
|
InitDeps(&coverageErrorCaller{result: &edition.ToolResult{Content: []edition.ContentBlock{{Type: "text", Text: "{"}}}})
|
|
if _, err := CallMCPToolDataOnServer(context.Background(), "dev", "get_thing", nil); err == nil {
|
|
t.Fatal("expected invalid JSON error")
|
|
}
|
|
|
|
InitDeps(&coverageErrorCaller{result: &edition.ToolResult{Content: []edition.ContentBlock{{Type: "text", Text: `{} {}`}}}})
|
|
if _, err := CallMCPToolDataOnServer(context.Background(), "dev", "get_thing", nil); err == nil || !strings.Contains(err.Error(), "存在多个 JSON 值") {
|
|
t.Fatalf("multiple JSON values error = %v", err)
|
|
}
|
|
|
|
InitDeps(&coverageErrorCaller{result: &edition.ToolResult{Content: []edition.ContentBlock{{Type: "text", Text: `{} {`}}}})
|
|
if _, err := CallMCPToolDataOnServer(context.Background(), "dev", "get_thing", nil); err == nil || !strings.Contains(err.Error(), "解析 get_thing 返回失败") {
|
|
t.Fatalf("trailing invalid JSON error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageFramework2LegacyTextAdapter(t *testing.T) {
|
|
original := deps
|
|
t.Cleanup(func() { deps = original })
|
|
caller := &coverageErrorCaller{}
|
|
InitDeps(caller)
|
|
var stdout bytes.Buffer
|
|
deps.Out = NewFormatterWithWriters(&stdout, &bytes.Buffer{})
|
|
if err := RenderLegacyMCPText("get_thing", `{"id":"x"}`); err != nil {
|
|
t.Fatalf("RenderLegacyMCPText: %v", err)
|
|
}
|
|
if !strings.Contains(stdout.String(), `"id": "x"`) {
|
|
t.Fatalf("stdout=%q", stdout.String())
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageFramework2LeafResultEdges(t *testing.T) {
|
|
mustPanic := func(name string, fn func()) {
|
|
t.Helper()
|
|
defer func() {
|
|
if recover() == nil {
|
|
t.Fatalf("%s: expected panic", name)
|
|
}
|
|
}()
|
|
fn()
|
|
}
|
|
resultCall := func(*cobra.Command, string, map[string]any) (output.CommandResult, error) {
|
|
return output.Success(map[string]any{"ok": true}), nil
|
|
}
|
|
mustPanic("metadata result call", func() {
|
|
DeclareLeafMetadata(&cobra.Command{Use: "meta"}, LeafSpec{ResultCall: resultCall})
|
|
})
|
|
mustPanic("two call styles", func() {
|
|
FromLeafSpec(LeafSpec{Use: "both", Call: func(*cobra.Command, string, map[string]any) error { return nil }, ResultCall: resultCall})
|
|
})
|
|
|
|
cmd := prepareUnifiedTestCommand(NewLeafCommand(LeafSpec{
|
|
Use: "result", Tool: "get_thing", OutputRollout: output.RolloutUnifiedActive, ResultCall: resultCall,
|
|
}))
|
|
cmd.SetOut(&bytes.Buffer{})
|
|
if err := cmd.Execute(); err != nil {
|
|
t.Fatalf("ResultCall command: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageFramework2DevDocRemainsLegacy(t *testing.T) {
|
|
cmd := newDevDocSearchCommand()
|
|
if got := output.CommandRollout(cmd); got != output.RolloutLegacyOnly {
|
|
t.Fatalf("dev doc rollout=%s, want legacy_only", got)
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageFramework2ConnectLegacyEdges(t *testing.T) {
|
|
original := connectDaemonDirOverride
|
|
t.Cleanup(func() { connectDaemonDirOverride = original })
|
|
|
|
blocked := filepath.Join(t.TempDir(), "blocked")
|
|
if err := os.WriteFile(blocked, []byte("x"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
connectDaemonDirOverride = blocked
|
|
stop := newDevAppRobotConnectStopCommand()
|
|
stop.Flags().Bool("yes", true, "")
|
|
if err := stop.Flags().Set("robot-client-id", "ding-test"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := stop.RunE(stop, nil); err == nil {
|
|
t.Fatal("expected daemon directory error")
|
|
}
|
|
|
|
connectDaemonDirOverride = t.TempDir()
|
|
list := newDevAppRobotConnectListCommand(nil)
|
|
output.SetCommandRollout(list, output.RolloutLegacyOnly)
|
|
if list.Flags().Lookup("format") == nil {
|
|
list.Flags().String("format", "table", "")
|
|
} else if err := list.Flags().Set("format", "table"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var stdout bytes.Buffer
|
|
list.SetOut(&stdout)
|
|
if err := list.RunE(list, nil); err != nil {
|
|
t.Fatalf("legacy list: %v", err)
|
|
}
|
|
if !strings.Contains(stdout.String(), "no connectors found") {
|
|
t.Fatalf("stdout=%q", stdout.String())
|
|
}
|
|
}
|