diff --git a/src/pcap/PcapOutput.test.ts b/src/pcap/PcapOutput.test.ts index fffaf0f4c7..3f0c0637f3 100644 --- a/src/pcap/PcapOutput.test.ts +++ b/src/pcap/PcapOutput.test.ts @@ -581,6 +581,25 @@ it("accepts exact machine packet counts and rejects scaled human counts", () => ); }); +it.each([ + ["0", 0], + ["1.250 seconds", 1.25], + ["2 second", 2], + ["n/a", null], + ["-1 seconds", null], + [`${"9".repeat(309)} seconds`, null], +] as const)( + "retains finite capinfos duration %s and preserves other metadata", + (duration, expected) => { + const metadata = parseCapinfosOutput( + `File type: pcap\nFile encapsulation: Ethernet\nNumber of packets: 2\nCapture duration: ${duration}\nPacket size limit: file hdr: 65535 bytes\n`, + ); + expect(metadata.captureDurationSeconds).toBe(expected); + expect(metadata.packetCount).toBe(2); + expect(metadata.snapshotLength).toBe(65535); + }, +); + it("excludes transport credentials without normalizing observed URL bytes", async () => { const result = await parseTsharkJsonOutput( capture([ diff --git a/src/pcap/PcapOutput.ts b/src/pcap/PcapOutput.ts index 4ab714fd05..3b73f2dd45 100644 --- a/src/pcap/PcapOutput.ts +++ b/src/pcap/PcapOutput.ts @@ -104,6 +104,7 @@ export const parseCapinfosOutput = (stdout: string): CapinfosMetadata => { durationText === undefined ? null : /^(\d+(?:\.\d+)?)(?:\s+seconds?)?$/u.exec(durationText); + const durationSeconds = duration === null ? null : Number(duration[1]); const snapshot = /^file hdr:\s*(\d+) bytes$/u.exec( lines.get("Packet size limit") ?? "", ); @@ -121,7 +122,10 @@ export const parseCapinfosOutput = (stdout: string): CapinfosMetadata => { captureEnd: captureInstant( lines.get("Latest packet time") ?? lines.get("Last packet time"), ), - captureDurationSeconds: duration === null ? null : Number(duration[1]), + captureDurationSeconds: + durationSeconds !== null && Number.isFinite(durationSeconds) + ? durationSeconds + : null, snapshotLength: snapshotLength !== null && Number.isSafeInteger(snapshotLength) &&