From 6f80c5700f899d360742c6dbd5ee8c944d5297cb Mon Sep 17 00:00:00 2001 From: hbc Date: Thu, 30 Jan 2025 16:56:28 -0800 Subject: [PATCH] fix: empty document should not panic on String() (#630) fixes #629 --- ast/ast.go | 4 +++- parser/parser_test.go | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/ast/ast.go b/ast/ast.go index 7f342275..d9607fa9 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -576,7 +576,9 @@ func (d *DocumentNode) String() string { if d.Start != nil { doc = append(doc, d.Start.Value) } - doc = append(doc, d.Body.String()) + if d.Body != nil { + doc = append(doc, d.Body.String()) + } if d.End != nil { doc = append(doc, d.End.Value) } diff --git a/parser/parser_test.go b/parser/parser_test.go index 8a809253..487bfe10 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -16,6 +16,7 @@ import ( func TestParser(t *testing.T) { sources := []string{ + "", "null\n", "0_", "{}\n", @@ -144,12 +145,52 @@ foo: zzz `, } for _, src := range sources { - if _, err := parser.Parse(lexer.Tokenize(src), 0); err != nil { + f, err := parser.Parse(lexer.Tokenize(src), 0) + if err != nil { t.Fatalf("parse error: source [%s]: %+v", src, err) } + _ = f.String() // ensure no panic } } +func TestParseEmptyDocument(t *testing.T) { + t.Run("empty document", func(t *testing.T) { + f, err := parser.ParseBytes([]byte(""), parser.ParseComments) + if err != nil { + t.Fatal(err) + } + got := f.String() + expected := "\n" + if got != expected { + t.Fatalf("failed to parse comment:\nexpected:\n%q\ngot:\n%q", expected, got) + } + }) + + t.Run("empty document with comment (parse comment = off)", func(t *testing.T) { + f, err := parser.ParseBytes([]byte("# comment"), 0) + if err != nil { + t.Fatal(err) + } + got := f.String() + expected := "\n" + if got != expected { + t.Fatalf("failed to parse comment:\nexpected:\n%q\ngot:\n%q", expected, got) + } + }) + + t.Run("empty document with comment (parse comment = on)", func(t *testing.T) { + f, err := parser.ParseBytes([]byte("# comment"), parser.ParseComments) + if err != nil { + t.Fatal(err) + } + got := f.String() + expected := "# comment\n" + if got != expected { + t.Fatalf("failed to parse comment:\nexpected:\n%q\ngot:\n%q", expected, got) + } + }) +} + func TestParseComplicatedDocument(t *testing.T) { tests := []struct { source string