cli.spec.ts•5.44 kB
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import * as fs from "node:fs";
import * as path from "node:path";
import { fileURLToPath } from "node:url";
import * as cliLib from "./cli_lib.js";
// Mock dependencies
vi.mock("node:fs");
vi.mock("node:path");
vi.mock("node:url");
vi.mock("./cli_lib.js");
vi.mock("./utils.js");
// Import the module containing the functions we want to test
import * as cliModule from "./cli.js";
describe("CLI Internal Functions", () => {
// Setup spies for console methods
const consoleErrorSpy = vi
.spyOn(console, "error")
.mockImplementation(() => {});
const consoleInfoSpy = vi.spyOn(console, "info").mockImplementation(() => {});
// Store original environment
const originalEnv = process.env;
beforeEach(() => {
// Reset mocks before each test
vi.resetAllMocks();
process.env = { ...originalEnv };
// Setup common mocks
vi.mocked(path.resolve).mockImplementation((...parts) => parts.join("/"));
vi.mocked(path.join).mockImplementation((...parts) => parts.join("/"));
vi.mocked(fileURLToPath).mockImplementation((url) => {
if (typeof url === "string") return url.replace("file://", "");
return "/mock/path";
});
// Mock the cli_lib functions
vi.mocked(cliLib.parseNameValuePair).mockImplementation((input) => {
if (input.includes(":")) {
const [name, value] = input.split(":", 2);
return { name, urlValue: value };
}
return null;
});
});
afterEach(() => {
process.env = originalEnv;
vi.resetAllMocks();
});
describe("loadDefaultSources", () => {
it("should load and parse default sources from file", () => {
const mockFileContent =
"- typescript:https://example.com/typescript\n- node:http://nodejs.org/docs";
vi.mocked(fs.readFileSync).mockReturnValue(mockFileContent);
const result = cliModule.loadDefaultSources("/mock/defaults.txt");
expect(result).toEqual({
typescript: "https://example.com/typescript",
node: "http://nodejs.org/docs",
});
});
it("should handle errors when reading defaults file", () => {
vi.mocked(fs.readFileSync).mockImplementation(() => {
throw new Error("File not found");
});
const result = cliModule.loadDefaultSources("/nonexistent/file");
expect(result).toEqual({});
expect(consoleErrorSpy).toHaveBeenCalled();
});
});
describe("processSourceOptions", () => {
it("should process individual source options", () => {
const sources = {};
const singleOptions = [
"node:https://example.com/node",
"typescript:https://example.com/ts",
];
const result = cliModule.processSourceOptions(
sources,
singleOptions,
"--llms-txt-source",
undefined,
"--llms-txt-sources"
);
expect(result).toEqual({
node: "https://example.com/node",
typescript: "https://example.com/ts",
});
});
it("should handle invalid source options", () => {
const sources = {};
const singleOptions = ["invalid-format"];
const result = cliModule.processSourceOptions(
sources,
singleOptions,
"--llms-txt-source",
undefined,
"--llms-txt-sources-file"
);
expect(result).toEqual({});
expect(consoleErrorSpy).toHaveBeenCalled();
});
});
describe("processDomainOptions", () => {
it("should process individual domain options", () => {
const allowDomainOptions = ["example.com", "test.org"];
const docSources = {
test: "https://example.com/docs",
};
const openApiSpecs = { test: "https://example.com/api/v1/openapi.json" };
const result = cliModule.processDomainOptions(
allowDomainOptions,
undefined,
undefined,
undefined,
docSources,
openApiSpecs
);
expect(result).toEqual(new Set(["example.com", "test.org"]));
});
it("should handle wildcard domain option", () => {
const allowDomainOptions = ["*"];
const docSources = {
test: "https://example.com/docs",
};
const openApiSpecs = { test: "https://example.com/api/v1/openapi.json" };
const result = cliModule.processDomainOptions(
allowDomainOptions,
undefined,
undefined,
undefined,
docSources,
openApiSpecs
);
expect(result).toEqual(new Set(["*"]));
});
});
describe("inferDomainsFromSources", () => {
it("should extract domains from HTTP/HTTPS URLs", () => {
const sources = {
typescript: "https://example.com/typescript/llms.txt",
nodejs: "http://nodejs.org/docs/llms.txt",
};
const allowedDomains = new Set<string>();
cliModule.inferDomainsFromSources(sources, allowedDomains);
expect(allowedDomains).toEqual(new Set(["example.com", "nodejs.org"]));
});
it("should not add domains when wildcard is present", () => {
const sources = {
typescript: "https://example.com/typescript/llms.txt",
};
const allowedDomains = new Set<string>(["*"]);
cliModule.inferDomainsFromSources(sources, allowedDomains);
expect(allowedDomains).toEqual(new Set(["*"]));
});
});
});
// Copyright (C) 2025 Christopher White
// SPDX-License-Identifier: AGPL-3.0-or-later