diff --git a/internal/engine/engine_test.go b/internal/engine/engine_test.go index 5f90d1de..2cfe3834 100644 --- a/internal/engine/engine_test.go +++ b/internal/engine/engine_test.go @@ -104,6 +104,33 @@ func TestStart_FastPath_InvalidJSON(t *testing.T) { assert.Len(t, errs, 1, "Expected one error message") } +func TestStart_EmptyInput(t *testing.T) { + tests := []struct { + name string + input string + }{ + {"empty", ""}, + {"whitespace", " "}, + {"newlines", "\n\t\n"}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + parser := jsonx.NewJsonParser(strings.NewReader(tc.input), false) + + var errs []string + opts := engine.Options{ + WriteOut: func(s string) {}, + WriteErr: func(s string) { errs = append(errs, s) }, + } + exitCode := engine.Start(parser, []string{"."}, opts) + + assert.Equal(t, 1, exitCode) + assert.Len(t, errs, 1) + }) + } +} + func TestStart_EscapeSequences(t *testing.T) { input := `{"emoji": "\ud83d\ude80"}` parser := jsonx.NewJsonParser(strings.NewReader(input), false) diff --git a/internal/jsonx/json.go b/internal/jsonx/json.go index 561d8c24..5c5217e5 100644 --- a/internal/jsonx/json.go +++ b/internal/jsonx/json.go @@ -52,10 +52,11 @@ func (p *JsonParser) Parse() (node *Node, err error) { err = p.errorSnippet(fmt.Sprintf("%v", r)) } }() - if p.count > 0 { - p.skipWhitespace() - } + p.skipWhitespace() if p.eof { + if p.count == 0 { + return nil, fmt.Errorf("empty input") + } return nil, io.EOF } node = p.parseValue(true) @@ -79,7 +80,7 @@ func (p *JsonParser) Recover() *Node { } end := p.end - 1 - if p.data[end-1] == '\n' { + if end > 0 && p.data[end-1] == '\n' { end-- // Trim trailing newline. } diff --git a/internal/jsonx/jsonx_test.go b/internal/jsonx/jsonx_test.go index 4ff7f592..2e2a5da3 100644 --- a/internal/jsonx/jsonx_test.go +++ b/internal/jsonx/jsonx_test.go @@ -56,6 +56,9 @@ func TestJsonParser_Parse_error(t *testing.T) { tests := []struct { input string }{ + {``}, + {` `}, + {"\n\t\n"}, {`"abc`}, {`truth`}, {`1e`},