90 lines
3.0 KiB
Go
90 lines
3.0 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package interpres
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// errReader fails every read with a fixed error.
|
|
type errReader struct{ err error }
|
|
|
|
func (r errReader) Read([]byte) (int, error) { return 0, r.err }
|
|
|
|
// TestUnmarshalRead covers the streaming entry: the happy path with options,
|
|
// a failing reader, and MaxInputSize bounding what a reader is drained into.
|
|
func TestUnmarshalRead(t *testing.T) {
|
|
var got struct {
|
|
Name string `toml:"name"`
|
|
N int `toml:"n"`
|
|
}
|
|
err := UnmarshalRead(strings.NewReader("name = \"x\"\n"), &got, RejectUnknownFields(true))
|
|
if err != nil {
|
|
t.Fatalf("UnmarshalRead: %v", err)
|
|
}
|
|
if got.Name != "x" {
|
|
t.Errorf("Name = %q", got.Name)
|
|
}
|
|
|
|
readErr := errors.New("boom")
|
|
if err := UnmarshalRead(errReader{readErr}, &got); !errors.Is(err, readErr) {
|
|
t.Errorf("err = %v, want the read error wrapped", err)
|
|
}
|
|
|
|
err = UnmarshalRead(strings.NewReader("name = \"x\"\n"), &got, MaxInputSize(4))
|
|
if err == nil || !strings.Contains(err.Error(), "over the limit") {
|
|
t.Errorf("err = %v, want the size limit", err)
|
|
}
|
|
// The limit bounds the read itself: a reader that would supply far more
|
|
// than the limit is not drained into memory first.
|
|
big := strings.Repeat("x", 1<<20)
|
|
if err := UnmarshalRead(strings.NewReader(big), &got, MaxInputSize(16)); err == nil || !strings.Contains(err.Error(), "over the limit") {
|
|
t.Errorf("err = %v, want the size limit before the read completes", err)
|
|
}
|
|
}
|
|
|
|
// TestParseAsWithOptions covers the generic shorthand carrying options.
|
|
func TestParseAsWithOptions(t *testing.T) {
|
|
type cfg struct {
|
|
Name string `toml:"name"`
|
|
}
|
|
got, err := ParseAs[cfg]([]byte("name = \"x\"\nrogue = 1\n"), RejectUnknownFields(true))
|
|
if err == nil || !strings.Contains(err.Error(), "unknown field") {
|
|
t.Errorf("err = %v, want the strict failure", err)
|
|
}
|
|
// The statements before the failure stay written, the contract the
|
|
// targeted path documents and encoding/json follows.
|
|
if got.Name != "x" {
|
|
t.Errorf("Name = %q, want the statement before the failure kept", got.Name)
|
|
}
|
|
}
|
|
|
|
// TestStatementsValueArrays pins that a value array is one statement, a
|
|
// scalar array and an array of inline tables alike; only an array of tables
|
|
// yields per element.
|
|
func TestStatementsValueArrays(t *testing.T) {
|
|
src := strings.NewReader("port = [8080, 9090]\nmix = [{y = 1, x = 2}]\n[[items]]\nn = 1\n")
|
|
var got []Statement
|
|
for stmt, err := range Statements(src) {
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got = append(got, stmt)
|
|
}
|
|
if len(got) != 3 {
|
|
t.Fatalf("got %d statements, want 3", len(got))
|
|
}
|
|
if got[0].Index != -1 || got[0].Table != nil {
|
|
t.Errorf("port statement = %+v, want one plain key/value", got[0])
|
|
}
|
|
if got[1].Index != -1 || got[1].Table != nil {
|
|
t.Errorf("mix statement = %+v, want one plain key/value", got[1])
|
|
}
|
|
if got[2].Index != 0 || got[2].Table == nil {
|
|
t.Errorf("items statement = %+v, want the element with its node", got[2])
|
|
}
|
|
}
|