2024-08-28 17:14:26 +00:00
|
|
|
import {
|
|
|
|
|
enforceFleetSentenceCasing,
|
|
|
|
|
pluralize,
|
|
|
|
|
strToBool,
|
|
|
|
|
stripQuotes,
|
|
|
|
|
isIncompleteQuoteQuery,
|
2025-05-22 19:59:15 +00:00
|
|
|
hyphenateString,
|
2026-03-12 21:56:01 +00:00
|
|
|
matchLoosePrefixToKey,
|
2024-08-28 17:14:26 +00:00
|
|
|
} from "./stringUtils";
|
2023-05-18 20:40:04 +00:00
|
|
|
|
2024-02-21 19:01:01 +00:00
|
|
|
describe("string utilities", () => {
|
|
|
|
|
describe("enforceFleetSentenceCasing utility", () => {
|
|
|
|
|
it("fixes a Title Cased String with no ignore words", () => {
|
|
|
|
|
expect(enforceFleetSentenceCasing("All Hosts")).toEqual("All hosts");
|
|
|
|
|
expect(enforceFleetSentenceCasing("all Hosts")).toEqual("All hosts");
|
|
|
|
|
expect(enforceFleetSentenceCasing("all hosts")).toEqual("All hosts");
|
|
|
|
|
expect(enforceFleetSentenceCasing("All HosTs ")).toEqual("All hosts");
|
|
|
|
|
});
|
2023-05-18 20:40:04 +00:00
|
|
|
|
2024-02-21 19:01:01 +00:00
|
|
|
it("fixes a title cased string while ignoring special words in various places ", () => {
|
|
|
|
|
expect(enforceFleetSentenceCasing("macOS")).toEqual("macOS");
|
|
|
|
|
expect(enforceFleetSentenceCasing("macOS Settings")).toEqual(
|
|
|
|
|
"macOS settings"
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
enforceFleetSentenceCasing("osquery shouldn't be Capitalized")
|
|
|
|
|
).toEqual("osquery shouldn't be capitalized");
|
|
|
|
|
});
|
|
|
|
|
expect(enforceFleetSentenceCasing("fleet uses MySQL")).toEqual(
|
|
|
|
|
"Fleet uses MySQL"
|
2023-05-18 20:40:04 +00:00
|
|
|
);
|
|
|
|
|
});
|
2024-02-21 19:01:01 +00:00
|
|
|
|
|
|
|
|
describe("pluralize utility", () => {
|
|
|
|
|
it("returns the singular form of a word when count is 1", () => {
|
|
|
|
|
expect(pluralize(1, "hero", "es", "")).toEqual("hero");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("returns the plural form of a word when count is not 1", () => {
|
|
|
|
|
expect(pluralize(0, "hero", "es", "")).toEqual("heroes");
|
|
|
|
|
expect(pluralize(2, "hero", "es", "")).toEqual("heroes");
|
|
|
|
|
expect(pluralize(100, "hero", "es", "")).toEqual("heroes");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("returns the singular form of a word when count is 1 and a no custom suffix are provided", () => {
|
|
|
|
|
expect(pluralize(1, "hero")).toEqual("hero");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("returns the pluralized form of a word with 's' suffix when count is not 1 and no custom suffix are provided", () => {
|
|
|
|
|
expect(pluralize(0, "hero")).toEqual("heros");
|
|
|
|
|
expect(pluralize(2, "hero")).toEqual("heros");
|
|
|
|
|
expect(pluralize(100, "hero")).toEqual("heros");
|
|
|
|
|
});
|
|
|
|
|
});
|
2024-08-28 17:14:26 +00:00
|
|
|
|
|
|
|
|
describe("strToBool utility", () => {
|
|
|
|
|
it("converts 'true' to true and 'false' to false", () => {
|
|
|
|
|
expect(strToBool("true")).toBe(true);
|
|
|
|
|
expect(strToBool("false")).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("returns false for undefined, null, or empty string", () => {
|
|
|
|
|
expect(strToBool(undefined)).toBe(false);
|
|
|
|
|
expect(strToBool(null)).toBe(false);
|
|
|
|
|
expect(strToBool("")).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe("stripQuotes utility", () => {
|
|
|
|
|
it("removes matching single or double quotes from the start and end of a string", () => {
|
|
|
|
|
expect(stripQuotes('"Hello, World!"')).toEqual("Hello, World!");
|
|
|
|
|
expect(stripQuotes("'Hello, World!'")).toEqual("Hello, World!");
|
|
|
|
|
});
|
|
|
|
|
it("does not modify a string without quotes or mismatched quotes", () => {
|
|
|
|
|
expect(stripQuotes("No quotes here")).toEqual("No quotes here");
|
|
|
|
|
expect(stripQuotes(`'Mismatched quotes"`)).toEqual(`'Mismatched quotes"`);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe("isIncompleteQuoteQuery utility", () => {
|
|
|
|
|
it("returns true for a string starting with a quote but not ending with one", () => {
|
|
|
|
|
expect(isIncompleteQuoteQuery('"incomplete')).toBe(true);
|
|
|
|
|
expect(isIncompleteQuoteQuery("'incomplete")).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("returns false for a string with matching quotes", () => {
|
|
|
|
|
expect(isIncompleteQuoteQuery('"complete"')).toBe(false);
|
|
|
|
|
expect(isIncompleteQuoteQuery("'complete'")).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("returns false for a string without any quotes or an empty string", () => {
|
|
|
|
|
expect(isIncompleteQuoteQuery("no quotes")).toBe(false);
|
|
|
|
|
expect(isIncompleteQuoteQuery("")).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
});
|
2025-05-22 19:59:15 +00:00
|
|
|
|
|
|
|
|
describe("hyphenatedTitle", () => {
|
|
|
|
|
it("converts spaces to hyphens and lowercases", () => {
|
|
|
|
|
expect(hyphenateString("My Cool App")).toBe("my-cool-app");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("trims leading and trailing spaces", () => {
|
|
|
|
|
expect(hyphenateString(" Leading and trailing ")).toBe(
|
|
|
|
|
"leading-and-trailing"
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("collapses multiple spaces into one hyphen", () => {
|
|
|
|
|
expect(hyphenateString("Multiple spaces here")).toBe(
|
|
|
|
|
"multiple-spaces-here"
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("returns empty string for empty input", () => {
|
|
|
|
|
expect(hyphenateString("")).toBe("");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("handles already hyphenated and lowercase input", () => {
|
|
|
|
|
expect(hyphenateString("already-hyphenated-title")).toBe(
|
|
|
|
|
"already-hyphenated-title"
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("handles single word", () => {
|
|
|
|
|
expect(hyphenateString("Word")).toBe("word");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("handles all uppercase", () => {
|
|
|
|
|
expect(hyphenateString("ALL UPPERCASE")).toBe("all-uppercase");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("handles mixed case and spaces", () => {
|
|
|
|
|
expect(hyphenateString(" MixED CaSe App ")).toBe("mixed-case-app");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("handles numbers separated by spaces", () => {
|
|
|
|
|
expect(hyphenateString("Numbered App 3")).toBe("numbered-app-3");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("handles numbers attached to words", () => {
|
|
|
|
|
expect(hyphenateString("Attached Numbered App3")).toBe(
|
|
|
|
|
"attached-numbered-app3"
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-03-12 21:56:01 +00:00
|
|
|
|
|
|
|
|
describe("matchLoosePrefixToKey", () => {
|
|
|
|
|
const MAP = {
|
|
|
|
|
arc: "Arc",
|
|
|
|
|
code: "VisualStudioCode",
|
|
|
|
|
archaeology: "Archaeology",
|
|
|
|
|
"visual studio code": "VisualStudioCode",
|
|
|
|
|
"windows app": "WindowsApp",
|
|
|
|
|
"windows app remote": "WindowsAppRemote",
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
it("matches exact key", () => {
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, "Arc")).toBe("arc");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("matches key followed by space and suffix", () => {
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, "Visual Studio Code - Insiders")).toBe(
|
|
|
|
|
"visual studio code"
|
|
|
|
|
);
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, "Code 2")).toBe("code");
|
|
|
|
|
expect(
|
|
|
|
|
matchLoosePrefixToKey(MAP, "Visual Studio Code 2025 Edition")
|
|
|
|
|
).toBe("visual studio code");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("does not match non-word prefix (Archive vs arc)", () => {
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, "Archive")).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("matches 'code' as a whole word but not 'Codex'", () => {
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, "Code")).toBe("code");
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, "Code Helper")).toBe("code");
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, "Codex")).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("matches variants that use a space before another variant correctly by matching the longest match key", () => {
|
|
|
|
|
// Exact matches
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, "Windows App")).toBe("windows app");
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, "Windows App Remote")).toBe(
|
|
|
|
|
"windows app remote"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// With suffixes
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, "Windows App - Something")).toBe(
|
|
|
|
|
"windows app"
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
matchLoosePrefixToKey(MAP, "Windows App Remote - Something Else")
|
|
|
|
|
).toBe("windows app remote");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("is case-insensitive and trims surrounding whitespace", () => {
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, " arc ")).toBe("arc");
|
|
|
|
|
expect(matchLoosePrefixToKey(MAP, "VISUAL STUDIO CODE")).toBe(
|
|
|
|
|
"visual studio code"
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
matchLoosePrefixToKey(MAP, " Visual Studio Code - Insiders ")
|
|
|
|
|
).toBe("visual studio code");
|
|
|
|
|
});
|
|
|
|
|
});
|
2023-05-18 20:40:04 +00:00
|
|
|
});
|