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"', ); }); });