Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/linkify/test/vscode-node/notebookCellLinkifier.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 { suite, test } from 'vitest';
7
import type { NotebookCell, NotebookDocument, TextDocument } from 'vscode';
8
import { ILogger, ILogService } from '../../../../platform/log/common/logService';
9
import { TestWorkspaceService } from '../../../../platform/test/node/testWorkspaceService';
10
import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService';
11
import { CancellationToken } from '../../../../util/vs/base/common/cancellation';
12
import { StringSHA1 } from '../../../../util/vs/base/common/hash';
13
import { NotebookCellKind, Uri } from '../../../../vscodeTypes';
14
import { LinkifiedPart, LinkifyLocationAnchor } from '../../common/linkifiedText';
15
import { NotebookCellLinkifier } from '../../vscode-node/notebookCellLinkifier';
16
import { assertPartsEqual } from '../node/util';
17
18
suite('Notebook Cell Linkifier', () => {
19
20
// The cell ID prefix from helpers.ts
21
const CELL_ID_PREFIX = '#VSC-';
22
23
function createMockNotebookCell(uri: Uri, index: number): NotebookCell {
24
return {
25
index,
26
kind: NotebookCellKind.Code,
27
document: {
28
uri,
29
lineCount: 1,
30
lineAt: () => ({ text: 'print("hello")' }),
31
languageId: 'python'
32
} as unknown as TextDocument,
33
metadata: {},
34
outputs: [],
35
executionSummary: undefined
36
} as unknown as NotebookCell;
37
}
38
39
function createMockNotebookDocument(cells: NotebookCell[]): NotebookDocument {
40
return {
41
uri: Uri.file('/test/notebook.ipynb'),
42
getCells: () => cells,
43
cellCount: cells.length,
44
cellAt: (index: number) => cells[index],
45
notebookType: 'jupyter-notebook',
46
isDirty: false,
47
isUntitled: false,
48
isClosed: false,
49
metadata: {},
50
version: 1,
51
save: () => Promise.resolve(true)
52
} as NotebookDocument;
53
}
54
55
function createMockWorkspaceService(notebooks: NotebookDocument[]): IWorkspaceService {
56
return new TestWorkspaceService([], [], notebooks);
57
}
58
59
function generateCellId(cellUri: Uri): string {
60
const hash = new StringSHA1();
61
hash.update(cellUri.toString());
62
return `${CELL_ID_PREFIX}${hash.digest().substring(0, 8)}`;
63
}
64
65
const logger: ILogger = {
66
error: () => { /* no-op */ },
67
warn: () => { /* no-op */ },
68
info: () => { /* no-op */ },
69
debug: () => { /* no-op */ },
70
trace: () => { /* no-op */ },
71
show: () => { /* no-op */ },
72
createSubLogger(): ILogger { return logger; },
73
withExtraTarget(): ILogger { return logger; }
74
};
75
const mockLogger = new class implements ILogService {
76
_serviceBrand: undefined;
77
internal = logger;
78
logger = logger;
79
trace = logger.trace;
80
debug = logger.debug;
81
info = logger.info;
82
warn = logger.warn;
83
error = logger.error;
84
show(preserveFocus?: boolean): void {
85
//
86
}
87
createSubLogger(): ILogger {
88
return this;
89
}
90
withExtraTarget(): ILogger {
91
return this;
92
}
93
}();
94
95
function normalizeParts(parts: readonly LinkifiedPart[]): LinkifiedPart[] {
96
const normalized: LinkifiedPart[] = [];
97
for (const part of parts) {
98
if (typeof part === 'string' && normalized.length && typeof normalized[normalized.length - 1] === 'string') {
99
normalized[normalized.length - 1] += part; // Concatenate strings
100
} else {
101
normalized.push(part);
102
}
103
}
104
return normalized;
105
}
106
test('Should linkify actual cell IDs', async () => {
107
// Create mock cells with specific URIs
108
const cellUri1 = Uri.parse('vscode-notebook-cell:/test/notebook.ipynb#cell1');
109
const cellUri2 = Uri.parse('vscode-notebook-cell:/test/notebook.ipynb#cell2');
110
111
const cell1 = createMockNotebookCell(cellUri1, 0);
112
const cell2 = createMockNotebookCell(cellUri2, 1);
113
114
const notebook = createMockNotebookDocument([cell1, cell2]);
115
const workspaceService = createMockWorkspaceService([notebook]);
116
117
// Generate the expected cell IDs
118
const cellId1 = generateCellId(cellUri1);
119
const cellId2 = generateCellId(cellUri2);
120
121
const linkifier = new NotebookCellLinkifier(workspaceService, mockLogger);
122
123
const testText = `Below is a list of the cells that were executed\n* Cell Id ${cellId1}\n* Cell Id ${cellId2}\n Cell 1: code cell, id=${cellId1}, nor markdown, language=Python\n Cell 2(${cellId2}), nor markdown, language=Python`;
124
125
const result = await linkifier.linkify(testText, { requestId: undefined, references: [] }, CancellationToken.None);
126
127
// Should have linkified both cell IDs
128
assertPartsEqual(
129
normalizeParts(result.parts),
130
[
131
`Below is a list of the cells that were executed\n* Cell Id ${cellId1} `,
132
new LinkifyLocationAnchor(cellUri1, 'Cell 1'),
133
`\n* Cell Id ${cellId2} `,
134
new LinkifyLocationAnchor(cellUri2, 'Cell 2'),
135
`\n Cell 1: code cell, id=#VSC-c6b3ce64 `,
136
new LinkifyLocationAnchor(cellUri1, 'Cell 1'),
137
`, nor markdown, language=Python\n Cell 2(#VSC-f9c1928a `,
138
new LinkifyLocationAnchor(cellUri2, 'Cell 2'),
139
`), nor markdown, language=Python`
140
]
141
);
142
});
143
});
144
145