rx-player
Version:
Canal+ HTML5 Video Player
305 lines (276 loc) • 11.8 kB
text/typescript
import { describe, it, expect } from "vitest";
import { getFilenameIndexInUrl, getRelativeUrl, resolveURL } from "../url-utils";
describe(`utils - resolveURL ${resolveURL.name}`, () => {
it("should return an empty string if no argument is given", () => {
expect(resolveURL()).toBe("");
});
it("should concatenate multiple URLs", () => {
expect(resolveURL("http://toto.com/a")).toBe("http://toto.com/a");
expect(
resolveURL("http://toto.com/a" /** Trailling slash missing */, "b/c/d/", "g.a"),
).toBe("http://toto.com/b/c/d/g.a");
expect(
resolveURL("http://toto.com/a/" /** With a trailling slash */, "b/c/d/", "g.a"),
).toBe("http://toto.com/a/b/c/d/g.a");
});
it("should ignore empty strings when concatenating multiple URLs", () => {
expect(resolveURL("", "http://toto.com/a", "")).toBe("http://toto.com/a");
expect(resolveURL("http://toto.com/a/", "b/c/d/", "", "g.a")).toBe(
"http://toto.com/a/b/c/d/g.a",
);
});
it("should handle absolute path and keep the last one only", () => {
expect(resolveURL("http://toto.com/a", "/b/c/d/", "/", "/g.a")).toBe(
"http://toto.com/g.a",
);
});
it("should reset the concatenation if a given string contains a scheme", () => {
expect(resolveURL("http://toto.com/a", "b/c/d/", "torrent://g.a", "b")).toBe(
"torrent://g.a/b",
);
});
it("should have a - fairly simple - algorithm to simplify parent directories", () => {
expect(
resolveURL("http://toto.com/a/", "b/c/d/", "torrent://g.a/b/c/d/", "../a"),
).toBe("torrent://g.a/b/c/a");
expect(
resolveURL("http://toto.com/a/", "b/c/d/", "torrent://g.a/b/c/d/", "../c/../../a"),
).toBe("torrent://g.a/b/a");
});
it("should have a - fairly simple - algorithm to simplify the current directory", () => {
expect(
resolveURL("http://toto.com/a/", "b/c/d/", "torrent://g.a/b/c/d/", "./a"),
).toBe("torrent://g.a/b/c/d/a");
expect(
resolveURL("http://toto.com/a/", "b/c/d/", "torrent://g.a/b/c/d/", "../c/.././a"),
).toBe("torrent://g.a/b/c/a");
});
it("should resolve absolute urls with overriding baseURL path", () => {
expect(resolveURL("http://a/b/c/d;p?q", "/g")).toBe("http://a/g");
});
const normalExamples = [
{ input: "g:h", output: "g:h" },
{ input: "g", output: "http://a/b/c/g" },
{ input: "./g", output: "http://a/b/c/g" },
{ input: "g/", output: "http://a/b/c/g/" },
{ input: "/g", output: "http://a/g" },
{ input: "//g", output: "http://g" },
{ input: "?y", output: "http://a/b/c/d;p?y" },
{ input: "g?y", output: "http://a/b/c/g?y" },
{ input: "#s", output: "http://a/b/c/d;p?q#s" },
{ input: "g#s", output: "http://a/b/c/g#s" },
{ input: "g?y#s", output: "http://a/b/c/g?y#s" },
{ input: ";x", output: "http://a/b/c/;x" },
{ input: "g;x", output: "http://a/b/c/g;x" },
{ input: "g;x?y#s", output: "http://a/b/c/g;x?y#s" },
{ input: "", output: "http://a/b/c/d;p?q" },
{ input: ".", output: "http://a/b/c/" },
{ input: "./", output: "http://a/b/c/" },
{ input: "..", output: "http://a/b/" },
{ input: "../", output: "http://a/b/" },
{ input: "../g", output: "http://a/b/g" },
{ input: "../..", output: "http://a/" },
{ input: "../../", output: "http://a/" },
{ input: "../../g", output: "http://a/g" },
];
normalExamples.forEach((example) => {
it("should conform to RFC 3986 normal examples - case: " + example.input, () => {
const baseURL: string = "http://a/b/c/d;p?q";
// https://datatracker.ietf.org/doc/html/rfc3986#section-5.4.1
expect(resolveURL(baseURL, example.input)).toBe(example.output);
});
});
const abnormalExamples = [
{ input: "../../../g", output: "http://a/g" },
{ input: "../../../../g", output: "http://a/g" },
{ input: "/./g", output: "http://a/g" },
{ input: "/../g", output: "http://a/g" },
{ input: "g.", output: "http://a/b/c/g." },
{ input: ".g", output: "http://a/b/c/.g" },
{ input: "g..", output: "http://a/b/c/g.." },
{ input: "..g", output: "http://a/b/c/..g" },
{ input: "./../g", output: "http://a/b/g" },
{ input: "./g/.", output: "http://a/b/c/g/" },
{ input: "g/./h", output: "http://a/b/c/g/h" },
{ input: "g/../h", output: "http://a/b/c/h" },
{ input: "g;x=1/./y", output: "http://a/b/c/g;x=1/y" },
{ input: "g;x=1/../y", output: "http://a/b/c/y" },
{ input: "g?y/./x", output: "http://a/b/c/g?y/./x" },
{ input: "g?y/../x", output: "http://a/b/c/g?y/../x" },
{ input: "g#s/./x", output: "http://a/b/c/g#s/./x" },
{ input: "g#s/../x", output: "http://a/b/c/g#s/../x" },
];
abnormalExamples.forEach((example) => {
it("should conform to RFC 3986 abnormal examples - case: " + example.input, () => {
// https://datatracker.ietf.org/doc/html/rfc3986#section-5.4.2
const baseURL: string = "http://a/b/c/d;p?q";
expect(resolveURL(baseURL, example.input)).toBe(example.output);
});
});
it("should work with URL with a port number in the URL", () => {
const baseURL = "http://example.com:8090/foo/";
const relative = "bar";
expect(resolveURL(baseURL, relative)).toBe("http://example.com:8090/foo/bar");
});
it("should work with credentials in the URL", () => {
const baseURL = "http://username:password@example.com/";
const relative = "bar";
expect(resolveURL(baseURL, relative)).toBe(
"http://username:password@example.com/bar",
);
});
});
describe("utils - getFilenameIndexInUrl", () => {
it("should return the length for a string without slash", () => {
const str = ";.<;L'dl'02984lirsahg;oliwr";
expect(getFilenameIndexInUrl(str)).toEqual(str.length);
});
it("should return the index after the last / if one in URL", () => {
expect(getFilenameIndexInUrl(";ojdsfgje/eprowig/tohjroj/9ohyjwoij/s")).toEqual(36);
});
it("should return length if the only slash are part of the protocol", () => {
const url1 = "http://www.example.com";
expect(getFilenameIndexInUrl(url1)).toEqual(url1.length);
const url2 = "https://a.t";
expect(getFilenameIndexInUrl(url2)).toEqual(url2.length);
const url3 = "ftp://s";
expect(getFilenameIndexInUrl(url3)).toEqual(url3.length);
});
it("should not include slash coming in query parameters", () => {
expect(getFilenameIndexInUrl("http://www.example.com?test/toto")).toEqual(22);
expect(getFilenameIndexInUrl("https://ww/ddd?test/toto/efewf/ffe/")).toEqual(11);
expect(getFilenameIndexInUrl("https://ww/rr/d?test/toto/efewf/ffe/")).toEqual(14);
expect(getFilenameIndexInUrl("https://ww/rr/d/?test/toto/efewf/ffe/")).toEqual(16);
});
});
describe("utils - getRelativeUrl", () => {
it("should succeed on two absolute URLs on the same domain", () => {
expect(
getRelativeUrl("https://foo.com/foo/bar/cil/", "https://foo.com/foo/bar/cil/diub"),
).toEqual("diub");
expect(
getRelativeUrl(
"https://foo.com/foo/bar/cil/",
"https://foo.com/foo/bar/cil/diub/emp",
),
).toEqual("diub/emp");
expect(
getRelativeUrl(
"https://foo.com/foo/bar/cil/diub/emp/",
"https://foo.com/foo/bar/cil/f/g/h/i",
),
).toEqual("../../f/g/h/i");
expect(
getRelativeUrl(
"https://foo.com/foo/bar/cil/emp",
"https://foo.com/foo/bar/cil/emp",
),
).toEqual("");
});
it("should handle it right when one of the input is just a domain name without a path", () => {
expect(
getRelativeUrl(
"http://github.com" /** Without a starting slash */,
"http://github.com/rx-player",
),
).toBe("/rx-player");
expect(
getRelativeUrl(
"http://github.com/rx-player/",
"http://github.com" /** Without a starting slash */,
),
).toBe("..");
});
it("should handle it right when one of the input has a path of length 0", () => {
expect(getRelativeUrl("http://github.com/", "http://github.com/rx-player")).toBe(
"rx-player",
);
expect(
getRelativeUrl(
"http://github.com/rx-player/",
"http://github.com" /** Without a starting slash */,
),
).toBe("..");
});
it("should fail if scheme is different", () => {
expect(
getRelativeUrl("http://foo.com/foo/bar/cil/emp", "https://foo.com/foo/bar/cil/emp"),
).toEqual(null);
expect(
getRelativeUrl("https://foo.com/foo/bar/cil/emp", "http://foo.com/foo/bar/cil/emp"),
).toEqual(null);
});
it("should fail if domain is different", () => {
expect(
getRelativeUrl(
"https://bar.com/foo/bar/cil/emp",
"https://foo.com/foo/bar/cil/emp",
),
).toEqual(null);
});
it("should fail if one anounce a domain but not the other", () => {
expect(getRelativeUrl("https://foo.com/foo/bar/cil/diub/emp", "/a")).toEqual(null);
expect(getRelativeUrl("../url", "https://foo.com")).toEqual(null);
});
it('should output "." if the URL points to the same file', () => {
expect(getRelativeUrl("../url", "../url")).toEqual("");
expect(
getRelativeUrl(
"https://foo.com/foo/bar/cil/diub/emp",
"https://foo.com/foo/bar/cil/diub/emp",
),
).toEqual("");
expect(
getRelativeUrl(
"https://foo.com/foo/bar/cil/diub/emp",
"https://foo.com/foo/bar/../bar/cil/diub/emp",
),
).toEqual("");
});
it("should succeed on two relative URLs", () => {
expect(getRelativeUrl("../url/a", "../url/a/b")).toEqual("a/b");
expect(getRelativeUrl("../url/a", "../url/b/c")).toEqual("b/c");
});
it("should fail if one seems to be relative to the domain's root, yet we don't know it", () => {
expect(getRelativeUrl("/url/a", "../../../url/b/c")).toEqual(null);
expect(getRelativeUrl("./url/a", "/url/b/c")).toEqual(null);
expect(getRelativeUrl("http://foo.com/url/a", "../url/b/c")).toEqual(null);
});
it("should succeed if both seem to be relative to the domain's root, even if we don't know it", () => {
expect(getRelativeUrl("/url/a", "/url/b/c")).toEqual("b/c");
});
const normalExamples = [
{ input: "http://a/b/c/g", output: "g" },
{ input: "http://a/b/c/g/", output: "g/" },
{ input: "http://a/g", output: "../../g" },
{ input: "http://a/b/c/d;p?y", output: "?y" },
{ input: "http://a/b/c/g?y", output: "g?y" },
{ input: "http://a/b/c/d;p?q#s", output: "#s" },
{ input: "http://a/b/c/g#s", output: "g#s" },
{ input: "http://a/b/c/g?y#s", output: "g?y#s" },
{ input: "http://a/b/c/;x", output: ";x" },
{ input: "http://a/b/c/g;x", output: "g;x" },
{ input: "http://a/b/c/g;x?y#s", output: "g;x?y#s" },
{ input: "http://a/b/c/d;p?q", output: "" },
{ input: "http://a/b/c/", output: "." },
{ input: "http://a/b/", output: ".." },
{ input: "http://a/b/g", output: "../g" },
{ input: "http://a/", output: "../.." },
{ input: "http://a/g", output: "../../g" },
];
normalExamples.forEach((example) => {
it("should conform to RFC 3986 normal examples - case: " + example.input, () => {
const baseURL: string = "http://a/b/c/d;p?q";
// https://datatracker.ietf.org/doc/html/rfc3986#section-5.4.1
expect(getRelativeUrl(baseURL, example.input)).toBe(example.output);
});
});
it("should succeed on two relative URLs", () => {
expect(getRelativeUrl("../url/a", "../url/a/b")).toEqual("a/b");
expect(getRelativeUrl("../url/a", "../url/b/c")).toEqual("b/c");
});
it("should return null if the relation between the two URLs is unclear", () => {
expect(getRelativeUrl("/url/a", "url/a/b")).toEqual(null);
expect(getRelativeUrl("url/a", "/url/a/b")).toEqual(null);
});
});