mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-14 20:48:17 +08:00
104 lines
3.4 KiB
Go
104 lines
3.4 KiB
Go
package cli
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"slices"
|
|
"testing"
|
|
|
|
"github.com/matthewlu070111/smart-srun/core/internal/config"
|
|
"github.com/matthewlu070111/smart-srun/core/internal/domain"
|
|
"github.com/matthewlu070111/smart-srun/core/internal/strategy"
|
|
)
|
|
|
|
func TestExitCodeForKnownCodes(t *testing.T) {
|
|
cases := map[domain.ErrorCode]int{
|
|
domain.CodeInvalidArgument: ExitInvalidInput,
|
|
domain.CodeInvalidConfig: ExitInvalidInput,
|
|
domain.CodeServiceStopped: ExitServiceStopped,
|
|
domain.CodeConflict: ExitConflict,
|
|
domain.CodeBusy: ExitConflict,
|
|
domain.CodeUnsupportedCapability: ExitUnsupported,
|
|
domain.CodeCancelled: ExitCancelled,
|
|
domain.CodeAuthRejected: ExitActionFailed,
|
|
domain.CodeBindingUnavailable: ExitActionFailed,
|
|
}
|
|
for code, want := range cases {
|
|
if got := ExitCodeFor(domain.Errorf(code, "x")); got != want {
|
|
t.Errorf("%s -> %d, want %d", code, got, want)
|
|
}
|
|
}
|
|
if got := ExitCodeFor(nil); got != ExitOK {
|
|
t.Errorf("nil -> %d, want 0", got)
|
|
}
|
|
// An error from outside this package means the command could not determine
|
|
// what happened. That is a failure, not a success.
|
|
if got := ExitCodeFor(errors.New("boom")); got != ExitActionFailed {
|
|
t.Errorf("unknown error -> %d, want %d", got, ExitActionFailed)
|
|
}
|
|
}
|
|
|
|
// A whole batch of validation problems must map to the same exit code as one of
|
|
// them. Reporting more problems is not a different kind of failure.
|
|
func TestExitCodeForValidationBatch(t *testing.T) {
|
|
cfg := config.Normalize(config.Defaults())
|
|
cfg.Checks.IntervalSeconds = 0
|
|
cfg.Log.Level = "LOUD"
|
|
|
|
err := config.Validate(cfg)
|
|
if err == nil {
|
|
t.Fatal("expected validation to fail")
|
|
}
|
|
if got := ExitCodeFor(err); got != ExitInvalidInput {
|
|
t.Fatalf("a batch of config problems exited %d, want %d", got, ExitInvalidInput)
|
|
}
|
|
|
|
// Wrapping must not change the answer either.
|
|
wrapped := fmt.Errorf("保存配置:%w", err)
|
|
if got := ExitCodeFor(wrapped); got != ExitInvalidInput {
|
|
t.Fatalf("wrapped batch exited %d, want %d", got, ExitInvalidInput)
|
|
}
|
|
}
|
|
|
|
// A strategy that shadowed a core command would break the documented way to do
|
|
// the thing that command does.
|
|
func TestCoreCommandsAreReserved(t *testing.T) {
|
|
for _, name := range []string{
|
|
"status", "login", "logout", "relogin", "daemon", "schools", "config",
|
|
"switch", "log", "enable", "disable", "help", "man", "update",
|
|
"presets", "detect",
|
|
} {
|
|
if !IsCoreCommand(name) {
|
|
t.Errorf("%q is not reserved", name)
|
|
}
|
|
}
|
|
for _, name := range []string{"", "jxnu", "campus-portal", "Login", "cfg"} {
|
|
if IsCoreCommand(name) {
|
|
t.Errorf("%q was reported reserved", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The CLI's view and the registry's view are the same list, not two lists that
|
|
// happen to look alike.
|
|
//
|
|
// They were two copies that had drifted apart by "service" and "version", each
|
|
// under a comment promising they could not disagree. A promise nothing checks
|
|
// is how they drifted.
|
|
func TestCoreCommandsAreExactlyTheRegistrysReservedList(t *testing.T) {
|
|
if !slices.Equal(CoreCommands(), strategy.ReservedCommands) {
|
|
t.Errorf("CoreCommands() = %v, registry reserves %v",
|
|
CoreCommands(), strategy.ReservedCommands)
|
|
}
|
|
|
|
// Returned by value: a caller that sorted or truncated the result must not
|
|
// be able to change what the registry refuses.
|
|
got := CoreCommands()
|
|
if len(got) > 0 {
|
|
got[0] = "mutated"
|
|
if strategy.ReservedCommands[0] == "mutated" {
|
|
t.Error("CoreCommands exposes the registry's own slice")
|
|
}
|
|
}
|
|
}
|