import { describe, it, expect, vi } from "vitest";
import log from "../../../../../../log";
import type { ITNode } from "../../../../../../utils/xml-parser";
import { parseXml } from "../../../../../../utils/xml-parser";
import { createAdaptationSetIntermediateRepresentation } from "../AdaptationSet";
import { MPDError } from "../utils";
function testBooleanAttribute(attributeName: string, variableName?: string): void {
const _variableName = variableName ?? attributeName;
it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{
attributes: { [_variableName]: true },
children: { baseURLs: [], representations: [] },
},
[],
]);
const element2 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{
attributes: { [_variableName]: false },
children: { baseURLs: [], representations: [] },
},
[],
]);
expect(spyLog).not.toHaveBeenCalled();
spyLog.mockRestore();
});
it(`should correctly parse an AdaptationSet element with an incorrect ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
const error1 = new MPDError(
`\`${attributeName}\` property is not a boolean value but "foobar"`,
);
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{
attributes: { [_variableName]: false },
children: { baseURLs: [], representations: [] },
},
[error1],
]);
expect(spyLog).toHaveBeenCalledTimes(1);
expect(spyLog).toHaveBeenNthCalledWith(
1,
"dash",
"failed to parse DASH value:",
error1.message,
{ dashName: attributeName },
);
const element2 = parseXml(``)[0] as ITNode;
const error2 = new MPDError(
`\`${attributeName}\` property is not a boolean value but ""`,
);
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{
attributes: { [_variableName]: false },
children: { baseURLs: [], representations: [] },
},
[error2],
]);
expect(spyLog).toHaveBeenCalledTimes(2);
expect(spyLog).toHaveBeenNthCalledWith(
2,
"dash",
"failed to parse DASH value:",
error2.message,
{ dashName: attributeName },
);
spyLog.mockRestore();
});
}
function testStringAttribute(attributeName: string, variableName?: string): void {
const _variableName = variableName ?? attributeName;
it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{
attributes: { [_variableName]: "foobar" },
children: { baseURLs: [], representations: [] },
},
[],
]);
const element2 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{
attributes: { [_variableName]: "" },
children: { baseURLs: [], representations: [] },
},
[],
]);
expect(spyLog).not.toHaveBeenCalled();
spyLog.mockRestore();
});
}
function testMaybeDividedNumber(attributeName: string, variableName?: string): void {
const _variableName = variableName ?? attributeName;
it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{
attributes: { [_variableName]: 12.4 },
children: { baseURLs: [], representations: [] },
},
[],
]);
const element2 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{
attributes: { [_variableName]: 0 },
children: { baseURLs: [], representations: [] },
},
[],
]);
const element3 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([
{
attributes: { [_variableName]: 13.5 },
children: { baseURLs: [], representations: [] },
},
[],
]);
expect(spyLog).not.toHaveBeenCalled();
spyLog.mockRestore();
});
it(`should correctly parse an AdaptationSet element with an incorrect ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
const error1 = new MPDError(`\`${attributeName}\` property is invalid: "toto"`);
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error1],
]);
expect(spyLog).toHaveBeenCalledTimes(1);
expect(spyLog).toHaveBeenNthCalledWith(
1,
"dash",
"failed to parse DASH value:",
error1.message,
{ dashName: attributeName },
);
const element2 = parseXml(``)[0] as ITNode;
const error2 = new MPDError(`\`${attributeName}\` property is invalid: "PT5M"`);
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error2],
]);
expect(spyLog).toHaveBeenCalledTimes(2);
expect(spyLog).toHaveBeenNthCalledWith(
2,
"dash",
"failed to parse DASH value:",
error2.message,
{ dashName: attributeName },
);
const element3 = parseXml(``)[0] as ITNode;
const error3 = new MPDError(`\`${attributeName}\` property is invalid: ""`);
expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error3],
]);
expect(spyLog).toHaveBeenCalledTimes(3);
expect(spyLog).toHaveBeenNthCalledWith(
3,
"dash",
"failed to parse DASH value:",
error3.message,
{ dashName: attributeName },
);
spyLog.mockRestore();
});
}
function testFloatAttribute(attributeName: string, variableName?: string): void {
const _variableName = variableName ?? attributeName;
it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{
attributes: { [_variableName]: 12 },
children: { baseURLs: [], representations: [] },
},
[],
]);
const element2 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{
attributes: { [_variableName]: 0 },
children: { baseURLs: [], representations: [] },
},
[],
]);
const element3 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([
{
attributes: { [_variableName]: -50.12 },
children: { baseURLs: [], representations: [] },
},
[],
]);
expect(spyLog).not.toHaveBeenCalled();
spyLog.mockRestore();
});
it(`should correctly parse an AdaptationSet element with an incorrect ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
const error1 = new MPDError(`\`${attributeName}\` property is invalid: "toto"`);
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error1],
]);
expect(spyLog).toHaveBeenCalledTimes(1);
expect(spyLog).toHaveBeenNthCalledWith(
1,
"dash",
"failed to parse DASH value:",
error1.message,
{ dashName: attributeName },
);
const element2 = parseXml(``)[0] as ITNode;
const error2 = new MPDError(`\`${attributeName}\` property is invalid: "PT5M"`);
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error2],
]);
expect(spyLog).toHaveBeenCalledTimes(2);
expect(spyLog).toHaveBeenNthCalledWith(
2,
"dash",
"failed to parse DASH value:",
error2.message,
{ dashName: attributeName },
);
const element3 = parseXml(``)[0] as ITNode;
const error3 = new MPDError(`\`${attributeName}\` property is invalid: ""`);
expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error3],
]);
expect(spyLog).toHaveBeenCalledTimes(3);
expect(spyLog).toHaveBeenNthCalledWith(
3,
"dash",
"failed to parse DASH value:",
error3.message,
{ dashName: attributeName },
);
spyLog.mockRestore();
});
}
function testIntegerAttribute(attributeName: string, variableName?: string): void {
const _variableName = variableName ?? attributeName;
it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{
attributes: { [_variableName]: 12 },
children: { baseURLs: [], representations: [] },
},
[],
]);
const element2 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{
attributes: { [_variableName]: 0 },
children: { baseURLs: [], representations: [] },
},
[],
]);
const element3 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([
{
attributes: { [_variableName]: -50 },
children: { baseURLs: [], representations: [] },
},
[],
]);
expect(spyLog).not.toHaveBeenCalled();
spyLog.mockRestore();
});
it(`should correctly parse an AdaptationSet element with an incorrect ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
const error1 = new MPDError(
`\`${attributeName}\` property is not an integer value but "toto"`,
);
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error1],
]);
expect(spyLog).toHaveBeenCalledTimes(1);
expect(spyLog).toHaveBeenNthCalledWith(
1,
"dash",
"failed to parse DASH value:",
error1.message,
{ dashName: attributeName },
);
const element2 = parseXml(``)[0] as ITNode;
const error2 = new MPDError(
`\`${attributeName}\` property is not an integer value but "PT5M"`,
);
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error2],
]);
expect(spyLog).toHaveBeenCalledTimes(2);
expect(spyLog).toHaveBeenNthCalledWith(
2,
"dash",
"failed to parse DASH value:",
error2.message,
{ dashName: attributeName },
);
const element3 = parseXml(``)[0] as ITNode;
const error3 = new MPDError(
`\`${attributeName}\` property is not an integer value but ""`,
);
expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error3],
]);
expect(spyLog).toHaveBeenCalledTimes(3);
expect(spyLog).toHaveBeenNthCalledWith(
3,
"dash",
"failed to parse DASH value:",
error3.message,
{ dashName: attributeName },
);
spyLog.mockRestore();
});
}
function testNumberOrBooleanAttribute(
attributeName: string,
variableName?: string,
): void {
const _variableName = variableName ?? attributeName;
it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{
attributes: { [_variableName]: 12 },
children: { baseURLs: [], representations: [] },
},
[],
]);
const element2 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{
attributes: { [_variableName]: 0 },
children: { baseURLs: [], representations: [] },
},
[],
]);
const element3 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([
{
attributes: { [_variableName]: -50 },
children: { baseURLs: [], representations: [] },
},
[],
]);
expect(spyLog).not.toHaveBeenCalled();
spyLog.mockRestore();
});
it(`should correctly parse an AdaptationSet element with an incorrect ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
const error1 = new MPDError(
`\`${attributeName}\` property is not a boolean nor an integer but "toto"`,
);
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error1],
]);
expect(spyLog).toHaveBeenCalledTimes(1);
expect(spyLog).toHaveBeenNthCalledWith(
1,
"dash",
"failed to parse DASH value:",
error1.message,
{ dashName: attributeName },
);
const element2 = parseXml(``)[0] as ITNode;
const error2 = new MPDError(
`\`${attributeName}\` property is not a boolean nor an integer but "PT5M"`,
);
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error2],
]);
expect(spyLog).toHaveBeenCalledTimes(2);
expect(spyLog).toHaveBeenNthCalledWith(
2,
"dash",
"failed to parse DASH value:",
error2.message,
{ dashName: attributeName },
);
const element3 = parseXml(``)[0] as ITNode;
const error3 = new MPDError(
`\`${attributeName}\` property is not a boolean nor an integer but ""`,
);
expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[error3],
]);
expect(spyLog).toHaveBeenCalledTimes(3);
expect(spyLog).toHaveBeenNthCalledWith(
3,
"dash",
"failed to parse DASH value:",
error3.message,
{ dashName: attributeName },
);
spyLog.mockRestore();
});
it(`should correctly parse an AdaptationSet element with a boolean ${attributeName} attribute`, () => {
const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn());
const element1 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{
attributes: { [_variableName]: true },
children: { baseURLs: [], representations: [] },
},
[],
]);
const element2 = parseXml(``)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{
attributes: { [_variableName]: false },
children: { baseURLs: [], representations: [] },
},
[],
]);
expect(spyLog).not.toHaveBeenCalled();
spyLog.mockRestore();
});
}
describe("DASH Node Parsers - AdaptationSet", () => {
it("should correctly parse an AdaptationSet element without attributes nor children", () => {
const element = parseXml("")[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[],
]);
});
testStringAttribute("audioSamplingRate");
testBooleanAttribute("bitstreamSwitching");
testStringAttribute("codecs");
testBooleanAttribute("codingDependency");
testStringAttribute("contentType");
testMaybeDividedNumber("frameRate");
testIntegerAttribute("group");
testIntegerAttribute("height");
testStringAttribute("id");
testStringAttribute("lang", "language");
testIntegerAttribute("maxBandwidth", "maxBitrate");
testMaybeDividedNumber("maxFrameRate");
testIntegerAttribute("maxHeight");
testFloatAttribute("maxPlayoutRate");
testIntegerAttribute("maxWidth");
testFloatAttribute("maximumSAPPeriod");
testStringAttribute("mimeType");
testIntegerAttribute("minBandwidth", "minBitrate");
testMaybeDividedNumber("minFrameRate");
testIntegerAttribute("minHeight");
testIntegerAttribute("minWidth");
testStringAttribute("par");
testStringAttribute("profiles");
testNumberOrBooleanAttribute("segmentAlignment");
testStringAttribute("segmentProfiles");
testNumberOrBooleanAttribute("subsegmentAlignment");
testIntegerAttribute("width");
testFloatAttribute("availabilityTimeOffset");
it("should correctly parse an empty baseURLs", () => {
const element1 = parseXml("")[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[],
]);
const element2 = parseXml(
"",
)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{ attributes: {}, children: { baseURLs: [], representations: [] } },
[],
]);
});
it("should correctly parse a non-empty baseURLs", () => {
const element1 = parseXml(
'a',
)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{
attributes: {},
children: { baseURLs: [{ value: "a" }], representations: [] },
},
[],
]);
const element2 = parseXml(
'foo bar',
)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([
{
attributes: {},
children: { baseURLs: [{ value: "foo bar" }], representations: [] },
},
[],
]);
});
it("should correctly parse multiple non-empty baseURLs", () => {
const element1 = parseXml(
'ab',
)[0] as ITNode;
expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([
{
attributes: {},
children: {
baseURLs: [{ value: "a" }, { value: "b" }],
representations: [],
},
},
[],
]);
});
});