Files
kandev/apps/backend/internal/worktree/config_test.go
T
2026-08-10 11:18:44 +01:00

124 lines
3.6 KiB
Go

package worktree
import "testing"
// TestConfigValidateBranchPrefix pins both halves of the default-application
// branch in Config.Validate: an empty prefix picks up DefaultBranchPrefix, and
// an explicitly configured prefix survives untouched. Inverting the condition
// (`!= ""`) breaks both and must fail here.
func TestConfigValidateBranchPrefix(t *testing.T) {
cases := []struct {
name string
given string
want string
}{
{name: "empty prefix falls back to the default", given: "", want: DefaultBranchPrefix},
{name: "explicit prefix is preserved", given: "kandev/", want: "kandev/"},
{name: "explicit prefix without separator is preserved", given: "wip", want: "wip"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
cfg := &Config{BranchPrefix: tc.given}
if err := cfg.Validate(); err != nil {
t.Fatalf("Validate() error = %v, want nil", err)
}
if cfg.BranchPrefix != tc.want {
t.Errorf("BranchPrefix = %q, want %q", cfg.BranchPrefix, tc.want)
}
})
}
}
// TestConfigValidateLeavesOtherFieldsAlone guards against Validate growing a
// side effect on fields it has no business defaulting.
func TestConfigValidateLeavesOtherFieldsAlone(t *testing.T) {
cfg := &Config{
Enabled: true,
TasksBasePath: "/tmp/kandev-tasks",
BranchPrefix: "feat/",
FetchTimeoutSeconds: 11,
PullTimeoutSeconds: 22,
}
want := *cfg
if err := cfg.Validate(); err != nil {
t.Fatalf("Validate() error = %v, want nil", err)
}
if *cfg != want {
t.Errorf("Validate() mutated the config: got %+v, want %+v", *cfg, want)
}
}
func TestTaskDirSuffix(t *testing.T) {
const id = "61ccfd2c-1121-4226-99ab-8d9a60a57e6e"
got := TaskDirSuffix(id)
if got == "" {
t.Fatal("TaskDirSuffix returned empty string")
}
if len(got) != taskDirSuffixLen {
t.Fatalf("TaskDirSuffix(%q) length = %d, want %d", id, len(got), taskDirSuffixLen)
}
for _, r := range got {
if !isASCIIAlphaNum(r) {
t.Errorf("TaskDirSuffix(%q) = %q, contains non-alphanumeric %q", id, got, r)
}
if r >= 'A' && r <= 'Z' {
t.Errorf("TaskDirSuffix(%q) = %q, contains uppercase %q", id, got, r)
}
}
if again := TaskDirSuffix(id); again != got {
t.Errorf("TaskDirSuffix is not stable: first %q, second %q", got, again)
}
other := TaskDirSuffix("a2ac3b48-0000-0000-0000-000000000000")
if other == got {
t.Errorf("TaskDirSuffix collided for two different IDs: both %q", got)
}
if TaskDirSuffix("") != "" {
t.Errorf("TaskDirSuffix(\"\") = %q, want empty", TaskDirSuffix(""))
}
}
func TestSemanticWorktreeNameTaskUnique(t *testing.T) {
const title = "We need to improve alerting"
a := SemanticWorktreeName(title, TaskDirSuffix("61ccfd2c-1121-4226-99ab-8d9a60a57e6e"))
b := SemanticWorktreeName(title, TaskDirSuffix("a2ac3b48-1111-2222-3333-444455556666"))
if a == b {
t.Errorf("two tasks with the same title produced the same task-root name %q", a)
}
}
func TestSanitizeRepoDirName(t *testing.T) {
cases := []struct {
in, want string
}{
{"widget-config", "widget-config"},
{"acme/widget-config", "acme-widget-config"},
{"acme/widget", "acme-widget"},
{"owner\\repo", "owner-repo"},
{"weird:name space", "weird-name-space"},
{"with..dots", "with..dots"},
{"trailing/", "trailing"},
{"/leading", "leading"},
{"a//b", "a-b"},
{"-a-b-", "a-b"},
{".hidden", "hidden"},
{"!@#$%", ""},
{"", ""},
{"under_score.dot-dash", "under_score.dot-dash"},
{"修复登录问题", ""},
{"acme/修复", "acme"},
{"🐛/repo", "repo"},
{"owner/répó", "owner-r-p"},
}
for _, c := range cases {
if got := SanitizeRepoDirName(c.in); got != c.want {
t.Errorf("SanitizeRepoDirName(%q) = %q, want %q", c.in, got, c.want)
}
}
}