Файли
openidea/src/features/settings/__tests__/languages.test.ts
T
l0ng-ai d3cb7c14ca feat(maven): add POMs outside the root reactor as Maven projects (#1446)
feat(maven): add POMs outside the root reactor as Maven projects

Add Maven Projects only re-linked POMs Maven had already discovered: picking a pom.xml inside the
project that the root POM doesn't list as a module (an independent build kept out of the reactor)
closed the dialog and changed nothing. Such POMs are now kept in the project's Maven settings
(linkedProjects) and loaded as independent top-level projects, after the root reactor, by the
static model, the sync, the Java language server import and the content roots; each runs its goals
in its own directory. A picked POM that the root reactor lists stays its module. The dialog takes
several POMs at once, and unlinking a linked project drops the link instead of hiding it.
2026-11-05 12:01:03 +08:00

190 рядки
7.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
DEFAULT_LANGUAGES,
PHP_LANGUAGE_LEVELS,
folderRole,
markFolder,
normalizeFolder,
validateLanguages,
validateProjectStructure,
} from "@/platform/languageSettings";
import { buildPageTree } from "../model/pages";
import { LANGUAGE_PAGES } from "../pages/languages";
import { filterPackages } from "../languages/PythonInterpreterPage";
import { tildify } from "../languages/components";
import { validateSettings } from "../model/schema";
describe("languages settings", () => {
it("defaults and normalises malformed values", () => {
expect(validateLanguages(undefined)).toEqual(DEFAULT_LANGUAGES);
const v = validateLanguages({
python: { interpreter: " /usr/bin/python3 ", activateVirtualenv: "yes" },
node: { packageManager: "pip" },
rust: { checkCommand: "clippy", checkOnSave: false },
typescript: { version: "" },
java: {
jdtlsVmArgs: " -Xmx2g ",
jdk: 21,
jdtlsJdk: " /opt/jdk-25 ",
maven: { home: " /opt/maven ", daemon: "yes", mvndHome: " /opt/mvnd " },
},
});
expect(v.python).toEqual({ interpreter: "/usr/bin/python3", activateVirtualenv: true });
expect(v.node.packageManager).toBe("");
expect(v.rust.checkCommand).toBe("clippy");
expect(v.rust.checkOnSave).toBe(false);
expect(v.typescript.version).toBe("bundled");
expect(v.java.jdtlsVmArgs).toBe("-Xmx2g");
expect(v.java.jdk).toBe("");
expect(v.java.jdtlsJdk).toBe("/opt/jdk-25");
expect(v.java.maven).toEqual({
home: "/opt/maven",
userSettings: "",
localRepository: "",
unlinkedProjects: [],
linkedProjects: [],
daemon: false,
mvndHome: "/opt/mvnd",
});
expect(validateSettings({}).languages).toEqual(DEFAULT_LANGUAGES);
});
it("keeps the Ruby interpreter through settings normalization and defaults to Auto", () => {
expect(validateSettings({}).languages.ruby.interpreter).toBe("");
expect(validateLanguages({ ruby: { interpreter: 42 } }).ruby.interpreter).toBe("");
const settings = validateSettings({ languages: { ruby: { interpreter: " /opt/ruby/bin/ruby " } } });
expect(settings.languages.ruby.interpreter).toBe("/opt/ruby/bin/ruby");
expect(validateSettings(settings).languages.ruby.interpreter).toBe("/opt/ruby/bin/ruby");
});
it("defaults the PHP language level to Auto and keeps only known levels", () => {
expect(validateSettings({}).languages.php).toEqual({
interpreter: "",
languageLevel: "",
includePaths: [],
stubs: [],
});
const lists = validateLanguages({ php: { includePaths: [" ../platform ", "", 3, "../platform"], stubs: "redis" } });
expect(lists.php.includePaths).toEqual(["../platform"]);
expect(lists.php.stubs).toEqual([]);
expect(validateLanguages({ php: { languageLevel: "7.4" } }).php.languageLevel).toBe("7.4");
for (const level of ["7.4.3", "9.0", 8.1, null]) {
expect(validateLanguages({ php: { languageLevel: level } }).php.languageLevel).toBe("");
}
expect(PHP_LANGUAGE_LEVELS[0]).toBe("");
expect(PHP_LANGUAGE_LEVELS).toContain("5.6");
expect(PHP_LANGUAGE_LEVELS.at(-1)).toBe("8.5");
});
it("finds the PHP page by its language level", () => {
const php = LANGUAGE_PAGES.find((p) => p.id === "languages.php")!;
expect(php.keywords).toContain("language level");
});
it("keeps Prettier opt-in on save and normalizes its enabled languages", () => {
expect(validateLanguages({}).prettier).toMatchObject({ prefer: false, runOnSave: false, path: "" });
expect(
validateLanguages({
prettier: { path: " ./bin/prettier ", languages: ["markdown", 4, "markdown"], prefer: true, runOnSave: true },
}).prettier,
).toEqual({ path: "./bin/prettier", languages: ["markdown"], prefer: true, runOnSave: true });
expect(validateLanguages({ prettier: { languages: [] } }).prettier.languages).toEqual([]);
});
it("gives oxfmt the same opt-in settings as Prettier, kept apart from them", () => {
expect(validateLanguages({}).oxfmt).toEqual(DEFAULT_LANGUAGES.prettier);
const v = validateLanguages({
prettier: { runOnSave: true },
oxfmt: { path: " ./bin/oxfmt ", languages: ["typescript", null, "typescript"], prefer: true },
});
expect(v.oxfmt).toEqual({ path: "./bin/oxfmt", languages: ["typescript"], prefer: true, runOnSave: false });
expect(v.prettier).toMatchObject({ runOnSave: true, prefer: false, path: "" });
});
it("leaves the Markdown preview font size unset (editor font) and keeps a set one in 8..72", () => {
expect(validateLanguages({}).markdown).toEqual({ previewFontSize: null });
expect(validateLanguages({ markdown: { previewFontSize: 90 } }).markdown).toEqual({ previewFontSize: 72 });
expect(validateLanguages({ markdown: { previewFontSize: "x" } }).markdown).toEqual({ previewFontSize: null });
});
it("keeps the Markdown page global, like IDEA's application-level setting", () => {
expect(LANGUAGE_PAGES.find((p) => p.id === "languages.markdown")).not.toHaveProperty("projectScope");
});
it("marks folders with one role each", () => {
expect(normalizeFolder("./src/main/")).toBe("src/main");
let ps = validateProjectStructure({ sourceRoots: ["src/", "src", 3], excluded: ["/dist"] });
expect(ps.sourceRoots).toEqual(["src"]);
expect(ps.excluded).toEqual(["dist"]);
ps = markFolder(ps, "src", "test");
expect(ps.sourceRoots).toEqual([]);
expect(folderRole(ps, "src/")).toBe("test");
ps = markFolder(ps, "src", null);
expect(folderRole(ps, "src")).toBeNull();
});
});
describe("language pages", () => {
it("keeps every language under Languages & Frameworks, as in IntelliJ IDEA", () => {
const tree = buildPageTree(LANGUAGE_PAGES.map((p) => ({ ...p, component: p.component! })));
expect(tree.map((n) => n.title)).toEqual(["Project Structure", "Languages & Frameworks"]);
const langs = tree.find((n) => n.title === "Languages & Frameworks")!;
expect(langs.children.map((n) => n.title)).toEqual([
"Go",
"Java",
"Markdown",
"Node.js",
"Python Interpreter",
"PHP",
"Prettier",
"oxfmt",
"Ruby",
"Rust",
"TypeScript",
]);
});
it("filters packages and shortens home paths", () => {
const pkgs = [
{ name: "Django", version: "5.1" },
{ name: "requests", version: "2.32.0" },
];
expect(filterPackages(pkgs, "dj").map((p) => p.name)).toEqual(["Django"]);
expect(filterPackages(pkgs, "")).toHaveLength(2);
expect(tildify("/Users/me/p/.venv/bin/python")).toBe("~/p/.venv/bin/python");
expect(tildify("C:/Users/me/.m2/wrapper/dists/apache-maven-3.9.16")).toBe(
"~/.m2/wrapper/dists/apache-maven-3.9.16",
);
expect(tildify("C:/Program Files/Java/jdk-21")).toBe("C:/Program Files/Java/jdk-21");
});
});
describe("Go module settings", () => {
it("keeps automatic vendoring by default and normalizes malformed environment entries", () => {
expect(validateLanguages({ go: {} }).go.modules).toEqual({ env: {}, autoVendor: true });
const modules = validateLanguages({
go: {
modules: {
autoVendor: false,
env: {
GOPROXY: "https://proxy.example",
GOPRIVATE: "example.com/private",
GOFLAGS: "-race",
INVALID: 3,
"BAD KEY": "value",
NULL: "x\0y",
},
},
},
}).go.modules;
expect(modules).toEqual({
autoVendor: false,
env: { GOPROXY: "https://proxy.example", GOPRIVATE: "example.com/private", GOFLAGS: "-race" },
});
expect(validateLanguages({ go: { modules: { autoVendor: "no", env: [] } } }).go.modules).toEqual({
env: {},
autoVendor: true,
});
});
});