Skip to content

Commit 5f01abd

Browse files
committed
Added tests for FcoTextDocumentContentProvider.ts to confirm no memory leaks.
1 parent 0a8547f commit 5f01abd

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
import { describe, it, expect, beforeEach, vi } from "vitest"
2+
import { FcoTextDocumentContentProvider } from "../FcoTextDocumentContentProvider"
3+
4+
// Mock VS Code API
5+
vi.mock("vscode", () => ({
6+
workspace: {
7+
onDidCloseTextDocument: vi.fn().mockReturnValue({ dispose: vi.fn() }),
8+
},
9+
window: {
10+
tabGroups: {
11+
all: [],
12+
},
13+
},
14+
Uri: {
15+
parse: vi.fn((str: string) => ({
16+
scheme: str.split(":")[0],
17+
path: str.split(":")[1] || "",
18+
toString: () => str,
19+
})),
20+
},
21+
}))
22+
23+
describe("FcoTextDocumentContentProvider", () => {
24+
let provider: FcoTextDocumentContentProvider
25+
26+
beforeEach(() => {
27+
// Reset singleton instance
28+
;(FcoTextDocumentContentProvider as any).instance = undefined
29+
provider = FcoTextDocumentContentProvider.getInstance()
30+
provider.clearAll()
31+
vi.clearAllMocks()
32+
})
33+
34+
describe("Core Functionality", () => {
35+
it("stores and retrieves diff content", () => {
36+
const beforeContent = "line 1\nline 2"
37+
const afterContent = "line 1\nline 2 modified"
38+
39+
const { beforeUri, afterUri } = provider.storeDiffContent(beforeContent, afterContent, "test/file.ts")
40+
41+
expect(beforeUri).toMatch(/^fco-diff:before-/)
42+
expect(afterUri).toMatch(/^fco-diff:after-/)
43+
expect(provider.getStoredContentCount()).toBe(2)
44+
})
45+
46+
it("creates different URIs for different file paths", () => {
47+
const content1 = "same content"
48+
const content2 = "same content"
49+
50+
const result1 = provider.storeDiffContent(content1, content2, "file1.ts")
51+
const result2 = provider.storeDiffContent(content1, content2, "file2.ts")
52+
53+
// URIs should be different because file paths are different (hash includes file path)
54+
expect(result1.beforeUri).not.toBe(result2.beforeUri)
55+
expect(result1.afterUri).not.toBe(result2.afterUri)
56+
expect(provider.getStoredContentCount()).toBe(4) // Each file gets its own content
57+
})
58+
59+
it("provides correct content for URI", () => {
60+
const beforeContent = "original"
61+
const afterContent = "modified"
62+
63+
const { beforeUri } = provider.storeDiffContent(beforeContent, afterContent)
64+
const uri = { path: beforeUri.replace("fco-diff:", "") } as any
65+
66+
expect(provider.provideTextDocumentContent(uri)).toBe(beforeContent)
67+
})
68+
69+
it("tracks file path to URI mapping", () => {
70+
const { beforeUri, afterUri } = provider.storeDiffContent("before", "after", "test/file.ts")
71+
72+
const mapping = provider.getUrisForFile("test/file.ts")
73+
expect(mapping).toEqual({ beforeUri, afterUri })
74+
})
75+
})
76+
77+
describe("Cleanup & Memory Management", () => {
78+
it("cleanupFile removes content and mapping", () => {
79+
const { beforeUri, afterUri } = provider.storeDiffContent("before", "after", "test/file.ts")
80+
81+
expect(provider.getStoredContentCount()).toBe(2)
82+
expect(provider.getUrisForFile("test/file.ts")).toBeDefined()
83+
84+
provider.cleanupFile("test/file.ts")
85+
86+
expect(provider.getStoredContentCount()).toBe(0)
87+
expect(provider.getUrisForFile("test/file.ts")).toBeUndefined()
88+
})
89+
90+
it("cleanup removes specific URIs", () => {
91+
const { beforeUri, afterUri } = provider.storeDiffContent("a", "b")
92+
const { beforeUri: beforeUri2 } = provider.storeDiffContent("c", "d")
93+
94+
expect(provider.getStoredContentCount()).toBe(4)
95+
96+
provider.cleanup([beforeUri])
97+
98+
expect(provider.getStoredContentCount()).toBe(3)
99+
})
100+
101+
it("handles multiple files without memory accumulation", () => {
102+
const fileCount = 10
103+
104+
// Create multiple diff sessions
105+
for (let i = 0; i < fileCount; i++) {
106+
provider.storeDiffContent(`before ${i}`, `after ${i}`, `file${i}.ts`)
107+
}
108+
109+
expect(provider.getStoredContentCount()).toBe(fileCount * 2)
110+
111+
// Clean up individual files
112+
for (let i = 0; i < fileCount; i++) {
113+
provider.cleanupFile(`file${i}.ts`)
114+
}
115+
116+
// All content should be cleaned up
117+
expect(provider.getStoredContentCount()).toBe(0)
118+
})
119+
120+
it("clearAll removes everything", () => {
121+
provider.storeDiffContent("a", "b", "file1.ts")
122+
provider.storeDiffContent("c", "d", "file2.ts")
123+
124+
expect(provider.getStoredContentCount()).toBe(4)
125+
expect(provider.getUrisForFile("file1.ts")).toBeDefined()
126+
127+
provider.clearAll()
128+
129+
expect(provider.getStoredContentCount()).toBe(0)
130+
expect(provider.getUrisForFile("file1.ts")).toBeUndefined()
131+
})
132+
})
133+
134+
describe("Integration", () => {
135+
it("registerCloseListener returns disposable and registers with VS Code", async () => {
136+
const vscode = await import("vscode")
137+
const disposable = provider.registerCloseListener()
138+
139+
expect(disposable).toEqual({ dispose: expect.any(Function) })
140+
expect(vscode.workspace.onDidCloseTextDocument).toHaveBeenCalledWith(expect.any(Function))
141+
})
142+
143+
it("singleton pattern works correctly", () => {
144+
const instance1 = FcoTextDocumentContentProvider.getInstance()
145+
const instance2 = FcoTextDocumentContentProvider.getInstance()
146+
147+
expect(instance1).toBe(instance2)
148+
})
149+
})
150+
151+
describe("Edge Cases", () => {
152+
it("handles cleanup of non-existent content gracefully", () => {
153+
expect(() => provider.cleanupFile("nonexistent.ts")).not.toThrow()
154+
expect(() => provider.cleanup(["fco-diff:nonexistent"])).not.toThrow()
155+
})
156+
157+
it("handles storeDiffContent without file path", () => {
158+
const result = provider.storeDiffContent("before", "after")
159+
160+
expect(result.beforeUri).toMatch(/^fco-diff:before-/)
161+
expect(result.afterUri).toMatch(/^fco-diff:after-/)
162+
expect(provider.getStoredContentCount()).toBe(2)
163+
})
164+
165+
it("returns empty string for non-existent URI", () => {
166+
const uri = { path: "non-existent-key" } as any
167+
expect(provider.provideTextDocumentContent(uri)).toBe("")
168+
})
169+
170+
it("returns undefined for unmapped file", () => {
171+
const mapping = provider.getUrisForFile("nonexistent.ts")
172+
expect(mapping).toBeUndefined()
173+
})
174+
})
175+
})

0 commit comments

Comments
 (0)