feat(encode): add the InlineTables option

Assisted-by: DeepSeek V4.1 Flash
This commit is contained in:
2026-09-19 12:18:30 +02:00
parent 8f85bb68fa
commit 959eaba4b0
6 changed files with 308 additions and 6 deletions
+127
View File
@@ -1673,3 +1673,130 @@ func TestMarshalNestedInlineTableBreaksIndependently(t *testing.T) {
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
}
}
type inlineTLS struct {
On bool `toml:"on"`
}
type inlineServer struct {
Host string `toml:"host"`
Port int `toml:"port"`
TLS inlineTLS `toml:"tls"`
}
type inlineBig struct {
A int `toml:"a"`
B int `toml:"b"`
C int `toml:"c"`
}
func TestEncoderInlineTables(t *testing.T) {
type Cfg struct {
Server inlineServer `toml:"server"`
Big inlineBig `toml:"big"`
}
cfg := Cfg{Server: inlineServer{Host: "127.0.0.1", Port: 9090}, Big: inlineBig{A: 1, B: 2, C: 3}}
// The default keeps every sub-table a header section.
headerForm, err := Marshal(cfg)
if err != nil {
t.Fatalf("marshal: %v", err)
}
want := "[server]\nhost = \"127.0.0.1\"\nport = 9090\n\n[server.tls]\non = false\n\n[big]\na = 1\nb = 2\nc = 3\n"
if string(headerForm) != want {
t.Errorf("default output mismatch:\ngot: %q\nwant: %q", headerForm, want)
}
// With the option both fit the threshold and become inline tables, nested
// ones included.
out, err := NewEncoder().InlineTables(60).Marshal(cfg)
if err != nil {
t.Fatalf("marshal: %v", err)
}
want = "server = {host = \"127.0.0.1\", port = 9090, tls = {on = false}}\nbig = {a = 1, b = 2, c = 3}\n"
if string(out) != want {
t.Errorf("compact output mismatch:\ngot: %q\nwant: %q", out, want)
}
// A threshold below the rendering keeps the header form.
out, err = NewEncoder().InlineTables(10).Marshal(cfg)
if err != nil {
t.Fatalf("marshal: %v", err)
}
if string(out) != string(headerForm) {
t.Errorf("small threshold output mismatch:\ngot: %q\nwant: %q", out, headerForm)
}
}
func TestEncoderInlineTablesOrderAndRoundTrip(t *testing.T) {
// An inlined sub-table is a value line, so it precedes every header of the
// document; written after a header it would be read back as part of that
// table. The compact form and the header form parse to the same tree.
type Four struct {
A int `toml:"a"`
B int `toml:"b"`
C int `toml:"c"`
D int `toml:"d"`
}
type Cfg struct {
Small inlineTLS `toml:"small"`
Big Four `toml:"big"`
}
cfg := Cfg{Small: inlineTLS{On: true}, Big: Four{A: 1, B: 2, C: 3, D: 4}}
headerForm, err := Marshal(cfg)
if err != nil {
t.Fatalf("marshal: %v", err)
}
compact, err := NewEncoder().InlineTables(20).Marshal(cfg)
if err != nil {
t.Fatalf("marshal: %v", err)
}
want := "small = {on = true}\n\n[big]\na = 1\nb = 2\nc = 3\nd = 4\n"
if string(compact) != want {
t.Errorf("output mismatch:\ngot: %q\nwant: %q", compact, want)
}
got, err := Parse(compact)
if err != nil {
t.Fatalf("parse of the compact output: %v", err)
}
ref, err := Parse(headerForm)
if err != nil {
t.Fatalf("parse of the header output: %v", err)
}
if !reflect.DeepEqual(got, ref) {
t.Errorf("the compact form changed the tree:\ncompact: %#v\nheaders: %#v", got, ref)
}
if _, ok := got["big"].(map[string]any); !ok {
t.Errorf("big = %#v, want a table", got["big"])
}
}
func TestEncoderInlineTablesKeepsArraysOfTables(t *testing.T) {
// An array of tables has no inline form that keeps the value's type, so the
// option leaves it alone and the tree keeps its []map[string]any shape.
type Item struct {
N int `toml:"n"`
}
type Cfg struct {
Items []Item `toml:"items"`
Small inlineTLS `toml:"small"`
}
cfg := Cfg{Items: []Item{{N: 1}}, Small: inlineTLS{On: true}}
out, err := NewEncoder().InlineTables(60).Marshal(cfg)
if err != nil {
t.Fatalf("marshal: %v", err)
}
want := "small = {on = true}\n\n[[items]]\nn = 1\n"
if string(out) != want {
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
}
tree, err := Parse(out)
if err != nil {
t.Fatalf("parse: %v", err)
}
if _, ok := tree["items"].([]map[string]any); !ok {
t.Errorf("items = %#v, want []map[string]any", tree["items"])
}
}