mirror of
https://github.com/larksuite/cli.git
synced 2026-07-07 17:45:15 +08:00
Emit structured validation, API, network, file, and internal error envelopes for Slides shortcuts so users and agents can recover from failed presentation workflows using stable type, subtype, param, and code fields. Add Slides domain errscontract and golangci guards to prevent legacy envelope and common helper regressions.
112 lines
3.4 KiB
Go
112 lines
3.4 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package slides
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/larksuite/cli/errs"
|
|
"github.com/larksuite/cli/extension/fileio"
|
|
)
|
|
|
|
// TestSlidesInputStatError verifies the shared stat-error helper tags the
|
|
// offending flag via the typed Param — so callers route on the structured
|
|
// field rather than parsing the message — and always classifies as a
|
|
// validation error while preserving the underlying cause.
|
|
func TestSlidesInputStatError(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if err := slidesInputStatError(nil, "--slides", "ctx"); err != nil {
|
|
t.Fatalf("nil input should return nil, got %v", err)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
in error
|
|
}{
|
|
{"path validation", fileio.ErrPathValidation},
|
|
{"generic stat error", errors.New("permission denied")},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
err := slidesInputStatError(tt.in, "--file", "file not found")
|
|
|
|
var ve *errs.ValidationError
|
|
if !errors.As(err, &ve) {
|
|
t.Fatalf("err = %v, want *errs.ValidationError", err)
|
|
}
|
|
if ve.Param != "--file" {
|
|
t.Fatalf("Param = %q, want --file", ve.Param)
|
|
}
|
|
if !errors.Is(err, tt.in) {
|
|
t.Fatalf("err must wrap the underlying cause %v", tt.in)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestAppendSlidesProgressHint covers both branches of the orchestration-hint
|
|
// helper: a typed error keeps its classification and gains (or extends) the
|
|
// progress hint, while an unclassified error surfaced from a shared-helper
|
|
// boundary falls back to a typed internal error that still carries the hint
|
|
// and the original cause.
|
|
func TestAppendSlidesProgressHint(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if err := appendSlidesProgressHint(nil, "hint"); err != nil {
|
|
t.Fatalf("nil input should return nil, got %v", err)
|
|
}
|
|
|
|
t.Run("typed error preserves classification and sets hint", func(t *testing.T) {
|
|
t.Parallel()
|
|
base := errs.NewValidationError(errs.SubtypeInvalidArgument, "bad input")
|
|
err := appendSlidesProgressHint(base, "2 image(s) uploaded before failure")
|
|
|
|
var ve *errs.ValidationError
|
|
if !errors.As(err, &ve) {
|
|
t.Fatalf("err = %v, want classification preserved as *errs.ValidationError", err)
|
|
}
|
|
p, _ := errs.ProblemOf(err)
|
|
if p.Hint != "2 image(s) uploaded before failure" {
|
|
t.Fatalf("Hint = %q, want the progress hint", p.Hint)
|
|
}
|
|
})
|
|
|
|
t.Run("typed error appends to an existing hint", func(t *testing.T) {
|
|
t.Parallel()
|
|
base := errs.NewValidationError(errs.SubtypeInvalidArgument, "bad input").WithHint("first")
|
|
err := appendSlidesProgressHint(base, "second")
|
|
|
|
p, _ := errs.ProblemOf(err)
|
|
if p.Hint != "first\nsecond" {
|
|
t.Fatalf("Hint = %q, want %q", p.Hint, "first\nsecond")
|
|
}
|
|
})
|
|
|
|
t.Run("unclassified error falls back to typed internal error", func(t *testing.T) {
|
|
t.Parallel()
|
|
cause := errors.New("raw boundary error")
|
|
err := appendSlidesProgressHint(cause, "presentation was created")
|
|
|
|
p, ok := errs.ProblemOf(err)
|
|
if !ok {
|
|
t.Fatalf("err = %v, want a typed errs.* error", err)
|
|
}
|
|
if p.Category != errs.CategoryInternal {
|
|
t.Fatalf("Category = %v, want CategoryInternal", p.Category)
|
|
}
|
|
if p.Subtype != errs.SubtypeUnknown {
|
|
t.Fatalf("Subtype = %v, want SubtypeUnknown", p.Subtype)
|
|
}
|
|
if p.Hint != "presentation was created" {
|
|
t.Fatalf("Hint = %q, want the progress hint", p.Hint)
|
|
}
|
|
if !errors.Is(err, cause) {
|
|
t.Fatalf("fallback must preserve the original cause via WithCause")
|
|
}
|
|
})
|
|
}
|