680 lines
17 KiB
Go
680 lines
17 KiB
Go
package interpres
|
|
|
|
import (
|
|
"math"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestMarshalScalars(t *testing.T) {
|
|
type Cfg struct {
|
|
Title string `toml:"title"`
|
|
Count int `toml:"count"`
|
|
Unsigned uint64 `toml:"unsigned"`
|
|
Ratio float64 `toml:"ratio"`
|
|
Enabled bool `toml:"enabled"`
|
|
Disabled bool `toml:"disabled"`
|
|
}
|
|
out, err := Marshal(Cfg{
|
|
Title: "demo",
|
|
Count: 42,
|
|
Unsigned: 99,
|
|
Ratio: 3.14,
|
|
Enabled: true,
|
|
Disabled: false,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "title = \"demo\"\ncount = 42\nunsigned = 99\nratio = 3.14\nenabled = true\ndisabled = false\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalFloatSpecials(t *testing.T) {
|
|
type Cfg struct {
|
|
PosInf float64 `toml:"pos_inf"`
|
|
NegInf float64 `toml:"neg_inf"`
|
|
NaN float64 `toml:"nan"`
|
|
Zero float64 `toml:"zero"`
|
|
IntVal float64 `toml:"int_val"`
|
|
NegZ float64 `toml:"neg_zero"`
|
|
}
|
|
out, err := Marshal(Cfg{
|
|
PosInf: math.Inf(1),
|
|
NegInf: math.Inf(-1),
|
|
NaN: math.NaN(),
|
|
Zero: 0,
|
|
IntVal: 7,
|
|
NegZ: math.Copysign(0, -1),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "pos_inf = inf\nneg_inf = -inf\nnan = nan\nzero = 0.0\nint_val = 7.0\nneg_zero = 0.0\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalStringEscapes(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
in string
|
|
want string // the TOML scalar value (without "s = " prefix)
|
|
}{
|
|
{"plain", "hello", `"hello"`},
|
|
{"quote", `say "hi"`, `"say \"hi\""`},
|
|
{"backslash", `a\b`, `"a\\b"`},
|
|
{"newline", "line1\nline2", `"line1\nline2"`},
|
|
{"tab", "col1\tcol2", `"col1\tcol2"`},
|
|
{"cr", "line\rmore", `"line\rmore"`},
|
|
{"control", "a\x01b", `"a\u0001b"`},
|
|
{"unicode", "\u201csmart\u201d", `"“smart”"`}, // printable unicode; not escaped
|
|
{"empty", "", `""`},
|
|
{"slash_only", "a/b", `"a/b"`},
|
|
}
|
|
for _, c := range cases {
|
|
out, err := Marshal(struct {
|
|
S string `toml:"s"`
|
|
}{S: c.in})
|
|
if err != nil {
|
|
t.Fatalf("%s: marshal: %v", c.name, err)
|
|
}
|
|
got := strings.TrimSuffix(string(out), "\n")
|
|
want := "s = " + c.want
|
|
if got != want {
|
|
t.Errorf("%s:\ngot: %s\nwant: %s", c.name, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMarshalDateTime(t *testing.T) {
|
|
type Cfg struct {
|
|
Offset time.Time `toml:"offset"`
|
|
Local LocalDateTime `toml:"local"`
|
|
Day LocalDate `toml:"day"`
|
|
Clock LocalTime `toml:"clock"`
|
|
}
|
|
out, err := Marshal(Cfg{
|
|
Offset: time.Date(2026, 6, 26, 10, 0, 0, 0, time.UTC),
|
|
Local: LocalDateTime{Time: time.Date(2026, 6, 26, 7, 32, 0, 0, time.UTC)},
|
|
Day: LocalDate{Time: time.Date(2026, 6, 26, 0, 0, 0, 0, time.UTC)},
|
|
Clock: LocalTime{Time: time.Date(0, 1, 1, 7, 32, 0, 0, time.UTC)},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "offset = 2026-06-26T10:00:00Z\nlocal = 2026-06-26T07:32:00\nday = 2026-06-26\nclock = 07:32:00\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalDateTimeFractional(t *testing.T) {
|
|
out, err := Marshal(struct {
|
|
LDT LocalDateTime `toml:"ldt"`
|
|
LT LocalTime `toml:"lt"`
|
|
}{
|
|
LDT: LocalDateTime{Time: time.Date(2026, 6, 26, 7, 32, 0, 123456789, time.UTC)},
|
|
LT: LocalTime{Time: time.Date(0, 1, 1, 7, 32, 0, 123, time.UTC)},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "ldt = 2026-06-26T07:32:00.123456789\nlt = 07:32:00.000000123\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalArraysOfScalars(t *testing.T) {
|
|
type Cfg struct {
|
|
Tags []string `toml:"tags"`
|
|
Ports []int `toml:"ports"`
|
|
Mixed []any `toml:"mixed"`
|
|
Empty []int `toml:"empty"`
|
|
EmptyS []string `toml:"empty_s"`
|
|
}
|
|
out, err := Marshal(Cfg{
|
|
Tags: []string{"a", "b"},
|
|
Ports: []int{80, 443},
|
|
Mixed: []any{int64(1), "x", true},
|
|
Empty: nil,
|
|
EmptyS: []string{},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "tags = [\"a\", \"b\"]\nports = [80, 443]\nmixed = [1, \"x\", true]\nempty_s = []\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalNestedArrays(t *testing.T) {
|
|
type Cfg struct {
|
|
Matrix [][]int `toml:"matrix"`
|
|
Words [][]string `toml:"words"`
|
|
}
|
|
out, err := Marshal(Cfg{
|
|
Matrix: [][]int{{1, 2}, {3, 4}},
|
|
Words: [][]string{{"a", "b"}, {"c"}},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "matrix = [[1, 2], [3, 4]]\nwords = [[\"a\", \"b\"], [\"c\"]]\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalFloatExponentNoLeadingZero(t *testing.T) {
|
|
// strconv.FormatFloat with 'g' would produce "1e+06" (leading zero in
|
|
// exponent). The encoder must strip it so the output is "1e+6".
|
|
type Cfg struct {
|
|
Large float64 `toml:"large"`
|
|
Small float64 `toml:"small"`
|
|
}
|
|
out, err := Marshal(Cfg{Large: 1e6, Small: 1e-5})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
// Parse to check the output is valid TOML (for a strict parser that
|
|
// rejects leading zeros in exponents).
|
|
if _, err := Parse(out); err != nil {
|
|
t.Fatalf("marshalled output is not valid TOML:\n%s\nerror: %v", out, err)
|
|
}
|
|
if string(out) != "large = 1e+6\nsmall = 1e-5\n" {
|
|
t.Errorf("output mismatch:\ngot: %q", out)
|
|
}
|
|
}
|
|
|
|
func TestMarshalStructAsTable(t *testing.T) {
|
|
type Server struct {
|
|
Host string `toml:"host"`
|
|
Port int `toml:"port"`
|
|
}
|
|
type Cfg struct {
|
|
Title string `toml:"title"`
|
|
Server Server `toml:"server"`
|
|
}
|
|
out, err := Marshal(Cfg{
|
|
Title: "demo",
|
|
Server: Server{Host: "127.0.0.1", Port: 9090},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "title = \"demo\"\n\n[server]\nhost = \"127.0.0.1\"\nport = 9090\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalArrayOfTables(t *testing.T) {
|
|
type Item struct {
|
|
Name string `toml:"name"`
|
|
Qty int `toml:"qty"`
|
|
}
|
|
type Cfg struct {
|
|
Items []Item `toml:"items"`
|
|
}
|
|
out, err := Marshal(Cfg{
|
|
Items: []Item{
|
|
{Name: "a", Qty: 1},
|
|
{Name: "b", Qty: 2},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "[[items]]\nname = \"a\"\nqty = 1\n\n[[items]]\nname = \"b\"\nqty = 2\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalEmptyArrayOfTablesIsSkipped(t *testing.T) {
|
|
type Item struct {
|
|
Name string `toml:"name"`
|
|
}
|
|
type Cfg struct {
|
|
Title string `toml:"title"`
|
|
Items []Item `toml:"items"`
|
|
}
|
|
out, err := Marshal(Cfg{
|
|
Title: "demo",
|
|
Items: nil,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "title = \"demo\"\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalNestedTablesAndArrays(t *testing.T) {
|
|
type SMTP struct {
|
|
Host string `toml:"host"`
|
|
Port int `toml:"port"`
|
|
}
|
|
type Form struct {
|
|
Name string `toml:"name"`
|
|
SMTP SMTP `toml:"smtp"`
|
|
}
|
|
type Cfg struct {
|
|
Port int `toml:"port"`
|
|
Forms []Form `toml:"forms"`
|
|
}
|
|
out, err := Marshal(Cfg{
|
|
Port: 8080,
|
|
Forms: []Form{
|
|
{Name: "contact", SMTP: SMTP{Host: "h1", Port: 587}},
|
|
{Name: "feedback", SMTP: SMTP{Host: "h2", Port: 25}},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "port = 8080\n\n[[forms]]\nname = \"contact\"\n\n[forms.smtp]\nhost = \"h1\"\nport = 587\n\n[[forms]]\nname = \"feedback\"\n\n[forms.smtp]\nhost = \"h2\"\nport = 25\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalStructTags(t *testing.T) {
|
|
type Cfg struct {
|
|
Keep string `toml:"keep"`
|
|
Rename string `toml:"renamed"`
|
|
Skip string `toml:"-"`
|
|
Untagged string
|
|
}
|
|
out, err := Marshal(Cfg{
|
|
Keep: "k", Rename: "r", Skip: "s", Untagged: "u",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "keep = \"k\"\nrenamed = \"r\"\nuntagged = \"u\"\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalEmbeddedStructPromoted(t *testing.T) {
|
|
type Base struct {
|
|
ID int `toml:"id"`
|
|
}
|
|
type Derived struct {
|
|
Base
|
|
Name string `toml:"name"`
|
|
}
|
|
out, err := Marshal(Derived{Base: Base{ID: 1}, Name: "x"})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "id = 1\nname = \"x\"\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalEmbeddedStructAsTable(t *testing.T) {
|
|
type Inner struct {
|
|
Host string `toml:"host"`
|
|
}
|
|
type Cfg struct {
|
|
Inner Inner `toml:"inner"`
|
|
Name string `toml:"name"`
|
|
}
|
|
out, err := Marshal(Cfg{Inner: Inner{Host: "h"}, Name: "n"})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "name = \"n\"\n\n[inner]\nhost = \"h\"\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalMapKeysSorted(t *testing.T) {
|
|
m := map[string]any{
|
|
"zeta": 1,
|
|
"alpha": 2,
|
|
"mu": 3,
|
|
}
|
|
out, err := Marshal(m)
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "alpha = 2\nmu = 3\nzeta = 1\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalMapWithSubMap(t *testing.T) {
|
|
m := map[string]any{
|
|
"meta": map[string]any{"x": 1, "y": 2},
|
|
"a": "z",
|
|
}
|
|
out, err := Marshal(m)
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "a = \"z\"\n\n[meta]\nx = 1\ny = 2\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalMarshaler(t *testing.T) {
|
|
type Port int
|
|
type Cfg struct {
|
|
P Port `toml:"p"`
|
|
}
|
|
out, err := Marshal(Cfg{P: 8080})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "p = 8080\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalMarshalerReturningScalar(t *testing.T) {
|
|
type Wrapped struct {
|
|
Value string `toml:"value"`
|
|
}
|
|
type Alias struct{}
|
|
out, err := Marshal(struct {
|
|
W Wrapped `toml:"w"`
|
|
}{W: Wrapped{Value: "hello"}})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "[w]\nvalue = \"hello\"\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
_ = Alias{}
|
|
}
|
|
|
|
func TestMarshalMarshalerReturningDifferentShape(t *testing.T) {
|
|
out, err := Marshal(struct {
|
|
C Custom `toml:"c"`
|
|
}{C: Custom{tag: "x"}})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
// Custom returns a string from MarshalTOML.
|
|
want := "c = \"x\"\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalNilPointerFieldSkipped(t *testing.T) {
|
|
type Cfg struct {
|
|
Name string `toml:"name"`
|
|
Hidden *string `toml:"hidden"`
|
|
}
|
|
out, err := Marshal(Cfg{Name: "x"})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "name = \"x\"\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalNonNilPointerFollowed(t *testing.T) {
|
|
v := "v"
|
|
type Cfg struct {
|
|
Name string `toml:"name"`
|
|
Hidden *string `toml:"hidden"`
|
|
}
|
|
out, err := Marshal(Cfg{Name: "n", Hidden: &v})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "name = \"n\"\nhidden = \"v\"\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalTopLevelMustBeStructOrMap(t *testing.T) {
|
|
if _, err := Marshal(42); err == nil {
|
|
t.Errorf("expected error marshalling int at top level")
|
|
}
|
|
if _, err := Marshal("hello"); err == nil {
|
|
t.Errorf("expected error marshalling string at top level")
|
|
}
|
|
if _, err := Marshal(nil); err == nil {
|
|
t.Errorf("expected error marshalling nil")
|
|
}
|
|
}
|
|
|
|
func TestMarshalMapKeyMustBeString(t *testing.T) {
|
|
m := map[int]any{1: "x"}
|
|
if _, err := Marshal(m); err == nil {
|
|
t.Errorf("expected error for non-string map key")
|
|
}
|
|
}
|
|
|
|
func TestMarshalUnexportedFieldSkipped(t *testing.T) {
|
|
type Cfg struct {
|
|
Pub string `toml:"pub"`
|
|
priv string
|
|
}
|
|
out, err := Marshal(Cfg{Pub: "p", priv: "s"})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "pub = \"p\"\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalBareAndQuotedKeys(t *testing.T) {
|
|
type Cfg struct {
|
|
Bare string `toml:"bare_key"`
|
|
Dash string `toml:"with-dash"`
|
|
Num string `toml:"num123"`
|
|
Q string `toml:"needs space"`
|
|
Dot string `toml:"needs.dot"`
|
|
}
|
|
out, err := Marshal(Cfg{
|
|
Bare: "a", Dash: "b", Num: "c", Q: "d", Dot: "e",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
want := "bare_key = \"a\"\nwith-dash = \"b\"\nnum123 = \"c\"\n\"needs space\" = \"d\"\n\"needs.dot\" = \"e\"\n"
|
|
if string(out) != want {
|
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
|
}
|
|
}
|
|
|
|
func TestMarshalThenParseRoundTrip(t *testing.T) {
|
|
type Server struct {
|
|
Host string `toml:"host"`
|
|
Port int `toml:"port"`
|
|
Enabled bool `toml:"enabled"`
|
|
Tags []string `toml:"tags"`
|
|
}
|
|
type Form struct {
|
|
Name string `toml:"name"`
|
|
Allowed []string `toml:"allowed"`
|
|
}
|
|
type Cfg struct {
|
|
Title string `toml:"title"`
|
|
Count int `toml:"count"`
|
|
Ratio float64 `toml:"ratio"`
|
|
Server Server `toml:"server"`
|
|
Forms []Form `toml:"forms"`
|
|
Due time.Time `toml:"due"`
|
|
Day LocalDate `toml:"day"`
|
|
}
|
|
in := Cfg{
|
|
Title: "demo",
|
|
Count: 42,
|
|
Ratio: 3.14,
|
|
Server: Server{
|
|
Host: "127.0.0.1", Port: 9090, Enabled: true,
|
|
Tags: []string{"a", "b"},
|
|
},
|
|
Forms: []Form{
|
|
{Name: "contact", Allowed: []string{"x"}},
|
|
{Name: "feedback", Allowed: nil},
|
|
},
|
|
Due: time.Date(2026, 6, 26, 10, 0, 0, 0, time.UTC),
|
|
Day: LocalDate{Time: time.Date(2026, 6, 26, 0, 0, 0, 0, time.UTC)},
|
|
}
|
|
out, err := Marshal(in)
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
tree1, err := Parse(out)
|
|
if err != nil {
|
|
t.Fatalf("parse of marshalled: %v\noutput:\n%s", err, out)
|
|
}
|
|
// Decode back into the struct.
|
|
var out2 Cfg
|
|
if err := Unmarshal(out, &out2); err != nil {
|
|
t.Fatalf("unmarshal of marshalled: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(in, out2) {
|
|
t.Errorf("round-trip mismatch:\nin: %#v\nout: %#v", in, out2)
|
|
}
|
|
_ = tree1
|
|
}
|
|
|
|
func TestMarshalRoundTripFromUntypedTree(t *testing.T) {
|
|
src := []byte(`title = "demo"
|
|
count = 42
|
|
ratio = 3.14
|
|
enabled = true
|
|
|
|
[server]
|
|
host = "127.0.0.1"
|
|
port = 9090
|
|
|
|
[[items]]
|
|
name = "a"
|
|
qty = 1
|
|
|
|
[[items]]
|
|
name = "b"
|
|
qty = 2
|
|
|
|
[meta]
|
|
created = 2026-06-26T10:00:00Z
|
|
`)
|
|
tree1, err := Parse(src)
|
|
if err != nil {
|
|
t.Fatalf("parse src: %v", err)
|
|
}
|
|
out, err := Marshal(tree1)
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
tree2, err := Parse(out)
|
|
if err != nil {
|
|
t.Fatalf("re-parse marshalled: %v\noutput:\n%s", err, out)
|
|
}
|
|
if !reflect.DeepEqual(tree1, tree2) {
|
|
t.Errorf("round-trip mismatch:\nbefore: %#v\nafter: %#v", tree1, tree2)
|
|
}
|
|
}
|
|
|
|
func TestMarshalUintOverflow(t *testing.T) {
|
|
type Cfg struct {
|
|
Big uint64 `toml:"big"`
|
|
}
|
|
if _, err := Marshal(Cfg{Big: 1<<63 + 1}); err == nil {
|
|
t.Errorf("expected overflow error")
|
|
}
|
|
}
|
|
|
|
func TestMarshalKeyRequiresUTF8(t *testing.T) {
|
|
m := map[string]any{"\xff": "x"}
|
|
if _, err := Marshal(m); err == nil {
|
|
t.Errorf("expected error for invalid UTF-8 key")
|
|
}
|
|
}
|
|
|
|
func TestMarshalStringRequiresUTF8(t *testing.T) {
|
|
type Cfg struct {
|
|
S string `toml:"s"`
|
|
}
|
|
if _, err := Marshal(Cfg{S: "abc\xff"}); err == nil {
|
|
t.Errorf("expected error for invalid UTF-8 string")
|
|
}
|
|
}
|
|
|
|
func TestLocalDateString(t *testing.T) {
|
|
ld := LocalDate{Time: time.Date(1979, 5, 27, 0, 0, 0, 0, time.UTC)}
|
|
if got := ld.String(); got != "1979-05-27" {
|
|
t.Errorf("LocalDate.String() = %q, want 1979-05-27", got)
|
|
}
|
|
}
|
|
|
|
func TestLocalDateTimeString(t *testing.T) {
|
|
ldt := LocalDateTime{Time: time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC)}
|
|
if got := ldt.String(); got != "1979-05-27T07:32:00" {
|
|
t.Errorf("LocalDateTime.String() = %q, want 1979-05-27T07:32:00", got)
|
|
}
|
|
ldt2 := LocalDateTime{Time: time.Date(1979, 5, 27, 7, 32, 0, 5, time.UTC)}
|
|
if got := ldt2.String(); got != "1979-05-27T07:32:00.000000005" {
|
|
t.Errorf("LocalDateTime.String() = %q, want 1979-05-27T07:32:00.000000005", got)
|
|
}
|
|
ldt3 := LocalDateTime{Time: time.Date(1979, 5, 27, 7, 32, 0, 500, time.UTC)}
|
|
if got := ldt3.String(); got != "1979-05-27T07:32:00.000000500" {
|
|
t.Errorf("LocalDateTime.String() = %q, want 1979-05-27T07:32:00.000000500", got)
|
|
}
|
|
}
|
|
|
|
func TestLocalTimeString(t *testing.T) {
|
|
lt := LocalTime{Time: time.Date(0, 1, 1, 7, 32, 0, 0, time.UTC)}
|
|
if got := lt.String(); got != "07:32:00" {
|
|
t.Errorf("LocalTime.String() = %q, want 07:32:00", got)
|
|
}
|
|
}
|
|
|
|
func TestEncoderEquivalenceToMarshal(t *testing.T) {
|
|
type Cfg struct {
|
|
Title string `toml:"title"`
|
|
Count int `toml:"count"`
|
|
}
|
|
in := Cfg{Title: "x", Count: 7}
|
|
a, err := Marshal(in)
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
b, err := NewEncoder().Marshal(in)
|
|
if err != nil {
|
|
t.Fatalf("encoder marshal: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(a, b) {
|
|
t.Errorf("Marshal and Encoder disagree:\n%s\n%s", a, b)
|
|
}
|
|
}
|
|
|
|
type Custom struct {
|
|
tag string
|
|
}
|
|
|
|
func (c Custom) MarshalTOML() (any, error) { return c.tag, nil }
|