Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/linkify/test/node/statCaching.spec.ts
13405 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { expect, suite, test } from 'vitest';
7
import { NullEnvService } from '../../../../platform/env/common/nullEnvService';
8
import { IFileSystemService } from '../../../../platform/filesystem/common/fileSystemService';
9
import { CancellationToken } from '../../../../util/vs/base/common/cancellation';
10
import { LinkifyLocationAnchor } from '../../common/linkifiedText';
11
import { LinkifyService } from '../../common/linkifyService';
12
import { assertPartsEqual, createMockFsService, createMockWorkspaceService, workspaceFile } from './util';
13
14
function createCountingFsService(listOfFiles: readonly string[]): { fs: IFileSystemService; statCallCount: () => number } {
15
const inner = createMockFsService(listOfFiles);
16
let callCount = 0;
17
const fs: IFileSystemService = {
18
...inner,
19
stat(uri) {
20
callCount++;
21
return inner.stat(uri);
22
},
23
};
24
return { fs, statCallCount: () => callCount };
25
}
26
27
suite('Stat Caching - FilePathLinkifier', () => {
28
29
test('Should cache stat calls for repeated file paths', async () => {
30
const { fs, statCallCount } = createCountingFsService(['file.ts']);
31
const workspaceService = createMockWorkspaceService();
32
const service = new LinkifyService(fs, workspaceService, NullEnvService.Instance);
33
34
const linkifier = service.createLinkifier({ requestId: undefined, references: [] }, []);
35
36
// First append: linkify `file.ts`
37
const r1 = await linkifier.append('`file.ts` ', CancellationToken.None);
38
const countAfterFirst = statCallCount();
39
40
// Second append: linkify `file.ts` again — should reuse cached stat
41
const r2 = await linkifier.append('`file.ts` ', CancellationToken.None);
42
const countAfterSecond = statCallCount();
43
44
// Both should produce file links
45
assertPartsEqual(r1.parts, [new LinkifyLocationAnchor(workspaceFile('file.ts')), ' ']);
46
assertPartsEqual(r2.parts, [new LinkifyLocationAnchor(workspaceFile('file.ts')), ' ']);
47
48
// The second call should not have increased the stat count
49
expect(countAfterSecond).toBe(countAfterFirst);
50
});
51
52
test('Should cache stat calls across different matches in same text', async () => {
53
const { fs, statCallCount } = createCountingFsService(['file.ts']);
54
const workspaceService = createMockWorkspaceService();
55
const service = new LinkifyService(fs, workspaceService, NullEnvService.Instance);
56
57
const linkifier = service.createLinkifier({ requestId: undefined, references: [] }, []);
58
59
// Two references to the same file in one chunk
60
await linkifier.append('`file.ts` and file.ts ', CancellationToken.None);
61
await linkifier.flush(CancellationToken.None);
62
63
// The stat should be cached, so only 1 stat call for the same URI
64
expect(statCallCount()).toBe(1);
65
});
66
67
test('Should not cache across different URIs', async () => {
68
const { fs, statCallCount } = createCountingFsService(['file.ts', 'other.ts']);
69
const workspaceService = createMockWorkspaceService();
70
const service = new LinkifyService(fs, workspaceService, NullEnvService.Instance);
71
72
const linkifier = service.createLinkifier({ requestId: undefined, references: [] }, []);
73
74
await linkifier.append('`file.ts` ', CancellationToken.None);
75
const countAfterFirst = statCallCount();
76
77
await linkifier.append('`other.ts` ', CancellationToken.None);
78
const countAfterSecond = statCallCount();
79
80
// Different files should each get their own stat call
81
expect(countAfterSecond).toBeGreaterThan(countAfterFirst);
82
});
83
});
84
85
suite('Stat Caching - ModelFilePathLinkifier', () => {
86
87
test('Should cache stat calls for repeated model file links', async () => {
88
const { fs, statCallCount } = createCountingFsService(['src/file.ts']);
89
const workspaceService = createMockWorkspaceService();
90
const service = new LinkifyService(fs, workspaceService, NullEnvService.Instance);
91
92
const linkifier = service.createLinkifier({ requestId: undefined, references: [] }, []);
93
94
// First link
95
await linkifier.append('[src/file.ts](src/file.ts) ', CancellationToken.None);
96
const countAfterFirst = statCallCount();
97
98
// Same link again — should reuse cache
99
await linkifier.append('[src/file.ts](src/file.ts) ', CancellationToken.None);
100
const countAfterSecond = statCallCount();
101
102
// Second should not add more stat calls
103
expect(countAfterSecond).toBe(countAfterFirst);
104
});
105
});
106
107
suite('Stat Caching - Shared across linkifiers', () => {
108
109
test('Should share stat cache between ModelFilePathLinkifier and FilePathLinkifier', async () => {
110
const { fs, statCallCount } = createCountingFsService(['src/file.ts']);
111
const workspaceService = createMockWorkspaceService();
112
const service = new LinkifyService(fs, workspaceService, NullEnvService.Instance);
113
114
const linkifier = service.createLinkifier({ requestId: undefined, references: [] }, []);
115
116
// ModelFilePathLinkifier processes this markdown link first
117
await linkifier.append('[src/file.ts](src/file.ts) ', CancellationToken.None);
118
const countAfterModel = statCallCount();
119
120
// FilePathLinkifier processes same path as inline code — should reuse shared cache
121
await linkifier.append('`src/file.ts` ', CancellationToken.None);
122
const countAfterFile = statCallCount();
123
124
// The shared cache should prevent additional stat calls
125
expect(countAfterFile).toBe(countAfterModel);
126
});
127
});
128
129