Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/util/misc.test.ts
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import seedrandom from "seedrandom";6import * as misc from "./misc";78describe("academic domain", () => {9const ia = misc.isAcademic;1011test("denies non academics", () => {12expect(ia("[email protected]")).toBe(false);13expect(ia("[email protected]")).toBe(false);14expect(ia("[email protected]")).toBe(false);15expect(ia("[email protected]")).toBe(false);16expect(ia("[email protected]")).toBe(false);17});1819test("detects academics", () => {20expect(ia("[email protected]")).toBe(true);21expect(ia("[email protected]")).toBe(true);22expect(ia("[email protected]")).toBe(true);23expect(ia("[email protected]")).toBe(true);24expect(ia("[email protected]")).toBe(true);25});26});2728describe("rpad_html", () => {29const rp = misc.rpad_html;30const round1 = misc.round1;31test("0", () => expect(rp(0, 3)).toEqual(" 0"));32test("99", () => expect(rp(99, 3)).toEqual(" 99"));33test("4444-5", () => expect(rp(4444, 5)).toEqual(" 4444"));34test("6666-4", () => expect(rp(6666, 4)).toEqual("6666"));35test("1000-4", () => expect(rp(1000, 4)).toEqual("1000"));36test("1000-3", () => expect(rp(1000, 3)).toEqual("1000"));37test("pi-1", () => expect(rp(3.1415, 4, round1)).toEqual(" 3.1"));38});3940describe("path_split", () => {41const ps = misc.path_split;4243test("full path", () =>44expect(ps("foo/bar")).toEqual({ head: "foo", tail: "bar" }));4546test("filename", () =>47expect(ps("foo.bar.baz")).toEqual({ head: "", tail: "foo.bar.baz" }));4849test("dirname", () => expect(ps("foo/")).toEqual({ head: "foo", tail: "" }));5051test("abspath", () =>52expect(ps("/HOME/USER/DIR")).toEqual({53head: "/HOME/USER",54tail: "DIR",55}));5657test("ROOT", () => expect(ps("/")).toEqual({ head: "", tail: "" }));58});5960describe("contains_url", () => {61const cu = misc.contains_url;6263test("normal html is fine", () =>64expect(cu("<h2>foo</h2><div>bar</div>")).toBe(false));6566test("detects URLs", () => {67expect(cu("<p><a href='http://foo.com'>click me</a></p>")).toBe(true);68expect(cu("abc bar.com xyz")).toBe(true);69expect(cu("abc www.buy.me xyz")).toBe(true);70});71});7273describe("date object some time ago", () => {74test("roughly 10 mins ago", () => {75const res = misc.minutes_ago(10);76const diff = new Date().getTime() - res.getTime();77expect(diff).toBeLessThan(10 * 60 * 1000 + 100);78expect(diff).toBeGreaterThan(10 * 60 * 1000 - 100);79});80test("2 months ago", () => {81const res = misc.months_ago(2);82const diff = new Date().getTime() - res.getTime();83expect(diff).toBeLessThan(2 * 31 * 24 * 60 * 60 * 1000);84expect(diff).toBeGreaterThan(2 * 30 * 24 * 60 * 60 * 1000);85});86});8788describe("how_long_ago_m", () => {89test("10 min ago by Date", () => {90const past: Date = misc.minutes_ago(10);91const diff = misc.how_long_ago_m(past);92expect(diff).toBeLessThan(10.1);93expect(diff).toBeGreaterThan(9.9);94});9596test("10 min ago by timestamp", () => {97const past: number = misc.minutes_ago(10).getTime();98const diff = misc.how_long_ago_m(past);99expect(diff).toBeLessThan(10.1);100expect(diff).toBeGreaterThan(9.9);101});102});103104describe("json patch test", () => {105const j = misc.test_valid_jsonpatch;106test("empty array is fine", () => expect(j([])).toBe(true));107test("a complete example is fine", () => {108// taken from https://jsonpatch.com/109const patch = [110{ op: "add", path: "/biscuits/1", value: { name: "Ginger Nut" } },111{ op: "remove", path: "/biscuits" },112{ op: "remove", path: "/biscuits/0" },113{ op: "replace", path: "/biscuits/0/name", value: "Chocolate Digestive" },114{ op: "copy", from: "/biscuits/0", path: "/best_biscuit" },115{ op: "move", from: "/biscuits", path: "/cookies" },116{ op: "test", path: "/best_biscuit/name", value: "Choco Leibniz" },117];118119expect(j(patch)).toBe(true);120});121test("fails with broken examples", () => {122expect(123j({ op: "add", path: "/biscuits/1", value: { name: "Ginger Nut" } }),124).toBe(false);125expect(j([{ opp: "remove", path: "/biscuits" }])).toBe(false);126expect(j([{ path: "/biscuits/0" }])).toBe(false);127expect(j([{ op: "replacce", path: "/biscuits/0/name" }])).toBe(false);128});129});130131test("firstLetterUppercase", () => {132const s = misc.firstLetterUppercase;133expect(s(undefined)).toBe("");134expect(s("")).toBe("");135expect(s("a")).toBe("A");136expect(s("abc")).toBe("Abc");137expect(s("ABC")).toBe("ABC");138expect(s("aBC")).toBe("ABC");139});140141test("hexColorToRGBA", () => {142const c1 = misc.hexColorToRGBA("#000000");143expect(c1).toEqual("rgb(0,0,0)");144const c2 = misc.hexColorToRGBA("#ffffff", 0.5);145expect(c2).toEqual("rgba(255,255,255,0.5)");146});147148test("strictMod", () => {149const mod = misc.strictMod;150expect(mod(0, 3)).toBe(0);151expect(mod(1, 3)).toBe(1);152expect(mod(-2, 3)).toBe(1);153expect(mod(-3, 3)).toBe(0);154expect(mod(-1, 10)).toBe(9);155});156157test("EDITOR_PREFIX", () => {158// don't change it, because codebase is not using the global variable everywhere159expect(misc.EDITOR_PREFIX).toBe("editor-");160});161162describe("test code for displaying numbers as currency with 2 or sometimes 3 decimals of precision", () => {163const { currency } = misc;164it("displays 1.23", () => {165expect(currency(1.23)).toBe("$1.23");166});167168it("displays 0.0094 with 3 digits (not 2), but only because n is less than 0.01", () => {169expect(currency(0.0094)).toBe("$0.009");170});171172it("displays 0.1941 with 2, because n is not less than 0.01", () => {173expect(currency(0.1941)).toBe("$0.19");174});175it("displays 0.01941 with 2, because n is not less than 0.01", () => {176expect(currency(0.01941)).toBe("$0.02");177});178179it("displays 0.0941 with 2 digits if second argument specifies that", () => {180expect(currency(0.0941, 2)).toBe("$0.09");181});182183it("displays 0.086 with 2 digits if second argument specifies that, and it is rounded to nearest", () => {184expect(currency(0.086, 2)).toBe("$0.09");185});186187it("displays 0.083 with 2 digits if second argument specifies that, and it is rounded to nearest (NOT up)", () => {188expect(currency(0.083, 2)).toBe("$0.08");189});190191it("always includes at least 2 decimals", () => {192expect(currency(10)).toBe("$10.00");193});194});195196describe("smallIntegerToEnglishWord", () => {197it("handles floats", () => {198expect(misc.smallIntegerToEnglishWord(1.2)).toBe(1.2);199});200201it("handles 0", () => {202expect(misc.smallIntegerToEnglishWord(0)).toBe("zero");203});204205it("handles 1", () => {206expect(misc.smallIntegerToEnglishWord(1)).toBe("one");207});208209it("handles 17", () => {210expect(misc.smallIntegerToEnglishWord(17)).toBe("seventeen");211});212213it("handles negative numbers", () => {214expect(misc.smallIntegerToEnglishWord(-1)).toBe(-1);215});216});217218describe("test round2up and round2down for various inputs", () => {219const { round2up, round2down } = misc;220it("round2up tests -- uses the decimal representation (not internal binary))", () => {221// see https://github.com/sagemathinc/cocalc/issues/7220222expect(round2up(20.01)).toBe(20.01);223expect(round2up(20.011)).toBe(20.02);224expect(round2up(20.01999)).toBe(20.02);225expect(round2up(4.73)).toBe(4.73);226expect(round2up(4.731)).toBe(4.74);227expect(round2up(4.736)).toBe(4.74);228});229230it("round2down tests -- uses the decimal representation (not internal binary))", () => {231// see https://github.com/sagemathinc/cocalc/issues/7220232expect(round2down(20.01)).toBe(20.01);233expect(round2down(20.011)).toBe(20.01);234expect(round2down(20.019)).toBe(20.01);235expect(round2down(4.73)).toBe(4.73);236expect(round2down(4.731)).toBe(4.73);237expect(round2down(4.736)).toBe(4.73);238});239240it("a random test of 1000 cases", () => {241let seed = "my-seed";242let rng = seedrandom(seed);243244for (let i = 0; i < 1000; i++) {245let randomNum = rng(); // Returns a number between 0 and 1246// Perform your tests with randomNum247// For example:248expect(round2up(randomNum)).toBeGreaterThanOrEqual(randomNum);249expect(round2up(randomNum)).toBeLessThan(randomNum + 0.01);250expect(round2down(randomNum)).toBeLessThanOrEqual(randomNum);251expect(round2down(randomNum)).toBeGreaterThan(randomNum - 0.01);252}253});254});255256describe("numToOrdinal", () => {257const { numToOrdinal } = misc;258it("appends proper suffixes", () => {259expect(numToOrdinal(1)).toBe("1st");260expect(numToOrdinal(2)).toBe("2nd");261expect(numToOrdinal(3)).toBe("3rd");262expect(numToOrdinal(4)).toBe("4th");263expect(numToOrdinal(5)).toBe("5th");264expect(numToOrdinal(6)).toBe("6th");265expect(numToOrdinal(7)).toBe("7th");266expect(numToOrdinal(8)).toBe("8th");267expect(numToOrdinal(9)).toBe("9th");268expect(numToOrdinal(10)).toBe("10th");269expect(numToOrdinal(11)).toBe("11th");270expect(numToOrdinal(12)).toBe("12th");271expect(numToOrdinal(13)).toBe("13th");272expect(numToOrdinal(21)).toBe("21st");273expect(numToOrdinal(22)).toBe("22nd");274expect(numToOrdinal(23)).toBe("23rd");275expect(numToOrdinal(24)).toBe("24th");276expect(numToOrdinal(42)).toBe("42nd");277expect(numToOrdinal(101)).toBe("101st");278expect(numToOrdinal(202)).toBe("202nd");279expect(numToOrdinal(303)).toBe("303rd");280expect(numToOrdinal(1000)).toBe("1000th");281});282it("Falls back in other cases", () => {283expect(numToOrdinal(-1)).toBe("-1th");284});285});286287describe("hoursToTimeIntervalHuman", () => {288const { hoursToTimeIntervalHuman } = misc;289it("converts nicely", () => {290expect(hoursToTimeIntervalHuman(1)).toBe("1 hour");291expect(hoursToTimeIntervalHuman(13.333)).toBe("13.3 hours");292expect(hoursToTimeIntervalHuman(13.888)).toBe("13.9 hours");293expect(hoursToTimeIntervalHuman(24)).toBe("1 day");294expect(hoursToTimeIntervalHuman(24 * 7)).toBe("1 week");295expect(hoursToTimeIntervalHuman(2)).toBe("2 hours");296expect(hoursToTimeIntervalHuman(2 * 24)).toBe("2 days");297expect(hoursToTimeIntervalHuman(5 * 7 * 24)).toBe("5 weeks");298expect(hoursToTimeIntervalHuman(2.5111 * 24)).toBe("2.5 days");299expect(hoursToTimeIntervalHuman(2.5111 * 24 * 7)).toBe("2.5 weeks");300});301});302303describe("tail", () => {304const s = `305foo306bar307baz308abc309xyz310test 123`;311const { tail } = misc;312it("return the last 3 lines", () => {313const t = tail(s, 3);314expect(t.split("\n").length).toEqual(3);315expect(t.startsWith("abc")).toBe(true);316});317it("return the last line", () => {318const t = tail("foo", 3);319expect(t.split("\n").length).toEqual(1);320expect(t).toEqual("foo");321});322});323324describe("suggest_duplicate_filename", () => {325const dup = misc.suggest_duplicate_filename;326it("works with numbers", () => {327expect(dup("filename-1.test")).toBe("filename-2.test");328expect(dup("filename-99.test")).toBe("filename-100.test");329expect(dup("filename_99.test")).toBe("filename_100.test");330});331it("handles leading zeros", () => {332// handles leading 0's properly: https://github.com/sagemathinc/cocalc/issues/2973333expect(dup("filename_001.test")).toBe("filename_002.test");334});335it("works also without", () => {336expect(dup("filename-test")).toBe("filename-test-1");337expect(dup("filename-xxx.test")).toBe("filename-xxx-1.test");338expect(dup("bla")).toBe("bla-1");339expect(dup("foo.bar")).toBe("foo-1.bar");340});341it("also works with weird corner cases", () => {342expect(dup("asdf-")).toBe("asdf--1");343});344});345346347