rx-player
Version:
Canal+ HTML5 Video Player
349 lines (322 loc) • 10.9 kB
text/typescript
import { describe, beforeEach, it, expect, vi } from "vitest";
import {
createFRMABox,
createFreeBox,
createHDLRBox,
createMDHDBox,
createSMHDBox,
createVMHDBox,
} from "../create_boxes";
const mocks = vi.hoisted(() => {
return {
isobmff: {
createBox: vi.fn(),
},
byteParsing: {
itobe2: vi.fn(),
itobe4: vi.fn(),
itobe8: vi.fn(),
le2toi: vi.fn(),
be2toi: vi.fn(),
be3toi: vi.fn(),
be4toi: vi.fn(),
be8toi: vi.fn(),
concat: vi.fn(),
be4toiSigned: vi.fn(),
},
stringParsing: {
strToUtf8: vi.fn(),
bytesToHex: vi.fn(),
guidToUuid: vi.fn(),
utf16LEToStr: vi.fn(),
hexToBytes: vi.fn(),
readNullTerminatedString: vi.fn(),
},
};
});
vi.mock("../../../../parsers/containers/isobmff", () => ({
createBox: mocks.isobmff.createBox,
}));
vi.mock("../../../../utils/byte_parsing", () => ({
itobe2: mocks.byteParsing.itobe2,
itobe4: mocks.byteParsing.itobe4,
itobe8: mocks.byteParsing.itobe8,
le2toi: mocks.byteParsing.le2toi,
be2toi: mocks.byteParsing.be2toi,
be3toi: mocks.byteParsing.be3toi,
be4toi: mocks.byteParsing.be4toi,
be8toi: mocks.byteParsing.be8toi,
concat: mocks.byteParsing.concat,
be4toiSigned: mocks.byteParsing.be4toiSigned,
}));
vi.mock("../../../../utils/string_parsing", () => ({
strToUtf8: mocks.stringParsing.strToUtf8,
bytesToHex: mocks.stringParsing.bytesToHex,
guidToUuid: mocks.stringParsing.guidToUuid,
utf16LEToStr: mocks.stringParsing.utf16LEToStr,
hexToBytes: mocks.stringParsing.hexToBytes,
readNullTerminatedString: mocks.stringParsing.readNullTerminatedString,
}));
describe("Smooth - ISOBMFF - boxes creation", () => {
beforeEach(async () => {
vi.resetModules();
const actualIsobmff = await vi.importActual("../../../../parsers/containers/isobmff");
const actualByteParsing = await vi.importActual("../../../../utils/byte_parsing");
const actualStringParsing = await vi.importActual("../../../../utils/string_parsing");
const isobmffKeys = Object.keys(mocks.isobmff) as Array<keyof typeof mocks.isobmff>;
isobmffKeys.forEach((key: keyof typeof mocks.isobmff) => {
mocks.isobmff[key].mockReset();
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
mocks.isobmff[key].mockImplementation(actualIsobmff[key] as (...args: any) => any);
});
const byteParsingKeys = Object.keys(mocks.byteParsing) as Array<
keyof typeof mocks.byteParsing
>;
byteParsingKeys.forEach((key: keyof typeof mocks.byteParsing) => {
mocks.byteParsing[key].mockReset();
mocks.byteParsing[key].mockImplementation(
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
actualByteParsing[key] as (...args: any) => any,
);
});
const stringParsingKeys = Object.keys(mocks.stringParsing) as Array<
keyof typeof mocks.stringParsing
>;
stringParsingKeys.forEach((key: keyof typeof mocks.stringParsing) => {
mocks.stringParsing[key].mockReset();
mocks.stringParsing[key].mockImplementation(
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
actualStringParsing[key] as (...args: any) => any,
);
});
});
describe("createVMHDBox", () => {
it("should create always the same vmhd box", () => {
const vmhdContent = new Uint8Array([0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
const box = new Uint8Array([1, 2, 3, 4]);
mocks.isobmff.createBox.mockImplementation(() => box);
expect(createVMHDBox()).toBe(box);
expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1);
expect(mocks.isobmff.createBox).toHaveBeenCalledWith("vmhd", vmhdContent);
});
});
describe("createFreeBox", () => {
it("should create box full of 0s", () => {
const box = new Uint8Array([1, 2, 3, 4]);
mocks.isobmff.createBox.mockImplementation(() => box);
expect(createFreeBox(8)).toBe(box);
expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1);
expect(mocks.isobmff.createBox).toHaveBeenCalledWith("free", new Uint8Array([]));
expect(createFreeBox(15)).toBe(box);
expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(2);
expect(mocks.isobmff.createBox).toHaveBeenCalledWith("free", new Uint8Array(7));
});
it("should throw when given a length below 8", () => {
const box = new Uint8Array([1, 2, 3, 4]);
mocks.isobmff.createBox.mockImplementation(() => box);
expect(() => createFreeBox(7)).toThrow();
expect(() => createFreeBox(6)).toThrow();
expect(() => createFreeBox(5)).toThrow();
expect(() => createFreeBox(4)).toThrow();
expect(() => createFreeBox(3)).toThrow();
expect(() => createFreeBox(2)).toThrow();
expect(() => createFreeBox(1)).toThrow();
expect(() => createFreeBox(0)).toThrow();
expect(mocks.isobmff.createBox).not.toHaveBeenCalled();
});
it("should throw when given a negative length", () => {
const box = new Uint8Array([1, 2, 3, 4]);
mocks.isobmff.createBox.mockImplementation(() => box);
expect(() => createFreeBox(-1)).toThrow();
expect(mocks.isobmff.createBox).not.toHaveBeenCalled();
});
it("should throw when given a non-finite length", () => {
const box = new Uint8Array([1, 2, 3, 4]);
mocks.isobmff.createBox.mockImplementation(() => box);
expect(() => createFreeBox(-Infinity)).toThrow();
expect(() => createFreeBox(+Infinity)).toThrow();
expect(mocks.isobmff.createBox).not.toHaveBeenCalled();
});
});
describe("createHDLRBox", () => {
it("should always create the same audio box", () => {
const box = new Uint8Array([1, 2, 3, 4]);
mocks.isobmff.createBox.mockImplementation(() => box);
expect(createHDLRBox("audio")).toBe(box);
expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1);
expect(mocks.isobmff.createBox).toHaveBeenCalledWith(
"hdlr",
new Uint8Array([
0,
0,
0,
0,
0,
0,
0,
0,
115,
111,
117,
110, // "soun"
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
83,
111,
117,
110,
100,
72,
97,
110,
100,
108,
101,
114, // "SoundHandler"
0,
]),
);
});
it("should always create the same video box", () => {
const box = new Uint8Array([1, 2, 3, 4]);
mocks.isobmff.createBox.mockImplementation(() => box);
expect(createHDLRBox("video")).toBe(box);
expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1);
expect(mocks.isobmff.createBox).toHaveBeenCalledWith(
"hdlr",
new Uint8Array([
0,
0,
0,
0,
0,
0,
0,
0,
118,
105,
100,
101, // "vide"
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
86,
105,
100,
101,
111,
72,
97,
110,
100,
108,
101,
114, // "VideoHandler"
0,
]),
);
});
it("should always create the same hint box", () => {
const box = new Uint8Array([1, 2, 3, 4]);
mocks.isobmff.createBox.mockImplementation(() => box);
expect(createHDLRBox("hint")).toBe(box);
expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1);
expect(mocks.isobmff.createBox).toHaveBeenCalledWith(
"hdlr",
new Uint8Array([
0,
0,
0,
0,
0,
0,
0,
0,
104,
105,
110,
116, // "soun"
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
]),
);
});
});
describe("createMDHDBox", () => {
it("should just integrate the timescale given", () => {
const translatedTimeScale = new Uint8Array([4, 3, 2, 1]);
const concatenated = new Uint8Array([9, 10, 11, 12]);
const box = new Uint8Array([1, 2, 3, 4]);
mocks.byteParsing.itobe4.mockImplementation(() => translatedTimeScale);
mocks.byteParsing.concat.mockImplementation(() => concatenated);
mocks.isobmff.createBox.mockImplementation(() => box);
expect(createMDHDBox(8)).toBe(box);
expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1);
expect(mocks.isobmff.createBox).toHaveBeenCalledWith("mdhd", concatenated);
expect(mocks.byteParsing.itobe4).toHaveBeenCalledTimes(1);
expect(mocks.byteParsing.itobe4).toHaveBeenCalledWith(8);
expect(mocks.byteParsing.concat).toHaveBeenCalledTimes(1);
expect(mocks.byteParsing.concat).toHaveBeenCalledWith(12, translatedTimeScale, 8);
expect(createMDHDBox(99)).toBe(box);
expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(2);
expect(mocks.isobmff.createBox).toHaveBeenCalledWith("mdhd", concatenated);
expect(mocks.byteParsing.itobe4).toHaveBeenCalledTimes(2);
expect(mocks.byteParsing.itobe4).toHaveBeenCalledWith(99);
expect(mocks.byteParsing.concat).toHaveBeenCalledTimes(2);
expect(mocks.byteParsing.concat).toHaveBeenCalledWith(12, translatedTimeScale, 8);
});
});
describe("createSMHDBox", () => {
it("should create always the same smhd box", () => {
const smhdContent = new Uint8Array(8);
const box = new Uint8Array([1, 2, 3, 4]);
mocks.isobmff.createBox.mockImplementation(() => box);
expect(createSMHDBox()).toBe(box);
expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1);
expect(mocks.isobmff.createBox).toHaveBeenCalledWith("smhd", smhdContent);
});
});
describe("createFRMABox", () => {
it("should just integrate the data format", () => {
const dataFormatToBytes = new Uint8Array([4, 3, 2, 1]);
const box = new Uint8Array([1, 2, 3, 4]);
mocks.stringParsing.strToUtf8.mockImplementation(() => dataFormatToBytes);
mocks.isobmff.createBox.mockImplementation(() => box);
expect(createFRMABox("foo")).toBe(box);
expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1);
expect(mocks.isobmff.createBox).toHaveBeenCalledWith("frma", dataFormatToBytes);
expect(mocks.stringParsing.strToUtf8).toHaveBeenCalledTimes(1);
expect(mocks.stringParsing.strToUtf8).toHaveBeenCalledWith("foo");
});
});
});