feat: teai role

This commit is contained in:
ydc3148
2026-09-14 16:13:02 +08:00
parent 8735e35db6
commit 540718dda7
12 changed files with 416 additions and 120 deletions
+25 -14
View File
@@ -1,4 +1,4 @@
// config_test.go 驗證 tea 相容組態的行級編輯:新增、更新、設預設、
// config_test.go 驗證登入組態的行級編輯:新增、更新、設預設、
// 移除,以及「未知欄位與其他區段逐字保留」的關鍵性質。
package gitea
@@ -10,8 +10,8 @@ import (
"testing"
)
// realWorldTeaConfig 是 tea 實際寫出的組態(含 ssh_* 等未知欄位與 preferences)。
const realWorldTeaConfig = `logins:
// extraFieldsConfig 含未知欄位與額外區段,用來驗證行級編輯不會改壞不相干內容。
const extraFieldsConfig = `logins:
- name: alterminal
url: https://gitea.alterminal.com
token: tok-1
@@ -32,7 +32,7 @@ preferences:
`
func TestListLoginsParsesAllEntries(t *testing.T) {
logins := ListLogins([]byte(realWorldTeaConfig))
logins := ListLogins([]byte(extraFieldsConfig))
if len(logins) != 1 {
t.Fatalf("want 1 login, got %d", len(logins))
}
@@ -43,7 +43,7 @@ func TestListLoginsParsesAllEntries(t *testing.T) {
}
func TestUpsertLoginUpdatesExistingPreservesRest(t *testing.T) {
out, final, err := UpsertLogin([]byte(realWorldTeaConfig), LoginEntry{
out, final, err := UpsertLogin([]byte(extraFieldsConfig), LoginEntry{
Name: "alterminal", URL: "https://gitea.alterminal.com", Token: "tok-2", User: "ceo",
}, false)
if err != nil {
@@ -74,7 +74,7 @@ func TestUpsertLoginUpdatesExistingPreservesRest(t *testing.T) {
}
func TestUpsertLoginAppendsNewAndMakesDefault(t *testing.T) {
out, final, err := UpsertLogin([]byte(realWorldTeaConfig), LoginEntry{
out, final, err := UpsertLogin([]byte(extraFieldsConfig), LoginEntry{
Name: "second", URL: "https://git.example.com", Token: "tok-b", User: "bob",
}, true)
if err != nil {
@@ -93,10 +93,15 @@ func TestUpsertLoginAppendsNewAndMakesDefault(t *testing.T) {
if !final.Default {
t.Fatalf("final should be default: %+v", final)
}
// tea 的欄位順序仍在。
// 新項目依 teai 欄位順序附加。
s := string(out)
if !strings.Contains(s, " - name: second\n") {
t.Fatalf("new item not appended in tea style:\n%s", s)
t.Fatalf("new item not appended:\n%s", s)
}
for _, ban := range []string{"ssh_", "insecure:", "version_check:", "created:"} {
if strings.Contains(s[strings.Index(s, "- name: second"):], ban) {
t.Fatalf("new item leaked tea field %q:\n%s", ban, s)
}
}
}
@@ -117,6 +122,12 @@ func TestUpsertLoginFirstEverLoginCreatesSection(t *testing.T) {
if !strings.HasPrefix(string(out), "logins:\n") {
t.Fatalf("section not created:\n%s", out)
}
s := string(out)
for _, ban := range []string{"ssh_", "insecure:", "version_check:", "created:", "preferences:"} {
if strings.Contains(s, ban) {
t.Fatalf("new config leaked tea field %q:\n%s", ban, s)
}
}
}
func TestUpsertLoginRejectsBadInput(t *testing.T) {
@@ -158,7 +169,7 @@ func TestSetDefaultLoginSwitchesFlag(t *testing.T) {
}
func TestSetDefaultLoginUnknownNameErrors(t *testing.T) {
if _, err := SetDefaultLogin([]byte(realWorldTeaConfig), "nope"); err == nil {
if _, err := SetDefaultLogin([]byte(extraFieldsConfig), "nope"); err == nil {
t.Fatal("unknown name should error")
}
}
@@ -195,7 +206,7 @@ preferences:
}
func TestRemoveLoginLastOne(t *testing.T) {
out, promoted, err := RemoveLogin([]byte(realWorldTeaConfig), "alterminal")
out, promoted, err := RemoveLogin([]byte(extraFieldsConfig), "alterminal")
if err != nil || promoted != "" {
t.Fatalf("want clean removal, promoted=%q err=%v", promoted, err)
}
@@ -207,10 +218,10 @@ func TestRemoveLoginLastOne(t *testing.T) {
}
}
func TestSaveTeaConfigFileAtomicAndMode(t *testing.T) {
func TestSaveConfigFileAtomicAndMode(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "tea", "config.yml")
if err := SaveTeaConfigFile(path, []byte("logins: []\n")); err != nil {
path := filepath.Join(dir, "teai", "config.yml")
if err := SaveConfigFile(path, []byte("logins: []\n")); err != nil {
t.Fatal(err)
}
info, err := os.Stat(path)
@@ -221,7 +232,7 @@ func TestSaveTeaConfigFileAtomicAndMode(t *testing.T) {
t.Fatalf("perm = %v, want 0600", info.Mode().Perm())
}
// 再寫一次(覆蓋既有檔),不留暫存殘檔。
if err := SaveTeaConfigFile(path, []byte("logins: []\n# v2\n")); err != nil {
if err := SaveConfigFile(path, []byte("logins: []\n# v2\n")); err != nil {
t.Fatal(err)
}
entries, _ := os.ReadDir(filepath.Dir(path))