Assisted-by: DeepSeek V4.1 Flash
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -283,3 +284,165 @@ func TestUnknownFlagReturnsTwo(t *testing.T) {
|
||||
t.Fatalf("Run returned %d, want 2; stderr = %q", code, stderr.String())
|
||||
}
|
||||
}
|
||||
|
||||
// --- encoder mode ----------------------------------------------------------
|
||||
|
||||
func TestRunEncoderScalars(t *testing.T) {
|
||||
in := `{
|
||||
"s": {"type": "string", "value": "quote \" and backslash \\"},
|
||||
"nl": {"type": "string", "value": "line1\nline2"},
|
||||
"i": {"type": "integer", "value": "-9223372036854775808"},
|
||||
"g": {"type": "float", "value": "1.5"},
|
||||
"f": {"type": "float", "value": "inf"},
|
||||
"b": {"type": "bool", "value": "false"},
|
||||
"dt": {"type": "datetime", "value": "1979-05-27T07:32:00-07:00"},
|
||||
"ldt": {"type": "datetime-local", "value": "1979-05-27T07:32:00"},
|
||||
"ld": {"type": "date-local", "value": "1979-05-27"},
|
||||
"lt": {"type": "time-local", "value": "07:32:00.999"}
|
||||
}
|
||||
`
|
||||
var stdout, stderr bytes.Buffer
|
||||
code := Run([]string{"-encode"}, strings.NewReader(in), &stdout, &stderr)
|
||||
if code != 0 {
|
||||
t.Fatalf("Run returned %d, stderr = %q", code, stderr.String())
|
||||
}
|
||||
want := "b = false\n" +
|
||||
"dt = 1979-05-27T07:32:00-07:00\n" +
|
||||
"f = inf\n" +
|
||||
"g = 1.5\n" +
|
||||
"i = -9223372036854775808\n" +
|
||||
"ld = 1979-05-27\n" +
|
||||
"ldt = 1979-05-27T07:32:00\n" +
|
||||
"lt = 07:32:00.999000000\n" +
|
||||
"nl = \"line1\\nline2\"\n" +
|
||||
"s = \"quote \\\" and backslash \\\\\"\n"
|
||||
if stdout.String() != want {
|
||||
t.Errorf("output mismatch:\ngot: %q\nwant: %q", stdout.String(), want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunEncoderNested(t *testing.T) {
|
||||
in := `{
|
||||
"tbl": {"x": {"type": "bool", "value": "true"},
|
||||
"sub": {"y": {"type": "integer", "value": "1"}}},
|
||||
"items": [{"n": {"type": "string", "value": "a"}},
|
||||
{"n": {"type": "string", "value": "b"}}],
|
||||
"list": [{"type": "integer", "value": "1"}, {"type": "string", "value": "two"}],
|
||||
"emptyTbl": {},
|
||||
"emptyArr": []
|
||||
}
|
||||
`
|
||||
var stdout, stderr bytes.Buffer
|
||||
code := Run([]string{"-encode"}, strings.NewReader(in), &stdout, &stderr)
|
||||
if code != 0 {
|
||||
t.Fatalf("Run returned %d, stderr = %q", code, stderr.String())
|
||||
}
|
||||
want := "emptyArr = []\n" +
|
||||
"list = [1, \"two\"]\n" +
|
||||
"\n[emptyTbl]\n" +
|
||||
"\n[tbl]\nx = true\n" +
|
||||
"\n[tbl.sub]\ny = 1\n" +
|
||||
"\n[[items]]\nn = \"a\"\n" +
|
||||
"\n[[items]]\nn = \"b\"\n"
|
||||
if stdout.String() != want {
|
||||
t.Errorf("output mismatch:\ngot: %q\nwant: %q", stdout.String(), want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunEncoderFloatTagDecides(t *testing.T) {
|
||||
// A float with no fraction is described by a bare integer literal, so the
|
||||
// tag decides the type; the output must stay a float.
|
||||
var stdout, stderr bytes.Buffer
|
||||
in := `{"whole": {"type": "float", "value": "1"}, "exp": {"type": "float", "value": "5e+22"}}`
|
||||
code := Run([]string{"-encode"}, strings.NewReader(in), &stdout, &stderr)
|
||||
if code != 0 {
|
||||
t.Fatalf("Run returned %d, stderr = %q", code, stderr.String())
|
||||
}
|
||||
if want := "exp = 5e+22\nwhole = 1.0\n"; stdout.String() != want {
|
||||
t.Errorf("output mismatch:\ngot: %q\nwant: %q", stdout.String(), want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunEncoderRejectsBadInput(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
in string
|
||||
want string
|
||||
}{
|
||||
{"not-json", "not json", "decode JSON"},
|
||||
{"top-level-array", `[{"type": "integer", "value": "1"}]`, "must be a JSON object"},
|
||||
{"untagged-scalar", `{"x": 1}`, "unsupported JSON value"},
|
||||
{"literal-mismatch", `{"x": {"type": "integer", "value": "1.5"}}`, "parsed as float64"},
|
||||
{"offset-for-local", `{"x": {"type": "datetime-local", "value": "1979-05-27T07:32:00Z"}}`, "parsed as time.Time"},
|
||||
{"bad-literal", `{"x": {"type": "date-local", "value": "nope"}}`, "date-local"},
|
||||
{"smuggled-statement", `{"x": {"type": "integer", "value": "1\nx = 2"}}`, "not a single bare value"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
var stdout, stderr bytes.Buffer
|
||||
code := Run([]string{"-encode"}, strings.NewReader(c.in), &stdout, &stderr)
|
||||
if code != 2 {
|
||||
t.Errorf("%s: Run returned %d, want 2; stderr = %q", c.name, code, stderr.String())
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(stderr.String(), c.want) {
|
||||
t.Errorf("%s: stderr = %q, want it to mention %q", c.name, stderr.String(), c.want)
|
||||
}
|
||||
if stdout.Len() != 0 {
|
||||
t.Errorf("%s: stdout should be empty, got %q", c.name, stdout.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunEncoderFlagConflicts(t *testing.T) {
|
||||
var stdout, stderr bytes.Buffer
|
||||
if code := Run([]string{"-encode", "-validate"}, strings.NewReader(""), &stdout, &stderr); code != 2 {
|
||||
t.Errorf("Run returned %d, want 2 for the two modes together", code)
|
||||
}
|
||||
if !strings.Contains(stderr.String(), "cannot be combined") {
|
||||
t.Errorf("stderr = %q, want it to explain the conflict", stderr.String())
|
||||
}
|
||||
|
||||
stdout.Reset()
|
||||
stderr.Reset()
|
||||
if code := Run([]string{"-encode", "file.json"}, strings.NewReader(""), &stdout, &stderr); code != 2 {
|
||||
t.Errorf("Run returned %d, want 2 for an argument", code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeAfterDecodeRoundTrip(t *testing.T) {
|
||||
doc := `title = "x"
|
||||
flt = 1.5
|
||||
whole = 7.0
|
||||
big = 9223372036854775807
|
||||
when = 1979-05-27T07:32:00-07:00
|
||||
day = 1979-05-27
|
||||
clock = 07:32:00.999
|
||||
list = [1, "two"]
|
||||
multi = "a\nb"
|
||||
|
||||
[tbl]
|
||||
x = true
|
||||
|
||||
[[items]]
|
||||
n = "a"
|
||||
`
|
||||
var tagged, stderr bytes.Buffer
|
||||
if code := Run(nil, strings.NewReader(doc), &tagged, &stderr); code != 0 {
|
||||
t.Fatalf("decode returned %d, stderr = %q", code, stderr.String())
|
||||
}
|
||||
var out bytes.Buffer
|
||||
if code := Run([]string{"-encode"}, bytes.NewReader(tagged.Bytes()), &out, &stderr); code != 0 {
|
||||
t.Fatalf("encode returned %d, stderr = %q", code, stderr.String())
|
||||
}
|
||||
want, err := interpres.Parse([]byte(doc))
|
||||
if err != nil {
|
||||
t.Fatalf("parse of the original: %v", err)
|
||||
}
|
||||
got, err := interpres.Parse(out.Bytes())
|
||||
if err != nil {
|
||||
t.Fatalf("parse of the encoder output (%q): %v", out.String(), err)
|
||||
}
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Errorf("round trip changed the document:\noriginal: %#v\nencoded: %#v\noutput: %q", want, got, out.String())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user