@@ -62,3 +62,123 @@ func TestDockerFileFormat(t *testing.T) {
6262 assert .Equal (t , message .StatusInfo , msg .Status )
6363 assert .Equal (t , "2019-06-06T16:35:55.930852915Z" , msg .ParsingExtra .Timestamp )
6464}
65+
66+ func TestDockerFileFormatNullJSON (t * testing.T ) {
67+ parser := New ()
68+
69+ // This test reproduces the bug found by fuzzing - JSON unmarshal succeeds
70+ // but returns nil, causing a panic when accessing log.Stream
71+ // Examples: the JSON literal null, arrays, primitives, etc.
72+ testCases := []struct {
73+ name string
74+ input []byte
75+ }{
76+ {
77+ name : "JSON literal null" ,
78+ input : []byte (`null` ),
79+ },
80+ {
81+ name : "JSON array" ,
82+ input : []byte (`[]` ),
83+ },
84+ {
85+ name : "JSON string" ,
86+ input : []byte (`"string"` ),
87+ },
88+ {
89+ name : "JSON number" ,
90+ input : []byte (`123` ),
91+ },
92+ {
93+ name : "JSON boolean true" ,
94+ input : []byte (`true` ),
95+ },
96+ {
97+ name : "JSON boolean false" ,
98+ input : []byte (`false` ),
99+ },
100+ }
101+
102+ for _ , tc := range testCases {
103+ t .Run (tc .name , func (t * testing.T ) {
104+ logMessage := message .NewMessage (tc .input , nil , "" , 0 )
105+
106+ // This should not panic
107+ assert .NotPanics (t , func () {
108+ msg , err := parser .Parse (logMessage )
109+ // Should return an error for these cases
110+ assert .NotNil (t , err )
111+ assert .Equal (t , message .StatusInfo , msg .Status )
112+ assert .Equal (t , tc .input , msg .GetContent ())
113+ })
114+ })
115+ }
116+ }
117+
118+ func TestDockerFileFormatMultipleNewlines (t * testing.T ) {
119+ parser := New ()
120+
121+ // This test documents the parser's behavior with newlines. The parser
122+ // strips exactly ONE trailing newline (the line terminator). Multiple
123+ // newlines represent actual content (empty lines).
124+ testCases := []struct {
125+ name string
126+ input []byte
127+ expectedContent []byte
128+ expectedPartial bool
129+ }{
130+ {
131+ name : "empty log without newline" ,
132+ input : []byte (`{"log":"","stream":"stdout","time":"2019-06-06T16:35:55.930852911Z"}` ),
133+ expectedContent : []byte ("" ),
134+ expectedPartial : false , // Empty content is not partial
135+ },
136+ {
137+ name : "single newline" ,
138+ input : []byte (`{"log":"\n","stream":"stdout","time":"2019-06-06T16:35:55.930852911Z"}` ),
139+ expectedContent : []byte ("" ),
140+ expectedPartial : false ,
141+ },
142+ {
143+ name : "double newline" ,
144+ input : []byte (`{"log":"\n\n","stream":"stdout","time":"2019-06-06T16:35:55.930852911Z"}` ),
145+ expectedContent : []byte ("\n " ),
146+ expectedPartial : false ,
147+ },
148+ {
149+ name : "triple newline" ,
150+ input : []byte (`{"log":"\n\n\n","stream":"stdout","time":"2019-06-06T16:35:55.930852911Z"}` ),
151+ expectedContent : []byte ("\n \n " ),
152+ expectedPartial : false ,
153+ },
154+ {
155+ name : "text with trailing newline" ,
156+ input : []byte (`{"log":"hello\n","stream":"stdout","time":"2019-06-06T16:35:55.930852911Z"}` ),
157+ expectedContent : []byte ("hello" ),
158+ expectedPartial : false ,
159+ },
160+ {
161+ name : "text with multiple trailing newlines" ,
162+ input : []byte (`{"log":"hello\n\n","stream":"stdout","time":"2019-06-06T16:35:55.930852911Z"}` ),
163+ expectedContent : []byte ("hello\n " ),
164+ expectedPartial : false ,
165+ },
166+ {
167+ name : "text without trailing newline" ,
168+ input : []byte (`{"log":"hello","stream":"stdout","time":"2019-06-06T16:35:55.930852911Z"}` ),
169+ expectedContent : []byte ("hello" ),
170+ expectedPartial : true ,
171+ },
172+ }
173+
174+ for _ , tc := range testCases {
175+ t .Run (tc .name , func (t * testing.T ) {
176+ logMessage := message .NewMessage (tc .input , nil , "" , 0 )
177+ msg , err := parser .Parse (logMessage )
178+ assert .Nil (t , err )
179+ assert .Equal (t , tc .expectedContent , msg .GetContent ())
180+ assert .Equal (t , tc .expectedPartial , msg .ParsingExtra .IsPartial )
181+ assert .Equal (t , message .StatusInfo , msg .Status )
182+ })
183+ }
184+ }
0 commit comments