Files
alterminal/internal/cli/createaccount_test.go
2026-10-03 10:44:29 +08:00

105 lines
4.0 KiB
Go

package cli
import (
"errors"
"strings"
"testing"
"alterminal/internal/auth"
)
func TestAccountInputValidate(t *testing.T) {
tests := []struct {
name string
in accountInput
wantErr string // 空字串表示應通過
}{
{"最小欄位", accountInput{Username: "alice", Email: "alice@example.com"}, ""},
{"含顯示名稱", accountInput{Username: "alice", Email: "alice@example.com", Name: "Alice"}, ""},
{"role 為 admin", accountInput{Username: "alice", Email: "alice@example.com", Role: auth.RoleAdmin}, ""},
{"role 為 user", accountInput{Username: "alice", Email: "alice@example.com", Role: auth.RoleUser}, ""},
{"role 為空", accountInput{Username: "alice", Email: "alice@example.com"}, ""},
{"role 不允許的值", accountInput{Username: "alice", Email: "alice@example.com", Role: "superuser"}, "role"},
{"role 為 Admin(大寫)", accountInput{Username: "alice", Email: "alice@example.com", Role: "Admin"}, "role"},
{"username 允許的符號", accountInput{Username: "a_li-ce.01", Email: "alice@example.com"}, ""},
{"缺 username", accountInput{Email: "alice@example.com"}, "username"},
{"username 過長", accountInput{Username: strings.Repeat("a", 65), Email: "alice@example.com"}, "64"},
{"username 含空白", accountInput{Username: "alice wang", Email: "alice@example.com"}, "username"},
{"username 含 @", accountInput{Username: "alice@example.com", Email: "alice@example.com"}, "username"},
{"缺 email", accountInput{Username: "alice"}, "email"},
{"email 過長", accountInput{Username: "alice", Email: strings.Repeat("a", 250) + "@example.com"}, "255"},
{"email 格式無效", accountInput{Username: "alice", Email: "example.com"}, "email"},
{"email 帶顯示名稱", accountInput{Username: "alice", Email: "Alice <alice@example.com>"}, "email"},
{"name 過長", accountInput{Username: "alice", Email: "alice@example.com", Name: strings.Repeat("名", 256)}, "255"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.in.validate()
if tt.wantErr == "" {
if err != nil {
t.Fatalf("validate() = %v, want nil", err)
}
return
}
if err == nil || !strings.Contains(err.Error(), tt.wantErr) {
t.Fatalf("validate() = %v, want error containing %q", err, tt.wantErr)
}
})
}
}
func TestResolvePasswordFromFlag(t *testing.T) {
got, err := resolvePassword("sup3r-secret")
if err != nil {
t.Fatalf("resolvePassword() = %v, want nil", err)
}
if got != "sup3r-secret" {
t.Fatalf("resolvePassword() = %q, want %q", got, "sup3r-secret")
}
}
func TestResolvePasswordTooShort(t *testing.T) {
_, err := resolvePassword("1234567")
if err == nil || !strings.Contains(err.Error(), "8") {
t.Fatalf("resolvePassword(\"1234567\") = %v, want 長度錯誤", err)
}
}
// go test 執行時 stdin 不是終端機,省略 -password 應直接報錯而非等待輸入。
func TestResolvePasswordRequiresFlagWithoutTerminal(t *testing.T) {
_, err := resolvePassword("")
if err == nil || !strings.Contains(err.Error(), "-password") {
t.Fatalf("resolvePassword(\"\") = %v, want 提示改用 -password 的錯誤", err)
}
}
func TestPromptPasswordTwice(t *testing.T) {
t.Run("兩次一致", func(t *testing.T) {
got, err := promptPasswordTwice(func(string) ([]byte, error) { return []byte("sup3r-secret"), nil })
if err != nil {
t.Fatalf("promptPasswordTwice() = %v, want nil", err)
}
if got != "sup3r-secret" {
t.Fatalf("promptPasswordTwice() = %q, want %q", got, "sup3r-secret")
}
})
t.Run("兩次不一致", func(t *testing.T) {
inputs := []string{"sup3r-secret", "sup3r-secret2"}
calls := 0
_, err := promptPasswordTwice(func(string) ([]byte, error) {
b := []byte(inputs[calls])
calls++
return b, nil
})
if err == nil || !strings.Contains(err.Error(), "不一致") {
t.Fatalf("promptPasswordTwice() = %v, want 不一致錯誤", err)
}
})
t.Run("讀取失敗", func(t *testing.T) {
_, err := promptPasswordTwice(func(string) ([]byte, error) { return nil, errors.New("boom") })
if err == nil {
t.Fatal("promptPasswordTwice() = nil, want error")
}
})
}