Files
openidea/src/platform/classFiles.test.ts
T
l0ng-ai 482241ebb9 feat(java): open class files as decompiled sources with breakpoints (#657)
Opening a .class file showed binary content. Class files from library jars, project output directories, navigation, Go to Class and debugger frames now all go through one route to JDT class documents:

- Library classes open the attached source, or the FernFlower decompilation when there is none, read-only and marked as decompiled. java-debug's decompiled-source support is enabled, so breakpoints set in decompiled code map to the original lines and hit, and stepping into such classes lands on the right line.
- Output-directory classes (target/classes, build/classes) open their project source when it exists; otherwise the decompiled text is shown read-only with breakpoints disabled, because jdt.ls returns no line mapping for classes outside the Java model.
- The preferred content provider id is corrected to fernflowerContentProvider (attached sources still win), and the decompiled marker recognises the current FernFlower header.

Verified on macOS with a Maven project: library class from Libraries and Go to Class, breakpoint hit and step into decompiled code, output class with and without source. Not run on Windows, Linux or Gradle projects.

Fixes #394
2026-11-01 15:04:28 +08:00

35 lines
1.5 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { classFileBreakpointReason, isClassFile } from "./classFiles";
import { isVirtualUri } from "./virtualDocs";
import { canPlaceBreakpoint } from "@/features/debugger/breakpoints/languages";
vi.mock("@/platform/workflowSettings", () => ({
workflowSettings: () => ({ debugger: { breakpointsAnyFile: true } }),
}));
describe("compiled class routing and breakpoint policy", () => {
it.each([
"/p/target/classes/p/C.class",
"/p/build/classes/java/main/p/C$1.class",
"C:\\p\\out\\C.class",
"file:///p/out/C.class",
])("disables output breakpoints even with any-file enabled: %s", (path) => {
expect(isClassFile(path)).toBe(true);
expect(classFileBreakpointReason(path)).toBeTruthy();
expect(canPlaceBreakpoint("java", path)).toBe(false);
});
it.each([
"jdt://contents/a.jar/p/C.class?=p/a.jar%3Cp%28C.class",
"jdt://contents/a.jar/p/C.java?=p/a.jar%3Cp%28C.class",
"/p/src/main/java/p/C.java",
])("keeps source and JDT breakpoints enabled: %s", (path) => {
expect(isClassFile(path)).toBe(false);
expect(classFileBreakpointReason(path)).toBeNull();
expect(canPlaceBreakpoint("java", path)).toBe(true);
});
it("treats disk class URIs as read-only server documents", () => {
expect(isVirtualUri("file:///p/out/C.class")).toBe(true);
expect(isVirtualUri("file:///p/src/C.java")).toBe(false);
expect(isClassFile("/m2/a.jar!/p/C.class")).toBe(true);
});
});