chore: import upstream snapshot with attribution
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package task
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/larksuite/cli/errs"
|
||||
"github.com/larksuite/cli/extension/fileio"
|
||||
"github.com/larksuite/cli/internal/output"
|
||||
)
|
||||
|
||||
func TestTaskInputStatError(t *testing.T) {
|
||||
t.Run("nil error returns nil", func(t *testing.T) {
|
||||
if err := taskInputStatError(nil, "--file"); err != nil {
|
||||
t.Errorf("taskInputStatError(nil) = %v, want nil", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("path validation failure maps to unsafe file path", func(t *testing.T) {
|
||||
err := taskInputStatError(fmt.Errorf("bad: %w", fileio.ErrPathValidation), "--file")
|
||||
var ve *errs.ValidationError
|
||||
if !errors.As(err, &ve) {
|
||||
t.Fatalf("err = %T, want *errs.ValidationError", err)
|
||||
}
|
||||
if ve.Subtype != errs.SubtypeInvalidArgument {
|
||||
t.Errorf("subtype = %q, want %q", ve.Subtype, errs.SubtypeInvalidArgument)
|
||||
}
|
||||
if output.ExitCodeOf(err) != output.ExitValidation {
|
||||
t.Errorf("exit = %d, want %d", output.ExitCodeOf(err), output.ExitValidation)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "unsafe file path") {
|
||||
t.Errorf("message = %q, want 'unsafe file path'", err.Error())
|
||||
}
|
||||
if ve.Param != "--file" {
|
||||
t.Errorf("param = %q, want --file", ve.Param)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("generic error uses readMsg prefix", func(t *testing.T) {
|
||||
err := taskInputStatError(errors.New("permission denied"), "--file", "cannot access file")
|
||||
var ve *errs.ValidationError
|
||||
if !errors.As(err, &ve) {
|
||||
t.Fatalf("err = %T, want *errs.ValidationError", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "cannot access file") {
|
||||
t.Errorf("message = %q, want 'cannot access file' prefix", err.Error())
|
||||
}
|
||||
if ve.Param != "--file" {
|
||||
t.Errorf("param = %q, want --file", ve.Param)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("default prefix when no readMsg", func(t *testing.T) {
|
||||
err := taskInputStatError(errors.New("boom"), "--file")
|
||||
var ve *errs.ValidationError
|
||||
if !errors.As(err, &ve) {
|
||||
t.Fatalf("err = %T, want *errs.ValidationError", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "cannot read file") {
|
||||
t.Errorf("message = %q, want default 'cannot read file'", err.Error())
|
||||
}
|
||||
if ve.Param != "--file" {
|
||||
t.Errorf("param = %q, want --file", ve.Param)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestWrapTaskNetworkErr(t *testing.T) {
|
||||
// wrapTaskNetworkErr is only ever called inside an `if err != nil` guard
|
||||
// (DoAPIStream failure), mirroring drive's wrapDriveNetworkErr, so it does
|
||||
// not special-case a nil cause.
|
||||
t.Run("untyped cause becomes typed network error wrapping the cause", func(t *testing.T) {
|
||||
cause := errors.New("dial timeout")
|
||||
err := wrapTaskNetworkErr(cause, "upload failed")
|
||||
var ne *errs.NetworkError
|
||||
if !errors.As(err, &ne) {
|
||||
t.Fatalf("err = %T, want *errs.NetworkError", err)
|
||||
}
|
||||
if ne.Subtype != errs.SubtypeNetworkTransport {
|
||||
t.Errorf("subtype = %q, want %q", ne.Subtype, errs.SubtypeNetworkTransport)
|
||||
}
|
||||
if !errors.Is(err, cause) {
|
||||
t.Error("expected the original cause to be wrapped (errors.Is)")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("already-typed cause is passed through unchanged", func(t *testing.T) {
|
||||
typed := errs.NewAPIError(errs.SubtypeNotFound, "missing")
|
||||
err := wrapTaskNetworkErr(typed, "upload failed")
|
||||
var ae *errs.APIError
|
||||
if !errors.As(err, &ae) {
|
||||
t.Fatalf("err = %T, want the original *errs.APIError passed through", err)
|
||||
}
|
||||
if ae.Subtype != errs.SubtypeNotFound {
|
||||
t.Errorf("subtype = %q, want %q (not re-wrapped as network)", ae.Subtype, errs.SubtypeNotFound)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user