import { beforeEach, describe, expect, it, vi } from "vitest";
import { parseDockerLogs, parseTimeSpec } from "./log-parser.js";
describe("parseTimeSpec", () => {
beforeEach(() => {
// Mock Date.now() to a known value for consistent testing
vi.setSystemTime(new Date("2024-01-01T12:00:00Z"));
});
it("should parse relative time in seconds", (): void => {
const result = parseTimeSpec("30s");
const expected = Math.floor(new Date("2024-01-01T11:59:30Z").getTime() / 1000);
expect(result).toBe(expected);
});
it("should parse relative time in minutes", (): void => {
const result = parseTimeSpec("10m");
const expected = Math.floor(new Date("2024-01-01T11:50:00Z").getTime() / 1000);
expect(result).toBe(expected);
});
it("should parse relative time in hours", (): void => {
const result = parseTimeSpec("2h");
const expected = Math.floor(new Date("2024-01-01T10:00:00Z").getTime() / 1000);
expect(result).toBe(expected);
});
it("should parse relative time in days", (): void => {
const result = parseTimeSpec("1d");
const expected = Math.floor(new Date("2023-12-31T12:00:00Z").getTime() / 1000);
expect(result).toBe(expected);
});
it("should parse absolute ISO timestamp", (): void => {
const result = parseTimeSpec("2024-01-01T10:00:00Z");
const expected = Math.floor(new Date("2024-01-01T10:00:00Z").getTime() / 1000);
expect(result).toBe(expected);
});
it("should parse absolute timestamp with milliseconds", (): void => {
const result = parseTimeSpec("2024-01-01T10:00:00.123Z");
const expected = Math.floor(new Date("2024-01-01T10:00:00.123Z").getTime() / 1000);
expect(result).toBe(expected);
});
});
describe("parseDockerLogs", () => {
it("should parse logs with timestamps", (): void => {
const raw = "2024-01-01T12:00:00.000Z Hello world\n2024-01-01T12:00:01.000Z Second line";
const result = parseDockerLogs(raw);
expect(result).toHaveLength(2);
expect(result[0]).toEqual({
timestamp: "2024-01-01T12:00:00.000Z",
stream: "stdout",
message: "Hello world",
});
expect(result[1]).toEqual({
timestamp: "2024-01-01T12:00:01.000Z",
stream: "stdout",
message: "Second line",
});
});
it("should handle logs without timestamps", (): void => {
const raw = "Plain log message";
const result = parseDockerLogs(raw);
expect(result).toHaveLength(1);
expect(result[0].message).toBe("Plain log message");
expect(result[0].stream).toBe("stdout");
// Timestamp should be current time (we're not mocking for this test)
expect(result[0].timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T/);
});
it("should handle empty input", (): void => {
const result = parseDockerLogs("");
expect(result).toHaveLength(0);
});
it("should filter out empty lines", (): void => {
const raw = "2024-01-01T12:00:00.000Z First\n\n\n2024-01-01T12:00:01.000Z Second";
const result = parseDockerLogs(raw);
expect(result).toHaveLength(2);
expect(result[0].message).toBe("First");
expect(result[1].message).toBe("Second");
});
it("should handle mixed timestamped and plain logs", (): void => {
const raw = "2024-01-01T12:00:00.000Z Timestamped\nPlain message";
const result = parseDockerLogs(raw);
expect(result).toHaveLength(2);
expect(result[0].timestamp).toBe("2024-01-01T12:00:00.000Z");
expect(result[0].message).toBe("Timestamped");
expect(result[1].message).toBe("Plain message");
});
it("should handle logs with only whitespace", (): void => {
const raw = " \n \t \n ";
const result = parseDockerLogs(raw);
expect(result).toHaveLength(0);
});
});