Files
dingtalk-workspace-cli/internal/helpers/whiteboard_coverage_test.go

311 lines
11 KiB
Go

package helpers
import (
"bytes"
"context"
"encoding/json"
"errors"
"os"
"path/filepath"
"strings"
"testing"
"github.com/spf13/cobra"
)
func TestWhiteboardInjectedEncodingFailures(t *testing.T) {
previousMarshal := whiteboardJSONMarshal
whiteboardJSONMarshal = func(any) ([]byte, error) { return nil, errors.New("marshal") }
if got := buildWhiteboardCardJSONML("b", "w"); got != "" {
t.Fatalf("got %q", got)
}
whiteboardJSONMarshal = previousMarshal
previousPrepare := prepareWhiteboardCard
prepareWhiteboardCard = func(*cobra.Command, string) (string, error) { return "", errors.New("prepare") }
t.Cleanup(func() { prepareWhiteboardCard = previousPrepare })
caller := &whiteboardTestCaller{}
installWhiteboardTestCaller(t, caller)
cmd := newDocWhiteboardCommand()
cmd.SetArgs([]string{"insert", "--node", "n", "--yes"})
if err := cmd.Execute(); err == nil || !strings.Contains(err.Error(), "模板未通过") {
t.Fatalf("err=%v", err)
}
previousCompact := compactWhiteboardJSON
compactWhiteboardJSON = func(*bytes.Buffer, []byte) error { return errors.New("compact") }
t.Cleanup(func() { compactWhiteboardJSON = previousCompact })
if _, _, err := validateWhiteboardNodes(json.RawMessage(`[{"id":"n"}]`)); err == nil {
t.Fatal("expected compact error")
}
}
func TestDocWhiteboardInsertDryRun(t *testing.T) {
caller := &whiteboardTestCaller{dry: true}
installWhiteboardTestCaller(t, caller)
cmd := newDocWhiteboardCommand()
cmd.SetArgs([]string{"insert", "--node", "n"})
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}
}
func writeWhiteboardFixture(t *testing.T, content string) string {
t.Helper()
path := filepath.Join(t.TempDir(), "whiteboard.json")
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
t.Fatal(err)
}
return path
}
func TestLoadWhiteboardUpdateFileRejectsInvalidInputs(t *testing.T) {
tests := []struct {
name string
content string
}{
{name: "invalid json", content: `{`},
{name: "trailing value", content: `{}` + ` {}`},
{name: "missing source", content: `{}`},
{name: "schema version", content: `{"source":{"schemaVersion":"2.0","catalogVersion":"dml-v1","nodes":[]}}`},
{name: "catalog version", content: `{"source":{"schemaVersion":"1.0","catalogVersion":"v2","nodes":[]}}`},
{name: "nodes missing", content: `{"source":{"schemaVersion":"1.0","catalogVersion":"dml-v1"}}`},
{name: "nodes malformed", content: `{"source":{"schemaVersion":"1.0","catalogVersion":"dml-v1","nodes":[}}`},
{name: "node primitive", content: `{"source":{"schemaVersion":"1.0","catalogVersion":"dml-v1","nodes":[1]}}`},
{name: "append empty", content: `{"source":{"schemaVersion":"1.0","catalogVersion":"dml-v1","nodes":[]}}`},
{name: "unknown field", content: `{"unknown":true}`},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if _, _, err := loadWhiteboardUpdateFile(writeWhiteboardFixture(t, test.content)); err == nil {
t.Fatal("expected validation error")
}
})
}
if _, _, err := loadWhiteboardUpdateFile(filepath.Join(t.TempDir(), "missing.json")); err == nil {
t.Fatal("expected missing-file error")
}
if _, _, err := loadWhiteboardUpdateFile(t.TempDir()); err == nil {
t.Fatal("expected directory read error")
}
if _, _, err := validateWhiteboardNodes(json.RawMessage(`[`)); err == nil {
t.Fatal("expected malformed nodes array error")
}
input, nodes, err := loadWhiteboardUpdateFile(writeWhiteboardFixture(t,
`{"overwrite":true,"source":{"schemaVersion":"1.0","catalogVersion":"dml-v1","nodes":[]}}`))
if err != nil || !input.Overwrite || nodes != "[]" {
t.Fatalf("input=%#v nodes=%q err=%v", input, nodes, err)
}
}
func TestWhiteboardOutputFiltersAndToolResponseErrors(t *testing.T) {
for _, name := range []string{"jq", "fields"} {
t.Run(name, func(t *testing.T) {
cmd := &cobra.Command{Use: "test"}
cmd.Flags().String(name, "", "")
if err := cmd.Flags().Set(name, ".result"); err != nil {
t.Fatal(err)
}
if err := rejectWhiteboardOutputFilters(cmd); err == nil {
t.Fatal("expected rejected output filter")
}
})
}
responses := []string{
`{`,
`{} {}`,
`null`,
`{"resultJson":"{"}`,
`{"resultJson":"{} {}"}`,
}
for _, response := range responses {
caller := &whiteboardTestCaller{format: "json", response: func(whiteboardTestCall, int) string { return response }}
installWhiteboardTestCaller(t, caller)
if err := callWhiteboardTool(&cobra.Command{}, whiteboardQueryTool, nil); err == nil {
t.Fatalf("response %q should fail", response)
}
}
caller := &whiteboardTestCaller{dry: true}
installWhiteboardTestCaller(t, caller)
if err := callWhiteboardTool(&cobra.Command{}, whiteboardQueryTool, map[string]any{"partId": "p"}); err != nil {
t.Fatal(err)
}
caller = &whiteboardTestCaller{response: func(whiteboardTestCall, int) string { return "" }}
installWhiteboardTestCaller(t, caller)
if err := callWhiteboardTool(&cobra.Command{}, whiteboardQueryTool, nil); err != nil {
t.Fatal(err)
}
}
func TestWhiteboardDocumentQueryValidation(t *testing.T) {
tests := []struct {
name string
response string
attrs bool
}{
{name: "invalid response", response: `{`},
{name: "missing block", response: `{"blocks":[]}`},
{name: "non object block", response: `{"blocks":[1]}`},
{name: "invalid jsonml", response: `{"blocks":[{"blockId":"b","jsonml":"{"}]}`},
{name: "missing attrs", response: `{"blocks":[{"blockId":"b","jsonml":"[]"}]}`, attrs: true},
{name: "attrs not object", response: `{"blocks":[{"blockId":"b","jsonml":"[\"card\",1]"}]}`, attrs: true},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
caller := &whiteboardTestCaller{response: func(whiteboardTestCall, int) string { return test.response }}
installWhiteboardTestCaller(t, caller)
var err error
if test.attrs {
_, err = queryWhiteboardCardAttrs(context.Background(), "n", "b")
} else {
_, err = queryWhiteboardCardNode(context.Background(), "n", "b")
}
if err == nil {
t.Fatal("expected query validation error")
}
})
}
caller := &whiteboardTestCaller{err: func(whiteboardTestCall, int) error { return errors.New("boom") }}
installWhiteboardTestCaller(t, caller)
if _, err := queryWhiteboardCardNode(context.Background(), "n", "b"); err == nil {
t.Fatal("expected caller error")
}
}
func TestWhiteboardCommandValidationBranches(t *testing.T) {
caller := &whiteboardTestCaller{format: "json"}
installWhiteboardTestCaller(t, caller)
for _, args := range [][]string{
{"query", "--node", "n"},
{"query", "--node", "n", "--part-id", "p", "--jq", "."},
{"update", "--node", "n", "--part-id", "p"},
{"update", "--node", "n", "--part-id", "p", "--fields", "result"},
} {
cmd := newWhiteboardCommand()
cmd.PersistentFlags().String("jq", "", "")
cmd.PersistentFlags().String("fields", "", "")
cmd.SetArgs(args)
if err := cmd.Execute(); err == nil {
t.Fatalf("args %v should fail", args)
}
}
}
func TestWhiteboardUpdateOverwriteAndSourceErrors(t *testing.T) {
caller := &whiteboardTestCaller{format: "json"}
installWhiteboardTestCaller(t, caller)
cmd := newWhiteboardCommand()
cmd.SetArgs([]string{"update", "--node", "n", "--part-id", "p", "--source", writeWhiteboardFixture(t,
`{"overwrite":true,"source":{"schemaVersion":"1.0","catalogVersion":"dml-v1","nodes":[]}}`), "--yes"})
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}
if caller.calls[0].args["mode"] != "overwrite" {
t.Fatalf("args=%#v", caller.calls[0].args)
}
cmd = newWhiteboardCommand()
cmd.SetArgs([]string{"update", "--node", "n", "--part-id", "p", "--source", filepath.Join(t.TempDir(), "missing")})
if err := cmd.Execute(); err == nil {
t.Fatal("expected source error")
}
}
func TestDocMediaUploadValidationAndSuccess(t *testing.T) {
caller := &whiteboardTestCaller{response: func(whiteboardTestCall, int) string {
return `{"uploadUrl":"https://upload.example.test/token","resourceId":"r","resourceUrl":"https://resource.example.test/icon"}`
}}
installWhiteboardTestCaller(t, caller)
previousPut := httpPutFile
httpPutFile = func(context.Context, string, map[string]string, string, int64) error { return nil }
t.Cleanup(func() { httpPutFile = previousPut })
file := writeWhiteboardFixture(t, "svg")
cmd := newDocCommand()
cmd.SetArgs([]string{"media", "upload", "--node", "n", "--file", file, "--name", "icon", "--mime-type", "image/custom", "--yes"})
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}
if caller.calls[0].args["fileName"] != "icon.json" || caller.calls[0].args["mimeType"] != "image/custom" {
t.Fatalf("args=%#v", caller.calls[0].args)
}
for _, args := range [][]string{
{"media", "upload", "--node", "n"},
{"media", "upload", "--node", "n", "--file", filepath.Join(t.TempDir(), "missing")},
{"media", "upload", "--node", "n", "--file", t.TempDir()},
} {
cmd = newDocCommand()
cmd.SetArgs(args)
if err := cmd.Execute(); err == nil {
t.Fatalf("args %v should fail", args)
}
}
}
func TestDocMediaUploadRemainingBranches(t *testing.T) {
file := writeWhiteboardFixture(t, "svg")
caller := &whiteboardTestCaller{dry: true}
installWhiteboardTestCaller(t, caller)
cmd := newDocCommand()
cmd.SetArgs([]string{"media", "upload", "--node", "n", "--file", file})
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}
for _, test := range []struct {
name string
caller *whiteboardTestCaller
response string
}{
{name: "caller error", caller: &whiteboardTestCaller{err: func(whiteboardTestCall, int) error { return errors.New("call") }}},
{name: "missing resource url", caller: &whiteboardTestCaller{response: func(whiteboardTestCall, int) string {
return `{"uploadUrl":"https://upload.example.test/token","resourceId":"r"}`
}}},
} {
t.Run(test.name, func(t *testing.T) {
installWhiteboardTestCaller(t, test.caller)
cmd := newDocCommand()
cmd.SetArgs([]string{"media", "upload", "--node", "n", "--file", file, "--yes"})
if err := cmd.Execute(); err == nil {
t.Fatal("expected upload error")
}
})
}
}
func TestDocWhiteboardInsertCallerError(t *testing.T) {
caller := &whiteboardTestCaller{err: func(call whiteboardTestCall, index int) error {
if index == 0 {
return errors.New("insert")
}
return nil
}}
installWhiteboardTestCaller(t, caller)
cmd := newDocWhiteboardCommand()
cmd.SetArgs([]string{"insert", "--node", "n", "--yes"})
if err := cmd.Execute(); err == nil {
t.Fatal("expected insert error")
}
}
func TestExtractWhiteboardIDAndJSONEOF(t *testing.T) {
if got := extractWhiteboardID(nil); got != "" {
t.Fatalf("got %q", got)
}
if got := extractWhiteboardID(map[string]any{"metadata": map[string]any{"id": 1}}); got != "" {
t.Fatalf("got %q", got)
}
decoder := json.NewDecoder(strings.NewReader(`{} trailing`))
var value any
if err := decoder.Decode(&value); err != nil {
t.Fatal(err)
}
if err := ensureWhiteboardJSONEOF(decoder); err == nil {
t.Fatal("expected trailing token error")
}
}