Files
dingtalk-workspace-cli/internal/shortcut/minutesdata/coverage_completion_test.go

318 lines
14 KiB
Go

// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0
package minutesdata
import (
"encoding/json"
"math"
"strings"
"testing"
"time"
)
func TestCrossPlatformCoverageMinutesResponseCompletion(t *testing.T) {
for _, data := range []map[string]any{
{},
{"success": false, "message": "denied"},
{"errorCode": "E", "msg": "bad"},
{"dingOpenErrcode": float64(1)},
} {
if err := ValidateEnvelope(data); err == nil {
t.Fatalf("invalid envelope accepted: %#v", data)
}
}
for _, value := range []any{nil, "", "0", float64(0), 0, int64(0), json.Number("0")} {
if !isZeroCode(value) {
t.Fatalf("zero code rejected: %#v", value)
}
}
if isZeroCode(true) {
t.Fatal("unsupported code treated as zero")
}
if got := envelopeMessage(map[string]any{}); got != "no backend error message" {
t.Fatalf("fallback message = %q", got)
}
list, err := ParseListPage(map[string]any{
"hasNext": true, "nextCursor": "outer",
"data": map[string]any{"result": map[string]any{"records": []any{map[string]any{"taskUUID": "u1"}}}},
})
if err != nil || !list.HasMoreKnown || list.NextToken != "outer" || len(list.Items) != 1 {
t.Fatalf("nested list = %#v, %v", list, err)
}
if _, err := ParseListPage(map[string]any{"result": map[string]any{"items": []any{map[string]any{}, "bad"}}}); err == nil {
t.Fatal("non-object list item accepted")
}
transcript, err := ParseTranscriptPage(map[string]any{
"hasMore": false,
"data": map[string]any{"data": map[string]any{"paragraphList": []any{map[string]any{"sentenceId": "p"}}}},
})
if err != nil || !transcript.HasMoreKnown || transcript.HasMore || len(transcript.Items) != 1 {
t.Fatalf("nested transcript = %#v, %v", transcript, err)
}
if _, err := ParseTranscriptPage(map[string]any{"result": map[string]any{"paragraphList": []any{"bad"}}}); err == nil {
t.Fatal("non-object paragraph accepted")
}
for _, tc := range []struct {
name string
data map[string]any
}{
{"no result", map[string]any{"success": true}},
{"basic missing", map[string]any{"result": map[string]any{}}},
{"basic mismatch", map[string]any{"result": map[string]any{"taskUuid": "other"}}},
{"summary missing", map[string]any{"result": map[string]any{}}},
{"keywords wrong", map[string]any{"result": map[string]any{"keywords": "bad"}}},
{"todos wrong", map[string]any{"result": map[string]any{"actions": "bad", "dingtalkTodoList": "bad"}}},
{"other empty", map[string]any{"result": map[string]any{}}},
} {
artifact := map[string]string{"no result": "basic", "basic missing": "basic", "basic mismatch": "basic", "summary missing": "summary", "keywords wrong": "keywords", "todos wrong": "todos", "other empty": "custom"}[tc.name]
if err := ValidateArtifact(artifact, "u1", tc.data); err == nil {
t.Fatalf("%s accepted", tc.name)
}
}
if err := ValidateArtifact("basic", "u1", map[string]any{}); err == nil {
t.Fatal("artifact envelope failure ignored")
}
if err := ValidateArtifact("todos", "", map[string]any{"result": map[string]any{"dingtalkTodoList": []any{}}}); err != nil {
t.Fatal(err)
}
if err := ValidateArtifact("custom", "", map[string]any{"result": map[string]any{"value": true}}); err != nil {
t.Fatal(err)
}
if _, err := Basic("u1", map[string]any{"result": map[string]any{}}); err == nil {
t.Fatal("invalid basic accepted")
}
if basic, err := Basic("u1", map[string]any{"result": map[string]any{"uuid": "u1"}}); err != nil || basic["uuid"] != "u1" {
t.Fatalf("basic = %#v, %v", basic, err)
}
if _, err := SummaryText(map[string]any{"result": map[string]any{}}); err == nil {
t.Fatal("invalid summary accepted")
}
if _, err := SummaryText(map[string]any{"result": map[string]any{"fullSummary": 1}}); err == nil {
t.Fatal("non-string summary accepted")
}
if text, err := SummaryText(map[string]any{"result": map[string]any{"fullSummary": "ok"}}); err != nil || text != "ok" {
t.Fatalf("summary = %q, %v", text, err)
}
for _, data := range []map[string]any{{}, {"result": "bad"}, {"result": map[string]any{}}} {
if _, err := MediaURL(data); err == nil {
t.Fatalf("invalid media accepted: %#v", data)
}
}
if value, err := MediaURL(map[string]any{"result": map[string]any{"audioUrl": " https://example.invalid/a "}}); err != nil || value == "" {
t.Fatalf("media = %q, %v", value, err)
}
for _, data := range []map[string]any{{}, {"result": "bad"}, {"result": map[string]any{"sessionId": "s"}}} {
if _, _, err := UploadSession(data); err == nil {
t.Fatalf("invalid upload session accepted: %#v", data)
}
}
if session, url, err := UploadSession(map[string]any{"result": map[string]any{"uploadId": 7, "uploadUrl": "https://example.invalid"}}); err != nil || session != "7" || url == "" {
t.Fatalf("upload session = %q/%q, %v", session, url, err)
}
if _, err := CompletedTaskUUID(map[string]any{}); err == nil {
t.Fatal("invalid completed envelope accepted")
}
if _, err := CompletedTaskUUID(map[string]any{"result": map[string]any{}}); err == nil {
t.Fatal("missing completed UUID accepted")
}
if id, err := CompletedTaskUUID(map[string]any{"data": map[string]any{"result": map[string]any{"task_uuid": "done"}}}); err != nil || id != "done" {
t.Fatalf("completed UUID = %q, %v", id, err)
}
rows, err := ProjectList(Page{Items: []map[string]any{{
"uuid": "u", "name": "n", "creatorNick": "c", "createTime": 1,
"deadline": 2, "link": "l", "state": "ready",
}}})
if err != nil || rows[0]["title"] != "n" || rows[0]["creator"] != "c" || rows[0]["url"] != "l" {
t.Fatalf("projected fallback fields = %#v, %v", rows, err)
}
if got := TaskUUID(map[string]any{"taskUUID": json.Number("9")}); got != "9" {
t.Fatalf("numeric task UUID = %q", got)
}
if id, err := LatestTaskUUID(Page{}); err != nil || id != "" {
t.Fatalf("empty latest = %q, %v", id, err)
}
if _, err := LatestTaskUUID(Page{Items: []map[string]any{{"startTime": 1}}}); err == nil {
t.Fatal("latest missing UUID accepted")
}
latest, err := LatestTaskUUID(Page{Items: []map[string]any{
{"uuid": "skip", "createTime": "bad"},
{"uuid": "int", "createTime": 1},
{"uuid": "int64", "gmtCreate": int64(2)},
{"uuid": "number", "startTime": json.Number("3")},
{"uuid": "rfc", "createTimeStart": time.Now().UTC().Format(time.RFC3339Nano)},
}})
if err != nil || latest != "rfc" {
t.Fatalf("typed latest = %q, %v", latest, err)
}
if key, err := StableItemKey(map[string]any{"text": "same"}); err != nil || !strings.HasPrefix(key, "json:") {
t.Fatalf("JSON stable key = %q, %v", key, err)
}
if _, err := StableItemKey(map[string]any{"bad": func() {}}); err == nil {
t.Fatal("unencodable stable key accepted")
}
for _, value := range []any{"value", json.Number("4"), float64(5), 6, int64(7)} {
if got := stringField(map[string]any{"x": value}, "missing", "x"); got == "" {
t.Fatalf("stringField(%#v) empty", value)
}
}
if got := stringField(map[string]any{"x": true}, "x"); got != "" {
t.Fatalf("unsupported string field = %q", got)
}
for _, value := range []any{float64(1), 2, int64(3), json.Number("4"), "5", "2026-08-11T00:00:00Z"} {
if _, ok := timestamp(map[string]any{"x": value}, "x"); !ok {
t.Fatalf("timestamp(%#v) rejected", value)
}
}
if _, ok := timestamp(map[string]any{"x": json.Number("bad")}, "x"); ok {
t.Fatal("invalid timestamp number accepted")
}
}
func TestCrossPlatformCoverageMinutesPagerCompletion(t *testing.T) {
if _, err := CollectTranscript(nil, "", false, 1); err == nil {
t.Fatal("nil transcript caller accepted")
}
defaulted, err := CollectTranscript(func(string) (map[string]any, error) {
return map[string]any{"result": map[string]any{"paragraphList": []any{}}}, nil
}, "", false, 0)
if err != nil || !defaulted.Complete {
t.Fatalf("default max pages = %#v, %v", defaulted, err)
}
invalid, err := CollectTranscript(func(string) (map[string]any, error) { return map[string]any{}, nil }, "", false, 1)
if err == nil || invalid.FailurePage != 1 || invalid.FailureMessage == "" {
t.Fatalf("invalid page = %#v, %v", invalid, err)
}
badKey, err := CollectTranscript(func(string) (map[string]any, error) {
return map[string]any{"result": map[string]any{"paragraphList": []any{map[string]any{"bad": func() {}}}}}, nil
}, "", false, 1)
if err == nil || badKey.FailurePage != 1 {
t.Fatalf("bad key = %#v, %v", badKey, err)
}
one, err := CollectTranscript(func(string) (map[string]any, error) {
return map[string]any{"result": map[string]any{"paragraphList": []any{}, "hasNext": false}}, nil
}, "", true, 1)
if err != nil || !one.Complete {
t.Fatalf("complete single page = %#v, %v", one, err)
}
limited, err := CollectTranscript(func(token string) (map[string]any, error) {
return map[string]any{"result": map[string]any{"paragraphList": []any{}, "hasNext": true, "nextToken": token + "n"}}, nil
}, "", false, 1)
if err == nil || limited.FailurePage != 2 || limited.FailureMessage == "" {
t.Fatalf("page limit = %#v, %v", limited, err)
}
payload := TranscriptPayload("u", "1", TranscriptResult{
Paragraphs: []map[string]any{{"id": "p"}}, Pages: 1, Duplicates: 2,
NextToken: "n", FailurePage: 2, FailureMessage: "failed",
})
if payload["nextToken"] != "n" || payload["failurePage"] != 2 || payload["failure"] != "failed" {
t.Fatalf("transcript payload = %#v", payload)
}
}
func TestCrossPlatformCoverageMinutesWorkflowCompletion(t *testing.T) {
for _, data := range []map[string]any{{}, {"other": true}, {"success": "yes"}, {"success": false}} {
if err := RequireWriteAcknowledgement("write", data); err == nil {
t.Fatalf("invalid acknowledgement accepted: %#v", data)
}
}
if err := RequireWriteAcknowledgement("write", map[string]any{"result": map[string]any{"updated": true}}); err != nil {
t.Fatal(err)
}
if err := RequirePermissionMutationAcknowledgement("unshare", []string{"u1"}, []string{"202397"}, map[string]any{
"success": true,
"result": map[string]any{"resultMap": map[string]any{"u1": []any{float64(202397)}}},
}); err != nil {
t.Fatalf("valid permission acknowledgement rejected: %v", err)
}
for _, data := range []map[string]any{
{"success": false, "errorMsg": "denied"},
{"success": "yes"},
{"success": true, "result": "bad"},
{"success": true, "result": map[string]any{}},
{"success": true, "result": map[string]any{"resultMap": map[string]any{}}},
{"success": true, "result": map[string]any{"resultMap": map[string]any{"other": []any{"202397"}}}},
{"success": true, "result": map[string]any{"resultMap": map[string]any{"u1": "bad"}}},
{"success": true, "result": map[string]any{"resultMap": map[string]any{"u1": []any{nil}}}},
{"success": true, "result": map[string]any{"resultMap": map[string]any{"u1": []any{"other"}}}},
} {
if err := RequirePermissionMutationAcknowledgement("unshare", []string{"u1"}, []string{"202397"}, data); err == nil {
t.Fatalf("invalid permission acknowledgement accepted: %#v", data)
}
}
if err := RequirePermissionMutationAcknowledgement("unshare", []string{"u1"}, []string{"202397", "other"}, map[string]any{
"success": true,
"result": map[string]any{"resultMap": map[string]any{"u1": []any{"202397"}}},
}); err == nil {
t.Fatal("incomplete member coverage accepted")
}
for _, tc := range []struct {
cmd, id string
data map[string]any
}{
{"pause", "u", map[string]any{}},
{"pause", "u", map[string]any{"success": true}},
{"pause", "u", map[string]any{"success": true, "result": map[string]any{"cmd": "resume", "uuid": "u"}}},
{"pause", "u", map[string]any{"success": true, "result": map[string]any{"cmd": "pause", "uuid": "other"}}},
} {
if _, err := RecordResult(tc.cmd, tc.id, tc.data); err == nil {
t.Fatalf("invalid record accepted: %#v", tc)
}
}
if _, err := RecordResult("create", "", map[string]any{"success": true, "result": map[string]any{"cmd": "create"}}); err != nil {
t.Fatal(err)
}
for _, data := range []map[string]any{{}, {"result": "bad"}, {"result": map[string]any{}}, {"result": map[string]any{"taskStatus": 3}}} {
if _, _, err := MindGraphStatus(data); err == nil {
t.Fatalf("invalid mind graph accepted: %#v", data)
}
}
for _, value := range []any{0, "1", json.Number("2")} {
status, _, err := MindGraphStatus(map[string]any{"result": map[string]any{"taskStatus": value}})
if err != nil || status < 0 || status > 2 {
t.Fatalf("mind status %#v = %d, %v", value, status, err)
}
}
for _, data := range []map[string]any{{}, {"success": true}, {"success": true, "result": map[string]any{}}} {
if _, _, err := SpeakerSummaryTask(data); err == nil {
t.Fatalf("invalid speaker task accepted: %#v", data)
}
}
if id, status, err := SpeakerSummaryTask(map[string]any{"result": map[string]any{"taskID": int64(7), "status": "READY"}}); err != nil || id != "7" || status != "ready" {
t.Fatalf("speaker task = %q/%q, %v", id, status, err)
}
for _, data := range []map[string]any{{}, {"result": nil}, {"result": []any(nil)}, {"result": "bad"}} {
if _, err := SpeakerSummaryResult(data); err == nil {
t.Fatalf("invalid speaker result accepted: %#v", data)
}
}
if value, err := SpeakerSummaryResult(map[string]any{"result": []any{}}); err != nil || value == nil {
t.Fatalf("empty speaker list = %#v, %v", value, err)
}
if value, err := SpeakerSummaryResult(map[string]any{"result": map[string]any{"summary": "ok"}}); err != nil || value == nil {
t.Fatalf("speaker map = %#v, %v", value, err)
}
for _, data := range []map[string]any{{}, {"result": "bad"}, {"result": map[string]any{}}, {"result": map[string]any{"hotWordList": "bad"}}, {"result": map[string]any{"hotWordList": []any{true}}}} {
if _, err := HotWords(data); err == nil {
t.Fatalf("invalid hot words accepted: %#v", data)
}
}
words, err := HotWords(map[string]any{"result": map[string]any{"hotWordList": []any{" A ", "A", map[string]any{"content": "B"}}}})
if err != nil || len(words) != 2 {
t.Fatalf("deduplicated hot words = %#v, %v", words, err)
}
for _, value := range []any{math.NaN(), math.Inf(1), 1.5, float64(-1), float64(3), json.Number("bad"), "bad", true} {
if _, err := intValue(value); err == nil {
t.Fatalf("invalid int value accepted: %#v", value)
}
}
if _, err := intValue(int64(1)); err == nil || !strings.Contains(err.Error(), "unsupported") {
t.Fatalf("unsupported int64 result = %v", err)
}
}