@@ -41,9 +41,14 @@ type ParseTest struct {
4141 EndLine string
4242 Corrupted bool
4343 Suppressed bool
44- HasReport bool
45- Report []byte
44+
45+ // HasReport is in charge of both Report and TailReports.
46+ HasReport bool
47+ Report []byte
48+ TailReports [][]byte
49+
4650 Executor string
51+ ContextIDs []string
4752 // Only used in report parsing:
4853 corruptedReason string
4954}
@@ -64,6 +69,9 @@ func (test *ParseTest) Equal(other *ParseTest) bool {
6469 if test .HasReport && ! bytes .Equal (test .Report , other .Report ) {
6570 return false
6671 }
72+ if test .HasReport && ! reflect .DeepEqual (test .TailReports , other .TailReports ) {
73+ return false
74+ }
6775 return test .Executor == other .Executor
6876}
6977
@@ -90,6 +98,9 @@ func (test *ParseTest) Headers() []byte {
9098 if test .Executor != "" {
9199 fmt .Fprintf (buf , "EXECUTOR: %s\n " , test .Executor )
92100 }
101+ if len (test .ContextIDs ) != 0 {
102+ fmt .Fprintf (buf , "CONTEXTS: %v\n " , test .ContextIDs )
103+ }
93104 return buf .Bytes ()
94105}
95106
@@ -98,8 +109,8 @@ func testParseFile(t *testing.T, reporter *Reporter, fn string) {
98109 testParseImpl (t , reporter , test )
99110}
100111
101- func parseReport (t * testing.T , reporter * Reporter , fn string ) * ParseTest {
102- data , err := os .ReadFile (fn )
112+ func parseReport (t * testing.T , reporter * Reporter , testFileName string ) * ParseTest {
113+ data , err := os .ReadFile (testFileName )
103114 if err != nil {
104115 t .Fatal (err )
105116 }
@@ -109,10 +120,11 @@ func parseReport(t *testing.T, reporter *Reporter, fn string) *ParseTest {
109120 phaseHeaders = iota
110121 phaseLog
111122 phaseReport
123+ phaseTailReports
112124 )
113125 phase := phaseHeaders
114126 test := & ParseTest {
115- FileName : fn ,
127+ FileName : testFileName ,
116128 }
117129 prevEmptyLine := false
118130 s := bufio .NewScanner (bytes .NewReader (data ))
@@ -134,8 +146,20 @@ func parseReport(t *testing.T, reporter *Reporter, fn string) *ParseTest {
134146 test .Log = append (test .Log , '\n' )
135147 }
136148 case phaseReport :
137- test .Report = append (test .Report , s .Bytes ()... )
138- test .Report = append (test .Report , '\n' )
149+ if string (s .Bytes ()) == "TAIL REPORTS:" {
150+ test .TailReports = [][]byte {{}}
151+ phase = phaseTailReports
152+ } else {
153+ test .Report = append (test .Report , s .Bytes ()... )
154+ test .Report = append (test .Report , '\n' )
155+ }
156+ case phaseTailReports :
157+ if string (s .Bytes ()) == reportSeparator {
158+ test .TailReports = append (test .TailReports , []byte {})
159+ continue
160+ }
161+ test .TailReports [len (test .TailReports )- 1 ] = append (test .TailReports [len (test .TailReports )- 1 ], s .Bytes ()... )
162+ test .TailReports [len (test .TailReports )- 1 ] = append (test .TailReports [len (test .TailReports )- 1 ], []byte {'\n' }... )
139163 }
140164 prevEmptyLine = len (s .Bytes ()) == 0
141165 }
@@ -160,6 +184,7 @@ func parseHeaderLine(t *testing.T, test *ParseTest, ln string) {
160184 corruptedPrefix = "CORRUPTED: "
161185 suppressedPrefix = "SUPPRESSED: "
162186 executorPrefix = "EXECUTOR: "
187+ contextidPrefix = "CONTEXTS: "
163188 )
164189 switch {
165190 case strings .HasPrefix (ln , "#" ):
@@ -195,60 +220,72 @@ func parseHeaderLine(t *testing.T, test *ParseTest, ln string) {
195220 }
196221 case strings .HasPrefix (ln , executorPrefix ):
197222 test .Executor = ln [len (executorPrefix ):]
223+ case strings .HasPrefix (ln , contextidPrefix ):
224+ test .ContextIDs = strings .Split (ln [len (contextidPrefix ):], ", " )
198225 default :
199226 t .Fatalf ("unknown header field %q" , ln )
200227 }
201228}
202229
203- func testFromReport ( rep * Report ) * ParseTest {
204- if rep == nil {
230+ func testFromReports ( reps ... * Report ) * ParseTest {
231+ if reps == nil || len ( reps ) > 0 && reps [ 0 ] == nil {
205232 return & ParseTest {}
206233 }
207234 ret := & ParseTest {
208- Title : rep .Title ,
209- AltTitles : rep .AltTitles ,
210- Corrupted : rep .Corrupted ,
211- corruptedReason : rep .CorruptedReason ,
212- Suppressed : rep .Suppressed ,
213- Type : crash .TitleToType (rep .Title ),
214- Frame : rep .Frame ,
215- Report : rep .Report ,
216- }
217- if rep .Executor != nil {
218- ret .Executor = fmt .Sprintf ("proc=%d, id=%d" , rep .Executor .ProcID , rep .Executor .ExecID )
235+ Title : reps [ 0 ] .Title ,
236+ AltTitles : reps [ 0 ] .AltTitles ,
237+ Corrupted : reps [ 0 ] .Corrupted ,
238+ corruptedReason : reps [ 0 ] .CorruptedReason ,
239+ Suppressed : reps [ 0 ] .Suppressed ,
240+ Type : crash .TitleToType (reps [ 0 ] .Title ),
241+ Frame : reps [ 0 ] .Frame ,
242+ Report : reps [ 0 ] .Report ,
243+ }
244+ if reps [ 0 ] .Executor != nil {
245+ ret .Executor = fmt .Sprintf ("proc=%d, id=%d" , reps [ 0 ] .Executor .ProcID , reps [ 0 ] .Executor .ExecID )
219246 }
220247 sort .Strings (ret .AltTitles )
248+ ret .ContextIDs = append (ret .ContextIDs , reps [0 ].ContextID )
249+ for i := 1 ; i < len (reps ); i ++ {
250+ ret .TailReports = append (ret .TailReports , reps [i ].Report )
251+ ret .ContextIDs = append (ret .ContextIDs , reps [i ].ContextID )
252+ }
221253 return ret
222254}
223255
224256func testParseImpl (t * testing.T , reporter * Reporter , test * ParseTest ) {
225- rep := reporter .Parse (test .Log )
257+ gotReports := ParseAll (reporter , test .Log , 0 )
258+
259+ var firstReport * Report
260+ if len (gotReports ) > 0 {
261+ firstReport = gotReports [0 ]
262+ }
226263 containsCrash := reporter .ContainsCrash (test .Log )
227264 expectCrash := (test .Title != "" )
228265 if expectCrash && ! containsCrash {
229266 t .Fatalf ("did not find crash" )
230267 }
231268 if ! expectCrash && containsCrash {
232- t .Fatalf ("found unexpected crash" )
269+ t .Fatalf ("found unexpected crash: %s" , firstReport . Title )
233270 }
234- if rep != nil && rep .Title == "" {
271+ if firstReport != nil && firstReport .Title == "" {
235272 t .Fatalf ("found crash, but title is empty" )
236273 }
237- parsed := testFromReport ( rep )
274+ parsed := testFromReports ( gotReports ... )
238275 if ! test .Equal (parsed ) {
239276 if * flagUpdate && test .StartLine + test .EndLine == "" {
240277 updateReportTest (t , test , parsed )
241278 }
242279 t .Fatalf ("want:\n %s\n got:\n %sCorrupted reason: %q" ,
243280 test .Headers (), parsed .Headers (), parsed .corruptedReason )
244281 }
245- if parsed .Title != "" && len (rep .Report ) == 0 {
282+ if parsed .Title != "" && len (firstReport .Report ) == 0 {
246283 t .Fatalf ("found crash message but report is empty" )
247284 }
248- if rep == nil {
285+ if firstReport == nil {
249286 return
250287 }
251- checkReport (t , reporter , rep , test )
288+ checkReport (t , reporter , firstReport , test )
252289}
253290
254291func checkReport (t * testing.T , reporter * Reporter , rep * Report , test * ParseTest ) {
@@ -285,11 +322,6 @@ func checkReport(t *testing.T, reporter *Reporter, rep *Report, test *ParseTest)
285322 if rep1 == nil || rep1 .Title != rep .Title || rep1 .StartPos != rep .StartPos {
286323 t .Fatalf ("did not find the same report from rep.StartPos=%v" , rep .StartPos )
287324 }
288- // If we parse from EndPos, we must not find the same report.
289- rep2 := reporter .ParseFrom (test .Log , rep .EndPos )
290- if rep2 != nil && rep2 .Title == rep .Title {
291- t .Fatalf ("found the same report after rep.EndPos=%v" , rep .EndPos )
292- }
293325 }
294326}
295327
@@ -303,6 +335,10 @@ func updateReportTest(t *testing.T, test, parsed *ParseTest) {
303335 fmt .Fprintf (buf , "\n %s" , test .Log )
304336 if test .HasReport {
305337 fmt .Fprintf (buf , "REPORT:\n %s" , parsed .Report )
338+ if len (parsed .TailReports ) > 0 {
339+ fmt .Fprintf (buf , "TAIL REPORTS:\n " )
340+ buf .Write (bytes .Join (parsed .TailReports , []byte (reportSeparator + "\n " )))
341+ }
306342 }
307343 if err := os .WriteFile (test .FileName , buf .Bytes (), 0640 ); err != nil {
308344 t .Logf ("failed to update test file: %v" , err )
@@ -395,7 +431,7 @@ func testSymbolizeFile(t *testing.T, reporter *Reporter, fn string) {
395431 if err != nil {
396432 t .Fatalf ("failed to symbolize: %v" , err )
397433 }
398- parsed := testFromReport (rep )
434+ parsed := testFromReports (rep )
399435 if ! test .Equal (parsed ) {
400436 if * flagUpdate {
401437 updateReportTest (t , test , parsed )
0 commit comments