| 346 | } |
| 347 | |
| 348 | func writeFailuresNDJSON(path string, failures []failure, capBytes int) error { |
| 349 | var output bytes.Buffer |
| 350 | for index, item := range failures { |
| 351 | recordLine, err := marshalRecord(failureRecord{ |
| 352 | Package: item.Package, |
| 353 | Test: item.Test, |
| 354 | ElapsedS: item.Elapsed, |
| 355 | Output: strings.ToValidUTF8(item.Output, ""), |
| 356 | }) |
| 357 | if err != nil { |
| 358 | return err |
| 359 | } |
| 360 | if output.Len()+len(recordLine) <= capBytes { |
| 361 | _, _ = output.Write(recordLine) |
| 362 | continue |
| 363 | } |
| 364 | |
| 365 | remainingAfterCurrent := len(failures) - index - 1 |
| 366 | summaryLine, err := marshalRecord(truncationRecord{Truncated: true, RemainingFailures: remainingAfterCurrent}) |
| 367 | if err != nil { |
| 368 | return err |
| 369 | } |
| 370 | availableForRecord := capBytes - output.Len() |
| 371 | if remainingAfterCurrent > 0 { |
| 372 | availableForRecord -= len(summaryLine) |
| 373 | } |
| 374 | truncatedLine, ok, err := truncateFailureRecord(item, availableForRecord) |
| 375 | if err != nil { |
| 376 | return err |
| 377 | } |
| 378 | if ok { |
| 379 | _, _ = output.Write(truncatedLine) |
| 380 | if remainingAfterCurrent > 0 && output.Len()+len(summaryLine) <= capBytes { |
| 381 | _, _ = output.Write(summaryLine) |
| 382 | } |
| 383 | break |
| 384 | } |
| 385 | |
| 386 | summaryLine, err = marshalRecord(truncationRecord{Truncated: true, RemainingFailures: len(failures) - index}) |
| 387 | if err != nil { |
| 388 | return err |
| 389 | } |
| 390 | if output.Len()+len(summaryLine) <= capBytes { |
| 391 | _, _ = output.Write(summaryLine) |
| 392 | } |
| 393 | break |
| 394 | } |
| 395 | return os.WriteFile(path, output.Bytes(), 0o600) |
| 396 | } |
| 397 | |
| 398 | type failureRecord struct { |
| 399 | Package string `json:"package"` |