package config import ( "strings" "testing" ) func TestParseTOMLValid(t *testing.T) { src := ` # top comment vertical = "demo" # trailing comment work_root = "." [loop] max_rounds = 4 [redmine] url = "https://rm.example.org" scope_query_id = 42 class_field = "Class" [litellm] base_url = "http://h:4001" timeout_secs = 30 max_retries = 3 [models] mopac-study = "glm-4.7-flash" # hyphenated bare key default_tier = "mopac-study" [models.classes] study = "mopac-study" code = "mopac-code" [tools.bash] enabled = false default = "deny" allow = ["pwd", "ls *", "cat *"] deny = [ "sudo *", # comment inside array "ssh *", ] [deep.nested.table] flag = true note = "quote \" and # inside string" empty = [] ` doc, err := ParseTOML(src) if err != nil { t.Fatalf("ParseTOML: %v", err) } tests := []struct { name string got any want any }{ {"vertical", str(doc.String("vertical")), "demo"}, {"work_root", str(doc.String("work_root")), "."}, {"max_rounds", intg(doc.Table("loop").Int("max_rounds")), int64(4)}, {"scope_query_id", intg(doc.Table("redmine").Int("scope_query_id")), int64(42)}, {"class_field", str(doc.Table("redmine").String("class_field")), "Class"}, {"timeout_secs", intg(doc.Table("litellm").Int("timeout_secs")), int64(30)}, {"max_retries", intg(doc.Table("litellm").Int("max_retries")), int64(3)}, {"tier", str(doc.Table("models").String("mopac-study")), "glm-4.7-flash"}, {"default_tier", str(doc.Table("models").String("default_tier")), "mopac-study"}, {"class map", str(doc.Table("models", "classes").String("study")), "mopac-study"}, {"bash enabled", boolean(doc.Table("tools", "bash").Bool("enabled")), false}, {"deep bool", boolean(doc.Table("deep", "nested", "table").Bool("flag")), true}, {"escaped string", str(doc.Table("deep", "nested", "table").String("note")), `quote " and # inside string`}, } for _, tc := range tests { if tc.got != tc.want { t.Errorf("%s = %v, want %v", tc.name, tc.got, tc.want) } } allow, ok := doc.Table("tools", "bash").StringList("allow") if !ok || len(allow) != 3 || allow[1] != "ls *" { t.Errorf("allow list = %v ok=%v", allow, ok) } deny, ok := doc.Table("tools", "bash").StringList("deny") if !ok || len(deny) != 2 || deny[0] != "sudo *" { t.Errorf("deny list = %v ok=%v", deny, ok) } if empty, ok := doc.Table("deep", "nested", "table").StringList("empty"); !ok || len(empty) != 0 { t.Errorf("empty array = %v ok=%v", empty, ok) } } func str(v string, ok bool) string { if !ok { panic("string key missing") } return v } func intg(v int64, ok bool) int64 { if !ok { panic("int key missing") } return v } func boolean(v bool, ok bool) bool { if !ok { panic("bool key missing") } return v } func TestParseTOMLErrors(t *testing.T) { cases := []struct { name string src string want string }{ {"unterminated string", `a = "oops`, "unterminated string"}, {"bare value", `a = sk-123`, "unsupported value"}, {"missing value", `a =`, "missing value"}, {"bad key", `a b = "c"`, "invalid key"}, {"duplicate key", "a = \"1\"\na = \"2\"", "duplicate key"}, {"scalar to table", "a = \"1\"\n[a.b]", "cannot become table"}, {"unterminated array", "a = [\n\"x\",", "unterminated array"}, {"bad table name", `[a.]`, "invalid table name"}, {"no equals", `[t]\njustakey`, "expected key = value"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { _, err := ParseTOML(strings.ReplaceAll(tc.src, `\n`, "\n")) if err == nil { t.Fatalf("expected error containing %q, got nil", tc.want) } if !strings.Contains(err.Error(), tc.want) { t.Fatalf("error %q does not contain %q", err, tc.want) } }) } }