import { describe, beforeEach, it, expect, vi, afterEach } from "vitest";
import type { ITNode } from "../../../../../../utils/xml-parser";
import { parseXml } from "../../../../../../utils/xml-parser";
import parseContentProtection from "../ContentProtection";
const mocks = vi.hoisted(() => {
return {
hexToBytes: vi.fn(),
};
});
vi.mock("../../../../../../utils/string_parsing", () => ({
hexToBytes: mocks.hexToBytes,
}));
function testStringAttribute(attributeName: string, variableName?: string): void {
const _variableName = variableName ?? attributeName;
it(`should correctly parse a ContentProtection element with a correct ${attributeName} attribute`, () => {
const element1 = parseXml(
``,
)[0] as ITNode;
expect(parseContentProtection(element1)).toEqual([
{ attributes: { [_variableName]: "foobar" }, children: { cencPssh: [] } },
[],
]);
const element2 = parseXml(``)[0] as ITNode;
expect(parseContentProtection(element2)).toEqual([
{ attributes: { [_variableName]: "" }, children: { cencPssh: [] } },
[],
]);
});
}
describe("DASH Node Parsers - ContentProtection", () => {
beforeEach(() => {
vi.resetModules();
});
afterEach(() => {
mocks.hexToBytes.mockReset();
});
it("should correctly parse a ContentProtection element without attributes", () => {
const element = parseXml("")[0] as ITNode;
expect(parseContentProtection(element)).toEqual([
{ attributes: {}, children: { cencPssh: [] } },
[],
]);
});
testStringAttribute("schemeIdUri");
testStringAttribute("value");
it("should correctly parse a ContentProtection element with a correct cenc:default_KID attribute", () => {
const keyId = new Uint8Array([0, 1, 2, 3]);
mocks.hexToBytes.mockImplementation(() => {
return keyId;
});
const element1 = parseXml(
'',
)[0] as ITNode;
expect(parseContentProtection(element1)).toEqual([
{ attributes: { keyId }, children: { cencPssh: [] } },
[],
]);
expect(mocks.hexToBytes).toHaveBeenCalledTimes(1);
expect(mocks.hexToBytes).toHaveBeenCalledWith("deadbeef");
});
it("should correctly parse a ContentProtection with every attributes", () => {
const keyId = new Uint8Array([0, 1, 2, 3]);
mocks.hexToBytes.mockImplementation(() => {
return keyId;
});
const element = parseXml(
``,
)[0] as ITNode;
expect(parseContentProtection(element)).toEqual([
{
attributes: { keyId, schemeIdUri: "foo", value: "bar" },
children: { cencPssh: [] },
},
[],
]);
});
it("should correctly parse a ContentProtection with cenc:pssh children", () => {
const element = parseXml(
`
AABBCC
AAABAC
`,
)[0] as ITNode;
expect(parseContentProtection(element)).toEqual([
{
attributes: {},
children: {
cencPssh: [new Uint8Array([0, 0, 65, 8]), new Uint8Array([0, 0, 1, 0])],
},
},
[],
]);
});
it("should correctly parse a ContentProtection with both cenc:pssh children and every attributes", () => {
const keyId = new Uint8Array([0, 1, 2, 3]);
mocks.hexToBytes.mockImplementation(() => {
return keyId;
});
const element = parseXml(
`
AABBCC
AAABAC
`,
)[0] as ITNode;
expect(parseContentProtection(element)).toEqual([
{
attributes: { keyId, schemeIdUri: "foo", value: "bar" },
children: {
cencPssh: [new Uint8Array([0, 0, 65, 8]), new Uint8Array([0, 0, 1, 0])],
},
},
[],
]);
});
it("should return a warning if one of the cenc:pssh is invalid base64", () => {
const element = parseXml(
`
AA!BCC
AAABAC
`,
)[0] as ITNode;
const parsed = parseContentProtection(element);
expect(parsed[0]).toEqual({
attributes: {},
children: { cencPssh: [new Uint8Array([0, 0, 1, 0])] },
});
expect(parsed[1]).not.toBe(null);
expect(parsed[1]).toHaveLength(1);
expect(parsed[1][0]).toBeInstanceOf(Error);
expect(parsed[1][0].message).toEqual(
'`cenc:pssh` is not a valid base64 string: "AA!BCC"',
);
});
});