DMRmap/frontend/src/cps-anytone.test.ts
2026-02-19 17:00:59 +01:00

104 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, it, expect } from "vitest";
import { generateAnytoneContactsCsv, generateAnytoneChannelsCsv, ANYTONE_CH_HEADER } from "./cps-anytone";
import type { Repeater, CpsTalkgroup } from "./types";
const makeRepeater = (overrides: Partial<Repeater> = {}): Repeater => ({
id: 1, callsign: "DB0ABC", freq_tx: 439.5, freq_rx: 431.9,
freq_offset: "-7.6", band: "70cm", lat: 52.5, lng: 13.4,
city: "Berlin", state: "Berlin", country: "Germany", color_code: 1,
ts_linked: "1,2", trustee: "DL1ABC", ipsc_network: "BrandMeister",
networks: ["BrandMeister"], hotspot: 0, status: "On-air",
last_seen: null, bm_status: 1, bm_status_text: "Connected",
hardware: "", firmware: "", pep: 0, agl: 0, website: "", description: "",
import_freq_inconsistent: false, inactive: false, last_polled: null,
...overrides,
});
describe("generateAnytoneContactsCsv", () => {
const tgs: CpsTalkgroup[] = [
{ id: 262, name: "TG262 Deutschlan", slot: "1" },
{ id: 2628, name: "TG2628 Bayern", slot: "1" },
];
it("generates CSV with correct header", () => {
const csv = generateAnytoneContactsCsv(tgs);
const lines = csv.split("\r\n");
expect(lines[0]).toBe("No.,Radio ID,Name,Call Type,Call Alert");
});
it("generates correct data rows", () => {
const csv = generateAnytoneContactsCsv(tgs);
const lines = csv.split("\r\n");
expect(lines).toHaveLength(3); // header + 2 rows
expect(lines[1]).toBe("1,262,TG262 Deutschlan,Group Call,None");
expect(lines[2]).toBe("2,2628,TG2628 Bayern,Group Call,None");
});
it("uses TG ID as fallback name", () => {
const tg: CpsTalkgroup[] = [{ id: 99999, name: "", slot: "1" }];
const csv = generateAnytoneContactsCsv(tg);
expect(csv).toContain("TG99999");
});
it("has 5 columns per row", () => {
const csv = generateAnytoneContactsCsv(tgs);
const lines = csv.split("\r\n");
for (const line of lines) {
expect(line.split(",")).toHaveLength(5);
}
});
});
describe("generateAnytoneChannelsCsv", () => {
const tgs: CpsTalkgroup[] = [
{ id: 262, name: "TG262", slot: "1" },
];
const repeaters = [makeRepeater()];
it("generates CSV with correct header", () => {
const csv = generateAnytoneChannelsCsv(repeaters, tgs);
const lines = csv.split("\r\n");
expect(lines[0]).toBe(ANYTONE_CH_HEADER);
});
it("creates one row per repeater × talkgroup", () => {
const tgs2: CpsTalkgroup[] = [
{ id: 262, name: "TG262", slot: "1" },
{ id: 2628, name: "TG2628", slot: "2" },
];
const csv = generateAnytoneChannelsCsv(repeaters, tgs2);
const lines = csv.split("\r\n");
expect(lines).toHaveLength(3); // header + 2 channels
});
it("has 55 columns per row (matching header)", () => {
const csv = generateAnytoneChannelsCsv(repeaters, tgs);
const lines = csv.split("\r\n");
const headerCols = lines[0].split(",").length;
expect(headerCols).toBe(55);
for (let i = 1; i < lines.length; i++) {
expect(lines[i].split(",")).toHaveLength(headerCols);
}
});
it("includes correct frequencies", () => {
const csv = generateAnytoneChannelsCsv(repeaters, tgs);
expect(csv).toContain("439.500000");
expect(csv).toContain("431.900000");
});
it("includes color code and timeslot", () => {
const csv = generateAnytoneChannelsCsv(repeaters, tgs);
const lines = csv.split("\r\n");
const cols = lines[1].split(",");
// Color code at index 20, slot at index 21
expect(cols[20]).toBe("1");
expect(cols[21]).toBe("1");
});
});
describe("ANYTONE_CH_HEADER", () => {
it("has 55 columns", () => {
expect(ANYTONE_CH_HEADER.split(",")).toHaveLength(55);
});
});