import { describe, expect, it } from "vitest";
import type { GridApiResponse } from "./tvlistings.js";
import {
buildChannelsXml,
buildProgrammesXml,
buildXmltv,
escapeXml,
formatDate,
} from "./xmltv.js";
const mockData: GridApiResponse = {
channels: [
{
callSign: "KOMODT",
affiliateName: "AMERICAN BROADCASTING COMPANY",
affiliateCallSign: null,
channelId: "19629",
channelNo: "4.1",
events: [
{
callSign: "KOMODT",
duration: "60",
startTime: "2025-07-18T19:00:00Z",
endTime: "2025-07-18T20:00:00Z",
thumbnail: "p30687311_b_v13_aa",
channelNo: "4.1",
filter: ["filter-news"],
seriesId: "SH05918266",
rating: "TV-PG",
flag: ["New"],
tags: ["Stereo", "CC"],
program: {
title: "GMA3",
id: "EP059182660025",
tmsId: "EP059182660025",
shortDesc:
"BIA performs; comic Zarna Garg; lifestyle contributor Lori Bergamotto; ABC News chief medical correspondent Dr. Tara Narula.",
season: "5",
releaseYear: null,
episode: "217",
episodeTitle: "Special Episode",
seriesId: "SH05918266",
isGeneric: "0",
},
},
],
id: "196290",
stationGenres: [false],
stationFilters: ["filter-news", "filter-talk"],
thumbnail:
"//zap2it.tmsimg.com/h3/NowShowing/19629/s28708_ll_h15_ac.png?w=55",
},
],
};
describe("buildXmltv", () => {
it("should generate valid XML structure", () => {
const result = buildXmltv(mockData);
expect(result).toContain('');
expect(result).toContain('');
expect(result).toContain("");
});
it("should include channel information", () => {
const result = buildXmltv(mockData);
expect(result).toContain('');
expect(result).toContain("KOMODT");
expect(result).toContain(
"AMERICAN BROADCASTING COMPANY",
);
expect(result).toContain("4.1");
});
it("should include programme information", () => {
const result = buildXmltv(mockData);
expect(result).toContain(
'',
);
expect(result).toContain("GMA3");
expect(result).toContain("Special Episode");
expect(result).toContain(
"BIA performs; comic Zarna Garg; lifestyle contributor Lori Bergamotto; ABC News chief medical correspondent Dr. Tara Narula.",
);
});
it("should include rating information", () => {
const result = buildXmltv(mockData);
expect(result).toContain("TV-PG");
});
it("should include categories from flags and tags", () => {
const result = buildXmltv(mockData);
expect(result).toContain("New");
expect(result).toContain("Stereo");
expect(result).toContain("CC");
});
it("should include episode information", () => {
const result = buildXmltv(mockData);
expect(result).toContain('5');
expect(result).toContain('217');
expect(result).toContain(
'SH05918266',
);
});
it("should handle empty data gracefully", () => {
const emptyData: GridApiResponse = { channels: [] };
const result = buildXmltv(emptyData);
expect(result).toContain('');
expect(result).toContain('');
expect(result).toContain("");
expect(result).not.toContain(" {
const minimalData: GridApiResponse = {
channels: [
{
callSign: "TEST",
affiliateName: "",
affiliateCallSign: null,
channelId: "123",
channelNo: "",
events: [
{
callSign: "TEST",
duration: "30",
startTime: "2025-07-18T19:00:00Z",
endTime: "2025-07-18T19:30:00Z",
thumbnail: "",
channelNo: "",
filter: [],
seriesId: "",
rating: "",
flag: [],
tags: [],
program: {
title: "Test Show",
id: "TEST123",
tmsId: "TEST123",
shortDesc: "",
season: "",
releaseYear: null,
episode: "",
episodeTitle: null,
seriesId: "",
isGeneric: "0",
},
},
],
id: "123",
stationGenres: [],
stationFilters: [],
thumbnail: "",
},
],
};
const result = buildXmltv(minimalData);
expect(result).toContain('');
expect(result).toContain("TEST");
expect(result).toContain(
'',
);
expect(result).toContain("Test Show");
expect(result).not.toContain("");
expect(result).not.toContain("");
expect(result).not.toContain("");
expect(result).not.toContain("");
expect(result).not.toContain(" {
it("should escape XML special characters", () => {
expect(escapeXml("&")).toBe("&");
expect(escapeXml("<")).toBe("<");
expect(escapeXml(">")).toBe(">");
expect(escapeXml('"')).toBe(""");
expect(escapeXml("'")).toBe("'");
});
it("should handle text with multiple special characters", () => {
expect(escapeXml("A & B < C > D \"E\" 'F'")).toBe(
"A & B < C > D "E" 'F'",
);
});
it("should handle normal text without special characters", () => {
expect(escapeXml("Normal text")).toBe("Normal text");
});
it("should handle empty string", () => {
expect(escapeXml("")).toBe("");
});
});
describe("formatDate", () => {
it("should format ISO date string correctly", () => {
expect(formatDate("2025-07-18T19:00:00Z")).toBe("20250718190000 +0000");
expect(formatDate("2025-12-31T23:59:59Z")).toBe("20251231235959 +0000");
});
it("should handle different times", () => {
expect(formatDate("2025-01-01T00:00:00Z")).toBe("20250101000000 +0000");
expect(formatDate("2025-06-15T12:30:45Z")).toBe("20250615123045 +0000");
});
it("should handle edge cases", () => {
expect(formatDate("2025-02-28T23:59:59Z")).toBe("20250228235959 +0000");
expect(formatDate("2025-03-01T00:00:00Z")).toBe("20250301000000 +0000");
});
});
describe("buildChannelsXml", () => {
it("should build channel XML correctly", () => {
const result = buildChannelsXml(mockData);
expect(result).toContain('');
expect(result).toContain("KOMODT");
expect(result).toContain(
"AMERICAN BROADCASTING COMPANY",
);
expect(result).toContain("4.1");
expect(result).toContain(
'',
);
});
it("should handle channels without optional fields", () => {
const minimalChannel: GridApiResponse = {
channels: [
{
callSign: "TEST",
affiliateName: "",
affiliateCallSign: null,
channelId: "123",
channelNo: "",
events: [],
id: "123",
stationGenres: [],
stationFilters: [],
thumbnail: "",
},
],
};
const result = buildChannelsXml(minimalChannel);
expect(result).toContain('');
expect(result).toContain("TEST");
expect(result).not.toContain(" {
it("should build programme XML correctly", () => {
const result = buildProgrammesXml(mockData);
expect(result).toContain(
'',
);
expect(result).toContain("GMA3");
expect(result).toContain("Special Episode");
expect(result).toContain(
"BIA performs; comic Zarna Garg; lifestyle contributor Lori Bergamotto; ABC News chief medical correspondent Dr. Tara Narula.",
);
expect(result).toContain("TV-PG");
expect(result).toContain("New");
expect(result).toContain("Stereo");
expect(result).toContain("CC");
expect(result).toContain('5');
expect(result).toContain('217');
expect(result).toContain(
'SH05918266',
);
expect(result).toContain('');
});
it("should handle programmes without optional fields", () => {
const minimalProgramme: GridApiResponse = {
channels: [
{
callSign: "TEST",
affiliateName: "",
affiliateCallSign: null,
channelId: "123",
channelNo: "",
events: [
{
callSign: "TEST",
duration: "30",
startTime: "2025-07-18T19:00:00Z",
endTime: "2025-07-18T19:30:00Z",
thumbnail: "",
channelNo: "",
filter: [],
seriesId: "",
rating: "",
flag: [],
tags: [],
program: {
title: "Test Show",
id: "TEST123",
tmsId: "TEST123",
shortDesc: "",
season: "",
releaseYear: null,
episode: "",
episodeTitle: null,
seriesId: "",
isGeneric: "0",
},
},
],
id: "123",
stationGenres: [],
stationFilters: [],
thumbnail: "",
},
],
};
const result = buildProgrammesXml(minimalProgramme);
expect(result).toContain(
'',
);
expect(result).toContain("Test Show");
expect(result).not.toContain("");
expect(result).not.toContain("");
expect(result).not.toContain("");
expect(result).not.toContain("");
expect(result).not.toContain("