Files
toml/encode_test.go
2026-07-13 02:45:49 -04:00

203 lines
4.9 KiB
Go

package toml
import (
"strings"
"testing"
)
func TestMarshal_Primitives(t *testing.T) {
tests := []struct {
name string
input map[string]any
expected string // partial match or exact
}{
{
name: "Scalars",
input: map[string]any{"str": "hello", "int": 42, "bool": true, "float": 3.14},
expected: `bool = true
float = 3.14
int = 42
str = "hello"`,
},
{
name: "Quoted Keys",
input: map[string]any{"123a": 1, "key.dot": 2, "true": 3},
expected: `"123a" = 1
"key.dot" = 2
"true" = 3`,
},
{
name: "Inline Arrays",
input: map[string]any{"arr": []int{1, 2, 3}},
expected: `arr = [1, 2, 3]`,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
b, err := Marshal(tc.input)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
out := strings.TrimSpace(string(b))
if out != tc.expected {
t.Errorf("Mismatch:\nGot:\n%s\nWant:\n%s", out, tc.expected)
}
})
}
}
func TestMarshal_StructsAndNesting(t *testing.T) {
type Server struct {
IP string `toml:"ip"`
Port int `toml:"port"`
}
type Config struct {
Name string `toml:"name"`
Tags []string `toml:"tags"`
Servers []Server `toml:"servers"` // Array of tables
Meta map[string]string `toml:"meta"` // Table
}
input := Config{
Name: "Production",
Tags: []string{"web", "api"},
Servers: []Server{
{IP: "10.0.0.1", Port: 80},
{IP: "10.0.0.2", Port: 8080},
},
Meta: map[string]string{
"env": "prod",
"dc": "us-east",
},
}
b, err := Marshal(input)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
out := string(b)
// Verify key order (determinism) and structure
// Scalars first: name, tags
if !strings.Contains(out, `name = "Production"`) {
t.Error("Missing name field")
}
if !strings.Contains(out, `tags = ["web", "api"]`) {
t.Error("Missing tags field")
}
// Tables later: meta
if !strings.Contains(out, `[meta]`) {
t.Error("Missing [meta] table")
}
if !strings.Contains(out, `env = "prod"`) {
t.Error("Missing env inside meta")
}
// Array of tables: servers
if !strings.Contains(out, `[[servers]]`) {
t.Error("Missing [[servers]] header")
}
if !strings.Contains(out, `ip = "10.0.0.1"`) {
t.Error("Missing server IP")
}
}
func TestMarshal_RoundTrip(t *testing.T) {
// Complex input covering most features
input := map[string]any{
"title": "Symmetry Test",
"owner": map[string]any{
"name": "Tom",
"dob": "1979-05-27T07:32:00Z", // String because date support is limited
},
"database": map[string]any{
"server": "192.168.1.1",
"ports": []any{8001, 8001, 8002},
"connection_max": 5000,
"enabled": true,
},
"servers": []map[string]any{
{"ip": "10.0.0.1", "role": "frontend"},
{"ip": "10.0.0.2", "role": "backend"},
},
"quoted-keys": map[string]any{
// "1234": "val" would fail because Parser explicitly forbids keys that validly Atoi()
"1234a": "alphanumeric starting with digit", // Should be quoted in output, accepted by Parser
"a-b": "bare key", // Should not be quoted
"true": "bool key", // Should be quoted
},
}
// 1. Marshal
data, err := Marshal(input)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
// 2. Unmarshal back
var output map[string]any
if err := Unmarshal(data, &output); err != nil {
t.Fatalf("Unmarshal failed on generated output: %v\nOutput:\n%s", err, string(data))
}
// 3. Compare
if input["title"] != output["title"] {
t.Errorf("Title mismatch: %v != %v", input["title"], output["title"])
}
dbIn := input["database"].(map[string]any)
dbOut := output["database"].(map[string]any)
if dbIn["server"] != dbOut["server"] {
t.Error("Database server mismatch")
}
// Check quoted keys
qk := output["quoted-keys"].(map[string]any)
if qk["1234a"] != "alphanumeric starting with digit" {
t.Error("Failed to round-trip numeric-like key '1234a'")
}
if qk["true"] != "bool key" {
t.Error("Failed to round-trip boolean key 'true'")
}
}
func TestMarshal_Omitempty(t *testing.T) {
type Config struct {
Visible string `toml:"visible"`
Hidden string `toml:"hidden,omitempty"`
Zero int `toml:"zero,omitempty"`
}
cfg := Config{Visible: "here"}
b, err := Marshal(cfg)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
out := string(b)
if !strings.Contains(out, `visible = "here"`) {
t.Error("Visible field missing")
}
if strings.Contains(out, "hidden") {
t.Error("Hidden field present but should be omitted")
}
if strings.Contains(out, "zero") {
t.Error("Zero field present but should be omitted")
}
}
func TestMarshal_SkipNil(t *testing.T) {
type Config struct {
Ptr *int `toml:"ptr"`
}
cfg := Config{Ptr: nil}
b, err := Marshal(cfg)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
if len(b) > 0 {
t.Errorf("Expected empty output for nil pointer, got: %s", string(b))
}
}